Skip to content

Commit

Permalink
Merge pull request #1141 from endojs/naugtur-import-meta-url
Browse files Browse the repository at this point in the history
feat: Add support for import.meta
  • Loading branch information
naugtur committed Jun 14, 2022
2 parents c92e02a + b7cd6e7 commit 35d9489
Show file tree
Hide file tree
Showing 20 changed files with 1,054 additions and 76 deletions.
1 change: 1 addition & 0 deletions packages/compartment-mapper/src/bundle.js
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,7 @@ ${importsCellSetter(__liveExportMap__, index)}\
onceVar: {
${importsCellSetter(__fixedExportMap__, index)}\
},
importMeta: {},
});
`,
),
Expand Down
5 changes: 4 additions & 1 deletion packages/ses/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -412,13 +412,16 @@ A compiled static module record has the following shape:
an initialization record and initializes the module.
This property distinguishes this type of module record.
The name implies a future record type that supports top-level await.
- An initialization record has the properties `imports`, `liveVar`, and
- An initialization record has the properties `imports`, `liveVar`, `importMeta` and
`onceVar`.
- `imports` is a function that accepts a map from partial import
module specifiers to maps from names that the corresponding module
exports to notifier functions.
A notifier function accepts an update function and registers
to receive updates for the value exported by the other module.
- `importMeta` is a null-prototype object with keys transferred from `importMeta`
property in the envelope returned by importHook and/or mutated by
calling `importMetaHook(moduleSpecifier, importMeta)`
- `liveVar` is a record that maps names exported by this module
to a function that may be called to initialize or update
the corresponding value in another module.
Expand Down
2 changes: 2 additions & 0 deletions packages/ses/src/compartment-shim.js
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,7 @@ export const makeCompartmentConstructor = (
resolveHook,
importHook,
moduleMapHook,
importMetaHook,
} = options;
const globalTransforms = [...transforms, ...__shimTransforms__];

Expand Down Expand Up @@ -316,6 +317,7 @@ export const makeCompartmentConstructor = (
importHook,
moduleMap,
moduleMapHook,
importMetaHook,
moduleRecords,
__shimTransforms__,
deferredExports,
Expand Down
20 changes: 18 additions & 2 deletions packages/ses/src/module-instance.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
mapGet,
weakmapGet,
reflectHas,
assign,
} from './commons.js';
import { compartmentEvaluate } from './compartment-evaluate.js';

Expand Down Expand Up @@ -122,17 +123,23 @@ export const makeModuleInstance = (
moduleRecord,
importedInstances,
) => {
const { compartment, moduleSpecifier, staticModuleRecord } = moduleRecord;
const {
compartment,
moduleSpecifier,
staticModuleRecord,
importMeta: moduleRecordMeta,
} = moduleRecord;
const {
reexports: exportAlls = [],
__syncModuleProgram__: functorSource,
__fixedExportMap__: fixedExportMap = {},
__liveExportMap__: liveExportMap = {},
__needsImportMeta__: needsImportMeta = false,
} = staticModuleRecord;

const compartmentFields = weakmapGet(privateFields, compartment);

const { __shimTransforms__ } = compartmentFields;
const { __shimTransforms__, importMetaHook } = compartmentFields;

const { exportsProxy, proxiedExports, activate } = getDeferredExports(
compartment,
Expand All @@ -158,6 +165,14 @@ export const makeModuleInstance = (
// both initialize and update live bindings.
const liveVar = create(null);

const importMeta = create(null);
if (moduleRecordMeta) {
assign(importMeta, moduleRecordMeta);
}
if (needsImportMeta && importMetaHook) {
importMetaHook(moduleSpecifier, importMeta);
}

// {_localName_: [{get, set, notify}]} used to merge all the export updaters.
const localGetNotify = create(null);

Expand Down Expand Up @@ -438,6 +453,7 @@ export const makeModuleInstance = (
imports: freeze(imports),
onceVar: freeze(onceVar),
liveVar: freeze(liveVar),
importMeta,
}),
);
} catch (e) {
Expand Down
4 changes: 4 additions & 0 deletions packages/ses/src/module-load.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ const loadRecord = async (
pendingJobs,
moduleLoads,
errors,
importMeta,
) => {
const { resolveHook, moduleRecords } = weakmapGet(
compartmentPrivateFields,
Expand All @@ -80,6 +81,7 @@ const loadRecord = async (
staticModuleRecord,
moduleSpecifier,
resolvedImports,
importMeta,
});

// Enqueue jobs to load this module's shallow dependencies.
Expand Down Expand Up @@ -181,6 +183,7 @@ const loadWithoutErrorAnnotation = async (
compartment: aliasCompartment = compartment,
specifier: aliasSpecifier = moduleSpecifier,
record: aliasModuleRecord,
importMeta,
} = staticModuleRecord;

const aliasRecord = await loadRecord(
Expand All @@ -192,6 +195,7 @@ const loadWithoutErrorAnnotation = async (
pendingJobs,
moduleLoads,
errors,
importMeta,
);
mapSet(moduleRecords, moduleSpecifier, aliasRecord);
return aliasRecord;
Expand Down
13 changes: 12 additions & 1 deletion packages/ses/test/node.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,21 @@ export const makeLocator = root => {
};
};

const wrapImporterWithMeta = (importer, importMeta) => async specifier => {
const moduleRecord = await importer(specifier);
return { record: moduleRecord, importMeta };
};

// 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);
};
88 changes: 88 additions & 0 deletions packages/ses/test/test-import.js
Original file line number Diff line number Diff line change
Expand Up @@ -556,3 +556,91 @@ test('child compartments are modular', async t => {

t.is(meaning, 42, 'child compartments have module support');
});

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({
'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'),
importMetaHook: (_moduleSpecifier, meta) => {
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 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: (_moduleSpecifier, 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');
});
2 changes: 2 additions & 0 deletions packages/static-module-record/DESIGN.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ moduleFunctor({
imports(importedVariableUpdaters) { /* ... */ },
liveVar: exportedVariableUpdaters,
onceVar: exportedConstantEmitters,
importMeta: Object.create(null)
});
```

Expand Down Expand Up @@ -85,6 +86,7 @@ line numbers.
imports: $h_imports,
liveVar: $h_live,
onceVar: $h_once,
importMeta: $h_import_meta,
}) => {
let foo, bar, fizz, buzz, colour;
$h_imports(
Expand Down
1 change: 1 addition & 0 deletions packages/static-module-record/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
"@endo/ses-ava": "^0.2.26",
"ava": "^3.12.1",
"babel-eslint": "^10.0.3",
"benchmark": "^2.1.4",
"c8": "^7.7.3",
"eslint": "^7.32.0",
"eslint-config-airbnb-base": "^14.0.0",
Expand Down
55 changes: 30 additions & 25 deletions packages/static-module-record/src/babelPlugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ function makeModulePlugins(options) {
importDecls,
importSources,
liveExportMap,
importMeta,
} = options;

if (sourceType !== 'module') {
Expand Down Expand Up @@ -85,10 +86,6 @@ function makeModulePlugins(options) {
return node;
};

const prependReplacements = (replacements, node) => {
replacements.unshift(node);
};

const allowedHiddens = new WeakSet();
const rewrittenDecls = new WeakSet();
const hiddenIdentifier = hi => {
Expand Down Expand Up @@ -240,7 +237,7 @@ function makeModulePlugins(options) {
return replacements;
};

const rewriteDeclaration = path => {
const rewriteExportDeclaration = path => {
// Find all the declared identifiers.
if (rewrittenDecls.has(path.node)) {
return;
Expand All @@ -253,31 +250,19 @@ function makeModulePlugins(options) {

// Create the export calls.
const isConst = decl.kind === 'const';
const replacements = rewriteVars(
const additions = rewriteVars(
vids,
isConst,
decl.type === 'FunctionDeclaration'
? 'function'
: !isConst && decl.kind !== 'let',
);

if (replacements.length > 0) {
switch (decl.type) {
case 'VariableDeclaration': {
// We rewrote the declaration.
rewrittenDecls.add(decl);
prependReplacements(replacements, decl);
break;
}
case 'FunctionDeclaration': {
prependReplacements(replacements, decl);
break;
}
default: {
throw TypeError(`Unknown declaration type ${decl.type}`);
}
if (additions.length > 0) {
if (decl.type === 'VariableDeclaration') {
rewrittenDecls.add(decl);
}
path.replaceWithMultiple(replacements);
path.insertAfter(additions);
}
};

Expand Down Expand Up @@ -308,6 +293,21 @@ function makeModulePlugins(options) {
},
};

const importMetaVisitor = {
MetaProperty(path) {
if (
path.node.meta &&
path.node.meta.name === 'import' &&
path.node.property.name === 'meta'
) {
importMeta.present = true;
path.replaceWithMultiple([
replace(path.node, hiddenIdentifier(h.HIDDEN_META)),
]);
}
},
};

const moduleVisitor = (doAnalyze, doTransform) => ({
// We handle all the import and export productions.
ImportDeclaration(path) {
Expand Down Expand Up @@ -456,7 +456,7 @@ function makeModulePlugins(options) {
}
if (doTransform) {
if (topLevelExported[name]) {
rewriteDeclaration(path);
rewriteExportDeclaration(path);
markExport(name);
}
}
Expand All @@ -479,7 +479,7 @@ function makeModulePlugins(options) {
if (doTransform) {
for (const { name } of vids) {
if (topLevelExported[name]) {
rewriteDeclaration(path);
rewriteExportDeclaration(path);
break;
}
}
Expand Down Expand Up @@ -597,7 +597,12 @@ function makeModulePlugins(options) {
},
};
case 1:
return { visitor: moduleVisitor(false, true) };
return {
visitor: {
...moduleVisitor(false, true),
...importMetaVisitor,
},
};
default:
throw TypeError(`Unrecognized module pass ${pass}`);
}
Expand Down
Loading

0 comments on commit 35d9489

Please sign in to comment.