Skip to content

Commit 0aa3e98

Browse files
authored
fix(cli): cdk init fails with pre-release --lib-version (#1013)
Using `cdk init` with a pre-release version via `--lib-version` (e.g., `cdk init --lib-version 2.234.0-rc.0`) failed because the `rangeFromSemver` function could not parse versions with pre-release identifiers or build metadata. This fix updates the regex to correctly handle these semver suffixes, allowing `cdk init` to work with pre-release versions. --- By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license
1 parent 3b11750 commit 0aa3e98

File tree

2 files changed

+176
-15
lines changed

2 files changed

+176
-15
lines changed

packages/@aws-cdk/toolkit-lib/lib/util/version-range.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { ToolkitError } from '../toolkit/toolkit-error';
66
export type RangeType = 'bracket' | 'pep';
77

88
export function rangeFromSemver(ver: string, targetType: RangeType) {
9-
const re = ver.match(/^([^\d]*)([\d.]*)$/);
9+
const re = ver.match(/^([^\d]*)([\d.]*)[^\s]*$/);
1010
if (!re || !semver.valid(re[2])) {
1111
throw new ToolkitError('not a semver or unsupported range syntax');
1212
}
Lines changed: 175 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,186 @@
1+
import { ToolkitError } from '../../lib/toolkit/toolkit-error';
12
import { rangeFromSemver } from '../../lib/util/version-range';
23

34
describe('rangeFromSemver', () => {
4-
describe('bracket', () => {
5-
test('valid', () => {
6-
expect(rangeFromSemver('1.2.3', 'bracket')).toEqual('1.2.3');
7-
expect(rangeFromSemver('^1.2.3', 'bracket')).toEqual('[1.2.3,2.0.0)');
5+
describe('bracket format', () => {
6+
describe('exact versions (no prefix)', () => {
7+
test('basic semver versions', () => {
8+
expect(rangeFromSemver('1.2.3', 'bracket')).toEqual('1.2.3');
9+
expect(rangeFromSemver('0.0.1', 'bracket')).toEqual('0.0.1');
10+
expect(rangeFromSemver('10.20.30', 'bracket')).toEqual('10.20.30');
11+
});
12+
13+
test('versions with pre-release identifiers', () => {
14+
expect(rangeFromSemver('1.2.3-alpha', 'bracket')).toEqual('1.2.3-alpha');
15+
expect(rangeFromSemver('2.0.0-beta.1', 'bracket')).toEqual('2.0.0-beta.1');
16+
expect(rangeFromSemver('1.0.0-rc.1+build.1', 'bracket')).toEqual('1.0.0-rc.1+build.1');
17+
});
18+
19+
test('versions with build metadata', () => {
20+
expect(rangeFromSemver('1.2.3+build.1', 'bracket')).toEqual('1.2.3+build.1');
21+
expect(rangeFromSemver('1.0.0+20130313144700', 'bracket')).toEqual('1.0.0+20130313144700');
22+
});
23+
});
24+
25+
describe('caret ranges (^)', () => {
26+
test('basic caret ranges', () => {
27+
expect(rangeFromSemver('^1.2.3', 'bracket')).toEqual('[1.2.3,2.0.0)');
28+
expect(rangeFromSemver('^0.2.3', 'bracket')).toEqual('[0.2.3,1.0.0)');
29+
expect(rangeFromSemver('^10.5.2', 'bracket')).toEqual('[10.5.2,11.0.0)');
30+
});
31+
32+
test('caret ranges with zero major version', () => {
33+
expect(rangeFromSemver('^0.0.1', 'bracket')).toEqual('[0.0.1,1.0.0)');
34+
expect(rangeFromSemver('^0.1.0', 'bracket')).toEqual('[0.1.0,1.0.0)');
35+
});
36+
37+
test('caret ranges with large version numbers', () => {
38+
expect(rangeFromSemver('^999.888.777', 'bracket')).toEqual('[999.888.777,1000.0.0)');
39+
});
40+
});
41+
});
42+
43+
describe('pep format', () => {
44+
describe('exact versions (no prefix)', () => {
45+
test('basic semver versions', () => {
46+
expect(rangeFromSemver('1.2.3', 'pep')).toEqual('==1.2.3');
47+
expect(rangeFromSemver('0.0.1', 'pep')).toEqual('==0.0.1');
48+
expect(rangeFromSemver('10.20.30', 'pep')).toEqual('==10.20.30');
49+
});
50+
51+
test('versions with pre-release identifiers', () => {
52+
expect(rangeFromSemver('1.2.3-alpha', 'pep')).toEqual('==1.2.3-alpha');
53+
expect(rangeFromSemver('2.0.0-beta.1', 'pep')).toEqual('==2.0.0-beta.1');
54+
expect(rangeFromSemver('1.0.0-rc.1+build.1', 'pep')).toEqual('==1.0.0-rc.1+build.1');
55+
});
56+
57+
test('versions with build metadata', () => {
58+
expect(rangeFromSemver('1.2.3+build.1', 'pep')).toEqual('==1.2.3+build.1');
59+
expect(rangeFromSemver('1.0.0+20130313144700', 'pep')).toEqual('==1.0.0+20130313144700');
60+
});
61+
});
62+
63+
describe('caret ranges (^)', () => {
64+
test('basic caret ranges', () => {
65+
expect(rangeFromSemver('^1.2.3', 'pep')).toEqual('>=1.2.3,<2.0.0');
66+
expect(rangeFromSemver('^0.2.3', 'pep')).toEqual('>=0.2.3,<1.0.0');
67+
expect(rangeFromSemver('^10.5.2', 'pep')).toEqual('>=10.5.2,<11.0.0');
68+
});
69+
70+
test('caret ranges with zero major version', () => {
71+
expect(rangeFromSemver('^0.0.1', 'pep')).toEqual('>=0.0.1,<1.0.0');
72+
expect(rangeFromSemver('^0.1.0', 'pep')).toEqual('>=0.1.0,<1.0.0');
73+
});
74+
75+
test('caret ranges with large version numbers', () => {
76+
expect(rangeFromSemver('^999.888.777', 'pep')).toEqual('>=999.888.777,<1000.0.0');
77+
});
878
});
979
});
1080

11-
describe('pep', () => {
12-
test('valid', () => {
13-
expect(rangeFromSemver('1.2.3', 'pep')).toEqual('==1.2.3');
14-
expect(rangeFromSemver('^1.2.3', 'pep')).toEqual('>=1.2.3,<2.0.0');
81+
describe('error handling', () => {
82+
describe('invalid semver versions', () => {
83+
test('incomplete version numbers', () => {
84+
expect(() => rangeFromSemver('1.2', 'bracket')).toThrow(ToolkitError);
85+
expect(() => rangeFromSemver('1', 'bracket')).toThrow(ToolkitError);
86+
expect(() => rangeFromSemver('1.2', 'pep')).toThrow(ToolkitError);
87+
expect(() => rangeFromSemver('1', 'pep')).toThrow(ToolkitError);
88+
});
89+
90+
test('invalid version formats', () => {
91+
expect(() => rangeFromSemver('1.2.3.4', 'bracket')).toThrow(ToolkitError);
92+
expect(() => rangeFromSemver('v1.2.3', 'bracket')).toThrow(ToolkitError);
93+
expect(() => rangeFromSemver('1.2.3.4', 'pep')).toThrow(ToolkitError);
94+
expect(() => rangeFromSemver('v1.2.3', 'pep')).toThrow(ToolkitError);
95+
});
96+
97+
test('non-numeric version parts', () => {
98+
expect(() => rangeFromSemver('a.b.c', 'bracket')).toThrow(ToolkitError);
99+
expect(() => rangeFromSemver('1.b.3', 'bracket')).toThrow(ToolkitError);
100+
expect(() => rangeFromSemver('a.b.c', 'pep')).toThrow(ToolkitError);
101+
expect(() => rangeFromSemver('1.b.3', 'pep')).toThrow(ToolkitError);
102+
});
103+
104+
test('empty or whitespace strings', () => {
105+
expect(() => rangeFromSemver('', 'bracket')).toThrow(ToolkitError);
106+
expect(() => rangeFromSemver(' ', 'bracket')).toThrow(ToolkitError);
107+
expect(() => rangeFromSemver('', 'pep')).toThrow(ToolkitError);
108+
expect(() => rangeFromSemver(' ', 'pep')).toThrow(ToolkitError);
109+
});
110+
});
111+
112+
describe('unsupported range prefixes', () => {
113+
test('tilde ranges (~)', () => {
114+
expect(() => rangeFromSemver('~1.2.3', 'bracket')).toThrow(ToolkitError);
115+
expect(() => rangeFromSemver('~1.2.3', 'pep')).toThrow(ToolkitError);
116+
expect(() => rangeFromSemver('~0.1.0', 'bracket')).toThrow(ToolkitError);
117+
expect(() => rangeFromSemver('~0.1.0', 'pep')).toThrow(ToolkitError);
118+
});
119+
120+
test('comparison operators', () => {
121+
expect(() => rangeFromSemver('>1.2.3', 'bracket')).toThrow(ToolkitError);
122+
expect(() => rangeFromSemver('>=1.2.3', 'bracket')).toThrow(ToolkitError);
123+
expect(() => rangeFromSemver('<1.2.3', 'bracket')).toThrow(ToolkitError);
124+
expect(() => rangeFromSemver('<=1.2.3', 'bracket')).toThrow(ToolkitError);
125+
expect(() => rangeFromSemver('>1.2.3', 'pep')).toThrow(ToolkitError);
126+
expect(() => rangeFromSemver('>=1.2.3', 'pep')).toThrow(ToolkitError);
127+
expect(() => rangeFromSemver('<1.2.3', 'pep')).toThrow(ToolkitError);
128+
expect(() => rangeFromSemver('<=1.2.3', 'pep')).toThrow(ToolkitError);
129+
});
130+
131+
test('wildcard patterns', () => {
132+
expect(() => rangeFromSemver('1.*', 'bracket')).toThrow(ToolkitError);
133+
expect(() => rangeFromSemver('1.2.*', 'bracket')).toThrow(ToolkitError);
134+
expect(() => rangeFromSemver('*', 'bracket')).toThrow(ToolkitError);
135+
expect(() => rangeFromSemver('1.*', 'pep')).toThrow(ToolkitError);
136+
expect(() => rangeFromSemver('1.2.*', 'pep')).toThrow(ToolkitError);
137+
expect(() => rangeFromSemver('*', 'pep')).toThrow(ToolkitError);
138+
});
139+
140+
test('hyphen ranges', () => {
141+
expect(() => rangeFromSemver('1.2.3 - 2.3.4', 'bracket')).toThrow(ToolkitError);
142+
expect(() => rangeFromSemver('1.2.3 - 2.3.4', 'pep')).toThrow(ToolkitError);
143+
});
144+
145+
test('x-ranges', () => {
146+
expect(() => rangeFromSemver('1.2.x', 'bracket')).toThrow(ToolkitError);
147+
expect(() => rangeFromSemver('1.x.x', 'bracket')).toThrow(ToolkitError);
148+
expect(() => rangeFromSemver('1.2.x', 'pep')).toThrow(ToolkitError);
149+
expect(() => rangeFromSemver('1.x.x', 'pep')).toThrow(ToolkitError);
150+
});
151+
152+
test('multiple operators', () => {
153+
expect(() => rangeFromSemver('^^1.2.3', 'bracket')).toThrow(ToolkitError);
154+
expect(() => rangeFromSemver('~^1.2.3', 'bracket')).toThrow(ToolkitError);
155+
expect(() => rangeFromSemver('^^1.2.3', 'pep')).toThrow(ToolkitError);
156+
expect(() => rangeFromSemver('~^1.2.3', 'pep')).toThrow(ToolkitError);
157+
});
158+
});
159+
160+
test('error message content', () => {
161+
expect(() => rangeFromSemver('1.2', 'bracket')).toThrow('not a semver or unsupported range syntax');
162+
expect(() => rangeFromSemver('~1.2.3', 'bracket')).toThrow('unsupported range syntax - ~');
163+
expect(() => rangeFromSemver('>1.2.3', 'pep')).toThrow('unsupported range syntax - >');
15164
});
16165
});
17166

18-
test('invalid', () => {
19-
expect(() => rangeFromSemver('1.2', 'bracket')).toThrow();
20-
expect(() => rangeFromSemver('~1.2.3', 'bracket')).toThrow();
21-
expect(() => rangeFromSemver('1.2.3-1.4.5', 'bracket')).toThrow();
22-
expect(() => rangeFromSemver('>2.4.5', 'bracket')).toThrow();
23-
expect(() => rangeFromSemver('2.*', 'bracket')).toThrow();
167+
describe('edge cases', () => {
168+
test('versions with leading/trailing whitespace', () => {
169+
expect(() => rangeFromSemver(' 1.2.3', 'bracket')).toThrow(ToolkitError);
170+
expect(() => rangeFromSemver('1.2.3 ', 'bracket')).toThrow(ToolkitError);
171+
expect(() => rangeFromSemver(' ^1.2.3', 'bracket')).toThrow(ToolkitError);
172+
});
173+
174+
test('versions with unusual but valid semver formats', () => {
175+
expect(rangeFromSemver('1.2.3-alpha.1.2.3', 'bracket')).toEqual('1.2.3-alpha.1.2.3');
176+
expect(rangeFromSemver('^1.2.3-alpha.1.2.3', 'bracket')).toEqual('[1.2.3,2.0.0)');
177+
expect(rangeFromSemver('1.2.3-alpha.1.2.3', 'pep')).toEqual('==1.2.3-alpha.1.2.3');
178+
expect(rangeFromSemver('^1.2.3-alpha.1.2.3', 'pep')).toEqual('>=1.2.3,<2.0.0');
179+
});
180+
181+
test('maximum version numbers', () => {
182+
expect(rangeFromSemver('^999999.999999.999999', 'bracket')).toEqual('[999999.999999.999999,1000000.0.0)');
183+
expect(rangeFromSemver('^999999.999999.999999', 'pep')).toEqual('>=999999.999999.999999,<1000000.0.0');
184+
});
24185
});
25186
});

0 commit comments

Comments
 (0)