Skip to content
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

fix(eslint-plugin): fix false positives for adjacent-overload-signatures regarding computed property names #340

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -26,6 +26,8 @@ export default util.createRule({
},
defaultOptions: [],
create(context) {
const sourceCode = context.getSourceCode();

/**
* Gets the name of the member being processed.
* @param member the member being processed.
Expand Down Expand Up @@ -57,7 +59,7 @@ export default util.createRule({
case AST_NODE_TYPES.TSConstructSignatureDeclaration:
return 'new';
case AST_NODE_TYPES.MethodDefinition:
return util.getNameFromPropertyName(member.key);
return util.getNameFromClassMember(member, sourceCode);
}

return null;
Expand Down
Expand Up @@ -20,6 +20,7 @@ export default util.createRule({
},
defaultOptions: [],
create(context) {
const sourceCode = context.getSourceCode();
/**
* Checks if a method declaration has an accessibility modifier.
* @param methodDefinition The node representing a MethodDefinition.
Expand All @@ -36,7 +37,7 @@ export default util.createRule({
messageId: 'missingAccessibility',
data: {
type: 'method definition',
name: util.getNameFromPropertyName(methodDefinition.key),
name: util.getNameFromClassMember(methodDefinition, sourceCode),
},
});
}
Expand Down
4 changes: 3 additions & 1 deletion packages/eslint-plugin/src/rules/member-naming.ts
Expand Up @@ -51,6 +51,8 @@ export default util.createRule<Options, MessageIds>({
},
defaultOptions: [{}],
create(context, [config]) {
const sourceCode = context.getSourceCode();

const conventions = (Object.keys(config) as Modifiers[]).reduce<
Config<RegExp>
>((acc, accessibility) => {
Expand All @@ -69,7 +71,7 @@ export default util.createRule<Options, MessageIds>({
function validateName(
node: TSESTree.MethodDefinition | TSESTree.ClassProperty,
): void {
const name = util.getNameFromPropertyName(node.key);
const name = util.getNameFromClassMember(node, sourceCode);
const accessibility: Modifiers = node.accessibility || 'public';
const convention = conventions[accessibility];

Expand Down
4 changes: 3 additions & 1 deletion packages/eslint-plugin/src/rules/member-ordering.ts
Expand Up @@ -164,6 +164,8 @@ export default util.createRule<Options, MessageIds>({
},
],
create(context, [options]) {
const sourceCode = context.getSourceCode();

const functionExpressions = [
AST_NODE_TYPES.FunctionExpression,
AST_NODE_TYPES.ArrowFunctionExpression,
Expand Down Expand Up @@ -213,7 +215,7 @@ export default util.createRule<Options, MessageIds>({
case AST_NODE_TYPES.MethodDefinition:
return node.kind === 'constructor'
? 'constructor'
: util.getNameFromPropertyName(node.key);
: util.getNameFromClassMember(node, sourceCode);
case AST_NODE_TYPES.TSConstructSignatureDeclaration:
return 'new';
default:
Expand Down
29 changes: 29 additions & 0 deletions packages/eslint-plugin/src/util/misc.ts
Expand Up @@ -4,6 +4,7 @@

import { TSESTree, AST_NODE_TYPES } from '@typescript-eslint/typescript-estree';
import RuleModule from 'ts-eslint';
import { SourceCode } from 'ts-eslint';

/**
* Check if the context file name is *.ts or *.tsx
Expand Down Expand Up @@ -63,3 +64,31 @@ export function getNameFromPropertyName(
}
return `${propertyName.value}`;
}

/**
* Gets a string name representation of the name of the given MethodDefinition
* or ClassProperty node, with handling for computed property names.
*/
export function getNameFromClassMember(
methodDefinition: TSESTree.MethodDefinition | TSESTree.ClassProperty,
sourceCode: SourceCode,
): string {
if (keyCanBeReadAsPropertyName(methodDefinition.key)) {
return getNameFromPropertyName(methodDefinition.key);
}

return sourceCode.text.slice(...methodDefinition.key.range);
}

/**
* This covers both actual property names, as well as computed properties that are either
* an identifier or a literal at the top level.
*/
function keyCanBeReadAsPropertyName(
node: TSESTree.Expression,
): node is TSESTree.PropertyName {
return (
node.type === AST_NODE_TYPES.Literal ||
node.type === AST_NODE_TYPES.Identifier
);
}
Expand Up @@ -217,6 +217,11 @@ class Test {
// examples from https://github.com/nzakas/eslint-plugin-typescript/issues/138
'export default function<T>(foo : T) {}',
'export default function named<T>(foo : T) {}',
`
interface Foo {
[Symbol.toStringTag](): void;
[Symbol.iterator](): void;
}`,
],
invalid: [
{
Expand Down
1 change: 1 addition & 0 deletions packages/eslint-plugin/typings/ts-eslint.d.ts
Expand Up @@ -683,6 +683,7 @@ declare module 'ts-eslint' {
RuleMetaData,
RuleMetaDataDocs,
Scope,
SourceCode,
};
export default RuleModule;
}
2 changes: 1 addition & 1 deletion packages/typescript-estree/src/ts-estree/ts-estree.ts
Expand Up @@ -500,7 +500,7 @@ interface LiteralBase extends BaseNode {
}

interface MethodDefinitionBase extends BaseNode {
key: PropertyName;
key: Expression;
value: FunctionExpression | TSEmptyBodyFunctionExpression;
computed: boolean;
static: boolean;
Expand Down