Skip to content

Commit ab37d3b

Browse files
feat: add enforceInClassFields option to no-underscore-dangle (#15818)
* fix: no-underscore-dangle support for class fields (es2022) * resolving code review suggestions * resolving code review suggestions
1 parent 2dc8d15 commit ab37d3b

File tree

3 files changed

+87
-2
lines changed

3 files changed

+87
-2
lines changed

docs/src/rules/no-underscore-dangle.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ This rule has an object option:
5454
* `"allowAfterSuper": false` (default) disallows dangling underscores in members of the `super` object
5555
* `"allowAfterThisConstructor": false` (default) disallows dangling underscores in members of the `this.constructor` object
5656
* `"enforceInMethodNames": false` (default) allows dangling underscores in method names
57+
* `"enforceInClassFields": false` (default) allows dangling underscores in es2022 class fields names
5758
* `"allowFunctionParams": true` (default) allows dangling underscores in function parameter names
5859

5960
### allow
@@ -124,6 +125,34 @@ const o = {
124125
};
125126
```
126127

128+
### enforceInClassFields
129+
130+
Examples of **incorrect** code for this rule with the `{ "enforceInClassFields": true }` option:
131+
132+
```js
133+
/*eslint no-underscore-dangle: ["error", { "enforceInClassFields": true }]*/
134+
135+
class Foo {
136+
_bar;
137+
}
138+
139+
class Foo {
140+
_bar = () => {};
141+
}
142+
143+
class Foo {
144+
bar_;
145+
}
146+
147+
class Foo {
148+
#_bar;
149+
}
150+
151+
class Foo {
152+
#bar_;
153+
}
154+
```
155+
127156
### allowFunctionParams
128157

129158
Examples of **incorrect** code for this rule with the `{ "allowFunctionParams": false }` option:

lib/rules/no-underscore-dangle.js

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,10 @@ module.exports = {
4949
allowFunctionParams: {
5050
type: "boolean",
5151
default: true
52+
},
53+
enforceInClassFields: {
54+
type: "boolean",
55+
default: false
5256
}
5357
},
5458
additionalProperties: false
@@ -68,6 +72,7 @@ module.exports = {
6872
const allowAfterSuper = typeof options.allowAfterSuper !== "undefined" ? options.allowAfterSuper : false;
6973
const allowAfterThisConstructor = typeof options.allowAfterThisConstructor !== "undefined" ? options.allowAfterThisConstructor : false;
7074
const enforceInMethodNames = typeof options.enforceInMethodNames !== "undefined" ? options.enforceInMethodNames : false;
75+
const enforceInClassFields = typeof options.enforceInClassFields !== "undefined" ? options.enforceInClassFields : false;
7176
const allowFunctionParams = typeof options.allowFunctionParams !== "undefined" ? options.allowFunctionParams : true;
7277

7378
//-------------------------------------------------------------------------
@@ -261,6 +266,30 @@ module.exports = {
261266
}
262267
}
263268

269+
/**
270+
* Check if a class field has a dangling underscore
271+
* @param {ASTNode} node node to evaluate
272+
* @returns {void}
273+
* @private
274+
*/
275+
function checkForDanglingUnderscoreInClassField(node) {
276+
const identifier = node.key.name;
277+
278+
if (typeof identifier !== "undefined" && hasDanglingUnderscore(identifier) &&
279+
enforceInClassFields &&
280+
!isAllowed(identifier)) {
281+
context.report({
282+
node,
283+
messageId: "unexpectedUnderscore",
284+
data: {
285+
identifier: node.key.type === "PrivateIdentifier"
286+
? `#${identifier}`
287+
: identifier
288+
}
289+
});
290+
}
291+
}
292+
264293
//--------------------------------------------------------------------------
265294
// Public API
266295
//--------------------------------------------------------------------------
@@ -270,7 +299,7 @@ module.exports = {
270299
VariableDeclarator: checkForDanglingUnderscoreInVariableExpression,
271300
MemberExpression: checkForDanglingUnderscoreInMemberExpression,
272301
MethodDefinition: checkForDanglingUnderscoreInMethod,
273-
PropertyDefinition: checkForDanglingUnderscoreInMethod,
302+
PropertyDefinition: checkForDanglingUnderscoreInClassField,
274303
Property: checkForDanglingUnderscoreInMethod,
275304
FunctionExpression: checkForDanglingUnderscoreInFunction,
276305
ArrowFunctionExpression: checkForDanglingUnderscoreInFunction

tests/lib/rules/no-underscore-dangle.js

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,10 @@ ruleTester.run("no-underscore-dangle", rule, {
7171
{ code: "function foo( { _bar = 0 } = {}) {}", options: [{ allowFunctionParams: false }], parserOptions: { ecmaVersion: 6 } },
7272
{ code: "function foo(...[_bar]) {}", options: [{ allowFunctionParams: false }], parserOptions: { ecmaVersion: 2016 } },
7373
{ code: "class foo { _field; }", parserOptions: { ecmaVersion: 2022 } },
74-
{ code: "class foo { #_field; }", parserOptions: { ecmaVersion: 2022 } }
74+
{ code: "class foo { _field; }", options: [{ enforceInClassFields: false }], parserOptions: { ecmaVersion: 2022 } },
75+
{ code: "class foo { #_field; }", parserOptions: { ecmaVersion: 2022 } },
76+
{ code: "class foo { #_field; }", options: [{ enforceInClassFields: false }], parserOptions: { ecmaVersion: 2022 } },
77+
{ code: "class foo { _field; }", options: [{}], parserOptions: { ecmaVersion: 2022 } }
7578
],
7679
invalid: [
7780
{ code: "var _foo = 1", errors: [{ messageId: "unexpectedUnderscore", data: { identifier: "_foo" }, type: "VariableDeclarator" }] },
@@ -109,6 +112,30 @@ ruleTester.run("no-underscore-dangle", rule, {
109112
options: [{ enforceInMethodNames: true }],
110113
parserOptions: { ecmaVersion: 2022 },
111114
errors: [{ messageId: "unexpectedUnderscore", data: { identifier: "#bar_" } }]
115+
},
116+
{
117+
code: "class foo { _field; }",
118+
options: [{ enforceInClassFields: true }],
119+
parserOptions: { ecmaVersion: 2022 },
120+
errors: [{ messageId: "unexpectedUnderscore", data: { identifier: "_field" } }]
121+
},
122+
{
123+
code: "class foo { #_field; }",
124+
options: [{ enforceInClassFields: true }],
125+
parserOptions: { ecmaVersion: 2022 },
126+
errors: [{ messageId: "unexpectedUnderscore", data: { identifier: "#_field" } }]
127+
},
128+
{
129+
code: "class foo { field_; }",
130+
options: [{ enforceInClassFields: true }],
131+
parserOptions: { ecmaVersion: 2022 },
132+
errors: [{ messageId: "unexpectedUnderscore", data: { identifier: "field_" } }]
133+
},
134+
{
135+
code: "class foo { #field_; }",
136+
options: [{ enforceInClassFields: true }],
137+
parserOptions: { ecmaVersion: 2022 },
138+
errors: [{ messageId: "unexpectedUnderscore", data: { identifier: "#field_" } }]
112139
}
113140
]
114141
});

0 commit comments

Comments
 (0)