@modulify/conventional-release 0.1.0 → 0.1.2

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.
@@ -0,0 +1,127 @@
1
+ //#region src/cli/reporter.ts
2
+ function createReporter({ output, git, showTags = false, verbosity = "summary" }) {
3
+ if (verbosity === "detailed") return new DetailedReporter({
4
+ output,
5
+ git,
6
+ showTags
7
+ });
8
+ return new SummaryReporter({
9
+ output,
10
+ git,
11
+ showTags
12
+ });
13
+ }
14
+ var SummaryReporter = class {
15
+ output;
16
+ git;
17
+ showTags;
18
+ scope = null;
19
+ position = /* @__PURE__ */ new Map();
20
+ constructor({ output, git, showTags }) {
21
+ this.output = output;
22
+ this.git = git;
23
+ this.showTags = showTags;
24
+ }
25
+ async onStart(context) {
26
+ this.output.info(context.dry ? "Starting dry release" : "Starting release");
27
+ }
28
+ async onScope(scope, context) {
29
+ this.scope = scope;
30
+ this.position = new Map(scope.slices.map((slice, index) => [slice.id, index + 1]));
31
+ }
32
+ async onSliceStart(slice) {
33
+ this.output.info("Running slice %s", [this.describeProgress(slice)]);
34
+ }
35
+ async onSuccess(result) {
36
+ if (!result.changed) {
37
+ this.output.success("No changes since last release");
38
+ return;
39
+ }
40
+ const changed = result.slices.filter((slice) => slice.changed);
41
+ const primary = changed[0];
42
+ const packages = collectPackages(changed);
43
+ this.output.success("Release slices: %s", [String(changed.length)]);
44
+ this.output.success("Updated packages: %s", [String(packages.length)]);
45
+ if (primary) this.output.success("Next version: %s", [primary.nextVersion]);
46
+ if (result.dry) {
47
+ this.output.info("No committing or tagging since this was a dry run");
48
+ return;
49
+ }
50
+ this.output.success("Committed %s staged files", [String(result.files.length)]);
51
+ if (this.showTags) {
52
+ const tags = collectTags(changed);
53
+ if (tags.length) this.output.success("Tags: %s", [tags.join(", ")]);
54
+ }
55
+ this.output.info("Run `%s` to publish", [`git push --follow-tags origin ${await this.resolveBranch()}`]);
56
+ }
57
+ async onError(error) {
58
+ const message = error instanceof Error ? error.message : String(error);
59
+ this.output.error(message);
60
+ }
61
+ describeProgress(slice) {
62
+ const position = this.position.get(slice.id);
63
+ const total = this.scope?.slices.length;
64
+ const label = describeSlice(slice);
65
+ return position && total ? `${position}/${total}: ${label}` : label;
66
+ }
67
+ async resolveBranch() {
68
+ try {
69
+ return await this.git.revParse("HEAD", { abbrevRef: true });
70
+ } catch {
71
+ return "%branch%";
72
+ }
73
+ }
74
+ };
75
+ var DetailedReporter = class extends SummaryReporter {
76
+ async onScope(scope, context) {
77
+ await super.onScope(scope, context);
78
+ this.output.info("%s scope: %s packages, %s affected, %s slices", [
79
+ scope.mode,
80
+ String(scope.packages.length),
81
+ String(scope.affected.length),
82
+ String(scope.slices.length)
83
+ ]);
84
+ }
85
+ async onSliceSuccess(slice) {
86
+ if (!slice.changed) {
87
+ this.output.warn("Completed slice %s without version changes (%s)", [describeSlice(slice), slice.currentVersion]);
88
+ return;
89
+ }
90
+ this.output.success("Completed slice %s: %s -> %s (%s)", [
91
+ describeSlice(slice),
92
+ slice.currentVersion,
93
+ slice.nextVersion,
94
+ slice.releaseType
95
+ ]);
96
+ if (this.showTags && slice.tag) this.output.info("Tag: %s", [slice.tag]);
97
+ }
98
+ async onSuccess(result) {
99
+ await super.onSuccess(result);
100
+ if (!result.changed) return;
101
+ const packages = collectPackages(result.slices.filter((slice) => slice.changed));
102
+ this.output.info("Updated packages: %s", [describePackages(packages)]);
103
+ }
104
+ };
105
+ function describeSlice(slice) {
106
+ if (slice.partition) return `${slice.partition} [${describePackages(slice.packages)}]`;
107
+ return describePackages(slice.packages);
108
+ }
109
+ function describePackages(packages) {
110
+ return packages.map((pkg) => pkg.name ?? pkg.path).join(", ");
111
+ }
112
+ function collectTags(slices) {
113
+ return slices.map((slice) => slice.tag).filter((tag) => !!tag);
114
+ }
115
+ function collectPackages(slices) {
116
+ const packages = [];
117
+ const seen = /* @__PURE__ */ new Set();
118
+ for (const slice of slices) for (const pkg of slice.packages) {
119
+ const identity = pkg.name ?? pkg.path;
120
+ if (seen.has(identity)) continue;
121
+ seen.add(identity);
122
+ packages.push(pkg);
123
+ }
124
+ return packages;
125
+ }
126
+ //#endregion
127
+ export { createReporter };
@@ -0,0 +1,54 @@
1
+ require("./_virtual/_rolldown/runtime.cjs");
2
+ const require_constants = require("./constants.cjs");
3
+ let node_fs = require("node:fs");
4
+ let node_path = require("node:path");
5
+ let node_url = require("node:url");
6
+ //#region src/config.ts
7
+ /**
8
+ * Resolves repository release configuration from `package.json`, `release.config.*`,
9
+ * and inline overrides using the public precedence rules.
10
+ */
11
+ async function resolveConfig(cwd, inline) {
12
+ const root = cwd ?? process.cwd();
13
+ const fromPackage = loadPackageJsonConfig(root);
14
+ const fromFile = await loadFileConfig(root);
15
+ return {
16
+ ...fromPackage,
17
+ ...fromFile,
18
+ ...inline ?? {}
19
+ };
20
+ }
21
+ /** Converts repository configuration to executor-ready release options. */
22
+ function toScopeOptions(config) {
23
+ const options = { ...config };
24
+ delete options.changelogFile;
25
+ return options;
26
+ }
27
+ /** Extracts inline overrides from high-level run options. */
28
+ function toInlineConfig(options) {
29
+ const config = { ...options };
30
+ delete config.cwd;
31
+ delete config.dry;
32
+ delete config.reporter;
33
+ return config;
34
+ }
35
+ function loadPackageJsonConfig(cwd) {
36
+ const file = (0, node_path.join)(cwd, "package.json");
37
+ if (!(0, node_fs.existsSync)(file)) return {};
38
+ const content = JSON.parse((0, node_fs.readFileSync)(file, "utf-8"));
39
+ return isRecord(content.release) ? content.release : {};
40
+ }
41
+ async function loadFileConfig(cwd) {
42
+ const configFile = require_constants.RELEASE_CONFIG_FILENAMES.map((file) => (0, node_path.join)(cwd, file)).find((file) => (0, node_fs.existsSync)(file));
43
+ if (!configFile) return {};
44
+ const module = await import((0, node_url.pathToFileURL)(configFile).href);
45
+ const config = module.default ?? module;
46
+ return isRecord(config) ? config : {};
47
+ }
48
+ function isRecord(value) {
49
+ return !!value && typeof value === "object";
50
+ }
51
+ //#endregion
52
+ exports.resolveConfig = resolveConfig;
53
+ exports.toInlineConfig = toInlineConfig;
54
+ exports.toScopeOptions = toScopeOptions;
@@ -0,0 +1,51 @@
1
+ import { RELEASE_CONFIG_FILENAMES } from "./constants.mjs";
2
+ import { existsSync, readFileSync } from "node:fs";
3
+ import { join } from "node:path";
4
+ import { pathToFileURL } from "node:url";
5
+ //#region src/config.ts
6
+ /**
7
+ * Resolves repository release configuration from `package.json`, `release.config.*`,
8
+ * and inline overrides using the public precedence rules.
9
+ */
10
+ async function resolveConfig(cwd, inline) {
11
+ const root = cwd ?? process.cwd();
12
+ const fromPackage = loadPackageJsonConfig(root);
13
+ const fromFile = await loadFileConfig(root);
14
+ return {
15
+ ...fromPackage,
16
+ ...fromFile,
17
+ ...inline ?? {}
18
+ };
19
+ }
20
+ /** Converts repository configuration to executor-ready release options. */
21
+ function toScopeOptions(config) {
22
+ const options = { ...config };
23
+ delete options.changelogFile;
24
+ return options;
25
+ }
26
+ /** Extracts inline overrides from high-level run options. */
27
+ function toInlineConfig(options) {
28
+ const config = { ...options };
29
+ delete config.cwd;
30
+ delete config.dry;
31
+ delete config.reporter;
32
+ return config;
33
+ }
34
+ function loadPackageJsonConfig(cwd) {
35
+ const file = join(cwd, "package.json");
36
+ if (!existsSync(file)) return {};
37
+ const content = JSON.parse(readFileSync(file, "utf-8"));
38
+ return isRecord(content.release) ? content.release : {};
39
+ }
40
+ async function loadFileConfig(cwd) {
41
+ const configFile = RELEASE_CONFIG_FILENAMES.map((file) => join(cwd, file)).find((file) => existsSync(file));
42
+ if (!configFile) return {};
43
+ const module = await import(pathToFileURL(configFile).href);
44
+ const config = module.default ?? module;
45
+ return isRecord(config) ? config : {};
46
+ }
47
+ function isRecord(value) {
48
+ return !!value && typeof value === "object";
49
+ }
50
+ //#endregion
51
+ export { resolveConfig, toInlineConfig, toScopeOptions };
@@ -0,0 +1,16 @@
1
+ //#region src/constants.ts
2
+ var DEFAULT_CHANGELOG_FILE = "CHANGELOG.md";
3
+ var DEFAULT_RELEASE_PREFIX = "chore(release): ";
4
+ var DEFAULT_RELEASE_MODE = "sync";
5
+ var DEFAULT_DEPENDENCY_POLICY_INTERNAL = "preserve";
6
+ var RELEASE_CONFIG_FILENAMES = [
7
+ "release.config.ts",
8
+ "release.config.mjs",
9
+ "release.config.js"
10
+ ];
11
+ //#endregion
12
+ exports.DEFAULT_CHANGELOG_FILE = DEFAULT_CHANGELOG_FILE;
13
+ exports.DEFAULT_DEPENDENCY_POLICY_INTERNAL = DEFAULT_DEPENDENCY_POLICY_INTERNAL;
14
+ exports.DEFAULT_RELEASE_MODE = DEFAULT_RELEASE_MODE;
15
+ exports.DEFAULT_RELEASE_PREFIX = DEFAULT_RELEASE_PREFIX;
16
+ exports.RELEASE_CONFIG_FILENAMES = RELEASE_CONFIG_FILENAMES;
@@ -0,0 +1,12 @@
1
+ //#region src/constants.ts
2
+ var DEFAULT_CHANGELOG_FILE = "CHANGELOG.md";
3
+ var DEFAULT_RELEASE_PREFIX = "chore(release): ";
4
+ var DEFAULT_RELEASE_MODE = "sync";
5
+ var DEFAULT_DEPENDENCY_POLICY_INTERNAL = "preserve";
6
+ var RELEASE_CONFIG_FILENAMES = [
7
+ "release.config.ts",
8
+ "release.config.mjs",
9
+ "release.config.js"
10
+ ];
11
+ //#endregion
12
+ export { DEFAULT_CHANGELOG_FILE, DEFAULT_DEPENDENCY_POLICY_INTERNAL, DEFAULT_RELEASE_MODE, DEFAULT_RELEASE_PREFIX, RELEASE_CONFIG_FILENAMES };
@@ -0,0 +1,192 @@
1
+ const require_runtime = require("./_virtual/_rolldown/runtime.cjs");
2
+ const require_reporter = require("./reporter.cjs");
3
+ const require_constants = require("./constants.cjs");
4
+ const require_plan = require("./plan.cjs");
5
+ let node_path = require("node:path");
6
+ let _modulify_conventional_changelog = require("@modulify/conventional-changelog");
7
+ let _modulify_pkg = require("@modulify/pkg");
8
+ let _modulify_conventional_bump = require("@modulify/conventional-bump");
9
+ let semver = require("semver");
10
+ semver = require_runtime.__toESM(semver, 1);
11
+ //#region src/execute.ts
12
+ async function runScope(runtime, scope, options, reporting) {
13
+ const slices = [];
14
+ for (const slice of scope.slices) {
15
+ if (reporting) await require_reporter.reportSliceStart(reporting.reporter, require_plan.toSlice(slice, runtime.cwd), reporting.context);
16
+ const result = await executeSlice(runtime, slice, options);
17
+ if (reporting) await require_reporter.reportSliceSuccess(reporting.reporter, result, reporting.context);
18
+ slices.push(result);
19
+ }
20
+ const files = require_plan.uniqueStrings(slices.flatMap((slice) => slice.files));
21
+ const changed = slices.some((slice) => slice.changed);
22
+ return {
23
+ mode: scope.mode,
24
+ changed,
25
+ dry: runtime.dry,
26
+ packages: scope.packages.map((pkg) => require_plan.toScopePackage(pkg, runtime.cwd)),
27
+ affected: scope.affected.map((pkg) => require_plan.toScopePackage(pkg, runtime.cwd)),
28
+ slices,
29
+ files
30
+ };
31
+ }
32
+ async function executeSlice(runtime, slice, options) {
33
+ const normalizedSlice = {
34
+ ...slice,
35
+ packages: require_plan.uniquePackages(slice.packages)
36
+ };
37
+ const currentVersion = resolveSliceCurrentVersion(normalizedSlice, runtime.cwd);
38
+ const releaseMeta = await collectSliceMeta(runtime, normalizedSlice);
39
+ const release = (0, _modulify_conventional_bump.resolveNextVersion)(currentVersion, {
40
+ recommendation: releaseMeta.recommendation,
41
+ type: options.releaseAs,
42
+ prerelease: options.prerelease,
43
+ preMajor: options.releaseAs ? false : options.preMajor ?? isPreMajorVersion(currentVersion)
44
+ });
45
+ const releaseType = String(release.type);
46
+ const nextVersion = release.version;
47
+ const base = require_plan.toSlice(normalizedSlice, runtime.cwd);
48
+ if (nextVersion === currentVersion) return {
49
+ ...base,
50
+ currentVersion,
51
+ nextVersion,
52
+ releaseType,
53
+ changed: false,
54
+ dry: runtime.dry,
55
+ files: []
56
+ };
57
+ const files = await applySlice(runtime, normalizedSlice, nextVersion, options, (0, _modulify_conventional_changelog.renderChangelog)(nextVersion, {
58
+ notes: releaseMeta.notes,
59
+ url: await runtime.history.url()
60
+ }));
61
+ const context = createTagContext(normalizedSlice, nextVersion, releaseType, runtime.cwd);
62
+ const tag = options.tagName ? options.tagName(context) : createDefaultTagName(normalizedSlice, nextVersion, runtime.cwd);
63
+ if (runtime.dry) return {
64
+ ...base,
65
+ currentVersion,
66
+ nextVersion,
67
+ releaseType,
68
+ changed: true,
69
+ dry: true,
70
+ tag,
71
+ files
72
+ };
73
+ const messageContext = {
74
+ ...context,
75
+ tag
76
+ };
77
+ const commitMessage = options.commitMessage ? options.commitMessage(messageContext) : require_constants.DEFAULT_RELEASE_PREFIX + tag;
78
+ const tagMessage = options.tagMessage ? options.tagMessage(messageContext) : require_constants.DEFAULT_RELEASE_PREFIX + tag;
79
+ await runtime.git.add(files);
80
+ await runtime.git.commit({
81
+ files,
82
+ message: commitMessage
83
+ });
84
+ await runtime.git.tag({
85
+ name: tag,
86
+ message: tagMessage
87
+ });
88
+ return {
89
+ ...base,
90
+ currentVersion,
91
+ nextVersion,
92
+ releaseType,
93
+ changed: true,
94
+ dry: false,
95
+ files,
96
+ tag,
97
+ commitMessage,
98
+ tagMessage
99
+ };
100
+ }
101
+ async function applySlice(runtime, slice, nextVersion, options, changes) {
102
+ const bumpedPackageNames = slice.packages.reduce((all, pkg) => {
103
+ const name = pkg.manifest.name ?? pkg.name;
104
+ if (name) all.add(name);
105
+ return all;
106
+ }, /* @__PURE__ */ new Set());
107
+ const dependencyPolicy = options.dependencyPolicy ?? "preserve";
108
+ const files = [];
109
+ for (const pkg of slice.packages) {
110
+ const diff = { version: nextVersion };
111
+ const manifest = pkg.manifest;
112
+ if (hasDependencies(manifest.peerDependencies)) diff.peerDependencies = actualizeDependencies(manifest.peerDependencies, nextVersion, bumpedPackageNames, dependencyPolicy);
113
+ if (hasDependencies(manifest.dependencies)) diff.dependencies = actualizeDependencies(manifest.dependencies, nextVersion, bumpedPackageNames, dependencyPolicy);
114
+ if (hasDependencies(manifest.optionalDependencies)) diff.optionalDependencies = actualizeDependencies(manifest.optionalDependencies, nextVersion, bumpedPackageNames, dependencyPolicy);
115
+ if (hasDependencies(manifest.devDependencies)) diff.devDependencies = actualizeDependencies(manifest.devDependencies, nextVersion, bumpedPackageNames, dependencyPolicy);
116
+ files.push((0, node_path.relative)(runtime.cwd, (0, _modulify_pkg.update)(pkg.path, diff, runtime.dry)));
117
+ }
118
+ const installArgs = resolveInstallArgs(runtime, options.install);
119
+ if (!runtime.dry && installArgs) await runtime.sh.exec(runtime.packageManager.command, ["install", ...installArgs]);
120
+ if (!runtime.dry) await runtime.writeChangelog(changes);
121
+ files.push((0, node_path.relative)(runtime.cwd, (0, node_path.join)(runtime.cwd, runtime.packageManager.lockfile)));
122
+ files.push((0, node_path.relative)(runtime.cwd, (0, node_path.join)(runtime.cwd, runtime.changelogFile)));
123
+ return require_plan.uniqueStrings(files);
124
+ }
125
+ async function collectSliceMeta(runtime, slice) {
126
+ const result = await runtime.history.traverse({
127
+ ...slice.range,
128
+ traversers: [(0, _modulify_conventional_bump.createRecommendationAnalyzer)({ strict: true }), (0, _modulify_conventional_changelog.createChangelogCapacitor)()]
129
+ });
130
+ return {
131
+ recommendation: result.results.get("recommendation"),
132
+ notes: result.results.get("changelog")
133
+ };
134
+ }
135
+ function resolveInstallArgs(runtime, install) {
136
+ if (install === false) return null;
137
+ if (Array.isArray(install)) return install;
138
+ if (runtime.packageManager.command === "yarn") return ["--no-immutable"];
139
+ return [];
140
+ }
141
+ function createTagContext(slice, version, releaseType, cwd) {
142
+ return {
143
+ id: slice.id,
144
+ kind: slice.kind,
145
+ mode: slice.mode,
146
+ partition: slice.partition,
147
+ packages: slice.packages.map((pkg) => require_plan.toScopePackage(pkg, cwd)),
148
+ version,
149
+ releaseType
150
+ };
151
+ }
152
+ function resolveSliceCurrentVersion(slice, cwd) {
153
+ const versions = require_plan.uniqueStrings(slice.packages.map((pkg) => pkg.manifest.version ?? "0.0.0"));
154
+ if (slice.mode === "sync" && versions.length > 1) {
155
+ const packageList = slice.packages.map((pkg) => require_plan.packageIdentity(pkg, cwd)).join(", ");
156
+ throw new Error(`Sync release slice "${slice.id}" requires aligned package versions: ${packageList}`);
157
+ }
158
+ return versions[0];
159
+ }
160
+ function isPreMajorVersion(version) {
161
+ return semver.default.valid(version) ? semver.default.lt(version, "1.0.0") : false;
162
+ }
163
+ function createDefaultTagName(slice, version, cwd) {
164
+ if (slice.kind === "sync") return `v${version}`;
165
+ if (slice.partition) return `${slice.partition}@${version}`;
166
+ return `${require_plan.packageIdentity(slice.packages[0], cwd)}@${version}`;
167
+ }
168
+ function hasDependencies(dependencies) {
169
+ return !!dependencies && Object.keys(dependencies).length > 0;
170
+ }
171
+ function actualizeDependencies(dependencies, nextVersion, bumpedPackages, internalPolicy) {
172
+ return Object.keys(dependencies).reduce((all, name) => ({
173
+ ...all,
174
+ [name]: bumpedPackages.has(name) ? updateDependencyRange(dependencies[name], nextVersion, internalPolicy) : dependencies[name]
175
+ }), {});
176
+ }
177
+ function updateDependencyRange(current, nextVersion, policy) {
178
+ if (policy === "caret") return "^" + nextVersion;
179
+ if (policy === "exact") return nextVersion;
180
+ if (current.startsWith("workspace:")) {
181
+ const value = current.slice(10);
182
+ if (value === "*") return "workspace:*";
183
+ if (value.startsWith("^")) return `workspace:^${nextVersion}`;
184
+ if (value.startsWith("~")) return `workspace:~${nextVersion}`;
185
+ return `workspace:${nextVersion}`;
186
+ }
187
+ if (current.startsWith("^")) return "^" + nextVersion;
188
+ if (current.startsWith("~")) return "~" + nextVersion;
189
+ return nextVersion;
190
+ }
191
+ //#endregion
192
+ exports.runScope = runScope;
@@ -0,0 +1,190 @@
1
+ import { reportSliceStart, reportSliceSuccess } from "./reporter.mjs";
2
+ import { DEFAULT_RELEASE_PREFIX } from "./constants.mjs";
3
+ import { packageIdentity, toScopePackage, toSlice, uniquePackages, uniqueStrings } from "./plan.mjs";
4
+ import { join, relative } from "node:path";
5
+ import { createChangelogCapacitor, renderChangelog } from "@modulify/conventional-changelog";
6
+ import { update } from "@modulify/pkg";
7
+ import { createRecommendationAnalyzer, resolveNextVersion } from "@modulify/conventional-bump";
8
+ import semver from "semver";
9
+ //#region src/execute.ts
10
+ async function runScope(runtime, scope, options, reporting) {
11
+ const slices = [];
12
+ for (const slice of scope.slices) {
13
+ if (reporting) await reportSliceStart(reporting.reporter, toSlice(slice, runtime.cwd), reporting.context);
14
+ const result = await executeSlice(runtime, slice, options);
15
+ if (reporting) await reportSliceSuccess(reporting.reporter, result, reporting.context);
16
+ slices.push(result);
17
+ }
18
+ const files = uniqueStrings(slices.flatMap((slice) => slice.files));
19
+ const changed = slices.some((slice) => slice.changed);
20
+ return {
21
+ mode: scope.mode,
22
+ changed,
23
+ dry: runtime.dry,
24
+ packages: scope.packages.map((pkg) => toScopePackage(pkg, runtime.cwd)),
25
+ affected: scope.affected.map((pkg) => toScopePackage(pkg, runtime.cwd)),
26
+ slices,
27
+ files
28
+ };
29
+ }
30
+ async function executeSlice(runtime, slice, options) {
31
+ const normalizedSlice = {
32
+ ...slice,
33
+ packages: uniquePackages(slice.packages)
34
+ };
35
+ const currentVersion = resolveSliceCurrentVersion(normalizedSlice, runtime.cwd);
36
+ const releaseMeta = await collectSliceMeta(runtime, normalizedSlice);
37
+ const release = resolveNextVersion(currentVersion, {
38
+ recommendation: releaseMeta.recommendation,
39
+ type: options.releaseAs,
40
+ prerelease: options.prerelease,
41
+ preMajor: options.releaseAs ? false : options.preMajor ?? isPreMajorVersion(currentVersion)
42
+ });
43
+ const releaseType = String(release.type);
44
+ const nextVersion = release.version;
45
+ const base = toSlice(normalizedSlice, runtime.cwd);
46
+ if (nextVersion === currentVersion) return {
47
+ ...base,
48
+ currentVersion,
49
+ nextVersion,
50
+ releaseType,
51
+ changed: false,
52
+ dry: runtime.dry,
53
+ files: []
54
+ };
55
+ const files = await applySlice(runtime, normalizedSlice, nextVersion, options, renderChangelog(nextVersion, {
56
+ notes: releaseMeta.notes,
57
+ url: await runtime.history.url()
58
+ }));
59
+ const context = createTagContext(normalizedSlice, nextVersion, releaseType, runtime.cwd);
60
+ const tag = options.tagName ? options.tagName(context) : createDefaultTagName(normalizedSlice, nextVersion, runtime.cwd);
61
+ if (runtime.dry) return {
62
+ ...base,
63
+ currentVersion,
64
+ nextVersion,
65
+ releaseType,
66
+ changed: true,
67
+ dry: true,
68
+ tag,
69
+ files
70
+ };
71
+ const messageContext = {
72
+ ...context,
73
+ tag
74
+ };
75
+ const commitMessage = options.commitMessage ? options.commitMessage(messageContext) : DEFAULT_RELEASE_PREFIX + tag;
76
+ const tagMessage = options.tagMessage ? options.tagMessage(messageContext) : DEFAULT_RELEASE_PREFIX + tag;
77
+ await runtime.git.add(files);
78
+ await runtime.git.commit({
79
+ files,
80
+ message: commitMessage
81
+ });
82
+ await runtime.git.tag({
83
+ name: tag,
84
+ message: tagMessage
85
+ });
86
+ return {
87
+ ...base,
88
+ currentVersion,
89
+ nextVersion,
90
+ releaseType,
91
+ changed: true,
92
+ dry: false,
93
+ files,
94
+ tag,
95
+ commitMessage,
96
+ tagMessage
97
+ };
98
+ }
99
+ async function applySlice(runtime, slice, nextVersion, options, changes) {
100
+ const bumpedPackageNames = slice.packages.reduce((all, pkg) => {
101
+ const name = pkg.manifest.name ?? pkg.name;
102
+ if (name) all.add(name);
103
+ return all;
104
+ }, /* @__PURE__ */ new Set());
105
+ const dependencyPolicy = options.dependencyPolicy ?? "preserve";
106
+ const files = [];
107
+ for (const pkg of slice.packages) {
108
+ const diff = { version: nextVersion };
109
+ const manifest = pkg.manifest;
110
+ if (hasDependencies(manifest.peerDependencies)) diff.peerDependencies = actualizeDependencies(manifest.peerDependencies, nextVersion, bumpedPackageNames, dependencyPolicy);
111
+ if (hasDependencies(manifest.dependencies)) diff.dependencies = actualizeDependencies(manifest.dependencies, nextVersion, bumpedPackageNames, dependencyPolicy);
112
+ if (hasDependencies(manifest.optionalDependencies)) diff.optionalDependencies = actualizeDependencies(manifest.optionalDependencies, nextVersion, bumpedPackageNames, dependencyPolicy);
113
+ if (hasDependencies(manifest.devDependencies)) diff.devDependencies = actualizeDependencies(manifest.devDependencies, nextVersion, bumpedPackageNames, dependencyPolicy);
114
+ files.push(relative(runtime.cwd, update(pkg.path, diff, runtime.dry)));
115
+ }
116
+ const installArgs = resolveInstallArgs(runtime, options.install);
117
+ if (!runtime.dry && installArgs) await runtime.sh.exec(runtime.packageManager.command, ["install", ...installArgs]);
118
+ if (!runtime.dry) await runtime.writeChangelog(changes);
119
+ files.push(relative(runtime.cwd, join(runtime.cwd, runtime.packageManager.lockfile)));
120
+ files.push(relative(runtime.cwd, join(runtime.cwd, runtime.changelogFile)));
121
+ return uniqueStrings(files);
122
+ }
123
+ async function collectSliceMeta(runtime, slice) {
124
+ const result = await runtime.history.traverse({
125
+ ...slice.range,
126
+ traversers: [createRecommendationAnalyzer({ strict: true }), createChangelogCapacitor()]
127
+ });
128
+ return {
129
+ recommendation: result.results.get("recommendation"),
130
+ notes: result.results.get("changelog")
131
+ };
132
+ }
133
+ function resolveInstallArgs(runtime, install) {
134
+ if (install === false) return null;
135
+ if (Array.isArray(install)) return install;
136
+ if (runtime.packageManager.command === "yarn") return ["--no-immutable"];
137
+ return [];
138
+ }
139
+ function createTagContext(slice, version, releaseType, cwd) {
140
+ return {
141
+ id: slice.id,
142
+ kind: slice.kind,
143
+ mode: slice.mode,
144
+ partition: slice.partition,
145
+ packages: slice.packages.map((pkg) => toScopePackage(pkg, cwd)),
146
+ version,
147
+ releaseType
148
+ };
149
+ }
150
+ function resolveSliceCurrentVersion(slice, cwd) {
151
+ const versions = uniqueStrings(slice.packages.map((pkg) => pkg.manifest.version ?? "0.0.0"));
152
+ if (slice.mode === "sync" && versions.length > 1) {
153
+ const packageList = slice.packages.map((pkg) => packageIdentity(pkg, cwd)).join(", ");
154
+ throw new Error(`Sync release slice "${slice.id}" requires aligned package versions: ${packageList}`);
155
+ }
156
+ return versions[0];
157
+ }
158
+ function isPreMajorVersion(version) {
159
+ return semver.valid(version) ? semver.lt(version, "1.0.0") : false;
160
+ }
161
+ function createDefaultTagName(slice, version, cwd) {
162
+ if (slice.kind === "sync") return `v${version}`;
163
+ if (slice.partition) return `${slice.partition}@${version}`;
164
+ return `${packageIdentity(slice.packages[0], cwd)}@${version}`;
165
+ }
166
+ function hasDependencies(dependencies) {
167
+ return !!dependencies && Object.keys(dependencies).length > 0;
168
+ }
169
+ function actualizeDependencies(dependencies, nextVersion, bumpedPackages, internalPolicy) {
170
+ return Object.keys(dependencies).reduce((all, name) => ({
171
+ ...all,
172
+ [name]: bumpedPackages.has(name) ? updateDependencyRange(dependencies[name], nextVersion, internalPolicy) : dependencies[name]
173
+ }), {});
174
+ }
175
+ function updateDependencyRange(current, nextVersion, policy) {
176
+ if (policy === "caret") return "^" + nextVersion;
177
+ if (policy === "exact") return nextVersion;
178
+ if (current.startsWith("workspace:")) {
179
+ const value = current.slice(10);
180
+ if (value === "*") return "workspace:*";
181
+ if (value.startsWith("^")) return `workspace:^${nextVersion}`;
182
+ if (value.startsWith("~")) return `workspace:~${nextVersion}`;
183
+ return `workspace:${nextVersion}`;
184
+ }
185
+ if (current.startsWith("^")) return "^" + nextVersion;
186
+ if (current.startsWith("~")) return "~" + nextVersion;
187
+ return nextVersion;
188
+ }
189
+ //#endregion
190
+ export { runScope };