@utoo/lint 0.2.9 → 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/README.md +41 -11
- package/bin/fishlint.js +23 -3
- package/bin/migrate.js +476 -10
- package/bin/utoo-lint.js +15 -15
- package/configs/frontend.d.ts +54 -2
- package/configs/frontend.json +15 -0
- package/index.cjs +471 -75
- package/index.d.ts +15 -2
- package/index.js +471 -75
- package/lib/config-loader.cjs +16 -3
- package/lib/config-loader.js +16 -3
- package/package.json +8 -6
- package/schema.json +41 -1
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",
|
|
@@ -77,6 +78,7 @@ const BUILTIN_RULE_IDS = [
|
|
|
77
78
|
"block-scoped-var",
|
|
78
79
|
"camelcase",
|
|
79
80
|
"capitalized-comments",
|
|
81
|
+
"class-methods-use-this",
|
|
80
82
|
"complexity",
|
|
81
83
|
"consistent-return",
|
|
82
84
|
"consistent-this",
|
|
@@ -168,6 +170,7 @@ const BUILTIN_RULE_IDS = [
|
|
|
168
170
|
"no-inline-comments",
|
|
169
171
|
"no-inner-declarations",
|
|
170
172
|
"no-invalid-regexp",
|
|
173
|
+
"no-invalid-this",
|
|
171
174
|
"no-irregular-whitespace",
|
|
172
175
|
"no-iterator",
|
|
173
176
|
"no-label-var",
|
|
@@ -176,6 +179,7 @@ const BUILTIN_RULE_IDS = [
|
|
|
176
179
|
"no-lonely-if",
|
|
177
180
|
"no-loop-func",
|
|
178
181
|
"no-loss-of-precision",
|
|
182
|
+
"no-magic-numbers",
|
|
179
183
|
"no-mixed-spaces-and-tabs",
|
|
180
184
|
"no-misleading-character-class",
|
|
181
185
|
"no-multi-assign",
|
|
@@ -234,6 +238,8 @@ const BUILTIN_RULE_IDS = [
|
|
|
234
238
|
"no-underscore-dangle",
|
|
235
239
|
"no-undefined",
|
|
236
240
|
"no-unneeded-ternary",
|
|
241
|
+
"no-unexpected-multiline",
|
|
242
|
+
"no-unmodified-loop-condition",
|
|
237
243
|
"no-unreachable",
|
|
238
244
|
"no-unreachable-loop",
|
|
239
245
|
"no-unsafe-finally",
|
|
@@ -244,6 +250,7 @@ const BUILTIN_RULE_IDS = [
|
|
|
244
250
|
"no-unused-private-class-members",
|
|
245
251
|
"no-unused-vars",
|
|
246
252
|
"no-use-before-define",
|
|
253
|
+
"no-useless-assignment",
|
|
247
254
|
"no-useless-backreference",
|
|
248
255
|
"no-useless-call",
|
|
249
256
|
"no-useless-catch",
|
|
@@ -305,6 +312,19 @@ const BUILTIN_RULE_IDS = [
|
|
|
305
312
|
"import/no-named-as-default-member",
|
|
306
313
|
"import/no-unresolved",
|
|
307
314
|
"import/no-self-import",
|
|
315
|
+
"jest/no-conditional-expect",
|
|
316
|
+
"jest/no-deprecated-functions",
|
|
317
|
+
"jest/no-export",
|
|
318
|
+
"jest/no-focused-tests",
|
|
319
|
+
"jest/no-identical-title",
|
|
320
|
+
"jest/no-interpolation-in-snapshots",
|
|
321
|
+
"jest/no-jasmine-globals",
|
|
322
|
+
"jest/no-mocks-import",
|
|
323
|
+
"jest/no-standalone-expect",
|
|
324
|
+
"jest/valid-describe-callback",
|
|
325
|
+
"jest/valid-expect-in-promise",
|
|
326
|
+
"jest/valid-expect",
|
|
327
|
+
"jest/valid-title",
|
|
308
328
|
"promise/no-promise-in-callback",
|
|
309
329
|
"promise/no-return-in-finally",
|
|
310
330
|
"promise/no-return-wrap",
|
|
@@ -349,9 +369,12 @@ const BUILTIN_RULE_IDS = [
|
|
|
349
369
|
"react/no-danger",
|
|
350
370
|
"react/no-danger-with-children",
|
|
351
371
|
"react/no-deprecated",
|
|
372
|
+
"react/no-direct-mutation-state",
|
|
352
373
|
"react/no-find-dom-node",
|
|
374
|
+
"react/no-forward-ref",
|
|
353
375
|
"react/no-is-mounted",
|
|
354
376
|
"react/no-multi-comp",
|
|
377
|
+
"react/no-unstable-nested-components",
|
|
355
378
|
"react/no-redundant-should-component-update",
|
|
356
379
|
"react/no-render-return-value",
|
|
357
380
|
"react/no-string-refs",
|
|
@@ -449,10 +472,15 @@ const NATIVE_ONLY_RULE_IDS = [
|
|
|
449
472
|
];
|
|
450
473
|
const NATIVE_RULE_IDS = [...BUILTIN_RULE_IDS, ...NATIVE_ONLY_RULE_IDS];
|
|
451
474
|
const FIXABLE_BUILTIN_RULE_IDS = new Set([
|
|
475
|
+
"jest/no-deprecated-functions",
|
|
476
|
+
"jest/no-jasmine-globals",
|
|
452
477
|
"no-extra-semi",
|
|
453
478
|
"@typescript-eslint/no-extra-semi",
|
|
454
479
|
"unused-imports/no-unused-imports"
|
|
455
480
|
]);
|
|
481
|
+
const SUGGESTION_BUILTIN_RULE_IDS = new Set([
|
|
482
|
+
"jest/no-focused-tests"
|
|
483
|
+
]);
|
|
456
484
|
const BUILTIN_RULES = new Map(BUILTIN_RULE_IDS.map((ruleId) => [ruleId, createBuiltinRule(ruleId)]));
|
|
457
485
|
|
|
458
486
|
class UtooLint {
|
|
@@ -542,7 +570,7 @@ class UtooLint {
|
|
|
542
570
|
}
|
|
543
571
|
|
|
544
572
|
async isPathIgnored(filePath) {
|
|
545
|
-
return isPathIgnored(filePath, mergeLintOptions(this.options, {}));
|
|
573
|
+
return isPathIgnored(filePath, withConfigCache(mergeLintOptions(this.options, {})));
|
|
546
574
|
}
|
|
547
575
|
|
|
548
576
|
async calculateConfigForFile(filePath) {
|
|
@@ -550,7 +578,7 @@ class UtooLint {
|
|
|
550
578
|
}
|
|
551
579
|
|
|
552
580
|
async findConfigFile(filePath) {
|
|
553
|
-
const options = eslintConstructorOptions(this.options);
|
|
581
|
+
const options = withConfigCache(eslintConstructorOptions(this.options));
|
|
554
582
|
if (options.noConfig) {
|
|
555
583
|
return undefined;
|
|
556
584
|
}
|
|
@@ -684,7 +712,7 @@ class CLIEngine {
|
|
|
684
712
|
}
|
|
685
713
|
|
|
686
714
|
isPathIgnored(filePath) {
|
|
687
|
-
return isPathIgnored(filePath, eslintConstructorOptions(this.options));
|
|
715
|
+
return isPathIgnored(filePath, withConfigCache(eslintConstructorOptions(this.options)));
|
|
688
716
|
}
|
|
689
717
|
|
|
690
718
|
getConfigForFile(filePath) {
|
|
@@ -692,6 +720,20 @@ class CLIEngine {
|
|
|
692
720
|
}
|
|
693
721
|
}
|
|
694
722
|
|
|
723
|
+
const DEFAULT_NATIVE_MAX_BUFFER = 64 * 1024 * 1024;
|
|
724
|
+
|
|
725
|
+
function nativeMaxBuffer(options, env) {
|
|
726
|
+
const configured = options.maxBuffer ?? env.UTOO_LINT_MAX_BUFFER;
|
|
727
|
+
if (configured === undefined || configured === "") {
|
|
728
|
+
return DEFAULT_NATIVE_MAX_BUFFER;
|
|
729
|
+
}
|
|
730
|
+
const value = typeof configured === "number" ? configured : Number(configured);
|
|
731
|
+
if (!Number.isSafeInteger(value) || value <= 0) {
|
|
732
|
+
throw new TypeError("maxBuffer and UTOO_LINT_MAX_BUFFER must be a positive integer byte count");
|
|
733
|
+
}
|
|
734
|
+
return value;
|
|
735
|
+
}
|
|
736
|
+
|
|
695
737
|
function run(args = [], options = {}) {
|
|
696
738
|
const cliArgs = normalizeStringArray(args, "args");
|
|
697
739
|
const env = options.env ? { ...process.env, ...options.env } : process.env;
|
|
@@ -702,7 +744,8 @@ function run(args = [], options = {}) {
|
|
|
702
744
|
env,
|
|
703
745
|
encoding: options.encoding ?? "utf8",
|
|
704
746
|
input: options.input,
|
|
705
|
-
stdio: options.stdio
|
|
747
|
+
stdio: options.stdio,
|
|
748
|
+
maxBuffer: nativeMaxBuffer(options, env)
|
|
706
749
|
});
|
|
707
750
|
}
|
|
708
751
|
|
|
@@ -844,8 +887,9 @@ function runCli(args = [], options = {}) {
|
|
|
844
887
|
extraArgs: parsed.passthroughArgs,
|
|
845
888
|
preserveNativeDefaults: Boolean(parsed.options.noConfig)
|
|
846
889
|
});
|
|
847
|
-
const
|
|
848
|
-
const
|
|
890
|
+
const usesDefaultTargets = parsed.targets.length === 0;
|
|
891
|
+
const targets = usesDefaultTargets ? defaultLintTargets(cliOptions) : parsed.targets;
|
|
892
|
+
const report = lintFiles(targets, { ...cliOptions, useDefaultConfigTargets: usesDefaultTargets });
|
|
849
893
|
report.diagnostics = normalizeReportDiagnostics(report.diagnostics, cliOptions);
|
|
850
894
|
report.exitCode = exitCodeForDiagnostics(report.diagnostics);
|
|
851
895
|
const status = report.exitCode ?? exitCodeForDiagnostics(report.diagnostics);
|
|
@@ -953,7 +997,8 @@ function runFishlint(args = [], options = {}) {
|
|
|
953
997
|
env,
|
|
954
998
|
encoding: options.encoding ?? "utf8",
|
|
955
999
|
input: options.input,
|
|
956
|
-
stdio: options.stdio
|
|
1000
|
+
stdio: options.stdio,
|
|
1001
|
+
maxBuffer: nativeMaxBuffer(options, env)
|
|
957
1002
|
});
|
|
958
1003
|
}
|
|
959
1004
|
|
|
@@ -1155,13 +1200,23 @@ function booleanFlagValue(arg) {
|
|
|
1155
1200
|
|
|
1156
1201
|
function lintFiles(paths, options = {}) {
|
|
1157
1202
|
options = withConfigCache(options);
|
|
1203
|
+
const usesDefaultTargets = paths == null || options.useDefaultConfigTargets;
|
|
1158
1204
|
const targets = lintTargetsForInput(paths, options);
|
|
1159
1205
|
const ignoredDiagnostics = ignoredLintPathDiagnostics(targets, options);
|
|
1160
|
-
|
|
1206
|
+
let lintPaths = filteredLintPaths(targets, options);
|
|
1207
|
+
if (usesDefaultTargets) {
|
|
1208
|
+
lintPaths = filterDefaultConfigLintPaths(lintPaths, options);
|
|
1209
|
+
}
|
|
1161
1210
|
if (lintPaths.length === 0) {
|
|
1162
1211
|
return { files: 0, filePaths: [], diagnostics: ignoredDiagnostics, suppressedDiagnostics: [], exitCode: exitCodeForDiagnostics(ignoredDiagnostics) };
|
|
1163
1212
|
}
|
|
1164
1213
|
|
|
1214
|
+
const nativeFlatOptions = nativeFlatConfigOptions(options);
|
|
1215
|
+
if (nativeFlatOptions) {
|
|
1216
|
+
const report = runNativeLintReport(lintPaths, nativeFlatOptions);
|
|
1217
|
+
return finalizeLintReport(report, ignoredDiagnostics, options);
|
|
1218
|
+
}
|
|
1219
|
+
|
|
1165
1220
|
const configRuns = nativeConfigRunsForFiles(expandNativeConfigRunPaths(lintPaths, options), options);
|
|
1166
1221
|
if (configRuns) {
|
|
1167
1222
|
const report = mergeNativeReports(
|
|
@@ -1174,6 +1229,76 @@ function lintFiles(paths, options = {}) {
|
|
|
1174
1229
|
return finalizeLintReport(report, ignoredDiagnostics, options);
|
|
1175
1230
|
}
|
|
1176
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
|
+
|
|
1177
1302
|
function expandNativeConfigRunPaths(paths, options) {
|
|
1178
1303
|
const cwd = options.cwd ?? process.cwd();
|
|
1179
1304
|
const patterns = ignoreDisabled(options) ? [] : ignorePatternsForOptions(options, cwd);
|
|
@@ -1247,13 +1372,15 @@ function nativeConfigRunsForFiles(paths, options) {
|
|
|
1247
1372
|
const fileConfigPath = options.noConfig ? undefined : configPathForFile(options, matchPath);
|
|
1248
1373
|
const configured = Boolean(options.baseConfig || options.overrideConfig || fileConfigPath);
|
|
1249
1374
|
hasConfigSource ||= configured;
|
|
1250
|
-
|
|
1375
|
+
const calculated = configured ? calculatedConfig({ ...options, rules: undefined }, matchPath) : {};
|
|
1376
|
+
let rules = calculated.rules;
|
|
1377
|
+
const settings = calculated.settings;
|
|
1251
1378
|
if (configured && options.rules) {
|
|
1252
1379
|
rules = selectedRulesWithConfigOptions(rules, options.rules);
|
|
1253
1380
|
}
|
|
1254
|
-
const signature = configured ? stableConfigSignature(rules) : "<native-defaults>";
|
|
1381
|
+
const signature = configured ? stableConfigSignature({ rules, settings }) : "<native-defaults>";
|
|
1255
1382
|
if (!groups.has(signature)) {
|
|
1256
|
-
groups.set(signature, { paths: [], rules, configured });
|
|
1383
|
+
groups.set(signature, { paths: [], rules, settings, configured });
|
|
1257
1384
|
}
|
|
1258
1385
|
groups.get(signature).paths.push(filePath);
|
|
1259
1386
|
}
|
|
@@ -1276,6 +1403,22 @@ function nativeConfigRunsForFiles(paths, options) {
|
|
|
1276
1403
|
};
|
|
1277
1404
|
}
|
|
1278
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
|
+
|
|
1279
1422
|
return {
|
|
1280
1423
|
paths: group.paths,
|
|
1281
1424
|
options: {
|
|
@@ -1283,13 +1426,50 @@ function nativeConfigRunsForFiles(paths, options) {
|
|
|
1283
1426
|
config: undefined,
|
|
1284
1427
|
noConfig: true,
|
|
1285
1428
|
baseConfig: undefined,
|
|
1286
|
-
overrideConfig: {
|
|
1429
|
+
overrideConfig: {
|
|
1430
|
+
rules: allDisabledNativeRules(group.rules),
|
|
1431
|
+
...(group.settings ? { settings: group.settings } : {})
|
|
1432
|
+
},
|
|
1287
1433
|
forceMaterializedConfig: true
|
|
1288
1434
|
}
|
|
1289
1435
|
};
|
|
1290
1436
|
});
|
|
1291
1437
|
}
|
|
1292
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
|
+
|
|
1293
1473
|
function allDisabledNativeRules(rules) {
|
|
1294
1474
|
return {
|
|
1295
1475
|
...Object.fromEntries(NATIVE_RULE_IDS.map((rule) => [rule, "off"])),
|
|
@@ -1406,7 +1586,7 @@ function buildNativeLintArgs(paths, options) {
|
|
|
1406
1586
|
if (options.noConfig) {
|
|
1407
1587
|
cliArgs.push("--no-config");
|
|
1408
1588
|
}
|
|
1409
|
-
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)) {
|
|
1410
1590
|
const configForRuleSelection = options.noConfig
|
|
1411
1591
|
? undefined
|
|
1412
1592
|
: options.config ? readConfig(options.config, options.cwd, options.configCache) : undefined;
|
|
@@ -1422,6 +1602,12 @@ function buildNativeLintArgs(paths, options) {
|
|
|
1422
1602
|
if (options.config) {
|
|
1423
1603
|
cliArgs.push(`--config=${options.config}`);
|
|
1424
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
|
+
}
|
|
1425
1611
|
if (options.rules) {
|
|
1426
1612
|
const rules = Array.isArray(options.rules) ? options.rules.join(",") : options.rules;
|
|
1427
1613
|
if (rules) {
|
|
@@ -1456,9 +1642,17 @@ function mergeLintOptions(base, override) {
|
|
|
1456
1642
|
}
|
|
1457
1643
|
|
|
1458
1644
|
function withConfigCache(options) {
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
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
|
+
};
|
|
1462
1656
|
}
|
|
1463
1657
|
|
|
1464
1658
|
function eslintConstructorOptions(options) {
|
|
@@ -1512,12 +1706,12 @@ function calculatedConfig(options = {}, filePath) {
|
|
|
1512
1706
|
);
|
|
1513
1707
|
return {
|
|
1514
1708
|
...configData,
|
|
1515
|
-
rules:
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1709
|
+
rules: mergeRuleConfigMaps(
|
|
1710
|
+
rulesFromConfig(options.baseConfig, filePath, options.cwd),
|
|
1711
|
+
rulesFromFileConfig(options, filePath),
|
|
1712
|
+
rulesFromConfig(options.overrideConfig, filePath, options.cwd),
|
|
1713
|
+
rulesFromNativeRuleList(options.rules)
|
|
1714
|
+
)
|
|
1521
1715
|
};
|
|
1522
1716
|
}
|
|
1523
1717
|
|
|
@@ -1612,10 +1806,10 @@ function rulesFromConfig(config, filePath, cwd) {
|
|
|
1612
1806
|
return {};
|
|
1613
1807
|
}
|
|
1614
1808
|
if (Array.isArray(config)) {
|
|
1615
|
-
return config.reduce(
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1809
|
+
return config.reduce(
|
|
1810
|
+
(rules, entry) => mergeRuleConfigMaps(rules, rulesFromConfig(entry, filePath, cwd)),
|
|
1811
|
+
{}
|
|
1812
|
+
);
|
|
1619
1813
|
}
|
|
1620
1814
|
if (!configAppliesToFile(config, filePath, cwd)) {
|
|
1621
1815
|
return {};
|
|
@@ -1668,12 +1862,64 @@ function defaultLintTargets(options = {}) {
|
|
|
1668
1862
|
return ["."];
|
|
1669
1863
|
}
|
|
1670
1864
|
|
|
1671
|
-
const
|
|
1865
|
+
const config = readConfig(configPath, options.cwd, options.configCache);
|
|
1866
|
+
if (configHasUnscopedRules(config)) {
|
|
1867
|
+
return ["."];
|
|
1868
|
+
}
|
|
1869
|
+
|
|
1870
|
+
const targets = filePatternsFromConfig(config);
|
|
1672
1871
|
return targets.length > 0
|
|
1673
1872
|
? targets.map((target) => resolveConfigPattern(target, dirname(configPath)))
|
|
1674
1873
|
: ["."];
|
|
1675
1874
|
}
|
|
1676
1875
|
|
|
1876
|
+
function filterDefaultConfigLintPaths(paths, options) {
|
|
1877
|
+
const configPath = configPathForOptions(options);
|
|
1878
|
+
if (!configPath) {
|
|
1879
|
+
return paths;
|
|
1880
|
+
}
|
|
1881
|
+
const config = readConfig(configPath, options.cwd, options.configCache);
|
|
1882
|
+
if (!configHasFileSelectors(config)) {
|
|
1883
|
+
return paths;
|
|
1884
|
+
}
|
|
1885
|
+
const cwd = dirname(configPath);
|
|
1886
|
+
return paths.filter((filePath) => configSelectsFile(config, filePath, cwd));
|
|
1887
|
+
}
|
|
1888
|
+
|
|
1889
|
+
function configHasFileSelectors(config) {
|
|
1890
|
+
if (Array.isArray(config)) {
|
|
1891
|
+
return config.some(configHasFileSelectors);
|
|
1892
|
+
}
|
|
1893
|
+
return Boolean(config && typeof config === "object" && normalizeConfigFileSelectors(config.files).length > 0);
|
|
1894
|
+
}
|
|
1895
|
+
|
|
1896
|
+
function configHasUnscopedRules(config) {
|
|
1897
|
+
if (Array.isArray(config)) {
|
|
1898
|
+
return config.some(configHasUnscopedRules);
|
|
1899
|
+
}
|
|
1900
|
+
return Boolean(
|
|
1901
|
+
config &&
|
|
1902
|
+
typeof config === "object" &&
|
|
1903
|
+
normalizeConfigFileSelectors(config.files).length === 0 &&
|
|
1904
|
+
config.rules &&
|
|
1905
|
+
typeof config.rules === "object" &&
|
|
1906
|
+
Object.keys(config.rules).length > 0
|
|
1907
|
+
);
|
|
1908
|
+
}
|
|
1909
|
+
|
|
1910
|
+
function configSelectsFile(config, filePath, cwd) {
|
|
1911
|
+
if (Array.isArray(config)) {
|
|
1912
|
+
return config.some((entry) => configSelectsFile(entry, filePath, cwd));
|
|
1913
|
+
}
|
|
1914
|
+
if (!config || typeof config !== "object") {
|
|
1915
|
+
return false;
|
|
1916
|
+
}
|
|
1917
|
+
const selectors = normalizeConfigFileSelectors(config.files);
|
|
1918
|
+
return selectors.length > 0
|
|
1919
|
+
? configAppliesToFile(config, filePath, cwd)
|
|
1920
|
+
: configHasUnscopedRules(config) && configAppliesToFile(config, filePath, cwd);
|
|
1921
|
+
}
|
|
1922
|
+
|
|
1677
1923
|
function resolveConfigPattern(pattern, configDirectory) {
|
|
1678
1924
|
if (isAbsolute(pattern)) {
|
|
1679
1925
|
return pattern;
|
|
@@ -1697,8 +1943,10 @@ function configAppliesToFile(config, filePath, cwd) {
|
|
|
1697
1943
|
}
|
|
1698
1944
|
|
|
1699
1945
|
const normalized = normalizeIgnoredPath(filePath, cwd ?? process.cwd());
|
|
1700
|
-
const files =
|
|
1701
|
-
if (files.length > 0 && !files.some((
|
|
1946
|
+
const files = normalizeConfigFileSelectors(config.files);
|
|
1947
|
+
if (files.length > 0 && !files.some((selector) => selector.every(
|
|
1948
|
+
(pattern) => matchesConfigFilePattern(normalized, normalizeIgnoredPattern(pattern))
|
|
1949
|
+
))) {
|
|
1702
1950
|
return false;
|
|
1703
1951
|
}
|
|
1704
1952
|
|
|
@@ -1706,6 +1954,23 @@ function configAppliesToFile(config, filePath, cwd) {
|
|
|
1706
1954
|
return !pathIgnoredByPatterns(normalized, ignores);
|
|
1707
1955
|
}
|
|
1708
1956
|
|
|
1957
|
+
function normalizeConfigFileSelectors(patterns) {
|
|
1958
|
+
if (!patterns) {
|
|
1959
|
+
return [];
|
|
1960
|
+
}
|
|
1961
|
+
const values = Array.isArray(patterns) ? patterns : [patterns];
|
|
1962
|
+
return values.flatMap((value) => {
|
|
1963
|
+
if (typeof value === "string") {
|
|
1964
|
+
return [[value]];
|
|
1965
|
+
}
|
|
1966
|
+
if (Array.isArray(value)) {
|
|
1967
|
+
const selector = normalizeConfigPatterns(value);
|
|
1968
|
+
return selector.length > 0 ? [selector] : [];
|
|
1969
|
+
}
|
|
1970
|
+
return [];
|
|
1971
|
+
});
|
|
1972
|
+
}
|
|
1973
|
+
|
|
1709
1974
|
function normalizeConfigPatterns(patterns) {
|
|
1710
1975
|
if (!patterns) {
|
|
1711
1976
|
return [];
|
|
@@ -1728,7 +1993,7 @@ function configPathForOptions(options) {
|
|
|
1728
1993
|
}
|
|
1729
1994
|
|
|
1730
1995
|
const cwd = options.cwd ?? process.cwd();
|
|
1731
|
-
return configPathFromDirectory(cwd);
|
|
1996
|
+
return configPathFromDirectory(cwd, options);
|
|
1732
1997
|
}
|
|
1733
1998
|
|
|
1734
1999
|
function configPathForFile(options, filePath) {
|
|
@@ -1738,7 +2003,7 @@ function configPathForFile(options, filePath) {
|
|
|
1738
2003
|
if (options.config) {
|
|
1739
2004
|
return resolvePath(options.cwd ?? process.cwd(), options.config);
|
|
1740
2005
|
}
|
|
1741
|
-
return configPathFromDirectory(configSearchDirectoryForFile(filePath, options.cwd));
|
|
2006
|
+
return configPathFromDirectory(configSearchDirectoryForFile(filePath, options.cwd), options);
|
|
1742
2007
|
}
|
|
1743
2008
|
|
|
1744
2009
|
function configSearchDirectoryForFile(filePath, cwd) {
|
|
@@ -1753,11 +2018,29 @@ function configSearchDirectoryForFile(filePath, cwd) {
|
|
|
1753
2018
|
return dirname(absolute);
|
|
1754
2019
|
}
|
|
1755
2020
|
|
|
1756
|
-
function configPathFromDirectory(directory) {
|
|
1757
|
-
return findConfigPathFromDirectory(directory);
|
|
2021
|
+
function configPathFromDirectory(directory, options) {
|
|
2022
|
+
return findConfigPathFromDirectory(directory, options[CONFIG_DISCOVERY_CACHE]);
|
|
1758
2023
|
}
|
|
1759
2024
|
|
|
1760
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
|
+
|
|
1761
2044
|
const fileConfigPath = !options.noConfig ? configPathForOptions(options) : undefined;
|
|
1762
2045
|
const shouldMaterializeFileConfig = Boolean(fileConfigPath);
|
|
1763
2046
|
const fileConfig = shouldMaterializeFileConfig
|
|
@@ -1767,7 +2050,15 @@ function withTemporaryConfig(options, callback) {
|
|
|
1767
2050
|
const rules = shouldMaterializeFileConfig
|
|
1768
2051
|
? materializedRulesFromConfigs(...configs)
|
|
1769
2052
|
: runtimeRulesFromConfigs(...configs);
|
|
1770
|
-
|
|
2053
|
+
const settings = configs.reduce(
|
|
2054
|
+
(result, config) => ({
|
|
2055
|
+
...result,
|
|
2056
|
+
...(configDataFromConfig(config, options.filePath ?? options.filename, options.cwd).settings ?? {})
|
|
2057
|
+
}),
|
|
2058
|
+
{}
|
|
2059
|
+
);
|
|
2060
|
+
const hasSettings = Object.keys(settings).length > 0;
|
|
2061
|
+
if (Object.keys(rules).length === 0 && !hasSettings) {
|
|
1771
2062
|
if (shouldMaterializeFileConfig) {
|
|
1772
2063
|
return callback({
|
|
1773
2064
|
...options,
|
|
@@ -1779,7 +2070,7 @@ function withTemporaryConfig(options, callback) {
|
|
|
1779
2070
|
}
|
|
1780
2071
|
const enabledRules = enabledRuleNamesFromConfigs(...configs);
|
|
1781
2072
|
const hasExplicitOffRules = Object.values(rules).some((value) => ruleConfigSeverity(value) === 0);
|
|
1782
|
-
if (!shouldMaterializeFileConfig && !hasRuleOptions(rules) && !hasExplicitOffRules && !options.forceMaterializedConfig) {
|
|
2073
|
+
if (!shouldMaterializeFileConfig && !hasSettings && !hasRuleOptions(rules) && !hasExplicitOffRules && !options.forceMaterializedConfig) {
|
|
1783
2074
|
return callback({
|
|
1784
2075
|
...options,
|
|
1785
2076
|
config: shouldMaterializeFileConfig ? undefined : options.config,
|
|
@@ -1791,7 +2082,7 @@ function withTemporaryConfig(options, callback) {
|
|
|
1791
2082
|
const tmp = mkdtempSync(join(tmpdir(), "utoo-lint-config-"));
|
|
1792
2083
|
const configPath = join(tmp, "utlint.config.json");
|
|
1793
2084
|
try {
|
|
1794
|
-
writeFileSync(configPath, JSON.stringify({ rules }));
|
|
2085
|
+
writeFileSync(configPath, JSON.stringify({ rules, ...(hasSettings ? { settings } : {}) }));
|
|
1795
2086
|
return callback({
|
|
1796
2087
|
...options,
|
|
1797
2088
|
config: shouldMaterializeFileConfig ? configPath : options.config ?? configPath,
|
|
@@ -1810,11 +2101,7 @@ function enabledRuleNames(rules) {
|
|
|
1810
2101
|
}
|
|
1811
2102
|
|
|
1812
2103
|
function runtimeRulesFromConfigs(...configs) {
|
|
1813
|
-
|
|
1814
|
-
for (const config of configs) {
|
|
1815
|
-
Object.assign(rules, runtimeRulesFromConfig(config));
|
|
1816
|
-
}
|
|
1817
|
-
return rules;
|
|
2104
|
+
return mergeRuleConfigMaps(...configs.map(runtimeRulesFromConfig));
|
|
1818
2105
|
}
|
|
1819
2106
|
|
|
1820
2107
|
function materializedRulesFromConfigs(...configs) {
|
|
@@ -1826,10 +2113,10 @@ function runtimeRulesFromConfig(config) {
|
|
|
1826
2113
|
return {};
|
|
1827
2114
|
}
|
|
1828
2115
|
if (Array.isArray(config)) {
|
|
1829
|
-
return config.reduce(
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
2116
|
+
return config.reduce(
|
|
2117
|
+
(rules, entry) => mergeRuleConfigMaps(rules, runtimeRulesFromConfig(entry)),
|
|
2118
|
+
{}
|
|
2119
|
+
);
|
|
1833
2120
|
}
|
|
1834
2121
|
|
|
1835
2122
|
const rules = {};
|
|
@@ -1839,6 +2126,26 @@ function runtimeRulesFromConfig(config) {
|
|
|
1839
2126
|
return rules;
|
|
1840
2127
|
}
|
|
1841
2128
|
|
|
2129
|
+
function mergeRuleConfigMaps(...ruleMaps) {
|
|
2130
|
+
const result = {};
|
|
2131
|
+
for (const rules of ruleMaps) {
|
|
2132
|
+
for (const [ruleId, ruleConfig] of Object.entries(rules ?? {})) {
|
|
2133
|
+
const previous = result[ruleId];
|
|
2134
|
+
if (previous !== undefined && isSeverityOnlyRuleConfig(ruleConfig) && Array.isArray(previous) && previous.length > 1) {
|
|
2135
|
+
const severity = Array.isArray(ruleConfig) ? ruleConfig[0] : ruleConfig;
|
|
2136
|
+
result[ruleId] = [severity, ...previous.slice(1)];
|
|
2137
|
+
} else {
|
|
2138
|
+
result[ruleId] = ruleConfig;
|
|
2139
|
+
}
|
|
2140
|
+
}
|
|
2141
|
+
}
|
|
2142
|
+
return result;
|
|
2143
|
+
}
|
|
2144
|
+
|
|
2145
|
+
function isSeverityOnlyRuleConfig(ruleConfig) {
|
|
2146
|
+
return !Array.isArray(ruleConfig) || ruleConfig.length === 1;
|
|
2147
|
+
}
|
|
2148
|
+
|
|
1842
2149
|
function enabledRuleNamesFromConfigs(...configs) {
|
|
1843
2150
|
const rules = new Set();
|
|
1844
2151
|
for (const config of configs) {
|
|
@@ -1915,15 +2222,20 @@ class Linter {
|
|
|
1915
2222
|
filename: filePath,
|
|
1916
2223
|
config: calculatedConfig({ cwd: verifyOptions.cwd, noConfig: true, overrideConfig: config }, normalizedFilePath)
|
|
1917
2224
|
});
|
|
2225
|
+
const nativeRuleFilter = applyDisableDirectives(
|
|
2226
|
+
(report.diagnostics ?? []).map((diagnostic) => diagnosticToESLintMessage(diagnostic, ruleSeverities)),
|
|
2227
|
+
sourceCode
|
|
2228
|
+
);
|
|
1918
2229
|
const customRuleFilter = applyDisableDirectives(customRuleMessages, sourceCode);
|
|
1919
2230
|
this.suppressedMessages = [
|
|
1920
2231
|
...(report.suppressedDiagnostics ?? []).map((diagnostic) => suppressedDiagnosticToESLintMessage(diagnostic, ruleSeverities)),
|
|
2232
|
+
...nativeRuleFilter.suppressedMessages,
|
|
1921
2233
|
...customRuleFilter.suppressedMessages
|
|
1922
2234
|
];
|
|
1923
2235
|
this.times = { passes: [] };
|
|
1924
2236
|
this.fixPassCount = 0;
|
|
1925
2237
|
return [
|
|
1926
|
-
...
|
|
2238
|
+
...nativeRuleFilter.messages,
|
|
1927
2239
|
...customRuleFilter.messages
|
|
1928
2240
|
];
|
|
1929
2241
|
}
|
|
@@ -2028,7 +2340,7 @@ function parserOptionsForConfig(config, filePath, cwd) {
|
|
|
2028
2340
|
|
|
2029
2341
|
function customRuleEntriesForConfig(config, rules, filePath, cwd) {
|
|
2030
2342
|
const entries = new Map();
|
|
2031
|
-
for (const [ruleId, ruleConfig] of
|
|
2343
|
+
for (const [ruleId, ruleConfig] of Object.entries(rulesFromConfig(config, filePath, cwd))) {
|
|
2032
2344
|
if (!rules.has(ruleId)) {
|
|
2033
2345
|
continue;
|
|
2034
2346
|
}
|
|
@@ -2085,19 +2397,6 @@ function matchingConfigEntries(config, filePath = undefined, cwd = undefined) {
|
|
|
2085
2397
|
return [config];
|
|
2086
2398
|
}
|
|
2087
2399
|
|
|
2088
|
-
function ruleConfigEntries(config, filePath = undefined, cwd = undefined) {
|
|
2089
|
-
if (Array.isArray(config)) {
|
|
2090
|
-
return config.flatMap((item) => ruleConfigEntries(item, filePath, cwd));
|
|
2091
|
-
}
|
|
2092
|
-
if (!config || typeof config !== "object" || !config.rules || typeof config.rules !== "object") {
|
|
2093
|
-
return [];
|
|
2094
|
-
}
|
|
2095
|
-
if (!configAppliesToFile(config, filePath, cwd)) {
|
|
2096
|
-
return [];
|
|
2097
|
-
}
|
|
2098
|
-
return Object.entries(config.rules);
|
|
2099
|
-
}
|
|
2100
|
-
|
|
2101
2400
|
function configWithoutCustomRules(config, rules) {
|
|
2102
2401
|
if (Array.isArray(config)) {
|
|
2103
2402
|
return config.map((item) => configWithoutCustomRules(item, rules));
|
|
@@ -2227,6 +2526,7 @@ function applyDisableDirectives(messages, sourceCode) {
|
|
|
2227
2526
|
}
|
|
2228
2527
|
const directives = sourceCode.getDisableDirectives()
|
|
2229
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)
|
|
2230
2530
|
.sort((left, right) => left.node.loc.start.line - right.node.loc.start.line);
|
|
2231
2531
|
const utlintDirectives = sourceCode.getAllComments()
|
|
2232
2532
|
.map((comment) => utlintDirectiveFromComment(comment, sourceCode))
|
|
@@ -2239,6 +2539,10 @@ function applyDisableDirectives(messages, sourceCode) {
|
|
|
2239
2539
|
const kept = [];
|
|
2240
2540
|
const suppressed = [];
|
|
2241
2541
|
for (const message of messages) {
|
|
2542
|
+
if (!message.ruleId || message.ruleId === "parse" || message.ruleId === "io") {
|
|
2543
|
+
kept.push(message);
|
|
2544
|
+
continue;
|
|
2545
|
+
}
|
|
2242
2546
|
const directive = utlintDirectiveForMessage(message, utlintDirectives) ?? disableDirectiveForMessage(message, directives);
|
|
2243
2547
|
if (directive) {
|
|
2244
2548
|
suppressed.push({
|
|
@@ -3398,10 +3702,7 @@ function mergeRuleTesterConfig(baseConfig, overrideConfig) {
|
|
|
3398
3702
|
return {
|
|
3399
3703
|
...baseConfig,
|
|
3400
3704
|
...overrideConfig,
|
|
3401
|
-
rules:
|
|
3402
|
-
...(baseConfig.rules ?? {}),
|
|
3403
|
-
...(overrideConfig.rules ?? {})
|
|
3404
|
-
}
|
|
3705
|
+
rules: mergeRuleConfigMaps(baseConfig.rules, overrideConfig.rules)
|
|
3405
3706
|
};
|
|
3406
3707
|
}
|
|
3407
3708
|
|
|
@@ -3822,12 +4123,38 @@ function reportToESLintResults(report, textOptions = {}) {
|
|
|
3822
4123
|
}
|
|
3823
4124
|
|
|
3824
4125
|
for (const result of byFile.values()) {
|
|
4126
|
+
applyCompatibilityDisableDirectives(result, textOptions);
|
|
3825
4127
|
finalizeESLintResult(result);
|
|
3826
4128
|
}
|
|
3827
4129
|
|
|
3828
4130
|
return [...byFile.values()];
|
|
3829
4131
|
}
|
|
3830
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
|
+
|
|
3831
4158
|
function normalizeReportDiagnostics(diagnostics, options = {}) {
|
|
3832
4159
|
return (diagnostics ?? []).flatMap((diagnostic) => {
|
|
3833
4160
|
if (!diagnostic?.ruleId) {
|
|
@@ -4055,7 +4382,7 @@ function collectGlobFiles(target, cwd, patterns, expression, files) {
|
|
|
4055
4382
|
|
|
4056
4383
|
const child = join(target, entry.name);
|
|
4057
4384
|
if (entry.isDirectory()) {
|
|
4058
|
-
if (
|
|
4385
|
+
if (shouldTraverseDirectory(normalizeIgnoredPath(child, cwd), patterns)) {
|
|
4059
4386
|
collectGlobFiles(child, cwd, patterns, expression, files);
|
|
4060
4387
|
}
|
|
4061
4388
|
continue;
|
|
@@ -4125,7 +4452,7 @@ function expandLintTarget(target, cwd, patterns) {
|
|
|
4125
4452
|
if (stat.isFile()) {
|
|
4126
4453
|
return isLintableFilePath(target) && !pathIgnoredByPatterns(normalizeIgnoredPath(target, cwd), patterns) ? [target] : [];
|
|
4127
4454
|
}
|
|
4128
|
-
if (!stat.isDirectory() ||
|
|
4455
|
+
if (!stat.isDirectory() || !shouldTraverseDirectory(normalizeIgnoredPath(target, cwd), patterns)) {
|
|
4129
4456
|
return [];
|
|
4130
4457
|
}
|
|
4131
4458
|
|
|
@@ -4143,7 +4470,7 @@ function collectLintableFiles(target, cwd, patterns, files) {
|
|
|
4143
4470
|
|
|
4144
4471
|
const child = join(target, entry.name);
|
|
4145
4472
|
if (entry.isDirectory()) {
|
|
4146
|
-
if (
|
|
4473
|
+
if (shouldTraverseDirectory(normalizeIgnoredPath(child, cwd), patterns)) {
|
|
4147
4474
|
collectLintableFiles(child, cwd, patterns, files);
|
|
4148
4475
|
}
|
|
4149
4476
|
continue;
|
|
@@ -4276,7 +4603,7 @@ function normalizeIgnoredPath(filePath, cwd) {
|
|
|
4276
4603
|
}
|
|
4277
4604
|
|
|
4278
4605
|
function normalizeIgnoredPattern(pattern) {
|
|
4279
|
-
return normalizePath(pattern.replace(/^!/, "")
|
|
4606
|
+
return normalizePath(pattern.replace(/^!/, "")).replace(/\/+$/, "");
|
|
4280
4607
|
}
|
|
4281
4608
|
|
|
4282
4609
|
function pathIgnoredByPatterns(target, patterns) {
|
|
@@ -4290,10 +4617,55 @@ function pathIgnoredByPatterns(target, patterns) {
|
|
|
4290
4617
|
return ignored;
|
|
4291
4618
|
}
|
|
4292
4619
|
|
|
4620
|
+
function shouldTraverseDirectory(target, patterns) {
|
|
4621
|
+
return !pathIgnoredByPatterns(target, patterns) || patterns.some(
|
|
4622
|
+
(pattern) => pattern.startsWith("!") && negatedPatternMayMatchDescendant(target, pattern)
|
|
4623
|
+
);
|
|
4624
|
+
}
|
|
4625
|
+
|
|
4626
|
+
function negatedPatternMayMatchDescendant(target, pattern) {
|
|
4627
|
+
pattern = normalizeIgnoredPattern(pattern);
|
|
4628
|
+
if (pattern.startsWith("/")) {
|
|
4629
|
+
pattern = pattern.slice(1);
|
|
4630
|
+
if (target.startsWith("/")) {
|
|
4631
|
+
target = target.slice(1);
|
|
4632
|
+
}
|
|
4633
|
+
}
|
|
4634
|
+
if (!pattern.includes("/")) {
|
|
4635
|
+
return true;
|
|
4636
|
+
}
|
|
4637
|
+
|
|
4638
|
+
const directoryPattern = pattern.slice(0, pattern.lastIndexOf("/"));
|
|
4639
|
+
if (hasGlobSyntax(directoryPattern)) {
|
|
4640
|
+
const directoryExpression = new RegExp(`^${globPatternRegExpSource(directoryPattern)}(?:/.*)?$`);
|
|
4641
|
+
if (directoryExpression.test(target)) {
|
|
4642
|
+
return true;
|
|
4643
|
+
}
|
|
4644
|
+
}
|
|
4645
|
+
|
|
4646
|
+
const globIndex = pattern.search(/[*?[{]/u);
|
|
4647
|
+
const staticPrefix = (globIndex === -1 ? pattern : pattern.slice(0, globIndex)).replace(/\/+$/u, "");
|
|
4648
|
+
return !staticPrefix ||
|
|
4649
|
+
staticPrefix === target ||
|
|
4650
|
+
staticPrefix.startsWith(`${target}/`) ||
|
|
4651
|
+
target.startsWith(`${staticPrefix}/`);
|
|
4652
|
+
}
|
|
4653
|
+
|
|
4293
4654
|
function matchesIgnorePattern(target, pattern) {
|
|
4655
|
+
const anchored = pattern.startsWith("/");
|
|
4656
|
+
if (anchored) {
|
|
4657
|
+
pattern = pattern.slice(1);
|
|
4658
|
+
if (target.startsWith("/")) {
|
|
4659
|
+
target = target.slice(1);
|
|
4660
|
+
}
|
|
4661
|
+
}
|
|
4294
4662
|
if (pattern.endsWith("/**")) {
|
|
4295
|
-
const
|
|
4296
|
-
|
|
4663
|
+
const directoryPattern = pattern.slice(0, -3);
|
|
4664
|
+
if (hasGlobSyntax(directoryPattern)) {
|
|
4665
|
+
const expression = new RegExp(`^${globPatternRegExpSource(directoryPattern)}(?:/.*)?$`);
|
|
4666
|
+
return expression.test(target);
|
|
4667
|
+
}
|
|
4668
|
+
return target === directoryPattern || target.startsWith(`${directoryPattern}/`);
|
|
4297
4669
|
}
|
|
4298
4670
|
if (pattern.startsWith("**/")) {
|
|
4299
4671
|
const suffix = pattern.slice(3);
|
|
@@ -4302,10 +4674,14 @@ function matchesIgnorePattern(target, pattern) {
|
|
|
4302
4674
|
}
|
|
4303
4675
|
}
|
|
4304
4676
|
if (!hasGlobSyntax(pattern)) {
|
|
4677
|
+
if (anchored || pattern.includes("/")) {
|
|
4678
|
+
return target === pattern || target.startsWith(`${pattern}/`);
|
|
4679
|
+
}
|
|
4305
4680
|
return target === pattern || target.endsWith(`/${pattern}`) || target.startsWith(`${pattern}/`);
|
|
4306
4681
|
}
|
|
4307
4682
|
|
|
4308
|
-
const
|
|
4683
|
+
const prefix = anchored || pattern.includes("/") ? "^" : "(^|/)";
|
|
4684
|
+
const expression = new RegExp(`${prefix}${globPatternRegExpSource(pattern)}$`);
|
|
4309
4685
|
return expression.test(target);
|
|
4310
4686
|
}
|
|
4311
4687
|
|
|
@@ -4414,6 +4790,9 @@ function ruleMetaForRuleId(ruleId) {
|
|
|
4414
4790
|
if (FIXABLE_BUILTIN_RULE_IDS.has(ruleId)) {
|
|
4415
4791
|
meta.fixable = "code";
|
|
4416
4792
|
}
|
|
4793
|
+
if (SUGGESTION_BUILTIN_RULE_IDS.has(ruleId)) {
|
|
4794
|
+
meta.hasSuggestions = true;
|
|
4795
|
+
}
|
|
4417
4796
|
return meta;
|
|
4418
4797
|
}
|
|
4419
4798
|
|
|
@@ -4504,16 +4883,33 @@ function diagnosticToESLintMessage(diagnostic, ruleSeverities) {
|
|
|
4504
4883
|
if (fixes.length > 0) {
|
|
4505
4884
|
message.fix = fixes.length === 1 ? fixes[0] : fixes;
|
|
4506
4885
|
}
|
|
4886
|
+
const suggestions = (diagnostic.suggestions ?? []).map((suggestion) => {
|
|
4887
|
+
const suggestionFixes = (suggestion.fix ?? []).map((fix) => ({
|
|
4888
|
+
range: fix.range,
|
|
4889
|
+
text: fix.text
|
|
4890
|
+
}));
|
|
4891
|
+
return {
|
|
4892
|
+
desc: suggestion.desc,
|
|
4893
|
+
...(suggestionFixes.length === 0 ? {} : {
|
|
4894
|
+
fix: suggestionFixes.length === 1 ? suggestionFixes[0] : suggestionFixes
|
|
4895
|
+
})
|
|
4896
|
+
};
|
|
4897
|
+
});
|
|
4898
|
+
if (suggestions.length > 0) {
|
|
4899
|
+
message.suggestions = suggestions;
|
|
4900
|
+
}
|
|
4507
4901
|
return message;
|
|
4508
4902
|
}
|
|
4509
4903
|
|
|
4510
4904
|
function suppressedDiagnosticToESLintMessage(diagnostic, ruleSeverities) {
|
|
4511
4905
|
return {
|
|
4512
4906
|
...diagnosticToESLintMessage(diagnostic, ruleSeverities),
|
|
4513
|
-
suppressions:
|
|
4514
|
-
|
|
4515
|
-
|
|
4516
|
-
|
|
4907
|
+
suppressions: diagnostic.suppressions?.length > 0
|
|
4908
|
+
? diagnostic.suppressions
|
|
4909
|
+
: [{
|
|
4910
|
+
kind: diagnostic.suppression?.kind ?? "directive",
|
|
4911
|
+
justification: diagnostic.suppression?.justification ?? ""
|
|
4912
|
+
}]
|
|
4517
4913
|
};
|
|
4518
4914
|
}
|
|
4519
4915
|
|