@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.
Files changed (95) hide show
  1. package/CHANGELOG.md +284 -0
  2. package/index.d.ts +4 -0
  3. package/lib/AssetGraph.js +27 -7
  4. package/lib/Atlaspack.js +35 -27
  5. package/lib/AtlaspackConfig.schema.js +7 -1
  6. package/lib/BundleGraph.js +8 -5
  7. package/lib/Dependency.js +6 -2
  8. package/lib/Environment.js +5 -3
  9. package/lib/EnvironmentManager.js +137 -0
  10. package/lib/InternalConfig.js +3 -2
  11. package/lib/PackagerRunner.js +54 -16
  12. package/lib/RequestTracker.js +345 -132
  13. package/lib/SymbolPropagation.js +14 -0
  14. package/lib/Transformation.js +2 -2
  15. package/lib/UncommittedAsset.js +20 -2
  16. package/lib/applyRuntimes.js +2 -1
  17. package/lib/assetUtils.js +2 -1
  18. package/lib/atlaspack-v3/AtlaspackV3.js +16 -3
  19. package/lib/atlaspack-v3/worker/compat/environment.js +2 -2
  20. package/lib/atlaspack-v3/worker/compat/mutable-asset.js +6 -6
  21. package/lib/atlaspack-v3/worker/compat/plugin-config.js +5 -5
  22. package/lib/atlaspack-v3/worker/index.js +3 -0
  23. package/lib/atlaspack-v3/worker/worker.js +8 -0
  24. package/lib/dumpGraphToGraphViz.js +1 -1
  25. package/lib/index.js +29 -1
  26. package/lib/public/Asset.js +7 -9
  27. package/lib/public/Bundle.js +12 -13
  28. package/lib/public/BundleGraph.js +3 -2
  29. package/lib/public/BundleGroup.js +2 -3
  30. package/lib/public/Config.js +95 -8
  31. package/lib/public/Dependency.js +4 -4
  32. package/lib/public/Environment.js +2 -3
  33. package/lib/public/MutableBundleGraph.js +5 -4
  34. package/lib/public/PluginOptions.js +1 -2
  35. package/lib/public/Target.js +4 -4
  36. package/lib/requests/AssetGraphRequest.js +13 -1
  37. package/lib/requests/AssetGraphRequestRust.js +17 -2
  38. package/lib/requests/AssetRequest.js +2 -1
  39. package/lib/requests/BundleGraphRequest.js +13 -1
  40. package/lib/requests/ConfigRequest.js +27 -4
  41. package/lib/requests/DevDepRequest.js +11 -1
  42. package/lib/requests/PathRequest.js +10 -0
  43. package/lib/requests/TargetRequest.js +18 -16
  44. package/lib/requests/WriteBundleRequest.js +15 -3
  45. package/lib/requests/WriteBundlesRequest.js +22 -1
  46. package/lib/resolveOptions.js +7 -4
  47. package/lib/worker.js +18 -1
  48. package/package.json +18 -25
  49. package/src/AssetGraph.js +30 -7
  50. package/src/Atlaspack.js +40 -23
  51. package/src/BundleGraph.js +13 -8
  52. package/src/Dependency.js +13 -5
  53. package/src/Environment.js +9 -6
  54. package/src/EnvironmentManager.js +145 -0
  55. package/src/InternalConfig.js +6 -5
  56. package/src/PackagerRunner.js +72 -20
  57. package/src/RequestTracker.js +526 -157
  58. package/src/SymbolPropagation.js +13 -1
  59. package/src/UncommittedAsset.js +23 -3
  60. package/src/applyRuntimes.js +6 -1
  61. package/src/assetUtils.js +4 -3
  62. package/src/atlaspack-v3/AtlaspackV3.js +24 -3
  63. package/src/atlaspack-v3/worker/compat/plugin-config.js +9 -5
  64. package/src/atlaspack-v3/worker/index.js +2 -1
  65. package/src/atlaspack-v3/worker/worker.js +7 -0
  66. package/src/index.js +5 -1
  67. package/src/public/Asset.js +13 -6
  68. package/src/public/Bundle.js +12 -11
  69. package/src/public/BundleGraph.js +10 -2
  70. package/src/public/BundleGroup.js +2 -2
  71. package/src/public/Config.js +132 -18
  72. package/src/public/Dependency.js +4 -3
  73. package/src/public/Environment.js +2 -2
  74. package/src/public/MutableBundleGraph.js +8 -5
  75. package/src/public/PluginOptions.js +1 -1
  76. package/src/public/Target.js +4 -3
  77. package/src/requests/AssetGraphRequest.js +13 -3
  78. package/src/requests/AssetGraphRequestRust.js +14 -2
  79. package/src/requests/AssetRequest.js +2 -1
  80. package/src/requests/BundleGraphRequest.js +13 -3
  81. package/src/requests/ConfigRequest.js +33 -9
  82. package/src/requests/DevDepRequest.js +22 -9
  83. package/src/requests/PathRequest.js +4 -0
  84. package/src/requests/TargetRequest.js +19 -25
  85. package/src/requests/WriteBundleRequest.js +14 -8
  86. package/src/requests/WriteBundlesRequest.js +31 -3
  87. package/src/resolveOptions.js +4 -2
  88. package/src/types.js +10 -7
  89. package/test/Environment.test.js +43 -34
  90. package/test/EnvironmentManager.test.js +192 -0
  91. package/test/PublicEnvironment.test.js +10 -7
  92. package/test/RequestTracker.test.js +124 -29
  93. package/test/public/Config.test.js +108 -0
  94. package/test/requests/ConfigRequest.test.js +199 -7
  95. 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 {runConfigRequest} from '../../src/requests/ConfigRequest';
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
- const farm = new WorkerFarm({
24
- workerPath: require.resolve('../../src/worker'),
25
- maxConcurrentWorkers: 1,
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
- let fs = new MemoryFS(farm);
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
+ });
@@ -1,19 +1,14 @@
1
1
  // @flow strict-local
2
2
 
3
- import type {Environment, AtlaspackOptions, Target} from '../src/types';
3
+ import type {AtlaspackOptions, Target} from '../src/types';
4
4
 
5
5
  import {DEFAULT_FEATURE_FLAGS} from '@atlaspack/feature-flags';
6
- import {FSCache} from '@atlaspack/cache';
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: Environment = createEnvironment({
55
+ export const DEFAULT_ENV: EnvironmentRef = createEnvironment({
61
56
  context: 'browser',
62
57
  engines: {
63
58
  browsers: ['> 1%'],