-
Notifications
You must be signed in to change notification settings - Fork 21
@typescript-eslint/max-params #480
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 1 commit
5117057
703e7a6
94ffd14
536b1db
e45bebe
e3207fc
81aeb77
5ce5760
a30a61d
5fb9856
4c41a9a
06ebc85
bc7530d
566c0ab
999cf30
c2c1093
d4d2968
066aabd
d7473aa
0826bbf
98a7de3
a63a0ec
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,141 @@ | ||
| package max_params | ||
|
|
||
| import ( | ||
| "fmt" | ||
|
|
||
| "github.com/microsoft/typescript-go/shim/ast" | ||
| "github.com/web-infra-dev/rslint/internal/rule" | ||
| ) | ||
|
|
||
| type MaxParamsOptions struct { | ||
| Max int `json:"max"` | ||
| CountVoidThis bool `json:"countVoidThis"` | ||
| } | ||
|
|
||
| func parseNumericOption(value interface{}) (int, bool) { | ||
| switch v := value.(type) { | ||
| case int: | ||
| return v, true | ||
| case int32: | ||
| return int(v), true | ||
| case int64: | ||
| return int(v), true | ||
| case float32: | ||
| return int(v), true | ||
| case float64: | ||
| return int(v), true | ||
| default: | ||
| return 0, false | ||
| } | ||
| } | ||
|
|
||
| func parseOptions(options any) MaxParamsOptions { | ||
| opts := MaxParamsOptions{ | ||
| Max: 3, | ||
| CountVoidThis: false, | ||
| } | ||
|
|
||
| if options == nil { | ||
| return opts | ||
| } | ||
|
|
||
| var optsMap map[string]interface{} | ||
| if arr, ok := options.([]interface{}); ok && len(arr) > 0 { | ||
| optsMap, _ = arr[0].(map[string]interface{}) | ||
| } else { | ||
| optsMap, _ = options.(map[string]interface{}) | ||
| } | ||
|
|
||
| if optsMap == nil { | ||
| return opts | ||
| } | ||
|
|
||
| hasMax := false | ||
| if value, ok := optsMap["max"]; ok { | ||
| if maxValue, ok := parseNumericOption(value); ok { | ||
| opts.Max = maxValue | ||
| hasMax = true | ||
| } | ||
| } | ||
| if !hasMax { | ||
| if value, ok := optsMap["maximum"]; ok { | ||
| if maxValue, ok := parseNumericOption(value); ok { | ||
| opts.Max = maxValue | ||
| } | ||
| } | ||
| } | ||
| if value, ok := optsMap["countVoidThis"]; ok { | ||
| if flag, ok := value.(bool); ok { | ||
| opts.CountVoidThis = flag | ||
| } | ||
| } | ||
|
|
||
| return opts | ||
| } | ||
|
|
||
| func isVoidThisParameter(param *ast.Node) bool { | ||
| if param == nil || !ast.IsParameter(param) { | ||
| return false | ||
| } | ||
|
|
||
| decl := param.AsParameterDeclaration() | ||
| if decl == nil { | ||
| return false | ||
| } | ||
|
|
||
| name := decl.Name() | ||
| if name == nil || name.Kind != ast.KindIdentifier { | ||
| return false | ||
| } | ||
|
|
||
| if name.AsIdentifier().Text != "this" { | ||
| return false | ||
| } | ||
|
|
||
| return decl.Type != nil && decl.Type.Kind == ast.KindVoidKeyword | ||
| } | ||
|
|
||
| func buildExceedMessage(count int, maxCount int) rule.RuleMessage { | ||
| return rule.RuleMessage{ | ||
| Id: "exceed", | ||
| Description: fmt.Sprintf("Function has too many parameters (%d). Maximum allowed is %d.", count, maxCount), | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The original ESLint core It might be worth generating the appropriate name based on the node kind to stay consistent with the upstream behavior. Something like:
Not a blocker, but would be nice to align! |
||
| } | ||
| } | ||
|
|
||
| var MaxParamsRule = rule.CreateRule(rule.Rule{ | ||
| Name: "max-params", | ||
| Run: func(ctx rule.RuleContext, options any) rule.RuleListeners { | ||
| opts := parseOptions(options) | ||
|
|
||
| checkParameters := func(node *ast.Node) { | ||
| params := node.Parameters() | ||
| if params == nil { | ||
| return | ||
| } | ||
|
|
||
| count := len(params) | ||
| if !opts.CountVoidThis && count > 0 && isVoidThisParameter(params[0]) { | ||
| count-- | ||
| } | ||
|
|
||
| if count > opts.Max { | ||
| ctx.ReportNode(node, buildExceedMessage(count, opts.Max)) | ||
| } | ||
| } | ||
|
|
||
| return rule.RuleListeners{ | ||
| ast.KindFunctionDeclaration: checkParameters, | ||
| ast.KindFunctionExpression: checkParameters, | ||
| ast.KindArrowFunction: checkParameters, | ||
| ast.KindMethodDeclaration: checkParameters, | ||
| ast.KindMethodSignature: checkParameters, | ||
| ast.KindConstructor: checkParameters, | ||
| ast.KindGetAccessor: checkParameters, | ||
| ast.KindSetAccessor: checkParameters, | ||
| ast.KindCallSignature: checkParameters, | ||
| ast.KindConstructSignature: checkParameters, | ||
| ast.KindFunctionType: checkParameters, | ||
|
ScriptedAlchemy marked this conversation as resolved.
|
||
| ast.KindConstructorType: checkParameters, | ||
| } | ||
| }, | ||
| }) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| # max-params | ||
|
|
||
| ## Rule Details | ||
|
|
||
| Enforce a maximum number of parameters in function-like declarations. | ||
|
|
||
|
ScriptedAlchemy marked this conversation as resolved.
|
||
| Examples of **incorrect** code for this rule: | ||
|
|
||
| ```typescript | ||
| function foo(a, b, c, d) {} | ||
|
|
||
| class Foo { | ||
| method(this: Foo, a, b, c) {} | ||
| } | ||
| ``` | ||
|
|
||
| Examples of **correct** code for this rule: | ||
|
|
||
| ```typescript | ||
| function foo(a, b, c) {} | ||
|
|
||
| class Foo { | ||
| method(this: void, a, b, c) {} | ||
| } | ||
| ``` | ||
|
|
||
| ## Original Documentation | ||
|
|
||
| https://typescript-eslint.io/rules/max-params | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,157 @@ | ||
| package max_params | ||
|
|
||
| import ( | ||
| "testing" | ||
|
|
||
| "github.com/web-infra-dev/rslint/internal/plugins/typescript/rules/fixtures" | ||
| "github.com/web-infra-dev/rslint/internal/rule_tester" | ||
| ) | ||
|
|
||
| func TestMaxParamsRule(t *testing.T) { | ||
| rule_tester.RunRuleTester(fixtures.GetRootDir(), "tsconfig.json", t, &MaxParamsRule, []rule_tester.ValidTestCase{ | ||
| {Code: `function foo() {}`}, | ||
| {Code: `const foo = function () {};`}, | ||
| {Code: `const foo = () => {};`}, | ||
| {Code: `function foo(a) {}`}, | ||
| { | ||
| Code: ` | ||
| class Foo { | ||
| constructor(a) {} | ||
| } | ||
| `, | ||
| }, | ||
| { | ||
| Code: ` | ||
| class Foo { | ||
| method(this: void, a, b, c) {} | ||
| } | ||
| `, | ||
| }, | ||
| { | ||
| Code: ` | ||
| class Foo { | ||
| method(this: Foo, a, b) {} | ||
| } | ||
| `, | ||
| }, | ||
| { | ||
| Code: `function foo(a, b, c, d) {}`, | ||
| Options: []interface{}{map[string]interface{}{"max": 4}}, | ||
| }, | ||
| { | ||
| Code: `function foo(a, b, c, d) {}`, | ||
| Options: []interface{}{map[string]interface{}{"maximum": 4}}, | ||
| }, | ||
| { | ||
| Code: ` | ||
| class Foo { | ||
| method(this: void) {} | ||
| } | ||
| `, | ||
| Options: []interface{}{map[string]interface{}{"max": 0}}, | ||
| }, | ||
| { | ||
| Code: ` | ||
| class Foo { | ||
| method(this: void, a) {} | ||
| } | ||
| `, | ||
| Options: []interface{}{map[string]interface{}{"max": 1}}, | ||
| }, | ||
| { | ||
| Code: ` | ||
| class Foo { | ||
| method(this: void, a) {} | ||
| } | ||
| `, | ||
| Options: []interface{}{map[string]interface{}{"countVoidThis": true, "max": 2}}, | ||
| }, | ||
| { | ||
| Code: ` | ||
| declare function makeDate(m: number, d: number, y: number): Date; | ||
| `, | ||
| Options: []interface{}{map[string]interface{}{"max": 3}}, | ||
| }, | ||
| { | ||
| Code: ` | ||
| type sum = (a: number, b: number) => number; | ||
| `, | ||
| Options: []interface{}{map[string]interface{}{"max": 2}}, | ||
| }, | ||
| }, []rule_tester.InvalidTestCase{ | ||
| { | ||
| Code: `function foo(a, b, c, d) {}`, | ||
| Errors: []rule_tester.InvalidTestCaseError{ | ||
| {MessageId: "exceed", Line: 1, Column: 1, EndLine: 1, EndColumn: 28}, | ||
| }, | ||
| }, | ||
| { | ||
| Code: `const foo = function (a, b, c, d) {};`, | ||
| Errors: []rule_tester.InvalidTestCaseError{ | ||
| {MessageId: "exceed", Line: 1, Column: 13, EndLine: 1, EndColumn: 37}, | ||
| }, | ||
| }, | ||
| { | ||
| Code: `const foo = (a, b, c, d) => {};`, | ||
| Errors: []rule_tester.InvalidTestCaseError{ | ||
| {MessageId: "exceed", Line: 1, Column: 13, EndLine: 1, EndColumn: 31}, | ||
| }, | ||
| }, | ||
| { | ||
| Code: `const foo = a => {};`, | ||
| Options: []interface{}{map[string]interface{}{"max": 0}}, | ||
| Errors: []rule_tester.InvalidTestCaseError{ | ||
| {MessageId: "exceed", Line: 1, Column: 13, EndLine: 1, EndColumn: 20}, | ||
| }, | ||
| }, | ||
| { | ||
| Code: ` | ||
| class Foo { | ||
| method(this: void, a, b, c, d) {} | ||
| } | ||
| `, | ||
| Errors: []rule_tester.InvalidTestCaseError{ | ||
| {MessageId: "exceed", Line: 3, Column: 3, EndLine: 3, EndColumn: 36}, | ||
| }, | ||
| }, | ||
| { | ||
| Code: ` | ||
| class Foo { | ||
| method(this: void, a) {} | ||
| } | ||
| `, | ||
| Options: []interface{}{map[string]interface{}{"countVoidThis": true, "max": 1}}, | ||
| Errors: []rule_tester.InvalidTestCaseError{ | ||
| {MessageId: "exceed", Line: 3, Column: 3, EndLine: 3, EndColumn: 27}, | ||
| }, | ||
| }, | ||
| { | ||
| Code: ` | ||
| class Foo { | ||
| method(this: Foo, a, b, c) {} | ||
| } | ||
| `, | ||
| Errors: []rule_tester.InvalidTestCaseError{ | ||
| {MessageId: "exceed", Line: 3, Column: 3, EndLine: 3, EndColumn: 32}, | ||
| }, | ||
| }, | ||
| { | ||
| Code: ` | ||
| declare function makeDate(m: number, d: number, y: number): Date; | ||
| `, | ||
| Options: []interface{}{map[string]interface{}{"max": 1}}, | ||
| Errors: []rule_tester.InvalidTestCaseError{ | ||
| {MessageId: "exceed", Line: 2, Column: 1, EndLine: 2, EndColumn: 66}, | ||
| }, | ||
| }, | ||
| { | ||
| Code: ` | ||
| type sum = (a: number, b: number) => number; | ||
| `, | ||
| Options: []interface{}{map[string]interface{}{"max": 1}}, | ||
| Errors: []rule_tester.InvalidTestCaseError{ | ||
| {MessageId: "exceed", Line: 2, Column: 12, EndLine: 2, EndColumn: 44}, | ||
| }, | ||
| }, | ||
| }) | ||
| } |
Uh oh!
There was an error while loading. Please reload this page.