From 9c8203f15854293f67dac7ea201c6a2ee527edc1 Mon Sep 17 00:00:00 2001 From: Alexander T Date: Thu, 14 Nov 2019 19:15:39 +0200 Subject: [PATCH] fix(eslint-plugin): [camelcase] handle optional member expr (#1204) --- packages/eslint-plugin/src/rules/camelcase.ts | 42 ++++++++++++------ .../tests/rules/camelcase.test.ts | 44 +++++++++++++++++++ 2 files changed, 73 insertions(+), 13 deletions(-) diff --git a/packages/eslint-plugin/src/rules/camelcase.ts b/packages/eslint-plugin/src/rules/camelcase.ts index 4bb614cba9d..0928484b629 100644 --- a/packages/eslint-plugin/src/rules/camelcase.ts +++ b/packages/eslint-plugin/src/rules/camelcase.ts @@ -72,23 +72,28 @@ export default util.createRule({ * @private */ function isTSPropertyType(node: TSESTree.Node): boolean { - if (!node.parent) { - return false; - } - if (TS_PROPERTY_TYPES.includes(node.parent.type)) { + if (TS_PROPERTY_TYPES.includes(node.type)) { return true; } - if (node.parent.type === AST_NODE_TYPES.AssignmentPattern) { + if (node.type === AST_NODE_TYPES.AssignmentPattern) { return ( - node.parent.parent !== undefined && - TS_PROPERTY_TYPES.includes(node.parent.parent.type) + node.parent !== undefined && + TS_PROPERTY_TYPES.includes(node.parent.type) ); } return false; } + function report(node: TSESTree.Identifier): void { + context.report({ + node, + messageId: 'notCamelCase', + data: { name: node.name }, + }); + } + return { Identifier(node): void { /* @@ -103,13 +108,24 @@ export default util.createRule({ } // Check TypeScript specific nodes - if (isTSPropertyType(node)) { + const parent = node.parent; + if (parent && isTSPropertyType(parent)) { if (properties === 'always' && isUnderscored(name)) { - context.report({ - node, - messageId: 'notCamelCase', - data: { name: node.name }, - }); + report(node); + } + + return; + } + + if (parent && parent.type === AST_NODE_TYPES.OptionalMemberExpression) { + // Report underscored object names + if ( + properties === 'always' && + parent.object.type === AST_NODE_TYPES.Identifier && + parent.object.name === node.name && + isUnderscored(name) + ) { + report(node); } return; diff --git a/packages/eslint-plugin/tests/rules/camelcase.test.ts b/packages/eslint-plugin/tests/rules/camelcase.test.ts index e0e142c70a4..d2d3287ce66 100644 --- a/packages/eslint-plugin/tests/rules/camelcase.test.ts +++ b/packages/eslint-plugin/tests/rules/camelcase.test.ts @@ -79,6 +79,22 @@ ruleTester.run('camelcase', rule, { code: 'abstract class Foo { abstract bar: number = 0; }', options: [{ properties: 'always' }], }, + { + code: 'const foo = foo?.baz;', + }, + { + code: 'const foo = foo?.foo_bar?.foo_bar_baz;', + }, + { + code: 'const foo = foo.bar?.foo_bar_baz;', + }, + { + code: 'const foo = (foo?.bar?.baz)?.foo_bar_baz;', + }, + { + code: 'const foo = foo_bar?.foo;', + options: [{ properties: 'never' }], + }, ], invalid: [ @@ -194,5 +210,33 @@ ruleTester.run('camelcase', rule, { }, ], }, + { + code: 'const foo = foo_bar?.foo;', + options: [{ properties: 'always' }], + errors: [ + { + messageId: 'notCamelCase', + data: { + name: 'foo_bar', + }, + line: 1, + column: 13, + }, + ], + }, + { + code: 'const foo = (foo_test?.bar)?.baz;', + options: [{ properties: 'always' }], + errors: [ + { + messageId: 'notCamelCase', + data: { + name: 'foo_test', + }, + line: 1, + column: 14, + }, + ], + }, ], });