@savvy-web/silk 1.3.6 → 1.3.8

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.
Files changed (42) hide show
  1. package/changesets-changelog.cjs +4769 -7026
  2. package/changesets-changelog.d.cts +1350 -696
  3. package/changesets-changelog.d.ts +1350 -696
  4. package/changesets-markdownlint.cjs +4769 -7026
  5. package/changesets-markdownlint.d.cts +1350 -696
  6. package/changesets-markdownlint.d.ts +1350 -696
  7. package/package.json +4 -4
  8. package/packages/silk-effects/dist/dev/pkg/changesets/api/linter.cjs +12 -10
  9. package/packages/silk-effects/dist/dev/pkg/changesets/api/linter.js +9 -7
  10. package/packages/silk-effects/dist/dev/pkg/changesets/errors.cjs +45 -0
  11. package/packages/silk-effects/dist/dev/pkg/changesets/errors.js +44 -1
  12. package/packages/silk-effects/dist/dev/pkg/changesets/index.cjs +35 -27
  13. package/packages/silk-effects/dist/dev/pkg/changesets/index.js +20 -16
  14. package/packages/silk-effects/dist/dev/pkg/changesets/markdownlint/rules/dependency-table-format.cjs +3 -3
  15. package/packages/silk-effects/dist/dev/pkg/changesets/markdownlint/rules/dependency-table-format.js +1 -1
  16. package/packages/silk-effects/dist/dev/pkg/changesets/remark/presets.cjs +1 -1
  17. package/packages/silk-effects/dist/dev/pkg/changesets/remark/presets.js +1 -1
  18. package/packages/silk-effects/dist/dev/pkg/changesets/schemas/dependency-table.cjs +12 -1
  19. package/packages/silk-effects/dist/dev/pkg/changesets/schemas/dependency-table.js +12 -2
  20. package/packages/silk-effects/dist/dev/pkg/changesets/services/config-inspector.cjs +4 -4
  21. package/packages/silk-effects/dist/dev/pkg/changesets/services/config-inspector.js +1 -1
  22. package/packages/silk-effects/dist/dev/pkg/changesets/services/deps-regen.cjs +375 -0
  23. package/packages/silk-effects/dist/dev/pkg/changesets/services/deps-regen.js +371 -0
  24. package/packages/silk-effects/dist/dev/pkg/changesets/services/release-planner.cjs +105 -81
  25. package/packages/silk-effects/dist/dev/pkg/changesets/services/release-planner.js +105 -81
  26. package/packages/silk-effects/dist/dev/pkg/changesets/utils/dep-diff.cjs +81 -47
  27. package/packages/silk-effects/dist/dev/pkg/changesets/utils/dep-diff.js +81 -47
  28. package/packages/silk-effects/dist/dev/pkg/changesets/utils/git.cjs +51 -0
  29. package/packages/silk-effects/dist/dev/pkg/changesets/utils/git.js +51 -0
  30. package/packages/silk-effects/dist/dev/pkg/changesets/utils/publishability.cjs +16 -4
  31. package/packages/silk-effects/dist/dev/pkg/changesets/utils/publishability.js +15 -3
  32. package/packages/silk-effects/dist/dev/pkg/services/ChangesetConfig.cjs +2 -1
  33. package/packages/silk-effects/dist/dev/pkg/services/ChangesetConfig.js +1 -1
  34. package/packages/silk-effects/dist/dev/pkg/services/ChangesetConfigReader.cjs +2 -1
  35. package/packages/silk-effects/dist/dev/pkg/services/ChangesetConfigReader.js +1 -1
  36. package/packages/silk-effects/dist/dev/pkg/services/SilkPublishability.cjs +15 -11
  37. package/packages/silk-effects/dist/dev/pkg/services/SilkPublishability.js +5 -2
  38. package/tsconfig/node/dist/tsconfig.tsbuildinfo +1 -1
  39. package/packages/silk-effects/dist/dev/pkg/changesets/services/workspace-snapshot.cjs +0 -162
  40. package/packages/silk-effects/dist/dev/pkg/changesets/services/workspace-snapshot.js +0 -160
  41. package/packages/silk-effects/dist/dev/pkg/changesets/utils/worktree-snapshot.cjs +0 -144
  42. package/packages/silk-effects/dist/dev/pkg/changesets/utils/worktree-snapshot.js +0 -142
@@ -1,162 +0,0 @@
1
- const require_errors = require('../errors.cjs');
2
- let effect = require("effect");
3
- let node_child_process = require("node:child_process");
4
-
5
- //#region ../silk-effects/dist/dev/pkg/changesets/services/workspace-snapshot.js
6
- /**
7
- * @internal
8
- */
9
- const WorkspaceSnapshotReaderBase = effect.Context.Tag("WorkspaceSnapshotReader")();
10
- /**
11
- * Effect service tag for {@link WorkspaceSnapshotReaderShape}.
12
- *
13
- * @public
14
- */
15
- var WorkspaceSnapshotReader = class extends WorkspaceSnapshotReaderBase {};
16
- function runGitShow(cwd, ref, path) {
17
- return effect.Effect.try({
18
- try: () => (0, node_child_process.execFileSync)("git", ["show", `${ref}:${path}`], {
19
- cwd,
20
- encoding: "utf8",
21
- stdio: [
22
- "ignore",
23
- "pipe",
24
- "pipe"
25
- ]
26
- }),
27
- catch: (error) => {
28
- const stderr = error.stderr;
29
- const text = typeof stderr === "string" ? stderr : stderr?.toString() ?? "";
30
- if (/exists on disk, but not in|does not exist|unknown revision|bad object/.test(text)) return new require_errors.GitError({
31
- command: `git show ${ref}:${path}`,
32
- cwd,
33
- reason: "PATH_NOT_AT_REF"
34
- });
35
- return new require_errors.GitError({
36
- command: `git show ${ref}:${path}`,
37
- cwd,
38
- reason: text.trim() || (error.message ?? String(error))
39
- });
40
- }
41
- }).pipe(effect.Effect.catchTag("GitError", (err) => err.reason === "PATH_NOT_AT_REF" ? effect.Effect.succeed(null) : effect.Effect.fail(err)));
42
- }
43
- /**
44
- * Parse a minimal `pnpm-workspace.yaml` (`packages:` list only). Tolerant
45
- * of comments and varied indentation; rejects on missing `packages:` key.
46
- */
47
- function parseWorkspaceGlobs(yamlText) {
48
- const lines = yamlText.split(/\r?\n/);
49
- const globs = [];
50
- let inPackagesBlock = false;
51
- for (const line of lines) {
52
- if (/^\s*#/.test(line)) continue;
53
- if (/^\s*packages\s*:\s*$/.test(line)) {
54
- inPackagesBlock = true;
55
- continue;
56
- }
57
- if (inPackagesBlock) {
58
- const match = line.match(/^\s+-\s+["']?(.+?)["']?\s*$/);
59
- if (match) {
60
- globs.push(match[1]);
61
- continue;
62
- }
63
- if (line.length > 0 && !line.startsWith(" ") && !line.startsWith(" ")) inPackagesBlock = false;
64
- }
65
- }
66
- return globs;
67
- }
68
- function toSnapshot(pkg, relativePath) {
69
- if (!pkg.name) return null;
70
- return {
71
- name: pkg.name,
72
- relativePath,
73
- version: pkg.version ?? "0.0.0",
74
- dependencies: pkg.dependencies ?? {},
75
- devDependencies: pkg.devDependencies ?? {},
76
- peerDependencies: pkg.peerDependencies ?? {},
77
- optionalDependencies: pkg.optionalDependencies ?? {}
78
- };
79
- }
80
- /**
81
- * Expand a workspace glob like `packages/*` or `apps/web` against the
82
- * directories present at the given git ref. We can't `globSync` here
83
- * (the directories may not be on disk at this ref); instead we use
84
- * `git ls-tree` to enumerate paths.
85
- */
86
- function expandGlobAtRef(cwd, ref, glob) {
87
- return effect.Effect.gen(function* () {
88
- const cleanGlob = glob.replace(/\/\*\*$/, "/*");
89
- if (!cleanGlob.includes("*") && !cleanGlob.includes("?")) return [cleanGlob];
90
- const prefix = cleanGlob.includes("/") ? cleanGlob.slice(0, cleanGlob.lastIndexOf("/") + 1) : "";
91
- const entries = (yield* effect.Effect.try({
92
- try: () => (0, node_child_process.execFileSync)("git", [
93
- "ls-tree",
94
- "--name-only",
95
- ref,
96
- prefix
97
- ], {
98
- cwd,
99
- encoding: "utf8",
100
- stdio: [
101
- "ignore",
102
- "pipe",
103
- "pipe"
104
- ]
105
- }),
106
- catch: (error) => {
107
- const stderr = error.stderr;
108
- const text = typeof stderr === "string" ? stderr : stderr?.toString() ?? "";
109
- return new require_errors.GitError({
110
- command: `git ls-tree ${ref} ${prefix}`,
111
- cwd,
112
- reason: text.trim() || (error.message ?? String(error))
113
- });
114
- }
115
- })).split(/\r?\n/).map((s) => s.trim()).filter((s) => s.length > 0);
116
- const regex = new RegExp(`^${cleanGlob.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, "[^/]*").replace(/\?/g, "[^/]")}$`);
117
- return entries.filter((e) => regex.test(e));
118
- });
119
- }
120
- function makeShape() {
121
- const cache = /* @__PURE__ */ new Map();
122
- const snapshotAt = (cwd, ref) => effect.Effect.gen(function* () {
123
- const cacheKey = `${cwd}::${ref}`;
124
- const cached = cache.get(cacheKey);
125
- if (cached) return cached;
126
- const wsYaml = yield* runGitShow(cwd, ref, "pnpm-workspace.yaml");
127
- const globs = wsYaml ? parseWorkspaceGlobs(wsYaml) : [];
128
- const dirs = [];
129
- for (const glob of globs) {
130
- const expanded = yield* expandGlobAtRef(cwd, ref, glob);
131
- for (const d of expanded) if (!dirs.includes(d)) dirs.push(d);
132
- }
133
- if (!dirs.includes(".")) dirs.unshift(".");
134
- const snapshots = [];
135
- for (const dir of dirs) {
136
- const pkgText = yield* runGitShow(cwd, ref, dir === "." ? "package.json" : `${dir}/package.json`);
137
- if (!pkgText) continue;
138
- let parsed;
139
- try {
140
- parsed = JSON.parse(pkgText);
141
- } catch {
142
- continue;
143
- }
144
- const snap = toSnapshot(parsed, dir);
145
- if (snap) snapshots.push(snap);
146
- }
147
- cache.set(cacheKey, snapshots);
148
- return snapshots;
149
- });
150
- return { snapshotAt };
151
- }
152
- /**
153
- * Production layer for {@link WorkspaceSnapshotReader}.
154
- *
155
- * @public
156
- */
157
- const WorkspaceSnapshotReaderLive = effect.Layer.succeed(WorkspaceSnapshotReader, makeShape());
158
-
159
- //#endregion
160
- exports.WorkspaceSnapshotReader = WorkspaceSnapshotReader;
161
- exports.WorkspaceSnapshotReaderBase = WorkspaceSnapshotReaderBase;
162
- exports.WorkspaceSnapshotReaderLive = WorkspaceSnapshotReaderLive;
@@ -1,160 +0,0 @@
1
- import { GitError } from "../errors.js";
2
- import { Context, Effect, Layer } from "effect";
3
- import { execFileSync } from "node:child_process";
4
-
5
- //#region ../silk-effects/dist/dev/pkg/changesets/services/workspace-snapshot.js
6
- /**
7
- * @internal
8
- */
9
- const WorkspaceSnapshotReaderBase = Context.Tag("WorkspaceSnapshotReader")();
10
- /**
11
- * Effect service tag for {@link WorkspaceSnapshotReaderShape}.
12
- *
13
- * @public
14
- */
15
- var WorkspaceSnapshotReader = class extends WorkspaceSnapshotReaderBase {};
16
- function runGitShow(cwd, ref, path) {
17
- return Effect.try({
18
- try: () => execFileSync("git", ["show", `${ref}:${path}`], {
19
- cwd,
20
- encoding: "utf8",
21
- stdio: [
22
- "ignore",
23
- "pipe",
24
- "pipe"
25
- ]
26
- }),
27
- catch: (error) => {
28
- const stderr = error.stderr;
29
- const text = typeof stderr === "string" ? stderr : stderr?.toString() ?? "";
30
- if (/exists on disk, but not in|does not exist|unknown revision|bad object/.test(text)) return new GitError({
31
- command: `git show ${ref}:${path}`,
32
- cwd,
33
- reason: "PATH_NOT_AT_REF"
34
- });
35
- return new GitError({
36
- command: `git show ${ref}:${path}`,
37
- cwd,
38
- reason: text.trim() || (error.message ?? String(error))
39
- });
40
- }
41
- }).pipe(Effect.catchTag("GitError", (err) => err.reason === "PATH_NOT_AT_REF" ? Effect.succeed(null) : Effect.fail(err)));
42
- }
43
- /**
44
- * Parse a minimal `pnpm-workspace.yaml` (`packages:` list only). Tolerant
45
- * of comments and varied indentation; rejects on missing `packages:` key.
46
- */
47
- function parseWorkspaceGlobs(yamlText) {
48
- const lines = yamlText.split(/\r?\n/);
49
- const globs = [];
50
- let inPackagesBlock = false;
51
- for (const line of lines) {
52
- if (/^\s*#/.test(line)) continue;
53
- if (/^\s*packages\s*:\s*$/.test(line)) {
54
- inPackagesBlock = true;
55
- continue;
56
- }
57
- if (inPackagesBlock) {
58
- const match = line.match(/^\s+-\s+["']?(.+?)["']?\s*$/);
59
- if (match) {
60
- globs.push(match[1]);
61
- continue;
62
- }
63
- if (line.length > 0 && !line.startsWith(" ") && !line.startsWith(" ")) inPackagesBlock = false;
64
- }
65
- }
66
- return globs;
67
- }
68
- function toSnapshot(pkg, relativePath) {
69
- if (!pkg.name) return null;
70
- return {
71
- name: pkg.name,
72
- relativePath,
73
- version: pkg.version ?? "0.0.0",
74
- dependencies: pkg.dependencies ?? {},
75
- devDependencies: pkg.devDependencies ?? {},
76
- peerDependencies: pkg.peerDependencies ?? {},
77
- optionalDependencies: pkg.optionalDependencies ?? {}
78
- };
79
- }
80
- /**
81
- * Expand a workspace glob like `packages/*` or `apps/web` against the
82
- * directories present at the given git ref. We can't `globSync` here
83
- * (the directories may not be on disk at this ref); instead we use
84
- * `git ls-tree` to enumerate paths.
85
- */
86
- function expandGlobAtRef(cwd, ref, glob) {
87
- return Effect.gen(function* () {
88
- const cleanGlob = glob.replace(/\/\*\*$/, "/*");
89
- if (!cleanGlob.includes("*") && !cleanGlob.includes("?")) return [cleanGlob];
90
- const prefix = cleanGlob.includes("/") ? cleanGlob.slice(0, cleanGlob.lastIndexOf("/") + 1) : "";
91
- const entries = (yield* Effect.try({
92
- try: () => execFileSync("git", [
93
- "ls-tree",
94
- "--name-only",
95
- ref,
96
- prefix
97
- ], {
98
- cwd,
99
- encoding: "utf8",
100
- stdio: [
101
- "ignore",
102
- "pipe",
103
- "pipe"
104
- ]
105
- }),
106
- catch: (error) => {
107
- const stderr = error.stderr;
108
- const text = typeof stderr === "string" ? stderr : stderr?.toString() ?? "";
109
- return new GitError({
110
- command: `git ls-tree ${ref} ${prefix}`,
111
- cwd,
112
- reason: text.trim() || (error.message ?? String(error))
113
- });
114
- }
115
- })).split(/\r?\n/).map((s) => s.trim()).filter((s) => s.length > 0);
116
- const regex = new RegExp(`^${cleanGlob.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, "[^/]*").replace(/\?/g, "[^/]")}$`);
117
- return entries.filter((e) => regex.test(e));
118
- });
119
- }
120
- function makeShape() {
121
- const cache = /* @__PURE__ */ new Map();
122
- const snapshotAt = (cwd, ref) => Effect.gen(function* () {
123
- const cacheKey = `${cwd}::${ref}`;
124
- const cached = cache.get(cacheKey);
125
- if (cached) return cached;
126
- const wsYaml = yield* runGitShow(cwd, ref, "pnpm-workspace.yaml");
127
- const globs = wsYaml ? parseWorkspaceGlobs(wsYaml) : [];
128
- const dirs = [];
129
- for (const glob of globs) {
130
- const expanded = yield* expandGlobAtRef(cwd, ref, glob);
131
- for (const d of expanded) if (!dirs.includes(d)) dirs.push(d);
132
- }
133
- if (!dirs.includes(".")) dirs.unshift(".");
134
- const snapshots = [];
135
- for (const dir of dirs) {
136
- const pkgText = yield* runGitShow(cwd, ref, dir === "." ? "package.json" : `${dir}/package.json`);
137
- if (!pkgText) continue;
138
- let parsed;
139
- try {
140
- parsed = JSON.parse(pkgText);
141
- } catch {
142
- continue;
143
- }
144
- const snap = toSnapshot(parsed, dir);
145
- if (snap) snapshots.push(snap);
146
- }
147
- cache.set(cacheKey, snapshots);
148
- return snapshots;
149
- });
150
- return { snapshotAt };
151
- }
152
- /**
153
- * Production layer for {@link WorkspaceSnapshotReader}.
154
- *
155
- * @public
156
- */
157
- const WorkspaceSnapshotReaderLive = Layer.succeed(WorkspaceSnapshotReader, makeShape());
158
-
159
- //#endregion
160
- export { WorkspaceSnapshotReader, WorkspaceSnapshotReaderBase, WorkspaceSnapshotReaderLive };
@@ -1,144 +0,0 @@
1
- const require_errors = require('../errors.cjs');
2
- let effect = require("effect");
3
- let node_path = require("node:path");
4
- let node_fs = require("node:fs");
5
- let node_child_process = require("node:child_process");
6
-
7
- //#region ../silk-effects/dist/dev/pkg/changesets/utils/worktree-snapshot.js
8
- /**
9
- * Shared helpers for `deps detect` and `deps regen` — both need to read
10
- * workspace package snapshots from the live working tree (the "after"
11
- * side of a dep diff that isn't pinned to a git ref) and to resolve the
12
- * merge-base for the default `--from` ref.
13
- *
14
- * @remarks
15
- * `WorkspaceSnapshotReader` covers the git-ref side via `git show`. This
16
- * module is the working-tree counterpart — staged and unstaged
17
- * `package.json` edits show up here, matching `analyze-branch`'s
18
- * coverage of the working tree.
19
- *
20
- * @internal
21
- */
22
- /**
23
- * Run `git merge-base <base> HEAD`, returning the SHA. Errors propagate
24
- * as {@link GitError}.
25
- *
26
- * @internal
27
- */
28
- function gitMergeBase(cwd, base) {
29
- return effect.Effect.try({
30
- try: () => (0, node_child_process.execFileSync)("git", [
31
- "merge-base",
32
- base,
33
- "HEAD"
34
- ], {
35
- cwd,
36
- encoding: "utf8",
37
- stdio: [
38
- "ignore",
39
- "pipe",
40
- "pipe"
41
- ]
42
- }).trim(),
43
- catch: (error) => {
44
- const stderr = error.stderr;
45
- const text = typeof stderr === "string" ? stderr : stderr?.toString() ?? "";
46
- return new require_errors.GitError({
47
- command: `git merge-base ${base} HEAD`,
48
- cwd,
49
- reason: text.trim() || (error.message ?? String(error))
50
- });
51
- }
52
- });
53
- }
54
- /**
55
- * Normalize a pnpm-workspace.yaml glob entry for filesystem expansion.
56
- *
57
- * `packages/**` collapses to `packages/*` (retains the wildcard so the
58
- * caller hits the directory-listing path); `packages/*` and a literal
59
- * `packages/foo` are passed through unchanged.
60
- *
61
- * Returning the literal-path form for `packages/**` (i.e., `"packages"`)
62
- * would route the caller through the "no wildcards" branch and silently
63
- * skip every child workspace.
64
- *
65
- * @internal
66
- */
67
- function normalizeWorkspaceGlob(glob) {
68
- return glob.replace(/\/\*\*$/, "/*");
69
- }
70
- /**
71
- * Read every workspace package's `package.json` from the live working
72
- * tree, returning {@link WorkspaceSnapshot} entries matching the shape
73
- * `WorkspaceSnapshotReader.snapshotAt` produces for git refs.
74
- *
75
- * @remarks
76
- * Falls back to root-only when `pnpm-workspace.yaml` is missing or
77
- * unparseable. Uses `node:fs.readdirSync` for directory expansion
78
- * (portable across platforms — `execFileSync("ls")` is not).
79
- *
80
- * @internal
81
- */
82
- function snapshotFromWorktree(cwd) {
83
- const snapshots = [];
84
- const dirs = /* @__PURE__ */ new Set([cwd]);
85
- for (const dir of expandWorkspaceDirs(cwd)) dirs.add(dir);
86
- for (const dir of dirs) try {
87
- const pkgJson = JSON.parse((0, node_fs.readFileSync)((0, node_path.join)(dir, "package.json"), "utf8"));
88
- if (!pkgJson.name) continue;
89
- const rel = dir === cwd ? "." : dir.slice(cwd.length + 1);
90
- snapshots.push({
91
- name: pkgJson.name,
92
- relativePath: rel,
93
- version: pkgJson.version ?? "0.0.0",
94
- dependencies: pkgJson.dependencies ?? {},
95
- devDependencies: pkgJson.devDependencies ?? {},
96
- peerDependencies: pkgJson.peerDependencies ?? {},
97
- optionalDependencies: pkgJson.optionalDependencies ?? {}
98
- });
99
- } catch {}
100
- return snapshots;
101
- }
102
- function expandWorkspaceDirs(cwd) {
103
- let yaml;
104
- try {
105
- yaml = (0, node_fs.readFileSync)((0, node_path.join)(cwd, "pnpm-workspace.yaml"), "utf8");
106
- } catch {
107
- return [];
108
- }
109
- const dirs = [];
110
- const lines = yaml.split(/\r?\n/);
111
- let inPackagesBlock = false;
112
- for (const line of lines) {
113
- if (/^\s*#/.test(line)) continue;
114
- if (/^\s*packages\s*:\s*$/.test(line)) {
115
- inPackagesBlock = true;
116
- continue;
117
- }
118
- if (!inPackagesBlock) continue;
119
- const m = line.match(/^\s+-\s+["']?(.+?)["']?\s*$/);
120
- if (m) {
121
- const glob = normalizeWorkspaceGlob(m[1]);
122
- if (glob.includes("*") || glob.includes("?")) {
123
- const prefix = glob.includes("/") ? glob.slice(0, glob.lastIndexOf("/") + 1) : "";
124
- let entries = [];
125
- try {
126
- entries = (0, node_fs.readdirSync)((0, node_path.join)(cwd, prefix || "."));
127
- } catch {
128
- continue;
129
- }
130
- const regex = new RegExp(`^${glob.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, "[^/]*").replace(/\?/g, "[^/]")}$`);
131
- for (const entry of entries) {
132
- const candidate = prefix ? `${prefix}${entry}` : entry;
133
- if (regex.test(candidate)) dirs.push((0, node_path.join)(cwd, candidate));
134
- }
135
- } else dirs.push((0, node_path.join)(cwd, glob));
136
- } else if (line.length > 0 && !line.startsWith(" ") && !line.startsWith(" ")) inPackagesBlock = false;
137
- }
138
- return dirs;
139
- }
140
-
141
- //#endregion
142
- exports.gitMergeBase = gitMergeBase;
143
- exports.normalizeWorkspaceGlob = normalizeWorkspaceGlob;
144
- exports.snapshotFromWorktree = snapshotFromWorktree;
@@ -1,142 +0,0 @@
1
- import { GitError } from "../errors.js";
2
- import { Effect } from "effect";
3
- import { join } from "node:path";
4
- import { readFileSync, readdirSync } from "node:fs";
5
- import { execFileSync } from "node:child_process";
6
-
7
- //#region ../silk-effects/dist/dev/pkg/changesets/utils/worktree-snapshot.js
8
- /**
9
- * Shared helpers for `deps detect` and `deps regen` — both need to read
10
- * workspace package snapshots from the live working tree (the "after"
11
- * side of a dep diff that isn't pinned to a git ref) and to resolve the
12
- * merge-base for the default `--from` ref.
13
- *
14
- * @remarks
15
- * `WorkspaceSnapshotReader` covers the git-ref side via `git show`. This
16
- * module is the working-tree counterpart — staged and unstaged
17
- * `package.json` edits show up here, matching `analyze-branch`'s
18
- * coverage of the working tree.
19
- *
20
- * @internal
21
- */
22
- /**
23
- * Run `git merge-base <base> HEAD`, returning the SHA. Errors propagate
24
- * as {@link GitError}.
25
- *
26
- * @internal
27
- */
28
- function gitMergeBase(cwd, base) {
29
- return Effect.try({
30
- try: () => execFileSync("git", [
31
- "merge-base",
32
- base,
33
- "HEAD"
34
- ], {
35
- cwd,
36
- encoding: "utf8",
37
- stdio: [
38
- "ignore",
39
- "pipe",
40
- "pipe"
41
- ]
42
- }).trim(),
43
- catch: (error) => {
44
- const stderr = error.stderr;
45
- const text = typeof stderr === "string" ? stderr : stderr?.toString() ?? "";
46
- return new GitError({
47
- command: `git merge-base ${base} HEAD`,
48
- cwd,
49
- reason: text.trim() || (error.message ?? String(error))
50
- });
51
- }
52
- });
53
- }
54
- /**
55
- * Normalize a pnpm-workspace.yaml glob entry for filesystem expansion.
56
- *
57
- * `packages/**` collapses to `packages/*` (retains the wildcard so the
58
- * caller hits the directory-listing path); `packages/*` and a literal
59
- * `packages/foo` are passed through unchanged.
60
- *
61
- * Returning the literal-path form for `packages/**` (i.e., `"packages"`)
62
- * would route the caller through the "no wildcards" branch and silently
63
- * skip every child workspace.
64
- *
65
- * @internal
66
- */
67
- function normalizeWorkspaceGlob(glob) {
68
- return glob.replace(/\/\*\*$/, "/*");
69
- }
70
- /**
71
- * Read every workspace package's `package.json` from the live working
72
- * tree, returning {@link WorkspaceSnapshot} entries matching the shape
73
- * `WorkspaceSnapshotReader.snapshotAt` produces for git refs.
74
- *
75
- * @remarks
76
- * Falls back to root-only when `pnpm-workspace.yaml` is missing or
77
- * unparseable. Uses `node:fs.readdirSync` for directory expansion
78
- * (portable across platforms — `execFileSync("ls")` is not).
79
- *
80
- * @internal
81
- */
82
- function snapshotFromWorktree(cwd) {
83
- const snapshots = [];
84
- const dirs = /* @__PURE__ */ new Set([cwd]);
85
- for (const dir of expandWorkspaceDirs(cwd)) dirs.add(dir);
86
- for (const dir of dirs) try {
87
- const pkgJson = JSON.parse(readFileSync(join(dir, "package.json"), "utf8"));
88
- if (!pkgJson.name) continue;
89
- const rel = dir === cwd ? "." : dir.slice(cwd.length + 1);
90
- snapshots.push({
91
- name: pkgJson.name,
92
- relativePath: rel,
93
- version: pkgJson.version ?? "0.0.0",
94
- dependencies: pkgJson.dependencies ?? {},
95
- devDependencies: pkgJson.devDependencies ?? {},
96
- peerDependencies: pkgJson.peerDependencies ?? {},
97
- optionalDependencies: pkgJson.optionalDependencies ?? {}
98
- });
99
- } catch {}
100
- return snapshots;
101
- }
102
- function expandWorkspaceDirs(cwd) {
103
- let yaml;
104
- try {
105
- yaml = readFileSync(join(cwd, "pnpm-workspace.yaml"), "utf8");
106
- } catch {
107
- return [];
108
- }
109
- const dirs = [];
110
- const lines = yaml.split(/\r?\n/);
111
- let inPackagesBlock = false;
112
- for (const line of lines) {
113
- if (/^\s*#/.test(line)) continue;
114
- if (/^\s*packages\s*:\s*$/.test(line)) {
115
- inPackagesBlock = true;
116
- continue;
117
- }
118
- if (!inPackagesBlock) continue;
119
- const m = line.match(/^\s+-\s+["']?(.+?)["']?\s*$/);
120
- if (m) {
121
- const glob = normalizeWorkspaceGlob(m[1]);
122
- if (glob.includes("*") || glob.includes("?")) {
123
- const prefix = glob.includes("/") ? glob.slice(0, glob.lastIndexOf("/") + 1) : "";
124
- let entries = [];
125
- try {
126
- entries = readdirSync(join(cwd, prefix || "."));
127
- } catch {
128
- continue;
129
- }
130
- const regex = new RegExp(`^${glob.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, "[^/]*").replace(/\?/g, "[^/]")}$`);
131
- for (const entry of entries) {
132
- const candidate = prefix ? `${prefix}${entry}` : entry;
133
- if (regex.test(candidate)) dirs.push(join(cwd, candidate));
134
- }
135
- } else dirs.push(join(cwd, glob));
136
- } else if (line.length > 0 && !line.startsWith(" ") && !line.startsWith(" ")) inPackagesBlock = false;
137
- }
138
- return dirs;
139
- }
140
-
141
- //#endregion
142
- export { gitMergeBase, normalizeWorkspaceGlob, snapshotFromWorktree };