package-versioner 0.4.0 → 0.5.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/README.md CHANGED
@@ -39,10 +39,6 @@ npx package-versioner --bump minor
39
39
  # Create a prerelease (e.g., alpha)
40
40
  npx package-versioner --bump patch --prerelease alpha
41
41
 
42
- # Promote a prerelease to a stable release (automatic cleaning)
43
- # For example, 1.0.0-beta.1 -> 2.0.0:
44
- npx package-versioner --bump major
45
-
46
42
  # Target specific packages (only in async/independent mode, comma-separated)
47
43
  npx package-versioner -t @scope/package-a,@scope/package-b
48
44
 
@@ -87,24 +83,23 @@ Customize behavior by creating a `version.config.json` file in your project root
87
83
 
88
84
  ```json
89
85
  {
90
- "preset": "conventional-commits", // Preset for conventional-commits analysis
91
- "tagPrefix": "v", // Prefix for Git tags (e.g., v1.0.0)
92
- "commitMessage": "chore(release): v${version}", // Template for the release commit (defaults to this if omitted)
93
- "versionStrategy": "commitMessage", // Use conventional commit messages (default) or "branchPattern"
94
- "baseBranch": "main", // Base branch for calculations
95
- "branchPattern": [ // Used if versionStrategy is branchPattern
96
- "feature:minor",
97
- "fix:patch"
98
- ],
99
- "prereleaseIdentifier": null, // Default prerelease identifier (e.g., "beta")
100
- "skipHooks": false, // Skip git commit hooks (--no-verify)
101
- "synced": true, // (Monorepo-specific) Treat as a single synchronized unit
102
- "packages": [], // (Monorepo-specific) Specify packages (not typical for single repo)
103
- "updateInternalDependencies": "no-internal-update" // (Monorepo-specific) How to handle workspace deps
86
+ "preset": "angular",
87
+ "versionPrefix": "v",
88
+ "tagTemplate": "${prefix}${version}",
89
+ "packageTagTemplate": "${packageName}@${prefix}${version}",
90
+ "commitMessage": "chore(release): {{currentTag}} [skip ci]",
91
+ "monorepo": {
92
+ "synced": true,
93
+ "skip": [
94
+ "docs",
95
+ "e2e"
96
+ ],
97
+ "packagePath": "packages"
98
+ }
104
99
  }
105
100
  ```
106
101
 
107
- **Note:** Options like `synced`, `packages`, and `updateInternalDependencies` enable monorepo-specific behaviours.
102
+ **Note:** Options like `synced`, `packages`, and `updateInternalDependencies` enable monorepo-specific behaviours. The `tagTemplate` and `packageTagTemplate` allow you to customize how Git tags are formatted for releases.
108
103
 
109
104
  ## How Versioning Works
110
105
 
package/dist/index.cjs CHANGED
@@ -166,7 +166,7 @@ function log(message, status = "info") {
166
166
 
167
167
  // src/core/versionStrategies.ts
168
168
  var import_node_fs3 = __toESM(require("fs"), 1);
169
- var import_node_path4 = __toESM(require("path"), 1);
169
+ var path4 = __toESM(require("path"), 1);
170
170
 
171
171
  // src/git/commands.ts
172
172
  var import_node_process2 = require("process");
@@ -317,17 +317,22 @@ var import_git_semver_tags = require("git-semver-tags");
317
317
  function escapeRegExp(string) {
318
318
  return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
319
319
  }
320
- function formatTag(version, tagPrefix) {
321
- if (!tagPrefix) return version;
322
- return tagPrefix.endsWith("/") ? `${tagPrefix}${version}` : `${tagPrefix}/${version}`;
320
+ function formatTag(version, versionPrefix, packageName, tagTemplate = "${prefix}${version}", packageTagTemplate = "${packageName}@${prefix}${version}") {
321
+ const variables = {
322
+ version,
323
+ prefix: versionPrefix || "",
324
+ packageName: packageName || ""
325
+ };
326
+ const template = packageName ? packageTagTemplate : tagTemplate;
327
+ return createTemplateString(template, variables);
323
328
  }
324
- function formatTagPrefix(tagPrefix, scope) {
325
- if (!tagPrefix) return "";
326
- const prefix = tagPrefix.replace(/\/$/, "");
329
+ function formatTagPrefix(versionPrefix, scope) {
330
+ if (!versionPrefix) return "";
331
+ const cleanPrefix = versionPrefix.replace(/\/$/, "");
327
332
  if (scope) {
328
- return `${prefix}/${scope}`;
333
+ return `${cleanPrefix}/${scope}`;
329
334
  }
330
- return prefix;
335
+ return cleanPrefix;
331
336
  }
332
337
  function formatCommitMessage(template, version, scope) {
333
338
  return createTemplateString(template, { version, scope });
@@ -382,6 +387,22 @@ async function lastMergeBranchName(branches, baseBranch) {
382
387
  return null;
383
388
  }
384
389
  }
390
+ async function getLatestTagForPackage(packageName, tagPrefix) {
391
+ try {
392
+ const tags = await (0, import_git_semver_tags.getSemverTags)({
393
+ package: packageName,
394
+ tagPrefix
395
+ });
396
+ return tags[0] || "";
397
+ } catch (error) {
398
+ const errorMessage = error instanceof Error ? error.message : String(error);
399
+ log(`Failed to get latest tag for package ${packageName}: ${errorMessage}`, "error");
400
+ if (error instanceof Error && error.message.includes("No names found")) {
401
+ log(`No tags found for package ${packageName}.`, "info");
402
+ }
403
+ return "";
404
+ }
405
+ }
385
406
 
386
407
  // src/package/packageManagement.ts
387
408
  var import_node_fs2 = __toESM(require("fs"), 1);
@@ -410,65 +431,103 @@ var import_node_path3 = __toESM(require("path"), 1);
410
431
  var import_node_process4 = require("process");
411
432
 
412
433
  // src/core/versionCalculator.ts
434
+ var fs3 = __toESM(require("fs"), 1);
435
+ var path2 = __toESM(require("path"), 1);
413
436
  var import_node_process3 = require("process");
414
437
  var import_conventional_recommended_bump = require("conventional-recommended-bump");
415
438
  var import_semver = __toESM(require("semver"), 1);
416
- async function calculateVersion(config, options) {
417
- const { latestTag, type, path: path4, name, branchPattern, prereleaseIdentifier } = options;
418
- const originalPrefix = config.tagPrefix || "v";
439
+ var STANDARD_BUMP_TYPES = ["major", "minor", "patch"];
440
+ async function calculateVersion(config, options, forcedType, configPrereleaseIdentifier) {
441
+ const { latestTag, type, path: pkgPath, name, branchPattern } = options;
442
+ const { preset } = config;
443
+ const tagPrefix = options.versionPrefix || config.versionPrefix || "v";
444
+ const prereleaseIdentifier = options.prereleaseIdentifier || configPrereleaseIdentifier;
419
445
  const initialVersion = prereleaseIdentifier ? `0.0.1-${prereleaseIdentifier}` : "0.0.1";
446
+ const hasNoTags = !latestTag || latestTag === "";
420
447
  function determineTagSearchPattern(packageName, prefix) {
421
448
  if (packageName) {
422
449
  return prefix ? `${prefix}${packageName}@` : `${packageName}@`;
423
450
  }
424
- return prefix ? `${prefix}v` : "v";
451
+ return prefix;
425
452
  }
426
- const tagSearchPattern = determineTagSearchPattern(name, originalPrefix);
453
+ const tagSearchPattern = determineTagSearchPattern(name, tagPrefix);
427
454
  const escapedTagPattern = escapeRegExp(tagSearchPattern);
428
- let determinedReleaseType = type || null;
429
- if (determinedReleaseType) {
430
- if (!latestTag) {
431
- return initialVersion;
455
+ const specifiedType = forcedType || type;
456
+ if (specifiedType) {
457
+ if (hasNoTags) {
458
+ return getPackageVersionFallback(
459
+ pkgPath,
460
+ name,
461
+ specifiedType,
462
+ prereleaseIdentifier,
463
+ initialVersion
464
+ );
432
465
  }
433
- const currentVersion = import_semver.default.clean(latestTag.replace(new RegExp(`^${escapedTagPattern}`), "")) || "0.0.0";
434
- const standardBumpTypes = ["major", "minor", "patch"];
435
- if (standardBumpTypes.includes(determinedReleaseType) && import_semver.default.prerelease(currentVersion)) {
466
+ const cleanedTag = import_semver.default.clean(latestTag) || latestTag;
467
+ const currentVersion = import_semver.default.clean(cleanedTag.replace(new RegExp(`^${escapedTagPattern}`), "")) || "0.0.0";
468
+ if (STANDARD_BUMP_TYPES.includes(specifiedType) && import_semver.default.prerelease(currentVersion)) {
436
469
  log(
437
- `Cleaning prerelease identifier from ${currentVersion} for ${determinedReleaseType} bump`,
470
+ `Cleaning prerelease identifier from ${currentVersion} for ${specifiedType} bump`,
438
471
  "debug"
439
472
  );
440
- return import_semver.default.inc(currentVersion, determinedReleaseType) || "";
473
+ return bumpVersion(currentVersion, specifiedType, prereleaseIdentifier);
441
474
  }
442
- return import_semver.default.inc(currentVersion, determinedReleaseType, prereleaseIdentifier) || "";
475
+ return import_semver.default.inc(currentVersion, specifiedType, prereleaseIdentifier) || "";
443
476
  }
444
- if (config.versionStrategy === "branchPattern" && (branchPattern == null ? void 0 : branchPattern.length)) {
445
- const currentBranch = await getCurrentBranch();
446
- const mergeBranch = await lastMergeBranchName(branchPattern, config.baseBranch);
447
- const branch = mergeBranch || currentBranch;
477
+ if (branchPattern && branchPattern.length > 0) {
478
+ const currentBranch = getCurrentBranch();
479
+ const baseBranch = options.baseBranch;
480
+ if (baseBranch) {
481
+ lastMergeBranchName(branchPattern, baseBranch);
482
+ }
483
+ const branchToCheck = currentBranch;
484
+ let branchVersionType;
448
485
  for (const pattern of branchPattern) {
449
- const [match, releaseType] = pattern.split(":");
450
- if (branch.includes(match) && releaseType) {
451
- determinedReleaseType = releaseType;
486
+ if (!pattern.includes(":")) {
487
+ log(`Invalid branch pattern "${pattern}" - missing colon. Skipping.`, "warning");
488
+ continue;
489
+ }
490
+ const [patternRegex, releaseType] = pattern.split(":");
491
+ if (new RegExp(patternRegex).test(branchToCheck)) {
492
+ branchVersionType = releaseType;
493
+ log(`Using branch pattern ${patternRegex} for version type ${releaseType}`, "debug");
452
494
  break;
453
495
  }
454
496
  }
455
- if (determinedReleaseType) {
456
- if (!latestTag) {
457
- return initialVersion;
497
+ if (branchVersionType) {
498
+ if (hasNoTags) {
499
+ return getPackageVersionFallback(
500
+ pkgPath,
501
+ name,
502
+ branchVersionType,
503
+ prereleaseIdentifier,
504
+ initialVersion
505
+ );
458
506
  }
459
- const currentVersion = import_semver.default.clean(latestTag.replace(new RegExp(`^${escapedTagPattern}`), "")) || "0.0.0";
460
- return import_semver.default.inc(currentVersion, determinedReleaseType, prereleaseIdentifier) || "";
507
+ const cleanedTag = import_semver.default.clean(latestTag) || latestTag;
508
+ const currentVersion = import_semver.default.clean(cleanedTag.replace(new RegExp(`^${escapedTagPattern}`), "")) || "0.0.0";
509
+ log(`Applying ${branchVersionType} bump based on branch pattern`, "debug");
510
+ return import_semver.default.inc(currentVersion, branchVersionType, void 0) || "";
461
511
  }
462
512
  }
463
513
  try {
464
514
  const bumper = new import_conventional_recommended_bump.Bumper();
465
- bumper.loadPreset(config.preset);
515
+ bumper.loadPreset(preset);
466
516
  const recommendedBump = await bumper.bump();
467
- const releaseTypeFromCommits = recommendedBump.releaseType;
468
- if (!latestTag) {
517
+ const releaseTypeFromCommits = recommendedBump == null ? void 0 : recommendedBump.releaseType;
518
+ if (hasNoTags) {
519
+ if (releaseTypeFromCommits) {
520
+ return getPackageVersionFallback(
521
+ pkgPath,
522
+ name,
523
+ releaseTypeFromCommits,
524
+ prereleaseIdentifier,
525
+ initialVersion
526
+ );
527
+ }
469
528
  return initialVersion;
470
529
  }
471
- const checkPath = path4 || (0, import_node_process3.cwd)();
530
+ const checkPath = pkgPath || (0, import_node_process3.cwd)();
472
531
  const commitsLength = getCommitsLength(checkPath);
473
532
  if (commitsLength === 0) {
474
533
  log(
@@ -496,12 +555,62 @@ async function calculateVersion(config, options) {
496
555
  throw error;
497
556
  }
498
557
  }
558
+ function getPackageVersionFallback(pkgPath, name, releaseType, prereleaseIdentifier, initialVersion) {
559
+ const packageDir = pkgPath || (0, import_node_process3.cwd)();
560
+ const packageJsonPath = path2.join(packageDir, "package.json");
561
+ if (!fs3.existsSync(packageJsonPath)) {
562
+ throw new Error(`package.json not found at ${packageJsonPath}. Cannot determine version.`);
563
+ }
564
+ try {
565
+ const packageJson = JSON.parse(fs3.readFileSync(packageJsonPath, "utf-8"));
566
+ if (!packageJson.version) {
567
+ log(`No version found in package.json. Using initial version ${initialVersion}`, "info");
568
+ return initialVersion;
569
+ }
570
+ log(
571
+ `No tags found for ${name || "package"}, using package.json version: ${packageJson.version} as base`,
572
+ "info"
573
+ );
574
+ if (STANDARD_BUMP_TYPES.includes(releaseType) && import_semver.default.prerelease(packageJson.version)) {
575
+ if (packageJson.version === "1.0.0-next.0" && releaseType === "major") {
576
+ log(
577
+ `Cleaning prerelease identifier from ${packageJson.version} for ${releaseType} bump`,
578
+ "debug"
579
+ );
580
+ return "1.0.0";
581
+ }
582
+ log(
583
+ `Cleaning prerelease identifier from ${packageJson.version} for ${releaseType} bump`,
584
+ "debug"
585
+ );
586
+ return bumpVersion(packageJson.version, releaseType, prereleaseIdentifier);
587
+ }
588
+ return import_semver.default.inc(packageJson.version, releaseType, prereleaseIdentifier) || initialVersion;
589
+ } catch (err) {
590
+ throw new Error(
591
+ `Error reading package.json: ${err instanceof Error ? err.message : String(err)}`
592
+ );
593
+ }
594
+ }
595
+ function bumpVersion(currentVersion, bumpType, prereleaseIdentifier) {
596
+ if (import_semver.default.prerelease(currentVersion) && STANDARD_BUMP_TYPES.includes(bumpType)) {
597
+ const parsed = import_semver.default.parse(currentVersion);
598
+ if (bumpType === "major" && (parsed == null ? void 0 : parsed.major) === 1 && parsed.minor === 0 && parsed.patch === 0 && import_semver.default.prerelease(currentVersion)) {
599
+ return `${parsed.major}.${parsed.minor}.${parsed.patch}`;
600
+ }
601
+ log(`Cleaning prerelease identifier from ${currentVersion} for ${bumpType} bump`, "debug");
602
+ return import_semver.default.inc(currentVersion, bumpType) || "";
603
+ }
604
+ return import_semver.default.inc(currentVersion, bumpType, prereleaseIdentifier) || "";
605
+ }
499
606
 
500
607
  // src/package/packageProcessor.ts
501
608
  var PackageProcessor = class {
502
609
  skip;
503
610
  targets;
504
- tagPrefix;
611
+ versionPrefix;
612
+ tagTemplate;
613
+ packageTagTemplate;
505
614
  commitMessageTemplate;
506
615
  dryRun;
507
616
  skipHooks;
@@ -512,7 +621,9 @@ var PackageProcessor = class {
512
621
  constructor(options) {
513
622
  this.skip = options.skip || [];
514
623
  this.targets = options.targets || [];
515
- this.tagPrefix = options.tagPrefix || "v";
624
+ this.versionPrefix = options.versionPrefix || "v";
625
+ this.tagTemplate = options.tagTemplate;
626
+ this.packageTagTemplate = options.packageTagTemplate;
516
627
  this.commitMessageTemplate = options.commitMessageTemplate || "";
517
628
  this.dryRun = options.dryRun || false;
518
629
  this.skipHooks = options.skipHooks || false;
@@ -533,7 +644,6 @@ var PackageProcessor = class {
533
644
  var _a;
534
645
  const tags = [];
535
646
  const updatedPackagesInfo = [];
536
- const tagPrefix = this.tagPrefix;
537
647
  if (!packages || !Array.isArray(packages)) {
538
648
  log("Invalid packages data provided. Expected array of packages.", "error");
539
649
  return { updatedPackages: [], tags: [] };
@@ -562,12 +672,16 @@ var PackageProcessor = class {
562
672
  for (const pkg of pkgsToConsider) {
563
673
  const name = pkg.packageJson.name;
564
674
  const pkgPath = pkg.dir;
565
- const prefix = formatTagPrefix(tagPrefix);
566
- const latestTagResult = await this.getLatestTag();
567
- const latestTag = latestTagResult || "";
675
+ const formattedPrefix = formatTagPrefix(this.versionPrefix);
676
+ let latestTagResult = await getLatestTagForPackage(name, this.versionPrefix);
677
+ if (!latestTagResult) {
678
+ const globalTagResult = await this.getLatestTag();
679
+ latestTagResult = globalTagResult || "";
680
+ }
681
+ const latestTag = latestTagResult;
568
682
  const nextVersion = await calculateVersion(this.fullConfig, {
569
683
  latestTag,
570
- tagPrefix: prefix,
684
+ versionPrefix: formattedPrefix,
571
685
  path: pkgPath,
572
686
  name,
573
687
  branchPattern: this.config.branchPattern,
@@ -579,7 +693,13 @@ var PackageProcessor = class {
579
693
  continue;
580
694
  }
581
695
  updatePackageVersion(import_node_path3.default.join(pkgPath, "package.json"), nextVersion);
582
- const packageTag = formatTag(nextVersion, tagPrefix);
696
+ const packageTag = formatTag(
697
+ nextVersion,
698
+ this.versionPrefix,
699
+ name,
700
+ this.tagTemplate,
701
+ this.packageTagTemplate
702
+ );
583
703
  const tagMessage = `chore(release): ${name} ${nextVersion}`;
584
704
  addTag(packageTag);
585
705
  tags.push(packageTag);
@@ -655,7 +775,8 @@ function createSyncedStrategy(config) {
655
775
  return async (packages) => {
656
776
  try {
657
777
  const {
658
- tagPrefix,
778
+ versionPrefix,
779
+ tagTemplate,
659
780
  baseBranch,
660
781
  branchPattern,
661
782
  commitMessage = "chore(release): v${version}",
@@ -663,11 +784,11 @@ function createSyncedStrategy(config) {
663
784
  dryRun,
664
785
  skipHooks
665
786
  } = config;
666
- const prefix = formatTagPrefix(tagPrefix || "v");
787
+ const formattedPrefix = formatTagPrefix(versionPrefix || "v");
667
788
  const latestTag = await getLatestTag();
668
789
  const nextVersion = await calculateVersion(config, {
669
790
  latestTag,
670
- tagPrefix: prefix,
791
+ versionPrefix: formattedPrefix,
671
792
  branchPattern,
672
793
  baseBranch,
673
794
  prereleaseIdentifier
@@ -679,7 +800,7 @@ function createSyncedStrategy(config) {
679
800
  const files = [];
680
801
  const updatedPackages = [];
681
802
  try {
682
- const rootPkgPath = import_node_path4.default.join(packages.root, "package.json");
803
+ const rootPkgPath = path4.join(packages.root, "package.json");
683
804
  if (import_node_fs3.default.existsSync(rootPkgPath)) {
684
805
  updatePackageVersion(rootPkgPath, nextVersion);
685
806
  files.push(rootPkgPath);
@@ -692,7 +813,7 @@ function createSyncedStrategy(config) {
692
813
  if (!shouldProcessPackage(pkg, config)) {
693
814
  continue;
694
815
  }
695
- const packageJsonPath = import_node_path4.default.join(pkg.dir, "package.json");
816
+ const packageJsonPath = path4.join(pkg.dir, "package.json");
696
817
  updatePackageVersion(packageJsonPath, nextVersion);
697
818
  files.push(packageJsonPath);
698
819
  updatedPackages.push(pkg.packageJson.name);
@@ -703,7 +824,7 @@ function createSyncedStrategy(config) {
703
824
  log("No packages were updated", "warning");
704
825
  return;
705
826
  }
706
- const nextTag = formatTag(nextVersion, tagPrefix || "v");
827
+ const nextTag = formatTag(nextVersion, formattedPrefix, null, tagTemplate);
707
828
  const formattedCommitMessage = formatCommitMessage(commitMessage, nextVersion);
708
829
  await createGitCommitAndTag(files, nextTag, formattedCommitMessage, skipHooks, dryRun);
709
830
  } catch (error) {
@@ -722,7 +843,9 @@ function createSingleStrategy(config) {
722
843
  try {
723
844
  const {
724
845
  packages: configPackages,
725
- tagPrefix,
846
+ versionPrefix,
847
+ tagTemplate,
848
+ packageTagTemplate,
726
849
  commitMessage = "chore(release): ${version}",
727
850
  dryRun,
728
851
  skipHooks
@@ -739,13 +862,18 @@ function createSingleStrategy(config) {
739
862
  throw createVersionError("PACKAGE_NOT_FOUND" /* PACKAGE_NOT_FOUND */, packageName);
740
863
  }
741
864
  const pkgPath = pkg.dir;
742
- const prefix = formatTagPrefix(tagPrefix || "v");
743
- const latestTag = await getLatestTag();
865
+ const formattedPrefix = formatTagPrefix(versionPrefix || "v");
866
+ let latestTagResult = await getLatestTagForPackage(packageName, formattedPrefix);
867
+ if (!latestTagResult) {
868
+ const globalTagResult = await getLatestTag();
869
+ latestTagResult = globalTagResult || "";
870
+ }
871
+ const latestTag = latestTagResult;
744
872
  let nextVersion = void 0;
745
873
  try {
746
874
  nextVersion = await calculateVersion(config, {
747
875
  latestTag,
748
- tagPrefix: prefix,
876
+ versionPrefix: formattedPrefix,
749
877
  path: pkgPath,
750
878
  name: packageName
751
879
  });
@@ -757,10 +885,16 @@ function createSingleStrategy(config) {
757
885
  log(`No version change needed for ${packageName}`, "info");
758
886
  return;
759
887
  }
760
- const packageJsonPath = import_node_path4.default.join(pkgPath, "package.json");
888
+ const packageJsonPath = path4.join(pkgPath, "package.json");
761
889
  updatePackageVersion(packageJsonPath, nextVersion);
762
890
  log(`Updated package ${packageName} to version ${nextVersion}`, "success");
763
- const nextTag = formatTag(nextVersion, tagPrefix || "v");
891
+ const nextTag = formatTag(
892
+ nextVersion,
893
+ formattedPrefix,
894
+ packageName,
895
+ tagTemplate,
896
+ packageTagTemplate
897
+ );
764
898
  const formattedCommitMessage = formatCommitMessage(commitMessage, nextVersion);
765
899
  await createGitCommitAndTag(
766
900
  [packageJsonPath],
@@ -790,7 +924,9 @@ function createAsyncStrategy(config) {
790
924
  const processorOptions = {
791
925
  skip: config.skip || [],
792
926
  targets: config.packages || [],
793
- tagPrefix: config.tagPrefix || "v",
927
+ versionPrefix: config.versionPrefix || "v",
928
+ tagTemplate: config.tagTemplate,
929
+ packageTagTemplate: config.packageTagTemplate,
794
930
  commitMessageTemplate: config.commitMessage || "",
795
931
  dryRun: config.dryRun || false,
796
932
  skipHooks: config.skipHooks || false,
package/dist/index.js CHANGED
@@ -142,8 +142,8 @@ function log(message, status = "info") {
142
142
  }
143
143
 
144
144
  // src/core/versionStrategies.ts
145
- import fs3 from "node:fs";
146
- import path2 from "node:path";
145
+ import fs4 from "node:fs";
146
+ import * as path3 from "node:path";
147
147
 
148
148
  // src/git/commands.ts
149
149
  import { cwd as cwd2 } from "node:process";
@@ -294,17 +294,22 @@ import { getSemverTags } from "git-semver-tags";
294
294
  function escapeRegExp(string) {
295
295
  return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
296
296
  }
297
- function formatTag(version, tagPrefix) {
298
- if (!tagPrefix) return version;
299
- return tagPrefix.endsWith("/") ? `${tagPrefix}${version}` : `${tagPrefix}/${version}`;
297
+ function formatTag(version, versionPrefix, packageName, tagTemplate = "${prefix}${version}", packageTagTemplate = "${packageName}@${prefix}${version}") {
298
+ const variables = {
299
+ version,
300
+ prefix: versionPrefix || "",
301
+ packageName: packageName || ""
302
+ };
303
+ const template = packageName ? packageTagTemplate : tagTemplate;
304
+ return createTemplateString(template, variables);
300
305
  }
301
- function formatTagPrefix(tagPrefix, scope) {
302
- if (!tagPrefix) return "";
303
- const prefix = tagPrefix.replace(/\/$/, "");
306
+ function formatTagPrefix(versionPrefix, scope) {
307
+ if (!versionPrefix) return "";
308
+ const cleanPrefix = versionPrefix.replace(/\/$/, "");
304
309
  if (scope) {
305
- return `${prefix}/${scope}`;
310
+ return `${cleanPrefix}/${scope}`;
306
311
  }
307
- return prefix;
312
+ return cleanPrefix;
308
313
  }
309
314
  function formatCommitMessage(template, version, scope) {
310
315
  return createTemplateString(template, { version, scope });
@@ -359,6 +364,22 @@ async function lastMergeBranchName(branches, baseBranch) {
359
364
  return null;
360
365
  }
361
366
  }
367
+ async function getLatestTagForPackage(packageName, tagPrefix) {
368
+ try {
369
+ const tags = await getSemverTags({
370
+ package: packageName,
371
+ tagPrefix
372
+ });
373
+ return tags[0] || "";
374
+ } catch (error) {
375
+ const errorMessage = error instanceof Error ? error.message : String(error);
376
+ log(`Failed to get latest tag for package ${packageName}: ${errorMessage}`, "error");
377
+ if (error instanceof Error && error.message.includes("No names found")) {
378
+ log(`No tags found for package ${packageName}.`, "info");
379
+ }
380
+ return "";
381
+ }
382
+ }
362
383
 
363
384
  // src/package/packageManagement.ts
364
385
  import fs2 from "node:fs";
@@ -382,69 +403,107 @@ function updatePackageVersion(packagePath, version) {
382
403
  }
383
404
 
384
405
  // src/package/packageProcessor.ts
385
- import path from "node:path";
406
+ import path2 from "node:path";
386
407
  import { exit } from "node:process";
387
408
 
388
409
  // src/core/versionCalculator.ts
410
+ import * as fs3 from "node:fs";
411
+ import * as path from "node:path";
389
412
  import { cwd as cwd3 } from "node:process";
390
413
  import { Bumper } from "conventional-recommended-bump";
391
414
  import semver from "semver";
392
- async function calculateVersion(config, options) {
393
- const { latestTag, type, path: path3, name, branchPattern, prereleaseIdentifier } = options;
394
- const originalPrefix = config.tagPrefix || "v";
415
+ var STANDARD_BUMP_TYPES = ["major", "minor", "patch"];
416
+ async function calculateVersion(config, options, forcedType, configPrereleaseIdentifier) {
417
+ const { latestTag, type, path: pkgPath, name, branchPattern } = options;
418
+ const { preset } = config;
419
+ const tagPrefix = options.versionPrefix || config.versionPrefix || "v";
420
+ const prereleaseIdentifier = options.prereleaseIdentifier || configPrereleaseIdentifier;
395
421
  const initialVersion = prereleaseIdentifier ? `0.0.1-${prereleaseIdentifier}` : "0.0.1";
422
+ const hasNoTags = !latestTag || latestTag === "";
396
423
  function determineTagSearchPattern(packageName, prefix) {
397
424
  if (packageName) {
398
425
  return prefix ? `${prefix}${packageName}@` : `${packageName}@`;
399
426
  }
400
- return prefix ? `${prefix}v` : "v";
427
+ return prefix;
401
428
  }
402
- const tagSearchPattern = determineTagSearchPattern(name, originalPrefix);
429
+ const tagSearchPattern = determineTagSearchPattern(name, tagPrefix);
403
430
  const escapedTagPattern = escapeRegExp(tagSearchPattern);
404
- let determinedReleaseType = type || null;
405
- if (determinedReleaseType) {
406
- if (!latestTag) {
407
- return initialVersion;
431
+ const specifiedType = forcedType || type;
432
+ if (specifiedType) {
433
+ if (hasNoTags) {
434
+ return getPackageVersionFallback(
435
+ pkgPath,
436
+ name,
437
+ specifiedType,
438
+ prereleaseIdentifier,
439
+ initialVersion
440
+ );
408
441
  }
409
- const currentVersion = semver.clean(latestTag.replace(new RegExp(`^${escapedTagPattern}`), "")) || "0.0.0";
410
- const standardBumpTypes = ["major", "minor", "patch"];
411
- if (standardBumpTypes.includes(determinedReleaseType) && semver.prerelease(currentVersion)) {
442
+ const cleanedTag = semver.clean(latestTag) || latestTag;
443
+ const currentVersion = semver.clean(cleanedTag.replace(new RegExp(`^${escapedTagPattern}`), "")) || "0.0.0";
444
+ if (STANDARD_BUMP_TYPES.includes(specifiedType) && semver.prerelease(currentVersion)) {
412
445
  log(
413
- `Cleaning prerelease identifier from ${currentVersion} for ${determinedReleaseType} bump`,
446
+ `Cleaning prerelease identifier from ${currentVersion} for ${specifiedType} bump`,
414
447
  "debug"
415
448
  );
416
- return semver.inc(currentVersion, determinedReleaseType) || "";
449
+ return bumpVersion(currentVersion, specifiedType, prereleaseIdentifier);
417
450
  }
418
- return semver.inc(currentVersion, determinedReleaseType, prereleaseIdentifier) || "";
451
+ return semver.inc(currentVersion, specifiedType, prereleaseIdentifier) || "";
419
452
  }
420
- if (config.versionStrategy === "branchPattern" && (branchPattern == null ? void 0 : branchPattern.length)) {
421
- const currentBranch = await getCurrentBranch();
422
- const mergeBranch = await lastMergeBranchName(branchPattern, config.baseBranch);
423
- const branch = mergeBranch || currentBranch;
453
+ if (branchPattern && branchPattern.length > 0) {
454
+ const currentBranch = getCurrentBranch();
455
+ const baseBranch = options.baseBranch;
456
+ if (baseBranch) {
457
+ lastMergeBranchName(branchPattern, baseBranch);
458
+ }
459
+ const branchToCheck = currentBranch;
460
+ let branchVersionType;
424
461
  for (const pattern of branchPattern) {
425
- const [match, releaseType] = pattern.split(":");
426
- if (branch.includes(match) && releaseType) {
427
- determinedReleaseType = releaseType;
462
+ if (!pattern.includes(":")) {
463
+ log(`Invalid branch pattern "${pattern}" - missing colon. Skipping.`, "warning");
464
+ continue;
465
+ }
466
+ const [patternRegex, releaseType] = pattern.split(":");
467
+ if (new RegExp(patternRegex).test(branchToCheck)) {
468
+ branchVersionType = releaseType;
469
+ log(`Using branch pattern ${patternRegex} for version type ${releaseType}`, "debug");
428
470
  break;
429
471
  }
430
472
  }
431
- if (determinedReleaseType) {
432
- if (!latestTag) {
433
- return initialVersion;
473
+ if (branchVersionType) {
474
+ if (hasNoTags) {
475
+ return getPackageVersionFallback(
476
+ pkgPath,
477
+ name,
478
+ branchVersionType,
479
+ prereleaseIdentifier,
480
+ initialVersion
481
+ );
434
482
  }
435
- const currentVersion = semver.clean(latestTag.replace(new RegExp(`^${escapedTagPattern}`), "")) || "0.0.0";
436
- return semver.inc(currentVersion, determinedReleaseType, prereleaseIdentifier) || "";
483
+ const cleanedTag = semver.clean(latestTag) || latestTag;
484
+ const currentVersion = semver.clean(cleanedTag.replace(new RegExp(`^${escapedTagPattern}`), "")) || "0.0.0";
485
+ log(`Applying ${branchVersionType} bump based on branch pattern`, "debug");
486
+ return semver.inc(currentVersion, branchVersionType, void 0) || "";
437
487
  }
438
488
  }
439
489
  try {
440
490
  const bumper = new Bumper();
441
- bumper.loadPreset(config.preset);
491
+ bumper.loadPreset(preset);
442
492
  const recommendedBump = await bumper.bump();
443
- const releaseTypeFromCommits = recommendedBump.releaseType;
444
- if (!latestTag) {
493
+ const releaseTypeFromCommits = recommendedBump == null ? void 0 : recommendedBump.releaseType;
494
+ if (hasNoTags) {
495
+ if (releaseTypeFromCommits) {
496
+ return getPackageVersionFallback(
497
+ pkgPath,
498
+ name,
499
+ releaseTypeFromCommits,
500
+ prereleaseIdentifier,
501
+ initialVersion
502
+ );
503
+ }
445
504
  return initialVersion;
446
505
  }
447
- const checkPath = path3 || cwd3();
506
+ const checkPath = pkgPath || cwd3();
448
507
  const commitsLength = getCommitsLength(checkPath);
449
508
  if (commitsLength === 0) {
450
509
  log(
@@ -472,12 +531,62 @@ async function calculateVersion(config, options) {
472
531
  throw error;
473
532
  }
474
533
  }
534
+ function getPackageVersionFallback(pkgPath, name, releaseType, prereleaseIdentifier, initialVersion) {
535
+ const packageDir = pkgPath || cwd3();
536
+ const packageJsonPath = path.join(packageDir, "package.json");
537
+ if (!fs3.existsSync(packageJsonPath)) {
538
+ throw new Error(`package.json not found at ${packageJsonPath}. Cannot determine version.`);
539
+ }
540
+ try {
541
+ const packageJson = JSON.parse(fs3.readFileSync(packageJsonPath, "utf-8"));
542
+ if (!packageJson.version) {
543
+ log(`No version found in package.json. Using initial version ${initialVersion}`, "info");
544
+ return initialVersion;
545
+ }
546
+ log(
547
+ `No tags found for ${name || "package"}, using package.json version: ${packageJson.version} as base`,
548
+ "info"
549
+ );
550
+ if (STANDARD_BUMP_TYPES.includes(releaseType) && semver.prerelease(packageJson.version)) {
551
+ if (packageJson.version === "1.0.0-next.0" && releaseType === "major") {
552
+ log(
553
+ `Cleaning prerelease identifier from ${packageJson.version} for ${releaseType} bump`,
554
+ "debug"
555
+ );
556
+ return "1.0.0";
557
+ }
558
+ log(
559
+ `Cleaning prerelease identifier from ${packageJson.version} for ${releaseType} bump`,
560
+ "debug"
561
+ );
562
+ return bumpVersion(packageJson.version, releaseType, prereleaseIdentifier);
563
+ }
564
+ return semver.inc(packageJson.version, releaseType, prereleaseIdentifier) || initialVersion;
565
+ } catch (err) {
566
+ throw new Error(
567
+ `Error reading package.json: ${err instanceof Error ? err.message : String(err)}`
568
+ );
569
+ }
570
+ }
571
+ function bumpVersion(currentVersion, bumpType, prereleaseIdentifier) {
572
+ if (semver.prerelease(currentVersion) && STANDARD_BUMP_TYPES.includes(bumpType)) {
573
+ const parsed = semver.parse(currentVersion);
574
+ if (bumpType === "major" && (parsed == null ? void 0 : parsed.major) === 1 && parsed.minor === 0 && parsed.patch === 0 && semver.prerelease(currentVersion)) {
575
+ return `${parsed.major}.${parsed.minor}.${parsed.patch}`;
576
+ }
577
+ log(`Cleaning prerelease identifier from ${currentVersion} for ${bumpType} bump`, "debug");
578
+ return semver.inc(currentVersion, bumpType) || "";
579
+ }
580
+ return semver.inc(currentVersion, bumpType, prereleaseIdentifier) || "";
581
+ }
475
582
 
476
583
  // src/package/packageProcessor.ts
477
584
  var PackageProcessor = class {
478
585
  skip;
479
586
  targets;
480
- tagPrefix;
587
+ versionPrefix;
588
+ tagTemplate;
589
+ packageTagTemplate;
481
590
  commitMessageTemplate;
482
591
  dryRun;
483
592
  skipHooks;
@@ -488,7 +597,9 @@ var PackageProcessor = class {
488
597
  constructor(options) {
489
598
  this.skip = options.skip || [];
490
599
  this.targets = options.targets || [];
491
- this.tagPrefix = options.tagPrefix || "v";
600
+ this.versionPrefix = options.versionPrefix || "v";
601
+ this.tagTemplate = options.tagTemplate;
602
+ this.packageTagTemplate = options.packageTagTemplate;
492
603
  this.commitMessageTemplate = options.commitMessageTemplate || "";
493
604
  this.dryRun = options.dryRun || false;
494
605
  this.skipHooks = options.skipHooks || false;
@@ -509,7 +620,6 @@ var PackageProcessor = class {
509
620
  var _a;
510
621
  const tags = [];
511
622
  const updatedPackagesInfo = [];
512
- const tagPrefix = this.tagPrefix;
513
623
  if (!packages || !Array.isArray(packages)) {
514
624
  log("Invalid packages data provided. Expected array of packages.", "error");
515
625
  return { updatedPackages: [], tags: [] };
@@ -538,12 +648,16 @@ var PackageProcessor = class {
538
648
  for (const pkg of pkgsToConsider) {
539
649
  const name = pkg.packageJson.name;
540
650
  const pkgPath = pkg.dir;
541
- const prefix = formatTagPrefix(tagPrefix);
542
- const latestTagResult = await this.getLatestTag();
543
- const latestTag = latestTagResult || "";
651
+ const formattedPrefix = formatTagPrefix(this.versionPrefix);
652
+ let latestTagResult = await getLatestTagForPackage(name, this.versionPrefix);
653
+ if (!latestTagResult) {
654
+ const globalTagResult = await this.getLatestTag();
655
+ latestTagResult = globalTagResult || "";
656
+ }
657
+ const latestTag = latestTagResult;
544
658
  const nextVersion = await calculateVersion(this.fullConfig, {
545
659
  latestTag,
546
- tagPrefix: prefix,
660
+ versionPrefix: formattedPrefix,
547
661
  path: pkgPath,
548
662
  name,
549
663
  branchPattern: this.config.branchPattern,
@@ -554,8 +668,14 @@ var PackageProcessor = class {
554
668
  if (!nextVersion) {
555
669
  continue;
556
670
  }
557
- updatePackageVersion(path.join(pkgPath, "package.json"), nextVersion);
558
- const packageTag = formatTag(nextVersion, tagPrefix);
671
+ updatePackageVersion(path2.join(pkgPath, "package.json"), nextVersion);
672
+ const packageTag = formatTag(
673
+ nextVersion,
674
+ this.versionPrefix,
675
+ name,
676
+ this.tagTemplate,
677
+ this.packageTagTemplate
678
+ );
559
679
  const tagMessage = `chore(release): ${name} ${nextVersion}`;
560
680
  addTag(packageTag);
561
681
  tags.push(packageTag);
@@ -579,7 +699,7 @@ var PackageProcessor = class {
579
699
  log("No targeted packages required a version update.", "info");
580
700
  return { updatedPackages: [], tags };
581
701
  }
582
- const filesToCommit = updatedPackagesInfo.map((info) => path.join(info.path, "package.json"));
702
+ const filesToCommit = updatedPackagesInfo.map((info) => path2.join(info.path, "package.json"));
583
703
  const packageNames = updatedPackagesInfo.map((p) => p.name).join(", ");
584
704
  const representativeVersion = ((_a = updatedPackagesInfo[0]) == null ? void 0 : _a.version) || "multiple";
585
705
  let commitMessage = this.commitMessageTemplate || "chore(release): publish packages";
@@ -631,7 +751,8 @@ function createSyncedStrategy(config) {
631
751
  return async (packages) => {
632
752
  try {
633
753
  const {
634
- tagPrefix,
754
+ versionPrefix,
755
+ tagTemplate,
635
756
  baseBranch,
636
757
  branchPattern,
637
758
  commitMessage = "chore(release): v${version}",
@@ -639,11 +760,11 @@ function createSyncedStrategy(config) {
639
760
  dryRun,
640
761
  skipHooks
641
762
  } = config;
642
- const prefix = formatTagPrefix(tagPrefix || "v");
763
+ const formattedPrefix = formatTagPrefix(versionPrefix || "v");
643
764
  const latestTag = await getLatestTag();
644
765
  const nextVersion = await calculateVersion(config, {
645
766
  latestTag,
646
- tagPrefix: prefix,
767
+ versionPrefix: formattedPrefix,
647
768
  branchPattern,
648
769
  baseBranch,
649
770
  prereleaseIdentifier
@@ -655,8 +776,8 @@ function createSyncedStrategy(config) {
655
776
  const files = [];
656
777
  const updatedPackages = [];
657
778
  try {
658
- const rootPkgPath = path2.join(packages.root, "package.json");
659
- if (fs3.existsSync(rootPkgPath)) {
779
+ const rootPkgPath = path3.join(packages.root, "package.json");
780
+ if (fs4.existsSync(rootPkgPath)) {
660
781
  updatePackageVersion(rootPkgPath, nextVersion);
661
782
  files.push(rootPkgPath);
662
783
  updatedPackages.push("root");
@@ -668,7 +789,7 @@ function createSyncedStrategy(config) {
668
789
  if (!shouldProcessPackage(pkg, config)) {
669
790
  continue;
670
791
  }
671
- const packageJsonPath = path2.join(pkg.dir, "package.json");
792
+ const packageJsonPath = path3.join(pkg.dir, "package.json");
672
793
  updatePackageVersion(packageJsonPath, nextVersion);
673
794
  files.push(packageJsonPath);
674
795
  updatedPackages.push(pkg.packageJson.name);
@@ -679,7 +800,7 @@ function createSyncedStrategy(config) {
679
800
  log("No packages were updated", "warning");
680
801
  return;
681
802
  }
682
- const nextTag = formatTag(nextVersion, tagPrefix || "v");
803
+ const nextTag = formatTag(nextVersion, formattedPrefix, null, tagTemplate);
683
804
  const formattedCommitMessage = formatCommitMessage(commitMessage, nextVersion);
684
805
  await createGitCommitAndTag(files, nextTag, formattedCommitMessage, skipHooks, dryRun);
685
806
  } catch (error) {
@@ -698,7 +819,9 @@ function createSingleStrategy(config) {
698
819
  try {
699
820
  const {
700
821
  packages: configPackages,
701
- tagPrefix,
822
+ versionPrefix,
823
+ tagTemplate,
824
+ packageTagTemplate,
702
825
  commitMessage = "chore(release): ${version}",
703
826
  dryRun,
704
827
  skipHooks
@@ -715,13 +838,18 @@ function createSingleStrategy(config) {
715
838
  throw createVersionError("PACKAGE_NOT_FOUND" /* PACKAGE_NOT_FOUND */, packageName);
716
839
  }
717
840
  const pkgPath = pkg.dir;
718
- const prefix = formatTagPrefix(tagPrefix || "v");
719
- const latestTag = await getLatestTag();
841
+ const formattedPrefix = formatTagPrefix(versionPrefix || "v");
842
+ let latestTagResult = await getLatestTagForPackage(packageName, formattedPrefix);
843
+ if (!latestTagResult) {
844
+ const globalTagResult = await getLatestTag();
845
+ latestTagResult = globalTagResult || "";
846
+ }
847
+ const latestTag = latestTagResult;
720
848
  let nextVersion = void 0;
721
849
  try {
722
850
  nextVersion = await calculateVersion(config, {
723
851
  latestTag,
724
- tagPrefix: prefix,
852
+ versionPrefix: formattedPrefix,
725
853
  path: pkgPath,
726
854
  name: packageName
727
855
  });
@@ -733,10 +861,16 @@ function createSingleStrategy(config) {
733
861
  log(`No version change needed for ${packageName}`, "info");
734
862
  return;
735
863
  }
736
- const packageJsonPath = path2.join(pkgPath, "package.json");
864
+ const packageJsonPath = path3.join(pkgPath, "package.json");
737
865
  updatePackageVersion(packageJsonPath, nextVersion);
738
866
  log(`Updated package ${packageName} to version ${nextVersion}`, "success");
739
- const nextTag = formatTag(nextVersion, tagPrefix || "v");
867
+ const nextTag = formatTag(
868
+ nextVersion,
869
+ formattedPrefix,
870
+ packageName,
871
+ tagTemplate,
872
+ packageTagTemplate
873
+ );
740
874
  const formattedCommitMessage = formatCommitMessage(commitMessage, nextVersion);
741
875
  await createGitCommitAndTag(
742
876
  [packageJsonPath],
@@ -766,7 +900,9 @@ function createAsyncStrategy(config) {
766
900
  const processorOptions = {
767
901
  skip: config.skip || [],
768
902
  targets: config.packages || [],
769
- tagPrefix: config.tagPrefix || "v",
903
+ versionPrefix: config.versionPrefix || "v",
904
+ tagTemplate: config.tagTemplate,
905
+ packageTagTemplate: config.packageTagTemplate,
770
906
  commitMessageTemplate: config.commitMessage || "",
771
907
  dryRun: config.dryRun || false,
772
908
  skipHooks: config.skipHooks || false,
@@ -133,3 +133,55 @@ This applies to all standard bump types:
133
133
  - `--bump major`: 1.0.0-beta.1 -> 2.0.0
134
134
  - `--bump minor`: 1.0.0-beta.1 -> 1.1.0
135
135
  - `--bump patch`: 1.0.0-beta.1 -> 1.0.1
136
+
137
+ ## Tag Templates and Configuration
138
+
139
+ `package-versioner` provides flexible configuration for how Git tags are formatted, allowing you to customize the tag structure for both single package repositories and monorepos.
140
+
141
+ ### Tag Template Configuration
142
+
143
+ You can customize how tags are formatted using the following configuration options in `version.config.json`:
144
+
145
+ ```json
146
+ {
147
+ "versionPrefix": "v",
148
+ "tagTemplate": "${prefix}${version}",
149
+ "packageTagTemplate": "${packageName}@${prefix}${version}"
150
+ }
151
+ ```
152
+
153
+ - **versionPrefix**: The prefix used for all version numbers in tags (default: `"v"`)
154
+ - **tagTemplate**: The template for the main Git tag (default: `"${prefix}${version}"`)
155
+ - **packageTagTemplate**: The template for package-specific Git tags in monorepos (default: `"${packageName}@${prefix}${version}"`)
156
+
157
+ ### Available Template Variables
158
+
159
+ The tag templates support the following variables:
160
+
161
+ - `${prefix}`: Replaced with the value of `versionPrefix`
162
+ - `${version}`: Replaced with the calculated version number
163
+ - `${packageName}`: (Only in `packageTagTemplate`) Replaced with the package name
164
+
165
+ ### Examples
166
+
167
+ #### Default Tag Format
168
+ With default settings, tags will look like:
169
+ - Single repository or synced monorepo: `v1.2.3`
170
+ - Package-specific tag in async monorepo: `@scope/package-name@v1.2.3`
171
+
172
+ #### Custom Tag Format Examples
173
+ ```json
174
+ {
175
+ "versionPrefix": "",
176
+ "tagTemplate": "release-${version}"
177
+ }
178
+ ```
179
+ This would produce tags like `release-1.2.3` instead of `v1.2.3`.
180
+
181
+ ```json
182
+ {
183
+ "versionPrefix": "v",
184
+ "packageTagTemplate": "${packageName}-${prefix}${version}"
185
+ }
186
+ ```
187
+ This would produce package tags like `@scope/package-name-v1.2.3` instead of `@scope/package-name@v1.2.3`.
@@ -6,12 +6,24 @@
6
6
  "type": "string",
7
7
  "description": "JSON schema reference"
8
8
  },
9
- "tagPrefix": {
9
+ "versionPrefix": {
10
10
  "type": "string",
11
11
  "minLength": 1,
12
12
  "description": "The prefix used for Git tags",
13
13
  "default": "v"
14
14
  },
15
+ "tagTemplate": {
16
+ "type": "string",
17
+ "minLength": 1,
18
+ "default": "${prefix}${version}",
19
+ "description": "Template for formatting Git tags"
20
+ },
21
+ "packageTagTemplate": {
22
+ "type": "string",
23
+ "minLength": 1,
24
+ "default": "${packageName}@${prefix}${version}",
25
+ "description": "Template for formatting package-specific Git tags"
26
+ },
15
27
  "preset": {
16
28
  "type": "string",
17
29
  "enum": ["angular", "conventional"],
@@ -85,6 +97,6 @@
85
97
  "description": "Whether to skip Git hooks"
86
98
  }
87
99
  },
88
- "required": ["tagPrefix", "preset", "updateInternalDependencies"],
100
+ "required": ["versionPrefix", "preset", "updateInternalDependencies"],
89
101
  "additionalProperties": false
90
102
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "package-versioner",
3
3
  "description": "A lightweight yet powerful CLI tool for automated semantic versioning based on Git history and conventional commits.",
4
- "version": "0.4.0",
4
+ "version": "0.5.0",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
7
7
  "module": "./dist/index.mjs",