@atlaspack/core 2.16.2-canary.13 → 2.16.2-canary.130
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/CHANGELOG.md +284 -0
- package/index.d.ts +4 -0
- package/lib/AssetGraph.js +27 -7
- package/lib/Atlaspack.js +35 -27
- package/lib/AtlaspackConfig.schema.js +7 -1
- package/lib/BundleGraph.js +8 -5
- package/lib/Dependency.js +6 -2
- package/lib/Environment.js +5 -3
- package/lib/EnvironmentManager.js +137 -0
- package/lib/InternalConfig.js +3 -2
- package/lib/PackagerRunner.js +54 -16
- package/lib/RequestTracker.js +345 -132
- package/lib/SymbolPropagation.js +14 -0
- package/lib/Transformation.js +2 -2
- package/lib/UncommittedAsset.js +20 -2
- package/lib/applyRuntimes.js +2 -1
- package/lib/assetUtils.js +2 -1
- package/lib/atlaspack-v3/AtlaspackV3.js +16 -3
- package/lib/atlaspack-v3/worker/compat/environment.js +2 -2
- package/lib/atlaspack-v3/worker/compat/mutable-asset.js +6 -6
- package/lib/atlaspack-v3/worker/compat/plugin-config.js +5 -5
- package/lib/atlaspack-v3/worker/index.js +3 -0
- package/lib/atlaspack-v3/worker/worker.js +8 -0
- package/lib/dumpGraphToGraphViz.js +1 -1
- package/lib/index.js +29 -1
- package/lib/public/Asset.js +7 -9
- package/lib/public/Bundle.js +12 -13
- package/lib/public/BundleGraph.js +3 -2
- package/lib/public/BundleGroup.js +2 -3
- package/lib/public/Config.js +95 -8
- package/lib/public/Dependency.js +4 -4
- package/lib/public/Environment.js +2 -3
- package/lib/public/MutableBundleGraph.js +5 -4
- package/lib/public/PluginOptions.js +1 -2
- package/lib/public/Target.js +4 -4
- package/lib/requests/AssetGraphRequest.js +13 -1
- package/lib/requests/AssetGraphRequestRust.js +17 -2
- package/lib/requests/AssetRequest.js +2 -1
- package/lib/requests/BundleGraphRequest.js +13 -1
- package/lib/requests/ConfigRequest.js +27 -4
- package/lib/requests/DevDepRequest.js +11 -1
- package/lib/requests/PathRequest.js +10 -0
- package/lib/requests/TargetRequest.js +18 -16
- package/lib/requests/WriteBundleRequest.js +15 -3
- package/lib/requests/WriteBundlesRequest.js +22 -1
- package/lib/resolveOptions.js +7 -4
- package/lib/worker.js +18 -1
- package/package.json +18 -25
- package/src/AssetGraph.js +30 -7
- package/src/Atlaspack.js +40 -23
- package/src/BundleGraph.js +13 -8
- package/src/Dependency.js +13 -5
- package/src/Environment.js +9 -6
- package/src/EnvironmentManager.js +145 -0
- package/src/InternalConfig.js +6 -5
- package/src/PackagerRunner.js +72 -20
- package/src/RequestTracker.js +526 -157
- package/src/SymbolPropagation.js +13 -1
- package/src/UncommittedAsset.js +23 -3
- package/src/applyRuntimes.js +6 -1
- package/src/assetUtils.js +4 -3
- package/src/atlaspack-v3/AtlaspackV3.js +24 -3
- package/src/atlaspack-v3/worker/compat/plugin-config.js +9 -5
- package/src/atlaspack-v3/worker/index.js +2 -1
- package/src/atlaspack-v3/worker/worker.js +7 -0
- package/src/index.js +5 -1
- package/src/public/Asset.js +13 -6
- package/src/public/Bundle.js +12 -11
- package/src/public/BundleGraph.js +10 -2
- package/src/public/BundleGroup.js +2 -2
- package/src/public/Config.js +132 -18
- package/src/public/Dependency.js +4 -3
- package/src/public/Environment.js +2 -2
- package/src/public/MutableBundleGraph.js +8 -5
- package/src/public/PluginOptions.js +1 -1
- package/src/public/Target.js +4 -3
- package/src/requests/AssetGraphRequest.js +13 -3
- package/src/requests/AssetGraphRequestRust.js +14 -2
- package/src/requests/AssetRequest.js +2 -1
- package/src/requests/BundleGraphRequest.js +13 -3
- package/src/requests/ConfigRequest.js +33 -9
- package/src/requests/DevDepRequest.js +22 -9
- package/src/requests/PathRequest.js +4 -0
- package/src/requests/TargetRequest.js +19 -25
- package/src/requests/WriteBundleRequest.js +14 -8
- package/src/requests/WriteBundlesRequest.js +31 -3
- package/src/resolveOptions.js +4 -2
- package/src/types.js +10 -7
- package/test/Environment.test.js +43 -34
- package/test/EnvironmentManager.test.js +192 -0
- package/test/PublicEnvironment.test.js +10 -7
- package/test/RequestTracker.test.js +124 -29
- package/test/public/Config.test.js +108 -0
- package/test/requests/ConfigRequest.test.js +199 -7
- package/test/test-utils.js +4 -9
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
// @flow strict-local
|
|
2
|
+
|
|
3
|
+
import sinon from 'sinon';
|
|
4
|
+
import {makeConfigProxy} from '../../src/public/Config';
|
|
5
|
+
import assert from 'assert';
|
|
6
|
+
|
|
7
|
+
describe('makeConfigProxy', () => {
|
|
8
|
+
it('tracks reads to nested fields', () => {
|
|
9
|
+
const onRead = sinon.spy();
|
|
10
|
+
const target = {a: {b: {c: 'd'}}};
|
|
11
|
+
const config = makeConfigProxy(onRead, target);
|
|
12
|
+
config.a.b.c;
|
|
13
|
+
assert.ok(onRead.calledWith(['a', 'b', 'c']));
|
|
14
|
+
assert.ok(onRead.calledOnce);
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it('works for reading package.json dependencies', () => {
|
|
18
|
+
const packageJson = {
|
|
19
|
+
dependencies: {
|
|
20
|
+
react: '18.2.0',
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const onRead = sinon.spy();
|
|
25
|
+
const config = makeConfigProxy(onRead, packageJson);
|
|
26
|
+
assert.equal(config.dependencies.react, '18.2.0');
|
|
27
|
+
// $FlowFixMe
|
|
28
|
+
assert.equal(config.dependencies.preact, undefined);
|
|
29
|
+
assert.ok(onRead.calledWith(['dependencies', 'react']));
|
|
30
|
+
assert.ok(onRead.calledWith(['dependencies', 'preact']));
|
|
31
|
+
assert.equal(onRead.callCount, 2);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('will track reads for any missing or null keys', () => {
|
|
35
|
+
const packageJson = {
|
|
36
|
+
dependencies: {
|
|
37
|
+
react: '18.2.0',
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const onRead = sinon.spy();
|
|
42
|
+
const config = makeConfigProxy(onRead, packageJson);
|
|
43
|
+
|
|
44
|
+
// $FlowFixMe
|
|
45
|
+
assert.equal(config.alias?.react, undefined);
|
|
46
|
+
assert.ok(onRead.calledWith(['alias']));
|
|
47
|
+
assert.equal(onRead.callCount, 1);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('iterating over keys works normally and will register a read for the key being enumerated', () => {
|
|
51
|
+
const packageJson = {
|
|
52
|
+
nested: {
|
|
53
|
+
dependencies: {
|
|
54
|
+
react: '18.2.0',
|
|
55
|
+
'react-dom': '18.2.0',
|
|
56
|
+
'react-router': '6.14.2',
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
const onRead = sinon.spy();
|
|
62
|
+
const config = makeConfigProxy(onRead, packageJson);
|
|
63
|
+
assert.equal(Object.keys(config.nested.dependencies).length, 3);
|
|
64
|
+
|
|
65
|
+
assert.ok(onRead.calledWith(['nested', 'dependencies']));
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it('if a key has an array value we will track a read for that key', () => {
|
|
69
|
+
const packageJson = {
|
|
70
|
+
scripts: ['build', 'test'],
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
const onRead = sinon.spy();
|
|
74
|
+
const config = makeConfigProxy(onRead, packageJson);
|
|
75
|
+
assert.equal(config.scripts[0], 'build');
|
|
76
|
+
assert.equal(onRead.callCount, 1);
|
|
77
|
+
assert.ok(onRead.calledWith(['scripts']));
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('if a key array value is iterated over we will track a read for that key', () => {
|
|
81
|
+
const packageJson = {
|
|
82
|
+
scripts: ['build', 'test'],
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
const onRead = sinon.spy();
|
|
86
|
+
const config = makeConfigProxy(onRead, packageJson);
|
|
87
|
+
let scriptCount = 0;
|
|
88
|
+
// eslint-disable-next-line no-unused-vars
|
|
89
|
+
for (const _script of config.scripts) {
|
|
90
|
+
scriptCount += 1;
|
|
91
|
+
}
|
|
92
|
+
assert.equal(scriptCount, 2);
|
|
93
|
+
assert.ok(onRead.calledWith(['scripts']));
|
|
94
|
+
assert.equal(onRead.callCount, 1);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it('if a key array value length is verified we will track a read for that key', () => {
|
|
98
|
+
const packageJson = {
|
|
99
|
+
scripts: ['build', 'test'],
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
const onRead = sinon.spy();
|
|
103
|
+
const config = makeConfigProxy(onRead, packageJson);
|
|
104
|
+
assert.equal(config.scripts.length, 2);
|
|
105
|
+
assert.ok(onRead.calledWith(['scripts']));
|
|
106
|
+
assert.equal(onRead.callCount, 1);
|
|
107
|
+
});
|
|
108
|
+
});
|
|
@@ -12,7 +12,10 @@ import type {
|
|
|
12
12
|
ConfigRequestResult,
|
|
13
13
|
} from '../../src/requests/ConfigRequest';
|
|
14
14
|
import type {RunAPI} from '../../src/RequestTracker';
|
|
15
|
-
import {
|
|
15
|
+
import {
|
|
16
|
+
getValueAtPath,
|
|
17
|
+
runConfigRequest,
|
|
18
|
+
} from '../../src/requests/ConfigRequest';
|
|
16
19
|
import {toProjectPath} from '../../src/projectPath';
|
|
17
20
|
|
|
18
21
|
// $FlowFixMe unclear-type forgive me
|
|
@@ -20,15 +23,23 @@ const mockCast = (f: any): any => f;
|
|
|
20
23
|
|
|
21
24
|
describe('ConfigRequest tests', () => {
|
|
22
25
|
const projectRoot = 'project_root';
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
+
let farm;
|
|
27
|
+
let fs;
|
|
28
|
+
before(() => {
|
|
29
|
+
farm = new WorkerFarm({
|
|
30
|
+
workerPath: require.resolve('../../src/worker'),
|
|
31
|
+
maxConcurrentWorkers: 1,
|
|
32
|
+
});
|
|
26
33
|
});
|
|
27
|
-
|
|
34
|
+
|
|
28
35
|
beforeEach(() => {
|
|
29
36
|
fs = new MemoryFS(farm);
|
|
30
37
|
});
|
|
31
38
|
|
|
39
|
+
after(() => {
|
|
40
|
+
farm.end();
|
|
41
|
+
});
|
|
42
|
+
|
|
32
43
|
const getMockRunApi = (
|
|
33
44
|
options: mixed = {projectRoot, inputFS: fs},
|
|
34
45
|
): RunAPI<ConfigRequestResult> => {
|
|
@@ -228,7 +239,7 @@ describe('ConfigRequest tests', () => {
|
|
|
228
239
|
...baseRequest,
|
|
229
240
|
invalidateOnConfigKeyChange: [
|
|
230
241
|
{
|
|
231
|
-
configKey: 'key1',
|
|
242
|
+
configKey: ['key1'],
|
|
232
243
|
filePath: toProjectPath(projectRoot, 'config.json'),
|
|
233
244
|
},
|
|
234
245
|
],
|
|
@@ -244,8 +255,189 @@ describe('ConfigRequest tests', () => {
|
|
|
244
255
|
const call = mockCast(mockRunApi.invalidateOnConfigKeyChange).getCall(0);
|
|
245
256
|
assert.deepEqual(
|
|
246
257
|
call.args,
|
|
247
|
-
['config.json', 'key1', hashString('"value1"')],
|
|
258
|
+
['config.json', ['key1'], hashString('"value1"')],
|
|
248
259
|
'Invalidate was called for key1',
|
|
249
260
|
);
|
|
250
261
|
});
|
|
251
262
|
});
|
|
263
|
+
|
|
264
|
+
describe('getValueAtPath', () => {
|
|
265
|
+
it('can get a key from an object', () => {
|
|
266
|
+
const obj = {a: {b: {c: 'd'}}};
|
|
267
|
+
assert.equal(getValueAtPath(obj, ['a', 'b', 'c']), 'd');
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
it('returns the original object when key array is empty', () => {
|
|
271
|
+
const obj = {a: 1, b: 2};
|
|
272
|
+
assert.deepEqual(getValueAtPath(obj, []), obj);
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
it('can access single-level properties', () => {
|
|
276
|
+
const obj = {name: 'test', age: 25};
|
|
277
|
+
assert.equal(getValueAtPath(obj, ['name']), 'test');
|
|
278
|
+
assert.equal(getValueAtPath(obj, ['age']), 25);
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
it('returns undefined for non-existent keys', () => {
|
|
282
|
+
const obj = {a: {b: 'value'}};
|
|
283
|
+
assert.equal(getValueAtPath(obj, ['nonexistent']), undefined);
|
|
284
|
+
assert.equal(getValueAtPath(obj, ['a', 'nonexistent']), undefined);
|
|
285
|
+
assert.equal(getValueAtPath(obj, ['a', 'b', 'nonexistent']), undefined);
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
it('handles null and undefined values in the path', () => {
|
|
289
|
+
const obj = {a: null, b: {c: undefined}};
|
|
290
|
+
assert.equal(getValueAtPath(obj, ['a']), null);
|
|
291
|
+
assert.equal(getValueAtPath(obj, ['b', 'c']), undefined);
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
it('does not throw when trying to access property of null', () => {
|
|
295
|
+
const obj = {a: null};
|
|
296
|
+
assert.equal(getValueAtPath(obj, ['a', 'b']), undefined);
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
it('does not throw when trying to access property of undefined', () => {
|
|
300
|
+
const obj = {a: undefined};
|
|
301
|
+
assert.equal(getValueAtPath(obj, ['a', 'b']), undefined);
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
it('can access nested arrays and objects', () => {
|
|
305
|
+
const obj = {
|
|
306
|
+
data: [
|
|
307
|
+
{name: 'item1', props: {color: 'red'}},
|
|
308
|
+
{name: 'item2', props: {color: 'blue'}},
|
|
309
|
+
],
|
|
310
|
+
};
|
|
311
|
+
assert.equal(getValueAtPath(obj, ['data', '0', 'name']), 'item1');
|
|
312
|
+
assert.equal(getValueAtPath(obj, ['data', '1', 'props', 'color']), 'blue');
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
it('handles numeric keys as strings', () => {
|
|
316
|
+
const obj = {'0': 'first', '1': {nested: 'value'}};
|
|
317
|
+
assert.equal(getValueAtPath(obj, ['0']), 'first');
|
|
318
|
+
assert.equal(getValueAtPath(obj, ['1', 'nested']), 'value');
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
it('handles keys with special characters', () => {
|
|
322
|
+
const obj = {
|
|
323
|
+
'key-with-dashes': 'value1',
|
|
324
|
+
'key.with.dots': {
|
|
325
|
+
'nested-key': 'value2',
|
|
326
|
+
},
|
|
327
|
+
'key with spaces': 'value3',
|
|
328
|
+
'@special$chars#': 'value4',
|
|
329
|
+
};
|
|
330
|
+
assert.equal(getValueAtPath(obj, ['key-with-dashes']), 'value1');
|
|
331
|
+
assert.equal(
|
|
332
|
+
getValueAtPath(obj, ['key.with.dots', 'nested-key']),
|
|
333
|
+
'value2',
|
|
334
|
+
);
|
|
335
|
+
assert.equal(getValueAtPath(obj, ['key with spaces']), 'value3');
|
|
336
|
+
assert.equal(getValueAtPath(obj, ['@special$chars#']), 'value4');
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
it('handles falsy values correctly', () => {
|
|
340
|
+
const obj = {
|
|
341
|
+
zero: 0,
|
|
342
|
+
false: false,
|
|
343
|
+
emptyString: '',
|
|
344
|
+
nullValue: null,
|
|
345
|
+
undefinedValue: undefined,
|
|
346
|
+
nested: {
|
|
347
|
+
zero: 0,
|
|
348
|
+
false: false,
|
|
349
|
+
},
|
|
350
|
+
};
|
|
351
|
+
assert.equal(getValueAtPath(obj, ['zero']), 0);
|
|
352
|
+
assert.equal(getValueAtPath(obj, ['false']), false);
|
|
353
|
+
assert.equal(getValueAtPath(obj, ['emptyString']), '');
|
|
354
|
+
assert.equal(getValueAtPath(obj, ['nullValue']), null);
|
|
355
|
+
assert.equal(getValueAtPath(obj, ['undefinedValue']), undefined);
|
|
356
|
+
assert.equal(getValueAtPath(obj, ['nested', 'zero']), 0);
|
|
357
|
+
assert.equal(getValueAtPath(obj, ['nested', 'false']), false);
|
|
358
|
+
});
|
|
359
|
+
|
|
360
|
+
it('handles deep nesting', () => {
|
|
361
|
+
const obj = {
|
|
362
|
+
level1: {
|
|
363
|
+
level2: {
|
|
364
|
+
level3: {
|
|
365
|
+
level4: {
|
|
366
|
+
level5: {
|
|
367
|
+
deepValue: 'found',
|
|
368
|
+
},
|
|
369
|
+
},
|
|
370
|
+
},
|
|
371
|
+
},
|
|
372
|
+
},
|
|
373
|
+
};
|
|
374
|
+
assert.equal(
|
|
375
|
+
getValueAtPath(obj, [
|
|
376
|
+
'level1',
|
|
377
|
+
'level2',
|
|
378
|
+
'level3',
|
|
379
|
+
'level4',
|
|
380
|
+
'level5',
|
|
381
|
+
'deepValue',
|
|
382
|
+
]),
|
|
383
|
+
'found',
|
|
384
|
+
);
|
|
385
|
+
});
|
|
386
|
+
|
|
387
|
+
it('handles Date objects', () => {
|
|
388
|
+
const date = new Date('2023-01-01');
|
|
389
|
+
const obj = {
|
|
390
|
+
timestamp: date,
|
|
391
|
+
nested: {
|
|
392
|
+
date: date,
|
|
393
|
+
},
|
|
394
|
+
};
|
|
395
|
+
assert.equal(getValueAtPath(obj, ['timestamp']), date);
|
|
396
|
+
assert.equal(getValueAtPath(obj, ['nested', 'date']), date);
|
|
397
|
+
});
|
|
398
|
+
|
|
399
|
+
it('handles complex nested structures with mixed types', () => {
|
|
400
|
+
const obj = {
|
|
401
|
+
users: [
|
|
402
|
+
{
|
|
403
|
+
id: 1,
|
|
404
|
+
profile: {
|
|
405
|
+
settings: {
|
|
406
|
+
theme: 'dark',
|
|
407
|
+
notifications: true,
|
|
408
|
+
},
|
|
409
|
+
},
|
|
410
|
+
},
|
|
411
|
+
{
|
|
412
|
+
id: 2,
|
|
413
|
+
profile: {
|
|
414
|
+
settings: {
|
|
415
|
+
theme: 'light',
|
|
416
|
+
notifications: false,
|
|
417
|
+
},
|
|
418
|
+
},
|
|
419
|
+
},
|
|
420
|
+
],
|
|
421
|
+
config: {
|
|
422
|
+
version: '1.0.0',
|
|
423
|
+
features: ['feature1', 'feature2'],
|
|
424
|
+
},
|
|
425
|
+
};
|
|
426
|
+
|
|
427
|
+
assert.equal(
|
|
428
|
+
getValueAtPath(obj, ['users', '0', 'profile', 'settings', 'theme']),
|
|
429
|
+
'dark',
|
|
430
|
+
);
|
|
431
|
+
assert.equal(
|
|
432
|
+
getValueAtPath(obj, [
|
|
433
|
+
'users',
|
|
434
|
+
'1',
|
|
435
|
+
'profile',
|
|
436
|
+
'settings',
|
|
437
|
+
'notifications',
|
|
438
|
+
]),
|
|
439
|
+
false,
|
|
440
|
+
);
|
|
441
|
+
assert.equal(getValueAtPath(obj, ['config', 'features', '0']), 'feature1');
|
|
442
|
+
});
|
|
443
|
+
});
|
package/test/test-utils.js
CHANGED
|
@@ -1,19 +1,14 @@
|
|
|
1
1
|
// @flow strict-local
|
|
2
2
|
|
|
3
|
-
import type {
|
|
3
|
+
import type {AtlaspackOptions, Target} from '../src/types';
|
|
4
4
|
|
|
5
5
|
import {DEFAULT_FEATURE_FLAGS} from '@atlaspack/feature-flags';
|
|
6
|
-
import {
|
|
7
|
-
import tempy from 'tempy';
|
|
8
|
-
import {inputFS, outputFS} from '@atlaspack/test-utils';
|
|
6
|
+
import {inputFS, outputFS, cache, cacheDir} from '@atlaspack/test-utils';
|
|
9
7
|
import {relativePath} from '@atlaspack/utils';
|
|
10
8
|
import {NodePackageManager} from '@atlaspack/package-manager';
|
|
11
9
|
import {createEnvironment} from '../src/Environment';
|
|
12
10
|
import {toProjectPath} from '../src/projectPath';
|
|
13
|
-
|
|
14
|
-
let cacheDir = tempy.directory();
|
|
15
|
-
export let cache: FSCache = new FSCache(outputFS, cacheDir);
|
|
16
|
-
cache.ensure();
|
|
11
|
+
import type {EnvironmentRef} from '../src/EnvironmentManager';
|
|
17
12
|
|
|
18
13
|
export const DEFAULT_OPTIONS: AtlaspackOptions = {
|
|
19
14
|
cacheDir,
|
|
@@ -57,7 +52,7 @@ export const DEFAULT_OPTIONS: AtlaspackOptions = {
|
|
|
57
52
|
},
|
|
58
53
|
};
|
|
59
54
|
|
|
60
|
-
export const DEFAULT_ENV:
|
|
55
|
+
export const DEFAULT_ENV: EnvironmentRef = createEnvironment({
|
|
61
56
|
context: 'browser',
|
|
62
57
|
engines: {
|
|
63
58
|
browsers: ['> 1%'],
|