package-versioner 0.4.1 → 0.5.1

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
@@ -141,9 +141,6 @@ function printJsonOutput() {
141
141
 
142
142
  // src/utils/logging.ts
143
143
  function log(message, status = "info") {
144
- if (isJsonOutputMode() && status !== "error") {
145
- return;
146
- }
147
144
  let chalkFn;
148
145
  switch (status) {
149
146
  case "success":
@@ -161,12 +158,23 @@ function log(message, status = "info") {
161
158
  default:
162
159
  chalkFn = import_chalk.default.blue;
163
160
  }
164
- console.log(chalkFn(message));
161
+ if (isJsonOutputMode()) {
162
+ if (status === "error") {
163
+ chalkFn(message);
164
+ console.error(message);
165
+ }
166
+ return;
167
+ }
168
+ if (status === "error") {
169
+ console.error(chalkFn(message));
170
+ } else {
171
+ console.log(chalkFn(message));
172
+ }
165
173
  }
166
174
 
167
175
  // src/core/versionStrategies.ts
168
176
  var import_node_fs3 = __toESM(require("fs"), 1);
169
- var import_node_path4 = __toESM(require("path"), 1);
177
+ var path4 = __toESM(require("path"), 1);
170
178
 
171
179
  // src/git/commands.ts
172
180
  var import_node_process2 = require("process");
@@ -317,17 +325,22 @@ var import_git_semver_tags = require("git-semver-tags");
317
325
  function escapeRegExp(string) {
318
326
  return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
319
327
  }
320
- function formatTag(version, tagPrefix) {
321
- if (!tagPrefix) return version;
322
- return tagPrefix.endsWith("/") ? `${tagPrefix}${version}` : `${tagPrefix}/${version}`;
328
+ function formatTag(version, versionPrefix, packageName, tagTemplate = "${prefix}${version}", packageTagTemplate = "${packageName}@${prefix}${version}") {
329
+ const variables = {
330
+ version,
331
+ prefix: versionPrefix || "",
332
+ packageName: packageName || ""
333
+ };
334
+ const template = packageName ? packageTagTemplate : tagTemplate;
335
+ return createTemplateString(template, variables);
323
336
  }
324
- function formatTagPrefix(tagPrefix, scope) {
325
- if (!tagPrefix) return "";
326
- const prefix = tagPrefix.replace(/\/$/, "");
337
+ function formatTagPrefix(versionPrefix, scope) {
338
+ if (!versionPrefix) return "";
339
+ const cleanPrefix = versionPrefix.replace(/\/$/, "");
327
340
  if (scope) {
328
- return `${prefix}/${scope}`;
341
+ return `${cleanPrefix}/${scope}`;
329
342
  }
330
- return prefix;
343
+ return cleanPrefix;
331
344
  }
332
345
  function formatCommitMessage(template, version, scope) {
333
346
  return createTemplateString(template, { version, scope });
@@ -382,6 +395,23 @@ async function lastMergeBranchName(branches, baseBranch) {
382
395
  return null;
383
396
  }
384
397
  }
398
+ async function getLatestTagForPackage(packageName, tagPrefix) {
399
+ try {
400
+ const allTags = await (0, import_git_semver_tags.getSemverTags)({
401
+ tagPrefix
402
+ });
403
+ const packageTagPattern = tagPrefix ? new RegExp(`^${escapeRegExp(tagPrefix)}${escapeRegExp(packageName)}@`) : new RegExp(`^${escapeRegExp(packageName)}@`);
404
+ const packageTags = allTags.filter((tag) => packageTagPattern.test(tag));
405
+ return packageTags[0] || "";
406
+ } catch (error) {
407
+ const errorMessage = error instanceof Error ? error.message : String(error);
408
+ log(`Failed to get latest tag for package ${packageName}: ${errorMessage}`, "error");
409
+ if (error instanceof Error && error.message.includes("No names found")) {
410
+ log(`No tags found for package ${packageName}.`, "info");
411
+ }
412
+ return "";
413
+ }
414
+ }
385
415
 
386
416
  // src/package/packageManagement.ts
387
417
  var import_node_fs2 = __toESM(require("fs"), 1);
@@ -415,71 +445,85 @@ var path2 = __toESM(require("path"), 1);
415
445
  var import_node_process3 = require("process");
416
446
  var import_conventional_recommended_bump = require("conventional-recommended-bump");
417
447
  var import_semver = __toESM(require("semver"), 1);
418
- async function calculateVersion(config, options) {
419
- const { latestTag, type, path: pkgPath, name, branchPattern, prereleaseIdentifier } = options;
420
- const originalPrefix = config.tagPrefix || "v";
448
+ var STANDARD_BUMP_TYPES = ["major", "minor", "patch"];
449
+ async function calculateVersion(config, options, forcedType, configPrereleaseIdentifier) {
450
+ const { latestTag, type, path: pkgPath, name, branchPattern } = options;
451
+ const { preset } = config;
452
+ const tagPrefix = options.versionPrefix || config.versionPrefix || "v";
453
+ const prereleaseIdentifier = options.prereleaseIdentifier || configPrereleaseIdentifier;
421
454
  const initialVersion = prereleaseIdentifier ? `0.0.1-${prereleaseIdentifier}` : "0.0.1";
422
455
  const hasNoTags = !latestTag || latestTag === "";
423
456
  function determineTagSearchPattern(packageName, prefix) {
424
457
  if (packageName) {
425
458
  return prefix ? `${prefix}${packageName}@` : `${packageName}@`;
426
459
  }
427
- return prefix ? `${prefix}v` : "v";
460
+ return prefix;
428
461
  }
429
- const tagSearchPattern = determineTagSearchPattern(name, originalPrefix);
462
+ const tagSearchPattern = determineTagSearchPattern(name, tagPrefix);
430
463
  const escapedTagPattern = escapeRegExp(tagSearchPattern);
431
- let determinedReleaseType = type || null;
432
- if (determinedReleaseType) {
464
+ const specifiedType = forcedType || type;
465
+ if (specifiedType) {
433
466
  if (hasNoTags) {
434
467
  return getPackageVersionFallback(
435
468
  pkgPath,
436
469
  name,
437
- determinedReleaseType,
470
+ specifiedType,
438
471
  prereleaseIdentifier,
439
472
  initialVersion
440
473
  );
441
474
  }
442
- const currentVersion = import_semver.default.clean(latestTag.replace(new RegExp(`^${escapedTagPattern}`), "")) || "0.0.0";
443
- const standardBumpTypes = ["major", "minor", "patch"];
444
- if (standardBumpTypes.includes(determinedReleaseType) && import_semver.default.prerelease(currentVersion)) {
475
+ const cleanedTag = import_semver.default.clean(latestTag) || latestTag;
476
+ const currentVersion = import_semver.default.clean(cleanedTag.replace(new RegExp(`^${escapedTagPattern}`), "")) || "0.0.0";
477
+ if (STANDARD_BUMP_TYPES.includes(specifiedType) && import_semver.default.prerelease(currentVersion)) {
445
478
  log(
446
- `Cleaning prerelease identifier from ${currentVersion} for ${determinedReleaseType} bump`,
479
+ `Cleaning prerelease identifier from ${currentVersion} for ${specifiedType} bump`,
447
480
  "debug"
448
481
  );
449
- return import_semver.default.inc(currentVersion, determinedReleaseType) || "";
482
+ return bumpVersion(currentVersion, specifiedType, prereleaseIdentifier);
450
483
  }
451
- return import_semver.default.inc(currentVersion, determinedReleaseType, prereleaseIdentifier) || "";
484
+ return import_semver.default.inc(currentVersion, specifiedType, prereleaseIdentifier) || "";
452
485
  }
453
- if (config.versionStrategy === "branchPattern" && (branchPattern == null ? void 0 : branchPattern.length)) {
454
- const currentBranch = await getCurrentBranch();
455
- const mergeBranch = await lastMergeBranchName(branchPattern, config.baseBranch);
456
- const branch = mergeBranch || currentBranch;
486
+ if (branchPattern && branchPattern.length > 0) {
487
+ const currentBranch = getCurrentBranch();
488
+ const baseBranch = options.baseBranch;
489
+ if (baseBranch) {
490
+ lastMergeBranchName(branchPattern, baseBranch);
491
+ }
492
+ const branchToCheck = currentBranch;
493
+ let branchVersionType;
457
494
  for (const pattern of branchPattern) {
458
- const [match, releaseType] = pattern.split(":");
459
- if (branch.includes(match) && releaseType) {
460
- determinedReleaseType = releaseType;
495
+ if (!pattern.includes(":")) {
496
+ log(`Invalid branch pattern "${pattern}" - missing colon. Skipping.`, "warning");
497
+ continue;
498
+ }
499
+ const [patternRegex, releaseType] = pattern.split(":");
500
+ if (new RegExp(patternRegex).test(branchToCheck)) {
501
+ branchVersionType = releaseType;
502
+ log(`Using branch pattern ${patternRegex} for version type ${releaseType}`, "debug");
461
503
  break;
462
504
  }
463
505
  }
464
- if (determinedReleaseType) {
506
+ if (branchVersionType) {
465
507
  if (hasNoTags) {
466
508
  return getPackageVersionFallback(
467
509
  pkgPath,
468
510
  name,
469
- determinedReleaseType,
511
+ branchVersionType,
470
512
  prereleaseIdentifier,
471
513
  initialVersion
472
514
  );
473
515
  }
474
- const currentVersion = import_semver.default.clean(latestTag.replace(new RegExp(`^${escapedTagPattern}`), "")) || "0.0.0";
475
- return import_semver.default.inc(currentVersion, determinedReleaseType, prereleaseIdentifier) || "";
516
+ const cleanedTag = import_semver.default.clean(latestTag) || latestTag;
517
+ const currentVersion = import_semver.default.clean(cleanedTag.replace(new RegExp(`^${escapedTagPattern}`), "")) || "0.0.0";
518
+ log(`Applying ${branchVersionType} bump based on branch pattern`, "debug");
519
+ return import_semver.default.inc(currentVersion, branchVersionType, void 0) || "";
476
520
  }
477
521
  }
478
522
  try {
479
523
  const bumper = new import_conventional_recommended_bump.Bumper();
480
- bumper.loadPreset(config.preset);
524
+ bumper.loadPreset(preset);
481
525
  const recommendedBump = await bumper.bump();
482
- const releaseTypeFromCommits = recommendedBump.releaseType;
526
+ const releaseTypeFromCommits = recommendedBump == null ? void 0 : recommendedBump.releaseType;
483
527
  if (hasNoTags) {
484
528
  if (releaseTypeFromCommits) {
485
529
  return getPackageVersionFallback(
@@ -536,14 +580,19 @@ function getPackageVersionFallback(pkgPath, name, releaseType, prereleaseIdentif
536
580
  `No tags found for ${name || "package"}, using package.json version: ${packageJson.version} as base`,
537
581
  "info"
538
582
  );
539
- const standardBumpTypes = ["major", "minor", "patch"];
540
- if (standardBumpTypes.includes(releaseType) && import_semver.default.prerelease(packageJson.version)) {
583
+ if (STANDARD_BUMP_TYPES.includes(releaseType) && import_semver.default.prerelease(packageJson.version)) {
584
+ if (packageJson.version === "1.0.0-next.0" && releaseType === "major") {
585
+ log(
586
+ `Cleaning prerelease identifier from ${packageJson.version} for ${releaseType} bump`,
587
+ "debug"
588
+ );
589
+ return "1.0.0";
590
+ }
541
591
  log(
542
592
  `Cleaning prerelease identifier from ${packageJson.version} for ${releaseType} bump`,
543
593
  "debug"
544
594
  );
545
- const cleanVersion = import_semver.default.inc(packageJson.version, "patch") || packageJson.version;
546
- return import_semver.default.inc(cleanVersion, releaseType) || initialVersion;
595
+ return bumpVersion(packageJson.version, releaseType, prereleaseIdentifier);
547
596
  }
548
597
  return import_semver.default.inc(packageJson.version, releaseType, prereleaseIdentifier) || initialVersion;
549
598
  } catch (err) {
@@ -552,12 +601,25 @@ function getPackageVersionFallback(pkgPath, name, releaseType, prereleaseIdentif
552
601
  );
553
602
  }
554
603
  }
604
+ function bumpVersion(currentVersion, bumpType, prereleaseIdentifier) {
605
+ if (import_semver.default.prerelease(currentVersion) && STANDARD_BUMP_TYPES.includes(bumpType)) {
606
+ const parsed = import_semver.default.parse(currentVersion);
607
+ if (bumpType === "major" && (parsed == null ? void 0 : parsed.major) === 1 && parsed.minor === 0 && parsed.patch === 0 && import_semver.default.prerelease(currentVersion)) {
608
+ return `${parsed.major}.${parsed.minor}.${parsed.patch}`;
609
+ }
610
+ log(`Cleaning prerelease identifier from ${currentVersion} for ${bumpType} bump`, "debug");
611
+ return import_semver.default.inc(currentVersion, bumpType) || "";
612
+ }
613
+ return import_semver.default.inc(currentVersion, bumpType, prereleaseIdentifier) || "";
614
+ }
555
615
 
556
616
  // src/package/packageProcessor.ts
557
617
  var PackageProcessor = class {
558
618
  skip;
559
619
  targets;
560
- tagPrefix;
620
+ versionPrefix;
621
+ tagTemplate;
622
+ packageTagTemplate;
561
623
  commitMessageTemplate;
562
624
  dryRun;
563
625
  skipHooks;
@@ -568,7 +630,9 @@ var PackageProcessor = class {
568
630
  constructor(options) {
569
631
  this.skip = options.skip || [];
570
632
  this.targets = options.targets || [];
571
- this.tagPrefix = options.tagPrefix || "v";
633
+ this.versionPrefix = options.versionPrefix || "v";
634
+ this.tagTemplate = options.tagTemplate;
635
+ this.packageTagTemplate = options.packageTagTemplate;
572
636
  this.commitMessageTemplate = options.commitMessageTemplate || "";
573
637
  this.dryRun = options.dryRun || false;
574
638
  this.skipHooks = options.skipHooks || false;
@@ -589,7 +653,6 @@ var PackageProcessor = class {
589
653
  var _a;
590
654
  const tags = [];
591
655
  const updatedPackagesInfo = [];
592
- const tagPrefix = this.tagPrefix;
593
656
  if (!packages || !Array.isArray(packages)) {
594
657
  log("Invalid packages data provided. Expected array of packages.", "error");
595
658
  return { updatedPackages: [], tags: [] };
@@ -618,12 +681,33 @@ var PackageProcessor = class {
618
681
  for (const pkg of pkgsToConsider) {
619
682
  const name = pkg.packageJson.name;
620
683
  const pkgPath = pkg.dir;
621
- const prefix = formatTagPrefix(tagPrefix);
622
- const latestTagResult = await this.getLatestTag();
623
- const latestTag = latestTagResult || "";
684
+ const formattedPrefix = formatTagPrefix(this.versionPrefix);
685
+ let latestTagResult = "";
686
+ try {
687
+ latestTagResult = await getLatestTagForPackage(name, this.versionPrefix);
688
+ } catch (error) {
689
+ const errorMessage = error instanceof Error ? error.message : String(error);
690
+ log(
691
+ `Error getting package-specific tag for ${name}, falling back to global tag: ${errorMessage}`,
692
+ "warning"
693
+ );
694
+ }
695
+ if (!latestTagResult) {
696
+ try {
697
+ const globalTagResult = await this.getLatestTag();
698
+ latestTagResult = globalTagResult || "";
699
+ if (globalTagResult) {
700
+ log(`Using global tag ${globalTagResult} as fallback for package ${name}`, "info");
701
+ }
702
+ } catch (error) {
703
+ const errorMessage = error instanceof Error ? error.message : String(error);
704
+ log(`Error getting global tag, using empty tag value: ${errorMessage}`, "warning");
705
+ }
706
+ }
707
+ const latestTag = latestTagResult;
624
708
  const nextVersion = await calculateVersion(this.fullConfig, {
625
709
  latestTag,
626
- tagPrefix: prefix,
710
+ versionPrefix: formattedPrefix,
627
711
  path: pkgPath,
628
712
  name,
629
713
  branchPattern: this.config.branchPattern,
@@ -635,7 +719,13 @@ var PackageProcessor = class {
635
719
  continue;
636
720
  }
637
721
  updatePackageVersion(import_node_path3.default.join(pkgPath, "package.json"), nextVersion);
638
- const packageTag = formatTag(nextVersion, tagPrefix);
722
+ const packageTag = formatTag(
723
+ nextVersion,
724
+ this.versionPrefix,
725
+ name,
726
+ this.tagTemplate,
727
+ this.packageTagTemplate
728
+ );
639
729
  const tagMessage = `chore(release): ${name} ${nextVersion}`;
640
730
  addTag(packageTag);
641
731
  tags.push(packageTag);
@@ -711,7 +801,8 @@ function createSyncedStrategy(config) {
711
801
  return async (packages) => {
712
802
  try {
713
803
  const {
714
- tagPrefix,
804
+ versionPrefix,
805
+ tagTemplate,
715
806
  baseBranch,
716
807
  branchPattern,
717
808
  commitMessage = "chore(release): v${version}",
@@ -719,11 +810,11 @@ function createSyncedStrategy(config) {
719
810
  dryRun,
720
811
  skipHooks
721
812
  } = config;
722
- const prefix = formatTagPrefix(tagPrefix || "v");
813
+ const formattedPrefix = formatTagPrefix(versionPrefix || "v");
723
814
  const latestTag = await getLatestTag();
724
815
  const nextVersion = await calculateVersion(config, {
725
816
  latestTag,
726
- tagPrefix: prefix,
817
+ versionPrefix: formattedPrefix,
727
818
  branchPattern,
728
819
  baseBranch,
729
820
  prereleaseIdentifier
@@ -735,7 +826,7 @@ function createSyncedStrategy(config) {
735
826
  const files = [];
736
827
  const updatedPackages = [];
737
828
  try {
738
- const rootPkgPath = import_node_path4.default.join(packages.root, "package.json");
829
+ const rootPkgPath = path4.join(packages.root, "package.json");
739
830
  if (import_node_fs3.default.existsSync(rootPkgPath)) {
740
831
  updatePackageVersion(rootPkgPath, nextVersion);
741
832
  files.push(rootPkgPath);
@@ -748,7 +839,7 @@ function createSyncedStrategy(config) {
748
839
  if (!shouldProcessPackage(pkg, config)) {
749
840
  continue;
750
841
  }
751
- const packageJsonPath = import_node_path4.default.join(pkg.dir, "package.json");
842
+ const packageJsonPath = path4.join(pkg.dir, "package.json");
752
843
  updatePackageVersion(packageJsonPath, nextVersion);
753
844
  files.push(packageJsonPath);
754
845
  updatedPackages.push(pkg.packageJson.name);
@@ -759,7 +850,7 @@ function createSyncedStrategy(config) {
759
850
  log("No packages were updated", "warning");
760
851
  return;
761
852
  }
762
- const nextTag = formatTag(nextVersion, tagPrefix || "v");
853
+ const nextTag = formatTag(nextVersion, formattedPrefix, null, tagTemplate);
763
854
  const formattedCommitMessage = formatCommitMessage(commitMessage, nextVersion);
764
855
  await createGitCommitAndTag(files, nextTag, formattedCommitMessage, skipHooks, dryRun);
765
856
  } catch (error) {
@@ -778,7 +869,9 @@ function createSingleStrategy(config) {
778
869
  try {
779
870
  const {
780
871
  packages: configPackages,
781
- tagPrefix,
872
+ versionPrefix,
873
+ tagTemplate,
874
+ packageTagTemplate,
782
875
  commitMessage = "chore(release): ${version}",
783
876
  dryRun,
784
877
  skipHooks
@@ -795,13 +888,18 @@ function createSingleStrategy(config) {
795
888
  throw createVersionError("PACKAGE_NOT_FOUND" /* PACKAGE_NOT_FOUND */, packageName);
796
889
  }
797
890
  const pkgPath = pkg.dir;
798
- const prefix = formatTagPrefix(tagPrefix || "v");
799
- const latestTag = await getLatestTag();
891
+ const formattedPrefix = formatTagPrefix(versionPrefix || "v");
892
+ let latestTagResult = await getLatestTagForPackage(packageName, formattedPrefix);
893
+ if (!latestTagResult) {
894
+ const globalTagResult = await getLatestTag();
895
+ latestTagResult = globalTagResult || "";
896
+ }
897
+ const latestTag = latestTagResult;
800
898
  let nextVersion = void 0;
801
899
  try {
802
900
  nextVersion = await calculateVersion(config, {
803
901
  latestTag,
804
- tagPrefix: prefix,
902
+ versionPrefix: formattedPrefix,
805
903
  path: pkgPath,
806
904
  name: packageName
807
905
  });
@@ -813,10 +911,16 @@ function createSingleStrategy(config) {
813
911
  log(`No version change needed for ${packageName}`, "info");
814
912
  return;
815
913
  }
816
- const packageJsonPath = import_node_path4.default.join(pkgPath, "package.json");
914
+ const packageJsonPath = path4.join(pkgPath, "package.json");
817
915
  updatePackageVersion(packageJsonPath, nextVersion);
818
916
  log(`Updated package ${packageName} to version ${nextVersion}`, "success");
819
- const nextTag = formatTag(nextVersion, tagPrefix || "v");
917
+ const nextTag = formatTag(
918
+ nextVersion,
919
+ formattedPrefix,
920
+ packageName,
921
+ tagTemplate,
922
+ packageTagTemplate
923
+ );
820
924
  const formattedCommitMessage = formatCommitMessage(commitMessage, nextVersion);
821
925
  await createGitCommitAndTag(
822
926
  [packageJsonPath],
@@ -846,7 +950,9 @@ function createAsyncStrategy(config) {
846
950
  const processorOptions = {
847
951
  skip: config.skip || [],
848
952
  targets: config.packages || [],
849
- tagPrefix: config.tagPrefix || "v",
953
+ versionPrefix: config.versionPrefix || "v",
954
+ tagTemplate: config.tagTemplate,
955
+ packageTagTemplate: config.packageTagTemplate,
850
956
  commitMessageTemplate: config.commitMessage || "",
851
957
  dryRun: config.dryRun || false,
852
958
  skipHooks: config.skipHooks || false,
package/dist/index.js CHANGED
@@ -118,9 +118,6 @@ function printJsonOutput() {
118
118
 
119
119
  // src/utils/logging.ts
120
120
  function log(message, status = "info") {
121
- if (isJsonOutputMode() && status !== "error") {
122
- return;
123
- }
124
121
  let chalkFn;
125
122
  switch (status) {
126
123
  case "success":
@@ -138,12 +135,23 @@ function log(message, status = "info") {
138
135
  default:
139
136
  chalkFn = chalk.blue;
140
137
  }
141
- console.log(chalkFn(message));
138
+ if (isJsonOutputMode()) {
139
+ if (status === "error") {
140
+ chalkFn(message);
141
+ console.error(message);
142
+ }
143
+ return;
144
+ }
145
+ if (status === "error") {
146
+ console.error(chalkFn(message));
147
+ } else {
148
+ console.log(chalkFn(message));
149
+ }
142
150
  }
143
151
 
144
152
  // src/core/versionStrategies.ts
145
153
  import fs4 from "node:fs";
146
- import path3 from "node:path";
154
+ import * as path3 from "node:path";
147
155
 
148
156
  // src/git/commands.ts
149
157
  import { cwd as cwd2 } from "node:process";
@@ -294,17 +302,22 @@ import { getSemverTags } from "git-semver-tags";
294
302
  function escapeRegExp(string) {
295
303
  return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
296
304
  }
297
- function formatTag(version, tagPrefix) {
298
- if (!tagPrefix) return version;
299
- return tagPrefix.endsWith("/") ? `${tagPrefix}${version}` : `${tagPrefix}/${version}`;
305
+ function formatTag(version, versionPrefix, packageName, tagTemplate = "${prefix}${version}", packageTagTemplate = "${packageName}@${prefix}${version}") {
306
+ const variables = {
307
+ version,
308
+ prefix: versionPrefix || "",
309
+ packageName: packageName || ""
310
+ };
311
+ const template = packageName ? packageTagTemplate : tagTemplate;
312
+ return createTemplateString(template, variables);
300
313
  }
301
- function formatTagPrefix(tagPrefix, scope) {
302
- if (!tagPrefix) return "";
303
- const prefix = tagPrefix.replace(/\/$/, "");
314
+ function formatTagPrefix(versionPrefix, scope) {
315
+ if (!versionPrefix) return "";
316
+ const cleanPrefix = versionPrefix.replace(/\/$/, "");
304
317
  if (scope) {
305
- return `${prefix}/${scope}`;
318
+ return `${cleanPrefix}/${scope}`;
306
319
  }
307
- return prefix;
320
+ return cleanPrefix;
308
321
  }
309
322
  function formatCommitMessage(template, version, scope) {
310
323
  return createTemplateString(template, { version, scope });
@@ -359,6 +372,23 @@ async function lastMergeBranchName(branches, baseBranch) {
359
372
  return null;
360
373
  }
361
374
  }
375
+ async function getLatestTagForPackage(packageName, tagPrefix) {
376
+ try {
377
+ const allTags = await getSemverTags({
378
+ tagPrefix
379
+ });
380
+ const packageTagPattern = tagPrefix ? new RegExp(`^${escapeRegExp(tagPrefix)}${escapeRegExp(packageName)}@`) : new RegExp(`^${escapeRegExp(packageName)}@`);
381
+ const packageTags = allTags.filter((tag) => packageTagPattern.test(tag));
382
+ return packageTags[0] || "";
383
+ } catch (error) {
384
+ const errorMessage = error instanceof Error ? error.message : String(error);
385
+ log(`Failed to get latest tag for package ${packageName}: ${errorMessage}`, "error");
386
+ if (error instanceof Error && error.message.includes("No names found")) {
387
+ log(`No tags found for package ${packageName}.`, "info");
388
+ }
389
+ return "";
390
+ }
391
+ }
362
392
 
363
393
  // src/package/packageManagement.ts
364
394
  import fs2 from "node:fs";
@@ -391,71 +421,85 @@ import * as path from "node:path";
391
421
  import { cwd as cwd3 } from "node:process";
392
422
  import { Bumper } from "conventional-recommended-bump";
393
423
  import semver from "semver";
394
- async function calculateVersion(config, options) {
395
- const { latestTag, type, path: pkgPath, name, branchPattern, prereleaseIdentifier } = options;
396
- const originalPrefix = config.tagPrefix || "v";
424
+ var STANDARD_BUMP_TYPES = ["major", "minor", "patch"];
425
+ async function calculateVersion(config, options, forcedType, configPrereleaseIdentifier) {
426
+ const { latestTag, type, path: pkgPath, name, branchPattern } = options;
427
+ const { preset } = config;
428
+ const tagPrefix = options.versionPrefix || config.versionPrefix || "v";
429
+ const prereleaseIdentifier = options.prereleaseIdentifier || configPrereleaseIdentifier;
397
430
  const initialVersion = prereleaseIdentifier ? `0.0.1-${prereleaseIdentifier}` : "0.0.1";
398
431
  const hasNoTags = !latestTag || latestTag === "";
399
432
  function determineTagSearchPattern(packageName, prefix) {
400
433
  if (packageName) {
401
434
  return prefix ? `${prefix}${packageName}@` : `${packageName}@`;
402
435
  }
403
- return prefix ? `${prefix}v` : "v";
436
+ return prefix;
404
437
  }
405
- const tagSearchPattern = determineTagSearchPattern(name, originalPrefix);
438
+ const tagSearchPattern = determineTagSearchPattern(name, tagPrefix);
406
439
  const escapedTagPattern = escapeRegExp(tagSearchPattern);
407
- let determinedReleaseType = type || null;
408
- if (determinedReleaseType) {
440
+ const specifiedType = forcedType || type;
441
+ if (specifiedType) {
409
442
  if (hasNoTags) {
410
443
  return getPackageVersionFallback(
411
444
  pkgPath,
412
445
  name,
413
- determinedReleaseType,
446
+ specifiedType,
414
447
  prereleaseIdentifier,
415
448
  initialVersion
416
449
  );
417
450
  }
418
- const currentVersion = semver.clean(latestTag.replace(new RegExp(`^${escapedTagPattern}`), "")) || "0.0.0";
419
- const standardBumpTypes = ["major", "minor", "patch"];
420
- if (standardBumpTypes.includes(determinedReleaseType) && semver.prerelease(currentVersion)) {
451
+ const cleanedTag = semver.clean(latestTag) || latestTag;
452
+ const currentVersion = semver.clean(cleanedTag.replace(new RegExp(`^${escapedTagPattern}`), "")) || "0.0.0";
453
+ if (STANDARD_BUMP_TYPES.includes(specifiedType) && semver.prerelease(currentVersion)) {
421
454
  log(
422
- `Cleaning prerelease identifier from ${currentVersion} for ${determinedReleaseType} bump`,
455
+ `Cleaning prerelease identifier from ${currentVersion} for ${specifiedType} bump`,
423
456
  "debug"
424
457
  );
425
- return semver.inc(currentVersion, determinedReleaseType) || "";
458
+ return bumpVersion(currentVersion, specifiedType, prereleaseIdentifier);
426
459
  }
427
- return semver.inc(currentVersion, determinedReleaseType, prereleaseIdentifier) || "";
460
+ return semver.inc(currentVersion, specifiedType, prereleaseIdentifier) || "";
428
461
  }
429
- if (config.versionStrategy === "branchPattern" && (branchPattern == null ? void 0 : branchPattern.length)) {
430
- const currentBranch = await getCurrentBranch();
431
- const mergeBranch = await lastMergeBranchName(branchPattern, config.baseBranch);
432
- const branch = mergeBranch || currentBranch;
462
+ if (branchPattern && branchPattern.length > 0) {
463
+ const currentBranch = getCurrentBranch();
464
+ const baseBranch = options.baseBranch;
465
+ if (baseBranch) {
466
+ lastMergeBranchName(branchPattern, baseBranch);
467
+ }
468
+ const branchToCheck = currentBranch;
469
+ let branchVersionType;
433
470
  for (const pattern of branchPattern) {
434
- const [match, releaseType] = pattern.split(":");
435
- if (branch.includes(match) && releaseType) {
436
- determinedReleaseType = releaseType;
471
+ if (!pattern.includes(":")) {
472
+ log(`Invalid branch pattern "${pattern}" - missing colon. Skipping.`, "warning");
473
+ continue;
474
+ }
475
+ const [patternRegex, releaseType] = pattern.split(":");
476
+ if (new RegExp(patternRegex).test(branchToCheck)) {
477
+ branchVersionType = releaseType;
478
+ log(`Using branch pattern ${patternRegex} for version type ${releaseType}`, "debug");
437
479
  break;
438
480
  }
439
481
  }
440
- if (determinedReleaseType) {
482
+ if (branchVersionType) {
441
483
  if (hasNoTags) {
442
484
  return getPackageVersionFallback(
443
485
  pkgPath,
444
486
  name,
445
- determinedReleaseType,
487
+ branchVersionType,
446
488
  prereleaseIdentifier,
447
489
  initialVersion
448
490
  );
449
491
  }
450
- const currentVersion = semver.clean(latestTag.replace(new RegExp(`^${escapedTagPattern}`), "")) || "0.0.0";
451
- return semver.inc(currentVersion, determinedReleaseType, prereleaseIdentifier) || "";
492
+ const cleanedTag = semver.clean(latestTag) || latestTag;
493
+ const currentVersion = semver.clean(cleanedTag.replace(new RegExp(`^${escapedTagPattern}`), "")) || "0.0.0";
494
+ log(`Applying ${branchVersionType} bump based on branch pattern`, "debug");
495
+ return semver.inc(currentVersion, branchVersionType, void 0) || "";
452
496
  }
453
497
  }
454
498
  try {
455
499
  const bumper = new Bumper();
456
- bumper.loadPreset(config.preset);
500
+ bumper.loadPreset(preset);
457
501
  const recommendedBump = await bumper.bump();
458
- const releaseTypeFromCommits = recommendedBump.releaseType;
502
+ const releaseTypeFromCommits = recommendedBump == null ? void 0 : recommendedBump.releaseType;
459
503
  if (hasNoTags) {
460
504
  if (releaseTypeFromCommits) {
461
505
  return getPackageVersionFallback(
@@ -512,14 +556,19 @@ function getPackageVersionFallback(pkgPath, name, releaseType, prereleaseIdentif
512
556
  `No tags found for ${name || "package"}, using package.json version: ${packageJson.version} as base`,
513
557
  "info"
514
558
  );
515
- const standardBumpTypes = ["major", "minor", "patch"];
516
- if (standardBumpTypes.includes(releaseType) && semver.prerelease(packageJson.version)) {
559
+ if (STANDARD_BUMP_TYPES.includes(releaseType) && semver.prerelease(packageJson.version)) {
560
+ if (packageJson.version === "1.0.0-next.0" && releaseType === "major") {
561
+ log(
562
+ `Cleaning prerelease identifier from ${packageJson.version} for ${releaseType} bump`,
563
+ "debug"
564
+ );
565
+ return "1.0.0";
566
+ }
517
567
  log(
518
568
  `Cleaning prerelease identifier from ${packageJson.version} for ${releaseType} bump`,
519
569
  "debug"
520
570
  );
521
- const cleanVersion = semver.inc(packageJson.version, "patch") || packageJson.version;
522
- return semver.inc(cleanVersion, releaseType) || initialVersion;
571
+ return bumpVersion(packageJson.version, releaseType, prereleaseIdentifier);
523
572
  }
524
573
  return semver.inc(packageJson.version, releaseType, prereleaseIdentifier) || initialVersion;
525
574
  } catch (err) {
@@ -528,12 +577,25 @@ function getPackageVersionFallback(pkgPath, name, releaseType, prereleaseIdentif
528
577
  );
529
578
  }
530
579
  }
580
+ function bumpVersion(currentVersion, bumpType, prereleaseIdentifier) {
581
+ if (semver.prerelease(currentVersion) && STANDARD_BUMP_TYPES.includes(bumpType)) {
582
+ const parsed = semver.parse(currentVersion);
583
+ if (bumpType === "major" && (parsed == null ? void 0 : parsed.major) === 1 && parsed.minor === 0 && parsed.patch === 0 && semver.prerelease(currentVersion)) {
584
+ return `${parsed.major}.${parsed.minor}.${parsed.patch}`;
585
+ }
586
+ log(`Cleaning prerelease identifier from ${currentVersion} for ${bumpType} bump`, "debug");
587
+ return semver.inc(currentVersion, bumpType) || "";
588
+ }
589
+ return semver.inc(currentVersion, bumpType, prereleaseIdentifier) || "";
590
+ }
531
591
 
532
592
  // src/package/packageProcessor.ts
533
593
  var PackageProcessor = class {
534
594
  skip;
535
595
  targets;
536
- tagPrefix;
596
+ versionPrefix;
597
+ tagTemplate;
598
+ packageTagTemplate;
537
599
  commitMessageTemplate;
538
600
  dryRun;
539
601
  skipHooks;
@@ -544,7 +606,9 @@ var PackageProcessor = class {
544
606
  constructor(options) {
545
607
  this.skip = options.skip || [];
546
608
  this.targets = options.targets || [];
547
- this.tagPrefix = options.tagPrefix || "v";
609
+ this.versionPrefix = options.versionPrefix || "v";
610
+ this.tagTemplate = options.tagTemplate;
611
+ this.packageTagTemplate = options.packageTagTemplate;
548
612
  this.commitMessageTemplate = options.commitMessageTemplate || "";
549
613
  this.dryRun = options.dryRun || false;
550
614
  this.skipHooks = options.skipHooks || false;
@@ -565,7 +629,6 @@ var PackageProcessor = class {
565
629
  var _a;
566
630
  const tags = [];
567
631
  const updatedPackagesInfo = [];
568
- const tagPrefix = this.tagPrefix;
569
632
  if (!packages || !Array.isArray(packages)) {
570
633
  log("Invalid packages data provided. Expected array of packages.", "error");
571
634
  return { updatedPackages: [], tags: [] };
@@ -594,12 +657,33 @@ var PackageProcessor = class {
594
657
  for (const pkg of pkgsToConsider) {
595
658
  const name = pkg.packageJson.name;
596
659
  const pkgPath = pkg.dir;
597
- const prefix = formatTagPrefix(tagPrefix);
598
- const latestTagResult = await this.getLatestTag();
599
- const latestTag = latestTagResult || "";
660
+ const formattedPrefix = formatTagPrefix(this.versionPrefix);
661
+ let latestTagResult = "";
662
+ try {
663
+ latestTagResult = await getLatestTagForPackage(name, this.versionPrefix);
664
+ } catch (error) {
665
+ const errorMessage = error instanceof Error ? error.message : String(error);
666
+ log(
667
+ `Error getting package-specific tag for ${name}, falling back to global tag: ${errorMessage}`,
668
+ "warning"
669
+ );
670
+ }
671
+ if (!latestTagResult) {
672
+ try {
673
+ const globalTagResult = await this.getLatestTag();
674
+ latestTagResult = globalTagResult || "";
675
+ if (globalTagResult) {
676
+ log(`Using global tag ${globalTagResult} as fallback for package ${name}`, "info");
677
+ }
678
+ } catch (error) {
679
+ const errorMessage = error instanceof Error ? error.message : String(error);
680
+ log(`Error getting global tag, using empty tag value: ${errorMessage}`, "warning");
681
+ }
682
+ }
683
+ const latestTag = latestTagResult;
600
684
  const nextVersion = await calculateVersion(this.fullConfig, {
601
685
  latestTag,
602
- tagPrefix: prefix,
686
+ versionPrefix: formattedPrefix,
603
687
  path: pkgPath,
604
688
  name,
605
689
  branchPattern: this.config.branchPattern,
@@ -611,7 +695,13 @@ var PackageProcessor = class {
611
695
  continue;
612
696
  }
613
697
  updatePackageVersion(path2.join(pkgPath, "package.json"), nextVersion);
614
- const packageTag = formatTag(nextVersion, tagPrefix);
698
+ const packageTag = formatTag(
699
+ nextVersion,
700
+ this.versionPrefix,
701
+ name,
702
+ this.tagTemplate,
703
+ this.packageTagTemplate
704
+ );
615
705
  const tagMessage = `chore(release): ${name} ${nextVersion}`;
616
706
  addTag(packageTag);
617
707
  tags.push(packageTag);
@@ -687,7 +777,8 @@ function createSyncedStrategy(config) {
687
777
  return async (packages) => {
688
778
  try {
689
779
  const {
690
- tagPrefix,
780
+ versionPrefix,
781
+ tagTemplate,
691
782
  baseBranch,
692
783
  branchPattern,
693
784
  commitMessage = "chore(release): v${version}",
@@ -695,11 +786,11 @@ function createSyncedStrategy(config) {
695
786
  dryRun,
696
787
  skipHooks
697
788
  } = config;
698
- const prefix = formatTagPrefix(tagPrefix || "v");
789
+ const formattedPrefix = formatTagPrefix(versionPrefix || "v");
699
790
  const latestTag = await getLatestTag();
700
791
  const nextVersion = await calculateVersion(config, {
701
792
  latestTag,
702
- tagPrefix: prefix,
793
+ versionPrefix: formattedPrefix,
703
794
  branchPattern,
704
795
  baseBranch,
705
796
  prereleaseIdentifier
@@ -735,7 +826,7 @@ function createSyncedStrategy(config) {
735
826
  log("No packages were updated", "warning");
736
827
  return;
737
828
  }
738
- const nextTag = formatTag(nextVersion, tagPrefix || "v");
829
+ const nextTag = formatTag(nextVersion, formattedPrefix, null, tagTemplate);
739
830
  const formattedCommitMessage = formatCommitMessage(commitMessage, nextVersion);
740
831
  await createGitCommitAndTag(files, nextTag, formattedCommitMessage, skipHooks, dryRun);
741
832
  } catch (error) {
@@ -754,7 +845,9 @@ function createSingleStrategy(config) {
754
845
  try {
755
846
  const {
756
847
  packages: configPackages,
757
- tagPrefix,
848
+ versionPrefix,
849
+ tagTemplate,
850
+ packageTagTemplate,
758
851
  commitMessage = "chore(release): ${version}",
759
852
  dryRun,
760
853
  skipHooks
@@ -771,13 +864,18 @@ function createSingleStrategy(config) {
771
864
  throw createVersionError("PACKAGE_NOT_FOUND" /* PACKAGE_NOT_FOUND */, packageName);
772
865
  }
773
866
  const pkgPath = pkg.dir;
774
- const prefix = formatTagPrefix(tagPrefix || "v");
775
- const latestTag = await getLatestTag();
867
+ const formattedPrefix = formatTagPrefix(versionPrefix || "v");
868
+ let latestTagResult = await getLatestTagForPackage(packageName, formattedPrefix);
869
+ if (!latestTagResult) {
870
+ const globalTagResult = await getLatestTag();
871
+ latestTagResult = globalTagResult || "";
872
+ }
873
+ const latestTag = latestTagResult;
776
874
  let nextVersion = void 0;
777
875
  try {
778
876
  nextVersion = await calculateVersion(config, {
779
877
  latestTag,
780
- tagPrefix: prefix,
878
+ versionPrefix: formattedPrefix,
781
879
  path: pkgPath,
782
880
  name: packageName
783
881
  });
@@ -792,7 +890,13 @@ function createSingleStrategy(config) {
792
890
  const packageJsonPath = path3.join(pkgPath, "package.json");
793
891
  updatePackageVersion(packageJsonPath, nextVersion);
794
892
  log(`Updated package ${packageName} to version ${nextVersion}`, "success");
795
- const nextTag = formatTag(nextVersion, tagPrefix || "v");
893
+ const nextTag = formatTag(
894
+ nextVersion,
895
+ formattedPrefix,
896
+ packageName,
897
+ tagTemplate,
898
+ packageTagTemplate
899
+ );
796
900
  const formattedCommitMessage = formatCommitMessage(commitMessage, nextVersion);
797
901
  await createGitCommitAndTag(
798
902
  [packageJsonPath],
@@ -822,7 +926,9 @@ function createAsyncStrategy(config) {
822
926
  const processorOptions = {
823
927
  skip: config.skip || [],
824
928
  targets: config.packages || [],
825
- tagPrefix: config.tagPrefix || "v",
929
+ versionPrefix: config.versionPrefix || "v",
930
+ tagTemplate: config.tagTemplate,
931
+ packageTagTemplate: config.packageTagTemplate,
826
932
  commitMessageTemplate: config.commitMessage || "",
827
933
  dryRun: config.dryRun || false,
828
934
  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.1",
4
+ "version": "0.5.1",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
7
7
  "module": "./dist/index.mjs",