@eslint-config-snapshot/cli 1.1.0 → 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 +19 -0
- package/dist/index.cjs +108 -101
- package/dist/index.js +106 -99
- package/package.json +2 -2
- package/src/commands/check.ts +20 -64
- package/src/commands/print.ts +31 -18
- package/src/commands/skipped-workspaces.ts +9 -0
- package/src/commands/snapshot-executor.ts +97 -0
- package/src/commands/update.ts +14 -57
- package/src/index.ts +2 -4
- package/test/cli.integration.test.ts +30 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
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
|
+
|
|
14
|
+
## 1.1.1
|
|
15
|
+
|
|
16
|
+
### Patch Changes
|
|
17
|
+
|
|
18
|
+
- Patch release: improve OSS compatibility workflow checks and align CLI zero-config print tolerance.
|
|
19
|
+
- Updated dependencies
|
|
20
|
+
- @eslint-config-snapshot/api@1.1.1
|
|
21
|
+
|
|
3
22
|
## 1.1.0
|
|
4
23
|
|
|
5
24
|
### Minor 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,28 +646,30 @@ ${objectLiteral}`;
|
|
|
641
646
|
${objectLiteral}`;
|
|
642
647
|
}
|
|
643
648
|
|
|
644
|
-
// src/commands/
|
|
645
|
-
var
|
|
646
|
-
async function
|
|
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 (
|
|
650
|
-
writeRunContextHeader(terminal, cwd,
|
|
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 (
|
|
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 = [];
|
|
668
|
+
const allowWorkspaceExtractionFailure = !foundConfig || isDefaultEquivalentConfig(foundConfig.config);
|
|
669
|
+
let currentSnapshots;
|
|
663
670
|
try {
|
|
664
671
|
currentSnapshots = await computeCurrentSnapshots(cwd, {
|
|
665
|
-
allowWorkspaceExtractionFailure
|
|
672
|
+
allowWorkspaceExtractionFailure,
|
|
666
673
|
onWorkspacesDiscovered: (workspacesRel) => {
|
|
667
674
|
discoveredWorkspaces = workspacesRel;
|
|
668
675
|
},
|
|
@@ -671,18 +678,56 @@ async function executeCheck(cwd, format, terminal, snapshotDir, defaultInvocatio
|
|
|
671
678
|
}
|
|
672
679
|
});
|
|
673
680
|
} catch (error) {
|
|
674
|
-
if (
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
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 };
|
|
679
688
|
}
|
|
680
689
|
throw error;
|
|
681
690
|
}
|
|
682
|
-
|
|
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) {
|
|
683
726
|
writeDiscoveredWorkspacesSummary(terminal, discoveredWorkspaces);
|
|
684
727
|
}
|
|
685
|
-
|
|
728
|
+
if (isStatusFormat === false) {
|
|
729
|
+
writeSkippedWorkspaceSummary(terminal, cwd, foundConfig?.path, skippedWorkspaces);
|
|
730
|
+
}
|
|
686
731
|
if (storedSnapshots.size === 0) {
|
|
687
732
|
const summary = summarizeSnapshots(currentSnapshots);
|
|
688
733
|
terminal.write(
|
|
@@ -777,32 +822,24 @@ function printWhatChanged(terminal, changes, currentSnapshots, eslintVersionsByG
|
|
|
777
822
|
terminal.subtle(UPDATE_HINT);
|
|
778
823
|
return 1;
|
|
779
824
|
}
|
|
780
|
-
function isWorkspaceDiscoveryDefaultsError(error) {
|
|
781
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
782
|
-
return message.includes("Unable to discover workspaces") || message.includes("Unmatched workspaces") || message.includes("zero-config mode");
|
|
783
|
-
}
|
|
784
|
-
function writeDiscoveredWorkspacesSummary(terminal, workspacesRel) {
|
|
785
|
-
if (workspacesRel.length === 0) {
|
|
786
|
-
terminal.subtle("Auto-discovered workspaces: none\n");
|
|
787
|
-
return;
|
|
788
|
-
}
|
|
789
|
-
terminal.subtle(`Auto-discovered workspaces (${workspacesRel.length}): ${workspacesRel.join(", ")}
|
|
790
|
-
`);
|
|
791
|
-
}
|
|
792
825
|
|
|
793
826
|
// src/commands/print.ts
|
|
794
827
|
var import_api4 = require("@eslint-config-snapshot/api");
|
|
795
828
|
async function executePrint(cwd, terminal, snapshotDir, format) {
|
|
796
|
-
const
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
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;
|
|
801
838
|
}
|
|
802
|
-
const currentSnapshots =
|
|
839
|
+
const { currentSnapshots } = prepared;
|
|
803
840
|
if (format === "short") {
|
|
804
841
|
terminal.write(formatShortPrint([...currentSnapshots.values()]));
|
|
805
|
-
return;
|
|
842
|
+
return 0;
|
|
806
843
|
}
|
|
807
844
|
const output = [...currentSnapshots.values()].map((snapshot) => ({
|
|
808
845
|
groupId: snapshot.groupId,
|
|
@@ -810,14 +847,20 @@ async function executePrint(cwd, terminal, snapshotDir, format) {
|
|
|
810
847
|
}));
|
|
811
848
|
terminal.write(`${JSON.stringify(output, null, 2)}
|
|
812
849
|
`);
|
|
850
|
+
return 0;
|
|
813
851
|
}
|
|
814
852
|
async function executeConfig(cwd, terminal, snapshotDir, format) {
|
|
815
|
-
const
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
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;
|
|
820
862
|
}
|
|
863
|
+
const { foundConfig } = prepared;
|
|
821
864
|
const config = await (0, import_api4.loadConfig)(cwd);
|
|
822
865
|
const resolved = await resolveWorkspaceAssignments(cwd, config);
|
|
823
866
|
const payload = {
|
|
@@ -833,50 +876,28 @@ async function executeConfig(cwd, terminal, snapshotDir, format) {
|
|
|
833
876
|
};
|
|
834
877
|
if (format === "short") {
|
|
835
878
|
terminal.write(formatShortConfig(payload));
|
|
836
|
-
return;
|
|
879
|
+
return 0;
|
|
837
880
|
}
|
|
838
881
|
terminal.write(`${JSON.stringify(payload, null, 2)}
|
|
839
882
|
`);
|
|
883
|
+
return 0;
|
|
840
884
|
}
|
|
841
885
|
|
|
842
886
|
// src/commands/update.ts
|
|
843
|
-
var import_api5 = require("@eslint-config-snapshot/api");
|
|
844
887
|
async function executeUpdate(cwd, terminal, snapshotDir, printSummary) {
|
|
845
|
-
const
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
);
|
|
855
|
-
}
|
|
856
|
-
let currentSnapshots;
|
|
857
|
-
const skippedWorkspaces = [];
|
|
858
|
-
let discoveredWorkspaces = [];
|
|
859
|
-
try {
|
|
860
|
-
currentSnapshots = await computeCurrentSnapshots(cwd, {
|
|
861
|
-
allowWorkspaceExtractionFailure: !foundConfig,
|
|
862
|
-
onWorkspacesDiscovered: (workspacesRel) => {
|
|
863
|
-
discoveredWorkspaces = workspacesRel;
|
|
864
|
-
},
|
|
865
|
-
onWorkspaceSkipped: (skipped) => {
|
|
866
|
-
skippedWorkspaces.push(skipped);
|
|
867
|
-
}
|
|
868
|
-
});
|
|
869
|
-
} catch (error) {
|
|
870
|
-
if (!foundConfig && isWorkspaceDiscoveryDefaultsError2(error)) {
|
|
871
|
-
terminal.write(
|
|
872
|
-
"Automatic workspace discovery could not complete with defaults.\nRun `eslint-config-snapshot init` to configure workspaces, then run `eslint-config-snapshot --update`.\n"
|
|
873
|
-
);
|
|
874
|
-
return 1;
|
|
875
|
-
}
|
|
876
|
-
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;
|
|
877
897
|
}
|
|
898
|
+
const { foundConfig, storedSnapshots, currentSnapshots, discoveredWorkspaces, skippedWorkspaces } = prepared;
|
|
878
899
|
if (!foundConfig) {
|
|
879
|
-
|
|
900
|
+
writeDiscoveredWorkspacesSummary(terminal, discoveredWorkspaces);
|
|
880
901
|
}
|
|
881
902
|
writeSkippedWorkspaceSummary(terminal, cwd, foundConfig?.path, skippedWorkspaces);
|
|
882
903
|
await writeSnapshots(cwd, snapshotDir, currentSnapshots);
|
|
@@ -893,28 +914,16 @@ async function executeUpdate(cwd, terminal, snapshotDir, printSummary) {
|
|
|
893
914
|
}
|
|
894
915
|
return 0;
|
|
895
916
|
}
|
|
896
|
-
function isWorkspaceDiscoveryDefaultsError2(error) {
|
|
897
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
898
|
-
return message.includes("Unable to discover workspaces") || message.includes("Unmatched workspaces") || message.includes("zero-config mode");
|
|
899
|
-
}
|
|
900
|
-
function writeDiscoveredWorkspacesSummary2(terminal, workspacesRel) {
|
|
901
|
-
if (workspacesRel.length === 0) {
|
|
902
|
-
terminal.subtle("Auto-discovered workspaces: none\n");
|
|
903
|
-
return;
|
|
904
|
-
}
|
|
905
|
-
terminal.subtle(`Auto-discovered workspaces (${workspacesRel.length}): ${workspacesRel.join(", ")}
|
|
906
|
-
`);
|
|
907
|
-
}
|
|
908
917
|
|
|
909
918
|
// src/init.ts
|
|
910
|
-
var
|
|
919
|
+
var import_api5 = require("@eslint-config-snapshot/api");
|
|
911
920
|
var import_fast_glob2 = __toESM(require("fast-glob"), 1);
|
|
912
921
|
var import_promises2 = require("fs/promises");
|
|
913
922
|
var import_node_path4 = __toESM(require("path"), 1);
|
|
914
923
|
async function runInit(cwd, opts, runtime) {
|
|
915
924
|
const force = opts.force ?? false;
|
|
916
925
|
const showEffective = opts.showEffective ?? false;
|
|
917
|
-
const existing = await (0,
|
|
926
|
+
const existing = await (0, import_api5.findConfigPath)(cwd);
|
|
918
927
|
if (existing && !force) {
|
|
919
928
|
runtime.writeStderr(
|
|
920
929
|
`Existing config detected at ${existing.path}. Creating another config can cause conflicts. Remove the existing config or rerun with --force.
|
|
@@ -1051,7 +1060,7 @@ function buildRecommendedConfigFromAssignments(workspaces, assignments) {
|
|
|
1051
1060
|
};
|
|
1052
1061
|
}
|
|
1053
1062
|
async function discoverInitWorkspaces(cwd) {
|
|
1054
|
-
const discovered = await (0,
|
|
1063
|
+
const discovered = await (0, import_api5.discoverWorkspaces)({ cwd, workspaceInput: { mode: "discover" } });
|
|
1055
1064
|
if (!(discovered.workspacesRel.length === 1 && discovered.workspacesRel[0] === ".")) {
|
|
1056
1065
|
return discovered.workspacesRel;
|
|
1057
1066
|
}
|
|
@@ -1073,7 +1082,7 @@ async function discoverInitWorkspaces(cwd) {
|
|
|
1073
1082
|
onlyFiles: true,
|
|
1074
1083
|
dot: true
|
|
1075
1084
|
});
|
|
1076
|
-
const workspaceDirs = [...new Set(workspacePackageFiles.map((entry) => (0,
|
|
1085
|
+
const workspaceDirs = [...new Set(workspacePackageFiles.map((entry) => (0, import_api5.normalizePath)(import_node_path4.default.dirname(entry))))].sort(
|
|
1077
1086
|
(a, b) => a.localeCompare(b)
|
|
1078
1087
|
);
|
|
1079
1088
|
if (workspaceDirs.length > 0) {
|
|
@@ -1124,7 +1133,7 @@ async function askRecommendedGroupAssignments(workspaces, runtime) {
|
|
|
1124
1133
|
}
|
|
1125
1134
|
function toConfigScaffold(configObject) {
|
|
1126
1135
|
if (Object.keys(configObject).length === 0) {
|
|
1127
|
-
return (0,
|
|
1136
|
+
return (0, import_api5.getConfigScaffold)("minimal");
|
|
1128
1137
|
}
|
|
1129
1138
|
return `export default ${JSON.stringify(configObject, null, 2)}
|
|
1130
1139
|
`;
|
|
@@ -1404,13 +1413,11 @@ function createProgram(cwd, terminal, onActionExit) {
|
|
|
1404
1413
|
});
|
|
1405
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) => {
|
|
1406
1415
|
const format = opts.short ? "short" : opts.format;
|
|
1407
|
-
await executePrint(cwd, terminal, SNAPSHOT_DIR, format);
|
|
1408
|
-
onActionExit(0);
|
|
1416
|
+
onActionExit(await executePrint(cwd, terminal, SNAPSHOT_DIR, format));
|
|
1409
1417
|
});
|
|
1410
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) => {
|
|
1411
1419
|
const format = opts.short ? "short" : opts.format;
|
|
1412
|
-
await executeConfig(cwd, terminal, SNAPSHOT_DIR, format);
|
|
1413
|
-
onActionExit(0);
|
|
1420
|
+
onActionExit(await executeConfig(cwd, terminal, SNAPSHOT_DIR, format));
|
|
1414
1421
|
});
|
|
1415
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(
|
|
1416
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 { 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,28 +624,30 @@ ${objectLiteral}`;
|
|
|
619
624
|
${objectLiteral}`;
|
|
620
625
|
}
|
|
621
626
|
|
|
622
|
-
// src/commands/
|
|
623
|
-
|
|
624
|
-
async function
|
|
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 (
|
|
628
|
-
writeRunContextHeader(terminal, cwd,
|
|
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 (
|
|
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 = [];
|
|
646
|
+
const allowWorkspaceExtractionFailure = !foundConfig || isDefaultEquivalentConfig(foundConfig.config);
|
|
647
|
+
let currentSnapshots;
|
|
641
648
|
try {
|
|
642
649
|
currentSnapshots = await computeCurrentSnapshots(cwd, {
|
|
643
|
-
allowWorkspaceExtractionFailure
|
|
650
|
+
allowWorkspaceExtractionFailure,
|
|
644
651
|
onWorkspacesDiscovered: (workspacesRel) => {
|
|
645
652
|
discoveredWorkspaces = workspacesRel;
|
|
646
653
|
},
|
|
@@ -649,18 +656,56 @@ async function executeCheck(cwd, format, terminal, snapshotDir, defaultInvocatio
|
|
|
649
656
|
}
|
|
650
657
|
});
|
|
651
658
|
} catch (error) {
|
|
652
|
-
if (
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
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 };
|
|
657
666
|
}
|
|
658
667
|
throw error;
|
|
659
668
|
}
|
|
660
|
-
|
|
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) {
|
|
661
704
|
writeDiscoveredWorkspacesSummary(terminal, discoveredWorkspaces);
|
|
662
705
|
}
|
|
663
|
-
|
|
706
|
+
if (isStatusFormat === false) {
|
|
707
|
+
writeSkippedWorkspaceSummary(terminal, cwd, foundConfig?.path, skippedWorkspaces);
|
|
708
|
+
}
|
|
664
709
|
if (storedSnapshots.size === 0) {
|
|
665
710
|
const summary = summarizeSnapshots(currentSnapshots);
|
|
666
711
|
terminal.write(
|
|
@@ -755,32 +800,24 @@ function printWhatChanged(terminal, changes, currentSnapshots, eslintVersionsByG
|
|
|
755
800
|
terminal.subtle(UPDATE_HINT);
|
|
756
801
|
return 1;
|
|
757
802
|
}
|
|
758
|
-
function isWorkspaceDiscoveryDefaultsError(error) {
|
|
759
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
760
|
-
return message.includes("Unable to discover workspaces") || message.includes("Unmatched workspaces") || message.includes("zero-config mode");
|
|
761
|
-
}
|
|
762
|
-
function writeDiscoveredWorkspacesSummary(terminal, workspacesRel) {
|
|
763
|
-
if (workspacesRel.length === 0) {
|
|
764
|
-
terminal.subtle("Auto-discovered workspaces: none\n");
|
|
765
|
-
return;
|
|
766
|
-
}
|
|
767
|
-
terminal.subtle(`Auto-discovered workspaces (${workspacesRel.length}): ${workspacesRel.join(", ")}
|
|
768
|
-
`);
|
|
769
|
-
}
|
|
770
803
|
|
|
771
804
|
// src/commands/print.ts
|
|
772
|
-
import {
|
|
805
|
+
import { loadConfig as loadConfig2 } from "@eslint-config-snapshot/api";
|
|
773
806
|
async function executePrint(cwd, terminal, snapshotDir, format) {
|
|
774
|
-
const
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
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;
|
|
779
816
|
}
|
|
780
|
-
const currentSnapshots =
|
|
817
|
+
const { currentSnapshots } = prepared;
|
|
781
818
|
if (format === "short") {
|
|
782
819
|
terminal.write(formatShortPrint([...currentSnapshots.values()]));
|
|
783
|
-
return;
|
|
820
|
+
return 0;
|
|
784
821
|
}
|
|
785
822
|
const output = [...currentSnapshots.values()].map((snapshot) => ({
|
|
786
823
|
groupId: snapshot.groupId,
|
|
@@ -788,14 +825,20 @@ async function executePrint(cwd, terminal, snapshotDir, format) {
|
|
|
788
825
|
}));
|
|
789
826
|
terminal.write(`${JSON.stringify(output, null, 2)}
|
|
790
827
|
`);
|
|
828
|
+
return 0;
|
|
791
829
|
}
|
|
792
830
|
async function executeConfig(cwd, terminal, snapshotDir, format) {
|
|
793
|
-
const
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
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;
|
|
798
840
|
}
|
|
841
|
+
const { foundConfig } = prepared;
|
|
799
842
|
const config = await loadConfig2(cwd);
|
|
800
843
|
const resolved = await resolveWorkspaceAssignments(cwd, config);
|
|
801
844
|
const payload = {
|
|
@@ -811,50 +854,28 @@ async function executeConfig(cwd, terminal, snapshotDir, format) {
|
|
|
811
854
|
};
|
|
812
855
|
if (format === "short") {
|
|
813
856
|
terminal.write(formatShortConfig(payload));
|
|
814
|
-
return;
|
|
857
|
+
return 0;
|
|
815
858
|
}
|
|
816
859
|
terminal.write(`${JSON.stringify(payload, null, 2)}
|
|
817
860
|
`);
|
|
861
|
+
return 0;
|
|
818
862
|
}
|
|
819
863
|
|
|
820
864
|
// src/commands/update.ts
|
|
821
|
-
import { findConfigPath as findConfigPath3 } from "@eslint-config-snapshot/api";
|
|
822
865
|
async function executeUpdate(cwd, terminal, snapshotDir, printSummary) {
|
|
823
|
-
const
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
);
|
|
833
|
-
}
|
|
834
|
-
let currentSnapshots;
|
|
835
|
-
const skippedWorkspaces = [];
|
|
836
|
-
let discoveredWorkspaces = [];
|
|
837
|
-
try {
|
|
838
|
-
currentSnapshots = await computeCurrentSnapshots(cwd, {
|
|
839
|
-
allowWorkspaceExtractionFailure: !foundConfig,
|
|
840
|
-
onWorkspacesDiscovered: (workspacesRel) => {
|
|
841
|
-
discoveredWorkspaces = workspacesRel;
|
|
842
|
-
},
|
|
843
|
-
onWorkspaceSkipped: (skipped) => {
|
|
844
|
-
skippedWorkspaces.push(skipped);
|
|
845
|
-
}
|
|
846
|
-
});
|
|
847
|
-
} catch (error) {
|
|
848
|
-
if (!foundConfig && isWorkspaceDiscoveryDefaultsError2(error)) {
|
|
849
|
-
terminal.write(
|
|
850
|
-
"Automatic workspace discovery could not complete with defaults.\nRun `eslint-config-snapshot init` to configure workspaces, then run `eslint-config-snapshot --update`.\n"
|
|
851
|
-
);
|
|
852
|
-
return 1;
|
|
853
|
-
}
|
|
854
|
-
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;
|
|
855
875
|
}
|
|
876
|
+
const { foundConfig, storedSnapshots, currentSnapshots, discoveredWorkspaces, skippedWorkspaces } = prepared;
|
|
856
877
|
if (!foundConfig) {
|
|
857
|
-
|
|
878
|
+
writeDiscoveredWorkspacesSummary(terminal, discoveredWorkspaces);
|
|
858
879
|
}
|
|
859
880
|
writeSkippedWorkspaceSummary(terminal, cwd, foundConfig?.path, skippedWorkspaces);
|
|
860
881
|
await writeSnapshots(cwd, snapshotDir, currentSnapshots);
|
|
@@ -871,28 +892,16 @@ async function executeUpdate(cwd, terminal, snapshotDir, printSummary) {
|
|
|
871
892
|
}
|
|
872
893
|
return 0;
|
|
873
894
|
}
|
|
874
|
-
function isWorkspaceDiscoveryDefaultsError2(error) {
|
|
875
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
876
|
-
return message.includes("Unable to discover workspaces") || message.includes("Unmatched workspaces") || message.includes("zero-config mode");
|
|
877
|
-
}
|
|
878
|
-
function writeDiscoveredWorkspacesSummary2(terminal, workspacesRel) {
|
|
879
|
-
if (workspacesRel.length === 0) {
|
|
880
|
-
terminal.subtle("Auto-discovered workspaces: none\n");
|
|
881
|
-
return;
|
|
882
|
-
}
|
|
883
|
-
terminal.subtle(`Auto-discovered workspaces (${workspacesRel.length}): ${workspacesRel.join(", ")}
|
|
884
|
-
`);
|
|
885
|
-
}
|
|
886
895
|
|
|
887
896
|
// src/init.ts
|
|
888
|
-
import { discoverWorkspaces as discoverWorkspaces2, findConfigPath as
|
|
897
|
+
import { discoverWorkspaces as discoverWorkspaces2, findConfigPath as findConfigPath2, getConfigScaffold, normalizePath as normalizePath2 } from "@eslint-config-snapshot/api";
|
|
889
898
|
import fg2 from "fast-glob";
|
|
890
899
|
import { access, readFile, writeFile } from "fs/promises";
|
|
891
900
|
import path4 from "path";
|
|
892
901
|
async function runInit(cwd, opts, runtime) {
|
|
893
902
|
const force = opts.force ?? false;
|
|
894
903
|
const showEffective = opts.showEffective ?? false;
|
|
895
|
-
const existing = await
|
|
904
|
+
const existing = await findConfigPath2(cwd);
|
|
896
905
|
if (existing && !force) {
|
|
897
906
|
runtime.writeStderr(
|
|
898
907
|
`Existing config detected at ${existing.path}. Creating another config can cause conflicts. Remove the existing config or rerun with --force.
|
|
@@ -1382,13 +1391,11 @@ function createProgram(cwd, terminal, onActionExit) {
|
|
|
1382
1391
|
});
|
|
1383
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) => {
|
|
1384
1393
|
const format = opts.short ? "short" : opts.format;
|
|
1385
|
-
await executePrint(cwd, terminal, SNAPSHOT_DIR, format);
|
|
1386
|
-
onActionExit(0);
|
|
1394
|
+
onActionExit(await executePrint(cwd, terminal, SNAPSHOT_DIR, format));
|
|
1387
1395
|
});
|
|
1388
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) => {
|
|
1389
1397
|
const format = opts.short ? "short" : opts.format;
|
|
1390
|
-
await executeConfig(cwd, terminal, SNAPSHOT_DIR, format);
|
|
1391
|
-
onActionExit(0);
|
|
1398
|
+
onActionExit(await executeConfig(cwd, terminal, SNAPSHOT_DIR, format));
|
|
1392
1399
|
});
|
|
1393
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(
|
|
1394
1401
|
"after",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eslint-config-snapshot/cli",
|
|
3
|
-
"version": "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.
|
|
34
|
+
"@eslint-config-snapshot/api": "1.2.0"
|
|
35
35
|
}
|
|
36
36
|
}
|
package/src/commands/check.ts
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { findConfigPath } 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
|
|
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,49 +30,27 @@ export async function executeCheck(
|
|
|
34
30
|
snapshotDir: string,
|
|
35
31
|
defaultInvocation = false
|
|
36
32
|
): Promise<number> {
|
|
37
|
-
const
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
if (
|
|
48
|
-
|
|
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
|
-
|
|
54
|
-
|
|
55
|
-
let discoveredWorkspaces: string[] = []
|
|
56
|
-
try {
|
|
57
|
-
currentSnapshots = await computeCurrentSnapshots(cwd, {
|
|
58
|
-
allowWorkspaceExtractionFailure: !foundConfig,
|
|
59
|
-
onWorkspacesDiscovered: (workspacesRel) => {
|
|
60
|
-
discoveredWorkspaces = workspacesRel
|
|
61
|
-
},
|
|
62
|
-
onWorkspaceSkipped: (skipped) => {
|
|
63
|
-
skippedWorkspaces.push(skipped)
|
|
64
|
-
}
|
|
65
|
-
})
|
|
66
|
-
} catch (error: unknown) {
|
|
67
|
-
if (!foundConfig && isWorkspaceDiscoveryDefaultsError(error)) {
|
|
68
|
-
terminal.write(
|
|
69
|
-
'Automatic workspace discovery could not complete with defaults.\nRun `eslint-config-snapshot init` to configure workspaces, then run `eslint-config-snapshot --update`.\n'
|
|
70
|
-
)
|
|
71
|
-
return 1
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
throw error
|
|
75
|
-
}
|
|
76
|
-
if (!foundConfig) {
|
|
47
|
+
const { foundConfig, storedSnapshots, currentSnapshots, discoveredWorkspaces, skippedWorkspaces } = prepared
|
|
48
|
+
if (foundConfig === null && isStatusFormat === false) {
|
|
77
49
|
writeDiscoveredWorkspacesSummary(terminal, discoveredWorkspaces)
|
|
78
50
|
}
|
|
79
|
-
|
|
51
|
+
if (isStatusFormat === false) {
|
|
52
|
+
writeSkippedWorkspaceSummary(terminal, cwd, foundConfig?.path, skippedWorkspaces)
|
|
53
|
+
}
|
|
80
54
|
if (storedSnapshots.size === 0) {
|
|
81
55
|
const summary = summarizeSnapshots(currentSnapshots)
|
|
82
56
|
terminal.write(
|
|
@@ -176,21 +150,3 @@ function printWhatChanged(
|
|
|
176
150
|
|
|
177
151
|
return 1
|
|
178
152
|
}
|
|
179
|
-
|
|
180
|
-
function isWorkspaceDiscoveryDefaultsError(error: unknown): boolean {
|
|
181
|
-
const message = error instanceof Error ? error.message : String(error)
|
|
182
|
-
return (
|
|
183
|
-
message.includes('Unable to discover workspaces') ||
|
|
184
|
-
message.includes('Unmatched workspaces') ||
|
|
185
|
-
message.includes('zero-config mode')
|
|
186
|
-
)
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
function writeDiscoveredWorkspacesSummary(terminal: TerminalIO, workspacesRel: string[]): void {
|
|
190
|
-
if (workspacesRel.length === 0) {
|
|
191
|
-
terminal.subtle('Auto-discovered workspaces: none\n')
|
|
192
|
-
return
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
terminal.subtle(`Auto-discovered workspaces (${workspacesRel.length}): ${workspacesRel.join(', ')}\n`)
|
|
196
|
-
}
|
package/src/commands/print.ts
CHANGED
|
@@ -1,24 +1,29 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { loadConfig } from '@eslint-config-snapshot/api'
|
|
2
2
|
|
|
3
3
|
import { formatShortConfig, formatShortPrint } from '../formatters.js'
|
|
4
|
-
import {
|
|
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<
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
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
|
-
|
|
21
|
+
|
|
22
|
+
const { currentSnapshots } = prepared
|
|
18
23
|
|
|
19
24
|
if (format === 'short') {
|
|
20
25
|
terminal.write(formatShortPrint([...currentSnapshots.values()]))
|
|
21
|
-
return
|
|
26
|
+
return 0
|
|
22
27
|
}
|
|
23
28
|
|
|
24
29
|
const output = [...currentSnapshots.values()].map((snapshot) => ({
|
|
@@ -26,15 +31,22 @@ export async function executePrint(cwd: string, terminal: TerminalIO, snapshotDi
|
|
|
26
31
|
rules: snapshot.rules
|
|
27
32
|
}))
|
|
28
33
|
terminal.write(`${JSON.stringify(output, null, 2)}\n`)
|
|
34
|
+
return 0
|
|
29
35
|
}
|
|
30
36
|
|
|
31
|
-
export async function executeConfig(cwd: string, terminal: TerminalIO, snapshotDir: string, format: PrintFormat): Promise<
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
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
|
|
37
47
|
}
|
|
48
|
+
|
|
49
|
+
const { foundConfig } = prepared
|
|
38
50
|
const config = await loadConfig(cwd)
|
|
39
51
|
const resolved: WorkspaceAssignments = await resolveWorkspaceAssignments(cwd, config)
|
|
40
52
|
const payload = {
|
|
@@ -51,8 +63,9 @@ export async function executeConfig(cwd: string, terminal: TerminalIO, snapshotD
|
|
|
51
63
|
|
|
52
64
|
if (format === 'short') {
|
|
53
65
|
terminal.write(formatShortConfig(payload))
|
|
54
|
-
return
|
|
66
|
+
return 0
|
|
55
67
|
}
|
|
56
68
|
|
|
57
69
|
terminal.write(`${JSON.stringify(payload, null, 2)}\n`)
|
|
70
|
+
return 0
|
|
58
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
|
+
}
|
package/src/commands/update.ts
CHANGED
|
@@ -1,48 +1,23 @@
|
|
|
1
|
-
import { findConfigPath } from '@eslint-config-snapshot/api'
|
|
2
|
-
|
|
3
1
|
import { countUniqueWorkspaces, formatBaselineSummaryLines, summarizeSnapshots } from '../formatters.js'
|
|
4
|
-
import { writeEslintVersionSummary
|
|
5
|
-
import {
|
|
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
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
if (
|
|
18
|
-
|
|
19
|
-
'Tip: no explicit config found. Using safe built-in defaults. Run `eslint-config-snapshot init` to customize when needed.\n'
|
|
20
|
-
)
|
|
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
|
|
21
18
|
}
|
|
22
19
|
|
|
23
|
-
|
|
24
|
-
const skippedWorkspaces: SkippedWorkspace[] = []
|
|
25
|
-
let discoveredWorkspaces: string[] = []
|
|
26
|
-
try {
|
|
27
|
-
currentSnapshots = await computeCurrentSnapshots(cwd, {
|
|
28
|
-
allowWorkspaceExtractionFailure: !foundConfig,
|
|
29
|
-
onWorkspacesDiscovered: (workspacesRel) => {
|
|
30
|
-
discoveredWorkspaces = workspacesRel
|
|
31
|
-
},
|
|
32
|
-
onWorkspaceSkipped: (skipped) => {
|
|
33
|
-
skippedWorkspaces.push(skipped)
|
|
34
|
-
}
|
|
35
|
-
})
|
|
36
|
-
} catch (error: unknown) {
|
|
37
|
-
if (!foundConfig && isWorkspaceDiscoveryDefaultsError(error)) {
|
|
38
|
-
terminal.write(
|
|
39
|
-
'Automatic workspace discovery could not complete with defaults.\nRun `eslint-config-snapshot init` to configure workspaces, then run `eslint-config-snapshot --update`.\n'
|
|
40
|
-
)
|
|
41
|
-
return 1
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
throw error
|
|
45
|
-
}
|
|
20
|
+
const { foundConfig, storedSnapshots, currentSnapshots, discoveredWorkspaces, skippedWorkspaces } = prepared
|
|
46
21
|
if (!foundConfig) {
|
|
47
22
|
writeDiscoveredWorkspacesSummary(terminal, discoveredWorkspaces)
|
|
48
23
|
}
|
|
@@ -62,21 +37,3 @@ export async function executeUpdate(cwd: string, terminal: TerminalIO, snapshotD
|
|
|
62
37
|
|
|
63
38
|
return 0
|
|
64
39
|
}
|
|
65
|
-
|
|
66
|
-
function isWorkspaceDiscoveryDefaultsError(error: unknown): boolean {
|
|
67
|
-
const message = error instanceof Error ? error.message : String(error)
|
|
68
|
-
return (
|
|
69
|
-
message.includes('Unable to discover workspaces') ||
|
|
70
|
-
message.includes('Unmatched workspaces') ||
|
|
71
|
-
message.includes('zero-config mode')
|
|
72
|
-
)
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
function writeDiscoveredWorkspacesSummary(terminal: TerminalIO, workspacesRel: string[]): void {
|
|
76
|
-
if (workspacesRel.length === 0) {
|
|
77
|
-
terminal.subtle('Auto-discovered workspaces: none\n')
|
|
78
|
-
return
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
terminal.subtle(`Auto-discovered workspaces (${workspacesRel.length}): ${workspacesRel.join(', ')}\n`)
|
|
82
|
-
}
|
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
|
|
@@ -142,6 +142,36 @@ describe.sequential('cli integration', () => {
|
|
|
142
142
|
})
|
|
143
143
|
})
|
|
144
144
|
|
|
145
|
+
it('update treats explicit empty package config as zero-config tolerant mode', async () => {
|
|
146
|
+
await rm(path.join(fixtureRoot, 'eslint-config-snapshot.config.mjs'), { force: true })
|
|
147
|
+
const packageJsonPath = path.join(fixtureRoot, 'package.json')
|
|
148
|
+
const packageJsonRaw = await readFile(packageJsonPath, 'utf8')
|
|
149
|
+
const packageJson = JSON.parse(packageJsonRaw) as Record<string, unknown>
|
|
150
|
+
packageJson['eslint-config-snapshot'] = {}
|
|
151
|
+
await writeFile(packageJsonPath, `${JSON.stringify(packageJson, null, 2)}\n`)
|
|
152
|
+
|
|
153
|
+
await writeFile(
|
|
154
|
+
path.join(fixtureRoot, 'packages/ws-b/node_modules/eslint/bin/eslint.js'),
|
|
155
|
+
"console.error('Failed to load config \"next/core-web-vitals\" to extend from.'); process.exit(1)\n"
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
const code = await runCli('update', fixtureRoot)
|
|
159
|
+
expect(code).toBe(0)
|
|
160
|
+
|
|
161
|
+
const snapshotRaw = await readFile(path.join(fixtureRoot, '.eslint-config-snapshot/default.json'), 'utf8')
|
|
162
|
+
const snapshot = JSON.parse(snapshotRaw)
|
|
163
|
+
|
|
164
|
+
expect(snapshot).toEqual({
|
|
165
|
+
formatVersion: 1,
|
|
166
|
+
groupId: 'default',
|
|
167
|
+
workspaces: ['packages/ws-a'],
|
|
168
|
+
rules: {
|
|
169
|
+
eqeqeq: ['error', 'always'],
|
|
170
|
+
'no-console': ['warn']
|
|
171
|
+
}
|
|
172
|
+
})
|
|
173
|
+
})
|
|
174
|
+
|
|
145
175
|
it('status is minimal and exits 0 when clean', async () => {
|
|
146
176
|
await runCli('snapshot', fixtureRoot)
|
|
147
177
|
|