feat: call importMetaHook on instantiation if import.meta uttered by module
MODIFY
packages/compartment-mapper/src/bundle.js
packages/compartment-mapper/src/bundle.js
@@ -332,7 +332,7 @@ ${importsCellSetter(__liveExportMap__, index)}\
onceVar: {
${importsCellSetter(__fixedExportMap__, index)}\
},
- metaVar: {
+ meta: {
url: '${packageLocation}'\
},
});

MODIFY
packages/ses/src/compartment-shim.js
packages/ses/src/compartment-shim.js
@@ -215,6 +215,7 @@ export const makeCompartmentConstructor = (
resolveHook,
importHook,
moduleMapHook,
+ importMetaHook,
} = options;
const globalTransforms = [...transforms, ...__shimTransforms__];
@@ -316,6 +317,7 @@ export const makeCompartmentConstructor = (
importHook,
moduleMap,
moduleMapHook,
+ importMetaHook,
moduleRecords,
__shimTransforms__,
deferredExports,

MODIFY
packages/ses/src/module-instance.js
packages/ses/src/module-instance.js
@@ -18,6 +18,7 @@ import {
mapGet,
weakmapGet,
reflectHas,
+ assign,
} from './commons.js';
import { compartmentEvaluate } from './compartment-evaluate.js';
@@ -122,17 +123,23 @@ export const makeModuleInstance = (
moduleRecord,
importedInstances,
) => {
- const { compartment, moduleSpecifier, staticModuleRecord } = moduleRecord;
+ const {
+ compartment,
+ moduleSpecifier,
+ staticModuleRecord,
+ meta: moduleRecordMeta,
+ } = moduleRecord;
const {
reexports: exportAlls = [],
__syncModuleProgram__: functorSource,
__fixedExportMap__: fixedExportMap = {},
__liveExportMap__: liveExportMap = {},
+ __usesImportMeta__: usesImportMeta = false,
} = staticModuleRecord;
const compartmentFields = weakmapGet(privateFields, compartment);
- const { __shimTransforms__ } = compartmentFields;
+ const { __shimTransforms__, importMetaHook } = compartmentFields;
const { exportsProxy, proxiedExports, activate } = getDeferredExports(
compartment,
@@ -158,15 +165,12 @@ export const makeModuleInstance = (
// both initialize and update live bindings.
const liveVar = create(null);
- const metaVar = create(null);
- try {
- metaVar.url = new URL(
- moduleSpecifier,
- compartmentFields.name || '.',
- ).toString();
- } catch (e) {
- metaVar.url = moduleSpecifier;
- console.error('Wont URL:', moduleSpecifier, compartmentFields.name);
+ const meta = create(null);
+ if (moduleRecordMeta) {
+ assign(meta, moduleRecordMeta);
+ }
+ if (usesImportMeta && importMetaHook) {
+ importMetaHook(meta);
}
// {_localName_: [{get, set, notify}]} used to merge all the export updaters.
@@ -449,7 +453,7 @@ export const makeModuleInstance = (
imports: freeze(imports),
onceVar: freeze(onceVar),
liveVar: freeze(liveVar),
- metaVar: freeze(metaVar),
+ meta,
}),
);
} catch (e) {

MODIFY
packages/ses/src/module-load.js
packages/ses/src/module-load.js
@@ -63,6 +63,7 @@ const loadRecord = async (
pendingJobs,
moduleLoads,
errors,
+ meta,
) => {
const { resolveHook, moduleRecords } = weakmapGet(
compartmentPrivateFields,
@@ -80,6 +81,7 @@ const loadRecord = async (
staticModuleRecord,
moduleSpecifier,
resolvedImports,
+ meta,
});
// Enqueue jobs to load this module's shallow dependencies.
@@ -181,6 +183,7 @@ const loadWithoutErrorAnnotation = async (
compartment: aliasCompartment = compartment,
specifier: aliasSpecifier = moduleSpecifier,
record: aliasModuleRecord,
+ meta,
} = staticModuleRecord;
const aliasRecord = await loadRecord(
@@ -192,6 +195,7 @@ const loadWithoutErrorAnnotation = async (
pendingJobs,
moduleLoads,
errors,
+ meta,
);
mapSet(moduleRecords, moduleSpecifier, aliasRecord);
return aliasRecord;
@@ -317,7 +321,7 @@ export const load = async (
`Failed to load module ${q(moduleSpecifier)} in package ${q(
compartmentName,
)} (${errors.length} underlying failures: ${arrayJoin(
- arrayMap(errors, error => error.message),
+ arrayMap(errors, error => error.stack),
', ',
)}`,
);

MODIFY
packages/ses/test/node.js
packages/ses/test/node.js
@@ -63,10 +63,21 @@ export const makeLocator = root => {
};
};
+const wrapImporterWithMeta = (importer, meta) => async specifier => {
+ const moduleRecord = await importer(specifier);
+ return { record: moduleRecord, meta };
+};
+
// makeNodeImporter conveniently curries makeImporter with a Node.js style
// locator and static file retriever.
-export const makeNodeImporter = sources => compartmentLocation => {
+export const makeNodeImporter = sources => (
+ compartmentLocation,
+ options = {},
+) => {
const locate = makeLocator(compartmentLocation);
const retrieve = makeStaticRetriever(sources);
+ if (options.meta) {
+ return wrapImporterWithMeta(makeImporter(locate, retrieve), options.meta);
+ }
return makeImporter(locate, retrieve);
};

MODIFY
packages/ses/test/test-import.js
packages/ses/test/test-import.js
@@ -557,7 +557,35 @@ test('child compartments are modular', async t => {
t.is(meaning, 42, 'child compartments have module support');
});
-test.only('import.meta.url points to the module', async t => {
+test('import.meta populated from module record', async t => {
+ t.plan(1);
+
+ const makeImportHook = makeNodeImporter({
+ 'https://example.com/index.js': `
+ const myloc = import.meta.url;
+ export default myloc;
+ `,
+ });
+
+ const compartment = new Compartment(
+ { t },
+ {},
+ {
+ name: 'https://example.com',
+ resolveHook: resolveNode,
+ importHook: makeImportHook('https://example.com', {
+ meta: { url: 'https://example.com/index.js' },
+ }),
+ },
+ );
+
+ const {
+ namespace: { default: metaurl },
+ } = await compartment.import('./index.js');
+ t.is(metaurl, 'https://example.com/index.js');
+});
+
+test('importMetaHook', async t => {
t.plan(1);
const makeImportHook = makeNodeImporter({
@@ -574,13 +602,45 @@ test.only('import.meta.url points to the module', async t => {
name: 'https://example.com',
resolveHook: resolveNode,
importHook: makeImportHook('https://example.com'),
+ importMetaHook: meta => {
+ meta.url = 'https://example.com/index.js';
+ },
},
);
const {
- namespace:{
- default: metaurl
- }
+ namespace: { default: metaurl },
} = await compartment.import('./index.js');
t.is(metaurl, 'https://example.com/index.js');
});
+test('importMetaHook and meta from record', async t => {
+ t.plan(1);
+
+ const makeImportHook = makeNodeImporter({
+ 'https://example.com/index.js': `
+ const myloc = import.meta.url;
+ export default myloc;
+ `,
+ });
+
+ const compartment = new Compartment(
+ { t },
+ {},
+ {
+ name: 'https://example.com',
+ resolveHook: resolveNode,
+ importHook: makeImportHook('https://example.com', {
+ meta: { url: 'https://example.com/index.js' },
+ }),
+ importMetaHook: meta => {
+ meta.url += '?foo';
+ meta.isStillMutableHopefully = 1;
+ },
+ },
+ );
+
+ const {
+ namespace: { default: metaurl },
+ } = await compartment.import('./index.js');
+ t.is(metaurl, 'https://example.com/index.js?foo');
+});

MODIFY
packages/static-module-record/src/babelPlugin.js
packages/static-module-record/src/babelPlugin.js
@@ -47,6 +47,7 @@ function makeModulePlugins(options) {
importDecls,
importSources,
liveExportMap,
+ importMetaProperties,
} = options;
if (sourceType !== 'module') {
@@ -310,8 +311,15 @@ function makeModulePlugins(options) {
const moduleVisitor = (doAnalyze, doTransform) => ({
MetaProperty(path) {
- if(path.node.meta.name==='import' && doTransform){
- path.replaceWithMultiple([replace(path.node, t.identifier(h.HIDDEN_META))]);
+ if (path.node.meta.name === 'import') {
+ if (doAnalyze && path.parentPath.isMemberExpression()) {
+ importMetaProperties.add(path.parentPath.node.property.name);
+ }
+ if (doTransform) {
+ path.replaceWithMultiple([
+ replace(path.node, hiddenIdentifier(h.HIDDEN_META)),
+ ]);
+ }
}
},
// We handle all the import and export productions.

MODIFY
packages/static-module-record/src/hidden.js
packages/static-module-record/src/hidden.js
@@ -5,7 +5,7 @@ export const HIDDEN_IMPORT = `${HIDDEN_PREFIX}import`;
export const HIDDEN_IMPORT_SELF = `${HIDDEN_PREFIX}importSelf`;
export const HIDDEN_IMPORTS = `${HIDDEN_PREFIX}imports`;
export const HIDDEN_ONCE = `${HIDDEN_PREFIX}once`;
-export const HIDDEN_META = `${HIDDEN_PREFIX}meta`;
+export const HIDDEN_META = `${HIDDEN_PREFIX}import_meta`;
export const HIDDEN_LIVE = `${HIDDEN_PREFIX}live`;
export const HIDDEN_IDENTIFIERS = [
HIDDEN_A,

MODIFY
packages/static-module-record/src/static-module-record.js
packages/static-module-record/src/static-module-record.js
@@ -51,6 +51,7 @@ export function StaticModuleRecord(source, url) {
liveExportMap,
fixedExportMap,
exportAlls,
+ importMetaProperties,
} = analyzeModule({ string: source, url });
this.imports = freeze([...keys(imports)].sort());
this.exports = freeze(
@@ -60,5 +61,8 @@ export function StaticModuleRecord(source, url) {
this.__syncModuleProgram__ = functorSource;
this.__liveExportMap__ = liveExportMap;
this.__fixedExportMap__ = fixedExportMap;
+ this.__usesImportMeta__ = importMetaProperties.length > 0;
+ // useful for knowing if resolve or any other expensive features are used
+ this.__usesImportMetaProperties__ = importMetaProperties;
freeze(this);
}

MODIFY
packages/static-module-record/src/transform-analyze.js
packages/static-module-record/src/transform-analyze.js
@@ -38,7 +38,6 @@ const makeTransformSource = (babel = null) => {
compact: true,
verbatim: true,
});
- // console.log(`transformed`, transformedCode);
return transformedCode;
};
@@ -65,6 +64,8 @@ const makeCreateStaticRecord = transformSource =>
hoistedDecls: [],
importSources: Object.create(null),
importDecls: [],
+ // enables passing import.meta usage hints up.
+ importMetaProperties: new Set(),
};
if (moduleSource.startsWith('#!')) {
// Comment out the shebang lines.
@@ -113,7 +114,7 @@ const makeCreateStaticRecord = transformSource =>
imports: ${h.HIDDEN_IMPORTS}, \
liveVar: ${h.HIDDEN_LIVE}, \
onceVar: ${h.HIDDEN_ONCE}, \
- metaVar: ${h.HIDDEN_META}, \
+ meta: ${h.HIDDEN_META}, \
}) => { \
${preamble} \
${scriptSource}
@@ -123,12 +124,14 @@ const makeCreateStaticRecord = transformSource =>
if (url) {
functorSource += `//# sourceURL=${url}\n`;
}
-
const moduleAnalysis = freeze({
exportAlls: freeze(sourceOptions.exportAlls),
imports: freeze(sourceOptions.imports),
liveExportMap: freeze(sourceOptions.liveExportMap),
fixedExportMap: freeze(sourceOptions.fixedExportMap),
+ importMetaProperties: freeze(
+ Array.from(sourceOptions.importMetaProperties),
+ ),
functorSource,
});
return moduleAnalysis;
@@ -198,7 +201,6 @@ export const makeModuleTransformer = (babel, importer) => {
? maybeSource.slice(0, -1)
: maybeSource;
- // console.log(ss.isExpr, `generated`, src, `from`, ast);
return { ...ss, endowments, src: actualSource };
},
};

MODIFY
packages/static-module-record/test/test-static-module-record.js
packages/static-module-record/test/test-static-module-record.js
@@ -152,7 +152,7 @@ function initialize(t, source, options = {}) {
imports: updateImports,
liveVar: liveUpdaters,
onceVar: onceUpdaters,
- metaVar: { url: 'file://meta.url' },
+ meta: { url: 'file://meta.url' },
});
return { record, namespace, log, updaters };

feat: call importMetaHook on instantiation if import.meta uttered by module