eslint-plugin-absolute 0.2.4 → 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.
package/dist/index.js CHANGED
@@ -219,55 +219,140 @@ var sortKeysFixable = {
219
219
  const natural = option && typeof option.natural === "boolean" ? option.natural : false;
220
220
  const minKeys = option && typeof option.minKeys === "number" ? option.minKeys : 2;
221
221
  const variablesBeforeFunctions = option && typeof option.variablesBeforeFunctions === "boolean" ? option.variablesBeforeFunctions : false;
222
- for (const statement of sourceCode.ast.body) {
223
- if (statement.type === "ImportDeclaration" && statement.specifiers.length > 0) {
224
- for (const specifier of statement.specifiers) {
225
- topLevelBindings.set(specifier.local.name, {
226
- kind: "import"
227
- });
228
- }
229
- continue;
222
+ const compareKeys = (keyLeft, keyRight) => {
223
+ let left = keyLeft;
224
+ let right = keyRight;
225
+ if (!caseSensitive) {
226
+ left = left.toLowerCase();
227
+ right = right.toLowerCase();
228
+ }
229
+ if (natural) {
230
+ return left.localeCompare(right, undefined, {
231
+ numeric: true
232
+ });
233
+ }
234
+ return left.localeCompare(right);
235
+ };
236
+ const addImportBindings = (statement) => {
237
+ if (statement.specifiers.length === 0) {
238
+ return;
239
+ }
240
+ for (const specifier of statement.specifiers) {
241
+ topLevelBindings.set(specifier.local.name, {
242
+ kind: "import"
243
+ });
244
+ }
245
+ };
246
+ const addVariableBinding = (declaration) => {
247
+ if (declaration.id.type !== "Identifier" || !declaration.init) {
248
+ return;
249
+ }
250
+ if (declaration.init.type === "ArrowFunctionExpression" || declaration.init.type === "FunctionExpression") {
251
+ topLevelBindings.set(declaration.id.name, {
252
+ kind: "function",
253
+ node: declaration.init
254
+ });
255
+ return;
256
+ }
257
+ topLevelBindings.set(declaration.id.name, {
258
+ kind: "value",
259
+ node: declaration.init
260
+ });
261
+ };
262
+ const addTopLevelBindings = (statement) => {
263
+ if (statement.type === "ImportDeclaration") {
264
+ addImportBindings(statement);
265
+ return;
230
266
  }
231
267
  if (statement.type === "FunctionDeclaration" && statement.id) {
232
268
  topLevelBindings.set(statement.id.name, {
233
269
  kind: "function",
234
270
  node: statement
235
271
  });
236
- continue;
272
+ return;
237
273
  }
238
274
  if (statement.type !== "VariableDeclaration" || statement.kind !== "const") {
239
- continue;
275
+ return;
240
276
  }
241
277
  for (const declaration of statement.declarations) {
242
- if (declaration.id.type !== "Identifier" || !declaration.init) {
243
- continue;
278
+ addVariableBinding(declaration);
279
+ }
280
+ };
281
+ for (const statement of sourceCode.ast.body) {
282
+ addTopLevelBindings(statement);
283
+ }
284
+ const addBoundIdentifiers = (node, stableLocals) => {
285
+ if (!node) {
286
+ return;
287
+ }
288
+ switch (node.type) {
289
+ case "Identifier":
290
+ stableLocals.add(node.name);
291
+ return;
292
+ case "AssignmentPattern":
293
+ addBoundIdentifiers(node.left, stableLocals);
294
+ return;
295
+ case "RestElement":
296
+ addBoundIdentifiers(node.argument, stableLocals);
297
+ return;
298
+ case "ArrayPattern":
299
+ for (const element of node.elements.filter(Boolean)) {
300
+ addBoundIdentifiers(element, stableLocals);
301
+ }
302
+ break;
303
+ case "ObjectPattern":
304
+ for (const property of node.properties) {
305
+ const bindingNode = property.type === "RestElement" ? property.argument : property.value;
306
+ addBoundIdentifiers(bindingNode, stableLocals);
307
+ }
308
+ break;
309
+ default:
310
+ break;
311
+ }
312
+ };
313
+ const addFunctionParamBindings = (functionNode, stableLocals) => {
314
+ for (const parameter of functionNode.params) {
315
+ addBoundIdentifiers(parameter, stableLocals);
316
+ }
317
+ };
318
+ const addAncestorConstBindings = (ancestor, node, stableLocals) => {
319
+ const addDeclarationBindings = (statement) => {
320
+ if (statement.type !== "VariableDeclaration" || statement.kind !== "const") {
321
+ return;
244
322
  }
245
- if (declaration.init.type === "ArrowFunctionExpression" || declaration.init.type === "FunctionExpression") {
246
- topLevelBindings.set(declaration.id.name, {
247
- kind: "function",
248
- node: declaration.init
249
- });
250
- continue;
323
+ for (const declaration of statement.declarations) {
324
+ addBoundIdentifiers(declaration.id, stableLocals);
251
325
  }
252
- topLevelBindings.set(declaration.id.name, {
253
- kind: "value",
254
- node: declaration.init
255
- });
326
+ };
327
+ for (const statement of ancestor.body) {
328
+ if (statement.range[0] >= node.range[0]) {
329
+ return;
330
+ }
331
+ addDeclarationBindings(statement);
256
332
  }
257
- }
258
- const compareKeys = (keyLeft, keyRight) => {
259
- let left = keyLeft;
260
- let right = keyRight;
261
- if (!caseSensitive) {
262
- left = left.toLowerCase();
263
- right = right.toLowerCase();
333
+ };
334
+ const addAncestorBindingsForNode = (ancestor, node, stableLocals) => {
335
+ if (ancestor.type !== "Program" && ancestor.type !== "BlockStatement") {
336
+ return;
264
337
  }
265
- if (natural) {
266
- return left.localeCompare(right, undefined, {
267
- numeric: true
268
- });
338
+ addAncestorConstBindings(ancestor, node, stableLocals);
339
+ };
340
+ const addFunctionBindingsForAncestor = (ancestor, stableLocals) => {
341
+ if (ancestor.type !== "FunctionDeclaration" && ancestor.type !== "FunctionExpression" && ancestor.type !== "ArrowFunctionExpression") {
342
+ return;
269
343
  }
270
- return left.localeCompare(right);
344
+ addFunctionParamBindings(ancestor, stableLocals);
345
+ };
346
+ const getStableLocalsForNode = (node) => {
347
+ const stableLocals = new Set;
348
+ const ancestors = sourceCode.getAncestors(node);
349
+ for (const ancestor of ancestors) {
350
+ addFunctionBindingsForAncestor(ancestor, stableLocals);
351
+ }
352
+ for (const ancestor of ancestors) {
353
+ addAncestorBindingsForNode(ancestor, node, stableLocals);
354
+ }
355
+ return stableLocals;
271
356
  };
272
357
  const getStaticMemberName = (memberExpression) => {
273
358
  if (!memberExpression.computed && memberExpression.property.type === "Identifier") {
@@ -294,6 +379,39 @@ var sortKeysFixable = {
294
379
  }
295
380
  return false;
296
381
  };
382
+ const isPureConstStatement = (statement, stableLocals, checkExpression) => {
383
+ if (statement.kind !== "const") {
384
+ return false;
385
+ }
386
+ for (const declaration of statement.declarations) {
387
+ if (declaration.id.type !== "Identifier" || !declaration.init) {
388
+ return false;
389
+ }
390
+ if (!checkExpression(declaration.init)) {
391
+ return false;
392
+ }
393
+ stableLocals.add(declaration.id.name);
394
+ }
395
+ return true;
396
+ };
397
+ const isPureFunctionStatement = (statement, stableLocals, checkExpression) => {
398
+ if (statement.type === "ReturnStatement") {
399
+ return !statement.argument || checkExpression(statement.argument);
400
+ }
401
+ if (statement.type === "VariableDeclaration") {
402
+ return isPureConstStatement(statement, stableLocals, checkExpression);
403
+ }
404
+ return false;
405
+ };
406
+ const isPureFunctionBody = (body, stableLocals, checkExpression) => {
407
+ for (const statement of body.body) {
408
+ const statementIsPure = isPureFunctionStatement(statement, stableLocals, checkExpression);
409
+ if (!statementIsPure) {
410
+ return false;
411
+ }
412
+ }
413
+ return true;
414
+ };
297
415
  const isPureTopLevelFunction = (functionNode) => {
298
416
  const cached = pureFunctionCache.get(functionNode);
299
417
  if (cached !== undefined) {
@@ -304,44 +422,23 @@ var sortKeysFixable = {
304
422
  }
305
423
  pureFunctionInProgress.add(functionNode);
306
424
  const stableLocals = new Set;
307
- for (const parameter of functionNode.params) {
308
- if (parameter.type === "Identifier") {
309
- stableLocals.add(parameter.name);
310
- }
311
- }
312
- let isPure = true;
425
+ addFunctionParamBindings(functionNode, stableLocals);
313
426
  const checkExpression = (expression) => isPureRuntimeExpression(expression, stableLocals);
314
- if (functionNode.body.type === "BlockStatement") {
315
- for (const statement of functionNode.body.body) {
316
- if (statement.type === "ReturnStatement") {
317
- if (statement.argument && !checkExpression(statement.argument)) {
318
- isPure = false;
319
- }
320
- continue;
321
- }
322
- if (statement.type === "VariableDeclaration" && statement.kind === "const") {
323
- for (const declaration of statement.declarations) {
324
- if (declaration.id.type !== "Identifier" || !declaration.init || !checkExpression(declaration.init)) {
325
- isPure = false;
326
- break;
327
- }
328
- stableLocals.add(declaration.id.name);
329
- }
330
- if (!isPure) {
331
- break;
332
- }
333
- continue;
334
- }
335
- isPure = false;
336
- break;
337
- }
338
- } else {
339
- isPure = checkExpression(functionNode.body);
340
- }
427
+ const isPure = functionNode.body.type === "BlockStatement" ? isPureFunctionBody(functionNode.body, stableLocals, checkExpression) : checkExpression(functionNode.body);
341
428
  pureFunctionInProgress.delete(functionNode);
342
429
  pureFunctionCache.set(functionNode, isPure);
343
430
  return isPure;
344
431
  };
432
+ const isPureIdentifierCall = (callExpression) => {
433
+ if (callExpression.callee.type !== "Identifier") {
434
+ return false;
435
+ }
436
+ if (PURE_GLOBAL_FUNCTIONS.has(callExpression.callee.name)) {
437
+ return true;
438
+ }
439
+ const binding = topLevelBindings.get(callExpression.callee.name);
440
+ return binding?.kind === "function" ? isPureTopLevelFunction(binding.node) : false;
441
+ };
345
442
  const isPureRuntimeExpression = (node, stableLocals) => {
346
443
  if (!node || node.type === "PrivateIdentifier") {
347
444
  return false;
@@ -405,11 +502,7 @@ var sortKeysFixable = {
405
502
  return false;
406
503
  }
407
504
  if (node.callee.type === "Identifier") {
408
- if (PURE_GLOBAL_FUNCTIONS.has(node.callee.name)) {
409
- return true;
410
- }
411
- const binding = topLevelBindings.get(node.callee.name);
412
- return binding?.kind === "function" && isPureTopLevelFunction(binding.node);
505
+ return isPureIdentifierCall(node);
413
506
  }
414
507
  if (node.callee.type !== "MemberExpression") {
415
508
  return false;
@@ -424,8 +517,7 @@ var sortKeysFixable = {
424
517
  return false;
425
518
  }
426
519
  };
427
- const isSafeToReorderExpression = (node) => isPureRuntimeExpression(node, new Set);
428
- const isSafeJSXAttributeValue = (value) => {
520
+ const isSafeJSXAttributeValue = (value, scopeNode) => {
429
521
  if (value === null) {
430
522
  return true;
431
523
  }
@@ -438,7 +530,7 @@ var sortKeysFixable = {
438
530
  if (value.expression.type === "JSXEmptyExpression") {
439
531
  return false;
440
532
  }
441
- return isSafeToReorderExpression(value.expression);
533
+ return isPureRuntimeExpression(value.expression, getStableLocalsForNode(scopeNode));
442
534
  };
443
535
  const isFunctionProperty = (prop) => {
444
536
  const { value } = prop;
@@ -586,7 +678,7 @@ ${indent}`;
586
678
  if (hasDuplicateNames(keys.map((key) => key.keyName))) {
587
679
  autoFixable = false;
588
680
  }
589
- if (autoFixable && keys.some((key) => key.node.type === "Property" && !isSafeToReorderExpression(key.node.value))) {
681
+ if (autoFixable && keys.some((key) => key.node.type === "Property" && !isPureRuntimeExpression(key.node.value, getStableLocalsForNode(key.node)))) {
590
682
  autoFixable = false;
591
683
  }
592
684
  let fixProvided = false;
@@ -685,7 +777,7 @@ ${indent}`;
685
777
  });
686
778
  return;
687
779
  }
688
- if (attrs.some((attr) => attr.type === "JSXAttribute" && !isSafeJSXAttributeValue(attr.value))) {
780
+ if (attrs.some((attr) => attr.type === "JSXAttribute" && !isSafeJSXAttributeValue(attr.value, attr))) {
689
781
  context.report({
690
782
  messageId: "unsorted",
691
783
  node: attrs[0].type === "JSXAttribute" ? attrs[0].name : attrs[0]
package/package.json CHANGED
@@ -30,5 +30,5 @@
30
30
  "typecheck": "bun run tsc --noEmit"
31
31
  },
32
32
  "type": "module",
33
- "version": "0.2.4"
33
+ "version": "0.2.6"
34
34
  }