@savvy-web/silk 1.1.2 → 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/changesets-changelog.cjs +25723 -879
- package/changesets-changelog.d.cts +153 -1
- package/changesets-changelog.d.ts +153 -1
- package/changesets-markdownlint.cjs +25723 -879
- package/changesets-markdownlint.d.cts +153 -1
- package/changesets-markdownlint.d.ts +153 -1
- package/package.json +4 -4
- package/packages/silk-effects/dist/dev/pkg/changesets/errors.cjs +26 -0
- package/packages/silk-effects/dist/dev/pkg/changesets/errors.js +25 -1
- package/packages/silk-effects/dist/dev/pkg/changesets/index.cjs +16 -1
- package/packages/silk-effects/dist/dev/pkg/changesets/index.js +17 -2
- package/packages/silk-effects/dist/dev/pkg/changesets/schemas/release-plan.cjs +63 -0
- package/packages/silk-effects/dist/dev/pkg/changesets/schemas/release-plan.js +57 -0
- package/packages/silk-effects/dist/dev/pkg/changesets/services/release-planner.cjs +255 -0
- package/packages/silk-effects/dist/dev/pkg/changesets/services/release-planner.js +252 -0
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
let effect = require("effect");
|
|
2
|
+
|
|
3
|
+
//#region ../silk-effects/dist/dev/pkg/changesets/schemas/release-plan.js
|
|
4
|
+
/**
|
|
5
|
+
* Result schemas for the {@link ReleasePlanner} service — the structured
|
|
6
|
+
* preview of pending releases and the result of a native apply.
|
|
7
|
+
*
|
|
8
|
+
* @packageDocumentation
|
|
9
|
+
*/
|
|
10
|
+
/** A semantic-version bump level (the `"none"` plan type is filtered out upstream). @public */
|
|
11
|
+
const BumpTypeSchema = effect.Schema.Literal("major", "minor", "patch");
|
|
12
|
+
/** One package's previewed release: version transition + rendered changelog block. @public */
|
|
13
|
+
const PreviewReleaseSchema = effect.Schema.Struct({
|
|
14
|
+
name: effect.Schema.String,
|
|
15
|
+
type: BumpTypeSchema,
|
|
16
|
+
oldVersion: effect.Schema.String,
|
|
17
|
+
newVersion: effect.Schema.String,
|
|
18
|
+
changesetIds: effect.Schema.Array(effect.Schema.String),
|
|
19
|
+
changelogEntry: effect.Schema.String
|
|
20
|
+
}).annotations({ identifier: "PreviewRelease" });
|
|
21
|
+
/** A parsed pending changeset (id + summary + the packages it bumps). @public */
|
|
22
|
+
const PendingChangesetSchema = effect.Schema.Struct({
|
|
23
|
+
id: effect.Schema.String,
|
|
24
|
+
summary: effect.Schema.String,
|
|
25
|
+
releases: effect.Schema.Array(effect.Schema.Struct({
|
|
26
|
+
name: effect.Schema.String,
|
|
27
|
+
type: BumpTypeSchema
|
|
28
|
+
}))
|
|
29
|
+
}).annotations({ identifier: "PendingChangeset" });
|
|
30
|
+
/** Read-only preview of what the next release would produce. @public */
|
|
31
|
+
const ChangesetPreviewSchema = effect.Schema.Struct({
|
|
32
|
+
preMode: effect.Schema.NullOr(effect.Schema.Literal("exit", "pre")),
|
|
33
|
+
releases: effect.Schema.Array(PreviewReleaseSchema),
|
|
34
|
+
changesets: effect.Schema.Array(PendingChangesetSchema)
|
|
35
|
+
}).annotations({ identifier: "ChangesetPreview" });
|
|
36
|
+
/** One applied package release (version transition). @public */
|
|
37
|
+
const AppliedReleaseEntrySchema = effect.Schema.Struct({
|
|
38
|
+
name: effect.Schema.String,
|
|
39
|
+
type: BumpTypeSchema,
|
|
40
|
+
oldVersion: effect.Schema.String,
|
|
41
|
+
newVersion: effect.Schema.String
|
|
42
|
+
}).annotations({ identifier: "AppliedReleaseEntry" });
|
|
43
|
+
/** A single versionFiles update applied (or planned, when dry). @public */
|
|
44
|
+
const VersionFileUpdateRecordSchema = effect.Schema.Struct({
|
|
45
|
+
filePath: effect.Schema.String,
|
|
46
|
+
version: effect.Schema.String
|
|
47
|
+
}).annotations({ identifier: "VersionFileUpdateRecord" });
|
|
48
|
+
/** Result of {@link ReleasePlanner.apply}. @public */
|
|
49
|
+
const AppliedReleaseSchema = effect.Schema.Struct({
|
|
50
|
+
dryRun: effect.Schema.Boolean,
|
|
51
|
+
touchedFiles: effect.Schema.Array(effect.Schema.String),
|
|
52
|
+
releases: effect.Schema.Array(AppliedReleaseEntrySchema),
|
|
53
|
+
versionFileUpdates: effect.Schema.Array(VersionFileUpdateRecordSchema)
|
|
54
|
+
}).annotations({ identifier: "AppliedRelease" });
|
|
55
|
+
|
|
56
|
+
//#endregion
|
|
57
|
+
exports.AppliedReleaseEntrySchema = AppliedReleaseEntrySchema;
|
|
58
|
+
exports.AppliedReleaseSchema = AppliedReleaseSchema;
|
|
59
|
+
exports.BumpTypeSchema = BumpTypeSchema;
|
|
60
|
+
exports.ChangesetPreviewSchema = ChangesetPreviewSchema;
|
|
61
|
+
exports.PendingChangesetSchema = PendingChangesetSchema;
|
|
62
|
+
exports.PreviewReleaseSchema = PreviewReleaseSchema;
|
|
63
|
+
exports.VersionFileUpdateRecordSchema = VersionFileUpdateRecordSchema;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { Schema } from "effect";
|
|
2
|
+
|
|
3
|
+
//#region ../silk-effects/dist/dev/pkg/changesets/schemas/release-plan.js
|
|
4
|
+
/**
|
|
5
|
+
* Result schemas for the {@link ReleasePlanner} service — the structured
|
|
6
|
+
* preview of pending releases and the result of a native apply.
|
|
7
|
+
*
|
|
8
|
+
* @packageDocumentation
|
|
9
|
+
*/
|
|
10
|
+
/** A semantic-version bump level (the `"none"` plan type is filtered out upstream). @public */
|
|
11
|
+
const BumpTypeSchema = Schema.Literal("major", "minor", "patch");
|
|
12
|
+
/** One package's previewed release: version transition + rendered changelog block. @public */
|
|
13
|
+
const PreviewReleaseSchema = Schema.Struct({
|
|
14
|
+
name: Schema.String,
|
|
15
|
+
type: BumpTypeSchema,
|
|
16
|
+
oldVersion: Schema.String,
|
|
17
|
+
newVersion: Schema.String,
|
|
18
|
+
changesetIds: Schema.Array(Schema.String),
|
|
19
|
+
changelogEntry: Schema.String
|
|
20
|
+
}).annotations({ identifier: "PreviewRelease" });
|
|
21
|
+
/** A parsed pending changeset (id + summary + the packages it bumps). @public */
|
|
22
|
+
const PendingChangesetSchema = Schema.Struct({
|
|
23
|
+
id: Schema.String,
|
|
24
|
+
summary: Schema.String,
|
|
25
|
+
releases: Schema.Array(Schema.Struct({
|
|
26
|
+
name: Schema.String,
|
|
27
|
+
type: BumpTypeSchema
|
|
28
|
+
}))
|
|
29
|
+
}).annotations({ identifier: "PendingChangeset" });
|
|
30
|
+
/** Read-only preview of what the next release would produce. @public */
|
|
31
|
+
const ChangesetPreviewSchema = Schema.Struct({
|
|
32
|
+
preMode: Schema.NullOr(Schema.Literal("exit", "pre")),
|
|
33
|
+
releases: Schema.Array(PreviewReleaseSchema),
|
|
34
|
+
changesets: Schema.Array(PendingChangesetSchema)
|
|
35
|
+
}).annotations({ identifier: "ChangesetPreview" });
|
|
36
|
+
/** One applied package release (version transition). @public */
|
|
37
|
+
const AppliedReleaseEntrySchema = Schema.Struct({
|
|
38
|
+
name: Schema.String,
|
|
39
|
+
type: BumpTypeSchema,
|
|
40
|
+
oldVersion: Schema.String,
|
|
41
|
+
newVersion: Schema.String
|
|
42
|
+
}).annotations({ identifier: "AppliedReleaseEntry" });
|
|
43
|
+
/** A single versionFiles update applied (or planned, when dry). @public */
|
|
44
|
+
const VersionFileUpdateRecordSchema = Schema.Struct({
|
|
45
|
+
filePath: Schema.String,
|
|
46
|
+
version: Schema.String
|
|
47
|
+
}).annotations({ identifier: "VersionFileUpdateRecord" });
|
|
48
|
+
/** Result of {@link ReleasePlanner.apply}. @public */
|
|
49
|
+
const AppliedReleaseSchema = Schema.Struct({
|
|
50
|
+
dryRun: Schema.Boolean,
|
|
51
|
+
touchedFiles: Schema.Array(Schema.String),
|
|
52
|
+
releases: Schema.Array(AppliedReleaseEntrySchema),
|
|
53
|
+
versionFileUpdates: Schema.Array(VersionFileUpdateRecordSchema)
|
|
54
|
+
}).annotations({ identifier: "AppliedRelease" });
|
|
55
|
+
|
|
56
|
+
//#endregion
|
|
57
|
+
export { AppliedReleaseEntrySchema, AppliedReleaseSchema, BumpTypeSchema, ChangesetPreviewSchema, PendingChangesetSchema, PreviewReleaseSchema, VersionFileUpdateRecordSchema };
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
const require_errors = require('../errors.cjs');
|
|
2
|
+
const require_transformer = require('../api/transformer.cjs');
|
|
3
|
+
const require_config_inspector = require('./config-inspector.cjs');
|
|
4
|
+
const require_version_files = require('../utils/version-files.cjs');
|
|
5
|
+
const require_get_packages_cjs$1 = require('../../../../../../../node_modules/.pnpm/@manypkg_get-packages@1.1.3/node_modules/@manypkg/get-packages/dist/get-packages.cjs.cjs');
|
|
6
|
+
const require_changesets_config_esm = require('../../../../../../../node_modules/.pnpm/@changesets_config@3.1.4/node_modules/@changesets/config/dist/changesets-config.esm.cjs');
|
|
7
|
+
const require_changesets_apply_release_plan_esm = require('../../../../../../../node_modules/.pnpm/@changesets_apply-release-plan@7.1.1/node_modules/@changesets/apply-release-plan/dist/changesets-apply-release-plan.esm.cjs');
|
|
8
|
+
const require_changesets_get_release_plan_esm = require('../../../../../../../node_modules/.pnpm/@changesets_get-release-plan@4.0.16/node_modules/@changesets/get-release-plan/dist/changesets-get-release-plan.esm.cjs');
|
|
9
|
+
let effect = require("effect");
|
|
10
|
+
let node_path = require("node:path");
|
|
11
|
+
let node_fs = require("node:fs");
|
|
12
|
+
let node_os = require("node:os");
|
|
13
|
+
|
|
14
|
+
//#region ../silk-effects/dist/dev/pkg/changesets/services/release-planner.js
|
|
15
|
+
var import_get_packages_cjs = require_get_packages_cjs$1.default;
|
|
16
|
+
/**
|
|
17
|
+
* `ReleasePlanner` service — drive the genuine changesets release engine to
|
|
18
|
+
* compute a plan, render a read-only preview, or natively apply a release.
|
|
19
|
+
*
|
|
20
|
+
* @remarks
|
|
21
|
+
* `preview` and `apply` both run the real `@changesets/apply-release-plan`;
|
|
22
|
+
* `preview` redirects every write into a throwaway temp directory by handing
|
|
23
|
+
* the engine a `@manypkg`-shaped `Packages` object whose `dir`s point at temp,
|
|
24
|
+
* then reads the generated CHANGELOG blocks back. No changesets-internal logic
|
|
25
|
+
* (e.g. `getChangelogEntry`) is re-implemented.
|
|
26
|
+
*
|
|
27
|
+
* @packageDocumentation
|
|
28
|
+
*/
|
|
29
|
+
/** Single workspace-discovery seam; swap to an Effect-native stack later here. */
|
|
30
|
+
const buildPackages = (root) => (0, import_get_packages_cjs.getPackages)(root);
|
|
31
|
+
const errMsg = (e) => e instanceof Error ? e.message : String(e);
|
|
32
|
+
/**
|
|
33
|
+
* Base class for {@link ReleasePlanner}.
|
|
34
|
+
*
|
|
35
|
+
* @privateRemarks Required export for api-extractor (anonymous Context.Tag base). Do not delete.
|
|
36
|
+
* @internal
|
|
37
|
+
*/
|
|
38
|
+
const ReleasePlannerBase = effect.Context.Tag("ReleasePlanner")();
|
|
39
|
+
/** Effect service tag for the release planner. @public */
|
|
40
|
+
var ReleasePlanner = class extends ReleasePlannerBase {};
|
|
41
|
+
/** Build the service shape over a resolved {@link ConfigInspector}. */
|
|
42
|
+
function makeShape(inspector) {
|
|
43
|
+
const plan = (root) => effect.Effect.tryPromise({
|
|
44
|
+
try: () => require_changesets_get_release_plan_esm.getReleasePlan(root),
|
|
45
|
+
catch: (e) => new require_errors.ReleasePlanError({
|
|
46
|
+
phase: "plan",
|
|
47
|
+
reason: errMsg(e)
|
|
48
|
+
})
|
|
49
|
+
});
|
|
50
|
+
const preview = (root) => effect.Effect.tryPromise({
|
|
51
|
+
try: () => previewImpl(root),
|
|
52
|
+
catch: (e) => new require_errors.ReleasePlanError({
|
|
53
|
+
phase: "preview",
|
|
54
|
+
reason: errMsg(e)
|
|
55
|
+
})
|
|
56
|
+
});
|
|
57
|
+
const apply = (root, options) => applyEffect(root, options?.dryRun ?? false, inspector);
|
|
58
|
+
return {
|
|
59
|
+
plan,
|
|
60
|
+
preview,
|
|
61
|
+
apply
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
/** Production layer. Requires {@link ConfigInspector} (used by `apply`). @public */
|
|
65
|
+
const ReleasePlannerLive = effect.Layer.effect(ReleasePlanner, effect.Effect.gen(function* () {
|
|
66
|
+
return makeShape(yield* require_config_inspector.ConfigInspector);
|
|
67
|
+
}));
|
|
68
|
+
/**
|
|
69
|
+
* Test factory — supply fixed results for any subset of methods. Unsupplied
|
|
70
|
+
* methods fail with a `ReleasePlanError`.
|
|
71
|
+
*
|
|
72
|
+
* @public
|
|
73
|
+
*/
|
|
74
|
+
function makeReleasePlannerTest(fixed) {
|
|
75
|
+
const fail = (phase) => effect.Effect.fail(new require_errors.ReleasePlanError({
|
|
76
|
+
phase,
|
|
77
|
+
reason: "not provided in test layer"
|
|
78
|
+
}));
|
|
79
|
+
return effect.Layer.succeed(ReleasePlanner, {
|
|
80
|
+
plan: () => fixed.plan ? effect.Effect.succeed(fixed.plan) : fail("plan"),
|
|
81
|
+
preview: () => fixed.preview ? effect.Effect.succeed(fixed.preview) : fail("preview"),
|
|
82
|
+
apply: () => fixed.apply ? effect.Effect.succeed(fixed.apply) : fail("apply")
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
/** Extract the `## <version>` block (down to the next H2 or EOF) from a changelog. */
|
|
86
|
+
function extractVersionBlock(changelog, version) {
|
|
87
|
+
const lines = changelog.split("\n");
|
|
88
|
+
const start = lines.findIndex((l) => l.trim() === `## ${version}`);
|
|
89
|
+
if (start === -1) return "";
|
|
90
|
+
let end = lines.length;
|
|
91
|
+
for (let i = start + 1; i < lines.length; i++) if (/^## /.test(lines[i])) {
|
|
92
|
+
end = i;
|
|
93
|
+
break;
|
|
94
|
+
}
|
|
95
|
+
return lines.slice(start, end).join("\n").trim();
|
|
96
|
+
}
|
|
97
|
+
async function previewImpl(root) {
|
|
98
|
+
const [plan, packages] = await Promise.all([require_changesets_get_release_plan_esm.getReleasePlan(root), buildPackages(root)]);
|
|
99
|
+
const config = await require_changesets_config_esm.read(root, packages);
|
|
100
|
+
const preMode = plan.preState ? plan.preState.mode : null;
|
|
101
|
+
const changesets = plan.changesets.map((cs) => ({
|
|
102
|
+
id: cs.id,
|
|
103
|
+
summary: cs.summary,
|
|
104
|
+
releases: cs.releases.filter((r) => r.type !== "none").map((r) => ({
|
|
105
|
+
name: r.name,
|
|
106
|
+
type: r.type
|
|
107
|
+
}))
|
|
108
|
+
}));
|
|
109
|
+
const releasesToRender = plan.releases.filter((r) => r.type !== "none");
|
|
110
|
+
if (releasesToRender.length === 0) return {
|
|
111
|
+
preMode,
|
|
112
|
+
releases: [],
|
|
113
|
+
changesets
|
|
114
|
+
};
|
|
115
|
+
const tempRoot = (0, node_fs.mkdtempSync)((0, node_path.join)((0, node_os.tmpdir)(), "silk-preview-"));
|
|
116
|
+
try {
|
|
117
|
+
const mapDir = (dir) => {
|
|
118
|
+
const rel = (0, node_path.relative)(packages.root.dir, dir);
|
|
119
|
+
if (rel.startsWith("..") || (0, node_path.isAbsolute)(rel)) throw new Error(`Package directory is outside the workspace root: ${dir}`);
|
|
120
|
+
return (0, node_path.join)(tempRoot, rel);
|
|
121
|
+
};
|
|
122
|
+
const tempPackages = {
|
|
123
|
+
tool: packages.tool,
|
|
124
|
+
root: {
|
|
125
|
+
...packages.root,
|
|
126
|
+
dir: tempRoot,
|
|
127
|
+
packageJson: structuredClone(packages.root.packageJson)
|
|
128
|
+
},
|
|
129
|
+
packages: packages.packages.map((p) => ({
|
|
130
|
+
...p,
|
|
131
|
+
dir: mapDir(p.dir),
|
|
132
|
+
packageJson: structuredClone(p.packageJson)
|
|
133
|
+
}))
|
|
134
|
+
};
|
|
135
|
+
(0, node_fs.mkdirSync)((0, node_path.join)(tempRoot, ".changeset"), { recursive: true });
|
|
136
|
+
(0, node_fs.cpSync)((0, node_path.join)(root, "package.json"), (0, node_path.join)(tempRoot, "package.json"));
|
|
137
|
+
const preJson = (0, node_path.join)(root, ".changeset", "pre.json");
|
|
138
|
+
if ((0, node_fs.existsSync)(preJson)) (0, node_fs.cpSync)(preJson, (0, node_path.join)(tempRoot, ".changeset", "pre.json"));
|
|
139
|
+
for (const p of packages.packages) {
|
|
140
|
+
const tDir = mapDir(p.dir);
|
|
141
|
+
(0, node_fs.mkdirSync)(tDir, { recursive: true });
|
|
142
|
+
(0, node_fs.cpSync)((0, node_path.join)(p.dir, "package.json"), (0, node_path.join)(tDir, "package.json"));
|
|
143
|
+
const realCl = (0, node_path.join)(p.dir, "CHANGELOG.md");
|
|
144
|
+
if ((0, node_fs.existsSync)(realCl)) (0, node_fs.cpSync)(realCl, (0, node_path.join)(tDir, "CHANGELOG.md"));
|
|
145
|
+
}
|
|
146
|
+
const rootCl = (0, node_path.join)(packages.root.dir, "CHANGELOG.md");
|
|
147
|
+
if ((0, node_fs.existsSync)(rootCl)) (0, node_fs.cpSync)(rootCl, (0, node_path.join)(tempRoot, "CHANGELOG.md"));
|
|
148
|
+
await require_changesets_apply_release_plan_esm.applyReleasePlan(plan, tempPackages, config, void 0, root);
|
|
149
|
+
const dirByName = /* @__PURE__ */ new Map();
|
|
150
|
+
for (const p of tempPackages.packages) dirByName.set(p.packageJson.name, p.dir);
|
|
151
|
+
if (tempPackages.root.packageJson.name) dirByName.set(tempPackages.root.packageJson.name, tempRoot);
|
|
152
|
+
const releases = [];
|
|
153
|
+
for (const r of releasesToRender) {
|
|
154
|
+
const dir = dirByName.get(r.name);
|
|
155
|
+
if (!dir) continue;
|
|
156
|
+
const clPath = (0, node_path.join)(dir, "CHANGELOG.md");
|
|
157
|
+
if (!(0, node_fs.existsSync)(clPath)) continue;
|
|
158
|
+
require_transformer.ChangelogTransformer.transformFile(clPath);
|
|
159
|
+
const content = (0, node_fs.readFileSync)(clPath, "utf-8");
|
|
160
|
+
releases.push({
|
|
161
|
+
name: r.name,
|
|
162
|
+
type: r.type,
|
|
163
|
+
oldVersion: r.oldVersion,
|
|
164
|
+
newVersion: r.newVersion,
|
|
165
|
+
changesetIds: [...r.changesets],
|
|
166
|
+
changelogEntry: extractVersionBlock(content, r.newVersion)
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
return {
|
|
170
|
+
preMode,
|
|
171
|
+
releases,
|
|
172
|
+
changesets
|
|
173
|
+
};
|
|
174
|
+
} finally {
|
|
175
|
+
(0, node_fs.rmSync)(tempRoot, {
|
|
176
|
+
recursive: true,
|
|
177
|
+
force: true
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
/** Re-read a package's version from disk (post-bump) to feed versionFiles. */
|
|
182
|
+
function diskVersion(workspaceDir, fallback) {
|
|
183
|
+
try {
|
|
184
|
+
return JSON.parse((0, node_fs.readFileSync)((0, node_path.join)(workspaceDir, "package.json"), "utf-8")).version ?? fallback;
|
|
185
|
+
} catch {
|
|
186
|
+
return fallback;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
function applyEffect(root, dryRun, inspector) {
|
|
190
|
+
return effect.Effect.gen(function* () {
|
|
191
|
+
const { plan, packages, config } = yield* effect.Effect.tryPromise({
|
|
192
|
+
try: async () => {
|
|
193
|
+
const [plan, packages] = await Promise.all([require_changesets_get_release_plan_esm.getReleasePlan(root), buildPackages(root)]);
|
|
194
|
+
return {
|
|
195
|
+
plan,
|
|
196
|
+
packages,
|
|
197
|
+
config: await require_changesets_config_esm.read(root, packages)
|
|
198
|
+
};
|
|
199
|
+
},
|
|
200
|
+
catch: (e) => new require_errors.ReleasePlanError({
|
|
201
|
+
phase: "apply",
|
|
202
|
+
reason: errMsg(e)
|
|
203
|
+
})
|
|
204
|
+
});
|
|
205
|
+
const releases = plan.releases.filter((r) => r.type !== "none").map((r) => ({
|
|
206
|
+
name: r.name,
|
|
207
|
+
type: r.type,
|
|
208
|
+
oldVersion: r.oldVersion,
|
|
209
|
+
newVersion: r.newVersion
|
|
210
|
+
}));
|
|
211
|
+
let touchedFiles = [];
|
|
212
|
+
if (!dryRun) touchedFiles = yield* effect.Effect.tryPromise({
|
|
213
|
+
try: async () => {
|
|
214
|
+
const touched = await require_changesets_apply_release_plan_esm.applyReleasePlan(plan, packages, config);
|
|
215
|
+
for (const f of touched) if (f.endsWith("CHANGELOG.md")) require_transformer.ChangelogTransformer.transformFile(f);
|
|
216
|
+
return touched;
|
|
217
|
+
},
|
|
218
|
+
catch: (e) => new require_errors.ReleasePlanError({
|
|
219
|
+
phase: "apply",
|
|
220
|
+
reason: errMsg(e)
|
|
221
|
+
})
|
|
222
|
+
});
|
|
223
|
+
const newVersionByName = new Map(plan.releases.map((r) => [r.name, r.newVersion]));
|
|
224
|
+
const inspected = yield* inspector.inspect(root).pipe(effect.Effect.catchAll((error) => effect.Effect.logWarning(`Skipping versionFiles update: ${errMsg(error)}`).pipe(effect.Effect.as(null))));
|
|
225
|
+
let versionFileUpdates = [];
|
|
226
|
+
if (inspected) versionFileUpdates = yield* effect.Effect.try({
|
|
227
|
+
try: () => {
|
|
228
|
+
const scopes = inspected.packages.filter((p) => p.versionFiles.length > 0).map((p) => {
|
|
229
|
+
const fresh = dryRun ? newVersionByName.get(p.name) ?? p.version : diskVersion(p.workspaceDir, p.version);
|
|
230
|
+
return fresh !== p.version ? {
|
|
231
|
+
...p,
|
|
232
|
+
version: fresh
|
|
233
|
+
} : p;
|
|
234
|
+
});
|
|
235
|
+
return scopes.length > 0 ? require_version_files.VersionFiles.processResolvedVersionFiles(scopes, dryRun) : [];
|
|
236
|
+
},
|
|
237
|
+
catch: (e) => new require_errors.ReleasePlanError({
|
|
238
|
+
phase: "apply",
|
|
239
|
+
reason: errMsg(e)
|
|
240
|
+
})
|
|
241
|
+
});
|
|
242
|
+
return {
|
|
243
|
+
dryRun,
|
|
244
|
+
touchedFiles,
|
|
245
|
+
releases,
|
|
246
|
+
versionFileUpdates
|
|
247
|
+
};
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
//#endregion
|
|
252
|
+
exports.ReleasePlanner = ReleasePlanner;
|
|
253
|
+
exports.ReleasePlannerBase = ReleasePlannerBase;
|
|
254
|
+
exports.ReleasePlannerLive = ReleasePlannerLive;
|
|
255
|
+
exports.makeReleasePlannerTest = makeReleasePlannerTest;
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
import { ReleasePlanError } from "../errors.js";
|
|
2
|
+
import { ChangelogTransformer } from "../api/transformer.js";
|
|
3
|
+
import { ConfigInspector } from "./config-inspector.js";
|
|
4
|
+
import { VersionFiles } from "../utils/version-files.js";
|
|
5
|
+
import { require_get_packages_cjs } from "../../../../../../../node_modules/.pnpm/@manypkg_get-packages@1.1.3/node_modules/@manypkg/get-packages/dist/get-packages.cjs.js";
|
|
6
|
+
import { read } from "../../../../../../../node_modules/.pnpm/@changesets_config@3.1.4/node_modules/@changesets/config/dist/changesets-config.esm.js";
|
|
7
|
+
import { applyReleasePlan } from "../../../../../../../node_modules/.pnpm/@changesets_apply-release-plan@7.1.1/node_modules/@changesets/apply-release-plan/dist/changesets-apply-release-plan.esm.js";
|
|
8
|
+
import { getReleasePlan } from "../../../../../../../node_modules/.pnpm/@changesets_get-release-plan@4.0.16/node_modules/@changesets/get-release-plan/dist/changesets-get-release-plan.esm.js";
|
|
9
|
+
import { Context, Effect, Layer } from "effect";
|
|
10
|
+
import { isAbsolute, join, relative } from "node:path";
|
|
11
|
+
import { cpSync, existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync } from "node:fs";
|
|
12
|
+
import { tmpdir } from "node:os";
|
|
13
|
+
|
|
14
|
+
//#region ../silk-effects/dist/dev/pkg/changesets/services/release-planner.js
|
|
15
|
+
var import_get_packages_cjs = require_get_packages_cjs();
|
|
16
|
+
/**
|
|
17
|
+
* `ReleasePlanner` service — drive the genuine changesets release engine to
|
|
18
|
+
* compute a plan, render a read-only preview, or natively apply a release.
|
|
19
|
+
*
|
|
20
|
+
* @remarks
|
|
21
|
+
* `preview` and `apply` both run the real `@changesets/apply-release-plan`;
|
|
22
|
+
* `preview` redirects every write into a throwaway temp directory by handing
|
|
23
|
+
* the engine a `@manypkg`-shaped `Packages` object whose `dir`s point at temp,
|
|
24
|
+
* then reads the generated CHANGELOG blocks back. No changesets-internal logic
|
|
25
|
+
* (e.g. `getChangelogEntry`) is re-implemented.
|
|
26
|
+
*
|
|
27
|
+
* @packageDocumentation
|
|
28
|
+
*/
|
|
29
|
+
/** Single workspace-discovery seam; swap to an Effect-native stack later here. */
|
|
30
|
+
const buildPackages = (root) => (0, import_get_packages_cjs.getPackages)(root);
|
|
31
|
+
const errMsg = (e) => e instanceof Error ? e.message : String(e);
|
|
32
|
+
/**
|
|
33
|
+
* Base class for {@link ReleasePlanner}.
|
|
34
|
+
*
|
|
35
|
+
* @privateRemarks Required export for api-extractor (anonymous Context.Tag base). Do not delete.
|
|
36
|
+
* @internal
|
|
37
|
+
*/
|
|
38
|
+
const ReleasePlannerBase = Context.Tag("ReleasePlanner")();
|
|
39
|
+
/** Effect service tag for the release planner. @public */
|
|
40
|
+
var ReleasePlanner = class extends ReleasePlannerBase {};
|
|
41
|
+
/** Build the service shape over a resolved {@link ConfigInspector}. */
|
|
42
|
+
function makeShape(inspector) {
|
|
43
|
+
const plan = (root) => Effect.tryPromise({
|
|
44
|
+
try: () => getReleasePlan(root),
|
|
45
|
+
catch: (e) => new ReleasePlanError({
|
|
46
|
+
phase: "plan",
|
|
47
|
+
reason: errMsg(e)
|
|
48
|
+
})
|
|
49
|
+
});
|
|
50
|
+
const preview = (root) => Effect.tryPromise({
|
|
51
|
+
try: () => previewImpl(root),
|
|
52
|
+
catch: (e) => new ReleasePlanError({
|
|
53
|
+
phase: "preview",
|
|
54
|
+
reason: errMsg(e)
|
|
55
|
+
})
|
|
56
|
+
});
|
|
57
|
+
const apply = (root, options) => applyEffect(root, options?.dryRun ?? false, inspector);
|
|
58
|
+
return {
|
|
59
|
+
plan,
|
|
60
|
+
preview,
|
|
61
|
+
apply
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
/** Production layer. Requires {@link ConfigInspector} (used by `apply`). @public */
|
|
65
|
+
const ReleasePlannerLive = Layer.effect(ReleasePlanner, Effect.gen(function* () {
|
|
66
|
+
return makeShape(yield* ConfigInspector);
|
|
67
|
+
}));
|
|
68
|
+
/**
|
|
69
|
+
* Test factory — supply fixed results for any subset of methods. Unsupplied
|
|
70
|
+
* methods fail with a `ReleasePlanError`.
|
|
71
|
+
*
|
|
72
|
+
* @public
|
|
73
|
+
*/
|
|
74
|
+
function makeReleasePlannerTest(fixed) {
|
|
75
|
+
const fail = (phase) => Effect.fail(new ReleasePlanError({
|
|
76
|
+
phase,
|
|
77
|
+
reason: "not provided in test layer"
|
|
78
|
+
}));
|
|
79
|
+
return Layer.succeed(ReleasePlanner, {
|
|
80
|
+
plan: () => fixed.plan ? Effect.succeed(fixed.plan) : fail("plan"),
|
|
81
|
+
preview: () => fixed.preview ? Effect.succeed(fixed.preview) : fail("preview"),
|
|
82
|
+
apply: () => fixed.apply ? Effect.succeed(fixed.apply) : fail("apply")
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
/** Extract the `## <version>` block (down to the next H2 or EOF) from a changelog. */
|
|
86
|
+
function extractVersionBlock(changelog, version) {
|
|
87
|
+
const lines = changelog.split("\n");
|
|
88
|
+
const start = lines.findIndex((l) => l.trim() === `## ${version}`);
|
|
89
|
+
if (start === -1) return "";
|
|
90
|
+
let end = lines.length;
|
|
91
|
+
for (let i = start + 1; i < lines.length; i++) if (/^## /.test(lines[i])) {
|
|
92
|
+
end = i;
|
|
93
|
+
break;
|
|
94
|
+
}
|
|
95
|
+
return lines.slice(start, end).join("\n").trim();
|
|
96
|
+
}
|
|
97
|
+
async function previewImpl(root) {
|
|
98
|
+
const [plan, packages] = await Promise.all([getReleasePlan(root), buildPackages(root)]);
|
|
99
|
+
const config = await read(root, packages);
|
|
100
|
+
const preMode = plan.preState ? plan.preState.mode : null;
|
|
101
|
+
const changesets = plan.changesets.map((cs) => ({
|
|
102
|
+
id: cs.id,
|
|
103
|
+
summary: cs.summary,
|
|
104
|
+
releases: cs.releases.filter((r) => r.type !== "none").map((r) => ({
|
|
105
|
+
name: r.name,
|
|
106
|
+
type: r.type
|
|
107
|
+
}))
|
|
108
|
+
}));
|
|
109
|
+
const releasesToRender = plan.releases.filter((r) => r.type !== "none");
|
|
110
|
+
if (releasesToRender.length === 0) return {
|
|
111
|
+
preMode,
|
|
112
|
+
releases: [],
|
|
113
|
+
changesets
|
|
114
|
+
};
|
|
115
|
+
const tempRoot = mkdtempSync(join(tmpdir(), "silk-preview-"));
|
|
116
|
+
try {
|
|
117
|
+
const mapDir = (dir) => {
|
|
118
|
+
const rel = relative(packages.root.dir, dir);
|
|
119
|
+
if (rel.startsWith("..") || isAbsolute(rel)) throw new Error(`Package directory is outside the workspace root: ${dir}`);
|
|
120
|
+
return join(tempRoot, rel);
|
|
121
|
+
};
|
|
122
|
+
const tempPackages = {
|
|
123
|
+
tool: packages.tool,
|
|
124
|
+
root: {
|
|
125
|
+
...packages.root,
|
|
126
|
+
dir: tempRoot,
|
|
127
|
+
packageJson: structuredClone(packages.root.packageJson)
|
|
128
|
+
},
|
|
129
|
+
packages: packages.packages.map((p) => ({
|
|
130
|
+
...p,
|
|
131
|
+
dir: mapDir(p.dir),
|
|
132
|
+
packageJson: structuredClone(p.packageJson)
|
|
133
|
+
}))
|
|
134
|
+
};
|
|
135
|
+
mkdirSync(join(tempRoot, ".changeset"), { recursive: true });
|
|
136
|
+
cpSync(join(root, "package.json"), join(tempRoot, "package.json"));
|
|
137
|
+
const preJson = join(root, ".changeset", "pre.json");
|
|
138
|
+
if (existsSync(preJson)) cpSync(preJson, join(tempRoot, ".changeset", "pre.json"));
|
|
139
|
+
for (const p of packages.packages) {
|
|
140
|
+
const tDir = mapDir(p.dir);
|
|
141
|
+
mkdirSync(tDir, { recursive: true });
|
|
142
|
+
cpSync(join(p.dir, "package.json"), join(tDir, "package.json"));
|
|
143
|
+
const realCl = join(p.dir, "CHANGELOG.md");
|
|
144
|
+
if (existsSync(realCl)) cpSync(realCl, join(tDir, "CHANGELOG.md"));
|
|
145
|
+
}
|
|
146
|
+
const rootCl = join(packages.root.dir, "CHANGELOG.md");
|
|
147
|
+
if (existsSync(rootCl)) cpSync(rootCl, join(tempRoot, "CHANGELOG.md"));
|
|
148
|
+
await applyReleasePlan(plan, tempPackages, config, void 0, root);
|
|
149
|
+
const dirByName = /* @__PURE__ */ new Map();
|
|
150
|
+
for (const p of tempPackages.packages) dirByName.set(p.packageJson.name, p.dir);
|
|
151
|
+
if (tempPackages.root.packageJson.name) dirByName.set(tempPackages.root.packageJson.name, tempRoot);
|
|
152
|
+
const releases = [];
|
|
153
|
+
for (const r of releasesToRender) {
|
|
154
|
+
const dir = dirByName.get(r.name);
|
|
155
|
+
if (!dir) continue;
|
|
156
|
+
const clPath = join(dir, "CHANGELOG.md");
|
|
157
|
+
if (!existsSync(clPath)) continue;
|
|
158
|
+
ChangelogTransformer.transformFile(clPath);
|
|
159
|
+
const content = readFileSync(clPath, "utf-8");
|
|
160
|
+
releases.push({
|
|
161
|
+
name: r.name,
|
|
162
|
+
type: r.type,
|
|
163
|
+
oldVersion: r.oldVersion,
|
|
164
|
+
newVersion: r.newVersion,
|
|
165
|
+
changesetIds: [...r.changesets],
|
|
166
|
+
changelogEntry: extractVersionBlock(content, r.newVersion)
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
return {
|
|
170
|
+
preMode,
|
|
171
|
+
releases,
|
|
172
|
+
changesets
|
|
173
|
+
};
|
|
174
|
+
} finally {
|
|
175
|
+
rmSync(tempRoot, {
|
|
176
|
+
recursive: true,
|
|
177
|
+
force: true
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
/** Re-read a package's version from disk (post-bump) to feed versionFiles. */
|
|
182
|
+
function diskVersion(workspaceDir, fallback) {
|
|
183
|
+
try {
|
|
184
|
+
return JSON.parse(readFileSync(join(workspaceDir, "package.json"), "utf-8")).version ?? fallback;
|
|
185
|
+
} catch {
|
|
186
|
+
return fallback;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
function applyEffect(root, dryRun, inspector) {
|
|
190
|
+
return Effect.gen(function* () {
|
|
191
|
+
const { plan, packages, config } = yield* Effect.tryPromise({
|
|
192
|
+
try: async () => {
|
|
193
|
+
const [plan, packages] = await Promise.all([getReleasePlan(root), buildPackages(root)]);
|
|
194
|
+
return {
|
|
195
|
+
plan,
|
|
196
|
+
packages,
|
|
197
|
+
config: await read(root, packages)
|
|
198
|
+
};
|
|
199
|
+
},
|
|
200
|
+
catch: (e) => new ReleasePlanError({
|
|
201
|
+
phase: "apply",
|
|
202
|
+
reason: errMsg(e)
|
|
203
|
+
})
|
|
204
|
+
});
|
|
205
|
+
const releases = plan.releases.filter((r) => r.type !== "none").map((r) => ({
|
|
206
|
+
name: r.name,
|
|
207
|
+
type: r.type,
|
|
208
|
+
oldVersion: r.oldVersion,
|
|
209
|
+
newVersion: r.newVersion
|
|
210
|
+
}));
|
|
211
|
+
let touchedFiles = [];
|
|
212
|
+
if (!dryRun) touchedFiles = yield* Effect.tryPromise({
|
|
213
|
+
try: async () => {
|
|
214
|
+
const touched = await applyReleasePlan(plan, packages, config);
|
|
215
|
+
for (const f of touched) if (f.endsWith("CHANGELOG.md")) ChangelogTransformer.transformFile(f);
|
|
216
|
+
return touched;
|
|
217
|
+
},
|
|
218
|
+
catch: (e) => new ReleasePlanError({
|
|
219
|
+
phase: "apply",
|
|
220
|
+
reason: errMsg(e)
|
|
221
|
+
})
|
|
222
|
+
});
|
|
223
|
+
const newVersionByName = new Map(plan.releases.map((r) => [r.name, r.newVersion]));
|
|
224
|
+
const inspected = yield* inspector.inspect(root).pipe(Effect.catchAll((error) => Effect.logWarning(`Skipping versionFiles update: ${errMsg(error)}`).pipe(Effect.as(null))));
|
|
225
|
+
let versionFileUpdates = [];
|
|
226
|
+
if (inspected) versionFileUpdates = yield* Effect.try({
|
|
227
|
+
try: () => {
|
|
228
|
+
const scopes = inspected.packages.filter((p) => p.versionFiles.length > 0).map((p) => {
|
|
229
|
+
const fresh = dryRun ? newVersionByName.get(p.name) ?? p.version : diskVersion(p.workspaceDir, p.version);
|
|
230
|
+
return fresh !== p.version ? {
|
|
231
|
+
...p,
|
|
232
|
+
version: fresh
|
|
233
|
+
} : p;
|
|
234
|
+
});
|
|
235
|
+
return scopes.length > 0 ? VersionFiles.processResolvedVersionFiles(scopes, dryRun) : [];
|
|
236
|
+
},
|
|
237
|
+
catch: (e) => new ReleasePlanError({
|
|
238
|
+
phase: "apply",
|
|
239
|
+
reason: errMsg(e)
|
|
240
|
+
})
|
|
241
|
+
});
|
|
242
|
+
return {
|
|
243
|
+
dryRun,
|
|
244
|
+
touchedFiles,
|
|
245
|
+
releases,
|
|
246
|
+
versionFileUpdates
|
|
247
|
+
};
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
//#endregion
|
|
252
|
+
export { ReleasePlanner, ReleasePlannerBase, ReleasePlannerLive, makeReleasePlannerTest };
|