@utoo/lint 0.2.1 → 0.2.3
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 +72 -11
- package/bin/fishlint.js +429 -64
- package/bin/migrate.js +8 -6
- package/index.cjs +298 -143
- package/index.d.ts +5 -1
- package/index.js +298 -143
- package/lib/config-loader.cjs +95 -0
- package/lib/config-loader.js +89 -0
- package/lib/load-config.js +23 -0
- package/package.json +15 -6
- package/schema.json +1 -1
package/index.js
CHANGED
|
@@ -2,10 +2,14 @@ import { spawnSync } from "node:child_process";
|
|
|
2
2
|
import { existsSync, mkdtempSync, readdirSync, readFileSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
3
3
|
import { writeFile as writeFileAsync } from "node:fs/promises";
|
|
4
4
|
import { tmpdir } from "node:os";
|
|
5
|
-
import { dirname, extname, isAbsolute, join, resolve as resolvePath } from "node:path";
|
|
5
|
+
import { dirname, extname, isAbsolute, join, relative, resolve as resolvePath } from "node:path";
|
|
6
6
|
import { fileURLToPath } from "node:url";
|
|
7
7
|
|
|
8
8
|
import { resolveBinary } from "./lib/binary.js";
|
|
9
|
+
import {
|
|
10
|
+
findConfigPath as findConfigPathFromDirectory,
|
|
11
|
+
readConfig
|
|
12
|
+
} from "./lib/config-loader.js";
|
|
9
13
|
|
|
10
14
|
export { platformPackageName, resolveBinary } from "./lib/binary.js";
|
|
11
15
|
|
|
@@ -69,20 +73,6 @@ const FISHLINT_DROP_VALUE_FLAGS = new Set([
|
|
|
69
73
|
"-E",
|
|
70
74
|
"-o"
|
|
71
75
|
]);
|
|
72
|
-
const CONFIG_FILENAMES = ["utoo.json", "utoo-lint.json"];
|
|
73
|
-
const JAVASCRIPT_CONFIG_EXTENSIONS = new Set([".js", ".mjs", ".cjs"]);
|
|
74
|
-
const JAVASCRIPT_CONFIG_LOADER_SCRIPT = `
|
|
75
|
-
import { pathToFileURL } from "node:url";
|
|
76
|
-
|
|
77
|
-
const configPath = process.argv[1];
|
|
78
|
-
const loaded = await import(pathToFileURL(configPath).href);
|
|
79
|
-
const value = loaded.default ?? loaded;
|
|
80
|
-
const json = JSON.stringify(value);
|
|
81
|
-
if (json === undefined) {
|
|
82
|
-
throw new TypeError("config did not export a JSON-serializable value");
|
|
83
|
-
}
|
|
84
|
-
process.stdout.write(json);
|
|
85
|
-
`;
|
|
86
76
|
const BUILTIN_RULE_IDS = [
|
|
87
77
|
"accessor-pairs",
|
|
88
78
|
"array-callback-return",
|
|
@@ -420,6 +410,33 @@ const BUILTIN_RULE_IDS = [
|
|
|
420
410
|
"@typescript-eslint/prefer-namespace-keyword",
|
|
421
411
|
"@typescript-eslint/restrict-plus-operands"
|
|
422
412
|
];
|
|
413
|
+
const NATIVE_ONLY_RULE_IDS = [
|
|
414
|
+
"@alipay/ant/disallow-typos",
|
|
415
|
+
"@alipay/ant/exhaustive-deps",
|
|
416
|
+
"@alipay/ant/jsx-handler-names",
|
|
417
|
+
"@alipay/ant/no-deprecated-dependence",
|
|
418
|
+
"@alipay/ant/no-deprecated-variable",
|
|
419
|
+
"@alipay/ant/no-import-files-from-pages-in-common",
|
|
420
|
+
"@alipay/ant/no-negative-conditionals",
|
|
421
|
+
"@alipay/ant/no-import-src",
|
|
422
|
+
"@alipay/ant/no-phantom-dependencies",
|
|
423
|
+
"@alipay/ant/no-too-large-file",
|
|
424
|
+
"@alipay/ant/prefer-elseif-end-with-else",
|
|
425
|
+
"@alipay/ant/prefer-catch-unsafe-func-call",
|
|
426
|
+
"@alipay/ant/prefer-click-with-debounce",
|
|
427
|
+
"@alipay/ant/prefer-import-as-required",
|
|
428
|
+
"@alipay/ant/no-spread-params",
|
|
429
|
+
"@alipay/ant/prefer-managed-resource",
|
|
430
|
+
"@alipay/ant/prefer-safe-image-renderer",
|
|
431
|
+
"@alipay/ant/prefer-import-from-stdlib",
|
|
432
|
+
"@alipay/spmLint/use-labeled-spm",
|
|
433
|
+
"@alipay/spmLint/valid-manual-click",
|
|
434
|
+
"@alipay/spmLint/valid-manual-expo",
|
|
435
|
+
"@alipay/spmLint/valid-manual-param",
|
|
436
|
+
"@alipay/spmLint/valid-manual-pv",
|
|
437
|
+
"semantic-errors"
|
|
438
|
+
];
|
|
439
|
+
const NATIVE_RULE_IDS = [...BUILTIN_RULE_IDS, ...NATIVE_ONLY_RULE_IDS];
|
|
423
440
|
const FIXABLE_BUILTIN_RULE_IDS = new Set(["no-extra-semi", "@typescript-eslint/no-extra-semi"]);
|
|
424
441
|
const BUILTIN_RULES = new Map(BUILTIN_RULE_IDS.map((ruleId) => [ruleId, createBuiltinRule(ruleId)]));
|
|
425
442
|
|
|
@@ -470,7 +487,7 @@ export class UtooLint {
|
|
|
470
487
|
}
|
|
471
488
|
|
|
472
489
|
async lintFiles(patterns, options = {}) {
|
|
473
|
-
const mergedOptions = mergeLintOptions(this.options, options);
|
|
490
|
+
const mergedOptions = withConfigCache(mergeLintOptions(this.options, options));
|
|
474
491
|
const customRuleConfig = [mergedOptions.baseConfig, mergedOptions.overrideConfig].filter(Boolean);
|
|
475
492
|
const customRuleFilterMap = customRuleMapForConfig(customRuleConfig, new Map());
|
|
476
493
|
const nativeOptions = lintOptionsWithoutCustomRules(mergedOptions, customRuleFilterMap);
|
|
@@ -490,7 +507,7 @@ export class UtooLint {
|
|
|
490
507
|
throw new TypeError("code must be a string");
|
|
491
508
|
}
|
|
492
509
|
|
|
493
|
-
const mergedOptions = mergeLintOptions(this.options, options);
|
|
510
|
+
const mergedOptions = withConfigCache(mergeLintOptions(this.options, options));
|
|
494
511
|
const filePath = normalizeESLintFilePath(textFilePathForOptions(options, "<text>"), mergedOptions.cwd);
|
|
495
512
|
const customRuleConfig = [mergedOptions.baseConfig, mergedOptions.overrideConfig].filter(Boolean);
|
|
496
513
|
const customRuleMap = customRuleMapForConfig(customRuleConfig, new Map(), filePath, mergedOptions.cwd);
|
|
@@ -514,7 +531,7 @@ export class UtooLint {
|
|
|
514
531
|
}
|
|
515
532
|
|
|
516
533
|
async calculateConfigForFile(filePath) {
|
|
517
|
-
return publicCalculatedConfig(eslintConstructorOptions(this.options), filePath);
|
|
534
|
+
return publicCalculatedConfig(withConfigCache(eslintConstructorOptions(this.options)), filePath);
|
|
518
535
|
}
|
|
519
536
|
|
|
520
537
|
async findConfigFile(filePath) {
|
|
@@ -2429,7 +2446,7 @@ export class CLIEngine {
|
|
|
2429
2446
|
}
|
|
2430
2447
|
|
|
2431
2448
|
executeOnFiles(patterns) {
|
|
2432
|
-
const mergedOptions = eslintConstructorOptions(this.options);
|
|
2449
|
+
const mergedOptions = withConfigCache(eslintConstructorOptions(this.options));
|
|
2433
2450
|
const report = lintFiles(patterns, mergedOptions);
|
|
2434
2451
|
throwOnUnmatchedPatternDiagnostics(report, mergedOptions);
|
|
2435
2452
|
const results = maybeFilterQuietResults(reportToESLintResults(report, {
|
|
@@ -2449,10 +2466,10 @@ export class CLIEngine {
|
|
|
2449
2466
|
typeof filePathOrOptions === "object" && filePathOrOptions !== null
|
|
2450
2467
|
? filePathOrOptions.filePath ?? filePathOrOptions.filename ?? "input.js"
|
|
2451
2468
|
: filePathOrOptions;
|
|
2452
|
-
const mergedOptions = {
|
|
2469
|
+
const mergedOptions = withConfigCache({
|
|
2453
2470
|
...eslintConstructorOptions(this.options),
|
|
2454
2471
|
...textOptions
|
|
2455
|
-
};
|
|
2472
|
+
});
|
|
2456
2473
|
const report = lintText(code, {
|
|
2457
2474
|
...mergedOptions,
|
|
2458
2475
|
filePath
|
|
@@ -2489,7 +2506,7 @@ export class CLIEngine {
|
|
|
2489
2506
|
}
|
|
2490
2507
|
|
|
2491
2508
|
getConfigForFile(filePath) {
|
|
2492
|
-
return publicCalculatedConfig(eslintConstructorOptions(this.options), filePath);
|
|
2509
|
+
return publicCalculatedConfig(withConfigCache(eslintConstructorOptions(this.options)), filePath);
|
|
2493
2510
|
}
|
|
2494
2511
|
}
|
|
2495
2512
|
|
|
@@ -2631,26 +2648,42 @@ export function runCli(args = [], options = {}) {
|
|
|
2631
2648
|
return run(parsed.passthroughArgs, options);
|
|
2632
2649
|
}
|
|
2633
2650
|
|
|
2634
|
-
const cliOptions = {
|
|
2651
|
+
const cliOptions = withConfigCache({
|
|
2635
2652
|
...options,
|
|
2636
|
-
...parsed.options
|
|
2637
|
-
|
|
2653
|
+
...parsed.options,
|
|
2654
|
+
extraArgs: parsed.passthroughArgs,
|
|
2655
|
+
preserveNativeDefaults: Boolean(parsed.options.noConfig)
|
|
2656
|
+
});
|
|
2638
2657
|
const targets = parsed.targets.length > 0 ? parsed.targets : defaultLintTargets(cliOptions);
|
|
2639
|
-
const
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
|
|
2658
|
+
const report = lintFiles(targets, cliOptions);
|
|
2659
|
+
report.diagnostics = normalizeReportDiagnostics(report.diagnostics, cliOptions);
|
|
2660
|
+
report.exitCode = exitCodeForDiagnostics(report.diagnostics);
|
|
2661
|
+
const status = report.exitCode ?? exitCodeForDiagnostics(report.diagnostics);
|
|
2662
|
+
if (cliOptions.format === "json" || parsed.passthroughArgs.includes("--json")) {
|
|
2663
|
+
return completedRunResult(status, `${JSON.stringify(publicCliReport(report))}\n`, report.stderr ?? "", options);
|
|
2643
2664
|
}
|
|
2665
|
+
return completedRunResult(status, "", `${report.stderr ?? ""}${formatNativeTextReport(report)}`, options);
|
|
2666
|
+
}
|
|
2644
2667
|
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
|
-
|
|
2668
|
+
function publicCliReport(report) {
|
|
2669
|
+
return {
|
|
2670
|
+
files: report.files ?? 0,
|
|
2671
|
+
filePaths: report.filePaths ?? [],
|
|
2672
|
+
diagnostics: report.diagnostics ?? [],
|
|
2673
|
+
outputs: report.outputs ?? []
|
|
2674
|
+
};
|
|
2675
|
+
}
|
|
2676
|
+
|
|
2677
|
+
function formatNativeTextReport(report) {
|
|
2678
|
+
const lines = [];
|
|
2679
|
+
for (const diagnostic of report.diagnostics ?? []) {
|
|
2680
|
+
const rule = diagnostic.ruleId ? ` [${diagnostic.ruleId}]` : "";
|
|
2681
|
+
lines.push(
|
|
2682
|
+
`${diagnostic.filePath}:${diagnostic.line ?? 0}:${diagnostic.column ?? 0}: ${diagnostic.severity ?? "error"}: ${diagnostic.message}${rule}`
|
|
2683
|
+
);
|
|
2684
|
+
}
|
|
2685
|
+
lines.push(`${report.files ?? 0} file(s) checked, ${(report.diagnostics ?? []).length} diagnostic(s)`);
|
|
2686
|
+
return `${lines.join("\n")}\n`;
|
|
2654
2687
|
}
|
|
2655
2688
|
|
|
2656
2689
|
export function runFishlint(args = [], options = {}) {
|
|
@@ -2866,15 +2899,35 @@ function booleanFlagValue(arg) {
|
|
|
2866
2899
|
}
|
|
2867
2900
|
|
|
2868
2901
|
export function lintFiles(paths, options = {}) {
|
|
2902
|
+
options = withConfigCache(options);
|
|
2869
2903
|
const targets = lintTargetsForInput(paths, options);
|
|
2870
2904
|
const ignoredDiagnostics = ignoredLintPathDiagnostics(targets, options);
|
|
2871
2905
|
const lintPaths = filteredLintPaths(targets, options);
|
|
2872
2906
|
if (lintPaths.length === 0) {
|
|
2873
|
-
return { files: 0, filePaths: [], diagnostics: ignoredDiagnostics, exitCode: ignoredDiagnostics
|
|
2907
|
+
return { files: 0, filePaths: [], diagnostics: ignoredDiagnostics, exitCode: exitCodeForDiagnostics(ignoredDiagnostics) };
|
|
2908
|
+
}
|
|
2909
|
+
|
|
2910
|
+
const configRuns = nativeConfigRunsForFiles(expandNativeConfigRunPaths(lintPaths, options), options);
|
|
2911
|
+
if (configRuns) {
|
|
2912
|
+
const report = mergeNativeReports(
|
|
2913
|
+
configRuns.map(({ paths: runPaths, options: runOptions }) => runNativeLintReport(runPaths, runOptions))
|
|
2914
|
+
);
|
|
2915
|
+
return finalizeLintReport(report, ignoredDiagnostics, options);
|
|
2874
2916
|
}
|
|
2875
2917
|
|
|
2918
|
+
const report = runNativeLintReport(lintPaths, options);
|
|
2919
|
+
return finalizeLintReport(report, ignoredDiagnostics, options);
|
|
2920
|
+
}
|
|
2921
|
+
|
|
2922
|
+
function expandNativeConfigRunPaths(paths, options) {
|
|
2923
|
+
const cwd = options.cwd ?? process.cwd();
|
|
2924
|
+
const patterns = ignoreDisabled(options) ? [] : ignorePatternsForOptions(options, cwd);
|
|
2925
|
+
return paths.flatMap((path) => expandLintTarget(path, cwd, patterns) ?? [path]);
|
|
2926
|
+
}
|
|
2927
|
+
|
|
2928
|
+
function runNativeLintReport(paths, options) {
|
|
2876
2929
|
return withTemporaryConfig(options, (resolvedOptions) => {
|
|
2877
|
-
const cliArgs = buildLintArgs(
|
|
2930
|
+
const cliArgs = buildLintArgs(paths, resolvedOptions);
|
|
2878
2931
|
const result = run(cliArgs, { ...resolvedOptions, stdio: undefined, encoding: "utf8" });
|
|
2879
2932
|
|
|
2880
2933
|
if (result.error) {
|
|
@@ -2897,17 +2950,6 @@ export function lintFiles(paths, options = {}) {
|
|
|
2897
2950
|
}
|
|
2898
2951
|
|
|
2899
2952
|
report.exitCode = status;
|
|
2900
|
-
report.diagnostics = [
|
|
2901
|
-
...(report.diagnostics ?? []),
|
|
2902
|
-
...ignoredDiagnostics
|
|
2903
|
-
];
|
|
2904
|
-
if (!resolvedOptions.deferDiagnosticConfigFiltering) {
|
|
2905
|
-
report.filePaths = normalizeReportFilePaths(report.filePaths, resolvedOptions);
|
|
2906
|
-
report.diagnostics = normalizeDiagnosticFilePaths(report.diagnostics, resolvedOptions);
|
|
2907
|
-
report.outputs = normalizeReportOutputs(report.outputs, resolvedOptions);
|
|
2908
|
-
report.diagnostics = normalizeReportDiagnostics(report.diagnostics, resolvedOptions);
|
|
2909
|
-
report.exitCode = exitCodeForDiagnostics(report.diagnostics);
|
|
2910
|
-
}
|
|
2911
2953
|
if (stderr) {
|
|
2912
2954
|
Object.defineProperty(report, "stderr", {
|
|
2913
2955
|
value: stderr,
|
|
@@ -2919,7 +2961,124 @@ export function lintFiles(paths, options = {}) {
|
|
|
2919
2961
|
});
|
|
2920
2962
|
}
|
|
2921
2963
|
|
|
2964
|
+
function finalizeLintReport(report, ignoredDiagnostics, options) {
|
|
2965
|
+
report.diagnostics = [
|
|
2966
|
+
...(report.diagnostics ?? []),
|
|
2967
|
+
...ignoredDiagnostics
|
|
2968
|
+
];
|
|
2969
|
+
if (!options.deferDiagnosticConfigFiltering) {
|
|
2970
|
+
report.filePaths = normalizeReportFilePaths(report.filePaths, options);
|
|
2971
|
+
report.diagnostics = normalizeDiagnosticFilePaths(report.diagnostics, options);
|
|
2972
|
+
report.outputs = normalizeReportOutputs(report.outputs, options);
|
|
2973
|
+
report.diagnostics = normalizeReportDiagnostics(report.diagnostics, options);
|
|
2974
|
+
report.exitCode = exitCodeForDiagnostics(report.diagnostics);
|
|
2975
|
+
}
|
|
2976
|
+
return report;
|
|
2977
|
+
}
|
|
2978
|
+
|
|
2979
|
+
function nativeConfigRunsForFiles(paths, options) {
|
|
2980
|
+
if (options.noConfig && !options.baseConfig && !options.overrideConfig) {
|
|
2981
|
+
return undefined;
|
|
2982
|
+
}
|
|
2983
|
+
|
|
2984
|
+
const groups = new Map();
|
|
2985
|
+
let hasConfigSource = Boolean(options.baseConfig || options.overrideConfig);
|
|
2986
|
+
for (const filePath of paths) {
|
|
2987
|
+
const matchPath = paths.length === 1
|
|
2988
|
+
? options.filePath ?? options.filename ?? filePath
|
|
2989
|
+
: filePath;
|
|
2990
|
+
const fileConfigPath = options.noConfig ? undefined : configPathForFile(options, matchPath);
|
|
2991
|
+
const configured = Boolean(options.baseConfig || options.overrideConfig || fileConfigPath);
|
|
2992
|
+
hasConfigSource ||= configured;
|
|
2993
|
+
let rules = configured ? calculatedConfig({ ...options, rules: undefined }, matchPath).rules : undefined;
|
|
2994
|
+
if (configured && options.rules) {
|
|
2995
|
+
rules = selectedRulesWithConfigOptions(rules, options.rules);
|
|
2996
|
+
}
|
|
2997
|
+
const signature = configured ? stableConfigSignature(rules) : "<native-defaults>";
|
|
2998
|
+
if (!groups.has(signature)) {
|
|
2999
|
+
groups.set(signature, { paths: [], rules, configured });
|
|
3000
|
+
}
|
|
3001
|
+
groups.get(signature).paths.push(filePath);
|
|
3002
|
+
}
|
|
3003
|
+
|
|
3004
|
+
if (!hasConfigSource) {
|
|
3005
|
+
return undefined;
|
|
3006
|
+
}
|
|
3007
|
+
|
|
3008
|
+
return [...groups.values()].map((group) => {
|
|
3009
|
+
if (!group.configured) {
|
|
3010
|
+
return {
|
|
3011
|
+
paths: group.paths,
|
|
3012
|
+
options: {
|
|
3013
|
+
...options,
|
|
3014
|
+
config: undefined,
|
|
3015
|
+
noConfig: true,
|
|
3016
|
+
baseConfig: undefined,
|
|
3017
|
+
overrideConfig: undefined
|
|
3018
|
+
}
|
|
3019
|
+
};
|
|
3020
|
+
}
|
|
3021
|
+
|
|
3022
|
+
return {
|
|
3023
|
+
paths: group.paths,
|
|
3024
|
+
options: {
|
|
3025
|
+
...options,
|
|
3026
|
+
config: undefined,
|
|
3027
|
+
noConfig: true,
|
|
3028
|
+
baseConfig: undefined,
|
|
3029
|
+
overrideConfig: { rules: allDisabledNativeRules(group.rules) },
|
|
3030
|
+
forceMaterializedConfig: true
|
|
3031
|
+
}
|
|
3032
|
+
};
|
|
3033
|
+
});
|
|
3034
|
+
}
|
|
3035
|
+
|
|
3036
|
+
function allDisabledNativeRules(rules) {
|
|
3037
|
+
return {
|
|
3038
|
+
...Object.fromEntries(NATIVE_RULE_IDS.map((rule) => [rule, "off"])),
|
|
3039
|
+
...rules
|
|
3040
|
+
};
|
|
3041
|
+
}
|
|
3042
|
+
|
|
3043
|
+
function selectedRulesWithConfigOptions(configRules, selectedRules) {
|
|
3044
|
+
const selected = rulesFromNativeRuleList(selectedRules);
|
|
3045
|
+
return Object.fromEntries(
|
|
3046
|
+
Object.keys(selected).map((rule) => [
|
|
3047
|
+
rule,
|
|
3048
|
+
configRules?.[rule] != null && ruleConfigSeverity(configRules[rule]) > 0
|
|
3049
|
+
? configRules[rule]
|
|
3050
|
+
: selected[rule]
|
|
3051
|
+
])
|
|
3052
|
+
);
|
|
3053
|
+
}
|
|
3054
|
+
|
|
3055
|
+
function stableConfigSignature(value) {
|
|
3056
|
+
if (Array.isArray(value)) {
|
|
3057
|
+
return `[${value.map((item) => stableConfigSignature(item)).join(",")}]`;
|
|
3058
|
+
}
|
|
3059
|
+
if (value && typeof value === "object") {
|
|
3060
|
+
return `{${Object.keys(value).sort().map((key) => `${JSON.stringify(key)}:${stableConfigSignature(value[key])}`).join(",")}}`;
|
|
3061
|
+
}
|
|
3062
|
+
return JSON.stringify(value);
|
|
3063
|
+
}
|
|
3064
|
+
|
|
3065
|
+
function mergeNativeReports(reports) {
|
|
3066
|
+
const report = {
|
|
3067
|
+
files: reports.reduce((count, item) => count + (item.files ?? 0), 0),
|
|
3068
|
+
filePaths: reports.flatMap((item) => item.filePaths ?? []),
|
|
3069
|
+
diagnostics: reports.flatMap((item) => item.diagnostics ?? []),
|
|
3070
|
+
outputs: reports.flatMap((item) => item.outputs ?? []),
|
|
3071
|
+
exitCode: reports.some((item) => item.exitCode) ? 1 : 0
|
|
3072
|
+
};
|
|
3073
|
+
const stderr = reports.map((item) => item.stderr ?? "").join("");
|
|
3074
|
+
if (stderr) {
|
|
3075
|
+
Object.defineProperty(report, "stderr", { value: stderr, enumerable: false });
|
|
3076
|
+
}
|
|
3077
|
+
return report;
|
|
3078
|
+
}
|
|
3079
|
+
|
|
2922
3080
|
export function lintText(code, options = {}) {
|
|
3081
|
+
options = withConfigCache(options);
|
|
2923
3082
|
if (typeof code !== "string") {
|
|
2924
3083
|
throw new TypeError("code must be a string");
|
|
2925
3084
|
}
|
|
@@ -2940,7 +3099,7 @@ export function lintText(code, options = {}) {
|
|
|
2940
3099
|
files: 0,
|
|
2941
3100
|
filePaths: [],
|
|
2942
3101
|
diagnostics,
|
|
2943
|
-
exitCode: diagnostics
|
|
3102
|
+
exitCode: exitCodeForDiagnostics(diagnostics)
|
|
2944
3103
|
};
|
|
2945
3104
|
}
|
|
2946
3105
|
|
|
@@ -2977,22 +3136,28 @@ function buildLintArgs(paths, options) {
|
|
|
2977
3136
|
});
|
|
2978
3137
|
}
|
|
2979
3138
|
|
|
2980
|
-
function buildRunCliArgs(paths, options, passthroughArgs) {
|
|
2981
|
-
return buildNativeLintArgs(paths, {
|
|
2982
|
-
...options,
|
|
2983
|
-
extraArgs: passthroughArgs
|
|
2984
|
-
});
|
|
2985
|
-
}
|
|
2986
|
-
|
|
2987
3139
|
function buildNativeLintArgs(paths, options) {
|
|
2988
3140
|
const cliArgs = [];
|
|
2989
3141
|
|
|
2990
|
-
if (options.config) {
|
|
2991
|
-
cliArgs.push(`--config=${options.config}`);
|
|
2992
|
-
}
|
|
2993
3142
|
if (options.noConfig) {
|
|
2994
3143
|
cliArgs.push("--no-config");
|
|
2995
3144
|
}
|
|
3145
|
+
if (!options.rules && !options.forceMaterializedConfig && (options.config || options.baseConfig || options.overrideConfig)) {
|
|
3146
|
+
const configForRuleSelection = options.noConfig
|
|
3147
|
+
? undefined
|
|
3148
|
+
: options.config ? readConfig(options.config, options.cwd, options.configCache) : undefined;
|
|
3149
|
+
const enabledRules = enabledRuleNamesFromConfigs(
|
|
3150
|
+
configForRuleSelection,
|
|
3151
|
+
options.baseConfig,
|
|
3152
|
+
options.overrideConfig
|
|
3153
|
+
);
|
|
3154
|
+
if (enabledRules.length > 0) {
|
|
3155
|
+
cliArgs.push(`--rules=${enabledRules.join(",")}`);
|
|
3156
|
+
}
|
|
3157
|
+
}
|
|
3158
|
+
if (options.config) {
|
|
3159
|
+
cliArgs.push(`--config=${options.config}`);
|
|
3160
|
+
}
|
|
2996
3161
|
if (options.rules) {
|
|
2997
3162
|
const rules = Array.isArray(options.rules) ? options.rules.join(",") : options.rules;
|
|
2998
3163
|
if (rules) {
|
|
@@ -3026,6 +3191,12 @@ function mergeLintOptions(base, override) {
|
|
|
3026
3191
|
};
|
|
3027
3192
|
}
|
|
3028
3193
|
|
|
3194
|
+
function withConfigCache(options) {
|
|
3195
|
+
// Executable configs are otherwise re-evaluated at every per-file lookup.
|
|
3196
|
+
// Keep the cache on the options object so one public invocation shares it.
|
|
3197
|
+
return options.configCache ? options : { ...options, configCache: new Map() };
|
|
3198
|
+
}
|
|
3199
|
+
|
|
3029
3200
|
function eslintConstructorOptions(options) {
|
|
3030
3201
|
const mapped = {
|
|
3031
3202
|
cwd: options.cwd,
|
|
@@ -3078,10 +3249,10 @@ function calculatedConfig(options = {}, filePath) {
|
|
|
3078
3249
|
return {
|
|
3079
3250
|
...configData,
|
|
3080
3251
|
rules: {
|
|
3081
|
-
...rulesFromNativeRuleList(options.rules),
|
|
3082
3252
|
...rulesFromConfig(options.baseConfig, filePath, options.cwd),
|
|
3083
3253
|
...rulesFromFileConfig(options, filePath),
|
|
3084
|
-
...rulesFromConfig(options.overrideConfig, filePath, options.cwd)
|
|
3254
|
+
...rulesFromConfig(options.overrideConfig, filePath, options.cwd),
|
|
3255
|
+
...rulesFromNativeRuleList(options.rules)
|
|
3085
3256
|
}
|
|
3086
3257
|
};
|
|
3087
3258
|
}
|
|
@@ -3198,8 +3369,8 @@ function rulesFromFileConfig(options, filePath) {
|
|
|
3198
3369
|
return {};
|
|
3199
3370
|
}
|
|
3200
3371
|
|
|
3201
|
-
const config = readConfig(configPath, options.cwd);
|
|
3202
|
-
return rulesFromConfig(config, filePath,
|
|
3372
|
+
const config = readConfig(configPath, options.cwd, options.configCache);
|
|
3373
|
+
return rulesFromConfig(config, filePath, dirname(configPath));
|
|
3203
3374
|
}
|
|
3204
3375
|
|
|
3205
3376
|
function configDataFromFileConfig(options, filePath) {
|
|
@@ -3212,8 +3383,8 @@ function configDataFromFileConfig(options, filePath) {
|
|
|
3212
3383
|
return {};
|
|
3213
3384
|
}
|
|
3214
3385
|
|
|
3215
|
-
const config = readConfig(configPath, options.cwd);
|
|
3216
|
-
return configDataFromConfig(config, filePath,
|
|
3386
|
+
const config = readConfig(configPath, options.cwd, options.configCache);
|
|
3387
|
+
return configDataFromConfig(config, filePath, dirname(configPath));
|
|
3217
3388
|
}
|
|
3218
3389
|
|
|
3219
3390
|
function lintTargetsForInput(paths, options = {}) {
|
|
@@ -3233,8 +3404,17 @@ function defaultLintTargets(options = {}) {
|
|
|
3233
3404
|
return ["."];
|
|
3234
3405
|
}
|
|
3235
3406
|
|
|
3236
|
-
const targets = filePatternsFromConfig(readConfig(configPath, options.cwd));
|
|
3237
|
-
return targets.length > 0
|
|
3407
|
+
const targets = filePatternsFromConfig(readConfig(configPath, options.cwd, options.configCache));
|
|
3408
|
+
return targets.length > 0
|
|
3409
|
+
? targets.map((target) => resolveConfigPattern(target, dirname(configPath)))
|
|
3410
|
+
: ["."];
|
|
3411
|
+
}
|
|
3412
|
+
|
|
3413
|
+
function resolveConfigPattern(pattern, configDirectory) {
|
|
3414
|
+
if (isAbsolute(pattern)) {
|
|
3415
|
+
return pattern;
|
|
3416
|
+
}
|
|
3417
|
+
return resolvePath(configDirectory, pattern.replace(/^[/\\]/, ""));
|
|
3238
3418
|
}
|
|
3239
3419
|
|
|
3240
3420
|
function filePatternsFromConfig(config) {
|
|
@@ -3288,6 +3468,9 @@ function configPathForOptions(options) {
|
|
|
3288
3468
|
}
|
|
3289
3469
|
|
|
3290
3470
|
function configPathForFile(options, filePath) {
|
|
3471
|
+
if (options.noConfig) {
|
|
3472
|
+
return undefined;
|
|
3473
|
+
}
|
|
3291
3474
|
if (options.config) {
|
|
3292
3475
|
return resolvePath(options.cwd ?? process.cwd(), options.config);
|
|
3293
3476
|
}
|
|
@@ -3307,66 +3490,20 @@ function configSearchDirectoryForFile(filePath, cwd) {
|
|
|
3307
3490
|
}
|
|
3308
3491
|
|
|
3309
3492
|
function configPathFromDirectory(directory) {
|
|
3310
|
-
|
|
3311
|
-
while (true) {
|
|
3312
|
-
for (const candidate of CONFIG_FILENAMES) {
|
|
3313
|
-
const path = resolvePath(current, candidate);
|
|
3314
|
-
if (existsSync(path)) {
|
|
3315
|
-
return path;
|
|
3316
|
-
}
|
|
3317
|
-
}
|
|
3318
|
-
const parent = dirname(current);
|
|
3319
|
-
if (parent === current) {
|
|
3320
|
-
return undefined;
|
|
3321
|
-
}
|
|
3322
|
-
current = parent;
|
|
3323
|
-
}
|
|
3324
|
-
}
|
|
3325
|
-
|
|
3326
|
-
function readConfig(path, cwd) {
|
|
3327
|
-
if (isJavaScriptConfigPath(path)) {
|
|
3328
|
-
return readJavaScriptConfig(path, cwd);
|
|
3329
|
-
}
|
|
3330
|
-
|
|
3331
|
-
try {
|
|
3332
|
-
return JSON.parse(readFileSync(path, "utf8"));
|
|
3333
|
-
} catch (error) {
|
|
3334
|
-
throw new Error(`utoo-lint unable to read config ${path}: ${error.message}`);
|
|
3335
|
-
}
|
|
3336
|
-
}
|
|
3337
|
-
|
|
3338
|
-
function readJavaScriptConfig(path, cwd) {
|
|
3339
|
-
const result = spawnSync(process.execPath, ["--input-type=module", "--eval", JAVASCRIPT_CONFIG_LOADER_SCRIPT, path], {
|
|
3340
|
-
cwd: cwd ?? process.cwd(),
|
|
3341
|
-
encoding: "utf8"
|
|
3342
|
-
});
|
|
3343
|
-
if (result.error) {
|
|
3344
|
-
throw result.error;
|
|
3345
|
-
}
|
|
3346
|
-
if (result.status !== 0) {
|
|
3347
|
-
throw new Error(`utoo-lint unable to read config ${path}: ${(result.stderr ?? "").trim() || "JavaScript config loader failed"}`);
|
|
3348
|
-
}
|
|
3349
|
-
try {
|
|
3350
|
-
return JSON.parse(result.stdout);
|
|
3351
|
-
} catch (error) {
|
|
3352
|
-
throw new Error(`utoo-lint unable to read config ${path}: ${error.message}`);
|
|
3353
|
-
}
|
|
3354
|
-
}
|
|
3355
|
-
|
|
3356
|
-
function isJavaScriptConfigPath(path) {
|
|
3357
|
-
return JAVASCRIPT_CONFIG_EXTENSIONS.has(extname(path));
|
|
3493
|
+
return findConfigPathFromDirectory(directory);
|
|
3358
3494
|
}
|
|
3359
3495
|
|
|
3360
3496
|
function withTemporaryConfig(options, callback) {
|
|
3361
3497
|
const fileConfigPath = !options.noConfig ? configPathForOptions(options) : undefined;
|
|
3362
|
-
const shouldMaterializeFileConfig =
|
|
3363
|
-
const fileConfig = shouldMaterializeFileConfig
|
|
3364
|
-
|
|
3365
|
-
|
|
3366
|
-
|
|
3367
|
-
|
|
3368
|
-
|
|
3369
|
-
|
|
3498
|
+
const shouldMaterializeFileConfig = Boolean(fileConfigPath);
|
|
3499
|
+
const fileConfig = shouldMaterializeFileConfig
|
|
3500
|
+
? readConfig(fileConfigPath, options.cwd, options.configCache)
|
|
3501
|
+
: undefined;
|
|
3502
|
+
const configs = [options.baseConfig, fileConfig, options.overrideConfig];
|
|
3503
|
+
const rules = shouldMaterializeFileConfig
|
|
3504
|
+
? materializedRulesFromConfigs(...configs)
|
|
3505
|
+
: runtimeRulesFromConfigs(...configs);
|
|
3506
|
+
if (Object.keys(rules).length === 0) {
|
|
3370
3507
|
if (shouldMaterializeFileConfig) {
|
|
3371
3508
|
return callback({
|
|
3372
3509
|
...options,
|
|
@@ -3376,10 +3513,9 @@ function withTemporaryConfig(options, callback) {
|
|
|
3376
3513
|
}
|
|
3377
3514
|
return callback(options);
|
|
3378
3515
|
}
|
|
3379
|
-
|
|
3380
|
-
const
|
|
3381
|
-
|
|
3382
|
-
if (!hasRuleOptions(rules)) {
|
|
3516
|
+
const enabledRules = enabledRuleNamesFromConfigs(...configs);
|
|
3517
|
+
const hasExplicitOffRules = Object.values(rules).some((value) => ruleConfigSeverity(value) === 0);
|
|
3518
|
+
if (!shouldMaterializeFileConfig && !hasRuleOptions(rules) && !hasExplicitOffRules && !options.forceMaterializedConfig) {
|
|
3383
3519
|
return callback({
|
|
3384
3520
|
...options,
|
|
3385
3521
|
config: shouldMaterializeFileConfig ? undefined : options.config,
|
|
@@ -3389,13 +3525,14 @@ function withTemporaryConfig(options, callback) {
|
|
|
3389
3525
|
}
|
|
3390
3526
|
|
|
3391
3527
|
const tmp = mkdtempSync(join(tmpdir(), "utoo-lint-config-"));
|
|
3392
|
-
const configPath = join(tmp, "
|
|
3528
|
+
const configPath = join(tmp, "utlint.config.json");
|
|
3393
3529
|
try {
|
|
3394
3530
|
writeFileSync(configPath, JSON.stringify({ rules }));
|
|
3395
3531
|
return callback({
|
|
3396
3532
|
...options,
|
|
3397
3533
|
config: shouldMaterializeFileConfig ? configPath : options.config ?? configPath,
|
|
3398
|
-
noConfig: false
|
|
3534
|
+
noConfig: false,
|
|
3535
|
+
rules: options.forceMaterializedConfig ? undefined : options.rules
|
|
3399
3536
|
});
|
|
3400
3537
|
} finally {
|
|
3401
3538
|
rmSync(tmp, { recursive: true, force: true });
|
|
@@ -3416,6 +3553,10 @@ function runtimeRulesFromConfigs(...configs) {
|
|
|
3416
3553
|
return rules;
|
|
3417
3554
|
}
|
|
3418
3555
|
|
|
3556
|
+
function materializedRulesFromConfigs(...configs) {
|
|
3557
|
+
return runtimeRulesFromConfigs(...configs);
|
|
3558
|
+
}
|
|
3559
|
+
|
|
3419
3560
|
function runtimeRulesFromConfig(config) {
|
|
3420
3561
|
if (!config) {
|
|
3421
3562
|
return {};
|
|
@@ -3429,9 +3570,7 @@ function runtimeRulesFromConfig(config) {
|
|
|
3429
3570
|
|
|
3430
3571
|
const rules = {};
|
|
3431
3572
|
for (const [rule, value] of Object.entries(rulesFromConfig(config))) {
|
|
3432
|
-
|
|
3433
|
-
rules[rule] = value;
|
|
3434
|
-
}
|
|
3573
|
+
rules[rule] = value;
|
|
3435
3574
|
}
|
|
3436
3575
|
return rules;
|
|
3437
3576
|
}
|
|
@@ -3512,19 +3651,19 @@ function reportToESLintResults(report, textOptions = {}) {
|
|
|
3512
3651
|
}
|
|
3513
3652
|
|
|
3514
3653
|
function normalizeReportDiagnostics(diagnostics, options = {}) {
|
|
3515
|
-
const filterUnconfiguredRules = hasRuleConfigSource(options);
|
|
3516
3654
|
return (diagnostics ?? []).flatMap((diagnostic) => {
|
|
3517
3655
|
if (!diagnostic?.ruleId) {
|
|
3518
3656
|
return [diagnostic];
|
|
3519
3657
|
}
|
|
3520
|
-
if (diagnostic.ruleId === "io") {
|
|
3658
|
+
if (diagnostic.ruleId === "io" || diagnostic.ruleId === "parse") {
|
|
3521
3659
|
return [diagnostic];
|
|
3522
3660
|
}
|
|
3523
3661
|
|
|
3524
3662
|
const filePath = normalizeESLintFilePath(diagnostic.filePath, options.cwd);
|
|
3663
|
+
const filterUnconfiguredRules = hasRuleConfigSource(options, filePath);
|
|
3525
3664
|
const ruleSeverities = ruleSeverityMapForOptions(options, filePath);
|
|
3526
3665
|
const severity = ruleSeverities?.get(diagnostic.ruleId);
|
|
3527
|
-
if (filterUnconfiguredRules && !ruleSeverities?.has(diagnostic.ruleId)) {
|
|
3666
|
+
if (!options.preserveNativeDefaults && filterUnconfiguredRules && !ruleSeverities?.has(diagnostic.ruleId)) {
|
|
3528
3667
|
return [];
|
|
3529
3668
|
}
|
|
3530
3669
|
if (severity === 0) {
|
|
@@ -3555,15 +3694,17 @@ function normalizeDiagnosticFilePaths(diagnostics, options = {}) {
|
|
|
3555
3694
|
}));
|
|
3556
3695
|
}
|
|
3557
3696
|
|
|
3558
|
-
function hasRuleConfigSource(options = {}) {
|
|
3559
|
-
if (options.
|
|
3697
|
+
function hasRuleConfigSource(options = {}, filePath) {
|
|
3698
|
+
if (options.baseConfig || options.overrideConfig || options.rules) {
|
|
3560
3699
|
return true;
|
|
3561
3700
|
}
|
|
3562
|
-
return !options.noConfig && Boolean(
|
|
3701
|
+
return !options.noConfig && Boolean(
|
|
3702
|
+
filePath ? configPathForFile(options, filePath) : configPathForOptions(options)
|
|
3703
|
+
);
|
|
3563
3704
|
}
|
|
3564
3705
|
|
|
3565
3706
|
function exitCodeForDiagnostics(diagnostics) {
|
|
3566
|
-
return
|
|
3707
|
+
return diagnostics?.some((diagnostic) => diagnostic?.severity === "error" || diagnostic?.severity === 2) ? 1 : 0;
|
|
3567
3708
|
}
|
|
3568
3709
|
|
|
3569
3710
|
function throwOnUnmatchedPatternDiagnostics(report, options = {}) {
|
|
@@ -3883,7 +4024,21 @@ function ignorePatternsFromFileConfig(options, filePath) {
|
|
|
3883
4024
|
return [];
|
|
3884
4025
|
}
|
|
3885
4026
|
|
|
3886
|
-
|
|
4027
|
+
const cwd = options.cwd ?? process.cwd();
|
|
4028
|
+
return ignorePatternsFromConfig(readConfig(configPath, options.cwd, options.configCache)).map((pattern) =>
|
|
4029
|
+
rebaseConfigPattern(pattern, dirname(configPath), cwd)
|
|
4030
|
+
);
|
|
4031
|
+
}
|
|
4032
|
+
|
|
4033
|
+
function rebaseConfigPattern(pattern, configDirectory, cwd) {
|
|
4034
|
+
const negated = pattern.startsWith("!");
|
|
4035
|
+
const value = negated ? pattern.slice(1) : pattern;
|
|
4036
|
+
const absolute = resolveConfigPattern(value, configDirectory);
|
|
4037
|
+
const relativePattern = normalizePath(relative(resolvePath(cwd), absolute));
|
|
4038
|
+
const rebased = relativePattern === ".." || relativePattern.startsWith("../")
|
|
4039
|
+
? normalizePath(absolute)
|
|
4040
|
+
: relativePattern;
|
|
4041
|
+
return negated ? `!${rebased}` : rebased;
|
|
3887
4042
|
}
|
|
3888
4043
|
|
|
3889
4044
|
function ignorePatternsFromConfig(config) {
|