@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.cjs
CHANGED
|
@@ -2,9 +2,13 @@ const { spawnSync } = require("node:child_process");
|
|
|
2
2
|
const { existsSync, mkdtempSync, readdirSync, readFileSync, rmSync, statSync, writeFileSync } = require("node:fs");
|
|
3
3
|
const { writeFile: writeFileAsync } = require("node:fs/promises");
|
|
4
4
|
const { tmpdir } = require("node:os");
|
|
5
|
-
const { dirname, extname, isAbsolute, join, resolve: resolvePath } = require("node:path");
|
|
5
|
+
const { dirname, extname, isAbsolute, join, relative, resolve: resolvePath } = require("node:path");
|
|
6
6
|
|
|
7
7
|
const { platformPackageName, resolveBinary } = require("./lib/binary.cjs");
|
|
8
|
+
const {
|
|
9
|
+
findConfigPath: findConfigPathFromDirectory,
|
|
10
|
+
readConfig
|
|
11
|
+
} = require("./lib/config-loader.cjs");
|
|
8
12
|
|
|
9
13
|
const version = JSON.parse(readFileSync(join(__dirname, "package.json"), "utf8")).version;
|
|
10
14
|
|
|
@@ -66,20 +70,6 @@ const FISHLINT_DROP_VALUE_FLAGS = new Set([
|
|
|
66
70
|
"-E",
|
|
67
71
|
"-o"
|
|
68
72
|
]);
|
|
69
|
-
const CONFIG_FILENAMES = ["utoo.json", "utoo-lint.json"];
|
|
70
|
-
const JAVASCRIPT_CONFIG_EXTENSIONS = new Set([".js", ".mjs", ".cjs"]);
|
|
71
|
-
const JAVASCRIPT_CONFIG_LOADER_SCRIPT = `
|
|
72
|
-
import { pathToFileURL } from "node:url";
|
|
73
|
-
|
|
74
|
-
const configPath = process.argv[1];
|
|
75
|
-
const loaded = await import(pathToFileURL(configPath).href);
|
|
76
|
-
const value = loaded.default ?? loaded;
|
|
77
|
-
const json = JSON.stringify(value);
|
|
78
|
-
if (json === undefined) {
|
|
79
|
-
throw new TypeError("config did not export a JSON-serializable value");
|
|
80
|
-
}
|
|
81
|
-
process.stdout.write(json);
|
|
82
|
-
`;
|
|
83
73
|
const BUILTIN_RULE_IDS = [
|
|
84
74
|
"accessor-pairs",
|
|
85
75
|
"array-callback-return",
|
|
@@ -417,6 +407,33 @@ const BUILTIN_RULE_IDS = [
|
|
|
417
407
|
"@typescript-eslint/prefer-namespace-keyword",
|
|
418
408
|
"@typescript-eslint/restrict-plus-operands"
|
|
419
409
|
];
|
|
410
|
+
const NATIVE_ONLY_RULE_IDS = [
|
|
411
|
+
"@alipay/ant/disallow-typos",
|
|
412
|
+
"@alipay/ant/exhaustive-deps",
|
|
413
|
+
"@alipay/ant/jsx-handler-names",
|
|
414
|
+
"@alipay/ant/no-deprecated-dependence",
|
|
415
|
+
"@alipay/ant/no-deprecated-variable",
|
|
416
|
+
"@alipay/ant/no-import-files-from-pages-in-common",
|
|
417
|
+
"@alipay/ant/no-negative-conditionals",
|
|
418
|
+
"@alipay/ant/no-import-src",
|
|
419
|
+
"@alipay/ant/no-phantom-dependencies",
|
|
420
|
+
"@alipay/ant/no-too-large-file",
|
|
421
|
+
"@alipay/ant/prefer-elseif-end-with-else",
|
|
422
|
+
"@alipay/ant/prefer-catch-unsafe-func-call",
|
|
423
|
+
"@alipay/ant/prefer-click-with-debounce",
|
|
424
|
+
"@alipay/ant/prefer-import-as-required",
|
|
425
|
+
"@alipay/ant/no-spread-params",
|
|
426
|
+
"@alipay/ant/prefer-managed-resource",
|
|
427
|
+
"@alipay/ant/prefer-safe-image-renderer",
|
|
428
|
+
"@alipay/ant/prefer-import-from-stdlib",
|
|
429
|
+
"@alipay/spmLint/use-labeled-spm",
|
|
430
|
+
"@alipay/spmLint/valid-manual-click",
|
|
431
|
+
"@alipay/spmLint/valid-manual-expo",
|
|
432
|
+
"@alipay/spmLint/valid-manual-param",
|
|
433
|
+
"@alipay/spmLint/valid-manual-pv",
|
|
434
|
+
"semantic-errors"
|
|
435
|
+
];
|
|
436
|
+
const NATIVE_RULE_IDS = [...BUILTIN_RULE_IDS, ...NATIVE_ONLY_RULE_IDS];
|
|
420
437
|
const FIXABLE_BUILTIN_RULE_IDS = new Set(["no-extra-semi", "@typescript-eslint/no-extra-semi"]);
|
|
421
438
|
const BUILTIN_RULES = new Map(BUILTIN_RULE_IDS.map((ruleId) => [ruleId, createBuiltinRule(ruleId)]));
|
|
422
439
|
|
|
@@ -467,7 +484,7 @@ class UtooLint {
|
|
|
467
484
|
}
|
|
468
485
|
|
|
469
486
|
async lintFiles(patterns, options = {}) {
|
|
470
|
-
const mergedOptions = mergeLintOptions(this.options, options);
|
|
487
|
+
const mergedOptions = withConfigCache(mergeLintOptions(this.options, options));
|
|
471
488
|
const customRuleConfig = [mergedOptions.baseConfig, mergedOptions.overrideConfig].filter(Boolean);
|
|
472
489
|
const customRuleFilterMap = customRuleMapForConfig(customRuleConfig, new Map());
|
|
473
490
|
const nativeOptions = lintOptionsWithoutCustomRules(mergedOptions, customRuleFilterMap);
|
|
@@ -487,7 +504,7 @@ class UtooLint {
|
|
|
487
504
|
throw new TypeError("code must be a string");
|
|
488
505
|
}
|
|
489
506
|
|
|
490
|
-
const mergedOptions = mergeLintOptions(this.options, options);
|
|
507
|
+
const mergedOptions = withConfigCache(mergeLintOptions(this.options, options));
|
|
491
508
|
const filePath = normalizeESLintFilePath(textFilePathForOptions(options, "<text>"), mergedOptions.cwd);
|
|
492
509
|
const customRuleConfig = [mergedOptions.baseConfig, mergedOptions.overrideConfig].filter(Boolean);
|
|
493
510
|
const customRuleMap = customRuleMapForConfig(customRuleConfig, new Map(), filePath, mergedOptions.cwd);
|
|
@@ -511,7 +528,7 @@ class UtooLint {
|
|
|
511
528
|
}
|
|
512
529
|
|
|
513
530
|
async calculateConfigForFile(filePath) {
|
|
514
|
-
return publicCalculatedConfig(eslintConstructorOptions(this.options), filePath);
|
|
531
|
+
return publicCalculatedConfig(withConfigCache(eslintConstructorOptions(this.options)), filePath);
|
|
515
532
|
}
|
|
516
533
|
|
|
517
534
|
async findConfigFile(filePath) {
|
|
@@ -593,7 +610,7 @@ class CLIEngine {
|
|
|
593
610
|
}
|
|
594
611
|
|
|
595
612
|
executeOnFiles(patterns) {
|
|
596
|
-
const mergedOptions = eslintConstructorOptions(this.options);
|
|
613
|
+
const mergedOptions = withConfigCache(eslintConstructorOptions(this.options));
|
|
597
614
|
const report = lintFiles(patterns, mergedOptions);
|
|
598
615
|
throwOnUnmatchedPatternDiagnostics(report, mergedOptions);
|
|
599
616
|
const results = maybeFilterQuietResults(reportToESLintResults(report, {
|
|
@@ -613,10 +630,10 @@ class CLIEngine {
|
|
|
613
630
|
typeof filePathOrOptions === "object" && filePathOrOptions !== null
|
|
614
631
|
? filePathOrOptions.filePath ?? filePathOrOptions.filename ?? "input.js"
|
|
615
632
|
: filePathOrOptions;
|
|
616
|
-
const mergedOptions = {
|
|
633
|
+
const mergedOptions = withConfigCache({
|
|
617
634
|
...eslintConstructorOptions(this.options),
|
|
618
635
|
...textOptions
|
|
619
|
-
};
|
|
636
|
+
});
|
|
620
637
|
const report = lintText(code, {
|
|
621
638
|
...mergedOptions,
|
|
622
639
|
filePath
|
|
@@ -653,7 +670,7 @@ class CLIEngine {
|
|
|
653
670
|
}
|
|
654
671
|
|
|
655
672
|
getConfigForFile(filePath) {
|
|
656
|
-
return publicCalculatedConfig(eslintConstructorOptions(this.options), filePath);
|
|
673
|
+
return publicCalculatedConfig(withConfigCache(eslintConstructorOptions(this.options)), filePath);
|
|
657
674
|
}
|
|
658
675
|
}
|
|
659
676
|
|
|
@@ -795,26 +812,42 @@ function runCli(args = [], options = {}) {
|
|
|
795
812
|
return run(parsed.passthroughArgs, options);
|
|
796
813
|
}
|
|
797
814
|
|
|
798
|
-
const cliOptions = {
|
|
815
|
+
const cliOptions = withConfigCache({
|
|
799
816
|
...options,
|
|
800
|
-
...parsed.options
|
|
801
|
-
|
|
817
|
+
...parsed.options,
|
|
818
|
+
extraArgs: parsed.passthroughArgs,
|
|
819
|
+
preserveNativeDefaults: Boolean(parsed.options.noConfig)
|
|
820
|
+
});
|
|
802
821
|
const targets = parsed.targets.length > 0 ? parsed.targets : defaultLintTargets(cliOptions);
|
|
803
|
-
const
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
822
|
+
const report = lintFiles(targets, cliOptions);
|
|
823
|
+
report.diagnostics = normalizeReportDiagnostics(report.diagnostics, cliOptions);
|
|
824
|
+
report.exitCode = exitCodeForDiagnostics(report.diagnostics);
|
|
825
|
+
const status = report.exitCode ?? exitCodeForDiagnostics(report.diagnostics);
|
|
826
|
+
if (cliOptions.format === "json" || parsed.passthroughArgs.includes("--json")) {
|
|
827
|
+
return completedRunResult(status, `${JSON.stringify(publicCliReport(report))}\n`, report.stderr ?? "", options);
|
|
807
828
|
}
|
|
829
|
+
return completedRunResult(status, "", `${report.stderr ?? ""}${formatNativeTextReport(report)}`, options);
|
|
830
|
+
}
|
|
808
831
|
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
832
|
+
function publicCliReport(report) {
|
|
833
|
+
return {
|
|
834
|
+
files: report.files ?? 0,
|
|
835
|
+
filePaths: report.filePaths ?? [],
|
|
836
|
+
diagnostics: report.diagnostics ?? [],
|
|
837
|
+
outputs: report.outputs ?? []
|
|
838
|
+
};
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
function formatNativeTextReport(report) {
|
|
842
|
+
const lines = [];
|
|
843
|
+
for (const diagnostic of report.diagnostics ?? []) {
|
|
844
|
+
const rule = diagnostic.ruleId ? ` [${diagnostic.ruleId}]` : "";
|
|
845
|
+
lines.push(
|
|
846
|
+
`${diagnostic.filePath}:${diagnostic.line ?? 0}:${diagnostic.column ?? 0}: ${diagnostic.severity ?? "error"}: ${diagnostic.message}${rule}`
|
|
847
|
+
);
|
|
848
|
+
}
|
|
849
|
+
lines.push(`${report.files ?? 0} file(s) checked, ${(report.diagnostics ?? []).length} diagnostic(s)`);
|
|
850
|
+
return `${lines.join("\n")}\n`;
|
|
818
851
|
}
|
|
819
852
|
|
|
820
853
|
function runFishlint(args = [], options = {}) {
|
|
@@ -1030,15 +1063,35 @@ function booleanFlagValue(arg) {
|
|
|
1030
1063
|
}
|
|
1031
1064
|
|
|
1032
1065
|
function lintFiles(paths, options = {}) {
|
|
1066
|
+
options = withConfigCache(options);
|
|
1033
1067
|
const targets = lintTargetsForInput(paths, options);
|
|
1034
1068
|
const ignoredDiagnostics = ignoredLintPathDiagnostics(targets, options);
|
|
1035
1069
|
const lintPaths = filteredLintPaths(targets, options);
|
|
1036
1070
|
if (lintPaths.length === 0) {
|
|
1037
|
-
return { files: 0, filePaths: [], diagnostics: ignoredDiagnostics, exitCode: ignoredDiagnostics
|
|
1071
|
+
return { files: 0, filePaths: [], diagnostics: ignoredDiagnostics, exitCode: exitCodeForDiagnostics(ignoredDiagnostics) };
|
|
1072
|
+
}
|
|
1073
|
+
|
|
1074
|
+
const configRuns = nativeConfigRunsForFiles(expandNativeConfigRunPaths(lintPaths, options), options);
|
|
1075
|
+
if (configRuns) {
|
|
1076
|
+
const report = mergeNativeReports(
|
|
1077
|
+
configRuns.map(({ paths: runPaths, options: runOptions }) => runNativeLintReport(runPaths, runOptions))
|
|
1078
|
+
);
|
|
1079
|
+
return finalizeLintReport(report, ignoredDiagnostics, options);
|
|
1038
1080
|
}
|
|
1039
1081
|
|
|
1082
|
+
const report = runNativeLintReport(lintPaths, options);
|
|
1083
|
+
return finalizeLintReport(report, ignoredDiagnostics, options);
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1086
|
+
function expandNativeConfigRunPaths(paths, options) {
|
|
1087
|
+
const cwd = options.cwd ?? process.cwd();
|
|
1088
|
+
const patterns = ignoreDisabled(options) ? [] : ignorePatternsForOptions(options, cwd);
|
|
1089
|
+
return paths.flatMap((path) => expandLintTarget(path, cwd, patterns) ?? [path]);
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1092
|
+
function runNativeLintReport(paths, options) {
|
|
1040
1093
|
return withTemporaryConfig(options, (resolvedOptions) => {
|
|
1041
|
-
const cliArgs = buildLintArgs(
|
|
1094
|
+
const cliArgs = buildLintArgs(paths, resolvedOptions);
|
|
1042
1095
|
const result = run(cliArgs, { ...resolvedOptions, stdio: undefined, encoding: "utf8" });
|
|
1043
1096
|
|
|
1044
1097
|
if (result.error) {
|
|
@@ -1061,17 +1114,6 @@ function lintFiles(paths, options = {}) {
|
|
|
1061
1114
|
}
|
|
1062
1115
|
|
|
1063
1116
|
report.exitCode = status;
|
|
1064
|
-
report.diagnostics = [
|
|
1065
|
-
...(report.diagnostics ?? []),
|
|
1066
|
-
...ignoredDiagnostics
|
|
1067
|
-
];
|
|
1068
|
-
if (!resolvedOptions.deferDiagnosticConfigFiltering) {
|
|
1069
|
-
report.filePaths = normalizeReportFilePaths(report.filePaths, resolvedOptions);
|
|
1070
|
-
report.diagnostics = normalizeDiagnosticFilePaths(report.diagnostics, resolvedOptions);
|
|
1071
|
-
report.outputs = normalizeReportOutputs(report.outputs, resolvedOptions);
|
|
1072
|
-
report.diagnostics = normalizeReportDiagnostics(report.diagnostics, resolvedOptions);
|
|
1073
|
-
report.exitCode = exitCodeForDiagnostics(report.diagnostics);
|
|
1074
|
-
}
|
|
1075
1117
|
if (stderr) {
|
|
1076
1118
|
Object.defineProperty(report, "stderr", {
|
|
1077
1119
|
value: stderr,
|
|
@@ -1083,7 +1125,124 @@ function lintFiles(paths, options = {}) {
|
|
|
1083
1125
|
});
|
|
1084
1126
|
}
|
|
1085
1127
|
|
|
1128
|
+
function finalizeLintReport(report, ignoredDiagnostics, options) {
|
|
1129
|
+
report.diagnostics = [
|
|
1130
|
+
...(report.diagnostics ?? []),
|
|
1131
|
+
...ignoredDiagnostics
|
|
1132
|
+
];
|
|
1133
|
+
if (!options.deferDiagnosticConfigFiltering) {
|
|
1134
|
+
report.filePaths = normalizeReportFilePaths(report.filePaths, options);
|
|
1135
|
+
report.diagnostics = normalizeDiagnosticFilePaths(report.diagnostics, options);
|
|
1136
|
+
report.outputs = normalizeReportOutputs(report.outputs, options);
|
|
1137
|
+
report.diagnostics = normalizeReportDiagnostics(report.diagnostics, options);
|
|
1138
|
+
report.exitCode = exitCodeForDiagnostics(report.diagnostics);
|
|
1139
|
+
}
|
|
1140
|
+
return report;
|
|
1141
|
+
}
|
|
1142
|
+
|
|
1143
|
+
function nativeConfigRunsForFiles(paths, options) {
|
|
1144
|
+
if (options.noConfig && !options.baseConfig && !options.overrideConfig) {
|
|
1145
|
+
return undefined;
|
|
1146
|
+
}
|
|
1147
|
+
|
|
1148
|
+
const groups = new Map();
|
|
1149
|
+
let hasConfigSource = Boolean(options.baseConfig || options.overrideConfig);
|
|
1150
|
+
for (const filePath of paths) {
|
|
1151
|
+
const matchPath = paths.length === 1
|
|
1152
|
+
? options.filePath ?? options.filename ?? filePath
|
|
1153
|
+
: filePath;
|
|
1154
|
+
const fileConfigPath = options.noConfig ? undefined : configPathForFile(options, matchPath);
|
|
1155
|
+
const configured = Boolean(options.baseConfig || options.overrideConfig || fileConfigPath);
|
|
1156
|
+
hasConfigSource ||= configured;
|
|
1157
|
+
let rules = configured ? calculatedConfig({ ...options, rules: undefined }, matchPath).rules : undefined;
|
|
1158
|
+
if (configured && options.rules) {
|
|
1159
|
+
rules = selectedRulesWithConfigOptions(rules, options.rules);
|
|
1160
|
+
}
|
|
1161
|
+
const signature = configured ? stableConfigSignature(rules) : "<native-defaults>";
|
|
1162
|
+
if (!groups.has(signature)) {
|
|
1163
|
+
groups.set(signature, { paths: [], rules, configured });
|
|
1164
|
+
}
|
|
1165
|
+
groups.get(signature).paths.push(filePath);
|
|
1166
|
+
}
|
|
1167
|
+
|
|
1168
|
+
if (!hasConfigSource) {
|
|
1169
|
+
return undefined;
|
|
1170
|
+
}
|
|
1171
|
+
|
|
1172
|
+
return [...groups.values()].map((group) => {
|
|
1173
|
+
if (!group.configured) {
|
|
1174
|
+
return {
|
|
1175
|
+
paths: group.paths,
|
|
1176
|
+
options: {
|
|
1177
|
+
...options,
|
|
1178
|
+
config: undefined,
|
|
1179
|
+
noConfig: true,
|
|
1180
|
+
baseConfig: undefined,
|
|
1181
|
+
overrideConfig: undefined
|
|
1182
|
+
}
|
|
1183
|
+
};
|
|
1184
|
+
}
|
|
1185
|
+
|
|
1186
|
+
return {
|
|
1187
|
+
paths: group.paths,
|
|
1188
|
+
options: {
|
|
1189
|
+
...options,
|
|
1190
|
+
config: undefined,
|
|
1191
|
+
noConfig: true,
|
|
1192
|
+
baseConfig: undefined,
|
|
1193
|
+
overrideConfig: { rules: allDisabledNativeRules(group.rules) },
|
|
1194
|
+
forceMaterializedConfig: true
|
|
1195
|
+
}
|
|
1196
|
+
};
|
|
1197
|
+
});
|
|
1198
|
+
}
|
|
1199
|
+
|
|
1200
|
+
function allDisabledNativeRules(rules) {
|
|
1201
|
+
return {
|
|
1202
|
+
...Object.fromEntries(NATIVE_RULE_IDS.map((rule) => [rule, "off"])),
|
|
1203
|
+
...rules
|
|
1204
|
+
};
|
|
1205
|
+
}
|
|
1206
|
+
|
|
1207
|
+
function selectedRulesWithConfigOptions(configRules, selectedRules) {
|
|
1208
|
+
const selected = rulesFromNativeRuleList(selectedRules);
|
|
1209
|
+
return Object.fromEntries(
|
|
1210
|
+
Object.keys(selected).map((rule) => [
|
|
1211
|
+
rule,
|
|
1212
|
+
configRules?.[rule] != null && ruleConfigSeverity(configRules[rule]) > 0
|
|
1213
|
+
? configRules[rule]
|
|
1214
|
+
: selected[rule]
|
|
1215
|
+
])
|
|
1216
|
+
);
|
|
1217
|
+
}
|
|
1218
|
+
|
|
1219
|
+
function stableConfigSignature(value) {
|
|
1220
|
+
if (Array.isArray(value)) {
|
|
1221
|
+
return `[${value.map((item) => stableConfigSignature(item)).join(",")}]`;
|
|
1222
|
+
}
|
|
1223
|
+
if (value && typeof value === "object") {
|
|
1224
|
+
return `{${Object.keys(value).sort().map((key) => `${JSON.stringify(key)}:${stableConfigSignature(value[key])}`).join(",")}}`;
|
|
1225
|
+
}
|
|
1226
|
+
return JSON.stringify(value);
|
|
1227
|
+
}
|
|
1228
|
+
|
|
1229
|
+
function mergeNativeReports(reports) {
|
|
1230
|
+
const report = {
|
|
1231
|
+
files: reports.reduce((count, item) => count + (item.files ?? 0), 0),
|
|
1232
|
+
filePaths: reports.flatMap((item) => item.filePaths ?? []),
|
|
1233
|
+
diagnostics: reports.flatMap((item) => item.diagnostics ?? []),
|
|
1234
|
+
outputs: reports.flatMap((item) => item.outputs ?? []),
|
|
1235
|
+
exitCode: reports.some((item) => item.exitCode) ? 1 : 0
|
|
1236
|
+
};
|
|
1237
|
+
const stderr = reports.map((item) => item.stderr ?? "").join("");
|
|
1238
|
+
if (stderr) {
|
|
1239
|
+
Object.defineProperty(report, "stderr", { value: stderr, enumerable: false });
|
|
1240
|
+
}
|
|
1241
|
+
return report;
|
|
1242
|
+
}
|
|
1243
|
+
|
|
1086
1244
|
function lintText(code, options = {}) {
|
|
1245
|
+
options = withConfigCache(options);
|
|
1087
1246
|
if (typeof code !== "string") {
|
|
1088
1247
|
throw new TypeError("code must be a string");
|
|
1089
1248
|
}
|
|
@@ -1104,7 +1263,7 @@ function lintText(code, options = {}) {
|
|
|
1104
1263
|
files: 0,
|
|
1105
1264
|
filePaths: [],
|
|
1106
1265
|
diagnostics,
|
|
1107
|
-
exitCode: diagnostics
|
|
1266
|
+
exitCode: exitCodeForDiagnostics(diagnostics)
|
|
1108
1267
|
};
|
|
1109
1268
|
}
|
|
1110
1269
|
|
|
@@ -1141,22 +1300,28 @@ function buildLintArgs(paths, options) {
|
|
|
1141
1300
|
});
|
|
1142
1301
|
}
|
|
1143
1302
|
|
|
1144
|
-
function buildRunCliArgs(paths, options, passthroughArgs) {
|
|
1145
|
-
return buildNativeLintArgs(paths, {
|
|
1146
|
-
...options,
|
|
1147
|
-
extraArgs: passthroughArgs
|
|
1148
|
-
});
|
|
1149
|
-
}
|
|
1150
|
-
|
|
1151
1303
|
function buildNativeLintArgs(paths, options) {
|
|
1152
1304
|
const cliArgs = [];
|
|
1153
1305
|
|
|
1154
|
-
if (options.config) {
|
|
1155
|
-
cliArgs.push(`--config=${options.config}`);
|
|
1156
|
-
}
|
|
1157
1306
|
if (options.noConfig) {
|
|
1158
1307
|
cliArgs.push("--no-config");
|
|
1159
1308
|
}
|
|
1309
|
+
if (!options.rules && !options.forceMaterializedConfig && (options.config || options.baseConfig || options.overrideConfig)) {
|
|
1310
|
+
const configForRuleSelection = options.noConfig
|
|
1311
|
+
? undefined
|
|
1312
|
+
: options.config ? readConfig(options.config, options.cwd, options.configCache) : undefined;
|
|
1313
|
+
const enabledRules = enabledRuleNamesFromConfigs(
|
|
1314
|
+
configForRuleSelection,
|
|
1315
|
+
options.baseConfig,
|
|
1316
|
+
options.overrideConfig
|
|
1317
|
+
);
|
|
1318
|
+
if (enabledRules.length > 0) {
|
|
1319
|
+
cliArgs.push(`--rules=${enabledRules.join(",")}`);
|
|
1320
|
+
}
|
|
1321
|
+
}
|
|
1322
|
+
if (options.config) {
|
|
1323
|
+
cliArgs.push(`--config=${options.config}`);
|
|
1324
|
+
}
|
|
1160
1325
|
if (options.rules) {
|
|
1161
1326
|
const rules = Array.isArray(options.rules) ? options.rules.join(",") : options.rules;
|
|
1162
1327
|
if (rules) {
|
|
@@ -1190,6 +1355,12 @@ function mergeLintOptions(base, override) {
|
|
|
1190
1355
|
};
|
|
1191
1356
|
}
|
|
1192
1357
|
|
|
1358
|
+
function withConfigCache(options) {
|
|
1359
|
+
// Executable configs are otherwise re-evaluated at every per-file lookup.
|
|
1360
|
+
// Keep the cache on the options object so one public invocation shares it.
|
|
1361
|
+
return options.configCache ? options : { ...options, configCache: new Map() };
|
|
1362
|
+
}
|
|
1363
|
+
|
|
1193
1364
|
function eslintConstructorOptions(options) {
|
|
1194
1365
|
const mapped = {
|
|
1195
1366
|
cwd: options.cwd,
|
|
@@ -1242,10 +1413,10 @@ function calculatedConfig(options = {}, filePath) {
|
|
|
1242
1413
|
return {
|
|
1243
1414
|
...configData,
|
|
1244
1415
|
rules: {
|
|
1245
|
-
...rulesFromNativeRuleList(options.rules),
|
|
1246
1416
|
...rulesFromConfig(options.baseConfig, filePath, options.cwd),
|
|
1247
1417
|
...rulesFromFileConfig(options, filePath),
|
|
1248
|
-
...rulesFromConfig(options.overrideConfig, filePath, options.cwd)
|
|
1418
|
+
...rulesFromConfig(options.overrideConfig, filePath, options.cwd),
|
|
1419
|
+
...rulesFromNativeRuleList(options.rules)
|
|
1249
1420
|
}
|
|
1250
1421
|
};
|
|
1251
1422
|
}
|
|
@@ -1362,8 +1533,8 @@ function rulesFromFileConfig(options, filePath) {
|
|
|
1362
1533
|
return {};
|
|
1363
1534
|
}
|
|
1364
1535
|
|
|
1365
|
-
const config = readConfig(configPath, options.cwd);
|
|
1366
|
-
return rulesFromConfig(config, filePath,
|
|
1536
|
+
const config = readConfig(configPath, options.cwd, options.configCache);
|
|
1537
|
+
return rulesFromConfig(config, filePath, dirname(configPath));
|
|
1367
1538
|
}
|
|
1368
1539
|
|
|
1369
1540
|
function configDataFromFileConfig(options, filePath) {
|
|
@@ -1376,8 +1547,8 @@ function configDataFromFileConfig(options, filePath) {
|
|
|
1376
1547
|
return {};
|
|
1377
1548
|
}
|
|
1378
1549
|
|
|
1379
|
-
const config = readConfig(configPath, options.cwd);
|
|
1380
|
-
return configDataFromConfig(config, filePath,
|
|
1550
|
+
const config = readConfig(configPath, options.cwd, options.configCache);
|
|
1551
|
+
return configDataFromConfig(config, filePath, dirname(configPath));
|
|
1381
1552
|
}
|
|
1382
1553
|
|
|
1383
1554
|
function lintTargetsForInput(paths, options = {}) {
|
|
@@ -1397,8 +1568,17 @@ function defaultLintTargets(options = {}) {
|
|
|
1397
1568
|
return ["."];
|
|
1398
1569
|
}
|
|
1399
1570
|
|
|
1400
|
-
const targets = filePatternsFromConfig(readConfig(configPath, options.cwd));
|
|
1401
|
-
return targets.length > 0
|
|
1571
|
+
const targets = filePatternsFromConfig(readConfig(configPath, options.cwd, options.configCache));
|
|
1572
|
+
return targets.length > 0
|
|
1573
|
+
? targets.map((target) => resolveConfigPattern(target, dirname(configPath)))
|
|
1574
|
+
: ["."];
|
|
1575
|
+
}
|
|
1576
|
+
|
|
1577
|
+
function resolveConfigPattern(pattern, configDirectory) {
|
|
1578
|
+
if (isAbsolute(pattern)) {
|
|
1579
|
+
return pattern;
|
|
1580
|
+
}
|
|
1581
|
+
return resolvePath(configDirectory, pattern.replace(/^[/\\]/, ""));
|
|
1402
1582
|
}
|
|
1403
1583
|
|
|
1404
1584
|
function filePatternsFromConfig(config) {
|
|
@@ -1452,6 +1632,9 @@ function configPathForOptions(options) {
|
|
|
1452
1632
|
}
|
|
1453
1633
|
|
|
1454
1634
|
function configPathForFile(options, filePath) {
|
|
1635
|
+
if (options.noConfig) {
|
|
1636
|
+
return undefined;
|
|
1637
|
+
}
|
|
1455
1638
|
if (options.config) {
|
|
1456
1639
|
return resolvePath(options.cwd ?? process.cwd(), options.config);
|
|
1457
1640
|
}
|
|
@@ -1471,66 +1654,20 @@ function configSearchDirectoryForFile(filePath, cwd) {
|
|
|
1471
1654
|
}
|
|
1472
1655
|
|
|
1473
1656
|
function configPathFromDirectory(directory) {
|
|
1474
|
-
|
|
1475
|
-
while (true) {
|
|
1476
|
-
for (const candidate of CONFIG_FILENAMES) {
|
|
1477
|
-
const path = resolvePath(current, candidate);
|
|
1478
|
-
if (existsSync(path)) {
|
|
1479
|
-
return path;
|
|
1480
|
-
}
|
|
1481
|
-
}
|
|
1482
|
-
const parent = dirname(current);
|
|
1483
|
-
if (parent === current) {
|
|
1484
|
-
return undefined;
|
|
1485
|
-
}
|
|
1486
|
-
current = parent;
|
|
1487
|
-
}
|
|
1488
|
-
}
|
|
1489
|
-
|
|
1490
|
-
function readConfig(path, cwd) {
|
|
1491
|
-
if (isJavaScriptConfigPath(path)) {
|
|
1492
|
-
return readJavaScriptConfig(path, cwd);
|
|
1493
|
-
}
|
|
1494
|
-
|
|
1495
|
-
try {
|
|
1496
|
-
return JSON.parse(readFileSync(path, "utf8"));
|
|
1497
|
-
} catch (error) {
|
|
1498
|
-
throw new Error(`utoo-lint unable to read config ${path}: ${error.message}`);
|
|
1499
|
-
}
|
|
1500
|
-
}
|
|
1501
|
-
|
|
1502
|
-
function readJavaScriptConfig(path, cwd) {
|
|
1503
|
-
const result = spawnSync(process.execPath, ["--input-type=module", "--eval", JAVASCRIPT_CONFIG_LOADER_SCRIPT, path], {
|
|
1504
|
-
cwd: cwd ?? process.cwd(),
|
|
1505
|
-
encoding: "utf8"
|
|
1506
|
-
});
|
|
1507
|
-
if (result.error) {
|
|
1508
|
-
throw result.error;
|
|
1509
|
-
}
|
|
1510
|
-
if (result.status !== 0) {
|
|
1511
|
-
throw new Error(`utoo-lint unable to read config ${path}: ${(result.stderr ?? "").trim() || "JavaScript config loader failed"}`);
|
|
1512
|
-
}
|
|
1513
|
-
try {
|
|
1514
|
-
return JSON.parse(result.stdout);
|
|
1515
|
-
} catch (error) {
|
|
1516
|
-
throw new Error(`utoo-lint unable to read config ${path}: ${error.message}`);
|
|
1517
|
-
}
|
|
1518
|
-
}
|
|
1519
|
-
|
|
1520
|
-
function isJavaScriptConfigPath(path) {
|
|
1521
|
-
return JAVASCRIPT_CONFIG_EXTENSIONS.has(extname(path));
|
|
1657
|
+
return findConfigPathFromDirectory(directory);
|
|
1522
1658
|
}
|
|
1523
1659
|
|
|
1524
1660
|
function withTemporaryConfig(options, callback) {
|
|
1525
1661
|
const fileConfigPath = !options.noConfig ? configPathForOptions(options) : undefined;
|
|
1526
|
-
const shouldMaterializeFileConfig =
|
|
1527
|
-
const fileConfig = shouldMaterializeFileConfig
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1662
|
+
const shouldMaterializeFileConfig = Boolean(fileConfigPath);
|
|
1663
|
+
const fileConfig = shouldMaterializeFileConfig
|
|
1664
|
+
? readConfig(fileConfigPath, options.cwd, options.configCache)
|
|
1665
|
+
: undefined;
|
|
1666
|
+
const configs = [options.baseConfig, fileConfig, options.overrideConfig];
|
|
1667
|
+
const rules = shouldMaterializeFileConfig
|
|
1668
|
+
? materializedRulesFromConfigs(...configs)
|
|
1669
|
+
: runtimeRulesFromConfigs(...configs);
|
|
1670
|
+
if (Object.keys(rules).length === 0) {
|
|
1534
1671
|
if (shouldMaterializeFileConfig) {
|
|
1535
1672
|
return callback({
|
|
1536
1673
|
...options,
|
|
@@ -1540,10 +1677,9 @@ function withTemporaryConfig(options, callback) {
|
|
|
1540
1677
|
}
|
|
1541
1678
|
return callback(options);
|
|
1542
1679
|
}
|
|
1543
|
-
|
|
1544
|
-
const
|
|
1545
|
-
|
|
1546
|
-
if (!hasRuleOptions(rules)) {
|
|
1680
|
+
const enabledRules = enabledRuleNamesFromConfigs(...configs);
|
|
1681
|
+
const hasExplicitOffRules = Object.values(rules).some((value) => ruleConfigSeverity(value) === 0);
|
|
1682
|
+
if (!shouldMaterializeFileConfig && !hasRuleOptions(rules) && !hasExplicitOffRules && !options.forceMaterializedConfig) {
|
|
1547
1683
|
return callback({
|
|
1548
1684
|
...options,
|
|
1549
1685
|
config: shouldMaterializeFileConfig ? undefined : options.config,
|
|
@@ -1553,13 +1689,14 @@ function withTemporaryConfig(options, callback) {
|
|
|
1553
1689
|
}
|
|
1554
1690
|
|
|
1555
1691
|
const tmp = mkdtempSync(join(tmpdir(), "utoo-lint-config-"));
|
|
1556
|
-
const configPath = join(tmp, "
|
|
1692
|
+
const configPath = join(tmp, "utlint.config.json");
|
|
1557
1693
|
try {
|
|
1558
1694
|
writeFileSync(configPath, JSON.stringify({ rules }));
|
|
1559
1695
|
return callback({
|
|
1560
1696
|
...options,
|
|
1561
1697
|
config: shouldMaterializeFileConfig ? configPath : options.config ?? configPath,
|
|
1562
|
-
noConfig: false
|
|
1698
|
+
noConfig: false,
|
|
1699
|
+
rules: options.forceMaterializedConfig ? undefined : options.rules
|
|
1563
1700
|
});
|
|
1564
1701
|
} finally {
|
|
1565
1702
|
rmSync(tmp, { recursive: true, force: true });
|
|
@@ -1580,6 +1717,10 @@ function runtimeRulesFromConfigs(...configs) {
|
|
|
1580
1717
|
return rules;
|
|
1581
1718
|
}
|
|
1582
1719
|
|
|
1720
|
+
function materializedRulesFromConfigs(...configs) {
|
|
1721
|
+
return runtimeRulesFromConfigs(...configs);
|
|
1722
|
+
}
|
|
1723
|
+
|
|
1583
1724
|
function runtimeRulesFromConfig(config) {
|
|
1584
1725
|
if (!config) {
|
|
1585
1726
|
return {};
|
|
@@ -1593,9 +1734,7 @@ function runtimeRulesFromConfig(config) {
|
|
|
1593
1734
|
|
|
1594
1735
|
const rules = {};
|
|
1595
1736
|
for (const [rule, value] of Object.entries(rulesFromConfig(config))) {
|
|
1596
|
-
|
|
1597
|
-
rules[rule] = value;
|
|
1598
|
-
}
|
|
1737
|
+
rules[rule] = value;
|
|
1599
1738
|
}
|
|
1600
1739
|
return rules;
|
|
1601
1740
|
}
|
|
@@ -3509,19 +3648,19 @@ function reportToESLintResults(report, textOptions = {}) {
|
|
|
3509
3648
|
}
|
|
3510
3649
|
|
|
3511
3650
|
function normalizeReportDiagnostics(diagnostics, options = {}) {
|
|
3512
|
-
const filterUnconfiguredRules = hasRuleConfigSource(options);
|
|
3513
3651
|
return (diagnostics ?? []).flatMap((diagnostic) => {
|
|
3514
3652
|
if (!diagnostic?.ruleId) {
|
|
3515
3653
|
return [diagnostic];
|
|
3516
3654
|
}
|
|
3517
|
-
if (diagnostic.ruleId === "io") {
|
|
3655
|
+
if (diagnostic.ruleId === "io" || diagnostic.ruleId === "parse") {
|
|
3518
3656
|
return [diagnostic];
|
|
3519
3657
|
}
|
|
3520
3658
|
|
|
3521
3659
|
const filePath = normalizeESLintFilePath(diagnostic.filePath, options.cwd);
|
|
3660
|
+
const filterUnconfiguredRules = hasRuleConfigSource(options, filePath);
|
|
3522
3661
|
const ruleSeverities = ruleSeverityMapForOptions(options, filePath);
|
|
3523
3662
|
const severity = ruleSeverities?.get(diagnostic.ruleId);
|
|
3524
|
-
if (filterUnconfiguredRules && !ruleSeverities?.has(diagnostic.ruleId)) {
|
|
3663
|
+
if (!options.preserveNativeDefaults && filterUnconfiguredRules && !ruleSeverities?.has(diagnostic.ruleId)) {
|
|
3525
3664
|
return [];
|
|
3526
3665
|
}
|
|
3527
3666
|
if (severity === 0) {
|
|
@@ -3552,15 +3691,17 @@ function normalizeDiagnosticFilePaths(diagnostics, options = {}) {
|
|
|
3552
3691
|
}));
|
|
3553
3692
|
}
|
|
3554
3693
|
|
|
3555
|
-
function hasRuleConfigSource(options = {}) {
|
|
3556
|
-
if (options.
|
|
3694
|
+
function hasRuleConfigSource(options = {}, filePath) {
|
|
3695
|
+
if (options.baseConfig || options.overrideConfig || options.rules) {
|
|
3557
3696
|
return true;
|
|
3558
3697
|
}
|
|
3559
|
-
return !options.noConfig && Boolean(
|
|
3698
|
+
return !options.noConfig && Boolean(
|
|
3699
|
+
filePath ? configPathForFile(options, filePath) : configPathForOptions(options)
|
|
3700
|
+
);
|
|
3560
3701
|
}
|
|
3561
3702
|
|
|
3562
3703
|
function exitCodeForDiagnostics(diagnostics) {
|
|
3563
|
-
return
|
|
3704
|
+
return diagnostics?.some((diagnostic) => diagnostic?.severity === "error" || diagnostic?.severity === 2) ? 1 : 0;
|
|
3564
3705
|
}
|
|
3565
3706
|
|
|
3566
3707
|
function throwOnUnmatchedPatternDiagnostics(report, options = {}) {
|
|
@@ -3880,7 +4021,21 @@ function ignorePatternsFromFileConfig(options, filePath) {
|
|
|
3880
4021
|
return [];
|
|
3881
4022
|
}
|
|
3882
4023
|
|
|
3883
|
-
|
|
4024
|
+
const cwd = options.cwd ?? process.cwd();
|
|
4025
|
+
return ignorePatternsFromConfig(readConfig(configPath, options.cwd, options.configCache)).map((pattern) =>
|
|
4026
|
+
rebaseConfigPattern(pattern, dirname(configPath), cwd)
|
|
4027
|
+
);
|
|
4028
|
+
}
|
|
4029
|
+
|
|
4030
|
+
function rebaseConfigPattern(pattern, configDirectory, cwd) {
|
|
4031
|
+
const negated = pattern.startsWith("!");
|
|
4032
|
+
const value = negated ? pattern.slice(1) : pattern;
|
|
4033
|
+
const absolute = resolveConfigPattern(value, configDirectory);
|
|
4034
|
+
const relativePattern = normalizePath(relative(resolvePath(cwd), absolute));
|
|
4035
|
+
const rebased = relativePattern === ".." || relativePattern.startsWith("../")
|
|
4036
|
+
? normalizePath(absolute)
|
|
4037
|
+
: relativePattern;
|
|
4038
|
+
return negated ? `!${rebased}` : rebased;
|
|
3884
4039
|
}
|
|
3885
4040
|
|
|
3886
4041
|
function ignorePatternsFromConfig(config) {
|