diff --git a/packages/eslint-plugin/src/rules/explicit-member-accessibility.ts b/packages/eslint-plugin/src/rules/explicit-member-accessibility.ts index 83591c7fa71d..a0e11f5cb69e 100644 --- a/packages/eslint-plugin/src/rules/explicit-member-accessibility.ts +++ b/packages/eslint-plugin/src/rules/explicit-member-accessibility.ts @@ -117,7 +117,9 @@ export default createRule({ * @param methodDefinition The node representing a MethodDefinition. */ function checkMethodAccessibilityModifier( - methodDefinition: TSESTree.MethodDefinition, + methodDefinition: + | TSESTree.MethodDefinition + | TSESTree.TSAbstractMethodDefinition, ): void { if (methodDefinition.key.type === AST_NODE_TYPES.PrivateIdentifier) { return; @@ -152,18 +154,19 @@ export default createRule({ check === 'no-public' && methodDefinition.accessibility === 'public' ) { + const publicKeyword = findPublicKeyword(methodDefinition); context.report({ - node: methodDefinition, + loc: rangeToLoc(context.sourceCode, publicKeyword.range), messageId: 'unwantedPublicAccessibility', data: { type: nodeType, name: methodName, }, - fix: getUnwantedPublicAccessibilityFixer(methodDefinition), + fix: fixer => fixer.removeRange(publicKeyword.rangeToRemove), }); } else if (check === 'explicit' && !methodDefinition.accessibility) { context.report({ - node: methodDefinition, + loc: getMissingAccessibilityReportLoc(methodDefinition), messageId: 'missingAccessibility', data: { type: nodeType, @@ -175,49 +178,132 @@ export default createRule({ } /** - * Creates a fixer that removes a "public" keyword with following spaces + * Returns an object containing a range that corresponds to the "public" + * keyword for a node, and the range that would need to be removed to + * remove the "public" keyword (including associated whitespace). */ - function getUnwantedPublicAccessibilityFixer( + function findPublicKeyword( node: | TSESTree.MethodDefinition | TSESTree.PropertyDefinition | TSESTree.TSAbstractMethodDefinition | TSESTree.TSAbstractPropertyDefinition | TSESTree.TSParameterProperty, - ): TSESLint.ReportFixFunction { - return function (fixer: TSESLint.RuleFixer): TSESLint.RuleFix { - const tokens = context.sourceCode.getTokens(node); - let rangeToRemove!: TSESLint.AST.Range; - for (let i = 0; i < tokens.length; i++) { - const token = tokens[i]; - if ( - token.type === AST_TOKEN_TYPES.Keyword && - token.value === 'public' - ) { - const commensAfterPublicKeyword = - context.sourceCode.getCommentsAfter(token); - if (commensAfterPublicKeyword.length) { - // public /* Hi there! */ static foo() - // ^^^^^^^ - rangeToRemove = [ - token.range[0], - commensAfterPublicKeyword[0].range[0], - ]; - break; - } else { - // public static foo() - // ^^^^^^^ - rangeToRemove = [token.range[0], tokens[i + 1].range[0]]; - break; - } + ): { range: TSESLint.AST.Range; rangeToRemove: TSESLint.AST.Range } { + const tokens = context.sourceCode.getTokens(node); + let rangeToRemove!: TSESLint.AST.Range; + let keywordRange!: TSESLint.AST.Range; + for (let i = 0; i < tokens.length; i++) { + const token = tokens[i]; + if ( + token.type === AST_TOKEN_TYPES.Keyword && + token.value === 'public' + ) { + keywordRange = structuredClone(token.range); + const commensAfterPublicKeyword = + context.sourceCode.getCommentsAfter(token); + if (commensAfterPublicKeyword.length) { + // public /* Hi there! */ static foo() + // ^^^^^^^ + rangeToRemove = [ + token.range[0], + commensAfterPublicKeyword[0].range[0], + ]; + break; + } else { + // public static foo() + // ^^^^^^^ + rangeToRemove = [token.range[0], tokens[i + 1].range[0]]; + break; } } - return fixer.removeRange(rangeToRemove); + } + return { range: keywordRange, rangeToRemove }; + } + + /** + * For missing accessibility modifiers, we want to report any keywords + * out in front of the key, and the key itself, but not anything afterwards, + * i.e. parens, type annotations, method bodies, or `?`. + */ + function getMissingAccessibilityReportLoc( + node: + | TSESTree.MethodDefinition + | TSESTree.TSAbstractMethodDefinition + | TSESTree.PropertyDefinition + | TSESTree.TSAbstractPropertyDefinition, + ): TSESTree.SourceLocation { + let start: TSESTree.Position; + + if (node.decorators.length === 0) { + start = node.loc.start; + } else { + const lastDecorator = node.decorators[node.decorators.length - 1]; + const nextToken = nullThrows( + context.sourceCode.getTokenAfter(lastDecorator), + NullThrowsReasons.MissingToken('token', 'last decorator'), + ); + start = nextToken.loc.start; + } + + let end: TSESTree.Position; + + if (!node.computed) { + end = node.key.loc.end; + } else { + const closingBracket = nullThrows( + context.sourceCode.getTokenAfter( + node.key, + token => token.value === ']', + ), + NullThrowsReasons.MissingToken(']', node.type), + ); + end = closingBracket.loc.end; + } + + return { + start: structuredClone(start), + end: structuredClone(end), + }; + } + + /** + * For missing accessibility modifiers, we want to report any keywords + * out in front of the key, and the key itself, but not anything afterwards, + * i.e. parens, type annotations, method bodies, or `?`. + */ + function getMissingAccessibilityReportLocForParameterProperty( + node: TSESTree.TSParameterProperty, + nodeName: string, + ): TSESTree.SourceLocation { + // Parameter properties have a weirdly different AST structure + // than other class members. + + let start: TSESTree.Position; + + if (node.decorators.length === 0) { + start = structuredClone(node.loc.start); + } else { + const lastDecorator = node.decorators[node.decorators.length - 1]; + const nextToken = nullThrows( + context.sourceCode.getTokenAfter(lastDecorator), + NullThrowsReasons.MissingToken('token', 'last decorator'), + ); + start = structuredClone(nextToken.loc.start); + } + + const end = context.sourceCode.getLocFromIndex( + node.parameter.range[0] + nodeName.length, + ); + + return { + start, + end, }; } /** - * Creates a fixer that adds a "public" keyword with following spaces + * Creates a fixer that adds an accessibility modifier keyword */ function getMissingAccessibilitySuggestions( node: @@ -284,21 +370,22 @@ export default createRule({ propCheck === 'no-public' && propertyDefinition.accessibility === 'public' ) { + const publicKeywordRange = findPublicKeyword(propertyDefinition); context.report({ - node: propertyDefinition, + loc: rangeToLoc(context.sourceCode, publicKeywordRange.range), messageId: 'unwantedPublicAccessibility', data: { type: nodeType, name: propertyName, }, - fix: getUnwantedPublicAccessibilityFixer(propertyDefinition), + fix: fixer => fixer.removeRange(publicKeywordRange.rangeToRemove), }); } else if ( propCheck === 'explicit' && !propertyDefinition.accessibility ) { context.report({ - node: propertyDefinition, + loc: getMissingAccessibilityReportLoc(propertyDefinition), messageId: 'missingAccessibility', data: { type: nodeType, @@ -335,7 +422,10 @@ export default createRule({ case 'explicit': { if (!node.accessibility) { context.report({ - node, + loc: getMissingAccessibilityReportLocForParameterProperty( + node, + nodeName, + ), messageId: 'missingAccessibility', data: { type: nodeType, @@ -348,14 +438,15 @@ export default createRule({ } case 'no-public': { if (node.accessibility === 'public' && node.readonly) { + const publicKeyword = findPublicKeyword(node); context.report({ - node, + loc: rangeToLoc(context.sourceCode, publicKeyword.range), messageId: 'unwantedPublicAccessibility', data: { type: nodeType, name: nodeName, }, - fix: getUnwantedPublicAccessibilityFixer(node), + fix: fixer => fixer.removeRange(publicKeyword.rangeToRemove), }); } break; @@ -372,3 +463,13 @@ export default createRule({ }; }, }); + +function rangeToLoc( + sourceCode: TSESLint.SourceCode, + range: TSESLint.AST.Range, +): TSESTree.SourceLocation { + return { + start: sourceCode.getLocFromIndex(range[0]), + end: sourceCode.getLocFromIndex(range[1]), + }; +} diff --git a/packages/eslint-plugin/tests/docs-eslint-output-snapshots/explicit-member-accessibility.shot b/packages/eslint-plugin/tests/docs-eslint-output-snapshots/explicit-member-accessibility.shot index ee066bed4686..ad4cf9847d1d 100644 --- a/packages/eslint-plugin/tests/docs-eslint-output-snapshots/explicit-member-accessibility.shot +++ b/packages/eslint-plugin/tests/docs-eslint-output-snapshots/explicit-member-accessibility.shot @@ -5,37 +5,26 @@ exports[`Validating rule docs explicit-member-accessibility.mdx code examples ES class Animal { constructor(name) { - ~~~~~~~~~~~~~~~~~~~ Missing accessibility modifier on method definition constructor. + ~~~~~~~~~~~ Missing accessibility modifier on method definition constructor. // No accessibility modifier -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ this.animalName = name; -~~~~~~~~~~~~~~~~~~~~~~~~~~~ } -~~~ animalName: string; // No accessibility modifier - ~~~~~~~~~~~~~~~~~~~ Missing accessibility modifier on class property animalName. + ~~~~~~~~~~ Missing accessibility modifier on class property animalName. get name(): string { - ~~~~~~~~~~~~~~~~~~~~ Missing accessibility modifier on get property accessor name. + ~~~~~~~~ Missing accessibility modifier on get property accessor name. // No accessibility modifier -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ return this.animalName; -~~~~~~~~~~~~~~~~~~~~~~~~~~~ } -~~~ set name(value: string) { - ~~~~~~~~~~~~~~~~~~~~~~~~~ Missing accessibility modifier on set property accessor name. + ~~~~~~~~ Missing accessibility modifier on set property accessor name. // No accessibility modifier -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ this.animalName = value; -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ } -~~~ walk() { - ~~~~~~~~ Missing accessibility modifier on method definition walk. + ~~~~ Missing accessibility modifier on method definition walk. // method -~~~~~~~~~~~~~ } -~~~ } " `; @@ -53,21 +42,15 @@ class Animal { } private animalName: string; // Property get name(): string { - ~~~~~~~~~~~~~~~~~~~~ Missing accessibility modifier on get property accessor name. + ~~~~~~~~ Missing accessibility modifier on get property accessor name. // get accessor -~~~~~~~~~~~~~~~~~~~ return this.animalName; -~~~~~~~~~~~~~~~~~~~~~~~~~~~ } -~~~ set name(value: string) { - ~~~~~~~~~~~~~~~~~~~~~~~~~ Missing accessibility modifier on set property accessor name. + ~~~~~~~~ Missing accessibility modifier on set property accessor name. // set accessor -~~~~~~~~~~~~~~~~~~~ this.animalName = value; -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ } -~~~ public walk() { // method } @@ -80,43 +63,29 @@ exports[`Validating rule docs explicit-member-accessibility.mdx code examples ES class Animal { public constructor( - ~~~~~~~~~~~~~~~~~~~ Public accessibility modifier on method definition constructor. + ~~~~~~ Public accessibility modifier on method definition constructor. public breed, -~~~~~~~~~~~~~~~~~ name, -~~~~~~~~~ ) { -~~~~~ // Parameter property and constructor -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ this.animalName = name; -~~~~~~~~~~~~~~~~~~~~~~~~~~~ } -~~~ public animalName: string; // Property - ~~~~~~~~~~~~~~~~~~~~~~~~~~ Public accessibility modifier on class property animalName. + ~~~~~~ Public accessibility modifier on class property animalName. public get name(): string { - ~~~~~~~~~~~~~~~~~~~~~~~~~~~ Public accessibility modifier on get property accessor name. + ~~~~~~ Public accessibility modifier on get property accessor name. // get accessor -~~~~~~~~~~~~~~~~~~~ return this.animalName; -~~~~~~~~~~~~~~~~~~~~~~~~~~~ } -~~~ public set name(value: string) { - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Public accessibility modifier on set property accessor name. + ~~~~~~ Public accessibility modifier on set property accessor name. // set accessor -~~~~~~~~~~~~~~~~~~~ this.animalName = value; -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ } -~~~ public walk() { - ~~~~~~~~~~~~~~~ Public accessibility modifier on method definition walk. + ~~~~~~ Public accessibility modifier on method definition walk. // method -~~~~~~~~~~~~~ } -~~~ } " `; @@ -153,7 +122,7 @@ exports[`Validating rule docs explicit-member-accessibility.mdx code examples ES class Animal { public constructor(protected animalName) {} - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Public accessibility modifier on method definition constructor. + ~~~~~~ Public accessibility modifier on method definition constructor. public get name() { return this.animalName; } @@ -185,7 +154,7 @@ class Animal { this.animalName = value; } legs: number; - ~~~~~~~~~~~~~ Missing accessibility modifier on class property legs. + ~~~~ Missing accessibility modifier on class property legs. private hasFleas: boolean; } " @@ -213,7 +182,7 @@ exports[`Validating rule docs explicit-member-accessibility.mdx code examples ES class Animal { constructor(readonly animalName: string) {} - ~~~~~~~~~~~~~~~~~~~~~~~~~~~ Missing accessibility modifier on parameter property animalName. + ~~~~~~~~~~~~~~~~~~~ Missing accessibility modifier on parameter property animalName. } " `; @@ -240,7 +209,7 @@ exports[`Validating rule docs explicit-member-accessibility.mdx code examples ES class Animal { constructor(public readonly animalName: string) {} - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Public accessibility modifier on parameter property animalName. + ~~~~~~ Public accessibility modifier on parameter property animalName. } " `; @@ -259,7 +228,7 @@ exports[`Validating rule docs explicit-member-accessibility.mdx code examples ES class Animal { constructor(protected animalName) {} - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Missing accessibility modifier on method definition constructor. + ~~~~~~~~~~~ Missing accessibility modifier on method definition constructor. public get name() { return this.animalName; } diff --git a/packages/eslint-plugin/tests/rules/explicit-member-accessibility.test.ts b/packages/eslint-plugin/tests/rules/explicit-member-accessibility.test.ts index 388cb1fa4a86..4b47ebe7826a 100644 --- a/packages/eslint-plugin/tests/rules/explicit-member-accessibility.test.ts +++ b/packages/eslint-plugin/tests/rules/explicit-member-accessibility.test.ts @@ -340,8 +340,10 @@ export class XXXX { errors: [ { messageId: 'missingAccessibility', - column: 22, line: 3, + column: 22, + endLine: 3, + endColumn: 36, suggestions: [ { messageId: 'addExplicitAccessibility', @@ -385,6 +387,10 @@ export class WithParameterProperty { errors: [ { messageId: 'missingAccessibility', + line: 3, + column: 22, + endLine: 3, + endColumn: 36, suggestions: [ { messageId: 'addExplicitAccessibility', @@ -436,6 +442,10 @@ export class XXXX { errors: [ { messageId: 'missingAccessibility', + line: 3, + column: 22, + endLine: 3, + endColumn: 37, suggestions: [ { messageId: 'addExplicitAccessibility', @@ -484,6 +494,10 @@ class Test { errors: [ { messageId: 'missingAccessibility', + line: 3, + column: 22, + endLine: 3, + endColumn: 34, suggestions: [ { messageId: 'addExplicitAccessibility', @@ -535,6 +549,8 @@ class Test { }, line: 3, column: 3, + endLine: 3, + endColumn: 4, suggestions: [ { messageId: 'addExplicitAccessibility', @@ -598,6 +614,8 @@ class Test { }, line: 4, column: 3, + endLine: 4, + endColumn: 7, suggestions: [ { messageId: 'addExplicitAccessibility', @@ -658,6 +676,8 @@ class Test { }, line: 3, column: 3, + endLine: 3, + endColumn: 4, suggestions: [ { messageId: 'addExplicitAccessibility', @@ -705,6 +725,8 @@ class Test { }, line: 4, column: 3, + endLine: 4, + endColumn: 7, suggestions: [ { messageId: 'addExplicitAccessibility', @@ -766,6 +788,8 @@ class Test { }, line: 5, column: 3, + endLine: 5, + endColumn: 9, }, ], output: ` @@ -798,6 +822,8 @@ class Test { }, line: 4, column: 3, + endLine: 4, + endColumn: 9, }, ], output: ` @@ -824,11 +850,15 @@ class Test { messageId: 'unwantedPublicAccessibility', line: 3, column: 3, + endLine: 3, + endColumn: 9, }, { messageId: 'unwantedPublicAccessibility', line: 4, column: 3, + endLine: 4, + endColumn: 9, }, ], options: [{ accessibility: 'no-public' }], @@ -862,6 +892,8 @@ class Test { messageId: 'missingAccessibility', line: 7, column: 3, + endLine: 7, + endColumn: 20, suggestions: [ { messageId: 'addExplicitAccessibility', @@ -923,6 +955,8 @@ class Test { messageId: 'missingAccessibility', line: 10, column: 3, + endLine: 10, + endColumn: 20, suggestions: [ { messageId: 'addExplicitAccessibility', @@ -1004,6 +1038,8 @@ class Test { messageId: 'missingAccessibility', line: 4, column: 3, + endLine: 4, + endColumn: 14, suggestions: [ { messageId: 'addExplicitAccessibility', @@ -1065,6 +1101,8 @@ class Test { messageId: 'missingAccessibility', line: 7, column: 3, + endLine: 7, + endColumn: 20, suggestions: [ { messageId: 'addExplicitAccessibility', @@ -1126,6 +1164,8 @@ class Test { messageId: 'missingAccessibility', line: 10, column: 3, + endLine: 10, + endColumn: 20, suggestions: [ { messageId: 'addExplicitAccessibility', @@ -1200,6 +1240,8 @@ class Test { messageId: 'missingAccessibility', line: 3, column: 3, + endLine: 3, + endColumn: 14, suggestions: [ { messageId: 'addExplicitAccessibility', @@ -1258,6 +1300,8 @@ class Test { messageId: 'missingAccessibility', line: 3, column: 3, + endLine: 3, + endColumn: 14, suggestions: [ { messageId: 'addExplicitAccessibility', @@ -1307,6 +1351,8 @@ class Test { messageId: 'unwantedPublicAccessibility', line: 3, column: 15, + endLine: 3, + endColumn: 21, }, ], output: ` @@ -1333,6 +1379,8 @@ class Test { messageId: 'missingAccessibility', line: 3, column: 3, + endLine: 3, + endColumn: 4, suggestions: [ { messageId: 'addExplicitAccessibility', @@ -1383,6 +1431,8 @@ class Test { messageId: 'unwantedPublicAccessibility', line: 3, column: 3, + endLine: 3, + endColumn: 9, }, ], output: ` @@ -1395,7 +1445,7 @@ class Test { { code: ` class Test { - constructor(public ...x: any[]) {} + constructor(public x: any[]) {} } `, output: null, @@ -1405,13 +1455,15 @@ class Test { messageId: 'missingAccessibility', line: 3, column: 3, + endLine: 3, + endColumn: 14, suggestions: [ { messageId: 'addExplicitAccessibility', data: { type: 'public' }, output: ` class Test { - public constructor(public ...x: any[]) {} + public constructor(public x: any[]) {} } `, }, @@ -1420,7 +1472,7 @@ class Test { data: { type: 'private' }, output: ` class Test { - private constructor(public ...x: any[]) {} + private constructor(public x: any[]) {} } `, }, @@ -1429,7 +1481,7 @@ class Test { data: { type: 'protected' }, output: ` class Test { - protected constructor(public ...x: any[]) {} + protected constructor(public x: any[]) {} } `, }, @@ -1453,6 +1505,8 @@ class Test { messageId: 'unwantedPublicAccessibility', line: 3, column: 3, + endLine: 3, + endColumn: 9, }, ], output: ` @@ -1476,8 +1530,10 @@ class Test { errors: [ { messageId: 'unwantedPublicAccessibility', - line: 3, + line: 4, column: 3, + endLine: 4, + endColumn: 9, }, ], output: ` @@ -1487,7 +1543,6 @@ class Test { } `, }, - { code: ` class Test { @@ -1503,8 +1558,10 @@ class Test { errors: [ { messageId: 'unwantedPublicAccessibility', - line: 3, + line: 4, column: 3, + endLine: 4, + endColumn: 9, }, ], output: ` @@ -1530,6 +1587,8 @@ class Test { messageId: 'unwantedPublicAccessibility', line: 3, column: 3, + endLine: 3, + endColumn: 9, }, ], output: ` @@ -1538,7 +1597,6 @@ class Test { } `, }, - { code: noFormat` class Test { @@ -1556,6 +1614,8 @@ class Test { messageId: 'unwantedPublicAccessibility', line: 3, column: 15, + endLine: 3, + endColumn: 21, }, ], output: ` @@ -1580,6 +1640,8 @@ class Test { messageId: 'unwantedPublicAccessibility', line: 3, column: 15, + endLine: 3, + endColumn: 21, }, ], output: ` @@ -1605,6 +1667,8 @@ class EnsureWhiteSPaceSpan { messageId: 'unwantedPublicAccessibility', line: 3, column: 3, + endLine: 3, + endColumn: 9, }, ], output: ` @@ -1630,6 +1694,8 @@ class EnsureWhiteSPaceSpan { messageId: 'unwantedPublicAccessibility', line: 3, column: 3, + endLine: 3, + endColumn: 9, }, ], output: ` @@ -1658,6 +1724,8 @@ class Test { }, line: 3, column: 3, + endLine: 3, + endColumn: 9, }, { messageId: 'unwantedPublicAccessibility', @@ -1667,6 +1735,8 @@ class Test { }, line: 4, column: 3, + endLine: 4, + endColumn: 9, }, { messageId: 'unwantedPublicAccessibility', @@ -1676,6 +1746,8 @@ class Test { }, line: 5, column: 3, + endLine: 5, + endColumn: 9, }, { messageId: 'unwantedPublicAccessibility', @@ -1685,6 +1757,8 @@ class Test { }, line: 6, column: 3, + endLine: 6, + endColumn: 9, }, ], output: ` @@ -1709,6 +1783,8 @@ abstract class SomeClass { messageId: 'missingAccessibility', line: 3, column: 3, + endLine: 3, + endColumn: 18, suggestions: [ { messageId: 'addExplicitAccessibility', @@ -1758,6 +1834,8 @@ abstract class SomeClass { messageId: 'unwantedPublicAccessibility', line: 3, column: 3, + endLine: 3, + endColumn: 9, }, ], output: ` @@ -1780,6 +1858,8 @@ abstract class SomeClass { messageId: 'missingAccessibility', line: 3, column: 3, + endLine: 3, + endColumn: 13, suggestions: [ { messageId: 'addExplicitAccessibility', @@ -1829,6 +1909,8 @@ abstract class SomeClass { messageId: 'unwantedPublicAccessibility', line: 3, column: 3, + endLine: 3, + endColumn: 9, }, ], output: ` @@ -1861,6 +1943,8 @@ class DecoratedClass { messageId: 'missingAccessibility', line: 3, column: 3, + endLine: 3, + endColumn: 14, suggestions: [ { messageId: 'addExplicitAccessibility', @@ -1930,7 +2014,9 @@ class DecoratedClass { { messageId: 'missingAccessibility', line: 3, - column: 15, + column: 27, + endLine: 3, + endColumn: 39, suggestions: [ { messageId: 'addExplicitAccessibility', @@ -2000,7 +2086,9 @@ class DecoratedClass { { messageId: 'missingAccessibility', line: 4, - column: 3, + column: 15, + endLine: 4, + endColumn: 16, suggestions: [ { messageId: 'addExplicitAccessibility', @@ -2070,7 +2158,9 @@ class DecoratedClass { { messageId: 'missingAccessibility', line: 5, - column: 3, + column: 15, + endLine: 5, + endColumn: 19, suggestions: [ { messageId: 'addExplicitAccessibility', @@ -2139,8 +2229,10 @@ class DecoratedClass { }, { messageId: 'missingAccessibility', - line: 8, + line: 10, column: 3, + endLine: 10, + endColumn: 8, suggestions: [ { messageId: 'addExplicitAccessibility', @@ -2210,7 +2302,9 @@ class DecoratedClass { { messageId: 'missingAccessibility', line: 13, - column: 3, + column: 15, + endLine: 13, + endColumn: 20, suggestions: [ { messageId: 'addExplicitAccessibility', @@ -2272,6 +2366,53 @@ class DecoratedClass { @foo @bar() protected set z(@foo @bar() value: x) { this.x = x; } +} + `, + }, + ], + }, + ], + }, + { + code: ` +abstract class SomeClass { + abstract ['computed-method-name'](): string; +} + `, + output: null, + options: [{ accessibility: 'explicit' }], + errors: [ + { + messageId: 'missingAccessibility', + line: 3, + column: 3, + endLine: 3, + endColumn: 36, + suggestions: [ + { + messageId: 'addExplicitAccessibility', + data: { type: 'public' }, + output: ` +abstract class SomeClass { + public abstract ['computed-method-name'](): string; +} + `, + }, + { + messageId: 'addExplicitAccessibility', + data: { type: 'private' }, + output: ` +abstract class SomeClass { + private abstract ['computed-method-name'](): string; +} + `, + }, + { + messageId: 'addExplicitAccessibility', + data: { type: 'protected' }, + output: ` +abstract class SomeClass { + protected abstract ['computed-method-name'](): string; } `, },