From c4aa2ce070f25e52efd827c181949a85976a41ac Mon Sep 17 00:00:00 2001 From: Roberto Cestari Date: Thu, 28 Apr 2022 08:27:07 -0300 Subject: [PATCH] fix: no-underscore-dangle support for private and public class fields from es2022 --- docs/src/rules/no-underscore-dangle.md | 29 +++++++++++++++++++++++ lib/rules/no-underscore-dangle.js | 31 ++++++++++++++++++++++++- tests/lib/rules/no-underscore-dangle.js | 28 +++++++++++++++++++++- 3 files changed, 86 insertions(+), 2 deletions(-) diff --git a/docs/src/rules/no-underscore-dangle.md b/docs/src/rules/no-underscore-dangle.md index 73b13244602e..15f082629e5f 100644 --- a/docs/src/rules/no-underscore-dangle.md +++ b/docs/src/rules/no-underscore-dangle.md @@ -54,6 +54,7 @@ This rule has an object option: * `"allowAfterSuper": false` (default) disallows dangling underscores in members of the `super` object * `"allowAfterThisConstructor": false` (default) disallows dangling underscores in members of the `this.constructor` object * `"enforceInMethodNames": false` (default) allows dangling underscores in method names +* `"enforceInClassFields": false` (default) allows dangling underscores in es2022 class fields names * `"allowFunctionParams": true` (default) allows dangling underscores in function parameter names ### allow @@ -124,6 +125,34 @@ const o = { }; ``` +### enforceInClassFields + +Examples of **incorrect** code for this rule with the `{ "enforceInClassFields": true }` option: + +```js +/*eslint no-underscore-dangle: ["error", { "enforceInClassFields": true }]*/ + +class Foo { + _bar; +} + +class Foo { + _bar = () => {}; +} + +class Foo { + bar_; +} + +class Foo { + #_bar; +} + +class Foo { + #bar_; +} +``` + ### allowFunctionParams Examples of **incorrect** code for this rule with the `{ "allowFunctionParams": false }` option: diff --git a/lib/rules/no-underscore-dangle.js b/lib/rules/no-underscore-dangle.js index 0ab41feb03c2..0acfa84409b7 100644 --- a/lib/rules/no-underscore-dangle.js +++ b/lib/rules/no-underscore-dangle.js @@ -49,6 +49,10 @@ module.exports = { allowFunctionParams: { type: "boolean", default: true + }, + enforceInClassFields: { + type: "boolean", + default: false } }, additionalProperties: false @@ -68,6 +72,7 @@ module.exports = { const allowAfterSuper = typeof options.allowAfterSuper !== "undefined" ? options.allowAfterSuper : false; const allowAfterThisConstructor = typeof options.allowAfterThisConstructor !== "undefined" ? options.allowAfterThisConstructor : false; const enforceInMethodNames = typeof options.enforceInMethodNames !== "undefined" ? options.enforceInMethodNames : false; + const enforceInClassFields = typeof options.enforceInClassFields !== "undefined" ? options.enforceInClassFields : false; const allowFunctionParams = typeof options.allowFunctionParams !== "undefined" ? options.allowFunctionParams : true; //------------------------------------------------------------------------- @@ -261,6 +266,30 @@ module.exports = { } } + /** + * Check if a class field has a dangling underscore + * @param {ASTNode} node node to evaluate + * @returns {void} + * @private + */ + function checkForDanglingUnderscoreInClassField(node) { + const identifier = node.key.name; + const isClassField = node.type === "PropertyDefinition" && node.parent && node.parent.type === "ClassBody"; + + if (typeof identifier !== "undefined" && hasDanglingUnderscore(identifier) && + isClassField && + enforceInClassFields && + !isAllowed(identifier)) { + context.report({ + node, + messageId: "unexpectedUnderscore", + data: { + identifier + } + }); + } + } + //-------------------------------------------------------------------------- // Public API //-------------------------------------------------------------------------- @@ -270,7 +299,7 @@ module.exports = { VariableDeclarator: checkForDanglingUnderscoreInVariableExpression, MemberExpression: checkForDanglingUnderscoreInMemberExpression, MethodDefinition: checkForDanglingUnderscoreInMethod, - PropertyDefinition: checkForDanglingUnderscoreInMethod, + PropertyDefinition: checkForDanglingUnderscoreInClassField, Property: checkForDanglingUnderscoreInMethod, FunctionExpression: checkForDanglingUnderscoreInFunction, ArrowFunctionExpression: checkForDanglingUnderscoreInFunction diff --git a/tests/lib/rules/no-underscore-dangle.js b/tests/lib/rules/no-underscore-dangle.js index c83a5b3fe284..6446c761ee4d 100644 --- a/tests/lib/rules/no-underscore-dangle.js +++ b/tests/lib/rules/no-underscore-dangle.js @@ -71,7 +71,9 @@ ruleTester.run("no-underscore-dangle", rule, { { code: "function foo( { _bar = 0 } = {}) {}", options: [{ allowFunctionParams: false }], parserOptions: { ecmaVersion: 6 } }, { code: "function foo(...[_bar]) {}", options: [{ allowFunctionParams: false }], parserOptions: { ecmaVersion: 2016 } }, { code: "class foo { _field; }", parserOptions: { ecmaVersion: 2022 } }, - { code: "class foo { #_field; }", parserOptions: { ecmaVersion: 2022 } } + { code: "class foo { _field; }", options: [{ enforceInClassFields: false }], parserOptions: { ecmaVersion: 2022 } }, + { code: "class foo { #_field; }", parserOptions: { ecmaVersion: 2022 } }, + { code: "class foo { #_field; }", options: [{ enforceInClassFields: false }], parserOptions: { ecmaVersion: 2022 } } ], invalid: [ { code: "var _foo = 1", errors: [{ messageId: "unexpectedUnderscore", data: { identifier: "_foo" }, type: "VariableDeclarator" }] }, @@ -109,6 +111,30 @@ ruleTester.run("no-underscore-dangle", rule, { options: [{ enforceInMethodNames: true }], parserOptions: { ecmaVersion: 2022 }, errors: [{ messageId: "unexpectedUnderscore", data: { identifier: "#bar_" } }] + }, + { + code: "class foo { _field; }", + options: [{ enforceInClassFields: true }], + parserOptions: { ecmaVersion: 2022 }, + errors: [{ messageId: "unexpectedUnderscore", data: { identifier: "_field" } }] + }, + { + code: "class foo { #_field; }", + options: [{ enforceInClassFields: true }], + parserOptions: { ecmaVersion: 2022 }, + errors: [{ messageId: "unexpectedUnderscore", data: { identifier: "_field" } }] + }, + { + code: "class foo { field_; }", + options: [{ enforceInClassFields: true }], + parserOptions: { ecmaVersion: 2022 }, + errors: [{ messageId: "unexpectedUnderscore", data: { identifier: "field_" } }] + }, + { + code: "class foo { #field_; }", + options: [{ enforceInClassFields: true }], + parserOptions: { ecmaVersion: 2022 }, + errors: [{ messageId: "unexpectedUnderscore", data: { identifier: "field_" } }] } ] });