diff --git a/internal/config/config.go b/internal/config/config.go index e0dc14aa1..fa990f871 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -19,6 +19,7 @@ import ( "github.com/web-infra-dev/rslint/internal/plugins/typescript/rules/ban_tslint_comment" "github.com/web-infra-dev/rslint/internal/plugins/typescript/rules/ban_types" "github.com/web-infra-dev/rslint/internal/plugins/typescript/rules/class_literal_property_style" + "github.com/web-infra-dev/rslint/internal/plugins/typescript/rules/class_methods_use_this" "github.com/web-infra-dev/rslint/internal/plugins/typescript/rules/consistent_generic_constructors" "github.com/web-infra-dev/rslint/internal/plugins/typescript/rules/consistent_indexed_object_style" "github.com/web-infra-dev/rslint/internal/plugins/typescript/rules/consistent_return" @@ -341,6 +342,7 @@ func registerAllTypeScriptEslintPluginRules() { GlobalRuleRegistry.Register("@typescript-eslint/ban-tslint-comment", ban_tslint_comment.BanTslintCommentRule) GlobalRuleRegistry.Register("@typescript-eslint/ban-types", ban_types.BanTypesRule) GlobalRuleRegistry.Register("@typescript-eslint/class-literal-property-style", class_literal_property_style.ClassLiteralPropertyStyleRule) + GlobalRuleRegistry.Register("@typescript-eslint/class-methods-use-this", class_methods_use_this.ClassMethodsUseThisRule) GlobalRuleRegistry.Register("@typescript-eslint/consistent-generic-constructors", consistent_generic_constructors.ConsistentGenericConstructorsRule) GlobalRuleRegistry.Register("@typescript-eslint/consistent-indexed-object-style", consistent_indexed_object_style.ConsistentIndexedObjectStyleRule) GlobalRuleRegistry.Register("@typescript-eslint/consistent-return", consistent_return.ConsistentReturnRule) diff --git a/internal/plugins/typescript/rules/class_methods_use_this/class_methods_use_this.go b/internal/plugins/typescript/rules/class_methods_use_this/class_methods_use_this.go new file mode 100644 index 000000000..a454831c8 --- /dev/null +++ b/internal/plugins/typescript/rules/class_methods_use_this/class_methods_use_this.go @@ -0,0 +1,583 @@ +package class_methods_use_this + +import ( + "fmt" + "strings" + + "github.com/microsoft/typescript-go/shim/ast" + "github.com/microsoft/typescript-go/shim/core" + "github.com/web-infra-dev/rslint/internal/rule" + "github.com/web-infra-dev/rslint/internal/utils" +) + +type ignoreInterfaceMode int + +const ( + ignoreInterfaceNone ignoreInterfaceMode = iota + ignoreInterfaceAll + ignoreInterfacePublic +) + +type classMethodsUseThisOptions struct { + ExceptMethods []string + EnforceForClassFields bool + IgnoreOverrideMethods bool + IgnoreClassesThatImplementMode ignoreInterfaceMode +} + +type memberNameInfo struct { + Name string + HasName bool + IsPrivate bool +} + +var ClassMethodsUseThisRule = rule.CreateRule(rule.Rule{ + Name: "class-methods-use-this", + Run: func(ctx rule.RuleContext, options any) rule.RuleListeners { + opts := parseOptions(options) + exceptMethods := make(map[string]struct{}, len(opts.ExceptMethods)) + for _, method := range opts.ExceptMethods { + exceptMethods[method] = struct{}{} + } + + shouldIgnoreForInterface := func(classNode *ast.Node, member *ast.Node, nameInfo memberNameInfo) bool { + if opts.IgnoreClassesThatImplementMode == ignoreInterfaceNone { + return false + } + if !classImplementsInterface(classNode) { + return false + } + if opts.IgnoreClassesThatImplementMode == ignoreInterfaceAll { + return true + } + return isPublicMember(member, nameInfo) + } + + reportMissingThis := func(member *ast.Node, startNode *ast.Node, nameNode *ast.Node, initializer *ast.Node, displayName string) { + msg := buildMissingThisMessage(displayName) + if startNode != nil { + if reportRange, ok := buildMemberReportRange(ctx.SourceFile, member, startNode, nameNode, initializer); ok { + ctx.ReportRange(reportRange, msg) + return + } + } + ctx.ReportNode(member, msg) + } + + checkMethodLike := func(member *ast.Node, body *ast.Node, parameters *ast.NodeList, kind string, startNode *ast.Node) { + if member == nil || body == nil { + return + } + + classNode := getParentClass(member) + if classNode == nil { + return + } + + nameNode := getMemberNameNode(member) + if startNode == nil { + startNode = nameNode + } + nameInfo := getMemberNameInfo(ctx.SourceFile, nameNode) + + if opts.IgnoreOverrideMethods && ast.HasSyntacticModifier(member, ast.ModifierFlagsOverride) { + return + } + + if ast.IsStatic(member) { + return + } + + if shouldIgnoreForInterface(classNode, member, nameInfo) { + return + } + + if nameInfo.HasName { + if _, ok := exceptMethods[nameInfo.Name]; ok { + return + } + } + + if containsThisOrSuperInFunction(body, parameters) { + return + } + + displayName := buildMemberDisplayName(kind, nameInfo) + reportMissingThis(member, startNode, nameNode, nil, displayName) + } + + checkProperty := func(member *ast.Node) { + if member == nil { + return + } + + if !opts.EnforceForClassFields { + return + } + + classNode := getParentClass(member) + if classNode == nil { + return + } + + if ast.IsStatic(member) { + return + } + + nameNode := getMemberNameNode(member) + nameInfo := getMemberNameInfo(ctx.SourceFile, nameNode) + + if opts.IgnoreOverrideMethods && ast.HasSyntacticModifier(member, ast.ModifierFlagsOverride) { + return + } + + if shouldIgnoreForInterface(classNode, member, nameInfo) { + return + } + + prop := member.AsPropertyDeclaration() + if prop == nil || prop.Initializer == nil { + return + } + + if nameInfo.HasName { + if _, ok := exceptMethods[nameInfo.Name]; ok { + return + } + } + + init := prop.Initializer + var body *ast.Node + var parameters *ast.NodeList + switch init.Kind { + case ast.KindFunctionExpression: + body = init.AsFunctionExpression().Body + parameters = init.AsFunctionExpression().Parameters + case ast.KindArrowFunction: + body = init.AsArrowFunction().Body + parameters = init.AsArrowFunction().Parameters + default: + return + } + + if body == nil { + return + } + + if containsThisOrSuperInFunction(body, parameters) { + return + } + + displayName := buildMemberDisplayName("method", nameInfo) + reportMissingThis(member, nameNode, nameNode, init, displayName) + } + + return rule.RuleListeners{ + ast.KindMethodDeclaration: func(node *ast.Node) { + method := node.AsMethodDeclaration() + if method == nil || method.Body == nil { + return + } + kind := "method" + var startNode *ast.Node + if method.AsteriskToken != nil { + kind = "generator method" + startNode = node + } + checkMethodLike(node, method.Body, method.Parameters, kind, startNode) + }, + ast.KindGetAccessor: func(node *ast.Node) { + accessor := node.AsGetAccessorDeclaration() + if accessor == nil || accessor.Body == nil { + return + } + checkMethodLike(node, accessor.Body, accessor.Parameters, "getter", node) + }, + ast.KindSetAccessor: func(node *ast.Node) { + accessor := node.AsSetAccessorDeclaration() + if accessor == nil || accessor.Body == nil { + return + } + checkMethodLike(node, accessor.Body, accessor.Parameters, "setter", node) + }, + ast.KindPropertyDeclaration: func(node *ast.Node) { + checkProperty(node) + }, + } + }, +}) + +func parseOptions(options any) classMethodsUseThisOptions { + opts := classMethodsUseThisOptions{ + ExceptMethods: []string{}, + EnforceForClassFields: true, + IgnoreOverrideMethods: false, + IgnoreClassesThatImplementMode: ignoreInterfaceNone, + } + + if options == nil { + return opts + } + + var optsMap map[string]interface{} + if arr, ok := options.([]interface{}); ok && len(arr) > 0 { + if m, ok := arr[0].(map[string]interface{}); ok { + optsMap = m + } + } else if m, ok := options.(map[string]interface{}); ok { + optsMap = m + } + + if optsMap == nil { + return opts + } + + if enforce, ok := optsMap["enforceForClassFields"].(bool); ok { + opts.EnforceForClassFields = enforce + } + + if ignoreOverride, ok := optsMap["ignoreOverrideMethods"].(bool); ok { + opts.IgnoreOverrideMethods = ignoreOverride + } + + if except, ok := optsMap["exceptMethods"].([]interface{}); ok { + for _, item := range except { + if name, ok := item.(string); ok { + opts.ExceptMethods = append(opts.ExceptMethods, name) + } + } + } + + if ignoreInterfaces, ok := optsMap["ignoreClassesThatImplementAnInterface"]; ok { + switch value := ignoreInterfaces.(type) { + case bool: + if value { + opts.IgnoreClassesThatImplementMode = ignoreInterfaceAll + } else { + opts.IgnoreClassesThatImplementMode = ignoreInterfaceNone + } + case string: + if value == "public-fields" { + opts.IgnoreClassesThatImplementMode = ignoreInterfacePublic + } + } + } + + return opts +} + +func buildMissingThisMessage(name string) rule.RuleMessage { + return rule.RuleMessage{ + Id: "missingThis", + Description: fmt.Sprintf("Expected 'this' to be used by class %s.", name), + } +} + +func buildMemberDisplayName(kind string, nameInfo memberNameInfo) string { + if nameInfo.IsPrivate { + return fmt.Sprintf("private %s %s", kind, nameInfo.Name) + } + if nameInfo.HasName { + return fmt.Sprintf("%s '%s'", kind, nameInfo.Name) + } + return kind +} + +func getParentClass(node *ast.Node) *ast.Node { + if node == nil { + return nil + } + parent := node.Parent + if parent == nil { + return nil + } + if ast.IsClassDeclaration(parent) || ast.IsClassExpression(parent) { + return parent + } + return nil +} + +func isPublicMember(node *ast.Node, nameInfo memberNameInfo) bool { + if nameInfo.IsPrivate { + return false + } + if ast.HasSyntacticModifier(node, ast.ModifierFlagsPrivate) || ast.HasSyntacticModifier(node, ast.ModifierFlagsProtected) { + return false + } + return true +} + +func classImplementsInterface(classNode *ast.Node) bool { + clauses := utils.GetHeritageClauses(classNode) + if clauses == nil { + return false + } + for _, clause := range clauses.Nodes { + heritage := clause.AsHeritageClause() + if heritage == nil { + continue + } + if heritage.Token == ast.KindImplementsKeyword && heritage.Types != nil && len(heritage.Types.Nodes) > 0 { + return true + } + } + return false +} + +func getMemberNameNode(member *ast.Node) *ast.Node { + switch member.Kind { + case ast.KindMethodDeclaration: + return member.AsMethodDeclaration().Name() + case ast.KindGetAccessor: + return member.AsGetAccessorDeclaration().Name() + case ast.KindSetAccessor: + return member.AsSetAccessorDeclaration().Name() + case ast.KindPropertyDeclaration: + return member.AsPropertyDeclaration().Name() + } + return nil +} + +func getMemberNameInfo(sourceFile *ast.SourceFile, nameNode *ast.Node) memberNameInfo { + if nameNode == nil { + return memberNameInfo{} + } + + switch nameNode.Kind { + case ast.KindIdentifier: + return memberNameInfo{Name: nameNode.AsIdentifier().Text, HasName: true} + case ast.KindPrivateIdentifier: + name := nameNode.AsPrivateIdentifier().Text + if !strings.HasPrefix(name, "#") { + name = "#" + name + } + return memberNameInfo{Name: name, HasName: true, IsPrivate: true} + case ast.KindComputedPropertyName: + computed := nameNode.AsComputedPropertyName() + if name, ok := literalNameFromExpression(computed.Expression); ok { + return memberNameInfo{Name: name, HasName: true} + } + default: + if ast.IsLiteralExpression(nameNode) { + if name, ok := literalNameFromExpression(nameNode); ok { + return memberNameInfo{Name: name, HasName: true} + } + } + } + + return memberNameInfo{} +} + +func literalNameFromExpression(expr *ast.Node) (string, bool) { + if expr == nil { + return "", false + } + + if ast.IsLiteralExpression(expr) || expr.Kind == ast.KindNoSubstitutionTemplateLiteral { + return trimLiteralText(expr.Text()), true + } + + if expr.Kind == ast.KindTemplateExpression { + template := expr.AsTemplateExpression() + if template != nil && len(template.TemplateSpans.Nodes) == 0 { + return trimLiteralText(expr.Text()), true + } + } + + return "", false +} + +func trimLiteralText(text string) string { + trimmed := strings.TrimSpace(text) + if len(trimmed) >= 2 { + first := trimmed[0] + last := trimmed[len(trimmed)-1] + if (first == '"' && last == '"') || (first == '\'' && last == '\'') || (first == '`' && last == '`') { + return trimmed[1 : len(trimmed)-1] + } + } + return trimmed +} + +func containsThisOrSuper(node *ast.Node) bool { + found := false + var visit func(n *ast.Node) + visitClass := func(n *ast.Node) { + if n == nil || found { + return + } + + if clauses := utils.GetHeritageClauses(n); clauses != nil { + for _, clause := range clauses.Nodes { + visit(clause) + if found { + return + } + } + } + + if modifiers := n.Modifiers(); modifiers != nil { + for _, mod := range modifiers.Nodes { + if mod.Kind == ast.KindDecorator { + visit(mod) + if found { + return + } + } + } + } + + var members *ast.NodeList + if ast.IsClassDeclaration(n) { + members = n.AsClassDeclaration().Members + } else if ast.IsClassExpression(n) { + members = n.AsClassExpression().Members + } + + if members == nil { + return + } + + for _, member := range members.Nodes { + if nameNode := getMemberNameNode(member); nameNode != nil && nameNode.Kind == ast.KindComputedPropertyName { + computed := nameNode.AsComputedPropertyName() + if computed != nil { + visit(computed.Expression) + if found { + return + } + } + } + + if modifiers := member.Modifiers(); modifiers != nil { + for _, mod := range modifiers.Nodes { + if mod.Kind == ast.KindDecorator { + visit(mod) + if found { + return + } + } + } + } + } + } + + visit = func(n *ast.Node) { + if n == nil || found { + return + } + switch n.Kind { + case ast.KindThisKeyword, ast.KindSuperKeyword: + found = true + return + case ast.KindFunctionDeclaration, ast.KindFunctionExpression, ast.KindMethodDeclaration, ast.KindGetAccessor, ast.KindSetAccessor, ast.KindConstructor: + return + case ast.KindClassDeclaration, ast.KindClassExpression: + visitClass(n) + return + } + + n.ForEachChild(func(child *ast.Node) bool { + visit(child) + return found + }) + } + + visit(node) + return found +} + +func containsThisOrSuperInFunction(body *ast.Node, parameters *ast.NodeList) bool { + if parameters != nil { + for _, parameter := range parameters.Nodes { + if parameter == nil || parameter.Kind != ast.KindParameter { + continue + } + paramDecl := parameter.AsParameterDeclaration() + if paramDecl != nil && paramDecl.Initializer != nil && containsThisOrSuper(paramDecl.Initializer) { + return true + } + } + } + + return containsThisOrSuper(body) +} + +func buildMemberReportRange(sourceFile *ast.SourceFile, member *ast.Node, startNode *ast.Node, nameNode *ast.Node, initializer *ast.Node) (core.TextRange, bool) { + if sourceFile == nil || startNode == nil { + return core.TextRange{}, false + } + + startRange := utils.TrimNodeTextRange(sourceFile, startNode) + start := startRange.Pos() + + searchStart := startNode.End() + if nameNode != nil { + searchStart = nameNode.End() + } + searchEnd := member.End() + if initializer != nil { + if end, ok := getSingleParamArrowHeadEnd(sourceFile, start, initializer); ok { + return core.NewTextRange(start, end), true + } + searchStart = initializer.Pos() + searchEnd = initializer.End() + } + + parenPos := findNextParen(sourceFile.Text(), searchStart, searchEnd) + if parenPos == -1 || parenPos <= start { + return core.TextRange{}, false + } + + return core.NewTextRange(start, parenPos), true +} + +func findNextParen(text string, start int, end int) int { + if start < 0 { + start = 0 + } + if start > len(text) { + return -1 + } + if end < start { + return -1 + } + if end > len(text) { + end = len(text) + } + for i := start; i < end; i++ { + if text[i] == '(' { + return i + } + } + return -1 +} + +func getSingleParamArrowHeadEnd(sourceFile *ast.SourceFile, start int, initializer *ast.Node) (int, bool) { + if sourceFile == nil || initializer == nil || initializer.Kind != ast.KindArrowFunction { + return 0, false + } + + arrow := initializer.AsArrowFunction() + if arrow == nil || arrow.Parameters == nil || len(arrow.Parameters.Nodes) != 1 { + return 0, false + } + + firstParam := arrow.Parameters.Nodes[0] + if firstParam == nil { + return 0, false + } + + firstParamRange := utils.TrimNodeTextRange(sourceFile, firstParam) + end := firstParamRange.Pos() + if end <= start || end <= 0 { + return 0, false + } + + text := sourceFile.Text() + if end-1 < len(text) && text[end-1] == '(' { + return 0, false + } + + return end, true +} diff --git a/internal/plugins/typescript/rules/class_methods_use_this/class_methods_use_this.md b/internal/plugins/typescript/rules/class_methods_use_this/class_methods_use_this.md new file mode 100644 index 000000000..8704264ca --- /dev/null +++ b/internal/plugins/typescript/rules/class_methods_use_this/class_methods_use_this.md @@ -0,0 +1,41 @@ +# class-methods-use-this + +## Rule Details + +Enforces that class methods use `this` (or `super`) to avoid unintentional reliance on `this` binding. + +Examples of **incorrect** code for this rule: + +```ts +class Foo { + method() {} +} +``` + +```ts +class Foo { + property = () => {}; +} +``` + +Examples of **correct** code for this rule: + +```ts +class Foo { + method() { + this.value = 1; + } +} +``` + +```ts +class Foo { + property = () => { + this.value = 1; + }; +} +``` + +## Original Documentation + +https://typescript-eslint.io/rules/class-methods-use-this diff --git a/internal/plugins/typescript/rules/class_methods_use_this/class_methods_use_this_test.go b/internal/plugins/typescript/rules/class_methods_use_this/class_methods_use_this_test.go new file mode 100644 index 000000000..b7dc448b9 --- /dev/null +++ b/internal/plugins/typescript/rules/class_methods_use_this/class_methods_use_this_test.go @@ -0,0 +1,172 @@ +package class_methods_use_this + +import ( + "testing" + + "github.com/web-infra-dev/rslint/internal/plugins/typescript/rules/fixtures" + "github.com/web-infra-dev/rslint/internal/rule_tester" +) + +func TestClassMethodsUseThisRule(t *testing.T) { + rule_tester.RunRuleTester(fixtures.GetRootDir(), "tsconfig.json", t, &ClassMethodsUseThisRule, []rule_tester.ValidTestCase{ + { + Code: ` +class Foo { + method() { + this.value = 1; + } +} + `, + }, + { + Code: ` +class Foo { + method() { + return () => this.value; + } +} + `, + }, + { + Code: ` +class Foo { + property = () => { + this.value = 1; + }; +} + `, + }, + { + Code: ` +class Foo { + property = () => {}; +} + `, + Options: map[string]interface{}{"enforceForClassFields": false}, + }, + { + Code: ` +class Foo implements Bar { + method() {} +} + `, + Options: map[string]interface{}{"ignoreClassesThatImplementAnInterface": true}, + }, + { + Code: ` +class Foo { + override method() {} +} + `, + Options: map[string]interface{}{"ignoreOverrideMethods": true}, + }, + { + Code: ` +class Foo { + method() {} +} + `, + Options: map[string]interface{}{"exceptMethods": []interface{}{"method"}}, + }, + { + Code: ` +class Foo { + method(value = this.value) {} +} + `, + }, + { + Code: ` +class Foo { + property = (value = this.value) => { + return value; + }; +} + `, + }, + }, []rule_tester.InvalidTestCase{ + { + Code: ` +class Foo { + method() {} +} + `, + Errors: []rule_tester.InvalidTestCaseError{{MessageId: "missingThis"}}, + }, + { + Code: ` +class Foo { + get value() { + return 1; + } +} + `, + Errors: []rule_tester.InvalidTestCaseError{{MessageId: "missingThis"}}, + }, + { + Code: ` +class Foo { + set value(next: number) {} +} + `, + Errors: []rule_tester.InvalidTestCaseError{{MessageId: "missingThis"}}, + }, + { + Code: ` +class Foo { + property = () => {}; +} + `, + Errors: []rule_tester.InvalidTestCaseError{{MessageId: "missingThis"}}, + }, + { + Code: ` +class Foo { + property = function () {}; +} + `, + Errors: []rule_tester.InvalidTestCaseError{{MessageId: "missingThis"}}, + }, + { + Code: ` +class Foo implements Bar { + method() {} +} + `, + Options: map[string]interface{}{"ignoreClassesThatImplementAnInterface": false}, + Errors: []rule_tester.InvalidTestCaseError{{MessageId: "missingThis"}}, + }, + { + Code: ` +class Foo implements Bar { + private method() {} +} + `, + Options: map[string]interface{}{"ignoreClassesThatImplementAnInterface": "public-fields"}, + Errors: []rule_tester.InvalidTestCaseError{{MessageId: "missingThis"}}, + }, + { + Code: ` +class Foo { + override method() {} +} + `, + Options: map[string]interface{}{"ignoreOverrideMethods": false}, + Errors: []rule_tester.InvalidTestCaseError{{MessageId: "missingThis"}}, + }, + { + Code: ` +class Foo { + property = value => value; +} + `, + Errors: []rule_tester.InvalidTestCaseError{{ + MessageId: "missingThis", + Line: 3, + Column: 3, + EndLine: 3, + EndColumn: 14, + }}, + }, + }) +} diff --git a/packages/rslint-test-tools/rstest.config.mts b/packages/rslint-test-tools/rstest.config.mts index 62116adae..e103d6bd5 100644 --- a/packages/rslint-test-tools/rstest.config.mts +++ b/packages/rslint-test-tools/rstest.config.mts @@ -50,8 +50,8 @@ export default defineConfig({ // './tests/typescript-eslint/rules/ban-ts-comment.test.ts', './tests/typescript-eslint/rules/ban-tslint-comment.test.ts', './tests/typescript-eslint/rules/class-literal-property-style.test.ts', - // './tests/typescript-eslint/rules/class-methods-use-this/class-methods-use-this-core.test.ts', - // './tests/typescript-eslint/rules/class-methods-use-this/class-methods-use-this.test.ts', + './tests/typescript-eslint/rules/class-methods-use-this/class-methods-use-this-core.test.ts', + './tests/typescript-eslint/rules/class-methods-use-this/class-methods-use-this.test.ts', // './tests/typescript-eslint/rules/consistent-generic-constructors.test.ts', // './tests/typescript-eslint/rules/consistent-indexed-object-style.test.ts', // './tests/typescript-eslint/rules/consistent-return.test.ts', diff --git a/packages/rslint-test-tools/tests/typescript-eslint/rules/class-methods-use-this/__snapshots__/class-methods-use-this-core.test.ts.snap b/packages/rslint-test-tools/tests/typescript-eslint/rules/class-methods-use-this/__snapshots__/class-methods-use-this-core.test.ts.snap new file mode 100644 index 000000000..140383af1 --- /dev/null +++ b/packages/rslint-test-tools/tests/typescript-eslint/rules/class-methods-use-this/__snapshots__/class-methods-use-this-core.test.ts.snap @@ -0,0 +1,708 @@ +// Rstest Snapshot v1 + +exports[`class-methods-use-this > invalid 1`] = ` +{ + "code": "class A { foo() {} }", + "diagnostics": [ + { + "message": "Expected 'this' to be used by class method 'foo'.", + "messageId": "missingThis", + "range": { + "end": { + "column": 14, + "line": 1, + }, + "start": { + "column": 11, + "line": 1, + }, + }, + "ruleName": "@typescript-eslint/class-methods-use-this", + }, + ], + "errorCount": 1, + "fileCount": 1, + "ruleCount": 1, +} +`; + +exports[`class-methods-use-this > invalid 2`] = ` +{ + "code": "class A { foo() {/**this**/} }", + "diagnostics": [ + { + "message": "Expected 'this' to be used by class method 'foo'.", + "messageId": "missingThis", + "range": { + "end": { + "column": 14, + "line": 1, + }, + "start": { + "column": 11, + "line": 1, + }, + }, + "ruleName": "@typescript-eslint/class-methods-use-this", + }, + ], + "errorCount": 1, + "fileCount": 1, + "ruleCount": 1, +} +`; + +exports[`class-methods-use-this > invalid 3`] = ` +{ + "code": "class A { foo() {var a = function () {this};} }", + "diagnostics": [ + { + "message": "Expected 'this' to be used by class method 'foo'.", + "messageId": "missingThis", + "range": { + "end": { + "column": 14, + "line": 1, + }, + "start": { + "column": 11, + "line": 1, + }, + }, + "ruleName": "@typescript-eslint/class-methods-use-this", + }, + ], + "errorCount": 1, + "fileCount": 1, + "ruleCount": 1, +} +`; + +exports[`class-methods-use-this > invalid 4`] = ` +{ + "code": "class A { foo() {var a = function () {var b = function(){this}};} }", + "diagnostics": [ + { + "message": "Expected 'this' to be used by class method 'foo'.", + "messageId": "missingThis", + "range": { + "end": { + "column": 14, + "line": 1, + }, + "start": { + "column": 11, + "line": 1, + }, + }, + "ruleName": "@typescript-eslint/class-methods-use-this", + }, + ], + "errorCount": 1, + "fileCount": 1, + "ruleCount": 1, +} +`; + +exports[`class-methods-use-this > invalid 5`] = ` +{ + "code": "class A { foo() {window.this} }", + "diagnostics": [ + { + "message": "Expected 'this' to be used by class method 'foo'.", + "messageId": "missingThis", + "range": { + "end": { + "column": 14, + "line": 1, + }, + "start": { + "column": 11, + "line": 1, + }, + }, + "ruleName": "@typescript-eslint/class-methods-use-this", + }, + ], + "errorCount": 1, + "fileCount": 1, + "ruleCount": 1, +} +`; + +exports[`class-methods-use-this > invalid 6`] = ` +{ + "code": "class A { foo() {that.this = 'this';} }", + "diagnostics": [ + { + "message": "Expected 'this' to be used by class method 'foo'.", + "messageId": "missingThis", + "range": { + "end": { + "column": 14, + "line": 1, + }, + "start": { + "column": 11, + "line": 1, + }, + }, + "ruleName": "@typescript-eslint/class-methods-use-this", + }, + ], + "errorCount": 1, + "fileCount": 1, + "ruleCount": 1, +} +`; + +exports[`class-methods-use-this > invalid 7`] = ` +{ + "code": "class A { foo() { () => undefined; } }", + "diagnostics": [ + { + "message": "Expected 'this' to be used by class method 'foo'.", + "messageId": "missingThis", + "range": { + "end": { + "column": 14, + "line": 1, + }, + "start": { + "column": 11, + "line": 1, + }, + }, + "ruleName": "@typescript-eslint/class-methods-use-this", + }, + ], + "errorCount": 1, + "fileCount": 1, + "ruleCount": 1, +} +`; + +exports[`class-methods-use-this > invalid 8`] = ` +{ + "code": "class A { foo() {} bar() {} }", + "diagnostics": [ + { + "message": "Expected 'this' to be used by class method 'foo'.", + "messageId": "missingThis", + "range": { + "end": { + "column": 14, + "line": 1, + }, + "start": { + "column": 11, + "line": 1, + }, + }, + "ruleName": "@typescript-eslint/class-methods-use-this", + }, + ], + "errorCount": 1, + "fileCount": 1, + "ruleCount": 1, +} +`; + +exports[`class-methods-use-this > invalid 9`] = ` +{ + "code": "class A { foo() {} hasOwnProperty() {} }", + "diagnostics": [ + { + "message": "Expected 'this' to be used by class method 'hasOwnProperty'.", + "messageId": "missingThis", + "range": { + "end": { + "column": 34, + "line": 1, + }, + "start": { + "column": 20, + "line": 1, + }, + }, + "ruleName": "@typescript-eslint/class-methods-use-this", + }, + ], + "errorCount": 1, + "fileCount": 1, + "ruleCount": 1, +} +`; + +exports[`class-methods-use-this > invalid 10`] = ` +{ + "code": "class A { [foo]() {} }", + "diagnostics": [ + { + "message": "Expected 'this' to be used by class method.", + "messageId": "missingThis", + "range": { + "end": { + "column": 16, + "line": 1, + }, + "start": { + "column": 11, + "line": 1, + }, + }, + "ruleName": "@typescript-eslint/class-methods-use-this", + }, + ], + "errorCount": 1, + "fileCount": 1, + "ruleCount": 1, +} +`; + +exports[`class-methods-use-this > invalid 11`] = ` +{ + "code": "class A { #foo() { } foo() {} #bar() {} }", + "diagnostics": [ + { + "message": "Expected 'this' to be used by class method 'foo'.", + "messageId": "missingThis", + "range": { + "end": { + "column": 25, + "line": 1, + }, + "start": { + "column": 22, + "line": 1, + }, + }, + "ruleName": "@typescript-eslint/class-methods-use-this", + }, + { + "message": "Expected 'this' to be used by class private method #bar.", + "messageId": "missingThis", + "range": { + "end": { + "column": 35, + "line": 1, + }, + "start": { + "column": 31, + "line": 1, + }, + }, + "ruleName": "@typescript-eslint/class-methods-use-this", + }, + ], + "errorCount": 2, + "fileCount": 1, + "ruleCount": 1, +} +`; + +exports[`class-methods-use-this > invalid 12`] = ` +{ + "code": "class A { foo(){} 'bar'(){} 123(){} [\`baz\`](){} [a](){} [f(a)](){} get quux(){} set[a](b){} *quuux(){} }", + "diagnostics": [ + { + "message": "Expected 'this' to be used by class method 'foo'.", + "messageId": "missingThis", + "range": { + "end": { + "column": 14, + "line": 1, + }, + "start": { + "column": 11, + "line": 1, + }, + }, + "ruleName": "@typescript-eslint/class-methods-use-this", + }, + { + "message": "Expected 'this' to be used by class method 'bar'.", + "messageId": "missingThis", + "range": { + "end": { + "column": 24, + "line": 1, + }, + "start": { + "column": 19, + "line": 1, + }, + }, + "ruleName": "@typescript-eslint/class-methods-use-this", + }, + { + "message": "Expected 'this' to be used by class method '123'.", + "messageId": "missingThis", + "range": { + "end": { + "column": 32, + "line": 1, + }, + "start": { + "column": 29, + "line": 1, + }, + }, + "ruleName": "@typescript-eslint/class-methods-use-this", + }, + { + "message": "Expected 'this' to be used by class method 'baz'.", + "messageId": "missingThis", + "range": { + "end": { + "column": 44, + "line": 1, + }, + "start": { + "column": 37, + "line": 1, + }, + }, + "ruleName": "@typescript-eslint/class-methods-use-this", + }, + { + "message": "Expected 'this' to be used by class method.", + "messageId": "missingThis", + "range": { + "end": { + "column": 52, + "line": 1, + }, + "start": { + "column": 49, + "line": 1, + }, + }, + "ruleName": "@typescript-eslint/class-methods-use-this", + }, + { + "message": "Expected 'this' to be used by class method.", + "messageId": "missingThis", + "range": { + "end": { + "column": 63, + "line": 1, + }, + "start": { + "column": 57, + "line": 1, + }, + }, + "ruleName": "@typescript-eslint/class-methods-use-this", + }, + { + "message": "Expected 'this' to be used by class getter 'quux'.", + "messageId": "missingThis", + "range": { + "end": { + "column": 76, + "line": 1, + }, + "start": { + "column": 68, + "line": 1, + }, + }, + "ruleName": "@typescript-eslint/class-methods-use-this", + }, + { + "message": "Expected 'this' to be used by class setter.", + "messageId": "missingThis", + "range": { + "end": { + "column": 87, + "line": 1, + }, + "start": { + "column": 81, + "line": 1, + }, + }, + "ruleName": "@typescript-eslint/class-methods-use-this", + }, + { + "message": "Expected 'this' to be used by class generator method 'quuux'.", + "messageId": "missingThis", + "range": { + "end": { + "column": 99, + "line": 1, + }, + "start": { + "column": 93, + "line": 1, + }, + }, + "ruleName": "@typescript-eslint/class-methods-use-this", + }, + ], + "errorCount": 9, + "fileCount": 1, + "ruleCount": 1, +} +`; + +exports[`class-methods-use-this > invalid 13`] = ` +{ + "code": "class A { foo = function() {} }", + "diagnostics": [ + { + "message": "Expected 'this' to be used by class method 'foo'.", + "messageId": "missingThis", + "range": { + "end": { + "column": 25, + "line": 1, + }, + "start": { + "column": 11, + "line": 1, + }, + }, + "ruleName": "@typescript-eslint/class-methods-use-this", + }, + ], + "errorCount": 1, + "fileCount": 1, + "ruleCount": 1, +} +`; + +exports[`class-methods-use-this > invalid 14`] = ` +{ + "code": "class A { foo = () => {} }", + "diagnostics": [ + { + "message": "Expected 'this' to be used by class method 'foo'.", + "messageId": "missingThis", + "range": { + "end": { + "column": 17, + "line": 1, + }, + "start": { + "column": 11, + "line": 1, + }, + }, + "ruleName": "@typescript-eslint/class-methods-use-this", + }, + ], + "errorCount": 1, + "fileCount": 1, + "ruleCount": 1, +} +`; + +exports[`class-methods-use-this > invalid 15`] = ` +{ + "code": "class A { #foo = function() {} }", + "diagnostics": [ + { + "message": "Expected 'this' to be used by class private method #foo.", + "messageId": "missingThis", + "range": { + "end": { + "column": 26, + "line": 1, + }, + "start": { + "column": 11, + "line": 1, + }, + }, + "ruleName": "@typescript-eslint/class-methods-use-this", + }, + ], + "errorCount": 1, + "fileCount": 1, + "ruleCount": 1, +} +`; + +exports[`class-methods-use-this > invalid 16`] = ` +{ + "code": "class A { #foo = () => {} }", + "diagnostics": [ + { + "message": "Expected 'this' to be used by class private method #foo.", + "messageId": "missingThis", + "range": { + "end": { + "column": 18, + "line": 1, + }, + "start": { + "column": 11, + "line": 1, + }, + }, + "ruleName": "@typescript-eslint/class-methods-use-this", + }, + ], + "errorCount": 1, + "fileCount": 1, + "ruleCount": 1, +} +`; + +exports[`class-methods-use-this > invalid 17`] = ` +{ + "code": "class A { #foo() {} }", + "diagnostics": [ + { + "message": "Expected 'this' to be used by class private method #foo.", + "messageId": "missingThis", + "range": { + "end": { + "column": 15, + "line": 1, + }, + "start": { + "column": 11, + "line": 1, + }, + }, + "ruleName": "@typescript-eslint/class-methods-use-this", + }, + ], + "errorCount": 1, + "fileCount": 1, + "ruleCount": 1, +} +`; + +exports[`class-methods-use-this > invalid 18`] = ` +{ + "code": "class A { get #foo() {} }", + "diagnostics": [ + { + "message": "Expected 'this' to be used by class private getter #foo.", + "messageId": "missingThis", + "range": { + "end": { + "column": 19, + "line": 1, + }, + "start": { + "column": 11, + "line": 1, + }, + }, + "ruleName": "@typescript-eslint/class-methods-use-this", + }, + ], + "errorCount": 1, + "fileCount": 1, + "ruleCount": 1, +} +`; + +exports[`class-methods-use-this > invalid 19`] = ` +{ + "code": "class A { set #foo(x) {} }", + "diagnostics": [ + { + "message": "Expected 'this' to be used by class private setter #foo.", + "messageId": "missingThis", + "range": { + "end": { + "column": 19, + "line": 1, + }, + "start": { + "column": 11, + "line": 1, + }, + }, + "ruleName": "@typescript-eslint/class-methods-use-this", + }, + ], + "errorCount": 1, + "fileCount": 1, + "ruleCount": 1, +} +`; + +exports[`class-methods-use-this > invalid 20`] = ` +{ + "code": "class A { foo () { return class { foo = this }; } }", + "diagnostics": [ + { + "message": "Expected 'this' to be used by class method 'foo'.", + "messageId": "missingThis", + "range": { + "end": { + "column": 15, + "line": 1, + }, + "start": { + "column": 11, + "line": 1, + }, + }, + "ruleName": "@typescript-eslint/class-methods-use-this", + }, + ], + "errorCount": 1, + "fileCount": 1, + "ruleCount": 1, +} +`; + +exports[`class-methods-use-this > invalid 21`] = ` +{ + "code": "class A { foo () { return function () { foo = this }; } }", + "diagnostics": [ + { + "message": "Expected 'this' to be used by class method 'foo'.", + "messageId": "missingThis", + "range": { + "end": { + "column": 15, + "line": 1, + }, + "start": { + "column": 11, + "line": 1, + }, + }, + "ruleName": "@typescript-eslint/class-methods-use-this", + }, + ], + "errorCount": 1, + "fileCount": 1, + "ruleCount": 1, +} +`; + +exports[`class-methods-use-this > invalid 22`] = ` +{ + "code": "class A { foo () { return class { static { this; } } } }", + "diagnostics": [ + { + "message": "Expected 'this' to be used by class method 'foo'.", + "messageId": "missingThis", + "range": { + "end": { + "column": 15, + "line": 1, + }, + "start": { + "column": 11, + "line": 1, + }, + }, + "ruleName": "@typescript-eslint/class-methods-use-this", + }, + ], + "errorCount": 1, + "fileCount": 1, + "ruleCount": 1, +} +`; diff --git a/packages/rslint-test-tools/tests/typescript-eslint/rules/class-methods-use-this/__snapshots__/class-methods-use-this.test.ts.snap b/packages/rslint-test-tools/tests/typescript-eslint/rules/class-methods-use-this/__snapshots__/class-methods-use-this.test.ts.snap new file mode 100644 index 000000000..10b924862 --- /dev/null +++ b/packages/rslint-test-tools/tests/typescript-eslint/rules/class-methods-use-this/__snapshots__/class-methods-use-this.test.ts.snap @@ -0,0 +1,1205 @@ +// Rstest Snapshot v1 + +exports[`class-methods-use-this > invalid 1`] = ` +{ + "code": " +class Foo { + method() {} +} + ", + "diagnostics": [ + { + "message": "Expected 'this' to be used by class method 'method'.", + "messageId": "missingThis", + "range": { + "end": { + "column": 9, + "line": 3, + }, + "start": { + "column": 3, + "line": 3, + }, + }, + "ruleName": "@typescript-eslint/class-methods-use-this", + }, + ], + "errorCount": 1, + "fileCount": 1, + "ruleCount": 1, +} +`; + +exports[`class-methods-use-this > invalid 2`] = ` +{ + "code": " +class Foo { + private method() {} +} + ", + "diagnostics": [ + { + "message": "Expected 'this' to be used by class method 'method'.", + "messageId": "missingThis", + "range": { + "end": { + "column": 17, + "line": 3, + }, + "start": { + "column": 11, + "line": 3, + }, + }, + "ruleName": "@typescript-eslint/class-methods-use-this", + }, + ], + "errorCount": 1, + "fileCount": 1, + "ruleCount": 1, +} +`; + +exports[`class-methods-use-this > invalid 3`] = ` +{ + "code": " +class Foo { + protected method() {} +} + ", + "diagnostics": [ + { + "message": "Expected 'this' to be used by class method 'method'.", + "messageId": "missingThis", + "range": { + "end": { + "column": 19, + "line": 3, + }, + "start": { + "column": 13, + "line": 3, + }, + }, + "ruleName": "@typescript-eslint/class-methods-use-this", + }, + ], + "errorCount": 1, + "fileCount": 1, + "ruleCount": 1, +} +`; + +exports[`class-methods-use-this > invalid 4`] = ` +{ + "code": " +class Foo { + accessor method = () => {}; +} + ", + "diagnostics": [ + { + "message": "Expected 'this' to be used by class method 'method'.", + "messageId": "missingThis", + "range": { + "end": { + "column": 21, + "line": 3, + }, + "start": { + "column": 12, + "line": 3, + }, + }, + "ruleName": "@typescript-eslint/class-methods-use-this", + }, + ], + "errorCount": 1, + "fileCount": 1, + "ruleCount": 1, +} +`; + +exports[`class-methods-use-this > invalid 5`] = ` +{ + "code": " +class Foo { + private accessor method = () => {}; +} + ", + "diagnostics": [ + { + "message": "Expected 'this' to be used by class method 'method'.", + "messageId": "missingThis", + "range": { + "end": { + "column": 29, + "line": 3, + }, + "start": { + "column": 20, + "line": 3, + }, + }, + "ruleName": "@typescript-eslint/class-methods-use-this", + }, + ], + "errorCount": 1, + "fileCount": 1, + "ruleCount": 1, +} +`; + +exports[`class-methods-use-this > invalid 6`] = ` +{ + "code": " +class Foo { + protected accessor method = () => {}; +} + ", + "diagnostics": [ + { + "message": "Expected 'this' to be used by class method 'method'.", + "messageId": "missingThis", + "range": { + "end": { + "column": 31, + "line": 3, + }, + "start": { + "column": 22, + "line": 3, + }, + }, + "ruleName": "@typescript-eslint/class-methods-use-this", + }, + ], + "errorCount": 1, + "fileCount": 1, + "ruleCount": 1, +} +`; + +exports[`class-methods-use-this > invalid 7`] = ` +{ + "code": " +class Foo { + #method() {} +} + ", + "diagnostics": [ + { + "message": "Expected 'this' to be used by class private method #method.", + "messageId": "missingThis", + "range": { + "end": { + "column": 10, + "line": 3, + }, + "start": { + "column": 3, + "line": 3, + }, + }, + "ruleName": "@typescript-eslint/class-methods-use-this", + }, + ], + "errorCount": 1, + "fileCount": 1, + "ruleCount": 1, +} +`; + +exports[`class-methods-use-this > invalid 8`] = ` +{ + "code": " +class Foo { + get getter(): number {} +} + ", + "diagnostics": [ + { + "message": "Expected 'this' to be used by class getter 'getter'.", + "messageId": "missingThis", + "range": { + "end": { + "column": 13, + "line": 3, + }, + "start": { + "column": 3, + "line": 3, + }, + }, + "ruleName": "@typescript-eslint/class-methods-use-this", + }, + ], + "errorCount": 1, + "fileCount": 1, + "ruleCount": 1, +} +`; + +exports[`class-methods-use-this > invalid 9`] = ` +{ + "code": " +class Foo { + private get getter(): number {} +} + ", + "diagnostics": [ + { + "message": "Expected 'this' to be used by class getter 'getter'.", + "messageId": "missingThis", + "range": { + "end": { + "column": 21, + "line": 3, + }, + "start": { + "column": 3, + "line": 3, + }, + }, + "ruleName": "@typescript-eslint/class-methods-use-this", + }, + ], + "errorCount": 1, + "fileCount": 1, + "ruleCount": 1, +} +`; + +exports[`class-methods-use-this > invalid 10`] = ` +{ + "code": " +class Foo { + protected get getter(): number {} +} + ", + "diagnostics": [ + { + "message": "Expected 'this' to be used by class getter 'getter'.", + "messageId": "missingThis", + "range": { + "end": { + "column": 23, + "line": 3, + }, + "start": { + "column": 3, + "line": 3, + }, + }, + "ruleName": "@typescript-eslint/class-methods-use-this", + }, + ], + "errorCount": 1, + "fileCount": 1, + "ruleCount": 1, +} +`; + +exports[`class-methods-use-this > invalid 11`] = ` +{ + "code": " +class Foo { + get #getter(): number {} +} + ", + "diagnostics": [ + { + "message": "Expected 'this' to be used by class private getter #getter.", + "messageId": "missingThis", + "range": { + "end": { + "column": 14, + "line": 3, + }, + "start": { + "column": 3, + "line": 3, + }, + }, + "ruleName": "@typescript-eslint/class-methods-use-this", + }, + ], + "errorCount": 1, + "fileCount": 1, + "ruleCount": 1, +} +`; + +exports[`class-methods-use-this > invalid 12`] = ` +{ + "code": " +class Foo { + set setter(b: number) {} +} + ", + "diagnostics": [ + { + "message": "Expected 'this' to be used by class setter 'setter'.", + "messageId": "missingThis", + "range": { + "end": { + "column": 13, + "line": 3, + }, + "start": { + "column": 3, + "line": 3, + }, + }, + "ruleName": "@typescript-eslint/class-methods-use-this", + }, + ], + "errorCount": 1, + "fileCount": 1, + "ruleCount": 1, +} +`; + +exports[`class-methods-use-this > invalid 13`] = ` +{ + "code": " +class Foo { + private set setter(b: number) {} +} + ", + "diagnostics": [ + { + "message": "Expected 'this' to be used by class setter 'setter'.", + "messageId": "missingThis", + "range": { + "end": { + "column": 21, + "line": 3, + }, + "start": { + "column": 3, + "line": 3, + }, + }, + "ruleName": "@typescript-eslint/class-methods-use-this", + }, + ], + "errorCount": 1, + "fileCount": 1, + "ruleCount": 1, +} +`; + +exports[`class-methods-use-this > invalid 14`] = ` +{ + "code": " +class Foo { + protected set setter(b: number) {} +} + ", + "diagnostics": [ + { + "message": "Expected 'this' to be used by class setter 'setter'.", + "messageId": "missingThis", + "range": { + "end": { + "column": 23, + "line": 3, + }, + "start": { + "column": 3, + "line": 3, + }, + }, + "ruleName": "@typescript-eslint/class-methods-use-this", + }, + ], + "errorCount": 1, + "fileCount": 1, + "ruleCount": 1, +} +`; + +exports[`class-methods-use-this > invalid 15`] = ` +{ + "code": " +class Foo { + set #setter(b: number) {} +} + ", + "diagnostics": [ + { + "message": "Expected 'this' to be used by class private setter #setter.", + "messageId": "missingThis", + "range": { + "end": { + "column": 14, + "line": 3, + }, + "start": { + "column": 3, + "line": 3, + }, + }, + "ruleName": "@typescript-eslint/class-methods-use-this", + }, + ], + "errorCount": 1, + "fileCount": 1, + "ruleCount": 1, +} +`; + +exports[`class-methods-use-this > invalid 16`] = ` +{ + "code": " +class Foo implements Bar { + method() {} +} + ", + "diagnostics": [ + { + "message": "Expected 'this' to be used by class method 'method'.", + "messageId": "missingThis", + "range": { + "end": { + "column": 9, + "line": 3, + }, + "start": { + "column": 3, + "line": 3, + }, + }, + "ruleName": "@typescript-eslint/class-methods-use-this", + }, + ], + "errorCount": 1, + "fileCount": 1, + "ruleCount": 1, +} +`; + +exports[`class-methods-use-this > invalid 17`] = ` +{ + "code": " +class Foo implements Bar { + #method() {} +} + ", + "diagnostics": [ + { + "message": "Expected 'this' to be used by class private method #method.", + "messageId": "missingThis", + "range": { + "end": { + "column": 10, + "line": 3, + }, + "start": { + "column": 3, + "line": 3, + }, + }, + "ruleName": "@typescript-eslint/class-methods-use-this", + }, + ], + "errorCount": 1, + "fileCount": 1, + "ruleCount": 1, +} +`; + +exports[`class-methods-use-this > invalid 18`] = ` +{ + "code": " +class Foo implements Bar { + private method() {} +} + ", + "diagnostics": [ + { + "message": "Expected 'this' to be used by class method 'method'.", + "messageId": "missingThis", + "range": { + "end": { + "column": 17, + "line": 3, + }, + "start": { + "column": 11, + "line": 3, + }, + }, + "ruleName": "@typescript-eslint/class-methods-use-this", + }, + ], + "errorCount": 1, + "fileCount": 1, + "ruleCount": 1, +} +`; + +exports[`class-methods-use-this > invalid 19`] = ` +{ + "code": " +class Foo implements Bar { + protected method() {} +} + ", + "diagnostics": [ + { + "message": "Expected 'this' to be used by class method 'method'.", + "messageId": "missingThis", + "range": { + "end": { + "column": 19, + "line": 3, + }, + "start": { + "column": 13, + "line": 3, + }, + }, + "ruleName": "@typescript-eslint/class-methods-use-this", + }, + ], + "errorCount": 1, + "fileCount": 1, + "ruleCount": 1, +} +`; + +exports[`class-methods-use-this > invalid 20`] = ` +{ + "code": " +class Foo implements Bar { + get getter(): number {} +} + ", + "diagnostics": [ + { + "message": "Expected 'this' to be used by class getter 'getter'.", + "messageId": "missingThis", + "range": { + "end": { + "column": 13, + "line": 3, + }, + "start": { + "column": 3, + "line": 3, + }, + }, + "ruleName": "@typescript-eslint/class-methods-use-this", + }, + ], + "errorCount": 1, + "fileCount": 1, + "ruleCount": 1, +} +`; + +exports[`class-methods-use-this > invalid 21`] = ` +{ + "code": " +class Foo implements Bar { + get #getter(): number {} +} + ", + "diagnostics": [ + { + "message": "Expected 'this' to be used by class private getter #getter.", + "messageId": "missingThis", + "range": { + "end": { + "column": 14, + "line": 3, + }, + "start": { + "column": 3, + "line": 3, + }, + }, + "ruleName": "@typescript-eslint/class-methods-use-this", + }, + ], + "errorCount": 1, + "fileCount": 1, + "ruleCount": 1, +} +`; + +exports[`class-methods-use-this > invalid 22`] = ` +{ + "code": " +class Foo implements Bar { + private get getter(): number {} +} + ", + "diagnostics": [ + { + "message": "Expected 'this' to be used by class getter 'getter'.", + "messageId": "missingThis", + "range": { + "end": { + "column": 21, + "line": 3, + }, + "start": { + "column": 3, + "line": 3, + }, + }, + "ruleName": "@typescript-eslint/class-methods-use-this", + }, + ], + "errorCount": 1, + "fileCount": 1, + "ruleCount": 1, +} +`; + +exports[`class-methods-use-this > invalid 23`] = ` +{ + "code": " +class Foo implements Bar { + protected get getter(): number {} +} + ", + "diagnostics": [ + { + "message": "Expected 'this' to be used by class getter 'getter'.", + "messageId": "missingThis", + "range": { + "end": { + "column": 23, + "line": 3, + }, + "start": { + "column": 3, + "line": 3, + }, + }, + "ruleName": "@typescript-eslint/class-methods-use-this", + }, + ], + "errorCount": 1, + "fileCount": 1, + "ruleCount": 1, +} +`; + +exports[`class-methods-use-this > invalid 24`] = ` +{ + "code": " +class Foo implements Bar { + set setter(v: number) {} +} + ", + "diagnostics": [ + { + "message": "Expected 'this' to be used by class setter 'setter'.", + "messageId": "missingThis", + "range": { + "end": { + "column": 13, + "line": 3, + }, + "start": { + "column": 3, + "line": 3, + }, + }, + "ruleName": "@typescript-eslint/class-methods-use-this", + }, + ], + "errorCount": 1, + "fileCount": 1, + "ruleCount": 1, +} +`; + +exports[`class-methods-use-this > invalid 25`] = ` +{ + "code": " +class Foo implements Bar { + set #setter(v: number) {} +} + ", + "diagnostics": [ + { + "message": "Expected 'this' to be used by class private setter #setter.", + "messageId": "missingThis", + "range": { + "end": { + "column": 14, + "line": 3, + }, + "start": { + "column": 3, + "line": 3, + }, + }, + "ruleName": "@typescript-eslint/class-methods-use-this", + }, + ], + "errorCount": 1, + "fileCount": 1, + "ruleCount": 1, +} +`; + +exports[`class-methods-use-this > invalid 26`] = ` +{ + "code": " +class Foo implements Bar { + private set setter(v: number) {} +} + ", + "diagnostics": [ + { + "message": "Expected 'this' to be used by class setter 'setter'.", + "messageId": "missingThis", + "range": { + "end": { + "column": 21, + "line": 3, + }, + "start": { + "column": 3, + "line": 3, + }, + }, + "ruleName": "@typescript-eslint/class-methods-use-this", + }, + ], + "errorCount": 1, + "fileCount": 1, + "ruleCount": 1, +} +`; + +exports[`class-methods-use-this > invalid 27`] = ` +{ + "code": " +class Foo implements Bar { + protected set setter(v: number) {} +} + ", + "diagnostics": [ + { + "message": "Expected 'this' to be used by class setter 'setter'.", + "messageId": "missingThis", + "range": { + "end": { + "column": 23, + "line": 3, + }, + "start": { + "column": 3, + "line": 3, + }, + }, + "ruleName": "@typescript-eslint/class-methods-use-this", + }, + ], + "errorCount": 1, + "fileCount": 1, + "ruleCount": 1, +} +`; + +exports[`class-methods-use-this > invalid 28`] = ` +{ + "code": " +class Foo { + override method() {} +} + ", + "diagnostics": [ + { + "message": "Expected 'this' to be used by class method 'method'.", + "messageId": "missingThis", + "range": { + "end": { + "column": 18, + "line": 3, + }, + "start": { + "column": 12, + "line": 3, + }, + }, + "ruleName": "@typescript-eslint/class-methods-use-this", + }, + ], + "errorCount": 1, + "fileCount": 1, + "ruleCount": 1, +} +`; + +exports[`class-methods-use-this > invalid 29`] = ` +{ + "code": " +class Foo { + override get getter(): number {} +} + ", + "diagnostics": [ + { + "message": "Expected 'this' to be used by class getter 'getter'.", + "messageId": "missingThis", + "range": { + "end": { + "column": 22, + "line": 3, + }, + "start": { + "column": 3, + "line": 3, + }, + }, + "ruleName": "@typescript-eslint/class-methods-use-this", + }, + ], + "errorCount": 1, + "fileCount": 1, + "ruleCount": 1, +} +`; + +exports[`class-methods-use-this > invalid 30`] = ` +{ + "code": " +class Foo { + override set setter(v: number) {} +} + ", + "diagnostics": [ + { + "message": "Expected 'this' to be used by class setter 'setter'.", + "messageId": "missingThis", + "range": { + "end": { + "column": 22, + "line": 3, + }, + "start": { + "column": 3, + "line": 3, + }, + }, + "ruleName": "@typescript-eslint/class-methods-use-this", + }, + ], + "errorCount": 1, + "fileCount": 1, + "ruleCount": 1, +} +`; + +exports[`class-methods-use-this > invalid 31`] = ` +{ + "code": " +class Foo implements Bar { + override method() {} +} + ", + "diagnostics": [ + { + "message": "Expected 'this' to be used by class method 'method'.", + "messageId": "missingThis", + "range": { + "end": { + "column": 18, + "line": 3, + }, + "start": { + "column": 12, + "line": 3, + }, + }, + "ruleName": "@typescript-eslint/class-methods-use-this", + }, + ], + "errorCount": 1, + "fileCount": 1, + "ruleCount": 1, +} +`; + +exports[`class-methods-use-this > invalid 32`] = ` +{ + "code": " +class Foo implements Bar { + override get getter(): number {} +} + ", + "diagnostics": [ + { + "message": "Expected 'this' to be used by class getter 'getter'.", + "messageId": "missingThis", + "range": { + "end": { + "column": 22, + "line": 3, + }, + "start": { + "column": 3, + "line": 3, + }, + }, + "ruleName": "@typescript-eslint/class-methods-use-this", + }, + ], + "errorCount": 1, + "fileCount": 1, + "ruleCount": 1, +} +`; + +exports[`class-methods-use-this > invalid 33`] = ` +{ + "code": " +class Foo implements Bar { + override set setter(v: number) {} +} + ", + "diagnostics": [ + { + "message": "Expected 'this' to be used by class setter 'setter'.", + "messageId": "missingThis", + "range": { + "end": { + "column": 22, + "line": 3, + }, + "start": { + "column": 3, + "line": 3, + }, + }, + "ruleName": "@typescript-eslint/class-methods-use-this", + }, + ], + "errorCount": 1, + "fileCount": 1, + "ruleCount": 1, +} +`; + +exports[`class-methods-use-this > invalid 34`] = ` +{ + "code": " +class Foo implements Bar { + property = () => {}; +} + ", + "diagnostics": [ + { + "message": "Expected 'this' to be used by class method 'property'.", + "messageId": "missingThis", + "range": { + "end": { + "column": 14, + "line": 3, + }, + "start": { + "column": 3, + "line": 3, + }, + }, + "ruleName": "@typescript-eslint/class-methods-use-this", + }, + ], + "errorCount": 1, + "fileCount": 1, + "ruleCount": 1, +} +`; + +exports[`class-methods-use-this > invalid 35`] = ` +{ + "code": " +class Foo implements Bar { + #property = () => {}; +} + ", + "diagnostics": [ + { + "message": "Expected 'this' to be used by class private method #property.", + "messageId": "missingThis", + "range": { + "end": { + "column": 15, + "line": 3, + }, + "start": { + "column": 3, + "line": 3, + }, + }, + "ruleName": "@typescript-eslint/class-methods-use-this", + }, + ], + "errorCount": 1, + "fileCount": 1, + "ruleCount": 1, +} +`; + +exports[`class-methods-use-this > invalid 36`] = ` +{ + "code": " +class Foo { + override property = () => {}; +} + ", + "diagnostics": [ + { + "message": "Expected 'this' to be used by class method 'property'.", + "messageId": "missingThis", + "range": { + "end": { + "column": 23, + "line": 3, + }, + "start": { + "column": 12, + "line": 3, + }, + }, + "ruleName": "@typescript-eslint/class-methods-use-this", + }, + ], + "errorCount": 1, + "fileCount": 1, + "ruleCount": 1, +} +`; + +exports[`class-methods-use-this > invalid 37`] = ` +{ + "code": " +class Foo implements Bar { + override property = () => {}; +} + ", + "diagnostics": [ + { + "message": "Expected 'this' to be used by class method 'property'.", + "messageId": "missingThis", + "range": { + "end": { + "column": 23, + "line": 3, + }, + "start": { + "column": 12, + "line": 3, + }, + }, + "ruleName": "@typescript-eslint/class-methods-use-this", + }, + ], + "errorCount": 1, + "fileCount": 1, + "ruleCount": 1, +} +`; + +exports[`class-methods-use-this > invalid 38`] = ` +{ + "code": " +class Foo implements Bar { + private property = () => {}; +} + ", + "diagnostics": [ + { + "message": "Expected 'this' to be used by class method 'property'.", + "messageId": "missingThis", + "range": { + "end": { + "column": 22, + "line": 3, + }, + "start": { + "column": 11, + "line": 3, + }, + }, + "ruleName": "@typescript-eslint/class-methods-use-this", + }, + ], + "errorCount": 1, + "fileCount": 1, + "ruleCount": 1, +} +`; + +exports[`class-methods-use-this > invalid 39`] = ` +{ + "code": " +class Foo implements Bar { + protected property = () => {}; +} + ", + "diagnostics": [ + { + "message": "Expected 'this' to be used by class method 'property'.", + "messageId": "missingThis", + "range": { + "end": { + "column": 24, + "line": 3, + }, + "start": { + "column": 13, + "line": 3, + }, + }, + "ruleName": "@typescript-eslint/class-methods-use-this", + }, + ], + "errorCount": 1, + "fileCount": 1, + "ruleCount": 1, +} +`; + +exports[`class-methods-use-this > invalid 40`] = ` +{ + "code": " +function fn() { + this.foo = 303; + + class Foo { + method() {} + } +} + ", + "diagnostics": [ + { + "message": "Expected 'this' to be used by class method 'method'.", + "messageId": "missingThis", + "range": { + "end": { + "column": 11, + "line": 6, + }, + "start": { + "column": 5, + "line": 6, + }, + }, + "ruleName": "@typescript-eslint/class-methods-use-this", + }, + ], + "errorCount": 1, + "fileCount": 1, + "ruleCount": 1, +} +`; diff --git a/rslint.json b/rslint.json index e00a7dc3d..0a82b4167 100644 --- a/rslint.json +++ b/rslint.json @@ -54,6 +54,7 @@ "@typescript-eslint/require-await": "warn", "@typescript-eslint/prefer-readonly": "warn", "@typescript-eslint/no-non-null-assertion": "warn", + "@typescript-eslint/class-methods-use-this": "off", "@typescript-eslint/no-dynamic-delete": "off", "@typescript-eslint/prefer-includes": "off", "@typescript-eslint/prefer-regexp-exec": "off",