Skip to content

Commit 9d16385

Browse files
committed
add >= version parsing
fixes microsoft#13590
1 parent 6ef5077 commit 9d16385

2 files changed

Lines changed: 83 additions & 51 deletions

File tree

src/vs/platform/extensions/node/extensionValidator.ts

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import * as paths from 'vs/base/common/paths';
1111

1212
export interface IParsedVersion {
1313
hasCaret: boolean;
14+
hasGreaterEquals: boolean;
1415
majorBase: number;
1516
majorMustEqual: boolean;
1617
minorBase: number;
@@ -27,9 +28,10 @@ export interface INormalizedVersion {
2728
minorMustEqual: boolean;
2829
patchBase: number;
2930
patchMustEqual: boolean;
31+
isMinimum: boolean;
3032
}
3133

32-
const VERSION_REGEXP = /^(\^)?((\d+)|x)\.((\d+)|x)\.((\d+)|x)(\-.*)?$/;
34+
const VERSION_REGEXP = /^(\^|>=)?((\d+)|x)\.((\d+)|x)\.((\d+)|x)(\-.*)?$/;
3335

3436
export function isValidVersionStr(version: string): boolean {
3537
version = version.trim();
@@ -46,6 +48,7 @@ export function parseVersion(version: string): IParsedVersion {
4648
if (version === '*') {
4749
return {
4850
hasCaret: false,
51+
hasGreaterEquals: false,
4952
majorBase: 0,
5053
majorMustEqual: false,
5154
minorBase: 0,
@@ -58,7 +61,8 @@ export function parseVersion(version: string): IParsedVersion {
5861

5962
let m = version.match(VERSION_REGEXP);
6063
return {
61-
hasCaret: !!m[1],
64+
hasCaret: m[1] === '^',
65+
hasGreaterEquals: m[1] === '>=',
6266
majorBase: m[2] === 'x' ? 0 : parseInt(m[2], 10),
6367
majorMustEqual: (m[2] === 'x' ? false : true),
6468
minorBase: m[4] === 'x' ? 0 : parseInt(m[4], 10),
@@ -96,7 +100,8 @@ export function normalizeVersion(version: IParsedVersion): INormalizedVersion {
96100
minorBase: minorBase,
97101
minorMustEqual: minorMustEqual,
98102
patchBase: patchBase,
99-
patchMustEqual: patchMustEqual
103+
patchMustEqual: patchMustEqual,
104+
isMinimum: version.hasGreaterEquals
100105
};
101106
}
102107

@@ -131,6 +136,26 @@ export function isValidVersion(_version: string | INormalizedVersion, _desiredVe
131136
let minorMustEqual = desiredVersion.minorMustEqual;
132137
let patchMustEqual = desiredVersion.patchMustEqual;
133138

139+
if (desiredVersion.isMinimum) {
140+
if (majorBase > desiredMajorBase) {
141+
return true;
142+
}
143+
144+
if (majorBase < desiredMajorBase) {
145+
return false;
146+
}
147+
148+
if (minorBase > desiredMinorBase) {
149+
return true;
150+
}
151+
152+
if (minorBase < desiredMinorBase) {
153+
return false;
154+
}
155+
156+
return patchBase >= desiredPatchBase;
157+
}
158+
134159
// Anything < 1.0.0 is compatible with >= 1.0.0, except exact matches
135160
if (majorBase === 1 && desiredMajorBase === 0 && (!majorMustEqual || !minorMustEqual || !patchMustEqual)) {
136161
desiredMajorBase = 1;

src/vs/platform/extensions/test/node/extensionValidator.test.ts

Lines changed: 55 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -29,63 +29,54 @@ suite('Extension Version Validator', () => {
2929
});
3030

3131
test('parseVersion', () => {
32-
function assertParseVersion(version: string, hasCaret: boolean, majorBase: number, majorMustEqual: boolean, minorBase: number, minorMustEqual: boolean, patchBase: number, patchMustEqual: boolean, preRelease: string): void {
33-
let actual = parseVersion(version);
34-
let expected: IParsedVersion = {
35-
hasCaret: hasCaret,
36-
majorBase: majorBase,
37-
majorMustEqual: majorMustEqual,
38-
minorBase: minorBase,
39-
minorMustEqual: minorMustEqual,
40-
patchBase: patchBase,
41-
patchMustEqual: patchMustEqual,
42-
preRelease: preRelease
43-
};
32+
function assertParseVersion(version: string, hasCaret: boolean, hasGreaterEquals: boolean, majorBase: number, majorMustEqual: boolean, minorBase: number, minorMustEqual: boolean, patchBase: number, patchMustEqual: boolean, preRelease: string): void {
33+
const actual = parseVersion(version);
34+
const expected: IParsedVersion = { hasCaret, hasGreaterEquals, majorBase, majorMustEqual, minorBase, minorMustEqual, patchBase, patchMustEqual, preRelease };
35+
4436
assert.deepEqual(actual, expected, 'parseVersion for ' + version);
4537
}
4638

47-
assertParseVersion('0.10.0-dev', false, 0, true, 10, true, 0, true, '-dev');
48-
assertParseVersion('0.10.0', false, 0, true, 10, true, 0, true, null);
49-
assertParseVersion('0.10.1', false, 0, true, 10, true, 1, true, null);
50-
assertParseVersion('0.10.100', false, 0, true, 10, true, 100, true, null);
51-
assertParseVersion('0.11.0', false, 0, true, 11, true, 0, true, null);
52-
53-
assertParseVersion('x.x.x', false, 0, false, 0, false, 0, false, null);
54-
assertParseVersion('0.x.x', false, 0, true, 0, false, 0, false, null);
55-
assertParseVersion('0.10.x', false, 0, true, 10, true, 0, false, null);
56-
assertParseVersion('^0.10.0', true, 0, true, 10, true, 0, true, null);
57-
assertParseVersion('^0.10.2', true, 0, true, 10, true, 2, true, null);
58-
assertParseVersion('^1.10.2', true, 1, true, 10, true, 2, true, null);
59-
assertParseVersion('*', false, 0, false, 0, false, 0, false, null);
39+
assertParseVersion('0.10.0-dev', false, false, 0, true, 10, true, 0, true, '-dev');
40+
assertParseVersion('0.10.0', false, false, 0, true, 10, true, 0, true, null);
41+
assertParseVersion('0.10.1', false, false, 0, true, 10, true, 1, true, null);
42+
assertParseVersion('0.10.100', false, false, 0, true, 10, true, 100, true, null);
43+
assertParseVersion('0.11.0', false, false, 0, true, 11, true, 0, true, null);
44+
45+
assertParseVersion('x.x.x', false, false, 0, false, 0, false, 0, false, null);
46+
assertParseVersion('0.x.x', false, false, 0, true, 0, false, 0, false, null);
47+
assertParseVersion('0.10.x', false, false, 0, true, 10, true, 0, false, null);
48+
assertParseVersion('^0.10.0', true, false, 0, true, 10, true, 0, true, null);
49+
assertParseVersion('^0.10.2', true, false, 0, true, 10, true, 2, true, null);
50+
assertParseVersion('^1.10.2', true, false, 1, true, 10, true, 2, true, null);
51+
assertParseVersion('*', false, false, 0, false, 0, false, 0, false, null);
52+
53+
assertParseVersion('>=0.0.1', false, true, 0, true, 0, true, 1, true, null);
54+
assertParseVersion('>=2.4.3', false, true, 2, true, 4, true, 3, true, null);
6055
});
6156

6257
test('normalizeVersion', () => {
63-
function assertNormalizeVersion(version: string, majorBase: number, majorMustEqual: boolean, minorBase: number, minorMustEqual: boolean, patchBase: number, patchMustEqual: boolean): void {
64-
let actual = normalizeVersion(parseVersion(version));
65-
let expected: INormalizedVersion = {
66-
majorBase: majorBase,
67-
majorMustEqual: majorMustEqual,
68-
minorBase: minorBase,
69-
minorMustEqual: minorMustEqual,
70-
patchBase: patchBase,
71-
patchMustEqual: patchMustEqual
72-
};
58+
function assertNormalizeVersion(version: string, majorBase: number, majorMustEqual: boolean, minorBase: number, minorMustEqual: boolean, patchBase: number, patchMustEqual: boolean, isMinimum: boolean): void {
59+
const actual = normalizeVersion(parseVersion(version));
60+
const expected: INormalizedVersion = { majorBase, majorMustEqual, minorBase, minorMustEqual, patchBase, patchMustEqual, isMinimum };
7361
assert.deepEqual(actual, expected, 'parseVersion for ' + version);
7462
}
7563

76-
assertNormalizeVersion('0.10.0-dev', 0, true, 10, true, 0, true);
77-
assertNormalizeVersion('0.10.0', 0, true, 10, true, 0, true);
78-
assertNormalizeVersion('0.10.1', 0, true, 10, true, 1, true);
79-
assertNormalizeVersion('0.10.100', 0, true, 10, true, 100, true);
80-
assertNormalizeVersion('0.11.0', 0, true, 11, true, 0, true);
81-
82-
assertNormalizeVersion('x.x.x', 0, false, 0, false, 0, false);
83-
assertNormalizeVersion('0.x.x', 0, true, 0, false, 0, false);
84-
assertNormalizeVersion('0.10.x', 0, true, 10, true, 0, false);
85-
assertNormalizeVersion('^0.10.0', 0, true, 10, true, 0, false);
86-
assertNormalizeVersion('^0.10.2', 0, true, 10, true, 2, false);
87-
assertNormalizeVersion('^1.10.2', 1, true, 10, false, 2, false);
88-
assertNormalizeVersion('*', 0, false, 0, false, 0, false);
64+
assertNormalizeVersion('0.10.0-dev', 0, true, 10, true, 0, true, false);
65+
assertNormalizeVersion('0.10.0', 0, true, 10, true, 0, true, false);
66+
assertNormalizeVersion('0.10.1', 0, true, 10, true, 1, true, false);
67+
assertNormalizeVersion('0.10.100', 0, true, 10, true, 100, true, false);
68+
assertNormalizeVersion('0.11.0', 0, true, 11, true, 0, true, false);
69+
70+
assertNormalizeVersion('x.x.x', 0, false, 0, false, 0, false, false);
71+
assertNormalizeVersion('0.x.x', 0, true, 0, false, 0, false, false);
72+
assertNormalizeVersion('0.10.x', 0, true, 10, true, 0, false, false);
73+
assertNormalizeVersion('^0.10.0', 0, true, 10, true, 0, false, false);
74+
assertNormalizeVersion('^0.10.2', 0, true, 10, true, 2, false, false);
75+
assertNormalizeVersion('^1.10.2', 1, true, 10, false, 2, false, false);
76+
assertNormalizeVersion('*', 0, false, 0, false, 0, false, false);
77+
78+
assertNormalizeVersion('>=0.0.1', 0, true, 0, true, 1, true, true);
79+
assertNormalizeVersion('>=2.4.3', 2, true, 4, true, 3, true, true);
8980
});
9081

9182
test('isValidVersion', () => {
@@ -102,6 +93,11 @@ suite('Extension Version Validator', () => {
10293
testIsValidVersion('0.10.0-dev', '0.10.x', true);
10394
testIsValidVersion('0.10.0-dev', '^0.10.0', true);
10495
testIsValidVersion('0.10.0-dev', '*', true);
96+
testIsValidVersion('0.10.0-dev', '>=0.0.1', true);
97+
testIsValidVersion('0.10.0-dev', '>=0.0.10', true);
98+
testIsValidVersion('0.10.0-dev', '>=0.10.0', true);
99+
testIsValidVersion('0.10.0-dev', '>=0.10.1', false);
100+
testIsValidVersion('0.10.0-dev', '>=1.0.0', false);
105101

106102
testIsValidVersion('0.10.0', 'x.x.x', true);
107103
testIsValidVersion('0.10.0', '0.x.x', true);
@@ -152,6 +148,14 @@ suite('Extension Version Validator', () => {
152148
testIsValidVersion('1.0.0', '^1.0.0', true);
153149
testIsValidVersion('1.0.0', '^2.0.0', false);
154150
testIsValidVersion('1.0.0', '*', true);
151+
testIsValidVersion('1.0.0', '>=0.0.1', true);
152+
testIsValidVersion('1.0.0', '>=0.0.10', true);
153+
testIsValidVersion('1.0.0', '>=0.10.0', true);
154+
testIsValidVersion('1.0.0', '>=0.10.1', true);
155+
testIsValidVersion('1.0.0', '>=1.0.0', true);
156+
testIsValidVersion('1.0.0', '>=1.1.0', false);
157+
testIsValidVersion('1.0.0', '>=1.0.1', false);
158+
testIsValidVersion('1.0.0', '>=2.0.0', false);
155159

156160
testIsValidVersion('1.0.100', 'x.x.x', true);
157161
testIsValidVersion('1.0.100', '0.x.x', true);
@@ -179,6 +183,9 @@ suite('Extension Version Validator', () => {
179183
testIsValidVersion('1.100.0', '^1.100.0', true);
180184
testIsValidVersion('1.100.0', '^2.0.0', false);
181185
testIsValidVersion('1.100.0', '*', true);
186+
testIsValidVersion('1.100.0', '>=1.99.0', true);
187+
testIsValidVersion('1.100.0', '>=1.100.0', true);
188+
testIsValidVersion('1.100.0', '>=1.101.0', false);
182189

183190
testIsValidVersion('2.0.0', 'x.x.x', true);
184191
testIsValidVersion('2.0.0', '0.x.x', false);

0 commit comments

Comments
 (0)