lintmax 0.1.15
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.
Potentially problematic release.
This version of lintmax might be problematic. Click here for more details.
- package/dist/cli.d.mts +1 -0
- package/dist/cli.mjs +1569 -0
- package/dist/constants-Cjkf4mJh.mjs +105 -0
- package/dist/eslint.d.mts +9 -0
- package/dist/eslint.mjs +344 -0
- package/dist/ignores-BzTRqd-5.mjs +102 -0
- package/dist/index.d.mts +13 -0
- package/dist/index.mjs +2 -0
- package/dist/lintmax-types-CJ7VY33l.d.mts +69 -0
- package/dist/path-Cu_Nf2ct.mjs +168 -0
- package/dist/src-C8jQ6tK0.mjs +784 -0
- package/oxlintrc.json +104 -0
- package/package.json +83 -0
- package/tsconfig.json +27 -0
|
@@ -0,0 +1,784 @@
|
|
|
1
|
+
import { i as DEFAULT_SHARED_IGNORE_PATTERNS, n as BIOME_PATTERN_RULE_OVERRIDES, o as OXLINT_PATTERN_RULE_OVERRIDES, r as BIOME_RULES_OFF, s as SHARED_OVERRIDE_SYMBOL_KEY, t as BIOME_IGNORE_PATTERNS } from "./constants-Cjkf4mJh.mjs";
|
|
2
|
+
import { a as assertJsonSerializable, c as findUnknownRules, d as normalizeObjectListInput, f as normalizePathListInput, h as stripPluginNamespace, i as joinPath, l as isRecord, m as normalizeTailwindOption, n as fromFileUrl, o as assertObject, p as normalizeRulesOffInput, s as assertOptionalString, t as dirnamePath, u as normalizeIgnorePattern } from "./path-Cu_Nf2ct.mjs";
|
|
3
|
+
import { file, spawnSync, write } from "bun";
|
|
4
|
+
import { relative } from "node:path";
|
|
5
|
+
//#region src/core.ts
|
|
6
|
+
var CliExitError = class extends Error {
|
|
7
|
+
code;
|
|
8
|
+
name = "CliExitError";
|
|
9
|
+
constructor({ code, message }) {
|
|
10
|
+
super(message ?? "");
|
|
11
|
+
this.code = code;
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
const decoder = new TextDecoder();
|
|
15
|
+
const cacheDir = "node_modules/.cache/lintmax";
|
|
16
|
+
const cwd = process.cwd();
|
|
17
|
+
const ignoreEntries = [".cache/", ".eslintcache"];
|
|
18
|
+
const lintmaxRoot = dirnamePath(dirnamePath(fromFileUrl(import.meta.url)));
|
|
19
|
+
const PRETTIER_MD_ARGS = [
|
|
20
|
+
"--single-quote",
|
|
21
|
+
"--no-semi",
|
|
22
|
+
"--trailing-comma",
|
|
23
|
+
"none",
|
|
24
|
+
"--print-width",
|
|
25
|
+
"80",
|
|
26
|
+
"--arrow-parens",
|
|
27
|
+
"avoid",
|
|
28
|
+
"--tab-width",
|
|
29
|
+
"2",
|
|
30
|
+
"--prose-wrap",
|
|
31
|
+
"preserve"
|
|
32
|
+
];
|
|
33
|
+
const parseJsonObject = ({ text }) => {
|
|
34
|
+
const parsed = JSON.parse(text);
|
|
35
|
+
return isRecord(parsed) ? parsed : {};
|
|
36
|
+
};
|
|
37
|
+
const decodeText = (bytes) => decoder.decode(bytes ?? new Uint8Array());
|
|
38
|
+
const pathExists = async ({ path }) => file(path).exists();
|
|
39
|
+
const readJson = async ({ path }) => {
|
|
40
|
+
if (!await pathExists({ path })) return {};
|
|
41
|
+
try {
|
|
42
|
+
return parseJsonObject({ text: await file(path).text() });
|
|
43
|
+
} catch {
|
|
44
|
+
return {};
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
const readRequiredJson = async ({ path }) => {
|
|
48
|
+
const text = await file(path).text();
|
|
49
|
+
return JSON.parse(text);
|
|
50
|
+
};
|
|
51
|
+
const writeJson = async ({ data, path }) => write(path, `${JSON.stringify(data, null, 2)}\n`);
|
|
52
|
+
const ensureDirectory = ({ directory }) => {
|
|
53
|
+
const result = spawnSync({
|
|
54
|
+
cmd: [
|
|
55
|
+
"mkdir",
|
|
56
|
+
"-p",
|
|
57
|
+
directory
|
|
58
|
+
],
|
|
59
|
+
stderr: "pipe",
|
|
60
|
+
stdout: "pipe"
|
|
61
|
+
});
|
|
62
|
+
if (result.exitCode === 0) return;
|
|
63
|
+
const stderr = decodeText(result.stderr).trim();
|
|
64
|
+
throw new CliExitError({
|
|
65
|
+
code: result.exitCode,
|
|
66
|
+
message: stderr.length > 0 ? stderr : `Failed to create directory: ${directory}`
|
|
67
|
+
});
|
|
68
|
+
};
|
|
69
|
+
const resolvePackageJsonPath = async ({ pkg }) => {
|
|
70
|
+
try {
|
|
71
|
+
return fromFileUrl(import.meta.resolve(`${pkg}/package.json`));
|
|
72
|
+
} catch {
|
|
73
|
+
const consumerCandidate = joinPath(cwd, "node_modules", pkg, "package.json");
|
|
74
|
+
if (await pathExists({ path: consumerCandidate })) return consumerCandidate;
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
const resolveBin = async ({ bin, pkg }) => {
|
|
79
|
+
const packageJsonPath = await resolvePackageJsonPath({ pkg });
|
|
80
|
+
if (!packageJsonPath) throw new CliExitError({
|
|
81
|
+
code: 1,
|
|
82
|
+
message: `Cannot find ${pkg} — run: bun add -d ${pkg}`
|
|
83
|
+
});
|
|
84
|
+
const pkgJson = await readRequiredJson({ path: packageJsonPath });
|
|
85
|
+
return joinPath(dirnamePath(packageJsonPath), typeof pkgJson.bin === "string" ? pkgJson.bin : pkgJson.bin?.[bin] ?? "");
|
|
86
|
+
};
|
|
87
|
+
const run = ({ args, command, env, label, silent = false }) => {
|
|
88
|
+
const result = spawnSync({
|
|
89
|
+
cmd: [command, ...args],
|
|
90
|
+
cwd,
|
|
91
|
+
env,
|
|
92
|
+
stderr: silent ? "pipe" : "inherit",
|
|
93
|
+
stdout: silent ? "pipe" : "inherit"
|
|
94
|
+
});
|
|
95
|
+
if (result.exitCode === 0) return;
|
|
96
|
+
if (silent) {
|
|
97
|
+
process.stderr.write(`[${label}]\n`);
|
|
98
|
+
const stdout = decodeText(result.stdout);
|
|
99
|
+
if (stdout.length > 0) process.stderr.write(stdout);
|
|
100
|
+
const stderr = decodeText(result.stderr);
|
|
101
|
+
if (stderr.length > 0) process.stderr.write(stderr);
|
|
102
|
+
}
|
|
103
|
+
throw new CliExitError({ code: result.exitCode });
|
|
104
|
+
};
|
|
105
|
+
const runCapture = ({ args, command, env }) => {
|
|
106
|
+
const result = spawnSync({
|
|
107
|
+
cmd: [command, ...args],
|
|
108
|
+
cwd,
|
|
109
|
+
env,
|
|
110
|
+
stderr: "pipe",
|
|
111
|
+
stdout: "pipe"
|
|
112
|
+
});
|
|
113
|
+
return {
|
|
114
|
+
exitCode: result.exitCode,
|
|
115
|
+
stderr: decodeText(result.stderr),
|
|
116
|
+
stdout: decodeText(result.stdout)
|
|
117
|
+
};
|
|
118
|
+
};
|
|
119
|
+
const readVersion = async () => {
|
|
120
|
+
return (await readRequiredJson({ path: joinPath(lintmaxRoot, "package.json") })).version;
|
|
121
|
+
};
|
|
122
|
+
const usage = ({ version }) => {
|
|
123
|
+
process.stdout.write(`lintmax v${version}\n\n`);
|
|
124
|
+
process.stdout.write("Usage: lintmax <command>\n\n");
|
|
125
|
+
process.stdout.write("Commands:\n");
|
|
126
|
+
process.stdout.write(" init Scaffold config files for a new project\n");
|
|
127
|
+
process.stdout.write(" fix Auto-fix and format all files\n");
|
|
128
|
+
process.stdout.write(" check Check all files without modifying\n");
|
|
129
|
+
process.stdout.write(" rules List all enabled rules\n");
|
|
130
|
+
process.stdout.write(" --version Show version\n");
|
|
131
|
+
};
|
|
132
|
+
//#endregion
|
|
133
|
+
//#region src/index.ts
|
|
134
|
+
const SHARED_OVERRIDE_KEYS = [
|
|
135
|
+
"biome",
|
|
136
|
+
"eslint",
|
|
137
|
+
"oxlint"
|
|
138
|
+
];
|
|
139
|
+
const ESLINT_IMPORT_MARKER_KEY = "__lintmaxImportRef";
|
|
140
|
+
const ESLINT_IMPORT_SENTINEL = "eslint-import";
|
|
141
|
+
const pkgRoot = dirnamePath(fromFileUrl(import.meta.resolve("../package.json")));
|
|
142
|
+
const normalizeBiomeIgnorePattern = ({ pattern }) => {
|
|
143
|
+
if (pattern.startsWith("!!")) return pattern;
|
|
144
|
+
const trimmed = normalizeIgnorePattern({ pattern });
|
|
145
|
+
return trimmed.startsWith("**/") ? `!!${trimmed}` : `!!**/${trimmed}`;
|
|
146
|
+
};
|
|
147
|
+
const resolveSchemaPath = async ({ cwd }) => {
|
|
148
|
+
try {
|
|
149
|
+
return fromFileUrl(import.meta.resolve("@biomejs/biome/configuration_schema.json"));
|
|
150
|
+
} catch (error) {
|
|
151
|
+
if (!(error instanceof Error)) throw error;
|
|
152
|
+
}
|
|
153
|
+
const consumerCandidate = joinPath(cwd, "node_modules", "@biomejs", "biome", "configuration_schema.json");
|
|
154
|
+
if (await file(consumerCandidate).exists()) return consumerCandidate;
|
|
155
|
+
throw new Error("Cannot find module @biomejs/biome/configuration_schema.json");
|
|
156
|
+
};
|
|
157
|
+
const resolveBiomeSchema = async ({ cwd }) => {
|
|
158
|
+
const schema = await readRequiredJson({ path: await resolveSchemaPath({ cwd }) });
|
|
159
|
+
const rulesProps = schema.$defs.Rules?.properties ?? {};
|
|
160
|
+
const categories = Object.keys(rulesProps).filter((k) => k !== "recommended");
|
|
161
|
+
const ruleMap = /* @__PURE__ */ new Map();
|
|
162
|
+
for (const cat of categories) {
|
|
163
|
+
const key = cat.charAt(0).toUpperCase() + cat.slice(1);
|
|
164
|
+
const props = schema.$defs[key]?.properties;
|
|
165
|
+
if (props) {
|
|
166
|
+
for (const rule of Object.keys(props)) if (rule !== "recommended" && rule !== "all") ruleMap.set(rule, cat);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
return {
|
|
170
|
+
categories,
|
|
171
|
+
ruleMap
|
|
172
|
+
};
|
|
173
|
+
};
|
|
174
|
+
const extractRuleNames = (rules) => {
|
|
175
|
+
const names = [];
|
|
176
|
+
for (const key of Object.keys(rules)) names.push(stripPluginNamespace({ rule: key }));
|
|
177
|
+
return names;
|
|
178
|
+
};
|
|
179
|
+
const assertKnownBiomeRuleNames = ({ categoryMap, label, rules }) => {
|
|
180
|
+
const unknown = findUnknownRules({
|
|
181
|
+
knownRules: new Set(categoryMap.keys()),
|
|
182
|
+
normalizeRule: (rule) => stripPluginNamespace({ rule }),
|
|
183
|
+
rules
|
|
184
|
+
});
|
|
185
|
+
if (unknown.length > 0) throw new Error(`${label} contains unknown biome rules: ${unknown.join(", ")}`);
|
|
186
|
+
};
|
|
187
|
+
const assertKnownOxlintRuleNames = ({ label, rules, knownRules }) => {
|
|
188
|
+
const unknown = findUnknownRules({
|
|
189
|
+
knownRules,
|
|
190
|
+
rules
|
|
191
|
+
});
|
|
192
|
+
if (unknown.length > 0) throw new Error(`${label} contains unknown oxlint rules: ${unknown.join(", ")}`);
|
|
193
|
+
};
|
|
194
|
+
const groupByCategory = ({ categoryMap, ruleNames }) => {
|
|
195
|
+
const result = {};
|
|
196
|
+
for (const rule of ruleNames) {
|
|
197
|
+
const cat = categoryMap.get(rule);
|
|
198
|
+
if (cat) {
|
|
199
|
+
result[cat] ??= {};
|
|
200
|
+
result[cat][rule] = "off";
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
return result;
|
|
204
|
+
};
|
|
205
|
+
const normalizeSharedOverrideItem = ({ index, item, label }) => {
|
|
206
|
+
const files = normalizePathListInput({
|
|
207
|
+
label: `${label}[${index}].files`,
|
|
208
|
+
value: item.files
|
|
209
|
+
});
|
|
210
|
+
const biomeRules = normalizeRulesOffInput({
|
|
211
|
+
label: `${label}[${index}].biome`,
|
|
212
|
+
value: item.biome
|
|
213
|
+
});
|
|
214
|
+
const eslintRules = normalizeRulesOffInput({
|
|
215
|
+
label: `${label}[${index}].eslint`,
|
|
216
|
+
value: item.eslint
|
|
217
|
+
});
|
|
218
|
+
const oxlintRules = normalizeRulesOffInput({
|
|
219
|
+
label: `${label}[${index}].oxlint`,
|
|
220
|
+
value: item.oxlint
|
|
221
|
+
});
|
|
222
|
+
if (!(biomeRules || eslintRules || oxlintRules)) throw new Error(`${label}[${index}] must define at least one action: biome, eslint, or oxlint`);
|
|
223
|
+
return {
|
|
224
|
+
biomeRules,
|
|
225
|
+
eslintRules,
|
|
226
|
+
files,
|
|
227
|
+
oxlintRules
|
|
228
|
+
};
|
|
229
|
+
};
|
|
230
|
+
const normalizeSharedOverrides = ({ label, value }) => {
|
|
231
|
+
const out = [];
|
|
232
|
+
if (value === void 0) return out;
|
|
233
|
+
const obj = assertObject({
|
|
234
|
+
label,
|
|
235
|
+
value
|
|
236
|
+
});
|
|
237
|
+
const entries = [];
|
|
238
|
+
for (const [pattern, rawOverride] of Object.entries(obj)) {
|
|
239
|
+
const override = assertObject({
|
|
240
|
+
label: `${label}.${pattern}`,
|
|
241
|
+
value: rawOverride
|
|
242
|
+
});
|
|
243
|
+
for (const key of Object.keys(override)) if (!SHARED_OVERRIDE_KEYS.includes(key)) throw new Error(`${label}.${pattern}.${key} is not supported. Use biome, eslint, or oxlint.`);
|
|
244
|
+
entries.push({
|
|
245
|
+
...override,
|
|
246
|
+
files: [pattern]
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
for (const [i, item] of entries.entries()) out.push(normalizeSharedOverrideItem({
|
|
250
|
+
index: i,
|
|
251
|
+
item,
|
|
252
|
+
label
|
|
253
|
+
}));
|
|
254
|
+
return out;
|
|
255
|
+
};
|
|
256
|
+
const collectSharedRuleOverrides = ({ ruleKey, sharedOverrides }) => {
|
|
257
|
+
const out = [];
|
|
258
|
+
for (const override of sharedOverrides) {
|
|
259
|
+
const rules = override[ruleKey];
|
|
260
|
+
if (rules) out.push({
|
|
261
|
+
files: override.files,
|
|
262
|
+
rules
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
return out;
|
|
266
|
+
};
|
|
267
|
+
const parseLinterOffOverrides = ({ assertKnownRules, fileKey, label, requireOff = false, value }) => {
|
|
268
|
+
const out = [];
|
|
269
|
+
for (const [i, override] of normalizeObjectListInput({
|
|
270
|
+
label,
|
|
271
|
+
value
|
|
272
|
+
}).entries()) {
|
|
273
|
+
const itemLabel = requireOff ? `${label}[${i}]` : label;
|
|
274
|
+
if (requireOff && override[fileKey] === void 0) throw new Error(`${label}[${i}].${fileKey} is required`);
|
|
275
|
+
if (requireOff && override.off === void 0) throw new Error(`${label}[${i}].off is required`);
|
|
276
|
+
const normalizedOverrideRules = normalizeRulesOffInput({
|
|
277
|
+
label: `${itemLabel}.off`,
|
|
278
|
+
value: override.off
|
|
279
|
+
});
|
|
280
|
+
if (normalizedOverrideRules) {
|
|
281
|
+
assertKnownRules?.(normalizedOverrideRules);
|
|
282
|
+
out.push({
|
|
283
|
+
files: normalizePathListInput({
|
|
284
|
+
label: `${itemLabel}.${fileKey}`,
|
|
285
|
+
value: override[fileKey]
|
|
286
|
+
}),
|
|
287
|
+
rules: normalizedOverrideRules
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
return out;
|
|
292
|
+
};
|
|
293
|
+
const parseTopLevelSyncScalars = ({ options }) => {
|
|
294
|
+
if (options.compact !== void 0 && typeof options.compact !== "boolean") throw new Error("compact must be a boolean");
|
|
295
|
+
const tailwind = normalizeTailwindOption({
|
|
296
|
+
label: "tailwind",
|
|
297
|
+
value: options.tailwind
|
|
298
|
+
});
|
|
299
|
+
assertOptionalString({
|
|
300
|
+
label: "tsconfigRootDir",
|
|
301
|
+
value: options.tsconfigRootDir
|
|
302
|
+
});
|
|
303
|
+
return {
|
|
304
|
+
sharedOverrides: options.overrides === void 0 ? [] : normalizeSharedOverrides({
|
|
305
|
+
label: "overrides",
|
|
306
|
+
value: options.overrides
|
|
307
|
+
}),
|
|
308
|
+
tailwind,
|
|
309
|
+
topLevelIgnores: options.ignores === void 0 ? [] : normalizePathListInput({
|
|
310
|
+
label: "ignores",
|
|
311
|
+
value: options.ignores
|
|
312
|
+
}),
|
|
313
|
+
tsconfigRootDir: options.tsconfigRootDir
|
|
314
|
+
};
|
|
315
|
+
};
|
|
316
|
+
const parseLinterSyncCommon = ({ linter, value }) => {
|
|
317
|
+
const parsed = {};
|
|
318
|
+
if (value.ignores !== void 0) parsed.ignores = normalizePathListInput({
|
|
319
|
+
label: `${linter}.ignores`,
|
|
320
|
+
value: value.ignores
|
|
321
|
+
});
|
|
322
|
+
const normalizedOffRules = normalizeRulesOffInput({
|
|
323
|
+
label: `${linter}.off`,
|
|
324
|
+
value: value.off
|
|
325
|
+
});
|
|
326
|
+
if (normalizedOffRules) parsed.off = Object.keys(normalizedOffRules);
|
|
327
|
+
return parsed;
|
|
328
|
+
};
|
|
329
|
+
const validateBiomeSyncConfig = ({ biome }) => {
|
|
330
|
+
const biomeValue = assertObject({
|
|
331
|
+
label: "biome config",
|
|
332
|
+
value: biome
|
|
333
|
+
});
|
|
334
|
+
const parsedCommon = parseLinterSyncCommon({
|
|
335
|
+
linter: "biome",
|
|
336
|
+
value: biomeValue
|
|
337
|
+
});
|
|
338
|
+
const parsedOverrides = parseLinterOffOverrides({
|
|
339
|
+
fileKey: "includes",
|
|
340
|
+
label: "biome.overrides",
|
|
341
|
+
requireOff: true,
|
|
342
|
+
value: biomeValue.overrides
|
|
343
|
+
}).map((override) => ({
|
|
344
|
+
includes: override.files,
|
|
345
|
+
off: Object.keys(override.rules)
|
|
346
|
+
}));
|
|
347
|
+
const parsed = { ...parsedCommon };
|
|
348
|
+
if (parsedOverrides.length > 0) parsed.overrides = parsedOverrides;
|
|
349
|
+
return parsed;
|
|
350
|
+
};
|
|
351
|
+
const parseEslintAppendEntry = ({ index, item }) => {
|
|
352
|
+
const { $lintmax: marker } = item;
|
|
353
|
+
if (marker === ESLINT_IMPORT_SENTINEL) {
|
|
354
|
+
const allowedKeys = new Set([
|
|
355
|
+
"$lintmax",
|
|
356
|
+
"files",
|
|
357
|
+
"from",
|
|
358
|
+
"ignores",
|
|
359
|
+
"name"
|
|
360
|
+
]);
|
|
361
|
+
for (const key of Object.keys(item)) if (!allowedKeys.has(key)) throw new Error(`eslint.append[${index}].${key} is not supported for eslint-import entries. Use from, name, files, ignores.`);
|
|
362
|
+
assertOptionalString({
|
|
363
|
+
label: `eslint.append[${index}].from`,
|
|
364
|
+
value: item.from
|
|
365
|
+
});
|
|
366
|
+
const { from } = item;
|
|
367
|
+
if (typeof from !== "string" || from.trim().length === 0) throw new Error(`eslint.append[${index}].from must be a non-empty string`);
|
|
368
|
+
assertOptionalString({
|
|
369
|
+
label: `eslint.append[${index}].name`,
|
|
370
|
+
value: item.name
|
|
371
|
+
});
|
|
372
|
+
return {
|
|
373
|
+
files: item.files === void 0 ? void 0 : normalizePathListInput({
|
|
374
|
+
label: `eslint.append[${index}].files`,
|
|
375
|
+
value: item.files
|
|
376
|
+
}),
|
|
377
|
+
from,
|
|
378
|
+
ignores: item.ignores === void 0 ? void 0 : normalizePathListInput({
|
|
379
|
+
label: `eslint.append[${index}].ignores`,
|
|
380
|
+
value: item.ignores
|
|
381
|
+
}),
|
|
382
|
+
name: typeof item.name === "string" && item.name.trim().length > 0 ? item.name : "default"
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
if ("$lintmax" in item) throw new Error(`eslint.append[${index}].$lintmax has unsupported value. Use eslintImport(...) or remove the $lintmax key.`);
|
|
386
|
+
assertJsonSerializable({
|
|
387
|
+
label: `eslint.append[${index}]`,
|
|
388
|
+
value: item
|
|
389
|
+
});
|
|
390
|
+
return { config: item };
|
|
391
|
+
};
|
|
392
|
+
const validateEslintSyncConfig = ({ eslint }) => {
|
|
393
|
+
const eslintValue = assertObject({
|
|
394
|
+
label: "eslint config",
|
|
395
|
+
value: eslint
|
|
396
|
+
});
|
|
397
|
+
const parsed = { ...parseLinterSyncCommon({
|
|
398
|
+
linter: "eslint",
|
|
399
|
+
value: eslintValue
|
|
400
|
+
}) };
|
|
401
|
+
if (eslintValue.tailwind !== void 0) throw new Error("eslint.tailwind is not supported in sync config. Use top-level tailwind.");
|
|
402
|
+
if (eslintValue.tsconfigRootDir !== void 0) throw new Error("eslint.tsconfigRootDir is not supported in sync config. Use top-level tsconfigRootDir.");
|
|
403
|
+
if (eslintValue.append !== void 0) parsed.append = normalizeObjectListInput({
|
|
404
|
+
label: "eslint.append",
|
|
405
|
+
value: eslintValue.append
|
|
406
|
+
}).map((item, i) => parseEslintAppendEntry({
|
|
407
|
+
index: i,
|
|
408
|
+
item
|
|
409
|
+
}));
|
|
410
|
+
return parsed;
|
|
411
|
+
};
|
|
412
|
+
const validateOxlintSyncConfig = ({ oxlint }) => {
|
|
413
|
+
const oxlintValue = assertObject({
|
|
414
|
+
label: "oxlint config",
|
|
415
|
+
value: oxlint
|
|
416
|
+
});
|
|
417
|
+
const parsedCommon = parseLinterSyncCommon({
|
|
418
|
+
linter: "oxlint",
|
|
419
|
+
value: oxlintValue
|
|
420
|
+
});
|
|
421
|
+
const parsedOverrides = parseLinterOffOverrides({
|
|
422
|
+
fileKey: "files",
|
|
423
|
+
label: "oxlint.overrides",
|
|
424
|
+
requireOff: true,
|
|
425
|
+
value: oxlintValue.overrides
|
|
426
|
+
}).map((override) => ({
|
|
427
|
+
files: override.files,
|
|
428
|
+
off: Object.keys(override.rules)
|
|
429
|
+
}));
|
|
430
|
+
const parsed = { ...parsedCommon };
|
|
431
|
+
if (parsedOverrides.length > 0) parsed.overrides = parsedOverrides;
|
|
432
|
+
return parsed;
|
|
433
|
+
};
|
|
434
|
+
const validateSyncOptions = ({ options }) => {
|
|
435
|
+
if (!options) return {
|
|
436
|
+
sharedOverrides: [],
|
|
437
|
+
topLevelIgnores: []
|
|
438
|
+
};
|
|
439
|
+
const parsed = { ...parseTopLevelSyncScalars({ options }) };
|
|
440
|
+
if (options.biome) parsed.biome = validateBiomeSyncConfig({ biome: options.biome });
|
|
441
|
+
if (options.eslint) parsed.eslint = validateEslintSyncConfig({ eslint: options.eslint });
|
|
442
|
+
if (options.oxlint) parsed.oxlint = validateOxlintSyncConfig({ oxlint: options.oxlint });
|
|
443
|
+
return parsed;
|
|
444
|
+
};
|
|
445
|
+
const mergeUniquePatterns = ({ into, patterns }) => {
|
|
446
|
+
if (!patterns) return;
|
|
447
|
+
for (const raw of patterns) {
|
|
448
|
+
const pattern = normalizeIgnorePattern({ pattern: raw });
|
|
449
|
+
if (pattern.length > 0 && !into.includes(pattern)) into.push(pattern);
|
|
450
|
+
}
|
|
451
|
+
};
|
|
452
|
+
const mergeIgnorePatternGroups = ({ groups }) => {
|
|
453
|
+
const merged = [];
|
|
454
|
+
for (const group of groups) mergeUniquePatterns({
|
|
455
|
+
into: merged,
|
|
456
|
+
patterns: group
|
|
457
|
+
});
|
|
458
|
+
return merged;
|
|
459
|
+
};
|
|
460
|
+
const buildUserIgnorePatterns = ({ topLevelIgnores }) => mergeIgnorePatternGroups({ groups: [topLevelIgnores] });
|
|
461
|
+
const buildLinterOptionsWithSharedOverrides = ({ createEmpty, ruleKey, sharedOverrides, source, mapSharedOverride }) => {
|
|
462
|
+
if (!(source || sharedOverrides.length > 0)) return source;
|
|
463
|
+
const next = source ? { ...source } : createEmpty();
|
|
464
|
+
next.off = source?.off;
|
|
465
|
+
const sharedRuleOverrides = collectSharedRuleOverrides({
|
|
466
|
+
ruleKey,
|
|
467
|
+
sharedOverrides
|
|
468
|
+
}).map(mapSharedOverride);
|
|
469
|
+
const localOverrides = source?.overrides ?? [];
|
|
470
|
+
const mergedOverrides = [...sharedRuleOverrides, ...localOverrides];
|
|
471
|
+
if (mergedOverrides.length > 0) next.overrides = mergedOverrides;
|
|
472
|
+
return next;
|
|
473
|
+
};
|
|
474
|
+
const buildBiomeOptions = ({ biomeSource, sharedOverrides }) => buildLinterOptionsWithSharedOverrides({
|
|
475
|
+
createEmpty: () => ({}),
|
|
476
|
+
mapSharedOverride: (override) => ({
|
|
477
|
+
includes: override.files,
|
|
478
|
+
off: Object.keys(override.rules)
|
|
479
|
+
}),
|
|
480
|
+
ruleKey: "biomeRules",
|
|
481
|
+
sharedOverrides,
|
|
482
|
+
source: biomeSource
|
|
483
|
+
});
|
|
484
|
+
const buildOxlintOptions = ({ oxlintSource, sharedOverrides }) => buildLinterOptionsWithSharedOverrides({
|
|
485
|
+
createEmpty: () => ({}),
|
|
486
|
+
mapSharedOverride: (override) => ({
|
|
487
|
+
files: override.files,
|
|
488
|
+
off: Object.keys(override.rules)
|
|
489
|
+
}),
|
|
490
|
+
ruleKey: "oxlintRules",
|
|
491
|
+
sharedOverrides,
|
|
492
|
+
source: oxlintSource
|
|
493
|
+
});
|
|
494
|
+
const buildEslintIgnorePatterns = ({ eslintSource, userIgnorePatterns }) => mergeIgnorePatternGroups({ groups: [userIgnorePatterns, eslintSource?.ignores === void 0 ? void 0 : normalizePathListInput({
|
|
495
|
+
label: "eslint.ignores",
|
|
496
|
+
value: eslintSource.ignores
|
|
497
|
+
})] });
|
|
498
|
+
const buildEslintOptions = ({ eslintSource, sharedOverrides, tailwind, tsconfigRootDir, userIgnorePatterns }) => {
|
|
499
|
+
const eslintIgnores = buildEslintIgnorePatterns({
|
|
500
|
+
eslintSource,
|
|
501
|
+
userIgnorePatterns
|
|
502
|
+
});
|
|
503
|
+
const sharedRuleOverrides = collectSharedRuleOverrides({
|
|
504
|
+
ruleKey: "eslintRules",
|
|
505
|
+
sharedOverrides
|
|
506
|
+
}).map((override) => ({
|
|
507
|
+
files: override.files,
|
|
508
|
+
rules: override.rules
|
|
509
|
+
}));
|
|
510
|
+
const sharedOverrideAppendIndexes = sharedRuleOverrides.map((_, index) => index);
|
|
511
|
+
const eslintImportRefs = [];
|
|
512
|
+
if (eslintSource || sharedOverrides.length > 0 || tailwind !== void 0 || tsconfigRootDir !== void 0) {
|
|
513
|
+
const eslintOptions = { off: eslintSource?.off };
|
|
514
|
+
if (eslintIgnores.length > 0) eslintOptions.ignores = eslintIgnores;
|
|
515
|
+
const appendEntries = [];
|
|
516
|
+
for (const entry of eslintSource?.append ?? []) if ("config" in entry) appendEntries.push(entry.config);
|
|
517
|
+
else {
|
|
518
|
+
const importRefIndex = eslintImportRefs.push({
|
|
519
|
+
exportName: entry.name,
|
|
520
|
+
files: entry.files,
|
|
521
|
+
ignores: entry.ignores,
|
|
522
|
+
source: entry.from
|
|
523
|
+
});
|
|
524
|
+
appendEntries.push({ [ESLINT_IMPORT_MARKER_KEY]: importRefIndex - 1 });
|
|
525
|
+
}
|
|
526
|
+
const mergedAppend = [...sharedRuleOverrides, ...appendEntries];
|
|
527
|
+
if (mergedAppend.length > 0) eslintOptions.append = mergedAppend;
|
|
528
|
+
eslintOptions.tailwind = normalizeTailwindOption({
|
|
529
|
+
label: "tailwind",
|
|
530
|
+
value: tailwind
|
|
531
|
+
}) ?? true;
|
|
532
|
+
eslintOptions.tsconfigRootDir = tsconfigRootDir;
|
|
533
|
+
return {
|
|
534
|
+
eslintImportRefs,
|
|
535
|
+
eslintOptions,
|
|
536
|
+
sharedOverrideAppendIndexes
|
|
537
|
+
};
|
|
538
|
+
}
|
|
539
|
+
if (eslintIgnores.length === 0) return {
|
|
540
|
+
eslintImportRefs,
|
|
541
|
+
eslintOptions: void 0,
|
|
542
|
+
sharedOverrideAppendIndexes
|
|
543
|
+
};
|
|
544
|
+
return {
|
|
545
|
+
eslintImportRefs,
|
|
546
|
+
eslintOptions: {
|
|
547
|
+
ignores: eslintIgnores,
|
|
548
|
+
tailwind: true
|
|
549
|
+
},
|
|
550
|
+
sharedOverrideAppendIndexes
|
|
551
|
+
};
|
|
552
|
+
};
|
|
553
|
+
const normalizeLinterOffOverrides = ({ assertKnownRules, fileKey, label, value }) => parseLinterOffOverrides({
|
|
554
|
+
assertKnownRules,
|
|
555
|
+
fileKey,
|
|
556
|
+
label,
|
|
557
|
+
value
|
|
558
|
+
});
|
|
559
|
+
const normalizeKnownOffRules = ({ assertKnownRules, label, value }) => {
|
|
560
|
+
const normalizedRules = normalizeRulesOffInput({
|
|
561
|
+
label,
|
|
562
|
+
value
|
|
563
|
+
});
|
|
564
|
+
if (!normalizedRules) return;
|
|
565
|
+
assertKnownRules?.(normalizedRules);
|
|
566
|
+
return normalizedRules;
|
|
567
|
+
};
|
|
568
|
+
const createBiomeConfig = async ({ cwd, options, sharedIgnorePatterns }) => {
|
|
569
|
+
const { categories, ruleMap } = await resolveBiomeSchema({ cwd });
|
|
570
|
+
const allRulesOff = [...BIOME_RULES_OFF];
|
|
571
|
+
const normalizedRules = normalizeKnownOffRules({
|
|
572
|
+
assertKnownRules: (rules) => assertKnownBiomeRuleNames({
|
|
573
|
+
categoryMap: ruleMap,
|
|
574
|
+
label: "biome.off",
|
|
575
|
+
rules
|
|
576
|
+
}),
|
|
577
|
+
label: "biome.off",
|
|
578
|
+
value: options?.off
|
|
579
|
+
});
|
|
580
|
+
if (normalizedRules) for (const key of Object.keys(normalizedRules)) {
|
|
581
|
+
const ruleName = stripPluginNamespace({ rule: key });
|
|
582
|
+
if (!allRulesOff.includes(ruleName)) allRulesOff.push(ruleName);
|
|
583
|
+
}
|
|
584
|
+
const ignorePatterns = [...BIOME_IGNORE_PATTERNS];
|
|
585
|
+
const mergedIgnorePatterns = mergeIgnorePatternGroups({ groups: [sharedIgnorePatterns, options?.ignores === void 0 ? void 0 : normalizePathListInput({
|
|
586
|
+
label: "biome.ignores",
|
|
587
|
+
value: options.ignores
|
|
588
|
+
})] });
|
|
589
|
+
for (const pattern of mergedIgnorePatterns) {
|
|
590
|
+
const negated = normalizeBiomeIgnorePattern({ pattern });
|
|
591
|
+
if (!ignorePatterns.includes(negated)) ignorePatterns.push(negated);
|
|
592
|
+
}
|
|
593
|
+
const overrides = [{
|
|
594
|
+
css: { parser: { tailwindDirectives: true } },
|
|
595
|
+
includes: ["**"],
|
|
596
|
+
linter: { rules: groupByCategory({
|
|
597
|
+
categoryMap: ruleMap,
|
|
598
|
+
ruleNames: allRulesOff
|
|
599
|
+
}) }
|
|
600
|
+
}];
|
|
601
|
+
for (const override of BIOME_PATTERN_RULE_OVERRIDES) overrides.push({
|
|
602
|
+
includes: [...override.includes],
|
|
603
|
+
linter: { rules: groupByCategory({
|
|
604
|
+
categoryMap: ruleMap,
|
|
605
|
+
ruleNames: override.rules
|
|
606
|
+
}) }
|
|
607
|
+
});
|
|
608
|
+
for (const override of normalizeLinterOffOverrides({
|
|
609
|
+
assertKnownRules: (rules) => assertKnownBiomeRuleNames({
|
|
610
|
+
categoryMap: ruleMap,
|
|
611
|
+
label: "biome.overrides.off",
|
|
612
|
+
rules
|
|
613
|
+
}),
|
|
614
|
+
fileKey: "includes",
|
|
615
|
+
label: "biome.overrides",
|
|
616
|
+
value: options?.overrides
|
|
617
|
+
})) overrides.push({
|
|
618
|
+
includes: override.files,
|
|
619
|
+
linter: { rules: groupByCategory({
|
|
620
|
+
categoryMap: ruleMap,
|
|
621
|
+
ruleNames: extractRuleNames(override.rules)
|
|
622
|
+
}) }
|
|
623
|
+
});
|
|
624
|
+
return {
|
|
625
|
+
$schema: "https://biomejs.dev/schemas/latest/schema.json",
|
|
626
|
+
assist: { actions: { source: { organizeImports: "off" } } },
|
|
627
|
+
css: {
|
|
628
|
+
formatter: {
|
|
629
|
+
enabled: true,
|
|
630
|
+
quoteStyle: "single"
|
|
631
|
+
},
|
|
632
|
+
parser: { tailwindDirectives: true }
|
|
633
|
+
},
|
|
634
|
+
files: { includes: ["**", ...ignorePatterns] },
|
|
635
|
+
formatter: {
|
|
636
|
+
indentStyle: "space",
|
|
637
|
+
lineWidth: 123
|
|
638
|
+
},
|
|
639
|
+
javascript: { formatter: {
|
|
640
|
+
arrowParentheses: "asNeeded",
|
|
641
|
+
bracketSameLine: true,
|
|
642
|
+
jsxQuoteStyle: "single",
|
|
643
|
+
quoteStyle: "single",
|
|
644
|
+
semicolons: "asNeeded",
|
|
645
|
+
trailingCommas: "none"
|
|
646
|
+
} },
|
|
647
|
+
json: { formatter: { trailingCommas: "none" } },
|
|
648
|
+
linter: {
|
|
649
|
+
domains: {
|
|
650
|
+
next: "all",
|
|
651
|
+
project: "all",
|
|
652
|
+
qwik: "all",
|
|
653
|
+
react: "all",
|
|
654
|
+
solid: "all",
|
|
655
|
+
tailwind: "all",
|
|
656
|
+
test: "all",
|
|
657
|
+
vue: "all"
|
|
658
|
+
},
|
|
659
|
+
rules: Object.fromEntries(categories.map((c) => [c, "error"]))
|
|
660
|
+
},
|
|
661
|
+
overrides
|
|
662
|
+
};
|
|
663
|
+
};
|
|
664
|
+
const createOxlintConfig = async ({ options, sharedIgnorePatterns }) => {
|
|
665
|
+
const base = await readRequiredJson({ path: joinPath(pkgRoot, "oxlintrc.json") });
|
|
666
|
+
const knownRules = new Set([
|
|
667
|
+
...Object.keys(base.rules),
|
|
668
|
+
...(base.overrides ?? []).flatMap((override) => Object.keys(override.rules)),
|
|
669
|
+
...OXLINT_PATTERN_RULE_OVERRIDES.flatMap((override) => Object.keys(override.rules))
|
|
670
|
+
]);
|
|
671
|
+
const mergedIgnorePatterns = mergeIgnorePatternGroups({ groups: [sharedIgnorePatterns, options?.ignores === void 0 ? void 0 : normalizePathListInput({
|
|
672
|
+
label: "oxlint.ignores",
|
|
673
|
+
value: options.ignores
|
|
674
|
+
})] });
|
|
675
|
+
base.overrides ??= [];
|
|
676
|
+
for (const override of OXLINT_PATTERN_RULE_OVERRIDES) base.overrides.push({
|
|
677
|
+
files: [...override.files],
|
|
678
|
+
rules: { ...override.rules }
|
|
679
|
+
});
|
|
680
|
+
if (mergedIgnorePatterns.length > 0) {
|
|
681
|
+
base.ignorePatterns ??= [];
|
|
682
|
+
for (const pattern of mergedIgnorePatterns) if (!base.ignorePatterns.includes(pattern)) base.ignorePatterns.push(pattern);
|
|
683
|
+
}
|
|
684
|
+
if (!options) return base;
|
|
685
|
+
const normalizedRules = normalizeKnownOffRules({
|
|
686
|
+
assertKnownRules: (rules) => assertKnownOxlintRuleNames({
|
|
687
|
+
knownRules,
|
|
688
|
+
label: "oxlint.off",
|
|
689
|
+
rules
|
|
690
|
+
}),
|
|
691
|
+
label: "oxlint.off",
|
|
692
|
+
value: options.off
|
|
693
|
+
});
|
|
694
|
+
if (normalizedRules) for (const [key, value] of Object.entries(normalizedRules)) base.rules[key] = value;
|
|
695
|
+
for (const override of normalizeLinterOffOverrides({
|
|
696
|
+
assertKnownRules: (rules) => assertKnownOxlintRuleNames({
|
|
697
|
+
knownRules,
|
|
698
|
+
label: "oxlint.overrides.off",
|
|
699
|
+
rules
|
|
700
|
+
}),
|
|
701
|
+
fileKey: "files",
|
|
702
|
+
label: "oxlint.overrides",
|
|
703
|
+
value: options.overrides
|
|
704
|
+
})) base.overrides.push({
|
|
705
|
+
files: override.files,
|
|
706
|
+
rules: override.rules
|
|
707
|
+
});
|
|
708
|
+
return base;
|
|
709
|
+
};
|
|
710
|
+
const resolveSyncImportSource = ({ cwd, dir, source }) => {
|
|
711
|
+
if (!(source.startsWith(".") || source.startsWith(".."))) return source;
|
|
712
|
+
const relativeSource = relative(dir, joinPath(cwd, source)).replaceAll("\\", "/");
|
|
713
|
+
return relativeSource.startsWith(".") ? relativeSource : `./${relativeSource}`;
|
|
714
|
+
};
|
|
715
|
+
const sync = async (options) => {
|
|
716
|
+
const { biome, eslint, oxlint, sharedOverrides, tailwind, topLevelIgnores, tsconfigRootDir } = validateSyncOptions({ options });
|
|
717
|
+
const cwd = process.cwd();
|
|
718
|
+
const dir = joinPath(cwd, cacheDir);
|
|
719
|
+
const userIgnorePatterns = buildUserIgnorePatterns({ topLevelIgnores });
|
|
720
|
+
const sharedIgnorePatterns = mergeIgnorePatternGroups({ groups: [DEFAULT_SHARED_IGNORE_PATTERNS, userIgnorePatterns] });
|
|
721
|
+
const biomeOptions = buildBiomeOptions({
|
|
722
|
+
biomeSource: biome,
|
|
723
|
+
sharedOverrides
|
|
724
|
+
});
|
|
725
|
+
const oxlintOptions = buildOxlintOptions({
|
|
726
|
+
oxlintSource: oxlint,
|
|
727
|
+
sharedOverrides
|
|
728
|
+
});
|
|
729
|
+
const { eslintImportRefs, eslintOptions, sharedOverrideAppendIndexes } = buildEslintOptions({
|
|
730
|
+
eslintSource: eslint,
|
|
731
|
+
sharedOverrides,
|
|
732
|
+
tailwind,
|
|
733
|
+
tsconfigRootDir,
|
|
734
|
+
userIgnorePatterns
|
|
735
|
+
});
|
|
736
|
+
ensureDirectory({ directory: dir });
|
|
737
|
+
const biomeConfig = await createBiomeConfig({
|
|
738
|
+
cwd,
|
|
739
|
+
options: biomeOptions,
|
|
740
|
+
sharedIgnorePatterns
|
|
741
|
+
});
|
|
742
|
+
const oxlintConfig = await createOxlintConfig({
|
|
743
|
+
options: oxlintOptions,
|
|
744
|
+
sharedIgnorePatterns
|
|
745
|
+
});
|
|
746
|
+
const normalizedImportRefs = eslintImportRefs.map((importRef) => ({
|
|
747
|
+
exportName: importRef.exportName,
|
|
748
|
+
files: importRef.files,
|
|
749
|
+
ignores: importRef.ignores,
|
|
750
|
+
source: resolveSyncImportSource({
|
|
751
|
+
cwd,
|
|
752
|
+
dir,
|
|
753
|
+
source: importRef.source
|
|
754
|
+
})
|
|
755
|
+
}));
|
|
756
|
+
const importStatements = normalizedImportRefs.map((importRef, index) => `import * as __lintmaxAppendImport${index} from ${JSON.stringify(importRef.source)}`).join("\n");
|
|
757
|
+
const importEntries = normalizedImportRefs.map((importRef, index) => ` { exportName: ${JSON.stringify(importRef.exportName)}, files: ${JSON.stringify(importRef.files ?? null)}, ignores: ${JSON.stringify(importRef.ignores ?? null)}, module: __lintmaxAppendImport${index} }`).join(",\n");
|
|
758
|
+
const importExpansion = normalizedImportRefs.length === 0 ? "" : `\nconst appendImports = [\n${importEntries}\n]\nconst normalizedAppend = []\nfor (const entry of options.append ?? []) {\n if (entry && typeof entry === 'object' && !Array.isArray(entry) && ${JSON.stringify(ESLINT_IMPORT_MARKER_KEY)} in entry) {\n const importIndex = entry[${JSON.stringify(ESLINT_IMPORT_MARKER_KEY)}]\n if (typeof importIndex !== 'number' || !Number.isInteger(importIndex))\n throw new Error('Invalid eslint import marker index in generated config')\n const importRef = appendImports[importIndex]\n if (!importRef) throw new Error(\`Missing eslint import ref for index \${importIndex}\`)\n const imported = importRef.module[importRef.exportName]\n const importedEntries = Array.isArray(imported) ? imported : [imported]\n for (const importedEntry of importedEntries) {\n if (!importedEntry || typeof importedEntry !== 'object' || Array.isArray(importedEntry))\n throw new Error(\`Imported eslint append from \${importRef.exportName} must resolve to config object(s)\`)\n normalizedAppend.push({\n ...importedEntry,\n ...(Array.isArray(importRef.files) ? { files: [...importRef.files] } : {}),\n ...(Array.isArray(importRef.ignores) ? { ignores: [...importRef.ignores] } : {})\n })\n }\n continue\n }\n normalizedAppend.push(entry)\n}\noptions.append = normalizedAppend\n`;
|
|
759
|
+
const eslintConfig = eslintOptions ? `${importStatements.length > 0 ? `${importStatements}\n` : ""}import { eslint } from 'lintmax/eslint'\nconst options = ${JSON.stringify(eslintOptions)}\nfor (const index of ${JSON.stringify(sharedOverrideAppendIndexes)}) {\n const entry = options.append?.[index]\n if (entry && typeof entry === 'object') entry[Symbol.for(${JSON.stringify(SHARED_OVERRIDE_SYMBOL_KEY)})] = true\n}${importExpansion}export default eslint(options)\n` : "export { default } from 'lintmax/eslint'\n";
|
|
760
|
+
const runtimeConfig = {
|
|
761
|
+
comments: options?.comments !== false,
|
|
762
|
+
compact: options?.compact !== false
|
|
763
|
+
};
|
|
764
|
+
await write(joinPath(dir, "biome.json"), `${JSON.stringify(biomeConfig, null, 2)}\n`);
|
|
765
|
+
await write(joinPath(dir, ".oxlintrc.json"), `${JSON.stringify(oxlintConfig, null, 2)}\n`);
|
|
766
|
+
await write(joinPath(dir, "eslint.generated.mjs"), eslintConfig);
|
|
767
|
+
await write(joinPath(dir, "lintmax.json"), `${JSON.stringify(runtimeConfig, null, 2)}\n`);
|
|
768
|
+
};
|
|
769
|
+
const eslintImport = ({ files, from, ignores, name }) => {
|
|
770
|
+
const entry = {
|
|
771
|
+
$lintmax: ESLINT_IMPORT_SENTINEL,
|
|
772
|
+
from
|
|
773
|
+
};
|
|
774
|
+
if (files !== void 0) entry.files = files;
|
|
775
|
+
if (ignores !== void 0) entry.ignores = ignores;
|
|
776
|
+
if (name !== void 0) entry.name = name;
|
|
777
|
+
return entry;
|
|
778
|
+
};
|
|
779
|
+
const defineConfig = (options) => {
|
|
780
|
+
validateSyncOptions({ options });
|
|
781
|
+
return options;
|
|
782
|
+
};
|
|
783
|
+
//#endregion
|
|
784
|
+
export { run as _, PRETTIER_MD_ARGS as a, writeJson as b, decodeText as c, lintmaxRoot as d, pathExists as f, resolveBin as g, readVersion as h, CliExitError as i, ensureDirectory as l, readRequiredJson as m, eslintImport as n, cacheDir as o, readJson as p, sync as r, cwd as s, defineConfig as t, ignoreEntries as u, runCapture as v, usage as y };
|