Skip to content

Commit 87b8b4d

Browse files
committed
fix(compartment-mapper,bundle-source): async parser support
This fixes the half-implemented type defs and support for async parsers by introducing `AsyncParserImplementation`. We needed sync-and-async-specific parse-mappers in `map-parser.js` and some type guards. A sync-parser-specific `SyncParserForLanguage` is introduced as well.
1 parent 88a16f0 commit 87b8b4d

7 files changed

Lines changed: 271 additions & 237 deletions

File tree

.changeset/fuzzy-hornets-shout.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'@endo/compartment-mapper': patch
3+
'@endo/bundle-source': patch
4+
---
5+
6+
Fixes poorly-defined support for asynchronous parsers.

packages/bundle-source/src/endo.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { defaultParserForLanguage as transparentParserForLanguage } from '@endo/
99
import tsBlankSpace from 'ts-blank-space';
1010

1111
/** @import {Language} from '@endo/compartment-mapper/node-powers.js' */
12+
/** @import {AsyncParserImplementation} from '@endo/compartment-mapper' */
1213
/** @import {BundlingKit, BundlingKitIO, BundlingKitOptions, ModuleTransformsLike, ParserForLanguageLike, SourceMapDescriptor} from './types.js' */
1314

1415
const textEncoder = new TextEncoder();
@@ -189,8 +190,9 @@ export const makeBundlingKit = (
189190
};
190191
}
191192

193+
/** @type {AsyncParserImplementation} */
192194
const mtsParser = {
193-
parse(
195+
async parse(
194196
sourceBytes,
195197
specifier,
196198
moduleLocation,
@@ -212,8 +214,9 @@ export const makeBundlingKit = (
212214
synchronous: false,
213215
};
214216

217+
/** @type {AsyncParserImplementation} */
215218
const ctsParser = {
216-
parse(
219+
async parse(
217220
sourceBytes,
218221
specifier,
219222
moduleLocation,

packages/compartment-mapper/src/import-hook.js

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,15 @@
99
*
1010
* @module
1111
*/
12-
12+
import { asyncTrampoline, syncTrampoline } from '@endo/trampoline';
13+
import { resolve } from './node-module-specifier.js';
14+
import {
15+
attenuateModuleHook,
16+
enforcePolicyByModule,
17+
enforcePackagePolicyByCanonicalName,
18+
} from './policy.js';
19+
import { ATTENUATORS_COMPARTMENT } from './policy-format.js';
20+
import { unpackReadPowers } from './powers.js';
1321
/**
1422
* @import {
1523
* ImportHook,
@@ -43,18 +51,19 @@
4351
* CanonicalName,
4452
* LocalModuleSource,
4553
* ModuleSourceHook,
54+
* ParseFn,
55+
* AsyncParseFn,
4656
* } from './types.js'
4757
*/
4858

49-
import { asyncTrampoline, syncTrampoline } from '@endo/trampoline';
50-
import { resolve } from './node-module-specifier.js';
51-
import {
52-
attenuateModuleHook,
53-
enforcePolicyByModule,
54-
enforcePackagePolicyByCanonicalName,
55-
} from './policy.js';
56-
import { ATTENUATORS_COMPARTMENT } from './policy-format.js';
57-
import { unpackReadPowers } from './powers.js';
59+
/**
60+
* Type guard that narrows a `ParseFn | AsyncParseFn` to `ParseFn` by checking
61+
* for the `isSyncParser` flag.
62+
*
63+
* @param {ParseFn | AsyncParseFn} parse
64+
* @returns {parse is ParseFn}
65+
*/
66+
const isSyncParseFn = parse => 'isSyncParser' in parse && !!parse.isSyncParser;
5867

5968
// q, as in quote, for quoting strings in error messages.
6069
const { quote: q } = assert;
@@ -324,8 +333,7 @@ const executeLocalModuleSourceHook = (
324333
* {@link StaticModuleType} for a particular {@link CompartmentDescriptor} (or
325334
* `undefined`).
326335
*
327-
* Supports both {@link SyncChooseModuleDescriptorOperators sync} and
328-
* {@link AsyncChooseModuleDescriptorOperators async} operators.
336+
* Supports both sync and async operators.
329337
*
330338
* Used by both {@link makeImportNowHookMaker} and {@link makeImportHookMaker}.
331339
*
@@ -839,13 +847,14 @@ export function makeImportNowHookMaker(
839847
}
840848
};
841849

842-
if (!('isSyncParser' in parse)) {
850+
if (!isSyncParseFn(parse)) {
843851
return function impossibleTransformImportNowHook() {
844852
throw new Error(
845853
'Dynamic requires are only possible with synchronous parsers and no asynchronous module transforms in options',
846854
);
847855
};
848856
}
857+
const /** @type {ParseFn} */ syncParse = parse;
849858

850859
const compartmentDescriptor =
851860
compartmentDescriptors[packageLocation] || create(null);
@@ -924,7 +933,7 @@ export function makeImportNowHookMaker(
924933
},
925934
{
926935
maybeRead: maybeReadNow,
927-
parse,
936+
parse: syncParse,
928937
shouldDeferError,
929938
},
930939
);

packages/compartment-mapper/src/link.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -404,8 +404,7 @@ export const link = (
404404
/** @type {ShouldDeferError} */
405405
const shouldDeferError = language => {
406406
if (language && has(parserForLanguage, language)) {
407-
return /** @type {ParserImplementation} */ (parserForLanguage[language])
408-
.heuristicImports;
407+
return parserForLanguage[language].heuristicImports;
409408
} else {
410409
// If language is undefined or there's no parser, the error we could consider deferring is surely related to
411410
// that. Nothing to throw here.

0 commit comments

Comments
 (0)