@williamthorsen/release-kit 6.0.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 (134) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/README.md +3 -3
  3. package/dist/esm/.cache +1 -1
  4. package/dist/esm/assertCleanWorkingTree.js +9 -14
  5. package/dist/esm/bin/release-kit.js +200 -199
  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 -102
  27. package/dist/esm/collectPolicyViolations.d.ts +2 -2
  28. package/dist/esm/collectPolicyViolations.js +11 -14
  29. package/dist/esm/commitCommand.js +48 -46
  30. package/dist/esm/compareVersions.js +20 -23
  31. package/dist/esm/createGithubRelease.js +56 -59
  32. package/dist/esm/createGithubReleaseCommand.js +21 -23
  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.js +4 -8
  55. package/dist/esm/index.d.ts +4 -4
  56. package/dist/esm/index.js +2 -8
  57. package/dist/esm/init/checks.js +28 -32
  58. package/dist/esm/init/detectRepoType.js +12 -15
  59. package/dist/esm/init/initCommand.js +60 -54
  60. package/dist/esm/init/parseJsonRecord.js +9 -11
  61. package/dist/esm/init/scaffold.d.ts +1 -1
  62. package/dist/esm/init/scaffold.js +32 -38
  63. package/dist/esm/init/templates.d.ts +1 -1
  64. package/dist/esm/init/templates.js +16 -22
  65. package/dist/esm/injectReleaseNotesIntoReadme.js +42 -49
  66. package/dist/esm/injectSection.js +17 -27
  67. package/dist/esm/loadConfig.d.ts +1 -1
  68. package/dist/esm/loadConfig.js +206 -225
  69. package/dist/esm/parseCommitMessage.d.ts +1 -1
  70. package/dist/esm/parseCommitMessage.js +72 -76
  71. package/dist/esm/parseRequestedTags.js +6 -9
  72. package/dist/esm/prepareCommand.d.ts +1 -1
  73. package/dist/esm/prepareCommand.js +225 -235
  74. package/dist/esm/previewTagPrefixes.d.ts +1 -1
  75. package/dist/esm/previewTagPrefixes.js +101 -96
  76. package/dist/esm/propagateBumps.d.ts +2 -2
  77. package/dist/esm/propagateBumps.js +48 -50
  78. package/dist/esm/publish.d.ts +2 -2
  79. package/dist/esm/publish.js +22 -28
  80. package/dist/esm/publishCommand.js +75 -80
  81. package/dist/esm/pushCommand.js +33 -34
  82. package/dist/esm/pushRelease.d.ts +1 -1
  83. package/dist/esm/pushRelease.js +21 -24
  84. package/dist/esm/readCurrentVersion.js +13 -17
  85. package/dist/esm/releasePrepare.d.ts +1 -1
  86. package/dist/esm/releasePrepare.js +213 -231
  87. package/dist/esm/releasePrepareMono.d.ts +2 -2
  88. package/dist/esm/releasePrepareMono.js +434 -494
  89. package/dist/esm/releasePrepareProject.d.ts +2 -2
  90. package/dist/esm/releasePrepareProject.js +143 -153
  91. package/dist/esm/renderChangelogMarkdown.d.ts +1 -1
  92. package/dist/esm/renderChangelogMarkdown.js +20 -24
  93. package/dist/esm/renderReleaseNotes.d.ts +1 -1
  94. package/dist/esm/renderReleaseNotes.js +50 -55
  95. package/dist/esm/reportPrepare.d.ts +1 -1
  96. package/dist/esm/reportPrepare.js +230 -231
  97. package/dist/esm/resolveCliffConfigPath.js +18 -23
  98. package/dist/esm/resolveCommandTags.d.ts +1 -1
  99. package/dist/esm/resolveCommandTags.js +47 -45
  100. package/dist/esm/resolveReleaseNotesConfig.d.ts +1 -1
  101. package/dist/esm/resolveReleaseNotesConfig.js +39 -43
  102. package/dist/esm/resolveReleaseTags.d.ts +1 -1
  103. package/dist/esm/resolveReleaseTags.js +39 -40
  104. package/dist/esm/runGitCliff.js +27 -30
  105. package/dist/esm/showTagPrefixesCommand.js +48 -70
  106. package/dist/esm/stripEmojiPrefix.js +2 -5
  107. package/dist/esm/stripScope.js +18 -21
  108. package/dist/esm/sync-labels/generateCommand.d.ts +1 -1
  109. package/dist/esm/sync-labels/generateCommand.js +51 -53
  110. package/dist/esm/sync-labels/initCommand.js +46 -48
  111. package/dist/esm/sync-labels/loadSyncLabelsConfig.d.ts +1 -1
  112. package/dist/esm/sync-labels/loadSyncLabelsConfig.js +46 -52
  113. package/dist/esm/sync-labels/presets.d.ts +1 -1
  114. package/dist/esm/sync-labels/presets.js +40 -43
  115. package/dist/esm/sync-labels/resolveLabels.d.ts +1 -1
  116. package/dist/esm/sync-labels/resolveLabels.js +28 -35
  117. package/dist/esm/sync-labels/syncCommand.js +30 -31
  118. package/dist/esm/sync-labels/templates.d.ts +1 -1
  119. package/dist/esm/sync-labels/templates.js +23 -26
  120. package/dist/esm/sync-labels/types.js +1 -0
  121. package/dist/esm/syncWorkTypes.js +83 -84
  122. package/dist/esm/tagCommand.js +12 -14
  123. package/dist/esm/typeGuards.js +4 -8
  124. package/dist/esm/types.js +66 -60
  125. package/dist/esm/validateConfig.d.ts +1 -1
  126. package/dist/esm/validateConfig.js +109 -115
  127. package/dist/esm/validateOnlyExcludesStrandedDependents.d.ts +2 -2
  128. package/dist/esm/validateOnlyExcludesStrandedDependents.js +97 -91
  129. package/dist/esm/validateOverridesCommand.d.ts +2 -2
  130. package/dist/esm/validateOverridesCommand.js +110 -111
  131. package/dist/esm/workTypesData.js +57 -60
  132. package/dist/esm/workTypesUtils.js +16 -21
  133. package/dist/esm/writeReleaseNotesPreviews.js +55 -57
  134. package/package.json +2 -2
@@ -1,58 +1,56 @@
1
- import { mkdirSync, writeFileSync } from "node:fs";
2
- import { dirname } from "node:path";
3
- import { reportError } from "@williamthorsen/nmr-core";
4
- import { stringify } from "yaml";
1
+ import { mkdirSync, writeFileSync } from 'node:fs';
2
+ import { dirname } from 'node:path';
3
+ import { reportError } from '@williamthorsen/nmr-core';
4
+ import { stringify } from 'yaml';
5
5
  import { loadSyncLabelsConfig, SYNC_LABELS_CONFIG_PATH } from "./loadSyncLabelsConfig.js";
6
6
  import { hashPresetFile } from "./presets.js";
7
7
  import { resolveLabels } from "./resolveLabels.js";
8
- const LABELS_OUTPUT_PATH = ".github/labels.yaml";
9
- function formatLabelsYaml(labels, presetHashes) {
10
- const headerLines = ["# Generated by release-kit sync-labels \u2014 do not edit.", `# Source: ${SYNC_LABELS_CONFIG_PATH}`];
11
- for (const [name, hash] of [...presetHashes.entries()].sort(([a], [b]) => a.localeCompare(b))) {
12
- headerLines.push(`# ${name} preset hash: ${hash}`);
13
- }
14
- const yamlBody = stringify(labels, { singleQuote: true, lineWidth: 0 });
15
- return headerLines.join("\n") + "\n" + yamlBody;
8
+ export const LABELS_OUTPUT_PATH = '.github/labels.yaml';
9
+ export function formatLabelsYaml(labels, presetHashes) {
10
+ const headerLines = ['# Generated by release-kit sync-labels — do not edit.', `# Source: ${SYNC_LABELS_CONFIG_PATH}`];
11
+ for (const [name, hash] of [...presetHashes.entries()].sort(([a], [b]) => a.localeCompare(b))) {
12
+ headerLines.push(`# ${name} preset hash: ${hash}`);
13
+ }
14
+ const yamlBody = stringify(labels, { singleQuote: true, lineWidth: 0 });
15
+ return headerLines.join('\n') + '\n' + yamlBody;
16
16
  }
17
- async function generateCommand() {
18
- let config;
19
- try {
20
- config = await loadSyncLabelsConfig();
21
- } catch (error) {
22
- const message = error instanceof Error ? error.message : String(error);
23
- reportError(`Failed to load config: ${message}`);
24
- return 1;
25
- }
26
- if (config === void 0) {
27
- reportError(`No config file found at ${SYNC_LABELS_CONFIG_PATH}. Run \`release-kit sync-labels init\` first.`);
28
- return 1;
29
- }
30
- let labels;
31
- try {
32
- labels = resolveLabels(config);
33
- } catch (error) {
34
- const message = error instanceof Error ? error.message : String(error);
35
- reportError(`Failed to resolve labels: ${message}`);
36
- return 1;
37
- }
38
- const presetHashes = /* @__PURE__ */ new Map();
39
- for (const presetName of config.presets ?? []) {
40
- presetHashes.set(presetName, hashPresetFile(presetName));
41
- }
42
- const content = formatLabelsYaml(labels, presetHashes);
43
- try {
44
- mkdirSync(dirname(LABELS_OUTPUT_PATH), { recursive: true });
45
- writeFileSync(LABELS_OUTPUT_PATH, content, "utf8");
46
- } catch (error) {
47
- const message = error instanceof Error ? error.message : String(error);
48
- reportError(`Failed to write ${LABELS_OUTPUT_PATH}: ${message}`);
49
- return 1;
50
- }
51
- console.info(`Generated ${LABELS_OUTPUT_PATH} with ${String(labels.length)} labels.`);
52
- return 0;
17
+ export async function generateCommand() {
18
+ let config;
19
+ try {
20
+ config = await loadSyncLabelsConfig();
21
+ }
22
+ catch (error) {
23
+ const message = error instanceof Error ? error.message : String(error);
24
+ reportError(`Failed to load config: ${message}`);
25
+ return 1;
26
+ }
27
+ if (config === undefined) {
28
+ reportError(`No config file found at ${SYNC_LABELS_CONFIG_PATH}. Run \`release-kit sync-labels init\` first.`);
29
+ return 1;
30
+ }
31
+ let labels;
32
+ try {
33
+ labels = resolveLabels(config);
34
+ }
35
+ catch (error) {
36
+ const message = error instanceof Error ? error.message : String(error);
37
+ reportError(`Failed to resolve labels: ${message}`);
38
+ return 1;
39
+ }
40
+ const presetHashes = new Map();
41
+ for (const presetName of config.presets ?? []) {
42
+ presetHashes.set(presetName, hashPresetFile(presetName));
43
+ }
44
+ const content = formatLabelsYaml(labels, presetHashes);
45
+ try {
46
+ mkdirSync(dirname(LABELS_OUTPUT_PATH), { recursive: true });
47
+ writeFileSync(LABELS_OUTPUT_PATH, content, 'utf8');
48
+ }
49
+ catch (error) {
50
+ const message = error instanceof Error ? error.message : String(error);
51
+ reportError(`Failed to write ${LABELS_OUTPUT_PATH}: ${message}`);
52
+ return 1;
53
+ }
54
+ console.info(`Generated ${LABELS_OUTPUT_PATH} with ${String(labels.length)} labels.`);
55
+ return 0;
53
56
  }
54
- export {
55
- LABELS_OUTPUT_PATH,
56
- formatLabelsYaml,
57
- generateCommand
58
- };
@@ -1,52 +1,53 @@
1
- import { reportWriteResult, writeFileWithCheck } from "@williamthorsen/nmr-core";
1
+ import { reportWriteResult, writeFileWithCheck } from '@williamthorsen/nmr-core';
2
2
  import { discoverWorkspaces } from "../discoverWorkspaces.js";
3
3
  import { generateCommand, LABELS_OUTPUT_PATH } from "./generateCommand.js";
4
4
  import { SYNC_LABELS_CONFIG_PATH } from "./loadSyncLabelsConfig.js";
5
5
  import { buildScopeLabels, syncLabelsConfigScript, syncLabelsWorkflow } from "./templates.js";
6
- const WORKFLOW_PATH = ".github/workflows/sync-labels.yaml";
7
- async function syncLabelsInitCommand({ dryRun, force }) {
8
- if (dryRun) {
9
- console.info("[dry-run mode]");
10
- }
11
- console.info("\n> Discovering workspaces");
12
- let workspacePaths;
13
- try {
14
- workspacePaths = await discoverWorkspaces();
15
- } catch (error) {
16
- const message = error instanceof Error ? error.message : String(error);
17
- process.stderr.write(` Failed to discover workspaces: ${message}
18
- `);
19
- return 1;
20
- }
21
- const scopeLabels = workspacePaths === void 0 ? [] : buildScopeLabels(workspacePaths);
22
- if (workspacePaths === void 0) {
23
- console.info(" No pnpm workspaces found (single-package repo)");
24
- } else {
25
- console.info(` Found ${String(workspacePaths.length)} workspaces`);
26
- }
27
- console.info("\n> Scaffolding files");
28
- const workflowResult = writeFileWithCheck(WORKFLOW_PATH, syncLabelsWorkflow(), { dryRun, overwrite: force });
29
- const configResult = writeFileWithCheck(SYNC_LABELS_CONFIG_PATH, syncLabelsConfigScript(scopeLabels), {
30
- dryRun,
31
- overwrite: force
32
- });
33
- reportWriteResult(workflowResult, dryRun);
34
- reportWriteResult(configResult, dryRun);
35
- if (workflowResult.outcome === "failed" || configResult.outcome === "failed") {
36
- process.stderr.write("Failed to scaffold one or more files.\n");
37
- return 1;
38
- }
39
- if (dryRun) {
6
+ const WORKFLOW_PATH = '.github/workflows/sync-labels.yaml';
7
+ export async function syncLabelsInitCommand({ dryRun, force }) {
8
+ if (dryRun) {
9
+ console.info('[dry-run mode]');
10
+ }
11
+ console.info('\n> Discovering workspaces');
12
+ let workspacePaths;
13
+ try {
14
+ workspacePaths = await discoverWorkspaces();
15
+ }
16
+ catch (error) {
17
+ const message = error instanceof Error ? error.message : String(error);
18
+ process.stderr.write(` Failed to discover workspaces: ${message}\n`);
19
+ return 1;
20
+ }
21
+ const scopeLabels = workspacePaths === undefined ? [] : buildScopeLabels(workspacePaths);
22
+ if (workspacePaths === undefined) {
23
+ console.info(' No pnpm workspaces found (single-package repo)');
24
+ }
25
+ else {
26
+ console.info(` Found ${String(workspacePaths.length)} workspaces`);
27
+ }
28
+ console.info('\n> Scaffolding files');
29
+ const workflowResult = writeFileWithCheck(WORKFLOW_PATH, syncLabelsWorkflow(), { dryRun, overwrite: force });
30
+ const configResult = writeFileWithCheck(SYNC_LABELS_CONFIG_PATH, syncLabelsConfigScript(scopeLabels), {
31
+ dryRun,
32
+ overwrite: force,
33
+ });
34
+ reportWriteResult(workflowResult, dryRun);
35
+ reportWriteResult(configResult, dryRun);
36
+ if (workflowResult.outcome === 'failed' || configResult.outcome === 'failed') {
37
+ process.stderr.write('Failed to scaffold one or more files.\n');
38
+ return 1;
39
+ }
40
+ if (dryRun) {
41
+ console.info(`\n> [dry-run] Would generate ${LABELS_OUTPUT_PATH}`);
42
+ }
43
+ else {
44
+ console.info('\n> Generating labels');
45
+ const generateExitCode = await generateCommand();
46
+ if (generateExitCode !== 0) {
47
+ return generateExitCode;
48
+ }
49
+ }
40
50
  console.info(`
41
- > [dry-run] Would generate ${LABELS_OUTPUT_PATH}`);
42
- } else {
43
- console.info("\n> Generating labels");
44
- const generateExitCode = await generateCommand();
45
- if (generateExitCode !== 0) {
46
- return generateExitCode;
47
- }
48
- }
49
- console.info(`
50
51
  > Next steps
51
52
  1. Review the generated files:
52
53
  - ${WORKFLOW_PATH}
@@ -56,8 +57,5 @@ async function syncLabelsInitCommand({ dryRun, force }) {
56
57
  3. Commit the generated files.
57
58
  4. Run \`release-kit sync-labels sync\` to apply labels to your GitHub repo.
58
59
  `);
59
- return 0;
60
+ return 0;
60
61
  }
61
- export {
62
- syncLabelsInitCommand
63
- };
@@ -1,3 +1,3 @@
1
- import type { SyncLabelsConfig } from './types.ts';
1
+ import type { SyncLabelsConfig } from './types.js';
2
2
  export declare const SYNC_LABELS_CONFIG_PATH = ".config/sync-labels.config.ts";
3
3
  export declare function loadSyncLabelsConfig(): Promise<SyncLabelsConfig | undefined>;
@@ -1,59 +1,53 @@
1
- import { existsSync } from "node:fs";
2
- import path from "node:path";
1
+ import { existsSync } from 'node:fs';
2
+ import path from 'node:path';
3
3
  import { isRecord } from "../typeGuards.js";
4
- const SYNC_LABELS_CONFIG_PATH = ".config/sync-labels.config.ts";
5
- async function loadSyncLabelsConfig() {
6
- const absoluteConfigPath = path.resolve(process.cwd(), SYNC_LABELS_CONFIG_PATH);
7
- if (!existsSync(absoluteConfigPath)) {
8
- return void 0;
9
- }
10
- const { createJiti } = await import("jiti");
11
- const jiti = createJiti(import.meta.url);
12
- const imported = await jiti.import(absoluteConfigPath);
13
- if (!isRecord(imported)) {
14
- throw new Error(`Config file must export an object, got ${Array.isArray(imported) ? "array" : typeof imported}`);
15
- }
16
- const resolved = imported.default ?? imported.config;
17
- if (resolved === void 0) {
18
- throw new Error(
19
- "Config file must have a default export or a named `config` export (e.g., `export default { ... }` or `export const config = { ... }`)"
20
- );
21
- }
22
- return validateSyncLabelsConfig(resolved);
4
+ export const SYNC_LABELS_CONFIG_PATH = '.config/sync-labels.config.ts';
5
+ export async function loadSyncLabelsConfig() {
6
+ const absoluteConfigPath = path.resolve(process.cwd(), SYNC_LABELS_CONFIG_PATH);
7
+ if (!existsSync(absoluteConfigPath)) {
8
+ return undefined;
9
+ }
10
+ const { createJiti } = await import('jiti');
11
+ const jiti = createJiti(import.meta.url);
12
+ const imported = await jiti.import(absoluteConfigPath);
13
+ if (!isRecord(imported)) {
14
+ throw new Error(`Config file must export an object, got ${Array.isArray(imported) ? 'array' : typeof imported}`);
15
+ }
16
+ const resolved = imported.default ?? imported.config;
17
+ if (resolved === undefined) {
18
+ throw new Error('Config file must have a default export or a named `config` export (e.g., `export default { ... }` or `export const config = { ... }`)');
19
+ }
20
+ return validateSyncLabelsConfig(resolved);
23
21
  }
24
22
  function validateSyncLabelsConfig(value) {
25
- if (!isRecord(value)) {
26
- throw new Error(`Config must be an object, got ${typeof value}`);
27
- }
28
- let presets;
29
- if (value.presets !== void 0) {
30
- if (!Array.isArray(value.presets) || !value.presets.every((p) => typeof p === "string")) {
31
- throw new Error("Config `presets` must be an array of strings");
23
+ if (!isRecord(value)) {
24
+ throw new Error(`Config must be an object, got ${typeof value}`);
32
25
  }
33
- presets = value.presets;
34
- }
35
- let labels;
36
- if (value.labels !== void 0) {
37
- if (!Array.isArray(value.labels)) {
38
- throw new TypeError("Config `labels` must be an array");
26
+ let presets;
27
+ if (value.presets !== undefined) {
28
+ if (!Array.isArray(value.presets) || !value.presets.every((p) => typeof p === 'string')) {
29
+ throw new Error('Config `presets` must be an array of strings');
30
+ }
31
+ presets = value.presets;
39
32
  }
40
- labels = [];
41
- for (const label of value.labels) {
42
- if (!isRecord(label)) {
43
- throw new Error("Each label must be an object with `name`, `color`, and `description`");
44
- }
45
- if (typeof label.name !== "string" || typeof label.color !== "string" || typeof label.description !== "string") {
46
- throw new TypeError("Each label must have string `name`, `color`, and `description` fields");
47
- }
48
- labels.push({ name: label.name, color: label.color, description: label.description });
33
+ let labels;
34
+ if (value.labels !== undefined) {
35
+ if (!Array.isArray(value.labels)) {
36
+ throw new TypeError('Config `labels` must be an array');
37
+ }
38
+ labels = [];
39
+ for (const label of value.labels) {
40
+ if (!isRecord(label)) {
41
+ throw new Error('Each label must be an object with `name`, `color`, and `description`');
42
+ }
43
+ if (typeof label.name !== 'string' || typeof label.color !== 'string' || typeof label.description !== 'string') {
44
+ throw new TypeError('Each label must have string `name`, `color`, and `description` fields');
45
+ }
46
+ labels.push({ name: label.name, color: label.color, description: label.description });
47
+ }
49
48
  }
50
- }
51
- return {
52
- ...presets !== void 0 && { presets },
53
- ...labels !== void 0 && { labels }
54
- };
49
+ return {
50
+ ...(presets !== undefined && { presets }),
51
+ ...(labels !== undefined && { labels }),
52
+ };
55
53
  }
56
- export {
57
- SYNC_LABELS_CONFIG_PATH,
58
- loadSyncLabelsConfig
59
- };
@@ -1,3 +1,3 @@
1
- import type { LabelDefinition } from './types.ts';
1
+ import type { LabelDefinition } from './types.js';
2
2
  export declare function hashPresetFile(presetName: string): string;
3
3
  export declare function loadPreset(presetName: string): LabelDefinition[];
@@ -1,50 +1,47 @@
1
- import { createHash } from "node:crypto";
2
- import { existsSync, readFileSync } from "node:fs";
3
- import { resolve } from "node:path";
4
- import { findPackageRoot } from "@williamthorsen/nmr-core";
5
- import { parse } from "yaml";
1
+ import { createHash } from 'node:crypto';
2
+ import { existsSync, readFileSync } from 'node:fs';
3
+ import { resolve } from 'node:path';
4
+ import { findPackageRoot } from '@williamthorsen/nmr-core';
5
+ import { parse } from 'yaml';
6
6
  import { isRecord } from "../typeGuards.js";
7
7
  function resolvePresetPath(presetName) {
8
- const root = findPackageRoot(import.meta.url);
9
- return resolve(root, "presets", "labels", `${presetName}.yaml`);
8
+ const root = findPackageRoot(import.meta.url);
9
+ return resolve(root, 'presets', 'labels', `${presetName}.yaml`);
10
10
  }
11
- function hashPresetFile(presetName) {
12
- const presetPath = resolvePresetPath(presetName);
13
- if (!existsSync(presetPath)) {
14
- throw new Error(`Unknown preset "${presetName}". No file found at ${presetPath}`);
15
- }
16
- const content = readFileSync(presetPath, "utf8");
17
- return createHash("sha256").update(content).digest("hex");
11
+ export function hashPresetFile(presetName) {
12
+ const presetPath = resolvePresetPath(presetName);
13
+ if (!existsSync(presetPath)) {
14
+ throw new Error(`Unknown preset "${presetName}". No file found at ${presetPath}`);
15
+ }
16
+ const content = readFileSync(presetPath, 'utf8');
17
+ return createHash('sha256').update(content).digest('hex');
18
18
  }
19
- function loadPreset(presetName) {
20
- const presetPath = resolvePresetPath(presetName);
21
- if (!existsSync(presetPath)) {
22
- throw new Error(`Unknown preset "${presetName}". No file found at ${presetPath}`);
23
- }
24
- let content;
25
- try {
26
- content = readFileSync(presetPath, "utf8");
27
- } catch (error) {
28
- const message = error instanceof Error ? error.message : String(error);
29
- throw new Error(`Failed to read preset "${presetName}": ${message}`);
30
- }
31
- const parsed = parse(content);
32
- if (!Array.isArray(parsed)) {
33
- throw new TypeError(`Preset "${presetName}" must be a YAML array of label definitions`);
34
- }
35
- const labels = [];
36
- for (const entry of parsed) {
37
- if (!isRecord(entry)) {
38
- throw new Error(`Preset "${presetName}" contains an invalid label entry: ${JSON.stringify(entry)}`);
19
+ export function loadPreset(presetName) {
20
+ const presetPath = resolvePresetPath(presetName);
21
+ if (!existsSync(presetPath)) {
22
+ throw new Error(`Unknown preset "${presetName}". No file found at ${presetPath}`);
23
+ }
24
+ let content;
25
+ try {
26
+ content = readFileSync(presetPath, 'utf8');
27
+ }
28
+ catch (error) {
29
+ const message = error instanceof Error ? error.message : String(error);
30
+ throw new Error(`Failed to read preset "${presetName}": ${message}`);
31
+ }
32
+ const parsed = parse(content);
33
+ if (!Array.isArray(parsed)) {
34
+ throw new TypeError(`Preset "${presetName}" must be a YAML array of label definitions`);
39
35
  }
40
- if (typeof entry.name !== "string" || typeof entry.color !== "string" || typeof entry.description !== "string") {
41
- throw new TypeError(`Preset "${presetName}" contains a label with invalid fields: ${JSON.stringify(entry)}`);
36
+ const labels = [];
37
+ for (const entry of parsed) {
38
+ if (!isRecord(entry)) {
39
+ throw new Error(`Preset "${presetName}" contains an invalid label entry: ${JSON.stringify(entry)}`);
40
+ }
41
+ if (typeof entry.name !== 'string' || typeof entry.color !== 'string' || typeof entry.description !== 'string') {
42
+ throw new TypeError(`Preset "${presetName}" contains a label with invalid fields: ${JSON.stringify(entry)}`);
43
+ }
44
+ labels.push({ name: entry.name, color: entry.color, description: entry.description });
42
45
  }
43
- labels.push({ name: entry.name, color: entry.color, description: entry.description });
44
- }
45
- return labels;
46
+ return labels;
46
47
  }
47
- export {
48
- hashPresetFile,
49
- loadPreset
50
- };
@@ -1,2 +1,2 @@
1
- import type { LabelDefinition, SyncLabelsConfig } from './types.ts';
1
+ import type { LabelDefinition, SyncLabelsConfig } from './types.js';
2
2
  export declare function resolveLabels(config: SyncLabelsConfig): LabelDefinition[];
@@ -1,43 +1,36 @@
1
1
  import { loadPreset } from "./presets.js";
2
- function resolveLabels(config) {
3
- const presetLabels = [];
4
- for (const presetName of config.presets ?? []) {
5
- const loaded = loadPreset(presetName);
6
- presetLabels.push(...loaded);
7
- }
8
- const customLabels = config.labels ?? [];
9
- detectCollisions(presetLabels, customLabels);
10
- return sortLabels([...presetLabels, ...customLabels]);
2
+ export function resolveLabels(config) {
3
+ const presetLabels = [];
4
+ for (const presetName of config.presets ?? []) {
5
+ const loaded = loadPreset(presetName);
6
+ presetLabels.push(...loaded);
7
+ }
8
+ const customLabels = config.labels ?? [];
9
+ detectCollisions(presetLabels, customLabels);
10
+ return sortLabels([...presetLabels, ...customLabels]);
11
11
  }
12
12
  function detectCollisions(presetLabels, customLabels) {
13
- const seenPresetNames = /* @__PURE__ */ new Set();
14
- const withinPresetDuplicates = [];
15
- for (const label of presetLabels) {
16
- if (seenPresetNames.has(label.name)) {
17
- withinPresetDuplicates.push(label.name);
13
+ const seenPresetNames = new Set();
14
+ const withinPresetDuplicates = [];
15
+ for (const label of presetLabels) {
16
+ if (seenPresetNames.has(label.name)) {
17
+ withinPresetDuplicates.push(label.name);
18
+ }
19
+ seenPresetNames.add(label.name);
20
+ }
21
+ if (withinPresetDuplicates.length > 0) {
22
+ throw new Error(`Label name collision within presets: the following labels are defined by multiple presets: ${withinPresetDuplicates.join(', ')}. Remove the duplicates or use different presets.`);
23
+ }
24
+ const conflicts = [];
25
+ for (const label of customLabels) {
26
+ if (seenPresetNames.has(label.name)) {
27
+ conflicts.push(label.name);
28
+ }
18
29
  }
19
- seenPresetNames.add(label.name);
20
- }
21
- if (withinPresetDuplicates.length > 0) {
22
- throw new Error(
23
- `Label name collision within presets: the following labels are defined by multiple presets: ${withinPresetDuplicates.join(", ")}. Remove the duplicates or use different presets.`
24
- );
25
- }
26
- const conflicts = [];
27
- for (const label of customLabels) {
28
- if (seenPresetNames.has(label.name)) {
29
- conflicts.push(label.name);
30
+ if (conflicts.length > 0) {
31
+ throw new Error(`Label name collision: the following labels appear in both presets and custom labels: ${conflicts.join(', ')}. Remove duplicates from your custom labels or use a different name.`);
30
32
  }
31
- }
32
- if (conflicts.length > 0) {
33
- throw new Error(
34
- `Label name collision: the following labels appear in both presets and custom labels: ${conflicts.join(", ")}. Remove duplicates from your custom labels or use a different name.`
35
- );
36
- }
37
33
  }
38
34
  function sortLabels(labels) {
39
- return [...labels].sort((a, b) => a.name.localeCompare(b.name));
35
+ return [...labels].sort((a, b) => a.name.localeCompare(b.name));
40
36
  }
41
- export {
42
- resolveLabels
43
- };
@@ -1,34 +1,33 @@
1
- import { execSync } from "node:child_process";
2
- import { existsSync } from "node:fs";
3
- import { reportError } from "@williamthorsen/nmr-core";
4
- const WORKFLOW_FILE = ".github/workflows/sync-labels.yaml";
1
+ import { execSync } from 'node:child_process';
2
+ import { existsSync } from 'node:fs';
3
+ import { reportError } from '@williamthorsen/nmr-core';
4
+ const WORKFLOW_FILE = '.github/workflows/sync-labels.yaml';
5
5
  function checkGhAvailable() {
6
- try {
7
- execSync("gh --version", { stdio: "pipe" });
8
- return true;
9
- } catch {
10
- return false;
11
- }
6
+ try {
7
+ execSync('gh --version', { stdio: 'pipe' });
8
+ return true;
9
+ }
10
+ catch {
11
+ return false;
12
+ }
12
13
  }
13
- function syncLabelsCommand() {
14
- if (!checkGhAvailable()) {
15
- reportError("The `gh` CLI is not installed or not in PATH. Install it from https://cli.github.com/");
16
- return 1;
17
- }
18
- if (!existsSync(WORKFLOW_FILE)) {
19
- reportError(`${WORKFLOW_FILE} not found. Run \`release-kit sync-labels init\` first.`);
20
- return 1;
21
- }
22
- try {
23
- execSync("gh workflow run sync-labels.yaml", { stdio: "inherit" });
24
- } catch (error) {
25
- const message = error instanceof Error ? error.message : String(error);
26
- reportError(`Failed to trigger workflow: ${message}`);
27
- return 1;
28
- }
29
- console.info("Workflow triggered successfully. View runs at: gh run list --workflow=sync-labels.yaml");
30
- return 0;
14
+ export function syncLabelsCommand() {
15
+ if (!checkGhAvailable()) {
16
+ reportError('The `gh` CLI is not installed or not in PATH. Install it from https://cli.github.com/');
17
+ return 1;
18
+ }
19
+ if (!existsSync(WORKFLOW_FILE)) {
20
+ reportError(`${WORKFLOW_FILE} not found. Run \`release-kit sync-labels init\` first.`);
21
+ return 1;
22
+ }
23
+ try {
24
+ execSync('gh workflow run sync-labels.yaml', { stdio: 'inherit' });
25
+ }
26
+ catch (error) {
27
+ const message = error instanceof Error ? error.message : String(error);
28
+ reportError(`Failed to trigger workflow: ${message}`);
29
+ return 1;
30
+ }
31
+ console.info('Workflow triggered successfully. View runs at: gh run list --workflow=sync-labels.yaml');
32
+ return 0;
31
33
  }
32
- export {
33
- syncLabelsCommand
34
- };
@@ -1,4 +1,4 @@
1
- import type { LabelDefinition } from './types.ts';
1
+ import type { LabelDefinition } from './types.js';
2
2
  export declare function syncLabelsWorkflow(): string;
3
3
  export declare function buildScopeLabels(workspacePaths: string[]): LabelDefinition[];
4
4
  export declare function syncLabelsConfigScript(scopeLabels: LabelDefinition[]): string;