@@ -26,10 +26,73 @@ function normalizeIgnoreValue(x) {
2626 return x ;
2727}
2828
29+ /**
30+ * Checks if the node parent is a TypeScript enum member
31+ * @param {ASTNode } node The node to be validated
32+ * @returns {boolean } True if the node parent is a TypeScript enum member
33+ */
34+ function isParentTSEnumDeclaration ( node ) {
35+ return node . parent . type === "TSEnumMember" ;
36+ }
37+
38+ /**
39+ * Checks if the node is a valid TypeScript numeric literal type.
40+ * @param {ASTNode } node The node to be validated
41+ * @returns {boolean } True if the node is a TypeScript numeric literal type
42+ */
43+ function isTSNumericLiteralType ( node ) {
44+ let ancestor = node . parent ;
45+
46+ // Go up while we're part of a type union
47+ while ( ancestor . parent . type === "TSUnionType" ) {
48+ ancestor = ancestor . parent ;
49+ }
50+
51+ // Check if the final ancestor is in a type alias declaration
52+ return ancestor . parent . type === "TSTypeAliasDeclaration" ;
53+ }
54+
55+ /**
56+ * Checks if the node parent is a readonly class property
57+ * @param {ASTNode } node The node to be validated
58+ * @returns {boolean } True if the node parent is a readonly class property
59+ */
60+ function isParentTSReadonlyPropertyDefinition ( node ) {
61+ if ( node . parent ?. type === "PropertyDefinition" && node . parent . readonly ) {
62+ return true ;
63+ }
64+
65+ return false ;
66+ }
67+
68+ /**
69+ * Checks if the node is part of a type indexed access (eg. Foo[4])
70+ * @param {ASTNode } node The node to be validated
71+ * @returns {boolean } True if the node is part of an indexed access
72+ */
73+ function isAncestorTSIndexedAccessType ( node ) {
74+ let ancestor = node . parent ;
75+
76+ /*
77+ * Go up another level while we're part of a type union (eg. 1 | 2) or
78+ * intersection (eg. 1 & 2)
79+ */
80+ while (
81+ ancestor . parent . type === "TSUnionType" ||
82+ ancestor . parent . type === "TSIntersectionType"
83+ ) {
84+ ancestor = ancestor . parent ;
85+ }
86+
87+ return ancestor . parent . type === "TSIndexedAccessType" ;
88+ }
89+
2990/** @type {import('../types').Rule.RuleModule } */
3091module . exports = {
3192 meta : {
3293 type : "suggestion" ,
94+ dialects : [ "typescript" , "javascript" ] ,
95+ language : "javascript" ,
3396
3497 docs : {
3598 description : "Disallow magic numbers" ,
@@ -75,6 +138,22 @@ module.exports = {
75138 type : "boolean" ,
76139 default : false ,
77140 } ,
141+ ignoreEnums : {
142+ type : "boolean" ,
143+ default : false ,
144+ } ,
145+ ignoreNumericLiteralTypes : {
146+ type : "boolean" ,
147+ default : false ,
148+ } ,
149+ ignoreReadonlyClassProperties : {
150+ type : "boolean" ,
151+ default : false ,
152+ } ,
153+ ignoreTypeIndexes : {
154+ type : "boolean" ,
155+ default : false ,
156+ } ,
78157 } ,
79158 additionalProperties : false ,
80159 } ,
@@ -94,7 +173,12 @@ module.exports = {
94173 ignoreArrayIndexes = ! ! config . ignoreArrayIndexes ,
95174 ignoreDefaultValues = ! ! config . ignoreDefaultValues ,
96175 ignoreClassFieldInitialValues =
97- ! ! config . ignoreClassFieldInitialValues ;
176+ ! ! config . ignoreClassFieldInitialValues ,
177+ ignoreEnums = ! ! config . ignoreEnums ,
178+ ignoreNumericLiteralTypes = ! ! config . ignoreNumericLiteralTypes ,
179+ ignoreReadonlyClassProperties =
180+ ! ! config . ignoreReadonlyClassProperties ,
181+ ignoreTypeIndexes = ! ! config . ignoreTypeIndexes ;
98182
99183 const okTypes = detectObjects
100184 ? [ ]
@@ -217,14 +301,15 @@ module.exports = {
217301 let value ;
218302 let raw ;
219303
220- // Treat unary minus as a part of the number
304+ // Treat unary minus/plus as a part of the number
221305 if (
222306 node . parent . type === "UnaryExpression" &&
223- node . parent . operator === "-"
307+ [ "-" , "+" ] . includes ( node . parent . operator )
224308 ) {
225309 fullNumberNode = node . parent ;
226- value = - node . value ;
227- raw = `-${ node . raw } ` ;
310+ value =
311+ node . parent . operator === "-" ? - node . value : node . value ;
312+ raw = `${ node . parent . operator } ${ node . raw } ` ;
228313 } else {
229314 fullNumberNode = node ;
230315 value = node . value ;
@@ -239,6 +324,14 @@ module.exports = {
239324 ( ignoreDefaultValues && isDefaultValue ( fullNumberNode ) ) ||
240325 ( ignoreClassFieldInitialValues &&
241326 isClassFieldInitialValue ( fullNumberNode ) ) ||
327+ ( ignoreEnums &&
328+ isParentTSEnumDeclaration ( fullNumberNode ) ) ||
329+ ( ignoreNumericLiteralTypes &&
330+ isTSNumericLiteralType ( fullNumberNode ) ) ||
331+ ( ignoreTypeIndexes &&
332+ isAncestorTSIndexedAccessType ( fullNumberNode ) ) ||
333+ ( ignoreReadonlyClassProperties &&
334+ isParentTSReadonlyPropertyDefinition ( fullNumberNode ) ) ||
242335 isParseIntRadix ( fullNumberNode ) ||
243336 isJSXNumber ( fullNumberNode ) ||
244337 ( ignoreArrayIndexes && isArrayIndex ( fullNumberNode , value ) )
0 commit comments