@eslint-config-snapshot/cli 0.3.2 → 0.4.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 CHANGED
@@ -1,5 +1,16 @@
1
1
  # @eslint-config-snapshot/cli
2
2
 
3
+ ## 0.4.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Minor release with improved CLI output consistency and faster workspace extraction using ESLint API fallback strategy.
8
+
9
+ ### Patch Changes
10
+
11
+ - Updated dependencies
12
+ - @eslint-config-snapshot/api@0.4.0
13
+
3
14
  ## 0.3.2
4
15
 
5
16
  ### Patch Changes
package/dist/index.cjs CHANGED
@@ -266,8 +266,13 @@ async function executeUpdate(cwd, printSummary) {
266
266
  await writeSnapshots(cwd, currentSnapshots);
267
267
  if (printSummary) {
268
268
  const summary = summarizeSnapshots(currentSnapshots);
269
- process.stdout.write(`Baseline updated: ${summary.groups} groups, ${summary.rules} rules.
270
- `);
269
+ const color = createColorizer();
270
+ writeSectionTitle("Summary", color);
271
+ process.stdout.write(
272
+ `Baseline updated: ${summary.groups} groups, ${summary.rules} rules.
273
+ Severity mix: ${summary.error} errors, ${summary.warn} warnings, ${summary.off} off.
274
+ `
275
+ );
271
276
  }
272
277
  return 0;
273
278
  }
@@ -317,19 +322,20 @@ async function computeCurrentSnapshots(cwd) {
317
322
  const sampled = await (0, import_api.sampleWorkspaceFiles)(workspaceAbs, config.sampling);
318
323
  let extractedCount = 0;
319
324
  let lastExtractionError;
320
- for (const sampledRel of sampled) {
321
- const sampledAbs = import_node_path.default.resolve(workspaceAbs, sampledRel);
322
- try {
323
- extractedForGroup.push((0, import_api.extractRulesFromPrintConfig)(workspaceAbs, sampledAbs));
325
+ const sampledAbs = sampled.map((sampledRel) => import_node_path.default.resolve(workspaceAbs, sampledRel));
326
+ const results = await (0, import_api.extractRulesForWorkspaceSamples)(workspaceAbs, sampledAbs);
327
+ for (const result of results) {
328
+ if (result.rules) {
329
+ extractedForGroup.push(result.rules);
324
330
  extractedCount += 1;
325
- } catch (error) {
326
- const message = error instanceof Error ? error.message : String(error);
327
- if (message.startsWith("Invalid JSON from eslint --print-config") || message.startsWith("Empty ESLint print-config output")) {
328
- lastExtractionError = message;
329
- continue;
330
- }
331
- throw error;
331
+ continue;
332
+ }
333
+ const message = result.error instanceof Error ? result.error.message : String(result.error);
334
+ if (isRecoverableExtractionError(message)) {
335
+ lastExtractionError = message;
336
+ continue;
332
337
  }
338
+ throw result.error ?? new Error(message);
333
339
  }
334
340
  if (extractedCount === 0) {
335
341
  const context = lastExtractionError ? ` Last error: ${lastExtractionError}` : "";
@@ -343,6 +349,9 @@ async function computeCurrentSnapshots(cwd) {
343
349
  }
344
350
  return snapshots;
345
351
  }
352
+ function isRecoverableExtractionError(message) {
353
+ 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");
354
+ }
346
355
  async function resolveWorkspaceAssignments(cwd, config) {
347
356
  const discovery = await (0, import_api.discoverWorkspaces)({ cwd, workspaceInput: config.workspaceInput });
348
357
  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: ["**/*"] }]);
@@ -705,22 +714,29 @@ function printWhatChanged(changes, currentSnapshots) {
705
714
  const changeSummary = summarizeChanges(changes);
706
715
  if (changes.length === 0) {
707
716
  process.stdout.write(color.green("Great news: no snapshot drift detected.\n"));
717
+ writeSectionTitle("Summary", color);
708
718
  process.stdout.write(
709
- `Baseline status: ${currentSummary.groups} groups, ${currentSummary.rules} rules (severity mix: ${currentSummary.error} errors, ${currentSummary.warn} warnings, ${currentSummary.off} off).
719
+ `- baseline: ${currentSummary.groups} groups, ${currentSummary.rules} rules
720
+ - severity mix: ${currentSummary.error} errors, ${currentSummary.warn} warnings, ${currentSummary.off} off
710
721
  `
711
722
  );
712
723
  return 0;
713
724
  }
714
725
  process.stdout.write(color.red("Heads up: snapshot drift detected.\n"));
726
+ writeSectionTitle("Summary", color);
715
727
  process.stdout.write(
716
- `Changed groups: ${changes.length} | introduced: ${changeSummary.introduced} | removed: ${changeSummary.removed} | severity: ${changeSummary.severity} | options: ${changeSummary.options} | workspace membership: ${changeSummary.workspace}
717
- `
718
- );
719
- process.stdout.write(
720
- `Current rules: ${currentSummary.rules} (severity mix: ${currentSummary.error} errors, ${currentSummary.warn} warnings, ${currentSummary.off} off)
728
+ `- changed groups: ${changes.length}
729
+ - introduced rules: ${changeSummary.introduced}
730
+ - removed rules: ${changeSummary.removed}
731
+ - severity changes: ${changeSummary.severity}
732
+ - options changes: ${changeSummary.options}
733
+ - workspace membership changes: ${changeSummary.workspace}
734
+ - current baseline: ${currentSummary.groups} groups, ${currentSummary.rules} rules
735
+ - current severity mix: ${currentSummary.error} errors, ${currentSummary.warn} warnings, ${currentSummary.off} off
721
736
 
722
737
  `
723
738
  );
739
+ writeSectionTitle("Changes", color);
724
740
  for (const change of changes) {
725
741
  process.stdout.write(color.bold(`group ${change.groupId}
726
742
  `));
@@ -735,6 +751,10 @@ function printWhatChanged(changes, currentSnapshots) {
735
751
  writeSubtleInfo(UPDATE_HINT);
736
752
  return 1;
737
753
  }
754
+ function writeSectionTitle(title, color) {
755
+ process.stdout.write(`${color.bold(title)}
756
+ `);
757
+ }
738
758
  function summarizeChanges(changes) {
739
759
  let introduced = 0;
740
760
  let removed = 0;
package/dist/index.js CHANGED
@@ -7,7 +7,7 @@ import {
7
7
  buildSnapshot,
8
8
  diffSnapshots,
9
9
  discoverWorkspaces,
10
- extractRulesFromPrintConfig,
10
+ extractRulesForWorkspaceSamples,
11
11
  findConfigPath,
12
12
  getConfigScaffold,
13
13
  hasDiff,
@@ -246,8 +246,13 @@ async function executeUpdate(cwd, printSummary) {
246
246
  await writeSnapshots(cwd, currentSnapshots);
247
247
  if (printSummary) {
248
248
  const summary = summarizeSnapshots(currentSnapshots);
249
- process.stdout.write(`Baseline updated: ${summary.groups} groups, ${summary.rules} rules.
250
- `);
249
+ const color = createColorizer();
250
+ writeSectionTitle("Summary", color);
251
+ process.stdout.write(
252
+ `Baseline updated: ${summary.groups} groups, ${summary.rules} rules.
253
+ Severity mix: ${summary.error} errors, ${summary.warn} warnings, ${summary.off} off.
254
+ `
255
+ );
251
256
  }
252
257
  return 0;
253
258
  }
@@ -297,19 +302,20 @@ async function computeCurrentSnapshots(cwd) {
297
302
  const sampled = await sampleWorkspaceFiles(workspaceAbs, config.sampling);
298
303
  let extractedCount = 0;
299
304
  let lastExtractionError;
300
- for (const sampledRel of sampled) {
301
- const sampledAbs = path.resolve(workspaceAbs, sampledRel);
302
- try {
303
- extractedForGroup.push(extractRulesFromPrintConfig(workspaceAbs, sampledAbs));
305
+ const sampledAbs = sampled.map((sampledRel) => path.resolve(workspaceAbs, sampledRel));
306
+ const results = await extractRulesForWorkspaceSamples(workspaceAbs, sampledAbs);
307
+ for (const result of results) {
308
+ if (result.rules) {
309
+ extractedForGroup.push(result.rules);
304
310
  extractedCount += 1;
305
- } catch (error) {
306
- const message = error instanceof Error ? error.message : String(error);
307
- if (message.startsWith("Invalid JSON from eslint --print-config") || message.startsWith("Empty ESLint print-config output")) {
308
- lastExtractionError = message;
309
- continue;
310
- }
311
- throw error;
311
+ continue;
312
+ }
313
+ const message = result.error instanceof Error ? result.error.message : String(result.error);
314
+ if (isRecoverableExtractionError(message)) {
315
+ lastExtractionError = message;
316
+ continue;
312
317
  }
318
+ throw result.error ?? new Error(message);
313
319
  }
314
320
  if (extractedCount === 0) {
315
321
  const context = lastExtractionError ? ` Last error: ${lastExtractionError}` : "";
@@ -323,6 +329,9 @@ async function computeCurrentSnapshots(cwd) {
323
329
  }
324
330
  return snapshots;
325
331
  }
332
+ function isRecoverableExtractionError(message) {
333
+ 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");
334
+ }
326
335
  async function resolveWorkspaceAssignments(cwd, config) {
327
336
  const discovery = await discoverWorkspaces({ cwd, workspaceInput: config.workspaceInput });
328
337
  const assignments = config.grouping.mode === "standalone" ? discovery.workspacesRel.map((workspace) => ({ name: workspace, workspaces: [workspace] })) : assignGroupsByMatch(discovery.workspacesRel, config.grouping.groups ?? [{ name: "default", match: ["**/*"] }]);
@@ -685,22 +694,29 @@ function printWhatChanged(changes, currentSnapshots) {
685
694
  const changeSummary = summarizeChanges(changes);
686
695
  if (changes.length === 0) {
687
696
  process.stdout.write(color.green("Great news: no snapshot drift detected.\n"));
697
+ writeSectionTitle("Summary", color);
688
698
  process.stdout.write(
689
- `Baseline status: ${currentSummary.groups} groups, ${currentSummary.rules} rules (severity mix: ${currentSummary.error} errors, ${currentSummary.warn} warnings, ${currentSummary.off} off).
699
+ `- baseline: ${currentSummary.groups} groups, ${currentSummary.rules} rules
700
+ - severity mix: ${currentSummary.error} errors, ${currentSummary.warn} warnings, ${currentSummary.off} off
690
701
  `
691
702
  );
692
703
  return 0;
693
704
  }
694
705
  process.stdout.write(color.red("Heads up: snapshot drift detected.\n"));
706
+ writeSectionTitle("Summary", color);
695
707
  process.stdout.write(
696
- `Changed groups: ${changes.length} | introduced: ${changeSummary.introduced} | removed: ${changeSummary.removed} | severity: ${changeSummary.severity} | options: ${changeSummary.options} | workspace membership: ${changeSummary.workspace}
697
- `
698
- );
699
- process.stdout.write(
700
- `Current rules: ${currentSummary.rules} (severity mix: ${currentSummary.error} errors, ${currentSummary.warn} warnings, ${currentSummary.off} off)
708
+ `- changed groups: ${changes.length}
709
+ - introduced rules: ${changeSummary.introduced}
710
+ - removed rules: ${changeSummary.removed}
711
+ - severity changes: ${changeSummary.severity}
712
+ - options changes: ${changeSummary.options}
713
+ - workspace membership changes: ${changeSummary.workspace}
714
+ - current baseline: ${currentSummary.groups} groups, ${currentSummary.rules} rules
715
+ - current severity mix: ${currentSummary.error} errors, ${currentSummary.warn} warnings, ${currentSummary.off} off
701
716
 
702
717
  `
703
718
  );
719
+ writeSectionTitle("Changes", color);
704
720
  for (const change of changes) {
705
721
  process.stdout.write(color.bold(`group ${change.groupId}
706
722
  `));
@@ -715,6 +731,10 @@ function printWhatChanged(changes, currentSnapshots) {
715
731
  writeSubtleInfo(UPDATE_HINT);
716
732
  return 1;
717
733
  }
734
+ function writeSectionTitle(title, color) {
735
+ process.stdout.write(`${color.bold(title)}
736
+ `);
737
+ }
718
738
  function summarizeChanges(changes) {
719
739
  let introduced = 0;
720
740
  let removed = 0;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eslint-config-snapshot/cli",
3
- "version": "0.3.2",
3
+ "version": "0.4.0",
4
4
  "type": "module",
5
5
  "repository": {
6
6
  "type": "git",
@@ -30,6 +30,6 @@
30
30
  "@inquirer/prompts": "^8.2.0",
31
31
  "commander": "^14.0.3",
32
32
  "fast-glob": "^3.3.3",
33
- "@eslint-config-snapshot/api": "0.3.2"
33
+ "@eslint-config-snapshot/api": "0.4.0"
34
34
  }
35
35
  }
package/src/index.ts CHANGED
@@ -5,7 +5,7 @@ import {
5
5
  buildSnapshot,
6
6
  diffSnapshots,
7
7
  discoverWorkspaces,
8
- extractRulesFromPrintConfig,
8
+ extractRulesForWorkspaceSamples,
9
9
  findConfigPath,
10
10
  getConfigScaffold,
11
11
  hasDiff,
@@ -340,7 +340,11 @@ async function executeUpdate(cwd: string, printSummary: boolean): Promise<number
340
340
 
341
341
  if (printSummary) {
342
342
  const summary = summarizeSnapshots(currentSnapshots)
343
- process.stdout.write(`Baseline updated: ${summary.groups} groups, ${summary.rules} rules.\n`)
343
+ const color = createColorizer()
344
+ writeSectionTitle('Summary', color)
345
+ process.stdout.write(
346
+ `Baseline updated: ${summary.groups} groups, ${summary.rules} rules.\nSeverity mix: ${summary.error} errors, ${summary.warn} warnings, ${summary.off} off.\n`
347
+ )
344
348
  }
345
349
 
346
350
  return 0
@@ -400,23 +404,23 @@ async function computeCurrentSnapshots(cwd: string): Promise<Map<string, BuiltSn
400
404
  let extractedCount = 0
401
405
  let lastExtractionError: string | undefined
402
406
 
403
- for (const sampledRel of sampled) {
404
- const sampledAbs = path.resolve(workspaceAbs, sampledRel)
405
- try {
406
- extractedForGroup.push(extractRulesFromPrintConfig(workspaceAbs, sampledAbs))
407
+ const sampledAbs = sampled.map((sampledRel) => path.resolve(workspaceAbs, sampledRel))
408
+ const results = await extractRulesForWorkspaceSamples(workspaceAbs, sampledAbs)
409
+
410
+ for (const result of results) {
411
+ if (result.rules) {
412
+ extractedForGroup.push(result.rules)
407
413
  extractedCount += 1
408
- } catch (error: unknown) {
409
- const message = error instanceof Error ? error.message : String(error)
410
- if (
411
- message.startsWith('Invalid JSON from eslint --print-config') ||
412
- message.startsWith('Empty ESLint print-config output')
413
- ) {
414
- lastExtractionError = message
415
- continue
416
- }
417
-
418
- throw error
414
+ continue
419
415
  }
416
+
417
+ const message = result.error instanceof Error ? result.error.message : String(result.error)
418
+ if (isRecoverableExtractionError(message)) {
419
+ lastExtractionError = message
420
+ continue
421
+ }
422
+
423
+ throw result.error ?? new Error(message)
420
424
  }
421
425
 
422
426
  if (extractedCount === 0) {
@@ -434,6 +438,15 @@ async function computeCurrentSnapshots(cwd: string): Promise<Map<string, BuiltSn
434
438
  return snapshots
435
439
  }
436
440
 
441
+ function isRecoverableExtractionError(message: string): boolean {
442
+ return (
443
+ message.startsWith('Invalid JSON from eslint --print-config') ||
444
+ message.startsWith('Empty ESLint print-config output') ||
445
+ message.includes('File ignored because of a matching ignore pattern') ||
446
+ message.includes('File ignored by default')
447
+ )
448
+ }
449
+
437
450
  async function resolveWorkspaceAssignments(cwd: string, config: Awaited<ReturnType<typeof loadConfig>>) {
438
451
  const discovery = await discoverWorkspaces({ cwd, workspaceInput: config.workspaceInput })
439
452
 
@@ -880,20 +893,20 @@ function printWhatChanged(changes: Array<{ groupId: string; diff: SnapshotDiff }
880
893
 
881
894
  if (changes.length === 0) {
882
895
  process.stdout.write(color.green('Great news: no snapshot drift detected.\n'))
896
+ writeSectionTitle('Summary', color)
883
897
  process.stdout.write(
884
- `Baseline status: ${currentSummary.groups} groups, ${currentSummary.rules} rules (severity mix: ${currentSummary.error} errors, ${currentSummary.warn} warnings, ${currentSummary.off} off).\n`
898
+ `- baseline: ${currentSummary.groups} groups, ${currentSummary.rules} rules\n- severity mix: ${currentSummary.error} errors, ${currentSummary.warn} warnings, ${currentSummary.off} off\n`
885
899
  )
886
900
  return 0
887
901
  }
888
902
 
889
903
  process.stdout.write(color.red('Heads up: snapshot drift detected.\n'))
904
+ writeSectionTitle('Summary', color)
890
905
  process.stdout.write(
891
- `Changed groups: ${changes.length} | introduced: ${changeSummary.introduced} | removed: ${changeSummary.removed} | severity: ${changeSummary.severity} | options: ${changeSummary.options} | workspace membership: ${changeSummary.workspace}\n`
892
- )
893
- process.stdout.write(
894
- `Current rules: ${currentSummary.rules} (severity mix: ${currentSummary.error} errors, ${currentSummary.warn} warnings, ${currentSummary.off} off)\n\n`
906
+ `- changed groups: ${changes.length}\n- introduced rules: ${changeSummary.introduced}\n- removed rules: ${changeSummary.removed}\n- severity changes: ${changeSummary.severity}\n- options changes: ${changeSummary.options}\n- workspace membership changes: ${changeSummary.workspace}\n- current baseline: ${currentSummary.groups} groups, ${currentSummary.rules} rules\n- current severity mix: ${currentSummary.error} errors, ${currentSummary.warn} warnings, ${currentSummary.off} off\n\n`
895
907
  )
896
908
 
909
+ writeSectionTitle('Changes', color)
897
910
  for (const change of changes) {
898
911
  process.stdout.write(color.bold(`group ${change.groupId}\n`))
899
912
  const lines = formatDiff(change.groupId, change.diff).split('\n').slice(1)
@@ -908,6 +921,10 @@ function printWhatChanged(changes: Array<{ groupId: string; diff: SnapshotDiff }
908
921
  return 1
909
922
  }
910
923
 
924
+ function writeSectionTitle(title: string, color: ReturnType<typeof createColorizer>): void {
925
+ process.stdout.write(`${color.bold(title)}\n`)
926
+ }
927
+
911
928
  function summarizeChanges(changes: Array<{ groupId: string; diff: SnapshotDiff }>) {
912
929
  let introduced = 0
913
930
  let removed = 0