@eslint-config-snapshot/cli 0.3.2 → 0.5.0
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/CHANGELOG.md +22 -0
- package/dist/index.cjs +318 -71
- package/dist/index.js +320 -72
- package/package.json +2 -2
- package/src/index.ts +370 -77
- package/test/cli.integration.test.ts +8 -0
- package/test/cli.npm-isolated.integration.test.ts +27 -6
- package/test/cli.pnpm-isolated.integration.test.ts +27 -10
- package/test/cli.terminal.integration.test.ts +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,27 @@
|
|
|
1
1
|
# @eslint-config-snapshot/cli
|
|
2
2
|
|
|
3
|
+
## 0.5.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- Add ESLint runtime version reporting by group in CLI summaries and improve pnpm/corepack isolated test resilience.
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- Updated dependencies
|
|
12
|
+
- @eslint-config-snapshot/api@0.5.0
|
|
13
|
+
|
|
14
|
+
## 0.4.0
|
|
15
|
+
|
|
16
|
+
### Minor Changes
|
|
17
|
+
|
|
18
|
+
- Minor release with improved CLI output consistency and faster workspace extraction using ESLint API fallback strategy.
|
|
19
|
+
|
|
20
|
+
### Patch Changes
|
|
21
|
+
|
|
22
|
+
- Updated dependencies
|
|
23
|
+
- @eslint-config-snapshot/api@0.4.0
|
|
24
|
+
|
|
3
25
|
## 0.3.2
|
|
4
26
|
|
|
5
27
|
### Patch Changes
|
package/dist/index.cjs
CHANGED
|
@@ -39,39 +39,53 @@ module.exports = __toCommonJS(index_exports);
|
|
|
39
39
|
var import_api = require("@eslint-config-snapshot/api");
|
|
40
40
|
var import_commander = require("commander");
|
|
41
41
|
var import_fast_glob = __toESM(require("fast-glob"), 1);
|
|
42
|
+
var import_node_fs = require("fs");
|
|
42
43
|
var import_promises = require("fs/promises");
|
|
43
44
|
var import_node_path = __toESM(require("path"), 1);
|
|
44
45
|
var import_node_readline = require("readline");
|
|
45
46
|
var SNAPSHOT_DIR = ".eslint-config-snapshot";
|
|
46
47
|
var UPDATE_HINT = "Tip: when you intentionally accept changes, run `eslint-config-snapshot --update` to refresh the baseline.\n";
|
|
48
|
+
var activeRunTimer;
|
|
49
|
+
var cachedCliVersion;
|
|
47
50
|
async function runCli(command, cwd, flags = []) {
|
|
48
51
|
const argv = command ? [command, ...flags] : [...flags];
|
|
49
52
|
return runArgv(argv, cwd);
|
|
50
53
|
}
|
|
51
54
|
async function runArgv(argv, cwd) {
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
}
|
|
56
|
-
let actionCode;
|
|
57
|
-
const program = createProgram(cwd, (code) => {
|
|
58
|
-
actionCode = code;
|
|
59
|
-
});
|
|
55
|
+
const invocationLabel = resolveInvocationLabel(argv);
|
|
56
|
+
beginRunTimer(invocationLabel);
|
|
57
|
+
let exitCode = 1;
|
|
60
58
|
try {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
return 0;
|
|
66
|
-
}
|
|
67
|
-
return error.exitCode;
|
|
59
|
+
const hasCommandToken = argv.some((token) => !token.startsWith("-"));
|
|
60
|
+
if (!hasCommandToken) {
|
|
61
|
+
exitCode = await runDefaultInvocation(argv, cwd);
|
|
62
|
+
return exitCode;
|
|
68
63
|
}
|
|
69
|
-
|
|
70
|
-
|
|
64
|
+
let actionCode;
|
|
65
|
+
const program = createProgram(cwd, (code) => {
|
|
66
|
+
actionCode = code;
|
|
67
|
+
});
|
|
68
|
+
try {
|
|
69
|
+
await program.parseAsync(argv, { from: "user" });
|
|
70
|
+
} catch (error) {
|
|
71
|
+
if (error instanceof import_commander.CommanderError) {
|
|
72
|
+
if (error.code === "commander.helpDisplayed") {
|
|
73
|
+
exitCode = 0;
|
|
74
|
+
return exitCode;
|
|
75
|
+
}
|
|
76
|
+
exitCode = error.exitCode;
|
|
77
|
+
return exitCode;
|
|
78
|
+
}
|
|
79
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
80
|
+
process.stderr.write(`${message}
|
|
71
81
|
`);
|
|
72
|
-
|
|
82
|
+
return 1;
|
|
83
|
+
}
|
|
84
|
+
exitCode = actionCode ?? 0;
|
|
85
|
+
return exitCode;
|
|
86
|
+
} finally {
|
|
87
|
+
endRunTimer(exitCode);
|
|
73
88
|
}
|
|
74
|
-
return actionCode ?? 0;
|
|
75
89
|
}
|
|
76
90
|
async function runDefaultInvocation(argv, cwd) {
|
|
77
91
|
const known = /* @__PURE__ */ new Set(["-u", "--update", "-h", "--help"]);
|
|
@@ -177,6 +191,13 @@ function parseInitPreset(value) {
|
|
|
177
191
|
}
|
|
178
192
|
async function executeCheck(cwd, format, defaultInvocation = false) {
|
|
179
193
|
const foundConfig = await (0, import_api.findConfigPath)(cwd);
|
|
194
|
+
const storedSnapshots = await loadStoredSnapshots(cwd);
|
|
195
|
+
if (format !== "status") {
|
|
196
|
+
writeRunContextHeader(cwd, defaultInvocation ? "check" : `check:${format}`, foundConfig?.path, storedSnapshots);
|
|
197
|
+
if (shouldShowRunLogs()) {
|
|
198
|
+
writeSubtleInfo("Analyzing current ESLint configuration...\n");
|
|
199
|
+
}
|
|
200
|
+
}
|
|
180
201
|
if (!foundConfig) {
|
|
181
202
|
writeSubtleInfo(
|
|
182
203
|
"Tip: no explicit config found. Using safe built-in defaults. Run `eslint-config-snapshot init` to customize when needed.\n"
|
|
@@ -194,7 +215,6 @@ async function executeCheck(cwd, format, defaultInvocation = false) {
|
|
|
194
215
|
}
|
|
195
216
|
throw error;
|
|
196
217
|
}
|
|
197
|
-
const storedSnapshots = await loadStoredSnapshots(cwd);
|
|
198
218
|
if (storedSnapshots.size === 0) {
|
|
199
219
|
const summary = summarizeSnapshots(currentSnapshots);
|
|
200
220
|
process.stdout.write(
|
|
@@ -221,6 +241,7 @@ async function executeCheck(cwd, format, defaultInvocation = false) {
|
|
|
221
241
|
return 1;
|
|
222
242
|
}
|
|
223
243
|
const changes = compareSnapshotMaps(storedSnapshots, currentSnapshots);
|
|
244
|
+
const eslintVersionsByGroup = shouldShowRunLogs() ? await resolveGroupEslintVersions(cwd) : /* @__PURE__ */ new Map();
|
|
224
245
|
if (format === "status") {
|
|
225
246
|
if (changes.length === 0) {
|
|
226
247
|
process.stdout.write("clean\n");
|
|
@@ -233,6 +254,7 @@ async function executeCheck(cwd, format, defaultInvocation = false) {
|
|
|
233
254
|
if (format === "diff") {
|
|
234
255
|
if (changes.length === 0) {
|
|
235
256
|
process.stdout.write("Great news: no snapshot changes detected.\n");
|
|
257
|
+
writeEslintVersionSummary(eslintVersionsByGroup);
|
|
236
258
|
return 0;
|
|
237
259
|
}
|
|
238
260
|
for (const change of changes) {
|
|
@@ -242,10 +264,15 @@ async function executeCheck(cwd, format, defaultInvocation = false) {
|
|
|
242
264
|
writeSubtleInfo(UPDATE_HINT);
|
|
243
265
|
return 1;
|
|
244
266
|
}
|
|
245
|
-
return printWhatChanged(changes, currentSnapshots);
|
|
267
|
+
return printWhatChanged(changes, currentSnapshots, eslintVersionsByGroup);
|
|
246
268
|
}
|
|
247
269
|
async function executeUpdate(cwd, printSummary) {
|
|
248
270
|
const foundConfig = await (0, import_api.findConfigPath)(cwd);
|
|
271
|
+
const storedSnapshots = await loadStoredSnapshots(cwd);
|
|
272
|
+
writeRunContextHeader(cwd, "update", foundConfig?.path, storedSnapshots);
|
|
273
|
+
if (shouldShowRunLogs()) {
|
|
274
|
+
writeSubtleInfo("Analyzing current ESLint configuration...\n");
|
|
275
|
+
}
|
|
249
276
|
if (!foundConfig) {
|
|
250
277
|
writeSubtleInfo(
|
|
251
278
|
"Tip: no explicit config found. Using safe built-in defaults. Run `eslint-config-snapshot init` to customize when needed.\n"
|
|
@@ -266,12 +293,25 @@ async function executeUpdate(cwd, printSummary) {
|
|
|
266
293
|
await writeSnapshots(cwd, currentSnapshots);
|
|
267
294
|
if (printSummary) {
|
|
268
295
|
const summary = summarizeSnapshots(currentSnapshots);
|
|
269
|
-
|
|
270
|
-
|
|
296
|
+
const color = createColorizer();
|
|
297
|
+
const eslintVersionsByGroup = shouldShowRunLogs() ? await resolveGroupEslintVersions(cwd) : /* @__PURE__ */ new Map();
|
|
298
|
+
writeSectionTitle("Summary", color);
|
|
299
|
+
process.stdout.write(
|
|
300
|
+
`Baseline updated: ${summary.groups} groups, ${summary.rules} rules.
|
|
301
|
+
Severity mix: ${summary.error} errors, ${summary.warn} warnings, ${summary.off} off.
|
|
302
|
+
`
|
|
303
|
+
);
|
|
304
|
+
writeEslintVersionSummary(eslintVersionsByGroup);
|
|
271
305
|
}
|
|
272
306
|
return 0;
|
|
273
307
|
}
|
|
274
308
|
async function executePrint(cwd, format) {
|
|
309
|
+
const foundConfig = await (0, import_api.findConfigPath)(cwd);
|
|
310
|
+
const storedSnapshots = await loadStoredSnapshots(cwd);
|
|
311
|
+
writeRunContextHeader(cwd, `print:${format}`, foundConfig?.path, storedSnapshots);
|
|
312
|
+
if (shouldShowRunLogs()) {
|
|
313
|
+
writeSubtleInfo("Analyzing current ESLint configuration...\n");
|
|
314
|
+
}
|
|
275
315
|
const currentSnapshots = await computeCurrentSnapshots(cwd);
|
|
276
316
|
if (format === "short") {
|
|
277
317
|
process.stdout.write(formatShortPrint([...currentSnapshots.values()]));
|
|
@@ -286,6 +326,11 @@ async function executePrint(cwd, format) {
|
|
|
286
326
|
}
|
|
287
327
|
async function executeConfig(cwd, format) {
|
|
288
328
|
const foundConfig = await (0, import_api.findConfigPath)(cwd);
|
|
329
|
+
const storedSnapshots = await loadStoredSnapshots(cwd);
|
|
330
|
+
writeRunContextHeader(cwd, `config:${format}`, foundConfig?.path, storedSnapshots);
|
|
331
|
+
if (shouldShowRunLogs()) {
|
|
332
|
+
writeSubtleInfo("Resolving effective runtime configuration...\n");
|
|
333
|
+
}
|
|
289
334
|
const config = await (0, import_api.loadConfig)(cwd);
|
|
290
335
|
const resolved = await resolveWorkspaceAssignments(cwd, config);
|
|
291
336
|
const payload = {
|
|
@@ -317,19 +362,20 @@ async function computeCurrentSnapshots(cwd) {
|
|
|
317
362
|
const sampled = await (0, import_api.sampleWorkspaceFiles)(workspaceAbs, config.sampling);
|
|
318
363
|
let extractedCount = 0;
|
|
319
364
|
let lastExtractionError;
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
365
|
+
const sampledAbs = sampled.map((sampledRel) => import_node_path.default.resolve(workspaceAbs, sampledRel));
|
|
366
|
+
const results = await (0, import_api.extractRulesForWorkspaceSamples)(workspaceAbs, sampledAbs);
|
|
367
|
+
for (const result of results) {
|
|
368
|
+
if (result.rules) {
|
|
369
|
+
extractedForGroup.push(result.rules);
|
|
324
370
|
extractedCount += 1;
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
throw error;
|
|
371
|
+
continue;
|
|
372
|
+
}
|
|
373
|
+
const message = result.error instanceof Error ? result.error.message : String(result.error);
|
|
374
|
+
if (isRecoverableExtractionError(message)) {
|
|
375
|
+
lastExtractionError = message;
|
|
376
|
+
continue;
|
|
332
377
|
}
|
|
378
|
+
throw result.error ?? new Error(message);
|
|
333
379
|
}
|
|
334
380
|
if (extractedCount === 0) {
|
|
335
381
|
const context = lastExtractionError ? ` Last error: ${lastExtractionError}` : "";
|
|
@@ -343,6 +389,9 @@ async function computeCurrentSnapshots(cwd) {
|
|
|
343
389
|
}
|
|
344
390
|
return snapshots;
|
|
345
391
|
}
|
|
392
|
+
function isRecoverableExtractionError(message) {
|
|
393
|
+
return message.startsWith("Invalid JSON from eslint --print-config") || message.startsWith("Empty ESLint print-config output") || message.includes("File ignored because of a matching ignore pattern") || message.includes("File ignored by default");
|
|
394
|
+
}
|
|
346
395
|
async function resolveWorkspaceAssignments(cwd, config) {
|
|
347
396
|
const discovery = await (0, import_api.discoverWorkspaces)({ cwd, workspaceInput: config.workspaceInput });
|
|
348
397
|
const assignments = config.grouping.mode === "standalone" ? discovery.workspacesRel.map((workspace) => ({ name: workspace, workspaces: [workspace] })) : (0, import_api.assignGroupsByMatch)(discovery.workspacesRel, config.grouping.groups ?? [{ name: "default", match: ["**/*"] }]);
|
|
@@ -467,8 +516,8 @@ ${JSON.stringify(configObject, null, 2)}
|
|
|
467
516
|
}
|
|
468
517
|
async function askInitPreferences() {
|
|
469
518
|
const { select } = await import("@inquirer/prompts");
|
|
470
|
-
const target = await askInitTarget(select);
|
|
471
|
-
const preset = await askInitPreset(select);
|
|
519
|
+
const target = await runPromptWithPausedTimer(() => askInitTarget(select));
|
|
520
|
+
const preset = await runPromptWithPausedTimer(() => askInitPreset(select));
|
|
472
521
|
return { target, preset };
|
|
473
522
|
}
|
|
474
523
|
async function askInitTarget(selectPrompt) {
|
|
@@ -491,8 +540,10 @@ async function askInitPreset(selectPrompt) {
|
|
|
491
540
|
});
|
|
492
541
|
}
|
|
493
542
|
function askQuestion(rl, prompt) {
|
|
543
|
+
pauseRunTimer();
|
|
494
544
|
return new Promise((resolve) => {
|
|
495
545
|
rl.question(prompt, (answer) => {
|
|
546
|
+
resumeRunTimer();
|
|
496
547
|
resolve(answer);
|
|
497
548
|
});
|
|
498
549
|
});
|
|
@@ -638,11 +689,13 @@ async function askRecommendedGroupAssignments(workspaces) {
|
|
|
638
689
|
'Recommended setup: default group "*" is a dynamic catch-all for every discovered workspace.\n'
|
|
639
690
|
);
|
|
640
691
|
process.stdout.write("Select only workspaces that should move to explicit static groups.\n");
|
|
641
|
-
const overrides = await
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
692
|
+
const overrides = await runPromptWithPausedTimer(
|
|
693
|
+
() => checkbox({
|
|
694
|
+
message: 'Choose exception workspaces (leave empty to keep all in default "*"):',
|
|
695
|
+
choices: workspaces.map((workspace) => ({ name: workspace, value: workspace })),
|
|
696
|
+
pageSize: Math.min(12, Math.max(4, workspaces.length))
|
|
697
|
+
})
|
|
698
|
+
);
|
|
646
699
|
const assignments = /* @__PURE__ */ new Map();
|
|
647
700
|
let nextGroup = 1;
|
|
648
701
|
for (const workspace of overrides) {
|
|
@@ -650,13 +703,15 @@ async function askRecommendedGroupAssignments(workspaces) {
|
|
|
650
703
|
while (usedGroups.includes(nextGroup)) {
|
|
651
704
|
nextGroup += 1;
|
|
652
705
|
}
|
|
653
|
-
const selected = await
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
706
|
+
const selected = await runPromptWithPausedTimer(
|
|
707
|
+
() => select({
|
|
708
|
+
message: `Select group for ${workspace}`,
|
|
709
|
+
choices: [
|
|
710
|
+
...usedGroups.map((group) => ({ name: `group-${group}`, value: group })),
|
|
711
|
+
{ name: `create new group (group-${nextGroup})`, value: "new" }
|
|
712
|
+
]
|
|
713
|
+
})
|
|
714
|
+
);
|
|
660
715
|
const groupNumber = selected === "new" ? nextGroup : selected;
|
|
661
716
|
assignments.set(workspace, groupNumber);
|
|
662
717
|
}
|
|
@@ -699,28 +754,38 @@ function isDirectCliExecution() {
|
|
|
699
754
|
if (isDirectCliExecution()) {
|
|
700
755
|
void main();
|
|
701
756
|
}
|
|
702
|
-
function printWhatChanged(changes, currentSnapshots) {
|
|
757
|
+
function printWhatChanged(changes, currentSnapshots, eslintVersionsByGroup) {
|
|
703
758
|
const color = createColorizer();
|
|
704
759
|
const currentSummary = summarizeSnapshots(currentSnapshots);
|
|
705
760
|
const changeSummary = summarizeChanges(changes);
|
|
706
761
|
if (changes.length === 0) {
|
|
707
762
|
process.stdout.write(color.green("Great news: no snapshot drift detected.\n"));
|
|
763
|
+
writeSectionTitle("Summary", color);
|
|
708
764
|
process.stdout.write(
|
|
709
|
-
|
|
765
|
+
`- baseline: ${currentSummary.groups} groups, ${currentSummary.rules} rules
|
|
766
|
+
- severity mix: ${currentSummary.error} errors, ${currentSummary.warn} warnings, ${currentSummary.off} off
|
|
710
767
|
`
|
|
711
768
|
);
|
|
769
|
+
writeEslintVersionSummary(eslintVersionsByGroup);
|
|
712
770
|
return 0;
|
|
713
771
|
}
|
|
714
772
|
process.stdout.write(color.red("Heads up: snapshot drift detected.\n"));
|
|
773
|
+
writeSectionTitle("Summary", color);
|
|
715
774
|
process.stdout.write(
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
775
|
+
`- changed groups: ${changes.length}
|
|
776
|
+
- introduced rules: ${changeSummary.introduced}
|
|
777
|
+
- removed rules: ${changeSummary.removed}
|
|
778
|
+
- severity changes: ${changeSummary.severity}
|
|
779
|
+
- options changes: ${changeSummary.options}
|
|
780
|
+
- workspace membership changes: ${changeSummary.workspace}
|
|
781
|
+
- current baseline: ${currentSummary.groups} groups, ${currentSummary.rules} rules
|
|
782
|
+
- current severity mix: ${currentSummary.error} errors, ${currentSummary.warn} warnings, ${currentSummary.off} off
|
|
721
783
|
|
|
722
784
|
`
|
|
723
785
|
);
|
|
786
|
+
writeEslintVersionSummary(eslintVersionsByGroup);
|
|
787
|
+
process.stdout.write("\n");
|
|
788
|
+
writeSectionTitle("Changes", color);
|
|
724
789
|
for (const change of changes) {
|
|
725
790
|
process.stdout.write(color.bold(`group ${change.groupId}
|
|
726
791
|
`));
|
|
@@ -735,6 +800,10 @@ function printWhatChanged(changes, currentSnapshots) {
|
|
|
735
800
|
writeSubtleInfo(UPDATE_HINT);
|
|
736
801
|
return 1;
|
|
737
802
|
}
|
|
803
|
+
function writeSectionTitle(title, color) {
|
|
804
|
+
process.stdout.write(`${color.bold(title)}
|
|
805
|
+
`);
|
|
806
|
+
}
|
|
738
807
|
function summarizeChanges(changes) {
|
|
739
808
|
let introduced = 0;
|
|
740
809
|
let removed = 0;
|
|
@@ -751,22 +820,7 @@ function summarizeChanges(changes) {
|
|
|
751
820
|
return { introduced, removed, severity, options, workspace };
|
|
752
821
|
}
|
|
753
822
|
function summarizeSnapshots(snapshots) {
|
|
754
|
-
|
|
755
|
-
let error = 0;
|
|
756
|
-
let warn = 0;
|
|
757
|
-
let off = 0;
|
|
758
|
-
for (const snapshot of snapshots.values()) {
|
|
759
|
-
for (const entry of Object.values(snapshot.rules)) {
|
|
760
|
-
rules += 1;
|
|
761
|
-
if (entry[0] === "error") {
|
|
762
|
-
error += 1;
|
|
763
|
-
} else if (entry[0] === "warn") {
|
|
764
|
-
warn += 1;
|
|
765
|
-
} else {
|
|
766
|
-
off += 1;
|
|
767
|
-
}
|
|
768
|
-
}
|
|
769
|
-
}
|
|
823
|
+
const { rules, error, warn, off } = countRuleSeverities([...snapshots.values()].map((snapshot) => snapshot.rules));
|
|
770
824
|
return { groups: snapshots.size, rules, error, warn, off };
|
|
771
825
|
}
|
|
772
826
|
function decorateDiffLine(line, color) {
|
|
@@ -796,6 +850,199 @@ function writeSubtleInfo(text) {
|
|
|
796
850
|
const color = createColorizer();
|
|
797
851
|
process.stdout.write(color.dim(text));
|
|
798
852
|
}
|
|
853
|
+
function resolveInvocationLabel(argv) {
|
|
854
|
+
const commandToken = argv.find((entry) => !entry.startsWith("-"));
|
|
855
|
+
if (commandToken) {
|
|
856
|
+
return commandToken;
|
|
857
|
+
}
|
|
858
|
+
if (argv.includes("-u") || argv.includes("--update")) {
|
|
859
|
+
return "update";
|
|
860
|
+
}
|
|
861
|
+
if (argv.includes("-h") || argv.includes("--help")) {
|
|
862
|
+
return "help";
|
|
863
|
+
}
|
|
864
|
+
return "check";
|
|
865
|
+
}
|
|
866
|
+
function shouldShowRunLogs() {
|
|
867
|
+
if (process.env.ESLINT_CONFIG_SNAPSHOT_NO_PROGRESS === "1") {
|
|
868
|
+
return false;
|
|
869
|
+
}
|
|
870
|
+
return process.stdout.isTTY === true;
|
|
871
|
+
}
|
|
872
|
+
function beginRunTimer(label) {
|
|
873
|
+
if (!shouldShowRunLogs()) {
|
|
874
|
+
activeRunTimer = void 0;
|
|
875
|
+
return;
|
|
876
|
+
}
|
|
877
|
+
activeRunTimer = {
|
|
878
|
+
label,
|
|
879
|
+
startedAtMs: Date.now(),
|
|
880
|
+
pausedMs: 0,
|
|
881
|
+
pauseStartedAtMs: void 0
|
|
882
|
+
};
|
|
883
|
+
}
|
|
884
|
+
function endRunTimer(exitCode) {
|
|
885
|
+
if (!activeRunTimer || !shouldShowRunLogs()) {
|
|
886
|
+
return;
|
|
887
|
+
}
|
|
888
|
+
if (activeRunTimer.pauseStartedAtMs !== void 0) {
|
|
889
|
+
activeRunTimer.pausedMs += Date.now() - activeRunTimer.pauseStartedAtMs;
|
|
890
|
+
activeRunTimer.pauseStartedAtMs = void 0;
|
|
891
|
+
}
|
|
892
|
+
const elapsedMs = Math.max(0, Date.now() - activeRunTimer.startedAtMs - activeRunTimer.pausedMs);
|
|
893
|
+
const color = createColorizer();
|
|
894
|
+
const status = exitCode === 0 ? color.green("done") : color.red("failed");
|
|
895
|
+
const seconds = (elapsedMs / 1e3).toFixed(2);
|
|
896
|
+
writeSubtleInfo(`Run ${status} in ${seconds}s
|
|
897
|
+
`);
|
|
898
|
+
activeRunTimer = void 0;
|
|
899
|
+
}
|
|
900
|
+
function pauseRunTimer() {
|
|
901
|
+
if (!activeRunTimer || activeRunTimer.pauseStartedAtMs !== void 0) {
|
|
902
|
+
return;
|
|
903
|
+
}
|
|
904
|
+
activeRunTimer.pauseStartedAtMs = Date.now();
|
|
905
|
+
}
|
|
906
|
+
function resumeRunTimer() {
|
|
907
|
+
if (!activeRunTimer || activeRunTimer.pauseStartedAtMs === void 0) {
|
|
908
|
+
return;
|
|
909
|
+
}
|
|
910
|
+
activeRunTimer.pausedMs += Date.now() - activeRunTimer.pauseStartedAtMs;
|
|
911
|
+
activeRunTimer.pauseStartedAtMs = void 0;
|
|
912
|
+
}
|
|
913
|
+
async function runPromptWithPausedTimer(prompt) {
|
|
914
|
+
pauseRunTimer();
|
|
915
|
+
try {
|
|
916
|
+
return await prompt();
|
|
917
|
+
} finally {
|
|
918
|
+
resumeRunTimer();
|
|
919
|
+
}
|
|
920
|
+
}
|
|
921
|
+
function readCliVersion() {
|
|
922
|
+
if (cachedCliVersion !== void 0) {
|
|
923
|
+
return cachedCliVersion;
|
|
924
|
+
}
|
|
925
|
+
const scriptPath = process.argv[1];
|
|
926
|
+
if (!scriptPath) {
|
|
927
|
+
cachedCliVersion = "unknown";
|
|
928
|
+
return cachedCliVersion;
|
|
929
|
+
}
|
|
930
|
+
let current = import_node_path.default.resolve(import_node_path.default.dirname(scriptPath));
|
|
931
|
+
while (true) {
|
|
932
|
+
const packageJsonPath = import_node_path.default.join(current, "package.json");
|
|
933
|
+
if ((0, import_node_fs.existsSync)(packageJsonPath)) {
|
|
934
|
+
try {
|
|
935
|
+
const raw = (0, import_node_fs.readFileSync)(packageJsonPath, "utf8");
|
|
936
|
+
const parsed = JSON.parse(raw);
|
|
937
|
+
cachedCliVersion = parsed.version ?? "unknown";
|
|
938
|
+
return cachedCliVersion;
|
|
939
|
+
} catch {
|
|
940
|
+
break;
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
const parent = import_node_path.default.dirname(current);
|
|
944
|
+
if (parent === current) {
|
|
945
|
+
break;
|
|
946
|
+
}
|
|
947
|
+
current = parent;
|
|
948
|
+
}
|
|
949
|
+
cachedCliVersion = "unknown";
|
|
950
|
+
return cachedCliVersion;
|
|
951
|
+
}
|
|
952
|
+
function writeRunContextHeader(cwd, commandLabel, configPath, storedSnapshots) {
|
|
953
|
+
if (!shouldShowRunLogs()) {
|
|
954
|
+
return;
|
|
955
|
+
}
|
|
956
|
+
const color = createColorizer();
|
|
957
|
+
process.stdout.write(color.bold(`eslint-config-snapshot v${readCliVersion()}
|
|
958
|
+
`));
|
|
959
|
+
process.stdout.write(`Command: ${commandLabel}
|
|
960
|
+
`);
|
|
961
|
+
process.stdout.write(`Repository: ${cwd}
|
|
962
|
+
`);
|
|
963
|
+
process.stdout.write(`Config: ${formatConfigSource(cwd, configPath)}
|
|
964
|
+
`);
|
|
965
|
+
process.stdout.write(`Baseline: ${formatStoredSnapshotSummary(storedSnapshots)}
|
|
966
|
+
|
|
967
|
+
`);
|
|
968
|
+
}
|
|
969
|
+
function formatConfigSource(cwd, configPath) {
|
|
970
|
+
if (!configPath) {
|
|
971
|
+
return "built-in defaults";
|
|
972
|
+
}
|
|
973
|
+
const rel = (0, import_api.normalizePath)(import_node_path.default.relative(cwd, configPath));
|
|
974
|
+
if (import_node_path.default.basename(configPath) === "package.json") {
|
|
975
|
+
return `${rel} (eslint-config-snapshot field)`;
|
|
976
|
+
}
|
|
977
|
+
return rel;
|
|
978
|
+
}
|
|
979
|
+
function formatStoredSnapshotSummary(storedSnapshots) {
|
|
980
|
+
if (storedSnapshots.size === 0) {
|
|
981
|
+
return "none";
|
|
982
|
+
}
|
|
983
|
+
const summary = summarizeStoredSnapshots(storedSnapshots);
|
|
984
|
+
return `${summary.groups} groups, ${summary.rules} rules (severity mix: ${summary.error} errors, ${summary.warn} warnings, ${summary.off} off)`;
|
|
985
|
+
}
|
|
986
|
+
async function resolveGroupEslintVersions(cwd) {
|
|
987
|
+
const config = await (0, import_api.loadConfig)(cwd);
|
|
988
|
+
const { discovery, assignments } = await resolveWorkspaceAssignments(cwd, config);
|
|
989
|
+
const result = /* @__PURE__ */ new Map();
|
|
990
|
+
for (const group of assignments) {
|
|
991
|
+
const versions = /* @__PURE__ */ new Set();
|
|
992
|
+
for (const workspaceRel of group.workspaces) {
|
|
993
|
+
const workspaceAbs = import_node_path.default.resolve(discovery.rootAbs, workspaceRel);
|
|
994
|
+
versions.add((0, import_api.resolveEslintVersionForWorkspace)(workspaceAbs));
|
|
995
|
+
}
|
|
996
|
+
result.set(group.name, [...versions].sort((a, b) => a.localeCompare(b)));
|
|
997
|
+
}
|
|
998
|
+
return result;
|
|
999
|
+
}
|
|
1000
|
+
function writeEslintVersionSummary(eslintVersionsByGroup) {
|
|
1001
|
+
if (!shouldShowRunLogs() || eslintVersionsByGroup.size === 0) {
|
|
1002
|
+
return;
|
|
1003
|
+
}
|
|
1004
|
+
const allVersions = /* @__PURE__ */ new Set();
|
|
1005
|
+
for (const versions of eslintVersionsByGroup.values()) {
|
|
1006
|
+
for (const version of versions) {
|
|
1007
|
+
allVersions.add(version);
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
1010
|
+
const sortedAllVersions = [...allVersions].sort((a, b) => a.localeCompare(b));
|
|
1011
|
+
if (sortedAllVersions.length === 1) {
|
|
1012
|
+
process.stdout.write(`- eslint runtime: ${sortedAllVersions[0]} (all groups)
|
|
1013
|
+
`);
|
|
1014
|
+
return;
|
|
1015
|
+
}
|
|
1016
|
+
process.stdout.write("- eslint runtime by group:\n");
|
|
1017
|
+
const sortedEntries = [...eslintVersionsByGroup.entries()].sort((a, b) => a[0].localeCompare(b[0]));
|
|
1018
|
+
for (const [groupName, versions] of sortedEntries) {
|
|
1019
|
+
process.stdout.write(` - ${groupName}: ${versions.join(", ")}
|
|
1020
|
+
`);
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1023
|
+
function summarizeStoredSnapshots(snapshots) {
|
|
1024
|
+
const { rules, error, warn, off } = countRuleSeverities([...snapshots.values()].map((snapshot) => snapshot.rules));
|
|
1025
|
+
return { groups: snapshots.size, rules, error, warn, off };
|
|
1026
|
+
}
|
|
1027
|
+
function countRuleSeverities(ruleObjects) {
|
|
1028
|
+
let rules = 0;
|
|
1029
|
+
let error = 0;
|
|
1030
|
+
let warn = 0;
|
|
1031
|
+
let off = 0;
|
|
1032
|
+
for (const rulesObject of ruleObjects) {
|
|
1033
|
+
for (const entry of Object.values(rulesObject)) {
|
|
1034
|
+
rules += 1;
|
|
1035
|
+
if (entry[0] === "error") {
|
|
1036
|
+
error += 1;
|
|
1037
|
+
} else if (entry[0] === "warn") {
|
|
1038
|
+
warn += 1;
|
|
1039
|
+
} else {
|
|
1040
|
+
off += 1;
|
|
1041
|
+
}
|
|
1042
|
+
}
|
|
1043
|
+
}
|
|
1044
|
+
return { rules, error, warn, off };
|
|
1045
|
+
}
|
|
799
1046
|
function formatShortPrint(snapshots) {
|
|
800
1047
|
const lines = [];
|
|
801
1048
|
const sorted = [...snapshots].sort((a, b) => a.groupId.localeCompare(b.groupId));
|