@helpers4/version 2.0.0-alpha.2 → 2.0.0-alpha.21

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
@@ -9,21 +9,26 @@ A set of helpers for working with URLs.
9
9
 
10
10
  ## Documentation
11
11
 
12
- [https://helpers4.js.org/version](https://helpers4.js.org/version)
12
+ [https://helpers4.dev/typescript/categories/version/](https://helpers4.dev/typescript/categories/version/)
13
13
 
14
14
  <!-- AUTOMATIC-METHODS -->
15
- - stripV
16
15
  - compare
17
- - satisfiesRange
18
16
  - increment
17
+ - isPrerelease
18
+ - parse
19
+ - satisfiesRange
20
+ - stringify
21
+ - stripV
19
22
  <!-- /AUTOMATIC-METHODS -->
20
23
 
21
24
  ## See
22
25
 
23
26
  <!-- AUTOMATIC-SIBLINGS -->
24
27
  - [array](../array)
28
+ - [commit](../commit)
25
29
  - [date](../date)
26
30
  - [function](../function)
31
+ - [math](../math)
27
32
  - [number](../number)
28
33
  - [object](../object)
29
34
  - [observable](../observable)
@@ -39,14 +44,16 @@ A set of helpers for working with URLs.
39
44
  | Name | Package | Source Code | Description |
40
45
  |------|---------|-------------|-------------|
41
46
  | array | [@helpers4/array](https://www.npmjs.com/package/@helpers4/array) | [Source](https://github.com/helpers4/helpers4/tree/main/helpers/array) | Array manipulation utilities |
42
- | date | [@helpers4/date](https://www.npmjs.com/package/@helpers4/date) | [Source](https://github.com/helpers4/helpers4/tree/main/helpers/date) | date utilities |
47
+ | commit | [@helpers4/commit](https://www.npmjs.com/package/@helpers4/commit) | [Source](https://github.com/helpers4/helpers4/tree/main/helpers/commit) | Conventional Commits parsing and analysis |
48
+ | date | [@helpers4/date](https://www.npmjs.com/package/@helpers4/date) | [Source](https://github.com/helpers4/helpers4/tree/main/helpers/date) | Date and time utility functions |
43
49
  | function | [@helpers4/function](https://www.npmjs.com/package/@helpers4/function) | [Source](https://github.com/helpers4/helpers4/tree/main/helpers/function) | Function utilities and type guards |
44
- | number | [@helpers4/number](https://www.npmjs.com/package/@helpers4/number) | [Source](https://github.com/helpers4/helpers4/tree/main/helpers/number) | number utilities |
50
+ | math | [@helpers4/math](https://www.npmjs.com/package/@helpers4/math) | [Source](https://github.com/helpers4/helpers4/tree/main/helpers/math) | Mathematical utility functions and calculations |
51
+ | number | [@helpers4/number](https://www.npmjs.com/package/@helpers4/number) | [Source](https://github.com/helpers4/helpers4/tree/main/helpers/number) | Number utility functions and validation |
45
52
  | object | [@helpers4/object](https://www.npmjs.com/package/@helpers4/object) | [Source](https://github.com/helpers4/helpers4/tree/main/helpers/object) | Object manipulation utilities |
46
53
  | observable | [@helpers4/observable](https://www.npmjs.com/package/@helpers4/observable) | [Source](https://github.com/helpers4/helpers4/tree/main/helpers/observable) | Observable utilities and combinators |
47
54
  | promise | [@helpers4/promise](https://www.npmjs.com/package/@helpers4/promise) | [Source](https://github.com/helpers4/helpers4/tree/main/helpers/promise) | Promise utilities and error handling |
48
55
  | string | [@helpers4/string](https://www.npmjs.com/package/@helpers4/string) | [Source](https://github.com/helpers4/helpers4/tree/main/helpers/string) | String manipulation and formatting utilities |
49
- | type | [@helpers4/type](https://www.npmjs.com/package/@helpers4/type) | [Source](https://github.com/helpers4/helpers4/tree/main/helpers/type) | type utilities |
56
+ | type | [@helpers4/type](https://www.npmjs.com/package/@helpers4/type) | [Source](https://github.com/helpers4/helpers4/tree/main/helpers/type) | Type checking and validation utilities |
50
57
  | url | [@helpers4/url](https://www.npmjs.com/package/@helpers4/url) | [Source](https://github.com/helpers4/helpers4/tree/main/helpers/url) | URL parsing and manipulation utilities |
51
58
  | version | [@helpers4/version](https://www.npmjs.com/package/@helpers4/version) | [Source](https://github.com/helpers4/helpers4/tree/main/helpers/version) | Version string manipulation utilities |
52
59
  <!-- /AUTOMATIC-CATEGORIES-TABLE -->
package/lib/index.d.ts CHANGED
@@ -1,4 +1,192 @@
1
- export declare function stripV(version: string): string; export function stripV(version: null): null; export function stripV(version: undefined): undefined; export function stripV(version: string | null | undefined): string | null | undefined;
2
- export declare function compare(version1: string, version2: string): number;
3
- export declare function satisfiesRange(version: string, range: string): boolean;
4
- export declare function increment(version: string, type: 'major' | 'minor' | 'patch'): string;
1
+ /**
2
+ * This file is part of helpers4.
3
+ * Copyright (C) 2025 baxyz
4
+ * SPDX-License-Identifier: LGPL-3.0-or-later
5
+ */
6
+ /**
7
+ * Compares two semantic version strings according to SemVer 2.0.0 specification
8
+ *
9
+ * Supports:
10
+ * - Core version: MAJOR.MINOR.PATCH
11
+ * - Pre-release: -alpha, -beta.1, -rc.1, etc.
12
+ * - Build metadata: +build, +sha.abc123 (ignored in comparison per spec)
13
+ * - Optional 'v' prefix
14
+ *
15
+ * @param version1 - First version string
16
+ * @param version2 - Second version string
17
+ * @returns -1 if version1 < version2, 0 if equal, 1 if version1 > version2
18
+ * @example
19
+ * compare('1.0.0', '2.0.0') // -1
20
+ * compare('1.0.0-alpha', '1.0.0') // -1 (prerelease < release)
21
+ * compare('1.0.0-alpha', '1.0.0-beta') // -1
22
+ * compare('1.0.0-alpha.1', '1.0.0-alpha.2') // -1
23
+ * compare('1.0.0+build1', '1.0.0+build2') // 0 (build metadata ignored)
24
+ * @since 1.9.0
25
+ */
26
+ declare function compare(version1: string, version2: string): number;
27
+
28
+ /**
29
+ * This file is part of helpers4.
30
+ * Copyright (C) 2025 baxyz
31
+ * SPDX-License-Identifier: LGPL-3.0-or-later
32
+ */
33
+ /**
34
+ * Increments a semantic version
35
+ * @param version - The version to increment
36
+ * @param type - The increment type ('major', 'minor', 'patch')
37
+ * @returns Incremented version string
38
+ * @since 1.9.0
39
+ */
40
+ declare function increment(version: string, type: 'major' | 'minor' | 'patch'): string;
41
+ declare function increment(version: undefined, type: 'major' | 'minor' | 'patch'): undefined;
42
+ declare function increment(version: null, type: 'major' | 'minor' | 'patch'): null;
43
+
44
+ /**
45
+ * This file is part of helpers4.
46
+ * Copyright (C) 2025 baxyz
47
+ * SPDX-License-Identifier: LGPL-3.0-or-later
48
+ */
49
+ /**
50
+ * Represents a parsed semantic version according to SemVer 2.0.0 specification
51
+ * @since 2.0.0
52
+ */
53
+ interface ParsedVersion {
54
+ /** Major version number */
55
+ major: number;
56
+ /** Minor version number */
57
+ minor: number;
58
+ /** Patch version number */
59
+ patch: number;
60
+ /** Pre-release identifiers (e.g., ['alpha', '1'] for -alpha.1) */
61
+ prerelease: string[];
62
+ /** Build metadata identifiers (e.g., ['build', '123'] for +build.123) */
63
+ build: string[];
64
+ }
65
+ /**
66
+ * Parses a semantic version string into its components according to SemVer 2.0.0 specification
67
+ *
68
+ * Supports:
69
+ * - Core version: MAJOR.MINOR.PATCH
70
+ * - Pre-release: -alpha, -beta.1, -rc.1, -0.3.7, -x.7.z.92
71
+ * - Build metadata: +build, +sha.abc123, +20130313144700
72
+ * - Optional 'v' prefix (commonly used in git tags)
73
+ *
74
+ * @param version - Version string to parse
75
+ * @returns Parsed version object with major, minor, patch, prerelease, and build
76
+ * @example
77
+ * parse('1.2.3') // { major: 1, minor: 2, patch: 3, prerelease: [], build: [] }
78
+ * parse('v1.0.0-alpha.1') // { major: 1, minor: 0, patch: 0, prerelease: ['alpha', '1'], build: [] }
79
+ * parse('2.0.0+build.123') // { major: 2, minor: 0, patch: 0, prerelease: [], build: ['build', '123'] }
80
+ * parse('1.0.0-beta+exp.sha.5114f85') // { major: 1, minor: 0, patch: 0, prerelease: ['beta'], build: ['exp', 'sha', '5114f85'] }
81
+ * @since 2.0.0
82
+ */
83
+ declare function parse(version: string): ParsedVersion;
84
+ declare function parse(version: undefined): undefined;
85
+ declare function parse(version: null): null;
86
+
87
+ /**
88
+ * This file is part of helpers4.
89
+ * Copyright (C) 2025 baxyz
90
+ * SPDX-License-Identifier: LGPL-3.0-or-later
91
+ */
92
+
93
+ /**
94
+ * Returns `true` when the version string has a prerelease suffix
95
+ * (i.e. contains a `-` after the core `MAJOR.MINOR.PATCH`).
96
+ *
97
+ * @param version - A semantic version string (e.g. `'2.0.0-alpha.1'`, `'1.0.0'`).
98
+ * @returns `true` if the version is a prerelease, `false` otherwise.
99
+ * @example
100
+ * isPrerelease('2.0.0-alpha.1') // true
101
+ * isPrerelease('1.0.0-rc.0') // true
102
+ * isPrerelease('1.0.0') // false
103
+ * isPrerelease('2.1.0') // false
104
+ * @since next
105
+ */
106
+ declare function isPrerelease(version: string): boolean;
107
+ /**
108
+ * Returns `true` when the parsed version has at least one prerelease identifier.
109
+ *
110
+ * @param version - A {@link ParsedVersion} object (as returned by {@link parse}).
111
+ * @returns `true` if `version.prerelease` is non-empty, `false` otherwise.
112
+ * @example
113
+ * isPrerelease(parse('2.0.0-alpha.1')) // true
114
+ * isPrerelease(parse('1.0.0')) // false
115
+ * @since next
116
+ */
117
+ declare function isPrerelease(version: ParsedVersion): boolean;
118
+ declare function isPrerelease(version: undefined): undefined;
119
+ declare function isPrerelease(version: null): null;
120
+
121
+ /**
122
+ * This file is part of helpers4.
123
+ * Copyright (C) 2025 baxyz
124
+ * SPDX-License-Identifier: LGPL-3.0-or-later
125
+ */
126
+ /**
127
+ * Checks if a version satisfies a range (simple implementation)
128
+ * @param version - Version to check
129
+ * @param range - Range pattern (e.g., ">=1.0.0", "~1.2.0", "^1.0.0")
130
+ * @returns True if version satisfies the range
131
+ * @since 1.9.0
132
+ */
133
+ declare function satisfiesRange(version: string, range: string): boolean;
134
+
135
+ /**
136
+ * This file is part of helpers4.
137
+ * Copyright (C) 2025 baxyz
138
+ * SPDX-License-Identifier: LGPL-3.0-or-later
139
+ */
140
+
141
+ /**
142
+ * Reconstruct a semantic version string from a {@link ParsedVersion} object.
143
+ *
144
+ * This is the inverse of {@link parse}:
145
+ * `stringify(parse(v)) === stripV(v)` for any valid SemVer string `v`.
146
+ *
147
+ * @param parsed - A parsed semantic version object.
148
+ * @returns The reconstructed version string (without leading `v`).
149
+ * @example
150
+ * stringify({ major: 1, minor: 2, patch: 3, prerelease: [], build: [] })
151
+ * // => '1.2.3'
152
+ * @example
153
+ * stringify({ major: 2, minor: 0, patch: 0, prerelease: ['alpha', '1'], build: [] })
154
+ * // => '2.0.0-alpha.1'
155
+ * @example
156
+ * stringify({ major: 1, minor: 0, patch: 0, prerelease: ['beta'], build: ['exp', 'sha', '5114f85'] })
157
+ * // => '1.0.0-beta+exp.sha.5114f85'
158
+ * @since next
159
+ */
160
+ declare function stringify(parsed: ParsedVersion): string;
161
+ declare function stringify(parsed: undefined): undefined;
162
+ declare function stringify(parsed: null): null;
163
+
164
+ /**
165
+ * This file is part of helpers4.
166
+ * Copyright (C) 2025 baxyz
167
+ * SPDX-License-Identifier: LGPL-3.0-or-later
168
+ */
169
+ /**
170
+ * Strip the leading "v" from a version string if it exists.
171
+ *
172
+ * @param version - The version string to process
173
+ * @returns The version string without leading "v", or the original value if it's not a string or doesn't start with "v"
174
+ *
175
+ * @example
176
+ * ```typescript
177
+ * stripV("v1.2.3") // "1.2.3"
178
+ * stripV("1.2.3") // "1.2.3"
179
+ * stripV("v20.1.0") // "20.1.0"
180
+ * stripV(null) // null
181
+ * stripV(undefined) // undefined
182
+ * stripV("") // ""
183
+ * stripV("1.0.0-beta") // "1.0.0-beta"
184
+ * ```
185
+ * @since 1.9.0
186
+ */
187
+ declare function stripV(version: string): string;
188
+ declare function stripV(version: null): null;
189
+ declare function stripV(version: undefined): undefined;
190
+
191
+ export { compare, increment, isPrerelease, parse, satisfiesRange, stringify, stripV };
192
+ export type { ParsedVersion };
package/lib/index.js CHANGED
@@ -1,108 +1,182 @@
1
- // helpers/version/stripV.ts
2
- function stripV(version) {
3
- return typeof version === "string" && version.startsWith("v") ? version.slice(1) : version;
1
+ //#region helpers/version/parse.ts
2
+ function parse(version) {
3
+ if (version === void 0 || version === null) return version;
4
+ const [versionWithPrerelease, buildString] = version.replace(/^v/, "").split("+");
5
+ const build = buildString ? buildString.split(".") : [];
6
+ const [coreVersion, prereleaseString] = versionWithPrerelease.split("-");
7
+ const prerelease = prereleaseString ? prereleaseString.split(".") : [];
8
+ const parts = coreVersion.split(".").map(Number);
9
+ return {
10
+ major: parts[0] || 0,
11
+ minor: parts[1] || 0,
12
+ patch: parts[2] || 0,
13
+ prerelease,
14
+ build
15
+ };
16
+ }
17
+ //#endregion
18
+ //#region helpers/version/compare.ts
19
+ /**
20
+ * This file is part of helpers4.
21
+ * Copyright (C) 2025 baxyz
22
+ * SPDX-License-Identifier: LGPL-3.0-or-later
23
+ */
24
+ /**
25
+ * Compares two prerelease identifier arrays according to SemVer spec
26
+ * Rules:
27
+ * - Numeric identifiers are compared as integers
28
+ * - Alphanumeric identifiers are compared lexically (ASCII)
29
+ * - Numeric identifiers have lower precedence than alphanumeric
30
+ * - A larger set of prerelease fields has higher precedence if all preceding are equal
31
+ * @param pre1 - First prerelease array
32
+ * @param pre2 - Second prerelease array
33
+ * @returns -1, 0, or 1
34
+ */
35
+ function comparePrerelease(pre1, pre2) {
36
+ if (pre1.length === 0 && pre2.length === 0) return 0;
37
+ if (pre1.length === 0) return 1;
38
+ if (pre2.length === 0) return -1;
39
+ const maxLength = Math.max(pre1.length, pre2.length);
40
+ for (let i = 0; i < maxLength; i++) {
41
+ if (i >= pre1.length) return -1;
42
+ if (i >= pre2.length) return 1;
43
+ const id1 = pre1[i];
44
+ const id2 = pre2[i];
45
+ const isNum1 = /^\d+$/.test(id1);
46
+ const isNum2 = /^\d+$/.test(id2);
47
+ if (isNum1 && isNum2) {
48
+ const num1 = parseInt(id1, 10);
49
+ const num2 = parseInt(id2, 10);
50
+ if (num1 < num2) return -1;
51
+ if (num1 > num2) return 1;
52
+ } else if (isNum1) return -1;
53
+ else if (isNum2) return 1;
54
+ else {
55
+ if (id1 < id2) return -1;
56
+ if (id1 > id2) return 1;
57
+ }
58
+ }
59
+ return 0;
4
60
  }
5
- // helpers/version/compare.ts
61
+ /**
62
+ * Compares two semantic version strings according to SemVer 2.0.0 specification
63
+ *
64
+ * Supports:
65
+ * - Core version: MAJOR.MINOR.PATCH
66
+ * - Pre-release: -alpha, -beta.1, -rc.1, etc.
67
+ * - Build metadata: +build, +sha.abc123 (ignored in comparison per spec)
68
+ * - Optional 'v' prefix
69
+ *
70
+ * @param version1 - First version string
71
+ * @param version2 - Second version string
72
+ * @returns -1 if version1 < version2, 0 if equal, 1 if version1 > version2
73
+ * @example
74
+ * compare('1.0.0', '2.0.0') // -1
75
+ * compare('1.0.0-alpha', '1.0.0') // -1 (prerelease < release)
76
+ * compare('1.0.0-alpha', '1.0.0-beta') // -1
77
+ * compare('1.0.0-alpha.1', '1.0.0-alpha.2') // -1
78
+ * compare('1.0.0+build1', '1.0.0+build2') // 0 (build metadata ignored)
79
+ * @since 1.9.0
80
+ */
6
81
  function compare(version1, version2) {
7
- const normalize = (v) => v.replace(/^v/, "");
8
- const v1 = normalize(version1);
9
- const v2 = normalize(version2);
10
- const parts1 = v1.split(".").map(Number);
11
- const parts2 = v2.split(".").map(Number);
12
- const maxLength = Math.max(parts1.length, parts2.length);
13
- for (let i = 0;i < maxLength; i++) {
14
- const part1 = parts1[i] || 0;
15
- const part2 = parts2[i] || 0;
16
- if (part1 < part2)
17
- return -1;
18
- if (part1 > part2)
19
- return 1;
20
- }
21
- return 0;
82
+ const v1 = parse(version1);
83
+ const v2 = parse(version2);
84
+ if (v1.major !== v2.major) return v1.major < v2.major ? -1 : 1;
85
+ if (v1.minor !== v2.minor) return v1.minor < v2.minor ? -1 : 1;
86
+ if (v1.patch !== v2.patch) return v1.patch < v2.patch ? -1 : 1;
87
+ return comparePrerelease(v1.prerelease, v2.prerelease);
88
+ }
89
+ //#endregion
90
+ //#region helpers/version/increment.ts
91
+ function increment(version, type) {
92
+ if (version === void 0 || version === null) return version;
93
+ const hasV = version.startsWith("v");
94
+ const parts = version.replace(/^v/, "").split(".").map(Number);
95
+ while (parts.length < 3) parts.push(0);
96
+ let [major, minor, patch] = parts;
97
+ switch (type) {
98
+ case "major":
99
+ major++;
100
+ minor = 0;
101
+ patch = 0;
102
+ break;
103
+ case "minor":
104
+ minor++;
105
+ patch = 0;
106
+ break;
107
+ case "patch":
108
+ patch++;
109
+ break;
110
+ default: throw new Error(`Invalid increment type: ${type}`);
111
+ }
112
+ const result = `${major}.${minor}.${patch}`;
113
+ return hasV ? `v${result}` : result;
22
114
  }
23
- // helpers/version/satisfiesRange.ts
115
+ //#endregion
116
+ //#region helpers/version/isPrerelease.ts
117
+ function isPrerelease(version) {
118
+ if (version === void 0 || version === null) return version;
119
+ if (typeof version === "string") return version.split("+")[0].includes("-");
120
+ return version.prerelease.length > 0;
121
+ }
122
+ //#endregion
123
+ //#region helpers/version/satisfiesRange.ts
124
+ /**
125
+ * This file is part of helpers4.
126
+ * Copyright (C) 2025 baxyz
127
+ * SPDX-License-Identifier: LGPL-3.0-or-later
128
+ */
129
+ /**
130
+ * Checks if a version satisfies a range (simple implementation)
131
+ * @param version - Version to check
132
+ * @param range - Range pattern (e.g., ">=1.0.0", "~1.2.0", "^1.0.0")
133
+ * @returns True if version satisfies the range
134
+ * @since 1.9.0
135
+ */
24
136
  function satisfiesRange(version, range) {
25
- const normalize = (v) => v.replace(/^v/, "");
26
- const normalizedVersion = normalize(version);
27
- if (!range.match(/[~^<>=]/)) {
28
- return normalizedVersion === normalize(range);
29
- }
30
- if (range.startsWith(">=")) {
31
- const targetVersion = normalize(range.slice(2));
32
- return compareVersionsSimple(normalizedVersion, targetVersion) >= 0;
33
- }
34
- if (range.startsWith(">")) {
35
- const targetVersion = normalize(range.slice(1));
36
- return compareVersionsSimple(normalizedVersion, targetVersion) > 0;
37
- }
38
- if (range.startsWith("<=")) {
39
- const targetVersion = normalize(range.slice(2));
40
- return compareVersionsSimple(normalizedVersion, targetVersion) <= 0;
41
- }
42
- if (range.startsWith("<")) {
43
- const targetVersion = normalize(range.slice(1));
44
- return compareVersionsSimple(normalizedVersion, targetVersion) < 0;
45
- }
46
- if (range.startsWith("^")) {
47
- const targetVersion = normalize(range.slice(1));
48
- const [targetMajor] = targetVersion.split(".").map(Number);
49
- const [versionMajor] = normalizedVersion.split(".").map(Number);
50
- return versionMajor === targetMajor && compareVersionsSimple(normalizedVersion, targetVersion) >= 0;
51
- }
52
- if (range.startsWith("~")) {
53
- const targetVersion = normalize(range.slice(1));
54
- const [targetMajor, targetMinor] = targetVersion.split(".").map(Number);
55
- const [versionMajor, versionMinor] = normalizedVersion.split(".").map(Number);
56
- return versionMajor === targetMajor && versionMinor === targetMinor && compareVersionsSimple(normalizedVersion, targetVersion) >= 0;
57
- }
58
- return false;
137
+ const normalizedVersion = version.replace(/^v/, "");
138
+ if (!range.match(/[~^<>=]/)) return normalizedVersion === range.replace(/^v/, "");
139
+ if (range.startsWith(">=")) return compareVersionsSimple(normalizedVersion, range.slice(2).replace(/^v/, "")) >= 0;
140
+ if (range.startsWith(">")) return compareVersionsSimple(normalizedVersion, range.slice(1).replace(/^v/, "")) > 0;
141
+ if (range.startsWith("<=")) return compareVersionsSimple(normalizedVersion, range.slice(2).replace(/^v/, "")) <= 0;
142
+ if (range.startsWith("<")) return compareVersionsSimple(normalizedVersion, range.slice(1).replace(/^v/, "")) < 0;
143
+ if (range.startsWith("^")) {
144
+ const targetVersion = range.slice(1).replace(/^v/, "");
145
+ const [targetMajor] = targetVersion.split(".").map(Number);
146
+ const [versionMajor] = normalizedVersion.split(".").map(Number);
147
+ return versionMajor === targetMajor && compareVersionsSimple(normalizedVersion, targetVersion) >= 0;
148
+ }
149
+ if (range.startsWith("~")) {
150
+ const targetVersion = range.slice(1).replace(/^v/, "");
151
+ const [targetMajor, targetMinor] = targetVersion.split(".").map(Number);
152
+ const [versionMajor, versionMinor] = normalizedVersion.split(".").map(Number);
153
+ return versionMajor === targetMajor && versionMinor === targetMinor && compareVersionsSimple(normalizedVersion, targetVersion) >= 0;
154
+ } else return false;
59
155
  }
60
156
  function compareVersionsSimple(version1, version2) {
61
- const parts1 = version1.split(".").map(Number);
62
- const parts2 = version2.split(".").map(Number);
63
- const maxLength = Math.max(parts1.length, parts2.length);
64
- for (let i = 0;i < maxLength; i++) {
65
- const part1 = parts1[i] || 0;
66
- const part2 = parts2[i] || 0;
67
- if (part1 < part2)
68
- return -1;
69
- if (part1 > part2)
70
- return 1;
71
- }
72
- return 0;
157
+ const parts1 = version1.split(".").map(Number);
158
+ const parts2 = version2.split(".").map(Number);
159
+ const maxLength = Math.max(parts1.length, parts2.length);
160
+ for (let i = 0; i < maxLength; i++) {
161
+ const part1 = parts1[i] || 0;
162
+ const part2 = parts2[i] || 0;
163
+ if (part1 < part2) return -1;
164
+ if (part1 > part2) return 1;
165
+ }
166
+ return 0;
73
167
  }
74
- // helpers/version/increment.ts
75
- function increment(version, type) {
76
- const normalize = (v) => v.replace(/^v/, "");
77
- const hasV = version.startsWith("v");
78
- const normalizedVersion = normalize(version);
79
- const parts = normalizedVersion.split(".").map(Number);
80
- while (parts.length < 3) {
81
- parts.push(0);
82
- }
83
- let [major, minor, patch] = parts;
84
- switch (type) {
85
- case "major":
86
- major++;
87
- minor = 0;
88
- patch = 0;
89
- break;
90
- case "minor":
91
- minor++;
92
- patch = 0;
93
- break;
94
- case "patch":
95
- patch++;
96
- break;
97
- default:
98
- throw new Error(`Invalid increment type: ${type}`);
99
- }
100
- const result = `${major}.${minor}.${patch}`;
101
- return hasV ? `v${result}` : result;
168
+ //#endregion
169
+ //#region helpers/version/stringify.ts
170
+ function stringify(parsed) {
171
+ if (parsed === void 0 || parsed === null) return parsed;
172
+ return `${`${parsed.major}.${parsed.minor}.${parsed.patch}`}${parsed.prerelease.length > 0 ? `-${parsed.prerelease.join(".")}` : ""}${parsed.build.length > 0 ? `+${parsed.build.join(".")}` : ""}`;
173
+ }
174
+ //#endregion
175
+ //#region helpers/version/stripV.ts
176
+ function stripV(version) {
177
+ return typeof version === "string" && version.startsWith("v") ? version.slice(1) : version;
102
178
  }
103
- export {
104
- stripV,
105
- satisfiesRange,
106
- increment,
107
- compare
108
- };
179
+ //#endregion
180
+ export { compare, increment, isPrerelease, parse, satisfiesRange, stringify, stripV };
181
+
182
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../helpers/version/parse.ts","../../../helpers/version/compare.ts","../../../helpers/version/increment.ts","../../../helpers/version/isPrerelease.ts","../../../helpers/version/satisfiesRange.ts","../../../helpers/version/stringify.ts","../../../helpers/version/stripV.ts"],"sourcesContent":["/**\n * This file is part of helpers4.\n * Copyright (C) 2025 baxyz\n * SPDX-License-Identifier: LGPL-3.0-or-later\n */\n\n/**\n * Represents a parsed semantic version according to SemVer 2.0.0 specification\n * @since 2.0.0\n */\nexport interface ParsedVersion {\n /** Major version number */\n major: number;\n /** Minor version number */\n minor: number;\n /** Patch version number */\n patch: number;\n /** Pre-release identifiers (e.g., ['alpha', '1'] for -alpha.1) */\n prerelease: string[];\n /** Build metadata identifiers (e.g., ['build', '123'] for +build.123) */\n build: string[];\n}\n\n/**\n * Parses a semantic version string into its components according to SemVer 2.0.0 specification\n *\n * Supports:\n * - Core version: MAJOR.MINOR.PATCH\n * - Pre-release: -alpha, -beta.1, -rc.1, -0.3.7, -x.7.z.92\n * - Build metadata: +build, +sha.abc123, +20130313144700\n * - Optional 'v' prefix (commonly used in git tags)\n *\n * @param version - Version string to parse\n * @returns Parsed version object with major, minor, patch, prerelease, and build\n * @example\n * parse('1.2.3') // { major: 1, minor: 2, patch: 3, prerelease: [], build: [] }\n * parse('v1.0.0-alpha.1') // { major: 1, minor: 0, patch: 0, prerelease: ['alpha', '1'], build: [] }\n * parse('2.0.0+build.123') // { major: 2, minor: 0, patch: 0, prerelease: [], build: ['build', '123'] }\n * parse('1.0.0-beta+exp.sha.5114f85') // { major: 1, minor: 0, patch: 0, prerelease: ['beta'], build: ['exp', 'sha', '5114f85'] }\n * @since 2.0.0\n */\nexport function parse(version: string): ParsedVersion;\nexport function parse(version: undefined): undefined;\nexport function parse(version: null): null;\nexport function parse(version: string | undefined | null): ParsedVersion | undefined | null {\n if (version === undefined || version === null) return version;\n // Remove optional 'v' prefix\n const normalized = version.replace(/^v/, '');\n\n // Split build metadata first (everything after +)\n const [versionWithPrerelease, buildString] = normalized.split('+');\n const build = buildString ? buildString.split('.') : [];\n\n // Split prerelease (everything after -)\n const [coreVersion, prereleaseString] = versionWithPrerelease.split('-');\n const prerelease = prereleaseString ? prereleaseString.split('.') : [];\n\n // Parse core version\n const parts = coreVersion.split('.').map(Number);\n\n return {\n major: parts[0] || 0,\n minor: parts[1] || 0,\n patch: parts[2] || 0,\n prerelease,\n build,\n };\n}\n","/**\n * This file is part of helpers4.\n * Copyright (C) 2025 baxyz\n * SPDX-License-Identifier: LGPL-3.0-or-later\n */\n\nimport { parse } from './parse';\n\n/**\n * Compares two prerelease identifier arrays according to SemVer spec\n * Rules:\n * - Numeric identifiers are compared as integers\n * - Alphanumeric identifiers are compared lexically (ASCII)\n * - Numeric identifiers have lower precedence than alphanumeric\n * - A larger set of prerelease fields has higher precedence if all preceding are equal\n * @param pre1 - First prerelease array\n * @param pre2 - Second prerelease array\n * @returns -1, 0, or 1\n */\nfunction comparePrerelease(pre1: string[], pre2: string[]): number {\n // No prerelease has higher precedence than prerelease\n // e.g., 1.0.0 > 1.0.0-alpha\n if (pre1.length === 0 && pre2.length === 0) return 0;\n if (pre1.length === 0) return 1; // No prerelease > prerelease\n if (pre2.length === 0) return -1; // prerelease < no prerelease\n\n const maxLength = Math.max(pre1.length, pre2.length);\n\n for (let i = 0; i < maxLength; i++) {\n // A larger set has higher precedence if all preceding are equal\n if (i >= pre1.length) return -1;\n if (i >= pre2.length) return 1;\n\n const id1 = pre1[i];\n const id2 = pre2[i];\n\n const isNum1 = /^\\d+$/.test(id1);\n const isNum2 = /^\\d+$/.test(id2);\n\n // Both numeric: compare as integers\n if (isNum1 && isNum2) {\n const num1 = parseInt(id1, 10);\n const num2 = parseInt(id2, 10);\n if (num1 < num2) return -1;\n if (num1 > num2) return 1;\n // num1 === num2, continue to next identifier\n }\n // Numeric has lower precedence than alphanumeric\n else if (isNum1) {\n return -1;\n } else if (isNum2) {\n return 1;\n }\n // Both alphanumeric: compare lexically (ASCII sort)\n else {\n if (id1 < id2) return -1;\n if (id1 > id2) return 1;\n // id1 === id2, continue to next identifier\n }\n }\n\n return 0;\n}\n\n/**\n * Compares two semantic version strings according to SemVer 2.0.0 specification\n *\n * Supports:\n * - Core version: MAJOR.MINOR.PATCH\n * - Pre-release: -alpha, -beta.1, -rc.1, etc.\n * - Build metadata: +build, +sha.abc123 (ignored in comparison per spec)\n * - Optional 'v' prefix\n *\n * @param version1 - First version string\n * @param version2 - Second version string\n * @returns -1 if version1 < version2, 0 if equal, 1 if version1 > version2\n * @example\n * compare('1.0.0', '2.0.0') // -1\n * compare('1.0.0-alpha', '1.0.0') // -1 (prerelease < release)\n * compare('1.0.0-alpha', '1.0.0-beta') // -1\n * compare('1.0.0-alpha.1', '1.0.0-alpha.2') // -1\n * compare('1.0.0+build1', '1.0.0+build2') // 0 (build metadata ignored)\n * @since 1.9.0\n */\nexport function compare(version1: string, version2: string): number {\n const v1 = parse(version1);\n const v2 = parse(version2);\n\n // Compare major, minor, patch\n if (v1.major !== v2.major) return v1.major < v2.major ? -1 : 1;\n if (v1.minor !== v2.minor) return v1.minor < v2.minor ? -1 : 1;\n if (v1.patch !== v2.patch) return v1.patch < v2.patch ? -1 : 1;\n\n // Compare prerelease (build metadata is ignored per SemVer spec)\n return comparePrerelease(v1.prerelease, v2.prerelease);\n}\n","/**\n * This file is part of helpers4.\n * Copyright (C) 2025 baxyz\n * SPDX-License-Identifier: LGPL-3.0-or-later\n */\n\n/**\n * Increments a semantic version\n * @param version - The version to increment\n * @param type - The increment type ('major', 'minor', 'patch')\n * @returns Incremented version string\n * @since 1.9.0\n */\nexport function increment(version: string, type: 'major' | 'minor' | 'patch'): string;\nexport function increment(version: undefined, type: 'major' | 'minor' | 'patch'): undefined;\nexport function increment(version: null, type: 'major' | 'minor' | 'patch'): null;\nexport function increment(\n version: string | undefined | null,\n type: 'major' | 'minor' | 'patch'\n): string | undefined | null {\n if (version === undefined || version === null) return version;\n const hasV = version.startsWith('v');\n const normalizedVersion = version.replace(/^v/, '');\n\n const parts = normalizedVersion.split('.').map(Number);\n\n // Ensure we have at least major.minor.patch\n while (parts.length < 3) {\n parts.push(0);\n }\n\n let [major, minor, patch] = parts;\n\n switch (type) {\n case 'major':\n major++;\n minor = 0;\n patch = 0;\n break;\n case 'minor':\n minor++;\n patch = 0;\n break;\n case 'patch':\n patch++;\n break;\n default:\n throw new Error(`Invalid increment type: ${type}`);\n }\n\n const result = `${major}.${minor}.${patch}`;\n return hasV ? `v${result}` : result;\n}\n","/**\n * This file is part of helpers4.\n * Copyright (C) 2025 baxyz\n * SPDX-License-Identifier: LGPL-3.0-or-later\n */\n\nimport type { ParsedVersion } from './parse';\n\n/**\n * Returns `true` when the version string has a prerelease suffix\n * (i.e. contains a `-` after the core `MAJOR.MINOR.PATCH`).\n *\n * @param version - A semantic version string (e.g. `'2.0.0-alpha.1'`, `'1.0.0'`).\n * @returns `true` if the version is a prerelease, `false` otherwise.\n * @example\n * isPrerelease('2.0.0-alpha.1') // true\n * isPrerelease('1.0.0-rc.0') // true\n * isPrerelease('1.0.0') // false\n * isPrerelease('2.1.0') // false\n * @since next\n */\nexport function isPrerelease(version: string): boolean;\n/**\n * Returns `true` when the parsed version has at least one prerelease identifier.\n *\n * @param version - A {@link ParsedVersion} object (as returned by {@link parse}).\n * @returns `true` if `version.prerelease` is non-empty, `false` otherwise.\n * @example\n * isPrerelease(parse('2.0.0-alpha.1')) // true\n * isPrerelease(parse('1.0.0')) // false\n * @since next\n */\nexport function isPrerelease(version: ParsedVersion): boolean;\nexport function isPrerelease(version: undefined): undefined;\nexport function isPrerelease(version: null): null;\nexport function isPrerelease(version: string | ParsedVersion | undefined | null): boolean | undefined | null {\n if (version === undefined || version === null) return version;\n if (typeof version === 'string') return version.split('+')[0].includes('-');\n return version.prerelease.length > 0;\n}\n","/**\n * This file is part of helpers4.\n * Copyright (C) 2025 baxyz\n * SPDX-License-Identifier: LGPL-3.0-or-later\n */\n\n/**\n * Checks if a version satisfies a range (simple implementation)\n * @param version - Version to check\n * @param range - Range pattern (e.g., \">=1.0.0\", \"~1.2.0\", \"^1.0.0\")\n * @returns True if version satisfies the range\n * @since 1.9.0\n */\nexport function satisfiesRange(version: string, range: string): boolean {\n const normalizedVersion = version.replace(/^v/, '');\n\n // Handle exact match\n if (!range.match(/[~^<>=]/)) {\n return normalizedVersion === range.replace(/^v/, '');\n }\n\n // Handle >= operator\n if (range.startsWith('>=')) {\n const targetVersion = range.slice(2).replace(/^v/, '');\n return compareVersionsSimple(normalizedVersion, targetVersion) >= 0;\n }\n\n // Handle > operator\n if (range.startsWith('>')) {\n const targetVersion = range.slice(1).replace(/^v/, '');\n return compareVersionsSimple(normalizedVersion, targetVersion) > 0;\n }\n\n // Handle <= operator\n if (range.startsWith('<=')) {\n const targetVersion = range.slice(2).replace(/^v/, '');\n return compareVersionsSimple(normalizedVersion, targetVersion) <= 0;\n }\n\n // Handle < operator\n if (range.startsWith('<')) {\n const targetVersion = range.slice(1).replace(/^v/, '');\n return compareVersionsSimple(normalizedVersion, targetVersion) < 0;\n }\n\n // Handle caret range (^1.2.3 allows patch and minor updates)\n if (range.startsWith('^')) {\n const targetVersion = range.slice(1).replace(/^v/, '');\n const [targetMajor] = targetVersion.split('.').map(Number);\n const [versionMajor] = normalizedVersion.split('.').map(Number);\n\n return versionMajor === targetMajor &&\n compareVersionsSimple(normalizedVersion, targetVersion) >= 0;\n }\n\n // Handle tilde range (~1.2.3 allows patch updates)\n if (range.startsWith('~')) {\n const targetVersion = range.slice(1).replace(/^v/, '');\n const [targetMajor, targetMinor] = targetVersion.split('.').map(Number);\n const [versionMajor, versionMinor] = normalizedVersion.split('.').map(Number);\n\n return versionMajor === targetMajor &&\n versionMinor === targetMinor &&\n compareVersionsSimple(normalizedVersion, targetVersion) >= 0;\n } else {\n // Unsupported range format\n return false;\n }\n}\n\nfunction compareVersionsSimple(version1: string, version2: string): number {\n const parts1 = version1.split('.').map(Number);\n const parts2 = version2.split('.').map(Number);\n\n const maxLength = Math.max(parts1.length, parts2.length);\n\n for (let i = 0; i < maxLength; i++) {\n const part1 = parts1[i] || 0;\n const part2 = parts2[i] || 0;\n\n if (part1 < part2) return -1;\n if (part1 > part2) return 1;\n }\n\n return 0;\n}\n","/**\n * This file is part of helpers4.\n * Copyright (C) 2025 baxyz\n * SPDX-License-Identifier: LGPL-3.0-or-later\n */\n\nimport type { ParsedVersion } from './parse';\n\n/**\n * Reconstruct a semantic version string from a {@link ParsedVersion} object.\n *\n * This is the inverse of {@link parse}:\n * `stringify(parse(v)) === stripV(v)` for any valid SemVer string `v`.\n *\n * @param parsed - A parsed semantic version object.\n * @returns The reconstructed version string (without leading `v`).\n * @example\n * stringify({ major: 1, minor: 2, patch: 3, prerelease: [], build: [] })\n * // => '1.2.3'\n * @example\n * stringify({ major: 2, minor: 0, patch: 0, prerelease: ['alpha', '1'], build: [] })\n * // => '2.0.0-alpha.1'\n * @example\n * stringify({ major: 1, minor: 0, patch: 0, prerelease: ['beta'], build: ['exp', 'sha', '5114f85'] })\n * // => '1.0.0-beta+exp.sha.5114f85'\n * @since next\n */\nexport function stringify(parsed: ParsedVersion): string;\nexport function stringify(parsed: undefined): undefined;\nexport function stringify(parsed: null): null;\nexport function stringify(parsed: ParsedVersion | undefined | null): string | undefined | null {\n if (parsed === undefined || parsed === null) return parsed;\n const base = `${parsed.major}.${parsed.minor}.${parsed.patch}`;\n const prerelease = parsed.prerelease.length > 0 ? `-${parsed.prerelease.join('.')}` : '';\n const build = parsed.build.length > 0 ? `+${parsed.build.join('.')}` : '';\n return `${base}${prerelease}${build}`;\n}\n","/**\n * This file is part of helpers4.\n * Copyright (C) 2025 baxyz\n * SPDX-License-Identifier: LGPL-3.0-or-later\n */\n\n/**\n * Strip the leading \"v\" from a version string if it exists.\n * \n * @param version - The version string to process\n * @returns The version string without leading \"v\", or the original value if it's not a string or doesn't start with \"v\"\n * \n * @example\n * ```typescript\n * stripV(\"v1.2.3\") // \"1.2.3\"\n * stripV(\"1.2.3\") // \"1.2.3\"\n * stripV(\"v20.1.0\") // \"20.1.0\"\n * stripV(null) // null\n * stripV(undefined) // undefined\n * stripV(\"\") // \"\"\n * stripV(\"1.0.0-beta\") // \"1.0.0-beta\"\n * ```\n * @since 1.9.0\n */\nexport function stripV(version: string): string;\nexport function stripV(version: null): null;\nexport function stripV(version: undefined): undefined;\nexport function stripV(version: string | null | undefined): string | null | undefined {\n return typeof version === \"string\" && version.startsWith(\"v\") ? version.slice(1) : version;\n}\n"],"mappings":"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"}