eslint-plugin-absolute 0.2.3 → 0.2.5
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
|
@@ -186,6 +186,16 @@ var explicitObjectTypes = {
|
|
|
186
186
|
|
|
187
187
|
// src/rules/sort-keys-fixable.ts
|
|
188
188
|
var SORT_BEFORE = -1;
|
|
189
|
+
var PURE_CONSTRUCTORS = new Set(["Date"]);
|
|
190
|
+
var PURE_GLOBAL_FUNCTIONS = new Set(["Boolean", "Number", "String"]);
|
|
191
|
+
var PURE_MEMBER_METHODS = new Set([
|
|
192
|
+
"getDay",
|
|
193
|
+
"getHours",
|
|
194
|
+
"getMilliseconds",
|
|
195
|
+
"getMinutes",
|
|
196
|
+
"getSeconds",
|
|
197
|
+
"padStart"
|
|
198
|
+
]);
|
|
189
199
|
var hasDuplicateNames = (names) => {
|
|
190
200
|
const seen = new Set;
|
|
191
201
|
const nonNullNames = names.flatMap((name) => name === null ? [] : [name]);
|
|
@@ -197,73 +207,54 @@ var hasDuplicateNames = (names) => {
|
|
|
197
207
|
}
|
|
198
208
|
return false;
|
|
199
209
|
};
|
|
200
|
-
var isSafeStaticTemplate = (node) => node.expressions.length === 0;
|
|
201
|
-
var isSafeArrayElement = (node) => {
|
|
202
|
-
if (!node || node.type === "SpreadElement") {
|
|
203
|
-
return false;
|
|
204
|
-
}
|
|
205
|
-
return isSafeToReorderExpression(node);
|
|
206
|
-
};
|
|
207
|
-
var isSafeObjectProperty = (property) => {
|
|
208
|
-
if (property.type !== "Property" || property.computed || property.kind !== "init") {
|
|
209
|
-
return false;
|
|
210
|
-
}
|
|
211
|
-
if (property.key.type !== "Identifier" && property.key.type !== "Literal") {
|
|
212
|
-
return false;
|
|
213
|
-
}
|
|
214
|
-
if (property.method) {
|
|
215
|
-
return true;
|
|
216
|
-
}
|
|
217
|
-
return isSafeToReorderExpression(property.value);
|
|
218
|
-
};
|
|
219
|
-
var isSafeToReorderExpression = (node) => {
|
|
220
|
-
if (!node || node.type === "PrivateIdentifier") {
|
|
221
|
-
return false;
|
|
222
|
-
}
|
|
223
|
-
switch (node.type) {
|
|
224
|
-
case "Identifier":
|
|
225
|
-
case "Literal":
|
|
226
|
-
case "ThisExpression":
|
|
227
|
-
case "FunctionExpression":
|
|
228
|
-
case "ArrowFunctionExpression":
|
|
229
|
-
case "ClassExpression":
|
|
230
|
-
return true;
|
|
231
|
-
case "TemplateLiteral":
|
|
232
|
-
return isSafeStaticTemplate(node);
|
|
233
|
-
case "UnaryExpression":
|
|
234
|
-
return isSafeToReorderExpression(node.argument);
|
|
235
|
-
case "ArrayExpression":
|
|
236
|
-
return node.elements.every(isSafeArrayElement);
|
|
237
|
-
case "ObjectExpression":
|
|
238
|
-
return node.properties.every(isSafeObjectProperty);
|
|
239
|
-
default:
|
|
240
|
-
return false;
|
|
241
|
-
}
|
|
242
|
-
};
|
|
243
|
-
var isSafeJSXAttributeValue = (value) => {
|
|
244
|
-
if (value === null) {
|
|
245
|
-
return true;
|
|
246
|
-
}
|
|
247
|
-
if (value.type === "Literal") {
|
|
248
|
-
return true;
|
|
249
|
-
}
|
|
250
|
-
if (value.type !== "JSXExpressionContainer") {
|
|
251
|
-
return false;
|
|
252
|
-
}
|
|
253
|
-
if (value.expression.type === "JSXEmptyExpression") {
|
|
254
|
-
return false;
|
|
255
|
-
}
|
|
256
|
-
return isSafeToReorderExpression(value.expression);
|
|
257
|
-
};
|
|
258
210
|
var sortKeysFixable = {
|
|
259
211
|
create(context) {
|
|
260
212
|
const { sourceCode } = context;
|
|
261
213
|
const [option] = context.options;
|
|
214
|
+
const topLevelBindings = new Map;
|
|
215
|
+
const pureFunctionCache = new Map;
|
|
216
|
+
const pureFunctionInProgress = new Set;
|
|
262
217
|
const order = option && option.order ? option.order : "asc";
|
|
263
218
|
const caseSensitive = option && typeof option.caseSensitive === "boolean" ? option.caseSensitive : false;
|
|
264
219
|
const natural = option && typeof option.natural === "boolean" ? option.natural : false;
|
|
265
220
|
const minKeys = option && typeof option.minKeys === "number" ? option.minKeys : 2;
|
|
266
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;
|
|
230
|
+
}
|
|
231
|
+
if (statement.type === "FunctionDeclaration" && statement.id) {
|
|
232
|
+
topLevelBindings.set(statement.id.name, {
|
|
233
|
+
kind: "function",
|
|
234
|
+
node: statement
|
|
235
|
+
});
|
|
236
|
+
continue;
|
|
237
|
+
}
|
|
238
|
+
if (statement.type !== "VariableDeclaration" || statement.kind !== "const") {
|
|
239
|
+
continue;
|
|
240
|
+
}
|
|
241
|
+
for (const declaration of statement.declarations) {
|
|
242
|
+
if (declaration.id.type !== "Identifier" || !declaration.init) {
|
|
243
|
+
continue;
|
|
244
|
+
}
|
|
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;
|
|
251
|
+
}
|
|
252
|
+
topLevelBindings.set(declaration.id.name, {
|
|
253
|
+
kind: "value",
|
|
254
|
+
node: declaration.init
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
}
|
|
267
258
|
const compareKeys = (keyLeft, keyRight) => {
|
|
268
259
|
let left = keyLeft;
|
|
269
260
|
let right = keyRight;
|
|
@@ -278,6 +269,237 @@ var sortKeysFixable = {
|
|
|
278
269
|
}
|
|
279
270
|
return left.localeCompare(right);
|
|
280
271
|
};
|
|
272
|
+
const addBoundIdentifiers = (node, stableLocals) => {
|
|
273
|
+
if (!node) {
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
if (node.type === "Identifier") {
|
|
277
|
+
stableLocals.add(node.name);
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
280
|
+
if (node.type === "AssignmentPattern") {
|
|
281
|
+
addBoundIdentifiers(node.left, stableLocals);
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
if (node.type === "RestElement") {
|
|
285
|
+
addBoundIdentifiers(node.argument, stableLocals);
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
if (node.type === "ArrayPattern") {
|
|
289
|
+
for (const element of node.elements) {
|
|
290
|
+
if (!element) {
|
|
291
|
+
continue;
|
|
292
|
+
}
|
|
293
|
+
addBoundIdentifiers(element, stableLocals);
|
|
294
|
+
}
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
if (node.type === "ObjectPattern") {
|
|
298
|
+
for (const property of node.properties) {
|
|
299
|
+
if (property.type === "RestElement") {
|
|
300
|
+
addBoundIdentifiers(property.argument, stableLocals);
|
|
301
|
+
continue;
|
|
302
|
+
}
|
|
303
|
+
addBoundIdentifiers(property.value, stableLocals);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
};
|
|
307
|
+
const getStableLocalsForNode = (node) => {
|
|
308
|
+
const stableLocals = new Set;
|
|
309
|
+
const ancestors = sourceCode.getAncestors(node);
|
|
310
|
+
for (const ancestor of ancestors) {
|
|
311
|
+
if (ancestor.type === "FunctionDeclaration" || ancestor.type === "FunctionExpression" || ancestor.type === "ArrowFunctionExpression") {
|
|
312
|
+
for (const parameter of ancestor.params) {
|
|
313
|
+
addBoundIdentifiers(parameter, stableLocals);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
for (const ancestor of ancestors) {
|
|
318
|
+
if (ancestor.type !== "Program" && ancestor.type !== "BlockStatement") {
|
|
319
|
+
continue;
|
|
320
|
+
}
|
|
321
|
+
for (const statement of ancestor.body) {
|
|
322
|
+
if (statement.range[0] >= node.range[0] || statement.type !== "VariableDeclaration" || statement.kind !== "const") {
|
|
323
|
+
break;
|
|
324
|
+
}
|
|
325
|
+
for (const declaration of statement.declarations) {
|
|
326
|
+
addBoundIdentifiers(declaration.id, stableLocals);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
return stableLocals;
|
|
331
|
+
};
|
|
332
|
+
const getStaticMemberName = (memberExpression) => {
|
|
333
|
+
if (!memberExpression.computed && memberExpression.property.type === "Identifier") {
|
|
334
|
+
return memberExpression.property.name;
|
|
335
|
+
}
|
|
336
|
+
if (memberExpression.computed && memberExpression.property.type === "Literal" && typeof memberExpression.property.value === "string") {
|
|
337
|
+
return memberExpression.property.value;
|
|
338
|
+
}
|
|
339
|
+
return null;
|
|
340
|
+
};
|
|
341
|
+
const isStableIdentifier = (name, stableLocals) => {
|
|
342
|
+
if (stableLocals.has(name)) {
|
|
343
|
+
return true;
|
|
344
|
+
}
|
|
345
|
+
const binding = topLevelBindings.get(name);
|
|
346
|
+
if (!binding) {
|
|
347
|
+
return false;
|
|
348
|
+
}
|
|
349
|
+
if (binding.kind === "import") {
|
|
350
|
+
return true;
|
|
351
|
+
}
|
|
352
|
+
if (binding.kind === "value") {
|
|
353
|
+
return isPureRuntimeExpression(binding.node, stableLocals);
|
|
354
|
+
}
|
|
355
|
+
return false;
|
|
356
|
+
};
|
|
357
|
+
const isPureTopLevelFunction = (functionNode) => {
|
|
358
|
+
const cached = pureFunctionCache.get(functionNode);
|
|
359
|
+
if (cached !== undefined) {
|
|
360
|
+
return cached;
|
|
361
|
+
}
|
|
362
|
+
if (pureFunctionInProgress.has(functionNode)) {
|
|
363
|
+
return false;
|
|
364
|
+
}
|
|
365
|
+
pureFunctionInProgress.add(functionNode);
|
|
366
|
+
const stableLocals = new Set;
|
|
367
|
+
for (const parameter of functionNode.params) {
|
|
368
|
+
if (parameter.type === "Identifier") {
|
|
369
|
+
stableLocals.add(parameter.name);
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
let isPure = true;
|
|
373
|
+
const checkExpression = (expression) => isPureRuntimeExpression(expression, stableLocals);
|
|
374
|
+
if (functionNode.body.type === "BlockStatement") {
|
|
375
|
+
for (const statement of functionNode.body.body) {
|
|
376
|
+
if (statement.type === "ReturnStatement") {
|
|
377
|
+
if (statement.argument && !checkExpression(statement.argument)) {
|
|
378
|
+
isPure = false;
|
|
379
|
+
}
|
|
380
|
+
continue;
|
|
381
|
+
}
|
|
382
|
+
if (statement.type === "VariableDeclaration" && statement.kind === "const") {
|
|
383
|
+
for (const declaration of statement.declarations) {
|
|
384
|
+
if (declaration.id.type !== "Identifier" || !declaration.init || !checkExpression(declaration.init)) {
|
|
385
|
+
isPure = false;
|
|
386
|
+
break;
|
|
387
|
+
}
|
|
388
|
+
stableLocals.add(declaration.id.name);
|
|
389
|
+
}
|
|
390
|
+
if (!isPure) {
|
|
391
|
+
break;
|
|
392
|
+
}
|
|
393
|
+
continue;
|
|
394
|
+
}
|
|
395
|
+
isPure = false;
|
|
396
|
+
break;
|
|
397
|
+
}
|
|
398
|
+
} else {
|
|
399
|
+
isPure = checkExpression(functionNode.body);
|
|
400
|
+
}
|
|
401
|
+
pureFunctionInProgress.delete(functionNode);
|
|
402
|
+
pureFunctionCache.set(functionNode, isPure);
|
|
403
|
+
return isPure;
|
|
404
|
+
};
|
|
405
|
+
const isPureRuntimeExpression = (node, stableLocals) => {
|
|
406
|
+
if (!node || node.type === "PrivateIdentifier") {
|
|
407
|
+
return false;
|
|
408
|
+
}
|
|
409
|
+
switch (node.type) {
|
|
410
|
+
case "Identifier":
|
|
411
|
+
return isStableIdentifier(node.name, stableLocals);
|
|
412
|
+
case "Literal":
|
|
413
|
+
case "FunctionExpression":
|
|
414
|
+
case "ArrowFunctionExpression":
|
|
415
|
+
case "ClassExpression":
|
|
416
|
+
return true;
|
|
417
|
+
case "ThisExpression":
|
|
418
|
+
return stableLocals.has("this");
|
|
419
|
+
case "TemplateLiteral":
|
|
420
|
+
return node.expressions.every((expression) => isPureRuntimeExpression(expression, stableLocals));
|
|
421
|
+
case "UnaryExpression":
|
|
422
|
+
return isPureRuntimeExpression(node.argument, stableLocals);
|
|
423
|
+
case "BinaryExpression":
|
|
424
|
+
case "LogicalExpression":
|
|
425
|
+
return isPureRuntimeExpression(node.left, stableLocals) && isPureRuntimeExpression(node.right, stableLocals);
|
|
426
|
+
case "ConditionalExpression":
|
|
427
|
+
return isPureRuntimeExpression(node.test, stableLocals) && isPureRuntimeExpression(node.consequent, stableLocals) && isPureRuntimeExpression(node.alternate, stableLocals);
|
|
428
|
+
case "ArrayExpression":
|
|
429
|
+
return node.elements.every((element) => {
|
|
430
|
+
if (!element || element.type === "SpreadElement") {
|
|
431
|
+
return false;
|
|
432
|
+
}
|
|
433
|
+
return isPureRuntimeExpression(element, stableLocals);
|
|
434
|
+
});
|
|
435
|
+
case "ObjectExpression":
|
|
436
|
+
return node.properties.every((property) => {
|
|
437
|
+
if (property.type !== "Property" || property.computed || property.kind !== "init") {
|
|
438
|
+
return false;
|
|
439
|
+
}
|
|
440
|
+
if (property.key.type !== "Identifier" && property.key.type !== "Literal") {
|
|
441
|
+
return false;
|
|
442
|
+
}
|
|
443
|
+
if (property.method) {
|
|
444
|
+
return true;
|
|
445
|
+
}
|
|
446
|
+
return isPureRuntimeExpression(property.value, stableLocals);
|
|
447
|
+
});
|
|
448
|
+
case "MemberExpression":
|
|
449
|
+
return isPureRuntimeExpression(node.object, stableLocals) && (!node.computed || isPureRuntimeExpression(node.property, stableLocals));
|
|
450
|
+
case "NewExpression":
|
|
451
|
+
return node.callee.type === "Identifier" && PURE_CONSTRUCTORS.has(node.callee.name) && node.arguments.every((argument) => {
|
|
452
|
+
if (argument.type === "SpreadElement") {
|
|
453
|
+
return false;
|
|
454
|
+
}
|
|
455
|
+
return isPureRuntimeExpression(argument, stableLocals);
|
|
456
|
+
});
|
|
457
|
+
case "CallExpression": {
|
|
458
|
+
const argsArePure = node.arguments.every((argument) => {
|
|
459
|
+
if (argument.type === "SpreadElement") {
|
|
460
|
+
return false;
|
|
461
|
+
}
|
|
462
|
+
return isPureRuntimeExpression(argument, stableLocals);
|
|
463
|
+
});
|
|
464
|
+
if (!argsArePure) {
|
|
465
|
+
return false;
|
|
466
|
+
}
|
|
467
|
+
if (node.callee.type === "Identifier") {
|
|
468
|
+
if (PURE_GLOBAL_FUNCTIONS.has(node.callee.name)) {
|
|
469
|
+
return true;
|
|
470
|
+
}
|
|
471
|
+
const binding = topLevelBindings.get(node.callee.name);
|
|
472
|
+
return binding?.kind === "function" && isPureTopLevelFunction(binding.node);
|
|
473
|
+
}
|
|
474
|
+
if (node.callee.type !== "MemberExpression") {
|
|
475
|
+
return false;
|
|
476
|
+
}
|
|
477
|
+
const memberName = getStaticMemberName(node.callee);
|
|
478
|
+
if (!memberName || !PURE_MEMBER_METHODS.has(memberName)) {
|
|
479
|
+
return false;
|
|
480
|
+
}
|
|
481
|
+
return isPureRuntimeExpression(node.callee.object, stableLocals);
|
|
482
|
+
}
|
|
483
|
+
default:
|
|
484
|
+
return false;
|
|
485
|
+
}
|
|
486
|
+
};
|
|
487
|
+
const isSafeToReorderExpression = (node) => isPureRuntimeExpression(node, new Set);
|
|
488
|
+
const isSafeJSXAttributeValue = (value, scopeNode) => {
|
|
489
|
+
if (value === null) {
|
|
490
|
+
return true;
|
|
491
|
+
}
|
|
492
|
+
if (value.type === "Literal") {
|
|
493
|
+
return true;
|
|
494
|
+
}
|
|
495
|
+
if (value.type !== "JSXExpressionContainer") {
|
|
496
|
+
return false;
|
|
497
|
+
}
|
|
498
|
+
if (value.expression.type === "JSXEmptyExpression") {
|
|
499
|
+
return false;
|
|
500
|
+
}
|
|
501
|
+
return isPureRuntimeExpression(value.expression, getStableLocalsForNode(scopeNode));
|
|
502
|
+
};
|
|
281
503
|
const isFunctionProperty = (prop) => {
|
|
282
504
|
const { value } = prop;
|
|
283
505
|
return Boolean(value) && (value.type === "FunctionExpression" || value.type === "ArrowFunctionExpression" || prop.method === true);
|
|
@@ -424,7 +646,7 @@ ${indent}`;
|
|
|
424
646
|
if (hasDuplicateNames(keys.map((key) => key.keyName))) {
|
|
425
647
|
autoFixable = false;
|
|
426
648
|
}
|
|
427
|
-
if (autoFixable && keys.some((key) => key.node.type === "Property" && !
|
|
649
|
+
if (autoFixable && keys.some((key) => key.node.type === "Property" && !isPureRuntimeExpression(key.node.value, getStableLocalsForNode(key.node)))) {
|
|
428
650
|
autoFixable = false;
|
|
429
651
|
}
|
|
430
652
|
let fixProvided = false;
|
|
@@ -523,7 +745,7 @@ ${indent}`;
|
|
|
523
745
|
});
|
|
524
746
|
return;
|
|
525
747
|
}
|
|
526
|
-
if (attrs.some((attr) => attr.type === "JSXAttribute" && !isSafeJSXAttributeValue(attr.value))) {
|
|
748
|
+
if (attrs.some((attr) => attr.type === "JSXAttribute" && !isSafeJSXAttributeValue(attr.value, attr))) {
|
|
527
749
|
context.report({
|
|
528
750
|
messageId: "unsorted",
|
|
529
751
|
node: attrs[0].type === "JSXAttribute" ? attrs[0].name : attrs[0]
|
|
@@ -1140,13 +1362,9 @@ var sortExports = {
|
|
|
1140
1362
|
}
|
|
1141
1363
|
const dependencies = getImmediateDependencyNames(item.node);
|
|
1142
1364
|
for (const dependency of dependencies) {
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
}
|
|
1146
|
-
const dependencyIndex = sortedIndices.get(dependency);
|
|
1147
|
-
if (dependencyIndex !== undefined && itemIndex < dependencyIndex) {
|
|
1365
|
+
const dependencyIndex = exportNames.has(dependency) ? sortedIndices.get(dependency) : undefined;
|
|
1366
|
+
if (dependencyIndex !== undefined && itemIndex < dependencyIndex)
|
|
1148
1367
|
return true;
|
|
1149
|
-
}
|
|
1150
1368
|
}
|
|
1151
1369
|
return false;
|
|
1152
1370
|
});
|
package/package.json
CHANGED
|
@@ -423,14 +423,14 @@ export const sortExports: TSESLint.RuleModule<MessageIds, Options> = {
|
|
|
423
423
|
|
|
424
424
|
const dependencies = getImmediateDependencyNames(item.node);
|
|
425
425
|
for (const dependency of dependencies) {
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
426
|
+
const dependencyIndex = exportNames.has(dependency)
|
|
427
|
+
? sortedIndices.get(dependency)
|
|
428
|
+
: undefined;
|
|
429
|
+
if (
|
|
430
|
+
dependencyIndex !== undefined &&
|
|
431
|
+
itemIndex < dependencyIndex
|
|
432
|
+
)
|
|
432
433
|
return true;
|
|
433
|
-
}
|
|
434
434
|
}
|
|
435
435
|
|
|
436
436
|
return false;
|