@utoo/lint 0.2.0 → 0.2.2
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 +91 -11
- package/bin/fishlint.js +429 -64
- package/bin/migrate.js +8 -6
- package/index.cjs +275 -130
- package/index.d.ts +5 -1
- package/index.js +275 -130
- package/lib/config-loader.cjs +87 -0
- package/lib/config-loader.js +81 -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
|
|
|
@@ -797,24 +814,40 @@ function runCli(args = [], options = {}) {
|
|
|
797
814
|
|
|
798
815
|
const cliOptions = {
|
|
799
816
|
...options,
|
|
800
|
-
...parsed.options
|
|
817
|
+
...parsed.options,
|
|
818
|
+
extraArgs: parsed.passthroughArgs,
|
|
819
|
+
preserveNativeDefaults: Boolean(parsed.options.noConfig)
|
|
801
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 = {}) {
|
|
@@ -1034,11 +1067,30 @@ function lintFiles(paths, options = {}) {
|
|
|
1034
1067
|
const ignoredDiagnostics = ignoredLintPathDiagnostics(targets, options);
|
|
1035
1068
|
const lintPaths = filteredLintPaths(targets, options);
|
|
1036
1069
|
if (lintPaths.length === 0) {
|
|
1037
|
-
return { files: 0, filePaths: [], diagnostics: ignoredDiagnostics, exitCode: ignoredDiagnostics
|
|
1070
|
+
return { files: 0, filePaths: [], diagnostics: ignoredDiagnostics, exitCode: exitCodeForDiagnostics(ignoredDiagnostics) };
|
|
1071
|
+
}
|
|
1072
|
+
|
|
1073
|
+
const configRuns = nativeConfigRunsForFiles(expandNativeConfigRunPaths(lintPaths, options), options);
|
|
1074
|
+
if (configRuns) {
|
|
1075
|
+
const report = mergeNativeReports(
|
|
1076
|
+
configRuns.map(({ paths: runPaths, options: runOptions }) => runNativeLintReport(runPaths, runOptions))
|
|
1077
|
+
);
|
|
1078
|
+
return finalizeLintReport(report, ignoredDiagnostics, options);
|
|
1038
1079
|
}
|
|
1039
1080
|
|
|
1081
|
+
const report = runNativeLintReport(lintPaths, options);
|
|
1082
|
+
return finalizeLintReport(report, ignoredDiagnostics, options);
|
|
1083
|
+
}
|
|
1084
|
+
|
|
1085
|
+
function expandNativeConfigRunPaths(paths, options) {
|
|
1086
|
+
const cwd = options.cwd ?? process.cwd();
|
|
1087
|
+
const patterns = ignoreDisabled(options) ? [] : ignorePatternsForOptions(options, cwd);
|
|
1088
|
+
return paths.flatMap((path) => expandLintTarget(path, cwd, patterns) ?? [path]);
|
|
1089
|
+
}
|
|
1090
|
+
|
|
1091
|
+
function runNativeLintReport(paths, options) {
|
|
1040
1092
|
return withTemporaryConfig(options, (resolvedOptions) => {
|
|
1041
|
-
const cliArgs = buildLintArgs(
|
|
1093
|
+
const cliArgs = buildLintArgs(paths, resolvedOptions);
|
|
1042
1094
|
const result = run(cliArgs, { ...resolvedOptions, stdio: undefined, encoding: "utf8" });
|
|
1043
1095
|
|
|
1044
1096
|
if (result.error) {
|
|
@@ -1061,17 +1113,6 @@ function lintFiles(paths, options = {}) {
|
|
|
1061
1113
|
}
|
|
1062
1114
|
|
|
1063
1115
|
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
1116
|
if (stderr) {
|
|
1076
1117
|
Object.defineProperty(report, "stderr", {
|
|
1077
1118
|
value: stderr,
|
|
@@ -1083,6 +1124,122 @@ function lintFiles(paths, options = {}) {
|
|
|
1083
1124
|
});
|
|
1084
1125
|
}
|
|
1085
1126
|
|
|
1127
|
+
function finalizeLintReport(report, ignoredDiagnostics, options) {
|
|
1128
|
+
report.diagnostics = [
|
|
1129
|
+
...(report.diagnostics ?? []),
|
|
1130
|
+
...ignoredDiagnostics
|
|
1131
|
+
];
|
|
1132
|
+
if (!options.deferDiagnosticConfigFiltering) {
|
|
1133
|
+
report.filePaths = normalizeReportFilePaths(report.filePaths, options);
|
|
1134
|
+
report.diagnostics = normalizeDiagnosticFilePaths(report.diagnostics, options);
|
|
1135
|
+
report.outputs = normalizeReportOutputs(report.outputs, options);
|
|
1136
|
+
report.diagnostics = normalizeReportDiagnostics(report.diagnostics, options);
|
|
1137
|
+
report.exitCode = exitCodeForDiagnostics(report.diagnostics);
|
|
1138
|
+
}
|
|
1139
|
+
return report;
|
|
1140
|
+
}
|
|
1141
|
+
|
|
1142
|
+
function nativeConfigRunsForFiles(paths, options) {
|
|
1143
|
+
if (options.noConfig && !options.baseConfig && !options.overrideConfig) {
|
|
1144
|
+
return undefined;
|
|
1145
|
+
}
|
|
1146
|
+
|
|
1147
|
+
const groups = new Map();
|
|
1148
|
+
let hasConfigSource = Boolean(options.baseConfig || options.overrideConfig);
|
|
1149
|
+
for (const filePath of paths) {
|
|
1150
|
+
const matchPath = paths.length === 1
|
|
1151
|
+
? options.filePath ?? options.filename ?? filePath
|
|
1152
|
+
: filePath;
|
|
1153
|
+
const fileConfigPath = options.noConfig ? undefined : configPathForFile(options, matchPath);
|
|
1154
|
+
const configured = Boolean(options.baseConfig || options.overrideConfig || fileConfigPath);
|
|
1155
|
+
hasConfigSource ||= configured;
|
|
1156
|
+
let rules = configured ? calculatedConfig({ ...options, rules: undefined }, matchPath).rules : undefined;
|
|
1157
|
+
if (configured && options.rules) {
|
|
1158
|
+
rules = selectedRulesWithConfigOptions(rules, options.rules);
|
|
1159
|
+
}
|
|
1160
|
+
const signature = configured ? stableConfigSignature(rules) : "<native-defaults>";
|
|
1161
|
+
if (!groups.has(signature)) {
|
|
1162
|
+
groups.set(signature, { paths: [], rules, configured });
|
|
1163
|
+
}
|
|
1164
|
+
groups.get(signature).paths.push(filePath);
|
|
1165
|
+
}
|
|
1166
|
+
|
|
1167
|
+
if (!hasConfigSource) {
|
|
1168
|
+
return undefined;
|
|
1169
|
+
}
|
|
1170
|
+
|
|
1171
|
+
return [...groups.values()].map((group) => {
|
|
1172
|
+
if (!group.configured) {
|
|
1173
|
+
return {
|
|
1174
|
+
paths: group.paths,
|
|
1175
|
+
options: {
|
|
1176
|
+
...options,
|
|
1177
|
+
config: undefined,
|
|
1178
|
+
noConfig: true,
|
|
1179
|
+
baseConfig: undefined,
|
|
1180
|
+
overrideConfig: undefined
|
|
1181
|
+
}
|
|
1182
|
+
};
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1185
|
+
return {
|
|
1186
|
+
paths: group.paths,
|
|
1187
|
+
options: {
|
|
1188
|
+
...options,
|
|
1189
|
+
config: undefined,
|
|
1190
|
+
noConfig: true,
|
|
1191
|
+
baseConfig: undefined,
|
|
1192
|
+
overrideConfig: { rules: allDisabledNativeRules(group.rules) },
|
|
1193
|
+
forceMaterializedConfig: true
|
|
1194
|
+
}
|
|
1195
|
+
};
|
|
1196
|
+
});
|
|
1197
|
+
}
|
|
1198
|
+
|
|
1199
|
+
function allDisabledNativeRules(rules) {
|
|
1200
|
+
return {
|
|
1201
|
+
...Object.fromEntries(NATIVE_RULE_IDS.map((rule) => [rule, "off"])),
|
|
1202
|
+
...rules
|
|
1203
|
+
};
|
|
1204
|
+
}
|
|
1205
|
+
|
|
1206
|
+
function selectedRulesWithConfigOptions(configRules, selectedRules) {
|
|
1207
|
+
const selected = rulesFromNativeRuleList(selectedRules);
|
|
1208
|
+
return Object.fromEntries(
|
|
1209
|
+
Object.keys(selected).map((rule) => [
|
|
1210
|
+
rule,
|
|
1211
|
+
configRules?.[rule] != null && ruleConfigSeverity(configRules[rule]) > 0
|
|
1212
|
+
? configRules[rule]
|
|
1213
|
+
: selected[rule]
|
|
1214
|
+
])
|
|
1215
|
+
);
|
|
1216
|
+
}
|
|
1217
|
+
|
|
1218
|
+
function stableConfigSignature(value) {
|
|
1219
|
+
if (Array.isArray(value)) {
|
|
1220
|
+
return `[${value.map((item) => stableConfigSignature(item)).join(",")}]`;
|
|
1221
|
+
}
|
|
1222
|
+
if (value && typeof value === "object") {
|
|
1223
|
+
return `{${Object.keys(value).sort().map((key) => `${JSON.stringify(key)}:${stableConfigSignature(value[key])}`).join(",")}}`;
|
|
1224
|
+
}
|
|
1225
|
+
return JSON.stringify(value);
|
|
1226
|
+
}
|
|
1227
|
+
|
|
1228
|
+
function mergeNativeReports(reports) {
|
|
1229
|
+
const report = {
|
|
1230
|
+
files: reports.reduce((count, item) => count + (item.files ?? 0), 0),
|
|
1231
|
+
filePaths: reports.flatMap((item) => item.filePaths ?? []),
|
|
1232
|
+
diagnostics: reports.flatMap((item) => item.diagnostics ?? []),
|
|
1233
|
+
outputs: reports.flatMap((item) => item.outputs ?? []),
|
|
1234
|
+
exitCode: reports.some((item) => item.exitCode) ? 1 : 0
|
|
1235
|
+
};
|
|
1236
|
+
const stderr = reports.map((item) => item.stderr ?? "").join("");
|
|
1237
|
+
if (stderr) {
|
|
1238
|
+
Object.defineProperty(report, "stderr", { value: stderr, enumerable: false });
|
|
1239
|
+
}
|
|
1240
|
+
return report;
|
|
1241
|
+
}
|
|
1242
|
+
|
|
1086
1243
|
function lintText(code, options = {}) {
|
|
1087
1244
|
if (typeof code !== "string") {
|
|
1088
1245
|
throw new TypeError("code must be a string");
|
|
@@ -1104,7 +1261,7 @@ function lintText(code, options = {}) {
|
|
|
1104
1261
|
files: 0,
|
|
1105
1262
|
filePaths: [],
|
|
1106
1263
|
diagnostics,
|
|
1107
|
-
exitCode: diagnostics
|
|
1264
|
+
exitCode: exitCodeForDiagnostics(diagnostics)
|
|
1108
1265
|
};
|
|
1109
1266
|
}
|
|
1110
1267
|
|
|
@@ -1141,22 +1298,28 @@ function buildLintArgs(paths, options) {
|
|
|
1141
1298
|
});
|
|
1142
1299
|
}
|
|
1143
1300
|
|
|
1144
|
-
function buildRunCliArgs(paths, options, passthroughArgs) {
|
|
1145
|
-
return buildNativeLintArgs(paths, {
|
|
1146
|
-
...options,
|
|
1147
|
-
extraArgs: passthroughArgs
|
|
1148
|
-
});
|
|
1149
|
-
}
|
|
1150
|
-
|
|
1151
1301
|
function buildNativeLintArgs(paths, options) {
|
|
1152
1302
|
const cliArgs = [];
|
|
1153
1303
|
|
|
1154
|
-
if (options.config) {
|
|
1155
|
-
cliArgs.push(`--config=${options.config}`);
|
|
1156
|
-
}
|
|
1157
1304
|
if (options.noConfig) {
|
|
1158
1305
|
cliArgs.push("--no-config");
|
|
1159
1306
|
}
|
|
1307
|
+
if (!options.rules && !options.forceMaterializedConfig && (options.config || options.baseConfig || options.overrideConfig)) {
|
|
1308
|
+
const configForRuleSelection = options.noConfig
|
|
1309
|
+
? undefined
|
|
1310
|
+
: options.config ? readConfig(options.config, options.cwd) : undefined;
|
|
1311
|
+
const enabledRules = enabledRuleNamesFromConfigs(
|
|
1312
|
+
configForRuleSelection,
|
|
1313
|
+
options.baseConfig,
|
|
1314
|
+
options.overrideConfig
|
|
1315
|
+
);
|
|
1316
|
+
if (enabledRules.length > 0) {
|
|
1317
|
+
cliArgs.push(`--rules=${enabledRules.join(",")}`);
|
|
1318
|
+
}
|
|
1319
|
+
}
|
|
1320
|
+
if (options.config) {
|
|
1321
|
+
cliArgs.push(`--config=${options.config}`);
|
|
1322
|
+
}
|
|
1160
1323
|
if (options.rules) {
|
|
1161
1324
|
const rules = Array.isArray(options.rules) ? options.rules.join(",") : options.rules;
|
|
1162
1325
|
if (rules) {
|
|
@@ -1242,10 +1405,10 @@ function calculatedConfig(options = {}, filePath) {
|
|
|
1242
1405
|
return {
|
|
1243
1406
|
...configData,
|
|
1244
1407
|
rules: {
|
|
1245
|
-
...rulesFromNativeRuleList(options.rules),
|
|
1246
1408
|
...rulesFromConfig(options.baseConfig, filePath, options.cwd),
|
|
1247
1409
|
...rulesFromFileConfig(options, filePath),
|
|
1248
|
-
...rulesFromConfig(options.overrideConfig, filePath, options.cwd)
|
|
1410
|
+
...rulesFromConfig(options.overrideConfig, filePath, options.cwd),
|
|
1411
|
+
...rulesFromNativeRuleList(options.rules)
|
|
1249
1412
|
}
|
|
1250
1413
|
};
|
|
1251
1414
|
}
|
|
@@ -1363,7 +1526,7 @@ function rulesFromFileConfig(options, filePath) {
|
|
|
1363
1526
|
}
|
|
1364
1527
|
|
|
1365
1528
|
const config = readConfig(configPath, options.cwd);
|
|
1366
|
-
return rulesFromConfig(config, filePath,
|
|
1529
|
+
return rulesFromConfig(config, filePath, dirname(configPath));
|
|
1367
1530
|
}
|
|
1368
1531
|
|
|
1369
1532
|
function configDataFromFileConfig(options, filePath) {
|
|
@@ -1377,7 +1540,7 @@ function configDataFromFileConfig(options, filePath) {
|
|
|
1377
1540
|
}
|
|
1378
1541
|
|
|
1379
1542
|
const config = readConfig(configPath, options.cwd);
|
|
1380
|
-
return configDataFromConfig(config, filePath,
|
|
1543
|
+
return configDataFromConfig(config, filePath, dirname(configPath));
|
|
1381
1544
|
}
|
|
1382
1545
|
|
|
1383
1546
|
function lintTargetsForInput(paths, options = {}) {
|
|
@@ -1398,7 +1561,16 @@ function defaultLintTargets(options = {}) {
|
|
|
1398
1561
|
}
|
|
1399
1562
|
|
|
1400
1563
|
const targets = filePatternsFromConfig(readConfig(configPath, options.cwd));
|
|
1401
|
-
return targets.length > 0
|
|
1564
|
+
return targets.length > 0
|
|
1565
|
+
? targets.map((target) => resolveConfigPattern(target, dirname(configPath)))
|
|
1566
|
+
: ["."];
|
|
1567
|
+
}
|
|
1568
|
+
|
|
1569
|
+
function resolveConfigPattern(pattern, configDirectory) {
|
|
1570
|
+
if (isAbsolute(pattern)) {
|
|
1571
|
+
return pattern;
|
|
1572
|
+
}
|
|
1573
|
+
return resolvePath(configDirectory, pattern.replace(/^[/\\]/, ""));
|
|
1402
1574
|
}
|
|
1403
1575
|
|
|
1404
1576
|
function filePatternsFromConfig(config) {
|
|
@@ -1452,6 +1624,9 @@ function configPathForOptions(options) {
|
|
|
1452
1624
|
}
|
|
1453
1625
|
|
|
1454
1626
|
function configPathForFile(options, filePath) {
|
|
1627
|
+
if (options.noConfig) {
|
|
1628
|
+
return undefined;
|
|
1629
|
+
}
|
|
1455
1630
|
if (options.config) {
|
|
1456
1631
|
return resolvePath(options.cwd ?? process.cwd(), options.config);
|
|
1457
1632
|
}
|
|
@@ -1471,66 +1646,18 @@ function configSearchDirectoryForFile(filePath, cwd) {
|
|
|
1471
1646
|
}
|
|
1472
1647
|
|
|
1473
1648
|
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));
|
|
1649
|
+
return findConfigPathFromDirectory(directory);
|
|
1522
1650
|
}
|
|
1523
1651
|
|
|
1524
1652
|
function withTemporaryConfig(options, callback) {
|
|
1525
1653
|
const fileConfigPath = !options.noConfig ? configPathForOptions(options) : undefined;
|
|
1526
|
-
const shouldMaterializeFileConfig =
|
|
1654
|
+
const shouldMaterializeFileConfig = Boolean(fileConfigPath);
|
|
1527
1655
|
const fileConfig = shouldMaterializeFileConfig ? readConfig(fileConfigPath, options.cwd) : undefined;
|
|
1528
|
-
const
|
|
1529
|
-
|
|
1530
|
-
...
|
|
1531
|
-
...
|
|
1532
|
-
|
|
1533
|
-
if (Object.keys(inlineRules).length === 0) {
|
|
1656
|
+
const configs = [options.baseConfig, fileConfig, options.overrideConfig];
|
|
1657
|
+
const rules = shouldMaterializeFileConfig
|
|
1658
|
+
? materializedRulesFromConfigs(...configs)
|
|
1659
|
+
: runtimeRulesFromConfigs(...configs);
|
|
1660
|
+
if (Object.keys(rules).length === 0) {
|
|
1534
1661
|
if (shouldMaterializeFileConfig) {
|
|
1535
1662
|
return callback({
|
|
1536
1663
|
...options,
|
|
@@ -1540,10 +1667,9 @@ function withTemporaryConfig(options, callback) {
|
|
|
1540
1667
|
}
|
|
1541
1668
|
return callback(options);
|
|
1542
1669
|
}
|
|
1543
|
-
|
|
1544
|
-
const
|
|
1545
|
-
|
|
1546
|
-
if (!hasRuleOptions(rules)) {
|
|
1670
|
+
const enabledRules = enabledRuleNamesFromConfigs(...configs);
|
|
1671
|
+
const hasExplicitOffRules = Object.values(rules).some((value) => ruleConfigSeverity(value) === 0);
|
|
1672
|
+
if (!shouldMaterializeFileConfig && !hasRuleOptions(rules) && !hasExplicitOffRules && !options.forceMaterializedConfig) {
|
|
1547
1673
|
return callback({
|
|
1548
1674
|
...options,
|
|
1549
1675
|
config: shouldMaterializeFileConfig ? undefined : options.config,
|
|
@@ -1553,13 +1679,14 @@ function withTemporaryConfig(options, callback) {
|
|
|
1553
1679
|
}
|
|
1554
1680
|
|
|
1555
1681
|
const tmp = mkdtempSync(join(tmpdir(), "utoo-lint-config-"));
|
|
1556
|
-
const configPath = join(tmp, "
|
|
1682
|
+
const configPath = join(tmp, "utlint.config.json");
|
|
1557
1683
|
try {
|
|
1558
1684
|
writeFileSync(configPath, JSON.stringify({ rules }));
|
|
1559
1685
|
return callback({
|
|
1560
1686
|
...options,
|
|
1561
1687
|
config: shouldMaterializeFileConfig ? configPath : options.config ?? configPath,
|
|
1562
|
-
noConfig: false
|
|
1688
|
+
noConfig: false,
|
|
1689
|
+
rules: options.forceMaterializedConfig ? undefined : options.rules
|
|
1563
1690
|
});
|
|
1564
1691
|
} finally {
|
|
1565
1692
|
rmSync(tmp, { recursive: true, force: true });
|
|
@@ -1580,6 +1707,10 @@ function runtimeRulesFromConfigs(...configs) {
|
|
|
1580
1707
|
return rules;
|
|
1581
1708
|
}
|
|
1582
1709
|
|
|
1710
|
+
function materializedRulesFromConfigs(...configs) {
|
|
1711
|
+
return runtimeRulesFromConfigs(...configs);
|
|
1712
|
+
}
|
|
1713
|
+
|
|
1583
1714
|
function runtimeRulesFromConfig(config) {
|
|
1584
1715
|
if (!config) {
|
|
1585
1716
|
return {};
|
|
@@ -1593,9 +1724,7 @@ function runtimeRulesFromConfig(config) {
|
|
|
1593
1724
|
|
|
1594
1725
|
const rules = {};
|
|
1595
1726
|
for (const [rule, value] of Object.entries(rulesFromConfig(config))) {
|
|
1596
|
-
|
|
1597
|
-
rules[rule] = value;
|
|
1598
|
-
}
|
|
1727
|
+
rules[rule] = value;
|
|
1599
1728
|
}
|
|
1600
1729
|
return rules;
|
|
1601
1730
|
}
|
|
@@ -3509,19 +3638,19 @@ function reportToESLintResults(report, textOptions = {}) {
|
|
|
3509
3638
|
}
|
|
3510
3639
|
|
|
3511
3640
|
function normalizeReportDiagnostics(diagnostics, options = {}) {
|
|
3512
|
-
const filterUnconfiguredRules = hasRuleConfigSource(options);
|
|
3513
3641
|
return (diagnostics ?? []).flatMap((diagnostic) => {
|
|
3514
3642
|
if (!diagnostic?.ruleId) {
|
|
3515
3643
|
return [diagnostic];
|
|
3516
3644
|
}
|
|
3517
|
-
if (diagnostic.ruleId === "io") {
|
|
3645
|
+
if (diagnostic.ruleId === "io" || diagnostic.ruleId === "parse") {
|
|
3518
3646
|
return [diagnostic];
|
|
3519
3647
|
}
|
|
3520
3648
|
|
|
3521
3649
|
const filePath = normalizeESLintFilePath(diagnostic.filePath, options.cwd);
|
|
3650
|
+
const filterUnconfiguredRules = hasRuleConfigSource(options, filePath);
|
|
3522
3651
|
const ruleSeverities = ruleSeverityMapForOptions(options, filePath);
|
|
3523
3652
|
const severity = ruleSeverities?.get(diagnostic.ruleId);
|
|
3524
|
-
if (filterUnconfiguredRules && !ruleSeverities?.has(diagnostic.ruleId)) {
|
|
3653
|
+
if (!options.preserveNativeDefaults && filterUnconfiguredRules && !ruleSeverities?.has(diagnostic.ruleId)) {
|
|
3525
3654
|
return [];
|
|
3526
3655
|
}
|
|
3527
3656
|
if (severity === 0) {
|
|
@@ -3552,15 +3681,17 @@ function normalizeDiagnosticFilePaths(diagnostics, options = {}) {
|
|
|
3552
3681
|
}));
|
|
3553
3682
|
}
|
|
3554
3683
|
|
|
3555
|
-
function hasRuleConfigSource(options = {}) {
|
|
3556
|
-
if (options.
|
|
3684
|
+
function hasRuleConfigSource(options = {}, filePath) {
|
|
3685
|
+
if (options.baseConfig || options.overrideConfig || options.rules) {
|
|
3557
3686
|
return true;
|
|
3558
3687
|
}
|
|
3559
|
-
return !options.noConfig && Boolean(
|
|
3688
|
+
return !options.noConfig && Boolean(
|
|
3689
|
+
filePath ? configPathForFile(options, filePath) : configPathForOptions(options)
|
|
3690
|
+
);
|
|
3560
3691
|
}
|
|
3561
3692
|
|
|
3562
3693
|
function exitCodeForDiagnostics(diagnostics) {
|
|
3563
|
-
return
|
|
3694
|
+
return diagnostics?.some((diagnostic) => diagnostic?.severity === "error" || diagnostic?.severity === 2) ? 1 : 0;
|
|
3564
3695
|
}
|
|
3565
3696
|
|
|
3566
3697
|
function throwOnUnmatchedPatternDiagnostics(report, options = {}) {
|
|
@@ -3880,7 +4011,21 @@ function ignorePatternsFromFileConfig(options, filePath) {
|
|
|
3880
4011
|
return [];
|
|
3881
4012
|
}
|
|
3882
4013
|
|
|
3883
|
-
|
|
4014
|
+
const cwd = options.cwd ?? process.cwd();
|
|
4015
|
+
return ignorePatternsFromConfig(readConfig(configPath, options.cwd)).map((pattern) =>
|
|
4016
|
+
rebaseConfigPattern(pattern, dirname(configPath), cwd)
|
|
4017
|
+
);
|
|
4018
|
+
}
|
|
4019
|
+
|
|
4020
|
+
function rebaseConfigPattern(pattern, configDirectory, cwd) {
|
|
4021
|
+
const negated = pattern.startsWith("!");
|
|
4022
|
+
const value = negated ? pattern.slice(1) : pattern;
|
|
4023
|
+
const absolute = resolveConfigPattern(value, configDirectory);
|
|
4024
|
+
const relativePattern = normalizePath(relative(resolvePath(cwd), absolute));
|
|
4025
|
+
const rebased = relativePattern === ".." || relativePattern.startsWith("../")
|
|
4026
|
+
? normalizePath(absolute)
|
|
4027
|
+
: relativePattern;
|
|
4028
|
+
return negated ? `!${rebased}` : rebased;
|
|
3884
4029
|
}
|
|
3885
4030
|
|
|
3886
4031
|
function ignorePatternsFromConfig(config) {
|
package/index.d.ts
CHANGED
|
@@ -11,6 +11,10 @@ export interface LintMessage {
|
|
|
11
11
|
suggestions?: LintSuggestion[];
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
+
export interface LintDiagnostic extends Omit<LintMessage, "severity"> {
|
|
15
|
+
severity: "warning" | "error";
|
|
16
|
+
}
|
|
17
|
+
|
|
14
18
|
export interface LintFix {
|
|
15
19
|
range: [number, number];
|
|
16
20
|
text: string;
|
|
@@ -37,7 +41,7 @@ export interface LintResult {
|
|
|
37
41
|
export interface LintReport {
|
|
38
42
|
files: number;
|
|
39
43
|
filePaths: string[];
|
|
40
|
-
diagnostics:
|
|
44
|
+
diagnostics: LintDiagnostic[];
|
|
41
45
|
outputs?: Array<{ filePath: string; output: string }>;
|
|
42
46
|
exitCode: number;
|
|
43
47
|
stderr?: string;
|