eslint-plugin-absolute 0.2.5 → 0.2.6

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.
@@ -105,59 +105,6 @@ export const sortKeysFixable: TSESLint.RuleModule<MessageIds, Options> = {
105
105
  ? option.variablesBeforeFunctions
106
106
  : false;
107
107
 
108
- for (const statement of sourceCode.ast.body) {
109
- if (
110
- statement.type === "ImportDeclaration" &&
111
- statement.specifiers.length > 0
112
- ) {
113
- for (const specifier of statement.specifiers) {
114
- topLevelBindings.set(specifier.local.name, {
115
- kind: "import"
116
- });
117
- }
118
-
119
- continue;
120
- }
121
-
122
- if (statement.type === "FunctionDeclaration" && statement.id) {
123
- topLevelBindings.set(statement.id.name, {
124
- kind: "function",
125
- node: statement
126
- });
127
-
128
- continue;
129
- }
130
-
131
- if (
132
- statement.type !== "VariableDeclaration" ||
133
- statement.kind !== "const"
134
- ) {
135
- continue;
136
- }
137
-
138
- for (const declaration of statement.declarations) {
139
- if (declaration.id.type !== "Identifier" || !declaration.init) {
140
- continue;
141
- }
142
-
143
- if (
144
- declaration.init.type === "ArrowFunctionExpression" ||
145
- declaration.init.type === "FunctionExpression"
146
- ) {
147
- topLevelBindings.set(declaration.id.name, {
148
- kind: "function",
149
- node: declaration.init
150
- });
151
- continue;
152
- }
153
-
154
- topLevelBindings.set(declaration.id.name, {
155
- kind: "value",
156
- node: declaration.init
157
- });
158
- }
159
- }
160
-
161
108
  /**
162
109
  * Compare two key strings based on the provided options.
163
110
  * This function mimics the behavior of the built-in rule.
@@ -180,50 +127,176 @@ export const sortKeysFixable: TSESLint.RuleModule<MessageIds, Options> = {
180
127
  return left.localeCompare(right);
181
128
  };
182
129
 
183
- const addBoundIdentifiers = (
184
- node: TSESTree.Node | null,
185
- stableLocals: Set<string>
130
+ const addImportBindings = (statement: TSESTree.ImportDeclaration) => {
131
+ if (statement.specifiers.length === 0) {
132
+ return;
133
+ }
134
+
135
+ for (const specifier of statement.specifiers) {
136
+ topLevelBindings.set(specifier.local.name, {
137
+ kind: "import"
138
+ });
139
+ }
140
+ };
141
+
142
+ const addVariableBinding = (
143
+ declaration: TSESTree.VariableDeclarator
186
144
  ) => {
187
- if (!node) {
145
+ if (declaration.id.type !== "Identifier" || !declaration.init) {
146
+ return;
147
+ }
148
+
149
+ if (
150
+ declaration.init.type === "ArrowFunctionExpression" ||
151
+ declaration.init.type === "FunctionExpression"
152
+ ) {
153
+ topLevelBindings.set(declaration.id.name, {
154
+ kind: "function",
155
+ node: declaration.init
156
+ });
188
157
  return;
189
158
  }
190
159
 
191
- if (node.type === "Identifier") {
192
- stableLocals.add(node.name);
160
+ topLevelBindings.set(declaration.id.name, {
161
+ kind: "value",
162
+ node: declaration.init
163
+ });
164
+ };
165
+
166
+ const addTopLevelBindings = (statement: TSESTree.ProgramStatement) => {
167
+ if (statement.type === "ImportDeclaration") {
168
+ addImportBindings(statement);
193
169
  return;
194
170
  }
195
171
 
196
- if (node.type === "AssignmentPattern") {
197
- addBoundIdentifiers(node.left, stableLocals);
172
+ if (statement.type === "FunctionDeclaration" && statement.id) {
173
+ topLevelBindings.set(statement.id.name, {
174
+ kind: "function",
175
+ node: statement
176
+ });
198
177
  return;
199
178
  }
200
179
 
201
- if (node.type === "RestElement") {
202
- addBoundIdentifiers(node.argument, stableLocals);
180
+ if (
181
+ statement.type !== "VariableDeclaration" ||
182
+ statement.kind !== "const"
183
+ ) {
203
184
  return;
204
185
  }
205
186
 
206
- if (node.type === "ArrayPattern") {
207
- for (const element of node.elements) {
208
- if (!element) {
209
- continue;
210
- }
187
+ for (const declaration of statement.declarations) {
188
+ addVariableBinding(declaration);
189
+ }
190
+ };
211
191
 
212
- addBoundIdentifiers(element, stableLocals);
213
- }
192
+ for (const statement of sourceCode.ast.body) {
193
+ addTopLevelBindings(statement);
194
+ }
195
+
196
+ const addBoundIdentifiers = (
197
+ node: TSESTree.Node | null,
198
+ stableLocals: Set<string>
199
+ ) => {
200
+ if (!node) {
214
201
  return;
215
202
  }
216
203
 
217
- if (node.type === "ObjectPattern") {
218
- for (const property of node.properties) {
219
- if (property.type === "RestElement") {
220
- addBoundIdentifiers(property.argument, stableLocals);
221
- continue;
204
+ switch (node.type) {
205
+ case "Identifier":
206
+ stableLocals.add(node.name);
207
+ return;
208
+ case "AssignmentPattern":
209
+ addBoundIdentifiers(node.left, stableLocals);
210
+ return;
211
+ case "RestElement":
212
+ addBoundIdentifiers(node.argument, stableLocals);
213
+ return;
214
+ case "ArrayPattern":
215
+ for (const element of node.elements.filter(Boolean)) {
216
+ addBoundIdentifiers(element, stableLocals);
222
217
  }
218
+ break;
219
+ case "ObjectPattern":
220
+ for (const property of node.properties) {
221
+ const bindingNode =
222
+ property.type === "RestElement"
223
+ ? property.argument
224
+ : property.value;
225
+ addBoundIdentifiers(bindingNode, stableLocals);
226
+ }
227
+ break;
228
+ default:
229
+ break;
230
+ }
231
+ };
232
+
233
+ const addFunctionParamBindings = (
234
+ functionNode:
235
+ | TSESTree.ArrowFunctionExpression
236
+ | TSESTree.FunctionDeclaration
237
+ | TSESTree.FunctionExpression,
238
+ stableLocals: Set<string>
239
+ ) => {
240
+ for (const parameter of functionNode.params) {
241
+ addBoundIdentifiers(parameter, stableLocals);
242
+ }
243
+ };
244
+
245
+ const addAncestorConstBindings = (
246
+ ancestor: TSESTree.BlockStatement | TSESTree.Program,
247
+ node: TSESTree.Node,
248
+ stableLocals: Set<string>
249
+ ) => {
250
+ const addDeclarationBindings = (statement: TSESTree.Statement) => {
251
+ if (
252
+ statement.type !== "VariableDeclaration" ||
253
+ statement.kind !== "const"
254
+ ) {
255
+ return;
256
+ }
223
257
 
224
- addBoundIdentifiers(property.value, stableLocals);
258
+ for (const declaration of statement.declarations) {
259
+ addBoundIdentifiers(declaration.id, stableLocals);
225
260
  }
261
+ };
262
+
263
+ for (const statement of ancestor.body) {
264
+ if (statement.range[0] >= node.range[0]) {
265
+ return;
266
+ }
267
+
268
+ addDeclarationBindings(statement);
269
+ }
270
+ };
271
+
272
+ const addAncestorBindingsForNode = (
273
+ ancestor: TSESTree.Node,
274
+ node: TSESTree.Node,
275
+ stableLocals: Set<string>
276
+ ) => {
277
+ if (
278
+ ancestor.type !== "Program" &&
279
+ ancestor.type !== "BlockStatement"
280
+ ) {
281
+ return;
282
+ }
283
+
284
+ addAncestorConstBindings(ancestor, node, stableLocals);
285
+ };
286
+
287
+ const addFunctionBindingsForAncestor = (
288
+ ancestor: TSESTree.Node,
289
+ stableLocals: Set<string>
290
+ ) => {
291
+ if (
292
+ ancestor.type !== "FunctionDeclaration" &&
293
+ ancestor.type !== "FunctionExpression" &&
294
+ ancestor.type !== "ArrowFunctionExpression"
295
+ ) {
296
+ return;
226
297
  }
298
+
299
+ addFunctionParamBindings(ancestor, stableLocals);
227
300
  };
228
301
 
229
302
  const getStableLocalsForNode = (node: TSESTree.Node) => {
@@ -231,38 +304,11 @@ export const sortKeysFixable: TSESLint.RuleModule<MessageIds, Options> = {
231
304
  const ancestors = sourceCode.getAncestors(node);
232
305
 
233
306
  for (const ancestor of ancestors) {
234
- if (
235
- ancestor.type === "FunctionDeclaration" ||
236
- ancestor.type === "FunctionExpression" ||
237
- ancestor.type === "ArrowFunctionExpression"
238
- ) {
239
- for (const parameter of ancestor.params) {
240
- addBoundIdentifiers(parameter, stableLocals);
241
- }
242
- }
307
+ addFunctionBindingsForAncestor(ancestor, stableLocals);
243
308
  }
244
309
 
245
310
  for (const ancestor of ancestors) {
246
- if (
247
- ancestor.type !== "Program" &&
248
- ancestor.type !== "BlockStatement"
249
- ) {
250
- continue;
251
- }
252
-
253
- for (const statement of ancestor.body) {
254
- if (
255
- statement.range[0] >= node.range[0] ||
256
- statement.type !== "VariableDeclaration" ||
257
- statement.kind !== "const"
258
- ) {
259
- break;
260
- }
261
-
262
- for (const declaration of statement.declarations) {
263
- addBoundIdentifiers(declaration.id, stableLocals);
264
- }
265
- }
311
+ addAncestorBindingsForNode(ancestor, node, stableLocals);
266
312
  }
267
313
 
268
314
  return stableLocals;
@@ -313,12 +359,77 @@ export const sortKeysFixable: TSESLint.RuleModule<MessageIds, Options> = {
313
359
  return false;
314
360
  };
315
361
 
362
+ const isPureConstStatement = (
363
+ statement: TSESTree.VariableDeclaration,
364
+ stableLocals: Set<string>,
365
+ checkExpression: (expression: TSESTree.Expression) => boolean
366
+ ) => {
367
+ if (statement.kind !== "const") {
368
+ return false;
369
+ }
370
+
371
+ for (const declaration of statement.declarations) {
372
+ if (declaration.id.type !== "Identifier" || !declaration.init) {
373
+ return false;
374
+ }
375
+
376
+ if (!checkExpression(declaration.init)) {
377
+ return false;
378
+ }
379
+
380
+ stableLocals.add(declaration.id.name);
381
+ }
382
+
383
+ return true;
384
+ };
385
+
386
+ const isPureFunctionStatement = (
387
+ statement: TSESTree.Statement,
388
+ stableLocals: Set<string>,
389
+ checkExpression: (expression: TSESTree.Expression) => boolean
390
+ ) => {
391
+ if (statement.type === "ReturnStatement") {
392
+ return (
393
+ !statement.argument || checkExpression(statement.argument)
394
+ );
395
+ }
396
+
397
+ if (statement.type === "VariableDeclaration") {
398
+ return isPureConstStatement(
399
+ statement,
400
+ stableLocals,
401
+ checkExpression
402
+ );
403
+ }
404
+
405
+ return false;
406
+ };
407
+
408
+ const isPureFunctionBody = (
409
+ body: TSESTree.BlockStatement,
410
+ stableLocals: Set<string>,
411
+ checkExpression: (expression: TSESTree.Expression) => boolean
412
+ ) => {
413
+ for (const statement of body.body) {
414
+ const statementIsPure = isPureFunctionStatement(
415
+ statement,
416
+ stableLocals,
417
+ checkExpression
418
+ );
419
+ if (!statementIsPure) {
420
+ return false;
421
+ }
422
+ }
423
+
424
+ return true;
425
+ };
426
+
316
427
  const isPureTopLevelFunction = (
317
428
  functionNode:
318
429
  | TSESTree.ArrowFunctionExpression
319
430
  | TSESTree.FunctionDeclaration
320
431
  | TSESTree.FunctionExpression
321
- ): boolean => {
432
+ ) => {
322
433
  const cached = pureFunctionCache.get(functionNode);
323
434
  if (cached !== undefined) {
324
435
  return cached;
@@ -331,63 +442,38 @@ export const sortKeysFixable: TSESLint.RuleModule<MessageIds, Options> = {
331
442
  pureFunctionInProgress.add(functionNode);
332
443
 
333
444
  const stableLocals = new Set<string>();
334
-
335
- for (const parameter of functionNode.params) {
336
- if (parameter.type === "Identifier") {
337
- stableLocals.add(parameter.name);
338
- }
339
- }
340
-
341
- let isPure = true;
445
+ addFunctionParamBindings(functionNode, stableLocals);
342
446
  const checkExpression = (expression: TSESTree.Expression) =>
343
447
  isPureRuntimeExpression(expression, stableLocals);
448
+ const isPure =
449
+ functionNode.body.type === "BlockStatement"
450
+ ? isPureFunctionBody(
451
+ functionNode.body,
452
+ stableLocals,
453
+ checkExpression
454
+ )
455
+ : checkExpression(functionNode.body);
344
456
 
345
- if (functionNode.body.type === "BlockStatement") {
346
- for (const statement of functionNode.body.body) {
347
- if (statement.type === "ReturnStatement") {
348
- if (
349
- statement.argument &&
350
- !checkExpression(statement.argument)
351
- ) {
352
- isPure = false;
353
- }
354
- continue;
355
- }
356
-
357
- if (
358
- statement.type === "VariableDeclaration" &&
359
- statement.kind === "const"
360
- ) {
361
- for (const declaration of statement.declarations) {
362
- if (
363
- declaration.id.type !== "Identifier" ||
364
- !declaration.init ||
365
- !checkExpression(declaration.init)
366
- ) {
367
- isPure = false;
368
- break;
369
- }
370
-
371
- stableLocals.add(declaration.id.name);
372
- }
373
-
374
- if (!isPure) {
375
- break;
376
- }
457
+ pureFunctionInProgress.delete(functionNode);
458
+ pureFunctionCache.set(functionNode, isPure);
459
+ return isPure;
460
+ };
377
461
 
378
- continue;
379
- }
462
+ const isPureIdentifierCall = (
463
+ callExpression: TSESTree.CallExpression
464
+ ) => {
465
+ if (callExpression.callee.type !== "Identifier") {
466
+ return false;
467
+ }
380
468
 
381
- isPure = false;
382
- break;
383
- }
384
- } else {
385
- isPure = checkExpression(functionNode.body);
469
+ if (PURE_GLOBAL_FUNCTIONS.has(callExpression.callee.name)) {
470
+ return true;
386
471
  }
387
472
 
388
- pureFunctionInProgress.delete(functionNode);
389
- pureFunctionCache.set(functionNode, isPure);
390
- return isPure;
473
+ const binding = topLevelBindings.get(callExpression.callee.name);
474
+ return binding?.kind === "function"
475
+ ? isPureTopLevelFunction(binding.node)
476
+ : false;
391
477
  };
392
478
 
393
479
  const isPureRuntimeExpression: (
@@ -501,15 +587,7 @@ export const sortKeysFixable: TSESLint.RuleModule<MessageIds, Options> = {
501
587
  }
502
588
 
503
589
  if (node.callee.type === "Identifier") {
504
- if (PURE_GLOBAL_FUNCTIONS.has(node.callee.name)) {
505
- return true;
506
- }
507
-
508
- const binding = topLevelBindings.get(node.callee.name);
509
- return (
510
- binding?.kind === "function" &&
511
- isPureTopLevelFunction(binding.node)
512
- );
590
+ return isPureIdentifierCall(node);
513
591
  }
514
592
 
515
593
  if (node.callee.type !== "MemberExpression") {
@@ -531,10 +609,6 @@ export const sortKeysFixable: TSESLint.RuleModule<MessageIds, Options> = {
531
609
  }
532
610
  };
533
611
 
534
- const isSafeToReorderExpression: (
535
- node: TSESTree.Node | null
536
- ) => boolean = (node) => isPureRuntimeExpression(node, new Set());
537
-
538
612
  const isSafeJSXAttributeValue = (
539
613
  value: TSESTree.JSXAttribute["value"],
540
614
  scopeNode: TSESTree.Node