@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.
package/dist/index.mjs CHANGED
@@ -1,712 +1,53 @@
1
- import { existsSync, readFileSync } from "node:fs";
2
- import { join, relative } from "node:path";
3
- import { pathToFileURL } from "node:url";
4
- import { Client, createChangesetTraverser } from "@modulify/conventional-git";
5
- import { writeChangelog, renderChangelog, createChangelogCapacitor } from "@modulify/conventional-changelog";
6
- import { GitCommander } from "@modulify/git-toolkit";
7
- import { Runner } from "@modulify/git-toolkit/shell";
8
- import { read, walk, update } from "@modulify/pkg";
9
- import { resolveNextVersion, createRecommendationAnalyzer } from "@modulify/conventional-bump";
10
- function createRunContext({
11
- cwd,
12
- dry
13
- }) {
14
- return { cwd, dry };
15
- }
16
- async function reportStart(reporter, context) {
17
- await reporter?.onStart?.(context);
18
- }
19
- async function reportScope(reporter, scope, context) {
20
- await reporter?.onScope?.(scope, context);
21
- }
22
- async function reportSliceStart(reporter, slice, context) {
23
- await reporter?.onSliceStart?.(slice, context);
24
- }
25
- async function reportSliceSuccess(reporter, slice, context) {
26
- await reporter?.onSliceSuccess?.(slice, context);
27
- }
28
- async function reportSuccess(reporter, result, context) {
29
- await reporter?.onSuccess?.(result, context);
30
- }
31
- async function reportError(reporter, error, context) {
32
- await reporter?.onError?.(error, context);
33
- }
34
- const DEFAULT_CHANGELOG_FILE = "CHANGELOG.md";
35
- const DEFAULT_RELEASE_PREFIX = "chore(release): ";
36
- const DEFAULT_RELEASE_MODE = "sync";
37
- const DEFAULT_DEPENDENCY_POLICY_INTERNAL = "preserve";
38
- const RELEASE_CONFIG_FILENAMES = [
39
- "release.config.ts",
40
- "release.config.mjs",
41
- "release.config.js"
42
- ];
43
- async function resolveConfig(cwd, inline) {
44
- const root = cwd ?? process.cwd();
45
- const fromPackage = loadPackageJsonConfig(root);
46
- const fromFile = await loadFileConfig(root);
47
- return {
48
- ...fromPackage,
49
- ...fromFile,
50
- ...inline ?? {}
51
- };
52
- }
53
- function toScopeOptions(config) {
54
- const options = { ...config };
55
- delete options.changelogFile;
56
- return options;
57
- }
58
- function toInlineConfig(options) {
59
- const config = { ...options };
60
- delete config.cwd;
61
- delete config.dry;
62
- delete config.reporter;
63
- return config;
64
- }
65
- function loadPackageJsonConfig(cwd) {
66
- const file = join(cwd, "package.json");
67
- if (!existsSync(file)) {
68
- return {};
69
- }
70
- const content = JSON.parse(readFileSync(file, "utf-8"));
71
- return isRecord(content.release) ? content.release : {};
72
- }
73
- async function loadFileConfig(cwd) {
74
- const configFile = RELEASE_CONFIG_FILENAMES.map((file) => join(cwd, file)).find((file) => existsSync(file));
75
- if (!configFile) {
76
- return {};
77
- }
78
- const module = await import(pathToFileURL(configFile).href);
79
- const config = module.default ?? module;
80
- return isRecord(config) ? config : {};
81
- }
82
- function isRecord(value) {
83
- return !!value && typeof value === "object";
84
- }
85
- function createRuntime({
86
- cwd = process.cwd(),
87
- dry = false,
88
- changelogFile = DEFAULT_CHANGELOG_FILE
89
- } = {}) {
90
- const sh = new Runner(cwd);
91
- return {
92
- cwd,
93
- dry,
94
- changelogFile,
95
- packageManager: resolvePackageManager(cwd),
96
- history: new Client({ cwd }),
97
- writeChangelog: (changes) => writeChangelog(changes, {
98
- file: dry ? void 0 : join(cwd, changelogFile)
99
- }),
100
- sh,
101
- git: createGit(sh)
102
- };
103
- }
104
- function createGit(sh) {
105
- const git = new GitCommander({ sh });
106
- return {
107
- add: (files) => git.add(files),
108
- commit: (options) => git.commit(options),
109
- tag: (options) => git.tag(options)
110
- };
111
- }
112
- function resolvePackageManager(cwd) {
113
- const command = readPackageManager(cwd) ?? inferPackageManagerFromLockfile(cwd) ?? "npm";
114
- return {
115
- command,
116
- lockfile: resolveLockfile(cwd, command)
117
- };
118
- }
119
- function readPackageManager(cwd) {
120
- const file = join(cwd, "package.json");
121
- if (!existsSync(file)) {
122
- return null;
123
- }
124
- const content = JSON.parse(readFileSync(file, "utf-8"));
125
- if (typeof content.packageManager !== "string" || content.packageManager === "") {
126
- return null;
127
- }
128
- const [name] = content.packageManager.split("@");
129
- return isPackageManagerName(name) ? name : null;
130
- }
131
- function inferPackageManagerFromLockfile(cwd) {
132
- if (existsSync(join(cwd, "yarn.lock"))) return "yarn";
133
- if (existsSync(join(cwd, "pnpm-lock.yaml"))) return "pnpm";
134
- if (existsSync(join(cwd, "package-lock.json"))) return "npm";
135
- if (existsSync(join(cwd, "bun.lock"))) return "bun";
136
- if (existsSync(join(cwd, "bun.lockb"))) return "bun";
137
- return null;
138
- }
139
- function resolveLockfile(cwd, command) {
140
- if (command === "bun" && existsSync(join(cwd, "bun.lockb"))) {
141
- return "bun.lockb";
142
- }
143
- return {
144
- yarn: "yarn.lock",
145
- pnpm: "pnpm-lock.yaml",
146
- npm: "package-lock.json",
147
- bun: "bun.lock"
148
- }[command];
149
- }
150
- function isPackageManagerName(value) {
151
- return value === "yarn" || value === "pnpm" || value === "npm" || value === "bun";
152
- }
153
- function toScope(scope, cwd) {
154
- return {
155
- mode: scope.mode,
156
- packages: scope.packages.map((pkg) => toScopePackage(pkg, cwd)),
157
- affected: scope.affected.map((pkg) => toScopePackage(pkg, cwd)),
158
- slices: scope.slices.map((slice) => toSlice(slice, cwd))
159
- };
160
- }
161
- async function discover(runtime, options) {
162
- const root = read(runtime.cwd);
163
- const packages = [];
164
- await walk([root], async (pkg) => {
165
- packages.push(pkg);
166
- });
167
- const discovered = sortPackages(
168
- uniquePackages(
169
- applyWorkspaceFilters(packages, runtime.cwd, options.workspaces)
170
- ),
171
- runtime.cwd
172
- );
173
- const mode = options.mode ?? DEFAULT_RELEASE_MODE;
174
- const affectedPaths = mode === "hybrid" ? null : await detectAffectedPackages({
175
- cwd: runtime.cwd,
176
- root,
177
- packages: discovered,
178
- history: runtime.history,
179
- range: {
180
- fromTag: options.fromTag,
181
- tagPrefix: options.tagPrefix
182
- }
183
- });
184
- const affected = affectedPaths ? sortPackages(
185
- uniquePackages(
186
- discovered.filter((pkg) => affectedPaths.has(pkg.path))
187
- ),
188
- runtime.cwd
189
- ) : [];
190
- const slices = mode === "hybrid" ? await createHybridSlices({
191
- root,
192
- packages: discovered,
193
- cwd: runtime.cwd,
194
- history: runtime.history,
195
- fromTag: options.fromTag,
196
- tagPrefix: options.tagPrefix,
197
- partitions: options.partitions
198
- }) : createSlices({
199
- mode,
200
- affected,
201
- cwd: runtime.cwd,
202
- fromTag: options.fromTag,
203
- tagPrefix: options.tagPrefix
204
- });
205
- const discoveredAffected = mode === "hybrid" ? sortPackages(
206
- uniquePackages(
207
- slices.flatMap((slice) => slice.packages)
208
- ),
209
- runtime.cwd
210
- ) : affected;
211
- return {
212
- mode,
213
- packages: discovered,
214
- affected: discoveredAffected,
215
- slices
216
- };
217
- }
218
- function toScopePackage(pkg, cwd) {
219
- return {
220
- name: pkg.manifest.name ?? pkg.name,
221
- version: pkg.manifest.version,
222
- path: toPublicPath(pkg, cwd)
223
- };
224
- }
225
- function toSlice(slice, cwd) {
226
- return {
227
- id: slice.id,
228
- kind: slice.kind,
229
- mode: slice.mode,
230
- partition: slice.partition,
231
- packages: slice.packages.map((pkg) => toScopePackage(pkg, cwd)),
232
- range: slice.range
233
- };
234
- }
235
- function uniquePackages(packages) {
236
- const seen = /* @__PURE__ */ new Set();
237
- return packages.filter((pkg) => {
238
- if (seen.has(pkg.path)) {
239
- return false;
240
- }
241
- seen.add(pkg.path);
242
- return true;
243
- });
244
- }
245
- function uniqueStrings(values) {
246
- return [...new Set(values)];
247
- }
248
- function packageIdentity(pkg, cwd) {
249
- const name = pkg.manifest.name ?? pkg.name;
250
- if (name) {
251
- return name;
252
- }
253
- const path = packagePath(pkg, cwd);
254
- return path === "" || path === "." ? "root" : path;
255
- }
256
- function createSlices({
257
- mode,
258
- affected,
259
- cwd,
260
- fromTag,
261
- tagPrefix
262
- }) {
263
- const touched = affected;
264
- if (mode === "sync") {
265
- return touched.length ? [{
266
- id: "sync:default",
267
- kind: "sync",
268
- mode: "sync",
269
- packages: touched,
270
- range: {
271
- fromTag,
272
- tagPrefix
273
- }
274
- }] : [];
275
- }
276
- return touched.map((pkg) => ({
277
- id: `async:${packageIdentity(pkg, cwd)}`,
278
- kind: "async",
279
- mode: "async",
280
- packages: [pkg],
281
- range: {
282
- fromTag,
283
- tagPrefix
284
- }
285
- }));
286
- }
287
- async function createHybridSlices({
288
- root,
289
- packages,
290
- cwd,
291
- history,
292
- fromTag,
293
- tagPrefix,
294
- partitions
295
- }) {
296
- const partitionEntries = Object.entries(partitions ?? {}).sort(([a], [b]) => a.localeCompare(b));
297
- const partitioned = [];
298
- const usedPaths = /* @__PURE__ */ new Set();
299
- for (const [partition, definition] of partitionEntries) {
300
- const matched = sortPackages(
301
- packages.filter((pkg) => {
302
- if (usedPaths.has(pkg.path)) {
303
- return false;
304
- }
305
- return definition.workspaces.some((selector) => matchesPackageSelector(pkg, cwd, selector));
306
- }),
307
- cwd
308
- );
309
- for (const pkg of matched) {
310
- usedPaths.add(pkg.path);
311
- }
312
- const affectedPaths = await detectAffectedPackages({
313
- cwd,
314
- root,
315
- packages: matched,
316
- history,
317
- range: resolvePartitionRange({ fromTag, tagPrefix, partition: definition })
318
- });
319
- const scoped = matched.filter((pkg) => affectedPaths.has(pkg.path));
320
- if (!scoped.length) {
321
- continue;
322
- }
323
- const resolvedRange = resolvePartitionRange({ fromTag, tagPrefix, partition: definition });
324
- if (definition.mode === "sync") {
325
- partitioned.push({
326
- id: `partition:${partition}`,
327
- kind: "partition",
328
- mode: "sync",
329
- partition,
330
- packages: scoped,
331
- range: resolvedRange
332
- });
333
- continue;
334
- }
335
- partitioned.push(...scoped.map((pkg) => ({
336
- id: `partition:${partition}:${packageIdentity(pkg, cwd)}`,
337
- kind: "partition",
338
- mode: "async",
339
- partition,
340
- packages: [pkg],
341
- range: resolvedRange
342
- })));
343
- }
344
- const fallbackCandidates = sortPackages(
345
- packages.filter((pkg) => !usedPaths.has(pkg.path)),
346
- cwd
347
- );
348
- const fallbackPaths = await detectAffectedPackages({
349
- cwd,
350
- root,
351
- packages: fallbackCandidates,
352
- history,
353
- range: {
354
- fromTag,
355
- tagPrefix
356
- }
357
- });
358
- const remainder = fallbackCandidates.filter((pkg) => fallbackPaths.has(pkg.path));
359
- const fallback = remainder.map((pkg) => ({
360
- id: `hybrid:${packageIdentity(pkg, cwd)}`,
361
- kind: "async",
362
- mode: "async",
363
- packages: [pkg],
364
- range: {
365
- fromTag,
366
- tagPrefix
367
- }
368
- }));
369
- return [...partitioned, ...fallback];
370
- }
371
- function resolvePartitionRange({
372
- fromTag,
373
- tagPrefix,
374
- partition
375
- }) {
376
- return {
377
- fromTag: partition.fromTag ?? fromTag,
378
- tagPrefix: partition.tagPrefix ?? tagPrefix
379
- };
380
- }
381
- async function detectAffectedPackages({
382
- cwd,
383
- root,
384
- packages,
385
- history,
386
- range
387
- }) {
388
- const touched = await readCommitRangePaths(history, range);
389
- if (touched === null) {
390
- return new Set(packages.map((pkg) => pkg.path));
391
- }
392
- if (!touched.length) {
393
- return /* @__PURE__ */ new Set();
394
- }
395
- const normalizedRoot = normalizePath(relative(cwd, root.path));
396
- const children = packages.filter((pkg) => pkg.path !== root.path).map((pkg) => ({
397
- packagePath: pkg.path,
398
- relativePath: normalizePath(relative(cwd, pkg.path))
399
- })).sort((a, b) => b.relativePath.length - a.relativePath.length);
400
- const affected = /* @__PURE__ */ new Set();
401
- for (const path of touched.map(normalizePath)) {
402
- if (!isPathInside(path, normalizedRoot)) continue;
403
- const child = children.find((entry) => isPathInside(path, entry.relativePath));
404
- affected.add(child?.packagePath ?? root.path);
405
- }
406
- return affected;
407
- }
408
- function applyWorkspaceFilters(packages, cwd, selector) {
409
- if (!selector?.include?.length && !selector?.exclude?.length) {
410
- return packages;
411
- }
412
- return packages.filter((pkg) => {
413
- const included = selector.include?.length ? selector.include.some((entry) => matchesPackageSelector(pkg, cwd, entry)) : true;
414
- if (!included) {
415
- return false;
416
- }
417
- return !(selector.exclude?.some((entry) => matchesPackageSelector(pkg, cwd, entry)) ?? false);
418
- });
419
- }
420
- function sortPackages(packages, cwd) {
421
- return [...packages].sort((a, b) => packagePath(a, cwd).localeCompare(packagePath(b, cwd)));
422
- }
423
- function packagePath(pkg, cwd) {
424
- return normalizePath(relative(cwd, pkg.path));
425
- }
426
- function toPublicPath(pkg, cwd) {
427
- return packagePath(pkg, cwd) || ".";
428
- }
429
- function matchesPackageSelector(pkg, cwd, selector) {
430
- const name = pkg.manifest.name ?? pkg.name ?? "";
431
- const path = packagePath(pkg, cwd);
432
- return matchesGlob(name, selector) || matchesGlob(path, selector);
433
- }
434
- function matchesGlob(input, pattern) {
435
- if (!pattern) return false;
436
- if (pattern === "*") return true;
437
- const escaped = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*\*/g, "__DOUBLE_STAR__").replace(/\*/g, "[^/]*").replace(/__DOUBLE_STAR__/g, ".*");
438
- return new RegExp(`^${escaped}$`).test(input);
439
- }
440
- async function readCommitRangePaths(history, range) {
441
- try {
442
- const result = await history.traverse({
443
- fromTag: range.fromTag,
444
- tagPrefix: range.tagPrefix,
445
- changeset: true,
446
- traversers: [createChangesetTraverser()]
447
- });
448
- return result.results.get("changeset").paths;
449
- } catch {
450
- return null;
451
- }
452
- }
453
- function normalizePath(path) {
454
- return path.replace(/\\/g, "/");
455
- }
456
- function isPathInside(path, root) {
457
- return !root || root === "." || root === path || path.startsWith(`${root}/`);
458
- }
459
- async function runScope(runtime, scope, options, reporting) {
460
- const slices = [];
461
- for (const slice of scope.slices) {
462
- if (reporting) {
463
- await reportSliceStart(reporting.reporter, toSlice(slice, runtime.cwd), reporting.context);
464
- }
465
- const result = await executeSlice(runtime, slice, options);
466
- if (reporting) {
467
- await reportSliceSuccess(reporting.reporter, result, reporting.context);
468
- }
469
- slices.push(result);
470
- }
471
- const files = uniqueStrings(
472
- slices.flatMap((slice) => slice.files)
473
- );
474
- const changed = slices.some((slice) => slice.changed);
475
- return {
476
- mode: scope.mode,
477
- changed,
478
- dry: runtime.dry,
479
- packages: scope.packages.map((pkg) => toScopePackage(pkg, runtime.cwd)),
480
- affected: scope.affected.map((pkg) => toScopePackage(pkg, runtime.cwd)),
481
- slices,
482
- files
483
- };
484
- }
485
- async function executeSlice(runtime, slice, options) {
486
- const normalizedSlice = {
487
- ...slice,
488
- packages: uniquePackages(slice.packages)
489
- };
490
- const currentVersion = resolveSliceCurrentVersion(normalizedSlice, runtime.cwd);
491
- const releaseMeta = await collectSliceMeta(runtime, normalizedSlice);
492
- const release = resolveNextVersion(currentVersion, {
493
- recommendation: releaseMeta.recommendation,
494
- type: options.releaseAs,
495
- prerelease: options.prerelease
496
- });
497
- const releaseType = String(release.type);
498
- const nextVersion = release.version;
499
- const base = toSlice(normalizedSlice, runtime.cwd);
500
- if (nextVersion === currentVersion) {
501
- return {
502
- ...base,
503
- currentVersion,
504
- nextVersion,
505
- releaseType,
506
- changed: false,
507
- dry: runtime.dry,
508
- files: []
509
- };
510
- }
511
- const changes = renderChangelog(nextVersion, {
512
- notes: releaseMeta.notes,
513
- url: await runtime.history.url()
514
- });
515
- const files = await applySlice(runtime, normalizedSlice, nextVersion, options, changes);
516
- const context = createTagContext(normalizedSlice, nextVersion, releaseType, runtime.cwd);
517
- const tag = options.tagName ? options.tagName(context) : createDefaultTagName(normalizedSlice, nextVersion, runtime.cwd);
518
- if (runtime.dry) {
519
- return {
520
- ...base,
521
- currentVersion,
522
- nextVersion,
523
- releaseType,
524
- changed: true,
525
- dry: true,
526
- tag,
527
- files
528
- };
529
- }
530
- const messageContext = { ...context, tag };
531
- const commitMessage = options.commitMessage ? options.commitMessage(messageContext) : DEFAULT_RELEASE_PREFIX + tag;
532
- const tagMessage = options.tagMessage ? options.tagMessage(messageContext) : DEFAULT_RELEASE_PREFIX + tag;
533
- await runtime.git.add(files);
534
- await runtime.git.commit({ files, message: commitMessage });
535
- await runtime.git.tag({ name: tag, message: tagMessage });
536
- return {
537
- ...base,
538
- currentVersion,
539
- nextVersion,
540
- releaseType,
541
- changed: true,
542
- dry: false,
543
- files,
544
- tag,
545
- commitMessage,
546
- tagMessage
547
- };
548
- }
549
- async function applySlice(runtime, slice, nextVersion, options, changes) {
550
- const bumpedPackageNames = slice.packages.reduce((all, pkg) => {
551
- const name = pkg.manifest.name ?? pkg.name;
552
- if (name) {
553
- all.add(name);
554
- }
555
- return all;
556
- }, /* @__PURE__ */ new Set());
557
- const dependencyPolicy = options.dependencyPolicy ?? DEFAULT_DEPENDENCY_POLICY_INTERNAL;
558
- const files = [];
559
- for (const pkg of slice.packages) {
560
- const diff = { version: nextVersion };
561
- const manifest = pkg.manifest;
562
- if (hasDependencies(manifest.peerDependencies)) {
563
- diff.peerDependencies = actualizeDependencies(manifest.peerDependencies, nextVersion, bumpedPackageNames, dependencyPolicy);
564
- }
565
- if (hasDependencies(manifest.dependencies)) {
566
- diff.dependencies = actualizeDependencies(manifest.dependencies, nextVersion, bumpedPackageNames, dependencyPolicy);
567
- }
568
- if (hasDependencies(manifest.optionalDependencies)) {
569
- diff.optionalDependencies = actualizeDependencies(manifest.optionalDependencies, nextVersion, bumpedPackageNames, dependencyPolicy);
570
- }
571
- if (hasDependencies(manifest.devDependencies)) {
572
- diff.devDependencies = actualizeDependencies(manifest.devDependencies, nextVersion, bumpedPackageNames, dependencyPolicy);
573
- }
574
- files.push(relative(runtime.cwd, update(pkg.path, diff, runtime.dry)));
575
- }
576
- const installArgs = resolveInstallArgs(runtime, options.install);
577
- if (!runtime.dry && installArgs) {
578
- await runtime.sh.exec(runtime.packageManager.command, ["install", ...installArgs]);
579
- }
580
- if (!runtime.dry) {
581
- await runtime.writeChangelog(changes);
582
- }
583
- files.push(relative(runtime.cwd, join(runtime.cwd, runtime.packageManager.lockfile)));
584
- files.push(relative(runtime.cwd, join(runtime.cwd, runtime.changelogFile)));
585
- return uniqueStrings(files);
586
- }
587
- async function collectSliceMeta(runtime, slice) {
588
- const result = await runtime.history.traverse({
589
- ...slice.range,
590
- traversers: [createRecommendationAnalyzer({
591
- strict: true
592
- }), createChangelogCapacitor()]
593
- });
594
- return {
595
- recommendation: result.results.get("recommendation"),
596
- notes: result.results.get("changelog")
597
- };
598
- }
599
- function resolveInstallArgs(runtime, install) {
600
- if (install === false) {
601
- return null;
602
- }
603
- if (Array.isArray(install)) {
604
- return install;
605
- }
606
- if (runtime.packageManager.command === "yarn") {
607
- return ["--no-immutable"];
608
- }
609
- return [];
610
- }
611
- function createTagContext(slice, version, releaseType, cwd) {
612
- return {
613
- id: slice.id,
614
- kind: slice.kind,
615
- mode: slice.mode,
616
- partition: slice.partition,
617
- packages: slice.packages.map((pkg) => toScopePackage(pkg, cwd)),
618
- version,
619
- releaseType
620
- };
621
- }
622
- function resolveSliceCurrentVersion(slice, cwd) {
623
- const versions = uniqueStrings(
624
- slice.packages.map((pkg) => pkg.manifest.version ?? "0.0.0")
625
- );
626
- if (slice.mode === "sync" && versions.length > 1) {
627
- const packageList = slice.packages.map((pkg) => packageIdentity(pkg, cwd)).join(", ");
628
- throw new Error(`Sync release slice "${slice.id}" requires aligned package versions: ${packageList}`);
629
- }
630
- return versions[0];
631
- }
632
- function createDefaultTagName(slice, version, cwd) {
633
- if (slice.kind === "sync") {
634
- return `v${version}`;
635
- }
636
- if (slice.partition) {
637
- return `${slice.partition}@${version}`;
638
- }
639
- const identity = packageIdentity(slice.packages[0], cwd);
640
- return `${identity}@${version}`;
641
- }
642
- function hasDependencies(dependencies) {
643
- return !!dependencies && Object.keys(dependencies).length > 0;
644
- }
645
- function actualizeDependencies(dependencies, nextVersion, bumpedPackages, internalPolicy) {
646
- return Object.keys(dependencies).reduce((all, name) => ({
647
- ...all,
648
- [name]: bumpedPackages.has(name) ? updateDependencyRange(dependencies[name], nextVersion, internalPolicy) : dependencies[name]
649
- }), {});
650
- }
651
- function updateDependencyRange(current, nextVersion, policy) {
652
- if (policy === "caret") return "^" + nextVersion;
653
- if (policy === "exact") return nextVersion;
654
- if (current.startsWith("workspace:")) {
655
- const value = current.slice("workspace:".length);
656
- if (value === "*") return "workspace:*";
657
- if (value.startsWith("^")) return `workspace:^${nextVersion}`;
658
- if (value.startsWith("~")) return `workspace:~${nextVersion}`;
659
- return `workspace:${nextVersion}`;
660
- }
661
- if (current.startsWith("^")) return "^" + nextVersion;
662
- if (current.startsWith("~")) return "~" + nextVersion;
663
- return nextVersion;
664
- }
1
+ import { createRunContext, reportError, reportScope, reportStart, reportSuccess } from "./reporter.mjs";
2
+ import "./constants.mjs";
3
+ import { resolveConfig, toInlineConfig, toScopeOptions } from "./config.mjs";
4
+ import { createRuntime } from "./runtime.mjs";
5
+ import { discover, toScope } from "./plan.mjs";
6
+ import { runScope } from "./execute.mjs";
7
+ //#region src/index.ts
8
+ /** Resolves config, creates a runtime, and executes the release in one high-level call. */
665
9
  async function run(options = {}) {
666
- const inline = toInlineConfig(options);
667
- const cwd = options.cwd ?? process.cwd();
668
- const context = createRunContext({
669
- cwd,
670
- dry: options.dry ?? false
671
- });
672
- try {
673
- await reportStart(options.reporter, context);
674
- const config = await resolveConfig(cwd, inline);
675
- const scopeOptions = toScopeOptions(config);
676
- const runtime = createRuntime({
677
- cwd,
678
- dry: context.dry,
679
- changelogFile: config.changelogFile ?? DEFAULT_CHANGELOG_FILE
680
- });
681
- const scope = await discover(runtime, scopeOptions);
682
- const publicScope = toScope(scope, runtime.cwd);
683
- await reportScope(options.reporter, publicScope, context);
684
- const result = await runScope(runtime, scope, scopeOptions, options.reporter ? {
685
- reporter: options.reporter,
686
- context
687
- } : void 0);
688
- await reportSuccess(options.reporter, result, context);
689
- return result;
690
- } catch (error) {
691
- await reportError(options.reporter, error, context);
692
- throw error;
693
- }
694
- }
10
+ const inline = toInlineConfig(options);
11
+ const cwd = options.cwd ?? process.cwd();
12
+ const context = createRunContext({
13
+ cwd,
14
+ dry: options.dry ?? false
15
+ });
16
+ try {
17
+ await reportStart(options.reporter, context);
18
+ const config = await resolveConfig(cwd, inline);
19
+ const scopeOptions = toScopeOptions(config);
20
+ const runtime = createRuntime({
21
+ cwd,
22
+ dry: context.dry,
23
+ changelogFile: config.changelogFile ?? "CHANGELOG.md"
24
+ });
25
+ const scope = await discover(runtime, scopeOptions);
26
+ const publicScope = toScope(scope, runtime.cwd);
27
+ await reportScope(options.reporter, publicScope, context);
28
+ const result = await runScope(runtime, scope, scopeOptions, options.reporter ? {
29
+ reporter: options.reporter,
30
+ context
31
+ } : void 0);
32
+ await reportSuccess(options.reporter, result, context);
33
+ return result;
34
+ } catch (error) {
35
+ await reportError(options.reporter, error, context);
36
+ throw error;
37
+ }
38
+ }
39
+ /** Resolves config, creates a runtime, and returns a deterministic release scope. */
695
40
  async function createScope(options = {}) {
696
- const inline = toInlineConfig(options);
697
- const cwd = options.cwd ?? process.cwd();
698
- const config = await resolveConfig(cwd, inline);
699
- const scopeOptions = toScopeOptions(config);
700
- const runtime = createRuntime({
701
- cwd,
702
- dry: options.dry ?? true,
703
- changelogFile: config.changelogFile ?? DEFAULT_CHANGELOG_FILE
704
- });
705
- const scope = await discover(runtime, scopeOptions);
706
- return toScope(scope, runtime.cwd);
707
- }
708
- export {
709
- createScope,
710
- resolveConfig,
711
- run
712
- };
41
+ const inline = toInlineConfig(options);
42
+ const cwd = options.cwd ?? process.cwd();
43
+ const config = await resolveConfig(cwd, inline);
44
+ const scopeOptions = toScopeOptions(config);
45
+ const runtime = createRuntime({
46
+ cwd,
47
+ dry: options.dry ?? true,
48
+ changelogFile: config.changelogFile ?? "CHANGELOG.md"
49
+ });
50
+ return toScope(await discover(runtime, scopeOptions), runtime.cwd);
51
+ }
52
+ //#endregion
53
+ export { createScope, resolveConfig, run };