@utoo/lint 0.2.9 → 0.3.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/README.md +41 -11
- package/bin/fishlint.js +23 -3
- package/bin/migrate.js +476 -10
- package/bin/utoo-lint.js +15 -15
- package/configs/frontend.d.ts +54 -2
- package/configs/frontend.json +15 -0
- package/index.cjs +258 -59
- package/index.d.ts +14 -1
- package/index.js +258 -59
- package/package.json +8 -6
- package/schema.json +41 -1
package/configs/frontend.json
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://raw.githubusercontent.com/utooland/utoo-lint/main/npm/utoo-lint/schema.json",
|
|
3
|
+
"files": ["src/**/*.{js,jsx,ts,tsx}"],
|
|
4
|
+
"ignores": ["dist", "coverage", "node_modules"],
|
|
3
5
|
"rules": {
|
|
4
6
|
"no-debugger": "error",
|
|
5
7
|
"no-alert": "error",
|
|
@@ -12,21 +14,34 @@
|
|
|
12
14
|
"no-constant-condition": "error",
|
|
13
15
|
"no-dupe-keys": "error",
|
|
14
16
|
"no-duplicate-imports": "error",
|
|
17
|
+
"no-script-url": "error",
|
|
15
18
|
"import/first": "error",
|
|
16
19
|
"import/newline-after-import": "warn",
|
|
17
20
|
"import/no-duplicates": "error",
|
|
18
21
|
"import/no-self-import": "error",
|
|
22
|
+
"promise/no-nesting": "error",
|
|
23
|
+
"react-hooks/rules-of-hooks": "error",
|
|
24
|
+
"react-hooks/exhaustive-deps": "warn",
|
|
19
25
|
"react/jsx-no-duplicate-props": "error",
|
|
26
|
+
"react/jsx-key": "error",
|
|
20
27
|
"react/jsx-no-target-blank": "error",
|
|
21
28
|
"react/jsx-pascal-case": "warn",
|
|
29
|
+
"react/no-array-index-key": "warn",
|
|
30
|
+
"react/no-children-prop": "error",
|
|
22
31
|
"react/no-danger": "warn",
|
|
32
|
+
"react/no-danger-with-children": "error",
|
|
23
33
|
"react/no-find-dom-node": "error",
|
|
34
|
+
"react/no-forward-ref": "warn",
|
|
35
|
+
"react/no-unstable-nested-components": "warn",
|
|
24
36
|
"react/no-unescaped-entities": "error",
|
|
37
|
+
"react/void-dom-elements-no-children": "error",
|
|
25
38
|
"jsx-a11y/aria-props": "error",
|
|
26
39
|
"jsx-a11y/aria-unsupported-elements": "error",
|
|
27
40
|
"jsx-a11y/iframe-has-title": "error",
|
|
28
41
|
"jsx-a11y/img-redundant-alt": "warn",
|
|
29
42
|
"jsx-a11y/no-access-key": "error",
|
|
43
|
+
"unused-imports/no-unused-imports": "warn",
|
|
44
|
+
"@typescript-eslint/ban-types": "warn",
|
|
30
45
|
"@typescript-eslint/no-unused-vars": "warn",
|
|
31
46
|
"@typescript-eslint/no-use-before-define": "error",
|
|
32
47
|
"@typescript-eslint/no-shadow": "error",
|
package/index.cjs
CHANGED
|
@@ -77,6 +77,7 @@ const BUILTIN_RULE_IDS = [
|
|
|
77
77
|
"block-scoped-var",
|
|
78
78
|
"camelcase",
|
|
79
79
|
"capitalized-comments",
|
|
80
|
+
"class-methods-use-this",
|
|
80
81
|
"complexity",
|
|
81
82
|
"consistent-return",
|
|
82
83
|
"consistent-this",
|
|
@@ -168,6 +169,7 @@ const BUILTIN_RULE_IDS = [
|
|
|
168
169
|
"no-inline-comments",
|
|
169
170
|
"no-inner-declarations",
|
|
170
171
|
"no-invalid-regexp",
|
|
172
|
+
"no-invalid-this",
|
|
171
173
|
"no-irregular-whitespace",
|
|
172
174
|
"no-iterator",
|
|
173
175
|
"no-label-var",
|
|
@@ -176,6 +178,7 @@ const BUILTIN_RULE_IDS = [
|
|
|
176
178
|
"no-lonely-if",
|
|
177
179
|
"no-loop-func",
|
|
178
180
|
"no-loss-of-precision",
|
|
181
|
+
"no-magic-numbers",
|
|
179
182
|
"no-mixed-spaces-and-tabs",
|
|
180
183
|
"no-misleading-character-class",
|
|
181
184
|
"no-multi-assign",
|
|
@@ -234,6 +237,8 @@ const BUILTIN_RULE_IDS = [
|
|
|
234
237
|
"no-underscore-dangle",
|
|
235
238
|
"no-undefined",
|
|
236
239
|
"no-unneeded-ternary",
|
|
240
|
+
"no-unexpected-multiline",
|
|
241
|
+
"no-unmodified-loop-condition",
|
|
237
242
|
"no-unreachable",
|
|
238
243
|
"no-unreachable-loop",
|
|
239
244
|
"no-unsafe-finally",
|
|
@@ -244,6 +249,7 @@ const BUILTIN_RULE_IDS = [
|
|
|
244
249
|
"no-unused-private-class-members",
|
|
245
250
|
"no-unused-vars",
|
|
246
251
|
"no-use-before-define",
|
|
252
|
+
"no-useless-assignment",
|
|
247
253
|
"no-useless-backreference",
|
|
248
254
|
"no-useless-call",
|
|
249
255
|
"no-useless-catch",
|
|
@@ -305,6 +311,19 @@ const BUILTIN_RULE_IDS = [
|
|
|
305
311
|
"import/no-named-as-default-member",
|
|
306
312
|
"import/no-unresolved",
|
|
307
313
|
"import/no-self-import",
|
|
314
|
+
"jest/no-conditional-expect",
|
|
315
|
+
"jest/no-deprecated-functions",
|
|
316
|
+
"jest/no-export",
|
|
317
|
+
"jest/no-focused-tests",
|
|
318
|
+
"jest/no-identical-title",
|
|
319
|
+
"jest/no-interpolation-in-snapshots",
|
|
320
|
+
"jest/no-jasmine-globals",
|
|
321
|
+
"jest/no-mocks-import",
|
|
322
|
+
"jest/no-standalone-expect",
|
|
323
|
+
"jest/valid-describe-callback",
|
|
324
|
+
"jest/valid-expect-in-promise",
|
|
325
|
+
"jest/valid-expect",
|
|
326
|
+
"jest/valid-title",
|
|
308
327
|
"promise/no-promise-in-callback",
|
|
309
328
|
"promise/no-return-in-finally",
|
|
310
329
|
"promise/no-return-wrap",
|
|
@@ -349,9 +368,12 @@ const BUILTIN_RULE_IDS = [
|
|
|
349
368
|
"react/no-danger",
|
|
350
369
|
"react/no-danger-with-children",
|
|
351
370
|
"react/no-deprecated",
|
|
371
|
+
"react/no-direct-mutation-state",
|
|
352
372
|
"react/no-find-dom-node",
|
|
373
|
+
"react/no-forward-ref",
|
|
353
374
|
"react/no-is-mounted",
|
|
354
375
|
"react/no-multi-comp",
|
|
376
|
+
"react/no-unstable-nested-components",
|
|
355
377
|
"react/no-redundant-should-component-update",
|
|
356
378
|
"react/no-render-return-value",
|
|
357
379
|
"react/no-string-refs",
|
|
@@ -449,10 +471,15 @@ const NATIVE_ONLY_RULE_IDS = [
|
|
|
449
471
|
];
|
|
450
472
|
const NATIVE_RULE_IDS = [...BUILTIN_RULE_IDS, ...NATIVE_ONLY_RULE_IDS];
|
|
451
473
|
const FIXABLE_BUILTIN_RULE_IDS = new Set([
|
|
474
|
+
"jest/no-deprecated-functions",
|
|
475
|
+
"jest/no-jasmine-globals",
|
|
452
476
|
"no-extra-semi",
|
|
453
477
|
"@typescript-eslint/no-extra-semi",
|
|
454
478
|
"unused-imports/no-unused-imports"
|
|
455
479
|
]);
|
|
480
|
+
const SUGGESTION_BUILTIN_RULE_IDS = new Set([
|
|
481
|
+
"jest/no-focused-tests"
|
|
482
|
+
]);
|
|
456
483
|
const BUILTIN_RULES = new Map(BUILTIN_RULE_IDS.map((ruleId) => [ruleId, createBuiltinRule(ruleId)]));
|
|
457
484
|
|
|
458
485
|
class UtooLint {
|
|
@@ -692,6 +719,20 @@ class CLIEngine {
|
|
|
692
719
|
}
|
|
693
720
|
}
|
|
694
721
|
|
|
722
|
+
const DEFAULT_NATIVE_MAX_BUFFER = 64 * 1024 * 1024;
|
|
723
|
+
|
|
724
|
+
function nativeMaxBuffer(options, env) {
|
|
725
|
+
const configured = options.maxBuffer ?? env.UTOO_LINT_MAX_BUFFER;
|
|
726
|
+
if (configured === undefined || configured === "") {
|
|
727
|
+
return DEFAULT_NATIVE_MAX_BUFFER;
|
|
728
|
+
}
|
|
729
|
+
const value = typeof configured === "number" ? configured : Number(configured);
|
|
730
|
+
if (!Number.isSafeInteger(value) || value <= 0) {
|
|
731
|
+
throw new TypeError("maxBuffer and UTOO_LINT_MAX_BUFFER must be a positive integer byte count");
|
|
732
|
+
}
|
|
733
|
+
return value;
|
|
734
|
+
}
|
|
735
|
+
|
|
695
736
|
function run(args = [], options = {}) {
|
|
696
737
|
const cliArgs = normalizeStringArray(args, "args");
|
|
697
738
|
const env = options.env ? { ...process.env, ...options.env } : process.env;
|
|
@@ -702,7 +743,8 @@ function run(args = [], options = {}) {
|
|
|
702
743
|
env,
|
|
703
744
|
encoding: options.encoding ?? "utf8",
|
|
704
745
|
input: options.input,
|
|
705
|
-
stdio: options.stdio
|
|
746
|
+
stdio: options.stdio,
|
|
747
|
+
maxBuffer: nativeMaxBuffer(options, env)
|
|
706
748
|
});
|
|
707
749
|
}
|
|
708
750
|
|
|
@@ -844,8 +886,9 @@ function runCli(args = [], options = {}) {
|
|
|
844
886
|
extraArgs: parsed.passthroughArgs,
|
|
845
887
|
preserveNativeDefaults: Boolean(parsed.options.noConfig)
|
|
846
888
|
});
|
|
847
|
-
const
|
|
848
|
-
const
|
|
889
|
+
const usesDefaultTargets = parsed.targets.length === 0;
|
|
890
|
+
const targets = usesDefaultTargets ? defaultLintTargets(cliOptions) : parsed.targets;
|
|
891
|
+
const report = lintFiles(targets, { ...cliOptions, useDefaultConfigTargets: usesDefaultTargets });
|
|
849
892
|
report.diagnostics = normalizeReportDiagnostics(report.diagnostics, cliOptions);
|
|
850
893
|
report.exitCode = exitCodeForDiagnostics(report.diagnostics);
|
|
851
894
|
const status = report.exitCode ?? exitCodeForDiagnostics(report.diagnostics);
|
|
@@ -953,7 +996,8 @@ function runFishlint(args = [], options = {}) {
|
|
|
953
996
|
env,
|
|
954
997
|
encoding: options.encoding ?? "utf8",
|
|
955
998
|
input: options.input,
|
|
956
|
-
stdio: options.stdio
|
|
999
|
+
stdio: options.stdio,
|
|
1000
|
+
maxBuffer: nativeMaxBuffer(options, env)
|
|
957
1001
|
});
|
|
958
1002
|
}
|
|
959
1003
|
|
|
@@ -1155,9 +1199,13 @@ function booleanFlagValue(arg) {
|
|
|
1155
1199
|
|
|
1156
1200
|
function lintFiles(paths, options = {}) {
|
|
1157
1201
|
options = withConfigCache(options);
|
|
1202
|
+
const usesDefaultTargets = paths == null || options.useDefaultConfigTargets;
|
|
1158
1203
|
const targets = lintTargetsForInput(paths, options);
|
|
1159
1204
|
const ignoredDiagnostics = ignoredLintPathDiagnostics(targets, options);
|
|
1160
|
-
|
|
1205
|
+
let lintPaths = filteredLintPaths(targets, options);
|
|
1206
|
+
if (usesDefaultTargets) {
|
|
1207
|
+
lintPaths = filterDefaultConfigLintPaths(lintPaths, options);
|
|
1208
|
+
}
|
|
1161
1209
|
if (lintPaths.length === 0) {
|
|
1162
1210
|
return { files: 0, filePaths: [], diagnostics: ignoredDiagnostics, suppressedDiagnostics: [], exitCode: exitCodeForDiagnostics(ignoredDiagnostics) };
|
|
1163
1211
|
}
|
|
@@ -1247,13 +1295,15 @@ function nativeConfigRunsForFiles(paths, options) {
|
|
|
1247
1295
|
const fileConfigPath = options.noConfig ? undefined : configPathForFile(options, matchPath);
|
|
1248
1296
|
const configured = Boolean(options.baseConfig || options.overrideConfig || fileConfigPath);
|
|
1249
1297
|
hasConfigSource ||= configured;
|
|
1250
|
-
|
|
1298
|
+
const calculated = configured ? calculatedConfig({ ...options, rules: undefined }, matchPath) : {};
|
|
1299
|
+
let rules = calculated.rules;
|
|
1300
|
+
const settings = calculated.settings;
|
|
1251
1301
|
if (configured && options.rules) {
|
|
1252
1302
|
rules = selectedRulesWithConfigOptions(rules, options.rules);
|
|
1253
1303
|
}
|
|
1254
|
-
const signature = configured ? stableConfigSignature(rules) : "<native-defaults>";
|
|
1304
|
+
const signature = configured ? stableConfigSignature({ rules, settings }) : "<native-defaults>";
|
|
1255
1305
|
if (!groups.has(signature)) {
|
|
1256
|
-
groups.set(signature, { paths: [], rules, configured });
|
|
1306
|
+
groups.set(signature, { paths: [], rules, settings, configured });
|
|
1257
1307
|
}
|
|
1258
1308
|
groups.get(signature).paths.push(filePath);
|
|
1259
1309
|
}
|
|
@@ -1283,7 +1333,10 @@ function nativeConfigRunsForFiles(paths, options) {
|
|
|
1283
1333
|
config: undefined,
|
|
1284
1334
|
noConfig: true,
|
|
1285
1335
|
baseConfig: undefined,
|
|
1286
|
-
overrideConfig: {
|
|
1336
|
+
overrideConfig: {
|
|
1337
|
+
rules: allDisabledNativeRules(group.rules),
|
|
1338
|
+
...(group.settings ? { settings: group.settings } : {})
|
|
1339
|
+
},
|
|
1287
1340
|
forceMaterializedConfig: true
|
|
1288
1341
|
}
|
|
1289
1342
|
};
|
|
@@ -1512,12 +1565,12 @@ function calculatedConfig(options = {}, filePath) {
|
|
|
1512
1565
|
);
|
|
1513
1566
|
return {
|
|
1514
1567
|
...configData,
|
|
1515
|
-
rules:
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1568
|
+
rules: mergeRuleConfigMaps(
|
|
1569
|
+
rulesFromConfig(options.baseConfig, filePath, options.cwd),
|
|
1570
|
+
rulesFromFileConfig(options, filePath),
|
|
1571
|
+
rulesFromConfig(options.overrideConfig, filePath, options.cwd),
|
|
1572
|
+
rulesFromNativeRuleList(options.rules)
|
|
1573
|
+
)
|
|
1521
1574
|
};
|
|
1522
1575
|
}
|
|
1523
1576
|
|
|
@@ -1612,10 +1665,10 @@ function rulesFromConfig(config, filePath, cwd) {
|
|
|
1612
1665
|
return {};
|
|
1613
1666
|
}
|
|
1614
1667
|
if (Array.isArray(config)) {
|
|
1615
|
-
return config.reduce(
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1668
|
+
return config.reduce(
|
|
1669
|
+
(rules, entry) => mergeRuleConfigMaps(rules, rulesFromConfig(entry, filePath, cwd)),
|
|
1670
|
+
{}
|
|
1671
|
+
);
|
|
1619
1672
|
}
|
|
1620
1673
|
if (!configAppliesToFile(config, filePath, cwd)) {
|
|
1621
1674
|
return {};
|
|
@@ -1668,12 +1721,64 @@ function defaultLintTargets(options = {}) {
|
|
|
1668
1721
|
return ["."];
|
|
1669
1722
|
}
|
|
1670
1723
|
|
|
1671
|
-
const
|
|
1724
|
+
const config = readConfig(configPath, options.cwd, options.configCache);
|
|
1725
|
+
if (configHasUnscopedRules(config)) {
|
|
1726
|
+
return ["."];
|
|
1727
|
+
}
|
|
1728
|
+
|
|
1729
|
+
const targets = filePatternsFromConfig(config);
|
|
1672
1730
|
return targets.length > 0
|
|
1673
1731
|
? targets.map((target) => resolveConfigPattern(target, dirname(configPath)))
|
|
1674
1732
|
: ["."];
|
|
1675
1733
|
}
|
|
1676
1734
|
|
|
1735
|
+
function filterDefaultConfigLintPaths(paths, options) {
|
|
1736
|
+
const configPath = configPathForOptions(options);
|
|
1737
|
+
if (!configPath) {
|
|
1738
|
+
return paths;
|
|
1739
|
+
}
|
|
1740
|
+
const config = readConfig(configPath, options.cwd, options.configCache);
|
|
1741
|
+
if (!configHasFileSelectors(config)) {
|
|
1742
|
+
return paths;
|
|
1743
|
+
}
|
|
1744
|
+
const cwd = dirname(configPath);
|
|
1745
|
+
return paths.filter((filePath) => configSelectsFile(config, filePath, cwd));
|
|
1746
|
+
}
|
|
1747
|
+
|
|
1748
|
+
function configHasFileSelectors(config) {
|
|
1749
|
+
if (Array.isArray(config)) {
|
|
1750
|
+
return config.some(configHasFileSelectors);
|
|
1751
|
+
}
|
|
1752
|
+
return Boolean(config && typeof config === "object" && normalizeConfigFileSelectors(config.files).length > 0);
|
|
1753
|
+
}
|
|
1754
|
+
|
|
1755
|
+
function configHasUnscopedRules(config) {
|
|
1756
|
+
if (Array.isArray(config)) {
|
|
1757
|
+
return config.some(configHasUnscopedRules);
|
|
1758
|
+
}
|
|
1759
|
+
return Boolean(
|
|
1760
|
+
config &&
|
|
1761
|
+
typeof config === "object" &&
|
|
1762
|
+
normalizeConfigFileSelectors(config.files).length === 0 &&
|
|
1763
|
+
config.rules &&
|
|
1764
|
+
typeof config.rules === "object" &&
|
|
1765
|
+
Object.keys(config.rules).length > 0
|
|
1766
|
+
);
|
|
1767
|
+
}
|
|
1768
|
+
|
|
1769
|
+
function configSelectsFile(config, filePath, cwd) {
|
|
1770
|
+
if (Array.isArray(config)) {
|
|
1771
|
+
return config.some((entry) => configSelectsFile(entry, filePath, cwd));
|
|
1772
|
+
}
|
|
1773
|
+
if (!config || typeof config !== "object") {
|
|
1774
|
+
return false;
|
|
1775
|
+
}
|
|
1776
|
+
const selectors = normalizeConfigFileSelectors(config.files);
|
|
1777
|
+
return selectors.length > 0
|
|
1778
|
+
? configAppliesToFile(config, filePath, cwd)
|
|
1779
|
+
: configHasUnscopedRules(config) && configAppliesToFile(config, filePath, cwd);
|
|
1780
|
+
}
|
|
1781
|
+
|
|
1677
1782
|
function resolveConfigPattern(pattern, configDirectory) {
|
|
1678
1783
|
if (isAbsolute(pattern)) {
|
|
1679
1784
|
return pattern;
|
|
@@ -1697,8 +1802,10 @@ function configAppliesToFile(config, filePath, cwd) {
|
|
|
1697
1802
|
}
|
|
1698
1803
|
|
|
1699
1804
|
const normalized = normalizeIgnoredPath(filePath, cwd ?? process.cwd());
|
|
1700
|
-
const files =
|
|
1701
|
-
if (files.length > 0 && !files.some((
|
|
1805
|
+
const files = normalizeConfigFileSelectors(config.files);
|
|
1806
|
+
if (files.length > 0 && !files.some((selector) => selector.every(
|
|
1807
|
+
(pattern) => matchesConfigFilePattern(normalized, normalizeIgnoredPattern(pattern))
|
|
1808
|
+
))) {
|
|
1702
1809
|
return false;
|
|
1703
1810
|
}
|
|
1704
1811
|
|
|
@@ -1706,6 +1813,23 @@ function configAppliesToFile(config, filePath, cwd) {
|
|
|
1706
1813
|
return !pathIgnoredByPatterns(normalized, ignores);
|
|
1707
1814
|
}
|
|
1708
1815
|
|
|
1816
|
+
function normalizeConfigFileSelectors(patterns) {
|
|
1817
|
+
if (!patterns) {
|
|
1818
|
+
return [];
|
|
1819
|
+
}
|
|
1820
|
+
const values = Array.isArray(patterns) ? patterns : [patterns];
|
|
1821
|
+
return values.flatMap((value) => {
|
|
1822
|
+
if (typeof value === "string") {
|
|
1823
|
+
return [[value]];
|
|
1824
|
+
}
|
|
1825
|
+
if (Array.isArray(value)) {
|
|
1826
|
+
const selector = normalizeConfigPatterns(value);
|
|
1827
|
+
return selector.length > 0 ? [selector] : [];
|
|
1828
|
+
}
|
|
1829
|
+
return [];
|
|
1830
|
+
});
|
|
1831
|
+
}
|
|
1832
|
+
|
|
1709
1833
|
function normalizeConfigPatterns(patterns) {
|
|
1710
1834
|
if (!patterns) {
|
|
1711
1835
|
return [];
|
|
@@ -1767,7 +1891,15 @@ function withTemporaryConfig(options, callback) {
|
|
|
1767
1891
|
const rules = shouldMaterializeFileConfig
|
|
1768
1892
|
? materializedRulesFromConfigs(...configs)
|
|
1769
1893
|
: runtimeRulesFromConfigs(...configs);
|
|
1770
|
-
|
|
1894
|
+
const settings = configs.reduce(
|
|
1895
|
+
(result, config) => ({
|
|
1896
|
+
...result,
|
|
1897
|
+
...(configDataFromConfig(config, options.filePath ?? options.filename, options.cwd).settings ?? {})
|
|
1898
|
+
}),
|
|
1899
|
+
{}
|
|
1900
|
+
);
|
|
1901
|
+
const hasSettings = Object.keys(settings).length > 0;
|
|
1902
|
+
if (Object.keys(rules).length === 0 && !hasSettings) {
|
|
1771
1903
|
if (shouldMaterializeFileConfig) {
|
|
1772
1904
|
return callback({
|
|
1773
1905
|
...options,
|
|
@@ -1779,7 +1911,7 @@ function withTemporaryConfig(options, callback) {
|
|
|
1779
1911
|
}
|
|
1780
1912
|
const enabledRules = enabledRuleNamesFromConfigs(...configs);
|
|
1781
1913
|
const hasExplicitOffRules = Object.values(rules).some((value) => ruleConfigSeverity(value) === 0);
|
|
1782
|
-
if (!shouldMaterializeFileConfig && !hasRuleOptions(rules) && !hasExplicitOffRules && !options.forceMaterializedConfig) {
|
|
1914
|
+
if (!shouldMaterializeFileConfig && !hasSettings && !hasRuleOptions(rules) && !hasExplicitOffRules && !options.forceMaterializedConfig) {
|
|
1783
1915
|
return callback({
|
|
1784
1916
|
...options,
|
|
1785
1917
|
config: shouldMaterializeFileConfig ? undefined : options.config,
|
|
@@ -1791,7 +1923,7 @@ function withTemporaryConfig(options, callback) {
|
|
|
1791
1923
|
const tmp = mkdtempSync(join(tmpdir(), "utoo-lint-config-"));
|
|
1792
1924
|
const configPath = join(tmp, "utlint.config.json");
|
|
1793
1925
|
try {
|
|
1794
|
-
writeFileSync(configPath, JSON.stringify({ rules }));
|
|
1926
|
+
writeFileSync(configPath, JSON.stringify({ rules, ...(hasSettings ? { settings } : {}) }));
|
|
1795
1927
|
return callback({
|
|
1796
1928
|
...options,
|
|
1797
1929
|
config: shouldMaterializeFileConfig ? configPath : options.config ?? configPath,
|
|
@@ -1810,11 +1942,7 @@ function enabledRuleNames(rules) {
|
|
|
1810
1942
|
}
|
|
1811
1943
|
|
|
1812
1944
|
function runtimeRulesFromConfigs(...configs) {
|
|
1813
|
-
|
|
1814
|
-
for (const config of configs) {
|
|
1815
|
-
Object.assign(rules, runtimeRulesFromConfig(config));
|
|
1816
|
-
}
|
|
1817
|
-
return rules;
|
|
1945
|
+
return mergeRuleConfigMaps(...configs.map(runtimeRulesFromConfig));
|
|
1818
1946
|
}
|
|
1819
1947
|
|
|
1820
1948
|
function materializedRulesFromConfigs(...configs) {
|
|
@@ -1826,10 +1954,10 @@ function runtimeRulesFromConfig(config) {
|
|
|
1826
1954
|
return {};
|
|
1827
1955
|
}
|
|
1828
1956
|
if (Array.isArray(config)) {
|
|
1829
|
-
return config.reduce(
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1957
|
+
return config.reduce(
|
|
1958
|
+
(rules, entry) => mergeRuleConfigMaps(rules, runtimeRulesFromConfig(entry)),
|
|
1959
|
+
{}
|
|
1960
|
+
);
|
|
1833
1961
|
}
|
|
1834
1962
|
|
|
1835
1963
|
const rules = {};
|
|
@@ -1839,6 +1967,26 @@ function runtimeRulesFromConfig(config) {
|
|
|
1839
1967
|
return rules;
|
|
1840
1968
|
}
|
|
1841
1969
|
|
|
1970
|
+
function mergeRuleConfigMaps(...ruleMaps) {
|
|
1971
|
+
const result = {};
|
|
1972
|
+
for (const rules of ruleMaps) {
|
|
1973
|
+
for (const [ruleId, ruleConfig] of Object.entries(rules ?? {})) {
|
|
1974
|
+
const previous = result[ruleId];
|
|
1975
|
+
if (previous !== undefined && isSeverityOnlyRuleConfig(ruleConfig) && Array.isArray(previous) && previous.length > 1) {
|
|
1976
|
+
const severity = Array.isArray(ruleConfig) ? ruleConfig[0] : ruleConfig;
|
|
1977
|
+
result[ruleId] = [severity, ...previous.slice(1)];
|
|
1978
|
+
} else {
|
|
1979
|
+
result[ruleId] = ruleConfig;
|
|
1980
|
+
}
|
|
1981
|
+
}
|
|
1982
|
+
}
|
|
1983
|
+
return result;
|
|
1984
|
+
}
|
|
1985
|
+
|
|
1986
|
+
function isSeverityOnlyRuleConfig(ruleConfig) {
|
|
1987
|
+
return !Array.isArray(ruleConfig) || ruleConfig.length === 1;
|
|
1988
|
+
}
|
|
1989
|
+
|
|
1842
1990
|
function enabledRuleNamesFromConfigs(...configs) {
|
|
1843
1991
|
const rules = new Set();
|
|
1844
1992
|
for (const config of configs) {
|
|
@@ -2028,7 +2176,7 @@ function parserOptionsForConfig(config, filePath, cwd) {
|
|
|
2028
2176
|
|
|
2029
2177
|
function customRuleEntriesForConfig(config, rules, filePath, cwd) {
|
|
2030
2178
|
const entries = new Map();
|
|
2031
|
-
for (const [ruleId, ruleConfig] of
|
|
2179
|
+
for (const [ruleId, ruleConfig] of Object.entries(rulesFromConfig(config, filePath, cwd))) {
|
|
2032
2180
|
if (!rules.has(ruleId)) {
|
|
2033
2181
|
continue;
|
|
2034
2182
|
}
|
|
@@ -2085,19 +2233,6 @@ function matchingConfigEntries(config, filePath = undefined, cwd = undefined) {
|
|
|
2085
2233
|
return [config];
|
|
2086
2234
|
}
|
|
2087
2235
|
|
|
2088
|
-
function ruleConfigEntries(config, filePath = undefined, cwd = undefined) {
|
|
2089
|
-
if (Array.isArray(config)) {
|
|
2090
|
-
return config.flatMap((item) => ruleConfigEntries(item, filePath, cwd));
|
|
2091
|
-
}
|
|
2092
|
-
if (!config || typeof config !== "object" || !config.rules || typeof config.rules !== "object") {
|
|
2093
|
-
return [];
|
|
2094
|
-
}
|
|
2095
|
-
if (!configAppliesToFile(config, filePath, cwd)) {
|
|
2096
|
-
return [];
|
|
2097
|
-
}
|
|
2098
|
-
return Object.entries(config.rules);
|
|
2099
|
-
}
|
|
2100
|
-
|
|
2101
2236
|
function configWithoutCustomRules(config, rules) {
|
|
2102
2237
|
if (Array.isArray(config)) {
|
|
2103
2238
|
return config.map((item) => configWithoutCustomRules(item, rules));
|
|
@@ -3398,10 +3533,7 @@ function mergeRuleTesterConfig(baseConfig, overrideConfig) {
|
|
|
3398
3533
|
return {
|
|
3399
3534
|
...baseConfig,
|
|
3400
3535
|
...overrideConfig,
|
|
3401
|
-
rules:
|
|
3402
|
-
...(baseConfig.rules ?? {}),
|
|
3403
|
-
...(overrideConfig.rules ?? {})
|
|
3404
|
-
}
|
|
3536
|
+
rules: mergeRuleConfigMaps(baseConfig.rules, overrideConfig.rules)
|
|
3405
3537
|
};
|
|
3406
3538
|
}
|
|
3407
3539
|
|
|
@@ -4055,7 +4187,7 @@ function collectGlobFiles(target, cwd, patterns, expression, files) {
|
|
|
4055
4187
|
|
|
4056
4188
|
const child = join(target, entry.name);
|
|
4057
4189
|
if (entry.isDirectory()) {
|
|
4058
|
-
if (
|
|
4190
|
+
if (shouldTraverseDirectory(normalizeIgnoredPath(child, cwd), patterns)) {
|
|
4059
4191
|
collectGlobFiles(child, cwd, patterns, expression, files);
|
|
4060
4192
|
}
|
|
4061
4193
|
continue;
|
|
@@ -4125,7 +4257,7 @@ function expandLintTarget(target, cwd, patterns) {
|
|
|
4125
4257
|
if (stat.isFile()) {
|
|
4126
4258
|
return isLintableFilePath(target) && !pathIgnoredByPatterns(normalizeIgnoredPath(target, cwd), patterns) ? [target] : [];
|
|
4127
4259
|
}
|
|
4128
|
-
if (!stat.isDirectory() ||
|
|
4260
|
+
if (!stat.isDirectory() || !shouldTraverseDirectory(normalizeIgnoredPath(target, cwd), patterns)) {
|
|
4129
4261
|
return [];
|
|
4130
4262
|
}
|
|
4131
4263
|
|
|
@@ -4143,7 +4275,7 @@ function collectLintableFiles(target, cwd, patterns, files) {
|
|
|
4143
4275
|
|
|
4144
4276
|
const child = join(target, entry.name);
|
|
4145
4277
|
if (entry.isDirectory()) {
|
|
4146
|
-
if (
|
|
4278
|
+
if (shouldTraverseDirectory(normalizeIgnoredPath(child, cwd), patterns)) {
|
|
4147
4279
|
collectLintableFiles(child, cwd, patterns, files);
|
|
4148
4280
|
}
|
|
4149
4281
|
continue;
|
|
@@ -4276,7 +4408,7 @@ function normalizeIgnoredPath(filePath, cwd) {
|
|
|
4276
4408
|
}
|
|
4277
4409
|
|
|
4278
4410
|
function normalizeIgnoredPattern(pattern) {
|
|
4279
|
-
return normalizePath(pattern.replace(/^!/, "")
|
|
4411
|
+
return normalizePath(pattern.replace(/^!/, "")).replace(/\/+$/, "");
|
|
4280
4412
|
}
|
|
4281
4413
|
|
|
4282
4414
|
function pathIgnoredByPatterns(target, patterns) {
|
|
@@ -4290,10 +4422,55 @@ function pathIgnoredByPatterns(target, patterns) {
|
|
|
4290
4422
|
return ignored;
|
|
4291
4423
|
}
|
|
4292
4424
|
|
|
4425
|
+
function shouldTraverseDirectory(target, patterns) {
|
|
4426
|
+
return !pathIgnoredByPatterns(target, patterns) || patterns.some(
|
|
4427
|
+
(pattern) => pattern.startsWith("!") && negatedPatternMayMatchDescendant(target, pattern)
|
|
4428
|
+
);
|
|
4429
|
+
}
|
|
4430
|
+
|
|
4431
|
+
function negatedPatternMayMatchDescendant(target, pattern) {
|
|
4432
|
+
pattern = normalizeIgnoredPattern(pattern);
|
|
4433
|
+
if (pattern.startsWith("/")) {
|
|
4434
|
+
pattern = pattern.slice(1);
|
|
4435
|
+
if (target.startsWith("/")) {
|
|
4436
|
+
target = target.slice(1);
|
|
4437
|
+
}
|
|
4438
|
+
}
|
|
4439
|
+
if (!pattern.includes("/")) {
|
|
4440
|
+
return true;
|
|
4441
|
+
}
|
|
4442
|
+
|
|
4443
|
+
const directoryPattern = pattern.slice(0, pattern.lastIndexOf("/"));
|
|
4444
|
+
if (hasGlobSyntax(directoryPattern)) {
|
|
4445
|
+
const directoryExpression = new RegExp(`^${globPatternRegExpSource(directoryPattern)}(?:/.*)?$`);
|
|
4446
|
+
if (directoryExpression.test(target)) {
|
|
4447
|
+
return true;
|
|
4448
|
+
}
|
|
4449
|
+
}
|
|
4450
|
+
|
|
4451
|
+
const globIndex = pattern.search(/[*?[{]/u);
|
|
4452
|
+
const staticPrefix = (globIndex === -1 ? pattern : pattern.slice(0, globIndex)).replace(/\/+$/u, "");
|
|
4453
|
+
return !staticPrefix ||
|
|
4454
|
+
staticPrefix === target ||
|
|
4455
|
+
staticPrefix.startsWith(`${target}/`) ||
|
|
4456
|
+
target.startsWith(`${staticPrefix}/`);
|
|
4457
|
+
}
|
|
4458
|
+
|
|
4293
4459
|
function matchesIgnorePattern(target, pattern) {
|
|
4460
|
+
const anchored = pattern.startsWith("/");
|
|
4461
|
+
if (anchored) {
|
|
4462
|
+
pattern = pattern.slice(1);
|
|
4463
|
+
if (target.startsWith("/")) {
|
|
4464
|
+
target = target.slice(1);
|
|
4465
|
+
}
|
|
4466
|
+
}
|
|
4294
4467
|
if (pattern.endsWith("/**")) {
|
|
4295
|
-
const
|
|
4296
|
-
|
|
4468
|
+
const directoryPattern = pattern.slice(0, -3);
|
|
4469
|
+
if (hasGlobSyntax(directoryPattern)) {
|
|
4470
|
+
const expression = new RegExp(`^${globPatternRegExpSource(directoryPattern)}(?:/.*)?$`);
|
|
4471
|
+
return expression.test(target);
|
|
4472
|
+
}
|
|
4473
|
+
return target === directoryPattern || target.startsWith(`${directoryPattern}/`);
|
|
4297
4474
|
}
|
|
4298
4475
|
if (pattern.startsWith("**/")) {
|
|
4299
4476
|
const suffix = pattern.slice(3);
|
|
@@ -4302,10 +4479,14 @@ function matchesIgnorePattern(target, pattern) {
|
|
|
4302
4479
|
}
|
|
4303
4480
|
}
|
|
4304
4481
|
if (!hasGlobSyntax(pattern)) {
|
|
4482
|
+
if (anchored || pattern.includes("/")) {
|
|
4483
|
+
return target === pattern || target.startsWith(`${pattern}/`);
|
|
4484
|
+
}
|
|
4305
4485
|
return target === pattern || target.endsWith(`/${pattern}`) || target.startsWith(`${pattern}/`);
|
|
4306
4486
|
}
|
|
4307
4487
|
|
|
4308
|
-
const
|
|
4488
|
+
const prefix = anchored || pattern.includes("/") ? "^" : "(^|/)";
|
|
4489
|
+
const expression = new RegExp(`${prefix}${globPatternRegExpSource(pattern)}$`);
|
|
4309
4490
|
return expression.test(target);
|
|
4310
4491
|
}
|
|
4311
4492
|
|
|
@@ -4414,6 +4595,9 @@ function ruleMetaForRuleId(ruleId) {
|
|
|
4414
4595
|
if (FIXABLE_BUILTIN_RULE_IDS.has(ruleId)) {
|
|
4415
4596
|
meta.fixable = "code";
|
|
4416
4597
|
}
|
|
4598
|
+
if (SUGGESTION_BUILTIN_RULE_IDS.has(ruleId)) {
|
|
4599
|
+
meta.hasSuggestions = true;
|
|
4600
|
+
}
|
|
4417
4601
|
return meta;
|
|
4418
4602
|
}
|
|
4419
4603
|
|
|
@@ -4504,6 +4688,21 @@ function diagnosticToESLintMessage(diagnostic, ruleSeverities) {
|
|
|
4504
4688
|
if (fixes.length > 0) {
|
|
4505
4689
|
message.fix = fixes.length === 1 ? fixes[0] : fixes;
|
|
4506
4690
|
}
|
|
4691
|
+
const suggestions = (diagnostic.suggestions ?? []).map((suggestion) => {
|
|
4692
|
+
const suggestionFixes = (suggestion.fix ?? []).map((fix) => ({
|
|
4693
|
+
range: fix.range,
|
|
4694
|
+
text: fix.text
|
|
4695
|
+
}));
|
|
4696
|
+
return {
|
|
4697
|
+
desc: suggestion.desc,
|
|
4698
|
+
...(suggestionFixes.length === 0 ? {} : {
|
|
4699
|
+
fix: suggestionFixes.length === 1 ? suggestionFixes[0] : suggestionFixes
|
|
4700
|
+
})
|
|
4701
|
+
};
|
|
4702
|
+
});
|
|
4703
|
+
if (suggestions.length > 0) {
|
|
4704
|
+
message.suggestions = suggestions;
|
|
4705
|
+
}
|
|
4507
4706
|
return message;
|
|
4508
4707
|
}
|
|
4509
4708
|
|
package/index.d.ts
CHANGED
|
@@ -67,13 +67,24 @@ export interface PluginObject {
|
|
|
67
67
|
[key: string]: unknown;
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
+
export interface JestPluginSettings {
|
|
71
|
+
version?: string | number;
|
|
72
|
+
globalAliases?: Record<string, string[]>;
|
|
73
|
+
[key: string]: unknown;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export interface SharedSettings {
|
|
77
|
+
jest?: JestPluginSettings;
|
|
78
|
+
[key: string]: unknown;
|
|
79
|
+
}
|
|
80
|
+
|
|
70
81
|
export interface ConfigObject {
|
|
71
82
|
name?: string;
|
|
72
83
|
files?: Array<string | string[]>;
|
|
73
84
|
ignores?: string[];
|
|
74
85
|
rules?: Record<string, RuleConfig>;
|
|
75
86
|
plugins?: Record<string, PluginObject>;
|
|
76
|
-
settings?:
|
|
87
|
+
settings?: SharedSettings;
|
|
77
88
|
languageOptions?: {
|
|
78
89
|
parser?: unknown;
|
|
79
90
|
parserOptions?: Record<string, unknown>;
|
|
@@ -93,6 +104,8 @@ export interface LintOptions {
|
|
|
93
104
|
cwd?: string;
|
|
94
105
|
binary?: string;
|
|
95
106
|
env?: Record<string, string | undefined>;
|
|
107
|
+
/** Maximum bytes captured from each native stdout/stderr stream. Defaults to 64 MiB. */
|
|
108
|
+
maxBuffer?: number;
|
|
96
109
|
threads?: number;
|
|
97
110
|
rules?: string[] | string;
|
|
98
111
|
format?: "text" | "json" | string;
|