diff --git a/packages/ses/src/module-link.js b/packages/ses/src/module-link.js index 76acce16c7..15da5a7820 100644 --- a/packages/ses/src/module-link.js +++ b/packages/ses/src/module-link.js @@ -76,27 +76,27 @@ function mayBeVirtualModuleSource(moduleSource) { function validateVirtualModuleSource(moduleSource, moduleSpecifier) { const { exports } = moduleSource; isArray(exports) || - Fail`Property 'exports' of a third-party module source must be an array, got ${q( + Fail`Invalid module source: 'exports' of a virtual module source must be an array, got ${q( exports, )}, for module ${q(moduleSpecifier)}`; } function validateModuleSource(moduleSource, moduleSpecifier) { isObject(moduleSource) || - Fail`Module sources must be of type object, got ${q( + Fail`Invalid module source: must be of type object, got ${q( moduleSource, )}, for module ${q(moduleSpecifier)}`; const { imports, exports, reexports = [] } = moduleSource; isArray(imports) || - Fail`Property 'imports' of a module source must be an array, got ${q( + Fail`Invalid module source: 'imports' must be an array, got ${q( imports, )}, for module ${q(moduleSpecifier)}`; isArray(exports) || - Fail`Property 'exports' of a precompiled module source must be an array, got ${q( + Fail`Invalid module source: 'exports' must be an array, got ${q( exports, )}, for module ${q(moduleSpecifier)}`; isArray(reexports) || - Fail`Property 'reexports' of a precompiled module source must be an array if present, got ${q( + Fail`Invalid module source: 'reexports' must be an array if present, got ${q( reexports, )}, for module ${q(moduleSpecifier)}`; } @@ -138,9 +138,7 @@ export const instantiate = ( resolvedImports, ); } else { - throw TypeError( - `importHook must provide a module source, got ${q(moduleSource)}`, - ); + throw TypeError(`Invalid module source, got ${q(moduleSource)}`); } // Memoize. diff --git a/packages/ses/src/module-load.js b/packages/ses/src/module-load.js index acd1a65e33..37b2d18166 100644 --- a/packages/ses/src/module-load.js +++ b/packages/ses/src/module-load.js @@ -6,11 +6,13 @@ import { arrayJoin, arrayMap, arrayPush, + arraySome, create, freeze, generatorNext, generatorThrow, getOwnPropertyNames, + isArray, isObject, mapGet, mapHas, @@ -85,14 +87,23 @@ const loadModuleSource = ( moduleLoads, importMeta, ) => { - const { resolveHook } = weakmapGet(compartmentPrivateFields, compartment); + const { resolveHook, name: compartmentName } = weakmapGet( + compartmentPrivateFields, + compartment, + ); + + const { imports } = moduleSource; + if ( + !isArray(imports) || + arraySome(imports, specifier => typeof specifier !== 'string') + ) { + throw makeError( + X`Invalid module source: 'imports' must be an array of strings, got ${imports} for module ${q(moduleSpecifier)} of compartment ${q(compartmentName)}`, + ); + } // resolve all imports relative to this referrer module. - const resolvedImports = resolveAll( - moduleSource.imports, - resolveHook, - moduleSpecifier, - ); + const resolvedImports = resolveAll(imports, resolveHook, moduleSpecifier); const moduleRecord = freeze({ compartment, moduleSource, diff --git a/packages/ses/test/module-map.test.js b/packages/ses/test/module-map.test.js index 8fd233db7f..77ac020a08 100644 --- a/packages/ses/test/module-map.test.js +++ b/packages/ses/test/module-map.test.js @@ -40,6 +40,77 @@ test('module map primed with module source descriptor with virtual module source t.is(index.default, 42); }); +test('module map primed with module source descriptor with no-imports virtual module source', async t => { + const compartment = new Compartment({ + modules: { + './index.js': { + source: {}, + }, + }, + resolveHook: specifier => specifier, + __noNamespaceBox__: true, + __options__: true, + }); + await t.throwsAsync(() => compartment.import('./index.js'), { + message: /Invalid module source: 'imports' must be an array/, + }); +}); + +test('module map primed with module source descriptor with imports-with-non-string virtual module source', async t => { + const compartment = new Compartment({ + modules: { + './index.js': { + source: { + imports: [1], + }, + }, + }, + resolveHook: specifier => specifier, + __noNamespaceBox__: true, + __options__: true, + }); + await t.throwsAsync(() => compartment.import('./index.js'), { + message: /Invalid module source: 'imports' must be an array of strings/, + }); +}); + +test('module map primed with module source descriptor with no-exports virtual module source', async t => { + const compartment = new Compartment({ + modules: { + './index.js': { + source: { + imports: [], + }, + }, + }, + resolveHook: specifier => specifier, + __noNamespaceBox__: true, + __options__: true, + }); + await t.throwsAsync(() => compartment.import('./index.js'), { + message: /Invalid module source: 'exports' must be an array/, + }); +}); + +test('module map primed with module source descriptor with no-execute virtual module source', async t => { + const compartment = new Compartment({ + modules: { + './index.js': { + source: { + imports: [], + exports: [], + }, + }, + }, + resolveHook: specifier => specifier, + __noNamespaceBox__: true, + __options__: true, + }); + await t.throwsAsync(() => compartment.import('./index.js'), { + message: /Invalid module source/, + }); +}); + test('module map primed with parent compartment module source descriptor with string reference to parent compartment', async t => { const parent = new Compartment({ modules: {