@endo/compartment-mapper 1.2.1 → 1.3.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 (67) hide show
  1. package/archive-lite.d.ts.map +1 -0
  2. package/archive-parsers.d.ts.map +1 -0
  3. package/archive.d.ts.map +1 -0
  4. package/bundle.d.ts.map +1 -0
  5. package/capture-lite.d.ts.map +1 -0
  6. package/import-archive-lite.d.ts.map +1 -0
  7. package/import-archive-parsers.d.ts.map +1 -0
  8. package/import-archive.d.ts.map +1 -0
  9. package/import-lite.d.ts.map +1 -0
  10. package/import-parsers.d.ts.map +1 -0
  11. package/import.d.ts.map +1 -0
  12. package/index.d.ts.map +1 -0
  13. package/node-modules.d.ts.map +1 -0
  14. package/node-powers.d.ts +1 -1
  15. package/node-powers.d.ts.map +1 -0
  16. package/node-powers.js +5 -1
  17. package/package.json +15 -11
  18. package/src/compartment-map.d.ts +1 -1
  19. package/src/compartment-map.d.ts.map +1 -1
  20. package/src/compartment-map.js +1 -1
  21. package/src/import-hook.d.ts +14 -1
  22. package/src/import-hook.d.ts.map +1 -1
  23. package/src/import-hook.js +493 -144
  24. package/src/import-lite.d.ts +20 -3
  25. package/src/import-lite.d.ts.map +1 -1
  26. package/src/import-lite.js +137 -15
  27. package/src/import.d.ts +45 -5
  28. package/src/import.d.ts.map +1 -1
  29. package/src/import.js +52 -6
  30. package/src/link.d.ts +2 -11
  31. package/src/link.d.ts.map +1 -1
  32. package/src/link.js +76 -154
  33. package/src/map-parser.d.ts +4 -0
  34. package/src/map-parser.d.ts.map +1 -0
  35. package/src/map-parser.js +339 -0
  36. package/src/node-modules.d.ts +2 -5
  37. package/src/node-modules.d.ts.map +1 -1
  38. package/src/node-modules.js +12 -5
  39. package/src/node-powers.d.ts +29 -23
  40. package/src/node-powers.d.ts.map +1 -1
  41. package/src/node-powers.js +102 -25
  42. package/src/parse-archive-cjs.js +2 -1
  43. package/src/parse-archive-mjs.js +2 -1
  44. package/src/parse-bytes.d.ts.map +1 -1
  45. package/src/parse-bytes.js +2 -6
  46. package/src/parse-cjs-shared-export-wrapper.d.ts.map +1 -1
  47. package/src/parse-cjs-shared-export-wrapper.js +23 -6
  48. package/src/parse-cjs.js +3 -2
  49. package/src/parse-json.d.ts +5 -3
  50. package/src/parse-json.d.ts.map +1 -1
  51. package/src/parse-json.js +9 -9
  52. package/src/parse-mjs.js +2 -1
  53. package/src/parse-pre-cjs.js +3 -2
  54. package/src/parse-pre-mjs.js +2 -1
  55. package/src/parse-text.d.ts.map +1 -1
  56. package/src/parse-text.js +2 -6
  57. package/src/policy.d.ts +21 -14
  58. package/src/policy.d.ts.map +1 -1
  59. package/src/policy.js +56 -37
  60. package/src/powers.d.ts +8 -1
  61. package/src/powers.d.ts.map +1 -1
  62. package/src/powers.js +60 -10
  63. package/src/search.d.ts.map +1 -1
  64. package/src/search.js +1 -2
  65. package/src/types.d.ts +343 -21
  66. package/src/types.d.ts.map +1 -1
  67. package/src/types.js +369 -22
package/src/link.js CHANGED
@@ -9,27 +9,34 @@
9
9
  // @ts-check
10
10
 
11
11
  /** @import {ModuleMapHook} from 'ses' */
12
- /** @import {ParseFn, ParserForLanguage} from './types.js' */
13
- /** @import {ParserImplementation} from './types.js' */
14
- /** @import {ShouldDeferError} from './types.js' */
15
- /** @import {ModuleTransforms} from './types.js' */
16
- /** @import {LanguageForExtension} from './types.js' */
17
- /** @import {ModuleDescriptor} from './types.js' */
18
- /** @import {CompartmentDescriptor} from './types.js' */
19
- /** @import {CompartmentMapDescriptor} from './types.js' */
20
- /** @import {LinkOptions} from './types.js' */
12
+ /**
13
+ * @import {
14
+ * CompartmentDescriptor,
15
+ * CompartmentMapDescriptor,
16
+ * ImportNowHookMaker,
17
+ * LanguageForExtension,
18
+ * LinkOptions,
19
+ * LinkResult,
20
+ * ModuleDescriptor,
21
+ * ParseFn,
22
+ * ParseFnAsync,
23
+ * ParserForLanguage,
24
+ * ParserImplementation,
25
+ * ShouldDeferError,
26
+ * } from './types.js'
27
+ */
21
28
  /** @import {ERef} from '@endo/eventual-send' */
22
29
 
30
+ import { makeMapParsers } from './map-parser.js';
23
31
  import { resolve as resolveFallback } from './node-module-specifier.js';
24
- import { parseExtension } from './extension.js';
25
32
  import {
26
- enforceModulePolicy,
27
33
  ATTENUATORS_COMPARTMENT,
28
34
  attenuateGlobals,
35
+ enforceModulePolicy,
29
36
  makeDeferredAttenuatorsProvider,
30
37
  } from './policy.js';
31
38
 
32
- const { assign, create, entries, freeze, fromEntries } = Object;
39
+ const { assign, create, entries, freeze } = Object;
33
40
  const { hasOwnProperty } = Object.prototype;
34
41
  const { apply } = Reflect;
35
42
  const { allSettled } = Promise;
@@ -52,130 +59,6 @@ const q = JSON.stringify;
52
59
  */
53
60
  const has = (object, key) => apply(hasOwnProperty, object, [key]);
54
61
 
55
- /**
56
- * Decide if extension is clearly indicating a parser/language for a file
57
- *
58
- * @param {string} extension
59
- * @returns {boolean}
60
- */
61
- const extensionImpliesLanguage = extension => extension !== 'js';
62
-
63
- /**
64
- * `makeExtensionParser` produces a `parser` that parses the content of a
65
- * module according to the corresponding module language, given the extension
66
- * of the module specifier and the configuration of the containing compartment.
67
- * We do not yet support import assertions and we do not have a mechanism
68
- * for validating the MIME type of the module content against the
69
- * language implied by the extension or file name.
70
- *
71
- * @param {Record<string, string>} languageForExtension - maps a file extension
72
- * to the corresponding language.
73
- * @param {Record<string, string>} languageForModuleSpecifier - In a rare case,
74
- * the type of a module is implied by package.json and should not be inferred
75
- * from its extension.
76
- * @param {ParserForLanguage} parserForLanguage
77
- * @param {ModuleTransforms} moduleTransforms
78
- * @returns {ParseFn}
79
- */
80
- const makeExtensionParser = (
81
- languageForExtension,
82
- languageForModuleSpecifier,
83
- parserForLanguage,
84
- moduleTransforms,
85
- ) => {
86
- return async (bytes, specifier, location, packageLocation, options) => {
87
- await null;
88
- let language;
89
- const extension = parseExtension(location);
90
-
91
- if (
92
- !extensionImpliesLanguage(extension) &&
93
- has(languageForModuleSpecifier, specifier)
94
- ) {
95
- language = languageForModuleSpecifier[specifier];
96
- } else {
97
- language = languageForExtension[extension] || extension;
98
- }
99
-
100
- let sourceMap;
101
-
102
- if (has(moduleTransforms, language)) {
103
- try {
104
- ({
105
- bytes,
106
- parser: language,
107
- sourceMap,
108
- } = await moduleTransforms[language](
109
- bytes,
110
- specifier,
111
- location,
112
- packageLocation,
113
- {
114
- // At time of writing, sourceMap is always undefined, but keeping
115
- // it here is more resilient if the surrounding if block becomes a
116
- // loop for multi-step transforms.
117
- sourceMap,
118
- },
119
- ));
120
- } catch (err) {
121
- throw Error(
122
- `Error transforming ${q(language)} source in ${q(location)}: ${
123
- err.message
124
- }`,
125
- { cause: err },
126
- );
127
- }
128
- }
129
-
130
- if (!has(parserForLanguage, language)) {
131
- throw Error(
132
- `Cannot parse module ${specifier} at ${location}, no parser configured for the language ${language}`,
133
- );
134
- }
135
- const { parse } = /** @type {ParserImplementation} */ (
136
- parserForLanguage[language]
137
- );
138
- return parse(bytes, specifier, location, packageLocation, {
139
- sourceMap,
140
- ...options,
141
- });
142
- };
143
- };
144
-
145
- /**
146
- * @param {LanguageForExtension} languageForExtension
147
- * @param {Record<string, string>} languageForModuleSpecifier - In a rare case, the type of a module
148
- * is implied by package.json and should not be inferred from its extension.
149
- * @param {ParserForLanguage} parserForLanguage
150
- * @param {ModuleTransforms} moduleTransforms
151
- * @returns {ParseFn}
152
- */
153
- export const mapParsers = (
154
- languageForExtension,
155
- languageForModuleSpecifier,
156
- parserForLanguage,
157
- moduleTransforms = {},
158
- ) => {
159
- const languageForExtensionEntries = [];
160
- const problems = [];
161
- for (const [extension, language] of entries(languageForExtension)) {
162
- if (has(parserForLanguage, language)) {
163
- languageForExtensionEntries.push([extension, language]);
164
- } else {
165
- problems.push(`${q(language)} for extension ${q(extension)}`);
166
- }
167
- }
168
- if (problems.length > 0) {
169
- throw Error(`No parser available for language: ${problems.join(', ')}`);
170
- }
171
- return makeExtensionParser(
172
- fromEntries(languageForExtensionEntries),
173
- languageForModuleSpecifier,
174
- parserForLanguage,
175
- moduleTransforms,
176
- );
177
- };
178
-
179
62
  /**
180
63
  * For a full, absolute module specifier like "dependency",
181
64
  * produce the module specifier in the dependency, like ".".
@@ -328,36 +211,57 @@ const makeModuleMapHook = (
328
211
  return moduleMapHook;
329
212
  };
330
213
 
214
+ /**
215
+ * @type {ImportNowHookMaker}
216
+ */
217
+ const impossibleImportNowHookMaker = () => {
218
+ return function impossibleImportNowHook() {
219
+ throw new Error('Provided read powers do not support dynamic requires');
220
+ };
221
+ };
222
+
331
223
  /**
332
224
  * Assemble a DAG of compartments as declared in a compartment map starting at
333
225
  * the named compartment and building all compartments that it depends upon,
334
226
  * recursively threading the modules exported by one compartment into the
335
227
  * compartment that imports them.
336
- * Returns the root of the compartment DAG.
337
- * Does not load or execute any modules.
338
- * Uses makeImportHook with the given "location" string of each compartment in
339
- * the DAG.
340
- * Passes the given globals and external modules into the root compartment
341
- * only.
342
228
  *
229
+ * - Returns the root of the compartment DAG.
230
+ * - Does not load or execute any modules.
231
+ * - Uses `makeImportHook` with the given "location" string of each compartment
232
+ * in the DAG.
233
+ * - Passes the given globals and external modules into the root compartment
234
+ * only.
235
+ *
236
+ * @param {CompartmentMapDescriptor} compartmentMap
237
+ * @param {LinkOptions} options
238
+ * @returns {LinkResult} the root compartment of the compartment DAG
239
+ */
240
+
241
+ /**
343
242
  * @param {CompartmentMapDescriptor} compartmentMap
344
243
  * @param {LinkOptions} options
244
+ * @returns {LinkResult}
345
245
  */
346
246
  export const link = (
347
247
  { entry, compartments: compartmentDescriptors },
348
- {
248
+ options,
249
+ ) => {
250
+ const {
349
251
  resolve = resolveFallback,
350
252
  makeImportHook,
253
+ makeImportNowHook = impossibleImportNowHookMaker,
351
254
  parserForLanguage: parserForLanguageOption = {},
352
255
  languageForExtension: languageForExtensionOption = {},
353
256
  globals = {},
354
257
  transforms = [],
355
- moduleTransforms = {},
258
+ moduleTransforms,
259
+ syncModuleTransforms,
356
260
  __shimTransforms__ = [],
357
261
  archiveOnly = false,
358
262
  Compartment = defaultCompartment,
359
- },
360
- ) => {
263
+ } = options;
264
+
361
265
  const { compartment: entryCompartmentName } = entry;
362
266
 
363
267
  /** @type {Record<string, Compartment>} */
@@ -382,19 +286,28 @@ export const link = (
382
286
  assign(create(null), parserForLanguageOption),
383
287
  );
384
288
 
289
+ const mapParsers = makeMapParsers({
290
+ parserForLanguage,
291
+ moduleTransforms,
292
+ syncModuleTransforms,
293
+ });
294
+
385
295
  for (const [compartmentName, compartmentDescriptor] of entries(
386
296
  compartmentDescriptors,
387
297
  )) {
388
- // TODO: The default assignments seem to break type inference
389
298
  const {
390
299
  location,
391
300
  name,
392
- modules = create(null),
393
301
  parsers: languageForExtensionOverrides = {},
394
302
  types: languageForModuleSpecifierOverrides = {},
395
- scopes = create(null),
396
303
  } = compartmentDescriptor;
397
304
 
305
+ // this is for retaining the correct type inference about these values
306
+ // without use of `let`
307
+ const { scopes: _scopes, modules: _modules } = compartmentDescriptor;
308
+ const modules = _modules || create(null);
309
+ const scopes = _scopes || create(null);
310
+
398
311
  // Capture the default.
399
312
  // The `moduleMapHook` writes back to the compartment map.
400
313
  compartmentDescriptor.modules = modules;
@@ -412,12 +325,12 @@ export const link = (
412
325
  ),
413
326
  );
414
327
 
415
- const parse = mapParsers(
416
- languageForExtension,
417
- languageForModuleSpecifier,
418
- parserForLanguage,
419
- moduleTransforms,
328
+ // TS is kind of dumb about this, so we can use a type assertion to avoid a
329
+ // pointless ternary.
330
+ const parse = /** @type {ParseFn|ParseFnAsync} */ (
331
+ mapParsers(languageForExtension, languageForModuleSpecifier)
420
332
  );
333
+
421
334
  /** @type {ShouldDeferError} */
422
335
  const shouldDeferError = language => {
423
336
  if (language && has(parserForLanguage, language)) {
@@ -441,6 +354,14 @@ export const link = (
441
354
  shouldDeferError,
442
355
  compartments,
443
356
  });
357
+
358
+ const importNowHook = makeImportNowHook({
359
+ packageLocation: location,
360
+ packageName: name,
361
+ parse,
362
+ compartments,
363
+ });
364
+
444
365
  const moduleMapHook = makeModuleMapHook(
445
366
  compartmentDescriptor,
446
367
  compartments,
@@ -453,6 +374,7 @@ export const link = (
453
374
  name: location,
454
375
  resolveHook,
455
376
  importHook,
377
+ importNowHook,
456
378
  moduleMapHook,
457
379
  transforms,
458
380
  __shimTransforms__,
@@ -0,0 +1,4 @@
1
+ export function makeMapParsers({ parserForLanguage, moduleTransforms, syncModuleTransforms, }: MakeMapParsersOptions): MapParsersFn;
2
+ import type { MakeMapParsersOptions } from './types.js';
3
+ import type { MapParsersFn } from './types.js';
4
+ //# sourceMappingURL=map-parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"map-parser.d.ts","sourceRoot":"","sources":["map-parser.js"],"names":[],"mappings":"AAqSO,+FAHI,qBAAqB,GACnB,YAAY,CA+CxB;2CAxTS,YAAY;kCAAZ,YAAY"}
@@ -0,0 +1,339 @@
1
+ /**
2
+ * Exports {@link makeMapParsers}, which creates a function which matches a
3
+ * module to a parser based on reasons.
4
+ *
5
+ * @module
6
+ */
7
+
8
+ // @ts-check
9
+
10
+ import { syncTrampoline, asyncTrampoline } from '@endo/trampoline';
11
+ import { parseExtension } from './extension.js';
12
+
13
+ /**
14
+ * @import {
15
+ * LanguageForExtension,
16
+ * LanguageForModuleSpecifier,
17
+ * MakeMapParsersOptions,
18
+ * MapParsersFn,
19
+ * ModuleTransform,
20
+ * ModuleTransforms,
21
+ * ParseFn,
22
+ * ParseFnAsync,
23
+ * ParseResult,
24
+ * ParserForLanguage,
25
+ * SyncModuleTransform,
26
+ * SyncModuleTransforms
27
+ * } from './types.js';
28
+ */
29
+
30
+ const { entries, fromEntries, keys, hasOwnProperty, values } = Object;
31
+ const { apply } = Reflect;
32
+ // q, as in quote, for strings in error messages.
33
+ const q = JSON.stringify;
34
+
35
+ /**
36
+ * @param {Record<string, unknown>} object
37
+ * @param {string} key
38
+ * @returns {boolean}
39
+ */
40
+ const has = (object, key) => apply(hasOwnProperty, object, [key]);
41
+
42
+ /**
43
+ * Decide if extension is clearly indicating a parser/language for a file
44
+ *
45
+ * @param {string} extension
46
+ * @returns {boolean}
47
+ */
48
+ const extensionImpliesLanguage = extension => extension !== 'js';
49
+
50
+ /**
51
+ * Produces a `parser` that parses the content of a module according to the
52
+ * corresponding module language, given the extension of the module specifier
53
+ * and the configuration of the containing compartment. We do not yet support
54
+ * import assertions and we do not have a mechanism for validating the MIME type
55
+ * of the module content against the language implied by the extension or file
56
+ * name.
57
+ *
58
+ * @param {boolean} preferSynchronous
59
+ * @param {Record<string, string>} languageForExtension - maps a file extension
60
+ * to the corresponding language.
61
+ * @param {Record<string, string>} languageForModuleSpecifier - In a rare case,
62
+ * the type of a module is implied by package.json and should not be inferred
63
+ * from its extension.
64
+ * @param {ParserForLanguage} parserForLanguage
65
+ * @param {ModuleTransforms} moduleTransforms
66
+ * @param {SyncModuleTransforms} syncModuleTransforms
67
+ * @returns {ParseFnAsync|ParseFn}
68
+ */
69
+ const makeExtensionParser = (
70
+ preferSynchronous,
71
+ languageForExtension,
72
+ languageForModuleSpecifier,
73
+ parserForLanguage,
74
+ moduleTransforms,
75
+ syncModuleTransforms,
76
+ ) => {
77
+ /** @type {Record<string, ModuleTransform | SyncModuleTransform>} */
78
+ let transforms;
79
+
80
+ /**
81
+ * Function returning a generator which executes a parser for a module in either sync or async context.
82
+ *
83
+ * @param {Uint8Array} bytes
84
+ * @param {string} specifier
85
+ * @param {string} location
86
+ * @param {string} packageLocation
87
+ * @param {*} options
88
+ * @returns {Generator<ReturnType<ModuleTransform>|ReturnType<SyncModuleTransform>, ParseResult, Awaited<ReturnType<ModuleTransform>|ReturnType<SyncModuleTransform>>>}
89
+ */
90
+ function* getParserGenerator(
91
+ bytes,
92
+ specifier,
93
+ location,
94
+ packageLocation,
95
+ options,
96
+ ) {
97
+ /** @type {string} */
98
+ let language;
99
+ const extension = parseExtension(location);
100
+
101
+ if (
102
+ !extensionImpliesLanguage(extension) &&
103
+ has(languageForModuleSpecifier, specifier)
104
+ ) {
105
+ language = languageForModuleSpecifier[specifier];
106
+ } else {
107
+ language = languageForExtension[extension] || extension;
108
+ }
109
+
110
+ /** @type {string|undefined} */
111
+ let sourceMap;
112
+
113
+ if (has(transforms, language)) {
114
+ try {
115
+ ({
116
+ bytes,
117
+ parser: language,
118
+ sourceMap,
119
+ } = yield transforms[language](
120
+ bytes,
121
+ specifier,
122
+ location,
123
+ packageLocation,
124
+ {
125
+ // At time of writing, sourceMap is always undefined, but keeping
126
+ // it here is more resilient if the surrounding if block becomes a
127
+ // loop for multi-step transforms.
128
+ sourceMap,
129
+ },
130
+ ));
131
+ } catch (err) {
132
+ throw Error(
133
+ `Error transforming ${q(language)} source in ${q(location)}: ${err.message}`,
134
+ { cause: err },
135
+ );
136
+ }
137
+ }
138
+ if (!has(parserForLanguage, language)) {
139
+ throw Error(
140
+ `Cannot parse module ${specifier} at ${location}, no parser configured for the language ${language}`,
141
+ );
142
+ }
143
+ const { parse } = parserForLanguage[language];
144
+ return parse(bytes, specifier, location, packageLocation, {
145
+ sourceMap,
146
+ ...options,
147
+ });
148
+ }
149
+
150
+ /**
151
+ * @type {ParseFn}
152
+ */
153
+ const syncParser = (bytes, specifier, location, packageLocation, options) => {
154
+ const result = syncTrampoline(
155
+ getParserGenerator,
156
+ bytes,
157
+ specifier,
158
+ location,
159
+ packageLocation,
160
+ options,
161
+ );
162
+ if ('then' in result && typeof result.then === 'function') {
163
+ throw new TypeError(
164
+ 'Sync parser cannot return a Thenable; ensure parser is actually synchronous',
165
+ );
166
+ }
167
+ return result;
168
+ };
169
+ syncParser.isSyncParser = true;
170
+
171
+ /**
172
+ * @type {ParseFnAsync}
173
+ */
174
+ const asyncParser = async (
175
+ bytes,
176
+ specifier,
177
+ location,
178
+ packageLocation,
179
+ options,
180
+ ) => {
181
+ return asyncTrampoline(
182
+ getParserGenerator,
183
+ bytes,
184
+ specifier,
185
+ location,
186
+ packageLocation,
187
+ options,
188
+ );
189
+ };
190
+
191
+ // Unfortunately, typescript was not smart enough to figure out the return
192
+ // type depending on a boolean in arguments, so it has to be
193
+ // ParseFnAsync|ParseFn
194
+ if (preferSynchronous) {
195
+ transforms = syncModuleTransforms;
196
+ return syncParser;
197
+ } else {
198
+ // we can fold syncModuleTransforms into moduleTransforms because
199
+ // async supports sync, but not vice-versa
200
+ transforms = {
201
+ ...syncModuleTransforms,
202
+ ...moduleTransforms,
203
+ };
204
+
205
+ return asyncParser;
206
+ }
207
+ };
208
+
209
+ /**
210
+ * Creates a synchronous parser
211
+ *
212
+ * @overload
213
+ * @param {LanguageForExtension} languageForExtension
214
+ * @param {LanguageForModuleSpecifier} languageForModuleSpecifier - In a rare case,
215
+ * the type of a module is implied by package.json and should not be inferred
216
+ * from its extension.
217
+ * @param {ParserForLanguage} parserForLanguage
218
+ * @param {ModuleTransforms} [moduleTransforms]
219
+ * @param {SyncModuleTransforms} [syncModuleTransforms]
220
+ * @param {true} preferSynchronous If `true`, will create a `ParseFn`
221
+ * @returns {ParseFn}
222
+ */
223
+
224
+ /**
225
+ * Creates an asynchronous parser
226
+ *
227
+ * @overload
228
+ * @param {LanguageForExtension} languageForExtension
229
+ * @param {LanguageForModuleSpecifier} languageForModuleSpecifier - In a rare case,
230
+ * the type of a module is implied by package.json and should not be inferred
231
+ * from its extension.
232
+ * @param {ParserForLanguage} parserForLanguage
233
+ * @param {ModuleTransforms} [moduleTransforms]
234
+ * @param {SyncModuleTransforms} [syncModuleTransforms]
235
+ * @param {false} [preferSynchronous]
236
+ * @returns {ParseFnAsync}
237
+ */
238
+
239
+ /**
240
+ * @param {LanguageForExtension} languageForExtension
241
+ * @param {LanguageForModuleSpecifier} languageForModuleSpecifier - In a rare case,
242
+ * the type of a module is implied by package.json and should not be inferred
243
+ * from its extension.
244
+ * @param {ParserForLanguage} parserForLanguage
245
+ * @param {ModuleTransforms} [moduleTransforms]
246
+ * @param {SyncModuleTransforms} [syncModuleTransforms]
247
+ * @param {boolean} [preferSynchronous] If `true`, will create a `ParseFn`
248
+ * @returns {ParseFnAsync|ParseFn}
249
+ */
250
+ function mapParsers(
251
+ languageForExtension,
252
+ languageForModuleSpecifier,
253
+ parserForLanguage,
254
+ moduleTransforms = {},
255
+ syncModuleTransforms = {},
256
+ preferSynchronous = false,
257
+ ) {
258
+ const languageForExtensionEntries = [];
259
+ const problems = [];
260
+ for (const [extension, language] of entries(languageForExtension)) {
261
+ if (has(parserForLanguage, language)) {
262
+ languageForExtensionEntries.push([extension, language]);
263
+ } else {
264
+ problems.push(`${q(language)} for extension ${q(extension)}`);
265
+ }
266
+ }
267
+ if (problems.length > 0) {
268
+ throw Error(`No parser available for language: ${problems.join(', ')}`);
269
+ }
270
+ return makeExtensionParser(
271
+ preferSynchronous,
272
+ fromEntries(languageForExtensionEntries),
273
+ languageForModuleSpecifier,
274
+ parserForLanguage,
275
+ moduleTransforms,
276
+ syncModuleTransforms,
277
+ );
278
+ }
279
+
280
+ /**
281
+ * Prepares a function to map parsers after verifying whether synchronous
282
+ * behavior is preferred. Synchronous behavior is selected if all parsers are
283
+ * synchronous and no async transforms are provided.
284
+ *
285
+ * _Note:_ The type argument for {@link MapParsersFn} _could_ be inferred from
286
+ * the function arguments _if_ {@link ParserForLanguage} contained only values
287
+ * of type `ParserImplementation & {synchronous: true}` (and also considering
288
+ * the emptiness of `moduleTransforms`); may only be worth the effort if it was
289
+ * causing issues in practice.
290
+ *
291
+ * @param {MakeMapParsersOptions} options
292
+ * @returns {MapParsersFn}
293
+ */
294
+ export const makeMapParsers = ({
295
+ parserForLanguage,
296
+ moduleTransforms,
297
+ syncModuleTransforms,
298
+ }) => {
299
+ /**
300
+ * Async `mapParsers()` function; returned when a non-synchronous parser is
301
+ * present _or_ when `moduleTransforms` is non-empty.
302
+ *
303
+ * @type {MapParsersFn<ParseFnAsync>}
304
+ */
305
+ const asyncParseFn = (languageForExtension, languageForModuleSpecifier) =>
306
+ mapParsers(
307
+ languageForExtension,
308
+ languageForModuleSpecifier,
309
+ parserForLanguage,
310
+ moduleTransforms,
311
+ syncModuleTransforms,
312
+ );
313
+
314
+ if (moduleTransforms && keys(moduleTransforms).length > 0) {
315
+ return asyncParseFn;
316
+ }
317
+
318
+ // all parsers must explicitly be flagged `synchronous` to return a
319
+ // `MapParsersFn<ParseFn>`
320
+ if (values(parserForLanguage).some(({ synchronous }) => !synchronous)) {
321
+ return asyncParseFn;
322
+ }
323
+
324
+ /**
325
+ * Synchronous `mapParsers()` function; returned when all parsers are
326
+ * synchronous and `moduleTransforms` is empty.
327
+ *
328
+ * @type {MapParsersFn<ParseFn>}
329
+ */
330
+ return (languageForExtension, languageForModuleSpecifier) =>
331
+ mapParsers(
332
+ languageForExtension,
333
+ languageForModuleSpecifier,
334
+ parserForLanguage,
335
+ moduleTransforms,
336
+ syncModuleTransforms,
337
+ true,
338
+ );
339
+ };
@@ -1,8 +1,4 @@
1
- export function compartmentMapForNodeModules(readPowers: ReadFn | ReadPowers | MaybeReadPowers, packageLocation: string, conditions: Set<string>, packageDescriptor: object, moduleSpecifier: string, options?: {
2
- dev?: boolean | undefined;
3
- commonDependencies?: object;
4
- policy?: object;
5
- } | undefined): Promise<CompartmentMapDescriptor>;
1
+ export function compartmentMapForNodeModules(readPowers: ReadFn | ReadPowers | MaybeReadPowers, packageLocation: string, conditions: Set<string>, packageDescriptor: object, moduleSpecifier: string, options?: CompartmentMapForNodeModulesOptions | undefined): Promise<CompartmentMapDescriptor>;
6
2
  export function mapNodeModules(readPowers: ReadFn | ReadPowers | MaybeReadPowers, moduleLocation: string, options?: {
7
3
  tags?: Set<string> | undefined;
8
4
  conditions?: Set<string> | undefined;
@@ -49,6 +45,7 @@ export type ReadDescriptorFn = (packageLocation: string) => Promise<object>;
49
45
  import type { ReadFn } from './types.js';
50
46
  import type { ReadPowers } from './types.js';
51
47
  import type { MaybeReadPowers } from './types.js';
48
+ import type { CompartmentMapForNodeModulesOptions } from './types.js';
52
49
  import type { CompartmentMapDescriptor } from './types.js';
53
50
  import type { LanguageForExtension } from './types.js';
54
51
  import type { Language } from './types.js';
@@ -1 +1 @@
1
- {"version":3,"file":"node-modules.d.ts","sourceRoot":"","sources":["node-modules.js"],"names":[],"mappings":"AAivBO,yDAXI,MAAM,GAAG,UAAU,GAAG,eAAe,mBACrC,MAAM,cACN,GAAG,CAAC,MAAM,CAAC,qBACX,MAAM,mBACN,MAAM;;yBAGN,MAAM;aACN,MAAM;gBACJ,OAAO,CAAC,wBAAwB,CAAC,CA+C7C;AAaM,2CAVI,MAAM,GAAG,UAAU,GAAG,eAAe,kBACrC,MAAM;;;;yBAKN,MAAM;aACN,MAAM;gBACJ,OAAO,CAAC,wBAAwB,CAAC,CAmC7C;;;;;;;oBA5yBY,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC;;WAKnB,MAAM;UACN,MAAM;UACN,KAAK,CAAC,MAAM,CAAC;iBACb,KAAK,CAAC,MAAM,CAAC;qBACb,OAAO;qBACP,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;qBACtB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;;;;;yBACtB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;;;;;aAEtB,oBAAoB;;;;;WAEpB,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC;;0CAKzB,MAAM,CAAC,MAAM,EAAE;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAC,CAAC;iDA+E/C,MAAM,KACJ,OAAO,CAAC,MAAM,CAAC;4BAhHF,YAAY;gCACR,YAAY;qCAHP,YAAY;8CAJH,YAAY;0CAEhB,YAAY;8BADxB,YAAY"}
1
+ {"version":3,"file":"node-modules.d.ts","sourceRoot":"","sources":["node-modules.js"],"names":[],"mappings":"AAwvBO,yDARI,MAAM,GAAG,UAAU,GAAG,eAAe,mBACrC,MAAM,cACN,GAAG,CAAC,MAAM,CAAC,qBACX,MAAM,mBACN,MAAM,8DAEJ,OAAO,CAAC,wBAAwB,CAAC,CA+C7C;AAaM,2CAVI,MAAM,GAAG,UAAU,GAAG,eAAe,kBACrC,MAAM;;;;yBAKN,MAAM;aACN,MAAM;gBACJ,OAAO,CAAC,wBAAwB,CAAC,CAmC7C;;;;;;;oBAjzBY,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC;;WAKnB,MAAM;UACN,MAAM;UACN,KAAK,CAAC,MAAM,CAAC;iBACb,KAAK,CAAC,MAAM,CAAC;qBACb,OAAO;qBACP,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;qBACtB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;;;;;yBACtB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;;;;;aAEtB,oBAAoB;;;;;WAEpB,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC;;0CAKzB,MAAM,CAAC,MAAM,EAAE;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAC,CAAC;iDA+E/C,MAAM,KACJ,OAAO,CAAC,MAAM,CAAC;4BAhHF,YAAY;gCACR,YAAY;qCAHP,YAAY;yDAPQ,YAAY;8CAGvB,YAAY;0CAEhB,YAAY;8BADxB,YAAY"}