@williamthorsen/release-kit 15.0.3 → 16.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/.meta/changelog.json +66 -0
  2. package/.readyup/kits/default.js +13 -13
  3. package/.readyup/kits/npm-auto-publish.js +4 -4
  4. package/.readyup/manifest.json +12 -12
  5. package/CHANGELOG.md +19 -0
  6. package/README.md +7 -1
  7. package/dist/esm/applyChangelogOverrides.js +6 -6
  8. package/dist/esm/assertReleasesOnNpm.js +11 -11
  9. package/dist/esm/assertTaggedBaseline.js +5 -5
  10. package/dist/esm/bin/release-kit.js +16 -16
  11. package/dist/esm/buildChangelogEntries.d.ts +19 -19
  12. package/dist/esm/buildChangelogEntries.js +40 -36
  13. package/dist/esm/buildChangelogItem.js +24 -24
  14. package/dist/esm/buildDependencyGraph.js +23 -23
  15. package/dist/esm/buildReleasedResult.js +21 -19
  16. package/dist/esm/buildSyntheticChangelogEntry.js +2 -2
  17. package/dist/esm/bumpVersion.js +8 -8
  18. package/dist/esm/changelogArchive.d.ts +1 -1
  19. package/dist/esm/changelogArchive.js +2 -2
  20. package/dist/esm/changelogJsonFile.js +5 -5
  21. package/dist/esm/changelogJsonUtils.js +3 -3
  22. package/dist/esm/changelogOverrides.d.ts +5 -5
  23. package/dist/esm/changelogOverrides.js +23 -23
  24. package/dist/esm/classifyChangelogCommit.js +4 -4
  25. package/dist/esm/commitCommand.js +3 -3
  26. package/dist/esm/compareVersions.js +13 -13
  27. package/dist/esm/configSchema.d.ts +2 -2
  28. package/dist/esm/configSchema.js +1 -1
  29. package/dist/esm/createGithubRelease.d.ts +4 -4
  30. package/dist/esm/createGithubRelease.js +10 -10
  31. package/dist/esm/createGithubReleaseCommand.js +9 -9
  32. package/dist/esm/createTags.d.ts +2 -2
  33. package/dist/esm/createTags.js +8 -8
  34. package/dist/esm/decideDirectReleases.d.ts +5 -5
  35. package/dist/esm/decideDirectReleases.js +25 -25
  36. package/dist/esm/decideRelease.d.ts +1 -1
  37. package/dist/esm/decideRelease.js +2 -2
  38. package/dist/esm/deriveDirectoryConfig.d.ts +1 -1
  39. package/dist/esm/deriveDirectoryConfig.js +18 -18
  40. package/dist/esm/deriveWorkspaceConfig.js +4 -4
  41. package/dist/esm/detectPackageManager.js +5 -5
  42. package/dist/esm/detectUndeclaredTagPrefixes.js +6 -6
  43. package/dist/esm/enumerateReleaseWindows.d.ts +1 -1
  44. package/dist/esm/enumerateReleaseWindows.js +7 -7
  45. package/dist/esm/findTransitiveDependents.js +5 -5
  46. package/dist/esm/findUnroutedEntryScopes.js +11 -11
  47. package/dist/esm/format.d.ts +1 -1
  48. package/dist/esm/format.js +1 -1
  49. package/dist/esm/formatPrepareFiles.d.ts +3 -3
  50. package/dist/esm/formatPrepareFiles.js +10 -10
  51. package/dist/esm/formatPrepareWarnings.js +6 -6
  52. package/dist/esm/hasPrettierConfig.js +2 -2
  53. package/dist/esm/init/checks.js +5 -3
  54. package/dist/esm/init/detectRepoType.js +3 -3
  55. package/dist/esm/init/initCommand.d.ts +4 -4
  56. package/dist/esm/init/initCommand.js +7 -7
  57. package/dist/esm/init/parseJsonRecord.d.ts +1 -1
  58. package/dist/esm/init/parseJsonRecord.js +4 -4
  59. package/dist/esm/init/scaffold.d.ts +4 -4
  60. package/dist/esm/init/scaffold.js +15 -15
  61. package/dist/esm/init/templates.d.ts +10 -10
  62. package/dist/esm/init/templates.js +5 -5
  63. package/dist/esm/init/updateTemplatesCommand.d.ts +2 -2
  64. package/dist/esm/init/updateTemplatesCommand.js +14 -12
  65. package/dist/esm/injectReleaseNotesIntoReadme.d.ts +1 -1
  66. package/dist/esm/injectReleaseNotesIntoReadme.js +6 -6
  67. package/dist/esm/injectSection.js +8 -8
  68. package/dist/esm/loadChangelogOverrides.d.ts +1 -1
  69. package/dist/esm/loadChangelogOverrides.js +9 -9
  70. package/dist/esm/loadConfig.d.ts +3 -3
  71. package/dist/esm/loadConfig.js +10 -10
  72. package/dist/esm/loadValidatedConfig.js +4 -4
  73. package/dist/esm/mergeConfig.d.ts +1 -1
  74. package/dist/esm/mergeConfig.js +27 -27
  75. package/dist/esm/monorepoConfigAssertions.js +15 -15
  76. package/dist/esm/npmRegistry.js +4 -4
  77. package/dist/esm/packsPath.js +3 -3
  78. package/dist/esm/parseChangeRecordBlock.js +33 -33
  79. package/dist/esm/parseCommitMessage.js +5 -5
  80. package/dist/esm/planChangelogFiles.js +8 -8
  81. package/dist/esm/planReleaseNotesPreviews.js +10 -10
  82. package/dist/esm/planVersionBump.js +24 -16
  83. package/dist/esm/prepareArgs.d.ts +9 -9
  84. package/dist/esm/prepareArgs.js +11 -11
  85. package/dist/esm/prepareCommand.js +23 -23
  86. package/dist/esm/prepareComposite.d.ts +4 -4
  87. package/dist/esm/prepareComposite.js +16 -16
  88. package/dist/esm/{releasePrepareTargets.d.ts → prepareReleaseTargets.d.ts} +9 -9
  89. package/dist/esm/{releasePrepareTargets.js → prepareReleaseTargets.js} +40 -40
  90. package/dist/esm/prepareRunContext.d.ts +1 -1
  91. package/dist/esm/prepareRunContext.js +5 -5
  92. package/dist/esm/prepareTarget.d.ts +3 -3
  93. package/dist/esm/prepareTarget.js +41 -39
  94. package/dist/esm/previewTagPrefixes.js +19 -19
  95. package/dist/esm/propagateBumps.js +8 -8
  96. package/dist/esm/publish.d.ts +2 -2
  97. package/dist/esm/publish.js +5 -5
  98. package/dist/esm/publishCommand.js +20 -20
  99. package/dist/esm/pushCommand.js +8 -8
  100. package/dist/esm/pushRelease.d.ts +1 -1
  101. package/dist/esm/pushRelease.js +2 -2
  102. package/dist/esm/readChangelogSections.d.ts +1 -1
  103. package/dist/esm/readChangelogSections.js +16 -16
  104. package/dist/esm/releasePlan.js +25 -25
  105. package/dist/esm/renderChangelogMarkdown.d.ts +4 -4
  106. package/dist/esm/renderChangelogMarkdown.js +18 -15
  107. package/dist/esm/renderReleaseNotes.d.ts +1 -1
  108. package/dist/esm/renderReleaseNotes.js +16 -16
  109. package/dist/esm/reportPrepare.js +34 -34
  110. package/dist/esm/resolveCommandTags.js +9 -9
  111. package/dist/esm/resolveReleaseDeclaration.d.ts +2 -2
  112. package/dist/esm/resolveReleaseDeclaration.js +22 -22
  113. package/dist/esm/resolveReleaseTags.js +17 -15
  114. package/dist/esm/resolveReleaseTargets.js +2 -2
  115. package/dist/esm/showTagPrefixesCommand.js +4 -4
  116. package/dist/esm/sync-labels/generateCommand.d.ts +3 -3
  117. package/dist/esm/sync-labels/generateCommand.js +10 -10
  118. package/dist/esm/sync-labels/initCommand.d.ts +3 -3
  119. package/dist/esm/sync-labels/initCommand.js +15 -15
  120. package/dist/esm/sync-labels/presets.js +3 -3
  121. package/dist/esm/sync-labels/resolveLabels.js +13 -13
  122. package/dist/esm/sync-labels/templates.d.ts +2 -2
  123. package/dist/esm/sync-labels/templates.js +1 -1
  124. package/dist/esm/tagCommand.js +4 -4
  125. package/dist/esm/topologicalSort.d.ts +2 -2
  126. package/dist/esm/topologicalSort.js +7 -7
  127. package/dist/esm/types.d.ts +3 -3
  128. package/dist/esm/validateAllChangelogOverrides.js +9 -9
  129. package/dist/esm/validateConfig.d.ts +1 -1
  130. package/dist/esm/validateConfig.js +60 -50
  131. package/dist/esm/validateOverridesCommand.js +2 -2
  132. package/docs/changelogs.md +5 -5
  133. package/docs/configuration.md +1 -1
  134. package/docs/work-types.md +1 -1
  135. package/package.json +1 -1
@@ -22,32 +22,34 @@ export function resolveReleaseTags(args) {
22
22
  return resolveSinglePackageTags(tags, args.singleWorkspace);
23
23
  }
24
24
  function resolveSinglePackageTags(tags, singleWorkspace) {
25
- const matched = tags.filter((tag) => VERSION_PATTERN.test(tag));
25
+ const matchedTags = tags.filter((tag) => VERSION_PATTERN.test(tag));
26
26
  const isPublishable = singleWorkspace?.isPublishable ?? true;
27
- if (matched.length > 1) {
28
- console.warn(`Warning: Multiple version tags found on HEAD: ${matched.join(', ')}. ` +
27
+ if (matchedTags.length > 1) {
28
+ console.warn(`Warning: Multiple version tags found on HEAD: ${matchedTags.join(', ')}. ` +
29
29
  `Publishing the same package multiple times is almost certainly unintended. Using only the first tag.`);
30
- return matched.slice(0, 1).map((tag) => ({ tag, kind: 'package', dir: '.', workspacePath: '.', isPublishable }));
30
+ return matchedTags
31
+ .slice(0, 1)
32
+ .map((tag) => ({ tag, kind: 'package', dir: '.', workspacePath: '.', isPublishable }));
31
33
  }
32
- return matched.map((tag) => ({ tag, kind: 'package', dir: '.', workspacePath: '.', isPublishable }));
34
+ return matchedTags.map((tag) => ({ tag, kind: 'package', dir: '.', workspacePath: '.', isPublishable }));
33
35
  }
34
36
  function resolveMonorepoTags(tags, workspaces, directories, project) {
35
37
  const sortedWorkspaces = workspaces.toSorted((a, b) => b.tagPrefix.length - a.tagPrefix.length);
36
- const resolved = [];
38
+ const resolvedTags = [];
37
39
  for (const tag of tags) {
38
- const match = findMatchingWorkspace(tag, sortedWorkspaces);
40
+ const matchedWorkspace = findMatchingWorkspace(tag, sortedWorkspaces);
39
41
  const directory = directories.find((candidate) => hasVersionAfterPrefix(tag, candidate.tagPrefix));
40
- if (match !== undefined) {
41
- resolved.push({
42
+ if (matchedWorkspace !== undefined) {
43
+ resolvedTags.push({
42
44
  tag,
43
45
  kind: 'package',
44
- dir: getTargetName(match),
45
- workspacePath: match.workspacePath,
46
- isPublishable: match.isPublishable,
46
+ dir: getTargetName(matchedWorkspace),
47
+ workspacePath: matchedWorkspace.workspacePath,
48
+ isPublishable: matchedWorkspace.isPublishable,
47
49
  });
48
50
  }
49
51
  else if (directory !== undefined) {
50
- resolved.push({
52
+ resolvedTags.push({
51
53
  tag,
52
54
  kind: 'directory',
53
55
  dir: directory.name,
@@ -56,7 +58,7 @@ function resolveMonorepoTags(tags, workspaces, directories, project) {
56
58
  });
57
59
  }
58
60
  else if (project !== undefined && hasVersionAfterPrefix(tag, project.tagPrefix)) {
59
- resolved.push({
61
+ resolvedTags.push({
60
62
  tag,
61
63
  kind: 'project',
62
64
  dir: project.name ?? PROJECT_TARGET_ID,
@@ -65,7 +67,7 @@ function resolveMonorepoTags(tags, workspaces, directories, project) {
65
67
  });
66
68
  }
67
69
  }
68
- return resolved;
70
+ return resolvedTags;
69
71
  }
70
72
  function findMatchingWorkspace(tag, sortedWorkspaces) {
71
73
  return sortedWorkspaces.find((workspace) => hasVersionAfterPrefix(tag, workspace.tagPrefix));
@@ -13,8 +13,8 @@ export function resolveReleaseTargets(userConfig, discovery) {
13
13
  return projectMonorepoConfig(mergeMonorepoConfig(discovery.packageDirs, userConfig, readRootPackageVersion()));
14
14
  }
15
15
  export function isSinglePackageTargets(targets) {
16
- const [only] = targets;
17
- return targets.length === 1 && only?.kind === 'package' && !only.isWorkspace;
16
+ const [onlyTarget] = targets;
17
+ return targets.length === 1 && onlyTarget?.kind === 'package' && !onlyTarget.isWorkspace;
18
18
  }
19
19
  export function projectMonorepoConfig(config) {
20
20
  const targets = [
@@ -59,12 +59,12 @@ function renderWorkspaceRow(row, style) {
59
59
  lines.push(` ${row.workspacePath}: derived prefix '${row.derivedPrefix}', ${statusMarker}`);
60
60
  for (const entry of row.legacyEntries) {
61
61
  if (entry.tagCount > 0) {
62
- const recognized = `${entry.tagCount} legacy tags with '${entry.prefix}' prefix (recognized)`;
63
- lines.push(` ${formatStatusLine(style, 'passed', recognized)}`);
62
+ const recognizedMessage = `${entry.tagCount} legacy tags with '${entry.prefix}' prefix (recognized)`;
63
+ lines.push(` ${formatStatusLine(style, 'passed', recognizedMessage)}`);
64
64
  }
65
65
  else {
66
- const tagless = `recorded legacy prefix '${entry.prefix}' does not have any tags`;
67
- lines.push(` ${formatStatusLine(style, 'warning', tagless)}`);
66
+ const taglessMessage = `recorded legacy prefix '${entry.prefix}' does not have any tags`;
67
+ lines.push(` ${formatStatusLine(style, 'warning', taglessMessage)}`);
68
68
  }
69
69
  }
70
70
  return lines;
@@ -20,7 +20,7 @@ export declare function loadRepoLabelsConfig(stderrStyle: OutputStyle, configPat
20
20
  /** Options for the `sync-labels generate` subcommand. */
21
21
  interface GenerateOptions {
22
22
  /** Compares the regenerated content against the committed file instead of writing. */
23
- check?: boolean;
23
+ shouldCheck?: boolean;
24
24
  /** Config file to read, relative to the working directory. Defaults to `CONFIG_FILE_PATH`. */
25
25
  configPath?: string;
26
26
  styles: StreamStyles;
@@ -28,11 +28,11 @@ interface GenerateOptions {
28
28
  /**
29
29
  * Runs the `sync-labels generate` command and returns the process exit code.
30
30
  *
31
- * Writes `.github/labels.yaml` from the config's `repoLabels` block, or, with `check`, reports whether the committed
31
+ * Writes `.github/labels.yaml` from the config's `repoLabels` block, or, with `shouldCheck`, reports whether the committed
32
32
  * file is stale and writes nothing.
33
33
  *
34
34
  * The header names the config by its POSIX path relative to the working directory, the repo root, so that the file
35
35
  * does not depend on the invocation directory or on the machine on which the command ran.
36
36
  */
37
- export declare function generateCommand({ check, configPath, styles }: GenerateOptions): Promise<number>;
37
+ export declare function generateCommand({ shouldCheck, configPath, styles }: GenerateOptions): Promise<number>;
38
38
  export {};
@@ -15,14 +15,14 @@ export function formatLabelsYaml(labels, presetHashes, configFilePath = CONFIG_F
15
15
  for (const [name, hash] of sortedPresetHashes) {
16
16
  headerLines.push(`# ${name} preset hash: ${hash}`);
17
17
  }
18
- const declared = labels.map(({ aliases, archived, color, description, name }) => ({
18
+ const declaredLabels = labels.map(({ aliases, archived, color, description, name }) => ({
19
19
  name,
20
20
  color,
21
21
  description: description ?? '',
22
22
  ...(aliases !== undefined && { aliases }),
23
23
  ...(archived !== undefined && { archived }),
24
24
  }));
25
- const yamlBody = stringify(declared, { singleQuote: true, lineWidth: 0 });
25
+ const yamlBody = stringify(declaredLabels, { singleQuote: true, lineWidth: 0 });
26
26
  return headerLines.join('\n') + '\n' + yamlBody;
27
27
  }
28
28
  export async function loadRepoLabelsConfig(stderrStyle, configPath) {
@@ -41,7 +41,7 @@ export async function loadRepoLabelsConfig(stderrStyle, configPath) {
41
41
  }
42
42
  return result.config.repoLabels;
43
43
  }
44
- export async function generateCommand({ check = false, configPath, styles }) {
44
+ export async function generateCommand({ shouldCheck = false, configPath, styles }) {
45
45
  if (checkRetiredSyncLabelsConfig(configPath)) {
46
46
  return 1;
47
47
  }
@@ -63,8 +63,8 @@ export async function generateCommand({ check = false, configPath, styles }) {
63
63
  for (const presetName of presetNames) {
64
64
  presetHashes.set(presetName, hashPreset(presetName));
65
65
  }
66
- const content = formatLabelsYaml(labels, presetHashes, toRootRelativePosixPath(configPath ?? CONFIG_FILE_PATH));
67
- if (check) {
66
+ const content = formatLabelsYaml(labels, presetHashes, convertToRootRelativePosixPath(configPath ?? CONFIG_FILE_PATH));
67
+ if (shouldCheck) {
68
68
  return compareAgainstCommittedFile(content);
69
69
  }
70
70
  try {
@@ -79,22 +79,22 @@ export async function generateCommand({ check = false, configPath, styles }) {
79
79
  console.info(`Generated ${LABELS_OUTPUT_PATH} with ${String(labels.length)} labels.`);
80
80
  return 0;
81
81
  }
82
- function compareAgainstCommittedFile(expected) {
83
- let existing;
82
+ function compareAgainstCommittedFile(expectedContent) {
83
+ let existingContent;
84
84
  try {
85
- existing = readFileSync(LABELS_OUTPUT_PATH, 'utf8');
85
+ existingContent = readFileSync(LABELS_OUTPUT_PATH, 'utf8');
86
86
  }
87
87
  catch {
88
88
  reportError(`${LABELS_OUTPUT_PATH} is missing. Run \`release-kit sync-labels generate\` and commit the result.`);
89
89
  return 1;
90
90
  }
91
- if (existing !== expected) {
91
+ if (existingContent !== expectedContent) {
92
92
  reportError(`${LABELS_OUTPUT_PATH} is stale. Run \`release-kit sync-labels generate\` and commit the result.`);
93
93
  return 1;
94
94
  }
95
95
  console.info(`${LABELS_OUTPUT_PATH} is up to date.`);
96
96
  return 0;
97
97
  }
98
- function toRootRelativePosixPath(filePath) {
98
+ function convertToRootRelativePosixPath(filePath) {
99
99
  return path.relative(process.cwd(), path.resolve(filePath)).split(path.sep).join('/');
100
100
  }
@@ -3,8 +3,8 @@ import { type StreamStyles } from '@williamthorsen/nmr-core';
3
3
  interface InitOptions {
4
4
  /** Config file to read, relative to the working directory. Defaults to `CONFIG_FILE_PATH`. */
5
5
  configPath?: string;
6
- dryRun: boolean;
7
- force: boolean;
6
+ isDryRun: boolean;
7
+ shouldForce: boolean;
8
8
  styles: StreamStyles;
9
9
  }
10
10
  /**
@@ -17,5 +17,5 @@ interface InitOptions {
17
17
  * `configPath` names the config to read. Because the command fails when the named config does not exist, it
18
18
  * reaches the scaffolding branch only under the default path, and that branch always writes to `CONFIG_FILE_PATH`.
19
19
  */
20
- export declare function syncLabelsInitCommand({ configPath, dryRun, force, styles }: InitOptions): Promise<number>;
20
+ export declare function syncLabelsInitCommand({ configPath, isDryRun, shouldForce, styles, }: InitOptions): Promise<number>;
21
21
  export {};
@@ -6,14 +6,14 @@ import { CONFIG_FILE_PATH } from "../loadConfig.js";
6
6
  import { loadValidatedConfig, reportConfigProblem } from "../loadValidatedConfig.js";
7
7
  import { generateCommand, LABELS_OUTPUT_PATH } from "./generateCommand.js";
8
8
  import { checkRetiredSyncLabelsConfig } from "./retiredConfig.js";
9
- import { buildScopeLabels, readSyncLabelsWorkflowTemplate, renderRepoLabelsBlock, repoLabelsConfigScript, } from "./templates.js";
9
+ import { buildScopeLabels, readSyncLabelsWorkflowTemplate, renderRepoLabelsBlock, renderRepoLabelsConfigScript, } from "./templates.js";
10
10
  const WORKFLOW_PATH = '.github/workflows/sync-labels.yaml';
11
- export async function syncLabelsInitCommand({ configPath, dryRun, force, styles }) {
11
+ export async function syncLabelsInitCommand({ configPath, isDryRun, shouldForce, styles, }) {
12
12
  const configFilePath = configPath ?? CONFIG_FILE_PATH;
13
13
  if (checkRetiredSyncLabelsConfig(configPath)) {
14
14
  return 1;
15
15
  }
16
- if (dryRun) {
16
+ if (isDryRun) {
17
17
  console.info('[dry-run mode]');
18
18
  }
19
19
  console.info('\n> Discovering workspaces');
@@ -36,8 +36,8 @@ export async function syncLabelsInitCommand({ configPath, dryRun, force, styles
36
36
  else {
37
37
  console.info(` Found ${String(workspace.packageDirs.length)} workspaces`);
38
38
  }
39
- const configExists = configPath !== undefined || existsSync(CONFIG_FILE_PATH);
40
- const retiredNames = configExists ? await loadRetiredPackageNames(styles, configPath) : [];
39
+ const doesConfigExist = configPath !== undefined || existsSync(CONFIG_FILE_PATH);
40
+ const retiredNames = doesConfigExist ? await loadRetiredPackageNames(styles, configPath) : [];
41
41
  if (retiredNames === undefined) {
42
42
  return 1;
43
43
  }
@@ -51,9 +51,9 @@ export async function syncLabelsInitCommand({ configPath, dryRun, force, styles
51
51
  process.stderr.write(` ${describeError(error)}\n`);
52
52
  return 1;
53
53
  }
54
- const workflowResult = writeFileWithCheck(WORKFLOW_PATH, workflow, { isDryRun: dryRun, shouldOverwrite: force });
55
- reportWriteResult(workflowResult, dryRun, styles);
56
- if (configExists) {
54
+ const workflowResult = writeFileWithCheck(WORKFLOW_PATH, workflow, { isDryRun, shouldOverwrite: shouldForce });
55
+ reportWriteResult(workflowResult, isDryRun, styles);
56
+ if (doesConfigExist) {
57
57
  console.info(`\n> ${configFilePath} already exists; add this block to the object passed to defineConfig:\n`);
58
58
  console.info(renderRepoLabelsBlock(scopeLabels));
59
59
  if (workflowResult.outcome === 'failed') {
@@ -69,16 +69,16 @@ export async function syncLabelsInitCommand({ configPath, dryRun, force, styles
69
69
  `);
70
70
  return 0;
71
71
  }
72
- const configResult = writeFileWithCheck(CONFIG_FILE_PATH, repoLabelsConfigScript(scopeLabels), {
73
- isDryRun: dryRun,
74
- shouldOverwrite: force,
72
+ const configResult = writeFileWithCheck(CONFIG_FILE_PATH, renderRepoLabelsConfigScript(scopeLabels), {
73
+ isDryRun,
74
+ shouldOverwrite: shouldForce,
75
75
  });
76
- reportWriteResult(configResult, dryRun, styles);
76
+ reportWriteResult(configResult, isDryRun, styles);
77
77
  if (workflowResult.outcome === 'failed' || configResult.outcome === 'failed') {
78
78
  process.stderr.write('Failed to scaffold one or more files.\n');
79
79
  return 1;
80
80
  }
81
- if (dryRun) {
81
+ if (isDryRun) {
82
82
  console.info(`\n> [dry-run] Would generate ${LABELS_OUTPUT_PATH}`);
83
83
  }
84
84
  else {
@@ -109,8 +109,8 @@ async function loadRetiredPackageNames(styles, configPath) {
109
109
  if (result.status === 'missing') {
110
110
  return [];
111
111
  }
112
- return (result.config.retiredPackages ?? []).map((retired) => toUnscopedName(retired.name));
112
+ return (result.config.retiredPackages ?? []).map((retired) => stripNpmScope(retired.name));
113
113
  }
114
- function toUnscopedName(name) {
114
+ function stripNpmScope(name) {
115
115
  return name.startsWith('@') ? name.slice(name.indexOf('/') + 1) : name;
116
116
  }
@@ -25,12 +25,12 @@ export function loadPreset(presetName) {
25
25
  catch (error) {
26
26
  throw chainError(`Failed to read preset "${presetName}"`, error);
27
27
  }
28
- const parsed = parse(content);
29
- if (!Array.isArray(parsed)) {
28
+ const parsedYaml = parse(content);
29
+ if (!Array.isArray(parsedYaml)) {
30
30
  throw new TypeError(`Preset "${presetName}" must be a YAML array of label definitions`);
31
31
  }
32
32
  const labels = [];
33
- for (const entry of parsed) {
33
+ for (const entry of parsedYaml) {
34
34
  if (!isRecord(entry)) {
35
35
  throw new Error(`Preset "${presetName}" contains an invalid label entry: ${JSON.stringify(entry)}`);
36
36
  }
@@ -6,23 +6,23 @@ export function resolveLabels(config) {
6
6
  const groupList = caseVariantGroups.map((group) => group.map((name) => `'${name}'`).join(' and ')).join('; ');
7
7
  throw new Error(`Keys in 'labels' differ only in case, which GitHub treats as the same label: ${groupList}. Keep one entry per label.`);
8
8
  }
9
- const resolved = new Map();
9
+ const resolvedLabels = new Map();
10
10
  const presetNames = config.extends ?? [];
11
11
  for (const presetName of presetNames) {
12
12
  for (const label of loadPreset(presetName)) {
13
- resolved.set(toLabelKey(label.name), label);
13
+ resolvedLabels.set(getLabelKey(label.name), label);
14
14
  }
15
15
  }
16
16
  for (const [name, spec] of labelEntries) {
17
- const key = toLabelKey(name);
17
+ const key = getLabelKey(name);
18
18
  if (spec === null) {
19
- if (!resolved.has(key)) {
19
+ if (!resolvedLabels.has(key)) {
20
20
  throw new Error(`Label '${name}' is set to null (remove), but the presets in 'extends' don't define it. Fix the name or delete the entry.`);
21
21
  }
22
- resolved.delete(key);
22
+ resolvedLabels.delete(key);
23
23
  }
24
24
  else {
25
- resolved.set(key, {
25
+ resolvedLabels.set(key, {
26
26
  name,
27
27
  color: spec.color,
28
28
  ...(spec.description !== undefined && { description: spec.description }),
@@ -31,7 +31,7 @@ export function resolveLabels(config) {
31
31
  });
32
32
  }
33
33
  }
34
- const labels = sortLabels(resolved.values().toArray());
34
+ const labels = sortLabels(resolvedLabels.values().toArray());
35
35
  const aliasCollisions = findAliasCollisions(labels);
36
36
  if (aliasCollisions.length > 0) {
37
37
  throw new Error(`Aliases must name labels that are not declared and must not repeat, or the sync merges one label into another and deletes it: ${aliasCollisions.join('; ')}.`);
@@ -39,13 +39,13 @@ export function resolveLabels(config) {
39
39
  return labels;
40
40
  }
41
41
  function findAliasCollisions(labels) {
42
- const labelNamesByKey = new Map(labels.map((label) => [toLabelKey(label.name), label.name]));
42
+ const labelNamesByKey = new Map(labels.map((label) => [getLabelKey(label.name), label.name]));
43
43
  const aliasOwnersByKey = new Map();
44
44
  const collisions = [];
45
45
  for (const label of labels) {
46
46
  const aliases = label.aliases ?? [];
47
47
  for (const alias of aliases) {
48
- const key = toLabelKey(alias);
48
+ const key = getLabelKey(alias);
49
49
  const namedLabel = labelNamesByKey.get(key);
50
50
  const earlierOwner = aliasOwnersByKey.get(key);
51
51
  if (namedLabel !== undefined) {
@@ -62,14 +62,14 @@ function findAliasCollisions(labels) {
62
62
  return collisions;
63
63
  }
64
64
  function findCaseVariantGroups(names) {
65
- return Map.groupBy(names, toLabelKey)
65
+ return Map.groupBy(names, getLabelKey)
66
66
  .values()
67
67
  .filter((group) => group.length > 1)
68
68
  .toArray();
69
69
  }
70
+ function getLabelKey(name) {
71
+ return name.toLowerCase();
72
+ }
70
73
  function sortLabels(labels) {
71
74
  return labels.toSorted((a, b) => a.name.localeCompare(b.name));
72
75
  }
73
- function toLabelKey(name) {
74
- return name.toLowerCase();
75
- }
@@ -15,5 +15,5 @@ export declare function buildScopeLabels(workspacePaths: string[], retiredNames?
15
15
  * `.config/release-kit.config.ts`.
16
16
  */
17
17
  export declare function renderRepoLabelsBlock(scopeLabels: LabelDefinition[]): string;
18
- /** Generates a new `.config/release-kit.config.ts` containing the `repoLabels` block. */
19
- export declare function repoLabelsConfigScript(scopeLabels: LabelDefinition[]): string;
18
+ /** Renders a new `.config/release-kit.config.ts` containing the `repoLabels` block. */
19
+ export declare function renderRepoLabelsConfigScript(scopeLabels: LabelDefinition[]): string;
@@ -33,7 +33,7 @@ export function renderRepoLabelsBlock(scopeLabels) {
33
33
  ${labelsBlock}
34
34
  },`;
35
35
  }
36
- export function repoLabelsConfigScript(scopeLabels) {
36
+ export function renderRepoLabelsConfigScript(scopeLabels) {
37
37
  return `import { defineConfig } from '@williamthorsen/release-kit/config';
38
38
 
39
39
  export default defineConfig({
@@ -2,13 +2,13 @@ import { parseArgsOrExit, reportError } from '@williamthorsen/nmr-core';
2
2
  import { describeError } from '@williamthorsen/toolbelt.errors';
3
3
  import { createTags } from "./createTags.js";
4
4
  const tagFlagSchema = {
5
- dryRun: { long: '--dry-run', type: 'boolean' },
6
- noGitChecks: { long: '--no-git-checks', type: 'boolean' },
5
+ isDryRun: { long: '--dry-run', type: 'boolean' },
6
+ shouldSkipGitChecks: { long: '--no-git-checks', type: 'boolean' },
7
7
  };
8
8
  export function tagCommand(argv, styles) {
9
- const { dryRun, noGitChecks } = parseArgsOrExit(argv, tagFlagSchema).flags;
9
+ const { isDryRun, shouldSkipGitChecks } = parseArgsOrExit(argv, tagFlagSchema).flags;
10
10
  try {
11
- createTags({ dryRun, noGitChecks, style: styles.stdout });
11
+ createTags({ isDryRun, shouldSkipGitChecks, style: styles.stdout });
12
12
  }
13
13
  catch (error) {
14
14
  reportError(describeError(error));
@@ -6,7 +6,7 @@ import type { ReleaseEntry } from './propagateBumps.js';
6
6
  * Uses Kahn's algorithm. Targets not in the release set are excluded. If the graph has
7
7
  * cycles, the remaining nodes are appended in arbitrary order and reported via `cyclicIds`.
8
8
  */
9
- export declare function topologicalSort(releaseSet: Map<string, ReleaseEntry>, graph: DependencyGraph): {
10
- sorted: string[];
9
+ export declare function sortTopologically(releaseSet: Map<string, ReleaseEntry>, graph: DependencyGraph): {
10
+ sortedIds: string[];
11
11
  cyclicIds: string[];
12
12
  };
@@ -1,7 +1,7 @@
1
- export function topologicalSort(releaseSet, graph) {
1
+ export function sortTopologically(releaseSet, graph) {
2
2
  const releaseIds = new Set(releaseSet.keys());
3
3
  if (releaseIds.size === 0) {
4
- return { sorted: [], cyclicIds: [] };
4
+ return { sortedIds: [], cyclicIds: [] };
5
5
  }
6
6
  const inDegree = new Map();
7
7
  const forwardEdges = new Map();
@@ -31,13 +31,13 @@ export function topologicalSort(releaseSet, graph) {
31
31
  queue.push(id);
32
32
  }
33
33
  }
34
- const sorted = [];
34
+ const sortedIds = [];
35
35
  while (queue.length > 0) {
36
36
  const id = queue.shift();
37
37
  if (id === undefined) {
38
38
  break;
39
39
  }
40
- sorted.push(id);
40
+ sortedIds.push(id);
41
41
  const dependents = forwardEdges.get(id) ?? [];
42
42
  for (const dependent of dependents) {
43
43
  const newDegree = (inDegree.get(dependent) ?? 1) - 1;
@@ -47,14 +47,14 @@ export function topologicalSort(releaseSet, graph) {
47
47
  }
48
48
  }
49
49
  }
50
- const sortedSet = new Set(sorted);
50
+ const sortedSet = new Set(sortedIds);
51
51
  const cyclicIds = [];
52
52
  for (const id of releaseIds) {
53
53
  if (sortedSet.has(id)) {
54
54
  continue;
55
55
  }
56
- sorted.push(id);
56
+ sortedIds.push(id);
57
57
  cyclicIds.push(id);
58
58
  }
59
- return { sorted, cyclicIds };
59
+ return { sortedIds, cyclicIds };
60
60
  }
@@ -70,7 +70,7 @@ export interface ChangelogMarkdownConfig {
70
70
  * How many of the newest versioned sections `CHANGELOG.md` keeps; older sections go to per-major archive files
71
71
  * under `changelogs/`. When omitted, `CHANGELOG.md` keeps every section.
72
72
  */
73
- keepVersions?: number;
73
+ keptVersionCount?: number;
74
74
  }
75
75
  /**
76
76
  * Editorial override for changelog items, keyed in the override file by `<hash>` (every item of the commit) or
@@ -245,7 +245,7 @@ export interface ReleasedPackageResult extends PackageResultFields, ReleaseField
245
245
  /** Present when propagation alone set the bump, the package's own commits having called for none. */
246
246
  propagatedOnly?: true;
247
247
  /** Present when the package was written via `--set-version`; the explicit version that was applied. */
248
- setVersion?: string;
248
+ versionOverride?: string;
249
249
  }
250
250
  /** Result of a package target that skips: the diagnostic fields and a human-readable `skipReason`. */
251
251
  export interface SkippedPackageResult extends PackageResultFields {
@@ -280,7 +280,7 @@ export interface ReleasedDirectoryResult extends DirectoryResultFields, ReleaseF
280
280
  /** Raw commits of the directory's unreleased window. */
281
281
  commits: Commit[];
282
282
  /** Present when the directory was written via `--set-version`; the explicit version that was applied. */
283
- setVersion?: string;
283
+ versionOverride?: string;
284
284
  }
285
285
  /** Result of a directory target that skips: the diagnostic fields and a human-readable `skipReason`. */
286
286
  export interface SkippedDirectoryResult extends DirectoryResultFields {
@@ -89,8 +89,8 @@ function prefixWithFilePath(filePath, message) {
89
89
  }
90
90
  function processProjectScope(args) {
91
91
  const { projectFilePath, projectMap, projectItems, errors, globalMatchedRootKeys } = args;
92
- const applied = applyChangelogOverrides(makeValidationEntries(projectItems), projectMap);
93
- for (const message of applied.errors) {
92
+ const appliedResult = applyChangelogOverrides(makeValidationEntries(projectItems), projectMap);
93
+ for (const message of appliedResult.errors) {
94
94
  errors.push(prefixWithFilePath(projectFilePath, message));
95
95
  }
96
96
  const positionsByHash = indexItemPositions(projectItems);
@@ -105,19 +105,19 @@ function processWorkspaceScope(args) {
105
105
  const { filePath, items, map } = workspace;
106
106
  const validationEntries = makeValidationEntries(items);
107
107
  const positionsByHash = indexItemPositions(items);
108
- const workspaceApplied = applyChangelogOverrides(validationEntries, map);
109
- for (const message of workspaceApplied.errors) {
108
+ const workspaceAppliedResult = applyChangelogOverrides(validationEntries, map);
109
+ for (const message of workspaceAppliedResult.errors) {
110
110
  errors.push(prefixWithFilePath(filePath, message));
111
111
  }
112
112
  if (projectFilePath !== undefined && projectMap.size > 0) {
113
113
  const projectMinusShadowed = filterShadowedKeys(projectMap, map);
114
- const projectApplied = applyChangelogOverrides(validationEntries, projectMinusShadowed);
115
- for (const message of projectApplied.errors) {
114
+ const projectAppliedResult = applyChangelogOverrides(validationEntries, projectMinusShadowed);
115
+ for (const message of projectAppliedResult.errors) {
116
116
  errors.push(prefixWithFilePath(projectFilePath, message));
117
117
  }
118
- const perFileErrors = new Set([...workspaceApplied.errors, ...projectApplied.errors]);
119
- const composedApplied = applyChangelogOverrides(validationEntries, composeOverrides(projectMap, map));
120
- for (const message of composedApplied.errors) {
118
+ const perFileErrors = new Set([...workspaceAppliedResult.errors, ...projectAppliedResult.errors]);
119
+ const composedAppliedResult = applyChangelogOverrides(validationEntries, composeOverrides(projectMap, map));
120
+ for (const message of composedAppliedResult.errors) {
121
121
  if (!perFileErrors.has(message)) {
122
122
  errors.push(prefixWithFilePath(filePath, message));
123
123
  }
@@ -3,7 +3,7 @@ import { type ReleaseKitConfig } from './configSchema.js';
3
3
  * Validates a raw config object loaded from `.config/release-kit.config.ts`. Returns `{}` with the errors for a config
4
4
  * that fails the schema parse, and runs the cross-field checks on one that passes.
5
5
  */
6
- export declare function validateConfig(raw: unknown): {
6
+ export declare function validateConfig(rawConfig: unknown): {
7
7
  config: ReleaseKitConfig;
8
8
  errors: string[];
9
9
  warnings: string[];