@atlaspack/core 2.12.1-dev.3401 → 2.12.1-dev.3443

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 (70) hide show
  1. package/lib/AssetGraph.js +1 -2
  2. package/lib/Atlaspack.js +25 -3
  3. package/lib/AtlaspackConfig.schema.js +10 -36
  4. package/lib/BundleGraph.js +59 -5
  5. package/lib/Dependency.js +46 -1
  6. package/lib/Environment.js +12 -2
  7. package/lib/PackagerRunner.js +3 -45
  8. package/lib/RequestTracker.js +112 -30
  9. package/lib/SymbolPropagation.js +1 -1
  10. package/lib/Transformation.js +1 -15
  11. package/lib/UncommittedAsset.js +4 -4
  12. package/lib/Validation.js +1 -13
  13. package/lib/applyRuntimes.js +96 -20
  14. package/lib/assetUtils.js +9 -3
  15. package/lib/atlaspack-v3/AtlaspackV3.js +6 -8
  16. package/lib/atlaspack-v3/fs.js +8 -1
  17. package/lib/atlaspack-v3/worker/compat.js +57 -0
  18. package/lib/atlaspack-v3/worker/worker.js +156 -1
  19. package/lib/public/BundleGraph.js +68 -0
  20. package/lib/requests/AssetGraphRequestRust.js +79 -12
  21. package/lib/requests/BundleGraphRequest.js +19 -0
  22. package/lib/requests/WriteBundleRequest.js +15 -15
  23. package/lib/requests/asset-graph-diff.js +128 -0
  24. package/lib/resolveOptions.js +15 -8
  25. package/lib/types.js +2 -1
  26. package/package.json +19 -17
  27. package/src/AssetGraph.js +1 -1
  28. package/src/Atlaspack.js +28 -6
  29. package/src/AtlaspackConfig.schema.js +13 -36
  30. package/src/BundleGraph.js +77 -1
  31. package/src/CommittedAsset.js +1 -1
  32. package/src/Dependency.js +50 -12
  33. package/src/Environment.js +13 -15
  34. package/src/PackagerRunner.js +5 -53
  35. package/src/RequestTracker.js +144 -38
  36. package/src/SymbolPropagation.js +5 -2
  37. package/src/Transformation.js +1 -9
  38. package/src/UncommittedAsset.js +6 -6
  39. package/src/Validation.js +1 -7
  40. package/src/applyRuntimes.js +86 -22
  41. package/src/assetUtils.js +12 -19
  42. package/src/atlaspack-v3/AtlaspackV3.js +8 -11
  43. package/src/atlaspack-v3/fs.js +8 -3
  44. package/src/atlaspack-v3/jsCallable.js +4 -0
  45. package/src/atlaspack-v3/worker/compat.js +82 -0
  46. package/src/atlaspack-v3/worker/worker.js +209 -2
  47. package/src/public/BundleGraph.js +106 -0
  48. package/src/requests/AssetGraphRequestRust.js +105 -17
  49. package/src/requests/BundleGraphRequest.js +18 -0
  50. package/src/requests/WriteBundleRequest.js +17 -23
  51. package/src/requests/asset-graph-diff.js +145 -0
  52. package/src/resolveOptions.js +12 -2
  53. package/src/types.js +10 -0
  54. package/test/AssetGraph.test.js +23 -9
  55. package/test/AtlaspackConfigRequest.test.js +0 -161
  56. package/test/BundleGraph.test.js +8 -3
  57. package/test/Dependency.test.js +21 -0
  58. package/test/Environment.test.js +16 -5
  59. package/test/InternalAsset.test.js +8 -2
  60. package/test/PublicAsset.test.js +6 -2
  61. package/test/PublicBundle.test.js +1 -0
  62. package/test/PublicMutableBundleGraph.test.js +9 -4
  63. package/test/RequestTracker.test.js +139 -2
  64. package/test/SymbolPropagation.test.js +1 -0
  65. package/test/TargetRequest.test.js +25 -25
  66. package/test/requests/WriteBundleRequest.test.js +132 -0
  67. package/lib/atlaspack-v3/plugins/Resolver.js +0 -12
  68. package/lib/atlaspack-v3/plugins/index.js +0 -16
  69. package/src/atlaspack-v3/plugins/Resolver.js +0 -9
  70. package/src/atlaspack-v3/plugins/index.js +0 -3
@@ -32,6 +32,7 @@ import createAssetGraphRequest from './requests/AssetGraphRequest';
32
32
  import {createDevDependency, runDevDepRequest} from './requests/DevDepRequest';
33
33
  import {toProjectPath, fromProjectPathRelative} from './projectPath';
34
34
  import {tracer, PluginTracer} from '@atlaspack/profiler';
35
+ import {DefaultMap} from '@atlaspack/utils';
35
36
 
36
37
  type RuntimeConnection = {|
37
38
  bundle: InternalBundle,
@@ -60,6 +61,14 @@ function nameRuntimeBundle(
60
61
  bundle.displayName = name.replace(hashReference, '[hash]');
61
62
  }
62
63
 
64
+ /**
65
+ * The applyRuntimes function is responsible for generating all the runtimes
66
+ * (assets created during the build that don't actually exist on disk) and then
67
+ * linking them into the bundle graph.
68
+ *
69
+ * Introduction of manifest bundles: https://github.com/parcel-bundler/parcel/pull/8837
70
+ * Introduction of reverse topology: https://github.com/parcel-bundler/parcel/pull/8981
71
+ */
63
72
  export default async function applyRuntimes<TResult: RequestResult>({
64
73
  bundleGraph,
65
74
  config,
@@ -82,11 +91,20 @@ export default async function applyRuntimes<TResult: RequestResult>({
82
91
  configs: Map<string, Config>,
83
92
  |}): Promise<Map<string, Asset>> {
84
93
  let runtimes = await config.getRuntimes();
85
- let connections: Array<RuntimeConnection> = [];
86
94
 
87
- // As manifest bundles may be added during runtimes we process them in reverse topological
88
- // sort order. This allows bundles to be added to their bundle groups before they are referenced
89
- // by other bundle groups by loader runtimes
95
+ /**
96
+ * Usually, the assets returned from a runtime will go in the same bundle. It is
97
+ * possible though, for a runtime to return an asset with a `parallel` priority,
98
+ * which allows it to be moved to a separate bundle. In practice, this is
99
+ * usually used to generate application manifest files.
100
+ *
101
+ * When adding a manifest bundle (a whole new separate bundle) during a runtime,
102
+ * it needs to be added to a bundle group which will be potentially referenced
103
+ * by another bundle group. To avoid trying to reference a manifest entry which
104
+ * hasn't been created yet, we process the bundles from the bottom up (topological
105
+ * order), so that children will always be available when parents try to reference
106
+ * them.
107
+ */
90
108
  let bundles = [];
91
109
  bundleGraph.traverseBundles({
92
110
  exit(bundle) {
@@ -94,6 +112,8 @@ export default async function applyRuntimes<TResult: RequestResult>({
94
112
  },
95
113
  });
96
114
 
115
+ let connectionMap = new DefaultMap(() => []);
116
+
97
117
  for (let bundle of bundles) {
98
118
  for (let runtime of runtimes) {
99
119
  let measurement;
@@ -146,6 +166,11 @@ export default async function applyRuntimes<TResult: RequestResult>({
146
166
 
147
167
  let connectionBundle = bundle;
148
168
 
169
+ /**
170
+ * If a runtime asset is marked with a priority of `parallel` this
171
+ * means we need to create a new bundle for the asset and add it to
172
+ * all the same bundle groups.
173
+ */
149
174
  if (priority === 'parallel' && !bundle.needsStableName) {
150
175
  let bundleGroups =
151
176
  bundleGraph.getBundleGroupsContainingBundle(bundle);
@@ -169,10 +194,12 @@ export default async function applyRuntimes<TResult: RequestResult>({
169
194
  }
170
195
  bundleGraph.createBundleReference(bundle, connectionBundle);
171
196
 
197
+ // Ensure we name the bundle now as all other bundles have already
198
+ // been named as this point.
172
199
  nameRuntimeBundle(connectionBundle, bundle);
173
200
  }
174
201
 
175
- connections.push({
202
+ connectionMap.get(connectionBundle).push({
176
203
  bundle: connectionBundle,
177
204
  assetGroup,
178
205
  dependency,
@@ -192,8 +219,28 @@ export default async function applyRuntimes<TResult: RequestResult>({
192
219
  }
193
220
  }
194
221
 
195
- // Correct connection order after generating runtimes in reverse order
196
- connections.reverse();
222
+ /**
223
+ * When merging the connections in to the bundle graph, the topological
224
+ * order can create module not found errors in some situations, often when HMR
225
+ * is enabled. To fix this, we put the connections into DFS order.
226
+ *
227
+ * Note: While DFS order seems to be the most reliable order to process the
228
+ * connections, this is likely due to it being close to the order that the bundles were
229
+ * inserted into the graph. There is a known issue where runtime assets marked
230
+ * as `isEntry` can create scenarios where there is no correct load order that
231
+ * won't error, as the entry runtime assets are added to many bundles in a
232
+ * single bundle group but their dependencies are not.
233
+ *
234
+ * This issue is almost exclusive to HMR scenarios as the two HMR runtime
235
+ * plugins (@atlaspack/runtime-browser-hmr and @atlaspack/runtime-react-refresh)
236
+ * are the only known cases where a runtime asset is marked as `isEntry`.
237
+ */
238
+ let connections: Array<RuntimeConnection> = [];
239
+ bundleGraph.traverseBundles({
240
+ enter(bundle) {
241
+ connections.push(...connectionMap.get(bundle));
242
+ },
243
+ });
197
244
 
198
245
  // Add dev deps for runtime plugins AFTER running them, to account for lazy require().
199
246
  for (let runtime of runtimes) {
@@ -214,23 +261,31 @@ export default async function applyRuntimes<TResult: RequestResult>({
214
261
  await runDevDepRequest(api, devDepRequest);
215
262
  }
216
263
 
264
+ // Create a new AssetGraph from the generated runtime assets which also runs
265
+ // transforms and resolves all dependencies.
217
266
  let {assetGraph: runtimesAssetGraph, changedAssets} =
218
267
  await reconcileNewRuntimes(api, connections, optionsRef);
219
268
 
220
- let runtimesGraph = InternalBundleGraph.fromAssetGraph(
269
+ // Convert the runtime AssetGraph into a BundleGraph, this includes assigning
270
+ // the assets their public ids
271
+ let runtimesBundleGraph = InternalBundleGraph.fromAssetGraph(
221
272
  runtimesAssetGraph,
222
273
  options.mode === 'production',
223
274
  bundleGraph._publicIdByAssetId,
224
275
  bundleGraph._assetPublicIds,
225
276
  );
226
277
 
227
- // Merge the runtimes graph into the main bundle graph.
228
- bundleGraph.merge(runtimesGraph);
229
- for (let [assetId, publicId] of runtimesGraph._publicIdByAssetId) {
278
+ // Merge the runtimes bundle graph into the main bundle graph.
279
+ bundleGraph.merge(runtimesBundleGraph);
280
+
281
+ // Add the public id mappings from the runtumes bundlegraph to the main bundle graph
282
+ for (let [assetId, publicId] of runtimesBundleGraph._publicIdByAssetId) {
230
283
  bundleGraph._publicIdByAssetId.set(assetId, publicId);
231
284
  bundleGraph._assetPublicIds.add(publicId);
232
285
  }
233
286
 
287
+ // Connect each of the generated runtime assets to bundles in the main bundle
288
+ // graph. This is like a mini-bundling algorithm for runtime assets.
234
289
  for (let {bundle, assetGroup, dependency, isEntry} of connections) {
235
290
  let assetGroupNode = nodeFromAssetGroup(assetGroup);
236
291
  let assetGroupAssetNodeIds = runtimesAssetGraph.getNodeIdsConnectedFrom(
@@ -241,6 +296,8 @@ export default async function applyRuntimes<TResult: RequestResult>({
241
296
  let runtimeNode = nullthrows(runtimesAssetGraph.getNode(runtimeNodeId));
242
297
  invariant(runtimeNode.type === 'asset');
243
298
 
299
+ // Find the asset that the runtime asset should be connected from by resolving
300
+ // it's dependency.
244
301
  let resolution =
245
302
  dependency &&
246
303
  bundleGraph.getResolvedAsset(
@@ -248,20 +305,25 @@ export default async function applyRuntimes<TResult: RequestResult>({
248
305
  bundle,
249
306
  );
250
307
 
251
- let runtimesGraphRuntimeNodeId = runtimesGraph._graph.getNodeIdByContentKey(
252
- runtimeNode.id,
253
- );
308
+ // Walk all the dependencies of the runtime assets and check if they are
309
+ // already reachable from the bundle that the runtime asset is assigned to.
310
+ // If so, we add them to `duplicatedContentKeys` to be skipped when assigning
311
+ // assets to bundles.
312
+ let runtimesBundleGraphRuntimeNodeId =
313
+ runtimesBundleGraph._graph.getNodeIdByContentKey(runtimeNode.id);
254
314
  let duplicatedContentKeys: Set<ContentKey> = new Set();
255
- runtimesGraph._graph.traverse((nodeId, _, actions) => {
256
- let node = nullthrows(runtimesGraph._graph.getNode(nodeId));
315
+ runtimesBundleGraph._graph.traverse((nodeId, _, actions) => {
316
+ let node = nullthrows(runtimesBundleGraph._graph.getNode(nodeId));
257
317
  if (node.type !== 'dependency') {
258
318
  return;
259
319
  }
260
320
 
261
- let assets = runtimesGraph._graph
321
+ let assets = runtimesBundleGraph._graph
262
322
  .getNodeIdsConnectedFrom(nodeId)
263
323
  .map(assetNodeId => {
264
- let assetNode = nullthrows(runtimesGraph._graph.getNode(assetNodeId));
324
+ let assetNode = nullthrows(
325
+ runtimesBundleGraph._graph.getNode(assetNodeId),
326
+ );
265
327
  invariant(assetNode.type === 'asset');
266
328
  return assetNode.value;
267
329
  });
@@ -275,15 +337,17 @@ export default async function applyRuntimes<TResult: RequestResult>({
275
337
  actions.skipChildren();
276
338
  }
277
339
  }
278
- }, runtimesGraphRuntimeNodeId);
340
+ }, runtimesBundleGraphRuntimeNodeId);
279
341
 
280
342
  let bundleNodeId = bundleGraph._graph.getNodeIdByContentKey(bundle.id);
281
343
  let bundleGraphRuntimeNodeId = bundleGraph._graph.getNodeIdByContentKey(
282
344
  runtimeNode.id,
283
345
  ); // the node id is not constant between graphs
284
346
 
285
- runtimesGraph._graph.traverse((nodeId, _, actions) => {
286
- let node = nullthrows(runtimesGraph._graph.getNode(nodeId));
347
+ // Assign the runtime assets and all of it's depepdencies to the bundle unless
348
+ // we have detected it as already being reachable from this bundle via `duplicatedContentKeys`.
349
+ runtimesBundleGraph._graph.traverse((nodeId, _, actions) => {
350
+ let node = nullthrows(runtimesBundleGraph._graph.getNode(nodeId));
287
351
  if (node.type === 'asset' || node.type === 'dependency') {
288
352
  if (duplicatedContentKeys.has(node.id)) {
289
353
  actions.skipChildren();
@@ -299,7 +363,7 @@ export default async function applyRuntimes<TResult: RequestResult>({
299
363
  bundleGraphEdgeTypes.contains,
300
364
  );
301
365
  }
302
- }, runtimesGraphRuntimeNodeId);
366
+ }, runtimesBundleGraphRuntimeNodeId);
303
367
 
304
368
  if (isEntry) {
305
369
  bundleGraph._graph.addEdge(bundleNodeId, bundleGraphRuntimeNodeId);
package/src/assetUtils.js CHANGED
@@ -36,14 +36,14 @@ import {
36
36
  fromProjectPath,
37
37
  fromProjectPathRelative,
38
38
  } from './projectPath';
39
- import {hashString} from '@atlaspack/rust';
39
+ import {hashString, createAssetId as createAssetIdRust} from '@atlaspack/rust';
40
40
  import {BundleBehavior as BundleBehaviorMap} from './types';
41
41
  import {PluginTracer} from '@atlaspack/profiler';
42
42
 
43
- type AssetOptions = {|
43
+ export type AssetOptions = {|
44
44
  id?: string,
45
45
  committed?: boolean,
46
- idBase?: ?string,
46
+ code: string | void | null,
47
47
  filePath: ProjectPath,
48
48
  query?: ?string,
49
49
  type: string,
@@ -69,22 +69,15 @@ type AssetOptions = {|
69
69
  |};
70
70
 
71
71
  export function createAssetIdFromOptions(options: AssetOptions): string {
72
- let uniqueKey = options.uniqueKey ?? '';
73
- let idBase =
74
- options.idBase != null
75
- ? options.idBase
76
- : fromProjectPathRelative(options.filePath);
77
-
78
- return hashString(
79
- idBase +
80
- options.type +
81
- options.env.id +
82
- uniqueKey +
83
- ':' +
84
- (options.pipeline ?? '') +
85
- ':' +
86
- (options.query ?? ''),
87
- );
72
+ return createAssetIdRust({
73
+ env: options.env,
74
+ filePath: options.filePath,
75
+ code: options.code,
76
+ pipeline: options.pipeline,
77
+ query: options.query,
78
+ uniqueKey: options.uniqueKey,
79
+ fileType: options.type,
80
+ });
88
81
  }
89
82
 
90
83
  export function createAsset(
@@ -24,6 +24,14 @@ export class AtlaspackV3 {
24
24
  threads,
25
25
  ...options
26
26
  }: AtlaspackV3Options) {
27
+ options.logLevel = options.logLevel || 'error';
28
+ options.defaultTargetOptions = options.defaultTargetOptions || {};
29
+ // $FlowFixMe "engines" are readonly
30
+ options.defaultTargetOptions.engines = options.defaultTargetOptions
31
+ .engines || {
32
+ browsers: [],
33
+ };
34
+
27
35
  this._internal = new AtlaspackNapi({
28
36
  fs,
29
37
  nodeWorkers,
@@ -33,17 +41,6 @@ export class AtlaspackV3 {
33
41
  });
34
42
  }
35
43
 
36
- async build(): Promise<any> {
37
- const [workers, registerWorker] = this.#createWorkers();
38
-
39
- let result = await this._internal.build({
40
- registerWorker,
41
- });
42
-
43
- for (const worker of workers) worker.terminate();
44
- return result;
45
- }
46
-
47
44
  async buildAssetGraph(): Promise<any> {
48
45
  const [workers, registerWorker] = this.#createWorkers();
49
46
 
@@ -15,9 +15,14 @@ export function toFileSystemV3(fs: ClassicFileSystem): FileSystem {
15
15
  canonicalize: jsCallable((path: FilePath) => fs.realpathSync(path)),
16
16
  createDirectory: jsCallable((path: FilePath) => fs.mkdirp(path)),
17
17
  cwd: jsCallable(() => fs.cwd()),
18
- readFile: jsCallable((path: string, encoding?: Encoding) =>
19
- fs.readFileSync(path, encoding ?? 'utf8'),
20
- ),
18
+ readFile: jsCallable((path: string, encoding?: Encoding) => {
19
+ if (!encoding) {
20
+ // $FlowFixMe
21
+ return [...fs.readFileSync(path)];
22
+ } else {
23
+ return fs.readFileSync(path, encoding);
24
+ }
25
+ }),
21
26
  isFile: (path: string) => {
22
27
  try {
23
28
  return fs.statSync(path).isFile();
@@ -1,5 +1,9 @@
1
1
  // @flow strict-local
2
2
 
3
+ export type JsCallable<Args: $ReadOnlyArray<mixed>, Return> = (
4
+ ...Args
5
+ ) => Return;
6
+
3
7
  export function jsCallable<Args: $ReadOnlyArray<mixed>, Return>(
4
8
  fn: (...Args) => Return,
5
9
  ): (...Args) => Return {
@@ -0,0 +1,82 @@
1
+ // @flow
2
+ import type {PluginOptions, BundleBehavior, AST} from '@atlaspack/types';
3
+
4
+ import Environment from '../../public/Environment';
5
+ import {
6
+ BundleBehaviorNames,
7
+ BundleBehavior as BundleBehaviorMap,
8
+ } from '../../types';
9
+
10
+ export type InnerAsset = {|
11
+ id: string,
12
+ filePath: string,
13
+ code: Array<number>,
14
+ type: string,
15
+ bundleBehavior: number | null,
16
+ env: any,
17
+ |};
18
+
19
+ export class AssetCompat {
20
+ _inner: InnerAsset;
21
+ _ast: ?AST;
22
+ // TODO: Type properly
23
+ _dependencies: Array<any>;
24
+
25
+ constructor(_inner: InnerAsset, options: PluginOptions) {
26
+ this._inner = _inner;
27
+ // $FlowFixMe This isn't correct to flow but is enough to satisfy the runtime checks
28
+ this.env = new Environment(_inner.env, options);
29
+ this._dependencies = [];
30
+ }
31
+
32
+ get id(): string {
33
+ return this._inner.id;
34
+ }
35
+
36
+ get filePath(): string {
37
+ return this._inner.filePath;
38
+ }
39
+
40
+ get type(): string {
41
+ return this._inner.type;
42
+ }
43
+ set type(value: string) {
44
+ this._inner.type = value;
45
+ }
46
+
47
+ get bundleBehavior(): ?BundleBehavior {
48
+ let bundleBehavior = this._inner.bundleBehavior;
49
+ return bundleBehavior == null ? null : BundleBehaviorNames[bundleBehavior];
50
+ }
51
+ set bundleBehavior(bundleBehavior: ?BundleBehavior): void {
52
+ this._inner.bundleBehavior = bundleBehavior
53
+ ? BundleBehaviorMap[bundleBehavior]
54
+ : null;
55
+ }
56
+
57
+ getCode(): string {
58
+ return Buffer.from(this._inner.code).toString();
59
+ }
60
+ setCode(code: string) {
61
+ this._inner.code = Array.from(new TextEncoder().encode(code));
62
+ }
63
+
64
+ getAST(): ?AST {
65
+ return this._ast;
66
+ }
67
+ setAST(ast: AST) {
68
+ this._ast = ast;
69
+ }
70
+
71
+ addDependency(): string {
72
+ throw new Error(
73
+ '[V3] Unimplemented: Asset.addDependency not yet implemented',
74
+ );
75
+ }
76
+
77
+ addURLDependency(): string {
78
+ throw new Error(
79
+ '[V3] Unimplemented: Asset.addURLDependency not yet implemented',
80
+ );
81
+ }
82
+ }
@@ -1,14 +1,221 @@
1
1
  // @flow
2
+ import assert from 'assert';
2
3
  import * as napi from '@atlaspack/rust';
4
+ import type {
5
+ Resolver,
6
+ Transformer,
7
+ PluginOptions,
8
+ Dependency,
9
+ FilePath,
10
+ } from '@atlaspack/types';
3
11
  import {workerData} from 'worker_threads';
4
- import type {ResolverNapi} from '../plugins/Resolver';
12
+ import * as module from 'module';
13
+
14
+ import {AssetCompat} from './compat';
15
+ import type {InnerAsset} from './compat';
16
+ import {jsCallable} from '../jsCallable';
17
+ import type {JsCallable} from '../jsCallable';
18
+
19
+ const CONFIG = Symbol.for('parcel-plugin-config');
5
20
 
6
21
  export class AtlaspackWorker {
7
- #resolvers: Map<string, ResolverNapi>;
22
+ #resolvers: Map<string, Resolver<*>>;
23
+
24
+ constructor() {
25
+ this.#resolvers = new Map();
26
+ }
27
+
28
+ loadPlugin: JsCallable<[LoadPluginOptions], Promise<void>> = jsCallable(
29
+ async ({kind, specifier, resolveFrom}) => {
30
+ let customRequire = module.createRequire(resolveFrom);
31
+ let resolvedPath = customRequire.resolve(specifier);
32
+ // $FlowFixMe
33
+ let resolvedModule = await import(resolvedPath);
34
+
35
+ let instance = undefined;
36
+ if (resolvedModule.default && resolvedModule.default[CONFIG]) {
37
+ instance = resolvedModule.default[CONFIG];
38
+ } else if (
39
+ resolvedModule.default &&
40
+ resolvedModule.default.default[CONFIG]
41
+ ) {
42
+ instance = resolvedModule.default.default[CONFIG];
43
+ } else {
44
+ throw new Error(
45
+ `Plugin could not be resolved\n\t${kind}\n\t${resolveFrom}\n\t${specifier}`,
46
+ );
47
+ }
48
+
49
+ switch (kind) {
50
+ case 'resolver':
51
+ this.#resolvers.set(specifier, instance);
52
+ break;
53
+ }
54
+ },
55
+ );
56
+
57
+ runResolverResolve: JsCallable<
58
+ [RunResolverResolveOptions],
59
+ Promise<RunResolverResolveResult>,
60
+ > = jsCallable(async ({key, dependency, specifier}) => {
61
+ const resolver = this.#resolvers.get(key);
62
+ if (!resolver) {
63
+ throw new Error(`Resolver not found: ${key}`);
64
+ }
65
+
66
+ const result = await resolver.resolve({
67
+ specifier,
68
+ dependency,
69
+ get options() {
70
+ throw new Error('TODO: Resolver.resolve.options');
71
+ },
72
+ get logger() {
73
+ throw new Error('TODO: Resolver.resolve.logger');
74
+ },
75
+ get tracer() {
76
+ throw new Error('TODO: Resolver.resolve.tracer');
77
+ },
78
+ get pipeline() {
79
+ throw new Error('TODO: Resolver.resolve.pipeline');
80
+ },
81
+ get config() {
82
+ throw new Error('TODO: Resolver.resolve.config');
83
+ },
84
+ });
85
+
86
+ if (!result) {
87
+ return {
88
+ invalidations: [],
89
+ resolution: {type: 'unresolved'},
90
+ };
91
+ }
92
+
93
+ return {
94
+ invalidations: [],
95
+ resolution: {
96
+ type: 'resolved',
97
+ filePath: result.filePath || '',
98
+ canDefer: result.canDefer || false,
99
+ sideEffects: result.sideEffects || false,
100
+ code: result.code || undefined,
101
+ meta: result.meta || undefined,
102
+ pipeline: result.pipeline || undefined,
103
+ priority: result.priority && PriorityMap[result.priority],
104
+ query: result.query && result.query.toString(),
105
+ },
106
+ };
107
+ });
8
108
 
9
109
  ping() {
10
110
  // console.log('Hi');
11
111
  }
112
+
113
+ async runTransformer({
114
+ resolveFrom,
115
+ specifier,
116
+ options,
117
+ asset,
118
+ }: {|
119
+ resolveFrom: string,
120
+ specifier: string,
121
+ options: PluginOptions,
122
+ asset: InnerAsset,
123
+ |}): any {
124
+ const customRequire = module.createRequire(resolveFrom);
125
+ const resolvedPath = customRequire.resolve(specifier);
126
+ // $FlowFixMe
127
+ const transformerModule = await import(resolvedPath);
128
+ const transformer: Transformer<*> =
129
+ transformerModule.default.default[CONFIG];
130
+
131
+ let assetCompat = new AssetCompat(asset, options);
132
+
133
+ try {
134
+ if (transformer.parse) {
135
+ // $FlowFixMe
136
+ const ast = await transformer.parse({asset: assetCompat}); // missing "config"
137
+ // $FlowFixMe
138
+ assetCompat.setAST(ast);
139
+ }
140
+
141
+ // $FlowFixMe
142
+ const result = await transformer.transform({
143
+ // $FlowFixMe
144
+ asset: assetCompat,
145
+ options,
146
+ config: null,
147
+ });
148
+
149
+ if (transformer.generate) {
150
+ // $FlowFixMe
151
+ let output = await transformer.generate({
152
+ // $FlowFixMe
153
+ asset: assetCompat,
154
+ // $FlowFixMe
155
+ ast: assetCompat.getAST(),
156
+ });
157
+ // $FlowFixMe
158
+ assetCompat.setCode(output.content);
159
+ }
160
+
161
+ assert(
162
+ result.length === 1,
163
+ '[V3] Unimplemented: Multiple asset return from Node transformer',
164
+ );
165
+ assert(
166
+ result[0] === assetCompat,
167
+ '[V3] Unimplemented: New asset returned from Node transformer',
168
+ );
169
+
170
+ return {
171
+ asset,
172
+ dependencies: assetCompat._dependencies,
173
+ };
174
+ } catch (e) {
175
+ // TODO: Improve error logging from JS plugins. Without this you currently
176
+ // only see the error message, no stack trace.
177
+ // eslint-disable-next-line no-console
178
+ console.error(e);
179
+ throw e;
180
+ }
181
+ }
12
182
  }
13
183
 
14
184
  napi.registerWorker(workerData.tx_worker, new AtlaspackWorker());
185
+
186
+ type LoadPluginOptions = {|
187
+ kind: 'resolver',
188
+ specifier: string,
189
+ resolveFrom: string,
190
+ |};
191
+
192
+ type RunResolverResolveOptions = {|
193
+ key: string,
194
+ dependency: Dependency,
195
+ specifier: FilePath,
196
+ |};
197
+
198
+ type RunResolverResolveResult = {|
199
+ invalidations: Array<*>,
200
+ resolution:
201
+ | {|type: 'unresolved'|}
202
+ | {|type: 'excluded'|}
203
+ | {|
204
+ type: 'resolved',
205
+ canDefer: boolean,
206
+ filePath: string,
207
+ sideEffects: boolean,
208
+ code?: string,
209
+ meta?: mixed,
210
+ pipeline?: string,
211
+ priority?: number,
212
+ query?: string,
213
+ |},
214
+ |};
215
+
216
+ const PriorityMap = {
217
+ sync: 0,
218
+ parallel: 1,
219
+ lazy: 2,
220
+ conditional: 3,
221
+ };