@ohos-ports/parcel-package-manager 2.9.3-beta.1
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/LICENSE +21 -0
- package/index.d.ts +22 -0
- package/lib/index.js +4967 -0
- package/lib/index.js.map +1 -0
- package/lib/types.d.ts +47 -0
- package/package.json +69 -0
- package/src/JSONParseStream.js +39 -0
- package/src/MockPackageInstaller.js +90 -0
- package/src/NodePackageManager.js +583 -0
- package/src/Npm.js +94 -0
- package/src/Pnpm.js +194 -0
- package/src/Yarn.js +157 -0
- package/src/index.js +8 -0
- package/src/installPackage.js +274 -0
- package/src/promiseFromProcess.js +19 -0
- package/src/types.js +63 -0
- package/src/utils.js +92 -0
- package/src/validateModuleSpecifier.js +12 -0
- package/test/NodePackageManager.test.js +310 -0
- package/test/fixtures/empty/package.json +1 -0
- package/test/fixtures/has-a-not-yet-installed/package.json +5 -0
- package/test/fixtures/has-foo/node_modules/foo/index.js +1 -0
- package/test/fixtures/has-foo/node_modules/foo/package.json +3 -0
- package/test/fixtures/has-foo/node_modules/index.js +0 -0
- package/test/fixtures/has-foo/package.json +5 -0
- package/test/fixtures/has-foo/subpackage/package.json +1 -0
- package/test/fixtures/packages/a/index.js +1 -0
- package/test/fixtures/packages/a/package.json +3 -0
- package/test/fixtures/packages/foo-2.0/index.js +1 -0
- package/test/fixtures/packages/foo-2.0/package.json +4 -0
- package/test/fixtures/packages/peers/index.js +1 -0
- package/test/fixtures/packages/peers/package.json +7 -0
- package/test/fixtures/packages/peers-2.0/index.js +1 -0
- package/test/fixtures/packages/peers-2.0/package.json +7 -0
- package/test/validateModuleSpecifiers.test.js +38 -0
package/src/utils.js
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
// @flow strict-local
|
|
2
|
+
|
|
3
|
+
import type {ModuleRequest} from './types';
|
|
4
|
+
import type {FilePath} from '@parcel/types';
|
|
5
|
+
import type {FileSystem} from '@parcel/fs';
|
|
6
|
+
|
|
7
|
+
import invariant from 'assert';
|
|
8
|
+
import ThrowableDiagnostic from '@parcel/diagnostic';
|
|
9
|
+
import {resolveConfig} from '@parcel/utils';
|
|
10
|
+
import {exec as _exec} from 'child_process';
|
|
11
|
+
import {promisify} from 'util';
|
|
12
|
+
|
|
13
|
+
export const exec: (
|
|
14
|
+
command: string,
|
|
15
|
+
options?: child_process$execOpts,
|
|
16
|
+
) => Promise<{|stdout: string | Buffer, stderr: string | Buffer|}> =
|
|
17
|
+
promisify(_exec);
|
|
18
|
+
|
|
19
|
+
export function npmSpecifierFromModuleRequest(
|
|
20
|
+
moduleRequest: ModuleRequest,
|
|
21
|
+
): string {
|
|
22
|
+
return moduleRequest.range != null
|
|
23
|
+
? [moduleRequest.name, moduleRequest.range].join('@')
|
|
24
|
+
: moduleRequest.name;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function moduleRequestsFromDependencyMap(dependencyMap: {|
|
|
28
|
+
[string]: string,
|
|
29
|
+
|}): Array<ModuleRequest> {
|
|
30
|
+
return Object.entries(dependencyMap).map(([name, range]) => {
|
|
31
|
+
invariant(typeof range === 'string');
|
|
32
|
+
return {
|
|
33
|
+
name,
|
|
34
|
+
range,
|
|
35
|
+
};
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export async function getConflictingLocalDependencies(
|
|
40
|
+
fs: FileSystem,
|
|
41
|
+
name: string,
|
|
42
|
+
local: FilePath,
|
|
43
|
+
projectRoot: FilePath,
|
|
44
|
+
): Promise<?{|json: string, filePath: FilePath, fields: Array<string>|}> {
|
|
45
|
+
let pkgPath = await resolveConfig(fs, local, ['package.json'], projectRoot);
|
|
46
|
+
if (pkgPath == null) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
let pkgStr = await fs.readFile(pkgPath, 'utf8');
|
|
51
|
+
let pkg;
|
|
52
|
+
try {
|
|
53
|
+
pkg = JSON.parse(pkgStr);
|
|
54
|
+
} catch (e) {
|
|
55
|
+
// TODO: codeframe
|
|
56
|
+
throw new ThrowableDiagnostic({
|
|
57
|
+
diagnostic: {
|
|
58
|
+
message: 'Failed to parse package.json',
|
|
59
|
+
origin: '@parcel/package-manager',
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (typeof pkg !== 'object' || pkg == null) {
|
|
65
|
+
// TODO: codeframe
|
|
66
|
+
throw new ThrowableDiagnostic({
|
|
67
|
+
diagnostic: {
|
|
68
|
+
message: 'Expected package.json contents to be an object.',
|
|
69
|
+
origin: '@parcel/package-manager',
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
let fields = [];
|
|
75
|
+
for (let field of ['dependencies', 'devDependencies', 'peerDependencies']) {
|
|
76
|
+
if (
|
|
77
|
+
typeof pkg[field] === 'object' &&
|
|
78
|
+
pkg[field] != null &&
|
|
79
|
+
pkg[field][name] != null
|
|
80
|
+
) {
|
|
81
|
+
fields.push(field);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (fields.length > 0) {
|
|
86
|
+
return {
|
|
87
|
+
filePath: pkgPath,
|
|
88
|
+
json: pkgStr,
|
|
89
|
+
fields,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
|
|
3
|
+
const MODULE_REGEX = /^((@[^/\s]+\/){0,1}([^/\s.~]+[^/\s]*)){1}(@[^/\s]+){0,1}/;
|
|
4
|
+
|
|
5
|
+
export default function validateModuleSpecifier(moduleName: string): string {
|
|
6
|
+
let matches = MODULE_REGEX.exec(moduleName);
|
|
7
|
+
if (matches) {
|
|
8
|
+
return matches[0];
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
return '';
|
|
12
|
+
}
|
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
// @flow strict-local
|
|
2
|
+
|
|
3
|
+
import {MemoryFS, NodeFS, OverlayFS} from '@parcel/fs';
|
|
4
|
+
import assert from 'assert';
|
|
5
|
+
import invariant from 'assert';
|
|
6
|
+
import path from 'path';
|
|
7
|
+
import sinon from 'sinon';
|
|
8
|
+
import ThrowableDiagnostic from '@parcel/diagnostic';
|
|
9
|
+
import {loadConfig} from '@parcel/utils';
|
|
10
|
+
import WorkerFarm from '@parcel/workers';
|
|
11
|
+
import {MockPackageInstaller, NodePackageManager} from '../src';
|
|
12
|
+
|
|
13
|
+
const FIXTURES_DIR = path.join(__dirname, 'fixtures');
|
|
14
|
+
|
|
15
|
+
describe('NodePackageManager', function () {
|
|
16
|
+
let fs;
|
|
17
|
+
let packageManager;
|
|
18
|
+
let packageInstaller;
|
|
19
|
+
let workerFarm;
|
|
20
|
+
|
|
21
|
+
// These can sometimes take a lil while
|
|
22
|
+
this.timeout(20000);
|
|
23
|
+
|
|
24
|
+
beforeEach(() => {
|
|
25
|
+
workerFarm = new WorkerFarm({
|
|
26
|
+
workerPath: require.resolve('@parcel/core/src/worker.js'),
|
|
27
|
+
});
|
|
28
|
+
fs = new OverlayFS(new MemoryFS(workerFarm), new NodeFS());
|
|
29
|
+
packageInstaller = new MockPackageInstaller();
|
|
30
|
+
packageManager = new NodePackageManager(fs, '/', packageInstaller);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
afterEach(async () => {
|
|
34
|
+
loadConfig.clear();
|
|
35
|
+
await workerFarm.end();
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('resolves packages that exist', async () => {
|
|
39
|
+
assert.deepEqual(
|
|
40
|
+
await packageManager.resolve(
|
|
41
|
+
'foo',
|
|
42
|
+
path.join(FIXTURES_DIR, 'has-foo/index.js'),
|
|
43
|
+
),
|
|
44
|
+
{
|
|
45
|
+
pkg: {
|
|
46
|
+
version: '1.1.0',
|
|
47
|
+
},
|
|
48
|
+
resolved: path.join(FIXTURES_DIR, 'has-foo/node_modules/foo/index.js'),
|
|
49
|
+
type: 1,
|
|
50
|
+
invalidateOnFileChange: new Set([
|
|
51
|
+
path.join(FIXTURES_DIR, 'has-foo/node_modules/foo/package.json'),
|
|
52
|
+
]),
|
|
53
|
+
invalidateOnFileCreate: [
|
|
54
|
+
{
|
|
55
|
+
fileName: 'node_modules/foo',
|
|
56
|
+
aboveFilePath: path.join(FIXTURES_DIR, 'has-foo'),
|
|
57
|
+
},
|
|
58
|
+
],
|
|
59
|
+
},
|
|
60
|
+
);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it('requires packages that exist', async () => {
|
|
64
|
+
assert.deepEqual(
|
|
65
|
+
await packageManager.require(
|
|
66
|
+
'foo',
|
|
67
|
+
path.join(FIXTURES_DIR, 'has-foo/index.js'),
|
|
68
|
+
),
|
|
69
|
+
'foobar',
|
|
70
|
+
);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it("autoinstalls packages that don't exist", async () => {
|
|
74
|
+
packageInstaller.register('a', fs, path.join(FIXTURES_DIR, 'packages/a'));
|
|
75
|
+
|
|
76
|
+
assert.deepEqual(
|
|
77
|
+
await packageManager.resolve(
|
|
78
|
+
'a',
|
|
79
|
+
path.join(FIXTURES_DIR, 'has-foo/index.js'),
|
|
80
|
+
{shouldAutoInstall: true},
|
|
81
|
+
),
|
|
82
|
+
{
|
|
83
|
+
pkg: {
|
|
84
|
+
name: 'a',
|
|
85
|
+
},
|
|
86
|
+
resolved: path.join(FIXTURES_DIR, 'has-foo/node_modules/a/index.js'),
|
|
87
|
+
type: 1,
|
|
88
|
+
invalidateOnFileChange: new Set([
|
|
89
|
+
path.join(FIXTURES_DIR, 'has-foo/node_modules/a/package.json'),
|
|
90
|
+
]),
|
|
91
|
+
invalidateOnFileCreate: [
|
|
92
|
+
{
|
|
93
|
+
fileName: 'node_modules/a',
|
|
94
|
+
aboveFilePath: path.join(FIXTURES_DIR, 'has-foo'),
|
|
95
|
+
},
|
|
96
|
+
],
|
|
97
|
+
},
|
|
98
|
+
);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it('does not autoinstall packages that are already listed in package.json', async () => {
|
|
102
|
+
packageInstaller.register('a', fs, path.join(FIXTURES_DIR, 'packages/a'));
|
|
103
|
+
|
|
104
|
+
// $FlowFixMe assert.rejects is Node 10+
|
|
105
|
+
await assert.rejects(
|
|
106
|
+
() =>
|
|
107
|
+
packageManager.resolve(
|
|
108
|
+
'a',
|
|
109
|
+
path.join(FIXTURES_DIR, 'has-a-not-yet-installed/index.js'),
|
|
110
|
+
{shouldAutoInstall: true},
|
|
111
|
+
),
|
|
112
|
+
err => {
|
|
113
|
+
invariant(err instanceof ThrowableDiagnostic);
|
|
114
|
+
assert(err.message.includes('Run your package manager'));
|
|
115
|
+
return true;
|
|
116
|
+
},
|
|
117
|
+
);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it('does not autoinstall peer dependencies that are already listed in package.json', async () => {
|
|
121
|
+
packageInstaller.register(
|
|
122
|
+
'peers',
|
|
123
|
+
fs,
|
|
124
|
+
path.join(FIXTURES_DIR, 'packages/peers'),
|
|
125
|
+
);
|
|
126
|
+
|
|
127
|
+
let spy = sinon.spy(packageInstaller, 'install');
|
|
128
|
+
await packageManager.resolve(
|
|
129
|
+
'peers',
|
|
130
|
+
path.join(FIXTURES_DIR, 'has-foo/index.js'),
|
|
131
|
+
{shouldAutoInstall: true},
|
|
132
|
+
);
|
|
133
|
+
assert.deepEqual(spy.args, [
|
|
134
|
+
[
|
|
135
|
+
{
|
|
136
|
+
cwd: path.join(FIXTURES_DIR, 'has-foo'),
|
|
137
|
+
packagePath: path.join(FIXTURES_DIR, 'has-foo/package.json'),
|
|
138
|
+
fs,
|
|
139
|
+
saveDev: true,
|
|
140
|
+
modules: [{name: 'peers', range: undefined}],
|
|
141
|
+
},
|
|
142
|
+
],
|
|
143
|
+
]);
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
it('autoinstalls peer dependencies that are not listed in package.json', async () => {
|
|
147
|
+
packageInstaller.register(
|
|
148
|
+
'foo',
|
|
149
|
+
fs,
|
|
150
|
+
path.join(FIXTURES_DIR, 'packages/foo-2.0'),
|
|
151
|
+
);
|
|
152
|
+
packageInstaller.register(
|
|
153
|
+
'peers',
|
|
154
|
+
fs,
|
|
155
|
+
path.join(FIXTURES_DIR, 'packages/peers-2.0'),
|
|
156
|
+
);
|
|
157
|
+
|
|
158
|
+
let spy = sinon.spy(packageInstaller, 'install');
|
|
159
|
+
await packageManager.resolve(
|
|
160
|
+
'peers',
|
|
161
|
+
path.join(FIXTURES_DIR, 'empty/index.js'),
|
|
162
|
+
{shouldAutoInstall: true},
|
|
163
|
+
);
|
|
164
|
+
assert.deepEqual(spy.args, [
|
|
165
|
+
[
|
|
166
|
+
{
|
|
167
|
+
cwd: path.join(FIXTURES_DIR, 'empty'),
|
|
168
|
+
packagePath: path.join(FIXTURES_DIR, 'empty/package.json'),
|
|
169
|
+
fs,
|
|
170
|
+
saveDev: true,
|
|
171
|
+
modules: [{name: 'peers', range: undefined}],
|
|
172
|
+
},
|
|
173
|
+
],
|
|
174
|
+
[
|
|
175
|
+
{
|
|
176
|
+
cwd: path.join(FIXTURES_DIR, 'empty'),
|
|
177
|
+
packagePath: path.join(FIXTURES_DIR, 'empty/package.json'),
|
|
178
|
+
fs,
|
|
179
|
+
saveDev: true,
|
|
180
|
+
modules: [{name: 'foo', range: '^2.0.0'}],
|
|
181
|
+
},
|
|
182
|
+
],
|
|
183
|
+
]);
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
describe('range mismatch', () => {
|
|
187
|
+
it("cannot autoinstall if there's a local requirement", async () => {
|
|
188
|
+
packageManager.invalidate(
|
|
189
|
+
'foo',
|
|
190
|
+
path.join(FIXTURES_DIR, 'has-foo/index.js'),
|
|
191
|
+
);
|
|
192
|
+
|
|
193
|
+
// $FlowFixMe assert.rejects is Node 10+
|
|
194
|
+
await assert.rejects(
|
|
195
|
+
() =>
|
|
196
|
+
packageManager.resolve(
|
|
197
|
+
'foo',
|
|
198
|
+
path.join(FIXTURES_DIR, 'has-foo/index.js'),
|
|
199
|
+
{
|
|
200
|
+
range: '^2.0.0',
|
|
201
|
+
},
|
|
202
|
+
),
|
|
203
|
+
err => {
|
|
204
|
+
invariant(err instanceof ThrowableDiagnostic);
|
|
205
|
+
assert.equal(
|
|
206
|
+
err.message,
|
|
207
|
+
'Could not find module "foo" satisfying ^2.0.0.',
|
|
208
|
+
);
|
|
209
|
+
return true;
|
|
210
|
+
},
|
|
211
|
+
);
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
it("can autoinstall into local package if there isn't a local requirement", async () => {
|
|
215
|
+
packageInstaller.register(
|
|
216
|
+
'foo',
|
|
217
|
+
fs,
|
|
218
|
+
path.join(FIXTURES_DIR, 'packages/foo-2.0'),
|
|
219
|
+
);
|
|
220
|
+
|
|
221
|
+
let spy = sinon.spy(packageInstaller, 'install');
|
|
222
|
+
assert.deepEqual(
|
|
223
|
+
await packageManager.resolve(
|
|
224
|
+
'foo',
|
|
225
|
+
path.join(FIXTURES_DIR, 'has-foo/subpackage/index.js'),
|
|
226
|
+
{
|
|
227
|
+
range: '^2.0.0',
|
|
228
|
+
shouldAutoInstall: true,
|
|
229
|
+
},
|
|
230
|
+
),
|
|
231
|
+
{
|
|
232
|
+
pkg: {
|
|
233
|
+
name: 'foo',
|
|
234
|
+
version: '2.0.0',
|
|
235
|
+
},
|
|
236
|
+
resolved: path.join(
|
|
237
|
+
FIXTURES_DIR,
|
|
238
|
+
'has-foo/subpackage/node_modules/foo/index.js',
|
|
239
|
+
),
|
|
240
|
+
type: 1,
|
|
241
|
+
invalidateOnFileChange: new Set([
|
|
242
|
+
path.join(
|
|
243
|
+
FIXTURES_DIR,
|
|
244
|
+
'has-foo/subpackage/node_modules/foo/package.json',
|
|
245
|
+
),
|
|
246
|
+
]),
|
|
247
|
+
invalidateOnFileCreate: [
|
|
248
|
+
{
|
|
249
|
+
fileName: 'node_modules/foo',
|
|
250
|
+
aboveFilePath: path.join(FIXTURES_DIR, 'has-foo/subpackage'),
|
|
251
|
+
},
|
|
252
|
+
],
|
|
253
|
+
},
|
|
254
|
+
);
|
|
255
|
+
|
|
256
|
+
assert.deepEqual(spy.args, [
|
|
257
|
+
[
|
|
258
|
+
{
|
|
259
|
+
cwd: path.join(FIXTURES_DIR, 'has-foo/subpackage'),
|
|
260
|
+
packagePath: path.join(
|
|
261
|
+
FIXTURES_DIR,
|
|
262
|
+
'has-foo/subpackage/package.json',
|
|
263
|
+
),
|
|
264
|
+
fs,
|
|
265
|
+
saveDev: true,
|
|
266
|
+
modules: [{name: 'foo', range: '^2.0.0'}],
|
|
267
|
+
},
|
|
268
|
+
],
|
|
269
|
+
]);
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
it("cannot autoinstall peer dependencies if there's an incompatible local requirement", async () => {
|
|
273
|
+
packageManager.invalidate(
|
|
274
|
+
'peers',
|
|
275
|
+
path.join(FIXTURES_DIR, 'has-foo/index.js'),
|
|
276
|
+
);
|
|
277
|
+
packageInstaller.register(
|
|
278
|
+
'foo',
|
|
279
|
+
fs,
|
|
280
|
+
path.join(FIXTURES_DIR, 'packages/foo-2.0'),
|
|
281
|
+
);
|
|
282
|
+
packageInstaller.register(
|
|
283
|
+
'peers',
|
|
284
|
+
fs,
|
|
285
|
+
path.join(FIXTURES_DIR, 'packages/peers-2.0'),
|
|
286
|
+
);
|
|
287
|
+
|
|
288
|
+
// $FlowFixMe assert.rejects is Node 10+
|
|
289
|
+
await assert.rejects(
|
|
290
|
+
() =>
|
|
291
|
+
packageManager.resolve(
|
|
292
|
+
'peers',
|
|
293
|
+
path.join(FIXTURES_DIR, 'has-foo/index.js'),
|
|
294
|
+
{
|
|
295
|
+
range: '^2.0.0',
|
|
296
|
+
shouldAutoInstall: true,
|
|
297
|
+
},
|
|
298
|
+
),
|
|
299
|
+
err => {
|
|
300
|
+
assert(err instanceof ThrowableDiagnostic);
|
|
301
|
+
assert.equal(
|
|
302
|
+
err.message,
|
|
303
|
+
'Could not install the peer dependency "foo" for "peers", installed version 1.1.0 is incompatible with ^2.0.0',
|
|
304
|
+
);
|
|
305
|
+
return true;
|
|
306
|
+
},
|
|
307
|
+
);
|
|
308
|
+
});
|
|
309
|
+
});
|
|
310
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
module.exports = 'foobar';
|
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
module.exports = 'a';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
module.exports = 'foo';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
module.exports = 'foo';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
module.exports = 'foo';
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
import assert from 'assert';
|
|
3
|
+
|
|
4
|
+
import validateModuleSpecifier from '../src/validateModuleSpecifier';
|
|
5
|
+
|
|
6
|
+
describe('Validate Module Specifiers', () => {
|
|
7
|
+
it('Validate Module Specifiers', () => {
|
|
8
|
+
let modules = [
|
|
9
|
+
'@parcel/transformer-posthtml/package.json',
|
|
10
|
+
'@some-org/package@v1.0.0',
|
|
11
|
+
'@org/some-package@v1.0.0-alpha.1',
|
|
12
|
+
'something.js/something/index.js',
|
|
13
|
+
'@some.org/something.js/index.js',
|
|
14
|
+
'lodash/something/index.js',
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
assert.deepEqual(
|
|
18
|
+
modules.map(module => validateModuleSpecifier(module)),
|
|
19
|
+
[
|
|
20
|
+
'@parcel/transformer-posthtml',
|
|
21
|
+
'@some-org/package@v1.0.0',
|
|
22
|
+
'@org/some-package@v1.0.0-alpha.1',
|
|
23
|
+
'something.js',
|
|
24
|
+
'@some.org/something.js',
|
|
25
|
+
'lodash',
|
|
26
|
+
],
|
|
27
|
+
);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it('Return empty on invalid modules', () => {
|
|
31
|
+
let modules = ['./somewhere.js', './hello/world.js', '~/hello/world.js'];
|
|
32
|
+
|
|
33
|
+
assert.deepEqual(
|
|
34
|
+
modules.map(module => validateModuleSpecifier(module)),
|
|
35
|
+
['', '', ''],
|
|
36
|
+
);
|
|
37
|
+
});
|
|
38
|
+
});
|