UNPKG

11.3 kBJavaScriptView Raw
1"use strict";
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6exports.__parseVersion = _parseVersion;
7exports.compareFlowVersionAsc = compareFlowVersionAsc;
8exports.determineFlowSpecificVersion = determineFlowSpecificVersion;
9exports.disjointVersionsAll = disjointVersionsAll;
10exports.extractFlowDirFromFlowDirPath = void 0;
11exports.parseDirString = parseDirString;
12exports.parseFlowSpecificVer = parseFlowSpecificVer;
13exports.toDirString = toDirString;
14exports.toSemverString = toSemverString;
15
16var _npmProjectUtils = require("./npm/npmProjectUtils");
17
18var _ValidationError = require("./ValidationError");
19
20function _parseVerNum(numStr, verName, context) {
21 const num = parseInt(numStr, 10);
22
23 if (String(num) !== numStr) {
24 throw new _ValidationError.ValidationError(`'${context}': Invalid ${verName} number: '${numStr}'. Expected a number.`);
25 }
26
27 return num;
28}
29
30function _parseVerNumOrX(numStr, verName, context) {
31 if (numStr == null) {
32 return 'x';
33 }
34
35 if (numStr === 'x') {
36 return numStr;
37 }
38
39 return _parseVerNum(numStr, verName, context);
40}
41
42function _parseVersion(verStr, expectPossibleRangeUpper) {
43 if (verStr[0] !== 'v') {
44 throw new _ValidationError.ValidationError('Flow version ranges must start with a `v`!');
45 }
46
47 const verParts = verStr.slice(1).match(/^([0-9]+)\.([0-9]+|x)(\.([0-9]+|x))?/);
48 let majorStr, minorStr, patchStr;
49
50 if (verParts == null) {
51 if (verStr[1] === 'x') {
52 throw new _ValidationError.ValidationError('The major version of a Flow version string cannot be `x`, it must ' + 'be a number!');
53 } else {
54 throw new _ValidationError.ValidationError('Flow versions must be a non-range semver with an exact major version ' + 'and either an exact minor version or an `x` minor ver. Instead got: ' + verStr);
55 }
56 } else {
57 majorStr = verParts[1];
58 minorStr = verParts[2];
59 patchStr = verParts[4];
60 }
61
62 const [major, minor, patch] = [_parseVerNum(majorStr, 'major', verStr), _parseVerNumOrX(minorStr, 'minor', verStr), _parseVerNumOrX(patchStr, 'patch', verStr)];
63 const verAfterParts = verStr.substr(verParts[0].length + 1);
64
65 if (patchStr != null && verAfterParts[0] === '-' && verAfterParts[1] != null) {
66 if (expectPossibleRangeUpper) {
67 // A `-` could indicate either a range or a prerel. This is technically
68 // a real ambiguity in our versioning syntax -- but luckily it's rarely
69 // encountered.
70 //
71 // To deal with this, we try parsing as a version. If it parses we assume
72 // a range. If it doesn't parse as a version, we assume a pre-rel
73 // identifier.
74 //
75 // This is excitingly inefficient but because it operates on tiny inputs
76 // (and only sometimes) it shouldn't be an issue in practice.
77 try {
78 _parseVersion(verAfterParts.substr(1), false);
79
80 return [verParts[0].length + 1, {
81 major,
82 minor,
83 patch,
84 prerel: null
85 }];
86 } catch (e) {
87 // It's possible that a prerel *and* a range co-exist!
88 // v0.1.x-prerel-v0.2.x
89 let prerelParts = verAfterParts.substr(1).split('-'); // ['prerel', 'v0.2.x']
90
91 let prerel = prerelParts.shift(); // 'prerel'
92
93 while (prerelParts.length > 0) {
94 try {
95 _parseVersion(prerelParts.join('-'), false);
96
97 break;
98 } catch (e) {
99 prerel += '-' + prerelParts.shift();
100 }
101 }
102
103 return [verParts[0].length + '-'.length + prerel.length + 1, {
104 major,
105 minor,
106 patch,
107 prerel
108 }];
109 }
110 } else {
111 // After the `-` must be a prerel
112 return [verStr.length + 1, {
113 major,
114 minor,
115 patch,
116 prerel: verAfterParts.substr(1)
117 }];
118 }
119 } else {
120 return [verParts[0].length + 1, {
121 major,
122 minor,
123 patch,
124 prerel: null
125 }];
126 }
127}
128
129function parseDirString(verStr) {
130 const prefix = 'flow_';
131
132 if (!verStr.startsWith(prefix)) {
133 throw new _ValidationError.ValidationError(`Flow versions must start with \`${prefix}\` but instead got ${verStr}`);
134 }
135
136 const afterPrefix = verStr.substr(verStr.indexOf(prefix) + prefix.length);
137
138 if (afterPrefix === 'all' || afterPrefix === 'vx.x.x') {
139 return {
140 kind: 'all'
141 };
142 } else if (afterPrefix[0] === '-') {
143 return {
144 kind: 'ranged',
145 lower: null,
146 upper: _parseVersion(verStr.substr(`${prefix}-`.length), false)[1]
147 };
148 } else {
149 const [offset, lowerVer] = _parseVersion(afterPrefix, true);
150
151 if (offset === afterPrefix.length) {
152 return {
153 kind: 'specific',
154 ver: lowerVer
155 };
156 } else if (afterPrefix[offset] === '-') {
157 const upperVer = offset + 1 === afterPrefix.length ? null : _parseVersion(afterPrefix.substr(offset + 1), false)[1];
158 return {
159 kind: 'ranged',
160 lower: lowerVer,
161 upper: upperVer
162 };
163 } else {
164 throw new _ValidationError.ValidationError(`Unexpected trailing characters: ${afterPrefix.substr(offset)}`);
165 }
166 }
167}
168
169function parseFlowSpecificVer(verStr) {
170 const flowVer = parseDirString(`flow_${verStr}`);
171
172 switch (flowVer.kind) {
173 case 'specific':
174 return flowVer.ver;
175
176 case 'all':
177 case 'ranged':
178 throw new _ValidationError.ValidationError(`This is not a specific Flow version.`);
179
180 default:
181 flowVer;
182 }
183
184 return {
185 major: -1,
186 minor: 'x',
187 patch: 'x',
188 prerel: null
189 };
190}
191
192async function determineFlowSpecificVersion(cwd, flowVersionArg) {
193 if (flowVersionArg && typeof flowVersionArg === 'string') {
194 // Be permissive if the prefix 'v' is left off
195 let flowVersionStr = flowVersionArg[0] === 'v' ? flowVersionArg : `v${flowVersionArg}`;
196
197 if (/^v[0-9]+\.[0-9]+$/.test(flowVersionStr)) {
198 flowVersionStr = `${flowVersionStr}.0`;
199 }
200
201 return {
202 kind: 'specific',
203 ver: parseFlowSpecificVer(flowVersionStr)
204 };
205 } else {
206 return {
207 kind: 'specific',
208 ver: await (0, _npmProjectUtils.findFlowSpecificVer)(cwd)
209 };
210 }
211}
212/**
213 * Given two version ranges a and b, determine whether a is before b.
214 */
215
216
217function lt(n1, n2) {
218 if (n1 === 'x' || n2 === 'x') return false;
219 if (n1 < n2) return true;
220 if (n1 > n2) return false;
221 return 'maybe';
222}
223
224function before(a, b) {
225 let test = lt(a.major, b.major);
226 if (test !== 'maybe') return test;
227 test = lt(a.minor, b.minor);
228 if (test !== 'maybe') return test;
229 test = lt(a.patch, b.patch);
230 if (test !== 'maybe') return test;
231 return false;
232}
233/**
234 * Given a version range, returns the max version satisfying the range.
235 */
236
237
238function maxSat(ver) {
239 switch (ver.kind) {
240 case 'all':
241 return null;
242
243 case 'ranged':
244 return ver.upper;
245
246 case 'specific':
247 return ver.ver;
248
249 default:
250 ver;
251 throw new Error('Unexpected FlowVersion kind!');
252 }
253}
254/**
255 * Given a version range, returns the min version satisfying the range.
256 */
257
258
259function minSat(ver) {
260 switch (ver.kind) {
261 case 'all':
262 return null;
263
264 case 'ranged':
265 return ver.lower;
266
267 case 'specific':
268 return ver.ver;
269
270 default:
271 ver;
272 throw new Error('Unexpected FlowVersion kind!');
273 }
274}
275/**
276 * Given two versions, returns whether they are disjoint.
277 */
278
279
280function _before(a, b) {
281 // If a is undefined, it denotes the maximum version. If b is undefined, it
282 // denotes the minimum version.
283 if (a && b) return before(a, b);
284 return false;
285}
286
287function disjointVersions(a, b) {
288 return _before(maxSat(a), minSat(b)) || _before(maxSat(b), minSat(a));
289}
290/**
291 * Given an array of versions, returns whether they are mutually disjoint.
292 */
293
294
295function _disjointVersionsAll(vers, len, i) {
296 if (i + 1 >= len) return true;
297
298 for (let j = i + 1; j < len; j++) {
299 if (!disjointVersions(vers[i], vers[j])) {
300 return false;
301 }
302 }
303
304 return _disjointVersionsAll(vers, len, i + 1);
305}
306
307function disjointVersionsAll(vers) {
308 return _disjointVersionsAll(vers, vers.length, 0);
309}
310
311function toDirString(ver) {
312 switch (ver.kind) {
313 case 'all':
314 return 'flow_all';
315
316 case 'specific':
317 {
318 let str = `flow_v${ver.ver.major}.${ver.ver.minor}`;
319
320 if (ver.ver.patch !== null) {
321 str += `.${ver.ver.patch}`;
322
323 if (ver.ver.prerel) {
324 str += `-${ver.ver.prerel}`;
325 }
326 }
327
328 return str;
329 }
330
331 case 'ranged':
332 {
333 const {
334 lower,
335 upper
336 } = ver;
337 let str = 'flow_';
338
339 if (lower !== null) {
340 str += `v${lower.major}.${lower.minor}`;
341
342 if (lower.patch !== null) {
343 str += `.${lower.patch}`;
344
345 if (lower.prerel !== null) {
346 str += `-${lower.prerel}`;
347 }
348 }
349 }
350
351 str += '-';
352
353 if (upper !== null) {
354 str += `v${upper.major}.${upper.minor}`;
355
356 if (upper.patch !== null) {
357 str += `.${upper.patch}`;
358
359 if (upper.prerel !== null) {
360 str += `-${upper.prerel}`;
361 }
362 }
363 }
364
365 return str;
366 }
367
368 default:
369 ver;
370 throw new Error('Unexpected FlowVersion kind!');
371 }
372}
373
374function toSemverString(ver) {
375 switch (ver.kind) {
376 case 'all':
377 return 'vx.x.x';
378
379 case 'specific':
380 return toDirString(ver).substr('flow_'.length);
381
382 case 'ranged':
383 {
384 const {
385 upper,
386 lower
387 } = ver;
388 let str = '';
389
390 if (lower !== null) {
391 str += `>=v${lower.major}.${lower.minor}`;
392
393 if (lower.patch !== null) {
394 str += `.${lower.patch}`;
395
396 if (lower.prerel !== null) {
397 str += `-${lower.prerel}`;
398 }
399 }
400
401 if (upper !== null) {
402 str += ' ';
403 }
404 }
405
406 if (upper !== null) {
407 str += `<=v${upper.major}.${upper.minor}`;
408
409 if (upper.patch !== null) {
410 str += `.${upper.patch}`;
411
412 if (upper.prerel !== null) {
413 str += `-${upper.prerel}`;
414 }
415 }
416 }
417
418 return str;
419 }
420
421 default:
422 ver;
423 throw new Error('Unexpected FlowVersion kind!');
424 }
425}
426
427function compareFlowVersionAsc(a, b) {
428 if (a.kind === 'all') {
429 return b.kind === 'all' ? 0 : -1;
430 }
431
432 if (b.kind === 'all') {
433 return 1;
434 }
435
436 const aLowerVer = a.kind === 'specific' ? a.ver : a.lower;
437 const bLowerVer = b.kind === 'specific' ? b.ver : b.lower;
438
439 if (aLowerVer === null) {
440 return bLowerVer === null ? 0 : 1;
441 }
442
443 if (bLowerVer === null) {
444 return -1;
445 }
446
447 const compareMajor = lt(aLowerVer.major, bLowerVer.major);
448
449 if (compareMajor !== 'maybe') {
450 return compareMajor ? 1 : -1;
451 }
452
453 const compareMinor = lt(aLowerVer.minor, bLowerVer.minor);
454
455 if (compareMinor !== 'maybe') {
456 return compareMinor ? 1 : -1;
457 }
458
459 const comparePatch = lt(aLowerVer.patch, bLowerVer.patch);
460
461 if (comparePatch !== 'maybe') {
462 return comparePatch ? 1 : -1;
463 }
464
465 return 0;
466}
467
468const extractFlowDirFromFlowDirPath = path => {
469 const split = path.split('/');
470 return split[split.length - 1];
471}; // Exported for tests
472
473
474exports.extractFlowDirFromFlowDirPath = extractFlowDirFromFlowDirPath;
\No newline at end of file