package-versioner 0.6.4 → 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.cjs CHANGED
@@ -34,79 +34,14 @@ __export(index_exports, {
34
34
  run: () => run
35
35
  });
36
36
  module.exports = __toCommonJS(index_exports);
37
- var fs8 = __toESM(require("fs"), 1);
38
- var import_node_path6 = __toESM(require("path"), 1);
37
+ var fs10 = __toESM(require("fs"), 1);
38
+ var import_node_path7 = __toESM(require("path"), 1);
39
39
  var import_commander = require("commander");
40
40
 
41
- // src/config.ts
42
- var fs = __toESM(require("fs"), 1);
43
- var import_node_process = require("process");
44
- function loadConfig(configPath) {
45
- const localProcess = (0, import_node_process.cwd)();
46
- const filePath = configPath || `${localProcess}/version.config.json`;
47
- return new Promise((resolve, reject) => {
48
- fs.readFile(filePath, "utf-8", (err, data) => {
49
- if (err) {
50
- reject(new Error(`Could not locate the config file at ${filePath}: ${err.message}`));
51
- return;
52
- }
53
- try {
54
- const config = JSON.parse(data);
55
- resolve(config);
56
- } catch (err2) {
57
- const errorMessage = err2 instanceof Error ? err2.message : String(err2);
58
- reject(new Error(`Failed to parse config file ${filePath}: ${errorMessage}`));
59
- }
60
- });
61
- });
62
- }
63
-
64
- // src/core/versionEngine.ts
65
- var import_node_process5 = require("process");
66
- var import_get_packages = require("@manypkg/get-packages");
67
-
68
- // src/errors/gitError.ts
69
- var GitError = class extends Error {
70
- constructor(message, code) {
71
- super(message);
72
- this.code = code;
73
- this.name = "GitError";
74
- }
75
- };
76
- function createGitError(code, details) {
77
- const messages = {
78
- ["NOT_GIT_REPO" /* NOT_GIT_REPO */]: "Not a git repository",
79
- ["GIT_PROCESS_ERROR" /* GIT_PROCESS_ERROR */]: "Failed to create new version",
80
- ["NO_FILES" /* NO_FILES */]: "No files specified for commit",
81
- ["NO_COMMIT_MESSAGE" /* NO_COMMIT_MESSAGE */]: "Commit message is required",
82
- ["GIT_ERROR" /* GIT_ERROR */]: "Git operation failed"
83
- };
84
- const baseMessage = messages[code];
85
- const fullMessage = details ? `${baseMessage}: ${details}` : baseMessage;
86
- return new GitError(fullMessage, code);
87
- }
88
-
89
- // src/errors/versionError.ts
90
- var VersionError = class extends Error {
91
- constructor(message, code) {
92
- super(message);
93
- this.code = code;
94
- this.name = "VersionError";
95
- }
96
- };
97
- function createVersionError(code, details) {
98
- const messages = {
99
- ["CONFIG_REQUIRED" /* CONFIG_REQUIRED */]: "Configuration is required",
100
- ["PACKAGES_NOT_FOUND" /* PACKAGES_NOT_FOUND */]: "Failed to get packages information",
101
- ["WORKSPACE_ERROR" /* WORKSPACE_ERROR */]: "Failed to get workspace packages",
102
- ["INVALID_CONFIG" /* INVALID_CONFIG */]: "Invalid configuration",
103
- ["PACKAGE_NOT_FOUND" /* PACKAGE_NOT_FOUND */]: "Package not found",
104
- ["VERSION_CALCULATION_ERROR" /* VERSION_CALCULATION_ERROR */]: "Failed to calculate version"
105
- };
106
- const baseMessage = messages[code];
107
- const fullMessage = details ? `${baseMessage}: ${details}` : baseMessage;
108
- return new VersionError(fullMessage, code);
109
- }
41
+ // src/changelog/changelogRegenerator.ts
42
+ var import_node_child_process2 = require("child_process");
43
+ var import_node_fs = __toESM(require("fs"), 1);
44
+ var import_node_path = __toESM(require("path"), 1);
110
45
 
111
46
  // src/utils/logging.ts
112
47
  var import_chalk = __toESM(require("chalk"), 1);
@@ -189,19 +124,518 @@ function log(message, level = "info") {
189
124
  }
190
125
  }
191
126
 
127
+ // src/changelog/commitParser.ts
128
+ var import_node_child_process = require("child_process");
129
+ var CONVENTIONAL_COMMIT_REGEX = /^(\w+)(?:\(([^)]+)\))?(!)?: (.+)(?:\n\n([\s\S]*))?/;
130
+ var BREAKING_CHANGE_REGEX = /BREAKING CHANGE: ([\s\S]+?)(?:\n\n|$)/;
131
+ function extractChangelogEntriesFromCommits(projectDir, revisionRange) {
132
+ try {
133
+ const command = `git log ${revisionRange} --pretty=format:"%B---COMMIT_DELIMITER---" --no-merges`;
134
+ const output = (0, import_node_child_process.execSync)(command, {
135
+ cwd: projectDir,
136
+ encoding: "utf8"
137
+ });
138
+ const commits = output.split("---COMMIT_DELIMITER---").filter((commit) => commit.trim() !== "");
139
+ return commits.map((commit) => parseCommitMessage(commit)).filter((entry) => entry !== null);
140
+ } catch (error) {
141
+ log(`Error extracting commits: ${error}`, "error");
142
+ return [];
143
+ }
144
+ }
145
+ function parseCommitMessage(message) {
146
+ const match = message.match(CONVENTIONAL_COMMIT_REGEX);
147
+ if (match) {
148
+ const [, type, scope, breakingMark, subject, body = ""] = match;
149
+ const breakingFromMark = breakingMark === "!";
150
+ const breakingChangeMatch = body.match(BREAKING_CHANGE_REGEX);
151
+ const hasBreakingChange = breakingFromMark || breakingChangeMatch !== null;
152
+ const changelogType = mapCommitTypeToChangelogType(type);
153
+ if (!changelogType) {
154
+ return null;
155
+ }
156
+ const issueIds = extractIssueIds(body);
157
+ let description = subject;
158
+ if (hasBreakingChange) {
159
+ description = `**BREAKING** ${description}`;
160
+ }
161
+ return {
162
+ type: changelogType,
163
+ description,
164
+ scope: scope || void 0,
165
+ issueIds: issueIds.length > 0 ? issueIds : void 0,
166
+ originalType: type
167
+ // Store original type for custom formatting
168
+ };
169
+ }
170
+ if (!message.startsWith("Merge") && !message.match(/^v?\d+\.\d+\.\d+/)) {
171
+ const firstLine = message.split("\n")[0].trim();
172
+ return {
173
+ type: "changed",
174
+ description: firstLine
175
+ };
176
+ }
177
+ return null;
178
+ }
179
+ function mapCommitTypeToChangelogType(type) {
180
+ switch (type) {
181
+ case "feat":
182
+ return "added";
183
+ case "fix":
184
+ return "fixed";
185
+ case "docs":
186
+ case "style":
187
+ case "refactor":
188
+ case "perf":
189
+ case "build":
190
+ case "ci":
191
+ return "changed";
192
+ case "revert":
193
+ return "removed";
194
+ case "chore":
195
+ return "changed";
196
+ case "test":
197
+ return null;
198
+ default:
199
+ return "changed";
200
+ }
201
+ }
202
+ function extractIssueIds(body) {
203
+ const issueRegex = /(?:fix|fixes|close|closes|resolve|resolves)\s+#(\d+)/gi;
204
+ const issueIds = [];
205
+ let match = issueRegex.exec(body);
206
+ while (match !== null) {
207
+ issueIds.push(`#${match[1]}`);
208
+ match = issueRegex.exec(body);
209
+ }
210
+ return issueIds;
211
+ }
212
+
213
+ // src/changelog/formatters.ts
214
+ function formatChangelogEntries(format, version, date, entries, packageName, repoUrl) {
215
+ const formattingEntries = entries.map((entry) => {
216
+ const hasBreaking = entry.description.includes("**BREAKING**");
217
+ return {
218
+ ...entry,
219
+ breaking: hasBreaking
220
+ };
221
+ });
222
+ return format === "keep-a-changelog" ? formatKeepAChangelogEntries(version, date, formattingEntries, repoUrl) : formatAngularEntries(version, date, formattingEntries, packageName);
223
+ }
224
+ function formatKeepAChangelogEntries(version, date, entries, repoUrl) {
225
+ const added = [];
226
+ const changed = [];
227
+ const deprecated = [];
228
+ const removed = [];
229
+ const fixed = [];
230
+ const security = [];
231
+ for (const entry of entries) {
232
+ const entryText = entry.scope ? `- **${entry.scope}**: ${entry.description}` : `- ${entry.description}`;
233
+ const formattedEntry = entry.breaking ? entryText.replace(/^- /, "- **BREAKING** ") : entryText;
234
+ const entryType = entry.originalType || entry.type;
235
+ switch (entryType) {
236
+ case "feat":
237
+ added.push(formattedEntry);
238
+ break;
239
+ case "fix":
240
+ fixed.push(formattedEntry);
241
+ break;
242
+ case "docs":
243
+ case "style":
244
+ case "refactor":
245
+ case "perf":
246
+ case "build":
247
+ case "ci":
248
+ changed.push(formattedEntry);
249
+ break;
250
+ case "test":
251
+ break;
252
+ case "chore":
253
+ if (entry.description.toLowerCase().includes("deprecat")) {
254
+ deprecated.push(formattedEntry);
255
+ } else {
256
+ changed.push(formattedEntry);
257
+ }
258
+ break;
259
+ // Keep-a-changelog standard types
260
+ case "added":
261
+ added.push(formattedEntry);
262
+ break;
263
+ case "changed":
264
+ changed.push(formattedEntry);
265
+ break;
266
+ case "deprecated":
267
+ deprecated.push(formattedEntry);
268
+ break;
269
+ case "removed":
270
+ removed.push(formattedEntry);
271
+ break;
272
+ case "fixed":
273
+ fixed.push(formattedEntry);
274
+ break;
275
+ case "security":
276
+ security.push(formattedEntry);
277
+ break;
278
+ default:
279
+ changed.push(formattedEntry);
280
+ }
281
+ }
282
+ let content = `## [${version}] - ${date}
283
+
284
+ `;
285
+ if (added.length > 0) {
286
+ content += `### Added
287
+
288
+ ${added.join("\n")}
289
+
290
+ `;
291
+ }
292
+ if (changed.length > 0) {
293
+ content += `### Changed
294
+
295
+ ${changed.join("\n")}
296
+
297
+ `;
298
+ }
299
+ if (deprecated.length > 0) {
300
+ content += `### Deprecated
301
+
302
+ ${deprecated.join("\n")}
303
+
304
+ `;
305
+ }
306
+ if (removed.length > 0) {
307
+ content += `### Removed
308
+
309
+ ${removed.join("\n")}
310
+
311
+ `;
312
+ }
313
+ if (fixed.length > 0) {
314
+ content += `### Fixed
315
+
316
+ ${fixed.join("\n")}
317
+
318
+ `;
319
+ }
320
+ if (security.length > 0) {
321
+ content += `### Security
322
+
323
+ ${security.join("\n")}
324
+
325
+ `;
326
+ }
327
+ if (repoUrl) {
328
+ content += `[${version}]: ${repoUrl}/compare/v${version}...HEAD
329
+ `;
330
+ }
331
+ return content.trim();
332
+ }
333
+ function formatAngularEntries(version, date, entries, packageName) {
334
+ const features = [];
335
+ const bugfixes = [];
336
+ const performance = [];
337
+ const breaking = [];
338
+ for (const entry of entries) {
339
+ if (entry.breaking) {
340
+ breaking.push(entry);
341
+ }
342
+ const entryType = entry.originalType || entry.type;
343
+ switch (entryType) {
344
+ case "feat":
345
+ case "added":
346
+ features.push(entry);
347
+ break;
348
+ case "fix":
349
+ case "fixed":
350
+ bugfixes.push(entry);
351
+ break;
352
+ case "perf":
353
+ performance.push(entry);
354
+ break;
355
+ }
356
+ }
357
+ let content = `## [${version}]${packageName ? ` (${packageName})` : ""} (${date})
358
+
359
+ `;
360
+ if (features.length > 0) {
361
+ content += "### Features\n\n";
362
+ content += formatAngularTypeEntries(features);
363
+ content += "\n";
364
+ }
365
+ if (bugfixes.length > 0) {
366
+ content += "### Bug Fixes\n\n";
367
+ content += formatAngularTypeEntries(bugfixes);
368
+ content += "\n";
369
+ }
370
+ if (performance.length > 0) {
371
+ content += "### Performance Improvements\n\n";
372
+ content += formatAngularTypeEntries(performance);
373
+ content += "\n";
374
+ }
375
+ if (breaking.length > 0) {
376
+ content += "### BREAKING CHANGES\n\n";
377
+ content += formatAngularTypeEntries(breaking);
378
+ content += "\n";
379
+ }
380
+ return content.trim();
381
+ }
382
+ function formatAngularTypeEntries(entries) {
383
+ var _a;
384
+ const entriesByScope = /* @__PURE__ */ new Map();
385
+ for (const entry of entries) {
386
+ const scope = entry.scope || "";
387
+ if (!entriesByScope.has(scope)) {
388
+ entriesByScope.set(scope, []);
389
+ }
390
+ (_a = entriesByScope.get(scope)) == null ? void 0 : _a.push(entry);
391
+ }
392
+ const result = [];
393
+ for (const [scope, scopeEntries] of Object.entries(groupEntriesByScope(entries))) {
394
+ if (scope !== "undefined" && scope !== "") {
395
+ result.push(`* **${scope}:**`);
396
+ for (const entry of scopeEntries) {
397
+ const description = entry.description.replace("**BREAKING** ", "");
398
+ result.push(` * ${description}`);
399
+ }
400
+ } else {
401
+ for (const entry of scopeEntries) {
402
+ const description = entry.description.replace("**BREAKING** ", "");
403
+ result.push(`* ${description}`);
404
+ }
405
+ }
406
+ }
407
+ return result.join("\n");
408
+ }
409
+ function groupEntriesByScope(entries) {
410
+ const result = {};
411
+ for (const entry of entries) {
412
+ const scope = entry.scope || "";
413
+ if (!result[scope]) {
414
+ result[scope] = [];
415
+ }
416
+ result[scope].push(entry);
417
+ }
418
+ return result;
419
+ }
420
+
421
+ // src/changelog/templates.ts
422
+ function getDefaultTemplate(format) {
423
+ return format === "keep-a-changelog" ? getKeepAChangelogTemplate() : getAngularTemplate();
424
+ }
425
+ function getKeepAChangelogTemplate() {
426
+ return `# Changelog
427
+
428
+ All notable changes to this project will be documented in this file.
429
+
430
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
431
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
432
+
433
+ `;
434
+ }
435
+ function getAngularTemplate() {
436
+ return `# Changelog
437
+
438
+ `;
439
+ }
440
+
441
+ // src/changelog/changelogRegenerator.ts
442
+ function getAllVersionTags(since, versionPrefix = "v") {
443
+ try {
444
+ const command = since ? `git tag --list "${versionPrefix}*" --sort=creatordate --contains ${since}` : `git tag --list "${versionPrefix}*" --sort=creatordate`;
445
+ const tagOutput = (0, import_node_child_process2.execSync)(command, { encoding: "utf8" }).trim();
446
+ if (!tagOutput) {
447
+ return [];
448
+ }
449
+ const tags = tagOutput.split("\n").filter((tag) => !!tag);
450
+ return tags.map((tag) => {
451
+ try {
452
+ const date = (0, import_node_child_process2.execSync)(`git log -1 --format=%ad --date=short ${tag}`, {
453
+ encoding: "utf8"
454
+ }).trim();
455
+ const version = tag.replace(new RegExp(`^${versionPrefix}`), "");
456
+ return { tag, version, date };
457
+ } catch (error) {
458
+ log(`Failed to get date for tag ${tag}: ${error}`, "warning");
459
+ return { tag, version: tag.replace(new RegExp(`^${versionPrefix}`), ""), date: "Unknown" };
460
+ }
461
+ });
462
+ } catch (error) {
463
+ log(`Failed to get version tags: ${error}`, "error");
464
+ return [];
465
+ }
466
+ }
467
+ async function regenerateChangelog(options) {
468
+ const { format, since, projectDir } = options;
469
+ const packageJsonPath = import_node_path.default.join(projectDir, "package.json");
470
+ let packageName = "";
471
+ let repoUrl = options.repoUrl;
472
+ if (import_node_fs.default.existsSync(packageJsonPath)) {
473
+ try {
474
+ const packageJson = JSON.parse(import_node_fs.default.readFileSync(packageJsonPath, "utf8"));
475
+ packageName = packageJson.name || "";
476
+ if (!repoUrl && packageJson.repository) {
477
+ if (typeof packageJson.repository === "string") {
478
+ repoUrl = packageJson.repository;
479
+ } else if (packageJson.repository.url) {
480
+ repoUrl = packageJson.repository.url;
481
+ }
482
+ if ((repoUrl == null ? void 0 : repoUrl.startsWith("git+")) && (repoUrl == null ? void 0 : repoUrl.endsWith(".git"))) {
483
+ repoUrl = repoUrl.substring(4, repoUrl.length - 4);
484
+ }
485
+ }
486
+ } catch (error) {
487
+ log(`Failed to read package.json: ${error}`, "warning");
488
+ }
489
+ }
490
+ let versionPrefix = "v";
491
+ try {
492
+ const allTags = (0, import_node_child_process2.execSync)("git tag --list", { encoding: "utf8" }).trim().split("\n");
493
+ const versionTag = allTags.find((tag) => /^[vV][0-9]/.test(tag));
494
+ if (versionTag) {
495
+ versionPrefix = versionTag.charAt(0);
496
+ }
497
+ } catch {
498
+ }
499
+ const tags = getAllVersionTags(since, versionPrefix);
500
+ if (!tags.length) {
501
+ throw new Error(
502
+ 'No version tags found in git history. Make sure you have tags that start with the version prefix (usually "v").'
503
+ );
504
+ }
505
+ let changelogContent = getDefaultTemplate(format);
506
+ log(`Found ${tags.length} version tags, generating changelog...`, "info");
507
+ const versions = [];
508
+ for (let i = tags.length - 1; i >= 0; i--) {
509
+ const currentTag = tags[i];
510
+ const previousTag = i > 0 ? tags[i - 1].tag : null;
511
+ log(`Processing changes for ${currentTag.tag}...`, "info");
512
+ try {
513
+ const tagRange = previousTag ? `${previousTag}..${currentTag.tag}` : currentTag.tag;
514
+ const entries = extractChangelogEntriesFromCommits(projectDir, tagRange);
515
+ if (!entries.length) {
516
+ log(`No changelog entries found for ${currentTag.tag}, adding placeholder entry`, "info");
517
+ entries.push({
518
+ type: "changed",
519
+ description: `Release version ${currentTag.version}`
520
+ });
521
+ }
522
+ versions.unshift(
523
+ formatChangelogEntries(
524
+ format,
525
+ currentTag.version,
526
+ currentTag.date,
527
+ entries,
528
+ packageName,
529
+ repoUrl
530
+ )
531
+ );
532
+ } catch (error) {
533
+ log(`Failed to process version ${currentTag.tag}: ${error}`, "error");
534
+ }
535
+ }
536
+ changelogContent += versions.join("\n\n");
537
+ return changelogContent;
538
+ }
539
+ async function writeChangelog(content, outputPath, dryRun) {
540
+ if (dryRun) {
541
+ log("--- Changelog Preview ---", "info");
542
+ console.log(content);
543
+ log("--- End Preview ---", "info");
544
+ return;
545
+ }
546
+ try {
547
+ import_node_fs.default.writeFileSync(outputPath, content, "utf8");
548
+ log(`Changelog successfully written to ${outputPath}`, "success");
549
+ } catch (error) {
550
+ throw new Error(
551
+ `Failed to write changelog: ${error instanceof Error ? error.message : String(error)}`
552
+ );
553
+ }
554
+ }
555
+
556
+ // src/config.ts
557
+ var fs2 = __toESM(require("fs"), 1);
558
+ var import_node_process = require("process");
559
+ function loadConfig(configPath) {
560
+ const localProcess = (0, import_node_process.cwd)();
561
+ const filePath = configPath || `${localProcess}/version.config.json`;
562
+ return new Promise((resolve, reject) => {
563
+ fs2.readFile(filePath, "utf-8", (err, data) => {
564
+ if (err) {
565
+ reject(new Error(`Could not locate the config file at ${filePath}: ${err.message}`));
566
+ return;
567
+ }
568
+ try {
569
+ const config = JSON.parse(data);
570
+ resolve(config);
571
+ } catch (err2) {
572
+ const errorMessage = err2 instanceof Error ? err2.message : String(err2);
573
+ reject(new Error(`Failed to parse config file ${filePath}: ${errorMessage}`));
574
+ }
575
+ });
576
+ });
577
+ }
578
+
579
+ // src/core/versionEngine.ts
580
+ var import_node_process5 = require("process");
581
+ var import_get_packages = require("@manypkg/get-packages");
582
+
583
+ // src/errors/gitError.ts
584
+ var GitError = class extends Error {
585
+ constructor(message, code) {
586
+ super(message);
587
+ this.code = code;
588
+ this.name = "GitError";
589
+ }
590
+ };
591
+ function createGitError(code, details) {
592
+ const messages = {
593
+ ["NOT_GIT_REPO" /* NOT_GIT_REPO */]: "Not a git repository",
594
+ ["GIT_PROCESS_ERROR" /* GIT_PROCESS_ERROR */]: "Failed to create new version",
595
+ ["NO_FILES" /* NO_FILES */]: "No files specified for commit",
596
+ ["NO_COMMIT_MESSAGE" /* NO_COMMIT_MESSAGE */]: "Commit message is required",
597
+ ["GIT_ERROR" /* GIT_ERROR */]: "Git operation failed"
598
+ };
599
+ const baseMessage = messages[code];
600
+ const fullMessage = details ? `${baseMessage}: ${details}` : baseMessage;
601
+ return new GitError(fullMessage, code);
602
+ }
603
+
604
+ // src/errors/versionError.ts
605
+ var VersionError = class extends Error {
606
+ constructor(message, code) {
607
+ super(message);
608
+ this.code = code;
609
+ this.name = "VersionError";
610
+ }
611
+ };
612
+ function createVersionError(code, details) {
613
+ const messages = {
614
+ ["CONFIG_REQUIRED" /* CONFIG_REQUIRED */]: "Configuration is required",
615
+ ["PACKAGES_NOT_FOUND" /* PACKAGES_NOT_FOUND */]: "Failed to get packages information",
616
+ ["WORKSPACE_ERROR" /* WORKSPACE_ERROR */]: "Failed to get workspace packages",
617
+ ["INVALID_CONFIG" /* INVALID_CONFIG */]: "Invalid configuration",
618
+ ["PACKAGE_NOT_FOUND" /* PACKAGE_NOT_FOUND */]: "Package not found",
619
+ ["VERSION_CALCULATION_ERROR" /* VERSION_CALCULATION_ERROR */]: "Failed to calculate version"
620
+ };
621
+ const baseMessage = messages[code];
622
+ const fullMessage = details ? `${baseMessage}: ${details}` : baseMessage;
623
+ return new VersionError(fullMessage, code);
624
+ }
625
+
192
626
  // src/core/versionStrategies.ts
193
- var import_node_fs6 = __toESM(require("fs"), 1);
194
- var path5 = __toESM(require("path"), 1);
627
+ var import_node_fs7 = __toESM(require("fs"), 1);
628
+ var path7 = __toESM(require("path"), 1);
195
629
 
196
630
  // src/git/commands.ts
197
631
  var import_node_process2 = require("process");
198
632
 
199
633
  // src/git/commandExecutor.ts
200
- var import_node_child_process = require("child_process");
634
+ var import_node_child_process3 = require("child_process");
201
635
  var execAsync = (command, options) => {
202
636
  const defaultOptions = { maxBuffer: 1024 * 1024 * 10, ...options };
203
637
  return new Promise((resolve, reject) => {
204
- (0, import_node_child_process.exec)(
638
+ (0, import_node_child_process3.exec)(
205
639
  command,
206
640
  defaultOptions,
207
641
  (error, stdout, stderr) => {
@@ -214,29 +648,29 @@ var execAsync = (command, options) => {
214
648
  );
215
649
  });
216
650
  };
217
- var execSync = (command, args) => (0, import_node_child_process.execSync)(command, { maxBuffer: 1024 * 1024 * 10, ...args });
651
+ var execSync3 = (command, args) => (0, import_node_child_process3.execSync)(command, { maxBuffer: 1024 * 1024 * 10, ...args });
218
652
 
219
653
  // src/git/repository.ts
220
- var import_node_fs = require("fs");
221
- var import_node_path = require("path");
654
+ var import_node_fs2 = require("fs");
655
+ var import_node_path2 = require("path");
222
656
  function isGitRepository(directory) {
223
- const gitDir = (0, import_node_path.join)(directory, ".git");
224
- if (!(0, import_node_fs.existsSync)(gitDir)) {
657
+ const gitDir = (0, import_node_path2.join)(directory, ".git");
658
+ if (!(0, import_node_fs2.existsSync)(gitDir)) {
225
659
  return false;
226
660
  }
227
- const stats = (0, import_node_fs.statSync)(gitDir);
661
+ const stats = (0, import_node_fs2.statSync)(gitDir);
228
662
  if (!stats.isDirectory()) {
229
663
  return false;
230
664
  }
231
665
  try {
232
- execSync("git rev-parse --is-inside-work-tree", { cwd: directory });
666
+ execSync3("git rev-parse --is-inside-work-tree", { cwd: directory });
233
667
  return true;
234
668
  } catch (_error) {
235
669
  return false;
236
670
  }
237
671
  }
238
672
  function getCurrentBranch() {
239
- const result = execSync("git rev-parse --abbrev-ref HEAD");
673
+ const result = execSync3("git rev-parse --abbrev-ref HEAD");
240
674
  return result.toString().trim();
241
675
  }
242
676
 
@@ -380,7 +814,7 @@ function createTemplateString(template, variables) {
380
814
  function getCommitsLength(pkgRoot) {
381
815
  try {
382
816
  const gitCommand = `git rev-list --count HEAD ^$(git describe --tags --abbrev=0) ${pkgRoot}`;
383
- const amount = execSync(gitCommand).toString().trim();
817
+ const amount = execSync3(gitCommand).toString().trim();
384
818
  return Number(amount);
385
819
  } catch (error) {
386
820
  const errorMessage = error instanceof Error ? error.message : String(error);
@@ -477,21 +911,21 @@ async function getLatestTagForPackage(packageName, versionPrefix) {
477
911
  }
478
912
 
479
913
  // src/package/packageManagement.ts
480
- var import_node_fs3 = __toESM(require("fs"), 1);
481
- var import_node_path3 = __toESM(require("path"), 1);
914
+ var import_node_fs4 = __toESM(require("fs"), 1);
915
+ var import_node_path4 = __toESM(require("path"), 1);
482
916
 
483
917
  // src/cargo/cargoHandler.ts
484
- var import_node_fs2 = __toESM(require("fs"), 1);
485
- var import_node_path2 = __toESM(require("path"), 1);
918
+ var import_node_fs3 = __toESM(require("fs"), 1);
919
+ var import_node_path3 = __toESM(require("path"), 1);
486
920
  var TOML = __toESM(require("smol-toml"), 1);
487
921
  function getCargoInfo(cargoPath) {
488
922
  var _a;
489
- if (!import_node_fs2.default.existsSync(cargoPath)) {
923
+ if (!import_node_fs3.default.existsSync(cargoPath)) {
490
924
  log(`Cargo.toml file not found at: ${cargoPath}`, "error");
491
925
  throw new Error(`Cargo.toml file not found at: ${cargoPath}`);
492
926
  }
493
927
  try {
494
- const fileContent = import_node_fs2.default.readFileSync(cargoPath, "utf8");
928
+ const fileContent = import_node_fs3.default.readFileSync(cargoPath, "utf8");
495
929
  const cargo = TOML.parse(fileContent);
496
930
  if (!((_a = cargo.package) == null ? void 0 : _a.name)) {
497
931
  log(`Package name not found in: ${cargoPath}`, "error");
@@ -501,7 +935,7 @@ function getCargoInfo(cargoPath) {
501
935
  name: cargo.package.name,
502
936
  version: cargo.package.version || "0.0.0",
503
937
  path: cargoPath,
504
- dir: import_node_path2.default.dirname(cargoPath),
938
+ dir: import_node_path3.default.dirname(cargoPath),
505
939
  content: cargo
506
940
  };
507
941
  } catch (error) {
@@ -514,12 +948,12 @@ function getCargoInfo(cargoPath) {
514
948
  }
515
949
  }
516
950
  function isCargoToml(filePath) {
517
- return import_node_path2.default.basename(filePath) === "Cargo.toml";
951
+ return import_node_path3.default.basename(filePath) === "Cargo.toml";
518
952
  }
519
953
  function updateCargoVersion(cargoPath, version) {
520
954
  var _a;
521
955
  try {
522
- const originalContent = import_node_fs2.default.readFileSync(cargoPath, "utf8");
956
+ const originalContent = import_node_fs3.default.readFileSync(cargoPath, "utf8");
523
957
  const cargo = TOML.parse(originalContent);
524
958
  const packageName = (_a = cargo.package) == null ? void 0 : _a.name;
525
959
  if (!packageName) {
@@ -531,7 +965,7 @@ function updateCargoVersion(cargoPath, version) {
531
965
  cargo.package.version = version;
532
966
  }
533
967
  const updatedContent = TOML.stringify(cargo);
534
- import_node_fs2.default.writeFileSync(cargoPath, updatedContent);
968
+ import_node_fs3.default.writeFileSync(cargoPath, updatedContent);
535
969
  addPackageUpdate(packageName, version, cargoPath);
536
970
  log(`Updated Cargo.toml at ${cargoPath} to version ${version}`, "success");
537
971
  } catch (error) {
@@ -550,11 +984,11 @@ function updatePackageVersion(packagePath, version) {
550
984
  return;
551
985
  }
552
986
  try {
553
- const packageContent = import_node_fs3.default.readFileSync(packagePath, "utf8");
987
+ const packageContent = import_node_fs4.default.readFileSync(packagePath, "utf8");
554
988
  const packageJson = JSON.parse(packageContent);
555
989
  const packageName = packageJson.name;
556
990
  packageJson.version = version;
557
- import_node_fs3.default.writeFileSync(packagePath, `${JSON.stringify(packageJson, null, 2)}
991
+ import_node_fs4.default.writeFileSync(packagePath, `${JSON.stringify(packageJson, null, 2)}
558
992
  `);
559
993
  addPackageUpdate(packageName, version, packagePath);
560
994
  log(`Updated package.json at ${packagePath} to version ${version}`, "success");
@@ -568,24 +1002,349 @@ function updatePackageVersion(packagePath, version) {
568
1002
  }
569
1003
 
570
1004
  // src/package/packageProcessor.ts
571
- var fs6 = __toESM(require("fs"), 1);
572
- var import_node_path5 = __toESM(require("path"), 1);
1005
+ var fs8 = __toESM(require("fs"), 1);
1006
+ var import_node_path6 = __toESM(require("path"), 1);
573
1007
  var import_node_process4 = require("process");
574
1008
 
1009
+ // src/changelog/changelogManager.ts
1010
+ var fs5 = __toESM(require("fs"), 1);
1011
+ var path4 = __toESM(require("path"), 1);
1012
+ function createChangelog(_packagePath, packageName) {
1013
+ return {
1014
+ projectName: packageName,
1015
+ unreleased: [],
1016
+ versions: []
1017
+ };
1018
+ }
1019
+ function parseChangelog(filePath) {
1020
+ try {
1021
+ if (!fs5.existsSync(filePath)) {
1022
+ return null;
1023
+ }
1024
+ fs5.readFileSync(filePath, "utf8");
1025
+ log(`Parsed changelog at ${filePath}`, "info");
1026
+ return {
1027
+ projectName: path4.basename(path4.dirname(filePath)),
1028
+ unreleased: [],
1029
+ versions: []
1030
+ };
1031
+ } catch (error) {
1032
+ log(
1033
+ `Error parsing changelog: ${error instanceof Error ? error.message : String(error)}`,
1034
+ "error"
1035
+ );
1036
+ return null;
1037
+ }
1038
+ }
1039
+ function generateLinks(changelog, repoUrl) {
1040
+ var _a, _b;
1041
+ if (!repoUrl || changelog.versions.length === 0) {
1042
+ return "";
1043
+ }
1044
+ let links = "\n";
1045
+ if (changelog.unreleased.length > 0) {
1046
+ const latestVersion = ((_a = changelog.versions[0]) == null ? void 0 : _a.version) || "";
1047
+ links += `[unreleased]: ${repoUrl}/compare/v${latestVersion}...HEAD
1048
+ `;
1049
+ }
1050
+ for (let i = 0; i < changelog.versions.length; i++) {
1051
+ const currentVersion = changelog.versions[i].version;
1052
+ const previousVersion = (_b = changelog.versions[i + 1]) == null ? void 0 : _b.version;
1053
+ if (previousVersion) {
1054
+ links += `[${currentVersion}]: ${repoUrl}/compare/v${previousVersion}...v${currentVersion}
1055
+ `;
1056
+ } else if (i === changelog.versions.length - 1) {
1057
+ links += `[${currentVersion}]: ${repoUrl}/releases/tag/v${currentVersion}
1058
+ `;
1059
+ }
1060
+ }
1061
+ return links;
1062
+ }
1063
+ function generateAngularChangelogContent(changelog, repoUrl) {
1064
+ let content = "# Changelog\n\n";
1065
+ if (changelog.unreleased.length > 0) {
1066
+ content += "## [Unreleased]\n\n";
1067
+ const groupedByType = groupEntriesByAngularType(changelog.unreleased);
1068
+ for (const [type, entries] of Object.entries(groupedByType)) {
1069
+ content += `### ${formatAngularType(type)}
1070
+
1071
+ `;
1072
+ const groupedByScope = groupEntriesByScope2(entries);
1073
+ for (const [scope, scopeEntries] of Object.entries(groupedByScope)) {
1074
+ if (scope !== "undefined" && scope !== "") {
1075
+ content += `* **${scope}:**
1076
+ `;
1077
+ for (const entry of scopeEntries) {
1078
+ content += formatAngularEntry(entry, false);
1079
+ }
1080
+ content += "\n";
1081
+ } else {
1082
+ for (const entry of scopeEntries) {
1083
+ content += formatAngularEntry(entry, true);
1084
+ }
1085
+ }
1086
+ }
1087
+ content += "\n";
1088
+ }
1089
+ const breakingChanges = changelog.unreleased.filter(
1090
+ (entry) => entry.description.includes("**BREAKING**")
1091
+ );
1092
+ if (breakingChanges.length > 0) {
1093
+ content += "### BREAKING CHANGES\n\n";
1094
+ for (const entry of breakingChanges) {
1095
+ const description = entry.description.replace("**BREAKING** ", "");
1096
+ content += `* ${entry.scope ? `**${entry.scope}:** ` : ""}${description}`;
1097
+ if (entry.issueIds && entry.issueIds.length > 0) {
1098
+ content += ` (${entry.issueIds.join(", ")})`;
1099
+ }
1100
+ content += "\n";
1101
+ }
1102
+ content += "\n";
1103
+ }
1104
+ }
1105
+ for (const version of changelog.versions) {
1106
+ content += `## [${version.version}] - ${version.date}
1107
+
1108
+ `;
1109
+ const groupedByType = groupEntriesByAngularType(version.entries);
1110
+ for (const [type, entries] of Object.entries(groupedByType)) {
1111
+ content += `### ${formatAngularType(type)}
1112
+
1113
+ `;
1114
+ const groupedByScope = groupEntriesByScope2(entries);
1115
+ for (const [scope, scopeEntries] of Object.entries(groupedByScope)) {
1116
+ if (scope !== "undefined" && scope !== "") {
1117
+ content += `* **${scope}:**
1118
+ `;
1119
+ for (const entry of scopeEntries) {
1120
+ content += formatAngularEntry(entry, false);
1121
+ }
1122
+ content += "\n";
1123
+ } else {
1124
+ for (const entry of scopeEntries) {
1125
+ content += formatAngularEntry(entry, true);
1126
+ }
1127
+ }
1128
+ }
1129
+ content += "\n";
1130
+ }
1131
+ const breakingChanges = version.entries.filter(
1132
+ (entry) => entry.description.includes("**BREAKING**")
1133
+ );
1134
+ if (breakingChanges.length > 0) {
1135
+ content += "### BREAKING CHANGES\n\n";
1136
+ for (const entry of breakingChanges) {
1137
+ const description = entry.description.replace("**BREAKING** ", "");
1138
+ content += `* ${entry.scope ? `**${entry.scope}:** ` : ""}${description}`;
1139
+ if (entry.issueIds && entry.issueIds.length > 0) {
1140
+ content += ` (${entry.issueIds.join(", ")})`;
1141
+ }
1142
+ content += "\n";
1143
+ }
1144
+ content += "\n";
1145
+ }
1146
+ }
1147
+ content += generateLinks(changelog, repoUrl);
1148
+ return content;
1149
+ }
1150
+ function groupEntriesByAngularType(entries) {
1151
+ const result = {};
1152
+ for (const entry of entries) {
1153
+ const type = entry.originalType || mapToAngularType(entry.type);
1154
+ if (!result[type]) {
1155
+ result[type] = [];
1156
+ }
1157
+ result[type].push(entry);
1158
+ }
1159
+ return result;
1160
+ }
1161
+ function mapToAngularType(type) {
1162
+ switch (type) {
1163
+ case "added":
1164
+ return "feat";
1165
+ case "fixed":
1166
+ return "fix";
1167
+ case "changed":
1168
+ return "perf";
1169
+ case "deprecated":
1170
+ case "removed":
1171
+ case "security":
1172
+ return type;
1173
+ default:
1174
+ return type;
1175
+ }
1176
+ }
1177
+ function formatAngularType(type) {
1178
+ switch (type) {
1179
+ case "feat":
1180
+ return "Features";
1181
+ case "fix":
1182
+ return "Bug Fixes";
1183
+ case "perf":
1184
+ return "Performance Improvements";
1185
+ case "security":
1186
+ return "Security";
1187
+ case "deprecated":
1188
+ return "Deprecated";
1189
+ case "removed":
1190
+ return "Removed";
1191
+ default:
1192
+ return capitalizeFirstLetter(type);
1193
+ }
1194
+ }
1195
+ function groupEntriesByScope2(entries) {
1196
+ const result = {};
1197
+ for (const entry of entries) {
1198
+ const scope = entry.scope || "";
1199
+ if (!result[scope]) {
1200
+ result[scope] = [];
1201
+ }
1202
+ result[scope].push(entry);
1203
+ }
1204
+ return result;
1205
+ }
1206
+ function formatAngularEntry(entry, includeScope) {
1207
+ let result = " * ";
1208
+ if (includeScope && entry.scope) {
1209
+ result += `**${entry.scope}:** `;
1210
+ }
1211
+ let description = entry.description;
1212
+ if (!includeScope && entry.scope && description.startsWith(`**${entry.scope}**: `)) {
1213
+ description = description.substring(`**${entry.scope}**: `.length);
1214
+ }
1215
+ if (description.startsWith("**BREAKING** ")) {
1216
+ description = description.substring("**BREAKING** ".length);
1217
+ }
1218
+ result += description;
1219
+ if (entry.issueIds && entry.issueIds.length > 0) {
1220
+ result += ` (${entry.issueIds.join(", ")})`;
1221
+ }
1222
+ result += "\n";
1223
+ return result;
1224
+ }
1225
+ function generateChangelogContent(changelog, repoUrl, format = "keep-a-changelog") {
1226
+ if (format === "angular") {
1227
+ return generateAngularChangelogContent(changelog, repoUrl);
1228
+ }
1229
+ let content = "# Changelog\n\n";
1230
+ content += `All notable changes to ${changelog.projectName} will be documented in this file.
1231
+
1232
+ `;
1233
+ content += "The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),\n";
1234
+ content += "and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).\n\n";
1235
+ if (changelog.unreleased.length > 0) {
1236
+ content += "## [Unreleased]\n\n";
1237
+ const grouped = changelog.unreleased.reduce(
1238
+ (acc, entry) => {
1239
+ if (!acc[entry.type]) {
1240
+ acc[entry.type] = [];
1241
+ }
1242
+ acc[entry.type].push(entry);
1243
+ return acc;
1244
+ },
1245
+ {}
1246
+ );
1247
+ for (const [type, entries] of Object.entries(grouped)) {
1248
+ content += `### ${capitalizeFirstLetter(type)}
1249
+
1250
+ `;
1251
+ for (const entry of entries) {
1252
+ let entryText = `- ${entry.description}`;
1253
+ if (entry.issueIds && entry.issueIds.length > 0) {
1254
+ entryText += ` (${entry.issueIds.join(", ")})`;
1255
+ }
1256
+ content += `${entryText}.
1257
+ `;
1258
+ }
1259
+ content += "\n";
1260
+ }
1261
+ }
1262
+ for (const version of changelog.versions) {
1263
+ content += `## [${version.version}] - ${version.date}
1264
+
1265
+ `;
1266
+ const grouped = version.entries.reduce(
1267
+ (acc, entry) => {
1268
+ if (!acc[entry.type]) {
1269
+ acc[entry.type] = [];
1270
+ }
1271
+ acc[entry.type].push(entry);
1272
+ return acc;
1273
+ },
1274
+ {}
1275
+ );
1276
+ for (const [type, entries] of Object.entries(grouped)) {
1277
+ content += `### ${capitalizeFirstLetter(type)}
1278
+
1279
+ `;
1280
+ for (const entry of entries) {
1281
+ let entryText = `- ${entry.description}`;
1282
+ if (entry.issueIds && entry.issueIds.length > 0) {
1283
+ entryText += ` (${entry.issueIds.join(", ")})`;
1284
+ }
1285
+ content += `${entryText}.
1286
+ `;
1287
+ }
1288
+ content += "\n";
1289
+ }
1290
+ }
1291
+ content += generateLinks(changelog, repoUrl);
1292
+ return content;
1293
+ }
1294
+ function updateChangelog(packagePath, packageName, version, entries, repoUrl, format = "keep-a-changelog") {
1295
+ try {
1296
+ const changelogPath = path4.join(packagePath, "CHANGELOG.md");
1297
+ let changelog;
1298
+ if (fs5.existsSync(changelogPath)) {
1299
+ const existingChangelog = parseChangelog(changelogPath);
1300
+ if (existingChangelog) {
1301
+ changelog = existingChangelog;
1302
+ } else {
1303
+ changelog = createChangelog(packagePath, packageName);
1304
+ }
1305
+ } else {
1306
+ changelog = createChangelog(packagePath, packageName);
1307
+ }
1308
+ if (version) {
1309
+ const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
1310
+ const newVersion = {
1311
+ version,
1312
+ date: today,
1313
+ entries: [...changelog.unreleased, ...entries]
1314
+ };
1315
+ changelog.unreleased = [];
1316
+ changelog.versions.unshift(newVersion);
1317
+ } else {
1318
+ changelog.unreleased = [...changelog.unreleased, ...entries];
1319
+ }
1320
+ const content = generateChangelogContent(changelog, repoUrl, format);
1321
+ fs5.writeFileSync(changelogPath, content);
1322
+ log(`Updated changelog at ${changelogPath}`, "success");
1323
+ } catch (error) {
1324
+ log(
1325
+ `Error updating changelog: ${error instanceof Error ? error.message : String(error)}`,
1326
+ "error"
1327
+ );
1328
+ }
1329
+ }
1330
+ function capitalizeFirstLetter(input) {
1331
+ return input.charAt(0).toUpperCase() + input.slice(1);
1332
+ }
1333
+
575
1334
  // src/core/versionCalculator.ts
576
1335
  var import_node_process3 = require("process");
577
1336
  var import_conventional_recommended_bump = require("conventional-recommended-bump");
578
1337
  var import_semver2 = __toESM(require("semver"), 1);
579
1338
 
580
1339
  // src/utils/manifestHelpers.ts
581
- var import_node_fs4 = __toESM(require("fs"), 1);
582
- var import_node_path4 = __toESM(require("path"), 1);
1340
+ var import_node_fs5 = __toESM(require("fs"), 1);
1341
+ var import_node_path5 = __toESM(require("path"), 1);
583
1342
  function getVersionFromManifests(packageDir) {
584
- const packageJsonPath = import_node_path4.default.join(packageDir, "package.json");
585
- const cargoTomlPath = import_node_path4.default.join(packageDir, "Cargo.toml");
586
- if (import_node_fs4.default.existsSync(packageJsonPath)) {
1343
+ const packageJsonPath = import_node_path5.default.join(packageDir, "package.json");
1344
+ const cargoTomlPath = import_node_path5.default.join(packageDir, "Cargo.toml");
1345
+ if (import_node_fs5.default.existsSync(packageJsonPath)) {
587
1346
  try {
588
- const packageJson = JSON.parse(import_node_fs4.default.readFileSync(packageJsonPath, "utf-8"));
1347
+ const packageJson = JSON.parse(import_node_fs5.default.readFileSync(packageJsonPath, "utf-8"));
589
1348
  if (packageJson.version) {
590
1349
  log(`Found version ${packageJson.version} in package.json`, "debug");
591
1350
  return {
@@ -601,7 +1360,7 @@ function getVersionFromManifests(packageDir) {
601
1360
  log(`Error reading package.json: ${errMsg}`, "warning");
602
1361
  }
603
1362
  }
604
- if (import_node_fs4.default.existsSync(cargoTomlPath)) {
1363
+ if (import_node_fs5.default.existsSync(cargoTomlPath)) {
605
1364
  try {
606
1365
  const cargoInfo = getCargoInfo(cargoTomlPath);
607
1366
  if (cargoInfo.version) {
@@ -627,15 +1386,15 @@ function getVersionFromManifests(packageDir) {
627
1386
  };
628
1387
  }
629
1388
  function throwIfNoManifestsFound(packageDir) {
630
- const packageJsonPath = import_node_path4.default.join(packageDir, "package.json");
631
- const cargoTomlPath = import_node_path4.default.join(packageDir, "Cargo.toml");
1389
+ const packageJsonPath = import_node_path5.default.join(packageDir, "package.json");
1390
+ const cargoTomlPath = import_node_path5.default.join(packageDir, "Cargo.toml");
632
1391
  throw new Error(
633
1392
  `Neither package.json nor Cargo.toml found at ${packageDir}. Checked paths: ${packageJsonPath}, ${cargoTomlPath}. Cannot determine version.`
634
1393
  );
635
1394
  }
636
1395
 
637
1396
  // src/utils/versionUtils.ts
638
- var import_node_fs5 = __toESM(require("fs"), 1);
1397
+ var import_node_fs6 = __toESM(require("fs"), 1);
639
1398
  var import_semver = __toESM(require("semver"), 1);
640
1399
  var TOML2 = __toESM(require("smol-toml"), 1);
641
1400
  var STANDARD_BUMP_TYPES = ["major", "minor", "patch"];
@@ -884,7 +1643,7 @@ var PackageProcessor = class {
884
1643
  * Process packages based on targeting criteria
885
1644
  */
886
1645
  async processPackages(packages) {
887
- var _a;
1646
+ var _a, _b, _c, _d, _e;
888
1647
  const tags = [];
889
1648
  const updatedPackagesInfo = [];
890
1649
  if (!packages || !Array.isArray(packages)) {
@@ -969,13 +1728,81 @@ var PackageProcessor = class {
969
1728
  if (!nextVersion) {
970
1729
  continue;
971
1730
  }
972
- const packageJsonPath = import_node_path5.default.join(pkgPath, "package.json");
973
- const cargoTomlPath = import_node_path5.default.join(pkgPath, "Cargo.toml");
974
- if (fs6.existsSync(packageJsonPath)) {
1731
+ if (this.fullConfig.updateChangelog !== false) {
1732
+ let changelogEntries = [];
1733
+ try {
1734
+ changelogEntries = extractChangelogEntriesFromCommits(pkgPath, latestTag);
1735
+ if (changelogEntries.length === 0) {
1736
+ changelogEntries = [
1737
+ {
1738
+ type: "changed",
1739
+ description: `Update version to ${nextVersion}`
1740
+ }
1741
+ ];
1742
+ }
1743
+ } catch (error) {
1744
+ log(
1745
+ `Error extracting changelog entries: ${error instanceof Error ? error.message : String(error)}`,
1746
+ "warning"
1747
+ );
1748
+ changelogEntries = [
1749
+ {
1750
+ type: "changed",
1751
+ description: `Update version to ${nextVersion}`
1752
+ }
1753
+ ];
1754
+ }
1755
+ let repoUrl;
1756
+ try {
1757
+ const packageJsonPath2 = import_node_path6.default.join(pkgPath, "package.json");
1758
+ if (fs8.existsSync(packageJsonPath2)) {
1759
+ const packageJson = JSON.parse(fs8.readFileSync(packageJsonPath2, "utf8"));
1760
+ if (packageJson.repository) {
1761
+ if (typeof packageJson.repository === "string") {
1762
+ repoUrl = packageJson.repository;
1763
+ } else if (packageJson.repository.url) {
1764
+ repoUrl = packageJson.repository.url;
1765
+ }
1766
+ if ((repoUrl == null ? void 0 : repoUrl.startsWith("git+")) && (repoUrl == null ? void 0 : repoUrl.endsWith(".git"))) {
1767
+ repoUrl = repoUrl.substring(4, repoUrl.length - 4);
1768
+ }
1769
+ }
1770
+ }
1771
+ } catch (error) {
1772
+ log(
1773
+ `Could not determine repository URL for changelog links: ${error instanceof Error ? error.message : String(error)}`,
1774
+ "warning"
1775
+ );
1776
+ }
1777
+ updateChangelog(
1778
+ pkgPath,
1779
+ name,
1780
+ nextVersion,
1781
+ changelogEntries,
1782
+ repoUrl,
1783
+ this.fullConfig.changelogFormat
1784
+ );
1785
+ }
1786
+ const packageJsonPath = import_node_path6.default.join(pkgPath, "package.json");
1787
+ if (fs8.existsSync(packageJsonPath)) {
975
1788
  updatePackageVersion(packageJsonPath, nextVersion);
976
1789
  }
977
- if (fs6.existsSync(cargoTomlPath)) {
978
- updatePackageVersion(cargoTomlPath, nextVersion);
1790
+ const cargoEnabled = ((_a = this.fullConfig.cargo) == null ? void 0 : _a.enabled) !== false;
1791
+ if (cargoEnabled) {
1792
+ const cargoPaths = (_b = this.fullConfig.cargo) == null ? void 0 : _b.paths;
1793
+ if (cargoPaths && cargoPaths.length > 0) {
1794
+ for (const cargoPath of cargoPaths) {
1795
+ const resolvedCargoPath = import_node_path6.default.resolve(pkgPath, cargoPath, "Cargo.toml");
1796
+ if (fs8.existsSync(resolvedCargoPath)) {
1797
+ updatePackageVersion(resolvedCargoPath, nextVersion);
1798
+ }
1799
+ }
1800
+ } else {
1801
+ const cargoTomlPath = import_node_path6.default.join(pkgPath, "Cargo.toml");
1802
+ if (fs8.existsSync(cargoTomlPath)) {
1803
+ updatePackageVersion(cargoTomlPath, nextVersion);
1804
+ }
1805
+ }
979
1806
  }
980
1807
  const packageTag = formatTag(
981
1808
  nextVersion,
@@ -1007,9 +1834,32 @@ var PackageProcessor = class {
1007
1834
  log("No targeted packages required a version update.", "info");
1008
1835
  return { updatedPackages: [], tags };
1009
1836
  }
1010
- const filesToCommit = updatedPackagesInfo.map((info) => import_node_path5.default.join(info.path, "package.json"));
1837
+ const filesToCommit = [];
1838
+ for (const info of updatedPackagesInfo) {
1839
+ const packageJsonPath = import_node_path6.default.join(info.path, "package.json");
1840
+ if (fs8.existsSync(packageJsonPath)) {
1841
+ filesToCommit.push(packageJsonPath);
1842
+ }
1843
+ const cargoEnabled = ((_c = this.fullConfig.cargo) == null ? void 0 : _c.enabled) !== false;
1844
+ if (cargoEnabled) {
1845
+ const cargoPaths = (_d = this.fullConfig.cargo) == null ? void 0 : _d.paths;
1846
+ if (cargoPaths && cargoPaths.length > 0) {
1847
+ for (const cargoPath of cargoPaths) {
1848
+ const resolvedCargoPath = import_node_path6.default.resolve(info.path, cargoPath, "Cargo.toml");
1849
+ if (fs8.existsSync(resolvedCargoPath)) {
1850
+ filesToCommit.push(resolvedCargoPath);
1851
+ }
1852
+ }
1853
+ } else {
1854
+ const cargoTomlPath = import_node_path6.default.join(info.path, "Cargo.toml");
1855
+ if (fs8.existsSync(cargoTomlPath)) {
1856
+ filesToCommit.push(cargoTomlPath);
1857
+ }
1858
+ }
1859
+ }
1860
+ }
1011
1861
  const packageNames = updatedPackagesInfo.map((p) => p.name).join(", ");
1012
- const representativeVersion = ((_a = updatedPackagesInfo[0]) == null ? void 0 : _a.version) || "multiple";
1862
+ const representativeVersion = ((_e = updatedPackagesInfo[0]) == null ? void 0 : _e.version) || "multiple";
1013
1863
  let commitMessage = this.commitMessageTemplate || "chore(release): publish packages";
1014
1864
  const placeholderRegex = /\$\{[^}]+\}/;
1015
1865
  if (updatedPackagesInfo.length === 1 && placeholderRegex.test(commitMessage)) {
@@ -1086,20 +1936,21 @@ function createSyncedStrategy(config) {
1086
1936
  const files = [];
1087
1937
  const updatedPackages = [];
1088
1938
  try {
1089
- const rootPkgPath = path5.join(packages.root, "package.json");
1090
- if (import_node_fs6.default.existsSync(rootPkgPath)) {
1939
+ const rootPkgPath = path7.join(packages.root, "package.json");
1940
+ if (import_node_fs7.default.existsSync(rootPkgPath)) {
1091
1941
  updatePackageVersion(rootPkgPath, nextVersion);
1092
1942
  files.push(rootPkgPath);
1093
1943
  updatedPackages.push("root");
1094
1944
  }
1095
- } catch (_error) {
1096
- log("Failed to update root package.json", "error");
1945
+ } catch (error) {
1946
+ const errMessage = error instanceof Error ? error.message : String(error);
1947
+ log(`Failed to update root package.json: ${errMessage}`, "error");
1097
1948
  }
1098
1949
  for (const pkg of packages.packages) {
1099
1950
  if (!shouldProcessPackage(pkg, config)) {
1100
1951
  continue;
1101
1952
  }
1102
- const packageJsonPath = path5.join(pkg.dir, "package.json");
1953
+ const packageJsonPath = path7.join(pkg.dir, "package.json");
1103
1954
  updatePackageVersion(packageJsonPath, nextVersion);
1104
1955
  files.push(packageJsonPath);
1105
1956
  updatedPackages.push(pkg.packageJson.name);
@@ -1172,7 +2023,7 @@ function createSingleStrategy(config) {
1172
2023
  log(`No version change needed for ${packageName}`, "info");
1173
2024
  return;
1174
2025
  }
1175
- const packageJsonPath = path5.join(pkgPath, "package.json");
2026
+ const packageJsonPath = path7.join(pkgPath, "package.json");
1176
2027
  updatePackageVersion(packageJsonPath, nextVersion);
1177
2028
  log(`Updated package ${packageName} to version ${nextVersion}`, "success");
1178
2029
  const nextTag = formatTag(
@@ -1351,11 +2202,11 @@ var VersionEngine = class {
1351
2202
  var import_meta = {};
1352
2203
  function getPackageVersion() {
1353
2204
  try {
1354
- const packageJsonPath = import_node_path6.default.resolve(
1355
- import_node_path6.default.dirname(import_meta.url.replace("file:", "")),
2205
+ const packageJsonPath = import_node_path7.default.resolve(
2206
+ import_node_path7.default.dirname(import_meta.url.replace("file:", "")),
1356
2207
  "../package.json"
1357
2208
  );
1358
- const packageJsonContent = fs8.readFileSync(packageJsonPath, "utf-8");
2209
+ const packageJsonContent = fs10.readFileSync(packageJsonPath, "utf-8");
1359
2210
  const packageJson = JSON.parse(packageJsonContent);
1360
2211
  return packageJson.version || "0.0.0";
1361
2212
  } catch (error) {
@@ -1364,53 +2215,94 @@ function getPackageVersion() {
1364
2215
  }
1365
2216
  }
1366
2217
  async function run() {
1367
- const buildTimestamp = (/* @__PURE__ */ new Date()).toISOString();
1368
- const packageVersion = getPackageVersion();
1369
- log(`package-versioner v${packageVersion} (Build: ${buildTimestamp})`, "debug");
1370
- const program = new import_commander.Command();
1371
- program.name("package-versioner").description(
1372
- "A lightweight yet powerful CLI tool for automated semantic versioning based on Git history and conventional commits."
1373
- ).version(packageVersion).option(
1374
- "-c, --config <path>",
1375
- "Path to config file (defaults to version.config.json in current directory)"
1376
- ).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);
1377
- const options = program.opts();
1378
- if (options.json) {
1379
- enableJsonOutput(options.dryRun);
1380
- }
1381
2218
  try {
1382
- const config = await loadConfig(options.config);
1383
- log(`Loaded configuration from ${options.config || "version.config.json"}`, "info");
1384
- if (options.dryRun) config.dryRun = true;
1385
- if (options.synced) config.synced = true;
1386
- if (options.bump) config.type = options.bump;
1387
- if (options.prerelease)
1388
- config.prereleaseIdentifier = options.prerelease === true ? "next" : options.prerelease;
1389
- const cliTargets = options.target ? options.target.split(",").map((t) => t.trim()) : [];
1390
- const engine = new VersionEngine(config, !!options.json);
1391
- if (config.synced) {
1392
- log("Using synced versioning strategy.", "info");
1393
- engine.setStrategy("synced");
1394
- await engine.run();
1395
- } else if (config.packages && config.packages.length === 1) {
1396
- log("Using single package versioning strategy.", "info");
1397
- if (cliTargets.length > 0) {
1398
- log("--target flag is ignored for single package strategy.", "warning");
1399
- }
1400
- engine.setStrategy("single");
1401
- await engine.run();
1402
- } else {
1403
- log("Using async versioning strategy.", "info");
1404
- if (cliTargets.length > 0) {
1405
- log(`Targeting specific packages: ${cliTargets.join(", ")}`, "info");
2219
+ const buildTimestamp = (/* @__PURE__ */ new Date()).toISOString();
2220
+ const packageVersion = getPackageVersion();
2221
+ log(`package-versioner v${packageVersion} (Build: ${buildTimestamp})`, "debug");
2222
+ const program = new import_commander.Command();
2223
+ program.name("package-versioner").description(
2224
+ "A lightweight yet powerful CLI tool for automated semantic versioning based on Git history and conventional commits."
2225
+ ).version(packageVersion);
2226
+ program.command("version", { isDefault: true }).description("Version a package or packages based on configuration").option(
2227
+ "-c, --config <path>",
2228
+ "Path to config file (defaults to version.config.json in current directory)"
2229
+ ).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) => {
2230
+ if (options.json) {
2231
+ enableJsonOutput(options.dryRun);
1406
2232
  }
1407
- engine.setStrategy("async");
1408
- await engine.run(cliTargets);
1409
- }
1410
- log("Versioning process completed.", "success");
1411
- printJsonOutput();
2233
+ try {
2234
+ const config = await loadConfig(options.config);
2235
+ log(`Loaded configuration from ${options.config || "version.config.json"}`, "info");
2236
+ if (options.dryRun) config.dryRun = true;
2237
+ if (options.synced) config.synced = true;
2238
+ if (options.bump) config.type = options.bump;
2239
+ if (options.prerelease)
2240
+ config.prereleaseIdentifier = options.prerelease === true ? "next" : options.prerelease;
2241
+ const cliTargets = options.target ? options.target.split(",").map((t) => t.trim()) : [];
2242
+ const engine = new VersionEngine(config, !!options.json);
2243
+ if (config.synced) {
2244
+ log("Using synced versioning strategy.", "info");
2245
+ engine.setStrategy("synced");
2246
+ await engine.run();
2247
+ } else if (config.packages && config.packages.length === 1) {
2248
+ log("Using single package versioning strategy.", "info");
2249
+ if (cliTargets.length > 0) {
2250
+ log("--target flag is ignored for single package strategy.", "warning");
2251
+ }
2252
+ engine.setStrategy("single");
2253
+ await engine.run();
2254
+ } else {
2255
+ log("Using async versioning strategy.", "info");
2256
+ if (cliTargets.length > 0) {
2257
+ log(`Targeting specific packages: ${cliTargets.join(", ")}`, "info");
2258
+ }
2259
+ engine.setStrategy("async");
2260
+ await engine.run(cliTargets);
2261
+ }
2262
+ log("Versioning process completed.", "success");
2263
+ printJsonOutput();
2264
+ } catch (error) {
2265
+ log(error instanceof Error ? error.message : String(error), "error");
2266
+ process.exit(1);
2267
+ }
2268
+ });
2269
+ program.command("regenerate-changelog").description("Regenerate a complete changelog from git history").option("-o, --output <path>", "Output path for changelog file", "CHANGELOG.md").option(
2270
+ "-f, --format <format>",
2271
+ "Changelog format (keep-a-changelog|angular)",
2272
+ "keep-a-changelog"
2273
+ ).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) => {
2274
+ try {
2275
+ log("Regenerating changelog from git history...", "info");
2276
+ if (options.format !== "keep-a-changelog" && options.format !== "angular") {
2277
+ throw new Error(
2278
+ 'Invalid format specified. Must be either "keep-a-changelog" or "angular"'
2279
+ );
2280
+ }
2281
+ const regenerateOptions = {
2282
+ format: options.format,
2283
+ since: options.since,
2284
+ output: options.output,
2285
+ dryRun: options.dryRun,
2286
+ projectDir: options.projectDir,
2287
+ repoUrl: options.repoUrl
2288
+ };
2289
+ const content = await regenerateChangelog(regenerateOptions);
2290
+ await writeChangelog(
2291
+ content,
2292
+ import_node_path7.default.resolve(options.projectDir, options.output),
2293
+ options.dryRun
2294
+ );
2295
+ if (!options.dryRun) {
2296
+ log(`Changelog successfully regenerated at ${options.output}`, "success");
2297
+ }
2298
+ } catch (error) {
2299
+ log(error instanceof Error ? error.message : String(error), "error");
2300
+ process.exit(1);
2301
+ }
2302
+ });
2303
+ program.parse(process.argv);
1412
2304
  } catch (error) {
1413
- log(error instanceof Error ? error.message : String(error), "error");
2305
+ console.error("Fatal error:", error);
1414
2306
  process.exit(1);
1415
2307
  }
1416
2308
  }