feat(ses): support RedirectStaticModuleInterface with implicit record
MODIFY
packages/ses/index.d.ts
packages/ses/index.d.ts
@@ -64,9 +64,10 @@ export type FinalStaticModuleType =
| ThirdPartyStaticModuleInterface;
export interface RedirectStaticModuleInterface {
- record: FinalStaticModuleType;
specifier: string;
+ record?: FinalStaticModuleType;
importMeta?: any;
+ compartment?: Compartment;
}
export type StaticModuleType =

MODIFY
packages/ses/src/module-load.js
packages/ses/src/module-load.js
@@ -175,7 +175,16 @@ const loadWithoutErrorAnnotation = async (
)} in compartment ${q(compartment.name)}`;
}
+ // check if record is a RedirectStaticModuleInterface
+ if (staticModuleRecord.specifier !== undefined) {
+ // check if this redirect with an explicit record
if (staticModuleRecord.record !== undefined) {
+ // ensure expected record shape
+ if (staticModuleRecord.compartment !== undefined) {
+ throw new TypeError(
+ 'Cannot redirect to an explicit record with a specified compartment',
+ );
+ }
const {
compartment: aliasCompartment = compartment,
specifier: aliasSpecifier = moduleSpecifier,
@@ -198,6 +207,34 @@ const loadWithoutErrorAnnotation = async (
return aliasRecord;
}
+ // check if this redirect with an explicit compartment
+ if (staticModuleRecord.compartment !== undefined) {
+ // ensure expected record shape
+ if (staticModuleRecord.importMeta !== undefined) {
+ throw new TypeError(
+ 'Cannot redirect to an implicit record with a specified importMeta',
+ );
+ }
+ // Behold: recursion.
+ // eslint-disable-next-line no-use-before-define
+ const aliasRecord = await memoizedLoadWithErrorAnnotation(
+ compartmentPrivateFields,
+ moduleAliases,
+ staticModuleRecord.compartment,
+ staticModuleRecord.specifier,
+ pendingJobs,
+ moduleLoads,
+ errors,
+ );
+ mapSet(moduleRecords, moduleSpecifier, aliasRecord);
+ return aliasRecord;
+ }
+
+ throw new TypeError(
+ 'Unnexpected RedirectStaticModuleInterface record shape',
+ );
+ }
+
return loadRecord(
compartmentPrivateFields,
moduleAliases,

MODIFY
packages/ses/test/node.js
packages/ses/test/node.js
@@ -65,7 +65,8 @@ export const makeLocator = root => {
const wrapImporterWithMeta = (importer, importMeta) => async specifier => {
const moduleRecord = await importer(specifier);
- return { record: moduleRecord, importMeta };
+ // return a RedirectStaticModuleInterface with an explicit record
+ return { specifier, record: moduleRecord, importMeta };
};
// makeNodeImporter conveniently curries makeImporter with a Node.js style

MODIFY
packages/ses/test/test-import-gauntlet.js
packages/ses/test/test-import-gauntlet.js
@@ -326,3 +326,43 @@ test.failing('reexport with implicit default syntax', async t => {
await compartment.import('./main.js');
});
+
+test('importHook returning a RedirectStaticModuleInterface with a specified compartment', async t => {
+ t.plan(1);
+
+ const makeImportHook = makeNodeImporter({
+ 'https://example.com/alias-target.js': `
+ const meaning = 42;
+ export { meaning as default };
+ `,
+ 'https://example.com/main.js': `
+ import meaning from './meaning.js';
+ t.is(meaning, 42);
+ `,
+ });
+ const importHook = makeImportHook('https://example.com');
+ const aliasRegistry = {
+ './meaning.js': './alias-target.js',
+ };
+
+ const compartment = new Compartment(
+ { t },
+ {},
+ {
+ resolveHook: resolveNode,
+ importHook: async moduleSpecifier => {
+ const aliasTarget = aliasRegistry[moduleSpecifier];
+ if (aliasTarget !== undefined) {
+ const record = {
+ specifier: aliasTarget,
+ compartment,
+ };
+ return record;
+ }
+ return importHook(moduleSpecifier);
+ },
+ },
+ );
+
+ await compartment.import('./main.js');
+});

MODIFY
packages/ses/test/test-import.js
packages/ses/test/test-import.js
@@ -443,6 +443,7 @@ test('module alias', async t => {
for (const candidate of candidates) {
// eslint-disable-next-line no-await-in-loop
const record = await wrappedImportHook(candidate).catch(_ => undefined);
+ // return a RedirectStaticModuleInterface with an explicit record
if (record !== undefined) {
return { record, specifier };
}
@@ -502,6 +503,7 @@ test('import reflexive module alias', async t => {
// eslint-disable-next-line no-await-in-loop
const record = await wrappedImportHook(candidate).catch(_ => undefined);
if (record !== undefined) {
+ // return a RedirectStaticModuleInterface with an explicit record
return { record, specifier };
}
}

feat(ses): support RedirectStaticModuleInterface with implicit record