@agilebot/eslint-plugin 0.1.2 → 0.1.4
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/lib/index.js +59 -52
- package/lib/rules/import/monorepo.js +7 -2
- package/lib/rules/intl/id-unused.js +2 -2
- package/lib/rules/react/better-exhaustive-deps.js +44 -58
- package/lib/rules/react/prefer-named-property-access.js +1 -1
- package/lib/rules/tss/class-naming.js +1 -1
- package/lib/rules/tss/no-color-value.js +0 -1
- package/lib/rules/tss/unused-classes.js +1 -1
- package/lib/util/intl.js +6 -6
- package/lib/util/translations.js +3 -4
- package/lib/util/tss.js +12 -7
- package/package.json +12 -6
- package/lib/util/import.js +0 -71
package/lib/index.js
CHANGED
@@ -1,52 +1,59 @@
|
|
1
|
-
// @ts-check
|
2
|
-
const path = require('path');
|
3
|
-
const { globSync } = require('fast-glob');
|
4
|
-
|
5
|
-
// List all rules in rules folder
|
6
|
-
const rulesPath = path.join(__dirname, 'rules');
|
7
|
-
const ruleFiles = globSync('**/*.js', {
|
8
|
-
cwd: rulesPath
|
9
|
-
});
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
'
|
34
|
-
value: true,
|
35
|
-
regexp: true
|
36
|
-
}
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
'@agilebot/
|
48
|
-
'@agilebot/
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
1
|
+
// @ts-check
|
2
|
+
const path = require('node:path');
|
3
|
+
const { globSync } = require('fast-glob');
|
4
|
+
|
5
|
+
// List all rules in rules folder
|
6
|
+
const rulesPath = path.join(__dirname, 'rules');
|
7
|
+
const ruleFiles = globSync('**/*.js', {
|
8
|
+
cwd: rulesPath
|
9
|
+
});
|
10
|
+
|
11
|
+
/**
|
12
|
+
* @type {import('eslint').Linter.RulesRecord}
|
13
|
+
*/
|
14
|
+
const rules = {};
|
15
|
+
ruleFiles.forEach(file => {
|
16
|
+
const { dir, name } = path.parse(file);
|
17
|
+
const ruleName = `${dir}/${name}`;
|
18
|
+
rules[ruleName] = require(path.join(rulesPath, file));
|
19
|
+
});
|
20
|
+
|
21
|
+
module.exports.rules = rules;
|
22
|
+
|
23
|
+
module.exports.configs = {
|
24
|
+
recommended: {
|
25
|
+
plugins: ['@agilebot'],
|
26
|
+
rules: {
|
27
|
+
'react-hooks/exhaustive-deps': 'off',
|
28
|
+
'@agilebot/react/better-exhaustive-deps': [
|
29
|
+
'warn',
|
30
|
+
{
|
31
|
+
checkMemoizedVariableIsStatic: true,
|
32
|
+
staticHooks: {
|
33
|
+
'useIpc.*': {
|
34
|
+
value: true,
|
35
|
+
regexp: true
|
36
|
+
},
|
37
|
+
useDialog: true,
|
38
|
+
useSnackbar: true,
|
39
|
+
useForm: true,
|
40
|
+
'use.*Store': {
|
41
|
+
value: true,
|
42
|
+
regexp: true
|
43
|
+
}
|
44
|
+
}
|
45
|
+
}
|
46
|
+
],
|
47
|
+
'@agilebot/react/prefer-named-property-access': 'error',
|
48
|
+
'@agilebot/react/hook-use-ref': 'warn',
|
49
|
+
'@agilebot/react/no-inline-styles': 'error',
|
50
|
+
'@agilebot/tss/unused-classes': 'warn',
|
51
|
+
'@agilebot/tss/no-color-value': 'error',
|
52
|
+
'@agilebot/tss/class-naming': 'error',
|
53
|
+
'@agilebot/import/enforce-icon-alias': 'error',
|
54
|
+
'@agilebot/import/monorepo': 'error',
|
55
|
+
'@agilebot/others/no-unnecessary-template-literals': 'error'
|
56
|
+
},
|
57
|
+
settings: {}
|
58
|
+
}
|
59
|
+
};
|
@@ -1,6 +1,7 @@
|
|
1
|
-
const { consola } = require('consola');
|
2
1
|
const { getSetting } = require('../../util/settings');
|
3
2
|
|
3
|
+
let warnedForMissingPrefix = false;
|
4
|
+
|
4
5
|
module.exports = {
|
5
6
|
meta: {
|
6
7
|
type: 'problem', // `problem`, `suggestion`, or `layout`
|
@@ -17,7 +18,11 @@ module.exports = {
|
|
17
18
|
ImportDeclaration(node) {
|
18
19
|
const prefix = getSetting(context, 'monorepo-prefix');
|
19
20
|
if (!prefix) {
|
20
|
-
|
21
|
+
if (!warnedForMissingPrefix) {
|
22
|
+
// eslint-disable-next-line no-console -- this is a CLI tool
|
23
|
+
console.error('Warning: agilebot/monorepo-prefix is not set.');
|
24
|
+
warnedForMissingPrefix = true;
|
25
|
+
}
|
21
26
|
return;
|
22
27
|
}
|
23
28
|
|
@@ -1,6 +1,3 @@
|
|
1
|
-
/* eslint-disable no-case-declarations */
|
2
|
-
/* eslint-disable no-continue */
|
3
|
-
|
4
1
|
/**
|
5
2
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
6
3
|
*
|
@@ -96,12 +93,13 @@ module.exports = {
|
|
96
93
|
};
|
97
94
|
|
98
95
|
function reportProblem(problem) {
|
99
|
-
if (
|
100
|
-
// Used to enable legacy behavior. Dangerous.
|
96
|
+
if (
|
97
|
+
enableDangerousAutofixThisMayCauseInfiniteLoops && // Used to enable legacy behavior. Dangerous.
|
101
98
|
// Keep this as an option until major IDEs upgrade (including VSCode FB ESLint extension).
|
102
|
-
|
103
|
-
|
104
|
-
|
99
|
+
Array.isArray(problem.suggest) &&
|
100
|
+
problem.suggest.length > 0
|
101
|
+
) {
|
102
|
+
problem.fix = problem.suggest[0].fix;
|
105
103
|
}
|
106
104
|
context.report(problem);
|
107
105
|
}
|
@@ -286,17 +284,14 @@ module.exports = {
|
|
286
284
|
if (name === 'useState') {
|
287
285
|
const references = resolved.references;
|
288
286
|
let writeCount = 0;
|
289
|
-
for (
|
290
|
-
if (
|
287
|
+
for (const reference of references) {
|
288
|
+
if (reference.isWrite()) {
|
291
289
|
writeCount++;
|
292
290
|
}
|
293
291
|
if (writeCount > 1) {
|
294
292
|
return false;
|
295
293
|
}
|
296
|
-
setStateCallSites.set(
|
297
|
-
references[i].identifier,
|
298
|
-
id.elements[0]
|
299
|
-
);
|
294
|
+
setStateCallSites.set(reference.identifier, id.elements[0]);
|
300
295
|
}
|
301
296
|
}
|
302
297
|
// Setter is stable.
|
@@ -304,8 +299,8 @@ module.exports = {
|
|
304
299
|
} else if (id.elements[0] === resolved.identifiers[0]) {
|
305
300
|
if (name === 'useState') {
|
306
301
|
const references = resolved.references;
|
307
|
-
for (
|
308
|
-
stateVariables.add(
|
302
|
+
for (const reference of references) {
|
303
|
+
stateVariables.add(reference.identifier);
|
309
304
|
}
|
310
305
|
}
|
311
306
|
// State variable itself is dynamic.
|
@@ -317,13 +312,11 @@ module.exports = {
|
|
317
312
|
if (
|
318
313
|
id.type === 'ArrayPattern' &&
|
319
314
|
id.elements.length === 2 &&
|
320
|
-
Array.isArray(resolved.identifiers)
|
315
|
+
Array.isArray(resolved.identifiers) && // Is second tuple value the same reference we're checking?
|
316
|
+
id.elements[1] === resolved.identifiers[0]
|
321
317
|
) {
|
322
|
-
//
|
323
|
-
|
324
|
-
// Setter is stable.
|
325
|
-
return true;
|
326
|
-
}
|
318
|
+
// Setter is stable.
|
319
|
+
return true;
|
327
320
|
}
|
328
321
|
} else if (
|
329
322
|
options.checkMemoizedVariableIsStatic &&
|
@@ -350,7 +343,7 @@ module.exports = {
|
|
350
343
|
);
|
351
344
|
|
352
345
|
if (
|
353
|
-
|
346
|
+
dependencyRefernece !== undefined &&
|
354
347
|
memoizedIsStableKnownHookValue(dependencyRefernece.resolved)
|
355
348
|
) {
|
356
349
|
continue;
|
@@ -372,7 +365,6 @@ module.exports = {
|
|
372
365
|
}
|
373
366
|
});
|
374
367
|
|
375
|
-
// eslint-disable-next-line no-lonely-if
|
376
368
|
if (options.staticHooks[name]) {
|
377
369
|
const staticParts = options.staticHooks[name];
|
378
370
|
if (staticParts === true) {
|
@@ -386,9 +378,7 @@ module.exports = {
|
|
386
378
|
Array.isArray(resolved.identifiers)
|
387
379
|
) {
|
388
380
|
// find index of the resolved ident in the array pattern
|
389
|
-
const idx = id.elements.
|
390
|
-
ident => ident === resolved.identifiers[0]
|
391
|
-
);
|
381
|
+
const idx = id.elements.indexOf(resolved.identifiers[0]);
|
392
382
|
if (idx >= 0) {
|
393
383
|
return staticParts[idx];
|
394
384
|
}
|
@@ -587,8 +577,7 @@ module.exports = {
|
|
587
577
|
// Is React managing this ref or us?
|
588
578
|
// Let's see if we can find a .current assignment.
|
589
579
|
let foundCurrentAssignment = false;
|
590
|
-
for (
|
591
|
-
const { identifier } = references[i];
|
580
|
+
for (const { identifier } of references) {
|
592
581
|
const { parent } = identifier;
|
593
582
|
if (
|
594
583
|
parent != null &&
|
@@ -764,8 +753,8 @@ module.exports = {
|
|
764
753
|
declaredDependencyNode,
|
765
754
|
null
|
766
755
|
);
|
767
|
-
} catch (
|
768
|
-
if (/Unsupported node type/.test(
|
756
|
+
} catch (err) {
|
757
|
+
if (/Unsupported node type/.test(err.message)) {
|
769
758
|
if (declaredDependencyNode.type === 'Literal') {
|
770
759
|
if (dependencies.has(declaredDependencyNode.value)) {
|
771
760
|
reportProblem({
|
@@ -795,7 +784,7 @@ module.exports = {
|
|
795
784
|
|
796
785
|
return;
|
797
786
|
}
|
798
|
-
throw
|
787
|
+
throw err;
|
799
788
|
}
|
800
789
|
|
801
790
|
let maybeID = declaredDependencyNode;
|
@@ -942,7 +931,7 @@ module.exports = {
|
|
942
931
|
return true;
|
943
932
|
}
|
944
933
|
const declaredDepKeys = declaredDependencies.map(dep => dep.key);
|
945
|
-
const sortedDeclaredDepKeys = declaredDepKeys.
|
934
|
+
const sortedDeclaredDepKeys = [...declaredDepKeys].sort();
|
946
935
|
return declaredDepKeys.join(',') === sortedDeclaredDepKeys.join(',');
|
947
936
|
}
|
948
937
|
if (areDeclaredDepsAlphabetized()) {
|
@@ -978,9 +967,7 @@ module.exports = {
|
|
978
967
|
(deps.size > 1 ? 'dependencies' : 'dependency') +
|
979
968
|
': ' +
|
980
969
|
joinEnglish(
|
981
|
-
|
982
|
-
.sort()
|
983
|
-
.map(name => "'" + formatDependency(name) + "'")
|
970
|
+
[...deps].sort().map(name => "'" + formatDependency(name) + "'")
|
984
971
|
) +
|
985
972
|
`. Either ${fixVerb} ${
|
986
973
|
deps.size > 1 ? 'them' : 'it'
|
@@ -991,7 +978,7 @@ module.exports = {
|
|
991
978
|
let extraWarning = '';
|
992
979
|
if (unnecessaryDependencies.size > 0) {
|
993
980
|
let badRef = null;
|
994
|
-
|
981
|
+
[...unnecessaryDependencies.keys()].forEach(key => {
|
995
982
|
if (badRef != null) {
|
996
983
|
return;
|
997
984
|
}
|
@@ -1004,7 +991,7 @@ module.exports = {
|
|
1004
991
|
` Mutable values like '${badRef}' aren't valid dependencies ` +
|
1005
992
|
"because mutating them doesn't re-render the component.";
|
1006
993
|
} else if (externalDependencies.size > 0) {
|
1007
|
-
const dep =
|
994
|
+
const dep = [...externalDependencies][0];
|
1008
995
|
// Don't show this warning for things that likely just got moved *inside* the callback
|
1009
996
|
// because in that case they're clearly not referring to globals.
|
1010
997
|
if (!scope.set.has(dep)) {
|
@@ -1028,8 +1015,7 @@ module.exports = {
|
|
1028
1015
|
return;
|
1029
1016
|
}
|
1030
1017
|
let isPropsOnlyUsedInMembers = true;
|
1031
|
-
for (
|
1032
|
-
const ref = refs[i];
|
1018
|
+
for (const ref of refs) {
|
1033
1019
|
const id = fastFindReferenceWithParent(
|
1034
1020
|
componentScope.block,
|
1035
1021
|
ref.identifier
|
@@ -1121,8 +1107,8 @@ module.exports = {
|
|
1121
1107
|
const references = usedDep.references;
|
1122
1108
|
let id;
|
1123
1109
|
let maybeCall;
|
1124
|
-
for (
|
1125
|
-
id =
|
1110
|
+
for (const reference of references) {
|
1111
|
+
id = reference.identifier;
|
1126
1112
|
maybeCall = id.parent;
|
1127
1113
|
// Try to see if we have setState(someExpr(missingDep)).
|
1128
1114
|
while (maybeCall != null && maybeCall !== componentScope.block) {
|
@@ -1146,7 +1132,7 @@ module.exports = {
|
|
1146
1132
|
form: 'reducer'
|
1147
1133
|
};
|
1148
1134
|
} else {
|
1149
|
-
const resolved =
|
1135
|
+
const resolved = reference.resolved;
|
1150
1136
|
if (resolved != null) {
|
1151
1137
|
// If it's a parameter *and* a missing dep,
|
1152
1138
|
// it must be a prop or something inside a prop.
|
@@ -1189,7 +1175,7 @@ module.exports = {
|
|
1189
1175
|
case 'updater':
|
1190
1176
|
extraWarning = ` You can also do a functional update '${
|
1191
1177
|
setStateRecommendation.setter
|
1192
|
-
}(${setStateRecommendation.missingDep.
|
1178
|
+
}(${setStateRecommendation.missingDep.slice(
|
1193
1179
|
0,
|
1194
1180
|
1
|
1195
1181
|
)} => ...)' if you only need '${
|
@@ -1224,13 +1210,13 @@ module.exports = {
|
|
1224
1210
|
suggest: [
|
1225
1211
|
{
|
1226
1212
|
desc: `Update the dependencies array to be: [${suggestedDeps
|
1227
|
-
.map(formatDependency)
|
1213
|
+
.map(element => formatDependency(element))
|
1228
1214
|
.join(', ')}]`,
|
1229
1215
|
fix(fixer) {
|
1230
1216
|
// TODO: consider preserving the comments or formatting?
|
1231
1217
|
return fixer.replaceText(
|
1232
1218
|
declaredDependenciesNode,
|
1233
|
-
`[${suggestedDeps.map(formatDependency).join(', ')}]`
|
1219
|
+
`[${suggestedDeps.map(element => formatDependency(element)).join(', ')}]`
|
1234
1220
|
);
|
1235
1221
|
}
|
1236
1222
|
}
|
@@ -1520,7 +1506,7 @@ function collectRecommendations({
|
|
1520
1506
|
declaredDependencies.forEach(({ key }) => {
|
1521
1507
|
// Does this declared dep satisfy a real need?
|
1522
1508
|
if (satisfyingDependencies.has(key)) {
|
1523
|
-
if (suggestedDependencies.
|
1509
|
+
if (!suggestedDependencies.includes(key)) {
|
1524
1510
|
// Good one.
|
1525
1511
|
suggestedDependencies.push(key);
|
1526
1512
|
} else {
|
@@ -1536,7 +1522,7 @@ function collectRecommendations({
|
|
1536
1522
|
// Such as resetting scroll when ID changes.
|
1537
1523
|
// Consider them legit.
|
1538
1524
|
// The exception is ref.current which is always wrong.
|
1539
|
-
if (suggestedDependencies.
|
1525
|
+
if (!suggestedDependencies.includes(key)) {
|
1540
1526
|
suggestedDependencies.push(key);
|
1541
1527
|
}
|
1542
1528
|
} else {
|
@@ -1681,12 +1667,12 @@ function scanForConstructions({
|
|
1681
1667
|
while (currentScope !== scope && currentScope != null) {
|
1682
1668
|
currentScope = currentScope.upper;
|
1683
1669
|
}
|
1684
|
-
if (
|
1685
|
-
// This reference is outside the Hook callback.
|
1670
|
+
if (
|
1671
|
+
currentScope !== scope && // This reference is outside the Hook callback.
|
1686
1672
|
// It can only be legit if it's the deps array.
|
1687
|
-
|
1688
|
-
|
1689
|
-
|
1673
|
+
!isAncestorNodeOf(declaredDependenciesNode, reference.identifier)
|
1674
|
+
) {
|
1675
|
+
return true;
|
1690
1676
|
}
|
1691
1677
|
}
|
1692
1678
|
return false;
|
@@ -1837,11 +1823,11 @@ function getReactiveHookCallbackIndex(calleeNode, options) {
|
|
1837
1823
|
let name;
|
1838
1824
|
try {
|
1839
1825
|
name = analyzePropertyChain(node, null);
|
1840
|
-
} catch (
|
1841
|
-
if (/Unsupported node type/.test(
|
1826
|
+
} catch (err) {
|
1827
|
+
if (/Unsupported node type/.test(err.message)) {
|
1842
1828
|
return 0;
|
1843
1829
|
}
|
1844
|
-
throw
|
1830
|
+
throw err;
|
1845
1831
|
}
|
1846
1832
|
return options.additionalHooks.test(name) ? 0 : -1;
|
1847
1833
|
}
|
@@ -1863,7 +1849,7 @@ function fastFindReferenceWithParent(start, target) {
|
|
1863
1849
|
const queue = [start];
|
1864
1850
|
let item = null;
|
1865
1851
|
|
1866
|
-
while (queue.length) {
|
1852
|
+
while (queue.length > 0) {
|
1867
1853
|
item = queue.shift();
|
1868
1854
|
|
1869
1855
|
if (isSameIdentifier(item, target)) {
|
@@ -1882,7 +1868,7 @@ function fastFindReferenceWithParent(start, target) {
|
|
1882
1868
|
value.parent = item;
|
1883
1869
|
queue.push(value);
|
1884
1870
|
} else if (Array.isArray(value)) {
|
1885
|
-
// eslint-disable-next-line no-loop-func
|
1871
|
+
// eslint-disable-next-line no-loop-func -- FIXME
|
1886
1872
|
value.forEach(val => {
|
1887
1873
|
if (isNodeLike(val)) {
|
1888
1874
|
val.parent = item;
|
@@ -40,7 +40,7 @@ function* updateImportStatement(context, fixer, key) {
|
|
40
40
|
}
|
41
41
|
|
42
42
|
// Named imports section is present and current key is not imported yet - add it to named imports section
|
43
|
-
yield fixer.insertTextAfter(importNode.specifiers.
|
43
|
+
yield fixer.insertTextAfter([...importNode.specifiers].pop(), `, ${key}`);
|
44
44
|
}
|
45
45
|
|
46
46
|
/** @type {import('eslint').Rule.RuleModule} */
|
@@ -25,7 +25,6 @@ module.exports = {
|
|
25
25
|
function checkColorLiteral(value) {
|
26
26
|
if (value.type === 'Literal' && typeof value.value === 'string') {
|
27
27
|
const colorCodePattern =
|
28
|
-
// eslint-disable-next-line max-len
|
29
28
|
/#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})|rgb\?\(\s*(\d{1,3}\s*,\s*){2}\d{1,3}(?:\s*,\s*\d*(?:\.\d+)?)?\s*\)/g;
|
30
29
|
const isColorCode = colorCodePattern.test(value.value);
|
31
30
|
if (isColorCode) {
|
package/lib/util/intl.js
CHANGED
@@ -9,13 +9,13 @@ function findFormatMessageAttrNode(node, attrName) {
|
|
9
9
|
// Find formatMessage usages
|
10
10
|
if (
|
11
11
|
node.type === 'CallExpression' &&
|
12
|
-
(node.callee.name === 'formatMessage' || node.callee.name === '$t')
|
12
|
+
(node.callee.name === 'formatMessage' || node.callee.name === '$t') &&
|
13
|
+
node.arguments.length > 0 &&
|
14
|
+
node.arguments[0].properties
|
13
15
|
) {
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
);
|
18
|
-
}
|
16
|
+
return node.arguments[0].properties.find(
|
17
|
+
a => a.key && a.key.name === attrName
|
18
|
+
);
|
19
19
|
}
|
20
20
|
|
21
21
|
// Find intl.formatMessage usages
|
package/lib/util/translations.js
CHANGED
@@ -1,7 +1,6 @@
|
|
1
|
-
|
2
|
-
const
|
3
|
-
const
|
4
|
-
const { tsImport } = require('./import');
|
1
|
+
const fs = require('node:fs');
|
2
|
+
const path = require('node:path');
|
3
|
+
const { tsImport } = require('@agilebot/eslint-utils');
|
5
4
|
const { getSetting } = require('./settings');
|
6
5
|
|
7
6
|
/**
|
package/lib/util/tss.js
CHANGED
@@ -12,7 +12,7 @@ function getBasicIdentifier(node) {
|
|
12
12
|
|
13
13
|
if (node.type === 'TemplateLiteral') {
|
14
14
|
// Handle template literals, e.g., classes[`foo`]
|
15
|
-
if (node.expressions.length) {
|
15
|
+
if (node.expressions.length > 0) {
|
16
16
|
// Template literals with expressions, e.g., classes[`foo${bar}`]
|
17
17
|
return null;
|
18
18
|
}
|
@@ -25,12 +25,17 @@ function getBasicIdentifier(node) {
|
|
25
25
|
|
26
26
|
// Helper function to recursively get the base identifier from a MemberExpression node
|
27
27
|
function getBaseIdentifier(node) {
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
28
|
+
switch (node.type) {
|
29
|
+
case 'Identifier': {
|
30
|
+
return node;
|
31
|
+
}
|
32
|
+
case 'CallExpression': {
|
33
|
+
return getBaseIdentifier(node.callee);
|
34
|
+
}
|
35
|
+
case 'MemberExpression': {
|
36
|
+
return getBaseIdentifier(node.object);
|
37
|
+
}
|
38
|
+
// No default
|
34
39
|
}
|
35
40
|
return null;
|
36
41
|
}
|
package/package.json
CHANGED
@@ -1,21 +1,27 @@
|
|
1
1
|
{
|
2
2
|
"name": "@agilebot/eslint-plugin",
|
3
|
-
"version": "0.1.
|
3
|
+
"version": "0.1.4",
|
4
4
|
"description": "Agilebot's ESLint plugin",
|
5
5
|
"main": "lib",
|
6
6
|
"license": "MIT",
|
7
|
+
"keywords": [
|
8
|
+
"eslint",
|
9
|
+
"eslint-plugin"
|
10
|
+
],
|
7
11
|
"repository": {
|
8
12
|
"url": "sh-agilebot/frontend-toolkit",
|
9
13
|
"directory": "packages/eslint-plugin"
|
10
14
|
},
|
11
15
|
"homepage": "https://github.com/sh-agilebot/frontend-toolkit/tree/master/packages/eslint-plugin#readme",
|
16
|
+
"engines": {
|
17
|
+
"node": "^18.18.0 || >=20.0.0"
|
18
|
+
},
|
12
19
|
"dependencies": {
|
13
20
|
"@typescript-eslint/utils": "^7.1.1",
|
14
|
-
"
|
15
|
-
|
16
|
-
|
17
|
-
"
|
18
|
-
"sucrase": "^3.35.0"
|
21
|
+
"fast-glob": "^3.3.2"
|
22
|
+
},
|
23
|
+
"peerDependencies": {
|
24
|
+
"eslint": "^7.0.0 || ^8.0.0"
|
19
25
|
},
|
20
26
|
"files": [
|
21
27
|
"lib"
|
package/lib/util/import.js
DELETED
@@ -1,71 +0,0 @@
|
|
1
|
-
const path = require('path');
|
2
|
-
const jiti = require('jiti');
|
3
|
-
const { transform } = require('sucrase');
|
4
|
-
const { getTsconfig } = require('get-tsconfig');
|
5
|
-
|
6
|
-
/**
|
7
|
-
* import ts module, like require, but support ts
|
8
|
-
* @param {*} modulePath - module path
|
9
|
-
*/
|
10
|
-
function tsImport(modulePath) {
|
11
|
-
if (!modulePath) {
|
12
|
-
return;
|
13
|
-
}
|
14
|
-
/** try to delete cache first */
|
15
|
-
try {
|
16
|
-
if (require.cache[modulePath]) {
|
17
|
-
delete require.cache[modulePath];
|
18
|
-
}
|
19
|
-
} catch (err) {
|
20
|
-
/* empty */
|
21
|
-
}
|
22
|
-
|
23
|
-
try {
|
24
|
-
return require(modulePath);
|
25
|
-
} catch (err) {
|
26
|
-
const tsconfig = getTsconfig(modulePath);
|
27
|
-
const { paths, baseUrl } = tsconfig.config.compilerOptions;
|
28
|
-
let basePath = path.dirname(tsconfig.path);
|
29
|
-
basePath = path.resolve(basePath, baseUrl);
|
30
|
-
|
31
|
-
const alias = resolveTsconfigPathsToAlias(paths, basePath);
|
32
|
-
|
33
|
-
return jiti(__filename, {
|
34
|
-
interopDefault: true,
|
35
|
-
cache: false,
|
36
|
-
debug: !!process.env.DEBUG,
|
37
|
-
transform: options => {
|
38
|
-
return transform(options.source, {
|
39
|
-
transforms: ['imports', 'typescript']
|
40
|
-
});
|
41
|
-
},
|
42
|
-
alias
|
43
|
-
})(modulePath);
|
44
|
-
}
|
45
|
-
}
|
46
|
-
|
47
|
-
/**
|
48
|
-
* Resolve tsconfig.json paths to Webpack aliases
|
49
|
-
* @param {string} paths - tsconfig.json paths
|
50
|
-
* @param {string} basePath - Path from tsconfig to Webpack config to create absolute aliases
|
51
|
-
* @return {object} - Webpack alias config
|
52
|
-
*/
|
53
|
-
function resolveTsconfigPathsToAlias(paths, basePath = __dirname) {
|
54
|
-
const aliases = {};
|
55
|
-
|
56
|
-
Object.keys(paths).forEach(item => {
|
57
|
-
const key = item.replace('/*', '');
|
58
|
-
const value = path.resolve(
|
59
|
-
basePath,
|
60
|
-
paths[item][0].replace('/*', '').replace('*', '')
|
61
|
-
);
|
62
|
-
|
63
|
-
aliases[key] = value;
|
64
|
-
});
|
65
|
-
|
66
|
-
return aliases;
|
67
|
-
}
|
68
|
-
|
69
|
-
module.exports = {
|
70
|
-
tsImport
|
71
|
-
};
|