Skip to content

Commit

Permalink
fix(eslint-plugin): [member-naming] should match constructor args (#771)
Browse files Browse the repository at this point in the history
  • Loading branch information
a-tarasyuk authored and JamesHenry committed Aug 19, 2019
1 parent 9f82099 commit b006667
Show file tree
Hide file tree
Showing 2 changed files with 124 additions and 15 deletions.
69 changes: 54 additions & 15 deletions packages/eslint-plugin/src/rules/member-naming.ts
@@ -1,4 +1,7 @@
import { TSESTree } from '@typescript-eslint/experimental-utils';
import {
TSESTree,
AST_NODE_TYPES,
} from '@typescript-eslint/experimental-utils';
import * as util from '../util';

interface Config<T = string> {
Expand Down Expand Up @@ -61,37 +64,73 @@ export default util.createRule<Options, MessageIds>({
return acc;
}, {});

/**
* Check that the property name matches the convention for its
* accessibility.
* @param {ASTNode} node the named node to evaluate.
* @returns {void}
* @private
*/
function getParameterNode(
node: TSESTree.TSParameterProperty,
): TSESTree.Identifier | null {
if (node.parameter.type === AST_NODE_TYPES.AssignmentPattern) {
return node.parameter.left as TSESTree.Identifier;
}

if (node.parameter.type === AST_NODE_TYPES.Identifier) {
return node.parameter;
}

return null;
}

function validateParameterName(node: TSESTree.TSParameterProperty): void {
const parameterNode = getParameterNode(node);
if (!parameterNode) {
return;
}

validate(parameterNode, parameterNode.name, node.accessibility);
}

function validateName(
node: TSESTree.MethodDefinition | TSESTree.ClassProperty,
): void {
const name = util.getNameFromClassMember(node, sourceCode);
const accessibility: Modifiers = node.accessibility || 'public';
const convention = conventions[accessibility];

const method = node as TSESTree.MethodDefinition;
if (method.kind === 'constructor') {
if (
node.type === AST_NODE_TYPES.MethodDefinition &&
node.kind === 'constructor'
) {
return;
}

validate(
node.key,
util.getNameFromClassMember(node, sourceCode),
node.accessibility,
);
}

/**
* Check that the name matches the convention for its accessibility.
* @param {ASTNode} node the named node to evaluate.
* @param {string} name
* @param {Modifiers} accessibility
* @returns {void}
* @private
*/
function validate(
node: TSESTree.Identifier | TSESTree.Expression,
name: string,
accessibility: Modifiers = 'public',
): void {
const convention = conventions[accessibility];
if (!convention || convention.test(name)) {
return;
}

context.report({
node: node.key,
node,
messageId: 'incorrectName',
data: { accessibility, name, convention },
});
}

return {
TSParameterProperty: validateParameterName,
MethodDefinition: validateName,
ClassProperty: validateName,
};
Expand Down
70 changes: 70 additions & 0 deletions packages/eslint-plugin/tests/rules/member-naming.test.ts
Expand Up @@ -86,6 +86,30 @@ class Class {
},
],
},

{
code: `
class Test {
constructor(public __a: string, protected __b: string, private __c: string = 100) {}
}
`,
options: [
{
protected: '^__',
private: '^__',
public: '^__',
},
],
},
{
code:
// Semantically invalid test case, TS has to throw an error.
`
class Foo {
constructor(private ...name: string[], private [test]: [string]) {}
}
`,
},
],
invalid: [
{
Expand Down Expand Up @@ -329,5 +353,51 @@ class Class {
},
],
},
{
code: `
class Test {
constructor(public a: string, protected b: string, private c: string = 100) {}
}
`,
options: [
{
public: '^__',
protected: '^__',
private: '^__',
},
],
errors: [
{
messageId: 'incorrectName',
data: {
accessibility: 'public',
convention: '/^__/',
name: 'a',
},
line: 3,
column: 24,
},
{
messageId: 'incorrectName',
data: {
accessibility: 'protected',
convention: '/^__/',
name: 'b',
},
line: 3,
column: 45,
},
{
messageId: 'incorrectName',
data: {
accessibility: 'private',
convention: '/^__/',
name: 'c',
},
line: 3,
column: 64,
},
],
},
],
});

0 comments on commit b006667

Please sign in to comment.