@utoo/lint 0.3.6 → 0.3.8
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 +34 -0
- package/index.cjs +79 -45
- package/index.js +79 -45
- package/lib/legacy-config.cjs +76 -0
- package/lib/stylish-formatter.cjs +79 -0
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -244,10 +244,44 @@ const results = await eslint.lintFiles(["src"]);
|
|
|
244
244
|
await ESLint.outputFixes(results);
|
|
245
245
|
```
|
|
246
246
|
|
|
247
|
+
`await eslint.loadFormatter()` and `cliEngine.getFormatter()` default to an
|
|
248
|
+
ESLint-style `stylish` report: aligned columns, blank lines between files,
|
|
249
|
+
diagnostics sorted by line and column, and a summary of fixable errors and
|
|
250
|
+
warnings. Rule messages (including punctuation), result arrays, and exit codes
|
|
251
|
+
are unchanged. Only actual autofixes count toward the `--fix` hint, not editor
|
|
252
|
+
suggestions; missing JSX keys still need a manually chosen stable, unique key.
|
|
253
|
+
|
|
254
|
+
The stylish formatter detects color support on stdout. Pass `color: true` or
|
|
255
|
+
`color: false` to the `ESLint` or `CLIEngine` constructor to override detection.
|
|
256
|
+
Otherwise, `NO_COLOR` or `NODE_DISABLE_COLORS` disables color; `FORCE_COLOR`
|
|
257
|
+
forces it (`0` disables), followed by `CLICOLOR_FORCE` and stdout TTY detection
|
|
258
|
+
(`TERM=dumb` disables automatic color). Constructor `env` overrides also apply.
|
|
259
|
+
JSON, JSON-with-metadata, compact, unix, and native CLI text formats are unchanged.
|
|
260
|
+
|
|
247
261
|
Raw reports include active diagnostics, suppressed diagnostics, fixed outputs,
|
|
248
262
|
and an exit code. The compatibility layer also exports `Linter`, `CLIEngine`,
|
|
249
263
|
`RuleTester`, and `SourceCode` APIs.
|
|
250
264
|
|
|
265
|
+
Native JSON diagnostics and ESLint-compatible messages include one-based `line`,
|
|
266
|
+
`column`, `endLine`, and `endColumn` positions for source spans. Columns count
|
|
267
|
+
UTF-16 code units, and the end position is exclusive. Suppressed diagnostics keep
|
|
268
|
+
the same range. I/O errors without a source span omit the end positions; messages
|
|
269
|
+
from older native binaries may also omit them.
|
|
270
|
+
|
|
271
|
+
`ESLint` and `CLIEngine` also discover classic `.eslintrc.*` files (or
|
|
272
|
+
`eslintConfig` in `package.json`) when no native config applies. Legacy
|
|
273
|
+
`extends`, directory cascades, `root`, `overrides`, and ignore patterns are
|
|
274
|
+
resolved per source filename. Precedence is `baseConfig`, project config,
|
|
275
|
+
then `overrideConfig`; `useEslintrc: false` disables discovery. Native config
|
|
276
|
+
files still take priority. The lower-level `lintFiles`, `lintText`, and native
|
|
277
|
+
CLI keep their native-only discovery behavior.
|
|
278
|
+
|
|
279
|
+
Legacy configuration resolution uses `@eslint/eslintrc`. If the project has
|
|
280
|
+
ESLint 8 installed, its configuration resolver is used instead to support
|
|
281
|
+
shared configs that patch ESLint's module resolution. Neither path uses ESLint
|
|
282
|
+
to parse or lint source files: rules still run in utoo-lint. Enabled rules that
|
|
283
|
+
utoo-lint does not support remain errors, not silently skipped checks.
|
|
284
|
+
|
|
251
285
|
The Node wrapper captures up to 64 MiB from each native stdout and stderr
|
|
252
286
|
stream by default. Programmatic `run`, `runCli`, and `runFishlint` calls can set
|
|
253
287
|
`maxBuffer` to another positive byte count. Set `UTOO_LINT_MAX_BUFFER` to apply
|
package/index.cjs
CHANGED
|
@@ -5,6 +5,8 @@ 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");
|
|
9
|
+
const { formatESLintResults } = require("./lib/stylish-formatter.cjs");
|
|
8
10
|
const {
|
|
9
11
|
findConfigPath: findConfigPathFromDirectory,
|
|
10
12
|
readConfig
|
|
@@ -15,6 +17,8 @@ const version = JSON.parse(readFileSync(join(__dirname, "package.json"), "utf8")
|
|
|
15
17
|
const LINTABLE_EXTENSIONS = new Set([".js", ".jsx", ".ts", ".tsx", ".mjs", ".cjs", ".mts", ".cts"]);
|
|
16
18
|
const MAX_AUTOFIX_PASSES = 10;
|
|
17
19
|
const CONFIG_DISCOVERY_CACHE = Symbol("configDiscoveryCache");
|
|
20
|
+
const LEGACY_CONFIG_ENABLED = Symbol("legacyConfigEnabled");
|
|
21
|
+
const LEGACY_CONFIG_RESOLVER = Symbol("legacyConfigResolver");
|
|
18
22
|
const JS_KEYWORDS = new Set([
|
|
19
23
|
"await", "break", "case", "catch", "class", "const", "continue", "debugger", "default", "delete",
|
|
20
24
|
"do", "else", "export", "extends", "finally", "for", "function", "if", "import", "in",
|
|
@@ -415,6 +419,7 @@ const BUILTIN_RULE_IDS = [
|
|
|
415
419
|
"@typescript-eslint/no-duplicate-enum-values",
|
|
416
420
|
"@typescript-eslint/no-extra-semi",
|
|
417
421
|
"@typescript-eslint/no-extra-non-null-assertion",
|
|
422
|
+
"@typescript-eslint/no-explicit-any",
|
|
418
423
|
"@typescript-eslint/no-inferrable-types",
|
|
419
424
|
"@typescript-eslint/no-invalid-void-type",
|
|
420
425
|
"@typescript-eslint/no-loop-func",
|
|
@@ -472,6 +477,7 @@ const NATIVE_ONLY_RULE_IDS = [
|
|
|
472
477
|
];
|
|
473
478
|
const NATIVE_RULE_IDS = [...BUILTIN_RULE_IDS, ...NATIVE_ONLY_RULE_IDS];
|
|
474
479
|
const FIXABLE_BUILTIN_RULE_IDS = new Set([
|
|
480
|
+
"@typescript-eslint/no-explicit-any",
|
|
475
481
|
"jest/no-deprecated-functions",
|
|
476
482
|
"jest/no-jasmine-globals",
|
|
477
483
|
"no-extra-semi",
|
|
@@ -479,6 +485,7 @@ const FIXABLE_BUILTIN_RULE_IDS = new Set([
|
|
|
479
485
|
"unused-imports/no-unused-imports"
|
|
480
486
|
]);
|
|
481
487
|
const SUGGESTION_BUILTIN_RULE_IDS = new Set([
|
|
488
|
+
"@typescript-eslint/no-explicit-any",
|
|
482
489
|
"jest/no-focused-tests"
|
|
483
490
|
]);
|
|
484
491
|
const BUILTIN_RULES = new Map(BUILTIN_RULE_IDS.map((ruleId) => [ruleId, createBuiltinRule(ruleId)]));
|
|
@@ -579,6 +586,9 @@ class UtooLint {
|
|
|
579
586
|
|
|
580
587
|
async findConfigFile(filePath) {
|
|
581
588
|
const options = withConfigCache(eslintConstructorOptions(this.options));
|
|
589
|
+
if (options.legacyConfigFile) {
|
|
590
|
+
return resolvePath(options.cwd ?? process.cwd(), options.legacyConfigFile);
|
|
591
|
+
}
|
|
582
592
|
if (options.noConfig) {
|
|
583
593
|
return undefined;
|
|
584
594
|
}
|
|
@@ -617,7 +627,7 @@ class UtooLint {
|
|
|
617
627
|
format(results) {
|
|
618
628
|
return formatResultsByName(results, name, {
|
|
619
629
|
rulesMeta: (results) => eslint.getRulesMetaForResults(results)
|
|
620
|
-
});
|
|
630
|
+
}, eslint.options);
|
|
621
631
|
}
|
|
622
632
|
};
|
|
623
633
|
}
|
|
@@ -695,7 +705,7 @@ class CLIEngine {
|
|
|
695
705
|
|
|
696
706
|
getFormatter(name = "stylish") {
|
|
697
707
|
return (results) => {
|
|
698
|
-
return formatResultsByName(results, name);
|
|
708
|
+
return formatResultsByName(results, name, {}, this.options);
|
|
699
709
|
};
|
|
700
710
|
}
|
|
701
711
|
|
|
@@ -1207,6 +1217,9 @@ function lintFiles(paths, options = {}) {
|
|
|
1207
1217
|
if (usesDefaultTargets) {
|
|
1208
1218
|
lintPaths = filterDefaultConfigLintPaths(lintPaths, options);
|
|
1209
1219
|
}
|
|
1220
|
+
if (options[LEGACY_CONFIG_ENABLED] && (!options.noConfig || options.legacyConfigFile) && !options.deferDiagnosticConfigFiltering) {
|
|
1221
|
+
lintPaths = expandNativeConfigRunPaths(lintPaths, options).filter((filePath) => !isPathIgnored(filePath, options));
|
|
1222
|
+
}
|
|
1210
1223
|
if (lintPaths.length === 0) {
|
|
1211
1224
|
return { files: 0, filePaths: [], diagnostics: ignoredDiagnostics, suppressedDiagnostics: [], exitCode: exitCodeForDiagnostics(ignoredDiagnostics) };
|
|
1212
1225
|
}
|
|
@@ -1230,6 +1243,10 @@ function lintFiles(paths, options = {}) {
|
|
|
1230
1243
|
}
|
|
1231
1244
|
|
|
1232
1245
|
function nativeFlatConfigOptions(options) {
|
|
1246
|
+
if (defersLegacyIgnores(options)) {
|
|
1247
|
+
// A legacy config may cascade from a nested directory even with baseConfig.
|
|
1248
|
+
return undefined;
|
|
1249
|
+
}
|
|
1233
1250
|
if (options.rules || options.extraArgs?.some((arg) => arg.startsWith("--") && arg !== "--fix" && arg !== "--fix-dry-run")) {
|
|
1234
1251
|
return undefined;
|
|
1235
1252
|
}
|
|
@@ -1301,7 +1318,7 @@ function nativeSerializableConfig(config) {
|
|
|
1301
1318
|
|
|
1302
1319
|
function expandNativeConfigRunPaths(paths, options) {
|
|
1303
1320
|
const cwd = options.cwd ?? process.cwd();
|
|
1304
|
-
const patterns = ignoreDisabled(options) ? [] : ignorePatternsForOptions(options, cwd);
|
|
1321
|
+
const patterns = ignoreDisabled(options) || defersLegacyIgnores(options) ? [] : ignorePatternsForOptions(options, cwd);
|
|
1305
1322
|
return paths.flatMap((path) => expandLintTarget(path, cwd, patterns) ?? [path]);
|
|
1306
1323
|
}
|
|
1307
1324
|
|
|
@@ -1359,7 +1376,7 @@ function finalizeLintReport(report, ignoredDiagnostics, options) {
|
|
|
1359
1376
|
}
|
|
1360
1377
|
|
|
1361
1378
|
function nativeConfigRunsForFiles(paths, options) {
|
|
1362
|
-
if (options.noConfig && !options.baseConfig && !options.overrideConfig) {
|
|
1379
|
+
if (options.noConfig && !options.legacyConfigFile && !options.baseConfig && !options.overrideConfig) {
|
|
1363
1380
|
return undefined;
|
|
1364
1381
|
}
|
|
1365
1382
|
|
|
@@ -1370,7 +1387,7 @@ function nativeConfigRunsForFiles(paths, options) {
|
|
|
1370
1387
|
? options.filePath ?? options.filename ?? filePath
|
|
1371
1388
|
: filePath;
|
|
1372
1389
|
const fileConfigPath = options.noConfig ? undefined : configPathForFile(options, matchPath);
|
|
1373
|
-
const configured = Boolean(options.baseConfig || options.overrideConfig || fileConfigPath);
|
|
1390
|
+
const configured = Boolean(options.baseConfig || options.overrideConfig || fileConfigPath || legacyConfigForFile(options, matchPath));
|
|
1374
1391
|
hasConfigSource ||= configured;
|
|
1375
1392
|
const calculated = configured ? calculatedConfig({ ...options, rules: undefined }, matchPath) : {};
|
|
1376
1393
|
let rules = calculated.rules;
|
|
@@ -1473,7 +1490,9 @@ function isPureRuleSeverity(config) {
|
|
|
1473
1490
|
function allDisabledNativeRules(rules) {
|
|
1474
1491
|
return {
|
|
1475
1492
|
...Object.fromEntries(NATIVE_RULE_IDS.map((rule) => [rule, "off"])),
|
|
1476
|
-
...rules
|
|
1493
|
+
...Object.fromEntries(Object.entries(rules ?? {}).filter(
|
|
1494
|
+
([rule, value]) => NATIVE_RULE_IDS.includes(rule) || ruleConfigSeverity(value) > 0
|
|
1495
|
+
))
|
|
1477
1496
|
};
|
|
1478
1497
|
}
|
|
1479
1498
|
|
|
@@ -1657,12 +1676,14 @@ function withConfigCache(options) {
|
|
|
1657
1676
|
|
|
1658
1677
|
function eslintConstructorOptions(options) {
|
|
1659
1678
|
const mapped = {
|
|
1679
|
+
[LEGACY_CONFIG_ENABLED]: true,
|
|
1660
1680
|
cwd: options.cwd,
|
|
1661
1681
|
threads: options.threads,
|
|
1662
1682
|
binary: options.binary,
|
|
1663
1683
|
env: options.env,
|
|
1664
1684
|
extraArgs: options.extraArgs,
|
|
1665
|
-
config: options.config
|
|
1685
|
+
config: options.config,
|
|
1686
|
+
legacyConfigFile: options.config == null ? options.configFile : undefined,
|
|
1666
1687
|
ignorePath: options.ignorePath,
|
|
1667
1688
|
ignorePatterns: options.ignorePatterns,
|
|
1668
1689
|
noIgnore: options.noIgnore ?? options.ignore === false,
|
|
@@ -1679,14 +1700,14 @@ function eslintConstructorOptions(options) {
|
|
|
1679
1700
|
}
|
|
1680
1701
|
if (typeof options.overrideConfigFile === "string") {
|
|
1681
1702
|
mapped.config = options.overrideConfigFile;
|
|
1703
|
+
mapped.legacyConfigFile = undefined;
|
|
1704
|
+
}
|
|
1705
|
+
if (mapped.config && /(?:^|[/\\\\])\.eslintrc(?:\.(?:js|cjs|json|yaml|yml))?$/.test(mapped.config)) {
|
|
1706
|
+
mapped.legacyConfigFile = mapped.config;
|
|
1707
|
+
mapped.config = undefined;
|
|
1682
1708
|
}
|
|
1683
1709
|
if (options.overrideConfig) {
|
|
1684
1710
|
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
1711
|
}
|
|
1691
1712
|
return mapped;
|
|
1692
1713
|
}
|
|
@@ -1818,13 +1839,13 @@ function rulesFromConfig(config, filePath, cwd) {
|
|
|
1818
1839
|
}
|
|
1819
1840
|
|
|
1820
1841
|
function rulesFromFileConfig(options, filePath) {
|
|
1821
|
-
if (options.noConfig) {
|
|
1842
|
+
if (options.noConfig && !options.legacyConfigFile) {
|
|
1822
1843
|
return {};
|
|
1823
1844
|
}
|
|
1824
1845
|
|
|
1825
1846
|
const configPath = filePath ? configPathForFile(options, filePath) : configPathForOptions(options);
|
|
1826
1847
|
if (!configPath) {
|
|
1827
|
-
return {};
|
|
1848
|
+
return legacyConfigForFile(options, filePath)?.rules ?? {};
|
|
1828
1849
|
}
|
|
1829
1850
|
|
|
1830
1851
|
const config = readConfig(configPath, options.cwd, options.configCache);
|
|
@@ -1832,19 +1853,40 @@ function rulesFromFileConfig(options, filePath) {
|
|
|
1832
1853
|
}
|
|
1833
1854
|
|
|
1834
1855
|
function configDataFromFileConfig(options, filePath) {
|
|
1835
|
-
if (options.noConfig) {
|
|
1856
|
+
if (options.noConfig && !options.legacyConfigFile) {
|
|
1836
1857
|
return {};
|
|
1837
1858
|
}
|
|
1838
1859
|
|
|
1839
1860
|
const configPath = filePath ? configPathForFile(options, filePath) : configPathForOptions(options);
|
|
1840
1861
|
if (!configPath) {
|
|
1841
|
-
return
|
|
1862
|
+
return configDataFromConfig(legacyConfigForFile(options, filePath), filePath, options.cwd);
|
|
1842
1863
|
}
|
|
1843
1864
|
|
|
1844
1865
|
const config = readConfig(configPath, options.cwd, options.configCache);
|
|
1845
1866
|
return configDataFromConfig(config, filePath, dirname(configPath));
|
|
1846
1867
|
}
|
|
1847
1868
|
|
|
1869
|
+
function legacyConfigForFile(options, filePath) {
|
|
1870
|
+
if (!options[LEGACY_CONFIG_ENABLED] || (options.noConfig && !options.legacyConfigFile)) return undefined;
|
|
1871
|
+
if (filePath ? configPathForFile(options, filePath) : configPathForOptions(options)) return undefined;
|
|
1872
|
+
const cwd = resolvePath(options.cwd ?? process.cwd());
|
|
1873
|
+
let resolver = options.configCache?.get(LEGACY_CONFIG_RESOLVER);
|
|
1874
|
+
if (!resolver) {
|
|
1875
|
+
resolver = createLegacyConfigResolver(cwd, {
|
|
1876
|
+
configFile: options.legacyConfigFile,
|
|
1877
|
+
useEslintrc: !options.noConfig,
|
|
1878
|
+
ignorePath: options.ignorePath,
|
|
1879
|
+
ignorePatterns: [
|
|
1880
|
+
...ignorePatternsFromConfig(options.baseConfig),
|
|
1881
|
+
...normalizeIgnorePatterns(options.ignorePatterns),
|
|
1882
|
+
...ignorePatternsFromConfig(options.overrideConfig)
|
|
1883
|
+
]
|
|
1884
|
+
});
|
|
1885
|
+
options.configCache?.set(LEGACY_CONFIG_RESOLVER, resolver);
|
|
1886
|
+
}
|
|
1887
|
+
return resolver(normalizeESLintFilePath(filePath ?? options.filePath ?? options.filename ?? "__placeholder__.js", cwd));
|
|
1888
|
+
}
|
|
1889
|
+
|
|
1848
1890
|
function lintTargetsForInput(paths, options = {}) {
|
|
1849
1891
|
if (paths == null) {
|
|
1850
1892
|
return defaultLintTargets(options);
|
|
@@ -1988,6 +2030,7 @@ function normalizeConfigPatterns(patterns) {
|
|
|
1988
2030
|
}
|
|
1989
2031
|
|
|
1990
2032
|
function configPathForOptions(options) {
|
|
2033
|
+
if (options.legacyConfigFile) return undefined;
|
|
1991
2034
|
if (options.config) {
|
|
1992
2035
|
return resolvePath(options.cwd ?? process.cwd(), options.config);
|
|
1993
2036
|
}
|
|
@@ -1997,6 +2040,7 @@ function configPathForOptions(options) {
|
|
|
1997
2040
|
}
|
|
1998
2041
|
|
|
1999
2042
|
function configPathForFile(options, filePath) {
|
|
2043
|
+
if (options.legacyConfigFile) return undefined;
|
|
2000
2044
|
if (options.noConfig) {
|
|
2001
2045
|
return undefined;
|
|
2002
2046
|
}
|
|
@@ -4286,7 +4330,7 @@ function isLintableFilePath(filePath) {
|
|
|
4286
4330
|
function filteredLintPaths(paths, options = {}) {
|
|
4287
4331
|
const values = normalizeStringArray(Array.isArray(paths) ? paths : [paths], "paths");
|
|
4288
4332
|
const cwd = options.cwd ?? process.cwd();
|
|
4289
|
-
const patterns = ignoreDisabled(options) ? [] : ignorePatternsForOptions(options, cwd);
|
|
4333
|
+
const patterns = ignoreDisabled(options) || defersLegacyIgnores(options) ? [] : ignorePatternsForOptions(options, cwd);
|
|
4290
4334
|
if (patterns.length === 0 && options.errorOnUnmatchedPattern !== false && !values.some(hasGlobMagic)) {
|
|
4291
4335
|
return values;
|
|
4292
4336
|
}
|
|
@@ -4405,7 +4449,7 @@ function ignoredLintPathDiagnostics(paths, options = {}) {
|
|
|
4405
4449
|
|
|
4406
4450
|
const cwd = options.cwd ?? process.cwd();
|
|
4407
4451
|
const patterns = ignorePatternsForOptions(options, cwd);
|
|
4408
|
-
if (patterns.length === 0) {
|
|
4452
|
+
if (patterns.length === 0 && !options[LEGACY_CONFIG_ENABLED]) {
|
|
4409
4453
|
return [];
|
|
4410
4454
|
}
|
|
4411
4455
|
|
|
@@ -4422,7 +4466,7 @@ function ignoredLintPathDiagnostics(paths, options = {}) {
|
|
|
4422
4466
|
continue;
|
|
4423
4467
|
}
|
|
4424
4468
|
|
|
4425
|
-
if (
|
|
4469
|
+
if (isPathIgnored(filePath, options)) {
|
|
4426
4470
|
diagnostics.push(ignoredFileDiagnostic(filePath));
|
|
4427
4471
|
}
|
|
4428
4472
|
}
|
|
@@ -4494,11 +4538,19 @@ function isPathIgnored(filePath, options = {}) {
|
|
|
4494
4538
|
}
|
|
4495
4539
|
|
|
4496
4540
|
const cwd = options.cwd ?? process.cwd();
|
|
4541
|
+
const legacyConfig = legacyConfigForFile(options, filePath);
|
|
4542
|
+
if (legacyConfig) {
|
|
4543
|
+
return Boolean(legacyConfig.isIgnored?.(normalizeESLintFilePath(filePath, cwd)));
|
|
4544
|
+
}
|
|
4497
4545
|
const normalized = normalizeIgnoredPath(filePath, cwd);
|
|
4498
4546
|
const patterns = ignorePatternsForOptions(options, cwd, filePath);
|
|
4499
4547
|
return pathIgnoredByPatterns(normalized, patterns);
|
|
4500
4548
|
}
|
|
4501
4549
|
|
|
4550
|
+
function defersLegacyIgnores(options) {
|
|
4551
|
+
return options[LEGACY_CONFIG_ENABLED] && (options.legacyConfigFile || (!options.noConfig && !configPathForOptions(options)));
|
|
4552
|
+
}
|
|
4553
|
+
|
|
4502
4554
|
function ignoreDisabled(options = {}) {
|
|
4503
4555
|
return options.noIgnore || options.ignore === false;
|
|
4504
4556
|
}
|
|
@@ -4876,6 +4928,12 @@ function diagnosticToESLintMessage(diagnostic, ruleSeverities) {
|
|
|
4876
4928
|
column: diagnostic.column,
|
|
4877
4929
|
nodeType: null
|
|
4878
4930
|
};
|
|
4931
|
+
if (diagnostic.endLine != null) {
|
|
4932
|
+
message.endLine = diagnostic.endLine;
|
|
4933
|
+
}
|
|
4934
|
+
if (diagnostic.endColumn != null) {
|
|
4935
|
+
message.endColumn = diagnostic.endColumn;
|
|
4936
|
+
}
|
|
4879
4937
|
const fixes = (diagnostic.fixes ?? []).map((fix) => ({
|
|
4880
4938
|
range: fix.range,
|
|
4881
4939
|
text: fix.text
|
|
@@ -4947,31 +5005,7 @@ function maybeFilterQuietResults(results, options = {}) {
|
|
|
4947
5005
|
return results;
|
|
4948
5006
|
}
|
|
4949
5007
|
|
|
4950
|
-
function
|
|
4951
|
-
const lines = [];
|
|
4952
|
-
let errorCount = 0;
|
|
4953
|
-
let warningCount = 0;
|
|
4954
|
-
|
|
4955
|
-
for (const result of results) {
|
|
4956
|
-
if (result.messages.length === 0) continue;
|
|
4957
|
-
lines.push(result.filePath);
|
|
4958
|
-
for (const message of result.messages) {
|
|
4959
|
-
const severity = message.severity === 2 ? "error" : "warning";
|
|
4960
|
-
lines.push(` ${message.line}:${message.column} ${severity} ${message.message} ${message.ruleId}`);
|
|
4961
|
-
}
|
|
4962
|
-
errorCount += result.errorCount;
|
|
4963
|
-
warningCount += result.warningCount;
|
|
4964
|
-
}
|
|
4965
|
-
|
|
4966
|
-
if (errorCount || warningCount) {
|
|
4967
|
-
lines.push("");
|
|
4968
|
-
lines.push(`x ${errorCount + warningCount} problem${errorCount + warningCount === 1 ? "" : "s"} (${errorCount} error${errorCount === 1 ? "" : "s"}, ${warningCount} warning${warningCount === 1 ? "" : "s"})`);
|
|
4969
|
-
}
|
|
4970
|
-
|
|
4971
|
-
return lines.join("\n");
|
|
4972
|
-
}
|
|
4973
|
-
|
|
4974
|
-
function formatResultsByName(input, name = "stylish", metadata = {}) {
|
|
5008
|
+
function formatResultsByName(input, name = "stylish", metadata = {}, options = {}) {
|
|
4975
5009
|
const results = formatterResults(input);
|
|
4976
5010
|
if (name === "json") {
|
|
4977
5011
|
return JSON.stringify(input);
|
|
@@ -4990,7 +5024,7 @@ function formatResultsByName(input, name = "stylish", metadata = {}) {
|
|
|
4990
5024
|
if (name === "unix") {
|
|
4991
5025
|
return formatUnixResults(results);
|
|
4992
5026
|
}
|
|
4993
|
-
return formatESLintResults(results);
|
|
5027
|
+
return formatESLintResults(results, options);
|
|
4994
5028
|
}
|
|
4995
5029
|
|
|
4996
5030
|
function formatterResults(input) {
|
package/index.js
CHANGED
|
@@ -6,6 +6,8 @@ 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";
|
|
10
|
+
import { formatESLintResults } from "./lib/stylish-formatter.cjs";
|
|
9
11
|
import {
|
|
10
12
|
findConfigPath as findConfigPathFromDirectory,
|
|
11
13
|
readConfig
|
|
@@ -18,6 +20,8 @@ export const version = JSON.parse(readFileSync(new URL("./package.json", import.
|
|
|
18
20
|
const LINTABLE_EXTENSIONS = new Set([".js", ".jsx", ".ts", ".tsx", ".mjs", ".cjs", ".mts", ".cts"]);
|
|
19
21
|
const MAX_AUTOFIX_PASSES = 10;
|
|
20
22
|
const CONFIG_DISCOVERY_CACHE = Symbol("configDiscoveryCache");
|
|
23
|
+
const LEGACY_CONFIG_ENABLED = Symbol("legacyConfigEnabled");
|
|
24
|
+
const LEGACY_CONFIG_RESOLVER = Symbol("legacyConfigResolver");
|
|
21
25
|
const JS_KEYWORDS = new Set([
|
|
22
26
|
"await", "break", "case", "catch", "class", "const", "continue", "debugger", "default", "delete",
|
|
23
27
|
"do", "else", "export", "extends", "finally", "for", "function", "if", "import", "in",
|
|
@@ -418,6 +422,7 @@ const BUILTIN_RULE_IDS = [
|
|
|
418
422
|
"@typescript-eslint/no-duplicate-enum-values",
|
|
419
423
|
"@typescript-eslint/no-extra-semi",
|
|
420
424
|
"@typescript-eslint/no-extra-non-null-assertion",
|
|
425
|
+
"@typescript-eslint/no-explicit-any",
|
|
421
426
|
"@typescript-eslint/no-inferrable-types",
|
|
422
427
|
"@typescript-eslint/no-invalid-void-type",
|
|
423
428
|
"@typescript-eslint/no-loop-func",
|
|
@@ -475,6 +480,7 @@ const NATIVE_ONLY_RULE_IDS = [
|
|
|
475
480
|
];
|
|
476
481
|
const NATIVE_RULE_IDS = [...BUILTIN_RULE_IDS, ...NATIVE_ONLY_RULE_IDS];
|
|
477
482
|
const FIXABLE_BUILTIN_RULE_IDS = new Set([
|
|
483
|
+
"@typescript-eslint/no-explicit-any",
|
|
478
484
|
"jest/no-deprecated-functions",
|
|
479
485
|
"jest/no-jasmine-globals",
|
|
480
486
|
"no-extra-semi",
|
|
@@ -482,6 +488,7 @@ const FIXABLE_BUILTIN_RULE_IDS = new Set([
|
|
|
482
488
|
"unused-imports/no-unused-imports"
|
|
483
489
|
]);
|
|
484
490
|
const SUGGESTION_BUILTIN_RULE_IDS = new Set([
|
|
491
|
+
"@typescript-eslint/no-explicit-any",
|
|
485
492
|
"jest/no-focused-tests"
|
|
486
493
|
]);
|
|
487
494
|
const BUILTIN_RULES = new Map(BUILTIN_RULE_IDS.map((ruleId) => [ruleId, createBuiltinRule(ruleId)]));
|
|
@@ -582,6 +589,9 @@ export class UtooLint {
|
|
|
582
589
|
|
|
583
590
|
async findConfigFile(filePath) {
|
|
584
591
|
const options = withConfigCache(eslintConstructorOptions(this.options));
|
|
592
|
+
if (options.legacyConfigFile) {
|
|
593
|
+
return resolvePath(options.cwd ?? process.cwd(), options.legacyConfigFile);
|
|
594
|
+
}
|
|
585
595
|
if (options.noConfig) {
|
|
586
596
|
return undefined;
|
|
587
597
|
}
|
|
@@ -620,7 +630,7 @@ export class UtooLint {
|
|
|
620
630
|
format(results) {
|
|
621
631
|
return formatResultsByName(results, name, {
|
|
622
632
|
rulesMeta: (results) => eslint.getRulesMetaForResults(results)
|
|
623
|
-
});
|
|
633
|
+
}, eslint.options);
|
|
624
634
|
}
|
|
625
635
|
};
|
|
626
636
|
}
|
|
@@ -2594,7 +2604,7 @@ export class CLIEngine {
|
|
|
2594
2604
|
|
|
2595
2605
|
getFormatter(name = "stylish") {
|
|
2596
2606
|
return (results) => {
|
|
2597
|
-
return formatResultsByName(results, name);
|
|
2607
|
+
return formatResultsByName(results, name, {}, this.options);
|
|
2598
2608
|
};
|
|
2599
2609
|
}
|
|
2600
2610
|
|
|
@@ -3106,6 +3116,9 @@ export function lintFiles(paths, options = {}) {
|
|
|
3106
3116
|
if (usesDefaultTargets) {
|
|
3107
3117
|
lintPaths = filterDefaultConfigLintPaths(lintPaths, options);
|
|
3108
3118
|
}
|
|
3119
|
+
if (options[LEGACY_CONFIG_ENABLED] && (!options.noConfig || options.legacyConfigFile) && !options.deferDiagnosticConfigFiltering) {
|
|
3120
|
+
lintPaths = expandNativeConfigRunPaths(lintPaths, options).filter((filePath) => !isPathIgnored(filePath, options));
|
|
3121
|
+
}
|
|
3109
3122
|
if (lintPaths.length === 0) {
|
|
3110
3123
|
return { files: 0, filePaths: [], diagnostics: ignoredDiagnostics, suppressedDiagnostics: [], exitCode: exitCodeForDiagnostics(ignoredDiagnostics) };
|
|
3111
3124
|
}
|
|
@@ -3129,6 +3142,10 @@ export function lintFiles(paths, options = {}) {
|
|
|
3129
3142
|
}
|
|
3130
3143
|
|
|
3131
3144
|
function nativeFlatConfigOptions(options) {
|
|
3145
|
+
if (defersLegacyIgnores(options)) {
|
|
3146
|
+
// A legacy config may cascade from a nested directory even with baseConfig.
|
|
3147
|
+
return undefined;
|
|
3148
|
+
}
|
|
3132
3149
|
if (options.rules || options.extraArgs?.some((arg) => arg.startsWith("--") && arg !== "--fix" && arg !== "--fix-dry-run")) {
|
|
3133
3150
|
return undefined;
|
|
3134
3151
|
}
|
|
@@ -3200,7 +3217,7 @@ function nativeSerializableConfig(config) {
|
|
|
3200
3217
|
|
|
3201
3218
|
function expandNativeConfigRunPaths(paths, options) {
|
|
3202
3219
|
const cwd = options.cwd ?? process.cwd();
|
|
3203
|
-
const patterns = ignoreDisabled(options) ? [] : ignorePatternsForOptions(options, cwd);
|
|
3220
|
+
const patterns = ignoreDisabled(options) || defersLegacyIgnores(options) ? [] : ignorePatternsForOptions(options, cwd);
|
|
3204
3221
|
return paths.flatMap((path) => expandLintTarget(path, cwd, patterns) ?? [path]);
|
|
3205
3222
|
}
|
|
3206
3223
|
|
|
@@ -3258,7 +3275,7 @@ function finalizeLintReport(report, ignoredDiagnostics, options) {
|
|
|
3258
3275
|
}
|
|
3259
3276
|
|
|
3260
3277
|
function nativeConfigRunsForFiles(paths, options) {
|
|
3261
|
-
if (options.noConfig && !options.baseConfig && !options.overrideConfig) {
|
|
3278
|
+
if (options.noConfig && !options.legacyConfigFile && !options.baseConfig && !options.overrideConfig) {
|
|
3262
3279
|
return undefined;
|
|
3263
3280
|
}
|
|
3264
3281
|
|
|
@@ -3269,7 +3286,7 @@ function nativeConfigRunsForFiles(paths, options) {
|
|
|
3269
3286
|
? options.filePath ?? options.filename ?? filePath
|
|
3270
3287
|
: filePath;
|
|
3271
3288
|
const fileConfigPath = options.noConfig ? undefined : configPathForFile(options, matchPath);
|
|
3272
|
-
const configured = Boolean(options.baseConfig || options.overrideConfig || fileConfigPath);
|
|
3289
|
+
const configured = Boolean(options.baseConfig || options.overrideConfig || fileConfigPath || legacyConfigForFile(options, matchPath));
|
|
3273
3290
|
hasConfigSource ||= configured;
|
|
3274
3291
|
const calculated = configured ? calculatedConfig({ ...options, rules: undefined }, matchPath) : {};
|
|
3275
3292
|
let rules = calculated.rules;
|
|
@@ -3372,7 +3389,9 @@ function isPureRuleSeverity(config) {
|
|
|
3372
3389
|
function allDisabledNativeRules(rules) {
|
|
3373
3390
|
return {
|
|
3374
3391
|
...Object.fromEntries(NATIVE_RULE_IDS.map((rule) => [rule, "off"])),
|
|
3375
|
-
...rules
|
|
3392
|
+
...Object.fromEntries(Object.entries(rules ?? {}).filter(
|
|
3393
|
+
([rule, value]) => NATIVE_RULE_IDS.includes(rule) || ruleConfigSeverity(value) > 0
|
|
3394
|
+
))
|
|
3376
3395
|
};
|
|
3377
3396
|
}
|
|
3378
3397
|
|
|
@@ -3556,12 +3575,14 @@ function withConfigCache(options) {
|
|
|
3556
3575
|
|
|
3557
3576
|
function eslintConstructorOptions(options) {
|
|
3558
3577
|
const mapped = {
|
|
3578
|
+
[LEGACY_CONFIG_ENABLED]: true,
|
|
3559
3579
|
cwd: options.cwd,
|
|
3560
3580
|
threads: options.threads,
|
|
3561
3581
|
binary: options.binary,
|
|
3562
3582
|
env: options.env,
|
|
3563
3583
|
extraArgs: options.extraArgs,
|
|
3564
|
-
config: options.config
|
|
3584
|
+
config: options.config,
|
|
3585
|
+
legacyConfigFile: options.config == null ? options.configFile : undefined,
|
|
3565
3586
|
ignorePath: options.ignorePath,
|
|
3566
3587
|
ignorePatterns: options.ignorePatterns,
|
|
3567
3588
|
noIgnore: options.noIgnore ?? options.ignore === false,
|
|
@@ -3578,14 +3599,14 @@ function eslintConstructorOptions(options) {
|
|
|
3578
3599
|
}
|
|
3579
3600
|
if (typeof options.overrideConfigFile === "string") {
|
|
3580
3601
|
mapped.config = options.overrideConfigFile;
|
|
3602
|
+
mapped.legacyConfigFile = undefined;
|
|
3603
|
+
}
|
|
3604
|
+
if (mapped.config && /(?:^|[/\\\\])\.eslintrc(?:\.(?:js|cjs|json|yaml|yml))?$/.test(mapped.config)) {
|
|
3605
|
+
mapped.legacyConfigFile = mapped.config;
|
|
3606
|
+
mapped.config = undefined;
|
|
3581
3607
|
}
|
|
3582
3608
|
if (options.overrideConfig) {
|
|
3583
3609
|
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
3610
|
}
|
|
3590
3611
|
return mapped;
|
|
3591
3612
|
}
|
|
@@ -3717,13 +3738,13 @@ function rulesFromConfig(config, filePath, cwd) {
|
|
|
3717
3738
|
}
|
|
3718
3739
|
|
|
3719
3740
|
function rulesFromFileConfig(options, filePath) {
|
|
3720
|
-
if (options.noConfig) {
|
|
3741
|
+
if (options.noConfig && !options.legacyConfigFile) {
|
|
3721
3742
|
return {};
|
|
3722
3743
|
}
|
|
3723
3744
|
|
|
3724
3745
|
const configPath = filePath ? configPathForFile(options, filePath) : configPathForOptions(options);
|
|
3725
3746
|
if (!configPath) {
|
|
3726
|
-
return {};
|
|
3747
|
+
return legacyConfigForFile(options, filePath)?.rules ?? {};
|
|
3727
3748
|
}
|
|
3728
3749
|
|
|
3729
3750
|
const config = readConfig(configPath, options.cwd, options.configCache);
|
|
@@ -3731,19 +3752,40 @@ function rulesFromFileConfig(options, filePath) {
|
|
|
3731
3752
|
}
|
|
3732
3753
|
|
|
3733
3754
|
function configDataFromFileConfig(options, filePath) {
|
|
3734
|
-
if (options.noConfig) {
|
|
3755
|
+
if (options.noConfig && !options.legacyConfigFile) {
|
|
3735
3756
|
return {};
|
|
3736
3757
|
}
|
|
3737
3758
|
|
|
3738
3759
|
const configPath = filePath ? configPathForFile(options, filePath) : configPathForOptions(options);
|
|
3739
3760
|
if (!configPath) {
|
|
3740
|
-
return
|
|
3761
|
+
return configDataFromConfig(legacyConfigForFile(options, filePath), filePath, options.cwd);
|
|
3741
3762
|
}
|
|
3742
3763
|
|
|
3743
3764
|
const config = readConfig(configPath, options.cwd, options.configCache);
|
|
3744
3765
|
return configDataFromConfig(config, filePath, dirname(configPath));
|
|
3745
3766
|
}
|
|
3746
3767
|
|
|
3768
|
+
function legacyConfigForFile(options, filePath) {
|
|
3769
|
+
if (!options[LEGACY_CONFIG_ENABLED] || (options.noConfig && !options.legacyConfigFile)) return undefined;
|
|
3770
|
+
if (filePath ? configPathForFile(options, filePath) : configPathForOptions(options)) return undefined;
|
|
3771
|
+
const cwd = resolvePath(options.cwd ?? process.cwd());
|
|
3772
|
+
let resolver = options.configCache?.get(LEGACY_CONFIG_RESOLVER);
|
|
3773
|
+
if (!resolver) {
|
|
3774
|
+
resolver = createLegacyConfigResolver(cwd, {
|
|
3775
|
+
configFile: options.legacyConfigFile,
|
|
3776
|
+
useEslintrc: !options.noConfig,
|
|
3777
|
+
ignorePath: options.ignorePath,
|
|
3778
|
+
ignorePatterns: [
|
|
3779
|
+
...ignorePatternsFromConfig(options.baseConfig),
|
|
3780
|
+
...normalizeIgnorePatterns(options.ignorePatterns),
|
|
3781
|
+
...ignorePatternsFromConfig(options.overrideConfig)
|
|
3782
|
+
]
|
|
3783
|
+
});
|
|
3784
|
+
options.configCache?.set(LEGACY_CONFIG_RESOLVER, resolver);
|
|
3785
|
+
}
|
|
3786
|
+
return resolver(normalizeESLintFilePath(filePath ?? options.filePath ?? options.filename ?? "__placeholder__.js", cwd));
|
|
3787
|
+
}
|
|
3788
|
+
|
|
3747
3789
|
function lintTargetsForInput(paths, options = {}) {
|
|
3748
3790
|
if (paths == null) {
|
|
3749
3791
|
return defaultLintTargets(options);
|
|
@@ -3887,6 +3929,7 @@ function normalizeConfigPatterns(patterns) {
|
|
|
3887
3929
|
}
|
|
3888
3930
|
|
|
3889
3931
|
function configPathForOptions(options) {
|
|
3932
|
+
if (options.legacyConfigFile) return undefined;
|
|
3890
3933
|
if (options.config) {
|
|
3891
3934
|
return resolvePath(options.cwd ?? process.cwd(), options.config);
|
|
3892
3935
|
}
|
|
@@ -3896,6 +3939,7 @@ function configPathForOptions(options) {
|
|
|
3896
3939
|
}
|
|
3897
3940
|
|
|
3898
3941
|
function configPathForFile(options, filePath) {
|
|
3942
|
+
if (options.legacyConfigFile) return undefined;
|
|
3899
3943
|
if (options.noConfig) {
|
|
3900
3944
|
return undefined;
|
|
3901
3945
|
}
|
|
@@ -4289,7 +4333,7 @@ function isLintableFilePath(filePath) {
|
|
|
4289
4333
|
function filteredLintPaths(paths, options = {}) {
|
|
4290
4334
|
const values = normalizeStringArray(Array.isArray(paths) ? paths : [paths], "paths");
|
|
4291
4335
|
const cwd = options.cwd ?? process.cwd();
|
|
4292
|
-
const patterns = ignoreDisabled(options) ? [] : ignorePatternsForOptions(options, cwd);
|
|
4336
|
+
const patterns = ignoreDisabled(options) || defersLegacyIgnores(options) ? [] : ignorePatternsForOptions(options, cwd);
|
|
4293
4337
|
if (patterns.length === 0 && options.errorOnUnmatchedPattern !== false && !values.some(hasGlobMagic)) {
|
|
4294
4338
|
return values;
|
|
4295
4339
|
}
|
|
@@ -4408,7 +4452,7 @@ function ignoredLintPathDiagnostics(paths, options = {}) {
|
|
|
4408
4452
|
|
|
4409
4453
|
const cwd = options.cwd ?? process.cwd();
|
|
4410
4454
|
const patterns = ignorePatternsForOptions(options, cwd);
|
|
4411
|
-
if (patterns.length === 0) {
|
|
4455
|
+
if (patterns.length === 0 && !options[LEGACY_CONFIG_ENABLED]) {
|
|
4412
4456
|
return [];
|
|
4413
4457
|
}
|
|
4414
4458
|
|
|
@@ -4425,7 +4469,7 @@ function ignoredLintPathDiagnostics(paths, options = {}) {
|
|
|
4425
4469
|
continue;
|
|
4426
4470
|
}
|
|
4427
4471
|
|
|
4428
|
-
if (
|
|
4472
|
+
if (isPathIgnored(filePath, options)) {
|
|
4429
4473
|
diagnostics.push(ignoredFileDiagnostic(filePath));
|
|
4430
4474
|
}
|
|
4431
4475
|
}
|
|
@@ -4497,11 +4541,19 @@ function isPathIgnored(filePath, options = {}) {
|
|
|
4497
4541
|
}
|
|
4498
4542
|
|
|
4499
4543
|
const cwd = options.cwd ?? process.cwd();
|
|
4544
|
+
const legacyConfig = legacyConfigForFile(options, filePath);
|
|
4545
|
+
if (legacyConfig) {
|
|
4546
|
+
return Boolean(legacyConfig.isIgnored?.(normalizeESLintFilePath(filePath, cwd)));
|
|
4547
|
+
}
|
|
4500
4548
|
const normalized = normalizeIgnoredPath(filePath, cwd);
|
|
4501
4549
|
const patterns = ignorePatternsForOptions(options, cwd, filePath);
|
|
4502
4550
|
return pathIgnoredByPatterns(normalized, patterns);
|
|
4503
4551
|
}
|
|
4504
4552
|
|
|
4553
|
+
function defersLegacyIgnores(options) {
|
|
4554
|
+
return options[LEGACY_CONFIG_ENABLED] && (options.legacyConfigFile || (!options.noConfig && !configPathForOptions(options)));
|
|
4555
|
+
}
|
|
4556
|
+
|
|
4505
4557
|
function ignoreDisabled(options = {}) {
|
|
4506
4558
|
return options.noIgnore || options.ignore === false;
|
|
4507
4559
|
}
|
|
@@ -4879,6 +4931,12 @@ function diagnosticToESLintMessage(diagnostic, ruleSeverities) {
|
|
|
4879
4931
|
column: diagnostic.column,
|
|
4880
4932
|
nodeType: null
|
|
4881
4933
|
};
|
|
4934
|
+
if (diagnostic.endLine != null) {
|
|
4935
|
+
message.endLine = diagnostic.endLine;
|
|
4936
|
+
}
|
|
4937
|
+
if (diagnostic.endColumn != null) {
|
|
4938
|
+
message.endColumn = diagnostic.endColumn;
|
|
4939
|
+
}
|
|
4882
4940
|
const fixes = (diagnostic.fixes ?? []).map((fix) => ({
|
|
4883
4941
|
range: fix.range,
|
|
4884
4942
|
text: fix.text
|
|
@@ -4950,31 +5008,7 @@ function maybeFilterQuietResults(results, options = {}) {
|
|
|
4950
5008
|
return results;
|
|
4951
5009
|
}
|
|
4952
5010
|
|
|
4953
|
-
function
|
|
4954
|
-
const lines = [];
|
|
4955
|
-
let errorCount = 0;
|
|
4956
|
-
let warningCount = 0;
|
|
4957
|
-
|
|
4958
|
-
for (const result of results) {
|
|
4959
|
-
if (result.messages.length === 0) continue;
|
|
4960
|
-
lines.push(result.filePath);
|
|
4961
|
-
for (const message of result.messages) {
|
|
4962
|
-
const severity = message.severity === 2 ? "error" : "warning";
|
|
4963
|
-
lines.push(` ${message.line}:${message.column} ${severity} ${message.message} ${message.ruleId}`);
|
|
4964
|
-
}
|
|
4965
|
-
errorCount += result.errorCount;
|
|
4966
|
-
warningCount += result.warningCount;
|
|
4967
|
-
}
|
|
4968
|
-
|
|
4969
|
-
if (errorCount || warningCount) {
|
|
4970
|
-
lines.push("");
|
|
4971
|
-
lines.push(`x ${errorCount + warningCount} problem${errorCount + warningCount === 1 ? "" : "s"} (${errorCount} error${errorCount === 1 ? "" : "s"}, ${warningCount} warning${warningCount === 1 ? "" : "s"})`);
|
|
4972
|
-
}
|
|
4973
|
-
|
|
4974
|
-
return lines.join("\n");
|
|
4975
|
-
}
|
|
4976
|
-
|
|
4977
|
-
function formatResultsByName(input, name = "stylish", metadata = {}) {
|
|
5011
|
+
function formatResultsByName(input, name = "stylish", metadata = {}, options = {}) {
|
|
4978
5012
|
const results = formatterResults(input);
|
|
4979
5013
|
if (name === "json") {
|
|
4980
5014
|
return JSON.stringify(input);
|
|
@@ -4993,7 +5027,7 @@ function formatResultsByName(input, name = "stylish", metadata = {}) {
|
|
|
4993
5027
|
if (name === "unix") {
|
|
4994
5028
|
return formatUnixResults(results);
|
|
4995
5029
|
}
|
|
4996
|
-
return formatESLintResults(results);
|
|
5030
|
+
return formatESLintResults(results, options);
|
|
4997
5031
|
}
|
|
4998
5032
|
|
|
4999
5033
|
function formatterResults(input) {
|
|
@@ -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 };
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
const { stripVTControlCharacters } = require("node:util");
|
|
2
|
+
|
|
3
|
+
function formatESLintResults(results, options = {}) {
|
|
4
|
+
const color = shouldUseColor(options);
|
|
5
|
+
const paint = (text, open, close) => color ? `\u001b[${open}m${text}\u001b[${close}m` : text;
|
|
6
|
+
const lines = [""];
|
|
7
|
+
let errorCount = 0;
|
|
8
|
+
let warningCount = 0;
|
|
9
|
+
let fixableErrorCount = 0;
|
|
10
|
+
let fixableWarningCount = 0;
|
|
11
|
+
|
|
12
|
+
for (const result of results) {
|
|
13
|
+
if (result.messages.length === 0) continue;
|
|
14
|
+
lines.push(paint(result.filePath, 4, 24));
|
|
15
|
+
// Sort a copy: formatting must not reorder the caller's results or JSON output.
|
|
16
|
+
const messages = [...result.messages].sort((left, right) =>
|
|
17
|
+
(left.line ?? 0) - (right.line ?? 0) || (left.column ?? 0) - (right.column ?? 0)
|
|
18
|
+
);
|
|
19
|
+
const rows = messages.map((message) => [
|
|
20
|
+
String(message.line || 0),
|
|
21
|
+
String(message.column || 0),
|
|
22
|
+
message.fatal || message.severity === 2 ? "error" : "warning",
|
|
23
|
+
// Unlike ESLint stylish, retain punctuation in the original rule message.
|
|
24
|
+
message.message,
|
|
25
|
+
message.ruleId || "",
|
|
26
|
+
]);
|
|
27
|
+
const widths = [0, 0, 0, 0];
|
|
28
|
+
for (const row of rows) {
|
|
29
|
+
for (let index = 0; index < widths.length; index += 1) {
|
|
30
|
+
widths[index] = Math.max(widths[index], stripVTControlCharacters(row[index]).length);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
for (const [line, column, severity, message, ruleId] of rows) {
|
|
34
|
+
const location = " ".repeat(widths[0] - line.length)
|
|
35
|
+
+ paint(`${line}:${column}`, 2, 22)
|
|
36
|
+
+ " ".repeat(widths[1] - column.length);
|
|
37
|
+
const label = paint(severity, severity === "error" ? 31 : 33, 39)
|
|
38
|
+
+ " ".repeat(widths[2] - severity.length);
|
|
39
|
+
const padding = " ".repeat(widths[3] - stripVTControlCharacters(message).length);
|
|
40
|
+
const description = ruleId ? `${message}${padding} ${paint(ruleId, 2, 22)}` : message;
|
|
41
|
+
lines.push(` ${location} ${label} ${description}`);
|
|
42
|
+
}
|
|
43
|
+
lines.push("");
|
|
44
|
+
errorCount += result.errorCount;
|
|
45
|
+
warningCount += result.warningCount;
|
|
46
|
+
fixableErrorCount += result.fixableErrorCount ?? 0;
|
|
47
|
+
fixableWarningCount += result.fixableWarningCount ?? 0;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (errorCount || warningCount) {
|
|
51
|
+
const summary = (text) => paint(paint(text, 1, 22), errorCount ? 31 : 33, 39);
|
|
52
|
+
lines.push(summary(
|
|
53
|
+
`✖ ${pluralize(errorCount + warningCount, "problem")} (${pluralize(errorCount, "error")}, ${pluralize(warningCount, "warning")})`
|
|
54
|
+
));
|
|
55
|
+
if (fixableErrorCount || fixableWarningCount) {
|
|
56
|
+
lines.push(summary(
|
|
57
|
+
` ${pluralize(fixableErrorCount, "error")} and ${pluralize(fixableWarningCount, "warning")} potentially fixable with the \`--fix\` option.`
|
|
58
|
+
));
|
|
59
|
+
}
|
|
60
|
+
lines.push("");
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return lines.join("\n");
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function pluralize(count, noun) {
|
|
67
|
+
return `${count} ${noun}${count === 1 ? "" : "s"}`;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function shouldUseColor(options) {
|
|
71
|
+
if (typeof options.color === "boolean") return options.color;
|
|
72
|
+
const env = options.env ? { ...process.env, ...options.env } : process.env;
|
|
73
|
+
if (env.NO_COLOR !== undefined || env.NODE_DISABLE_COLORS !== undefined) return false;
|
|
74
|
+
if (env.FORCE_COLOR !== undefined) return env.FORCE_COLOR !== "0";
|
|
75
|
+
if (env.CLICOLOR_FORCE && env.CLICOLOR_FORCE !== "0") return true;
|
|
76
|
+
return env.TERM !== "dumb" && Boolean(process.stdout.isTTY);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
module.exports = { formatESLintResults };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@utoo/lint",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.8",
|
|
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.8",
|
|
80
|
+
"@utoo/lint-darwin-x64": "0.3.8",
|
|
81
|
+
"@utoo/lint-linux-arm64": "0.3.8",
|
|
82
|
+
"@utoo/lint-linux-x64": "0.3.8",
|
|
83
|
+
"@utoo/lint-win32-x64": "0.3.8"
|
|
84
84
|
},
|
|
85
85
|
"dependencies": {
|
|
86
86
|
"@eslint/eslintrc": "2.1.4",
|