Skip to content

Commit 63bce44

Browse files
authored
feat: add ignoreClassFieldInitialValues option to no-magic-numbers (#16539)
Fixes #16228
1 parent c50ae4f commit 63bce44

3 files changed

Lines changed: 166 additions & 1 deletion

File tree

docs/src/rules/no-magic-numbers.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,45 @@ let head;
193193

194194
:::
195195

196+
### ignoreClassFieldInitialValues
197+
198+
A boolean to specify if numbers used as initial values of class fields are considered okay. `false` by default.
199+
200+
Examples of **correct** code for the `{ "ignoreClassFieldInitialValues": true }` option:
201+
202+
::: correct
203+
204+
```js
205+
/*eslint no-magic-numbers: ["error", { "ignoreClassFieldInitialValues": true }]*/
206+
207+
class C {
208+
foo = 2;
209+
bar = -3;
210+
#baz = 4;
211+
static qux = 5;
212+
}
213+
```
214+
215+
:::
216+
217+
Examples of **incorrect** code for the `{ "ignoreClassFieldInitialValues": true }` option:
218+
219+
::: incorrect
220+
221+
```js
222+
/*eslint no-magic-numbers: ["error", { "ignoreClassFieldInitialValues": true }]*/
223+
224+
class C {
225+
foo = 2 + 3;
226+
}
227+
228+
class D {
229+
2;
230+
}
231+
```
232+
233+
:::
234+
196235
### enforceConst
197236

198237
A boolean to specify if we should check for the const keyword in variable declaration of numbers. `false` by default.

lib/rules/no-magic-numbers.js

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,10 @@ module.exports = {
6565
ignoreDefaultValues: {
6666
type: "boolean",
6767
default: false
68+
},
69+
ignoreClassFieldInitialValues: {
70+
type: "boolean",
71+
default: false
6872
}
6973
},
7074
additionalProperties: false
@@ -82,7 +86,8 @@ module.exports = {
8286
enforceConst = !!config.enforceConst,
8387
ignore = new Set((config.ignore || []).map(normalizeIgnoreValue)),
8488
ignoreArrayIndexes = !!config.ignoreArrayIndexes,
85-
ignoreDefaultValues = !!config.ignoreDefaultValues;
89+
ignoreDefaultValues = !!config.ignoreDefaultValues,
90+
ignoreClassFieldInitialValues = !!config.ignoreClassFieldInitialValues;
8691

8792
const okTypes = detectObjects ? [] : ["ObjectExpression", "Property", "AssignmentExpression"];
8893

@@ -106,6 +111,17 @@ module.exports = {
106111
return parent.type === "AssignmentPattern" && parent.right === fullNumberNode;
107112
}
108113

114+
/**
115+
* Returns whether the number is the initial value of a class field.
116+
* @param {ASTNode} fullNumberNode `Literal` or `UnaryExpression` full number node
117+
* @returns {boolean} true if the number is the initial value of a class field.
118+
*/
119+
function isClassFieldInitialValue(fullNumberNode) {
120+
const parent = fullNumberNode.parent;
121+
122+
return parent.type === "PropertyDefinition" && parent.value === fullNumberNode;
123+
}
124+
109125
/**
110126
* Returns whether the given node is used as a radix within parseInt() or Number.parseInt()
111127
* @param {ASTNode} fullNumberNode `Literal` or `UnaryExpression` full number node
@@ -194,6 +210,7 @@ module.exports = {
194210
if (
195211
isIgnoredValue(value) ||
196212
(ignoreDefaultValues && isDefaultValue(fullNumberNode)) ||
213+
(ignoreClassFieldInitialValues && isClassFieldInitialValue(fullNumberNode)) ||
197214
isParseIntRadix(fullNumberNode) ||
198215
isJSXNumber(fullNumberNode) ||
199216
(ignoreArrayIndexes && isArrayIndex(fullNumberNode, value))

tests/lib/rules/no-magic-numbers.js

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,33 @@ ruleTester.run("no-magic-numbers", rule, {
257257
code: "foo?.[777]",
258258
options: [{ ignoreArrayIndexes: true }],
259259
parserOptions: { ecmaVersion: 2020 }
260+
},
261+
262+
// ignoreClassFieldInitialValues
263+
{
264+
code: "class C { foo = 2; }",
265+
options: [{ ignoreClassFieldInitialValues: true }],
266+
parserOptions: { ecmaVersion: 2022 }
267+
},
268+
{
269+
code: "class C { foo = -2; }",
270+
options: [{ ignoreClassFieldInitialValues: true }],
271+
parserOptions: { ecmaVersion: 2022 }
272+
},
273+
{
274+
code: "class C { static foo = 2; }",
275+
options: [{ ignoreClassFieldInitialValues: true }],
276+
parserOptions: { ecmaVersion: 2022 }
277+
},
278+
{
279+
code: "class C { #foo = 2; }",
280+
options: [{ ignoreClassFieldInitialValues: true }],
281+
parserOptions: { ecmaVersion: 2022 }
282+
},
283+
{
284+
code: "class C { static #foo = 2; }",
285+
options: [{ ignoreClassFieldInitialValues: true }],
286+
parserOptions: { ecmaVersion: 2022 }
260287
}
261288
],
262289
invalid: [
@@ -812,6 +839,88 @@ ruleTester.run("no-magic-numbers", rule, {
812839
{ messageId: "noMagic", data: { raw: "1" }, line: 1 },
813840
{ messageId: "noMagic", data: { raw: "2" }, line: 1 }
814841
]
842+
},
843+
844+
// ignoreClassFieldInitialValues
845+
{
846+
code: "class C { foo = 2; }",
847+
parserOptions: { ecmaVersion: 2022 },
848+
errors: [
849+
{ messageId: "noMagic", data: { raw: "2" }, line: 1, column: 17 }
850+
]
851+
},
852+
{
853+
code: "class C { foo = 2; }",
854+
options: [{}],
855+
parserOptions: { ecmaVersion: 2022 },
856+
errors: [
857+
{ messageId: "noMagic", data: { raw: "2" }, line: 1, column: 17 }
858+
]
859+
},
860+
{
861+
code: "class C { foo = 2; }",
862+
options: [{ ignoreClassFieldInitialValues: false }],
863+
parserOptions: { ecmaVersion: 2022 },
864+
errors: [
865+
{ messageId: "noMagic", data: { raw: "2" }, line: 1, column: 17 }
866+
]
867+
},
868+
{
869+
code: "class C { foo = -2; }",
870+
options: [{ ignoreClassFieldInitialValues: false }],
871+
parserOptions: { ecmaVersion: 2022 },
872+
errors: [
873+
{ messageId: "noMagic", data: { raw: "-2" }, line: 1, column: 17 }
874+
]
875+
},
876+
{
877+
code: "class C { static foo = 2; }",
878+
options: [{ ignoreClassFieldInitialValues: false }],
879+
parserOptions: { ecmaVersion: 2022 },
880+
errors: [
881+
{ messageId: "noMagic", data: { raw: "2" }, line: 1, column: 24 }
882+
]
883+
},
884+
{
885+
code: "class C { #foo = 2; }",
886+
options: [{ ignoreClassFieldInitialValues: false }],
887+
parserOptions: { ecmaVersion: 2022 },
888+
errors: [
889+
{ messageId: "noMagic", data: { raw: "2" }, line: 1, column: 18 }
890+
]
891+
},
892+
{
893+
code: "class C { static #foo = 2; }",
894+
options: [{ ignoreClassFieldInitialValues: false }],
895+
parserOptions: { ecmaVersion: 2022 },
896+
errors: [
897+
{ messageId: "noMagic", data: { raw: "2" }, line: 1, column: 25 }
898+
]
899+
},
900+
{
901+
code: "class C { foo = 2 + 3; }",
902+
options: [{ ignoreClassFieldInitialValues: true }],
903+
parserOptions: { ecmaVersion: 2022 },
904+
errors: [
905+
{ messageId: "noMagic", data: { raw: "2" }, line: 1, column: 17 },
906+
{ messageId: "noMagic", data: { raw: "3" }, line: 1, column: 21 }
907+
]
908+
},
909+
{
910+
code: "class C { 2; }",
911+
options: [{ ignoreClassFieldInitialValues: true }],
912+
parserOptions: { ecmaVersion: 2022 },
913+
errors: [
914+
{ messageId: "noMagic", data: { raw: "2" }, line: 1, column: 11 }
915+
]
916+
},
917+
{
918+
code: "class C { [2]; }",
919+
options: [{ ignoreClassFieldInitialValues: true }],
920+
parserOptions: { ecmaVersion: 2022 },
921+
errors: [
922+
{ messageId: "noMagic", data: { raw: "2" }, line: 1, column: 12 }
923+
]
815924
}
816925
]
817926
});

0 commit comments

Comments
 (0)