diff --git a/docs/src/rules/no-underscore-dangle.md b/docs/src/rules/no-underscore-dangle.md index 73b13244602..15f082629e5 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 0ab41feb03c..55fb9b8cfbc 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; + + if (typeof identifier !== "undefined" && hasDanglingUnderscore(identifier) && + enforceInClassFields && + !isAllowed(identifier)) { + context.report({ + node, + messageId: "unexpectedUnderscore", + data: { + identifier: node.key.type === "PrivateIdentifier" + ? `#${identifier}` + : 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 c83a5b3fe28..f3e11cc3e76 100644 --- a/tests/lib/rules/no-underscore-dangle.js +++ b/tests/lib/rules/no-underscore-dangle.js @@ -71,7 +71,10 @@ 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 } }, + { code: "class foo { _field; }", options: [{}], parserOptions: { ecmaVersion: 2022 } } ], invalid: [ { code: "var _foo = 1", errors: [{ messageId: "unexpectedUnderscore", data: { identifier: "_foo" }, type: "VariableDeclarator" }] }, @@ -109,6 +112,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_" } }] } ] });