eslint 9.27.0 → 9.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  /**
2
- * @fileoverview The event generator for AST nodes.
3
- * @author Toru Nagashima
2
+ * @fileoverview Traverser for SourceCode objects.
3
+ * @author Nicholas C. Zakas
4
4
  */
5
5
 
6
6
  "use strict";
@@ -10,6 +10,7 @@
10
10
  //------------------------------------------------------------------------------
11
11
 
12
12
  const { parse, matches } = require("./esquery");
13
+ const vk = require("eslint-visitor-keys");
13
14
 
14
15
  //-----------------------------------------------------------------------------
15
16
  // Typedefs
@@ -17,12 +18,16 @@ const { parse, matches } = require("./esquery");
17
18
 
18
19
  /**
19
20
  * @import { ESQueryParsedSelector } from "./esquery.js";
21
+ * @import { Language, SourceCode } from "@eslint/core";
20
22
  */
21
23
 
22
24
  //-----------------------------------------------------------------------------
23
25
  // Helpers
24
26
  //-----------------------------------------------------------------------------
25
27
 
28
+ const STEP_KIND_VISIT = 1;
29
+ const STEP_KIND_CALL = 2;
30
+
26
31
  /**
27
32
  * Compares two ESQuery selectors by specificity.
28
33
  * @param {ESQueryParsedSelector} a The first selector to compare.
@@ -33,69 +38,10 @@ function compareSpecificity(a, b) {
33
38
  return a.compare(b);
34
39
  }
35
40
 
36
- //------------------------------------------------------------------------------
37
- // Public Interface
38
- //------------------------------------------------------------------------------
39
-
40
41
  /**
41
- * The event generator for AST nodes.
42
- * This implements below interface.
43
- *
44
- * ```ts
45
- * interface EventGenerator {
46
- * emitter: SafeEmitter;
47
- * enterNode(node: ASTNode): void;
48
- * leaveNode(node: ASTNode): void;
49
- * }
50
- * ```
42
+ * Helper to wrap ESQuery operations.
51
43
  */
52
- class NodeEventGenerator {
53
- /**
54
- * The emitter to use during traversal.
55
- * @type {SafeEmitter}
56
- */
57
- emitter;
58
-
59
- /**
60
- * The options for `esquery` to use during matching.
61
- * @type {ESQueryOptions}
62
- */
63
- esqueryOptions;
64
-
65
- /**
66
- * The ancestry of the currently visited node.
67
- * @type {ASTNode[]}
68
- */
69
- currentAncestry = [];
70
-
71
- /**
72
- * A map of node type to selectors targeting that node type on the
73
- * enter phase of traversal.
74
- * @type {Map<string, ESQueryParsedSelector[]>}
75
- */
76
- enterSelectorsByNodeType = new Map();
77
-
78
- /**
79
- * A map of node type to selectors targeting that node type on the
80
- * exit phase of traversal.
81
- * @type {Map<string, ESQueryParsedSelector[]>}
82
- */
83
- exitSelectorsByNodeType = new Map();
84
-
85
- /**
86
- * An array of selectors that match any node type on the
87
- * enter phase of traversal.
88
- * @type {ESQueryParsedSelector[]}
89
- */
90
- anyTypeEnterSelectors = [];
91
-
92
- /**
93
- * An array of selectors that match any node type on the
94
- * exit phase of traversal.
95
- * @type {ESQueryParsedSelector[]}
96
- */
97
- anyTypeExitSelectors = [];
98
-
44
+ class ESQueryHelper {
99
45
  /**
100
46
  * @param {SafeEmitter} emitter
101
47
  * An SafeEmitter which is the destination of events. This emitter must already
@@ -105,9 +51,46 @@ class NodeEventGenerator {
105
51
  * @returns {NodeEventGenerator} new instance
106
52
  */
107
53
  constructor(emitter, esqueryOptions) {
54
+ /**
55
+ * The emitter to use during traversal.
56
+ * @type {SafeEmitter}
57
+ */
108
58
  this.emitter = emitter;
59
+
60
+ /**
61
+ * The options for `esquery` to use during matching.
62
+ * @type {ESQueryOptions}
63
+ */
109
64
  this.esqueryOptions = esqueryOptions;
110
65
 
66
+ /**
67
+ * A map of node type to selectors targeting that node type on the
68
+ * enter phase of traversal.
69
+ * @type {Map<string, ESQueryParsedSelector[]>}
70
+ */
71
+ this.enterSelectorsByNodeType = new Map();
72
+
73
+ /**
74
+ * A map of node type to selectors targeting that node type on the
75
+ * exit phase of traversal.
76
+ * @type {Map<string, ESQueryParsedSelector[]>}
77
+ */
78
+ this.exitSelectorsByNodeType = new Map();
79
+
80
+ /**
81
+ * An array of selectors that match any node type on the
82
+ * enter phase of traversal.
83
+ * @type {ESQueryParsedSelector[]}
84
+ */
85
+ this.anyTypeEnterSelectors = [];
86
+
87
+ /**
88
+ * An array of selectors that match any node type on the
89
+ * exit phase of traversal.
90
+ * @type {ESQueryParsedSelector[]}
91
+ */
92
+ this.anyTypeExitSelectors = [];
93
+
111
94
  emitter.eventNames().forEach(rawSelector => {
112
95
  const selector = parse(rawSelector);
113
96
 
@@ -156,18 +139,12 @@ class NodeEventGenerator {
156
139
  /**
157
140
  * Checks a selector against a node, and emits it if it matches
158
141
  * @param {ASTNode} node The node to check
142
+ * @param {ASTNode[]} ancestry The ancestry of the node being checked.
159
143
  * @param {ESQueryParsedSelector} selector An AST selector descriptor
160
144
  * @returns {void}
161
145
  */
162
- applySelector(node, selector) {
163
- if (
164
- matches(
165
- node,
166
- selector.root,
167
- this.currentAncestry,
168
- this.esqueryOptions,
169
- )
170
- ) {
146
+ #applySelector(node, ancestry, selector) {
147
+ if (matches(node, selector.root, ancestry, this.esqueryOptions)) {
171
148
  this.emitter.emit(selector.source, node);
172
149
  }
173
150
  }
@@ -175,10 +152,11 @@ class NodeEventGenerator {
175
152
  /**
176
153
  * Applies all appropriate selectors to a node, in specificity order
177
154
  * @param {ASTNode} node The node to check
155
+ * @param {ASTNode[]} ancestry The ancestry of the node being checked.
178
156
  * @param {boolean} isExit `false` if the node is currently being entered, `true` if it's currently being exited
179
157
  * @returns {void}
180
158
  */
181
- applySelectors(node, isExit) {
159
+ applySelectors(node, ancestry, isExit) {
182
160
  const nodeTypeKey = this.esqueryOptions?.nodeTypeKey || "type";
183
161
 
184
162
  /*
@@ -218,39 +196,117 @@ class NodeEventGenerator {
218
196
  selectorsByNodeType[selectorsByNodeTypeIndex],
219
197
  ) < 0)
220
198
  ) {
221
- this.applySelector(
199
+ this.#applySelector(
222
200
  node,
201
+ ancestry,
223
202
  anyTypeSelectors[anyTypeSelectorsIndex++],
224
203
  );
225
204
  } else {
226
205
  // otherwise apply the node type selector
227
- this.applySelector(
206
+ this.#applySelector(
228
207
  node,
208
+ ancestry,
229
209
  selectorsByNodeType[selectorsByNodeTypeIndex++],
230
210
  );
231
211
  }
232
212
  }
233
213
  }
214
+ }
215
+
216
+ //------------------------------------------------------------------------------
217
+ // Public Interface
218
+ //------------------------------------------------------------------------------
234
219
 
220
+ /**
221
+ * Traverses source code and ensures that visitor methods are called when
222
+ * entering and leaving each node.
223
+ */
224
+ class SourceCodeTraverser {
235
225
  /**
236
- * Emits an event of entering AST node.
237
- * @param {ASTNode} node A node which was entered.
238
- * @returns {void}
226
+ * The language of the source code being traversed.
227
+ * @type {Language}
228
+ */
229
+ #language;
230
+
231
+ /**
232
+ * Map of languages to instances of this class.
233
+ * @type {WeakMap<Language, SourceCodeTraverser>}
234
+ */
235
+ static instances = new WeakMap();
236
+
237
+ /**
238
+ * Creates a new instance.
239
+ * @param {Language} language The language of the source code being traversed.
239
240
  */
240
- enterNode(node) {
241
- this.applySelectors(node, false);
242
- this.currentAncestry.unshift(node);
241
+ constructor(language) {
242
+ this.#language = language;
243
+ }
244
+
245
+ static getInstance(language) {
246
+ if (!this.instances.has(language)) {
247
+ this.instances.set(language, new this(language));
248
+ }
249
+
250
+ return this.instances.get(language);
243
251
  }
244
252
 
245
253
  /**
246
- * Emits an event of leaving AST node.
247
- * @param {ASTNode} node A node which was left.
254
+ * Traverses the given source code synchronously.
255
+ * @param {SourceCode} sourceCode The source code to traverse.
256
+ * @param {SafeEmitter} emitter The emitter to use for events.
257
+ * @param {Object} options Options for traversal.
258
+ * @param {ReturnType<SourceCode["traverse"]>} options.steps The steps to take during traversal.
248
259
  * @returns {void}
260
+ * @throws {Error} If an error occurs during traversal.
249
261
  */
250
- leaveNode(node) {
251
- this.currentAncestry.shift();
252
- this.applySelectors(node, true);
262
+ traverseSync(sourceCode, emitter, { steps } = {}) {
263
+ const esquery = new ESQueryHelper(emitter, {
264
+ visitorKeys: sourceCode.visitorKeys ?? this.#language.visitorKeys,
265
+ fallback: vk.getKeys,
266
+ matchClass: this.#language.matchesSelectorClass ?? (() => false),
267
+ nodeTypeKey: this.#language.nodeTypeKey,
268
+ });
269
+
270
+ const currentAncestry = [];
271
+
272
+ for (const step of steps ?? sourceCode.traverse()) {
273
+ switch (step.kind) {
274
+ case STEP_KIND_VISIT: {
275
+ try {
276
+ if (step.phase === 1) {
277
+ esquery.applySelectors(
278
+ step.target,
279
+ currentAncestry,
280
+ false,
281
+ );
282
+ currentAncestry.unshift(step.target);
283
+ } else {
284
+ currentAncestry.shift();
285
+ esquery.applySelectors(
286
+ step.target,
287
+ currentAncestry,
288
+ true,
289
+ );
290
+ }
291
+ } catch (err) {
292
+ err.currentNode = step.target;
293
+ throw err;
294
+ }
295
+ break;
296
+ }
297
+
298
+ case STEP_KIND_CALL: {
299
+ emitter.emit(step.target, ...step.args);
300
+ break;
301
+ }
302
+
303
+ default:
304
+ throw new Error(
305
+ `Invalid traversal step found: "${step.kind}".`,
306
+ );
307
+ }
308
+ }
253
309
  }
254
310
  }
255
311
 
256
- module.exports = NodeEventGenerator;
312
+ module.exports = { SourceCodeTraverser };
package/lib/options.js CHANGED
@@ -66,6 +66,7 @@ const optionator = require("optionator");
66
66
  * @property {string[]} [suppressRule] Suppress specific rules
67
67
  * @property {string} [suppressionsLocation] Path to the suppressions file or directory
68
68
  * @property {boolean} [pruneSuppressions] Prune unused suppressions
69
+ * @property {boolean} [passOnUnprunedSuppressions] Ignore unused suppressions
69
70
  */
70
71
 
71
72
  //------------------------------------------------------------------------------
@@ -449,6 +450,12 @@ module.exports = function (usingFlatConfig) {
449
450
  default: "false",
450
451
  description: "Prune unused suppressions",
451
452
  },
453
+ {
454
+ option: "pass-on-unpruned-suppressions",
455
+ type: "Boolean",
456
+ default: "false",
457
+ description: "Ignore unused suppressions",
458
+ },
452
459
  {
453
460
  heading: "Miscellaneous",
454
461
  },
@@ -11,12 +11,15 @@
11
11
  /** @type {import('../types').Rule.RuleModule} */
12
12
  module.exports = {
13
13
  meta: {
14
+ dialects: ["javascript", "typescript"],
15
+ language: "javascript",
14
16
  type: "suggestion",
15
17
 
16
18
  defaultOptions: [
17
19
  "expression",
18
20
  {
19
21
  allowArrowFunctions: false,
22
+ allowTypeAnnotation: false,
20
23
  overrides: {},
21
24
  },
22
25
  ],
@@ -39,6 +42,9 @@ module.exports = {
39
42
  allowArrowFunctions: {
40
43
  type: "boolean",
41
44
  },
45
+ allowTypeAnnotation: {
46
+ type: "boolean",
47
+ },
42
48
  overrides: {
43
49
  type: "object",
44
50
  properties: {
@@ -60,11 +66,49 @@ module.exports = {
60
66
  },
61
67
 
62
68
  create(context) {
63
- const [style, { allowArrowFunctions, overrides }] = context.options;
69
+ const [style, { allowArrowFunctions, allowTypeAnnotation, overrides }] =
70
+ context.options;
64
71
  const enforceDeclarations = style === "declaration";
65
72
  const { namedExports: exportFunctionStyle } = overrides;
66
73
  const stack = [];
67
74
 
75
+ /**
76
+ * Checks if a function declaration is part of an overloaded function
77
+ * @param {ASTNode} node The function declaration node to check
78
+ * @returns {boolean} True if the function is overloaded
79
+ */
80
+ function isOverloadedFunction(node) {
81
+ const functionName = node.id.name;
82
+
83
+ if (node.parent.type === "ExportNamedDeclaration") {
84
+ return node.parent.parent.body.some(
85
+ member =>
86
+ member.type === "ExportNamedDeclaration" &&
87
+ member.declaration?.type === "TSDeclareFunction" &&
88
+ member.declaration.id.name === functionName,
89
+ );
90
+ }
91
+
92
+ if (node.parent.type === "SwitchCase") {
93
+ return node.parent.parent.cases.some(switchCase =>
94
+ switchCase.consequent.some(
95
+ member =>
96
+ member.type === "TSDeclareFunction" &&
97
+ member.id.name === functionName,
98
+ ),
99
+ );
100
+ }
101
+
102
+ return (
103
+ Array.isArray(node.parent.body) &&
104
+ node.parent.body.some(
105
+ member =>
106
+ member.type === "TSDeclareFunction" &&
107
+ member.id.name === functionName,
108
+ )
109
+ );
110
+ }
111
+
68
112
  const nodesToCheck = {
69
113
  FunctionDeclaration(node) {
70
114
  stack.push(false);
@@ -73,14 +117,16 @@ module.exports = {
73
117
  !enforceDeclarations &&
74
118
  node.parent.type !== "ExportDefaultDeclaration" &&
75
119
  (typeof exportFunctionStyle === "undefined" ||
76
- node.parent.type !== "ExportNamedDeclaration")
120
+ node.parent.type !== "ExportNamedDeclaration") &&
121
+ !isOverloadedFunction(node)
77
122
  ) {
78
123
  context.report({ node, messageId: "expression" });
79
124
  }
80
125
 
81
126
  if (
82
127
  node.parent.type === "ExportNamedDeclaration" &&
83
- exportFunctionStyle === "expression"
128
+ exportFunctionStyle === "expression" &&
129
+ !isOverloadedFunction(node)
84
130
  ) {
85
131
  context.report({ node, messageId: "expression" });
86
132
  }
@@ -97,7 +143,8 @@ module.exports = {
97
143
  node.parent.type === "VariableDeclarator" &&
98
144
  (typeof exportFunctionStyle === "undefined" ||
99
145
  node.parent.parent.parent.type !==
100
- "ExportNamedDeclaration")
146
+ "ExportNamedDeclaration") &&
147
+ !(allowTypeAnnotation && node.parent.id.typeAnnotation)
101
148
  ) {
102
149
  context.report({
103
150
  node: node.parent,
@@ -109,7 +156,8 @@ module.exports = {
109
156
  node.parent.type === "VariableDeclarator" &&
110
157
  node.parent.parent.parent.type ===
111
158
  "ExportNamedDeclaration" &&
112
- exportFunctionStyle === "declaration"
159
+ exportFunctionStyle === "declaration" &&
160
+ !(allowTypeAnnotation && node.parent.id.typeAnnotation)
113
161
  ) {
114
162
  context.report({
115
163
  node: node.parent,
@@ -144,7 +192,8 @@ module.exports = {
144
192
  enforceDeclarations &&
145
193
  (typeof exportFunctionStyle === "undefined" ||
146
194
  node.parent.parent.parent.type !==
147
- "ExportNamedDeclaration")
195
+ "ExportNamedDeclaration") &&
196
+ !(allowTypeAnnotation && node.parent.id.typeAnnotation)
148
197
  ) {
149
198
  context.report({
150
199
  node: node.parent,
@@ -155,7 +204,8 @@ module.exports = {
155
204
  if (
156
205
  node.parent.parent.parent.type ===
157
206
  "ExportNamedDeclaration" &&
158
- exportFunctionStyle === "declaration"
207
+ exportFunctionStyle === "declaration" &&
208
+ !(allowTypeAnnotation && node.parent.id.typeAnnotation)
159
209
  ) {
160
210
  context.report({
161
211
  node: node.parent,
@@ -5,6 +5,12 @@
5
5
 
6
6
  "use strict";
7
7
 
8
+ const ASSIGNMENT_NODES = new Set([
9
+ "AssignmentExpression",
10
+ "ForInStatement",
11
+ "ForOfStatement",
12
+ ]);
13
+
8
14
  //------------------------------------------------------------------------------
9
15
  // Rule Definition
10
16
  //------------------------------------------------------------------------------
@@ -142,27 +148,37 @@ module.exports = {
142
148
  }
143
149
  }
144
150
  });
145
- });
146
151
 
147
- // Undeclared assigned variables.
148
- scope.implicit.variables.forEach(variable => {
149
- const scopeVariable = scope.set.get(variable.name);
150
- let messageId;
152
+ if (
153
+ isReadonlyEslintGlobalVariable &&
154
+ variable.defs.length === 0
155
+ ) {
156
+ variable.references.forEach(reference => {
157
+ if (reference.isWrite() && !reference.isRead()) {
158
+ let assignmentParent =
159
+ reference.identifier.parent;
160
+
161
+ while (
162
+ assignmentParent &&
163
+ !ASSIGNMENT_NODES.has(assignmentParent.type)
164
+ ) {
165
+ assignmentParent = assignmentParent.parent;
166
+ }
151
167
 
152
- if (scopeVariable) {
153
- // ESLint global variable
154
- if (scopeVariable.writeable) {
155
- return;
156
- }
157
- messageId = "assignmentToReadonlyGlobal";
158
- } else {
159
- // Reference to an unknown variable, possible global leak.
160
- messageId = "globalVariableLeak";
168
+ report(
169
+ assignmentParent ?? reference.identifier,
170
+ "assignmentToReadonlyGlobal",
171
+ );
172
+ }
173
+ });
161
174
  }
175
+ });
162
176
 
177
+ // Undeclared assigned variables.
178
+ scope.implicit.variables.forEach(variable => {
163
179
  // def.node is an AssignmentExpression, ForInStatement or ForOfStatement.
164
180
  variable.defs.forEach(def => {
165
- report(def.node, messageId);
181
+ report(def.node, "globalVariableLeak");
166
182
  });
167
183
  });
168
184
  },
@@ -26,10 +26,73 @@ function normalizeIgnoreValue(x) {
26
26
  return x;
27
27
  }
28
28
 
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
+
29
90
  /** @type {import('../types').Rule.RuleModule} */
30
91
  module.exports = {
31
92
  meta: {
32
93
  type: "suggestion",
94
+ dialects: ["typescript", "javascript"],
95
+ language: "javascript",
33
96
 
34
97
  docs: {
35
98
  description: "Disallow magic numbers",
@@ -75,6 +138,22 @@ module.exports = {
75
138
  type: "boolean",
76
139
  default: false,
77
140
  },
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
+ },
78
157
  },
79
158
  additionalProperties: false,
80
159
  },
@@ -94,7 +173,12 @@ module.exports = {
94
173
  ignoreArrayIndexes = !!config.ignoreArrayIndexes,
95
174
  ignoreDefaultValues = !!config.ignoreDefaultValues,
96
175
  ignoreClassFieldInitialValues =
97
- !!config.ignoreClassFieldInitialValues;
176
+ !!config.ignoreClassFieldInitialValues,
177
+ ignoreEnums = !!config.ignoreEnums,
178
+ ignoreNumericLiteralTypes = !!config.ignoreNumericLiteralTypes,
179
+ ignoreReadonlyClassProperties =
180
+ !!config.ignoreReadonlyClassProperties,
181
+ ignoreTypeIndexes = !!config.ignoreTypeIndexes;
98
182
 
99
183
  const okTypes = detectObjects
100
184
  ? []
@@ -217,14 +301,15 @@ module.exports = {
217
301
  let value;
218
302
  let raw;
219
303
 
220
- // Treat unary minus as a part of the number
304
+ // Treat unary minus/plus as a part of the number
221
305
  if (
222
306
  node.parent.type === "UnaryExpression" &&
223
- node.parent.operator === "-"
307
+ ["-", "+"].includes(node.parent.operator)
224
308
  ) {
225
309
  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}`;
228
313
  } else {
229
314
  fullNumberNode = node;
230
315
  value = node.value;
@@ -239,6 +324,14 @@ module.exports = {
239
324
  (ignoreDefaultValues && isDefaultValue(fullNumberNode)) ||
240
325
  (ignoreClassFieldInitialValues &&
241
326
  isClassFieldInitialValue(fullNumberNode)) ||
327
+ (ignoreEnums &&
328
+ isParentTSEnumDeclaration(fullNumberNode)) ||
329
+ (ignoreNumericLiteralTypes &&
330
+ isTSNumericLiteralType(fullNumberNode)) ||
331
+ (ignoreTypeIndexes &&
332
+ isAncestorTSIndexedAccessType(fullNumberNode)) ||
333
+ (ignoreReadonlyClassProperties &&
334
+ isParentTSReadonlyPropertyDefinition(fullNumberNode)) ||
242
335
  isParseIntRadix(fullNumberNode) ||
243
336
  isJSXNumber(fullNumberNode) ||
244
337
  (ignoreArrayIndexes && isArrayIndex(fullNumberNode, value))