@codluv/versionguard 0.3.0 → 0.4.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.
Files changed (42) hide show
  1. package/dist/calver.d.ts +65 -22
  2. package/dist/calver.d.ts.map +1 -1
  3. package/dist/chunks/{index-BrZJDWya.js → index-B3R60bYJ.js} +451 -151
  4. package/dist/chunks/index-B3R60bYJ.js.map +1 -0
  5. package/dist/cli.d.ts.map +1 -1
  6. package/dist/cli.js +248 -25
  7. package/dist/cli.js.map +1 -1
  8. package/dist/config.d.ts.map +1 -1
  9. package/dist/feedback/index.d.ts +1 -1
  10. package/dist/feedback/index.d.ts.map +1 -1
  11. package/dist/fix/index.d.ts +6 -1
  12. package/dist/fix/index.d.ts.map +1 -1
  13. package/dist/guard.d.ts +45 -1
  14. package/dist/guard.d.ts.map +1 -1
  15. package/dist/index.d.ts +1 -1
  16. package/dist/index.d.ts.map +1 -1
  17. package/dist/index.js +14 -13
  18. package/dist/init-wizard.d.ts +49 -0
  19. package/dist/init-wizard.d.ts.map +1 -0
  20. package/dist/project.d.ts +23 -2
  21. package/dist/project.d.ts.map +1 -1
  22. package/dist/sources/git-tag.d.ts +29 -0
  23. package/dist/sources/git-tag.d.ts.map +1 -1
  24. package/dist/sources/json.d.ts +31 -0
  25. package/dist/sources/json.d.ts.map +1 -1
  26. package/dist/sources/regex.d.ts +30 -0
  27. package/dist/sources/regex.d.ts.map +1 -1
  28. package/dist/sources/resolve.d.ts +27 -8
  29. package/dist/sources/resolve.d.ts.map +1 -1
  30. package/dist/sources/toml.d.ts +36 -1
  31. package/dist/sources/toml.d.ts.map +1 -1
  32. package/dist/sources/utils.d.ts +73 -0
  33. package/dist/sources/utils.d.ts.map +1 -0
  34. package/dist/sources/version-file.d.ts +28 -1
  35. package/dist/sources/version-file.d.ts.map +1 -1
  36. package/dist/sources/yaml.d.ts +29 -0
  37. package/dist/sources/yaml.d.ts.map +1 -1
  38. package/dist/tag/index.d.ts.map +1 -1
  39. package/dist/types.d.ts +89 -4
  40. package/dist/types.d.ts.map +1 -1
  41. package/package.json +2 -1
  42. package/dist/chunks/index-BrZJDWya.js.map +0 -1
@@ -6,38 +6,83 @@ import { parse as parse$2 } from "smol-toml";
6
6
  import * as yaml from "js-yaml";
7
7
  import { globSync } from "glob";
8
8
  import { fileURLToPath } from "node:url";
9
+ const VALID_TOKENS = /* @__PURE__ */ new Set([
10
+ "YYYY",
11
+ "YY",
12
+ "0Y",
13
+ "MM",
14
+ "M",
15
+ "0M",
16
+ "WW",
17
+ "0W",
18
+ "DD",
19
+ "D",
20
+ "0D",
21
+ "MICRO",
22
+ "PATCH"
23
+ ]);
24
+ const YEAR_TOKENS = /* @__PURE__ */ new Set(["YYYY", "YY", "0Y"]);
25
+ const MONTH_TOKENS = /* @__PURE__ */ new Set(["MM", "M", "0M"]);
26
+ const WEEK_TOKENS = /* @__PURE__ */ new Set(["WW", "0W"]);
27
+ const DAY_TOKENS = /* @__PURE__ */ new Set(["DD", "D", "0D"]);
28
+ const COUNTER_TOKENS = /* @__PURE__ */ new Set(["MICRO", "PATCH"]);
29
+ function isValidCalVerFormat(formatStr) {
30
+ const tokens = formatStr.split(".");
31
+ if (tokens.length < 2) return false;
32
+ if (!tokens.every((t) => VALID_TOKENS.has(t))) return false;
33
+ if (!YEAR_TOKENS.has(tokens[0])) return false;
34
+ const hasWeek = tokens.some((t) => WEEK_TOKENS.has(t));
35
+ const hasMonthOrDay = tokens.some((t) => MONTH_TOKENS.has(t) || DAY_TOKENS.has(t));
36
+ if (hasWeek && hasMonthOrDay) return false;
37
+ const counterIndex = tokens.findIndex((t) => COUNTER_TOKENS.has(t));
38
+ if (counterIndex !== -1 && counterIndex !== tokens.length - 1) return false;
39
+ return true;
40
+ }
9
41
  function parseFormat(calverFormat) {
10
- const parts = calverFormat.split(".");
42
+ const tokens = calverFormat.split(".");
11
43
  const result = {
12
- year: parts[0],
13
- month: parts[1]
44
+ year: tokens[0]
14
45
  };
15
- if (parts[2] === "PATCH") {
16
- result.patch = "PATCH";
17
- } else if (parts[2]) {
18
- result.day = parts[2];
19
- }
20
- if (parts[3] === "PATCH") {
21
- result.patch = "PATCH";
46
+ for (let i = 1; i < tokens.length; i++) {
47
+ const token = tokens[i];
48
+ if (MONTH_TOKENS.has(token)) {
49
+ result.month = token;
50
+ } else if (WEEK_TOKENS.has(token)) {
51
+ result.week = token;
52
+ } else if (DAY_TOKENS.has(token)) {
53
+ result.day = token;
54
+ } else if (COUNTER_TOKENS.has(token)) {
55
+ result.counter = token;
56
+ }
22
57
  }
23
58
  return result;
24
59
  }
60
+ const MODIFIER_PATTERN = "(?:-([0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*))?";
25
61
  function tokenPattern(token) {
26
62
  switch (token) {
27
63
  case "YYYY":
28
- return "(\\d{4})";
64
+ return "([1-9]\\d{3})";
29
65
  case "YY":
30
- return "(\\d{2})";
31
- case "0M":
32
- case "0D":
33
- return "(\\d{2})";
66
+ return "(\\d{1,3})";
67
+ case "0Y":
68
+ return "(\\d{2,3})";
34
69
  case "MM":
35
- case "DD":
36
70
  case "M":
71
+ return "([1-9]|1[0-2])";
72
+ case "0M":
73
+ return "(0[1-9]|1[0-2])";
74
+ case "WW":
75
+ return "([1-9]|[1-4]\\d|5[0-3])";
76
+ case "0W":
77
+ return "(0[1-9]|[1-4]\\d|5[0-3])";
78
+ case "DD":
37
79
  case "D":
38
- return "(\\d{1,2})";
80
+ return "([1-9]|[12]\\d|3[01])";
81
+ case "0D":
82
+ return "(0[1-9]|[12]\\d|3[01])";
83
+ case "MICRO":
39
84
  case "PATCH":
40
- return "(\\d+)";
85
+ return "(0|[1-9]\\d*)";
41
86
  default:
42
87
  throw new Error(`Unsupported CalVer token: ${token}`);
43
88
  }
@@ -45,7 +90,7 @@ function tokenPattern(token) {
45
90
  function getRegexForFormat(calverFormat) {
46
91
  const tokens = calverFormat.split(".");
47
92
  const pattern = tokens.map(tokenPattern).join("\\.");
48
- return new RegExp(`^${pattern}$`);
93
+ return new RegExp(`^${pattern}${MODIFIER_PATTERN}$`);
49
94
  }
50
95
  function parse$1(version, calverFormat) {
51
96
  const match = version.match(getRegexForFormat(calverFormat));
@@ -53,28 +98,44 @@ function parse$1(version, calverFormat) {
53
98
  return null;
54
99
  }
55
100
  const definition = parseFormat(calverFormat);
56
- const year = definition.year === "YYYY" ? Number.parseInt(match[1], 10) : 2e3 + Number.parseInt(match[1], 10);
57
- const month = Number.parseInt(match[2], 10);
58
- let cursor = 3;
101
+ const yearToken = definition.year;
102
+ let year = Number.parseInt(match[1], 10);
103
+ if (yearToken === "YY" || yearToken === "0Y") {
104
+ year = 2e3 + year;
105
+ }
106
+ let cursor = 2;
107
+ let month;
59
108
  let day;
60
109
  let patch;
110
+ if (definition.month) {
111
+ month = Number.parseInt(match[cursor], 10);
112
+ cursor += 1;
113
+ }
114
+ if (definition.week) {
115
+ month = Number.parseInt(match[cursor], 10);
116
+ cursor += 1;
117
+ }
61
118
  if (definition.day) {
62
119
  day = Number.parseInt(match[cursor], 10);
63
120
  cursor += 1;
64
121
  }
65
- if (definition.patch) {
122
+ if (definition.counter) {
66
123
  patch = Number.parseInt(match[cursor], 10);
124
+ cursor += 1;
67
125
  }
126
+ const modifierGroup = match[cursor];
127
+ const modifier = modifierGroup || void 0;
68
128
  return {
69
129
  year,
70
- month,
130
+ month: month ?? 1,
71
131
  day,
72
132
  patch,
133
+ modifier,
73
134
  format: calverFormat,
74
135
  raw: version
75
136
  };
76
137
  }
77
- function validate$2(version, calverFormat, preventFutureDates = true) {
138
+ function validate$2(version, calverFormat, preventFutureDates = true, schemeRules) {
78
139
  const errors = [];
79
140
  const parsed = parse$1(version, calverFormat);
80
141
  if (!parsed) {
@@ -88,19 +149,26 @@ function validate$2(version, calverFormat, preventFutureDates = true) {
88
149
  ]
89
150
  };
90
151
  }
91
- if (parsed.month < 1 || parsed.month > 12) {
152
+ const definition = parseFormat(calverFormat);
153
+ if (definition.month && (parsed.month < 1 || parsed.month > 12)) {
92
154
  errors.push({
93
155
  message: `Invalid month: ${parsed.month}. Must be between 1 and 12.`,
94
156
  severity: "error"
95
157
  });
96
158
  }
159
+ if (definition.week && (parsed.month < 1 || parsed.month > 53)) {
160
+ errors.push({
161
+ message: `Invalid week: ${parsed.month}. Must be between 1 and 53.`,
162
+ severity: "error"
163
+ });
164
+ }
97
165
  if (parsed.day !== void 0) {
98
166
  if (parsed.day < 1 || parsed.day > 31) {
99
167
  errors.push({
100
168
  message: `Invalid day: ${parsed.day}. Must be between 1 and 31.`,
101
169
  severity: "error"
102
170
  });
103
- } else {
171
+ } else if (definition.month) {
104
172
  const daysInMonth = new Date(parsed.year, parsed.month, 0).getDate();
105
173
  if (parsed.day > daysInMonth) {
106
174
  errors.push({
@@ -120,56 +188,83 @@ function validate$2(version, calverFormat, preventFutureDates = true) {
120
188
  message: `Future year not allowed: ${parsed.year}. Current year is ${currentYear}.`,
121
189
  severity: "error"
122
190
  });
123
- } else if (parsed.year === currentYear && parsed.month > currentMonth) {
191
+ } else if (definition.month && parsed.year === currentYear && parsed.month > currentMonth) {
124
192
  errors.push({
125
193
  message: `Future month not allowed: ${parsed.year}.${parsed.month}. Current month is ${currentMonth}.`,
126
194
  severity: "error"
127
195
  });
128
- } else if (parsed.year === currentYear && parsed.month === currentMonth && parsed.day !== void 0 && parsed.day > currentDay) {
196
+ } else if (definition.month && parsed.year === currentYear && parsed.month === currentMonth && parsed.day !== void 0 && parsed.day > currentDay) {
129
197
  errors.push({
130
198
  message: `Future day not allowed: ${parsed.year}.${parsed.month}.${parsed.day}. Current day is ${currentDay}.`,
131
199
  severity: "error"
132
200
  });
133
201
  }
134
202
  }
203
+ if (parsed.modifier && schemeRules?.allowedModifiers) {
204
+ const baseModifier = parsed.modifier.replace(/[\d.]+$/, "") || parsed.modifier;
205
+ if (!schemeRules.allowedModifiers.includes(baseModifier)) {
206
+ errors.push({
207
+ message: `Modifier "${parsed.modifier}" is not allowed. Allowed: ${schemeRules.allowedModifiers.join(", ")}`,
208
+ severity: "error"
209
+ });
210
+ }
211
+ }
212
+ if (schemeRules?.maxNumericSegments) {
213
+ const segmentCount = calverFormat.split(".").length;
214
+ if (segmentCount > schemeRules.maxNumericSegments) {
215
+ errors.push({
216
+ message: `Format has ${segmentCount} segments, convention recommends ${schemeRules.maxNumericSegments} or fewer`,
217
+ severity: "warning"
218
+ });
219
+ }
220
+ }
135
221
  return {
136
- valid: errors.length === 0,
222
+ valid: errors.filter((e) => e.severity === "error").length === 0,
137
223
  errors,
138
224
  version: { type: "calver", version: parsed }
139
225
  };
140
226
  }
141
227
  function formatToken(token, value) {
142
- if (token === "0M" || token === "0D") {
143
- return String(value).padStart(2, "0");
144
- }
145
- if (token === "YY") {
146
- return String(value % 100).padStart(2, "0");
228
+ switch (token) {
229
+ case "0M":
230
+ case "0D":
231
+ case "0W":
232
+ case "0Y":
233
+ return String(token === "0Y" ? value % 100 : value).padStart(2, "0");
234
+ case "YY":
235
+ return String(value % 100).padStart(2, "0");
236
+ default:
237
+ return String(value);
147
238
  }
148
- return String(value);
149
239
  }
150
240
  function format$1(version) {
151
- const tokens = version.format.split(".");
152
- const values = [version.year, version.month];
153
- if (tokens.includes("DD") || tokens.includes("D") || tokens.includes("0D")) {
154
- values.push(version.day ?? 1);
241
+ const definition = parseFormat(version.format);
242
+ const parts = [formatToken(definition.year, version.year)];
243
+ if (definition.month) {
244
+ parts.push(formatToken(definition.month, version.month));
155
245
  }
156
- if (tokens.includes("PATCH")) {
157
- values.push(version.patch ?? 0);
246
+ if (definition.week) {
247
+ parts.push(formatToken(definition.week, version.month));
158
248
  }
159
- return tokens.map((token, index) => formatToken(token, values[index])).join(".");
249
+ if (definition.day) {
250
+ parts.push(formatToken(definition.day, version.day ?? 1));
251
+ }
252
+ if (definition.counter) {
253
+ parts.push(formatToken(definition.counter, version.patch ?? 0));
254
+ }
255
+ const base = parts.join(".");
256
+ return version.modifier ? `${base}-${version.modifier}` : base;
160
257
  }
161
258
  function getCurrentVersion(calverFormat, now = /* @__PURE__ */ new Date()) {
162
259
  const definition = parseFormat(calverFormat);
163
- const currentDay = now.getDate();
164
260
  const base = {
165
261
  year: now.getFullYear(),
166
262
  month: now.getMonth() + 1,
167
- day: definition.day ? currentDay : void 0,
168
- patch: definition.patch ? 0 : void 0
263
+ day: definition.day ? now.getDate() : void 0,
264
+ patch: definition.counter ? 0 : void 0,
265
+ format: calverFormat
169
266
  };
170
- const day = base.day ?? currentDay;
171
- const patch = base.patch ?? 0;
172
- return formatToken(definition.year, base.year).concat(`.${formatToken(definition.month, base.month)}`).concat(definition.day ? `.${formatToken(definition.day, day)}` : "").concat(definition.patch ? `.${patch}` : "");
267
+ return format$1(base);
173
268
  }
174
269
  function compare$1(a, b, calverFormat) {
175
270
  const left = parse$1(a, calverFormat);
@@ -195,12 +290,11 @@ function increment$1(version, calverFormat) {
195
290
  const next = {
196
291
  ...parsed
197
292
  };
198
- if (definition.patch) {
199
- const patch = parsed.patch ?? 0;
200
- next.patch = patch + 1;
293
+ if (definition.counter) {
294
+ next.patch = (parsed.patch ?? 0) + 1;
201
295
  } else {
202
296
  next.patch = 0;
203
- next.format = `${calverFormat}.PATCH`;
297
+ next.format = `${calverFormat}.MICRO`;
204
298
  }
205
299
  return format$1(next);
206
300
  }
@@ -215,6 +309,7 @@ const calver = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProper
215
309
  getNextVersions,
216
310
  getRegexForFormat,
217
311
  increment: increment$1,
312
+ isValidCalVerFormat,
218
313
  parse: parse$1,
219
314
  parseFormat,
220
315
  validate: validate$2
@@ -246,7 +341,7 @@ function validateChangelog(changelogPath, version, strict = true, requireEntry =
246
341
  errors.push("Changelog should include compare links at the bottom");
247
342
  }
248
343
  const versionHeaderMatch = content.match(
249
- new RegExp(`## \\[${escapeRegExp$2(version)}\\] - ([^\r
344
+ new RegExp(`## \\[${escapeRegExp$1(version)}\\] - ([^\r
250
345
  ]+)`)
251
346
  );
252
347
  if (requireEntry && hasEntryForVersion) {
@@ -286,7 +381,7 @@ function addVersionEntry(changelogPath, version, date = (/* @__PURE__ */ new Dat
286
381
  const updated = `${content.slice(0, insertIndex)}${block}${content.slice(insertIndex)}`;
287
382
  fs.writeFileSync(changelogPath, updated, "utf-8");
288
383
  }
289
- function escapeRegExp$2(value) {
384
+ function escapeRegExp$1(value) {
290
385
  return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
291
386
  }
292
387
  const HOOK_NAMES$1 = ["pre-commit", "pre-push", "post-tag"];
@@ -356,8 +451,16 @@ fi
356
451
  `;
357
452
  }
358
453
  class GitTagSource {
454
+ /** Human-readable provider name. */
359
455
  name = "git-tag";
456
+ /** Empty string since git-tag has no manifest file. */
360
457
  manifestFile = "";
458
+ /**
459
+ * Returns `true` when `cwd` is inside a Git repository.
460
+ *
461
+ * @param cwd - Project directory to check.
462
+ * @returns Whether a Git repository is found.
463
+ */
361
464
  exists(cwd) {
362
465
  try {
363
466
  execFileSync("git", ["rev-parse", "--git-dir"], {
@@ -369,87 +472,167 @@ class GitTagSource {
369
472
  return false;
370
473
  }
371
474
  }
475
+ /**
476
+ * Reads the version string from the latest Git tag.
477
+ *
478
+ * @param cwd - Project directory containing the Git repository.
479
+ * @returns The version string extracted from the latest version tag.
480
+ */
372
481
  getVersion(cwd) {
373
482
  try {
374
- const tag = execFileSync("git", ["describe", "--tags", "--abbrev=0"], {
375
- cwd,
376
- encoding: "utf-8",
377
- stdio: ["pipe", "pipe", "ignore"]
378
- }).trim();
483
+ const tag = this.describeVersionTag(cwd);
379
484
  return tag.replace(/^v/, "");
380
485
  } catch {
381
- throw new Error("No git tags found. Create a tag first (e.g., git tag v0.1.0)");
486
+ throw new Error("No version tags found. Create a tag first (e.g., git tag v0.1.0)");
382
487
  }
383
488
  }
489
+ /**
490
+ * Creates a new annotated Git tag for the given version.
491
+ *
492
+ * @param version - Version string to tag.
493
+ * @param cwd - Project directory containing the Git repository.
494
+ */
384
495
  setVersion(version, cwd) {
385
- const tagName = `v${version}`;
496
+ const prefix = this.detectPrefix(cwd);
497
+ const tagName = `${prefix}${version}`;
386
498
  execFileSync("git", ["tag", "-a", tagName, "-m", `Release ${version}`], {
387
499
  cwd,
388
500
  stdio: ["pipe", "pipe", "ignore"]
389
501
  });
390
502
  }
503
+ /** Try version-like tag patterns, fall back to any tag. */
504
+ describeVersionTag(cwd) {
505
+ try {
506
+ return execFileSync("git", ["describe", "--tags", "--abbrev=0", "--match", "v[0-9]*"], {
507
+ cwd,
508
+ encoding: "utf-8",
509
+ stdio: ["pipe", "pipe", "ignore"]
510
+ }).trim();
511
+ } catch {
512
+ }
513
+ try {
514
+ return execFileSync("git", ["describe", "--tags", "--abbrev=0", "--match", "[0-9]*"], {
515
+ cwd,
516
+ encoding: "utf-8",
517
+ stdio: ["pipe", "pipe", "ignore"]
518
+ }).trim();
519
+ } catch {
520
+ throw new Error("No version tags found");
521
+ }
522
+ }
523
+ /** Detect whether existing tags use a `v` prefix or not. */
524
+ detectPrefix(cwd) {
525
+ try {
526
+ const tag = this.describeVersionTag(cwd);
527
+ return tag.startsWith("v") ? "v" : "";
528
+ } catch {
529
+ return "v";
530
+ }
531
+ }
532
+ }
533
+ function getNestedValue(obj, dotPath) {
534
+ let current = obj;
535
+ for (const key of dotPath.split(".")) {
536
+ if (current === null || typeof current !== "object") {
537
+ return void 0;
538
+ }
539
+ current = current[key];
540
+ }
541
+ return current;
542
+ }
543
+ function setNestedValue(obj, dotPath, value) {
544
+ const keys = dotPath.split(".");
545
+ let current = obj;
546
+ for (let i = 0; i < keys.length - 1; i++) {
547
+ const next = current[keys[i]];
548
+ if (typeof next !== "object" || next === null) {
549
+ throw new Error(`Missing intermediate key '${keys.slice(0, i + 1).join(".")}' in manifest`);
550
+ }
551
+ current = next;
552
+ }
553
+ current[keys[keys.length - 1]] = value;
554
+ }
555
+ function escapeRegExp(value) {
556
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
391
557
  }
392
558
  class JsonVersionSource {
559
+ /** Human-readable provider name. */
393
560
  name;
561
+ /** Filename of the JSON manifest (e.g. `'package.json'`). */
394
562
  manifestFile;
563
+ /** Dotted key path to the version field within the JSON document. */
395
564
  versionPath;
565
+ /**
566
+ * Creates a new JSON version source.
567
+ *
568
+ * @param manifestFile - JSON manifest filename.
569
+ * @param versionPath - Dotted key path to the version field.
570
+ */
396
571
  constructor(manifestFile = "package.json", versionPath = "version") {
397
572
  this.name = manifestFile;
398
573
  this.manifestFile = manifestFile;
399
574
  this.versionPath = versionPath;
400
575
  }
576
+ /**
577
+ * Returns `true` when the manifest file exists in `cwd`.
578
+ *
579
+ * @param cwd - Project directory to check.
580
+ * @returns Whether the manifest file exists.
581
+ */
401
582
  exists(cwd) {
402
583
  return fs.existsSync(path.join(cwd, this.manifestFile));
403
584
  }
585
+ /**
586
+ * Reads the version string from the JSON manifest.
587
+ *
588
+ * @param cwd - Project directory containing the manifest.
589
+ * @returns The version string extracted from the manifest.
590
+ */
404
591
  getVersion(cwd) {
405
592
  const filePath = path.join(cwd, this.manifestFile);
406
593
  if (!fs.existsSync(filePath)) {
407
594
  throw new Error(`${this.manifestFile} not found in ${cwd}`);
408
595
  }
409
596
  const content = JSON.parse(fs.readFileSync(filePath, "utf-8"));
410
- const version = getNestedValue$1(content, this.versionPath);
597
+ const version = getNestedValue(content, this.versionPath);
411
598
  if (typeof version !== "string" || version.length === 0) {
412
599
  throw new Error(`No version field in ${this.manifestFile}`);
413
600
  }
414
601
  return version;
415
602
  }
603
+ /**
604
+ * Writes a version string to the JSON manifest, preserving indentation.
605
+ *
606
+ * @param version - Version string to write.
607
+ * @param cwd - Project directory containing the manifest.
608
+ */
416
609
  setVersion(version, cwd) {
417
610
  const filePath = path.join(cwd, this.manifestFile);
418
611
  if (!fs.existsSync(filePath)) {
419
612
  throw new Error(`${this.manifestFile} not found in ${cwd}`);
420
613
  }
421
- const content = JSON.parse(fs.readFileSync(filePath, "utf-8"));
614
+ const raw = fs.readFileSync(filePath, "utf-8");
615
+ const indentMatch = raw.match(/^(\s+)"/m);
616
+ const indent = indentMatch?.[1]?.length ?? 2;
617
+ const content = JSON.parse(raw);
422
618
  setNestedValue(content, this.versionPath, version);
423
- fs.writeFileSync(filePath, `${JSON.stringify(content, null, 2)}
619
+ fs.writeFileSync(filePath, `${JSON.stringify(content, null, indent)}
424
620
  `, "utf-8");
425
621
  }
426
622
  }
427
- function getNestedValue$1(obj, dotPath) {
428
- let current = obj;
429
- for (const key of dotPath.split(".")) {
430
- if (current === null || typeof current !== "object") {
431
- return void 0;
432
- }
433
- current = current[key];
434
- }
435
- return current;
436
- }
437
- function setNestedValue(obj, dotPath, value) {
438
- const keys = dotPath.split(".");
439
- let current = obj;
440
- for (let i = 0; i < keys.length - 1; i++) {
441
- const key = keys[i];
442
- if (typeof current[key] !== "object" || current[key] === null) {
443
- current[key] = {};
444
- }
445
- current = current[key];
446
- }
447
- current[keys[keys.length - 1]] = value;
448
- }
449
623
  class RegexVersionSource {
624
+ /** Human-readable provider name. */
450
625
  name;
626
+ /** Filename of the source manifest (e.g. `'setup.py'`). */
451
627
  manifestFile;
628
+ /** Compiled regex used to locate the version string. */
452
629
  versionRegex;
630
+ /**
631
+ * Creates a new regex version source.
632
+ *
633
+ * @param manifestFile - Source manifest filename.
634
+ * @param versionRegex - Regex string with at least one capture group for the version.
635
+ */
453
636
  constructor(manifestFile, versionRegex) {
454
637
  this.name = manifestFile;
455
638
  this.manifestFile = manifestFile;
@@ -462,9 +645,21 @@ class RegexVersionSource {
462
645
  throw new Error(`Version regex for ${manifestFile} must contain at least one capture group`);
463
646
  }
464
647
  }
648
+ /**
649
+ * Returns `true` when the manifest file exists in `cwd`.
650
+ *
651
+ * @param cwd - Project directory to check.
652
+ * @returns Whether the manifest file exists.
653
+ */
465
654
  exists(cwd) {
466
655
  return fs.existsSync(path.join(cwd, this.manifestFile));
467
656
  }
657
+ /**
658
+ * Reads the version string from the source manifest using regex extraction.
659
+ *
660
+ * @param cwd - Project directory containing the manifest.
661
+ * @returns The version string captured by group 1 of the regex.
662
+ */
468
663
  getVersion(cwd) {
469
664
  const filePath = path.join(cwd, this.manifestFile);
470
665
  if (!fs.existsSync(filePath)) {
@@ -477,6 +672,12 @@ class RegexVersionSource {
477
672
  }
478
673
  return match[1];
479
674
  }
675
+ /**
676
+ * Writes a version string to the source manifest using position-based replacement.
677
+ *
678
+ * @param version - Version string to write.
679
+ * @param cwd - Project directory containing the manifest.
680
+ */
480
681
  setVersion(version, cwd) {
481
682
  const filePath = path.join(cwd, this.manifestFile);
482
683
  if (!fs.existsSync(filePath)) {
@@ -494,17 +695,38 @@ class RegexVersionSource {
494
695
  }
495
696
  }
496
697
  class TomlVersionSource {
698
+ /** Human-readable provider name. */
497
699
  name;
700
+ /** Filename of the TOML manifest (e.g. `'Cargo.toml'`). */
498
701
  manifestFile;
702
+ /** Dotted key path to the version field within the TOML document. */
499
703
  versionPath;
704
+ /**
705
+ * Creates a new TOML version source.
706
+ *
707
+ * @param manifestFile - TOML manifest filename.
708
+ * @param versionPath - Dotted key path to the version field.
709
+ */
500
710
  constructor(manifestFile = "Cargo.toml", versionPath = "package.version") {
501
711
  this.name = manifestFile;
502
712
  this.manifestFile = manifestFile;
503
713
  this.versionPath = versionPath;
504
714
  }
715
+ /**
716
+ * Returns `true` when the manifest file exists in `cwd`.
717
+ *
718
+ * @param cwd - Project directory to check.
719
+ * @returns Whether the manifest file exists.
720
+ */
505
721
  exists(cwd) {
506
722
  return fs.existsSync(path.join(cwd, this.manifestFile));
507
723
  }
724
+ /**
725
+ * Reads the version string from the TOML manifest.
726
+ *
727
+ * @param cwd - Project directory containing the manifest.
728
+ * @returns The version string extracted from the manifest.
729
+ */
508
730
  getVersion(cwd) {
509
731
  const filePath = path.join(cwd, this.manifestFile);
510
732
  if (!fs.existsSync(filePath)) {
@@ -518,6 +740,12 @@ class TomlVersionSource {
518
740
  }
519
741
  return version;
520
742
  }
743
+ /**
744
+ * Writes a version string to the TOML manifest, preserving formatting.
745
+ *
746
+ * @param version - Version string to write.
747
+ * @param cwd - Project directory containing the manifest.
748
+ */
521
749
  setVersion(version, cwd) {
522
750
  const filePath = path.join(cwd, this.manifestFile);
523
751
  if (!fs.existsSync(filePath)) {
@@ -531,6 +759,11 @@ class TomlVersionSource {
531
759
  }
532
760
  fs.writeFileSync(filePath, updated, "utf-8");
533
761
  }
762
+ /**
763
+ * Splits the dotted version path into a TOML section name and key name.
764
+ *
765
+ * @returns An object with `section` and `key` components.
766
+ */
534
767
  getSectionKey() {
535
768
  const parts = this.versionPath.split(".");
536
769
  if (parts.length === 1) {
@@ -542,21 +775,32 @@ class TomlVersionSource {
542
775
  };
543
776
  }
544
777
  }
545
- function getNestedValue(obj, dotPath) {
546
- let current = obj;
547
- for (const key of dotPath.split(".")) {
548
- if (current === null || typeof current !== "object") {
549
- return void 0;
550
- }
551
- current = current[key];
778
+ function replaceTomlVersion(content, target, newVersion) {
779
+ const result = replaceInSection(content, target, newVersion);
780
+ if (result !== content) return result;
781
+ if (target.section) {
782
+ const dottedRegex = new RegExp(
783
+ `^(\\s*${escapeRegExp(target.section)}\\.${escapeRegExp(target.key)}\\s*=\\s*)(["'])([^"']*)(\\2)`,
784
+ "m"
785
+ );
786
+ const dottedResult = content.replace(dottedRegex, `$1$2${newVersion}$4`);
787
+ if (dottedResult !== content) return dottedResult;
552
788
  }
553
- return current;
789
+ if (target.section) {
790
+ const inlineRegex = new RegExp(
791
+ `^(\\s*${escapeRegExp(target.section)}\\s*=\\s*\\{[^}]*${escapeRegExp(target.key)}\\s*=\\s*)(["'])([^"']*)(\\2)`,
792
+ "m"
793
+ );
794
+ const inlineResult = content.replace(inlineRegex, `$1$2${newVersion}$4`);
795
+ if (inlineResult !== content) return inlineResult;
796
+ }
797
+ return content;
554
798
  }
555
- function replaceTomlVersion(content, target, newVersion) {
799
+ function replaceInSection(content, target, newVersion) {
556
800
  const lines = content.split("\n");
557
801
  const sectionHeader = target.section ? `[${target.section}]` : null;
558
802
  let inSection = sectionHeader === null;
559
- const versionRegex = new RegExp(`^(\\s*${escapeRegExp$1(target.key)}\\s*=\\s*)(["'])([^"']*)(\\2)`);
803
+ const versionRegex = new RegExp(`^(\\s*${escapeRegExp(target.key)}\\s*=\\s*)(["'])([^"']*)(\\2)`);
560
804
  for (let i = 0; i < lines.length; i++) {
561
805
  const trimmed = lines[i].trim();
562
806
  if (sectionHeader !== null) {
@@ -579,30 +823,56 @@ function replaceTomlVersion(content, target, newVersion) {
579
823
  }
580
824
  return content;
581
825
  }
582
- function escapeRegExp$1(value) {
583
- return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
584
- }
585
826
  class VersionFileSource {
827
+ /** Human-readable provider name. */
586
828
  name;
829
+ /** Filename of the version file (e.g. `'VERSION'`). */
587
830
  manifestFile;
831
+ /**
832
+ * Creates a new plain text version file source.
833
+ *
834
+ * @param manifestFile - Version filename.
835
+ */
588
836
  constructor(manifestFile = "VERSION") {
589
837
  this.name = manifestFile;
590
838
  this.manifestFile = manifestFile;
591
839
  }
840
+ /**
841
+ * Returns `true` when the version file exists in `cwd`.
842
+ *
843
+ * @param cwd - Project directory to check.
844
+ * @returns Whether the version file exists.
845
+ */
592
846
  exists(cwd) {
593
847
  return fs.existsSync(path.join(cwd, this.manifestFile));
594
848
  }
849
+ /**
850
+ * Reads the version string from the plain text version file.
851
+ *
852
+ * @param cwd - Project directory containing the version file.
853
+ * @returns The version string from the first line of the file.
854
+ */
595
855
  getVersion(cwd) {
596
856
  const filePath = path.join(cwd, this.manifestFile);
597
857
  if (!fs.existsSync(filePath)) {
598
858
  throw new Error(`${this.manifestFile} not found in ${cwd}`);
599
859
  }
600
- const version = fs.readFileSync(filePath, "utf-8").trim();
860
+ const raw = fs.readFileSync(filePath, "utf-8");
861
+ if (raw.includes("\0")) {
862
+ throw new Error(`${this.manifestFile} appears to be a binary file`);
863
+ }
864
+ const version = raw.split("\n")[0].trim();
601
865
  if (version.length === 0) {
602
866
  throw new Error(`${this.manifestFile} is empty`);
603
867
  }
604
868
  return version;
605
869
  }
870
+ /**
871
+ * Writes a version string to the plain text version file.
872
+ *
873
+ * @param version - Version string to write.
874
+ * @param cwd - Project directory containing the version file.
875
+ */
606
876
  setVersion(version, cwd) {
607
877
  const filePath = path.join(cwd, this.manifestFile);
608
878
  if (!fs.existsSync(filePath)) {
@@ -613,17 +883,38 @@ class VersionFileSource {
613
883
  }
614
884
  }
615
885
  class YamlVersionSource {
886
+ /** Human-readable provider name. */
616
887
  name;
888
+ /** Filename of the YAML manifest (e.g. `'pubspec.yaml'`). */
617
889
  manifestFile;
890
+ /** Dotted key path to the version field within the YAML document. */
618
891
  versionKey;
892
+ /**
893
+ * Creates a new YAML version source.
894
+ *
895
+ * @param manifestFile - YAML manifest filename.
896
+ * @param versionKey - Dotted key path to the version field.
897
+ */
619
898
  constructor(manifestFile = "pubspec.yaml", versionKey = "version") {
620
899
  this.name = manifestFile;
621
900
  this.manifestFile = manifestFile;
622
901
  this.versionKey = versionKey;
623
902
  }
903
+ /**
904
+ * Returns `true` when the manifest file exists in `cwd`.
905
+ *
906
+ * @param cwd - Project directory to check.
907
+ * @returns Whether the manifest file exists.
908
+ */
624
909
  exists(cwd) {
625
910
  return fs.existsSync(path.join(cwd, this.manifestFile));
626
911
  }
912
+ /**
913
+ * Reads the version string from the YAML manifest.
914
+ *
915
+ * @param cwd - Project directory containing the manifest.
916
+ * @returns The version string extracted from the manifest.
917
+ */
627
918
  getVersion(cwd) {
628
919
  const filePath = path.join(cwd, this.manifestFile);
629
920
  if (!fs.existsSync(filePath)) {
@@ -634,7 +925,7 @@ class YamlVersionSource {
634
925
  if (!parsed || typeof parsed !== "object") {
635
926
  throw new Error(`Failed to parse ${this.manifestFile}`);
636
927
  }
637
- const version = parsed[this.versionKey];
928
+ const version = getNestedValue(parsed, this.versionKey);
638
929
  if (typeof version !== "string" || version.length === 0) {
639
930
  if (typeof version === "number") {
640
931
  return String(version);
@@ -643,13 +934,21 @@ class YamlVersionSource {
643
934
  }
644
935
  return version;
645
936
  }
937
+ /**
938
+ * Writes a version string to the YAML manifest, preserving formatting.
939
+ *
940
+ * @param version - Version string to write.
941
+ * @param cwd - Project directory containing the manifest.
942
+ */
646
943
  setVersion(version, cwd) {
647
944
  const filePath = path.join(cwd, this.manifestFile);
648
945
  if (!fs.existsSync(filePath)) {
649
946
  throw new Error(`${this.manifestFile} not found in ${cwd}`);
650
947
  }
948
+ const keyParts = this.versionKey.split(".");
949
+ const leafKey = keyParts[keyParts.length - 1];
651
950
  const content = fs.readFileSync(filePath, "utf-8");
652
- const regex = new RegExp(`^(${escapeRegExp(this.versionKey)}:\\s*)(["']?)(.+?)\\2\\s*$`, "m");
951
+ const regex = new RegExp(`^(\\s*${escapeRegExp(leafKey)}:\\s*)(["']?)(.+?)\\2\\s*$`, "m");
653
952
  const updated = content.replace(regex, `$1$2${version}$2`);
654
953
  if (updated === content) {
655
954
  throw new Error(`Could not find version field to update in ${this.manifestFile}`);
@@ -657,9 +956,6 @@ class YamlVersionSource {
657
956
  fs.writeFileSync(filePath, updated, "utf-8");
658
957
  }
659
958
  }
660
- function escapeRegExp(value) {
661
- return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
662
- }
663
959
  const VALID_SOURCES = /* @__PURE__ */ new Set([
664
960
  "auto",
665
961
  "package.json",
@@ -765,7 +1061,10 @@ function resolveVersionSource(config, cwd = process.cwd()) {
765
1061
  return provider;
766
1062
  }
767
1063
  }
768
- return new JsonVersionSource("package.json", "version");
1064
+ const supported = DETECTION_TABLE.map((e) => e.file).join(", ");
1065
+ throw new Error(
1066
+ `No supported manifest file found in ${cwd}. Looked for: ${supported}. Set manifest.source explicitly in .versionguard.yml or create a supported manifest file.`
1067
+ );
769
1068
  }
770
1069
  function detectManifests(cwd = process.cwd()) {
771
1070
  const detected = [];
@@ -1059,6 +1358,12 @@ function checkHardcodedVersions(expectedVersion, config, ignorePatterns, cwd = p
1059
1358
  }
1060
1359
  return mismatches;
1061
1360
  }
1361
+ function getCalVerConfig(config) {
1362
+ if (!config.versioning.calver) {
1363
+ throw new Error('CalVer configuration is required when versioning.type is "calver"');
1364
+ }
1365
+ return config.versioning.calver;
1366
+ }
1062
1367
  const CONFIG_FILE_NAMES = [
1063
1368
  ".versionguard.yml",
1064
1369
  ".versionguard.yaml",
@@ -1068,9 +1373,14 @@ const CONFIG_FILE_NAMES = [
1068
1373
  const DEFAULT_CONFIG = {
1069
1374
  versioning: {
1070
1375
  type: "semver",
1376
+ schemeRules: {
1377
+ maxNumericSegments: 3,
1378
+ allowedModifiers: ["dev", "alpha", "beta", "rc"]
1379
+ },
1071
1380
  calver: {
1072
1381
  format: "YYYY.MM.PATCH",
1073
- preventFutureDates: true
1382
+ preventFutureDates: true,
1383
+ strictMutualExclusion: true
1074
1384
  }
1075
1385
  },
1076
1386
  manifest: {
@@ -1196,13 +1506,7 @@ function getVersionFeedback(version, config, previousVersion) {
1196
1506
  if (config.versioning.type === "semver") {
1197
1507
  return getSemVerFeedback(version, previousVersion);
1198
1508
  }
1199
- return getCalVerFeedback(version, getCalVerConfig$2(config), previousVersion);
1200
- }
1201
- function getCalVerConfig$2(config) {
1202
- if (!config.versioning.calver) {
1203
- throw new Error('CalVer configuration is required when versioning.type is "calver"');
1204
- }
1205
- return config.versioning.calver;
1509
+ return getCalVerFeedback(version, getCalVerConfig(config), previousVersion);
1206
1510
  }
1207
1511
  function getSemVerFeedback(version, previousVersion) {
1208
1512
  const errors = [];
@@ -1218,7 +1522,7 @@ function getSemVerFeedback(version, previousVersion) {
1218
1522
  });
1219
1523
  suggestions.push({
1220
1524
  message: `Remove the 'v' prefix`,
1221
- fix: `npm version ${cleanVersion}`,
1525
+ fix: `npx versionguard fix --version ${cleanVersion}`,
1222
1526
  autoFixable: true
1223
1527
  });
1224
1528
  } else if (version.split(".").length === 2) {
@@ -1228,7 +1532,7 @@ function getSemVerFeedback(version, previousVersion) {
1228
1532
  });
1229
1533
  suggestions.push({
1230
1534
  message: `Add patch number (e.g., ${version}.0)`,
1231
- fix: `npm version ${version}.0`,
1535
+ fix: `npx versionguard fix --version ${version}.0`,
1232
1536
  autoFixable: true
1233
1537
  });
1234
1538
  } else if (/^\d+\.\d+\.\d+\.\d+$/.test(version)) {
@@ -1278,7 +1582,7 @@ function getSemVerFeedback(version, previousVersion) {
1278
1582
  });
1279
1583
  suggestions.push({
1280
1584
  message: `Version must be greater than ${previousVersion}`,
1281
- fix: `npm version ${increment(previousVersion, "patch")}`,
1585
+ fix: `npx versionguard fix --version ${increment(previousVersion, "patch")}`,
1282
1586
  autoFixable: true
1283
1587
  });
1284
1588
  } else if (comparison === 0) {
@@ -1288,7 +1592,7 @@ function getSemVerFeedback(version, previousVersion) {
1288
1592
  });
1289
1593
  suggestions.push({
1290
1594
  message: `Bump the version`,
1291
- fix: `npm version ${increment(previousVersion, "patch")}`,
1595
+ fix: `npx versionguard fix --version ${increment(previousVersion, "patch")}`,
1292
1596
  autoFixable: true
1293
1597
  });
1294
1598
  } else {
@@ -1358,21 +1662,21 @@ function getCalVerFeedback(version, calverConfig, previousVersion) {
1358
1662
  if (preventFutureDates && parsed.year > now.getFullYear()) {
1359
1663
  suggestions.push({
1360
1664
  message: `Use current year (${now.getFullYear()}) or a past year`,
1361
- fix: `npm version ${formatCalVerVersion({ ...parsed, year: now.getFullYear() })}`,
1665
+ fix: `npx versionguard fix --version ${formatCalVerVersion({ ...parsed, year: now.getFullYear() })}`,
1362
1666
  autoFixable: true
1363
1667
  });
1364
1668
  }
1365
1669
  if (preventFutureDates && parsed.year === now.getFullYear() && parsed.month > now.getMonth() + 1) {
1366
1670
  suggestions.push({
1367
1671
  message: `Current month is ${now.getMonth() + 1}`,
1368
- fix: `npm version ${formatCalVerVersion({ ...parsed, month: now.getMonth() + 1 })}`,
1672
+ fix: `npx versionguard fix --version ${formatCalVerVersion({ ...parsed, month: now.getMonth() + 1 })}`,
1369
1673
  autoFixable: true
1370
1674
  });
1371
1675
  }
1372
1676
  if (preventFutureDates && parsed.year === now.getFullYear() && parsed.month === now.getMonth() + 1 && parsed.day !== void 0 && parsed.day > now.getDate()) {
1373
1677
  suggestions.push({
1374
1678
  message: `Current day is ${now.getDate()}`,
1375
- fix: `npm version ${formatCalVerVersion({ ...parsed, day: now.getDate() })}`,
1679
+ fix: `npx versionguard fix --version ${formatCalVerVersion({ ...parsed, day: now.getDate() })}`,
1376
1680
  autoFixable: true
1377
1681
  });
1378
1682
  }
@@ -1386,7 +1690,7 @@ function getCalVerFeedback(version, calverConfig, previousVersion) {
1386
1690
  });
1387
1691
  suggestions.push({
1388
1692
  message: `CalVer must increase over time`,
1389
- fix: `npm version ${increment$1(previousVersion, format2)}`,
1693
+ fix: `npx versionguard fix --version ${increment$1(previousVersion, format2)}`,
1390
1694
  autoFixable: true
1391
1695
  });
1392
1696
  }
@@ -1595,7 +1899,7 @@ function suggestNextVersion(currentVersion, config, changeType) {
1595
1899
  });
1596
1900
  }
1597
1901
  } else {
1598
- const format2 = getCalVerConfig$1(config).format;
1902
+ const format2 = getCalVerConfig(config).format;
1599
1903
  const currentCal = getCurrentVersion(format2);
1600
1904
  suggestions.push({
1601
1905
  version: currentCal,
@@ -1608,12 +1912,6 @@ function suggestNextVersion(currentVersion, config, changeType) {
1608
1912
  }
1609
1913
  return suggestions;
1610
1914
  }
1611
- function getCalVerConfig$1(config) {
1612
- if (!config.versioning.calver) {
1613
- throw new Error('CalVer configuration is required when versioning.type is "calver"');
1614
- }
1615
- return config.versioning.calver;
1616
- }
1617
1915
  const HOOK_NAMES = ["pre-commit", "pre-push", "post-tag"];
1618
1916
  function checkHooksPathOverride(cwd) {
1619
1917
  try {
@@ -1897,7 +2195,8 @@ function getTagPreflightError(config, cwd, expectedVersion, allowAutoFix = false
1897
2195
  const versionResult = config.versioning.type === "semver" ? validate$1(version) : validate$2(
1898
2196
  version,
1899
2197
  config.versioning.calver?.format ?? "YYYY.MM.PATCH",
1900
- config.versioning.calver?.preventFutureDates ?? true
2198
+ config.versioning.calver?.preventFutureDates ?? true,
2199
+ config.versioning.schemeRules
1901
2200
  );
1902
2201
  if (!versionResult.valid) {
1903
2202
  return versionResult.errors[0]?.message ?? `Invalid version: ${version}`;
@@ -1981,7 +2280,12 @@ function validateVersion(version, config) {
1981
2280
  return validate$1(version);
1982
2281
  }
1983
2282
  const calverConfig = getCalVerConfig(config);
1984
- return validate$2(version, calverConfig.format, calverConfig.preventFutureDates);
2283
+ return validate$2(
2284
+ version,
2285
+ calverConfig.format,
2286
+ calverConfig.preventFutureDates,
2287
+ config.versioning.schemeRules
2288
+ );
1985
2289
  }
1986
2290
  function validate(config, cwd = process.cwd()) {
1987
2291
  const errors = [];
@@ -2093,12 +2397,6 @@ function canBump(currentVersion, newVersion, config) {
2093
2397
  }
2094
2398
  return { canBump: true };
2095
2399
  }
2096
- function getCalVerConfig(config) {
2097
- if (!config.versioning.calver) {
2098
- throw new Error('CalVer configuration is required when versioning.type is "calver"');
2099
- }
2100
- return config.versioning.calver;
2101
- }
2102
2400
  function isWorktreeClean(cwd) {
2103
2401
  try {
2104
2402
  return execSync("git status --porcelain", { cwd, encoding: "utf-8" }).trim().length === 0;
@@ -2110,20 +2408,22 @@ export {
2110
2408
  fixChangelog as A,
2111
2409
  fixPackageVersion as B,
2112
2410
  getAllTags as C,
2113
- getLatestTag as D,
2114
- getTagFeedback as E,
2115
- getVersionSource as F,
2411
+ getCalVerConfig as D,
2412
+ getLatestTag as E,
2413
+ getTagFeedback as F,
2116
2414
  GitTagSource as G,
2117
- resolveVersionSource as H,
2118
- semver as I,
2415
+ getVersionSource as H,
2416
+ initConfig as I,
2119
2417
  JsonVersionSource as J,
2120
- suggestTagMessage as K,
2121
- sync as L,
2122
- syncVersion as M,
2123
- validateChangelog as N,
2124
- validateTagForPush as O,
2125
- validateVersion as P,
2418
+ resolveVersionSource as K,
2419
+ semver as L,
2420
+ suggestTagMessage as M,
2421
+ sync as N,
2422
+ syncVersion as O,
2423
+ validateChangelog as P,
2424
+ validateTagForPush as Q,
2126
2425
  RegexVersionSource as R,
2426
+ validateVersion as S,
2127
2427
  TomlVersionSource as T,
2128
2428
  VersionFileSource as V,
2129
2429
  YamlVersionSource as Y,
@@ -2135,7 +2435,7 @@ export {
2135
2435
  doctor as f,
2136
2436
  getConfig as g,
2137
2437
  handlePostTag as h,
2138
- initConfig as i,
2438
+ isValidCalVerFormat as i,
2139
2439
  fixAll as j,
2140
2440
  fixSyncIssues as k,
2141
2441
  setPackageVersion as l,
@@ -2154,4 +2454,4 @@ export {
2154
2454
  checkHuskyBypass as y,
2155
2455
  detectManifests as z
2156
2456
  };
2157
- //# sourceMappingURL=index-BrZJDWya.js.map
2457
+ //# sourceMappingURL=index-B3R60bYJ.js.map