@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.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",
|
|
@@ -80,6 +81,7 @@ const BUILTIN_RULE_IDS = [
|
|
|
80
81
|
"block-scoped-var",
|
|
81
82
|
"camelcase",
|
|
82
83
|
"capitalized-comments",
|
|
84
|
+
"class-methods-use-this",
|
|
83
85
|
"complexity",
|
|
84
86
|
"consistent-return",
|
|
85
87
|
"consistent-this",
|
|
@@ -171,6 +173,7 @@ const BUILTIN_RULE_IDS = [
|
|
|
171
173
|
"no-inline-comments",
|
|
172
174
|
"no-inner-declarations",
|
|
173
175
|
"no-invalid-regexp",
|
|
176
|
+
"no-invalid-this",
|
|
174
177
|
"no-irregular-whitespace",
|
|
175
178
|
"no-iterator",
|
|
176
179
|
"no-label-var",
|
|
@@ -179,6 +182,7 @@ const BUILTIN_RULE_IDS = [
|
|
|
179
182
|
"no-lonely-if",
|
|
180
183
|
"no-loop-func",
|
|
181
184
|
"no-loss-of-precision",
|
|
185
|
+
"no-magic-numbers",
|
|
182
186
|
"no-mixed-spaces-and-tabs",
|
|
183
187
|
"no-misleading-character-class",
|
|
184
188
|
"no-multi-assign",
|
|
@@ -237,6 +241,8 @@ const BUILTIN_RULE_IDS = [
|
|
|
237
241
|
"no-underscore-dangle",
|
|
238
242
|
"no-undefined",
|
|
239
243
|
"no-unneeded-ternary",
|
|
244
|
+
"no-unexpected-multiline",
|
|
245
|
+
"no-unmodified-loop-condition",
|
|
240
246
|
"no-unreachable",
|
|
241
247
|
"no-unreachable-loop",
|
|
242
248
|
"no-unsafe-finally",
|
|
@@ -247,6 +253,7 @@ const BUILTIN_RULE_IDS = [
|
|
|
247
253
|
"no-unused-private-class-members",
|
|
248
254
|
"no-unused-vars",
|
|
249
255
|
"no-use-before-define",
|
|
256
|
+
"no-useless-assignment",
|
|
250
257
|
"no-useless-backreference",
|
|
251
258
|
"no-useless-call",
|
|
252
259
|
"no-useless-catch",
|
|
@@ -308,6 +315,19 @@ const BUILTIN_RULE_IDS = [
|
|
|
308
315
|
"import/no-named-as-default-member",
|
|
309
316
|
"import/no-unresolved",
|
|
310
317
|
"import/no-self-import",
|
|
318
|
+
"jest/no-conditional-expect",
|
|
319
|
+
"jest/no-deprecated-functions",
|
|
320
|
+
"jest/no-export",
|
|
321
|
+
"jest/no-focused-tests",
|
|
322
|
+
"jest/no-identical-title",
|
|
323
|
+
"jest/no-interpolation-in-snapshots",
|
|
324
|
+
"jest/no-jasmine-globals",
|
|
325
|
+
"jest/no-mocks-import",
|
|
326
|
+
"jest/no-standalone-expect",
|
|
327
|
+
"jest/valid-describe-callback",
|
|
328
|
+
"jest/valid-expect-in-promise",
|
|
329
|
+
"jest/valid-expect",
|
|
330
|
+
"jest/valid-title",
|
|
311
331
|
"promise/no-promise-in-callback",
|
|
312
332
|
"promise/no-return-in-finally",
|
|
313
333
|
"promise/no-return-wrap",
|
|
@@ -352,9 +372,12 @@ const BUILTIN_RULE_IDS = [
|
|
|
352
372
|
"react/no-danger",
|
|
353
373
|
"react/no-danger-with-children",
|
|
354
374
|
"react/no-deprecated",
|
|
375
|
+
"react/no-direct-mutation-state",
|
|
355
376
|
"react/no-find-dom-node",
|
|
377
|
+
"react/no-forward-ref",
|
|
356
378
|
"react/no-is-mounted",
|
|
357
379
|
"react/no-multi-comp",
|
|
380
|
+
"react/no-unstable-nested-components",
|
|
358
381
|
"react/no-redundant-should-component-update",
|
|
359
382
|
"react/no-render-return-value",
|
|
360
383
|
"react/no-string-refs",
|
|
@@ -452,10 +475,15 @@ const NATIVE_ONLY_RULE_IDS = [
|
|
|
452
475
|
];
|
|
453
476
|
const NATIVE_RULE_IDS = [...BUILTIN_RULE_IDS, ...NATIVE_ONLY_RULE_IDS];
|
|
454
477
|
const FIXABLE_BUILTIN_RULE_IDS = new Set([
|
|
478
|
+
"jest/no-deprecated-functions",
|
|
479
|
+
"jest/no-jasmine-globals",
|
|
455
480
|
"no-extra-semi",
|
|
456
481
|
"@typescript-eslint/no-extra-semi",
|
|
457
482
|
"unused-imports/no-unused-imports"
|
|
458
483
|
]);
|
|
484
|
+
const SUGGESTION_BUILTIN_RULE_IDS = new Set([
|
|
485
|
+
"jest/no-focused-tests"
|
|
486
|
+
]);
|
|
459
487
|
const BUILTIN_RULES = new Map(BUILTIN_RULE_IDS.map((ruleId) => [ruleId, createBuiltinRule(ruleId)]));
|
|
460
488
|
|
|
461
489
|
export class UtooLint {
|
|
@@ -545,7 +573,7 @@ export class UtooLint {
|
|
|
545
573
|
}
|
|
546
574
|
|
|
547
575
|
async isPathIgnored(filePath) {
|
|
548
|
-
return isPathIgnored(filePath, mergeLintOptions(this.options, {}));
|
|
576
|
+
return isPathIgnored(filePath, withConfigCache(mergeLintOptions(this.options, {})));
|
|
549
577
|
}
|
|
550
578
|
|
|
551
579
|
async calculateConfigForFile(filePath) {
|
|
@@ -553,7 +581,7 @@ export class UtooLint {
|
|
|
553
581
|
}
|
|
554
582
|
|
|
555
583
|
async findConfigFile(filePath) {
|
|
556
|
-
const options = eslintConstructorOptions(this.options);
|
|
584
|
+
const options = withConfigCache(eslintConstructorOptions(this.options));
|
|
557
585
|
if (options.noConfig) {
|
|
558
586
|
return undefined;
|
|
559
587
|
}
|
|
@@ -652,15 +680,20 @@ export class Linter {
|
|
|
652
680
|
filename: filePath,
|
|
653
681
|
config: calculatedConfig({ cwd: verifyOptions.cwd, noConfig: true, overrideConfig: config }, normalizedFilePath)
|
|
654
682
|
});
|
|
683
|
+
const nativeRuleFilter = applyDisableDirectives(
|
|
684
|
+
(report.diagnostics ?? []).map((diagnostic) => diagnosticToESLintMessage(diagnostic, ruleSeverities)),
|
|
685
|
+
sourceCode
|
|
686
|
+
);
|
|
655
687
|
const customRuleFilter = applyDisableDirectives(customRuleMessages, sourceCode);
|
|
656
688
|
this.suppressedMessages = [
|
|
657
689
|
...(report.suppressedDiagnostics ?? []).map((diagnostic) => suppressedDiagnosticToESLintMessage(diagnostic, ruleSeverities)),
|
|
690
|
+
...nativeRuleFilter.suppressedMessages,
|
|
658
691
|
...customRuleFilter.suppressedMessages
|
|
659
692
|
];
|
|
660
693
|
this.times = { passes: [] };
|
|
661
694
|
this.fixPassCount = 0;
|
|
662
695
|
return [
|
|
663
|
-
...
|
|
696
|
+
...nativeRuleFilter.messages,
|
|
664
697
|
...customRuleFilter.messages
|
|
665
698
|
];
|
|
666
699
|
}
|
|
@@ -765,7 +798,7 @@ function parserOptionsForConfig(config, filePath, cwd) {
|
|
|
765
798
|
|
|
766
799
|
function customRuleEntriesForConfig(config, rules, filePath, cwd) {
|
|
767
800
|
const entries = new Map();
|
|
768
|
-
for (const [ruleId, ruleConfig] of
|
|
801
|
+
for (const [ruleId, ruleConfig] of Object.entries(rulesFromConfig(config, filePath, cwd))) {
|
|
769
802
|
if (!rules.has(ruleId)) {
|
|
770
803
|
continue;
|
|
771
804
|
}
|
|
@@ -822,19 +855,6 @@ function matchingConfigEntries(config, filePath = undefined, cwd = undefined) {
|
|
|
822
855
|
return [config];
|
|
823
856
|
}
|
|
824
857
|
|
|
825
|
-
function ruleConfigEntries(config, filePath = undefined, cwd = undefined) {
|
|
826
|
-
if (Array.isArray(config)) {
|
|
827
|
-
return config.flatMap((item) => ruleConfigEntries(item, filePath, cwd));
|
|
828
|
-
}
|
|
829
|
-
if (!config || typeof config !== "object" || !config.rules || typeof config.rules !== "object") {
|
|
830
|
-
return [];
|
|
831
|
-
}
|
|
832
|
-
if (!configAppliesToFile(config, filePath, cwd)) {
|
|
833
|
-
return [];
|
|
834
|
-
}
|
|
835
|
-
return Object.entries(config.rules);
|
|
836
|
-
}
|
|
837
|
-
|
|
838
858
|
function configWithoutCustomRules(config, rules) {
|
|
839
859
|
if (Array.isArray(config)) {
|
|
840
860
|
return config.map((item) => configWithoutCustomRules(item, rules));
|
|
@@ -964,6 +984,7 @@ function applyDisableDirectives(messages, sourceCode) {
|
|
|
964
984
|
}
|
|
965
985
|
const directives = sourceCode.getDisableDirectives()
|
|
966
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)
|
|
967
988
|
.sort((left, right) => left.node.loc.start.line - right.node.loc.start.line);
|
|
968
989
|
const utlintDirectives = sourceCode.getAllComments()
|
|
969
990
|
.map((comment) => utlintDirectiveFromComment(comment, sourceCode))
|
|
@@ -976,6 +997,10 @@ function applyDisableDirectives(messages, sourceCode) {
|
|
|
976
997
|
const kept = [];
|
|
977
998
|
const suppressed = [];
|
|
978
999
|
for (const message of messages) {
|
|
1000
|
+
if (!message.ruleId || message.ruleId === "parse" || message.ruleId === "io") {
|
|
1001
|
+
kept.push(message);
|
|
1002
|
+
continue;
|
|
1003
|
+
}
|
|
979
1004
|
const directive = utlintDirectiveForMessage(message, utlintDirectives) ?? disableDirectiveForMessage(message, directives);
|
|
980
1005
|
if (directive) {
|
|
981
1006
|
suppressed.push({
|
|
@@ -2135,10 +2160,7 @@ function mergeRuleTesterConfig(baseConfig, overrideConfig) {
|
|
|
2135
2160
|
return {
|
|
2136
2161
|
...baseConfig,
|
|
2137
2162
|
...overrideConfig,
|
|
2138
|
-
rules:
|
|
2139
|
-
...(baseConfig.rules ?? {}),
|
|
2140
|
-
...(overrideConfig.rules ?? {})
|
|
2141
|
-
}
|
|
2163
|
+
rules: mergeRuleConfigMaps(baseConfig.rules, overrideConfig.rules)
|
|
2142
2164
|
};
|
|
2143
2165
|
}
|
|
2144
2166
|
|
|
@@ -2589,7 +2611,7 @@ export class CLIEngine {
|
|
|
2589
2611
|
}
|
|
2590
2612
|
|
|
2591
2613
|
isPathIgnored(filePath) {
|
|
2592
|
-
return isPathIgnored(filePath, eslintConstructorOptions(this.options));
|
|
2614
|
+
return isPathIgnored(filePath, withConfigCache(eslintConstructorOptions(this.options)));
|
|
2593
2615
|
}
|
|
2594
2616
|
|
|
2595
2617
|
getConfigForFile(filePath) {
|
|
@@ -2597,6 +2619,20 @@ export class CLIEngine {
|
|
|
2597
2619
|
}
|
|
2598
2620
|
}
|
|
2599
2621
|
|
|
2622
|
+
const DEFAULT_NATIVE_MAX_BUFFER = 64 * 1024 * 1024;
|
|
2623
|
+
|
|
2624
|
+
function nativeMaxBuffer(options, env) {
|
|
2625
|
+
const configured = options.maxBuffer ?? env.UTOO_LINT_MAX_BUFFER;
|
|
2626
|
+
if (configured === undefined || configured === "") {
|
|
2627
|
+
return DEFAULT_NATIVE_MAX_BUFFER;
|
|
2628
|
+
}
|
|
2629
|
+
const value = typeof configured === "number" ? configured : Number(configured);
|
|
2630
|
+
if (!Number.isSafeInteger(value) || value <= 0) {
|
|
2631
|
+
throw new TypeError("maxBuffer and UTOO_LINT_MAX_BUFFER must be a positive integer byte count");
|
|
2632
|
+
}
|
|
2633
|
+
return value;
|
|
2634
|
+
}
|
|
2635
|
+
|
|
2600
2636
|
export function run(args = [], options = {}) {
|
|
2601
2637
|
const cliArgs = normalizeStringArray(args, "args");
|
|
2602
2638
|
const env = options.env ? { ...process.env, ...options.env } : process.env;
|
|
@@ -2607,7 +2643,8 @@ export function run(args = [], options = {}) {
|
|
|
2607
2643
|
env,
|
|
2608
2644
|
encoding: options.encoding ?? "utf8",
|
|
2609
2645
|
input: options.input,
|
|
2610
|
-
stdio: options.stdio
|
|
2646
|
+
stdio: options.stdio,
|
|
2647
|
+
maxBuffer: nativeMaxBuffer(options, env)
|
|
2611
2648
|
});
|
|
2612
2649
|
}
|
|
2613
2650
|
|
|
@@ -2749,8 +2786,9 @@ export function runCli(args = [], options = {}) {
|
|
|
2749
2786
|
extraArgs: parsed.passthroughArgs,
|
|
2750
2787
|
preserveNativeDefaults: Boolean(parsed.options.noConfig)
|
|
2751
2788
|
});
|
|
2752
|
-
const
|
|
2753
|
-
const
|
|
2789
|
+
const usesDefaultTargets = parsed.targets.length === 0;
|
|
2790
|
+
const targets = usesDefaultTargets ? defaultLintTargets(cliOptions) : parsed.targets;
|
|
2791
|
+
const report = lintFiles(targets, { ...cliOptions, useDefaultConfigTargets: usesDefaultTargets });
|
|
2754
2792
|
report.diagnostics = normalizeReportDiagnostics(report.diagnostics, cliOptions);
|
|
2755
2793
|
report.exitCode = exitCodeForDiagnostics(report.diagnostics);
|
|
2756
2794
|
const status = report.exitCode ?? exitCodeForDiagnostics(report.diagnostics);
|
|
@@ -2858,7 +2896,8 @@ export function runFishlint(args = [], options = {}) {
|
|
|
2858
2896
|
env,
|
|
2859
2897
|
encoding: options.encoding ?? "utf8",
|
|
2860
2898
|
input: options.input,
|
|
2861
|
-
stdio: options.stdio
|
|
2899
|
+
stdio: options.stdio,
|
|
2900
|
+
maxBuffer: nativeMaxBuffer(options, env)
|
|
2862
2901
|
});
|
|
2863
2902
|
}
|
|
2864
2903
|
|
|
@@ -3060,13 +3099,23 @@ function booleanFlagValue(arg) {
|
|
|
3060
3099
|
|
|
3061
3100
|
export function lintFiles(paths, options = {}) {
|
|
3062
3101
|
options = withConfigCache(options);
|
|
3102
|
+
const usesDefaultTargets = paths == null || options.useDefaultConfigTargets;
|
|
3063
3103
|
const targets = lintTargetsForInput(paths, options);
|
|
3064
3104
|
const ignoredDiagnostics = ignoredLintPathDiagnostics(targets, options);
|
|
3065
|
-
|
|
3105
|
+
let lintPaths = filteredLintPaths(targets, options);
|
|
3106
|
+
if (usesDefaultTargets) {
|
|
3107
|
+
lintPaths = filterDefaultConfigLintPaths(lintPaths, options);
|
|
3108
|
+
}
|
|
3066
3109
|
if (lintPaths.length === 0) {
|
|
3067
3110
|
return { files: 0, filePaths: [], diagnostics: ignoredDiagnostics, suppressedDiagnostics: [], exitCode: exitCodeForDiagnostics(ignoredDiagnostics) };
|
|
3068
3111
|
}
|
|
3069
3112
|
|
|
3113
|
+
const nativeFlatOptions = nativeFlatConfigOptions(options);
|
|
3114
|
+
if (nativeFlatOptions) {
|
|
3115
|
+
const report = runNativeLintReport(lintPaths, nativeFlatOptions);
|
|
3116
|
+
return finalizeLintReport(report, ignoredDiagnostics, options);
|
|
3117
|
+
}
|
|
3118
|
+
|
|
3070
3119
|
const configRuns = nativeConfigRunsForFiles(expandNativeConfigRunPaths(lintPaths, options), options);
|
|
3071
3120
|
if (configRuns) {
|
|
3072
3121
|
const report = mergeNativeReports(
|
|
@@ -3079,6 +3128,76 @@ export function lintFiles(paths, options = {}) {
|
|
|
3079
3128
|
return finalizeLintReport(report, ignoredDiagnostics, options);
|
|
3080
3129
|
}
|
|
3081
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
|
+
|
|
3082
3201
|
function expandNativeConfigRunPaths(paths, options) {
|
|
3083
3202
|
const cwd = options.cwd ?? process.cwd();
|
|
3084
3203
|
const patterns = ignoreDisabled(options) ? [] : ignorePatternsForOptions(options, cwd);
|
|
@@ -3152,13 +3271,15 @@ function nativeConfigRunsForFiles(paths, options) {
|
|
|
3152
3271
|
const fileConfigPath = options.noConfig ? undefined : configPathForFile(options, matchPath);
|
|
3153
3272
|
const configured = Boolean(options.baseConfig || options.overrideConfig || fileConfigPath);
|
|
3154
3273
|
hasConfigSource ||= configured;
|
|
3155
|
-
|
|
3274
|
+
const calculated = configured ? calculatedConfig({ ...options, rules: undefined }, matchPath) : {};
|
|
3275
|
+
let rules = calculated.rules;
|
|
3276
|
+
const settings = calculated.settings;
|
|
3156
3277
|
if (configured && options.rules) {
|
|
3157
3278
|
rules = selectedRulesWithConfigOptions(rules, options.rules);
|
|
3158
3279
|
}
|
|
3159
|
-
const signature = configured ? stableConfigSignature(rules) : "<native-defaults>";
|
|
3280
|
+
const signature = configured ? stableConfigSignature({ rules, settings }) : "<native-defaults>";
|
|
3160
3281
|
if (!groups.has(signature)) {
|
|
3161
|
-
groups.set(signature, { paths: [], rules, configured });
|
|
3282
|
+
groups.set(signature, { paths: [], rules, settings, configured });
|
|
3162
3283
|
}
|
|
3163
3284
|
groups.get(signature).paths.push(filePath);
|
|
3164
3285
|
}
|
|
@@ -3181,6 +3302,22 @@ function nativeConfigRunsForFiles(paths, options) {
|
|
|
3181
3302
|
};
|
|
3182
3303
|
}
|
|
3183
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
|
+
|
|
3184
3321
|
return {
|
|
3185
3322
|
paths: group.paths,
|
|
3186
3323
|
options: {
|
|
@@ -3188,13 +3325,50 @@ function nativeConfigRunsForFiles(paths, options) {
|
|
|
3188
3325
|
config: undefined,
|
|
3189
3326
|
noConfig: true,
|
|
3190
3327
|
baseConfig: undefined,
|
|
3191
|
-
overrideConfig: {
|
|
3328
|
+
overrideConfig: {
|
|
3329
|
+
rules: allDisabledNativeRules(group.rules),
|
|
3330
|
+
...(group.settings ? { settings: group.settings } : {})
|
|
3331
|
+
},
|
|
3192
3332
|
forceMaterializedConfig: true
|
|
3193
3333
|
}
|
|
3194
3334
|
};
|
|
3195
3335
|
});
|
|
3196
3336
|
}
|
|
3197
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
|
+
|
|
3198
3372
|
function allDisabledNativeRules(rules) {
|
|
3199
3373
|
return {
|
|
3200
3374
|
...Object.fromEntries(NATIVE_RULE_IDS.map((rule) => [rule, "off"])),
|
|
@@ -3311,7 +3485,7 @@ function buildNativeLintArgs(paths, options) {
|
|
|
3311
3485
|
if (options.noConfig) {
|
|
3312
3486
|
cliArgs.push("--no-config");
|
|
3313
3487
|
}
|
|
3314
|
-
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)) {
|
|
3315
3489
|
const configForRuleSelection = options.noConfig
|
|
3316
3490
|
? undefined
|
|
3317
3491
|
: options.config ? readConfig(options.config, options.cwd, options.configCache) : undefined;
|
|
@@ -3327,6 +3501,12 @@ function buildNativeLintArgs(paths, options) {
|
|
|
3327
3501
|
if (options.config) {
|
|
3328
3502
|
cliArgs.push(`--config=${options.config}`);
|
|
3329
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
|
+
}
|
|
3330
3510
|
if (options.rules) {
|
|
3331
3511
|
const rules = Array.isArray(options.rules) ? options.rules.join(",") : options.rules;
|
|
3332
3512
|
if (rules) {
|
|
@@ -3361,9 +3541,17 @@ function mergeLintOptions(base, override) {
|
|
|
3361
3541
|
}
|
|
3362
3542
|
|
|
3363
3543
|
function withConfigCache(options) {
|
|
3364
|
-
|
|
3365
|
-
|
|
3366
|
-
|
|
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
|
+
};
|
|
3367
3555
|
}
|
|
3368
3556
|
|
|
3369
3557
|
function eslintConstructorOptions(options) {
|
|
@@ -3417,12 +3605,12 @@ function calculatedConfig(options = {}, filePath) {
|
|
|
3417
3605
|
);
|
|
3418
3606
|
return {
|
|
3419
3607
|
...configData,
|
|
3420
|
-
rules:
|
|
3421
|
-
|
|
3422
|
-
|
|
3423
|
-
|
|
3424
|
-
|
|
3425
|
-
|
|
3608
|
+
rules: mergeRuleConfigMaps(
|
|
3609
|
+
rulesFromConfig(options.baseConfig, filePath, options.cwd),
|
|
3610
|
+
rulesFromFileConfig(options, filePath),
|
|
3611
|
+
rulesFromConfig(options.overrideConfig, filePath, options.cwd),
|
|
3612
|
+
rulesFromNativeRuleList(options.rules)
|
|
3613
|
+
)
|
|
3426
3614
|
};
|
|
3427
3615
|
}
|
|
3428
3616
|
|
|
@@ -3517,10 +3705,10 @@ function rulesFromConfig(config, filePath, cwd) {
|
|
|
3517
3705
|
return {};
|
|
3518
3706
|
}
|
|
3519
3707
|
if (Array.isArray(config)) {
|
|
3520
|
-
return config.reduce(
|
|
3521
|
-
|
|
3522
|
-
|
|
3523
|
-
|
|
3708
|
+
return config.reduce(
|
|
3709
|
+
(rules, entry) => mergeRuleConfigMaps(rules, rulesFromConfig(entry, filePath, cwd)),
|
|
3710
|
+
{}
|
|
3711
|
+
);
|
|
3524
3712
|
}
|
|
3525
3713
|
if (!configAppliesToFile(config, filePath, cwd)) {
|
|
3526
3714
|
return {};
|
|
@@ -3573,12 +3761,64 @@ function defaultLintTargets(options = {}) {
|
|
|
3573
3761
|
return ["."];
|
|
3574
3762
|
}
|
|
3575
3763
|
|
|
3576
|
-
const
|
|
3764
|
+
const config = readConfig(configPath, options.cwd, options.configCache);
|
|
3765
|
+
if (configHasUnscopedRules(config)) {
|
|
3766
|
+
return ["."];
|
|
3767
|
+
}
|
|
3768
|
+
|
|
3769
|
+
const targets = filePatternsFromConfig(config);
|
|
3577
3770
|
return targets.length > 0
|
|
3578
3771
|
? targets.map((target) => resolveConfigPattern(target, dirname(configPath)))
|
|
3579
3772
|
: ["."];
|
|
3580
3773
|
}
|
|
3581
3774
|
|
|
3775
|
+
function filterDefaultConfigLintPaths(paths, options) {
|
|
3776
|
+
const configPath = configPathForOptions(options);
|
|
3777
|
+
if (!configPath) {
|
|
3778
|
+
return paths;
|
|
3779
|
+
}
|
|
3780
|
+
const config = readConfig(configPath, options.cwd, options.configCache);
|
|
3781
|
+
if (!configHasFileSelectors(config)) {
|
|
3782
|
+
return paths;
|
|
3783
|
+
}
|
|
3784
|
+
const cwd = dirname(configPath);
|
|
3785
|
+
return paths.filter((filePath) => configSelectsFile(config, filePath, cwd));
|
|
3786
|
+
}
|
|
3787
|
+
|
|
3788
|
+
function configHasFileSelectors(config) {
|
|
3789
|
+
if (Array.isArray(config)) {
|
|
3790
|
+
return config.some(configHasFileSelectors);
|
|
3791
|
+
}
|
|
3792
|
+
return Boolean(config && typeof config === "object" && normalizeConfigFileSelectors(config.files).length > 0);
|
|
3793
|
+
}
|
|
3794
|
+
|
|
3795
|
+
function configHasUnscopedRules(config) {
|
|
3796
|
+
if (Array.isArray(config)) {
|
|
3797
|
+
return config.some(configHasUnscopedRules);
|
|
3798
|
+
}
|
|
3799
|
+
return Boolean(
|
|
3800
|
+
config &&
|
|
3801
|
+
typeof config === "object" &&
|
|
3802
|
+
normalizeConfigFileSelectors(config.files).length === 0 &&
|
|
3803
|
+
config.rules &&
|
|
3804
|
+
typeof config.rules === "object" &&
|
|
3805
|
+
Object.keys(config.rules).length > 0
|
|
3806
|
+
);
|
|
3807
|
+
}
|
|
3808
|
+
|
|
3809
|
+
function configSelectsFile(config, filePath, cwd) {
|
|
3810
|
+
if (Array.isArray(config)) {
|
|
3811
|
+
return config.some((entry) => configSelectsFile(entry, filePath, cwd));
|
|
3812
|
+
}
|
|
3813
|
+
if (!config || typeof config !== "object") {
|
|
3814
|
+
return false;
|
|
3815
|
+
}
|
|
3816
|
+
const selectors = normalizeConfigFileSelectors(config.files);
|
|
3817
|
+
return selectors.length > 0
|
|
3818
|
+
? configAppliesToFile(config, filePath, cwd)
|
|
3819
|
+
: configHasUnscopedRules(config) && configAppliesToFile(config, filePath, cwd);
|
|
3820
|
+
}
|
|
3821
|
+
|
|
3582
3822
|
function resolveConfigPattern(pattern, configDirectory) {
|
|
3583
3823
|
if (isAbsolute(pattern)) {
|
|
3584
3824
|
return pattern;
|
|
@@ -3602,8 +3842,10 @@ function configAppliesToFile(config, filePath, cwd) {
|
|
|
3602
3842
|
}
|
|
3603
3843
|
|
|
3604
3844
|
const normalized = normalizeIgnoredPath(filePath, cwd ?? process.cwd());
|
|
3605
|
-
const files =
|
|
3606
|
-
if (files.length > 0 && !files.some((
|
|
3845
|
+
const files = normalizeConfigFileSelectors(config.files);
|
|
3846
|
+
if (files.length > 0 && !files.some((selector) => selector.every(
|
|
3847
|
+
(pattern) => matchesConfigFilePattern(normalized, normalizeIgnoredPattern(pattern))
|
|
3848
|
+
))) {
|
|
3607
3849
|
return false;
|
|
3608
3850
|
}
|
|
3609
3851
|
|
|
@@ -3611,6 +3853,23 @@ function configAppliesToFile(config, filePath, cwd) {
|
|
|
3611
3853
|
return !pathIgnoredByPatterns(normalized, ignores);
|
|
3612
3854
|
}
|
|
3613
3855
|
|
|
3856
|
+
function normalizeConfigFileSelectors(patterns) {
|
|
3857
|
+
if (!patterns) {
|
|
3858
|
+
return [];
|
|
3859
|
+
}
|
|
3860
|
+
const values = Array.isArray(patterns) ? patterns : [patterns];
|
|
3861
|
+
return values.flatMap((value) => {
|
|
3862
|
+
if (typeof value === "string") {
|
|
3863
|
+
return [[value]];
|
|
3864
|
+
}
|
|
3865
|
+
if (Array.isArray(value)) {
|
|
3866
|
+
const selector = normalizeConfigPatterns(value);
|
|
3867
|
+
return selector.length > 0 ? [selector] : [];
|
|
3868
|
+
}
|
|
3869
|
+
return [];
|
|
3870
|
+
});
|
|
3871
|
+
}
|
|
3872
|
+
|
|
3614
3873
|
function normalizeConfigPatterns(patterns) {
|
|
3615
3874
|
if (!patterns) {
|
|
3616
3875
|
return [];
|
|
@@ -3633,7 +3892,7 @@ function configPathForOptions(options) {
|
|
|
3633
3892
|
}
|
|
3634
3893
|
|
|
3635
3894
|
const cwd = options.cwd ?? process.cwd();
|
|
3636
|
-
return configPathFromDirectory(cwd);
|
|
3895
|
+
return configPathFromDirectory(cwd, options);
|
|
3637
3896
|
}
|
|
3638
3897
|
|
|
3639
3898
|
function configPathForFile(options, filePath) {
|
|
@@ -3643,7 +3902,7 @@ function configPathForFile(options, filePath) {
|
|
|
3643
3902
|
if (options.config) {
|
|
3644
3903
|
return resolvePath(options.cwd ?? process.cwd(), options.config);
|
|
3645
3904
|
}
|
|
3646
|
-
return configPathFromDirectory(configSearchDirectoryForFile(filePath, options.cwd));
|
|
3905
|
+
return configPathFromDirectory(configSearchDirectoryForFile(filePath, options.cwd), options);
|
|
3647
3906
|
}
|
|
3648
3907
|
|
|
3649
3908
|
function configSearchDirectoryForFile(filePath, cwd) {
|
|
@@ -3658,11 +3917,29 @@ function configSearchDirectoryForFile(filePath, cwd) {
|
|
|
3658
3917
|
return dirname(absolute);
|
|
3659
3918
|
}
|
|
3660
3919
|
|
|
3661
|
-
function configPathFromDirectory(directory) {
|
|
3662
|
-
return findConfigPathFromDirectory(directory);
|
|
3920
|
+
function configPathFromDirectory(directory, options) {
|
|
3921
|
+
return findConfigPathFromDirectory(directory, options[CONFIG_DISCOVERY_CACHE]);
|
|
3663
3922
|
}
|
|
3664
3923
|
|
|
3665
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
|
+
|
|
3666
3943
|
const fileConfigPath = !options.noConfig ? configPathForOptions(options) : undefined;
|
|
3667
3944
|
const shouldMaterializeFileConfig = Boolean(fileConfigPath);
|
|
3668
3945
|
const fileConfig = shouldMaterializeFileConfig
|
|
@@ -3672,7 +3949,15 @@ function withTemporaryConfig(options, callback) {
|
|
|
3672
3949
|
const rules = shouldMaterializeFileConfig
|
|
3673
3950
|
? materializedRulesFromConfigs(...configs)
|
|
3674
3951
|
: runtimeRulesFromConfigs(...configs);
|
|
3675
|
-
|
|
3952
|
+
const settings = configs.reduce(
|
|
3953
|
+
(result, config) => ({
|
|
3954
|
+
...result,
|
|
3955
|
+
...(configDataFromConfig(config, options.filePath ?? options.filename, options.cwd).settings ?? {})
|
|
3956
|
+
}),
|
|
3957
|
+
{}
|
|
3958
|
+
);
|
|
3959
|
+
const hasSettings = Object.keys(settings).length > 0;
|
|
3960
|
+
if (Object.keys(rules).length === 0 && !hasSettings) {
|
|
3676
3961
|
if (shouldMaterializeFileConfig) {
|
|
3677
3962
|
return callback({
|
|
3678
3963
|
...options,
|
|
@@ -3684,7 +3969,7 @@ function withTemporaryConfig(options, callback) {
|
|
|
3684
3969
|
}
|
|
3685
3970
|
const enabledRules = enabledRuleNamesFromConfigs(...configs);
|
|
3686
3971
|
const hasExplicitOffRules = Object.values(rules).some((value) => ruleConfigSeverity(value) === 0);
|
|
3687
|
-
if (!shouldMaterializeFileConfig && !hasRuleOptions(rules) && !hasExplicitOffRules && !options.forceMaterializedConfig) {
|
|
3972
|
+
if (!shouldMaterializeFileConfig && !hasSettings && !hasRuleOptions(rules) && !hasExplicitOffRules && !options.forceMaterializedConfig) {
|
|
3688
3973
|
return callback({
|
|
3689
3974
|
...options,
|
|
3690
3975
|
config: shouldMaterializeFileConfig ? undefined : options.config,
|
|
@@ -3696,7 +3981,7 @@ function withTemporaryConfig(options, callback) {
|
|
|
3696
3981
|
const tmp = mkdtempSync(join(tmpdir(), "utoo-lint-config-"));
|
|
3697
3982
|
const configPath = join(tmp, "utlint.config.json");
|
|
3698
3983
|
try {
|
|
3699
|
-
writeFileSync(configPath, JSON.stringify({ rules }));
|
|
3984
|
+
writeFileSync(configPath, JSON.stringify({ rules, ...(hasSettings ? { settings } : {}) }));
|
|
3700
3985
|
return callback({
|
|
3701
3986
|
...options,
|
|
3702
3987
|
config: shouldMaterializeFileConfig ? configPath : options.config ?? configPath,
|
|
@@ -3715,11 +4000,7 @@ function enabledRuleNames(rules) {
|
|
|
3715
4000
|
}
|
|
3716
4001
|
|
|
3717
4002
|
function runtimeRulesFromConfigs(...configs) {
|
|
3718
|
-
|
|
3719
|
-
for (const config of configs) {
|
|
3720
|
-
Object.assign(rules, runtimeRulesFromConfig(config));
|
|
3721
|
-
}
|
|
3722
|
-
return rules;
|
|
4003
|
+
return mergeRuleConfigMaps(...configs.map(runtimeRulesFromConfig));
|
|
3723
4004
|
}
|
|
3724
4005
|
|
|
3725
4006
|
function materializedRulesFromConfigs(...configs) {
|
|
@@ -3731,10 +4012,10 @@ function runtimeRulesFromConfig(config) {
|
|
|
3731
4012
|
return {};
|
|
3732
4013
|
}
|
|
3733
4014
|
if (Array.isArray(config)) {
|
|
3734
|
-
return config.reduce(
|
|
3735
|
-
|
|
3736
|
-
|
|
3737
|
-
|
|
4015
|
+
return config.reduce(
|
|
4016
|
+
(rules, entry) => mergeRuleConfigMaps(rules, runtimeRulesFromConfig(entry)),
|
|
4017
|
+
{}
|
|
4018
|
+
);
|
|
3738
4019
|
}
|
|
3739
4020
|
|
|
3740
4021
|
const rules = {};
|
|
@@ -3744,6 +4025,26 @@ function runtimeRulesFromConfig(config) {
|
|
|
3744
4025
|
return rules;
|
|
3745
4026
|
}
|
|
3746
4027
|
|
|
4028
|
+
function mergeRuleConfigMaps(...ruleMaps) {
|
|
4029
|
+
const result = {};
|
|
4030
|
+
for (const rules of ruleMaps) {
|
|
4031
|
+
for (const [ruleId, ruleConfig] of Object.entries(rules ?? {})) {
|
|
4032
|
+
const previous = result[ruleId];
|
|
4033
|
+
if (previous !== undefined && isSeverityOnlyRuleConfig(ruleConfig) && Array.isArray(previous) && previous.length > 1) {
|
|
4034
|
+
const severity = Array.isArray(ruleConfig) ? ruleConfig[0] : ruleConfig;
|
|
4035
|
+
result[ruleId] = [severity, ...previous.slice(1)];
|
|
4036
|
+
} else {
|
|
4037
|
+
result[ruleId] = ruleConfig;
|
|
4038
|
+
}
|
|
4039
|
+
}
|
|
4040
|
+
}
|
|
4041
|
+
return result;
|
|
4042
|
+
}
|
|
4043
|
+
|
|
4044
|
+
function isSeverityOnlyRuleConfig(ruleConfig) {
|
|
4045
|
+
return !Array.isArray(ruleConfig) || ruleConfig.length === 1;
|
|
4046
|
+
}
|
|
4047
|
+
|
|
3747
4048
|
function enabledRuleNamesFromConfigs(...configs) {
|
|
3748
4049
|
const rules = new Set();
|
|
3749
4050
|
for (const config of configs) {
|
|
@@ -3825,12 +4126,38 @@ function reportToESLintResults(report, textOptions = {}) {
|
|
|
3825
4126
|
}
|
|
3826
4127
|
|
|
3827
4128
|
for (const result of byFile.values()) {
|
|
4129
|
+
applyCompatibilityDisableDirectives(result, textOptions);
|
|
3828
4130
|
finalizeESLintResult(result);
|
|
3829
4131
|
}
|
|
3830
4132
|
|
|
3831
4133
|
return [...byFile.values()];
|
|
3832
4134
|
}
|
|
3833
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
|
+
|
|
3834
4161
|
function normalizeReportDiagnostics(diagnostics, options = {}) {
|
|
3835
4162
|
return (diagnostics ?? []).flatMap((diagnostic) => {
|
|
3836
4163
|
if (!diagnostic?.ruleId) {
|
|
@@ -4058,7 +4385,7 @@ function collectGlobFiles(target, cwd, patterns, expression, files) {
|
|
|
4058
4385
|
|
|
4059
4386
|
const child = join(target, entry.name);
|
|
4060
4387
|
if (entry.isDirectory()) {
|
|
4061
|
-
if (
|
|
4388
|
+
if (shouldTraverseDirectory(normalizeIgnoredPath(child, cwd), patterns)) {
|
|
4062
4389
|
collectGlobFiles(child, cwd, patterns, expression, files);
|
|
4063
4390
|
}
|
|
4064
4391
|
continue;
|
|
@@ -4128,7 +4455,7 @@ function expandLintTarget(target, cwd, patterns) {
|
|
|
4128
4455
|
if (stat.isFile()) {
|
|
4129
4456
|
return isLintableFilePath(target) && !pathIgnoredByPatterns(normalizeIgnoredPath(target, cwd), patterns) ? [target] : [];
|
|
4130
4457
|
}
|
|
4131
|
-
if (!stat.isDirectory() ||
|
|
4458
|
+
if (!stat.isDirectory() || !shouldTraverseDirectory(normalizeIgnoredPath(target, cwd), patterns)) {
|
|
4132
4459
|
return [];
|
|
4133
4460
|
}
|
|
4134
4461
|
|
|
@@ -4146,7 +4473,7 @@ function collectLintableFiles(target, cwd, patterns, files) {
|
|
|
4146
4473
|
|
|
4147
4474
|
const child = join(target, entry.name);
|
|
4148
4475
|
if (entry.isDirectory()) {
|
|
4149
|
-
if (
|
|
4476
|
+
if (shouldTraverseDirectory(normalizeIgnoredPath(child, cwd), patterns)) {
|
|
4150
4477
|
collectLintableFiles(child, cwd, patterns, files);
|
|
4151
4478
|
}
|
|
4152
4479
|
continue;
|
|
@@ -4279,7 +4606,7 @@ function normalizeIgnoredPath(filePath, cwd) {
|
|
|
4279
4606
|
}
|
|
4280
4607
|
|
|
4281
4608
|
function normalizeIgnoredPattern(pattern) {
|
|
4282
|
-
return normalizePath(pattern.replace(/^!/, "")
|
|
4609
|
+
return normalizePath(pattern.replace(/^!/, "")).replace(/\/+$/, "");
|
|
4283
4610
|
}
|
|
4284
4611
|
|
|
4285
4612
|
function pathIgnoredByPatterns(target, patterns) {
|
|
@@ -4293,10 +4620,55 @@ function pathIgnoredByPatterns(target, patterns) {
|
|
|
4293
4620
|
return ignored;
|
|
4294
4621
|
}
|
|
4295
4622
|
|
|
4623
|
+
function shouldTraverseDirectory(target, patterns) {
|
|
4624
|
+
return !pathIgnoredByPatterns(target, patterns) || patterns.some(
|
|
4625
|
+
(pattern) => pattern.startsWith("!") && negatedPatternMayMatchDescendant(target, pattern)
|
|
4626
|
+
);
|
|
4627
|
+
}
|
|
4628
|
+
|
|
4629
|
+
function negatedPatternMayMatchDescendant(target, pattern) {
|
|
4630
|
+
pattern = normalizeIgnoredPattern(pattern);
|
|
4631
|
+
if (pattern.startsWith("/")) {
|
|
4632
|
+
pattern = pattern.slice(1);
|
|
4633
|
+
if (target.startsWith("/")) {
|
|
4634
|
+
target = target.slice(1);
|
|
4635
|
+
}
|
|
4636
|
+
}
|
|
4637
|
+
if (!pattern.includes("/")) {
|
|
4638
|
+
return true;
|
|
4639
|
+
}
|
|
4640
|
+
|
|
4641
|
+
const directoryPattern = pattern.slice(0, pattern.lastIndexOf("/"));
|
|
4642
|
+
if (hasGlobSyntax(directoryPattern)) {
|
|
4643
|
+
const directoryExpression = new RegExp(`^${globPatternRegExpSource(directoryPattern)}(?:/.*)?$`);
|
|
4644
|
+
if (directoryExpression.test(target)) {
|
|
4645
|
+
return true;
|
|
4646
|
+
}
|
|
4647
|
+
}
|
|
4648
|
+
|
|
4649
|
+
const globIndex = pattern.search(/[*?[{]/u);
|
|
4650
|
+
const staticPrefix = (globIndex === -1 ? pattern : pattern.slice(0, globIndex)).replace(/\/+$/u, "");
|
|
4651
|
+
return !staticPrefix ||
|
|
4652
|
+
staticPrefix === target ||
|
|
4653
|
+
staticPrefix.startsWith(`${target}/`) ||
|
|
4654
|
+
target.startsWith(`${staticPrefix}/`);
|
|
4655
|
+
}
|
|
4656
|
+
|
|
4296
4657
|
function matchesIgnorePattern(target, pattern) {
|
|
4658
|
+
const anchored = pattern.startsWith("/");
|
|
4659
|
+
if (anchored) {
|
|
4660
|
+
pattern = pattern.slice(1);
|
|
4661
|
+
if (target.startsWith("/")) {
|
|
4662
|
+
target = target.slice(1);
|
|
4663
|
+
}
|
|
4664
|
+
}
|
|
4297
4665
|
if (pattern.endsWith("/**")) {
|
|
4298
|
-
const
|
|
4299
|
-
|
|
4666
|
+
const directoryPattern = pattern.slice(0, -3);
|
|
4667
|
+
if (hasGlobSyntax(directoryPattern)) {
|
|
4668
|
+
const expression = new RegExp(`^${globPatternRegExpSource(directoryPattern)}(?:/.*)?$`);
|
|
4669
|
+
return expression.test(target);
|
|
4670
|
+
}
|
|
4671
|
+
return target === directoryPattern || target.startsWith(`${directoryPattern}/`);
|
|
4300
4672
|
}
|
|
4301
4673
|
if (pattern.startsWith("**/")) {
|
|
4302
4674
|
const suffix = pattern.slice(3);
|
|
@@ -4305,10 +4677,14 @@ function matchesIgnorePattern(target, pattern) {
|
|
|
4305
4677
|
}
|
|
4306
4678
|
}
|
|
4307
4679
|
if (!hasGlobSyntax(pattern)) {
|
|
4680
|
+
if (anchored || pattern.includes("/")) {
|
|
4681
|
+
return target === pattern || target.startsWith(`${pattern}/`);
|
|
4682
|
+
}
|
|
4308
4683
|
return target === pattern || target.endsWith(`/${pattern}`) || target.startsWith(`${pattern}/`);
|
|
4309
4684
|
}
|
|
4310
4685
|
|
|
4311
|
-
const
|
|
4686
|
+
const prefix = anchored || pattern.includes("/") ? "^" : "(^|/)";
|
|
4687
|
+
const expression = new RegExp(`${prefix}${globPatternRegExpSource(pattern)}$`);
|
|
4312
4688
|
return expression.test(target);
|
|
4313
4689
|
}
|
|
4314
4690
|
|
|
@@ -4417,6 +4793,9 @@ function ruleMetaForRuleId(ruleId) {
|
|
|
4417
4793
|
if (FIXABLE_BUILTIN_RULE_IDS.has(ruleId)) {
|
|
4418
4794
|
meta.fixable = "code";
|
|
4419
4795
|
}
|
|
4796
|
+
if (SUGGESTION_BUILTIN_RULE_IDS.has(ruleId)) {
|
|
4797
|
+
meta.hasSuggestions = true;
|
|
4798
|
+
}
|
|
4420
4799
|
return meta;
|
|
4421
4800
|
}
|
|
4422
4801
|
|
|
@@ -4507,16 +4886,33 @@ function diagnosticToESLintMessage(diagnostic, ruleSeverities) {
|
|
|
4507
4886
|
if (fixes.length > 0) {
|
|
4508
4887
|
message.fix = fixes.length === 1 ? fixes[0] : fixes;
|
|
4509
4888
|
}
|
|
4889
|
+
const suggestions = (diagnostic.suggestions ?? []).map((suggestion) => {
|
|
4890
|
+
const suggestionFixes = (suggestion.fix ?? []).map((fix) => ({
|
|
4891
|
+
range: fix.range,
|
|
4892
|
+
text: fix.text
|
|
4893
|
+
}));
|
|
4894
|
+
return {
|
|
4895
|
+
desc: suggestion.desc,
|
|
4896
|
+
...(suggestionFixes.length === 0 ? {} : {
|
|
4897
|
+
fix: suggestionFixes.length === 1 ? suggestionFixes[0] : suggestionFixes
|
|
4898
|
+
})
|
|
4899
|
+
};
|
|
4900
|
+
});
|
|
4901
|
+
if (suggestions.length > 0) {
|
|
4902
|
+
message.suggestions = suggestions;
|
|
4903
|
+
}
|
|
4510
4904
|
return message;
|
|
4511
4905
|
}
|
|
4512
4906
|
|
|
4513
4907
|
function suppressedDiagnosticToESLintMessage(diagnostic, ruleSeverities) {
|
|
4514
4908
|
return {
|
|
4515
4909
|
...diagnosticToESLintMessage(diagnostic, ruleSeverities),
|
|
4516
|
-
suppressions:
|
|
4517
|
-
|
|
4518
|
-
|
|
4519
|
-
|
|
4910
|
+
suppressions: diagnostic.suppressions?.length > 0
|
|
4911
|
+
? diagnostic.suppressions
|
|
4912
|
+
: [{
|
|
4913
|
+
kind: diagnostic.suppression?.kind ?? "directive",
|
|
4914
|
+
justification: diagnostic.suppression?.justification ?? ""
|
|
4915
|
+
}]
|
|
4520
4916
|
};
|
|
4521
4917
|
}
|
|
4522
4918
|
|