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