From 3c231fa364845d1ec0374f16449fe42ea547a163 Mon Sep 17 00:00:00 2001 From: Gabriele Petronella Date: Mon, 17 Jul 2017 00:19:26 +0200 Subject: [PATCH] Update: add enforceInMethodNames to no-underscore-dangle (fixes #7065) (#7234) When enforceInMethodNames is true, the rule checks for dangling underscores in method names too. This includes methods of classes and method properties of objects. The option is false by default. --- docs/rules/no-underscore-dangle.md | 25 +++++++++++++++++++++ lib/rules/no-underscore-dangle.js | 29 ++++++++++++++++++++++++- tests/lib/rules/no-underscore-dangle.js | 14 ++++++++++-- 3 files changed, 65 insertions(+), 3 deletions(-) diff --git a/docs/rules/no-underscore-dangle.md b/docs/rules/no-underscore-dangle.md index d09c6d6ade4..e51a020dbe5 100644 --- a/docs/rules/no-underscore-dangle.md +++ b/docs/rules/no-underscore-dangle.md @@ -42,6 +42,7 @@ This rule has an object option: * `"allow"` allows specified identifiers to have dangling underscores * `"allowAfterThis": false` (default) disallows dangling underscores in members of the `this` object * `"allowAfterSuper": false` (default) disallows dangling underscores in members of the `super` object +* `"enforceInMethodNames": false (default) allows dangling underscores in method names` ### allow @@ -76,6 +77,30 @@ var a = super.foo_; super._bar(); ``` +### enforceInMethodNames + +Examples of incorrect code for this rule with the `{ "enforceInMethodNames": true }` option: + +```js +/*eslint no-underscore-dangle: ["error", { "enforceInMethodNames": true }]*/ + +class Foo { + _bar() {} +} + +class Foo { + bar_() {} +} + +const o = { + _bar() {} +}; + +const o = { + bar_() = {} +}; +``` + ## When Not To Use It If you want to allow dangling underscores in identifiers, then you can safely turn this rule off. diff --git a/lib/rules/no-underscore-dangle.js b/lib/rules/no-underscore-dangle.js index 6803cc68fc7..5964da41cde 100644 --- a/lib/rules/no-underscore-dangle.js +++ b/lib/rules/no-underscore-dangle.js @@ -32,6 +32,9 @@ module.exports = { }, allowAfterSuper: { type: "boolean" + }, + enforceInMethodNames: { + type: "boolean" } }, additionalProperties: false @@ -45,6 +48,7 @@ module.exports = { const ALLOWED_VARIABLES = options.allow ? options.allow : []; const allowAfterThis = typeof options.allowAfterThis !== "undefined" ? options.allowAfterThis : false; const allowAfterSuper = typeof options.allowAfterSuper !== "undefined" ? options.allowAfterSuper : false; + const enforceInMethodNames = typeof options.enforceInMethodNames !== "undefined" ? options.enforceInMethodNames : false; //------------------------------------------------------------------------- // Helpers @@ -162,6 +166,27 @@ module.exports = { } } + /** + * Check if method declaration or method property has a underscore at the end + * @param {ASTNode} node node to evaluate + * @returns {void} + * @private + */ + function checkForTrailingUnderscoreInMethod(node) { + const identifier = node.key.name; + const isMethod = node.type === "MethodDefinition" || node.type === "Property" && node.method; + + if (typeof identifier !== "undefined" && enforceInMethodNames && isMethod && hasTrailingUnderscore(identifier)) { + context.report({ + node, + message: "Unexpected dangling '_' in '{{identifier}}'.", + data: { + identifier + } + }); + } + } + //-------------------------------------------------------------------------- // Public API //-------------------------------------------------------------------------- @@ -169,7 +194,9 @@ module.exports = { return { FunctionDeclaration: checkForTrailingUnderscoreInFunctionDeclaration, VariableDeclarator: checkForTrailingUnderscoreInVariableExpression, - MemberExpression: checkForTrailingUnderscoreInMemberExpression + MemberExpression: checkForTrailingUnderscoreInMemberExpression, + MethodDefinition: checkForTrailingUnderscoreInMethod, + Property: checkForTrailingUnderscoreInMethod }; } diff --git a/tests/lib/rules/no-underscore-dangle.js b/tests/lib/rules/no-underscore-dangle.js index 0f7a8ad4352..ba23575f35c 100644 --- a/tests/lib/rules/no-underscore-dangle.js +++ b/tests/lib/rules/no-underscore-dangle.js @@ -32,7 +32,13 @@ ruleTester.run("no-underscore-dangle", rule, { { code: "foo._bar;", options: [{ allow: ["_bar"] }] }, { code: "function _foo() {}", options: [{ allow: ["_foo"] }] }, { code: "this._bar;", options: [{ allowAfterThis: true }] }, - { code: "class foo { constructor() { super._bar; } }", parserOptions: { ecmaVersion: 6 }, options: [{ allowAfterSuper: true }] } + { code: "class foo { constructor() { super._bar; } }", parserOptions: { ecmaVersion: 6 }, options: [{ allowAfterSuper: true }] }, + { code: "class foo { _onClick() { } }", parserOptions: { ecmaVersion: 6 } }, + { code: "class foo { onClick_() { } }", parserOptions: { ecmaVersion: 6 } }, + { code: "const o = { _onClick() { } }", parserOptions: { ecmaVersion: 6 } }, + { code: "const o = { onClick_() { } }", parserOptions: { ecmaVersion: 6 } }, + { code: "const o = { _foo: 'bar' }", parserOptions: { ecmaVersion: 6 } }, + { code: "const o = { foo_: 'bar' }", parserOptions: { ecmaVersion: 6 } } ], invalid: [ { code: "var _foo = 1", errors: [{ message: "Unexpected dangling '_' in '_foo'.", type: "VariableDeclarator" }] }, @@ -43,6 +49,10 @@ ruleTester.run("no-underscore-dangle", rule, { { code: "foo._bar;", errors: [{ message: "Unexpected dangling '_' in '_bar'.", type: "MemberExpression" }] }, { code: "this._prop;", errors: [{ message: "Unexpected dangling '_' in '_prop'.", type: "MemberExpression" }] }, { code: "class foo { constructor() { super._prop; } }", parserOptions: { ecmaVersion: 6 }, errors: [{ message: "Unexpected dangling '_' in '_prop'.", type: "MemberExpression" }] }, - { code: "class foo { constructor() { this._prop; } }", options: [{ allowAfterSuper: true }], parserOptions: { ecmaVersion: 6 }, errors: [{ message: "Unexpected dangling '_' in '_prop'.", type: "MemberExpression" }] } + { code: "class foo { constructor() { this._prop; } }", options: [{ allowAfterSuper: true }], parserOptions: { ecmaVersion: 6 }, errors: [{ message: "Unexpected dangling '_' in '_prop'.", type: "MemberExpression" }] }, + { code: "class foo { _onClick() { } }", options: [{ enforceInMethodNames: true }], parserOptions: { ecmaVersion: 6 }, errors: [{ message: "Unexpected dangling '_' in '_onClick'.", type: "MethodDefinition" }] }, + { code: "class foo { onClick_() { } }", options: [{ enforceInMethodNames: true }], parserOptions: { ecmaVersion: 6 }, errors: [{ message: "Unexpected dangling '_' in 'onClick_'.", type: "MethodDefinition" }] }, + { code: "const o = { _onClick() { } }", options: [{ enforceInMethodNames: true }], parserOptions: { ecmaVersion: 6 }, errors: [{ message: "Unexpected dangling '_' in '_onClick'.", type: "Property" }] }, + { code: "const o = { onClick_() { } }", options: [{ enforceInMethodNames: true }], parserOptions: { ecmaVersion: 6 }, errors: [{ message: "Unexpected dangling '_' in 'onClick_'.", type: "Property" }] } ] });