@williamthorsen/release-kit 5.4.0 → 7.0.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.
Files changed (135) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/README.md +12 -12
  3. package/dist/esm/.cache +1 -1
  4. package/dist/esm/assertCleanWorkingTree.js +9 -14
  5. package/dist/esm/bin/release-kit.js +202 -229
  6. package/dist/esm/buildChangelogEntries.d.ts +2 -2
  7. package/dist/esm/buildChangelogEntries.js +142 -149
  8. package/dist/esm/buildDependencyGraph.d.ts +1 -1
  9. package/dist/esm/buildDependencyGraph.js +60 -59
  10. package/dist/esm/buildEmptyReleaseEntry.d.ts +1 -1
  11. package/dist/esm/buildEmptyReleaseEntry.js +12 -15
  12. package/dist/esm/buildReleaseSummary.d.ts +1 -1
  13. package/dist/esm/buildReleaseSummary.js +23 -26
  14. package/dist/esm/buildSyntheticChangelogEntry.d.ts +1 -1
  15. package/dist/esm/buildSyntheticChangelogEntry.js +9 -12
  16. package/dist/esm/bumpAllVersions.d.ts +1 -1
  17. package/dist/esm/bumpAllVersions.js +51 -52
  18. package/dist/esm/bumpVersion.d.ts +1 -1
  19. package/dist/esm/bumpVersion.js +25 -28
  20. package/dist/esm/changelogJsonFile.d.ts +1 -1
  21. package/dist/esm/changelogJsonFile.js +59 -62
  22. package/dist/esm/changelogJsonUtils.d.ts +1 -1
  23. package/dist/esm/changelogJsonUtils.js +35 -32
  24. package/dist/esm/changelogOverrides.d.ts +1 -1
  25. package/dist/esm/changelogOverrides.js +374 -377
  26. package/dist/esm/checkWorkTypesDrift.js +104 -99
  27. package/dist/esm/collectPolicyViolations.d.ts +2 -2
  28. package/dist/esm/collectPolicyViolations.js +11 -14
  29. package/dist/esm/commitCommand.js +48 -53
  30. package/dist/esm/compareVersions.js +20 -23
  31. package/dist/esm/createGithubRelease.js +56 -59
  32. package/dist/esm/createGithubReleaseCommand.js +21 -29
  33. package/dist/esm/createTags.js +57 -56
  34. package/dist/esm/decideRelease.d.ts +2 -2
  35. package/dist/esm/decideRelease.js +27 -41
  36. package/dist/esm/defaults.d.ts +3 -3
  37. package/dist/esm/defaults.js +36 -48
  38. package/dist/esm/deleteFileIfExists.js +10 -12
  39. package/dist/esm/deriveWorkspaceConfig.d.ts +1 -1
  40. package/dist/esm/deriveWorkspaceConfig.js +34 -36
  41. package/dist/esm/detectPackageManager.js +35 -37
  42. package/dist/esm/detectUndeclaredTagPrefixes.js +41 -40
  43. package/dist/esm/determineBumpFromCommits.d.ts +2 -2
  44. package/dist/esm/determineBumpFromCommits.js +25 -29
  45. package/dist/esm/determineBumpType.d.ts +1 -1
  46. package/dist/esm/determineBumpType.js +31 -32
  47. package/dist/esm/discoverWorkspaces.js +38 -40
  48. package/dist/esm/format.js +6 -11
  49. package/dist/esm/generateChangelogs.d.ts +1 -1
  50. package/dist/esm/generateChangelogs.js +13 -17
  51. package/dist/esm/getCommitsSinceTarget.d.ts +1 -1
  52. package/dist/esm/getCommitsSinceTarget.js +54 -55
  53. package/dist/esm/hasPrettierConfig.js +33 -35
  54. package/dist/esm/help/prepareHelp.d.ts +2 -0
  55. package/dist/esm/help/prepareHelp.js +26 -0
  56. package/dist/esm/index.d.ts +4 -4
  57. package/dist/esm/index.js +2 -8
  58. package/dist/esm/init/checks.js +28 -32
  59. package/dist/esm/init/detectRepoType.js +12 -15
  60. package/dist/esm/init/initCommand.js +60 -54
  61. package/dist/esm/init/parseJsonRecord.js +9 -11
  62. package/dist/esm/init/scaffold.d.ts +1 -1
  63. package/dist/esm/init/scaffold.js +32 -38
  64. package/dist/esm/init/templates.d.ts +1 -1
  65. package/dist/esm/init/templates.js +16 -22
  66. package/dist/esm/injectReleaseNotesIntoReadme.js +42 -49
  67. package/dist/esm/injectSection.js +17 -27
  68. package/dist/esm/loadConfig.d.ts +1 -1
  69. package/dist/esm/loadConfig.js +206 -225
  70. package/dist/esm/parseCommitMessage.d.ts +1 -1
  71. package/dist/esm/parseCommitMessage.js +72 -76
  72. package/dist/esm/parseRequestedTags.js +6 -9
  73. package/dist/esm/prepareCommand.d.ts +32 -1
  74. package/dist/esm/prepareCommand.js +225 -271
  75. package/dist/esm/previewTagPrefixes.d.ts +1 -1
  76. package/dist/esm/previewTagPrefixes.js +101 -96
  77. package/dist/esm/propagateBumps.d.ts +2 -2
  78. package/dist/esm/propagateBumps.js +48 -50
  79. package/dist/esm/publish.d.ts +2 -2
  80. package/dist/esm/publish.js +22 -28
  81. package/dist/esm/publishCommand.js +75 -86
  82. package/dist/esm/pushCommand.js +33 -40
  83. package/dist/esm/pushRelease.d.ts +1 -1
  84. package/dist/esm/pushRelease.js +21 -24
  85. package/dist/esm/readCurrentVersion.js +13 -17
  86. package/dist/esm/releasePrepare.d.ts +1 -1
  87. package/dist/esm/releasePrepare.js +213 -231
  88. package/dist/esm/releasePrepareMono.d.ts +2 -2
  89. package/dist/esm/releasePrepareMono.js +434 -493
  90. package/dist/esm/releasePrepareProject.d.ts +2 -2
  91. package/dist/esm/releasePrepareProject.js +143 -153
  92. package/dist/esm/renderChangelogMarkdown.d.ts +1 -1
  93. package/dist/esm/renderChangelogMarkdown.js +20 -24
  94. package/dist/esm/renderReleaseNotes.d.ts +1 -1
  95. package/dist/esm/renderReleaseNotes.js +50 -55
  96. package/dist/esm/reportPrepare.d.ts +1 -1
  97. package/dist/esm/reportPrepare.js +230 -231
  98. package/dist/esm/resolveCliffConfigPath.js +18 -23
  99. package/dist/esm/resolveCommandTags.d.ts +1 -1
  100. package/dist/esm/resolveCommandTags.js +47 -44
  101. package/dist/esm/resolveReleaseNotesConfig.d.ts +1 -1
  102. package/dist/esm/resolveReleaseNotesConfig.js +39 -41
  103. package/dist/esm/resolveReleaseTags.d.ts +1 -1
  104. package/dist/esm/resolveReleaseTags.js +39 -40
  105. package/dist/esm/runGitCliff.js +27 -30
  106. package/dist/esm/showTagPrefixesCommand.js +48 -70
  107. package/dist/esm/stripEmojiPrefix.js +2 -5
  108. package/dist/esm/stripScope.js +18 -21
  109. package/dist/esm/sync-labels/generateCommand.d.ts +1 -1
  110. package/dist/esm/sync-labels/generateCommand.js +51 -52
  111. package/dist/esm/sync-labels/initCommand.js +46 -47
  112. package/dist/esm/sync-labels/loadSyncLabelsConfig.d.ts +1 -1
  113. package/dist/esm/sync-labels/loadSyncLabelsConfig.js +46 -52
  114. package/dist/esm/sync-labels/presets.d.ts +1 -1
  115. package/dist/esm/sync-labels/presets.js +40 -43
  116. package/dist/esm/sync-labels/resolveLabels.d.ts +1 -1
  117. package/dist/esm/sync-labels/resolveLabels.js +28 -35
  118. package/dist/esm/sync-labels/syncCommand.js +30 -30
  119. package/dist/esm/sync-labels/templates.d.ts +1 -1
  120. package/dist/esm/sync-labels/templates.js +23 -26
  121. package/dist/esm/sync-labels/types.js +1 -0
  122. package/dist/esm/syncWorkTypes.js +83 -81
  123. package/dist/esm/tagCommand.js +12 -21
  124. package/dist/esm/typeGuards.js +4 -8
  125. package/dist/esm/types.js +66 -60
  126. package/dist/esm/validateConfig.d.ts +1 -1
  127. package/dist/esm/validateConfig.js +109 -115
  128. package/dist/esm/validateOnlyExcludesStrandedDependents.d.ts +2 -2
  129. package/dist/esm/validateOnlyExcludesStrandedDependents.js +97 -91
  130. package/dist/esm/validateOverridesCommand.d.ts +2 -2
  131. package/dist/esm/validateOverridesCommand.js +111 -111
  132. package/dist/esm/workTypesData.js +57 -60
  133. package/dist/esm/workTypesUtils.js +16 -21
  134. package/dist/esm/writeReleaseNotesPreviews.js +55 -57
  135. package/package.json +2 -6
@@ -1,65 +1,66 @@
1
- import { execFileSync } from "node:child_process";
2
- import { readFileSync } from "node:fs";
1
+ import { execFileSync } from 'node:child_process';
2
+ import { readFileSync } from 'node:fs';
3
3
  import { deleteFileIfExists } from "./deleteFileIfExists.js";
4
4
  import { RELEASE_SUMMARY_FILE, RELEASE_TAGS_FILE } from "./prepareCommand.js";
5
- function createTags(options) {
6
- const { dryRun, noGitChecks } = options;
7
- let content;
8
- try {
9
- content = readFileSync(RELEASE_TAGS_FILE, "utf8");
10
- } catch {
11
- throw new Error("No tags file found. Run `release-kit prepare` first.");
12
- }
13
- const tags = content.split("\n").map((line) => line.trim()).filter((line) => line.length > 0);
14
- if (tags.length === 0) {
15
- return [];
16
- }
17
- if (!dryRun && !noGitChecks) {
18
- assertCleanWorkingTree();
19
- }
20
- if (dryRun) {
21
- console.info("[dry-run] Would create tags:");
22
- for (const tag of tags) {
23
- console.info(`\u{1F3F7}\uFE0F ${tag}`);
24
- }
25
- return tags;
26
- }
27
- const created = [];
28
- for (const tag of tags) {
5
+ export function createTags(options) {
6
+ const { dryRun, noGitChecks } = options;
7
+ let content;
29
8
  try {
30
- execFileSync("git", ["tag", "-a", tag, "-m", tag]);
31
- created.push(tag);
32
- } catch (error) {
33
- if (created.length > 0) {
34
- console.warn("Tags created before failure:");
35
- for (const t of created) {
36
- console.warn(` ${t}`);
9
+ content = readFileSync(RELEASE_TAGS_FILE, 'utf8');
10
+ }
11
+ catch {
12
+ throw new Error('No tags file found. Run `release-kit prepare` first.');
13
+ }
14
+ const tags = content
15
+ .split('\n')
16
+ .map((line) => line.trim())
17
+ .filter((line) => line.length > 0);
18
+ if (tags.length === 0) {
19
+ return [];
20
+ }
21
+ if (!dryRun && !noGitChecks) {
22
+ assertCleanWorkingTree();
23
+ }
24
+ if (dryRun) {
25
+ console.info('[dry-run] Would create tags:');
26
+ for (const tag of tags) {
27
+ console.info(`🏷️ ${tag}`);
37
28
  }
38
- }
39
- throw error;
29
+ return tags;
40
30
  }
41
- }
42
- console.info("Created tags:");
43
- for (const tag of tags) {
44
- console.info(`\u{1F3F7}\uFE0F ${tag}`);
45
- }
46
- deleteFileIfExists(RELEASE_TAGS_FILE);
47
- deleteFileIfExists(RELEASE_SUMMARY_FILE);
48
- return tags;
31
+ const created = [];
32
+ for (const tag of tags) {
33
+ try {
34
+ execFileSync('git', ['tag', '-a', tag, '-m', tag]);
35
+ created.push(tag);
36
+ }
37
+ catch (error) {
38
+ if (created.length > 0) {
39
+ console.warn('Tags created before failure:');
40
+ for (const t of created) {
41
+ console.warn(` ${t}`);
42
+ }
43
+ }
44
+ throw error;
45
+ }
46
+ }
47
+ console.info('Created tags:');
48
+ for (const tag of tags) {
49
+ console.info(`🏷️ ${tag}`);
50
+ }
51
+ deleteFileIfExists(RELEASE_TAGS_FILE);
52
+ deleteFileIfExists(RELEASE_SUMMARY_FILE);
53
+ return tags;
49
54
  }
50
55
  function assertCleanWorkingTree() {
51
- try {
52
- execFileSync("git", ["diff", "--quiet"]);
53
- execFileSync("git", ["diff", "--quiet", "--cached"]);
54
- } catch (error) {
55
- if (error instanceof Error && "code" in error && error.code === "ENOENT") {
56
- throw error;
56
+ try {
57
+ execFileSync('git', ['diff', '--quiet']);
58
+ execFileSync('git', ['diff', '--quiet', '--cached']);
59
+ }
60
+ catch (error) {
61
+ if (error instanceof Error && 'code' in error && error.code === 'ENOENT') {
62
+ throw error;
63
+ }
64
+ throw new Error('Working tree is dirty. Commit or stash changes before tagging, or use `--no-git-checks` to skip this check.');
57
65
  }
58
- throw new Error(
59
- "Working tree is dirty. Commit or stash changes before tagging, or use `--no-git-checks` to skip this check."
60
- );
61
- }
62
66
  }
63
- export {
64
- createTags
65
- };
@@ -1,5 +1,5 @@
1
- import { type PolicyViolationHandler } from './parseCommitMessage.ts';
2
- import type { Commit, ReleaseType, VersionPatterns, WorkTypeConfig } from './types.ts';
1
+ import { type PolicyViolationHandler } from './parseCommitMessage.js';
2
+ import type { Commit, ReleaseType, VersionPatterns, WorkTypeConfig } from './types.js';
3
3
  export interface DecideReleaseArgs {
4
4
  commits: readonly Commit[];
5
5
  force?: boolean | undefined;
@@ -1,44 +1,30 @@
1
1
  import { determineBumpType } from "./determineBumpType.js";
2
- import {
3
- parseCommitMessage
4
- } from "./parseCommitMessage.js";
5
- function decideRelease(args) {
6
- const {
7
- commits,
8
- force = false,
9
- bumpOverride,
10
- workTypes,
11
- versionPatterns,
12
- scopeAliases,
13
- breakingPolicies,
14
- onPolicyViolation,
15
- skipReasons
16
- } = args;
17
- const parseOptions = {
18
- ...breakingPolicies !== void 0 && { breakingPolicies },
19
- ...onPolicyViolation !== void 0 && { onPolicyViolation }
20
- };
21
- const parsedCommits = [];
22
- const unparseable = [];
23
- for (const commit of commits) {
24
- const parsed = parseCommitMessage(commit.message, commit.hash, workTypes, scopeAliases, parseOptions);
25
- if (parsed === void 0) {
26
- unparseable.push(commit);
27
- } else {
28
- parsedCommits.push(parsed);
2
+ import { parseCommitMessage, } from "./parseCommitMessage.js";
3
+ export function decideRelease(args) {
4
+ const { commits, force = false, bumpOverride, workTypes, versionPatterns, scopeAliases, breakingPolicies, onPolicyViolation, skipReasons, } = args;
5
+ const parseOptions = {
6
+ ...(breakingPolicies !== undefined && { breakingPolicies }),
7
+ ...(onPolicyViolation !== undefined && { onPolicyViolation }),
8
+ };
9
+ const parsedCommits = [];
10
+ const unparseable = [];
11
+ for (const commit of commits) {
12
+ const parsed = parseCommitMessage(commit.message, commit.hash, workTypes, scopeAliases, parseOptions);
13
+ if (parsed === undefined) {
14
+ unparseable.push(commit);
15
+ }
16
+ else {
17
+ parsedCommits.push(parsed);
18
+ }
29
19
  }
30
- }
31
- const parsedCommitCount = parsedCommits.length;
32
- const unparseableCommits = unparseable.length > 0 ? unparseable : void 0;
33
- const naturalBump = determineBumpType(parsedCommits, workTypes, versionPatterns);
34
- const shouldRelease = naturalBump !== void 0 || force;
35
- if (!shouldRelease) {
36
- const skipReason = commits.length === 0 ? skipReasons.noCommits : skipReasons.noBumpWorthy;
37
- return { outcome: "skip", skipReason, parsedCommitCount, unparseableCommits };
38
- }
39
- const releaseType = bumpOverride ?? naturalBump ?? "patch";
40
- return { outcome: "release", releaseType, parsedCommitCount, unparseableCommits };
20
+ const parsedCommitCount = parsedCommits.length;
21
+ const unparseableCommits = unparseable.length > 0 ? unparseable : undefined;
22
+ const naturalBump = determineBumpType(parsedCommits, workTypes, versionPatterns);
23
+ const shouldRelease = naturalBump !== undefined || force;
24
+ if (!shouldRelease) {
25
+ const skipReason = commits.length === 0 ? skipReasons.noCommits : skipReasons.noBumpWorthy;
26
+ return { outcome: 'skip', skipReason, parsedCommitCount, unparseableCommits };
27
+ }
28
+ const releaseType = bumpOverride ?? naturalBump ?? 'patch';
29
+ return { outcome: 'release', releaseType, parsedCommitCount, unparseableCommits };
41
30
  }
42
- export {
43
- decideRelease
44
- };
@@ -1,6 +1,6 @@
1
- import type { ChangelogJsonConfig, ReleaseNotesConfig, VersionPatterns, WorkTypeConfig } from './types.ts';
2
- export type { WorkTypesData } from './workTypesData.ts';
3
- export { WORK_TYPES_DATA } from './workTypesData.ts';
1
+ import type { ChangelogJsonConfig, ReleaseNotesConfig, VersionPatterns, WorkTypeConfig } from './types.js';
2
+ export type { WorkTypesData } from './workTypesData.js';
3
+ export { WORK_TYPES_DATA } from './workTypesData.js';
4
4
  export declare function composeHeader(entry: {
5
5
  emoji: string;
6
6
  label: string;
@@ -1,59 +1,47 @@
1
1
  import { WORK_TYPES_DATA } from "./workTypesData.js";
2
- import { WORK_TYPES_DATA as WORK_TYPES_DATA2 } from "./workTypesData.js";
3
- function composeHeader(entry) {
4
- return `${entry.emoji} ${entry.label}`;
2
+ export { WORK_TYPES_DATA } from "./workTypesData.js";
3
+ export function composeHeader(entry) {
4
+ return `${entry.emoji} ${entry.label}`;
5
5
  }
6
- const DEV_ONLY_TIERS = /* @__PURE__ */ new Set(["internal", "process"]);
6
+ const DEV_ONLY_TIERS = new Set(['internal', 'process']);
7
7
  function deriveDefaultWorkTypes() {
8
- const result = {};
9
- for (const entry of WORK_TYPES_DATA.types) {
10
- const config = {
11
- header: composeHeader(entry)
12
- };
13
- if (entry.aliases.length > 0) {
14
- config.aliases = [...entry.aliases];
8
+ const result = {};
9
+ for (const entry of WORK_TYPES_DATA.types) {
10
+ const config = {
11
+ header: composeHeader(entry),
12
+ };
13
+ if (entry.aliases.length > 0) {
14
+ config.aliases = [...entry.aliases];
15
+ }
16
+ result[entry.key] = config;
15
17
  }
16
- result[entry.key] = config;
17
- }
18
- return result;
18
+ return result;
19
19
  }
20
20
  function deriveDevOnlySections() {
21
- const sections = [];
22
- for (const entry of WORK_TYPES_DATA.types) {
23
- if (!DEV_ONLY_TIERS.has(entry.tier)) {
24
- continue;
21
+ const sections = [];
22
+ for (const entry of WORK_TYPES_DATA.types) {
23
+ if (!DEV_ONLY_TIERS.has(entry.tier)) {
24
+ continue;
25
+ }
26
+ if (entry.excludedFromChangelog === true) {
27
+ continue;
28
+ }
29
+ sections.push(composeHeader(entry));
25
30
  }
26
- if (entry.excludedFromChangelog === true) {
27
- continue;
28
- }
29
- sections.push(composeHeader(entry));
30
- }
31
- return sections;
31
+ return sections;
32
32
  }
33
- const DEFAULT_WORK_TYPES = deriveDefaultWorkTypes();
34
- const DEFAULT_BREAKING_POLICIES = Object.fromEntries(
35
- WORK_TYPES_DATA.types.map((entry) => [entry.key, entry.breakingPolicy])
36
- );
37
- const DEFAULT_VERSION_PATTERNS = {
38
- major: ["!"],
39
- minor: ["feat"]
40
- };
41
- const DEFAULT_CHANGELOG_JSON_CONFIG = {
42
- enabled: true,
43
- outputPath: ".meta/changelog.json",
44
- devOnlySections: deriveDevOnlySections()
33
+ export const DEFAULT_WORK_TYPES = deriveDefaultWorkTypes();
34
+ export const DEFAULT_BREAKING_POLICIES = Object.fromEntries(WORK_TYPES_DATA.types.map((entry) => [entry.key, entry.breakingPolicy]));
35
+ export const DEFAULT_VERSION_PATTERNS = {
36
+ major: ['!'],
37
+ minor: ['feat'],
45
38
  };
46
- const DEFAULT_RELEASE_NOTES_CONFIG = {
47
- shouldInjectIntoReadme: false
39
+ export const DEFAULT_CHANGELOG_JSON_CONFIG = {
40
+ enabled: true,
41
+ outputPath: '.meta/changelog.json',
42
+ devOnlySections: deriveDevOnlySections(),
48
43
  };
49
- const DEFAULT_PROJECT_TAG_PREFIX = "v";
50
- export {
51
- DEFAULT_BREAKING_POLICIES,
52
- DEFAULT_CHANGELOG_JSON_CONFIG,
53
- DEFAULT_PROJECT_TAG_PREFIX,
54
- DEFAULT_RELEASE_NOTES_CONFIG,
55
- DEFAULT_VERSION_PATTERNS,
56
- DEFAULT_WORK_TYPES,
57
- WORK_TYPES_DATA2 as WORK_TYPES_DATA,
58
- composeHeader
44
+ export const DEFAULT_RELEASE_NOTES_CONFIG = {
45
+ shouldInjectIntoReadme: false,
59
46
  };
47
+ export const DEFAULT_PROJECT_TAG_PREFIX = 'v';
@@ -1,14 +1,12 @@
1
- import { unlinkSync } from "node:fs";
2
- function deleteFileIfExists(filePath) {
3
- try {
4
- unlinkSync(filePath);
5
- } catch (error) {
6
- if (error instanceof Error && "code" in error && error.code === "ENOENT") {
7
- return;
1
+ import { unlinkSync } from 'node:fs';
2
+ export function deleteFileIfExists(filePath) {
3
+ try {
4
+ unlinkSync(filePath);
5
+ }
6
+ catch (error) {
7
+ if (error instanceof Error && 'code' in error && error.code === 'ENOENT') {
8
+ return;
9
+ }
10
+ throw error;
8
11
  }
9
- throw error;
10
- }
11
12
  }
12
- export {
13
- deleteFileIfExists
14
- };
@@ -1,2 +1,2 @@
1
- import type { WorkspaceConfig } from './types.ts';
1
+ import type { WorkspaceConfig } from './types.js';
2
2
  export declare function deriveWorkspaceConfig(workspacePath: string): WorkspaceConfig;
@@ -1,40 +1,38 @@
1
- import { readFileSync } from "node:fs";
2
- import { basename } from "node:path";
1
+ import { readFileSync } from 'node:fs';
2
+ import { basename } from 'node:path';
3
3
  import { isRecord } from "./typeGuards.js";
4
- function deriveWorkspaceConfig(workspacePath) {
5
- const dir = basename(workspacePath);
6
- const packageJsonPath = `${workspacePath}/package.json`;
7
- let parsed;
8
- try {
9
- parsed = JSON.parse(readFileSync(packageJsonPath, "utf8"));
10
- } catch (error) {
11
- const message = error instanceof Error ? error.message : String(error);
12
- throw new Error(`Failed to read ${packageJsonPath}: ${message}`);
13
- }
14
- const name = isRecord(parsed) ? parsed.name : void 0;
15
- if (typeof name !== "string" || name.length === 0) {
16
- throw new Error(`${packageJsonPath} is missing a 'name' field (required for tag derivation).`);
17
- }
18
- const unscopedName = stripNpmScope(name);
19
- const privateField = isRecord(parsed) ? parsed.private : void 0;
20
- const isPublishable = privateField === void 0 || privateField === false;
21
- return {
22
- dir,
23
- name,
24
- tagPrefix: `${unscopedName}-v`,
25
- workspacePath,
26
- isPublishable,
27
- packageFiles: [packageJsonPath],
28
- changelogPaths: [workspacePath],
29
- paths: [`${workspacePath}/**`]
30
- };
4
+ export function deriveWorkspaceConfig(workspacePath) {
5
+ const dir = basename(workspacePath);
6
+ const packageJsonPath = `${workspacePath}/package.json`;
7
+ let parsed;
8
+ try {
9
+ parsed = JSON.parse(readFileSync(packageJsonPath, 'utf8'));
10
+ }
11
+ catch (error) {
12
+ const message = error instanceof Error ? error.message : String(error);
13
+ throw new Error(`Failed to read ${packageJsonPath}: ${message}`);
14
+ }
15
+ const name = isRecord(parsed) ? parsed.name : undefined;
16
+ if (typeof name !== 'string' || name.length === 0) {
17
+ throw new Error(`${packageJsonPath} is missing a 'name' field (required for tag derivation).`);
18
+ }
19
+ const unscopedName = stripNpmScope(name);
20
+ const privateField = isRecord(parsed) ? parsed.private : undefined;
21
+ const isPublishable = privateField === undefined || privateField === false;
22
+ return {
23
+ dir,
24
+ name,
25
+ tagPrefix: `${unscopedName}-v`,
26
+ workspacePath,
27
+ isPublishable,
28
+ packageFiles: [packageJsonPath],
29
+ changelogPaths: [workspacePath],
30
+ paths: [`${workspacePath}/**`],
31
+ };
31
32
  }
32
33
  function stripNpmScope(name) {
33
- if (name.startsWith("@") && name.includes("/")) {
34
- return name.slice(name.indexOf("/") + 1);
35
- }
36
- return name;
34
+ if (name.startsWith('@') && name.includes('/')) {
35
+ return name.slice(name.indexOf('/') + 1);
36
+ }
37
+ return name;
37
38
  }
38
- export {
39
- deriveWorkspaceConfig
40
- };
@@ -1,44 +1,42 @@
1
- import { existsSync, readFileSync } from "node:fs";
2
- import { join } from "node:path";
1
+ import { existsSync, readFileSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
3
  import { isRecord } from "./typeGuards.js";
4
- function detectPackageManager() {
5
- const packageJsonPath = join(process.cwd(), "package.json");
6
- try {
7
- const content = readFileSync(packageJsonPath, "utf8");
8
- const parsed = JSON.parse(content);
9
- if (isRecord(parsed) && typeof parsed.packageManager === "string") {
10
- const [name, version] = parsed.packageManager.split("@");
11
- if (name === "pnpm" || name === "npm") {
12
- return name;
13
- }
14
- if (name === "yarn") {
15
- return isYarnBerry(version) ? "yarn-berry" : "yarn";
16
- }
4
+ export function detectPackageManager() {
5
+ const packageJsonPath = join(process.cwd(), 'package.json');
6
+ try {
7
+ const content = readFileSync(packageJsonPath, 'utf8');
8
+ const parsed = JSON.parse(content);
9
+ if (isRecord(parsed) && typeof parsed.packageManager === 'string') {
10
+ const [name, version] = parsed.packageManager.split('@');
11
+ if (name === 'pnpm' || name === 'npm') {
12
+ return name;
13
+ }
14
+ if (name === 'yarn') {
15
+ return isYarnBerry(version) ? 'yarn-berry' : 'yarn';
16
+ }
17
+ }
17
18
  }
18
- } catch {
19
- }
20
- return detectFromLockfile();
19
+ catch {
20
+ }
21
+ return detectFromLockfile();
21
22
  }
22
23
  function isYarnBerry(version) {
23
- if (version === void 0) {
24
- return false;
25
- }
26
- const major = Number.parseInt(version, 10);
27
- return !Number.isNaN(major) && major >= 2;
24
+ if (version === undefined) {
25
+ return false;
26
+ }
27
+ const major = Number.parseInt(version, 10);
28
+ return !Number.isNaN(major) && major >= 2;
28
29
  }
29
30
  function detectFromLockfile() {
30
- const cwd = process.cwd();
31
- if (existsSync(join(cwd, "pnpm-lock.yaml"))) {
32
- return "pnpm";
33
- }
34
- if (existsSync(join(cwd, "package-lock.json"))) {
35
- return "npm";
36
- }
37
- if (existsSync(join(cwd, "yarn.lock"))) {
38
- return "yarn";
39
- }
40
- return "npm";
31
+ const cwd = process.cwd();
32
+ if (existsSync(join(cwd, 'pnpm-lock.yaml'))) {
33
+ return 'pnpm';
34
+ }
35
+ if (existsSync(join(cwd, 'package-lock.json'))) {
36
+ return 'npm';
37
+ }
38
+ if (existsSync(join(cwd, 'yarn.lock'))) {
39
+ return 'yarn';
40
+ }
41
+ return 'npm';
41
42
  }
42
- export {
43
- detectPackageManager
44
- };
@@ -1,46 +1,47 @@
1
- import { execFileSync } from "node:child_process";
1
+ import { execFileSync } from 'node:child_process';
2
2
  const EXAMPLE_TAG_LIMIT = 3;
3
3
  const CANDIDATE_TAG_PATTERN = /^(?<prefix>[a-z][a-z0-9-]*-v)\d+\.\d+\.\d+(?:-[A-Za-z0-9.-]+)?$/;
4
- function detectUndeclaredTagPrefixes(knownPrefixes) {
5
- const known = new Set(knownPrefixes);
6
- let rawOutput;
7
- try {
8
- rawOutput = execFileSync("git", ["tag", "--list"], {
9
- encoding: "utf8",
10
- stdio: ["pipe", "pipe", "pipe"]
11
- });
12
- } catch {
13
- return [];
14
- }
15
- const grouped = /* @__PURE__ */ new Map();
16
- for (const line of rawOutput.split("\n")) {
17
- const tag = line.trim();
18
- if (tag === "") continue;
19
- const match = CANDIDATE_TAG_PATTERN.exec(tag);
20
- if (match === null) continue;
21
- const prefix = match.groups?.prefix ?? "";
22
- if (prefix === "" || known.has(prefix)) continue;
23
- let tags = grouped.get(prefix);
24
- if (tags === void 0) {
25
- tags = [];
26
- grouped.set(prefix, tags);
4
+ export function detectUndeclaredTagPrefixes(knownPrefixes) {
5
+ const known = new Set(knownPrefixes);
6
+ let rawOutput;
7
+ try {
8
+ rawOutput = execFileSync('git', ['tag', '--list'], {
9
+ encoding: 'utf8',
10
+ stdio: ['pipe', 'pipe', 'pipe'],
11
+ });
27
12
  }
28
- tags.push(tag);
29
- }
30
- const results = [];
31
- for (const [prefix, tags] of grouped) {
32
- results.push({
33
- prefix,
34
- tagCount: tags.length,
35
- exampleTags: tags.slice(0, EXAMPLE_TAG_LIMIT),
36
- suggestedDir: stripTrailingTagMarker(prefix)
37
- });
38
- }
39
- return results.sort((a, b) => a.prefix.localeCompare(b.prefix));
13
+ catch {
14
+ return [];
15
+ }
16
+ const grouped = new Map();
17
+ for (const line of rawOutput.split('\n')) {
18
+ const tag = line.trim();
19
+ if (tag === '')
20
+ continue;
21
+ const match = CANDIDATE_TAG_PATTERN.exec(tag);
22
+ if (match === null)
23
+ continue;
24
+ const prefix = match.groups?.prefix ?? '';
25
+ if (prefix === '' || known.has(prefix))
26
+ continue;
27
+ let tags = grouped.get(prefix);
28
+ if (tags === undefined) {
29
+ tags = [];
30
+ grouped.set(prefix, tags);
31
+ }
32
+ tags.push(tag);
33
+ }
34
+ const results = [];
35
+ for (const [prefix, tags] of grouped) {
36
+ results.push({
37
+ prefix,
38
+ tagCount: tags.length,
39
+ exampleTags: tags.slice(0, EXAMPLE_TAG_LIMIT),
40
+ suggestedDir: stripTrailingTagMarker(prefix),
41
+ });
42
+ }
43
+ return results.sort((a, b) => a.prefix.localeCompare(b.prefix));
40
44
  }
41
45
  function stripTrailingTagMarker(prefix) {
42
- return prefix.endsWith("-v") ? prefix.slice(0, -2) : prefix;
46
+ return prefix.endsWith('-v') ? prefix.slice(0, -2) : prefix;
43
47
  }
44
- export {
45
- detectUndeclaredTagPrefixes
46
- };
@@ -1,5 +1,5 @@
1
- import { type PolicyViolationHandler } from './parseCommitMessage.ts';
2
- import type { Commit, ReleaseType, VersionPatterns, WorkTypeConfig } from './types.ts';
1
+ import { type PolicyViolationHandler } from './parseCommitMessage.js';
2
+ import type { Commit, ReleaseType, VersionPatterns, WorkTypeConfig } from './types.js';
3
3
  export interface BumpDetermination {
4
4
  releaseType: ReleaseType | undefined;
5
5
  parsedCommitCount: number;