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.
- package/.absolutejs/eslint.cache.json +1 -5
- package/.absolutejs/prettier.cache.json +2 -2
- package/.absolutejs/tsconfig.tsbuildinfo +1 -1
- package/dist/index.js +144 -112
- package/package.json +1 -1
- package/src/rules/sort-keys-fixable.ts +243 -169
|
@@ -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
|
|
184
|
-
|
|
185
|
-
|
|
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 (!
|
|
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
|
-
|
|
192
|
-
|
|
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 (
|
|
197
|
-
|
|
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 (
|
|
202
|
-
|
|
180
|
+
if (
|
|
181
|
+
statement.type !== "VariableDeclaration" ||
|
|
182
|
+
statement.kind !== "const"
|
|
183
|
+
) {
|
|
203
184
|
return;
|
|
204
185
|
}
|
|
205
186
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
}
|
|
187
|
+
for (const declaration of statement.declarations) {
|
|
188
|
+
addVariableBinding(declaration);
|
|
189
|
+
}
|
|
190
|
+
};
|
|
211
191
|
|
|
212
|
-
|
|
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
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
)
|
|
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
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
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
|
-
|
|
379
|
-
|
|
462
|
+
const isPureIdentifierCall = (
|
|
463
|
+
callExpression: TSESTree.CallExpression
|
|
464
|
+
) => {
|
|
465
|
+
if (callExpression.callee.type !== "Identifier") {
|
|
466
|
+
return false;
|
|
467
|
+
}
|
|
380
468
|
|
|
381
|
-
|
|
382
|
-
|
|
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
|
-
|
|
389
|
-
|
|
390
|
-
|
|
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
|
-
|
|
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
|