@endo/compartment-mapper 1.5.0 → 1.6.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 (71) hide show
  1. package/README.md +278 -111
  2. package/bundle.d.ts +1 -1
  3. package/bundle.js +4 -1
  4. package/functor-lite.d.ts +3 -0
  5. package/functor-lite.d.ts.map +1 -0
  6. package/functor-lite.js +4 -0
  7. package/functor.d.ts +3 -0
  8. package/functor.d.ts.map +1 -0
  9. package/functor.js +4 -0
  10. package/index.d.ts +1 -1
  11. package/index.js +4 -1
  12. package/package.json +8 -4
  13. package/script-lite.d.ts +3 -0
  14. package/script-lite.d.ts.map +1 -0
  15. package/script-lite.js +4 -0
  16. package/script.d.ts +3 -0
  17. package/script.d.ts.map +1 -0
  18. package/script.js +4 -0
  19. package/src/archive-lite.js +1 -1
  20. package/src/bundle-cjs.d.ts +1 -1
  21. package/src/bundle-cjs.d.ts.map +1 -1
  22. package/src/bundle-cjs.js +57 -28
  23. package/src/bundle-json.d.ts.map +1 -1
  24. package/src/bundle-json.js +2 -3
  25. package/src/bundle-lite.d.ts +91 -0
  26. package/src/bundle-lite.d.ts.map +1 -0
  27. package/src/bundle-lite.js +668 -0
  28. package/src/bundle-mjs.d.ts +2 -2
  29. package/src/bundle-mjs.d.ts.map +1 -1
  30. package/src/bundle-mjs.js +36 -19
  31. package/src/bundle.d.ts +48 -10
  32. package/src/bundle.d.ts.map +1 -1
  33. package/src/bundle.js +391 -125
  34. package/src/capture-lite.js +1 -1
  35. package/src/import-hook.d.ts +3 -16
  36. package/src/import-hook.d.ts.map +1 -1
  37. package/src/import-hook.js +11 -18
  38. package/src/import-lite.d.ts.map +1 -1
  39. package/src/import-lite.js +4 -2
  40. package/src/node-modules.d.ts +4 -47
  41. package/src/node-modules.d.ts.map +1 -1
  42. package/src/node-modules.js +121 -121
  43. package/src/parse-archive-cjs.d.ts.map +1 -1
  44. package/src/parse-archive-cjs.js +8 -3
  45. package/src/parse-cjs-shared-export-wrapper.d.ts.map +1 -1
  46. package/src/parse-cjs-shared-export-wrapper.js +2 -10
  47. package/src/parse-cjs.js +1 -1
  48. package/src/parse-mjs.js +2 -2
  49. package/src/policy.d.ts.map +1 -1
  50. package/src/policy.js +4 -7
  51. package/src/search.d.ts +6 -12
  52. package/src/search.d.ts.map +1 -1
  53. package/src/search.js +29 -12
  54. package/src/types/compartment-map-schema.d.ts +5 -0
  55. package/src/types/compartment-map-schema.d.ts.map +1 -1
  56. package/src/types/compartment-map-schema.ts +5 -0
  57. package/src/types/external.d.ts +112 -8
  58. package/src/types/external.d.ts.map +1 -1
  59. package/src/types/external.ts +127 -8
  60. package/src/types/internal.d.ts +85 -13
  61. package/src/types/internal.d.ts.map +1 -1
  62. package/src/types/internal.ts +106 -13
  63. package/src/types/node-modules.d.ts +79 -0
  64. package/src/types/node-modules.d.ts.map +1 -0
  65. package/src/types/node-modules.ts +89 -0
  66. package/src/types/node-powers.d.ts +4 -4
  67. package/src/types/node-powers.d.ts.map +1 -1
  68. package/src/types/node-powers.ts +4 -4
  69. package/src/types/powers.d.ts +2 -2
  70. package/src/types/powers.d.ts.map +1 -1
  71. package/src/types/powers.ts +2 -2
@@ -0,0 +1,668 @@
1
+ /* eslint no-shadow: 0 */
2
+
3
+ /**
4
+ * @import {
5
+ * StaticModuleType,
6
+ * PrecompiledStaticModuleInterface
7
+ * } from 'ses'
8
+ * @import {
9
+ * BundleOptions,
10
+ * CompartmentDescriptor,
11
+ * CompartmentMapDescriptor,
12
+ * CompartmentSources,
13
+ * MaybeReadPowers,
14
+ * ReadFn,
15
+ * ReadPowers,
16
+ * Sources,
17
+ * } from './types.js'
18
+ */
19
+
20
+ /**
21
+ * The bundler kit defines a language-specific behavior for injecting a module
22
+ * into a bundle.
23
+ * Each module must allocate cells for its imports and exports, link those cells
24
+ * to the cells of dependencies, and provide both the linker and evaluation behavior
25
+ * for the module.
26
+ * The linker behavior gets injected in a lexical scope with the linker runtime
27
+ * and has access to the cells of all modules, whereas the evaluation behavior
28
+ * gets injected in the generated script's top level lexical scope, so has
29
+ * no accidental visibility into the linkage runtime.
30
+ *
31
+ * For example, JSON modules produce a single "default" cell ("getCells"):
32
+ *
33
+ * { default: cell('default') },
34
+ *
35
+ * Then, the JSON gets injected verbatim for the evaluation behavior ("getFunctor").
36
+ * The linker simply sets the cell to the value.
37
+ *
38
+ * functors[0]['default'].set(modules[0]);
39
+ *
40
+ * For an ECMAScript or CommonJS module, the evaluation behavior is a function
41
+ * that the linker runtime can call to inject it with the cells it needs by
42
+ * the names it sees for them.
43
+ *
44
+ * @typedef {object} BundlerKit
45
+ * @property {() => string} getFunctor Produces a JavaScript string consisting of
46
+ * a function expression followed by a comma delimiter that will be evaluated in
47
+ * a lexical scope with no free variables except the globals.
48
+ * In the generated bundle runtime, the function will receive an environment
49
+ * record: a record mapping every name of the corresponding module's internal
50
+ * namespace to a "cell" it can use to get, set, or observe the linked
51
+ * variable.
52
+ * @property {() => string} getCells Produces a JavaScript string consisting of
53
+ * a JavaScript object and a trailing comma.
54
+ * The string is evaluated in the linker runtime's lexical context.
55
+ * @property {() => string} getFunctorCall Produces a JavaScript string,
56
+ * a statement that effects the module's evaluation behavior using the cells
57
+ * it imports and exports and the evaluated "functor".
58
+ * @property {() => string} getReexportsWiring Produces a JavaScript string
59
+ * that may include statements that bind the cells reexported by this module.
60
+ */
61
+
62
+ /**
63
+ * @template {unknown} SpecificModuleSource
64
+ * @typedef {object} BundleModule
65
+ * @property {string} key
66
+ * @property {string} exit
67
+ * @property {string} compartmentName
68
+ * @property {string} moduleSpecifier
69
+ * @property {string} sourceDirname
70
+ * @property {string} parser
71
+ * @property {StaticModuleType & SpecificModuleSource} record
72
+ * @property {Record<string, string>} resolvedImports
73
+ * @property {Record<string, number>} indexedImports
74
+ * @property {Uint8Array} bytes
75
+ * @property {number} index
76
+ * @property {BundlerKit} bundlerKit
77
+ */
78
+
79
+ /**
80
+ * @typedef {object} BundleExit
81
+ * @property {string} exit
82
+ * @property {number} index
83
+ * @property {BundlerKit} bundlerKit
84
+ * @property {Record<string, number>} indexedImports
85
+ * @property {Record<string, string>} resolvedImports
86
+ */
87
+
88
+ /**
89
+ * @template {unknown} SpecificModuleSource
90
+ * @callback GetBundlerKit
91
+ * @param {BundleModule<SpecificModuleSource>} module
92
+ * @param {object} params
93
+ * @param {boolean} [params.useEvaluate]
94
+ * @param {string} [params.sourceUrlPrefix]
95
+ * @returns {BundlerKit}
96
+ */
97
+
98
+ /**
99
+ * @template {unknown} SpecificModuleSource
100
+ * @typedef {object} BundlerSupport
101
+ * @property {string} runtime
102
+ * @property {GetBundlerKit<SpecificModuleSource>} getBundlerKit
103
+ */
104
+
105
+ import { resolve } from './node-module-specifier.js';
106
+ import { link } from './link.js';
107
+ import { makeImportHookMaker } from './import-hook.js';
108
+ import { defaultParserForLanguage } from './archive-parsers.js';
109
+
110
+ import mjsSupport from './bundle-mjs.js';
111
+ import cjsSupport from './bundle-cjs.js';
112
+ import jsonSupport from './bundle-json.js';
113
+
114
+ const { quote: q } = assert;
115
+
116
+ /**
117
+ * @param {BundleExit} source
118
+ * @returns {BundlerKit}
119
+ */
120
+ const makeCjsExitBundlerKit = ({ exit, index }) => ({
121
+ getFunctor: () => `\
122
+ null,
123
+ `,
124
+ getCells: () => `\
125
+ namespaceCells(tryRequire(${JSON.stringify(exit)})),
126
+ `,
127
+ getReexportsWiring: () => '',
128
+ getFunctorCall: () => ``,
129
+ });
130
+
131
+ /**
132
+ * Produces a list of modules in the order they should be evaluated, and
133
+ * a side-table for following aliases.
134
+ * The modules are produce in topological postorder, such that the entry
135
+ * module appears last.
136
+ * The post-order traversal does not revisit modules that appear in cycles.
137
+ *
138
+ * Synthesizes a unique key for each module and translates
139
+ * each module's imports to their corresponding keys.
140
+ * Some import keys are aliased to other keys, such that walking from
141
+ * key to value in the aliases side table will eventually arrive at
142
+ * the key of a module that is present in the modules list.
143
+ *
144
+ * The first modules are place-holders for the modules that exit
145
+ * the compartment map to the host's module system.
146
+ *
147
+ * @param {Record<string, CompartmentDescriptor>} compartmentDescriptors
148
+ * @param {Record<string, CompartmentSources>} compartmentSources
149
+ * @param {string} entryCompartmentName
150
+ * @param {string} entryModuleSpecifier
151
+ * @param {Array<string>} exitModuleSpecifiers
152
+ */
153
+ const sortedModules = (
154
+ compartmentDescriptors,
155
+ compartmentSources,
156
+ entryCompartmentName,
157
+ entryModuleSpecifier,
158
+ exitModuleSpecifiers,
159
+ ) => {
160
+ /** @type {BundleModule<unknown>[]} */
161
+ const modules = [];
162
+ /** @type {Map<string, string>} aliaes */
163
+ const aliases = new Map();
164
+ /** @type {Set<string>} seen */
165
+ const seen = new Set();
166
+
167
+ for (const exit of exitModuleSpecifiers) {
168
+ modules.push({
169
+ key: exit,
170
+ exit,
171
+ // @ts-expect-error
172
+ index: undefined,
173
+ // @ts-expect-error
174
+ bundlerKit: null,
175
+ });
176
+ }
177
+
178
+ /**
179
+ * @param {string} compartmentName
180
+ * @param {string} moduleSpecifier
181
+ */
182
+ const recur = (compartmentName, moduleSpecifier) => {
183
+ const key = `${compartmentName}#${moduleSpecifier}`;
184
+ if (seen.has(key)) {
185
+ return key;
186
+ }
187
+ seen.add(key);
188
+
189
+ const source = compartmentSources[compartmentName][moduleSpecifier];
190
+ if (source !== undefined) {
191
+ const { record, parser, deferredError, bytes, sourceDirname, exit } =
192
+ source;
193
+ if (exit !== undefined) {
194
+ return exit;
195
+ }
196
+ assert(
197
+ bytes !== undefined,
198
+ `No bytes for ${moduleSpecifier} in ${compartmentName}`,
199
+ );
200
+ assert(
201
+ parser !== undefined,
202
+ `No parser for ${moduleSpecifier} in ${compartmentName}`,
203
+ );
204
+ assert(
205
+ sourceDirname !== undefined,
206
+ `No sourceDirname for ${moduleSpecifier} in ${compartmentName}`,
207
+ );
208
+ if (deferredError) {
209
+ throw Error(
210
+ `Cannot bundle: encountered deferredError ${deferredError}`,
211
+ );
212
+ }
213
+ if (record) {
214
+ const { imports = [], reexports = [] } =
215
+ /** @type {PrecompiledStaticModuleInterface} */ (record);
216
+ const resolvedImports = Object.create(null);
217
+ for (const importSpecifier of [...imports, ...reexports]) {
218
+ // If we ever support another module resolution algorithm, that
219
+ // should be indicated in the compartment descriptor by name and the
220
+ // corresponding behavior selected here.
221
+ const resolvedSpecifier = resolve(importSpecifier, moduleSpecifier);
222
+ resolvedImports[importSpecifier] = recur(
223
+ compartmentName,
224
+ resolvedSpecifier,
225
+ );
226
+ }
227
+
228
+ modules.push({
229
+ key,
230
+ compartmentName,
231
+ moduleSpecifier,
232
+ sourceDirname,
233
+ parser,
234
+ record,
235
+ resolvedImports,
236
+ bytes,
237
+ // @ts-expect-error
238
+ index: undefined,
239
+ // @ts-expect-error
240
+ bundlerKit: null,
241
+ });
242
+
243
+ return key;
244
+ }
245
+ } else {
246
+ const descriptor =
247
+ compartmentDescriptors[compartmentName].modules[moduleSpecifier];
248
+ if (descriptor) {
249
+ const {
250
+ compartment: aliasCompartmentName,
251
+ module: aliasModuleSpecifier,
252
+ } = descriptor;
253
+ if (
254
+ aliasCompartmentName !== undefined &&
255
+ aliasModuleSpecifier !== undefined
256
+ ) {
257
+ const aliasKey = recur(aliasCompartmentName, aliasModuleSpecifier);
258
+ aliases.set(key, aliasKey);
259
+ return aliasKey;
260
+ }
261
+ }
262
+ }
263
+
264
+ throw Error(
265
+ `Cannot bundle: cannot follow module import ${moduleSpecifier} in compartment ${compartmentName}`,
266
+ );
267
+ };
268
+
269
+ recur(entryCompartmentName, entryModuleSpecifier);
270
+
271
+ return { modules, aliases };
272
+ };
273
+
274
+ /** @type {Record<string, BundlerSupport<unknown>>} */
275
+ const bundlerSupportForLanguage = {
276
+ 'pre-mjs-json': mjsSupport,
277
+ 'pre-cjs-json': cjsSupport,
278
+ json: jsonSupport,
279
+ };
280
+
281
+ /** @param {string} language */
282
+ const getRuntime = language =>
283
+ bundlerSupportForLanguage[language]
284
+ ? bundlerSupportForLanguage[language].runtime
285
+ : `/*unknown language:${language}*/`;
286
+
287
+ /**
288
+ * @param {BundleModule<unknown>} module
289
+ * @param {object} params
290
+ * @param {boolean} [params.useEvaluate]
291
+ * @param {string} [params.sourceUrlPrefix]
292
+ */
293
+ const getBundlerKitForModule = (module, params) => {
294
+ const language = module.parser;
295
+ assert(language !== undefined);
296
+ if (bundlerSupportForLanguage[language] === undefined) {
297
+ const warning = `/*unknown language:${language}*/`;
298
+ // each item is a function to avoid creating more in-memory copies of the source text etc.
299
+ /** @type {BundlerKit} */
300
+ return {
301
+ getFunctor: () => `(()=>{${warning}}),`,
302
+ getCells: () => `{${warning}},`,
303
+ getFunctorCall: () => warning,
304
+ getReexportsWiring: () => '',
305
+ };
306
+ }
307
+ const { getBundlerKit } = bundlerSupportForLanguage[language];
308
+ return getBundlerKit(module, params);
309
+ };
310
+
311
+ /**
312
+ * @param {ReadFn | ReadPowers | MaybeReadPowers} readPowers
313
+ * @param {CompartmentMapDescriptor} compartmentMap
314
+ * @param {BundleOptions} [options]
315
+ * @returns {Promise<string>}
316
+ */
317
+ export const makeFunctorFromMap = async (
318
+ readPowers,
319
+ compartmentMap,
320
+ options,
321
+ ) => {
322
+ const {
323
+ moduleTransforms,
324
+ searchSuffixes,
325
+ sourceMapHook = undefined,
326
+ useEvaluate = false,
327
+ sourceUrlPrefix = undefined,
328
+ format = undefined,
329
+ parserForLanguage: parserForLanguageOption = {},
330
+ } = options || {};
331
+
332
+ /** @type {((module: BundleExit) => BundlerKit) | undefined} */
333
+ let makeExitBundlerKit;
334
+ if (format === 'cjs') {
335
+ makeExitBundlerKit = makeCjsExitBundlerKit;
336
+ }
337
+
338
+ const parserForLanguage = Object.freeze(
339
+ Object.assign(
340
+ Object.create(null),
341
+ defaultParserForLanguage,
342
+ parserForLanguageOption,
343
+ ),
344
+ );
345
+
346
+ const bundlerKitParams = {
347
+ useEvaluate,
348
+ sourceUrlPrefix,
349
+ };
350
+
351
+ const {
352
+ compartments,
353
+ entry: { compartment: entryCompartmentName, module: entryModuleSpecifier },
354
+ } = compartmentMap;
355
+ /** @type {string[]} */
356
+ const exitModuleSpecifiers = [];
357
+ /** @type {Sources} */
358
+ const sources = Object.create(null);
359
+
360
+ /**
361
+ * @param {string} moduleSpecifier
362
+ * @param {string} compartmentName
363
+ */
364
+ const exitModuleImportHook =
365
+ format !== undefined
366
+ ? /**
367
+ * @param {string} moduleSpecifier
368
+ * @param {string} compartmentName
369
+ */
370
+ async (moduleSpecifier, compartmentName) => {
371
+ const compartmentSources =
372
+ sources[compartmentName] || Object.create(null);
373
+ sources[compartmentName] = compartmentSources;
374
+ compartmentSources[moduleSpecifier] = {
375
+ exit: moduleSpecifier,
376
+ };
377
+ exitModuleSpecifiers.push(moduleSpecifier);
378
+ return { imports: [], exports: [], execute() {} };
379
+ }
380
+ : undefined;
381
+
382
+ const makeImportHook = makeImportHookMaker(readPowers, entryCompartmentName, {
383
+ archiveOnly: true,
384
+ sources,
385
+ compartmentDescriptors: compartments,
386
+ searchSuffixes,
387
+ entryCompartmentName,
388
+ entryModuleSpecifier,
389
+ sourceMapHook,
390
+ importHook: exitModuleImportHook,
391
+ });
392
+
393
+ // Induce importHook to record all the necessary modules to import the given module specifier.
394
+ const { compartment } = link(compartmentMap, {
395
+ resolve,
396
+ makeImportHook,
397
+ moduleTransforms,
398
+ parserForLanguage,
399
+ });
400
+ await compartment.load(entryModuleSpecifier);
401
+
402
+ const { modules, aliases } = sortedModules(
403
+ compartmentMap.compartments,
404
+ sources,
405
+ entryCompartmentName,
406
+ entryModuleSpecifier,
407
+ exitModuleSpecifiers,
408
+ );
409
+
410
+ // Create an index of modules so we can resolve import specifiers to the
411
+ // index of the corresponding functor.
412
+ const modulesByKey = Object.create(null);
413
+ for (let index = 0; index < modules.length; index += 1) {
414
+ const module = modules[index];
415
+ module.index = index;
416
+ modulesByKey[module.key] = module;
417
+ }
418
+ const parsersInUse = new Set();
419
+ for (const module of modules) {
420
+ if (module.exit !== undefined) {
421
+ if (makeExitBundlerKit === undefined) {
422
+ // makeExitBundlerKit must have been provided to makeImportHookMaker for any modules with an exit property to have been created.
423
+ throw TypeError('Unreachable');
424
+ }
425
+ module.bundlerKit = makeExitBundlerKit(module);
426
+ } else {
427
+ module.indexedImports = Object.fromEntries(
428
+ Object.entries(module.resolvedImports).map(([importSpecifier, key]) => {
429
+ // UNTIL https://github.com/endojs/endo/issues/1514
430
+ // Prefer: key = aliases.get(key) ?? key;
431
+ const alias = aliases.get(key);
432
+ if (alias != null) {
433
+ key = alias;
434
+ }
435
+ const module = modulesByKey[key];
436
+ if (module === undefined) {
437
+ throw new Error(
438
+ `Unable to locate module for key ${q(key)} import specifier ${q(
439
+ importSpecifier,
440
+ )}`,
441
+ );
442
+ }
443
+ const { index } = module;
444
+ return [importSpecifier, index];
445
+ }),
446
+ );
447
+ parsersInUse.add(module.parser);
448
+ module.bundlerKit = getBundlerKitForModule(module, bundlerKitParams);
449
+ }
450
+ }
451
+
452
+ // Some bundles appeal to the host module system appropriate to their format
453
+ // like `require` for bundles used as CommonJS modules.
454
+ // Each module in the modules array is constructed by a language-specific bundler kit,
455
+ // and in the case of an exit module, is a bundler kit made with
456
+ // makeExitBundlerKit, like makeCjsExitBundlerKit.
457
+ // This will generate a module initialization runtime that in turn needs this
458
+ // namespaceCells utility function to take a host module exports namespace
459
+ // and turn it into a bank of cells for importing and exporting the
460
+ // properties of the module exports namespace object.
461
+ const exitNamespaces =
462
+ exitModuleSpecifiers.length === 0
463
+ ? ''
464
+ : `\
465
+ const namespaceCells = namespace => fromEntries(
466
+ getOwnPropertyNames(namespace)
467
+ .map(name => [name, {
468
+ get() {
469
+ return get(namespace, name);
470
+ },
471
+ set() {
472
+ throw new TypeError('Non-writable export');
473
+ },
474
+ observe(observer) {
475
+ observer(get(namespace, name));
476
+ },
477
+ enumerable: true,
478
+ }])
479
+ );
480
+ `;
481
+
482
+ // The linkage runtime creates a cell for every value exported by any of the
483
+ // bundled modules.
484
+ // The interface of a cell is very much like a getter/setter property
485
+ // deescriptor, and additionally has a method for registering an observer to
486
+ // notice when a variable is changed in its originating module, to support
487
+ // live bindings.
488
+ // Each module language defines its own behavior for the generation of its
489
+ // exported cells.
490
+ // After all cells are allocated, each language gets a second opportunity
491
+ // to introduce bindings for cells that the module re-exports from another
492
+ // module, but does not itself own.
493
+ const runtimeLinkageCells = `\
494
+ const cell = (name, value = undefined) => {
495
+ const observers = [];
496
+ return freeze({
497
+ get: freeze(() => {
498
+ return value;
499
+ }),
500
+ set: freeze((newValue) => {
501
+ value = newValue;
502
+ for (let i = 0; i < observers.length; i += 1) {
503
+ const observe = observers[i];
504
+ observe(value);
505
+ }
506
+ }),
507
+ observe: freeze((observe) => {
508
+ observers.push(observe);
509
+ observe(value);
510
+ }),
511
+ enumerable: true,
512
+ });
513
+ };
514
+
515
+ const cells = [
516
+ ${''.concat(...modules.map(m => m.bundlerKit.getCells()))}\
517
+ ];
518
+
519
+ ${''.concat(...modules.map(m => m.bundlerKit.getReexportsWiring()))}\
520
+ `;
521
+
522
+ // The linker runtime includes a parallel array of module exports namespace
523
+ // objects for each bundled module, for each respective index of the module
524
+ // functors array.
525
+ // Each namespace has a special '*' property for the namespace object itself,
526
+ // which is what modules obtain with `import * as x from 'x'` notation.
527
+ const moduleNamespaces = `\
528
+ const namespaces = cells.map(cells => freeze(create(null, {
529
+ ...cells,
530
+ // Make this appear like an ESM module namespace object.
531
+ [Symbol.toStringTag]: {
532
+ value: 'Module',
533
+ writable: false,
534
+ enumerable: false,
535
+ configurable: false,
536
+ },
537
+ })));
538
+
539
+ for (let index = 0; index < namespaces.length; index += 1) {
540
+ cells[index]['*'] = cell('*', namespaces[index]);
541
+ }
542
+ `;
543
+
544
+ // Each language in use within the bundle has an opportunity to inject
545
+ // utilities into the bundle runtime that it can use in the shared lexical
546
+ // scope of module execution.
547
+ // CommonJS in particular injects a utility function here, if the script
548
+ // entrains any CommonJS modules.
549
+ const languageRuntimeExtensions = `\
550
+ ${''.concat(...Array.from(parsersInUse).map(parser => getRuntime(parser)))}\
551
+ `;
552
+
553
+ // This section of the linker runtime causes each of the modules to execute
554
+ // in topological order, using a language-specific calling convention to
555
+ // link its imports and exports to other modules.
556
+ const moduleExecutionRuntime = `\
557
+ ${''.concat(...modules.map(m => m.bundlerKit.getFunctorCall()))}\
558
+ `;
559
+
560
+ // The linker runtime receives an array of language-specific representations
561
+ // of each module, which in the simplest case is just a function and a
562
+ // runtime initialization calling convention (a functor).
563
+ // Then, in the style of partial application, it receives runtime options.
564
+ // When driven by makeScript, the script will statically apply the options,
565
+ // but with makeFunctor, the runtime must evaluate and apply runtime options.
566
+ // Scripts are suitable for injection with <script> tags on the web, whereas
567
+ // functors require use of an evaluator at runtime.
568
+ const linkerRuntime = `functors => options => {
569
+ 'use strict';
570
+
571
+ const {
572
+ Map,
573
+ Object,
574
+ ReferenceError,
575
+ Reflect,
576
+ TypeError,
577
+ } = globalThis;
578
+ const {
579
+ create,
580
+ defineProperties,
581
+ defineProperty,
582
+ freeze,
583
+ fromEntries,
584
+ getOwnPropertyDescriptors,
585
+ getOwnPropertyNames,
586
+ keys,
587
+ } = Object;
588
+ const { get, set } = Reflect;
589
+
590
+ const {
591
+ ${
592
+ !useEvaluate
593
+ ? ''
594
+ : `\
595
+ evaluate = eval,
596
+ sourceUrlPrefix = ${JSON.stringify(sourceUrlPrefix)},
597
+ `
598
+ }\
599
+ ${
600
+ format !== 'cjs'
601
+ ? ''
602
+ : `\
603
+ require: tryRequire = typeof require === 'function' ? require : specifier => {
604
+ throw new TypeError('Cannot import host module: ' + specifier);
605
+ },
606
+ `
607
+ }\
608
+ } = options || {};
609
+
610
+ ${
611
+ !useEvaluate
612
+ ? ''
613
+ : `\
614
+ const evaluateSource = (source, sourceUrl) => {
615
+ return evaluate(source + '\\n//# sourceURL=' + sourceUrlPrefix + sourceUrl + '\\n');
616
+ };`
617
+ }\
618
+
619
+ ${exitNamespaces}\
620
+
621
+ ${runtimeLinkageCells}\
622
+
623
+ ${moduleNamespaces}\
624
+
625
+ ${languageRuntimeExtensions}\
626
+
627
+ ${moduleExecutionRuntime}\
628
+
629
+ return cells[cells.length - 1]['*'].get();
630
+ }`;
631
+
632
+ // An array of language-specific representations of each bundled module,
633
+ // which in the simplest case is a function that must be initialized by the
634
+ // linkage runtime using a calling convention.
635
+ // We pass this array into the linkage runtime rather than embedding it in
636
+ // the linkage runtime in order to assure that the runtime's lexical context
637
+ // doesn't overshadow each module's lexical scope.
638
+ const moduleFunctors = `[
639
+ ${''.concat(
640
+ ...modules.map(
641
+ (m, index) => `\
642
+ // === ${index}. ${m.sourceDirname} ${m.moduleSpecifier} ===
643
+ ${m.bundlerKit.getFunctor()}`,
644
+ ),
645
+ )}\
646
+ ]`;
647
+
648
+ // Functors partially apply the linker runtime.
649
+ // Scripts go on to apply static options and execute immediately.
650
+ return `(${linkerRuntime})(${moduleFunctors})`;
651
+ };
652
+
653
+ /**
654
+ * @param {ReadFn | ReadPowers | MaybeReadPowers} readPowers
655
+ * @param {CompartmentMapDescriptor} compartmentMap
656
+ * @param {BundleOptions} [options]
657
+ * @returns {Promise<string>}
658
+ */
659
+ export const makeScriptFromMap = async (
660
+ readPowers,
661
+ compartmentMap,
662
+ options,
663
+ ) => {
664
+ // Functors partially apply the linker runtime.
665
+ // Scripts go on to apply static options and execute immediately.
666
+ const functor = await makeFunctorFromMap(readPowers, compartmentMap, options);
667
+ return `${functor}()`;
668
+ };
@@ -1,6 +1,6 @@
1
- export const runtime: "function observeImports(map, importName, importIndex) {\n for (const [name, observers] of map.get(importName)) {\n const cell = cells[importIndex][name];\n if (cell === undefined) {\n throw new ReferenceError(`Cannot import name ${name}`);\n }\n for (const observer of observers) {\n cell.observe(observer);\n }\n }\n}\n";
1
+ export const runtime: "function observeImports(map, importName, importIndex) {\n for (const [name, observers] of map.get(importName)) {\n const cell = cells[importIndex][name];\n if (cell === undefined) {\n throw new ReferenceError(`Cannot import name ${name} (has ${Object.getOwnPropertyNames(cells[importIndex]).join(', ')})`);\n }\n for (const observer of observers) {\n cell.observe(observer);\n }\n }\n}\n";
2
2
  declare const _default: BundlerSupport<PrecompiledModuleSource>;
3
3
  export default _default;
4
4
  import type { PrecompiledModuleSource } from 'ses';
5
- import type { BundlerSupport } from './bundle.js';
5
+ import type { BundlerSupport } from './bundle-lite.js';
6
6
  //# sourceMappingURL=bundle-mjs.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"bundle-mjs.d.ts","sourceRoot":"","sources":["bundle-mjs.js"],"names":[],"mappings":"AAsCA,oXAYE;wBAES,eAAe,uBAAuB,CAAC;;6CAlDP,KAAK;oCACd,aAAa"}
1
+ {"version":3,"file":"bundle-mjs.d.ts","sourceRoot":"","sources":["bundle-mjs.js"],"names":[],"mappings":"AAwCA,ubAYE;wBAES,eAAe,uBAAuB,CAAC;;6CApDP,KAAK;oCACd,kBAAkB"}