rollup-plugin-concurrent-top-level-await 0.0.5 → 0.0.6

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/dist/index.d.mts CHANGED
@@ -1,24 +1,23 @@
1
1
  import { FilterPattern } from "@rollup/pluginutils";
2
+ import * as magic_string0 from "magic-string";
2
3
  import * as rollup0 from "rollup";
3
4
 
4
5
  //#region src/index.d.ts
5
6
  declare function concurrentTopLevelAwait(options?: {
6
7
  include?: FilterPattern;
7
8
  exclude?: FilterPattern;
9
+ sourceMap?: boolean;
8
10
  }): {
9
11
  name: string;
10
12
  apply: "build";
11
13
  transform: {
12
14
  handler(this: rollup0.TransformPluginContext, code: string, id: string): Promise<{
13
15
  code: string;
14
- meta: {
15
- async: true;
16
- };
16
+ map: magic_string0.SourceMap | null;
17
17
  } | undefined>;
18
18
  };
19
19
  resolveImportMeta(this: rollup0.PluginContext, property: string | null, {
20
- moduleId,
21
- chunkId
20
+ moduleId
22
21
  }: {
23
22
  chunkId: string;
24
23
  format: rollup0.InternalModuleFormat;
package/dist/index.mjs CHANGED
@@ -31,69 +31,92 @@ function withResolvers() {
31
31
  }
32
32
 
33
33
  //#endregion
34
- //#region src/AsyncTlaTracker.ts
34
+ //#region src/AsyncModuleTracker.ts
35
35
  var AwaitableCache = class {
36
36
  #store = /* @__PURE__ */ new Map();
37
37
  #getPromise(key) {
38
38
  const entry = this.#store.get(key);
39
39
  if (entry) return entry;
40
- const { promise, resolve } = withResolvers();
41
- this.#store.set(key, [promise, resolve]);
42
- return [promise, resolve];
40
+ const { promise, resolve, reject } = withResolvers();
41
+ this.#store.set(key, [
42
+ promise,
43
+ resolve,
44
+ reject
45
+ ]);
46
+ return [
47
+ promise,
48
+ resolve,
49
+ reject
50
+ ];
43
51
  }
44
- set(key, value) {
52
+ resolve(key, value) {
45
53
  const [_, resolve] = this.#getPromise(key);
46
54
  resolve(value);
47
55
  }
56
+ reject(key) {
57
+ const [_, __, reject] = this.#getPromise(key);
58
+ reject();
59
+ }
48
60
  get(key) {
49
61
  const [promise] = this.#getPromise(key);
50
62
  return promise;
51
63
  }
52
64
  };
53
- var AsyncTlaTracker = class {
54
- #all = /* @__PURE__ */ new Set();
55
- #unseen = /* @__PURE__ */ new Set();
56
- #unresolved = /* @__PURE__ */ new Set();
57
- #resultCache = new AwaitableCache();
58
- get(key) {
59
- return this.#resultCache.get(key);
65
+ /**
66
+ * AsyncModuleTracker tracks whether modules must be treated as async due to
67
+ * containing top-level await or being an ancestor of an async module.
68
+ */
69
+ var AsyncModuleTracker = class {
70
+ #entryCache = new AwaitableCache();
71
+ #subtreeCache = new AwaitableCache();
72
+ #resultCache = /* @__PURE__ */ new Map();
73
+ #seen = /* @__PURE__ */ new Set();
74
+ #resolved = /* @__PURE__ */ new Set();
75
+ #childrenSeen = /* @__PURE__ */ new Set();
76
+ #cycleResolver;
77
+ #resolveCycles;
78
+ constructor() {
79
+ this.#createCycleResolver();
60
80
  }
61
- setMarked(key, value) {
62
- this.#all.add(key);
63
- this.#unseen.delete(key);
64
- this.#unresolved.delete(key);
65
- this.#resultCache.set(key, true);
66
- setTimeout(() => {
67
- if (this.#unseen.size == 0) {
68
- this.#unresolved.forEach((e) => this.#resultCache.set(e, false));
69
- this.#all.forEach((e) => this.#resultCache.set(e, false));
70
- this.#unresolved.clear();
71
- }
72
- }, 0);
81
+ #createCycleResolver() {
82
+ const { promise, resolve } = withResolvers();
83
+ this.#cycleResolver = promise;
84
+ this.#resolveCycles = () => resolve(false);
73
85
  }
74
- setChildren(key, children) {
75
- if (!this.#all.has(key)) {
76
- this.#all.add(key);
77
- this.#unresolved.add(key);
78
- }
79
- this.#unseen.delete(key);
80
- children.forEach((children$1) => {
81
- if (!this.#all.has(children$1)) {
82
- this.#all.add(children$1);
83
- this.#unresolved.add(key);
84
- this.#unseen.add(children$1);
85
- }
86
- this.#resultCache.get(children$1).then((value) => {
87
- if (value) this.setMarked(key, true);
86
+ #checkForCycles() {
87
+ if (this.#childrenSeen.size === this.#seen.size && this.#resolved.size === this.#seen.size) {
88
+ const resolveCycles = this.#resolveCycles;
89
+ this.#createCycleResolver();
90
+ setTimeout(() => {
91
+ resolveCycles();
88
92
  });
93
+ }
94
+ }
95
+ #bindResultCache(key) {
96
+ if (!this.#resultCache.has(key)) this.#resultCache.set(key, this.#subtreeCache.get(key).then(() => false).catch(() => true));
97
+ }
98
+ isAsync(key) {
99
+ this.#bindResultCache(key);
100
+ return this.#resultCache.get(key);
101
+ }
102
+ setEntryAsync(key, value) {
103
+ this.#seen.add(key);
104
+ this.#resolved.add(key);
105
+ if (value) {
106
+ this.#entryCache.reject(key);
107
+ this.#entryCache.get(key).catch(() => {});
108
+ } else this.#entryCache.resolve(key, void 0);
109
+ this.#checkForCycles();
110
+ }
111
+ setDependencies(key, children) {
112
+ this.#seen.add(key);
113
+ this.#childrenSeen.add(key);
114
+ children.forEach((child) => {
115
+ this.#seen.add(child);
89
116
  });
90
- setTimeout(() => {
91
- if (this.#unseen.size == 0) {
92
- this.#unresolved.forEach((e) => this.#resultCache.set(e, false));
93
- this.#all.forEach((e) => this.#resultCache.set(e, false));
94
- this.#unresolved.clear();
95
- }
96
- }, 0);
117
+ Promise.race([this.#cycleResolver, Promise.all([this.#entryCache.get(key), ...children.map((child) => this.#subtreeCache.get(child))])]).then(() => this.#subtreeCache.resolve(key, void 0)).catch(() => this.#subtreeCache.reject(key));
118
+ this.#bindResultCache(key);
119
+ this.#checkForCycles();
97
120
  }
98
121
  };
99
122
 
@@ -153,7 +176,7 @@ function isDeclaration(type) {
153
176
  function moveVarDeclarationToModuleScope(s, node, declarationsEnd) {
154
177
  const kind = replaceConstWithLet(node.kind);
155
178
  const names = node.declarations.flatMap((decl) => getNames(decl.id)).join(", ");
156
- s = s.appendRight(node.declarations[0].start, "(");
179
+ s = s.appendRight(node.declarations[0].start, ";(");
157
180
  s = s.appendLeft(node.declarations[node.declarations.length - 1].end, ")");
158
181
  s = s.appendLeft(declarationsEnd, `\n${kind} ${names};\n`);
159
182
  s = s.remove(node.start, node.declarations[0].start);
@@ -183,41 +206,41 @@ function getNames(pattern) {
183
206
  //#region src/index.ts
184
207
  function concurrentTopLevelAwait(options = {}) {
185
208
  const filter = createFilter(options.include, options.exclude);
186
- const asyncTree = new AsyncTlaTracker();
209
+ const asyncTracker = new AsyncModuleTracker();
187
210
  return {
188
211
  name: "rollup-plugin-concurrent-tla-plugin",
189
212
  apply: "build",
190
213
  transform: { async handler(code, id) {
191
214
  if (!filter(id)) return;
192
- const ast = this.parse(code, { jsx: false });
215
+ const ast = this.parse(code);
193
216
  const importDeclarations = ast.body.filter((a) => a.type === "ImportDeclaration");
194
217
  const hasAwait = hasTopLevelAwait(ast);
195
- if (hasAwait) asyncTree.setMarked(id, true);
218
+ asyncTracker.setEntryAsync(id, hasAwait);
219
+ if (hasAwait) asyncTracker.setDependencies(id, []);
196
220
  else {
197
221
  const childrenIds = (await Promise.all(importDeclarations.map(async (declaration) => {
198
222
  const importId = await this.resolve(declaration.source.value, id);
199
223
  if (!importId || !filter(importId.id)) return null;
200
224
  return importId.id;
201
225
  }))).filter((a) => a != null);
202
- asyncTree.setChildren(id, childrenIds);
226
+ asyncTracker.setDependencies(id, childrenIds);
203
227
  }
204
228
  const asyncImports = (await Promise.all(importDeclarations.map(async (declaration) => {
205
229
  const importId = await this.resolve(declaration.source.value, id);
206
230
  if (!importId || !filter(importId.id)) return null;
207
231
  this.load(importId);
208
- if (!await asyncTree.get(importId.id)) return null;
232
+ if (!await asyncTracker.isAsync(importId.id)) return null;
209
233
  return declaration;
210
234
  }))).filter(Boolean);
211
- const isAsyncModule = asyncImports.length > 0 || hasAwait;
212
- if (!isAsyncModule) return;
235
+ if (!(asyncImports.length > 0 || hasAwait)) return;
213
236
  let s = new MagicString(code);
214
237
  s = transform(s, ast, asyncImports, hasAwait);
215
238
  return {
216
239
  code: s.toString(),
217
- meta: { async: isAsyncModule }
240
+ map: options.sourceMap !== false ? s.generateMap({ hires: true }) : null
218
241
  };
219
242
  } },
220
- resolveImportMeta(property, { moduleId, chunkId }) {
243
+ resolveImportMeta(property, { moduleId }) {
221
244
  if (property !== "useTla") return;
222
245
  const moduleInfo = this.getModuleInfo(moduleId);
223
246
  const importers = moduleInfo?.importers;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rollup-plugin-concurrent-top-level-await",
3
- "version": "0.0.5",
3
+ "version": "0.0.6",
4
4
  "description": "Rollup (and Vite) plugin enabling concurrent execution of modules that contain top level await.",
5
5
  "keywords": [
6
6
  "rollup-plugin",