@endo/compartment-mapper 1.4.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 +292 -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/import-archive-all-parsers.d.ts +2 -0
- package/import-archive-all-parsers.d.ts.map +1 -0
- package/import-archive-all-parsers.js +1 -0
- package/index.d.ts +1 -1
- package/index.js +4 -1
- package/package.json +14 -5
- 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.d.ts +2 -4
- package/src/archive-lite.d.ts.map +1 -1
- package/src/archive-lite.js +16 -192
- package/src/archive.d.ts.map +1 -1
- package/src/archive.js +8 -0
- 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 +399 -127
- package/src/capture-lite.d.ts.map +1 -1
- package/src/capture-lite.js +10 -188
- package/src/digest.d.ts +5 -0
- package/src/digest.d.ts.map +1 -0
- package/src/digest.js +235 -0
- package/src/import-archive-all-parsers.d.ts +11 -0
- package/src/import-archive-all-parsers.d.ts.map +1 -0
- package/src/import-archive-all-parsers.js +29 -0
- package/src/import-archive-lite.d.ts.map +1 -1
- package/src/import-archive-lite.js +4 -0
- 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 +7 -2
- package/src/import.d.ts.map +1 -1
- package/src/import.js +2 -0
- package/src/link.d.ts.map +1 -1
- package/src/link.js +2 -0
- package/src/map-parser.d.ts.map +1 -1
- package/src/map-parser.js +4 -1
- package/src/node-modules.d.ts +4 -47
- package/src/node-modules.d.ts.map +1 -1
- package/src/node-modules.js +157 -131
- 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 +159 -12
- package/src/types/external.d.ts.map +1 -1
- package/src/types/external.ts +180 -12
- package/src/types/internal.d.ts +86 -13
- package/src/types/internal.d.ts.map +1 -1
- package/src/types/internal.ts +107 -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,9 +192,23 @@ const sortedModules = (
|
|
|
116
192
|
|
|
117
193
|
const source = compartmentSources[compartmentName][moduleSpecifier];
|
|
118
194
|
if (source !== undefined) {
|
|
119
|
-
const { record, parser, deferredError, bytes } =
|
|
120
|
-
|
|
121
|
-
|
|
195
|
+
const { record, parser, deferredError, bytes, sourceDirname, exit } =
|
|
196
|
+
source;
|
|
197
|
+
if (exit !== undefined) {
|
|
198
|
+
return exit;
|
|
199
|
+
}
|
|
200
|
+
assert(
|
|
201
|
+
bytes !== undefined,
|
|
202
|
+
`No bytes for ${moduleSpecifier} in ${compartmentName}`,
|
|
203
|
+
);
|
|
204
|
+
assert(
|
|
205
|
+
parser !== undefined,
|
|
206
|
+
`No parser for ${moduleSpecifier} in ${compartmentName}`,
|
|
207
|
+
);
|
|
208
|
+
assert(
|
|
209
|
+
sourceDirname !== undefined,
|
|
210
|
+
`No sourceDirname for ${moduleSpecifier} in ${compartmentName}`,
|
|
211
|
+
);
|
|
122
212
|
if (deferredError) {
|
|
123
213
|
throw Error(
|
|
124
214
|
`Cannot bundle: encountered deferredError ${deferredError}`,
|
|
@@ -143,6 +233,7 @@ const sortedModules = (
|
|
|
143
233
|
key,
|
|
144
234
|
compartmentName,
|
|
145
235
|
moduleSpecifier,
|
|
236
|
+
sourceDirname,
|
|
146
237
|
parser,
|
|
147
238
|
record,
|
|
148
239
|
resolvedImports,
|
|
@@ -197,8 +288,13 @@ const getRuntime = language =>
|
|
|
197
288
|
? bundlerSupportForLanguage[language].runtime
|
|
198
289
|
: `/*unknown language:${language}*/`;
|
|
199
290
|
|
|
200
|
-
/**
|
|
201
|
-
|
|
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) => {
|
|
202
298
|
const language = module.parser;
|
|
203
299
|
assert(language !== undefined);
|
|
204
300
|
if (bundlerSupportForLanguage[language] === undefined) {
|
|
@@ -213,37 +309,36 @@ const getBundlerKitForModule = module => {
|
|
|
213
309
|
};
|
|
214
310
|
}
|
|
215
311
|
const { getBundlerKit } = bundlerSupportForLanguage[language];
|
|
216
|
-
return getBundlerKit(module);
|
|
312
|
+
return getBundlerKit(module, params);
|
|
217
313
|
};
|
|
218
314
|
|
|
219
315
|
/**
|
|
220
316
|
* @param {ReadFn | ReadPowers | MaybeReadPowers} readPowers
|
|
221
|
-
* @param {
|
|
222
|
-
* @param {
|
|
317
|
+
* @param {CompartmentMapDescriptor} compartmentMap
|
|
318
|
+
* @param {BundleOptions} [options]
|
|
223
319
|
* @returns {Promise<string>}
|
|
224
320
|
*/
|
|
225
|
-
export const
|
|
226
|
-
|
|
227
|
-
|
|
321
|
+
export const makeFunctorFromMap = async (
|
|
322
|
+
readPowers,
|
|
323
|
+
compartmentMap,
|
|
324
|
+
options,
|
|
325
|
+
) => {
|
|
228
326
|
const {
|
|
229
327
|
moduleTransforms,
|
|
230
|
-
|
|
231
|
-
tags: tagsOption,
|
|
232
|
-
conditions: conditionsOption = tagsOption,
|
|
328
|
+
syncModuleTransforms,
|
|
233
329
|
searchSuffixes,
|
|
234
|
-
commonDependencies,
|
|
235
330
|
sourceMapHook = undefined,
|
|
331
|
+
useEvaluate = false,
|
|
332
|
+
sourceUrlPrefix = undefined,
|
|
333
|
+
format = undefined,
|
|
236
334
|
parserForLanguage: parserForLanguageOption = {},
|
|
237
|
-
languageForExtension: languageForExtensionOption = {},
|
|
238
|
-
commonjsLanguageForExtension: commonjsLanguageForExtensionOption = {},
|
|
239
|
-
moduleLanguageForExtension: moduleLanguageForExtensionOption = {},
|
|
240
|
-
workspaceLanguageForExtension: workspaceLanguageForExtensionOption = {},
|
|
241
|
-
workspaceCommonjsLanguageForExtension:
|
|
242
|
-
workspaceCommonjsLanguageForExtensionOption = {},
|
|
243
|
-
workspaceModuleLanguageForExtension:
|
|
244
|
-
workspaceModuleLanguageForExtensionOption = {},
|
|
245
335
|
} = options || {};
|
|
246
|
-
|
|
336
|
+
|
|
337
|
+
/** @type {((module: BundleExit) => BundlerKit) | undefined} */
|
|
338
|
+
let makeExitBundlerKit;
|
|
339
|
+
if (format === 'cjs') {
|
|
340
|
+
makeExitBundlerKit = makeCjsExitBundlerKit;
|
|
341
|
+
}
|
|
247
342
|
|
|
248
343
|
const parserForLanguage = Object.freeze(
|
|
249
344
|
Object.assign(
|
|
@@ -252,74 +347,52 @@ export const makeBundle = async (readPowers, moduleLocation, options) => {
|
|
|
252
347
|
parserForLanguageOption,
|
|
253
348
|
),
|
|
254
349
|
);
|
|
255
|
-
const languageForExtension = Object.freeze(
|
|
256
|
-
Object.assign(Object.create(null), languageForExtensionOption),
|
|
257
|
-
);
|
|
258
|
-
const commonjsLanguageForExtension = Object.freeze(
|
|
259
|
-
Object.assign(Object.create(null), commonjsLanguageForExtensionOption),
|
|
260
|
-
);
|
|
261
|
-
const moduleLanguageForExtension = Object.freeze(
|
|
262
|
-
Object.assign(Object.create(null), moduleLanguageForExtensionOption),
|
|
263
|
-
);
|
|
264
|
-
const workspaceLanguageForExtension = Object.freeze(
|
|
265
|
-
Object.assign(Object.create(null), workspaceLanguageForExtensionOption),
|
|
266
|
-
);
|
|
267
|
-
const workspaceCommonjsLanguageForExtension = Object.freeze(
|
|
268
|
-
Object.assign(
|
|
269
|
-
Object.create(null),
|
|
270
|
-
workspaceCommonjsLanguageForExtensionOption,
|
|
271
|
-
),
|
|
272
|
-
);
|
|
273
|
-
const workspaceModuleLanguageForExtension = Object.freeze(
|
|
274
|
-
Object.assign(
|
|
275
|
-
Object.create(null),
|
|
276
|
-
workspaceModuleLanguageForExtensionOption,
|
|
277
|
-
),
|
|
278
|
-
);
|
|
279
350
|
|
|
280
|
-
const {
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
moduleSpecifier,
|
|
285
|
-
} = await search(readPowers, moduleLocation);
|
|
286
|
-
|
|
287
|
-
const packageDescriptor = parseLocatedJson(
|
|
288
|
-
packageDescriptorText,
|
|
289
|
-
packageDescriptorLocation,
|
|
290
|
-
);
|
|
291
|
-
const compartmentMap = await compartmentMapForNodeModules(
|
|
292
|
-
read,
|
|
293
|
-
packageLocation,
|
|
294
|
-
conditions,
|
|
295
|
-
packageDescriptor,
|
|
296
|
-
moduleSpecifier,
|
|
297
|
-
{
|
|
298
|
-
dev,
|
|
299
|
-
commonDependencies,
|
|
300
|
-
languageForExtension,
|
|
301
|
-
commonjsLanguageForExtension,
|
|
302
|
-
moduleLanguageForExtension,
|
|
303
|
-
workspaceLanguageForExtension,
|
|
304
|
-
workspaceCommonjsLanguageForExtension,
|
|
305
|
-
workspaceModuleLanguageForExtension,
|
|
306
|
-
},
|
|
307
|
-
);
|
|
351
|
+
const bundlerKitParams = {
|
|
352
|
+
useEvaluate,
|
|
353
|
+
sourceUrlPrefix,
|
|
354
|
+
};
|
|
308
355
|
|
|
309
356
|
const {
|
|
310
357
|
compartments,
|
|
311
358
|
entry: { compartment: entryCompartmentName, module: entryModuleSpecifier },
|
|
312
359
|
} = compartmentMap;
|
|
360
|
+
/** @type {string[]} */
|
|
361
|
+
const exitModuleSpecifiers = [];
|
|
313
362
|
/** @type {Sources} */
|
|
314
363
|
const sources = Object.create(null);
|
|
315
364
|
|
|
316
|
-
|
|
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,
|
|
317
389
|
sources,
|
|
318
390
|
compartmentDescriptors: compartments,
|
|
319
391
|
searchSuffixes,
|
|
320
392
|
entryCompartmentName,
|
|
321
393
|
entryModuleSpecifier,
|
|
322
394
|
sourceMapHook,
|
|
395
|
+
importHook: exitModuleImportHook,
|
|
323
396
|
});
|
|
324
397
|
|
|
325
398
|
// Induce importHook to record all the necessary modules to import the given module specifier.
|
|
@@ -327,6 +400,7 @@ export const makeBundle = async (readPowers, moduleLocation, options) => {
|
|
|
327
400
|
resolve,
|
|
328
401
|
makeImportHook,
|
|
329
402
|
moduleTransforms,
|
|
403
|
+
syncModuleTransforms,
|
|
330
404
|
parserForLanguage,
|
|
331
405
|
});
|
|
332
406
|
await compartment.load(entryModuleSpecifier);
|
|
@@ -336,6 +410,7 @@ export const makeBundle = async (readPowers, moduleLocation, options) => {
|
|
|
336
410
|
sources,
|
|
337
411
|
entryCompartmentName,
|
|
338
412
|
entryModuleSpecifier,
|
|
413
|
+
exitModuleSpecifiers,
|
|
339
414
|
);
|
|
340
415
|
|
|
341
416
|
// Create an index of modules so we can resolve import specifiers to the
|
|
@@ -348,49 +423,93 @@ export const makeBundle = async (readPowers, moduleLocation, options) => {
|
|
|
348
423
|
}
|
|
349
424
|
const parsersInUse = new Set();
|
|
350
425
|
for (const module of modules) {
|
|
351
|
-
module.
|
|
352
|
-
|
|
353
|
-
//
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
)
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
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
|
+
}
|
|
375
456
|
}
|
|
376
457
|
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
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
|
+
`;
|
|
380
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 = `\
|
|
381
500
|
const cell = (name, value = undefined) => {
|
|
382
501
|
const observers = [];
|
|
383
|
-
return
|
|
384
|
-
get:
|
|
502
|
+
return freeze({
|
|
503
|
+
get: freeze(() => {
|
|
385
504
|
return value;
|
|
386
505
|
}),
|
|
387
|
-
set:
|
|
506
|
+
set: freeze((newValue) => {
|
|
388
507
|
value = newValue;
|
|
389
508
|
for (const observe of observers) {
|
|
390
509
|
observe(value);
|
|
391
510
|
}
|
|
392
511
|
}),
|
|
393
|
-
observe:
|
|
512
|
+
observe: freeze((observe) => {
|
|
394
513
|
observers.push(observe);
|
|
395
514
|
observe(value);
|
|
396
515
|
}),
|
|
@@ -403,8 +522,15 @@ ${''.concat(...modules.map(m => m.bundlerKit.getCells()))}\
|
|
|
403
522
|
];
|
|
404
523
|
|
|
405
524
|
${''.concat(...modules.map(m => m.bundlerKit.getReexportsWiring()))}\
|
|
525
|
+
`;
|
|
406
526
|
|
|
407
|
-
|
|
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, {
|
|
408
534
|
...cells,
|
|
409
535
|
// Make this appear like an ESM module namespace object.
|
|
410
536
|
[Symbol.toStringTag]: {
|
|
@@ -418,16 +544,162 @@ ${''.concat(...modules.map(m => m.bundlerKit.getReexportsWiring()))}\
|
|
|
418
544
|
for (let index = 0; index < namespaces.length; index += 1) {
|
|
419
545
|
cells[index]['*'] = cell('*', namespaces[index]);
|
|
420
546
|
}
|
|
547
|
+
`;
|
|
421
548
|
|
|
422
|
-
|
|
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
|
+
`;
|
|
423
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 = `\
|
|
424
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}\
|
|
425
633
|
|
|
426
634
|
return cells[cells.length - 1]['*'].get();
|
|
427
|
-
}
|
|
428
|
-
|
|
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
|
+
};
|
|
657
|
+
|
|
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
|
+
};
|
|
429
689
|
|
|
430
|
-
|
|
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);
|
|
431
703
|
};
|
|
432
704
|
|
|
433
705
|
/**
|
|
@@ -435,16 +707,16 @@ ${''.concat(...modules.map(m => m.bundlerKit.getFunctorCall()))}\
|
|
|
435
707
|
* @param {ReadFn} read
|
|
436
708
|
* @param {string} bundleLocation
|
|
437
709
|
* @param {string} moduleLocation
|
|
438
|
-
* @param {
|
|
710
|
+
* @param {BundleOptions} [options]
|
|
439
711
|
*/
|
|
440
|
-
export const
|
|
712
|
+
export const writeScript = async (
|
|
441
713
|
write,
|
|
442
714
|
read,
|
|
443
715
|
bundleLocation,
|
|
444
716
|
moduleLocation,
|
|
445
717
|
options,
|
|
446
718
|
) => {
|
|
447
|
-
const bundleString = await
|
|
719
|
+
const bundleString = await makeScript(read, moduleLocation, options);
|
|
448
720
|
const bundleBytes = textEncoder.encode(bundleString);
|
|
449
721
|
await write(bundleLocation, bundleBytes);
|
|
450
722
|
};
|