package-versioner 0.8.5 → 0.9.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
@@ -130,7 +130,7 @@ Customize behaviour by creating a `version.config.json` file in your project roo
130
130
  "updateChangelog": true,
131
131
  "changelogFormat": "keep-a-changelog",
132
132
  "strictReachable": false,
133
- "synced": true,
133
+ "sync": true,
134
134
  "skip": [
135
135
  "docs",
136
136
  "e2e"
@@ -160,7 +160,7 @@ Customize behaviour by creating a `version.config.json` file in your project roo
160
160
  - `paths`: Directories to search for Cargo.toml files (optional)
161
161
 
162
162
  #### Monorepo-Specific Options
163
- - `synced`: Whether all packages should be versioned together (default: true)
163
+ - `sync`: Whether all packages should be versioned together (default: true)
164
164
  - `skip`: Array of package names or patterns to exclude from versioning. Supports exact names, scope wildcards, path patterns, and global wildcards (e.g., ["@scope/package-a", "@scope/*", "packages/**/*"])
165
165
  - `packages`: Array of package names or patterns to target for versioning. Supports exact names, scope wildcards, path patterns and global wildcards (e.g., ["@scope/package-a", "@scope/*", "*"])
166
166
  - `mainPackage`: Package name whose commit history should drive version determination
@@ -234,7 +234,7 @@ This option works in conjunction with `tagTemplate` to control tag formatting. T
234
234
 
235
235
  **Examples:**
236
236
 
237
- For single-package repositories or synced monorepos:
237
+ For single-package repositories or sync monorepos:
238
238
  ```json
239
239
  {
240
240
  "packageSpecificTags": true,
@@ -253,8 +253,8 @@ For global versioning:
253
253
  Creates tags like `v1.2.3`
254
254
 
255
255
  **Important Notes:**
256
- - In **synced mode** with a single package, `packageSpecificTags: true` will use the package name even though all packages are versioned together
257
- - In **synced mode** with multiple packages, package names are not used regardless of the setting
256
+ - In **sync mode** with a single package, `packageSpecificTags: true` will use the package name even though all packages are versioned together
257
+ - In **sync mode** with multiple packages, package names are not used regardless of the setting
258
258
  - In **async mode**, each package gets its own tag when `packageSpecificTags` is enabled
259
259
 
260
260
  With package-specific tagging enabled, the tool will:
@@ -269,7 +269,7 @@ With package-specific tagging enabled, the tool will:
269
269
  1. **Conventional Commits:** Analyzes commit messages (like `feat:`, `fix:`, `BREAKING CHANGE:`) since the last tag.
270
270
  2. **Branch Pattern:** Determines the bump based on the current or recently merged branch name matching predefined patterns.
271
271
 
272
- For a detailed explanation of these concepts and monorepo modes (Synced vs. Async), see [Versioning Strategies and Concepts](./docs/versioning.md).
272
+ For a detailed explanation of these concepts and monorepo modes (Sync vs. Async), see [Versioning Strategies and Concepts](./docs/versioning.md).
273
273
 
274
274
  ## Documentation
275
275
 
package/dist/index.cjs CHANGED
@@ -472,7 +472,7 @@ function getAllVersionTags(since, versionPrefix = "v") {
472
472
  const allTags = tagOutput.split("\n").filter((tag) => !!tag);
473
473
  let filteredTags = allTags;
474
474
  if (since) {
475
- const sinceIndex = allTags.findIndex((tag) => tag === since);
475
+ const sinceIndex = allTags.indexOf(since);
476
476
  if (sinceIndex >= 0) {
477
477
  filteredTags = allTags.slice(sinceIndex);
478
478
  } else {
@@ -556,7 +556,7 @@ async function regenerateChangelog(options) {
556
556
  const allTagsCmd = `git tag --list "${versionPrefix}*" --sort=creatordate`;
557
557
  const allTagsOutput = (0, import_node_child_process2.execSync)(allTagsCmd, { encoding: "utf8" }).trim();
558
558
  const allTags = allTagsOutput.split("\n").filter((tag) => !!tag);
559
- const sinceIndex = allTags.findIndex((tag) => tag === since);
559
+ const sinceIndex = allTags.indexOf(since);
560
560
  const actualPreviousTag = sinceIndex > 0 ? allTags[sinceIndex - 1] : null;
561
561
  if (actualPreviousTag) {
562
562
  tagRange = `${actualPreviousTag}..${currentTag.tag}`;
@@ -694,8 +694,12 @@ function filterPackagesByConfig(packages, configTargets, workspaceRoot) {
694
694
  for (const target of configTargets) {
695
695
  const dirMatches = filterByDirectoryPattern(packages, target, workspaceRoot);
696
696
  const nameMatches = filterByPackageNamePattern(packages, target);
697
- dirMatches.forEach((pkg) => matchedPackages.add(pkg));
698
- nameMatches.forEach((pkg) => matchedPackages.add(pkg));
697
+ for (const pkg of dirMatches) {
698
+ matchedPackages.add(pkg);
699
+ }
700
+ for (const pkg of nameMatches) {
701
+ matchedPackages.add(pkg);
702
+ }
699
703
  }
700
704
  return Array.from(matchedPackages);
701
705
  }
@@ -1008,7 +1012,7 @@ function formatVersionPrefix(prefix) {
1008
1012
  function formatTag(version, prefix, packageName, template, packageSpecificTags) {
1009
1013
  if ((template == null ? void 0 : template.includes("${packageName}")) && !packageName) {
1010
1014
  log(
1011
- 'Warning: Your tagTemplate contains ${packageName} but no package name is available.\nThis will result in an empty package name in the tag (e.g., "@v1.0.0" instead of "my-package@v1.0.0").\n\nTo fix this:\n\u2022 If using synced mode: Set "packageSpecificTags": true in your config to enable package names in tags\n\u2022 If you want global tags: Remove ${packageName} from your tagTemplate (e.g., use "${prefix}${version}")\n\u2022 If using single/async mode: Ensure your package.json has a valid "name" field',
1015
+ 'Warning: Your tagTemplate contains ${packageName} but no package name is available.\nThis will result in an empty package name in the tag (e.g., "@v1.0.0" instead of "my-package@v1.0.0").\n\nTo fix this:\n\u2022 If using sync mode: Set "packageSpecificTags": true in your config to enable package names in tags\n\u2022 If you want global tags: Remove ${packageName} from your tagTemplate (e.g., use "${prefix}${version}")\n\u2022 If using single/async mode: Ensure your package.json has a valid "name" field',
1012
1016
  "warning"
1013
1017
  );
1014
1018
  }
@@ -1023,7 +1027,7 @@ function formatTag(version, prefix, packageName, template, packageSpecificTags)
1023
1027
  function formatCommitMessage(template, version, packageName, additionalContext) {
1024
1028
  if (template.includes("${packageName}") && !packageName) {
1025
1029
  log(
1026
- 'Warning: Your commitMessage template contains ${packageName} but no package name is available.\nThis will result in an empty package name in the commit message (e.g., "Release @v1.0.0").\n\nTo fix this:\n\u2022 If using synced mode: Set "packageSpecificTags": true to enable package names in commits\n\u2022 If you want generic commit messages: Remove ${packageName} from your commitMessage template\n\u2022 If using single/async mode: Ensure your package.json has a valid "name" field',
1030
+ 'Warning: Your commitMessage template contains ${packageName} but no package name is available.\nThis will result in an empty package name in the commit message (e.g., "Release @v1.0.0").\n\nTo fix this:\n\u2022 If using sync mode: Set "packageSpecificTags": true to enable package names in commits\n\u2022 If you want generic commit messages: Remove ${packageName} from your commitMessage template\n\u2022 If using single/async mode: Ensure your package.json has a valid "name" field',
1027
1031
  "warning"
1028
1032
  );
1029
1033
  }
@@ -1561,14 +1565,21 @@ async function calculateVersion(config, options) {
1561
1565
  const specifiedType = type;
1562
1566
  if (specifiedType) {
1563
1567
  const currentVersion = getCurrentVersionFromSource2();
1564
- if (STANDARD_BUMP_TYPES.includes(specifiedType) && (import_semver3.default.prerelease(currentVersion) || normalizedPrereleaseId)) {
1568
+ const isCurrentPrerelease = import_semver3.default.prerelease(currentVersion);
1569
+ const explicitlyRequestedPrerelease = config.isPrerelease;
1570
+ if (STANDARD_BUMP_TYPES.includes(specifiedType) && (isCurrentPrerelease || explicitlyRequestedPrerelease)) {
1571
+ const prereleaseId2 = explicitlyRequestedPrerelease || isCurrentPrerelease ? normalizedPrereleaseId : void 0;
1565
1572
  log(
1566
- normalizedPrereleaseId ? `Creating prerelease version with identifier '${normalizedPrereleaseId}' using ${specifiedType}` : `Cleaning prerelease identifier from ${currentVersion} for ${specifiedType} bump`,
1573
+ explicitlyRequestedPrerelease ? `Creating prerelease version with identifier '${prereleaseId2}' using ${specifiedType}` : `Cleaning prerelease identifier from ${currentVersion} for ${specifiedType} bump`,
1567
1574
  "debug"
1568
1575
  );
1569
- return bumpVersion(currentVersion, specifiedType, normalizedPrereleaseId);
1576
+ return bumpVersion(currentVersion, specifiedType, prereleaseId2);
1570
1577
  }
1571
- return bumpVersion(currentVersion, specifiedType, normalizedPrereleaseId);
1578
+ const isPrereleaseBumpType = ["prerelease", "premajor", "preminor", "prepatch"].includes(
1579
+ specifiedType
1580
+ );
1581
+ const prereleaseId = config.isPrerelease || isPrereleaseBumpType ? normalizedPrereleaseId : void 0;
1582
+ return bumpVersion(currentVersion, specifiedType, prereleaseId);
1572
1583
  }
1573
1584
  if (branchPattern && branchPattern.length > 0) {
1574
1585
  const currentBranch = getCurrentBranch();
@@ -1592,7 +1603,11 @@ async function calculateVersion(config, options) {
1592
1603
  if (branchVersionType) {
1593
1604
  const currentVersion = getCurrentVersionFromSource2();
1594
1605
  log(`Applying ${branchVersionType} bump based on branch pattern`, "debug");
1595
- return bumpVersion(currentVersion, branchVersionType, normalizedPrereleaseId);
1606
+ const isPrereleaseBumpType = ["prerelease", "premajor", "preminor", "prepatch"].includes(
1607
+ branchVersionType
1608
+ );
1609
+ const prereleaseId = config.isPrerelease || isPrereleaseBumpType ? normalizedPrereleaseId : void 0;
1610
+ return bumpVersion(currentVersion, branchVersionType, prereleaseId);
1596
1611
  }
1597
1612
  }
1598
1613
  try {
@@ -1628,7 +1643,11 @@ async function calculateVersion(config, options) {
1628
1643
  }
1629
1644
  return "";
1630
1645
  }
1631
- return bumpVersion(currentVersion, releaseTypeFromCommits, normalizedPrereleaseId);
1646
+ const isPrereleaseBumpType = ["prerelease", "premajor", "preminor", "prepatch"].includes(
1647
+ releaseTypeFromCommits
1648
+ );
1649
+ const prereleaseId = config.isPrerelease || isPrereleaseBumpType ? normalizedPrereleaseId : void 0;
1650
+ return bumpVersion(currentVersion, releaseTypeFromCommits, prereleaseId);
1632
1651
  } catch (error) {
1633
1652
  log(`Failed to calculate version for ${name || "project"}`, "error");
1634
1653
  console.error(error);
@@ -1978,7 +1997,7 @@ function shouldProcessPackage2(pkg, config) {
1978
1997
  const pkgName = pkg.packageJson.name;
1979
1998
  return shouldProcessPackage(pkgName, config.skip);
1980
1999
  }
1981
- function createSyncedStrategy(config) {
2000
+ function createSyncStrategy(config) {
1982
2001
  return async (packages) => {
1983
2002
  try {
1984
2003
  const {
@@ -2315,14 +2334,14 @@ function createAsyncStrategy(config) {
2315
2334
  };
2316
2335
  }
2317
2336
  function createStrategy(config) {
2318
- if (config.synced) {
2319
- return createSyncedStrategy(config);
2337
+ if (config.sync) {
2338
+ return createSyncStrategy(config);
2320
2339
  }
2321
2340
  return createAsyncStrategy(config);
2322
2341
  }
2323
2342
  function createStrategyMap(config) {
2324
2343
  return {
2325
- synced: createSyncedStrategy(config),
2344
+ sync: createSyncStrategy(config),
2326
2345
  single: createSingleStrategy(config),
2327
2346
  async: createAsyncStrategy(config)
2328
2347
  };
@@ -2331,11 +2350,10 @@ function createStrategyMap(config) {
2331
2350
  // src/core/versionEngine.ts
2332
2351
  var VersionEngine = class {
2333
2352
  config;
2334
- jsonMode;
2335
2353
  workspaceCache = null;
2336
2354
  strategies;
2337
2355
  currentStrategy;
2338
- constructor(config, jsonMode = false) {
2356
+ constructor(config, _jsonMode = false) {
2339
2357
  if (!config) {
2340
2358
  throw createVersionError("CONFIG_REQUIRED" /* CONFIG_REQUIRED */);
2341
2359
  }
@@ -2344,7 +2362,6 @@ var VersionEngine = class {
2344
2362
  log("No preset specified, using default: conventional-commits", "warning");
2345
2363
  }
2346
2364
  this.config = config;
2347
- this.jsonMode = jsonMode;
2348
2365
  this.strategies = createStrategyMap(config);
2349
2366
  this.currentStrategy = createStrategy(config);
2350
2367
  }
@@ -2425,7 +2442,7 @@ var VersionEngine = class {
2425
2442
  }
2426
2443
  /**
2427
2444
  * Change the current strategy
2428
- * @param strategyType The strategy type to use: 'synced', 'single', or 'async'
2445
+ * @param strategyType The strategy type to use: 'sync', 'single', or 'async'
2429
2446
  */
2430
2447
  setStrategy(strategyType) {
2431
2448
  this.currentStrategy = this.strategies[strategyType];
@@ -2460,7 +2477,7 @@ async function run() {
2460
2477
  program.command("version", { isDefault: true }).description("Version a package or packages based on configuration").option(
2461
2478
  "-c, --config <path>",
2462
2479
  "Path to config file (defaults to version.config.json in current directory)"
2463
- ).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").option("--project-dir <path>", "Project directory to run commands in", process.cwd()).action(async (options) => {
2480
+ ).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, --sync", "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").option("--project-dir <path>", "Project directory to run commands in", process.cwd()).action(async (options) => {
2464
2481
  if (options.json) {
2465
2482
  enableJsonOutput(options.dryRun);
2466
2483
  }
@@ -2479,20 +2496,22 @@ async function run() {
2479
2496
  const config = await loadConfig(options.config);
2480
2497
  log(`Loaded configuration from ${options.config || "version.config.json"}`, "info");
2481
2498
  if (options.dryRun) config.dryRun = true;
2482
- if (options.synced) config.synced = true;
2499
+ if (options.sync) config.sync = true;
2483
2500
  if (options.bump) config.type = options.bump;
2484
- if (options.prerelease)
2501
+ if (options.prerelease) {
2485
2502
  config.prereleaseIdentifier = options.prerelease === true ? "next" : options.prerelease;
2503
+ config.isPrerelease = true;
2504
+ }
2486
2505
  const cliTargets = options.target ? options.target.split(",").map((t) => t.trim()) : [];
2487
2506
  const engine = new VersionEngine(config, !!options.json);
2488
2507
  const pkgsResult = await engine.getWorkspacePackages();
2489
2508
  const resolvedCount = pkgsResult.packages.length;
2490
2509
  log(`Resolved ${resolvedCount} packages from workspace`, "debug");
2491
2510
  log(`Config packages: ${JSON.stringify(config.packages)}`, "debug");
2492
- log(`Config synced: ${config.synced}`, "debug");
2493
- if (config.synced) {
2494
- log("Using synced versioning strategy.", "info");
2495
- engine.setStrategy("synced");
2511
+ log(`Config sync: ${config.sync}`, "debug");
2512
+ if (config.sync) {
2513
+ log("Using sync versioning strategy.", "info");
2514
+ engine.setStrategy("sync");
2496
2515
  await engine.run(pkgsResult);
2497
2516
  } else if (resolvedCount === 1) {
2498
2517
  log("Using single package versioning strategy.", "info");
package/dist/index.js CHANGED
@@ -439,7 +439,7 @@ function getAllVersionTags(since, versionPrefix = "v") {
439
439
  const allTags = tagOutput.split("\n").filter((tag) => !!tag);
440
440
  let filteredTags = allTags;
441
441
  if (since) {
442
- const sinceIndex = allTags.findIndex((tag) => tag === since);
442
+ const sinceIndex = allTags.indexOf(since);
443
443
  if (sinceIndex >= 0) {
444
444
  filteredTags = allTags.slice(sinceIndex);
445
445
  } else {
@@ -523,7 +523,7 @@ async function regenerateChangelog(options) {
523
523
  const allTagsCmd = `git tag --list "${versionPrefix}*" --sort=creatordate`;
524
524
  const allTagsOutput = execSync2(allTagsCmd, { encoding: "utf8" }).trim();
525
525
  const allTags = allTagsOutput.split("\n").filter((tag) => !!tag);
526
- const sinceIndex = allTags.findIndex((tag) => tag === since);
526
+ const sinceIndex = allTags.indexOf(since);
527
527
  const actualPreviousTag = sinceIndex > 0 ? allTags[sinceIndex - 1] : null;
528
528
  if (actualPreviousTag) {
529
529
  tagRange = `${actualPreviousTag}..${currentTag.tag}`;
@@ -661,8 +661,12 @@ function filterPackagesByConfig(packages, configTargets, workspaceRoot) {
661
661
  for (const target of configTargets) {
662
662
  const dirMatches = filterByDirectoryPattern(packages, target, workspaceRoot);
663
663
  const nameMatches = filterByPackageNamePattern(packages, target);
664
- dirMatches.forEach((pkg) => matchedPackages.add(pkg));
665
- nameMatches.forEach((pkg) => matchedPackages.add(pkg));
664
+ for (const pkg of dirMatches) {
665
+ matchedPackages.add(pkg);
666
+ }
667
+ for (const pkg of nameMatches) {
668
+ matchedPackages.add(pkg);
669
+ }
666
670
  }
667
671
  return Array.from(matchedPackages);
668
672
  }
@@ -975,7 +979,7 @@ function formatVersionPrefix(prefix) {
975
979
  function formatTag(version, prefix, packageName, template, packageSpecificTags) {
976
980
  if ((template == null ? void 0 : template.includes("${packageName}")) && !packageName) {
977
981
  log(
978
- 'Warning: Your tagTemplate contains ${packageName} but no package name is available.\nThis will result in an empty package name in the tag (e.g., "@v1.0.0" instead of "my-package@v1.0.0").\n\nTo fix this:\n\u2022 If using synced mode: Set "packageSpecificTags": true in your config to enable package names in tags\n\u2022 If you want global tags: Remove ${packageName} from your tagTemplate (e.g., use "${prefix}${version}")\n\u2022 If using single/async mode: Ensure your package.json has a valid "name" field',
982
+ 'Warning: Your tagTemplate contains ${packageName} but no package name is available.\nThis will result in an empty package name in the tag (e.g., "@v1.0.0" instead of "my-package@v1.0.0").\n\nTo fix this:\n\u2022 If using sync mode: Set "packageSpecificTags": true in your config to enable package names in tags\n\u2022 If you want global tags: Remove ${packageName} from your tagTemplate (e.g., use "${prefix}${version}")\n\u2022 If using single/async mode: Ensure your package.json has a valid "name" field',
979
983
  "warning"
980
984
  );
981
985
  }
@@ -990,7 +994,7 @@ function formatTag(version, prefix, packageName, template, packageSpecificTags)
990
994
  function formatCommitMessage(template, version, packageName, additionalContext) {
991
995
  if (template.includes("${packageName}") && !packageName) {
992
996
  log(
993
- 'Warning: Your commitMessage template contains ${packageName} but no package name is available.\nThis will result in an empty package name in the commit message (e.g., "Release @v1.0.0").\n\nTo fix this:\n\u2022 If using synced mode: Set "packageSpecificTags": true to enable package names in commits\n\u2022 If you want generic commit messages: Remove ${packageName} from your commitMessage template\n\u2022 If using single/async mode: Ensure your package.json has a valid "name" field',
997
+ 'Warning: Your commitMessage template contains ${packageName} but no package name is available.\nThis will result in an empty package name in the commit message (e.g., "Release @v1.0.0").\n\nTo fix this:\n\u2022 If using sync mode: Set "packageSpecificTags": true to enable package names in commits\n\u2022 If you want generic commit messages: Remove ${packageName} from your commitMessage template\n\u2022 If using single/async mode: Ensure your package.json has a valid "name" field',
994
998
  "warning"
995
999
  );
996
1000
  }
@@ -1528,14 +1532,21 @@ async function calculateVersion(config, options) {
1528
1532
  const specifiedType = type;
1529
1533
  if (specifiedType) {
1530
1534
  const currentVersion = getCurrentVersionFromSource2();
1531
- if (STANDARD_BUMP_TYPES.includes(specifiedType) && (semver3.prerelease(currentVersion) || normalizedPrereleaseId)) {
1535
+ const isCurrentPrerelease = semver3.prerelease(currentVersion);
1536
+ const explicitlyRequestedPrerelease = config.isPrerelease;
1537
+ if (STANDARD_BUMP_TYPES.includes(specifiedType) && (isCurrentPrerelease || explicitlyRequestedPrerelease)) {
1538
+ const prereleaseId2 = explicitlyRequestedPrerelease || isCurrentPrerelease ? normalizedPrereleaseId : void 0;
1532
1539
  log(
1533
- normalizedPrereleaseId ? `Creating prerelease version with identifier '${normalizedPrereleaseId}' using ${specifiedType}` : `Cleaning prerelease identifier from ${currentVersion} for ${specifiedType} bump`,
1540
+ explicitlyRequestedPrerelease ? `Creating prerelease version with identifier '${prereleaseId2}' using ${specifiedType}` : `Cleaning prerelease identifier from ${currentVersion} for ${specifiedType} bump`,
1534
1541
  "debug"
1535
1542
  );
1536
- return bumpVersion(currentVersion, specifiedType, normalizedPrereleaseId);
1543
+ return bumpVersion(currentVersion, specifiedType, prereleaseId2);
1537
1544
  }
1538
- return bumpVersion(currentVersion, specifiedType, normalizedPrereleaseId);
1545
+ const isPrereleaseBumpType = ["prerelease", "premajor", "preminor", "prepatch"].includes(
1546
+ specifiedType
1547
+ );
1548
+ const prereleaseId = config.isPrerelease || isPrereleaseBumpType ? normalizedPrereleaseId : void 0;
1549
+ return bumpVersion(currentVersion, specifiedType, prereleaseId);
1539
1550
  }
1540
1551
  if (branchPattern && branchPattern.length > 0) {
1541
1552
  const currentBranch = getCurrentBranch();
@@ -1559,7 +1570,11 @@ async function calculateVersion(config, options) {
1559
1570
  if (branchVersionType) {
1560
1571
  const currentVersion = getCurrentVersionFromSource2();
1561
1572
  log(`Applying ${branchVersionType} bump based on branch pattern`, "debug");
1562
- return bumpVersion(currentVersion, branchVersionType, normalizedPrereleaseId);
1573
+ const isPrereleaseBumpType = ["prerelease", "premajor", "preminor", "prepatch"].includes(
1574
+ branchVersionType
1575
+ );
1576
+ const prereleaseId = config.isPrerelease || isPrereleaseBumpType ? normalizedPrereleaseId : void 0;
1577
+ return bumpVersion(currentVersion, branchVersionType, prereleaseId);
1563
1578
  }
1564
1579
  }
1565
1580
  try {
@@ -1595,7 +1610,11 @@ async function calculateVersion(config, options) {
1595
1610
  }
1596
1611
  return "";
1597
1612
  }
1598
- return bumpVersion(currentVersion, releaseTypeFromCommits, normalizedPrereleaseId);
1613
+ const isPrereleaseBumpType = ["prerelease", "premajor", "preminor", "prepatch"].includes(
1614
+ releaseTypeFromCommits
1615
+ );
1616
+ const prereleaseId = config.isPrerelease || isPrereleaseBumpType ? normalizedPrereleaseId : void 0;
1617
+ return bumpVersion(currentVersion, releaseTypeFromCommits, prereleaseId);
1599
1618
  } catch (error) {
1600
1619
  log(`Failed to calculate version for ${name || "project"}`, "error");
1601
1620
  console.error(error);
@@ -1945,7 +1964,7 @@ function shouldProcessPackage2(pkg, config) {
1945
1964
  const pkgName = pkg.packageJson.name;
1946
1965
  return shouldProcessPackage(pkgName, config.skip);
1947
1966
  }
1948
- function createSyncedStrategy(config) {
1967
+ function createSyncStrategy(config) {
1949
1968
  return async (packages) => {
1950
1969
  try {
1951
1970
  const {
@@ -2282,14 +2301,14 @@ function createAsyncStrategy(config) {
2282
2301
  };
2283
2302
  }
2284
2303
  function createStrategy(config) {
2285
- if (config.synced) {
2286
- return createSyncedStrategy(config);
2304
+ if (config.sync) {
2305
+ return createSyncStrategy(config);
2287
2306
  }
2288
2307
  return createAsyncStrategy(config);
2289
2308
  }
2290
2309
  function createStrategyMap(config) {
2291
2310
  return {
2292
- synced: createSyncedStrategy(config),
2311
+ sync: createSyncStrategy(config),
2293
2312
  single: createSingleStrategy(config),
2294
2313
  async: createAsyncStrategy(config)
2295
2314
  };
@@ -2298,11 +2317,10 @@ function createStrategyMap(config) {
2298
2317
  // src/core/versionEngine.ts
2299
2318
  var VersionEngine = class {
2300
2319
  config;
2301
- jsonMode;
2302
2320
  workspaceCache = null;
2303
2321
  strategies;
2304
2322
  currentStrategy;
2305
- constructor(config, jsonMode = false) {
2323
+ constructor(config, _jsonMode = false) {
2306
2324
  if (!config) {
2307
2325
  throw createVersionError("CONFIG_REQUIRED" /* CONFIG_REQUIRED */);
2308
2326
  }
@@ -2311,7 +2329,6 @@ var VersionEngine = class {
2311
2329
  log("No preset specified, using default: conventional-commits", "warning");
2312
2330
  }
2313
2331
  this.config = config;
2314
- this.jsonMode = jsonMode;
2315
2332
  this.strategies = createStrategyMap(config);
2316
2333
  this.currentStrategy = createStrategy(config);
2317
2334
  }
@@ -2392,7 +2409,7 @@ var VersionEngine = class {
2392
2409
  }
2393
2410
  /**
2394
2411
  * Change the current strategy
2395
- * @param strategyType The strategy type to use: 'synced', 'single', or 'async'
2412
+ * @param strategyType The strategy type to use: 'sync', 'single', or 'async'
2396
2413
  */
2397
2414
  setStrategy(strategyType) {
2398
2415
  this.currentStrategy = this.strategies[strategyType];
@@ -2426,7 +2443,7 @@ async function run() {
2426
2443
  program.command("version", { isDefault: true }).description("Version a package or packages based on configuration").option(
2427
2444
  "-c, --config <path>",
2428
2445
  "Path to config file (defaults to version.config.json in current directory)"
2429
- ).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").option("--project-dir <path>", "Project directory to run commands in", process.cwd()).action(async (options) => {
2446
+ ).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, --sync", "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").option("--project-dir <path>", "Project directory to run commands in", process.cwd()).action(async (options) => {
2430
2447
  if (options.json) {
2431
2448
  enableJsonOutput(options.dryRun);
2432
2449
  }
@@ -2445,20 +2462,22 @@ async function run() {
2445
2462
  const config = await loadConfig(options.config);
2446
2463
  log(`Loaded configuration from ${options.config || "version.config.json"}`, "info");
2447
2464
  if (options.dryRun) config.dryRun = true;
2448
- if (options.synced) config.synced = true;
2465
+ if (options.sync) config.sync = true;
2449
2466
  if (options.bump) config.type = options.bump;
2450
- if (options.prerelease)
2467
+ if (options.prerelease) {
2451
2468
  config.prereleaseIdentifier = options.prerelease === true ? "next" : options.prerelease;
2469
+ config.isPrerelease = true;
2470
+ }
2452
2471
  const cliTargets = options.target ? options.target.split(",").map((t) => t.trim()) : [];
2453
2472
  const engine = new VersionEngine(config, !!options.json);
2454
2473
  const pkgsResult = await engine.getWorkspacePackages();
2455
2474
  const resolvedCount = pkgsResult.packages.length;
2456
2475
  log(`Resolved ${resolvedCount} packages from workspace`, "debug");
2457
2476
  log(`Config packages: ${JSON.stringify(config.packages)}`, "debug");
2458
- log(`Config synced: ${config.synced}`, "debug");
2459
- if (config.synced) {
2460
- log("Using synced versioning strategy.", "info");
2461
- engine.setStrategy("synced");
2477
+ log(`Config sync: ${config.sync}`, "debug");
2478
+ if (config.sync) {
2479
+ log("Using sync versioning strategy.", "info");
2480
+ engine.setStrategy("sync");
2462
2481
  await engine.run(pkgsResult);
2463
2482
  } else if (resolvedCount === 1) {
2464
2483
  log("Using single package versioning strategy.", "info");
@@ -334,7 +334,7 @@ Warning: Your tagTemplate contains ${packageName} but no package name is availab
334
334
  This will result in an empty package name in the tag (e.g., "@v1.0.0" instead of "my-package@v1.0.0").
335
335
 
336
336
  To fix this:
337
- • If using synced mode: Set "packageSpecificTags": true in your config to enable package names in tags
337
+ • If using sync mode: Set "packageSpecificTags": true in your config to enable package names in tags
338
338
  • If you want global tags: Remove ${packageName} from your tagTemplate (e.g., use "${prefix}${version}")
339
339
  • If using single/async mode: Ensure your package.json has a valid "name" field
340
340
  ```
@@ -344,7 +344,7 @@ To fix this:
344
344
  1. **For Synced Mode with Package Names**: Enable package-specific tags
345
345
  ```json
346
346
  {
347
- "synced": true,
347
+ "sync": true,
348
348
  "packageSpecificTags": true,
349
349
  "tagTemplate": "${packageName}@${prefix}${version}"
350
350
  }
@@ -397,11 +397,11 @@ For global commit messages, use templates without `${packageName}`:
397
397
 
398
398
  ## Monorepo Versioning Modes
399
399
 
400
- While primarily used for single packages now, `package-versioner` retains options for monorepo workflows, controlled mainly by the `synced` flag in `version.config.json`.
400
+ While primarily used for single packages now, `package-versioner` retains options for monorepo workflows, controlled mainly by the `sync` flag in `version.config.json`.
401
401
 
402
- ### Synced Mode (`synced: true`)
402
+ ### Sync Mode (`sync: true`)
403
403
 
404
- This is the default if the `synced` flag is present and true.
404
+ This is the default if the `sync` flag is present and true.
405
405
 
406
406
  - **Behaviour:** The tool calculates **one** version bump based on the overall history (or branch pattern). This single new version is applied to **all** packages within the repository (or just the root `package.json` if not a structured monorepo). A single Git tag is created.
407
407
  - **Tag Behaviour:**
@@ -409,7 +409,7 @@ This is the default if the `synced` flag is present and true.
409
409
  - In **single-package repositories**: Respects the `packageSpecificTags` setting - can create either `v1.2.3` or `package-name@v1.2.3`
410
410
  - **Use Case:** Suitable for monorepos where all packages are tightly coupled and released together with the same version number. Also the effective mode for single-package repositories.
411
411
 
412
- ### Async Mode (`synced: false`)
412
+ ### Async Mode (`sync: false`)
413
413
 
414
414
  *(Note: This mode relies heavily on monorepo tooling and structure, like `pnpm workspaces` and correctly configured package dependencies.)*
415
415
 
@@ -41,7 +41,7 @@
41
41
  "description": "The main branch for versioning",
42
42
  "default": "main"
43
43
  },
44
- "synced": {
44
+ "sync": {
45
45
  "type": "boolean",
46
46
  "default": false,
47
47
  "description": "Whether packages should be versioned together"
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.8.5",
4
+ "version": "0.9.1",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
7
7
  "module": "./dist/index.mjs",
@@ -37,34 +37,34 @@
37
37
  ]
38
38
  },
39
39
  "devDependencies": {
40
- "@biomejs/biome": "^2.0.6",
40
+ "@biomejs/biome": "^2.2.2",
41
41
  "@types/figlet": "^1.5.5",
42
- "@types/node": "^24.0.10",
42
+ "@types/node": "^24.3.0",
43
43
  "@types/semver": "^7.3.13",
44
44
  "@vitest/coverage-v8": "^3.2.4",
45
- "cross-env": "^7.0.3",
45
+ "cross-env": "^10.0.0",
46
46
  "husky": "^9.1.7",
47
- "lint-staged": "^16.1.2",
47
+ "lint-staged": "^16.1.5",
48
48
  "tsup": "^8.5.0",
49
- "tsx": "^4.20.3",
50
- "typescript": "^5.8.3",
49
+ "tsx": "^4.20.5",
50
+ "typescript": "^5.9.2",
51
51
  "vitest": "^3.2.4"
52
52
  },
53
53
  "dependencies": {
54
- "@manypkg/get-packages": "^3.0.0",
54
+ "@manypkg/get-packages": "^3.1.0",
55
55
  "@types/micromatch": "^4.0.9",
56
- "chalk": "^5.4.1",
56
+ "chalk": "^5.6.0",
57
57
  "commander": "^14.0.0",
58
58
  "conventional-changelog-angular": "^8.0.0",
59
59
  "conventional-changelog-conventional-commits": "npm:conventional-changelog-conventionalcommits@^9.0.0",
60
- "conventional-changelog-conventionalcommits": "^9.0.0",
60
+ "conventional-changelog-conventionalcommits": "^9.1.0",
61
61
  "conventional-commits-filter": "^5.0.0",
62
62
  "conventional-recommended-bump": "^11.2.0",
63
- "figlet": "^1.8.1",
63
+ "figlet": "^1.8.2",
64
64
  "git-semver-tags": "^8.0.0",
65
65
  "micromatch": "^4.0.8",
66
66
  "semver": "^7.7.2",
67
- "smol-toml": "^1.4.1"
67
+ "smol-toml": "^1.4.2"
68
68
  },
69
69
  "scripts": {
70
70
  "build": "tsup src/index.ts --format esm,cjs --dts",