From 025252c0de5bd0061b033c35c785efd07693c97c Mon Sep 17 00:00:00 2001 From: Kei Sakamoto Date: Tue, 2 Dec 2025 19:02:59 +0900 Subject: [PATCH] feat: implement no-sparse-arrays --- internal/config/config.go | 2 + .../no_sparse_arrays/no_sparse_arrays.go | 25 ++++++++ .../no_sparse_arrays/no_sparse_arrays_test.go | 58 +++++++++++++++++++ 3 files changed, 85 insertions(+) create mode 100644 internal/rules/no_sparse_arrays/no_sparse_arrays.go create mode 100644 internal/rules/no_sparse_arrays/no_sparse_arrays_test.go diff --git a/internal/config/config.go b/internal/config/config.go index c43fab90..a796d856 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -95,6 +95,7 @@ import ( "github.com/web-infra-dev/rslint/internal/rules/no_constant_condition" "github.com/web-infra-dev/rslint/internal/rules/no_constructor_return" "github.com/web-infra-dev/rslint/internal/rules/no_debugger" + "github.com/web-infra-dev/rslint/internal/rules/no_sparse_arrays" ) // RslintConfig represents the top-level configuration array @@ -459,6 +460,7 @@ func registerAllCoreEslintRules() { GlobalRuleRegistry.Register("no-constant-condition", no_constant_condition.NoConstantConditionRule) GlobalRuleRegistry.Register("no-constructor-return", no_constructor_return.NoConstructorReturnRule) GlobalRuleRegistry.Register("no-debugger", no_debugger.NoDebuggerRule) + GlobalRuleRegistry.Register("no-sparse-arrays", no_sparse_arrays.NoSparseArraysRule) } // getAllTypeScriptEslintPluginRules returns all registered rules (for backward compatibility when no config is provided) diff --git a/internal/rules/no_sparse_arrays/no_sparse_arrays.go b/internal/rules/no_sparse_arrays/no_sparse_arrays.go new file mode 100644 index 00000000..3184fcac --- /dev/null +++ b/internal/rules/no_sparse_arrays/no_sparse_arrays.go @@ -0,0 +1,25 @@ +package no_sparse_arrays + +import ( + "github.com/microsoft/typescript-go/shim/ast" + "github.com/web-infra-dev/rslint/internal/rule" +) + +// https://eslint.org/docs/latest/rules/no-sparse-arrays +var NoSparseArraysRule = rule.Rule{ + Name: "no-sparse-arrays", + Run: func(ctx rule.RuleContext, options any) rule.RuleListeners { + return rule.RuleListeners{ + ast.KindArrayLiteralExpression: func(node *ast.Node) { + for _, v := range node.AsArrayLiteralExpression().Elements.Nodes { + if v.Kind == ast.KindOmittedExpression { + ctx.ReportNode(node, rule.RuleMessage{ + Id: "unexpectedSparseArray", + Description: "Unexpected comma in middle of array.", + }) + } + } + }, + } + }, +} diff --git a/internal/rules/no_sparse_arrays/no_sparse_arrays_test.go b/internal/rules/no_sparse_arrays/no_sparse_arrays_test.go new file mode 100644 index 00000000..ad88a483 --- /dev/null +++ b/internal/rules/no_sparse_arrays/no_sparse_arrays_test.go @@ -0,0 +1,58 @@ +package no_sparse_arrays + +import ( + "testing" + + "github.com/web-infra-dev/rslint/internal/plugins/typescript/rules/fixtures" + "github.com/web-infra-dev/rslint/internal/rule_tester" +) + +func TestNoSparseArraysRule(t *testing.T) { + rule_tester.RunRuleTester( + fixtures.GetRootDir(), + "tsconfig.json", + t, + &NoSparseArraysRule, + // Valid cases - ported from ESLint + []rule_tester.ValidTestCase{ + {Code: `var a = [ 1, 2, ]`}, + }, + // Invalid cases - ported from ESLint + []rule_tester.InvalidTestCase{ + { + Code: `var a = [,];`, + Errors: []rule_tester.InvalidTestCaseError{ + {MessageId: "unexpectedSparseArray", Line: 1, Column: 9}, + }, + }, + { + Code: `var a = [ 1,, 2];`, + Errors: []rule_tester.InvalidTestCaseError{ + {MessageId: "unexpectedSparseArray", Line: 1, Column: 9}, + }, + }, + // This test case is commented out because it produces a TypeScript compilation error: + // error creating TS program for /tsconfig.json: found 5 syntactic errors. [Invalid character. [\r\n\t/* comment */,\n// comment\n ,]; Invalid character. [\r\n\t/* comment */,\n// comment\n ,]; Invalid character. [\r\n\t/* comment */,\n// comment\n ,]; Invalid character. [\r\n\t/* comment */,\n// comment\n ,]; ']' expected. [\r\n\t/* comment */,\n// comment\n ,];] + //{ + // Code: `[\r\n\t/* comment */,\n// comment\n ,];`, + // Errors: []rule_tester.InvalidTestCaseError{ + // {MessageId: "unexpectedSparseArray", Line: 1, Column: 9}, + // }, + //}, + { + Code: `[(( [a,] )),,,];`, + Errors: []rule_tester.InvalidTestCaseError{ + {MessageId: "unexpectedSparseArray", Line: 1, Column: 1}, + {MessageId: "unexpectedSparseArray", Line: 1, Column: 1}, + }, + }, + { + Code: `[,(( [a,] )),,];`, + Errors: []rule_tester.InvalidTestCaseError{ + {MessageId: "unexpectedSparseArray", Line: 1, Column: 1}, + {MessageId: "unexpectedSparseArray", Line: 1, Column: 1}, + }, + }, + }, + ) +}