@contractspec/lib.contracts 1.45.2 → 1.45.4

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.
@@ -0,0 +1,180 @@
1
+ //#region src/versioning/utils.ts
2
+ /** Regex for parsing semantic versions */
3
+ const SEMVER_REGEX = /^(\d+)\.(\d+)\.(\d+)(?:-([a-zA-Z0-9]+(?:\.[a-zA-Z0-9]+)*))?(?:\+([a-zA-Z0-9]+(?:\.[a-zA-Z0-9]+)*))?$/;
4
+ /**
5
+ * Parse a semantic version string into components.
6
+ *
7
+ * @param version - Version string (e.g., "1.2.3", "1.0.0-alpha.1")
8
+ * @returns Parsed SemanticVersion or null if invalid
9
+ *
10
+ * @example
11
+ * parseVersion("1.2.3") // { major: 1, minor: 2, patch: 3 }
12
+ * parseVersion("2.0.0-beta.1") // { major: 2, minor: 0, patch: 0, prerelease: "beta.1" }
13
+ */
14
+ function parseVersion(version) {
15
+ const match = version.trim().match(SEMVER_REGEX);
16
+ if (!match) return null;
17
+ const majorStr = match[1];
18
+ const minorStr = match[2];
19
+ const patchStr = match[3];
20
+ const prerelease = match[4];
21
+ const build = match[5];
22
+ if (!majorStr || !minorStr || !patchStr) return null;
23
+ return {
24
+ major: parseInt(majorStr, 10),
25
+ minor: parseInt(minorStr, 10),
26
+ patch: parseInt(patchStr, 10),
27
+ ...prerelease && { prerelease },
28
+ ...build && { build }
29
+ };
30
+ }
31
+ /**
32
+ * Strictly parse a version, throwing on invalid input.
33
+ *
34
+ * @throws Error if version is not valid semver
35
+ */
36
+ function parseVersionStrict(version) {
37
+ const parsed = parseVersion(version);
38
+ if (!parsed) throw new Error(`Invalid semantic version: "${version}"`);
39
+ return parsed;
40
+ }
41
+ /**
42
+ * Format a SemanticVersion back to string.
43
+ *
44
+ * @example
45
+ * formatVersion({ major: 1, minor: 2, patch: 3 }) // "1.2.3"
46
+ * formatVersion({ major: 2, minor: 0, patch: 0, prerelease: "beta.1" }) // "2.0.0-beta.1"
47
+ */
48
+ function formatVersion(version) {
49
+ let result = `${version.major}.${version.minor}.${version.patch}`;
50
+ if (version.prerelease) result += `-${version.prerelease}`;
51
+ if (version.build) result += `+${version.build}`;
52
+ return result;
53
+ }
54
+ /**
55
+ * Compare two version strings.
56
+ *
57
+ * @returns -1 if a < b, 0 if a === b, 1 if a > b
58
+ *
59
+ * @example
60
+ * compareVersions("1.0.0", "2.0.0") // -1
61
+ * compareVersions("1.2.3", "1.2.3") // 0
62
+ * compareVersions("2.0.0", "1.9.9") // 1
63
+ */
64
+ function compareVersions(a, b) {
65
+ const versionA = parseVersionStrict(a);
66
+ const versionB = parseVersionStrict(b);
67
+ if (versionA.major !== versionB.major) return versionA.major > versionB.major ? 1 : -1;
68
+ if (versionA.minor !== versionB.minor) return versionA.minor > versionB.minor ? 1 : -1;
69
+ if (versionA.patch !== versionB.patch) return versionA.patch > versionB.patch ? 1 : -1;
70
+ if (versionA.prerelease && !versionB.prerelease) return -1;
71
+ if (!versionA.prerelease && versionB.prerelease) return 1;
72
+ if (versionA.prerelease && versionB.prerelease) return versionA.prerelease < versionB.prerelease ? -1 : versionA.prerelease > versionB.prerelease ? 1 : 0;
73
+ return 0;
74
+ }
75
+ /**
76
+ * Check if version a is greater than version b.
77
+ */
78
+ function isVersionGreater(a, b) {
79
+ return compareVersions(a, b) === 1;
80
+ }
81
+ /**
82
+ * Check if version a is less than version b.
83
+ */
84
+ function isVersionLess(a, b) {
85
+ return compareVersions(a, b) === -1;
86
+ }
87
+ /**
88
+ * Check if two versions are equal.
89
+ */
90
+ function isVersionEqual(a, b) {
91
+ return compareVersions(a, b) === 0;
92
+ }
93
+ /**
94
+ * Bump a version by the specified type.
95
+ *
96
+ * @param current - Current version string
97
+ * @param bumpType - Type of bump: 'patch', 'minor', or 'major'
98
+ * @returns New version string
99
+ *
100
+ * @example
101
+ * bumpVersion("1.2.3", "patch") // "1.2.4"
102
+ * bumpVersion("1.2.3", "minor") // "1.3.0"
103
+ * bumpVersion("1.2.3", "major") // "2.0.0"
104
+ */
105
+ function bumpVersion(current, bumpType) {
106
+ const version = parseVersionStrict(current);
107
+ switch (bumpType) {
108
+ case "major": return formatVersion({
109
+ major: version.major + 1,
110
+ minor: 0,
111
+ patch: 0
112
+ });
113
+ case "minor": return formatVersion({
114
+ major: version.major,
115
+ minor: version.minor + 1,
116
+ patch: 0
117
+ });
118
+ case "patch": return formatVersion({
119
+ major: version.major,
120
+ minor: version.minor,
121
+ patch: version.patch + 1
122
+ });
123
+ }
124
+ }
125
+ /**
126
+ * Determine the appropriate version bump type based on change impact.
127
+ *
128
+ * - Breaking changes → major
129
+ * - Non-breaking additions/changes → minor
130
+ * - Fixes only → patch
131
+ *
132
+ * @param hasBreaking - Whether breaking changes were detected
133
+ * @param hasNonBreaking - Whether non-breaking changes (additions, changes) were detected
134
+ * @returns Appropriate bump type
135
+ */
136
+ function determineBumpType(hasBreaking, hasNonBreaking) {
137
+ if (hasBreaking) return "major";
138
+ if (hasNonBreaking) return "minor";
139
+ return "patch";
140
+ }
141
+ /**
142
+ * Get sort priority for bump types (higher = more significant).
143
+ */
144
+ function getBumpTypePriority(bumpType) {
145
+ switch (bumpType) {
146
+ case "major": return 3;
147
+ case "minor": return 2;
148
+ case "patch": return 1;
149
+ }
150
+ }
151
+ /**
152
+ * Get the most significant bump type from a list.
153
+ */
154
+ function getMaxBumpType(bumpTypes) {
155
+ if (bumpTypes.length === 0) return null;
156
+ return bumpTypes.reduce((max, current) => getBumpTypePriority(current) > getBumpTypePriority(max) ? current : max);
157
+ }
158
+ /**
159
+ * Check if a string is a valid semantic version.
160
+ */
161
+ function isValidVersion(version) {
162
+ return parseVersion(version) !== null;
163
+ }
164
+ /**
165
+ * Validate a version string, returning validation errors.
166
+ */
167
+ function validateVersion(version) {
168
+ const errors = [];
169
+ if (!version || typeof version !== "string") {
170
+ errors.push("Version must be a non-empty string");
171
+ return errors;
172
+ }
173
+ const trimmed = version.trim();
174
+ if (trimmed !== version) errors.push("Version should not have leading or trailing whitespace");
175
+ if (!parseVersion(trimmed)) errors.push(`Invalid semantic version format: "${version}". Expected format: MAJOR.MINOR.PATCH[-prerelease][+build]`);
176
+ return errors;
177
+ }
178
+
179
+ //#endregion
180
+ export { bumpVersion, compareVersions, determineBumpType, formatVersion, getBumpTypePriority, getMaxBumpType, isValidVersion, isVersionEqual, isVersionGreater, isVersionLess, parseVersion, parseVersionStrict, validateVersion };