@utoo/lint 0.3.4 → 0.3.5
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/index.cjs +213 -16
- package/index.d.ts +1 -1
- package/index.js +213 -16
- package/lib/config-loader.cjs +16 -3
- package/lib/config-loader.js +16 -3
- package/package.json +6 -6
package/index.cjs
CHANGED
|
@@ -14,6 +14,7 @@ const version = JSON.parse(readFileSync(join(__dirname, "package.json"), "utf8")
|
|
|
14
14
|
|
|
15
15
|
const LINTABLE_EXTENSIONS = new Set([".js", ".jsx", ".ts", ".tsx", ".mjs", ".cjs", ".mts", ".cts"]);
|
|
16
16
|
const MAX_AUTOFIX_PASSES = 10;
|
|
17
|
+
const CONFIG_DISCOVERY_CACHE = Symbol("configDiscoveryCache");
|
|
17
18
|
const JS_KEYWORDS = new Set([
|
|
18
19
|
"await", "break", "case", "catch", "class", "const", "continue", "debugger", "default", "delete",
|
|
19
20
|
"do", "else", "export", "extends", "finally", "for", "function", "if", "import", "in",
|
|
@@ -569,7 +570,7 @@ class UtooLint {
|
|
|
569
570
|
}
|
|
570
571
|
|
|
571
572
|
async isPathIgnored(filePath) {
|
|
572
|
-
return isPathIgnored(filePath, mergeLintOptions(this.options, {}));
|
|
573
|
+
return isPathIgnored(filePath, withConfigCache(mergeLintOptions(this.options, {})));
|
|
573
574
|
}
|
|
574
575
|
|
|
575
576
|
async calculateConfigForFile(filePath) {
|
|
@@ -577,7 +578,7 @@ class UtooLint {
|
|
|
577
578
|
}
|
|
578
579
|
|
|
579
580
|
async findConfigFile(filePath) {
|
|
580
|
-
const options = eslintConstructorOptions(this.options);
|
|
581
|
+
const options = withConfigCache(eslintConstructorOptions(this.options));
|
|
581
582
|
if (options.noConfig) {
|
|
582
583
|
return undefined;
|
|
583
584
|
}
|
|
@@ -711,7 +712,7 @@ class CLIEngine {
|
|
|
711
712
|
}
|
|
712
713
|
|
|
713
714
|
isPathIgnored(filePath) {
|
|
714
|
-
return isPathIgnored(filePath, eslintConstructorOptions(this.options));
|
|
715
|
+
return isPathIgnored(filePath, withConfigCache(eslintConstructorOptions(this.options)));
|
|
715
716
|
}
|
|
716
717
|
|
|
717
718
|
getConfigForFile(filePath) {
|
|
@@ -1210,6 +1211,12 @@ function lintFiles(paths, options = {}) {
|
|
|
1210
1211
|
return { files: 0, filePaths: [], diagnostics: ignoredDiagnostics, suppressedDiagnostics: [], exitCode: exitCodeForDiagnostics(ignoredDiagnostics) };
|
|
1211
1212
|
}
|
|
1212
1213
|
|
|
1214
|
+
const nativeFlatOptions = nativeFlatConfigOptions(options);
|
|
1215
|
+
if (nativeFlatOptions) {
|
|
1216
|
+
const report = runNativeLintReport(lintPaths, nativeFlatOptions);
|
|
1217
|
+
return finalizeLintReport(report, ignoredDiagnostics, options);
|
|
1218
|
+
}
|
|
1219
|
+
|
|
1213
1220
|
const configRuns = nativeConfigRunsForFiles(expandNativeConfigRunPaths(lintPaths, options), options);
|
|
1214
1221
|
if (configRuns) {
|
|
1215
1222
|
const report = mergeNativeReports(
|
|
@@ -1222,6 +1229,76 @@ function lintFiles(paths, options = {}) {
|
|
|
1222
1229
|
return finalizeLintReport(report, ignoredDiagnostics, options);
|
|
1223
1230
|
}
|
|
1224
1231
|
|
|
1232
|
+
function nativeFlatConfigOptions(options) {
|
|
1233
|
+
if (options.rules || options.extraArgs?.some((arg) => arg.startsWith("--") && arg !== "--fix" && arg !== "--fix-dry-run")) {
|
|
1234
|
+
return undefined;
|
|
1235
|
+
}
|
|
1236
|
+
|
|
1237
|
+
const fileConfigPath = options.noConfig ? undefined : configPathForOptions(options);
|
|
1238
|
+
const inlineConfigs = [options.baseConfig, options.overrideConfig].filter(Boolean);
|
|
1239
|
+
if (fileConfigPath && inlineConfigs.length > 0) {
|
|
1240
|
+
return undefined;
|
|
1241
|
+
}
|
|
1242
|
+
|
|
1243
|
+
let config;
|
|
1244
|
+
let configRoot;
|
|
1245
|
+
if (fileConfigPath) {
|
|
1246
|
+
config = readConfig(fileConfigPath, options.cwd, options.configCache);
|
|
1247
|
+
configRoot = dirname(fileConfigPath);
|
|
1248
|
+
} else if (inlineConfigs.length > 0) {
|
|
1249
|
+
config = inlineConfigs.length === 1 ? inlineConfigs[0] : inlineConfigs;
|
|
1250
|
+
configRoot = resolvePath(options.cwd ?? process.cwd());
|
|
1251
|
+
} else {
|
|
1252
|
+
return undefined;
|
|
1253
|
+
}
|
|
1254
|
+
|
|
1255
|
+
if (configCanUseNativeRulesFastPath(config)) {
|
|
1256
|
+
return undefined;
|
|
1257
|
+
}
|
|
1258
|
+
|
|
1259
|
+
const serializedConfig = nativeSerializableConfig(config);
|
|
1260
|
+
return {
|
|
1261
|
+
...options,
|
|
1262
|
+
nativeFlatConfigData: Array.isArray(serializedConfig) ? serializedConfig : [serializedConfig],
|
|
1263
|
+
nativeConfigRoot: configRoot,
|
|
1264
|
+
nativeConfigCwd: resolvePath(options.cwd ?? process.cwd())
|
|
1265
|
+
};
|
|
1266
|
+
}
|
|
1267
|
+
|
|
1268
|
+
function configCanUseNativeRulesFastPath(config) {
|
|
1269
|
+
const entries = Array.isArray(config) ? config : [config];
|
|
1270
|
+
let hasEnabledRule = false;
|
|
1271
|
+
for (const entry of entries) {
|
|
1272
|
+
if (!entry || typeof entry !== "object" || Object.keys(entry.settings ?? {}).length > 0) {
|
|
1273
|
+
return false;
|
|
1274
|
+
}
|
|
1275
|
+
for (const ruleConfig of Object.values(entry.rules ?? {})) {
|
|
1276
|
+
if (ruleConfigSeverity(ruleConfig) === 0) {
|
|
1277
|
+
continue;
|
|
1278
|
+
}
|
|
1279
|
+
if (!isPureRuleSeverity(ruleConfig)) {
|
|
1280
|
+
return false;
|
|
1281
|
+
}
|
|
1282
|
+
hasEnabledRule = true;
|
|
1283
|
+
}
|
|
1284
|
+
}
|
|
1285
|
+
return hasEnabledRule;
|
|
1286
|
+
}
|
|
1287
|
+
|
|
1288
|
+
function nativeSerializableConfig(config) {
|
|
1289
|
+
if (Array.isArray(config)) {
|
|
1290
|
+
return config.map(nativeSerializableConfig);
|
|
1291
|
+
}
|
|
1292
|
+
if (!config || typeof config !== "object") {
|
|
1293
|
+
return config;
|
|
1294
|
+
}
|
|
1295
|
+
return Object.fromEntries(
|
|
1296
|
+
["$schema", "name", "files", "ignores", "rules", "settings"]
|
|
1297
|
+
.filter((key) => config[key] !== undefined)
|
|
1298
|
+
.map((key) => [key, config[key]])
|
|
1299
|
+
);
|
|
1300
|
+
}
|
|
1301
|
+
|
|
1225
1302
|
function expandNativeConfigRunPaths(paths, options) {
|
|
1226
1303
|
const cwd = options.cwd ?? process.cwd();
|
|
1227
1304
|
const patterns = ignoreDisabled(options) ? [] : ignorePatternsForOptions(options, cwd);
|
|
@@ -1326,6 +1403,22 @@ function nativeConfigRunsForFiles(paths, options) {
|
|
|
1326
1403
|
};
|
|
1327
1404
|
}
|
|
1328
1405
|
|
|
1406
|
+
const selectedRules = severityOnlyNativeRuleNames(group.rules, group.settings);
|
|
1407
|
+
if (selectedRules) {
|
|
1408
|
+
return {
|
|
1409
|
+
paths: group.paths,
|
|
1410
|
+
options: {
|
|
1411
|
+
...options,
|
|
1412
|
+
config: undefined,
|
|
1413
|
+
noConfig: true,
|
|
1414
|
+
baseConfig: undefined,
|
|
1415
|
+
overrideConfig: undefined,
|
|
1416
|
+
rules: selectedRules,
|
|
1417
|
+
forceMaterializedConfig: undefined
|
|
1418
|
+
}
|
|
1419
|
+
};
|
|
1420
|
+
}
|
|
1421
|
+
|
|
1329
1422
|
return {
|
|
1330
1423
|
paths: group.paths,
|
|
1331
1424
|
options: {
|
|
@@ -1343,6 +1436,40 @@ function nativeConfigRunsForFiles(paths, options) {
|
|
|
1343
1436
|
});
|
|
1344
1437
|
}
|
|
1345
1438
|
|
|
1439
|
+
function severityOnlyNativeRuleNames(rules, settings) {
|
|
1440
|
+
if (Object.keys(settings ?? {}).length > 0) {
|
|
1441
|
+
return undefined;
|
|
1442
|
+
}
|
|
1443
|
+
|
|
1444
|
+
const selected = [];
|
|
1445
|
+
for (const [rule, config] of Object.entries(rules ?? {})) {
|
|
1446
|
+
if (ruleConfigSeverity(config) === 0) {
|
|
1447
|
+
continue;
|
|
1448
|
+
}
|
|
1449
|
+
if (!isPureRuleSeverity(config)) {
|
|
1450
|
+
return undefined;
|
|
1451
|
+
}
|
|
1452
|
+
selected.push(rule);
|
|
1453
|
+
}
|
|
1454
|
+
return selected.length > 0 ? selected : undefined;
|
|
1455
|
+
}
|
|
1456
|
+
|
|
1457
|
+
function isPureRuleSeverity(config) {
|
|
1458
|
+
if (Array.isArray(config)) {
|
|
1459
|
+
if (config.length !== 1) {
|
|
1460
|
+
return false;
|
|
1461
|
+
}
|
|
1462
|
+
[config] = config;
|
|
1463
|
+
}
|
|
1464
|
+
if (typeof config === "boolean") {
|
|
1465
|
+
return true;
|
|
1466
|
+
}
|
|
1467
|
+
if (typeof config === "number") {
|
|
1468
|
+
return config === 0 || config === 1 || config === 2;
|
|
1469
|
+
}
|
|
1470
|
+
return typeof config === "string" && ["off", "warn", "warning", "error", "0", "1", "2"].includes(config.toLowerCase());
|
|
1471
|
+
}
|
|
1472
|
+
|
|
1346
1473
|
function allDisabledNativeRules(rules) {
|
|
1347
1474
|
return {
|
|
1348
1475
|
...Object.fromEntries(NATIVE_RULE_IDS.map((rule) => [rule, "off"])),
|
|
@@ -1459,7 +1586,7 @@ function buildNativeLintArgs(paths, options) {
|
|
|
1459
1586
|
if (options.noConfig) {
|
|
1460
1587
|
cliArgs.push("--no-config");
|
|
1461
1588
|
}
|
|
1462
|
-
if (!options.rules && !options.forceMaterializedConfig && (options.config || options.baseConfig || options.overrideConfig)) {
|
|
1589
|
+
if (!options.nativeFlatConfigData && !options.rules && !options.forceMaterializedConfig && (options.config || options.baseConfig || options.overrideConfig)) {
|
|
1463
1590
|
const configForRuleSelection = options.noConfig
|
|
1464
1591
|
? undefined
|
|
1465
1592
|
: options.config ? readConfig(options.config, options.cwd, options.configCache) : undefined;
|
|
@@ -1475,6 +1602,12 @@ function buildNativeLintArgs(paths, options) {
|
|
|
1475
1602
|
if (options.config) {
|
|
1476
1603
|
cliArgs.push(`--config=${options.config}`);
|
|
1477
1604
|
}
|
|
1605
|
+
if (options.nativeConfigRoot) {
|
|
1606
|
+
cliArgs.push(`--config-root=${options.nativeConfigRoot}`);
|
|
1607
|
+
}
|
|
1608
|
+
if (options.nativeConfigCwd) {
|
|
1609
|
+
cliArgs.push(`--config-cwd=${options.nativeConfigCwd}`);
|
|
1610
|
+
}
|
|
1478
1611
|
if (options.rules) {
|
|
1479
1612
|
const rules = Array.isArray(options.rules) ? options.rules.join(",") : options.rules;
|
|
1480
1613
|
if (rules) {
|
|
@@ -1509,9 +1642,17 @@ function mergeLintOptions(base, override) {
|
|
|
1509
1642
|
}
|
|
1510
1643
|
|
|
1511
1644
|
function withConfigCache(options) {
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1645
|
+
if (options.configCache && options[CONFIG_DISCOVERY_CACHE]) {
|
|
1646
|
+
return options;
|
|
1647
|
+
}
|
|
1648
|
+
|
|
1649
|
+
return {
|
|
1650
|
+
...options,
|
|
1651
|
+
// Executable configs are otherwise re-evaluated at every per-file lookup.
|
|
1652
|
+
configCache: options.configCache ?? new Map(),
|
|
1653
|
+
// Discovery results must not survive into a later public invocation.
|
|
1654
|
+
[CONFIG_DISCOVERY_CACHE]: new Map()
|
|
1655
|
+
};
|
|
1515
1656
|
}
|
|
1516
1657
|
|
|
1517
1658
|
function eslintConstructorOptions(options) {
|
|
@@ -1852,7 +1993,7 @@ function configPathForOptions(options) {
|
|
|
1852
1993
|
}
|
|
1853
1994
|
|
|
1854
1995
|
const cwd = options.cwd ?? process.cwd();
|
|
1855
|
-
return configPathFromDirectory(cwd);
|
|
1996
|
+
return configPathFromDirectory(cwd, options);
|
|
1856
1997
|
}
|
|
1857
1998
|
|
|
1858
1999
|
function configPathForFile(options, filePath) {
|
|
@@ -1862,7 +2003,7 @@ function configPathForFile(options, filePath) {
|
|
|
1862
2003
|
if (options.config) {
|
|
1863
2004
|
return resolvePath(options.cwd ?? process.cwd(), options.config);
|
|
1864
2005
|
}
|
|
1865
|
-
return configPathFromDirectory(configSearchDirectoryForFile(filePath, options.cwd));
|
|
2006
|
+
return configPathFromDirectory(configSearchDirectoryForFile(filePath, options.cwd), options);
|
|
1866
2007
|
}
|
|
1867
2008
|
|
|
1868
2009
|
function configSearchDirectoryForFile(filePath, cwd) {
|
|
@@ -1877,11 +2018,29 @@ function configSearchDirectoryForFile(filePath, cwd) {
|
|
|
1877
2018
|
return dirname(absolute);
|
|
1878
2019
|
}
|
|
1879
2020
|
|
|
1880
|
-
function configPathFromDirectory(directory) {
|
|
1881
|
-
return findConfigPathFromDirectory(directory);
|
|
2021
|
+
function configPathFromDirectory(directory, options) {
|
|
2022
|
+
return findConfigPathFromDirectory(directory, options[CONFIG_DISCOVERY_CACHE]);
|
|
1882
2023
|
}
|
|
1883
2024
|
|
|
1884
2025
|
function withTemporaryConfig(options, callback) {
|
|
2026
|
+
if (options.nativeFlatConfigData !== undefined) {
|
|
2027
|
+
const tmp = mkdtempSync(join(tmpdir(), "utoo-lint-flat-config-"));
|
|
2028
|
+
const configPath = join(tmp, "utlint.config.json");
|
|
2029
|
+
try {
|
|
2030
|
+
writeFileSync(configPath, JSON.stringify(options.nativeFlatConfigData));
|
|
2031
|
+
return callback({
|
|
2032
|
+
...options,
|
|
2033
|
+
config: configPath,
|
|
2034
|
+
noConfig: false,
|
|
2035
|
+
baseConfig: undefined,
|
|
2036
|
+
overrideConfig: undefined,
|
|
2037
|
+
forceMaterializedConfig: true
|
|
2038
|
+
});
|
|
2039
|
+
} finally {
|
|
2040
|
+
rmSync(tmp, { recursive: true, force: true });
|
|
2041
|
+
}
|
|
2042
|
+
}
|
|
2043
|
+
|
|
1885
2044
|
const fileConfigPath = !options.noConfig ? configPathForOptions(options) : undefined;
|
|
1886
2045
|
const shouldMaterializeFileConfig = Boolean(fileConfigPath);
|
|
1887
2046
|
const fileConfig = shouldMaterializeFileConfig
|
|
@@ -2063,15 +2222,20 @@ class Linter {
|
|
|
2063
2222
|
filename: filePath,
|
|
2064
2223
|
config: calculatedConfig({ cwd: verifyOptions.cwd, noConfig: true, overrideConfig: config }, normalizedFilePath)
|
|
2065
2224
|
});
|
|
2225
|
+
const nativeRuleFilter = applyDisableDirectives(
|
|
2226
|
+
(report.diagnostics ?? []).map((diagnostic) => diagnosticToESLintMessage(diagnostic, ruleSeverities)),
|
|
2227
|
+
sourceCode
|
|
2228
|
+
);
|
|
2066
2229
|
const customRuleFilter = applyDisableDirectives(customRuleMessages, sourceCode);
|
|
2067
2230
|
this.suppressedMessages = [
|
|
2068
2231
|
...(report.suppressedDiagnostics ?? []).map((diagnostic) => suppressedDiagnosticToESLintMessage(diagnostic, ruleSeverities)),
|
|
2232
|
+
...nativeRuleFilter.suppressedMessages,
|
|
2069
2233
|
...customRuleFilter.suppressedMessages
|
|
2070
2234
|
];
|
|
2071
2235
|
this.times = { passes: [] };
|
|
2072
2236
|
this.fixPassCount = 0;
|
|
2073
2237
|
return [
|
|
2074
|
-
...
|
|
2238
|
+
...nativeRuleFilter.messages,
|
|
2075
2239
|
...customRuleFilter.messages
|
|
2076
2240
|
];
|
|
2077
2241
|
}
|
|
@@ -2362,6 +2526,7 @@ function applyDisableDirectives(messages, sourceCode) {
|
|
|
2362
2526
|
}
|
|
2363
2527
|
const directives = sourceCode.getDisableDirectives()
|
|
2364
2528
|
.filter((directive) => directive.node?.loc?.start?.line)
|
|
2529
|
+
.filter((directive) => directive.type !== "eslint-disable-line" || directive.node.loc.start.line === directive.node.loc.end.line)
|
|
2365
2530
|
.sort((left, right) => left.node.loc.start.line - right.node.loc.start.line);
|
|
2366
2531
|
const utlintDirectives = sourceCode.getAllComments()
|
|
2367
2532
|
.map((comment) => utlintDirectiveFromComment(comment, sourceCode))
|
|
@@ -2374,6 +2539,10 @@ function applyDisableDirectives(messages, sourceCode) {
|
|
|
2374
2539
|
const kept = [];
|
|
2375
2540
|
const suppressed = [];
|
|
2376
2541
|
for (const message of messages) {
|
|
2542
|
+
if (!message.ruleId || message.ruleId === "parse" || message.ruleId === "io") {
|
|
2543
|
+
kept.push(message);
|
|
2544
|
+
continue;
|
|
2545
|
+
}
|
|
2377
2546
|
const directive = utlintDirectiveForMessage(message, utlintDirectives) ?? disableDirectiveForMessage(message, directives);
|
|
2378
2547
|
if (directive) {
|
|
2379
2548
|
suppressed.push({
|
|
@@ -3954,12 +4123,38 @@ function reportToESLintResults(report, textOptions = {}) {
|
|
|
3954
4123
|
}
|
|
3955
4124
|
|
|
3956
4125
|
for (const result of byFile.values()) {
|
|
4126
|
+
applyCompatibilityDisableDirectives(result, textOptions);
|
|
3957
4127
|
finalizeESLintResult(result);
|
|
3958
4128
|
}
|
|
3959
4129
|
|
|
3960
4130
|
return [...byFile.values()];
|
|
3961
4131
|
}
|
|
3962
4132
|
|
|
4133
|
+
function applyCompatibilityDisableDirectives(result, textOptions) {
|
|
4134
|
+
if (result.messages.length === 0) {
|
|
4135
|
+
return;
|
|
4136
|
+
}
|
|
4137
|
+
|
|
4138
|
+
let source = result.source;
|
|
4139
|
+
if (typeof source !== "string" && textOptions.filePath === result.filePath) {
|
|
4140
|
+
source = textOptions.source;
|
|
4141
|
+
}
|
|
4142
|
+
if (typeof source !== "string") {
|
|
4143
|
+
try {
|
|
4144
|
+
source = readFileSync(result.filePath, "utf8");
|
|
4145
|
+
} catch {
|
|
4146
|
+
return;
|
|
4147
|
+
}
|
|
4148
|
+
}
|
|
4149
|
+
if (!source.includes("eslint-")) {
|
|
4150
|
+
return;
|
|
4151
|
+
}
|
|
4152
|
+
|
|
4153
|
+
const filtered = applyDisableDirectives(result.messages, createLinterSourceCode(source));
|
|
4154
|
+
result.messages = filtered.messages;
|
|
4155
|
+
result.suppressedMessages.push(...filtered.suppressedMessages);
|
|
4156
|
+
}
|
|
4157
|
+
|
|
3963
4158
|
function normalizeReportDiagnostics(diagnostics, options = {}) {
|
|
3964
4159
|
return (diagnostics ?? []).flatMap((diagnostic) => {
|
|
3965
4160
|
if (!diagnostic?.ruleId) {
|
|
@@ -4709,10 +4904,12 @@ function diagnosticToESLintMessage(diagnostic, ruleSeverities) {
|
|
|
4709
4904
|
function suppressedDiagnosticToESLintMessage(diagnostic, ruleSeverities) {
|
|
4710
4905
|
return {
|
|
4711
4906
|
...diagnosticToESLintMessage(diagnostic, ruleSeverities),
|
|
4712
|
-
suppressions:
|
|
4713
|
-
|
|
4714
|
-
|
|
4715
|
-
|
|
4907
|
+
suppressions: diagnostic.suppressions?.length > 0
|
|
4908
|
+
? diagnostic.suppressions
|
|
4909
|
+
: [{
|
|
4910
|
+
kind: diagnostic.suppression?.kind ?? "directive",
|
|
4911
|
+
justification: diagnostic.suppression?.justification ?? ""
|
|
4912
|
+
}]
|
|
4716
4913
|
};
|
|
4717
4914
|
}
|
|
4718
4915
|
|
package/index.d.ts
CHANGED
|
@@ -17,7 +17,7 @@ export interface LintSuppression {
|
|
|
17
17
|
justification: string;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
export interface LintDiagnostic extends Omit<LintMessage, "severity"
|
|
20
|
+
export interface LintDiagnostic extends Omit<LintMessage, "severity"> {
|
|
21
21
|
severity: "warning" | "error";
|
|
22
22
|
suppression?: LintSuppression;
|
|
23
23
|
}
|
package/index.js
CHANGED
|
@@ -17,6 +17,7 @@ export const version = JSON.parse(readFileSync(new URL("./package.json", import.
|
|
|
17
17
|
|
|
18
18
|
const LINTABLE_EXTENSIONS = new Set([".js", ".jsx", ".ts", ".tsx", ".mjs", ".cjs", ".mts", ".cts"]);
|
|
19
19
|
const MAX_AUTOFIX_PASSES = 10;
|
|
20
|
+
const CONFIG_DISCOVERY_CACHE = Symbol("configDiscoveryCache");
|
|
20
21
|
const JS_KEYWORDS = new Set([
|
|
21
22
|
"await", "break", "case", "catch", "class", "const", "continue", "debugger", "default", "delete",
|
|
22
23
|
"do", "else", "export", "extends", "finally", "for", "function", "if", "import", "in",
|
|
@@ -572,7 +573,7 @@ export class UtooLint {
|
|
|
572
573
|
}
|
|
573
574
|
|
|
574
575
|
async isPathIgnored(filePath) {
|
|
575
|
-
return isPathIgnored(filePath, mergeLintOptions(this.options, {}));
|
|
576
|
+
return isPathIgnored(filePath, withConfigCache(mergeLintOptions(this.options, {})));
|
|
576
577
|
}
|
|
577
578
|
|
|
578
579
|
async calculateConfigForFile(filePath) {
|
|
@@ -580,7 +581,7 @@ export class UtooLint {
|
|
|
580
581
|
}
|
|
581
582
|
|
|
582
583
|
async findConfigFile(filePath) {
|
|
583
|
-
const options = eslintConstructorOptions(this.options);
|
|
584
|
+
const options = withConfigCache(eslintConstructorOptions(this.options));
|
|
584
585
|
if (options.noConfig) {
|
|
585
586
|
return undefined;
|
|
586
587
|
}
|
|
@@ -679,15 +680,20 @@ export class Linter {
|
|
|
679
680
|
filename: filePath,
|
|
680
681
|
config: calculatedConfig({ cwd: verifyOptions.cwd, noConfig: true, overrideConfig: config }, normalizedFilePath)
|
|
681
682
|
});
|
|
683
|
+
const nativeRuleFilter = applyDisableDirectives(
|
|
684
|
+
(report.diagnostics ?? []).map((diagnostic) => diagnosticToESLintMessage(diagnostic, ruleSeverities)),
|
|
685
|
+
sourceCode
|
|
686
|
+
);
|
|
682
687
|
const customRuleFilter = applyDisableDirectives(customRuleMessages, sourceCode);
|
|
683
688
|
this.suppressedMessages = [
|
|
684
689
|
...(report.suppressedDiagnostics ?? []).map((diagnostic) => suppressedDiagnosticToESLintMessage(diagnostic, ruleSeverities)),
|
|
690
|
+
...nativeRuleFilter.suppressedMessages,
|
|
685
691
|
...customRuleFilter.suppressedMessages
|
|
686
692
|
];
|
|
687
693
|
this.times = { passes: [] };
|
|
688
694
|
this.fixPassCount = 0;
|
|
689
695
|
return [
|
|
690
|
-
...
|
|
696
|
+
...nativeRuleFilter.messages,
|
|
691
697
|
...customRuleFilter.messages
|
|
692
698
|
];
|
|
693
699
|
}
|
|
@@ -978,6 +984,7 @@ function applyDisableDirectives(messages, sourceCode) {
|
|
|
978
984
|
}
|
|
979
985
|
const directives = sourceCode.getDisableDirectives()
|
|
980
986
|
.filter((directive) => directive.node?.loc?.start?.line)
|
|
987
|
+
.filter((directive) => directive.type !== "eslint-disable-line" || directive.node.loc.start.line === directive.node.loc.end.line)
|
|
981
988
|
.sort((left, right) => left.node.loc.start.line - right.node.loc.start.line);
|
|
982
989
|
const utlintDirectives = sourceCode.getAllComments()
|
|
983
990
|
.map((comment) => utlintDirectiveFromComment(comment, sourceCode))
|
|
@@ -990,6 +997,10 @@ function applyDisableDirectives(messages, sourceCode) {
|
|
|
990
997
|
const kept = [];
|
|
991
998
|
const suppressed = [];
|
|
992
999
|
for (const message of messages) {
|
|
1000
|
+
if (!message.ruleId || message.ruleId === "parse" || message.ruleId === "io") {
|
|
1001
|
+
kept.push(message);
|
|
1002
|
+
continue;
|
|
1003
|
+
}
|
|
993
1004
|
const directive = utlintDirectiveForMessage(message, utlintDirectives) ?? disableDirectiveForMessage(message, directives);
|
|
994
1005
|
if (directive) {
|
|
995
1006
|
suppressed.push({
|
|
@@ -2600,7 +2611,7 @@ export class CLIEngine {
|
|
|
2600
2611
|
}
|
|
2601
2612
|
|
|
2602
2613
|
isPathIgnored(filePath) {
|
|
2603
|
-
return isPathIgnored(filePath, eslintConstructorOptions(this.options));
|
|
2614
|
+
return isPathIgnored(filePath, withConfigCache(eslintConstructorOptions(this.options)));
|
|
2604
2615
|
}
|
|
2605
2616
|
|
|
2606
2617
|
getConfigForFile(filePath) {
|
|
@@ -3099,6 +3110,12 @@ export function lintFiles(paths, options = {}) {
|
|
|
3099
3110
|
return { files: 0, filePaths: [], diagnostics: ignoredDiagnostics, suppressedDiagnostics: [], exitCode: exitCodeForDiagnostics(ignoredDiagnostics) };
|
|
3100
3111
|
}
|
|
3101
3112
|
|
|
3113
|
+
const nativeFlatOptions = nativeFlatConfigOptions(options);
|
|
3114
|
+
if (nativeFlatOptions) {
|
|
3115
|
+
const report = runNativeLintReport(lintPaths, nativeFlatOptions);
|
|
3116
|
+
return finalizeLintReport(report, ignoredDiagnostics, options);
|
|
3117
|
+
}
|
|
3118
|
+
|
|
3102
3119
|
const configRuns = nativeConfigRunsForFiles(expandNativeConfigRunPaths(lintPaths, options), options);
|
|
3103
3120
|
if (configRuns) {
|
|
3104
3121
|
const report = mergeNativeReports(
|
|
@@ -3111,6 +3128,76 @@ export function lintFiles(paths, options = {}) {
|
|
|
3111
3128
|
return finalizeLintReport(report, ignoredDiagnostics, options);
|
|
3112
3129
|
}
|
|
3113
3130
|
|
|
3131
|
+
function nativeFlatConfigOptions(options) {
|
|
3132
|
+
if (options.rules || options.extraArgs?.some((arg) => arg.startsWith("--") && arg !== "--fix" && arg !== "--fix-dry-run")) {
|
|
3133
|
+
return undefined;
|
|
3134
|
+
}
|
|
3135
|
+
|
|
3136
|
+
const fileConfigPath = options.noConfig ? undefined : configPathForOptions(options);
|
|
3137
|
+
const inlineConfigs = [options.baseConfig, options.overrideConfig].filter(Boolean);
|
|
3138
|
+
if (fileConfigPath && inlineConfigs.length > 0) {
|
|
3139
|
+
return undefined;
|
|
3140
|
+
}
|
|
3141
|
+
|
|
3142
|
+
let config;
|
|
3143
|
+
let configRoot;
|
|
3144
|
+
if (fileConfigPath) {
|
|
3145
|
+
config = readConfig(fileConfigPath, options.cwd, options.configCache);
|
|
3146
|
+
configRoot = dirname(fileConfigPath);
|
|
3147
|
+
} else if (inlineConfigs.length > 0) {
|
|
3148
|
+
config = inlineConfigs.length === 1 ? inlineConfigs[0] : inlineConfigs;
|
|
3149
|
+
configRoot = resolvePath(options.cwd ?? process.cwd());
|
|
3150
|
+
} else {
|
|
3151
|
+
return undefined;
|
|
3152
|
+
}
|
|
3153
|
+
|
|
3154
|
+
if (configCanUseNativeRulesFastPath(config)) {
|
|
3155
|
+
return undefined;
|
|
3156
|
+
}
|
|
3157
|
+
|
|
3158
|
+
const serializedConfig = nativeSerializableConfig(config);
|
|
3159
|
+
return {
|
|
3160
|
+
...options,
|
|
3161
|
+
nativeFlatConfigData: Array.isArray(serializedConfig) ? serializedConfig : [serializedConfig],
|
|
3162
|
+
nativeConfigRoot: configRoot,
|
|
3163
|
+
nativeConfigCwd: resolvePath(options.cwd ?? process.cwd())
|
|
3164
|
+
};
|
|
3165
|
+
}
|
|
3166
|
+
|
|
3167
|
+
function configCanUseNativeRulesFastPath(config) {
|
|
3168
|
+
const entries = Array.isArray(config) ? config : [config];
|
|
3169
|
+
let hasEnabledRule = false;
|
|
3170
|
+
for (const entry of entries) {
|
|
3171
|
+
if (!entry || typeof entry !== "object" || Object.keys(entry.settings ?? {}).length > 0) {
|
|
3172
|
+
return false;
|
|
3173
|
+
}
|
|
3174
|
+
for (const ruleConfig of Object.values(entry.rules ?? {})) {
|
|
3175
|
+
if (ruleConfigSeverity(ruleConfig) === 0) {
|
|
3176
|
+
continue;
|
|
3177
|
+
}
|
|
3178
|
+
if (!isPureRuleSeverity(ruleConfig)) {
|
|
3179
|
+
return false;
|
|
3180
|
+
}
|
|
3181
|
+
hasEnabledRule = true;
|
|
3182
|
+
}
|
|
3183
|
+
}
|
|
3184
|
+
return hasEnabledRule;
|
|
3185
|
+
}
|
|
3186
|
+
|
|
3187
|
+
function nativeSerializableConfig(config) {
|
|
3188
|
+
if (Array.isArray(config)) {
|
|
3189
|
+
return config.map(nativeSerializableConfig);
|
|
3190
|
+
}
|
|
3191
|
+
if (!config || typeof config !== "object") {
|
|
3192
|
+
return config;
|
|
3193
|
+
}
|
|
3194
|
+
return Object.fromEntries(
|
|
3195
|
+
["$schema", "name", "files", "ignores", "rules", "settings"]
|
|
3196
|
+
.filter((key) => config[key] !== undefined)
|
|
3197
|
+
.map((key) => [key, config[key]])
|
|
3198
|
+
);
|
|
3199
|
+
}
|
|
3200
|
+
|
|
3114
3201
|
function expandNativeConfigRunPaths(paths, options) {
|
|
3115
3202
|
const cwd = options.cwd ?? process.cwd();
|
|
3116
3203
|
const patterns = ignoreDisabled(options) ? [] : ignorePatternsForOptions(options, cwd);
|
|
@@ -3215,6 +3302,22 @@ function nativeConfigRunsForFiles(paths, options) {
|
|
|
3215
3302
|
};
|
|
3216
3303
|
}
|
|
3217
3304
|
|
|
3305
|
+
const selectedRules = severityOnlyNativeRuleNames(group.rules, group.settings);
|
|
3306
|
+
if (selectedRules) {
|
|
3307
|
+
return {
|
|
3308
|
+
paths: group.paths,
|
|
3309
|
+
options: {
|
|
3310
|
+
...options,
|
|
3311
|
+
config: undefined,
|
|
3312
|
+
noConfig: true,
|
|
3313
|
+
baseConfig: undefined,
|
|
3314
|
+
overrideConfig: undefined,
|
|
3315
|
+
rules: selectedRules,
|
|
3316
|
+
forceMaterializedConfig: undefined
|
|
3317
|
+
}
|
|
3318
|
+
};
|
|
3319
|
+
}
|
|
3320
|
+
|
|
3218
3321
|
return {
|
|
3219
3322
|
paths: group.paths,
|
|
3220
3323
|
options: {
|
|
@@ -3232,6 +3335,40 @@ function nativeConfigRunsForFiles(paths, options) {
|
|
|
3232
3335
|
});
|
|
3233
3336
|
}
|
|
3234
3337
|
|
|
3338
|
+
function severityOnlyNativeRuleNames(rules, settings) {
|
|
3339
|
+
if (Object.keys(settings ?? {}).length > 0) {
|
|
3340
|
+
return undefined;
|
|
3341
|
+
}
|
|
3342
|
+
|
|
3343
|
+
const selected = [];
|
|
3344
|
+
for (const [rule, config] of Object.entries(rules ?? {})) {
|
|
3345
|
+
if (ruleConfigSeverity(config) === 0) {
|
|
3346
|
+
continue;
|
|
3347
|
+
}
|
|
3348
|
+
if (!isPureRuleSeverity(config)) {
|
|
3349
|
+
return undefined;
|
|
3350
|
+
}
|
|
3351
|
+
selected.push(rule);
|
|
3352
|
+
}
|
|
3353
|
+
return selected.length > 0 ? selected : undefined;
|
|
3354
|
+
}
|
|
3355
|
+
|
|
3356
|
+
function isPureRuleSeverity(config) {
|
|
3357
|
+
if (Array.isArray(config)) {
|
|
3358
|
+
if (config.length !== 1) {
|
|
3359
|
+
return false;
|
|
3360
|
+
}
|
|
3361
|
+
[config] = config;
|
|
3362
|
+
}
|
|
3363
|
+
if (typeof config === "boolean") {
|
|
3364
|
+
return true;
|
|
3365
|
+
}
|
|
3366
|
+
if (typeof config === "number") {
|
|
3367
|
+
return config === 0 || config === 1 || config === 2;
|
|
3368
|
+
}
|
|
3369
|
+
return typeof config === "string" && ["off", "warn", "warning", "error", "0", "1", "2"].includes(config.toLowerCase());
|
|
3370
|
+
}
|
|
3371
|
+
|
|
3235
3372
|
function allDisabledNativeRules(rules) {
|
|
3236
3373
|
return {
|
|
3237
3374
|
...Object.fromEntries(NATIVE_RULE_IDS.map((rule) => [rule, "off"])),
|
|
@@ -3348,7 +3485,7 @@ function buildNativeLintArgs(paths, options) {
|
|
|
3348
3485
|
if (options.noConfig) {
|
|
3349
3486
|
cliArgs.push("--no-config");
|
|
3350
3487
|
}
|
|
3351
|
-
if (!options.rules && !options.forceMaterializedConfig && (options.config || options.baseConfig || options.overrideConfig)) {
|
|
3488
|
+
if (!options.nativeFlatConfigData && !options.rules && !options.forceMaterializedConfig && (options.config || options.baseConfig || options.overrideConfig)) {
|
|
3352
3489
|
const configForRuleSelection = options.noConfig
|
|
3353
3490
|
? undefined
|
|
3354
3491
|
: options.config ? readConfig(options.config, options.cwd, options.configCache) : undefined;
|
|
@@ -3364,6 +3501,12 @@ function buildNativeLintArgs(paths, options) {
|
|
|
3364
3501
|
if (options.config) {
|
|
3365
3502
|
cliArgs.push(`--config=${options.config}`);
|
|
3366
3503
|
}
|
|
3504
|
+
if (options.nativeConfigRoot) {
|
|
3505
|
+
cliArgs.push(`--config-root=${options.nativeConfigRoot}`);
|
|
3506
|
+
}
|
|
3507
|
+
if (options.nativeConfigCwd) {
|
|
3508
|
+
cliArgs.push(`--config-cwd=${options.nativeConfigCwd}`);
|
|
3509
|
+
}
|
|
3367
3510
|
if (options.rules) {
|
|
3368
3511
|
const rules = Array.isArray(options.rules) ? options.rules.join(",") : options.rules;
|
|
3369
3512
|
if (rules) {
|
|
@@ -3398,9 +3541,17 @@ function mergeLintOptions(base, override) {
|
|
|
3398
3541
|
}
|
|
3399
3542
|
|
|
3400
3543
|
function withConfigCache(options) {
|
|
3401
|
-
|
|
3402
|
-
|
|
3403
|
-
|
|
3544
|
+
if (options.configCache && options[CONFIG_DISCOVERY_CACHE]) {
|
|
3545
|
+
return options;
|
|
3546
|
+
}
|
|
3547
|
+
|
|
3548
|
+
return {
|
|
3549
|
+
...options,
|
|
3550
|
+
// Executable configs are otherwise re-evaluated at every per-file lookup.
|
|
3551
|
+
configCache: options.configCache ?? new Map(),
|
|
3552
|
+
// Discovery results must not survive into a later public invocation.
|
|
3553
|
+
[CONFIG_DISCOVERY_CACHE]: new Map()
|
|
3554
|
+
};
|
|
3404
3555
|
}
|
|
3405
3556
|
|
|
3406
3557
|
function eslintConstructorOptions(options) {
|
|
@@ -3741,7 +3892,7 @@ function configPathForOptions(options) {
|
|
|
3741
3892
|
}
|
|
3742
3893
|
|
|
3743
3894
|
const cwd = options.cwd ?? process.cwd();
|
|
3744
|
-
return configPathFromDirectory(cwd);
|
|
3895
|
+
return configPathFromDirectory(cwd, options);
|
|
3745
3896
|
}
|
|
3746
3897
|
|
|
3747
3898
|
function configPathForFile(options, filePath) {
|
|
@@ -3751,7 +3902,7 @@ function configPathForFile(options, filePath) {
|
|
|
3751
3902
|
if (options.config) {
|
|
3752
3903
|
return resolvePath(options.cwd ?? process.cwd(), options.config);
|
|
3753
3904
|
}
|
|
3754
|
-
return configPathFromDirectory(configSearchDirectoryForFile(filePath, options.cwd));
|
|
3905
|
+
return configPathFromDirectory(configSearchDirectoryForFile(filePath, options.cwd), options);
|
|
3755
3906
|
}
|
|
3756
3907
|
|
|
3757
3908
|
function configSearchDirectoryForFile(filePath, cwd) {
|
|
@@ -3766,11 +3917,29 @@ function configSearchDirectoryForFile(filePath, cwd) {
|
|
|
3766
3917
|
return dirname(absolute);
|
|
3767
3918
|
}
|
|
3768
3919
|
|
|
3769
|
-
function configPathFromDirectory(directory) {
|
|
3770
|
-
return findConfigPathFromDirectory(directory);
|
|
3920
|
+
function configPathFromDirectory(directory, options) {
|
|
3921
|
+
return findConfigPathFromDirectory(directory, options[CONFIG_DISCOVERY_CACHE]);
|
|
3771
3922
|
}
|
|
3772
3923
|
|
|
3773
3924
|
function withTemporaryConfig(options, callback) {
|
|
3925
|
+
if (options.nativeFlatConfigData !== undefined) {
|
|
3926
|
+
const tmp = mkdtempSync(join(tmpdir(), "utoo-lint-flat-config-"));
|
|
3927
|
+
const configPath = join(tmp, "utlint.config.json");
|
|
3928
|
+
try {
|
|
3929
|
+
writeFileSync(configPath, JSON.stringify(options.nativeFlatConfigData));
|
|
3930
|
+
return callback({
|
|
3931
|
+
...options,
|
|
3932
|
+
config: configPath,
|
|
3933
|
+
noConfig: false,
|
|
3934
|
+
baseConfig: undefined,
|
|
3935
|
+
overrideConfig: undefined,
|
|
3936
|
+
forceMaterializedConfig: true
|
|
3937
|
+
});
|
|
3938
|
+
} finally {
|
|
3939
|
+
rmSync(tmp, { recursive: true, force: true });
|
|
3940
|
+
}
|
|
3941
|
+
}
|
|
3942
|
+
|
|
3774
3943
|
const fileConfigPath = !options.noConfig ? configPathForOptions(options) : undefined;
|
|
3775
3944
|
const shouldMaterializeFileConfig = Boolean(fileConfigPath);
|
|
3776
3945
|
const fileConfig = shouldMaterializeFileConfig
|
|
@@ -3957,12 +4126,38 @@ function reportToESLintResults(report, textOptions = {}) {
|
|
|
3957
4126
|
}
|
|
3958
4127
|
|
|
3959
4128
|
for (const result of byFile.values()) {
|
|
4129
|
+
applyCompatibilityDisableDirectives(result, textOptions);
|
|
3960
4130
|
finalizeESLintResult(result);
|
|
3961
4131
|
}
|
|
3962
4132
|
|
|
3963
4133
|
return [...byFile.values()];
|
|
3964
4134
|
}
|
|
3965
4135
|
|
|
4136
|
+
function applyCompatibilityDisableDirectives(result, textOptions) {
|
|
4137
|
+
if (result.messages.length === 0) {
|
|
4138
|
+
return;
|
|
4139
|
+
}
|
|
4140
|
+
|
|
4141
|
+
let source = result.source;
|
|
4142
|
+
if (typeof source !== "string" && textOptions.filePath === result.filePath) {
|
|
4143
|
+
source = textOptions.source;
|
|
4144
|
+
}
|
|
4145
|
+
if (typeof source !== "string") {
|
|
4146
|
+
try {
|
|
4147
|
+
source = readFileSync(result.filePath, "utf8");
|
|
4148
|
+
} catch {
|
|
4149
|
+
return;
|
|
4150
|
+
}
|
|
4151
|
+
}
|
|
4152
|
+
if (!source.includes("eslint-")) {
|
|
4153
|
+
return;
|
|
4154
|
+
}
|
|
4155
|
+
|
|
4156
|
+
const filtered = applyDisableDirectives(result.messages, createLinterSourceCode(source));
|
|
4157
|
+
result.messages = filtered.messages;
|
|
4158
|
+
result.suppressedMessages.push(...filtered.suppressedMessages);
|
|
4159
|
+
}
|
|
4160
|
+
|
|
3966
4161
|
function normalizeReportDiagnostics(diagnostics, options = {}) {
|
|
3967
4162
|
return (diagnostics ?? []).flatMap((diagnostic) => {
|
|
3968
4163
|
if (!diagnostic?.ruleId) {
|
|
@@ -4712,10 +4907,12 @@ function diagnosticToESLintMessage(diagnostic, ruleSeverities) {
|
|
|
4712
4907
|
function suppressedDiagnosticToESLintMessage(diagnostic, ruleSeverities) {
|
|
4713
4908
|
return {
|
|
4714
4909
|
...diagnosticToESLintMessage(diagnostic, ruleSeverities),
|
|
4715
|
-
suppressions:
|
|
4716
|
-
|
|
4717
|
-
|
|
4718
|
-
|
|
4910
|
+
suppressions: diagnostic.suppressions?.length > 0
|
|
4911
|
+
? diagnostic.suppressions
|
|
4912
|
+
: [{
|
|
4913
|
+
kind: diagnostic.suppression?.kind ?? "directive",
|
|
4914
|
+
justification: diagnostic.suppression?.justification ?? ""
|
|
4915
|
+
}]
|
|
4719
4916
|
};
|
|
4720
4917
|
}
|
|
4721
4918
|
|
package/lib/config-loader.cjs
CHANGED
|
@@ -13,23 +13,36 @@ const TYPESCRIPT_CONFIG_EXTENSIONS = new Set([".ts", ".mts", ".cts"]);
|
|
|
13
13
|
const JAVASCRIPT_CONFIG_EXTENSIONS = new Set([".js", ".mjs", ".cjs"]);
|
|
14
14
|
const loaderPath = join(__dirname, "load-config.js");
|
|
15
15
|
|
|
16
|
-
function findConfigPath(directory) {
|
|
16
|
+
function findConfigPath(directory, cache) {
|
|
17
17
|
let current = resolvePath(directory);
|
|
18
|
+
const visited = [];
|
|
18
19
|
while (true) {
|
|
20
|
+
if (cache?.has(current)) {
|
|
21
|
+
return cacheConfigPath(cache, visited, cache.get(current));
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
visited.push(current);
|
|
19
25
|
for (const filename of CONFIG_FILENAMES) {
|
|
20
26
|
const candidate = resolvePath(current, filename);
|
|
21
27
|
if (isFile(candidate)) {
|
|
22
|
-
return candidate;
|
|
28
|
+
return cacheConfigPath(cache, visited, candidate);
|
|
23
29
|
}
|
|
24
30
|
}
|
|
25
31
|
const parent = dirname(current);
|
|
26
32
|
if (parent === current) {
|
|
27
|
-
return undefined;
|
|
33
|
+
return cacheConfigPath(cache, visited, undefined);
|
|
28
34
|
}
|
|
29
35
|
current = parent;
|
|
30
36
|
}
|
|
31
37
|
}
|
|
32
38
|
|
|
39
|
+
function cacheConfigPath(cache, directories, configPath) {
|
|
40
|
+
for (const directory of directories) {
|
|
41
|
+
cache?.set(directory, configPath);
|
|
42
|
+
}
|
|
43
|
+
return configPath;
|
|
44
|
+
}
|
|
45
|
+
|
|
33
46
|
function isFile(path) {
|
|
34
47
|
try {
|
|
35
48
|
return statSync(path).isFile();
|
package/lib/config-loader.js
CHANGED
|
@@ -14,23 +14,36 @@ const TYPESCRIPT_CONFIG_EXTENSIONS = new Set([".ts", ".mts", ".cts"]);
|
|
|
14
14
|
const JAVASCRIPT_CONFIG_EXTENSIONS = new Set([".js", ".mjs", ".cjs"]);
|
|
15
15
|
const loaderPath = fileURLToPath(new URL("./load-config.js", import.meta.url));
|
|
16
16
|
|
|
17
|
-
export function findConfigPath(directory) {
|
|
17
|
+
export function findConfigPath(directory, cache) {
|
|
18
18
|
let current = resolvePath(directory);
|
|
19
|
+
const visited = [];
|
|
19
20
|
while (true) {
|
|
21
|
+
if (cache?.has(current)) {
|
|
22
|
+
return cacheConfigPath(cache, visited, cache.get(current));
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
visited.push(current);
|
|
20
26
|
for (const filename of CONFIG_FILENAMES) {
|
|
21
27
|
const candidate = resolvePath(current, filename);
|
|
22
28
|
if (isFile(candidate)) {
|
|
23
|
-
return candidate;
|
|
29
|
+
return cacheConfigPath(cache, visited, candidate);
|
|
24
30
|
}
|
|
25
31
|
}
|
|
26
32
|
const parent = dirname(current);
|
|
27
33
|
if (parent === current) {
|
|
28
|
-
return undefined;
|
|
34
|
+
return cacheConfigPath(cache, visited, undefined);
|
|
29
35
|
}
|
|
30
36
|
current = parent;
|
|
31
37
|
}
|
|
32
38
|
}
|
|
33
39
|
|
|
40
|
+
function cacheConfigPath(cache, directories, configPath) {
|
|
41
|
+
for (const directory of directories) {
|
|
42
|
+
cache?.set(directory, configPath);
|
|
43
|
+
}
|
|
44
|
+
return configPath;
|
|
45
|
+
}
|
|
46
|
+
|
|
34
47
|
function isFile(path) {
|
|
35
48
|
try {
|
|
36
49
|
return statSync(path).isFile();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@utoo/lint",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.5",
|
|
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.5",
|
|
80
|
+
"@utoo/lint-darwin-x64": "0.3.5",
|
|
81
|
+
"@utoo/lint-linux-arm64": "0.3.5",
|
|
82
|
+
"@utoo/lint-linux-x64": "0.3.5",
|
|
83
|
+
"@utoo/lint-win32-x64": "0.3.5"
|
|
84
84
|
},
|
|
85
85
|
"dependencies": {
|
|
86
86
|
"@eslint/eslintrc": "2.1.4",
|