@ohos-ports/parcel-package-manager 2.16.4-beta.0

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.
Files changed (36) hide show
  1. package/LICENSE +21 -0
  2. package/index.d.ts +40 -0
  3. package/lib/index.d.ts +10 -0
  4. package/lib/index.js +1968 -0
  5. package/lib/index.js.map +1 -0
  6. package/package.json +73 -0
  7. package/src/JSONParseStream.js +39 -0
  8. package/src/MockPackageInstaller.js +94 -0
  9. package/src/NodePackageManager.js +662 -0
  10. package/src/Npm.js +94 -0
  11. package/src/Pnpm.js +194 -0
  12. package/src/Yarn.js +157 -0
  13. package/src/getCurrentPackageManager.js +17 -0
  14. package/src/index.js +19 -0
  15. package/src/installPackage.js +284 -0
  16. package/src/promiseFromProcess.js +19 -0
  17. package/src/utils.js +93 -0
  18. package/src/validateModuleSpecifier.js +12 -0
  19. package/test/NodePackageManager.test.js +387 -0
  20. package/test/fixtures/empty/package.json +1 -0
  21. package/test/fixtures/has-a-not-yet-installed/package.json +5 -0
  22. package/test/fixtures/has-foo/node_modules/foo/index.js +1 -0
  23. package/test/fixtures/has-foo/node_modules/foo/package.json +3 -0
  24. package/test/fixtures/has-foo/node_modules/index.js +0 -0
  25. package/test/fixtures/has-foo/package.json +5 -0
  26. package/test/fixtures/has-foo/subpackage/package.json +1 -0
  27. package/test/fixtures/packages/a/index.js +1 -0
  28. package/test/fixtures/packages/a/package.json +3 -0
  29. package/test/fixtures/packages/foo-2.0/index.js +1 -0
  30. package/test/fixtures/packages/foo-2.0/package.json +4 -0
  31. package/test/fixtures/packages/peers/index.js +1 -0
  32. package/test/fixtures/packages/peers/package.json +7 -0
  33. package/test/fixtures/packages/peers-2.0/index.js +1 -0
  34. package/test/fixtures/packages/peers-2.0/package.json +7 -0
  35. package/test/getCurrentPackageManager.test.js +28 -0
  36. package/test/validateModuleSpecifiers.test.js +38 -0
@@ -0,0 +1,387 @@
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
+ function normalize(res) {
16
+ return {
17
+ ...res,
18
+ invalidateOnFileCreate:
19
+ res?.invalidateOnFileCreate?.sort((a, b) => {
20
+ let ax =
21
+ a.filePath ??
22
+ a.glob ??
23
+ (a.aboveFilePath != null && a.fileName != null
24
+ ? a.aboveFilePath + a.fileName
25
+ : '');
26
+ let bx =
27
+ b.filePath ??
28
+ b.glob ??
29
+ (b.aboveFilePath != null && b.fileName != null
30
+ ? b.aboveFilePath + b.fileName
31
+ : '');
32
+ return ax < bx ? -1 : 1;
33
+ }) ?? [],
34
+ };
35
+ }
36
+
37
+ function check(resolved, expected) {
38
+ assert.deepEqual(normalize(resolved), normalize(expected));
39
+ }
40
+
41
+ describe('NodePackageManager', function () {
42
+ let fs;
43
+ let packageManager;
44
+ let packageInstaller;
45
+ let workerFarm;
46
+
47
+ // These can sometimes take a lil while
48
+ this.timeout(20000);
49
+
50
+ beforeEach(() => {
51
+ workerFarm = new WorkerFarm({
52
+ workerPath: require.resolve('@parcel/core/src/worker.js'),
53
+ });
54
+ fs = new OverlayFS(new MemoryFS(workerFarm), new NodeFS());
55
+ packageInstaller = new MockPackageInstaller();
56
+ packageManager = new NodePackageManager(fs, '/', packageInstaller);
57
+ });
58
+
59
+ afterEach(async () => {
60
+ loadConfig.clear();
61
+ await workerFarm.end();
62
+ });
63
+
64
+ it('resolves packages that exist', async () => {
65
+ check(
66
+ await packageManager.resolve(
67
+ 'foo',
68
+ path.join(FIXTURES_DIR, 'has-foo/index.js'),
69
+ ),
70
+ {
71
+ pkg: {
72
+ version: '1.1.0',
73
+ },
74
+ resolved: path.join(FIXTURES_DIR, 'has-foo/node_modules/foo/index.js'),
75
+ type: 1,
76
+ invalidateOnFileChange: new Set([
77
+ path.join(FIXTURES_DIR, 'has-foo/package.json'),
78
+ path.join(FIXTURES_DIR, 'has-foo/node_modules/foo/package.json'),
79
+ ]),
80
+ invalidateOnFileCreate: [
81
+ {
82
+ filePath: path.join(
83
+ FIXTURES_DIR,
84
+ 'has-foo/node_modules/foo/index.ts',
85
+ ),
86
+ },
87
+ {
88
+ filePath: path.join(
89
+ FIXTURES_DIR,
90
+ 'has-foo/node_modules/foo/index.tsx',
91
+ ),
92
+ },
93
+ {
94
+ fileName: 'node_modules/foo',
95
+ aboveFilePath: path.join(FIXTURES_DIR, 'has-foo'),
96
+ },
97
+ {
98
+ fileName: 'tsconfig.json',
99
+ aboveFilePath: path.join(FIXTURES_DIR, 'has-foo'),
100
+ },
101
+ ],
102
+ },
103
+ );
104
+ });
105
+
106
+ it('requires packages that exist', async () => {
107
+ assert.deepEqual(
108
+ await packageManager.require(
109
+ 'foo',
110
+ path.join(FIXTURES_DIR, 'has-foo/index.js'),
111
+ ),
112
+ 'foobar',
113
+ );
114
+ });
115
+
116
+ it("autoinstalls packages that don't exist", async () => {
117
+ packageInstaller.register('a', fs, path.join(FIXTURES_DIR, 'packages/a'));
118
+
119
+ check(
120
+ await packageManager.resolve(
121
+ 'a',
122
+ path.join(FIXTURES_DIR, 'has-foo/index.js'),
123
+ {shouldAutoInstall: true},
124
+ ),
125
+ {
126
+ pkg: {
127
+ name: 'a',
128
+ },
129
+ resolved: path.join(FIXTURES_DIR, 'has-foo/node_modules/a/index.js'),
130
+ type: 1,
131
+ invalidateOnFileChange: new Set([
132
+ path.join(FIXTURES_DIR, 'has-foo/package.json'),
133
+ path.join(FIXTURES_DIR, 'has-foo/node_modules/a/package.json'),
134
+ ]),
135
+ invalidateOnFileCreate: [
136
+ {
137
+ filePath: path.join(
138
+ FIXTURES_DIR,
139
+ 'has-foo/node_modules/a/index.ts',
140
+ ),
141
+ },
142
+ {
143
+ filePath: path.join(
144
+ FIXTURES_DIR,
145
+ 'has-foo/node_modules/a/index.tsx',
146
+ ),
147
+ },
148
+ {
149
+ fileName: 'node_modules/a',
150
+ aboveFilePath: path.join(FIXTURES_DIR, 'has-foo'),
151
+ },
152
+ {
153
+ fileName: 'tsconfig.json',
154
+ aboveFilePath: path.join(FIXTURES_DIR, 'has-foo'),
155
+ },
156
+ ],
157
+ },
158
+ );
159
+ });
160
+
161
+ it('does not autoinstall packages that are already listed in package.json', async () => {
162
+ packageInstaller.register('a', fs, path.join(FIXTURES_DIR, 'packages/a'));
163
+
164
+ // $FlowFixMe assert.rejects is Node 10+
165
+ await assert.rejects(
166
+ () =>
167
+ packageManager.resolve(
168
+ 'a',
169
+ path.join(FIXTURES_DIR, 'has-a-not-yet-installed/index.js'),
170
+ {shouldAutoInstall: true},
171
+ ),
172
+ err => {
173
+ invariant(err instanceof ThrowableDiagnostic);
174
+ assert(err.message.includes('Run your package manager'));
175
+ return true;
176
+ },
177
+ );
178
+ });
179
+
180
+ it('does not autoinstall peer dependencies that are already listed in package.json', async () => {
181
+ packageInstaller.register(
182
+ 'peers',
183
+ fs,
184
+ path.join(FIXTURES_DIR, 'packages/peers'),
185
+ );
186
+
187
+ let spy = sinon.spy(packageInstaller, 'install');
188
+ await packageManager.resolve(
189
+ 'peers',
190
+ path.join(FIXTURES_DIR, 'has-foo/index.js'),
191
+ {shouldAutoInstall: true},
192
+ );
193
+ assert.deepEqual(spy.args, [
194
+ [
195
+ {
196
+ cwd: path.join(FIXTURES_DIR, 'has-foo'),
197
+ packagePath: path.join(FIXTURES_DIR, 'has-foo/package.json'),
198
+ fs,
199
+ saveDev: true,
200
+ modules: [{name: 'peers', range: undefined}],
201
+ },
202
+ ],
203
+ ]);
204
+ });
205
+
206
+ it('autoinstalls peer dependencies that are not listed in package.json', async () => {
207
+ packageInstaller.register(
208
+ 'foo',
209
+ fs,
210
+ path.join(FIXTURES_DIR, 'packages/foo-2.0'),
211
+ );
212
+ packageInstaller.register(
213
+ 'peers',
214
+ fs,
215
+ path.join(FIXTURES_DIR, 'packages/peers-2.0'),
216
+ );
217
+
218
+ let spy = sinon.spy(packageInstaller, 'install');
219
+ await packageManager.resolve(
220
+ 'peers',
221
+ path.join(FIXTURES_DIR, 'empty/index.js'),
222
+ {shouldAutoInstall: true},
223
+ );
224
+ assert.deepEqual(spy.args, [
225
+ [
226
+ {
227
+ cwd: path.join(FIXTURES_DIR, 'empty'),
228
+ packagePath: path.join(FIXTURES_DIR, 'empty/package.json'),
229
+ fs,
230
+ saveDev: true,
231
+ modules: [{name: 'peers', range: undefined}],
232
+ },
233
+ ],
234
+ [
235
+ {
236
+ cwd: path.join(FIXTURES_DIR, 'empty'),
237
+ packagePath: path.join(FIXTURES_DIR, 'empty/package.json'),
238
+ fs,
239
+ saveDev: true,
240
+ modules: [{name: 'foo', range: '^2.0.0'}],
241
+ },
242
+ ],
243
+ ]);
244
+ });
245
+
246
+ describe('range mismatch', () => {
247
+ it("cannot autoinstall if there's a local requirement", async () => {
248
+ packageManager.invalidate(
249
+ 'foo',
250
+ path.join(FIXTURES_DIR, 'has-foo/index.js'),
251
+ );
252
+
253
+ // $FlowFixMe assert.rejects is Node 10+
254
+ await assert.rejects(
255
+ () =>
256
+ packageManager.resolve(
257
+ 'foo',
258
+ path.join(FIXTURES_DIR, 'has-foo/index.js'),
259
+ {
260
+ range: '^2.0.0',
261
+ },
262
+ ),
263
+ err => {
264
+ invariant(err instanceof ThrowableDiagnostic);
265
+ assert.equal(
266
+ err.message,
267
+ 'Could not find module "foo" satisfying ^2.0.0.',
268
+ );
269
+ return true;
270
+ },
271
+ );
272
+ });
273
+
274
+ it("can autoinstall into local package if there isn't a local requirement", async () => {
275
+ packageInstaller.register(
276
+ 'foo',
277
+ fs,
278
+ path.join(FIXTURES_DIR, 'packages/foo-2.0'),
279
+ );
280
+
281
+ let spy = sinon.spy(packageInstaller, 'install');
282
+ check(
283
+ await packageManager.resolve(
284
+ 'foo',
285
+ path.join(FIXTURES_DIR, 'has-foo/subpackage/index.js'),
286
+ {
287
+ range: '^2.0.0',
288
+ shouldAutoInstall: true,
289
+ },
290
+ ),
291
+ {
292
+ pkg: {
293
+ name: 'foo',
294
+ version: '2.0.0',
295
+ },
296
+ resolved: path.join(
297
+ FIXTURES_DIR,
298
+ 'has-foo/subpackage/node_modules/foo/index.js',
299
+ ),
300
+ type: 1,
301
+ invalidateOnFileChange: new Set([
302
+ path.join(FIXTURES_DIR, 'has-foo/subpackage/package.json'),
303
+ path.join(
304
+ FIXTURES_DIR,
305
+ 'has-foo/subpackage/node_modules/foo/package.json',
306
+ ),
307
+ ]),
308
+ invalidateOnFileCreate: [
309
+ {
310
+ filePath: path.join(
311
+ FIXTURES_DIR,
312
+ 'has-foo/subpackage/node_modules/foo/index.ts',
313
+ ),
314
+ },
315
+ {
316
+ filePath: path.join(
317
+ FIXTURES_DIR,
318
+ 'has-foo/subpackage/node_modules/foo/index.tsx',
319
+ ),
320
+ },
321
+ {
322
+ fileName: 'node_modules/foo',
323
+ aboveFilePath: path.join(FIXTURES_DIR, 'has-foo/subpackage'),
324
+ },
325
+ {
326
+ fileName: 'tsconfig.json',
327
+ aboveFilePath: path.join(FIXTURES_DIR, 'has-foo/subpackage'),
328
+ },
329
+ ],
330
+ },
331
+ );
332
+
333
+ assert.deepEqual(spy.args, [
334
+ [
335
+ {
336
+ cwd: path.join(FIXTURES_DIR, 'has-foo/subpackage'),
337
+ packagePath: path.join(
338
+ FIXTURES_DIR,
339
+ 'has-foo/subpackage/package.json',
340
+ ),
341
+ fs,
342
+ saveDev: true,
343
+ modules: [{name: 'foo', range: '^2.0.0'}],
344
+ },
345
+ ],
346
+ ]);
347
+ });
348
+
349
+ it("cannot autoinstall peer dependencies if there's an incompatible local requirement", async () => {
350
+ packageManager.invalidate(
351
+ 'peers',
352
+ path.join(FIXTURES_DIR, 'has-foo/index.js'),
353
+ );
354
+ packageInstaller.register(
355
+ 'foo',
356
+ fs,
357
+ path.join(FIXTURES_DIR, 'packages/foo-2.0'),
358
+ );
359
+ packageInstaller.register(
360
+ 'peers',
361
+ fs,
362
+ path.join(FIXTURES_DIR, 'packages/peers-2.0'),
363
+ );
364
+
365
+ // $FlowFixMe assert.rejects is Node 10+
366
+ await assert.rejects(
367
+ () =>
368
+ packageManager.resolve(
369
+ 'peers',
370
+ path.join(FIXTURES_DIR, 'has-foo/index.js'),
371
+ {
372
+ range: '^2.0.0',
373
+ shouldAutoInstall: true,
374
+ },
375
+ ),
376
+ err => {
377
+ assert(err instanceof ThrowableDiagnostic);
378
+ assert.equal(
379
+ err.message,
380
+ 'Could not install the peer dependency "foo" for "peers", installed version 1.1.0 is incompatible with ^2.0.0',
381
+ );
382
+ return true;
383
+ },
384
+ );
385
+ });
386
+ });
387
+ });
@@ -0,0 +1 @@
1
+ {}
@@ -0,0 +1,5 @@
1
+ {
2
+ "dependencies": {
3
+ "a": "1.1.0"
4
+ }
5
+ }
@@ -0,0 +1 @@
1
+ module.exports = 'foobar';
@@ -0,0 +1,3 @@
1
+ {
2
+ "version": "1.1.0"
3
+ }
File without changes
@@ -0,0 +1,5 @@
1
+ {
2
+ "dependencies": {
3
+ "foo": "1.1.0"
4
+ }
5
+ }
@@ -0,0 +1 @@
1
+ module.exports = 'a';
@@ -0,0 +1,3 @@
1
+ {
2
+ "name": "a"
3
+ }
@@ -0,0 +1 @@
1
+ module.exports = 'foo';
@@ -0,0 +1,4 @@
1
+ {
2
+ "name": "foo",
3
+ "version": "2.0.0"
4
+ }
@@ -0,0 +1 @@
1
+ module.exports = 'foo';
@@ -0,0 +1,7 @@
1
+ {
2
+ "name": "peers",
3
+ "version": "1.0.0",
4
+ "peerDependencies": {
5
+ "foo": "^1.0.0"
6
+ }
7
+ }
@@ -0,0 +1 @@
1
+ module.exports = 'foo';
@@ -0,0 +1,7 @@
1
+ {
2
+ "name": "peers",
3
+ "version": "2.0.0",
4
+ "peerDependencies": {
5
+ "foo": "^2.0.0"
6
+ }
7
+ }
@@ -0,0 +1,28 @@
1
+ // @flow
2
+ import assert from 'assert';
3
+ import getCurrentPackageManager from '../src/getCurrentPackageManager';
4
+
5
+ describe('getCurrentPackageManager', () => {
6
+ it('yarn', () => {
7
+ const npm_config_user_agent = 'yarn/1.22.21 npm/? node/v21.1.0 darwin x64';
8
+ const currentPackageManager = getCurrentPackageManager(
9
+ npm_config_user_agent,
10
+ );
11
+ assert(currentPackageManager?.name, 'yarn');
12
+ });
13
+ it('npm', () => {
14
+ const npm_config_user_agent =
15
+ 'npm/10.2.0 node/v21.1.0 darwin x64 workspaces/true';
16
+ const currentPackageManager = getCurrentPackageManager(
17
+ npm_config_user_agent,
18
+ );
19
+ assert(currentPackageManager?.name, 'npm');
20
+ });
21
+ it('pnpm', () => {
22
+ const npm_config_user_agent = 'pnpm/8.14.2 npm/? node/v18.17.1 darwin x64';
23
+ const currentPackageManager = getCurrentPackageManager(
24
+ npm_config_user_agent,
25
+ );
26
+ assert(currentPackageManager?.name, 'pnpm');
27
+ });
28
+ });
@@ -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
+ });