package-versioner 0.6.3 → 0.7.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.
package/dist/index.js CHANGED
@@ -1,79 +1,14 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/index.ts
4
- import * as fs7 from "node:fs";
5
- import path5 from "node:path";
4
+ import * as fs9 from "node:fs";
5
+ import path7 from "node:path";
6
6
  import { Command } from "commander";
7
7
 
8
- // src/config.ts
9
- import * as fs from "node:fs";
10
- import { cwd } from "node:process";
11
- function loadConfig(configPath) {
12
- const localProcess = cwd();
13
- const filePath = configPath || `${localProcess}/version.config.json`;
14
- return new Promise((resolve, reject) => {
15
- fs.readFile(filePath, "utf-8", (err, data) => {
16
- if (err) {
17
- reject(new Error(`Could not locate the config file at ${filePath}: ${err.message}`));
18
- return;
19
- }
20
- try {
21
- const config = JSON.parse(data);
22
- resolve(config);
23
- } catch (err2) {
24
- const errorMessage = err2 instanceof Error ? err2.message : String(err2);
25
- reject(new Error(`Failed to parse config file ${filePath}: ${errorMessage}`));
26
- }
27
- });
28
- });
29
- }
30
-
31
- // src/core/versionEngine.ts
32
- import { cwd as cwd4 } from "node:process";
33
- import { getPackagesSync } from "@manypkg/get-packages";
34
-
35
- // src/errors/gitError.ts
36
- var GitError = class extends Error {
37
- constructor(message, code) {
38
- super(message);
39
- this.code = code;
40
- this.name = "GitError";
41
- }
42
- };
43
- function createGitError(code, details) {
44
- const messages = {
45
- ["NOT_GIT_REPO" /* NOT_GIT_REPO */]: "Not a git repository",
46
- ["GIT_PROCESS_ERROR" /* GIT_PROCESS_ERROR */]: "Failed to create new version",
47
- ["NO_FILES" /* NO_FILES */]: "No files specified for commit",
48
- ["NO_COMMIT_MESSAGE" /* NO_COMMIT_MESSAGE */]: "Commit message is required",
49
- ["GIT_ERROR" /* GIT_ERROR */]: "Git operation failed"
50
- };
51
- const baseMessage = messages[code];
52
- const fullMessage = details ? `${baseMessage}: ${details}` : baseMessage;
53
- return new GitError(fullMessage, code);
54
- }
55
-
56
- // src/errors/versionError.ts
57
- var VersionError = class extends Error {
58
- constructor(message, code) {
59
- super(message);
60
- this.code = code;
61
- this.name = "VersionError";
62
- }
63
- };
64
- function createVersionError(code, details) {
65
- const messages = {
66
- ["CONFIG_REQUIRED" /* CONFIG_REQUIRED */]: "Configuration is required",
67
- ["PACKAGES_NOT_FOUND" /* PACKAGES_NOT_FOUND */]: "Failed to get packages information",
68
- ["WORKSPACE_ERROR" /* WORKSPACE_ERROR */]: "Failed to get workspace packages",
69
- ["INVALID_CONFIG" /* INVALID_CONFIG */]: "Invalid configuration",
70
- ["PACKAGE_NOT_FOUND" /* PACKAGE_NOT_FOUND */]: "Package not found",
71
- ["VERSION_CALCULATION_ERROR" /* VERSION_CALCULATION_ERROR */]: "Failed to calculate version"
72
- };
73
- const baseMessage = messages[code];
74
- const fullMessage = details ? `${baseMessage}: ${details}` : baseMessage;
75
- return new VersionError(fullMessage, code);
76
- }
8
+ // src/changelog/changelogRegenerator.ts
9
+ import { execSync as execSync2 } from "node:child_process";
10
+ import fs from "node:fs";
11
+ import path from "node:path";
77
12
 
78
13
  // src/utils/logging.ts
79
14
  import chalk from "chalk";
@@ -156,9 +91,508 @@ function log(message, level = "info") {
156
91
  }
157
92
  }
158
93
 
94
+ // src/changelog/commitParser.ts
95
+ import { execSync } from "node:child_process";
96
+ var CONVENTIONAL_COMMIT_REGEX = /^(\w+)(?:\(([^)]+)\))?(!)?: (.+)(?:\n\n([\s\S]*))?/;
97
+ var BREAKING_CHANGE_REGEX = /BREAKING CHANGE: ([\s\S]+?)(?:\n\n|$)/;
98
+ function extractChangelogEntriesFromCommits(projectDir, revisionRange) {
99
+ try {
100
+ const command = `git log ${revisionRange} --pretty=format:"%B---COMMIT_DELIMITER---" --no-merges`;
101
+ const output = execSync(command, {
102
+ cwd: projectDir,
103
+ encoding: "utf8"
104
+ });
105
+ const commits = output.split("---COMMIT_DELIMITER---").filter((commit) => commit.trim() !== "");
106
+ return commits.map((commit) => parseCommitMessage(commit)).filter((entry) => entry !== null);
107
+ } catch (error) {
108
+ log(`Error extracting commits: ${error}`, "error");
109
+ return [];
110
+ }
111
+ }
112
+ function parseCommitMessage(message) {
113
+ const match = message.match(CONVENTIONAL_COMMIT_REGEX);
114
+ if (match) {
115
+ const [, type, scope, breakingMark, subject, body = ""] = match;
116
+ const breakingFromMark = breakingMark === "!";
117
+ const breakingChangeMatch = body.match(BREAKING_CHANGE_REGEX);
118
+ const hasBreakingChange = breakingFromMark || breakingChangeMatch !== null;
119
+ const changelogType = mapCommitTypeToChangelogType(type);
120
+ if (!changelogType) {
121
+ return null;
122
+ }
123
+ const issueIds = extractIssueIds(body);
124
+ let description = subject;
125
+ if (hasBreakingChange) {
126
+ description = `**BREAKING** ${description}`;
127
+ }
128
+ return {
129
+ type: changelogType,
130
+ description,
131
+ scope: scope || void 0,
132
+ issueIds: issueIds.length > 0 ? issueIds : void 0,
133
+ originalType: type
134
+ // Store original type for custom formatting
135
+ };
136
+ }
137
+ if (!message.startsWith("Merge") && !message.match(/^v?\d+\.\d+\.\d+/)) {
138
+ const firstLine = message.split("\n")[0].trim();
139
+ return {
140
+ type: "changed",
141
+ description: firstLine
142
+ };
143
+ }
144
+ return null;
145
+ }
146
+ function mapCommitTypeToChangelogType(type) {
147
+ switch (type) {
148
+ case "feat":
149
+ return "added";
150
+ case "fix":
151
+ return "fixed";
152
+ case "docs":
153
+ case "style":
154
+ case "refactor":
155
+ case "perf":
156
+ case "build":
157
+ case "ci":
158
+ return "changed";
159
+ case "revert":
160
+ return "removed";
161
+ case "chore":
162
+ return "changed";
163
+ case "test":
164
+ return null;
165
+ default:
166
+ return "changed";
167
+ }
168
+ }
169
+ function extractIssueIds(body) {
170
+ const issueRegex = /(?:fix|fixes|close|closes|resolve|resolves)\s+#(\d+)/gi;
171
+ const issueIds = [];
172
+ let match = issueRegex.exec(body);
173
+ while (match !== null) {
174
+ issueIds.push(`#${match[1]}`);
175
+ match = issueRegex.exec(body);
176
+ }
177
+ return issueIds;
178
+ }
179
+
180
+ // src/changelog/formatters.ts
181
+ function formatChangelogEntries(format, version, date, entries, packageName, repoUrl) {
182
+ const formattingEntries = entries.map((entry) => {
183
+ const hasBreaking = entry.description.includes("**BREAKING**");
184
+ return {
185
+ ...entry,
186
+ breaking: hasBreaking
187
+ };
188
+ });
189
+ return format === "keep-a-changelog" ? formatKeepAChangelogEntries(version, date, formattingEntries, repoUrl) : formatAngularEntries(version, date, formattingEntries, packageName);
190
+ }
191
+ function formatKeepAChangelogEntries(version, date, entries, repoUrl) {
192
+ const added = [];
193
+ const changed = [];
194
+ const deprecated = [];
195
+ const removed = [];
196
+ const fixed = [];
197
+ const security = [];
198
+ for (const entry of entries) {
199
+ const entryText = entry.scope ? `- **${entry.scope}**: ${entry.description}` : `- ${entry.description}`;
200
+ const formattedEntry = entry.breaking ? entryText.replace(/^- /, "- **BREAKING** ") : entryText;
201
+ const entryType = entry.originalType || entry.type;
202
+ switch (entryType) {
203
+ case "feat":
204
+ added.push(formattedEntry);
205
+ break;
206
+ case "fix":
207
+ fixed.push(formattedEntry);
208
+ break;
209
+ case "docs":
210
+ case "style":
211
+ case "refactor":
212
+ case "perf":
213
+ case "build":
214
+ case "ci":
215
+ changed.push(formattedEntry);
216
+ break;
217
+ case "test":
218
+ break;
219
+ case "chore":
220
+ if (entry.description.toLowerCase().includes("deprecat")) {
221
+ deprecated.push(formattedEntry);
222
+ } else {
223
+ changed.push(formattedEntry);
224
+ }
225
+ break;
226
+ // Keep-a-changelog standard types
227
+ case "added":
228
+ added.push(formattedEntry);
229
+ break;
230
+ case "changed":
231
+ changed.push(formattedEntry);
232
+ break;
233
+ case "deprecated":
234
+ deprecated.push(formattedEntry);
235
+ break;
236
+ case "removed":
237
+ removed.push(formattedEntry);
238
+ break;
239
+ case "fixed":
240
+ fixed.push(formattedEntry);
241
+ break;
242
+ case "security":
243
+ security.push(formattedEntry);
244
+ break;
245
+ default:
246
+ changed.push(formattedEntry);
247
+ }
248
+ }
249
+ let content = `## [${version}] - ${date}
250
+
251
+ `;
252
+ if (added.length > 0) {
253
+ content += `### Added
254
+
255
+ ${added.join("\n")}
256
+
257
+ `;
258
+ }
259
+ if (changed.length > 0) {
260
+ content += `### Changed
261
+
262
+ ${changed.join("\n")}
263
+
264
+ `;
265
+ }
266
+ if (deprecated.length > 0) {
267
+ content += `### Deprecated
268
+
269
+ ${deprecated.join("\n")}
270
+
271
+ `;
272
+ }
273
+ if (removed.length > 0) {
274
+ content += `### Removed
275
+
276
+ ${removed.join("\n")}
277
+
278
+ `;
279
+ }
280
+ if (fixed.length > 0) {
281
+ content += `### Fixed
282
+
283
+ ${fixed.join("\n")}
284
+
285
+ `;
286
+ }
287
+ if (security.length > 0) {
288
+ content += `### Security
289
+
290
+ ${security.join("\n")}
291
+
292
+ `;
293
+ }
294
+ if (repoUrl) {
295
+ content += `[${version}]: ${repoUrl}/compare/v${version}...HEAD
296
+ `;
297
+ }
298
+ return content.trim();
299
+ }
300
+ function formatAngularEntries(version, date, entries, packageName) {
301
+ const features = [];
302
+ const bugfixes = [];
303
+ const performance = [];
304
+ const breaking = [];
305
+ for (const entry of entries) {
306
+ if (entry.breaking) {
307
+ breaking.push(entry);
308
+ }
309
+ const entryType = entry.originalType || entry.type;
310
+ switch (entryType) {
311
+ case "feat":
312
+ case "added":
313
+ features.push(entry);
314
+ break;
315
+ case "fix":
316
+ case "fixed":
317
+ bugfixes.push(entry);
318
+ break;
319
+ case "perf":
320
+ performance.push(entry);
321
+ break;
322
+ }
323
+ }
324
+ let content = `## [${version}]${packageName ? ` (${packageName})` : ""} (${date})
325
+
326
+ `;
327
+ if (features.length > 0) {
328
+ content += "### Features\n\n";
329
+ content += formatAngularTypeEntries(features);
330
+ content += "\n";
331
+ }
332
+ if (bugfixes.length > 0) {
333
+ content += "### Bug Fixes\n\n";
334
+ content += formatAngularTypeEntries(bugfixes);
335
+ content += "\n";
336
+ }
337
+ if (performance.length > 0) {
338
+ content += "### Performance Improvements\n\n";
339
+ content += formatAngularTypeEntries(performance);
340
+ content += "\n";
341
+ }
342
+ if (breaking.length > 0) {
343
+ content += "### BREAKING CHANGES\n\n";
344
+ content += formatAngularTypeEntries(breaking);
345
+ content += "\n";
346
+ }
347
+ return content.trim();
348
+ }
349
+ function formatAngularTypeEntries(entries) {
350
+ var _a;
351
+ const entriesByScope = /* @__PURE__ */ new Map();
352
+ for (const entry of entries) {
353
+ const scope = entry.scope || "";
354
+ if (!entriesByScope.has(scope)) {
355
+ entriesByScope.set(scope, []);
356
+ }
357
+ (_a = entriesByScope.get(scope)) == null ? void 0 : _a.push(entry);
358
+ }
359
+ const result = [];
360
+ for (const [scope, scopeEntries] of Object.entries(groupEntriesByScope(entries))) {
361
+ if (scope !== "undefined" && scope !== "") {
362
+ result.push(`* **${scope}:**`);
363
+ for (const entry of scopeEntries) {
364
+ const description = entry.description.replace("**BREAKING** ", "");
365
+ result.push(` * ${description}`);
366
+ }
367
+ } else {
368
+ for (const entry of scopeEntries) {
369
+ const description = entry.description.replace("**BREAKING** ", "");
370
+ result.push(`* ${description}`);
371
+ }
372
+ }
373
+ }
374
+ return result.join("\n");
375
+ }
376
+ function groupEntriesByScope(entries) {
377
+ const result = {};
378
+ for (const entry of entries) {
379
+ const scope = entry.scope || "";
380
+ if (!result[scope]) {
381
+ result[scope] = [];
382
+ }
383
+ result[scope].push(entry);
384
+ }
385
+ return result;
386
+ }
387
+
388
+ // src/changelog/templates.ts
389
+ function getDefaultTemplate(format) {
390
+ return format === "keep-a-changelog" ? getKeepAChangelogTemplate() : getAngularTemplate();
391
+ }
392
+ function getKeepAChangelogTemplate() {
393
+ return `# Changelog
394
+
395
+ All notable changes to this project will be documented in this file.
396
+
397
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
398
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
399
+
400
+ `;
401
+ }
402
+ function getAngularTemplate() {
403
+ return `# Changelog
404
+
405
+ `;
406
+ }
407
+
408
+ // src/changelog/changelogRegenerator.ts
409
+ function getAllVersionTags(since, versionPrefix = "v") {
410
+ try {
411
+ const command = since ? `git tag --list "${versionPrefix}*" --sort=creatordate --contains ${since}` : `git tag --list "${versionPrefix}*" --sort=creatordate`;
412
+ const tagOutput = execSync2(command, { encoding: "utf8" }).trim();
413
+ if (!tagOutput) {
414
+ return [];
415
+ }
416
+ const tags = tagOutput.split("\n").filter((tag) => !!tag);
417
+ return tags.map((tag) => {
418
+ try {
419
+ const date = execSync2(`git log -1 --format=%ad --date=short ${tag}`, {
420
+ encoding: "utf8"
421
+ }).trim();
422
+ const version = tag.replace(new RegExp(`^${versionPrefix}`), "");
423
+ return { tag, version, date };
424
+ } catch (error) {
425
+ log(`Failed to get date for tag ${tag}: ${error}`, "warning");
426
+ return { tag, version: tag.replace(new RegExp(`^${versionPrefix}`), ""), date: "Unknown" };
427
+ }
428
+ });
429
+ } catch (error) {
430
+ log(`Failed to get version tags: ${error}`, "error");
431
+ return [];
432
+ }
433
+ }
434
+ async function regenerateChangelog(options) {
435
+ const { format, since, projectDir } = options;
436
+ const packageJsonPath = path.join(projectDir, "package.json");
437
+ let packageName = "";
438
+ let repoUrl = options.repoUrl;
439
+ if (fs.existsSync(packageJsonPath)) {
440
+ try {
441
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
442
+ packageName = packageJson.name || "";
443
+ if (!repoUrl && packageJson.repository) {
444
+ if (typeof packageJson.repository === "string") {
445
+ repoUrl = packageJson.repository;
446
+ } else if (packageJson.repository.url) {
447
+ repoUrl = packageJson.repository.url;
448
+ }
449
+ if ((repoUrl == null ? void 0 : repoUrl.startsWith("git+")) && (repoUrl == null ? void 0 : repoUrl.endsWith(".git"))) {
450
+ repoUrl = repoUrl.substring(4, repoUrl.length - 4);
451
+ }
452
+ }
453
+ } catch (error) {
454
+ log(`Failed to read package.json: ${error}`, "warning");
455
+ }
456
+ }
457
+ let versionPrefix = "v";
458
+ try {
459
+ const allTags = execSync2("git tag --list", { encoding: "utf8" }).trim().split("\n");
460
+ const versionTag = allTags.find((tag) => /^[vV][0-9]/.test(tag));
461
+ if (versionTag) {
462
+ versionPrefix = versionTag.charAt(0);
463
+ }
464
+ } catch {
465
+ }
466
+ const tags = getAllVersionTags(since, versionPrefix);
467
+ if (!tags.length) {
468
+ throw new Error(
469
+ 'No version tags found in git history. Make sure you have tags that start with the version prefix (usually "v").'
470
+ );
471
+ }
472
+ let changelogContent = getDefaultTemplate(format);
473
+ log(`Found ${tags.length} version tags, generating changelog...`, "info");
474
+ const versions = [];
475
+ for (let i = tags.length - 1; i >= 0; i--) {
476
+ const currentTag = tags[i];
477
+ const previousTag = i > 0 ? tags[i - 1].tag : null;
478
+ log(`Processing changes for ${currentTag.tag}...`, "info");
479
+ try {
480
+ const tagRange = previousTag ? `${previousTag}..${currentTag.tag}` : currentTag.tag;
481
+ const entries = extractChangelogEntriesFromCommits(projectDir, tagRange);
482
+ if (!entries.length) {
483
+ log(`No changelog entries found for ${currentTag.tag}, adding placeholder entry`, "info");
484
+ entries.push({
485
+ type: "changed",
486
+ description: `Release version ${currentTag.version}`
487
+ });
488
+ }
489
+ versions.unshift(
490
+ formatChangelogEntries(
491
+ format,
492
+ currentTag.version,
493
+ currentTag.date,
494
+ entries,
495
+ packageName,
496
+ repoUrl
497
+ )
498
+ );
499
+ } catch (error) {
500
+ log(`Failed to process version ${currentTag.tag}: ${error}`, "error");
501
+ }
502
+ }
503
+ changelogContent += versions.join("\n\n");
504
+ return changelogContent;
505
+ }
506
+ async function writeChangelog(content, outputPath, dryRun) {
507
+ if (dryRun) {
508
+ log("--- Changelog Preview ---", "info");
509
+ console.log(content);
510
+ log("--- End Preview ---", "info");
511
+ return;
512
+ }
513
+ try {
514
+ fs.writeFileSync(outputPath, content, "utf8");
515
+ log(`Changelog successfully written to ${outputPath}`, "success");
516
+ } catch (error) {
517
+ throw new Error(
518
+ `Failed to write changelog: ${error instanceof Error ? error.message : String(error)}`
519
+ );
520
+ }
521
+ }
522
+
523
+ // src/config.ts
524
+ import * as fs2 from "node:fs";
525
+ import { cwd } from "node:process";
526
+ function loadConfig(configPath) {
527
+ const localProcess = cwd();
528
+ const filePath = configPath || `${localProcess}/version.config.json`;
529
+ return new Promise((resolve, reject) => {
530
+ fs2.readFile(filePath, "utf-8", (err, data) => {
531
+ if (err) {
532
+ reject(new Error(`Could not locate the config file at ${filePath}: ${err.message}`));
533
+ return;
534
+ }
535
+ try {
536
+ const config = JSON.parse(data);
537
+ resolve(config);
538
+ } catch (err2) {
539
+ const errorMessage = err2 instanceof Error ? err2.message : String(err2);
540
+ reject(new Error(`Failed to parse config file ${filePath}: ${errorMessage}`));
541
+ }
542
+ });
543
+ });
544
+ }
545
+
546
+ // src/core/versionEngine.ts
547
+ import { cwd as cwd4 } from "node:process";
548
+ import { getPackagesSync } from "@manypkg/get-packages";
549
+
550
+ // src/errors/gitError.ts
551
+ var GitError = class extends Error {
552
+ constructor(message, code) {
553
+ super(message);
554
+ this.code = code;
555
+ this.name = "GitError";
556
+ }
557
+ };
558
+ function createGitError(code, details) {
559
+ const messages = {
560
+ ["NOT_GIT_REPO" /* NOT_GIT_REPO */]: "Not a git repository",
561
+ ["GIT_PROCESS_ERROR" /* GIT_PROCESS_ERROR */]: "Failed to create new version",
562
+ ["NO_FILES" /* NO_FILES */]: "No files specified for commit",
563
+ ["NO_COMMIT_MESSAGE" /* NO_COMMIT_MESSAGE */]: "Commit message is required",
564
+ ["GIT_ERROR" /* GIT_ERROR */]: "Git operation failed"
565
+ };
566
+ const baseMessage = messages[code];
567
+ const fullMessage = details ? `${baseMessage}: ${details}` : baseMessage;
568
+ return new GitError(fullMessage, code);
569
+ }
570
+
571
+ // src/errors/versionError.ts
572
+ var VersionError = class extends Error {
573
+ constructor(message, code) {
574
+ super(message);
575
+ this.code = code;
576
+ this.name = "VersionError";
577
+ }
578
+ };
579
+ function createVersionError(code, details) {
580
+ const messages = {
581
+ ["CONFIG_REQUIRED" /* CONFIG_REQUIRED */]: "Configuration is required",
582
+ ["PACKAGES_NOT_FOUND" /* PACKAGES_NOT_FOUND */]: "Failed to get packages information",
583
+ ["WORKSPACE_ERROR" /* WORKSPACE_ERROR */]: "Failed to get workspace packages",
584
+ ["INVALID_CONFIG" /* INVALID_CONFIG */]: "Invalid configuration",
585
+ ["PACKAGE_NOT_FOUND" /* PACKAGE_NOT_FOUND */]: "Package not found",
586
+ ["VERSION_CALCULATION_ERROR" /* VERSION_CALCULATION_ERROR */]: "Failed to calculate version"
587
+ };
588
+ const baseMessage = messages[code];
589
+ const fullMessage = details ? `${baseMessage}: ${details}` : baseMessage;
590
+ return new VersionError(fullMessage, code);
591
+ }
592
+
159
593
  // src/core/versionStrategies.ts
160
- import fs6 from "node:fs";
161
- import * as path4 from "node:path";
594
+ import fs8 from "node:fs";
595
+ import * as path6 from "node:path";
162
596
 
163
597
  // src/git/commands.ts
164
598
  import { cwd as cwd2 } from "node:process";
@@ -181,7 +615,7 @@ var execAsync = (command, options) => {
181
615
  );
182
616
  });
183
617
  };
184
- var execSync = (command, args) => nativeExecSync(command, { maxBuffer: 1024 * 1024 * 10, ...args });
618
+ var execSync3 = (command, args) => nativeExecSync(command, { maxBuffer: 1024 * 1024 * 10, ...args });
185
619
 
186
620
  // src/git/repository.ts
187
621
  import { existsSync, statSync } from "node:fs";
@@ -196,14 +630,14 @@ function isGitRepository(directory) {
196
630
  return false;
197
631
  }
198
632
  try {
199
- execSync("git rev-parse --is-inside-work-tree", { cwd: directory });
633
+ execSync3("git rev-parse --is-inside-work-tree", { cwd: directory });
200
634
  return true;
201
635
  } catch (_error) {
202
636
  return false;
203
637
  }
204
638
  }
205
639
  function getCurrentBranch() {
206
- const result = execSync("git rev-parse --abbrev-ref HEAD");
640
+ const result = execSync3("git rev-parse --abbrev-ref HEAD");
207
641
  return result.toString().trim();
208
642
  }
209
643
 
@@ -326,8 +760,12 @@ function formatVersionPrefix(versionPrefix, scope) {
326
760
  }
327
761
  return cleanPrefix;
328
762
  }
329
- function formatCommitMessage(template, version, scope) {
330
- return createTemplateString(template, { version, scope });
763
+ function formatCommitMessage(template, version, packageName, scope) {
764
+ return createTemplateString(template, {
765
+ version,
766
+ scope,
767
+ packageName: packageName || ""
768
+ });
331
769
  }
332
770
  function createTemplateString(template, variables) {
333
771
  return Object.entries(variables).reduce((result, [key, value]) => {
@@ -343,7 +781,7 @@ function createTemplateString(template, variables) {
343
781
  function getCommitsLength(pkgRoot) {
344
782
  try {
345
783
  const gitCommand = `git rev-list --count HEAD ^$(git describe --tags --abbrev=0) ${pkgRoot}`;
346
- const amount = execSync(gitCommand).toString().trim();
784
+ const amount = execSync3(gitCommand).toString().trim();
347
785
  return Number(amount);
348
786
  } catch (error) {
349
787
  const errorMessage = error instanceof Error ? error.message : String(error);
@@ -440,20 +878,20 @@ async function getLatestTagForPackage(packageName, versionPrefix) {
440
878
  }
441
879
 
442
880
  // src/package/packageManagement.ts
443
- import fs3 from "node:fs";
881
+ import fs4 from "node:fs";
444
882
 
445
883
  // src/cargo/cargoHandler.ts
446
- import fs2 from "node:fs";
447
- import path from "node:path";
884
+ import fs3 from "node:fs";
885
+ import path2 from "node:path";
448
886
  import * as TOML from "smol-toml";
449
887
  function getCargoInfo(cargoPath) {
450
888
  var _a;
451
- if (!fs2.existsSync(cargoPath)) {
889
+ if (!fs3.existsSync(cargoPath)) {
452
890
  log(`Cargo.toml file not found at: ${cargoPath}`, "error");
453
891
  throw new Error(`Cargo.toml file not found at: ${cargoPath}`);
454
892
  }
455
893
  try {
456
- const fileContent = fs2.readFileSync(cargoPath, "utf8");
894
+ const fileContent = fs3.readFileSync(cargoPath, "utf8");
457
895
  const cargo = TOML.parse(fileContent);
458
896
  if (!((_a = cargo.package) == null ? void 0 : _a.name)) {
459
897
  log(`Package name not found in: ${cargoPath}`, "error");
@@ -463,7 +901,7 @@ function getCargoInfo(cargoPath) {
463
901
  name: cargo.package.name,
464
902
  version: cargo.package.version || "0.0.0",
465
903
  path: cargoPath,
466
- dir: path.dirname(cargoPath),
904
+ dir: path2.dirname(cargoPath),
467
905
  content: cargo
468
906
  };
469
907
  } catch (error) {
@@ -476,12 +914,12 @@ function getCargoInfo(cargoPath) {
476
914
  }
477
915
  }
478
916
  function isCargoToml(filePath) {
479
- return path.basename(filePath) === "Cargo.toml";
917
+ return path2.basename(filePath) === "Cargo.toml";
480
918
  }
481
919
  function updateCargoVersion(cargoPath, version) {
482
920
  var _a;
483
921
  try {
484
- const originalContent = fs2.readFileSync(cargoPath, "utf8");
922
+ const originalContent = fs3.readFileSync(cargoPath, "utf8");
485
923
  const cargo = TOML.parse(originalContent);
486
924
  const packageName = (_a = cargo.package) == null ? void 0 : _a.name;
487
925
  if (!packageName) {
@@ -493,7 +931,7 @@ function updateCargoVersion(cargoPath, version) {
493
931
  cargo.package.version = version;
494
932
  }
495
933
  const updatedContent = TOML.stringify(cargo);
496
- fs2.writeFileSync(cargoPath, updatedContent);
934
+ fs3.writeFileSync(cargoPath, updatedContent);
497
935
  addPackageUpdate(packageName, version, cargoPath);
498
936
  log(`Updated Cargo.toml at ${cargoPath} to version ${version}`, "success");
499
937
  } catch (error) {
@@ -512,11 +950,11 @@ function updatePackageVersion(packagePath, version) {
512
950
  return;
513
951
  }
514
952
  try {
515
- const packageContent = fs3.readFileSync(packagePath, "utf8");
953
+ const packageContent = fs4.readFileSync(packagePath, "utf8");
516
954
  const packageJson = JSON.parse(packageContent);
517
955
  const packageName = packageJson.name;
518
956
  packageJson.version = version;
519
- fs3.writeFileSync(packagePath, `${JSON.stringify(packageJson, null, 2)}
957
+ fs4.writeFileSync(packagePath, `${JSON.stringify(packageJson, null, 2)}
520
958
  `);
521
959
  addPackageUpdate(packageName, version, packagePath);
522
960
  log(`Updated package.json at ${packagePath} to version ${version}`, "success");
@@ -530,24 +968,349 @@ function updatePackageVersion(packagePath, version) {
530
968
  }
531
969
 
532
970
  // src/package/packageProcessor.ts
533
- import * as fs5 from "node:fs";
534
- import path3 from "node:path";
971
+ import * as fs7 from "node:fs";
972
+ import path5 from "node:path";
535
973
  import { exit } from "node:process";
536
974
 
975
+ // src/changelog/changelogManager.ts
976
+ import * as fs5 from "node:fs";
977
+ import * as path3 from "node:path";
978
+ function createChangelog(_packagePath, packageName) {
979
+ return {
980
+ projectName: packageName,
981
+ unreleased: [],
982
+ versions: []
983
+ };
984
+ }
985
+ function parseChangelog(filePath) {
986
+ try {
987
+ if (!fs5.existsSync(filePath)) {
988
+ return null;
989
+ }
990
+ fs5.readFileSync(filePath, "utf8");
991
+ log(`Parsed changelog at ${filePath}`, "info");
992
+ return {
993
+ projectName: path3.basename(path3.dirname(filePath)),
994
+ unreleased: [],
995
+ versions: []
996
+ };
997
+ } catch (error) {
998
+ log(
999
+ `Error parsing changelog: ${error instanceof Error ? error.message : String(error)}`,
1000
+ "error"
1001
+ );
1002
+ return null;
1003
+ }
1004
+ }
1005
+ function generateLinks(changelog, repoUrl) {
1006
+ var _a, _b;
1007
+ if (!repoUrl || changelog.versions.length === 0) {
1008
+ return "";
1009
+ }
1010
+ let links = "\n";
1011
+ if (changelog.unreleased.length > 0) {
1012
+ const latestVersion = ((_a = changelog.versions[0]) == null ? void 0 : _a.version) || "";
1013
+ links += `[unreleased]: ${repoUrl}/compare/v${latestVersion}...HEAD
1014
+ `;
1015
+ }
1016
+ for (let i = 0; i < changelog.versions.length; i++) {
1017
+ const currentVersion = changelog.versions[i].version;
1018
+ const previousVersion = (_b = changelog.versions[i + 1]) == null ? void 0 : _b.version;
1019
+ if (previousVersion) {
1020
+ links += `[${currentVersion}]: ${repoUrl}/compare/v${previousVersion}...v${currentVersion}
1021
+ `;
1022
+ } else if (i === changelog.versions.length - 1) {
1023
+ links += `[${currentVersion}]: ${repoUrl}/releases/tag/v${currentVersion}
1024
+ `;
1025
+ }
1026
+ }
1027
+ return links;
1028
+ }
1029
+ function generateAngularChangelogContent(changelog, repoUrl) {
1030
+ let content = "# Changelog\n\n";
1031
+ if (changelog.unreleased.length > 0) {
1032
+ content += "## [Unreleased]\n\n";
1033
+ const groupedByType = groupEntriesByAngularType(changelog.unreleased);
1034
+ for (const [type, entries] of Object.entries(groupedByType)) {
1035
+ content += `### ${formatAngularType(type)}
1036
+
1037
+ `;
1038
+ const groupedByScope = groupEntriesByScope2(entries);
1039
+ for (const [scope, scopeEntries] of Object.entries(groupedByScope)) {
1040
+ if (scope !== "undefined" && scope !== "") {
1041
+ content += `* **${scope}:**
1042
+ `;
1043
+ for (const entry of scopeEntries) {
1044
+ content += formatAngularEntry(entry, false);
1045
+ }
1046
+ content += "\n";
1047
+ } else {
1048
+ for (const entry of scopeEntries) {
1049
+ content += formatAngularEntry(entry, true);
1050
+ }
1051
+ }
1052
+ }
1053
+ content += "\n";
1054
+ }
1055
+ const breakingChanges = changelog.unreleased.filter(
1056
+ (entry) => entry.description.includes("**BREAKING**")
1057
+ );
1058
+ if (breakingChanges.length > 0) {
1059
+ content += "### BREAKING CHANGES\n\n";
1060
+ for (const entry of breakingChanges) {
1061
+ const description = entry.description.replace("**BREAKING** ", "");
1062
+ content += `* ${entry.scope ? `**${entry.scope}:** ` : ""}${description}`;
1063
+ if (entry.issueIds && entry.issueIds.length > 0) {
1064
+ content += ` (${entry.issueIds.join(", ")})`;
1065
+ }
1066
+ content += "\n";
1067
+ }
1068
+ content += "\n";
1069
+ }
1070
+ }
1071
+ for (const version of changelog.versions) {
1072
+ content += `## [${version.version}] - ${version.date}
1073
+
1074
+ `;
1075
+ const groupedByType = groupEntriesByAngularType(version.entries);
1076
+ for (const [type, entries] of Object.entries(groupedByType)) {
1077
+ content += `### ${formatAngularType(type)}
1078
+
1079
+ `;
1080
+ const groupedByScope = groupEntriesByScope2(entries);
1081
+ for (const [scope, scopeEntries] of Object.entries(groupedByScope)) {
1082
+ if (scope !== "undefined" && scope !== "") {
1083
+ content += `* **${scope}:**
1084
+ `;
1085
+ for (const entry of scopeEntries) {
1086
+ content += formatAngularEntry(entry, false);
1087
+ }
1088
+ content += "\n";
1089
+ } else {
1090
+ for (const entry of scopeEntries) {
1091
+ content += formatAngularEntry(entry, true);
1092
+ }
1093
+ }
1094
+ }
1095
+ content += "\n";
1096
+ }
1097
+ const breakingChanges = version.entries.filter(
1098
+ (entry) => entry.description.includes("**BREAKING**")
1099
+ );
1100
+ if (breakingChanges.length > 0) {
1101
+ content += "### BREAKING CHANGES\n\n";
1102
+ for (const entry of breakingChanges) {
1103
+ const description = entry.description.replace("**BREAKING** ", "");
1104
+ content += `* ${entry.scope ? `**${entry.scope}:** ` : ""}${description}`;
1105
+ if (entry.issueIds && entry.issueIds.length > 0) {
1106
+ content += ` (${entry.issueIds.join(", ")})`;
1107
+ }
1108
+ content += "\n";
1109
+ }
1110
+ content += "\n";
1111
+ }
1112
+ }
1113
+ content += generateLinks(changelog, repoUrl);
1114
+ return content;
1115
+ }
1116
+ function groupEntriesByAngularType(entries) {
1117
+ const result = {};
1118
+ for (const entry of entries) {
1119
+ const type = entry.originalType || mapToAngularType(entry.type);
1120
+ if (!result[type]) {
1121
+ result[type] = [];
1122
+ }
1123
+ result[type].push(entry);
1124
+ }
1125
+ return result;
1126
+ }
1127
+ function mapToAngularType(type) {
1128
+ switch (type) {
1129
+ case "added":
1130
+ return "feat";
1131
+ case "fixed":
1132
+ return "fix";
1133
+ case "changed":
1134
+ return "perf";
1135
+ case "deprecated":
1136
+ case "removed":
1137
+ case "security":
1138
+ return type;
1139
+ default:
1140
+ return type;
1141
+ }
1142
+ }
1143
+ function formatAngularType(type) {
1144
+ switch (type) {
1145
+ case "feat":
1146
+ return "Features";
1147
+ case "fix":
1148
+ return "Bug Fixes";
1149
+ case "perf":
1150
+ return "Performance Improvements";
1151
+ case "security":
1152
+ return "Security";
1153
+ case "deprecated":
1154
+ return "Deprecated";
1155
+ case "removed":
1156
+ return "Removed";
1157
+ default:
1158
+ return capitalizeFirstLetter(type);
1159
+ }
1160
+ }
1161
+ function groupEntriesByScope2(entries) {
1162
+ const result = {};
1163
+ for (const entry of entries) {
1164
+ const scope = entry.scope || "";
1165
+ if (!result[scope]) {
1166
+ result[scope] = [];
1167
+ }
1168
+ result[scope].push(entry);
1169
+ }
1170
+ return result;
1171
+ }
1172
+ function formatAngularEntry(entry, includeScope) {
1173
+ let result = " * ";
1174
+ if (includeScope && entry.scope) {
1175
+ result += `**${entry.scope}:** `;
1176
+ }
1177
+ let description = entry.description;
1178
+ if (!includeScope && entry.scope && description.startsWith(`**${entry.scope}**: `)) {
1179
+ description = description.substring(`**${entry.scope}**: `.length);
1180
+ }
1181
+ if (description.startsWith("**BREAKING** ")) {
1182
+ description = description.substring("**BREAKING** ".length);
1183
+ }
1184
+ result += description;
1185
+ if (entry.issueIds && entry.issueIds.length > 0) {
1186
+ result += ` (${entry.issueIds.join(", ")})`;
1187
+ }
1188
+ result += "\n";
1189
+ return result;
1190
+ }
1191
+ function generateChangelogContent(changelog, repoUrl, format = "keep-a-changelog") {
1192
+ if (format === "angular") {
1193
+ return generateAngularChangelogContent(changelog, repoUrl);
1194
+ }
1195
+ let content = "# Changelog\n\n";
1196
+ content += `All notable changes to ${changelog.projectName} will be documented in this file.
1197
+
1198
+ `;
1199
+ content += "The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),\n";
1200
+ content += "and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).\n\n";
1201
+ if (changelog.unreleased.length > 0) {
1202
+ content += "## [Unreleased]\n\n";
1203
+ const grouped = changelog.unreleased.reduce(
1204
+ (acc, entry) => {
1205
+ if (!acc[entry.type]) {
1206
+ acc[entry.type] = [];
1207
+ }
1208
+ acc[entry.type].push(entry);
1209
+ return acc;
1210
+ },
1211
+ {}
1212
+ );
1213
+ for (const [type, entries] of Object.entries(grouped)) {
1214
+ content += `### ${capitalizeFirstLetter(type)}
1215
+
1216
+ `;
1217
+ for (const entry of entries) {
1218
+ let entryText = `- ${entry.description}`;
1219
+ if (entry.issueIds && entry.issueIds.length > 0) {
1220
+ entryText += ` (${entry.issueIds.join(", ")})`;
1221
+ }
1222
+ content += `${entryText}.
1223
+ `;
1224
+ }
1225
+ content += "\n";
1226
+ }
1227
+ }
1228
+ for (const version of changelog.versions) {
1229
+ content += `## [${version.version}] - ${version.date}
1230
+
1231
+ `;
1232
+ const grouped = version.entries.reduce(
1233
+ (acc, entry) => {
1234
+ if (!acc[entry.type]) {
1235
+ acc[entry.type] = [];
1236
+ }
1237
+ acc[entry.type].push(entry);
1238
+ return acc;
1239
+ },
1240
+ {}
1241
+ );
1242
+ for (const [type, entries] of Object.entries(grouped)) {
1243
+ content += `### ${capitalizeFirstLetter(type)}
1244
+
1245
+ `;
1246
+ for (const entry of entries) {
1247
+ let entryText = `- ${entry.description}`;
1248
+ if (entry.issueIds && entry.issueIds.length > 0) {
1249
+ entryText += ` (${entry.issueIds.join(", ")})`;
1250
+ }
1251
+ content += `${entryText}.
1252
+ `;
1253
+ }
1254
+ content += "\n";
1255
+ }
1256
+ }
1257
+ content += generateLinks(changelog, repoUrl);
1258
+ return content;
1259
+ }
1260
+ function updateChangelog(packagePath, packageName, version, entries, repoUrl, format = "keep-a-changelog") {
1261
+ try {
1262
+ const changelogPath = path3.join(packagePath, "CHANGELOG.md");
1263
+ let changelog;
1264
+ if (fs5.existsSync(changelogPath)) {
1265
+ const existingChangelog = parseChangelog(changelogPath);
1266
+ if (existingChangelog) {
1267
+ changelog = existingChangelog;
1268
+ } else {
1269
+ changelog = createChangelog(packagePath, packageName);
1270
+ }
1271
+ } else {
1272
+ changelog = createChangelog(packagePath, packageName);
1273
+ }
1274
+ if (version) {
1275
+ const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
1276
+ const newVersion = {
1277
+ version,
1278
+ date: today,
1279
+ entries: [...changelog.unreleased, ...entries]
1280
+ };
1281
+ changelog.unreleased = [];
1282
+ changelog.versions.unshift(newVersion);
1283
+ } else {
1284
+ changelog.unreleased = [...changelog.unreleased, ...entries];
1285
+ }
1286
+ const content = generateChangelogContent(changelog, repoUrl, format);
1287
+ fs5.writeFileSync(changelogPath, content);
1288
+ log(`Updated changelog at ${changelogPath}`, "success");
1289
+ } catch (error) {
1290
+ log(
1291
+ `Error updating changelog: ${error instanceof Error ? error.message : String(error)}`,
1292
+ "error"
1293
+ );
1294
+ }
1295
+ }
1296
+ function capitalizeFirstLetter(input) {
1297
+ return input.charAt(0).toUpperCase() + input.slice(1);
1298
+ }
1299
+
537
1300
  // src/core/versionCalculator.ts
538
1301
  import { cwd as cwd3 } from "node:process";
539
1302
  import { Bumper } from "conventional-recommended-bump";
540
1303
  import semver2 from "semver";
541
1304
 
542
1305
  // src/utils/manifestHelpers.ts
543
- import fs4 from "node:fs";
544
- import path2 from "node:path";
1306
+ import fs6 from "node:fs";
1307
+ import path4 from "node:path";
545
1308
  function getVersionFromManifests(packageDir) {
546
- const packageJsonPath = path2.join(packageDir, "package.json");
547
- const cargoTomlPath = path2.join(packageDir, "Cargo.toml");
548
- if (fs4.existsSync(packageJsonPath)) {
1309
+ const packageJsonPath = path4.join(packageDir, "package.json");
1310
+ const cargoTomlPath = path4.join(packageDir, "Cargo.toml");
1311
+ if (fs6.existsSync(packageJsonPath)) {
549
1312
  try {
550
- const packageJson = JSON.parse(fs4.readFileSync(packageJsonPath, "utf-8"));
1313
+ const packageJson = JSON.parse(fs6.readFileSync(packageJsonPath, "utf-8"));
551
1314
  if (packageJson.version) {
552
1315
  log(`Found version ${packageJson.version} in package.json`, "debug");
553
1316
  return {
@@ -563,7 +1326,7 @@ function getVersionFromManifests(packageDir) {
563
1326
  log(`Error reading package.json: ${errMsg}`, "warning");
564
1327
  }
565
1328
  }
566
- if (fs4.existsSync(cargoTomlPath)) {
1329
+ if (fs6.existsSync(cargoTomlPath)) {
567
1330
  try {
568
1331
  const cargoInfo = getCargoInfo(cargoTomlPath);
569
1332
  if (cargoInfo.version) {
@@ -589,8 +1352,8 @@ function getVersionFromManifests(packageDir) {
589
1352
  };
590
1353
  }
591
1354
  function throwIfNoManifestsFound(packageDir) {
592
- const packageJsonPath = path2.join(packageDir, "package.json");
593
- const cargoTomlPath = path2.join(packageDir, "Cargo.toml");
1355
+ const packageJsonPath = path4.join(packageDir, "package.json");
1356
+ const cargoTomlPath = path4.join(packageDir, "Cargo.toml");
594
1357
  throw new Error(
595
1358
  `Neither package.json nor Cargo.toml found at ${packageDir}. Checked paths: ${packageJsonPath}, ${cargoTomlPath}. Cannot determine version.`
596
1359
  );
@@ -845,7 +1608,7 @@ var PackageProcessor = class {
845
1608
  * Process packages based on targeting criteria
846
1609
  */
847
1610
  async processPackages(packages) {
848
- var _a;
1611
+ var _a, _b, _c, _d, _e;
849
1612
  const tags = [];
850
1613
  const updatedPackagesInfo = [];
851
1614
  if (!packages || !Array.isArray(packages)) {
@@ -930,13 +1693,81 @@ var PackageProcessor = class {
930
1693
  if (!nextVersion) {
931
1694
  continue;
932
1695
  }
933
- const packageJsonPath = path3.join(pkgPath, "package.json");
934
- const cargoTomlPath = path3.join(pkgPath, "Cargo.toml");
935
- if (fs5.existsSync(packageJsonPath)) {
1696
+ if (this.fullConfig.updateChangelog !== false) {
1697
+ let changelogEntries = [];
1698
+ try {
1699
+ changelogEntries = extractChangelogEntriesFromCommits(pkgPath, latestTag);
1700
+ if (changelogEntries.length === 0) {
1701
+ changelogEntries = [
1702
+ {
1703
+ type: "changed",
1704
+ description: `Update version to ${nextVersion}`
1705
+ }
1706
+ ];
1707
+ }
1708
+ } catch (error) {
1709
+ log(
1710
+ `Error extracting changelog entries: ${error instanceof Error ? error.message : String(error)}`,
1711
+ "warning"
1712
+ );
1713
+ changelogEntries = [
1714
+ {
1715
+ type: "changed",
1716
+ description: `Update version to ${nextVersion}`
1717
+ }
1718
+ ];
1719
+ }
1720
+ let repoUrl;
1721
+ try {
1722
+ const packageJsonPath2 = path5.join(pkgPath, "package.json");
1723
+ if (fs7.existsSync(packageJsonPath2)) {
1724
+ const packageJson = JSON.parse(fs7.readFileSync(packageJsonPath2, "utf8"));
1725
+ if (packageJson.repository) {
1726
+ if (typeof packageJson.repository === "string") {
1727
+ repoUrl = packageJson.repository;
1728
+ } else if (packageJson.repository.url) {
1729
+ repoUrl = packageJson.repository.url;
1730
+ }
1731
+ if ((repoUrl == null ? void 0 : repoUrl.startsWith("git+")) && (repoUrl == null ? void 0 : repoUrl.endsWith(".git"))) {
1732
+ repoUrl = repoUrl.substring(4, repoUrl.length - 4);
1733
+ }
1734
+ }
1735
+ }
1736
+ } catch (error) {
1737
+ log(
1738
+ `Could not determine repository URL for changelog links: ${error instanceof Error ? error.message : String(error)}`,
1739
+ "warning"
1740
+ );
1741
+ }
1742
+ updateChangelog(
1743
+ pkgPath,
1744
+ name,
1745
+ nextVersion,
1746
+ changelogEntries,
1747
+ repoUrl,
1748
+ this.fullConfig.changelogFormat
1749
+ );
1750
+ }
1751
+ const packageJsonPath = path5.join(pkgPath, "package.json");
1752
+ if (fs7.existsSync(packageJsonPath)) {
936
1753
  updatePackageVersion(packageJsonPath, nextVersion);
937
1754
  }
938
- if (fs5.existsSync(cargoTomlPath)) {
939
- updatePackageVersion(cargoTomlPath, nextVersion);
1755
+ const cargoEnabled = ((_a = this.fullConfig.cargo) == null ? void 0 : _a.enabled) !== false;
1756
+ if (cargoEnabled) {
1757
+ const cargoPaths = (_b = this.fullConfig.cargo) == null ? void 0 : _b.paths;
1758
+ if (cargoPaths && cargoPaths.length > 0) {
1759
+ for (const cargoPath of cargoPaths) {
1760
+ const resolvedCargoPath = path5.resolve(pkgPath, cargoPath, "Cargo.toml");
1761
+ if (fs7.existsSync(resolvedCargoPath)) {
1762
+ updatePackageVersion(resolvedCargoPath, nextVersion);
1763
+ }
1764
+ }
1765
+ } else {
1766
+ const cargoTomlPath = path5.join(pkgPath, "Cargo.toml");
1767
+ if (fs7.existsSync(cargoTomlPath)) {
1768
+ updatePackageVersion(cargoTomlPath, nextVersion);
1769
+ }
1770
+ }
940
1771
  }
941
1772
  const packageTag = formatTag(
942
1773
  nextVersion,
@@ -968,12 +1799,37 @@ var PackageProcessor = class {
968
1799
  log("No targeted packages required a version update.", "info");
969
1800
  return { updatedPackages: [], tags };
970
1801
  }
971
- const filesToCommit = updatedPackagesInfo.map((info) => path3.join(info.path, "package.json"));
1802
+ const filesToCommit = [];
1803
+ for (const info of updatedPackagesInfo) {
1804
+ const packageJsonPath = path5.join(info.path, "package.json");
1805
+ if (fs7.existsSync(packageJsonPath)) {
1806
+ filesToCommit.push(packageJsonPath);
1807
+ }
1808
+ const cargoEnabled = ((_c = this.fullConfig.cargo) == null ? void 0 : _c.enabled) !== false;
1809
+ if (cargoEnabled) {
1810
+ const cargoPaths = (_d = this.fullConfig.cargo) == null ? void 0 : _d.paths;
1811
+ if (cargoPaths && cargoPaths.length > 0) {
1812
+ for (const cargoPath of cargoPaths) {
1813
+ const resolvedCargoPath = path5.resolve(info.path, cargoPath, "Cargo.toml");
1814
+ if (fs7.existsSync(resolvedCargoPath)) {
1815
+ filesToCommit.push(resolvedCargoPath);
1816
+ }
1817
+ }
1818
+ } else {
1819
+ const cargoTomlPath = path5.join(info.path, "Cargo.toml");
1820
+ if (fs7.existsSync(cargoTomlPath)) {
1821
+ filesToCommit.push(cargoTomlPath);
1822
+ }
1823
+ }
1824
+ }
1825
+ }
972
1826
  const packageNames = updatedPackagesInfo.map((p) => p.name).join(", ");
973
- const representativeVersion = ((_a = updatedPackagesInfo[0]) == null ? void 0 : _a.version) || "multiple";
1827
+ const representativeVersion = ((_e = updatedPackagesInfo[0]) == null ? void 0 : _e.version) || "multiple";
974
1828
  let commitMessage = this.commitMessageTemplate || "chore(release): publish packages";
975
- if (updatedPackagesInfo.length === 1 && commitMessage.includes("${version}")) {
976
- commitMessage = formatCommitMessage(commitMessage, representativeVersion);
1829
+ const placeholderRegex = /\$\{[^}]+\}/;
1830
+ if (updatedPackagesInfo.length === 1 && placeholderRegex.test(commitMessage)) {
1831
+ const packageName = updatedPackagesInfo[0].name;
1832
+ commitMessage = formatCommitMessage(commitMessage, representativeVersion, packageName);
977
1833
  } else {
978
1834
  commitMessage = `chore(release): ${packageNames} ${representativeVersion}`;
979
1835
  }
@@ -1045,20 +1901,21 @@ function createSyncedStrategy(config) {
1045
1901
  const files = [];
1046
1902
  const updatedPackages = [];
1047
1903
  try {
1048
- const rootPkgPath = path4.join(packages.root, "package.json");
1049
- if (fs6.existsSync(rootPkgPath)) {
1904
+ const rootPkgPath = path6.join(packages.root, "package.json");
1905
+ if (fs8.existsSync(rootPkgPath)) {
1050
1906
  updatePackageVersion(rootPkgPath, nextVersion);
1051
1907
  files.push(rootPkgPath);
1052
1908
  updatedPackages.push("root");
1053
1909
  }
1054
- } catch (_error) {
1055
- log("Failed to update root package.json", "error");
1910
+ } catch (error) {
1911
+ const errMessage = error instanceof Error ? error.message : String(error);
1912
+ log(`Failed to update root package.json: ${errMessage}`, "error");
1056
1913
  }
1057
1914
  for (const pkg of packages.packages) {
1058
1915
  if (!shouldProcessPackage(pkg, config)) {
1059
1916
  continue;
1060
1917
  }
1061
- const packageJsonPath = path4.join(pkg.dir, "package.json");
1918
+ const packageJsonPath = path6.join(pkg.dir, "package.json");
1062
1919
  updatePackageVersion(packageJsonPath, nextVersion);
1063
1920
  files.push(packageJsonPath);
1064
1921
  updatedPackages.push(pkg.packageJson.name);
@@ -1131,7 +1988,7 @@ function createSingleStrategy(config) {
1131
1988
  log(`No version change needed for ${packageName}`, "info");
1132
1989
  return;
1133
1990
  }
1134
- const packageJsonPath = path4.join(pkgPath, "package.json");
1991
+ const packageJsonPath = path6.join(pkgPath, "package.json");
1135
1992
  updatePackageVersion(packageJsonPath, nextVersion);
1136
1993
  log(`Updated package ${packageName} to version ${nextVersion}`, "success");
1137
1994
  const nextTag = formatTag(
@@ -1141,7 +1998,7 @@ function createSingleStrategy(config) {
1141
1998
  tagTemplate,
1142
1999
  packageTagTemplate
1143
2000
  );
1144
- const formattedCommitMessage = formatCommitMessage(commitMessage, nextVersion);
2001
+ const formattedCommitMessage = formatCommitMessage(commitMessage, nextVersion, packageName);
1145
2002
  await createGitCommitAndTag(
1146
2003
  [packageJsonPath],
1147
2004
  nextTag,
@@ -1309,11 +2166,11 @@ var VersionEngine = class {
1309
2166
  // src/index.ts
1310
2167
  function getPackageVersion() {
1311
2168
  try {
1312
- const packageJsonPath = path5.resolve(
1313
- path5.dirname(import.meta.url.replace("file:", "")),
2169
+ const packageJsonPath = path7.resolve(
2170
+ path7.dirname(import.meta.url.replace("file:", "")),
1314
2171
  "../package.json"
1315
2172
  );
1316
- const packageJsonContent = fs7.readFileSync(packageJsonPath, "utf-8");
2173
+ const packageJsonContent = fs9.readFileSync(packageJsonPath, "utf-8");
1317
2174
  const packageJson = JSON.parse(packageJsonContent);
1318
2175
  return packageJson.version || "0.0.0";
1319
2176
  } catch (error) {
@@ -1322,53 +2179,94 @@ function getPackageVersion() {
1322
2179
  }
1323
2180
  }
1324
2181
  async function run() {
1325
- const buildTimestamp = (/* @__PURE__ */ new Date()).toISOString();
1326
- const packageVersion = getPackageVersion();
1327
- log(`package-versioner v${packageVersion} (Build: ${buildTimestamp})`, "debug");
1328
- const program = new Command();
1329
- program.name("package-versioner").description(
1330
- "A lightweight yet powerful CLI tool for automated semantic versioning based on Git history and conventional commits."
1331
- ).version(packageVersion).option(
1332
- "-c, --config <path>",
1333
- "Path to config file (defaults to version.config.json in current directory)"
1334
- ).option("-d, --dry-run", "Dry run (no changes made)", false).option("-b, --bump <type>", "Specify bump type (patch|minor|major)").option("-p, --prerelease [identifier]", "Create prerelease version").option("-s, --synced", "Use synchronized versioning across all packages").option("-j, --json", "Output results as JSON", false).option("-t, --target <packages>", "Comma-delimited list of package names to target").parse(process.argv);
1335
- const options = program.opts();
1336
- if (options.json) {
1337
- enableJsonOutput(options.dryRun);
1338
- }
1339
2182
  try {
1340
- const config = await loadConfig(options.config);
1341
- log(`Loaded configuration from ${options.config || "version.config.json"}`, "info");
1342
- if (options.dryRun) config.dryRun = true;
1343
- if (options.synced) config.synced = true;
1344
- if (options.bump) config.type = options.bump;
1345
- if (options.prerelease)
1346
- config.prereleaseIdentifier = options.prerelease === true ? "next" : options.prerelease;
1347
- const cliTargets = options.target ? options.target.split(",").map((t) => t.trim()) : [];
1348
- const engine = new VersionEngine(config, !!options.json);
1349
- if (config.synced) {
1350
- log("Using synced versioning strategy.", "info");
1351
- engine.setStrategy("synced");
1352
- await engine.run();
1353
- } else if (config.packages && config.packages.length === 1) {
1354
- log("Using single package versioning strategy.", "info");
1355
- if (cliTargets.length > 0) {
1356
- log("--target flag is ignored for single package strategy.", "warning");
1357
- }
1358
- engine.setStrategy("single");
1359
- await engine.run();
1360
- } else {
1361
- log("Using async versioning strategy.", "info");
1362
- if (cliTargets.length > 0) {
1363
- log(`Targeting specific packages: ${cliTargets.join(", ")}`, "info");
2183
+ const buildTimestamp = (/* @__PURE__ */ new Date()).toISOString();
2184
+ const packageVersion = getPackageVersion();
2185
+ log(`package-versioner v${packageVersion} (Build: ${buildTimestamp})`, "debug");
2186
+ const program = new Command();
2187
+ program.name("package-versioner").description(
2188
+ "A lightweight yet powerful CLI tool for automated semantic versioning based on Git history and conventional commits."
2189
+ ).version(packageVersion);
2190
+ program.command("version", { isDefault: true }).description("Version a package or packages based on configuration").option(
2191
+ "-c, --config <path>",
2192
+ "Path to config file (defaults to version.config.json in current directory)"
2193
+ ).option("-d, --dry-run", "Dry run (no changes made)", false).option("-b, --bump <type>", "Specify bump type (patch|minor|major)").option("-p, --prerelease [identifier]", "Create prerelease version").option("-s, --synced", "Use synchronized versioning across all packages").option("-j, --json", "Output results as JSON", false).option("-t, --target <packages>", "Comma-delimited list of package names to target").action(async (options) => {
2194
+ if (options.json) {
2195
+ enableJsonOutput(options.dryRun);
1364
2196
  }
1365
- engine.setStrategy("async");
1366
- await engine.run(cliTargets);
1367
- }
1368
- log("Versioning process completed.", "success");
1369
- printJsonOutput();
2197
+ try {
2198
+ const config = await loadConfig(options.config);
2199
+ log(`Loaded configuration from ${options.config || "version.config.json"}`, "info");
2200
+ if (options.dryRun) config.dryRun = true;
2201
+ if (options.synced) config.synced = true;
2202
+ if (options.bump) config.type = options.bump;
2203
+ if (options.prerelease)
2204
+ config.prereleaseIdentifier = options.prerelease === true ? "next" : options.prerelease;
2205
+ const cliTargets = options.target ? options.target.split(",").map((t) => t.trim()) : [];
2206
+ const engine = new VersionEngine(config, !!options.json);
2207
+ if (config.synced) {
2208
+ log("Using synced versioning strategy.", "info");
2209
+ engine.setStrategy("synced");
2210
+ await engine.run();
2211
+ } else if (config.packages && config.packages.length === 1) {
2212
+ log("Using single package versioning strategy.", "info");
2213
+ if (cliTargets.length > 0) {
2214
+ log("--target flag is ignored for single package strategy.", "warning");
2215
+ }
2216
+ engine.setStrategy("single");
2217
+ await engine.run();
2218
+ } else {
2219
+ log("Using async versioning strategy.", "info");
2220
+ if (cliTargets.length > 0) {
2221
+ log(`Targeting specific packages: ${cliTargets.join(", ")}`, "info");
2222
+ }
2223
+ engine.setStrategy("async");
2224
+ await engine.run(cliTargets);
2225
+ }
2226
+ log("Versioning process completed.", "success");
2227
+ printJsonOutput();
2228
+ } catch (error) {
2229
+ log(error instanceof Error ? error.message : String(error), "error");
2230
+ process.exit(1);
2231
+ }
2232
+ });
2233
+ program.command("regenerate-changelog").description("Regenerate a complete changelog from git history").option("-o, --output <path>", "Output path for changelog file", "CHANGELOG.md").option(
2234
+ "-f, --format <format>",
2235
+ "Changelog format (keep-a-changelog|angular)",
2236
+ "keep-a-changelog"
2237
+ ).option("-s, --since <tag>", "Start changelog from specific tag").option("-u, --repo-url <url>", "Repository URL for changelog links").option("-d, --dry-run", "Preview changelog without writing to file", false).option("-p, --project-dir <path>", "Project directory", process.cwd()).action(async (options) => {
2238
+ try {
2239
+ log("Regenerating changelog from git history...", "info");
2240
+ if (options.format !== "keep-a-changelog" && options.format !== "angular") {
2241
+ throw new Error(
2242
+ 'Invalid format specified. Must be either "keep-a-changelog" or "angular"'
2243
+ );
2244
+ }
2245
+ const regenerateOptions = {
2246
+ format: options.format,
2247
+ since: options.since,
2248
+ output: options.output,
2249
+ dryRun: options.dryRun,
2250
+ projectDir: options.projectDir,
2251
+ repoUrl: options.repoUrl
2252
+ };
2253
+ const content = await regenerateChangelog(regenerateOptions);
2254
+ await writeChangelog(
2255
+ content,
2256
+ path7.resolve(options.projectDir, options.output),
2257
+ options.dryRun
2258
+ );
2259
+ if (!options.dryRun) {
2260
+ log(`Changelog successfully regenerated at ${options.output}`, "success");
2261
+ }
2262
+ } catch (error) {
2263
+ log(error instanceof Error ? error.message : String(error), "error");
2264
+ process.exit(1);
2265
+ }
2266
+ });
2267
+ program.parse(process.argv);
1370
2268
  } catch (error) {
1371
- log(error instanceof Error ? error.message : String(error), "error");
2269
+ console.error("Fatal error:", error);
1372
2270
  process.exit(1);
1373
2271
  }
1374
2272
  }