@eslint-config-snapshot/cli 1.1.1 → 1.2.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
+ ## 1.2.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Minor release: centralize shared command execution flow with reusable snapshot preparation executor.
8
+
9
+ ### Patch Changes
10
+
11
+ - Updated dependencies
12
+ - @eslint-config-snapshot/api@1.2.0
13
+
3
14
  ## 1.1.1
4
15
 
5
16
  ### Patch Changes
package/dist/index.cjs CHANGED
@@ -40,9 +40,6 @@ var import_commander = require("commander");
40
40
  var import_debug2 = __toESM(require("debug"), 1);
41
41
  var import_node_path5 = __toESM(require("path"), 1);
42
42
 
43
- // src/commands/check.ts
44
- var import_api3 = require("@eslint-config-snapshot/api");
45
-
46
43
  // src/formatters.ts
47
44
  function formatDiff(groupId, diff) {
48
45
  const lines = [`group: ${groupId}`];
@@ -586,6 +583,14 @@ async function resolveGroupEslintVersions(cwd) {
586
583
 
587
584
  // src/commands/skipped-workspaces.ts
588
585
  var import_node_path3 = __toESM(require("path"), 1);
586
+ function writeDiscoveredWorkspacesSummary(terminal, workspacesRel) {
587
+ if (workspacesRel.length === 0) {
588
+ terminal.subtle("Auto-discovered workspaces: none\n");
589
+ return;
590
+ }
591
+ terminal.subtle(`Auto-discovered workspaces (${workspacesRel.length}): ${workspacesRel.join(", ")}
592
+ `);
593
+ }
589
594
  function writeSkippedWorkspaceSummary(terminal, cwd, configPath, skippedWorkspaces) {
590
595
  if (skippedWorkspaces.length === 0) {
591
596
  return;
@@ -641,26 +646,27 @@ ${objectLiteral}`;
641
646
  ${objectLiteral}`;
642
647
  }
643
648
 
644
- // src/commands/check.ts
645
- var UPDATE_HINT = "Tip: when you intentionally accept changes, run `eslint-config-snapshot --update` to refresh the baseline.\n";
646
- async function executeCheck(cwd, format, terminal, snapshotDir, defaultInvocation = false) {
649
+ // src/commands/snapshot-executor.ts
650
+ var import_api3 = require("@eslint-config-snapshot/api");
651
+ async function prepareSnapshotExecution(options) {
652
+ const { cwd, snapshotDir, terminal, commandLabel, progressMessage, showContext = true } = options;
647
653
  const foundConfig = await (0, import_api3.findConfigPath)(cwd);
648
654
  const storedSnapshots = await loadStoredSnapshots(cwd, snapshotDir);
649
- if (format !== "status") {
650
- writeRunContextHeader(terminal, cwd, defaultInvocation ? "check" : `check:${format}`, foundConfig?.path, storedSnapshots);
651
- if (terminal.showProgress) {
652
- terminal.subtle("\u{1F50E} Checking current ESLint configuration...\n");
653
- }
655
+ if (showContext) {
656
+ writeRunContextHeader(terminal, cwd, commandLabel, foundConfig?.path, storedSnapshots);
654
657
  }
655
- if (!foundConfig) {
658
+ if (showContext && terminal.showProgress && progressMessage.length > 0) {
659
+ terminal.subtle(progressMessage);
660
+ }
661
+ if (showContext && !foundConfig) {
656
662
  terminal.subtle(
657
663
  "Tip: no explicit config found. Using safe built-in defaults. Run `eslint-config-snapshot init` to customize when needed.\n"
658
664
  );
659
665
  }
660
- let currentSnapshots;
661
666
  const skippedWorkspaces = [];
662
667
  let discoveredWorkspaces = [];
663
668
  const allowWorkspaceExtractionFailure = !foundConfig || isDefaultEquivalentConfig(foundConfig.config);
669
+ let currentSnapshots;
664
670
  try {
665
671
  currentSnapshots = await computeCurrentSnapshots(cwd, {
666
672
  allowWorkspaceExtractionFailure,
@@ -672,18 +678,56 @@ async function executeCheck(cwd, format, terminal, snapshotDir, defaultInvocatio
672
678
  }
673
679
  });
674
680
  } catch (error) {
675
- if (!foundConfig && isWorkspaceDiscoveryDefaultsError(error)) {
676
- terminal.write(
677
- "Automatic workspace discovery could not complete with defaults.\nRun `eslint-config-snapshot init` to configure workspaces, then run `eslint-config-snapshot --update`.\n"
678
- );
679
- return 1;
681
+ if (allowWorkspaceExtractionFailure && isWorkspaceDiscoveryDefaultsError(error)) {
682
+ if (showContext) {
683
+ terminal.write(
684
+ "Automatic workspace discovery could not complete with defaults.\nRun `eslint-config-snapshot init` to configure workspaces, then run `eslint-config-snapshot --update`.\n"
685
+ );
686
+ }
687
+ return { ok: false, exitCode: 1 };
680
688
  }
681
689
  throw error;
682
690
  }
683
- if (!foundConfig) {
691
+ return {
692
+ ok: true,
693
+ foundConfig,
694
+ storedSnapshots,
695
+ currentSnapshots,
696
+ discoveredWorkspaces,
697
+ skippedWorkspaces
698
+ };
699
+ }
700
+ function isWorkspaceDiscoveryDefaultsError(error) {
701
+ const message = error instanceof Error ? error.message : String(error);
702
+ return message.includes("Unable to discover workspaces") || message.includes("Unmatched workspaces") || message.includes("zero-config mode");
703
+ }
704
+ function isDefaultEquivalentConfig(config) {
705
+ return JSON.stringify(config) === JSON.stringify(import_api3.DEFAULT_CONFIG);
706
+ }
707
+
708
+ // src/commands/check.ts
709
+ var UPDATE_HINT = "Tip: when you intentionally accept changes, run `eslint-config-snapshot --update` to refresh the baseline.\n";
710
+ async function executeCheck(cwd, format, terminal, snapshotDir, defaultInvocation = false) {
711
+ const isStatusFormat = format === "status";
712
+ const commandLabel = defaultInvocation ? "check" : `check:${format}`;
713
+ const prepared = await prepareSnapshotExecution({
714
+ cwd,
715
+ snapshotDir,
716
+ terminal,
717
+ commandLabel: isStatusFormat ? "check:status" : commandLabel,
718
+ progressMessage: isStatusFormat ? "" : "\u{1F50E} Checking current ESLint configuration...\n",
719
+ showContext: isStatusFormat === false
720
+ });
721
+ if (prepared.ok === false) {
722
+ return prepared.exitCode;
723
+ }
724
+ const { foundConfig, storedSnapshots, currentSnapshots, discoveredWorkspaces, skippedWorkspaces } = prepared;
725
+ if (foundConfig === null && isStatusFormat === false) {
684
726
  writeDiscoveredWorkspacesSummary(terminal, discoveredWorkspaces);
685
727
  }
686
- writeSkippedWorkspaceSummary(terminal, cwd, foundConfig?.path, skippedWorkspaces);
728
+ if (isStatusFormat === false) {
729
+ writeSkippedWorkspaceSummary(terminal, cwd, foundConfig?.path, skippedWorkspaces);
730
+ }
687
731
  if (storedSnapshots.size === 0) {
688
732
  const summary = summarizeSnapshots(currentSnapshots);
689
733
  terminal.write(
@@ -778,36 +822,24 @@ function printWhatChanged(terminal, changes, currentSnapshots, eslintVersionsByG
778
822
  terminal.subtle(UPDATE_HINT);
779
823
  return 1;
780
824
  }
781
- function isWorkspaceDiscoveryDefaultsError(error) {
782
- const message = error instanceof Error ? error.message : String(error);
783
- return message.includes("Unable to discover workspaces") || message.includes("Unmatched workspaces") || message.includes("zero-config mode");
784
- }
785
- function isDefaultEquivalentConfig(config) {
786
- return JSON.stringify(config) === JSON.stringify(import_api3.DEFAULT_CONFIG);
787
- }
788
- function writeDiscoveredWorkspacesSummary(terminal, workspacesRel) {
789
- if (workspacesRel.length === 0) {
790
- terminal.subtle("Auto-discovered workspaces: none\n");
791
- return;
792
- }
793
- terminal.subtle(`Auto-discovered workspaces (${workspacesRel.length}): ${workspacesRel.join(", ")}
794
- `);
795
- }
796
825
 
797
826
  // src/commands/print.ts
798
827
  var import_api4 = require("@eslint-config-snapshot/api");
799
828
  async function executePrint(cwd, terminal, snapshotDir, format) {
800
- const foundConfig = await (0, import_api4.findConfigPath)(cwd);
801
- const storedSnapshots = await loadStoredSnapshots(cwd, snapshotDir);
802
- writeRunContextHeader(terminal, cwd, `print:${format}`, foundConfig?.path, storedSnapshots);
803
- if (terminal.showProgress) {
804
- terminal.subtle("\u{1F50E} Checking current ESLint configuration...\n");
829
+ const prepared = await prepareSnapshotExecution({
830
+ cwd,
831
+ snapshotDir,
832
+ terminal,
833
+ commandLabel: `print:${format}`,
834
+ progressMessage: "\u{1F50E} Checking current ESLint configuration...\n"
835
+ });
836
+ if (!prepared.ok) {
837
+ return prepared.exitCode;
805
838
  }
806
- const allowWorkspaceExtractionFailure = !foundConfig || isDefaultEquivalentConfig2(foundConfig.config);
807
- const currentSnapshots = await computeCurrentSnapshots(cwd, { allowWorkspaceExtractionFailure });
839
+ const { currentSnapshots } = prepared;
808
840
  if (format === "short") {
809
841
  terminal.write(formatShortPrint([...currentSnapshots.values()]));
810
- return;
842
+ return 0;
811
843
  }
812
844
  const output = [...currentSnapshots.values()].map((snapshot) => ({
813
845
  groupId: snapshot.groupId,
@@ -815,14 +847,20 @@ async function executePrint(cwd, terminal, snapshotDir, format) {
815
847
  }));
816
848
  terminal.write(`${JSON.stringify(output, null, 2)}
817
849
  `);
850
+ return 0;
818
851
  }
819
852
  async function executeConfig(cwd, terminal, snapshotDir, format) {
820
- const foundConfig = await (0, import_api4.findConfigPath)(cwd);
821
- const storedSnapshots = await loadStoredSnapshots(cwd, snapshotDir);
822
- writeRunContextHeader(terminal, cwd, `config:${format}`, foundConfig?.path, storedSnapshots);
823
- if (terminal.showProgress) {
824
- terminal.subtle("\u2699\uFE0F Resolving effective runtime configuration...\n");
853
+ const prepared = await prepareSnapshotExecution({
854
+ cwd,
855
+ snapshotDir,
856
+ terminal,
857
+ commandLabel: `config:${format}`,
858
+ progressMessage: "\u2699\uFE0F Resolving effective runtime configuration...\n"
859
+ });
860
+ if (!prepared.ok) {
861
+ return prepared.exitCode;
825
862
  }
863
+ const { foundConfig } = prepared;
826
864
  const config = await (0, import_api4.loadConfig)(cwd);
827
865
  const resolved = await resolveWorkspaceAssignments(cwd, config);
828
866
  const payload = {
@@ -838,54 +876,28 @@ async function executeConfig(cwd, terminal, snapshotDir, format) {
838
876
  };
839
877
  if (format === "short") {
840
878
  terminal.write(formatShortConfig(payload));
841
- return;
879
+ return 0;
842
880
  }
843
881
  terminal.write(`${JSON.stringify(payload, null, 2)}
844
882
  `);
845
- }
846
- function isDefaultEquivalentConfig2(config) {
847
- return JSON.stringify(config) === JSON.stringify(import_api4.DEFAULT_CONFIG);
883
+ return 0;
848
884
  }
849
885
 
850
886
  // src/commands/update.ts
851
- var import_api5 = require("@eslint-config-snapshot/api");
852
887
  async function executeUpdate(cwd, terminal, snapshotDir, printSummary) {
853
- const foundConfig = await (0, import_api5.findConfigPath)(cwd);
854
- const storedSnapshots = await loadStoredSnapshots(cwd, snapshotDir);
855
- writeRunContextHeader(terminal, cwd, "update", foundConfig?.path, storedSnapshots);
856
- if (terminal.showProgress) {
857
- terminal.subtle("\u{1F50E} Checking current ESLint configuration...\n");
858
- }
859
- if (!foundConfig) {
860
- terminal.subtle(
861
- "Tip: no explicit config found. Using safe built-in defaults. Run `eslint-config-snapshot init` to customize when needed.\n"
862
- );
863
- }
864
- let currentSnapshots;
865
- const skippedWorkspaces = [];
866
- let discoveredWorkspaces = [];
867
- const allowWorkspaceExtractionFailure = !foundConfig || isDefaultEquivalentConfig3(foundConfig.config);
868
- try {
869
- currentSnapshots = await computeCurrentSnapshots(cwd, {
870
- allowWorkspaceExtractionFailure,
871
- onWorkspacesDiscovered: (workspacesRel) => {
872
- discoveredWorkspaces = workspacesRel;
873
- },
874
- onWorkspaceSkipped: (skipped) => {
875
- skippedWorkspaces.push(skipped);
876
- }
877
- });
878
- } catch (error) {
879
- if (!foundConfig && isWorkspaceDiscoveryDefaultsError2(error)) {
880
- terminal.write(
881
- "Automatic workspace discovery could not complete with defaults.\nRun `eslint-config-snapshot init` to configure workspaces, then run `eslint-config-snapshot --update`.\n"
882
- );
883
- return 1;
884
- }
885
- throw error;
888
+ const prepared = await prepareSnapshotExecution({
889
+ cwd,
890
+ snapshotDir,
891
+ terminal,
892
+ commandLabel: "update",
893
+ progressMessage: "\u{1F50E} Checking current ESLint configuration...\n"
894
+ });
895
+ if (prepared.ok === false) {
896
+ return prepared.exitCode;
886
897
  }
898
+ const { foundConfig, storedSnapshots, currentSnapshots, discoveredWorkspaces, skippedWorkspaces } = prepared;
887
899
  if (!foundConfig) {
888
- writeDiscoveredWorkspacesSummary2(terminal, discoveredWorkspaces);
900
+ writeDiscoveredWorkspacesSummary(terminal, discoveredWorkspaces);
889
901
  }
890
902
  writeSkippedWorkspaceSummary(terminal, cwd, foundConfig?.path, skippedWorkspaces);
891
903
  await writeSnapshots(cwd, snapshotDir, currentSnapshots);
@@ -902,31 +914,16 @@ async function executeUpdate(cwd, terminal, snapshotDir, printSummary) {
902
914
  }
903
915
  return 0;
904
916
  }
905
- function isWorkspaceDiscoveryDefaultsError2(error) {
906
- const message = error instanceof Error ? error.message : String(error);
907
- return message.includes("Unable to discover workspaces") || message.includes("Unmatched workspaces") || message.includes("zero-config mode");
908
- }
909
- function isDefaultEquivalentConfig3(config) {
910
- return JSON.stringify(config) === JSON.stringify(import_api5.DEFAULT_CONFIG);
911
- }
912
- function writeDiscoveredWorkspacesSummary2(terminal, workspacesRel) {
913
- if (workspacesRel.length === 0) {
914
- terminal.subtle("Auto-discovered workspaces: none\n");
915
- return;
916
- }
917
- terminal.subtle(`Auto-discovered workspaces (${workspacesRel.length}): ${workspacesRel.join(", ")}
918
- `);
919
- }
920
917
 
921
918
  // src/init.ts
922
- var import_api6 = require("@eslint-config-snapshot/api");
919
+ var import_api5 = require("@eslint-config-snapshot/api");
923
920
  var import_fast_glob2 = __toESM(require("fast-glob"), 1);
924
921
  var import_promises2 = require("fs/promises");
925
922
  var import_node_path4 = __toESM(require("path"), 1);
926
923
  async function runInit(cwd, opts, runtime) {
927
924
  const force = opts.force ?? false;
928
925
  const showEffective = opts.showEffective ?? false;
929
- const existing = await (0, import_api6.findConfigPath)(cwd);
926
+ const existing = await (0, import_api5.findConfigPath)(cwd);
930
927
  if (existing && !force) {
931
928
  runtime.writeStderr(
932
929
  `Existing config detected at ${existing.path}. Creating another config can cause conflicts. Remove the existing config or rerun with --force.
@@ -1063,7 +1060,7 @@ function buildRecommendedConfigFromAssignments(workspaces, assignments) {
1063
1060
  };
1064
1061
  }
1065
1062
  async function discoverInitWorkspaces(cwd) {
1066
- const discovered = await (0, import_api6.discoverWorkspaces)({ cwd, workspaceInput: { mode: "discover" } });
1063
+ const discovered = await (0, import_api5.discoverWorkspaces)({ cwd, workspaceInput: { mode: "discover" } });
1067
1064
  if (!(discovered.workspacesRel.length === 1 && discovered.workspacesRel[0] === ".")) {
1068
1065
  return discovered.workspacesRel;
1069
1066
  }
@@ -1085,7 +1082,7 @@ async function discoverInitWorkspaces(cwd) {
1085
1082
  onlyFiles: true,
1086
1083
  dot: true
1087
1084
  });
1088
- const workspaceDirs = [...new Set(workspacePackageFiles.map((entry) => (0, import_api6.normalizePath)(import_node_path4.default.dirname(entry))))].sort(
1085
+ const workspaceDirs = [...new Set(workspacePackageFiles.map((entry) => (0, import_api5.normalizePath)(import_node_path4.default.dirname(entry))))].sort(
1089
1086
  (a, b) => a.localeCompare(b)
1090
1087
  );
1091
1088
  if (workspaceDirs.length > 0) {
@@ -1136,7 +1133,7 @@ async function askRecommendedGroupAssignments(workspaces, runtime) {
1136
1133
  }
1137
1134
  function toConfigScaffold(configObject) {
1138
1135
  if (Object.keys(configObject).length === 0) {
1139
- return (0, import_api6.getConfigScaffold)("minimal");
1136
+ return (0, import_api5.getConfigScaffold)("minimal");
1140
1137
  }
1141
1138
  return `export default ${JSON.stringify(configObject, null, 2)}
1142
1139
  `;
@@ -1416,13 +1413,11 @@ function createProgram(cwd, terminal, onActionExit) {
1416
1413
  });
1417
1414
  program.command("print").description("Print aggregated rules").option("--format <format>", "Output format: json|short", parsePrintFormat, "json").option("--short", "Alias for --format short").action(async (opts) => {
1418
1415
  const format = opts.short ? "short" : opts.format;
1419
- await executePrint(cwd, terminal, SNAPSHOT_DIR, format);
1420
- onActionExit(0);
1416
+ onActionExit(await executePrint(cwd, terminal, SNAPSHOT_DIR, format));
1421
1417
  });
1422
1418
  program.command("config").description("Print effective evaluated config").option("--format <format>", "Output format: json|short", parsePrintFormat, "json").option("--short", "Alias for --format short").action(async (opts) => {
1423
1419
  const format = opts.short ? "short" : opts.format;
1424
- await executeConfig(cwd, terminal, SNAPSHOT_DIR, format);
1425
- onActionExit(0);
1420
+ onActionExit(await executeConfig(cwd, terminal, SNAPSHOT_DIR, format));
1426
1421
  });
1427
1422
  program.command("init").description("Initialize config (file or package.json)").option("--target <target>", "Config target: file|package-json", parseInitTarget).option("--preset <preset>", "Config preset: recommended|minimal|full", parseInitPreset).option("--show-effective", "Print the evaluated config that will be written").option("-f, --force", "Allow init even when an existing config is detected").option("-y, --yes", "Skip prompts and use defaults/options").addHelpText(
1428
1423
  "after",
package/dist/index.js CHANGED
@@ -5,9 +5,6 @@ import { Command, CommanderError, InvalidArgumentError } from "commander";
5
5
  import createDebug2 from "debug";
6
6
  import path5 from "path";
7
7
 
8
- // src/commands/check.ts
9
- import { DEFAULT_CONFIG, findConfigPath } from "@eslint-config-snapshot/api";
10
-
11
8
  // src/formatters.ts
12
9
  function formatDiff(groupId, diff) {
13
10
  const lines = [`group: ${groupId}`];
@@ -564,6 +561,14 @@ async function resolveGroupEslintVersions(cwd) {
564
561
 
565
562
  // src/commands/skipped-workspaces.ts
566
563
  import path3 from "path";
564
+ function writeDiscoveredWorkspacesSummary(terminal, workspacesRel) {
565
+ if (workspacesRel.length === 0) {
566
+ terminal.subtle("Auto-discovered workspaces: none\n");
567
+ return;
568
+ }
569
+ terminal.subtle(`Auto-discovered workspaces (${workspacesRel.length}): ${workspacesRel.join(", ")}
570
+ `);
571
+ }
567
572
  function writeSkippedWorkspaceSummary(terminal, cwd, configPath, skippedWorkspaces) {
568
573
  if (skippedWorkspaces.length === 0) {
569
574
  return;
@@ -619,26 +624,27 @@ ${objectLiteral}`;
619
624
  ${objectLiteral}`;
620
625
  }
621
626
 
622
- // src/commands/check.ts
623
- var UPDATE_HINT = "Tip: when you intentionally accept changes, run `eslint-config-snapshot --update` to refresh the baseline.\n";
624
- async function executeCheck(cwd, format, terminal, snapshotDir, defaultInvocation = false) {
627
+ // src/commands/snapshot-executor.ts
628
+ import { DEFAULT_CONFIG, findConfigPath } from "@eslint-config-snapshot/api";
629
+ async function prepareSnapshotExecution(options) {
630
+ const { cwd, snapshotDir, terminal, commandLabel, progressMessage, showContext = true } = options;
625
631
  const foundConfig = await findConfigPath(cwd);
626
632
  const storedSnapshots = await loadStoredSnapshots(cwd, snapshotDir);
627
- if (format !== "status") {
628
- writeRunContextHeader(terminal, cwd, defaultInvocation ? "check" : `check:${format}`, foundConfig?.path, storedSnapshots);
629
- if (terminal.showProgress) {
630
- terminal.subtle("\u{1F50E} Checking current ESLint configuration...\n");
631
- }
633
+ if (showContext) {
634
+ writeRunContextHeader(terminal, cwd, commandLabel, foundConfig?.path, storedSnapshots);
632
635
  }
633
- if (!foundConfig) {
636
+ if (showContext && terminal.showProgress && progressMessage.length > 0) {
637
+ terminal.subtle(progressMessage);
638
+ }
639
+ if (showContext && !foundConfig) {
634
640
  terminal.subtle(
635
641
  "Tip: no explicit config found. Using safe built-in defaults. Run `eslint-config-snapshot init` to customize when needed.\n"
636
642
  );
637
643
  }
638
- let currentSnapshots;
639
644
  const skippedWorkspaces = [];
640
645
  let discoveredWorkspaces = [];
641
646
  const allowWorkspaceExtractionFailure = !foundConfig || isDefaultEquivalentConfig(foundConfig.config);
647
+ let currentSnapshots;
642
648
  try {
643
649
  currentSnapshots = await computeCurrentSnapshots(cwd, {
644
650
  allowWorkspaceExtractionFailure,
@@ -650,18 +656,56 @@ async function executeCheck(cwd, format, terminal, snapshotDir, defaultInvocatio
650
656
  }
651
657
  });
652
658
  } catch (error) {
653
- if (!foundConfig && isWorkspaceDiscoveryDefaultsError(error)) {
654
- terminal.write(
655
- "Automatic workspace discovery could not complete with defaults.\nRun `eslint-config-snapshot init` to configure workspaces, then run `eslint-config-snapshot --update`.\n"
656
- );
657
- return 1;
659
+ if (allowWorkspaceExtractionFailure && isWorkspaceDiscoveryDefaultsError(error)) {
660
+ if (showContext) {
661
+ terminal.write(
662
+ "Automatic workspace discovery could not complete with defaults.\nRun `eslint-config-snapshot init` to configure workspaces, then run `eslint-config-snapshot --update`.\n"
663
+ );
664
+ }
665
+ return { ok: false, exitCode: 1 };
658
666
  }
659
667
  throw error;
660
668
  }
661
- if (!foundConfig) {
669
+ return {
670
+ ok: true,
671
+ foundConfig,
672
+ storedSnapshots,
673
+ currentSnapshots,
674
+ discoveredWorkspaces,
675
+ skippedWorkspaces
676
+ };
677
+ }
678
+ function isWorkspaceDiscoveryDefaultsError(error) {
679
+ const message = error instanceof Error ? error.message : String(error);
680
+ return message.includes("Unable to discover workspaces") || message.includes("Unmatched workspaces") || message.includes("zero-config mode");
681
+ }
682
+ function isDefaultEquivalentConfig(config) {
683
+ return JSON.stringify(config) === JSON.stringify(DEFAULT_CONFIG);
684
+ }
685
+
686
+ // src/commands/check.ts
687
+ var UPDATE_HINT = "Tip: when you intentionally accept changes, run `eslint-config-snapshot --update` to refresh the baseline.\n";
688
+ async function executeCheck(cwd, format, terminal, snapshotDir, defaultInvocation = false) {
689
+ const isStatusFormat = format === "status";
690
+ const commandLabel = defaultInvocation ? "check" : `check:${format}`;
691
+ const prepared = await prepareSnapshotExecution({
692
+ cwd,
693
+ snapshotDir,
694
+ terminal,
695
+ commandLabel: isStatusFormat ? "check:status" : commandLabel,
696
+ progressMessage: isStatusFormat ? "" : "\u{1F50E} Checking current ESLint configuration...\n",
697
+ showContext: isStatusFormat === false
698
+ });
699
+ if (prepared.ok === false) {
700
+ return prepared.exitCode;
701
+ }
702
+ const { foundConfig, storedSnapshots, currentSnapshots, discoveredWorkspaces, skippedWorkspaces } = prepared;
703
+ if (foundConfig === null && isStatusFormat === false) {
662
704
  writeDiscoveredWorkspacesSummary(terminal, discoveredWorkspaces);
663
705
  }
664
- writeSkippedWorkspaceSummary(terminal, cwd, foundConfig?.path, skippedWorkspaces);
706
+ if (isStatusFormat === false) {
707
+ writeSkippedWorkspaceSummary(terminal, cwd, foundConfig?.path, skippedWorkspaces);
708
+ }
665
709
  if (storedSnapshots.size === 0) {
666
710
  const summary = summarizeSnapshots(currentSnapshots);
667
711
  terminal.write(
@@ -756,36 +800,24 @@ function printWhatChanged(terminal, changes, currentSnapshots, eslintVersionsByG
756
800
  terminal.subtle(UPDATE_HINT);
757
801
  return 1;
758
802
  }
759
- function isWorkspaceDiscoveryDefaultsError(error) {
760
- const message = error instanceof Error ? error.message : String(error);
761
- return message.includes("Unable to discover workspaces") || message.includes("Unmatched workspaces") || message.includes("zero-config mode");
762
- }
763
- function isDefaultEquivalentConfig(config) {
764
- return JSON.stringify(config) === JSON.stringify(DEFAULT_CONFIG);
765
- }
766
- function writeDiscoveredWorkspacesSummary(terminal, workspacesRel) {
767
- if (workspacesRel.length === 0) {
768
- terminal.subtle("Auto-discovered workspaces: none\n");
769
- return;
770
- }
771
- terminal.subtle(`Auto-discovered workspaces (${workspacesRel.length}): ${workspacesRel.join(", ")}
772
- `);
773
- }
774
803
 
775
804
  // src/commands/print.ts
776
- import { DEFAULT_CONFIG as DEFAULT_CONFIG2, findConfigPath as findConfigPath2, loadConfig as loadConfig2 } from "@eslint-config-snapshot/api";
805
+ import { loadConfig as loadConfig2 } from "@eslint-config-snapshot/api";
777
806
  async function executePrint(cwd, terminal, snapshotDir, format) {
778
- const foundConfig = await findConfigPath2(cwd);
779
- const storedSnapshots = await loadStoredSnapshots(cwd, snapshotDir);
780
- writeRunContextHeader(terminal, cwd, `print:${format}`, foundConfig?.path, storedSnapshots);
781
- if (terminal.showProgress) {
782
- terminal.subtle("\u{1F50E} Checking current ESLint configuration...\n");
807
+ const prepared = await prepareSnapshotExecution({
808
+ cwd,
809
+ snapshotDir,
810
+ terminal,
811
+ commandLabel: `print:${format}`,
812
+ progressMessage: "\u{1F50E} Checking current ESLint configuration...\n"
813
+ });
814
+ if (!prepared.ok) {
815
+ return prepared.exitCode;
783
816
  }
784
- const allowWorkspaceExtractionFailure = !foundConfig || isDefaultEquivalentConfig2(foundConfig.config);
785
- const currentSnapshots = await computeCurrentSnapshots(cwd, { allowWorkspaceExtractionFailure });
817
+ const { currentSnapshots } = prepared;
786
818
  if (format === "short") {
787
819
  terminal.write(formatShortPrint([...currentSnapshots.values()]));
788
- return;
820
+ return 0;
789
821
  }
790
822
  const output = [...currentSnapshots.values()].map((snapshot) => ({
791
823
  groupId: snapshot.groupId,
@@ -793,14 +825,20 @@ async function executePrint(cwd, terminal, snapshotDir, format) {
793
825
  }));
794
826
  terminal.write(`${JSON.stringify(output, null, 2)}
795
827
  `);
828
+ return 0;
796
829
  }
797
830
  async function executeConfig(cwd, terminal, snapshotDir, format) {
798
- const foundConfig = await findConfigPath2(cwd);
799
- const storedSnapshots = await loadStoredSnapshots(cwd, snapshotDir);
800
- writeRunContextHeader(terminal, cwd, `config:${format}`, foundConfig?.path, storedSnapshots);
801
- if (terminal.showProgress) {
802
- terminal.subtle("\u2699\uFE0F Resolving effective runtime configuration...\n");
831
+ const prepared = await prepareSnapshotExecution({
832
+ cwd,
833
+ snapshotDir,
834
+ terminal,
835
+ commandLabel: `config:${format}`,
836
+ progressMessage: "\u2699\uFE0F Resolving effective runtime configuration...\n"
837
+ });
838
+ if (!prepared.ok) {
839
+ return prepared.exitCode;
803
840
  }
841
+ const { foundConfig } = prepared;
804
842
  const config = await loadConfig2(cwd);
805
843
  const resolved = await resolveWorkspaceAssignments(cwd, config);
806
844
  const payload = {
@@ -816,54 +854,28 @@ async function executeConfig(cwd, terminal, snapshotDir, format) {
816
854
  };
817
855
  if (format === "short") {
818
856
  terminal.write(formatShortConfig(payload));
819
- return;
857
+ return 0;
820
858
  }
821
859
  terminal.write(`${JSON.stringify(payload, null, 2)}
822
860
  `);
823
- }
824
- function isDefaultEquivalentConfig2(config) {
825
- return JSON.stringify(config) === JSON.stringify(DEFAULT_CONFIG2);
861
+ return 0;
826
862
  }
827
863
 
828
864
  // src/commands/update.ts
829
- import { DEFAULT_CONFIG as DEFAULT_CONFIG3, findConfigPath as findConfigPath3 } from "@eslint-config-snapshot/api";
830
865
  async function executeUpdate(cwd, terminal, snapshotDir, printSummary) {
831
- const foundConfig = await findConfigPath3(cwd);
832
- const storedSnapshots = await loadStoredSnapshots(cwd, snapshotDir);
833
- writeRunContextHeader(terminal, cwd, "update", foundConfig?.path, storedSnapshots);
834
- if (terminal.showProgress) {
835
- terminal.subtle("\u{1F50E} Checking current ESLint configuration...\n");
836
- }
837
- if (!foundConfig) {
838
- terminal.subtle(
839
- "Tip: no explicit config found. Using safe built-in defaults. Run `eslint-config-snapshot init` to customize when needed.\n"
840
- );
841
- }
842
- let currentSnapshots;
843
- const skippedWorkspaces = [];
844
- let discoveredWorkspaces = [];
845
- const allowWorkspaceExtractionFailure = !foundConfig || isDefaultEquivalentConfig3(foundConfig.config);
846
- try {
847
- currentSnapshots = await computeCurrentSnapshots(cwd, {
848
- allowWorkspaceExtractionFailure,
849
- onWorkspacesDiscovered: (workspacesRel) => {
850
- discoveredWorkspaces = workspacesRel;
851
- },
852
- onWorkspaceSkipped: (skipped) => {
853
- skippedWorkspaces.push(skipped);
854
- }
855
- });
856
- } catch (error) {
857
- if (!foundConfig && isWorkspaceDiscoveryDefaultsError2(error)) {
858
- terminal.write(
859
- "Automatic workspace discovery could not complete with defaults.\nRun `eslint-config-snapshot init` to configure workspaces, then run `eslint-config-snapshot --update`.\n"
860
- );
861
- return 1;
862
- }
863
- throw error;
866
+ const prepared = await prepareSnapshotExecution({
867
+ cwd,
868
+ snapshotDir,
869
+ terminal,
870
+ commandLabel: "update",
871
+ progressMessage: "\u{1F50E} Checking current ESLint configuration...\n"
872
+ });
873
+ if (prepared.ok === false) {
874
+ return prepared.exitCode;
864
875
  }
876
+ const { foundConfig, storedSnapshots, currentSnapshots, discoveredWorkspaces, skippedWorkspaces } = prepared;
865
877
  if (!foundConfig) {
866
- writeDiscoveredWorkspacesSummary2(terminal, discoveredWorkspaces);
878
+ writeDiscoveredWorkspacesSummary(terminal, discoveredWorkspaces);
867
879
  }
868
880
  writeSkippedWorkspaceSummary(terminal, cwd, foundConfig?.path, skippedWorkspaces);
869
881
  await writeSnapshots(cwd, snapshotDir, currentSnapshots);
@@ -880,31 +892,16 @@ async function executeUpdate(cwd, terminal, snapshotDir, printSummary) {
880
892
  }
881
893
  return 0;
882
894
  }
883
- function isWorkspaceDiscoveryDefaultsError2(error) {
884
- const message = error instanceof Error ? error.message : String(error);
885
- return message.includes("Unable to discover workspaces") || message.includes("Unmatched workspaces") || message.includes("zero-config mode");
886
- }
887
- function isDefaultEquivalentConfig3(config) {
888
- return JSON.stringify(config) === JSON.stringify(DEFAULT_CONFIG3);
889
- }
890
- function writeDiscoveredWorkspacesSummary2(terminal, workspacesRel) {
891
- if (workspacesRel.length === 0) {
892
- terminal.subtle("Auto-discovered workspaces: none\n");
893
- return;
894
- }
895
- terminal.subtle(`Auto-discovered workspaces (${workspacesRel.length}): ${workspacesRel.join(", ")}
896
- `);
897
- }
898
895
 
899
896
  // src/init.ts
900
- import { discoverWorkspaces as discoverWorkspaces2, findConfigPath as findConfigPath4, getConfigScaffold, normalizePath as normalizePath2 } from "@eslint-config-snapshot/api";
897
+ import { discoverWorkspaces as discoverWorkspaces2, findConfigPath as findConfigPath2, getConfigScaffold, normalizePath as normalizePath2 } from "@eslint-config-snapshot/api";
901
898
  import fg2 from "fast-glob";
902
899
  import { access, readFile, writeFile } from "fs/promises";
903
900
  import path4 from "path";
904
901
  async function runInit(cwd, opts, runtime) {
905
902
  const force = opts.force ?? false;
906
903
  const showEffective = opts.showEffective ?? false;
907
- const existing = await findConfigPath4(cwd);
904
+ const existing = await findConfigPath2(cwd);
908
905
  if (existing && !force) {
909
906
  runtime.writeStderr(
910
907
  `Existing config detected at ${existing.path}. Creating another config can cause conflicts. Remove the existing config or rerun with --force.
@@ -1394,13 +1391,11 @@ function createProgram(cwd, terminal, onActionExit) {
1394
1391
  });
1395
1392
  program.command("print").description("Print aggregated rules").option("--format <format>", "Output format: json|short", parsePrintFormat, "json").option("--short", "Alias for --format short").action(async (opts) => {
1396
1393
  const format = opts.short ? "short" : opts.format;
1397
- await executePrint(cwd, terminal, SNAPSHOT_DIR, format);
1398
- onActionExit(0);
1394
+ onActionExit(await executePrint(cwd, terminal, SNAPSHOT_DIR, format));
1399
1395
  });
1400
1396
  program.command("config").description("Print effective evaluated config").option("--format <format>", "Output format: json|short", parsePrintFormat, "json").option("--short", "Alias for --format short").action(async (opts) => {
1401
1397
  const format = opts.short ? "short" : opts.format;
1402
- await executeConfig(cwd, terminal, SNAPSHOT_DIR, format);
1403
- onActionExit(0);
1398
+ onActionExit(await executeConfig(cwd, terminal, SNAPSHOT_DIR, format));
1404
1399
  });
1405
1400
  program.command("init").description("Initialize config (file or package.json)").option("--target <target>", "Config target: file|package-json", parseInitTarget).option("--preset <preset>", "Config preset: recommended|minimal|full", parseInitPreset).option("--show-effective", "Print the evaluated config that will be written").option("-f, --force", "Allow init even when an existing config is detected").option("-y, --yes", "Skip prompts and use defaults/options").addHelpText(
1406
1401
  "after",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eslint-config-snapshot/cli",
3
- "version": "1.1.1",
3
+ "version": "1.2.0",
4
4
  "type": "module",
5
5
  "repository": {
6
6
  "type": "git",
@@ -31,6 +31,6 @@
31
31
  "commander": "^14.0.3",
32
32
  "debug": "^4.4.3",
33
33
  "fast-glob": "^3.3.3",
34
- "@eslint-config-snapshot/api": "1.1.1"
34
+ "@eslint-config-snapshot/api": "1.2.0"
35
35
  }
36
36
  }
@@ -1,5 +1,3 @@
1
- import { DEFAULT_CONFIG, findConfigPath, type SnapshotConfig } from '@eslint-config-snapshot/api'
2
-
3
1
  import {
4
2
  countUniqueWorkspaces,
5
3
  decorateDiffLine,
@@ -8,20 +6,18 @@ import {
8
6
  summarizeChanges,
9
7
  summarizeSnapshots
10
8
  } from '../formatters.js'
11
- import { writeEslintVersionSummary, writeRunContextHeader } from '../run-context.js'
9
+ import { writeEslintVersionSummary } from '../run-context.js'
12
10
  import {
13
11
  type BuiltSnapshot,
14
12
  compareSnapshotMaps,
15
- computeCurrentSnapshots,
16
13
  type GroupEslintVersions,
17
- loadStoredSnapshots,
18
14
  resolveGroupEslintVersions,
19
- type SkippedWorkspace,
20
15
  type SnapshotDiff,
21
16
  writeSnapshots
22
17
  } from '../runtime.js'
23
18
  import { type TerminalIO } from '../terminal.js'
24
- import { writeSkippedWorkspaceSummary } from './skipped-workspaces.js'
19
+ import { writeDiscoveredWorkspacesSummary, writeSkippedWorkspaceSummary } from './skipped-workspaces.js'
20
+ import { prepareSnapshotExecution } from './snapshot-executor.js'
25
21
 
26
22
  export type CheckFormat = 'summary' | 'status' | 'diff'
27
23
 
@@ -34,50 +30,27 @@ export async function executeCheck(
34
30
  snapshotDir: string,
35
31
  defaultInvocation = false
36
32
  ): Promise<number> {
37
- const foundConfig = await findConfigPath(cwd)
38
- const storedSnapshots = await loadStoredSnapshots(cwd, snapshotDir)
39
-
40
- if (format !== 'status') {
41
- writeRunContextHeader(terminal, cwd, defaultInvocation ? 'check' : `check:${format}`, foundConfig?.path, storedSnapshots)
42
- if (terminal.showProgress) {
43
- terminal.subtle('🔎 Checking current ESLint configuration...\n')
44
- }
45
- }
46
-
47
- if (!foundConfig) {
48
- terminal.subtle(
49
- 'Tip: no explicit config found. Using safe built-in defaults. Run `eslint-config-snapshot init` to customize when needed.\n'
50
- )
33
+ const isStatusFormat = format === 'status'
34
+ const commandLabel = defaultInvocation ? 'check' : `check:${format}`
35
+ const prepared = await prepareSnapshotExecution({
36
+ cwd,
37
+ snapshotDir,
38
+ terminal,
39
+ commandLabel: isStatusFormat ? 'check:status' : commandLabel,
40
+ progressMessage: isStatusFormat ? '' : '🔎 Checking current ESLint configuration...\n',
41
+ showContext: isStatusFormat === false
42
+ })
43
+ if (prepared.ok === false) {
44
+ return prepared.exitCode
51
45
  }
52
46
 
53
- let currentSnapshots: Map<string, BuiltSnapshot>
54
- const skippedWorkspaces: SkippedWorkspace[] = []
55
- let discoveredWorkspaces: string[] = []
56
- const allowWorkspaceExtractionFailure = !foundConfig || isDefaultEquivalentConfig(foundConfig.config)
57
- try {
58
- currentSnapshots = await computeCurrentSnapshots(cwd, {
59
- allowWorkspaceExtractionFailure,
60
- onWorkspacesDiscovered: (workspacesRel) => {
61
- discoveredWorkspaces = workspacesRel
62
- },
63
- onWorkspaceSkipped: (skipped) => {
64
- skippedWorkspaces.push(skipped)
65
- }
66
- })
67
- } catch (error: unknown) {
68
- if (!foundConfig && isWorkspaceDiscoveryDefaultsError(error)) {
69
- terminal.write(
70
- 'Automatic workspace discovery could not complete with defaults.\nRun `eslint-config-snapshot init` to configure workspaces, then run `eslint-config-snapshot --update`.\n'
71
- )
72
- return 1
73
- }
74
-
75
- throw error
76
- }
77
- if (!foundConfig) {
47
+ const { foundConfig, storedSnapshots, currentSnapshots, discoveredWorkspaces, skippedWorkspaces } = prepared
48
+ if (foundConfig === null && isStatusFormat === false) {
78
49
  writeDiscoveredWorkspacesSummary(terminal, discoveredWorkspaces)
79
50
  }
80
- writeSkippedWorkspaceSummary(terminal, cwd, foundConfig?.path, skippedWorkspaces)
51
+ if (isStatusFormat === false) {
52
+ writeSkippedWorkspaceSummary(terminal, cwd, foundConfig?.path, skippedWorkspaces)
53
+ }
81
54
  if (storedSnapshots.size === 0) {
82
55
  const summary = summarizeSnapshots(currentSnapshots)
83
56
  terminal.write(
@@ -177,25 +150,3 @@ function printWhatChanged(
177
150
 
178
151
  return 1
179
152
  }
180
-
181
- function isWorkspaceDiscoveryDefaultsError(error: unknown): boolean {
182
- const message = error instanceof Error ? error.message : String(error)
183
- return (
184
- message.includes('Unable to discover workspaces') ||
185
- message.includes('Unmatched workspaces') ||
186
- message.includes('zero-config mode')
187
- )
188
- }
189
-
190
- function isDefaultEquivalentConfig(config: SnapshotConfig): boolean {
191
- return JSON.stringify(config) === JSON.stringify(DEFAULT_CONFIG)
192
- }
193
-
194
- function writeDiscoveredWorkspacesSummary(terminal: TerminalIO, workspacesRel: string[]): void {
195
- if (workspacesRel.length === 0) {
196
- terminal.subtle('Auto-discovered workspaces: none\n')
197
- return
198
- }
199
-
200
- terminal.subtle(`Auto-discovered workspaces (${workspacesRel.length}): ${workspacesRel.join(', ')}\n`)
201
- }
@@ -1,25 +1,29 @@
1
- import { DEFAULT_CONFIG, findConfigPath, loadConfig, type SnapshotConfig } from '@eslint-config-snapshot/api'
1
+ import { loadConfig } from '@eslint-config-snapshot/api'
2
2
 
3
3
  import { formatShortConfig, formatShortPrint } from '../formatters.js'
4
- import { writeRunContextHeader } from '../run-context.js'
5
- import { computeCurrentSnapshots, loadStoredSnapshots, resolveWorkspaceAssignments, type WorkspaceAssignments } from '../runtime.js'
4
+ import { resolveWorkspaceAssignments, type WorkspaceAssignments } from '../runtime.js'
6
5
  import { type TerminalIO } from '../terminal.js'
6
+ import { prepareSnapshotExecution } from './snapshot-executor.js'
7
7
 
8
8
  export type PrintFormat = 'json' | 'short'
9
9
 
10
- export async function executePrint(cwd: string, terminal: TerminalIO, snapshotDir: string, format: PrintFormat): Promise<void> {
11
- const foundConfig = await findConfigPath(cwd)
12
- const storedSnapshots = await loadStoredSnapshots(cwd, snapshotDir)
13
- writeRunContextHeader(terminal, cwd, `print:${format}`, foundConfig?.path, storedSnapshots)
14
- if (terminal.showProgress) {
15
- terminal.subtle('🔎 Checking current ESLint configuration...\n')
10
+ export async function executePrint(cwd: string, terminal: TerminalIO, snapshotDir: string, format: PrintFormat): Promise<number> {
11
+ const prepared = await prepareSnapshotExecution({
12
+ cwd,
13
+ snapshotDir,
14
+ terminal,
15
+ commandLabel: `print:${format}`,
16
+ progressMessage: '🔎 Checking current ESLint configuration...\n'
17
+ })
18
+ if (!prepared.ok) {
19
+ return prepared.exitCode
16
20
  }
17
- const allowWorkspaceExtractionFailure = !foundConfig || isDefaultEquivalentConfig(foundConfig.config)
18
- const currentSnapshots = await computeCurrentSnapshots(cwd, { allowWorkspaceExtractionFailure })
21
+
22
+ const { currentSnapshots } = prepared
19
23
 
20
24
  if (format === 'short') {
21
25
  terminal.write(formatShortPrint([...currentSnapshots.values()]))
22
- return
26
+ return 0
23
27
  }
24
28
 
25
29
  const output = [...currentSnapshots.values()].map((snapshot) => ({
@@ -27,15 +31,22 @@ export async function executePrint(cwd: string, terminal: TerminalIO, snapshotDi
27
31
  rules: snapshot.rules
28
32
  }))
29
33
  terminal.write(`${JSON.stringify(output, null, 2)}\n`)
34
+ return 0
30
35
  }
31
36
 
32
- export async function executeConfig(cwd: string, terminal: TerminalIO, snapshotDir: string, format: PrintFormat): Promise<void> {
33
- const foundConfig = await findConfigPath(cwd)
34
- const storedSnapshots = await loadStoredSnapshots(cwd, snapshotDir)
35
- writeRunContextHeader(terminal, cwd, `config:${format}`, foundConfig?.path, storedSnapshots)
36
- if (terminal.showProgress) {
37
- terminal.subtle('⚙️ Resolving effective runtime configuration...\n')
37
+ export async function executeConfig(cwd: string, terminal: TerminalIO, snapshotDir: string, format: PrintFormat): Promise<number> {
38
+ const prepared = await prepareSnapshotExecution({
39
+ cwd,
40
+ snapshotDir,
41
+ terminal,
42
+ commandLabel: `config:${format}`,
43
+ progressMessage: '⚙️ Resolving effective runtime configuration...\n'
44
+ })
45
+ if (!prepared.ok) {
46
+ return prepared.exitCode
38
47
  }
48
+
49
+ const { foundConfig } = prepared
39
50
  const config = await loadConfig(cwd)
40
51
  const resolved: WorkspaceAssignments = await resolveWorkspaceAssignments(cwd, config)
41
52
  const payload = {
@@ -52,12 +63,9 @@ export async function executeConfig(cwd: string, terminal: TerminalIO, snapshotD
52
63
 
53
64
  if (format === 'short') {
54
65
  terminal.write(formatShortConfig(payload))
55
- return
66
+ return 0
56
67
  }
57
68
 
58
69
  terminal.write(`${JSON.stringify(payload, null, 2)}\n`)
59
- }
60
-
61
- function isDefaultEquivalentConfig(config: SnapshotConfig): boolean {
62
- return JSON.stringify(config) === JSON.stringify(DEFAULT_CONFIG)
70
+ return 0
63
71
  }
@@ -3,6 +3,15 @@ import path from 'node:path'
3
3
  import { type SkippedWorkspace } from '../runtime.js'
4
4
  import { type TerminalIO } from '../terminal.js'
5
5
 
6
+ export function writeDiscoveredWorkspacesSummary(terminal: TerminalIO, workspacesRel: string[]): void {
7
+ if (workspacesRel.length === 0) {
8
+ terminal.subtle('Auto-discovered workspaces: none\n')
9
+ return
10
+ }
11
+
12
+ terminal.subtle(`Auto-discovered workspaces (${workspacesRel.length}): ${workspacesRel.join(', ')}\n`)
13
+ }
14
+
6
15
  export function writeSkippedWorkspaceSummary(
7
16
  terminal: TerminalIO,
8
17
  cwd: string,
@@ -0,0 +1,97 @@
1
+ import { DEFAULT_CONFIG, findConfigPath, type SnapshotConfig } from '@eslint-config-snapshot/api'
2
+
3
+ import { writeRunContextHeader } from '../run-context.js'
4
+ import { type BuiltSnapshot, computeCurrentSnapshots, loadStoredSnapshots, type SkippedWorkspace, type StoredSnapshot } from '../runtime.js'
5
+ import { type TerminalIO } from '../terminal.js'
6
+
7
+ type SnapshotPreparationSuccess = {
8
+ ok: true
9
+ foundConfig: Awaited<ReturnType<typeof findConfigPath>>
10
+ storedSnapshots: Map<string, StoredSnapshot>
11
+ currentSnapshots: Map<string, BuiltSnapshot>
12
+ discoveredWorkspaces: string[]
13
+ skippedWorkspaces: SkippedWorkspace[]
14
+ }
15
+
16
+ type SnapshotPreparationFailure = {
17
+ ok: false
18
+ exitCode: number
19
+ }
20
+
21
+ export type SnapshotPreparationResult = SnapshotPreparationSuccess | SnapshotPreparationFailure
22
+
23
+ export async function prepareSnapshotExecution(options: {
24
+ cwd: string
25
+ snapshotDir: string
26
+ terminal: TerminalIO
27
+ commandLabel: string
28
+ progressMessage: string
29
+ showContext?: boolean
30
+ }): Promise<SnapshotPreparationResult> {
31
+ const { cwd, snapshotDir, terminal, commandLabel, progressMessage, showContext = true } = options
32
+
33
+ const foundConfig = await findConfigPath(cwd)
34
+ const storedSnapshots = await loadStoredSnapshots(cwd, snapshotDir)
35
+ if (showContext) {
36
+ writeRunContextHeader(terminal, cwd, commandLabel, foundConfig?.path, storedSnapshots)
37
+ }
38
+ if (showContext && terminal.showProgress && progressMessage.length > 0) {
39
+ terminal.subtle(progressMessage)
40
+ }
41
+
42
+ if (showContext && !foundConfig) {
43
+ terminal.subtle(
44
+ 'Tip: no explicit config found. Using safe built-in defaults. Run `eslint-config-snapshot init` to customize when needed.\n'
45
+ )
46
+ }
47
+
48
+ const skippedWorkspaces: SkippedWorkspace[] = []
49
+ let discoveredWorkspaces: string[] = []
50
+ const allowWorkspaceExtractionFailure = !foundConfig || isDefaultEquivalentConfig(foundConfig.config)
51
+
52
+ let currentSnapshots: Map<string, BuiltSnapshot>
53
+ try {
54
+ currentSnapshots = await computeCurrentSnapshots(cwd, {
55
+ allowWorkspaceExtractionFailure,
56
+ onWorkspacesDiscovered: (workspacesRel) => {
57
+ discoveredWorkspaces = workspacesRel
58
+ },
59
+ onWorkspaceSkipped: (skipped) => {
60
+ skippedWorkspaces.push(skipped)
61
+ }
62
+ })
63
+ } catch (error: unknown) {
64
+ if (allowWorkspaceExtractionFailure && isWorkspaceDiscoveryDefaultsError(error)) {
65
+ if (showContext) {
66
+ terminal.write(
67
+ 'Automatic workspace discovery could not complete with defaults.\nRun `eslint-config-snapshot init` to configure workspaces, then run `eslint-config-snapshot --update`.\n'
68
+ )
69
+ }
70
+ return { ok: false, exitCode: 1 }
71
+ }
72
+
73
+ throw error
74
+ }
75
+
76
+ return {
77
+ ok: true,
78
+ foundConfig,
79
+ storedSnapshots,
80
+ currentSnapshots,
81
+ discoveredWorkspaces,
82
+ skippedWorkspaces
83
+ }
84
+ }
85
+
86
+ export function isWorkspaceDiscoveryDefaultsError(error: unknown): boolean {
87
+ const message = error instanceof Error ? error.message : String(error)
88
+ return (
89
+ message.includes('Unable to discover workspaces') ||
90
+ message.includes('Unmatched workspaces') ||
91
+ message.includes('zero-config mode')
92
+ )
93
+ }
94
+
95
+ function isDefaultEquivalentConfig(config: SnapshotConfig): boolean {
96
+ return JSON.stringify(config) === JSON.stringify(DEFAULT_CONFIG)
97
+ }
@@ -1,49 +1,23 @@
1
- import { DEFAULT_CONFIG, findConfigPath, type SnapshotConfig } from '@eslint-config-snapshot/api'
2
-
3
1
  import { countUniqueWorkspaces, formatBaselineSummaryLines, summarizeSnapshots } from '../formatters.js'
4
- import { writeEslintVersionSummary, writeRunContextHeader } from '../run-context.js'
5
- import { computeCurrentSnapshots, loadStoredSnapshots, resolveGroupEslintVersions, type SkippedWorkspace, writeSnapshots } from '../runtime.js'
2
+ import { writeEslintVersionSummary } from '../run-context.js'
3
+ import { resolveGroupEslintVersions, writeSnapshots } from '../runtime.js'
6
4
  import { type TerminalIO } from '../terminal.js'
7
- import { writeSkippedWorkspaceSummary } from './skipped-workspaces.js'
5
+ import { writeDiscoveredWorkspacesSummary, writeSkippedWorkspaceSummary } from './skipped-workspaces.js'
6
+ import { prepareSnapshotExecution } from './snapshot-executor.js'
8
7
 
9
8
  export async function executeUpdate(cwd: string, terminal: TerminalIO, snapshotDir: string, printSummary: boolean): Promise<number> {
10
- const foundConfig = await findConfigPath(cwd)
11
- const storedSnapshots = await loadStoredSnapshots(cwd, snapshotDir)
12
- writeRunContextHeader(terminal, cwd, 'update', foundConfig?.path, storedSnapshots)
13
- if (terminal.showProgress) {
14
- terminal.subtle('🔎 Checking current ESLint configuration...\n')
9
+ const prepared = await prepareSnapshotExecution({
10
+ cwd,
11
+ snapshotDir,
12
+ terminal,
13
+ commandLabel: 'update',
14
+ progressMessage: '🔎 Checking current ESLint configuration...\n'
15
+ })
16
+ if (prepared.ok === false) {
17
+ return prepared.exitCode
15
18
  }
16
19
 
17
- if (!foundConfig) {
18
- terminal.subtle(
19
- 'Tip: no explicit config found. Using safe built-in defaults. Run `eslint-config-snapshot init` to customize when needed.\n'
20
- )
21
- }
22
-
23
- let currentSnapshots
24
- const skippedWorkspaces: SkippedWorkspace[] = []
25
- let discoveredWorkspaces: string[] = []
26
- const allowWorkspaceExtractionFailure = !foundConfig || isDefaultEquivalentConfig(foundConfig.config)
27
- try {
28
- currentSnapshots = await computeCurrentSnapshots(cwd, {
29
- allowWorkspaceExtractionFailure,
30
- onWorkspacesDiscovered: (workspacesRel) => {
31
- discoveredWorkspaces = workspacesRel
32
- },
33
- onWorkspaceSkipped: (skipped) => {
34
- skippedWorkspaces.push(skipped)
35
- }
36
- })
37
- } catch (error: unknown) {
38
- if (!foundConfig && isWorkspaceDiscoveryDefaultsError(error)) {
39
- terminal.write(
40
- 'Automatic workspace discovery could not complete with defaults.\nRun `eslint-config-snapshot init` to configure workspaces, then run `eslint-config-snapshot --update`.\n'
41
- )
42
- return 1
43
- }
44
-
45
- throw error
46
- }
20
+ const { foundConfig, storedSnapshots, currentSnapshots, discoveredWorkspaces, skippedWorkspaces } = prepared
47
21
  if (!foundConfig) {
48
22
  writeDiscoveredWorkspacesSummary(terminal, discoveredWorkspaces)
49
23
  }
@@ -63,25 +37,3 @@ export async function executeUpdate(cwd: string, terminal: TerminalIO, snapshotD
63
37
 
64
38
  return 0
65
39
  }
66
-
67
- function isWorkspaceDiscoveryDefaultsError(error: unknown): boolean {
68
- const message = error instanceof Error ? error.message : String(error)
69
- return (
70
- message.includes('Unable to discover workspaces') ||
71
- message.includes('Unmatched workspaces') ||
72
- message.includes('zero-config mode')
73
- )
74
- }
75
-
76
- function isDefaultEquivalentConfig(config: SnapshotConfig): boolean {
77
- return JSON.stringify(config) === JSON.stringify(DEFAULT_CONFIG)
78
- }
79
-
80
- function writeDiscoveredWorkspacesSummary(terminal: TerminalIO, workspacesRel: string[]): void {
81
- if (workspacesRel.length === 0) {
82
- terminal.subtle('Auto-discovered workspaces: none\n')
83
- return
84
- }
85
-
86
- terminal.subtle(`Auto-discovered workspaces (${workspacesRel.length}): ${workspacesRel.join(', ')}\n`)
87
- }
package/src/index.ts CHANGED
@@ -141,8 +141,7 @@ function createProgram(cwd: string, terminal: TerminalIO, onActionExit: (code: n
141
141
  .option('--short', 'Alias for --format short')
142
142
  .action(async (opts: { format: PrintFormat; short?: boolean }) => {
143
143
  const format: PrintFormat = opts.short ? 'short' : opts.format
144
- await executePrint(cwd, terminal, SNAPSHOT_DIR, format)
145
- onActionExit(0)
144
+ onActionExit(await executePrint(cwd, terminal, SNAPSHOT_DIR, format))
146
145
  })
147
146
 
148
147
  program
@@ -152,8 +151,7 @@ function createProgram(cwd: string, terminal: TerminalIO, onActionExit: (code: n
152
151
  .option('--short', 'Alias for --format short')
153
152
  .action(async (opts: { format: PrintFormat; short?: boolean }) => {
154
153
  const format: PrintFormat = opts.short ? 'short' : opts.format
155
- await executeConfig(cwd, terminal, SNAPSHOT_DIR, format)
156
- onActionExit(0)
154
+ onActionExit(await executeConfig(cwd, terminal, SNAPSHOT_DIR, format))
157
155
  })
158
156
 
159
157
  program