@utoo/lint 0.3.5 → 0.3.7
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 +20 -0
- package/index.cjs +74 -17
- package/index.js +74 -17
- package/lib/legacy-config.cjs +76 -0
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -248,6 +248,26 @@ Raw reports include active diagnostics, suppressed diagnostics, fixed outputs,
|
|
|
248
248
|
and an exit code. The compatibility layer also exports `Linter`, `CLIEngine`,
|
|
249
249
|
`RuleTester`, and `SourceCode` APIs.
|
|
250
250
|
|
|
251
|
+
Native JSON diagnostics and ESLint-compatible messages include one-based `line`,
|
|
252
|
+
`column`, `endLine`, and `endColumn` positions for source spans. Columns count
|
|
253
|
+
UTF-16 code units, and the end position is exclusive. Suppressed diagnostics keep
|
|
254
|
+
the same range. I/O errors without a source span omit the end positions; messages
|
|
255
|
+
from older native binaries may also omit them.
|
|
256
|
+
|
|
257
|
+
`ESLint` and `CLIEngine` also discover classic `.eslintrc.*` files (or
|
|
258
|
+
`eslintConfig` in `package.json`) when no native config applies. Legacy
|
|
259
|
+
`extends`, directory cascades, `root`, `overrides`, and ignore patterns are
|
|
260
|
+
resolved per source filename. Precedence is `baseConfig`, project config,
|
|
261
|
+
then `overrideConfig`; `useEslintrc: false` disables discovery. Native config
|
|
262
|
+
files still take priority. The lower-level `lintFiles`, `lintText`, and native
|
|
263
|
+
CLI keep their native-only discovery behavior.
|
|
264
|
+
|
|
265
|
+
Legacy configuration resolution uses `@eslint/eslintrc`. If the project has
|
|
266
|
+
ESLint 8 installed, its configuration resolver is used instead to support
|
|
267
|
+
shared configs that patch ESLint's module resolution. Neither path uses ESLint
|
|
268
|
+
to parse or lint source files: rules still run in utoo-lint. Enabled rules that
|
|
269
|
+
utoo-lint does not support remain errors, not silently skipped checks.
|
|
270
|
+
|
|
251
271
|
The Node wrapper captures up to 64 MiB from each native stdout and stderr
|
|
252
272
|
stream by default. Programmatic `run`, `runCli`, and `runFishlint` calls can set
|
|
253
273
|
`maxBuffer` to another positive byte count. Set `UTOO_LINT_MAX_BUFFER` to apply
|
package/index.cjs
CHANGED
|
@@ -5,6 +5,7 @@ const { tmpdir } = require("node:os");
|
|
|
5
5
|
const { dirname, extname, isAbsolute, join, relative, resolve: resolvePath } = require("node:path");
|
|
6
6
|
|
|
7
7
|
const { platformPackageName, resolveBinary } = require("./lib/binary.cjs");
|
|
8
|
+
const { createLegacyConfigResolver } = require("./lib/legacy-config.cjs");
|
|
8
9
|
const {
|
|
9
10
|
findConfigPath: findConfigPathFromDirectory,
|
|
10
11
|
readConfig
|
|
@@ -15,6 +16,8 @@ const version = JSON.parse(readFileSync(join(__dirname, "package.json"), "utf8")
|
|
|
15
16
|
const LINTABLE_EXTENSIONS = new Set([".js", ".jsx", ".ts", ".tsx", ".mjs", ".cjs", ".mts", ".cts"]);
|
|
16
17
|
const MAX_AUTOFIX_PASSES = 10;
|
|
17
18
|
const CONFIG_DISCOVERY_CACHE = Symbol("configDiscoveryCache");
|
|
19
|
+
const LEGACY_CONFIG_ENABLED = Symbol("legacyConfigEnabled");
|
|
20
|
+
const LEGACY_CONFIG_RESOLVER = Symbol("legacyConfigResolver");
|
|
18
21
|
const JS_KEYWORDS = new Set([
|
|
19
22
|
"await", "break", "case", "catch", "class", "const", "continue", "debugger", "default", "delete",
|
|
20
23
|
"do", "else", "export", "extends", "finally", "for", "function", "if", "import", "in",
|
|
@@ -415,6 +418,7 @@ const BUILTIN_RULE_IDS = [
|
|
|
415
418
|
"@typescript-eslint/no-duplicate-enum-values",
|
|
416
419
|
"@typescript-eslint/no-extra-semi",
|
|
417
420
|
"@typescript-eslint/no-extra-non-null-assertion",
|
|
421
|
+
"@typescript-eslint/no-explicit-any",
|
|
418
422
|
"@typescript-eslint/no-inferrable-types",
|
|
419
423
|
"@typescript-eslint/no-invalid-void-type",
|
|
420
424
|
"@typescript-eslint/no-loop-func",
|
|
@@ -472,6 +476,7 @@ const NATIVE_ONLY_RULE_IDS = [
|
|
|
472
476
|
];
|
|
473
477
|
const NATIVE_RULE_IDS = [...BUILTIN_RULE_IDS, ...NATIVE_ONLY_RULE_IDS];
|
|
474
478
|
const FIXABLE_BUILTIN_RULE_IDS = new Set([
|
|
479
|
+
"@typescript-eslint/no-explicit-any",
|
|
475
480
|
"jest/no-deprecated-functions",
|
|
476
481
|
"jest/no-jasmine-globals",
|
|
477
482
|
"no-extra-semi",
|
|
@@ -479,6 +484,7 @@ const FIXABLE_BUILTIN_RULE_IDS = new Set([
|
|
|
479
484
|
"unused-imports/no-unused-imports"
|
|
480
485
|
]);
|
|
481
486
|
const SUGGESTION_BUILTIN_RULE_IDS = new Set([
|
|
487
|
+
"@typescript-eslint/no-explicit-any",
|
|
482
488
|
"jest/no-focused-tests"
|
|
483
489
|
]);
|
|
484
490
|
const BUILTIN_RULES = new Map(BUILTIN_RULE_IDS.map((ruleId) => [ruleId, createBuiltinRule(ruleId)]));
|
|
@@ -579,6 +585,9 @@ class UtooLint {
|
|
|
579
585
|
|
|
580
586
|
async findConfigFile(filePath) {
|
|
581
587
|
const options = withConfigCache(eslintConstructorOptions(this.options));
|
|
588
|
+
if (options.legacyConfigFile) {
|
|
589
|
+
return resolvePath(options.cwd ?? process.cwd(), options.legacyConfigFile);
|
|
590
|
+
}
|
|
582
591
|
if (options.noConfig) {
|
|
583
592
|
return undefined;
|
|
584
593
|
}
|
|
@@ -1207,6 +1216,9 @@ function lintFiles(paths, options = {}) {
|
|
|
1207
1216
|
if (usesDefaultTargets) {
|
|
1208
1217
|
lintPaths = filterDefaultConfigLintPaths(lintPaths, options);
|
|
1209
1218
|
}
|
|
1219
|
+
if (options[LEGACY_CONFIG_ENABLED] && (!options.noConfig || options.legacyConfigFile) && !options.deferDiagnosticConfigFiltering) {
|
|
1220
|
+
lintPaths = expandNativeConfigRunPaths(lintPaths, options).filter((filePath) => !isPathIgnored(filePath, options));
|
|
1221
|
+
}
|
|
1210
1222
|
if (lintPaths.length === 0) {
|
|
1211
1223
|
return { files: 0, filePaths: [], diagnostics: ignoredDiagnostics, suppressedDiagnostics: [], exitCode: exitCodeForDiagnostics(ignoredDiagnostics) };
|
|
1212
1224
|
}
|
|
@@ -1230,6 +1242,10 @@ function lintFiles(paths, options = {}) {
|
|
|
1230
1242
|
}
|
|
1231
1243
|
|
|
1232
1244
|
function nativeFlatConfigOptions(options) {
|
|
1245
|
+
if (defersLegacyIgnores(options)) {
|
|
1246
|
+
// A legacy config may cascade from a nested directory even with baseConfig.
|
|
1247
|
+
return undefined;
|
|
1248
|
+
}
|
|
1233
1249
|
if (options.rules || options.extraArgs?.some((arg) => arg.startsWith("--") && arg !== "--fix" && arg !== "--fix-dry-run")) {
|
|
1234
1250
|
return undefined;
|
|
1235
1251
|
}
|
|
@@ -1301,7 +1317,7 @@ function nativeSerializableConfig(config) {
|
|
|
1301
1317
|
|
|
1302
1318
|
function expandNativeConfigRunPaths(paths, options) {
|
|
1303
1319
|
const cwd = options.cwd ?? process.cwd();
|
|
1304
|
-
const patterns = ignoreDisabled(options) ? [] : ignorePatternsForOptions(options, cwd);
|
|
1320
|
+
const patterns = ignoreDisabled(options) || defersLegacyIgnores(options) ? [] : ignorePatternsForOptions(options, cwd);
|
|
1305
1321
|
return paths.flatMap((path) => expandLintTarget(path, cwd, patterns) ?? [path]);
|
|
1306
1322
|
}
|
|
1307
1323
|
|
|
@@ -1359,7 +1375,7 @@ function finalizeLintReport(report, ignoredDiagnostics, options) {
|
|
|
1359
1375
|
}
|
|
1360
1376
|
|
|
1361
1377
|
function nativeConfigRunsForFiles(paths, options) {
|
|
1362
|
-
if (options.noConfig && !options.baseConfig && !options.overrideConfig) {
|
|
1378
|
+
if (options.noConfig && !options.legacyConfigFile && !options.baseConfig && !options.overrideConfig) {
|
|
1363
1379
|
return undefined;
|
|
1364
1380
|
}
|
|
1365
1381
|
|
|
@@ -1370,7 +1386,7 @@ function nativeConfigRunsForFiles(paths, options) {
|
|
|
1370
1386
|
? options.filePath ?? options.filename ?? filePath
|
|
1371
1387
|
: filePath;
|
|
1372
1388
|
const fileConfigPath = options.noConfig ? undefined : configPathForFile(options, matchPath);
|
|
1373
|
-
const configured = Boolean(options.baseConfig || options.overrideConfig || fileConfigPath);
|
|
1389
|
+
const configured = Boolean(options.baseConfig || options.overrideConfig || fileConfigPath || legacyConfigForFile(options, matchPath));
|
|
1374
1390
|
hasConfigSource ||= configured;
|
|
1375
1391
|
const calculated = configured ? calculatedConfig({ ...options, rules: undefined }, matchPath) : {};
|
|
1376
1392
|
let rules = calculated.rules;
|
|
@@ -1473,7 +1489,9 @@ function isPureRuleSeverity(config) {
|
|
|
1473
1489
|
function allDisabledNativeRules(rules) {
|
|
1474
1490
|
return {
|
|
1475
1491
|
...Object.fromEntries(NATIVE_RULE_IDS.map((rule) => [rule, "off"])),
|
|
1476
|
-
...rules
|
|
1492
|
+
...Object.fromEntries(Object.entries(rules ?? {}).filter(
|
|
1493
|
+
([rule, value]) => NATIVE_RULE_IDS.includes(rule) || ruleConfigSeverity(value) > 0
|
|
1494
|
+
))
|
|
1477
1495
|
};
|
|
1478
1496
|
}
|
|
1479
1497
|
|
|
@@ -1657,12 +1675,14 @@ function withConfigCache(options) {
|
|
|
1657
1675
|
|
|
1658
1676
|
function eslintConstructorOptions(options) {
|
|
1659
1677
|
const mapped = {
|
|
1678
|
+
[LEGACY_CONFIG_ENABLED]: true,
|
|
1660
1679
|
cwd: options.cwd,
|
|
1661
1680
|
threads: options.threads,
|
|
1662
1681
|
binary: options.binary,
|
|
1663
1682
|
env: options.env,
|
|
1664
1683
|
extraArgs: options.extraArgs,
|
|
1665
|
-
config: options.config
|
|
1684
|
+
config: options.config,
|
|
1685
|
+
legacyConfigFile: options.config == null ? options.configFile : undefined,
|
|
1666
1686
|
ignorePath: options.ignorePath,
|
|
1667
1687
|
ignorePatterns: options.ignorePatterns,
|
|
1668
1688
|
noIgnore: options.noIgnore ?? options.ignore === false,
|
|
@@ -1679,14 +1699,14 @@ function eslintConstructorOptions(options) {
|
|
|
1679
1699
|
}
|
|
1680
1700
|
if (typeof options.overrideConfigFile === "string") {
|
|
1681
1701
|
mapped.config = options.overrideConfigFile;
|
|
1702
|
+
mapped.legacyConfigFile = undefined;
|
|
1703
|
+
}
|
|
1704
|
+
if (mapped.config && /(?:^|[/\\\\])\.eslintrc(?:\.(?:js|cjs|json|yaml|yml))?$/.test(mapped.config)) {
|
|
1705
|
+
mapped.legacyConfigFile = mapped.config;
|
|
1706
|
+
mapped.config = undefined;
|
|
1682
1707
|
}
|
|
1683
1708
|
if (options.overrideConfig) {
|
|
1684
1709
|
mapped.overrideConfig = Array.isArray(options.overrideConfig) ? options.overrideConfig : { ...options.overrideConfig };
|
|
1685
|
-
if (!Array.isArray(mapped.overrideConfig) && !mapped.overrideConfig.rules && options.baseConfig?.rules) {
|
|
1686
|
-
mapped.overrideConfig.rules = options.baseConfig.rules;
|
|
1687
|
-
}
|
|
1688
|
-
} else if (options.baseConfig?.rules) {
|
|
1689
|
-
mapped.overrideConfig = { rules: options.baseConfig.rules };
|
|
1690
1710
|
}
|
|
1691
1711
|
return mapped;
|
|
1692
1712
|
}
|
|
@@ -1818,13 +1838,13 @@ function rulesFromConfig(config, filePath, cwd) {
|
|
|
1818
1838
|
}
|
|
1819
1839
|
|
|
1820
1840
|
function rulesFromFileConfig(options, filePath) {
|
|
1821
|
-
if (options.noConfig) {
|
|
1841
|
+
if (options.noConfig && !options.legacyConfigFile) {
|
|
1822
1842
|
return {};
|
|
1823
1843
|
}
|
|
1824
1844
|
|
|
1825
1845
|
const configPath = filePath ? configPathForFile(options, filePath) : configPathForOptions(options);
|
|
1826
1846
|
if (!configPath) {
|
|
1827
|
-
return {};
|
|
1847
|
+
return legacyConfigForFile(options, filePath)?.rules ?? {};
|
|
1828
1848
|
}
|
|
1829
1849
|
|
|
1830
1850
|
const config = readConfig(configPath, options.cwd, options.configCache);
|
|
@@ -1832,19 +1852,40 @@ function rulesFromFileConfig(options, filePath) {
|
|
|
1832
1852
|
}
|
|
1833
1853
|
|
|
1834
1854
|
function configDataFromFileConfig(options, filePath) {
|
|
1835
|
-
if (options.noConfig) {
|
|
1855
|
+
if (options.noConfig && !options.legacyConfigFile) {
|
|
1836
1856
|
return {};
|
|
1837
1857
|
}
|
|
1838
1858
|
|
|
1839
1859
|
const configPath = filePath ? configPathForFile(options, filePath) : configPathForOptions(options);
|
|
1840
1860
|
if (!configPath) {
|
|
1841
|
-
return
|
|
1861
|
+
return configDataFromConfig(legacyConfigForFile(options, filePath), filePath, options.cwd);
|
|
1842
1862
|
}
|
|
1843
1863
|
|
|
1844
1864
|
const config = readConfig(configPath, options.cwd, options.configCache);
|
|
1845
1865
|
return configDataFromConfig(config, filePath, dirname(configPath));
|
|
1846
1866
|
}
|
|
1847
1867
|
|
|
1868
|
+
function legacyConfigForFile(options, filePath) {
|
|
1869
|
+
if (!options[LEGACY_CONFIG_ENABLED] || (options.noConfig && !options.legacyConfigFile)) return undefined;
|
|
1870
|
+
if (filePath ? configPathForFile(options, filePath) : configPathForOptions(options)) return undefined;
|
|
1871
|
+
const cwd = resolvePath(options.cwd ?? process.cwd());
|
|
1872
|
+
let resolver = options.configCache?.get(LEGACY_CONFIG_RESOLVER);
|
|
1873
|
+
if (!resolver) {
|
|
1874
|
+
resolver = createLegacyConfigResolver(cwd, {
|
|
1875
|
+
configFile: options.legacyConfigFile,
|
|
1876
|
+
useEslintrc: !options.noConfig,
|
|
1877
|
+
ignorePath: options.ignorePath,
|
|
1878
|
+
ignorePatterns: [
|
|
1879
|
+
...ignorePatternsFromConfig(options.baseConfig),
|
|
1880
|
+
...normalizeIgnorePatterns(options.ignorePatterns),
|
|
1881
|
+
...ignorePatternsFromConfig(options.overrideConfig)
|
|
1882
|
+
]
|
|
1883
|
+
});
|
|
1884
|
+
options.configCache?.set(LEGACY_CONFIG_RESOLVER, resolver);
|
|
1885
|
+
}
|
|
1886
|
+
return resolver(normalizeESLintFilePath(filePath ?? options.filePath ?? options.filename ?? "__placeholder__.js", cwd));
|
|
1887
|
+
}
|
|
1888
|
+
|
|
1848
1889
|
function lintTargetsForInput(paths, options = {}) {
|
|
1849
1890
|
if (paths == null) {
|
|
1850
1891
|
return defaultLintTargets(options);
|
|
@@ -1988,6 +2029,7 @@ function normalizeConfigPatterns(patterns) {
|
|
|
1988
2029
|
}
|
|
1989
2030
|
|
|
1990
2031
|
function configPathForOptions(options) {
|
|
2032
|
+
if (options.legacyConfigFile) return undefined;
|
|
1991
2033
|
if (options.config) {
|
|
1992
2034
|
return resolvePath(options.cwd ?? process.cwd(), options.config);
|
|
1993
2035
|
}
|
|
@@ -1997,6 +2039,7 @@ function configPathForOptions(options) {
|
|
|
1997
2039
|
}
|
|
1998
2040
|
|
|
1999
2041
|
function configPathForFile(options, filePath) {
|
|
2042
|
+
if (options.legacyConfigFile) return undefined;
|
|
2000
2043
|
if (options.noConfig) {
|
|
2001
2044
|
return undefined;
|
|
2002
2045
|
}
|
|
@@ -4286,7 +4329,7 @@ function isLintableFilePath(filePath) {
|
|
|
4286
4329
|
function filteredLintPaths(paths, options = {}) {
|
|
4287
4330
|
const values = normalizeStringArray(Array.isArray(paths) ? paths : [paths], "paths");
|
|
4288
4331
|
const cwd = options.cwd ?? process.cwd();
|
|
4289
|
-
const patterns = ignoreDisabled(options) ? [] : ignorePatternsForOptions(options, cwd);
|
|
4332
|
+
const patterns = ignoreDisabled(options) || defersLegacyIgnores(options) ? [] : ignorePatternsForOptions(options, cwd);
|
|
4290
4333
|
if (patterns.length === 0 && options.errorOnUnmatchedPattern !== false && !values.some(hasGlobMagic)) {
|
|
4291
4334
|
return values;
|
|
4292
4335
|
}
|
|
@@ -4405,7 +4448,7 @@ function ignoredLintPathDiagnostics(paths, options = {}) {
|
|
|
4405
4448
|
|
|
4406
4449
|
const cwd = options.cwd ?? process.cwd();
|
|
4407
4450
|
const patterns = ignorePatternsForOptions(options, cwd);
|
|
4408
|
-
if (patterns.length === 0) {
|
|
4451
|
+
if (patterns.length === 0 && !options[LEGACY_CONFIG_ENABLED]) {
|
|
4409
4452
|
return [];
|
|
4410
4453
|
}
|
|
4411
4454
|
|
|
@@ -4422,7 +4465,7 @@ function ignoredLintPathDiagnostics(paths, options = {}) {
|
|
|
4422
4465
|
continue;
|
|
4423
4466
|
}
|
|
4424
4467
|
|
|
4425
|
-
if (
|
|
4468
|
+
if (isPathIgnored(filePath, options)) {
|
|
4426
4469
|
diagnostics.push(ignoredFileDiagnostic(filePath));
|
|
4427
4470
|
}
|
|
4428
4471
|
}
|
|
@@ -4494,11 +4537,19 @@ function isPathIgnored(filePath, options = {}) {
|
|
|
4494
4537
|
}
|
|
4495
4538
|
|
|
4496
4539
|
const cwd = options.cwd ?? process.cwd();
|
|
4540
|
+
const legacyConfig = legacyConfigForFile(options, filePath);
|
|
4541
|
+
if (legacyConfig) {
|
|
4542
|
+
return Boolean(legacyConfig.isIgnored?.(normalizeESLintFilePath(filePath, cwd)));
|
|
4543
|
+
}
|
|
4497
4544
|
const normalized = normalizeIgnoredPath(filePath, cwd);
|
|
4498
4545
|
const patterns = ignorePatternsForOptions(options, cwd, filePath);
|
|
4499
4546
|
return pathIgnoredByPatterns(normalized, patterns);
|
|
4500
4547
|
}
|
|
4501
4548
|
|
|
4549
|
+
function defersLegacyIgnores(options) {
|
|
4550
|
+
return options[LEGACY_CONFIG_ENABLED] && (options.legacyConfigFile || (!options.noConfig && !configPathForOptions(options)));
|
|
4551
|
+
}
|
|
4552
|
+
|
|
4502
4553
|
function ignoreDisabled(options = {}) {
|
|
4503
4554
|
return options.noIgnore || options.ignore === false;
|
|
4504
4555
|
}
|
|
@@ -4876,6 +4927,12 @@ function diagnosticToESLintMessage(diagnostic, ruleSeverities) {
|
|
|
4876
4927
|
column: diagnostic.column,
|
|
4877
4928
|
nodeType: null
|
|
4878
4929
|
};
|
|
4930
|
+
if (diagnostic.endLine != null) {
|
|
4931
|
+
message.endLine = diagnostic.endLine;
|
|
4932
|
+
}
|
|
4933
|
+
if (diagnostic.endColumn != null) {
|
|
4934
|
+
message.endColumn = diagnostic.endColumn;
|
|
4935
|
+
}
|
|
4879
4936
|
const fixes = (diagnostic.fixes ?? []).map((fix) => ({
|
|
4880
4937
|
range: fix.range,
|
|
4881
4938
|
text: fix.text
|
package/index.js
CHANGED
|
@@ -6,6 +6,7 @@ import { dirname, extname, isAbsolute, join, relative, resolve as resolvePath }
|
|
|
6
6
|
import { fileURLToPath } from "node:url";
|
|
7
7
|
|
|
8
8
|
import { resolveBinary } from "./lib/binary.js";
|
|
9
|
+
import { createLegacyConfigResolver } from "./lib/legacy-config.cjs";
|
|
9
10
|
import {
|
|
10
11
|
findConfigPath as findConfigPathFromDirectory,
|
|
11
12
|
readConfig
|
|
@@ -18,6 +19,8 @@ export const version = JSON.parse(readFileSync(new URL("./package.json", import.
|
|
|
18
19
|
const LINTABLE_EXTENSIONS = new Set([".js", ".jsx", ".ts", ".tsx", ".mjs", ".cjs", ".mts", ".cts"]);
|
|
19
20
|
const MAX_AUTOFIX_PASSES = 10;
|
|
20
21
|
const CONFIG_DISCOVERY_CACHE = Symbol("configDiscoveryCache");
|
|
22
|
+
const LEGACY_CONFIG_ENABLED = Symbol("legacyConfigEnabled");
|
|
23
|
+
const LEGACY_CONFIG_RESOLVER = Symbol("legacyConfigResolver");
|
|
21
24
|
const JS_KEYWORDS = new Set([
|
|
22
25
|
"await", "break", "case", "catch", "class", "const", "continue", "debugger", "default", "delete",
|
|
23
26
|
"do", "else", "export", "extends", "finally", "for", "function", "if", "import", "in",
|
|
@@ -418,6 +421,7 @@ const BUILTIN_RULE_IDS = [
|
|
|
418
421
|
"@typescript-eslint/no-duplicate-enum-values",
|
|
419
422
|
"@typescript-eslint/no-extra-semi",
|
|
420
423
|
"@typescript-eslint/no-extra-non-null-assertion",
|
|
424
|
+
"@typescript-eslint/no-explicit-any",
|
|
421
425
|
"@typescript-eslint/no-inferrable-types",
|
|
422
426
|
"@typescript-eslint/no-invalid-void-type",
|
|
423
427
|
"@typescript-eslint/no-loop-func",
|
|
@@ -475,6 +479,7 @@ const NATIVE_ONLY_RULE_IDS = [
|
|
|
475
479
|
];
|
|
476
480
|
const NATIVE_RULE_IDS = [...BUILTIN_RULE_IDS, ...NATIVE_ONLY_RULE_IDS];
|
|
477
481
|
const FIXABLE_BUILTIN_RULE_IDS = new Set([
|
|
482
|
+
"@typescript-eslint/no-explicit-any",
|
|
478
483
|
"jest/no-deprecated-functions",
|
|
479
484
|
"jest/no-jasmine-globals",
|
|
480
485
|
"no-extra-semi",
|
|
@@ -482,6 +487,7 @@ const FIXABLE_BUILTIN_RULE_IDS = new Set([
|
|
|
482
487
|
"unused-imports/no-unused-imports"
|
|
483
488
|
]);
|
|
484
489
|
const SUGGESTION_BUILTIN_RULE_IDS = new Set([
|
|
490
|
+
"@typescript-eslint/no-explicit-any",
|
|
485
491
|
"jest/no-focused-tests"
|
|
486
492
|
]);
|
|
487
493
|
const BUILTIN_RULES = new Map(BUILTIN_RULE_IDS.map((ruleId) => [ruleId, createBuiltinRule(ruleId)]));
|
|
@@ -582,6 +588,9 @@ export class UtooLint {
|
|
|
582
588
|
|
|
583
589
|
async findConfigFile(filePath) {
|
|
584
590
|
const options = withConfigCache(eslintConstructorOptions(this.options));
|
|
591
|
+
if (options.legacyConfigFile) {
|
|
592
|
+
return resolvePath(options.cwd ?? process.cwd(), options.legacyConfigFile);
|
|
593
|
+
}
|
|
585
594
|
if (options.noConfig) {
|
|
586
595
|
return undefined;
|
|
587
596
|
}
|
|
@@ -3106,6 +3115,9 @@ export function lintFiles(paths, options = {}) {
|
|
|
3106
3115
|
if (usesDefaultTargets) {
|
|
3107
3116
|
lintPaths = filterDefaultConfigLintPaths(lintPaths, options);
|
|
3108
3117
|
}
|
|
3118
|
+
if (options[LEGACY_CONFIG_ENABLED] && (!options.noConfig || options.legacyConfigFile) && !options.deferDiagnosticConfigFiltering) {
|
|
3119
|
+
lintPaths = expandNativeConfigRunPaths(lintPaths, options).filter((filePath) => !isPathIgnored(filePath, options));
|
|
3120
|
+
}
|
|
3109
3121
|
if (lintPaths.length === 0) {
|
|
3110
3122
|
return { files: 0, filePaths: [], diagnostics: ignoredDiagnostics, suppressedDiagnostics: [], exitCode: exitCodeForDiagnostics(ignoredDiagnostics) };
|
|
3111
3123
|
}
|
|
@@ -3129,6 +3141,10 @@ export function lintFiles(paths, options = {}) {
|
|
|
3129
3141
|
}
|
|
3130
3142
|
|
|
3131
3143
|
function nativeFlatConfigOptions(options) {
|
|
3144
|
+
if (defersLegacyIgnores(options)) {
|
|
3145
|
+
// A legacy config may cascade from a nested directory even with baseConfig.
|
|
3146
|
+
return undefined;
|
|
3147
|
+
}
|
|
3132
3148
|
if (options.rules || options.extraArgs?.some((arg) => arg.startsWith("--") && arg !== "--fix" && arg !== "--fix-dry-run")) {
|
|
3133
3149
|
return undefined;
|
|
3134
3150
|
}
|
|
@@ -3200,7 +3216,7 @@ function nativeSerializableConfig(config) {
|
|
|
3200
3216
|
|
|
3201
3217
|
function expandNativeConfigRunPaths(paths, options) {
|
|
3202
3218
|
const cwd = options.cwd ?? process.cwd();
|
|
3203
|
-
const patterns = ignoreDisabled(options) ? [] : ignorePatternsForOptions(options, cwd);
|
|
3219
|
+
const patterns = ignoreDisabled(options) || defersLegacyIgnores(options) ? [] : ignorePatternsForOptions(options, cwd);
|
|
3204
3220
|
return paths.flatMap((path) => expandLintTarget(path, cwd, patterns) ?? [path]);
|
|
3205
3221
|
}
|
|
3206
3222
|
|
|
@@ -3258,7 +3274,7 @@ function finalizeLintReport(report, ignoredDiagnostics, options) {
|
|
|
3258
3274
|
}
|
|
3259
3275
|
|
|
3260
3276
|
function nativeConfigRunsForFiles(paths, options) {
|
|
3261
|
-
if (options.noConfig && !options.baseConfig && !options.overrideConfig) {
|
|
3277
|
+
if (options.noConfig && !options.legacyConfigFile && !options.baseConfig && !options.overrideConfig) {
|
|
3262
3278
|
return undefined;
|
|
3263
3279
|
}
|
|
3264
3280
|
|
|
@@ -3269,7 +3285,7 @@ function nativeConfigRunsForFiles(paths, options) {
|
|
|
3269
3285
|
? options.filePath ?? options.filename ?? filePath
|
|
3270
3286
|
: filePath;
|
|
3271
3287
|
const fileConfigPath = options.noConfig ? undefined : configPathForFile(options, matchPath);
|
|
3272
|
-
const configured = Boolean(options.baseConfig || options.overrideConfig || fileConfigPath);
|
|
3288
|
+
const configured = Boolean(options.baseConfig || options.overrideConfig || fileConfigPath || legacyConfigForFile(options, matchPath));
|
|
3273
3289
|
hasConfigSource ||= configured;
|
|
3274
3290
|
const calculated = configured ? calculatedConfig({ ...options, rules: undefined }, matchPath) : {};
|
|
3275
3291
|
let rules = calculated.rules;
|
|
@@ -3372,7 +3388,9 @@ function isPureRuleSeverity(config) {
|
|
|
3372
3388
|
function allDisabledNativeRules(rules) {
|
|
3373
3389
|
return {
|
|
3374
3390
|
...Object.fromEntries(NATIVE_RULE_IDS.map((rule) => [rule, "off"])),
|
|
3375
|
-
...rules
|
|
3391
|
+
...Object.fromEntries(Object.entries(rules ?? {}).filter(
|
|
3392
|
+
([rule, value]) => NATIVE_RULE_IDS.includes(rule) || ruleConfigSeverity(value) > 0
|
|
3393
|
+
))
|
|
3376
3394
|
};
|
|
3377
3395
|
}
|
|
3378
3396
|
|
|
@@ -3556,12 +3574,14 @@ function withConfigCache(options) {
|
|
|
3556
3574
|
|
|
3557
3575
|
function eslintConstructorOptions(options) {
|
|
3558
3576
|
const mapped = {
|
|
3577
|
+
[LEGACY_CONFIG_ENABLED]: true,
|
|
3559
3578
|
cwd: options.cwd,
|
|
3560
3579
|
threads: options.threads,
|
|
3561
3580
|
binary: options.binary,
|
|
3562
3581
|
env: options.env,
|
|
3563
3582
|
extraArgs: options.extraArgs,
|
|
3564
|
-
config: options.config
|
|
3583
|
+
config: options.config,
|
|
3584
|
+
legacyConfigFile: options.config == null ? options.configFile : undefined,
|
|
3565
3585
|
ignorePath: options.ignorePath,
|
|
3566
3586
|
ignorePatterns: options.ignorePatterns,
|
|
3567
3587
|
noIgnore: options.noIgnore ?? options.ignore === false,
|
|
@@ -3578,14 +3598,14 @@ function eslintConstructorOptions(options) {
|
|
|
3578
3598
|
}
|
|
3579
3599
|
if (typeof options.overrideConfigFile === "string") {
|
|
3580
3600
|
mapped.config = options.overrideConfigFile;
|
|
3601
|
+
mapped.legacyConfigFile = undefined;
|
|
3602
|
+
}
|
|
3603
|
+
if (mapped.config && /(?:^|[/\\\\])\.eslintrc(?:\.(?:js|cjs|json|yaml|yml))?$/.test(mapped.config)) {
|
|
3604
|
+
mapped.legacyConfigFile = mapped.config;
|
|
3605
|
+
mapped.config = undefined;
|
|
3581
3606
|
}
|
|
3582
3607
|
if (options.overrideConfig) {
|
|
3583
3608
|
mapped.overrideConfig = Array.isArray(options.overrideConfig) ? options.overrideConfig : { ...options.overrideConfig };
|
|
3584
|
-
if (!Array.isArray(mapped.overrideConfig) && !mapped.overrideConfig.rules && options.baseConfig?.rules) {
|
|
3585
|
-
mapped.overrideConfig.rules = options.baseConfig.rules;
|
|
3586
|
-
}
|
|
3587
|
-
} else if (options.baseConfig?.rules) {
|
|
3588
|
-
mapped.overrideConfig = { rules: options.baseConfig.rules };
|
|
3589
3609
|
}
|
|
3590
3610
|
return mapped;
|
|
3591
3611
|
}
|
|
@@ -3717,13 +3737,13 @@ function rulesFromConfig(config, filePath, cwd) {
|
|
|
3717
3737
|
}
|
|
3718
3738
|
|
|
3719
3739
|
function rulesFromFileConfig(options, filePath) {
|
|
3720
|
-
if (options.noConfig) {
|
|
3740
|
+
if (options.noConfig && !options.legacyConfigFile) {
|
|
3721
3741
|
return {};
|
|
3722
3742
|
}
|
|
3723
3743
|
|
|
3724
3744
|
const configPath = filePath ? configPathForFile(options, filePath) : configPathForOptions(options);
|
|
3725
3745
|
if (!configPath) {
|
|
3726
|
-
return {};
|
|
3746
|
+
return legacyConfigForFile(options, filePath)?.rules ?? {};
|
|
3727
3747
|
}
|
|
3728
3748
|
|
|
3729
3749
|
const config = readConfig(configPath, options.cwd, options.configCache);
|
|
@@ -3731,19 +3751,40 @@ function rulesFromFileConfig(options, filePath) {
|
|
|
3731
3751
|
}
|
|
3732
3752
|
|
|
3733
3753
|
function configDataFromFileConfig(options, filePath) {
|
|
3734
|
-
if (options.noConfig) {
|
|
3754
|
+
if (options.noConfig && !options.legacyConfigFile) {
|
|
3735
3755
|
return {};
|
|
3736
3756
|
}
|
|
3737
3757
|
|
|
3738
3758
|
const configPath = filePath ? configPathForFile(options, filePath) : configPathForOptions(options);
|
|
3739
3759
|
if (!configPath) {
|
|
3740
|
-
return
|
|
3760
|
+
return configDataFromConfig(legacyConfigForFile(options, filePath), filePath, options.cwd);
|
|
3741
3761
|
}
|
|
3742
3762
|
|
|
3743
3763
|
const config = readConfig(configPath, options.cwd, options.configCache);
|
|
3744
3764
|
return configDataFromConfig(config, filePath, dirname(configPath));
|
|
3745
3765
|
}
|
|
3746
3766
|
|
|
3767
|
+
function legacyConfigForFile(options, filePath) {
|
|
3768
|
+
if (!options[LEGACY_CONFIG_ENABLED] || (options.noConfig && !options.legacyConfigFile)) return undefined;
|
|
3769
|
+
if (filePath ? configPathForFile(options, filePath) : configPathForOptions(options)) return undefined;
|
|
3770
|
+
const cwd = resolvePath(options.cwd ?? process.cwd());
|
|
3771
|
+
let resolver = options.configCache?.get(LEGACY_CONFIG_RESOLVER);
|
|
3772
|
+
if (!resolver) {
|
|
3773
|
+
resolver = createLegacyConfigResolver(cwd, {
|
|
3774
|
+
configFile: options.legacyConfigFile,
|
|
3775
|
+
useEslintrc: !options.noConfig,
|
|
3776
|
+
ignorePath: options.ignorePath,
|
|
3777
|
+
ignorePatterns: [
|
|
3778
|
+
...ignorePatternsFromConfig(options.baseConfig),
|
|
3779
|
+
...normalizeIgnorePatterns(options.ignorePatterns),
|
|
3780
|
+
...ignorePatternsFromConfig(options.overrideConfig)
|
|
3781
|
+
]
|
|
3782
|
+
});
|
|
3783
|
+
options.configCache?.set(LEGACY_CONFIG_RESOLVER, resolver);
|
|
3784
|
+
}
|
|
3785
|
+
return resolver(normalizeESLintFilePath(filePath ?? options.filePath ?? options.filename ?? "__placeholder__.js", cwd));
|
|
3786
|
+
}
|
|
3787
|
+
|
|
3747
3788
|
function lintTargetsForInput(paths, options = {}) {
|
|
3748
3789
|
if (paths == null) {
|
|
3749
3790
|
return defaultLintTargets(options);
|
|
@@ -3887,6 +3928,7 @@ function normalizeConfigPatterns(patterns) {
|
|
|
3887
3928
|
}
|
|
3888
3929
|
|
|
3889
3930
|
function configPathForOptions(options) {
|
|
3931
|
+
if (options.legacyConfigFile) return undefined;
|
|
3890
3932
|
if (options.config) {
|
|
3891
3933
|
return resolvePath(options.cwd ?? process.cwd(), options.config);
|
|
3892
3934
|
}
|
|
@@ -3896,6 +3938,7 @@ function configPathForOptions(options) {
|
|
|
3896
3938
|
}
|
|
3897
3939
|
|
|
3898
3940
|
function configPathForFile(options, filePath) {
|
|
3941
|
+
if (options.legacyConfigFile) return undefined;
|
|
3899
3942
|
if (options.noConfig) {
|
|
3900
3943
|
return undefined;
|
|
3901
3944
|
}
|
|
@@ -4289,7 +4332,7 @@ function isLintableFilePath(filePath) {
|
|
|
4289
4332
|
function filteredLintPaths(paths, options = {}) {
|
|
4290
4333
|
const values = normalizeStringArray(Array.isArray(paths) ? paths : [paths], "paths");
|
|
4291
4334
|
const cwd = options.cwd ?? process.cwd();
|
|
4292
|
-
const patterns = ignoreDisabled(options) ? [] : ignorePatternsForOptions(options, cwd);
|
|
4335
|
+
const patterns = ignoreDisabled(options) || defersLegacyIgnores(options) ? [] : ignorePatternsForOptions(options, cwd);
|
|
4293
4336
|
if (patterns.length === 0 && options.errorOnUnmatchedPattern !== false && !values.some(hasGlobMagic)) {
|
|
4294
4337
|
return values;
|
|
4295
4338
|
}
|
|
@@ -4408,7 +4451,7 @@ function ignoredLintPathDiagnostics(paths, options = {}) {
|
|
|
4408
4451
|
|
|
4409
4452
|
const cwd = options.cwd ?? process.cwd();
|
|
4410
4453
|
const patterns = ignorePatternsForOptions(options, cwd);
|
|
4411
|
-
if (patterns.length === 0) {
|
|
4454
|
+
if (patterns.length === 0 && !options[LEGACY_CONFIG_ENABLED]) {
|
|
4412
4455
|
return [];
|
|
4413
4456
|
}
|
|
4414
4457
|
|
|
@@ -4425,7 +4468,7 @@ function ignoredLintPathDiagnostics(paths, options = {}) {
|
|
|
4425
4468
|
continue;
|
|
4426
4469
|
}
|
|
4427
4470
|
|
|
4428
|
-
if (
|
|
4471
|
+
if (isPathIgnored(filePath, options)) {
|
|
4429
4472
|
diagnostics.push(ignoredFileDiagnostic(filePath));
|
|
4430
4473
|
}
|
|
4431
4474
|
}
|
|
@@ -4497,11 +4540,19 @@ function isPathIgnored(filePath, options = {}) {
|
|
|
4497
4540
|
}
|
|
4498
4541
|
|
|
4499
4542
|
const cwd = options.cwd ?? process.cwd();
|
|
4543
|
+
const legacyConfig = legacyConfigForFile(options, filePath);
|
|
4544
|
+
if (legacyConfig) {
|
|
4545
|
+
return Boolean(legacyConfig.isIgnored?.(normalizeESLintFilePath(filePath, cwd)));
|
|
4546
|
+
}
|
|
4500
4547
|
const normalized = normalizeIgnoredPath(filePath, cwd);
|
|
4501
4548
|
const patterns = ignorePatternsForOptions(options, cwd, filePath);
|
|
4502
4549
|
return pathIgnoredByPatterns(normalized, patterns);
|
|
4503
4550
|
}
|
|
4504
4551
|
|
|
4552
|
+
function defersLegacyIgnores(options) {
|
|
4553
|
+
return options[LEGACY_CONFIG_ENABLED] && (options.legacyConfigFile || (!options.noConfig && !configPathForOptions(options)));
|
|
4554
|
+
}
|
|
4555
|
+
|
|
4505
4556
|
function ignoreDisabled(options = {}) {
|
|
4506
4557
|
return options.noIgnore || options.ignore === false;
|
|
4507
4558
|
}
|
|
@@ -4879,6 +4930,12 @@ function diagnosticToESLintMessage(diagnostic, ruleSeverities) {
|
|
|
4879
4930
|
column: diagnostic.column,
|
|
4880
4931
|
nodeType: null
|
|
4881
4932
|
};
|
|
4933
|
+
if (diagnostic.endLine != null) {
|
|
4934
|
+
message.endLine = diagnostic.endLine;
|
|
4935
|
+
}
|
|
4936
|
+
if (diagnostic.endColumn != null) {
|
|
4937
|
+
message.endColumn = diagnostic.endColumn;
|
|
4938
|
+
}
|
|
4882
4939
|
const fixes = (diagnostic.fixes ?? []).map((fix) => ({
|
|
4883
4940
|
range: fix.range,
|
|
4884
4941
|
text: fix.text
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
const { createRequire } = require("node:module");
|
|
2
|
+
const { dirname, join, resolve } = require("node:path");
|
|
3
|
+
|
|
4
|
+
// The same reviewed aliases used by the ESLint config migrator.
|
|
5
|
+
const RULE_ALIASES = new Map([
|
|
6
|
+
["no-native-reassign", "no-global-assign"],
|
|
7
|
+
["@typescript-eslint/no-invalid-this", "no-invalid-this"]
|
|
8
|
+
]);
|
|
9
|
+
|
|
10
|
+
// Resolve configuration only. Parsing, rule execution, and fixes stay native.
|
|
11
|
+
function createLegacyConfigResolver(cwd, { ignorePath, ignorePatterns, configFile, useEslintrc = true } = {}) {
|
|
12
|
+
const resolvedIgnorePath = ignorePath ? resolve(cwd, ignorePath) : undefined;
|
|
13
|
+
const resolvedConfigFile = configFile ? resolve(cwd, configFile) : undefined;
|
|
14
|
+
const projectRequire = createRequire(join(cwd, "package.json"));
|
|
15
|
+
let eslintPackage;
|
|
16
|
+
try {
|
|
17
|
+
eslintPackage = projectRequire.resolve("eslint/package.json");
|
|
18
|
+
} catch (error) {
|
|
19
|
+
if (error.code !== "MODULE_NOT_FOUND") throw error;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
let load;
|
|
23
|
+
if (eslintPackage) {
|
|
24
|
+
const manifest = projectRequire(eslintPackage);
|
|
25
|
+
// Some shared configs patch ESLint's module-resolution internals. Use their
|
|
26
|
+
// own ESLint 8 config resolver when installed, and never recurse into an
|
|
27
|
+
// eslint package alias that points back to @utoo/lint.
|
|
28
|
+
const major = Number(manifest.version.split(".")[0]);
|
|
29
|
+
if (manifest.name === "eslint" && major === 8) {
|
|
30
|
+
const { CLIEngine } = projectRequire(join(dirname(eslintPackage), "lib/cli-engine/cli-engine.js"));
|
|
31
|
+
const engine = new CLIEngine({ cwd, ignorePath: resolvedIgnorePath, ignorePattern: ignorePatterns, configFile: resolvedConfigFile, useEslintrc });
|
|
32
|
+
load = (filePath) => {
|
|
33
|
+
try {
|
|
34
|
+
return { ...engine.getConfigForFile(filePath), isIgnored: (path) => engine.isPathIgnored(path) };
|
|
35
|
+
} catch (error) {
|
|
36
|
+
if (error.messageTemplate === "no-config-found") return undefined;
|
|
37
|
+
throw error;
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (!load) {
|
|
44
|
+
const { Legacy } = require("@eslint/eslintrc");
|
|
45
|
+
const eslintJs = require("@eslint/js");
|
|
46
|
+
const factory = new Legacy.CascadingConfigArrayFactory({
|
|
47
|
+
cwd,
|
|
48
|
+
specificConfigPath: resolvedConfigFile,
|
|
49
|
+
useEslintrc,
|
|
50
|
+
ignorePath: resolvedIgnorePath,
|
|
51
|
+
cliConfig: ignorePatterns?.length ? { ignorePatterns } : undefined,
|
|
52
|
+
getEslintRecommendedConfig: () => eslintJs.configs.recommended,
|
|
53
|
+
getEslintAllConfig: () => eslintJs.configs.all
|
|
54
|
+
});
|
|
55
|
+
load = (filePath) => {
|
|
56
|
+
const configs = factory.getConfigArrayForFile(filePath, { ignoreNotFoundError: true });
|
|
57
|
+
if (!configs.some((entry) => entry.type === "config" && entry.filePath)) return undefined;
|
|
58
|
+
const config = configs.extractConfig(filePath);
|
|
59
|
+
return { ...config.toCompatibleObjectAsConfigFileContent(), isIgnored: config.ignores };
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const configs = new Map();
|
|
64
|
+
return (filePath) => {
|
|
65
|
+
if (!configs.has(filePath)) {
|
|
66
|
+
const config = load(filePath);
|
|
67
|
+
if (config) {
|
|
68
|
+
config.rules = Object.fromEntries(Object.entries(config.rules).map(([rule, value]) => [RULE_ALIASES.get(rule) ?? rule, value]));
|
|
69
|
+
}
|
|
70
|
+
configs.set(filePath, config);
|
|
71
|
+
}
|
|
72
|
+
return configs.get(filePath);
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
module.exports = { createLegacyConfigResolver };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@utoo/lint",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.7",
|
|
4
4
|
"description": "High-performance JavaScript and TypeScript linter powered by Yuku",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -76,11 +76,11 @@
|
|
|
76
76
|
"use-at-your-own-risk.js"
|
|
77
77
|
],
|
|
78
78
|
"optionalDependencies": {
|
|
79
|
-
"@utoo/lint-darwin-arm64": "0.3.
|
|
80
|
-
"@utoo/lint-darwin-x64": "0.3.
|
|
81
|
-
"@utoo/lint-linux-arm64": "0.3.
|
|
82
|
-
"@utoo/lint-linux-x64": "0.3.
|
|
83
|
-
"@utoo/lint-win32-x64": "0.3.
|
|
79
|
+
"@utoo/lint-darwin-arm64": "0.3.7",
|
|
80
|
+
"@utoo/lint-darwin-x64": "0.3.7",
|
|
81
|
+
"@utoo/lint-linux-arm64": "0.3.7",
|
|
82
|
+
"@utoo/lint-linux-x64": "0.3.7",
|
|
83
|
+
"@utoo/lint-win32-x64": "0.3.7"
|
|
84
84
|
},
|
|
85
85
|
"dependencies": {
|
|
86
86
|
"@eslint/eslintrc": "2.1.4",
|