piral-cli 0.15.0-alpha.3549 → 0.15.0-alpha.3592
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/lib/apps/debug-pilet.js +16 -11
- package/lib/apps/debug-pilet.js.map +1 -1
- package/lib/apps/debug-piral.js +15 -7
- package/lib/apps/debug-piral.js.map +1 -1
- package/lib/common/http.d.ts +0 -1
- package/lib/common/http.js +1 -14
- package/lib/common/http.js.map +1 -1
- package/lib/common/importmap.d.ts +2 -0
- package/lib/common/importmap.js +147 -0
- package/lib/common/importmap.js.map +1 -0
- package/lib/common/index.d.ts +1 -0
- package/lib/common/index.js +1 -0
- package/lib/common/index.js.map +1 -1
- package/lib/common/io.d.ts +1 -1
- package/lib/common/io.js +10 -2
- package/lib/common/io.js.map +1 -1
- package/lib/common/package.d.ts +2 -3
- package/lib/common/package.js +3 -95
- package/lib/common/package.js.map +1 -1
- package/lib/common/scripts.js +1 -1
- package/lib/common/scripts.js.map +1 -1
- package/lib/common/spec.js +1 -0
- package/lib/common/spec.js.map +1 -1
- package/lib/common/version.d.ts +2 -0
- package/lib/common/version.js +130 -0
- package/lib/common/version.js.map +1 -0
- package/lib/injectors/pilet.d.ts +1 -0
- package/lib/injectors/pilet.js +7 -4
- package/lib/injectors/pilet.js.map +1 -1
- package/lib/messages.d.ts +187 -0
- package/lib/messages.js +201 -2
- package/lib/messages.js.map +1 -1
- package/lib/types/common.d.ts +1 -0
- package/package.json +2 -2
- package/src/apps/debug-pilet.ts +6 -2
- package/src/apps/debug-piral.ts +3 -1
- package/src/common/http.ts +0 -13
- package/src/common/importmap.ts +153 -0
- package/src/common/index.ts +1 -0
- package/src/common/io.ts +11 -2
- package/src/common/package.ts +2 -104
- package/src/common/scripts.ts +1 -1
- package/src/common/spec.ts +1 -0
- package/src/common/version.test.ts +233 -0
- package/src/common/version.ts +142 -0
- package/src/injectors/pilet.ts +10 -4
- package/src/messages.ts +199 -0
- package/src/types/common.ts +1 -0
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { resolve, dirname } from 'path';
|
|
2
|
+
import { log, fail } from './log';
|
|
3
|
+
import { satisfies, validate } from './version';
|
|
4
|
+
import { computeHash } from './hash';
|
|
5
|
+
import { getHash, readJson, findFile, checkExists, checkIsDirectory } from './io';
|
|
6
|
+
import { SharedDependency } from '../types';
|
|
7
|
+
|
|
8
|
+
interface Importmap {
|
|
9
|
+
imports: Record<string, string>;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function tryResolve(baseDir: string, name: string) {
|
|
13
|
+
try {
|
|
14
|
+
return require.resolve(name, {
|
|
15
|
+
paths: [baseDir],
|
|
16
|
+
});
|
|
17
|
+
} catch (ex) {
|
|
18
|
+
log('generalDebug_0003', `Could not resolve the package "${name}" in "${baseDir}": ${ex}`);
|
|
19
|
+
return undefined;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function getDependencyDetails(depName: string): [assetName: string, identifier: string, versionSpec: string] {
|
|
24
|
+
const sep = depName.indexOf('@', 1);
|
|
25
|
+
const version = sep > 0 ? depName.substring(sep + 1) : '';
|
|
26
|
+
const id = sep > 0 ? depName.substring(0, sep) : depName;
|
|
27
|
+
const assetName = (id.startsWith('@') ? id.substring(1) : id).replace(/[\/\.]/g, '-').replace(/(\-)+/, '-');
|
|
28
|
+
return [assetName, id, version];
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function getLocalDependencyVersion(
|
|
32
|
+
packageJson: string,
|
|
33
|
+
depName: string,
|
|
34
|
+
versionSpec: string,
|
|
35
|
+
): [offeredVersion: string, requiredVersion: string] {
|
|
36
|
+
const details = require(packageJson);
|
|
37
|
+
|
|
38
|
+
if (versionSpec) {
|
|
39
|
+
if (!validate(versionSpec)) {
|
|
40
|
+
fail('importMapVersionSpecInvalid_0026', depName);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (!satisfies(details.version, versionSpec)) {
|
|
44
|
+
fail('importMapVersionSpecNotSatisfied_0025', depName, details.version);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return [details.version, versionSpec];
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return [details.version, details.version];
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async function resolveImportmap(dir: string, importmap: Importmap) {
|
|
54
|
+
const dependencies: Array<SharedDependency> = [];
|
|
55
|
+
const sharedImports = importmap?.imports;
|
|
56
|
+
|
|
57
|
+
if (typeof sharedImports === 'object' && sharedImports) {
|
|
58
|
+
for (const depName of Object.keys(sharedImports)) {
|
|
59
|
+
const url = sharedImports[depName];
|
|
60
|
+
const [assetName, identifier, versionSpec] = getDependencyDetails(depName);
|
|
61
|
+
|
|
62
|
+
if (typeof url !== 'string') {
|
|
63
|
+
log('generalInfo_0000', `The value of "${depName}" in the importmap is not a string and will be ignored.`);
|
|
64
|
+
} else if (/^https?:\/\//.test(url)) {
|
|
65
|
+
const hash = computeHash(url);
|
|
66
|
+
|
|
67
|
+
dependencies.push({
|
|
68
|
+
id: `${identifier}@${hash}`,
|
|
69
|
+
requireId: `${identifier}@${hash}`,
|
|
70
|
+
entry: url,
|
|
71
|
+
name: identifier,
|
|
72
|
+
ref: url,
|
|
73
|
+
type: 'remote',
|
|
74
|
+
});
|
|
75
|
+
} else if (url === identifier) {
|
|
76
|
+
const entry = tryResolve(dir, identifier);
|
|
77
|
+
|
|
78
|
+
if (entry) {
|
|
79
|
+
const packageJson = await findFile(dirname(entry), 'package.json');
|
|
80
|
+
const [version, requireVersion] = getLocalDependencyVersion(packageJson, depName, versionSpec);
|
|
81
|
+
|
|
82
|
+
dependencies.push({
|
|
83
|
+
id: `${identifier}@${version}`,
|
|
84
|
+
requireId: `${identifier}@${requireVersion}`,
|
|
85
|
+
entry,
|
|
86
|
+
name: identifier,
|
|
87
|
+
ref: `${assetName}.js`,
|
|
88
|
+
type: 'local',
|
|
89
|
+
});
|
|
90
|
+
} else {
|
|
91
|
+
fail('importMapReferenceNotFound_0027', dir, url);
|
|
92
|
+
}
|
|
93
|
+
} else {
|
|
94
|
+
const entry = resolve(dir, url);
|
|
95
|
+
const exists = await checkExists(entry);
|
|
96
|
+
|
|
97
|
+
if (exists) {
|
|
98
|
+
const isDirectory = await checkIsDirectory(entry);
|
|
99
|
+
const packageJson = isDirectory ? resolve(entry, 'package.json') : await findFile(dirname(entry), 'package.json');
|
|
100
|
+
const packageJsonExists = await checkExists(packageJson);
|
|
101
|
+
|
|
102
|
+
if (packageJsonExists) {
|
|
103
|
+
const [version, requireVersion] = getLocalDependencyVersion(packageJson, depName, versionSpec);
|
|
104
|
+
|
|
105
|
+
dependencies.push({
|
|
106
|
+
id: `${identifier}@${version}`,
|
|
107
|
+
requireId: `${identifier}@${requireVersion}`,
|
|
108
|
+
entry: isDirectory ? tryResolve(dir, entry) : entry,
|
|
109
|
+
name: identifier,
|
|
110
|
+
ref: `${assetName}.js`,
|
|
111
|
+
type: 'local',
|
|
112
|
+
});
|
|
113
|
+
} else if (isDirectory) {
|
|
114
|
+
fail('importMapReferenceNotFound_0027', entry, 'package.json');
|
|
115
|
+
} else {
|
|
116
|
+
const hash = await getHash(entry);
|
|
117
|
+
|
|
118
|
+
dependencies.push({
|
|
119
|
+
id: `${identifier}@${hash}`,
|
|
120
|
+
requireId: `${identifier}@${hash}`,
|
|
121
|
+
entry,
|
|
122
|
+
name: identifier,
|
|
123
|
+
ref: `${assetName}.js`,
|
|
124
|
+
type: 'local',
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
} else {
|
|
128
|
+
fail('importMapReferenceNotFound_0027', dir, url);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return dependencies;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export async function readImportmap(dir: string, packageDetails: any) {
|
|
138
|
+
const importmap = packageDetails.importmap;
|
|
139
|
+
|
|
140
|
+
if (typeof importmap === 'string') {
|
|
141
|
+
const notFound = {};
|
|
142
|
+
const content = await readJson(dir, importmap, notFound);
|
|
143
|
+
|
|
144
|
+
if (content === notFound) {
|
|
145
|
+
fail('importMapFileNotFound_0028', dir, importmap);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const baseDir = dirname(resolve(dir, importmap));
|
|
149
|
+
return resolveImportmap(baseDir, content);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
return resolveImportmap(dir, importmap);
|
|
153
|
+
}
|
package/src/common/index.ts
CHANGED
package/src/common/io.ts
CHANGED
|
@@ -371,12 +371,21 @@ export async function mergeWithJson<T>(targetDir: string, fileName: string, newC
|
|
|
371
371
|
return deepMerge(originalContent, newContent);
|
|
372
372
|
}
|
|
373
373
|
|
|
374
|
-
export async function readJson<T = any>(targetDir: string, fileName: string) {
|
|
374
|
+
export async function readJson<T = any>(targetDir: string, fileName: string, defaultValue = {}) {
|
|
375
375
|
const targetFile = join(targetDir, fileName);
|
|
376
376
|
const content = await new Promise<string>((resolve) => {
|
|
377
377
|
readFile(targetFile, 'utf8', (err, c) => (err ? resolve('') : resolve(c)));
|
|
378
378
|
});
|
|
379
|
-
|
|
379
|
+
|
|
380
|
+
if (content) {
|
|
381
|
+
try {
|
|
382
|
+
return JSON.parse(content) as T;
|
|
383
|
+
} catch (ex) {
|
|
384
|
+
log('generalError_0002', `Invalid JSON found in file "${fileName}" at "${targetDir}".`);
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
return defaultValue as T;
|
|
380
389
|
}
|
|
381
390
|
|
|
382
391
|
export function readBinary(targetDir: string, fileName: string) {
|
package/src/common/package.ts
CHANGED
|
@@ -6,13 +6,13 @@ import { getDependencies, getDevDependencies } from './language';
|
|
|
6
6
|
import { SourceLanguage, ForceOverwrite } from './enums';
|
|
7
7
|
import { checkAppShellCompatibility } from './compatibility';
|
|
8
8
|
import { deepMerge } from './merge';
|
|
9
|
-
import { getHashFromUrl } from './http';
|
|
10
9
|
import { applyTemplate } from './template';
|
|
10
|
+
import { readImportmap } from './importmap';
|
|
11
11
|
import { isGitPackage, isLocalPackage, makeGitUrl, makeFilePath, makePiletExternals, makeExternals } from './npm';
|
|
12
12
|
import { filesTar, filesOnceTar, declarationEntryExtensions } from './constants';
|
|
13
13
|
import { getHash, checkIsDirectory, matchFiles } from './io';
|
|
14
14
|
import { readJson, copy, updateExistingJson, findFile, checkExists } from './io';
|
|
15
|
-
import { Framework, FileInfo, PiletsInfo, TemplateFileLocation
|
|
15
|
+
import { Framework, FileInfo, PiletsInfo, TemplateFileLocation } from '../types';
|
|
16
16
|
|
|
17
17
|
function getDependencyVersion(
|
|
18
18
|
name: string,
|
|
@@ -574,108 +574,6 @@ export function checkAppShellPackage(appPackage: any) {
|
|
|
574
574
|
return false;
|
|
575
575
|
}
|
|
576
576
|
|
|
577
|
-
function tryResolve(baseDir: string, name: string) {
|
|
578
|
-
try {
|
|
579
|
-
return require.resolve(name, {
|
|
580
|
-
paths: [baseDir],
|
|
581
|
-
});
|
|
582
|
-
} catch (ex) {
|
|
583
|
-
log('generalDebug_0003', `Could not resolve the package "${name}" in "${baseDir}": ${ex}`);
|
|
584
|
-
return undefined;
|
|
585
|
-
}
|
|
586
|
-
}
|
|
587
|
-
|
|
588
|
-
interface Importmap {
|
|
589
|
-
imports: Record<string, string>;
|
|
590
|
-
}
|
|
591
|
-
|
|
592
|
-
function normalizeDepName(s: string) {
|
|
593
|
-
return (s.startsWith('@') ? s.substring(1) : s).replace(/[\/\.]/g, '-').replace(/(\-)+/, '-');
|
|
594
|
-
}
|
|
595
|
-
|
|
596
|
-
async function resolveImportmap(dir: string, importmap: Importmap) {
|
|
597
|
-
const dependencies: Array<SharedDependency> = [];
|
|
598
|
-
const sharedImports = importmap?.imports;
|
|
599
|
-
|
|
600
|
-
if (typeof sharedImports === 'object' && sharedImports) {
|
|
601
|
-
for (const depName of Object.keys(sharedImports)) {
|
|
602
|
-
const url = sharedImports[depName];
|
|
603
|
-
const assetName = normalizeDepName(depName);
|
|
604
|
-
|
|
605
|
-
if (typeof url !== 'string') {
|
|
606
|
-
} else if (/^https?:\/\//.test(url)) {
|
|
607
|
-
const hash = await getHashFromUrl(url);
|
|
608
|
-
|
|
609
|
-
dependencies.push({
|
|
610
|
-
id: `${depName}@${hash}`,
|
|
611
|
-
entry: url,
|
|
612
|
-
name: depName,
|
|
613
|
-
ref: url,
|
|
614
|
-
type: 'remote',
|
|
615
|
-
});
|
|
616
|
-
} else if (url === depName) {
|
|
617
|
-
const entry = tryResolve(dir, depName);
|
|
618
|
-
|
|
619
|
-
if (entry) {
|
|
620
|
-
const packageJson = await findFile(dirname(entry), 'package.json');
|
|
621
|
-
const details = require(packageJson);
|
|
622
|
-
|
|
623
|
-
dependencies.push({
|
|
624
|
-
id: `${depName}@${details.version}`,
|
|
625
|
-
entry,
|
|
626
|
-
ref: `${assetName}.js`,
|
|
627
|
-
name: depName,
|
|
628
|
-
type: 'local',
|
|
629
|
-
});
|
|
630
|
-
}
|
|
631
|
-
} else {
|
|
632
|
-
const entry = resolve(dir, url);
|
|
633
|
-
const exists = await checkExists(entry);
|
|
634
|
-
|
|
635
|
-
if (exists) {
|
|
636
|
-
const packageJson = await findFile(dirname(entry), 'package.json');
|
|
637
|
-
|
|
638
|
-
if (packageJson) {
|
|
639
|
-
const details = require(packageJson);
|
|
640
|
-
|
|
641
|
-
dependencies.push({
|
|
642
|
-
id: `${depName}@${details.version}`,
|
|
643
|
-
entry,
|
|
644
|
-
name: depName,
|
|
645
|
-
ref: `${assetName}.js`,
|
|
646
|
-
type: 'local',
|
|
647
|
-
});
|
|
648
|
-
} else {
|
|
649
|
-
const hash = await getHash(entry);
|
|
650
|
-
|
|
651
|
-
dependencies.push({
|
|
652
|
-
id: `${depName}@${hash}`,
|
|
653
|
-
entry,
|
|
654
|
-
name: depName,
|
|
655
|
-
ref: `${assetName}.js`,
|
|
656
|
-
type: 'local',
|
|
657
|
-
});
|
|
658
|
-
}
|
|
659
|
-
}
|
|
660
|
-
}
|
|
661
|
-
}
|
|
662
|
-
}
|
|
663
|
-
|
|
664
|
-
return dependencies;
|
|
665
|
-
}
|
|
666
|
-
|
|
667
|
-
export async function readImportmap(dir: string, packageDetails: any) {
|
|
668
|
-
const importmap = packageDetails.importmap;
|
|
669
|
-
|
|
670
|
-
if (typeof importmap === 'string') {
|
|
671
|
-
const content = await readJson(dir, importmap);
|
|
672
|
-
const baseDir = dirname(resolve(dir, importmap));
|
|
673
|
-
return resolveImportmap(baseDir, content);
|
|
674
|
-
}
|
|
675
|
-
|
|
676
|
-
return resolveImportmap(dir, importmap);
|
|
677
|
-
}
|
|
678
|
-
|
|
679
577
|
export async function retrievePiletData(target: string, app?: string) {
|
|
680
578
|
const packageJson = await findFile(target, 'package.json');
|
|
681
579
|
|
package/src/common/scripts.ts
CHANGED
|
@@ -15,7 +15,7 @@ function resolveWinPath(specialFolder: string, subPath: string): string | undefi
|
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
export function runScript(script: string, cwd = process.cwd(), output: NodeJS.WritableStream = process.stdout) {
|
|
18
|
-
const bin = resolve('./node_modules/.bin');
|
|
18
|
+
const bin = resolve(cwd, './node_modules/.bin');
|
|
19
19
|
const sep = isWindows ? ';' : ':';
|
|
20
20
|
const env = Object.assign({}, process.env);
|
|
21
21
|
|
package/src/common/spec.ts
CHANGED
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
import { satisfies, validate } from './version';
|
|
2
|
+
|
|
3
|
+
describe('semver check module', () => {
|
|
4
|
+
it('specific publish version is valid', () => {
|
|
5
|
+
const result = validate('1.2.3');
|
|
6
|
+
expect(result).toBeTruthy();
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
it('shortened publish version is valid', () => {
|
|
10
|
+
const result = validate('1.2');
|
|
11
|
+
expect(result).toBeTruthy();
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it('some hash is invalid', () => {
|
|
15
|
+
const result = validate('fabcde');
|
|
16
|
+
expect(result).toBeFalsy();
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('some longer hash is invalid', () => {
|
|
20
|
+
const result = validate('123fabdef0012');
|
|
21
|
+
expect(result).toBeFalsy();
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('major publish version is valid', () => {
|
|
25
|
+
const result = validate('1');
|
|
26
|
+
expect(result).toBeTruthy();
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('any publish version is valid', () => {
|
|
30
|
+
const result = validate('1.2.x');
|
|
31
|
+
expect(result).toBeTruthy();
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('specific preview version is valid', () => {
|
|
35
|
+
const result = validate('1.2.3-pre.123');
|
|
36
|
+
expect(result).toBeTruthy();
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('caret version is specifier valid', () => {
|
|
40
|
+
const result = validate('^1.2.3');
|
|
41
|
+
expect(result).toBeTruthy();
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('tilde version is specifier valid', () => {
|
|
45
|
+
const result = validate('~1.2.3');
|
|
46
|
+
expect(result).toBeTruthy();
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('greater version is specifier valid', () => {
|
|
50
|
+
const result = validate('>1.2.3');
|
|
51
|
+
expect(result).toBeTruthy();
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('greater equals version is specifier valid', () => {
|
|
55
|
+
const result = validate('>=1.2.3');
|
|
56
|
+
expect(result).toBeTruthy();
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('greater equals with x version is specifier valid', () => {
|
|
60
|
+
const result = validate('>=1.x');
|
|
61
|
+
expect(result).toBeTruthy();
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('satisfies exact version match', () => {
|
|
65
|
+
const result = satisfies('1.2.3', '1.2.3');
|
|
66
|
+
expect(result).toBeTruthy();
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it('does not satisfy exact version mismatch greater', () => {
|
|
70
|
+
const result = satisfies('1.2.3', '1.2.4');
|
|
71
|
+
expect(result).toBeFalsy();
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it('does not satisfy exact version mismatch smaller', () => {
|
|
75
|
+
const result = satisfies('1.2.3', '1.2.2');
|
|
76
|
+
expect(result).toBeFalsy();
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it('satisfies constraint with caret patch', () => {
|
|
80
|
+
const result = satisfies('1.2.3', '^1.2.0');
|
|
81
|
+
expect(result).toBeTruthy();
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('satisfies constraint with caret minor', () => {
|
|
85
|
+
const result = satisfies('1.3.0', '^1.2.0');
|
|
86
|
+
expect(result).toBeTruthy();
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it('satisfies constraint with caret exact', () => {
|
|
90
|
+
const result = satisfies('1.3.0', '^1.3.0');
|
|
91
|
+
expect(result).toBeTruthy();
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it('satisfies constraint with caret exact with dropped number', () => {
|
|
95
|
+
const result = satisfies('1.3.0', '^1.3');
|
|
96
|
+
expect(result).toBeTruthy();
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it('satisfies constraint with caret exact with dropped numbers', () => {
|
|
100
|
+
const result = satisfies('1', '^1');
|
|
101
|
+
expect(result).toBeTruthy();
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it('does not satisfy constraint with caret major', () => {
|
|
105
|
+
const result = satisfies('2.0.0', '^1.2.0');
|
|
106
|
+
expect(result).toBeFalsy();
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it('satisfies constraint with tilde patch', () => {
|
|
110
|
+
const result = satisfies('1.2.3', '~1.2.0');
|
|
111
|
+
expect(result).toBeTruthy();
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it('does not satisfy constraint with tilde minor', () => {
|
|
115
|
+
const result = satisfies('1.3.0', '~1.2.0');
|
|
116
|
+
expect(result).toBeFalsy();
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it('does not satisfy constraint with tilde patch greater', () => {
|
|
120
|
+
const result = satisfies('1.3.0', '~1.3.2');
|
|
121
|
+
expect(result).toBeFalsy();
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it('satisfies constraint with tilde patch lighter', () => {
|
|
125
|
+
const result = satisfies('1.3.3', '~1.3.2');
|
|
126
|
+
expect(result).toBeTruthy();
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
it('satisfies constraint with x patch', () => {
|
|
130
|
+
const result = satisfies('1.2.3', '1.x.3');
|
|
131
|
+
expect(result).toBeTruthy();
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
it('does not satisfy constraint x minor', () => {
|
|
135
|
+
const result = satisfies('1.3.0', '1.2.x');
|
|
136
|
+
expect(result).toBeFalsy();
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
it('satsfies greater than matching', () => {
|
|
140
|
+
const result = satisfies('1.3.0', '>=1.2.0');
|
|
141
|
+
expect(result).toBeTruthy();
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
it('satsfies less than matching', () => {
|
|
145
|
+
const result = satisfies('1.3.0', '<=1.3.0');
|
|
146
|
+
expect(result).toBeTruthy();
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
it('does not satisfy only greater than non-matching', () => {
|
|
150
|
+
const result = satisfies('1.3.0', '>1.3.0');
|
|
151
|
+
expect(result).toBeFalsy();
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
it('does not satisfy greater than non-matching', () => {
|
|
155
|
+
const result = satisfies('1.3.0', '>=1.3.1');
|
|
156
|
+
expect(result).toBeFalsy();
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it('does not satisfy less than non-matching', () => {
|
|
160
|
+
const result = satisfies('1.3.0', '<=1.2.0');
|
|
161
|
+
expect(result).toBeFalsy();
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
it('does not satisfy less than non-matching', () => {
|
|
165
|
+
const result = satisfies('1.3.0', '<1.3.0');
|
|
166
|
+
expect(result).toBeFalsy();
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
it('does not satisfy less than non-matching', () => {
|
|
170
|
+
const result = satisfies('1.3.0', '<=1.2.0');
|
|
171
|
+
expect(result).toBeFalsy();
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
it('satisfies exact version match with previews', () => {
|
|
175
|
+
const result = satisfies('1.2.3-pre.5', '1.2.3-pre.5');
|
|
176
|
+
expect(result).toBeTruthy();
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
it('satisfies exact version match with dropped number', () => {
|
|
180
|
+
const result = satisfies('1.0', '1');
|
|
181
|
+
expect(result).toBeTruthy();
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
it('satisfies exact version match with dropped numbers', () => {
|
|
185
|
+
const result = satisfies('1', '1.0.0');
|
|
186
|
+
expect(result).toBeTruthy();
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
it('does not satisfy exact version mismatch preview', () => {
|
|
190
|
+
const result = satisfies('1.2.4-pre.5', '1.2.4-pre.6');
|
|
191
|
+
expect(result).toBeFalsy();
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
it('does not satisfy exact version mismatch preview version offered', () => {
|
|
195
|
+
const result = satisfies('1.2.4-beta', '1.2.4-beta.5');
|
|
196
|
+
expect(result).toBeFalsy();
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
it('does not satisfy exact version mismatch preview version demanded', () => {
|
|
200
|
+
const result = satisfies('1.2.4-beta.5', '1.2.4-beta');
|
|
201
|
+
expect(result).toBeFalsy();
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
it('does not satisfy exact version mismatch preview higher', () => {
|
|
205
|
+
const result = satisfies('1.2.4-gamma', '1.2.4-beta');
|
|
206
|
+
expect(result).toBeFalsy();
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
it('does not satisfy exact version mismatch preview smaller', () => {
|
|
210
|
+
const result = satisfies('1.2.4-alpha', '1.2.4-beta');
|
|
211
|
+
expect(result).toBeFalsy();
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
it('does not satisfy exact and preview mismatch', () => {
|
|
215
|
+
const result = satisfies('1.2.4-pre.5', '1.2.4');
|
|
216
|
+
expect(result).toBeFalsy();
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
it('satisfies just an x', () => {
|
|
220
|
+
const result = satisfies('1.2.3', 'x');
|
|
221
|
+
expect(result).toBeTruthy();
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
it('satisfies just a *', () => {
|
|
225
|
+
const result = satisfies('1.2.3', '*');
|
|
226
|
+
expect(result).toBeTruthy();
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
it('satisfies just a >=0', () => {
|
|
230
|
+
const result = satisfies('1.2.3', '>=0');
|
|
231
|
+
expect(result).toBeTruthy();
|
|
232
|
+
});
|
|
233
|
+
});
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
const semver =
|
|
2
|
+
/^[v^~<>=]*?(\d+)(?:\.([x*]|\d+)(?:\.([x*]|\d+)(?:\.([x*]|\d+))?(?:-([\da-z\-]+(?:\.[\da-z\-]+)*))?(?:\+[\da-z\-]+(?:\.[\da-z\-]+)*)?)?)?$/i;
|
|
3
|
+
|
|
4
|
+
const acceptsAll = ['*', 'x', '>=0'];
|
|
5
|
+
|
|
6
|
+
const operatorResMap: Record<string, [number, number?]> = {
|
|
7
|
+
'>': [1],
|
|
8
|
+
'>=': [0, 1],
|
|
9
|
+
'=': [0],
|
|
10
|
+
'<=': [-1, 0],
|
|
11
|
+
'<': [-1],
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
function indexOrEnd(str: string, q: string) {
|
|
15
|
+
return str.indexOf(q) === -1 ? str.length : str.indexOf(q);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function splitVersion(v: string) {
|
|
19
|
+
var c = v.replace(/^v/, '').replace(/\+.*$/, '');
|
|
20
|
+
var patchIndex = indexOrEnd(c, '-');
|
|
21
|
+
var arr = c.substring(0, patchIndex).split('.');
|
|
22
|
+
arr.push(c.substring(patchIndex + 1));
|
|
23
|
+
return arr;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function parseSegment(v: string) {
|
|
27
|
+
var n = parseInt(v, 10);
|
|
28
|
+
return isNaN(n) ? v : n;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function validateAndParse(v: string) {
|
|
32
|
+
const match = v.match(semver);
|
|
33
|
+
match.shift();
|
|
34
|
+
return match;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function compareStrings(a: string, b: string) {
|
|
38
|
+
const ap = parseSegment(a);
|
|
39
|
+
const bp = parseSegment(b);
|
|
40
|
+
|
|
41
|
+
if (ap > bp) {
|
|
42
|
+
return 1;
|
|
43
|
+
} else if (ap < bp) {
|
|
44
|
+
return -1;
|
|
45
|
+
} else {
|
|
46
|
+
return 0;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function compareSegments(a: [string, string], b: [string, string]) {
|
|
51
|
+
for (let i = 0; i < 2; i++) {
|
|
52
|
+
const r = compareStrings(a[i] || '0', b[i] || '0');
|
|
53
|
+
|
|
54
|
+
if (r !== 0) {
|
|
55
|
+
return r;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return 0;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function compareVersions(v1: string, v2: string) {
|
|
63
|
+
const s1 = splitVersion(v1);
|
|
64
|
+
const s2 = splitVersion(v2);
|
|
65
|
+
const len = Math.max(s1.length - 1, s2.length - 1);
|
|
66
|
+
|
|
67
|
+
for (let i = 0; i < len; i++) {
|
|
68
|
+
const n1 = parseInt(s1[i] || '0', 10);
|
|
69
|
+
const n2 = parseInt(s2[i] || '0', 10);
|
|
70
|
+
|
|
71
|
+
if (n1 > n2) {
|
|
72
|
+
return 1;
|
|
73
|
+
} else if (n2 > n1) {
|
|
74
|
+
return -1;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const sp1 = s1[s1.length - 1];
|
|
79
|
+
const sp2 = s2[s2.length - 1];
|
|
80
|
+
|
|
81
|
+
if (sp1 && sp2) {
|
|
82
|
+
const p1 = sp1.split('.').map(parseSegment);
|
|
83
|
+
const p2 = sp2.split('.').map(parseSegment);
|
|
84
|
+
const len = Math.max(p1.length, p2.length);
|
|
85
|
+
|
|
86
|
+
for (let i = 0; i < len; i++) {
|
|
87
|
+
if (p1[i] === undefined || (typeof p2[i] === 'string' && typeof p1[i] === 'number')) {
|
|
88
|
+
return -1;
|
|
89
|
+
} else if (p2[i] === undefined || (typeof p1[i] === 'string' && typeof p2[i] === 'number')) {
|
|
90
|
+
return 1;
|
|
91
|
+
} else if (p1[i] > p2[i]) {
|
|
92
|
+
return 1;
|
|
93
|
+
} else if (p2[i] > p1[i]) {
|
|
94
|
+
return -1;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
} else if (sp1 || sp2) {
|
|
98
|
+
return sp1 ? -1 : 1;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return 0;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function compare(v1: string, v2: string, operator: string) {
|
|
105
|
+
// since result of compareVersions can only be -1 or 0 or 1
|
|
106
|
+
// a simple map can be used to replace switch
|
|
107
|
+
const res = compareVersions(v1, v2);
|
|
108
|
+
return operatorResMap[operator].indexOf(res) > -1;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export function validate(version: string) {
|
|
112
|
+
return acceptsAll.includes(version) || semver.test(version);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export function satisfies(v: string, r: string) {
|
|
116
|
+
if (!acceptsAll.includes(r)) {
|
|
117
|
+
// if no range operator then "="
|
|
118
|
+
const match = r.match(/^([<>=~^]+)/);
|
|
119
|
+
const op = match ? match[1] : '=';
|
|
120
|
+
|
|
121
|
+
// if gt/lt/eq then operator compare
|
|
122
|
+
if (op !== '^' && op !== '~') {
|
|
123
|
+
return compare(v, r, op);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// else range of either "~" or "^" is assumed
|
|
127
|
+
const [v1, v2, v3] = validateAndParse(v);
|
|
128
|
+
const [m1, m2, m3] = validateAndParse(r);
|
|
129
|
+
|
|
130
|
+
if (compareStrings(v1, m1) !== 0) {
|
|
131
|
+
return false;
|
|
132
|
+
} else if (op === '^') {
|
|
133
|
+
return compareSegments([v2, v3], [m2, m3]) >= 0;
|
|
134
|
+
} else if (compareStrings(v2, m2) !== 0) {
|
|
135
|
+
return false;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return compareStrings(v3, m3) >= 0;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return true;
|
|
142
|
+
}
|