node/test/parallel/test-vm-module-link.js
Gus Caplan 26eed3e0ed
vm: add import assertion support
PR-URL: https://github.com/nodejs/node/pull/37176
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Michaël Zasso <targos@protonmail.com>
2021-03-23 11:03:18 -05:00

150 lines
3.7 KiB
JavaScript

'use strict';
// Flags: --experimental-vm-modules --harmony-import-assertions
const common = require('../common');
const assert = require('assert');
const { SourceTextModule } = require('vm');
async function simple() {
const foo = new SourceTextModule('export default 5;');
await foo.link(common.mustNotCall());
globalThis.fiveResult = undefined;
const bar = new SourceTextModule('import five from "foo"; fiveResult = five');
assert.deepStrictEqual(bar.dependencySpecifiers, ['foo']);
await bar.link(common.mustCall((specifier, module) => {
assert.strictEqual(module, bar);
assert.strictEqual(specifier, 'foo');
return foo;
}));
await bar.evaluate();
assert.strictEqual(globalThis.fiveResult, 5);
delete globalThis.fiveResult;
}
async function depth() {
const foo = new SourceTextModule('export default 5');
await foo.link(common.mustNotCall());
async function getProxy(parentName, parentModule) {
const mod = new SourceTextModule(`
import ${parentName} from '${parentName}';
export default ${parentName};
`);
await mod.link(common.mustCall((specifier, module) => {
assert.strictEqual(module, mod);
assert.strictEqual(specifier, parentName);
return parentModule;
}));
return mod;
}
const bar = await getProxy('foo', foo);
const baz = await getProxy('bar', bar);
const barz = await getProxy('baz', baz);
await barz.evaluate();
assert.strictEqual(barz.namespace.default, 5);
}
async function circular() {
const foo = new SourceTextModule(`
import getFoo from 'bar';
export let foo = 42;
export default getFoo();
`);
const bar = new SourceTextModule(`
import { foo } from 'foo';
export default function getFoo() {
return foo;
}
`);
await foo.link(common.mustCall(async (specifier, module) => {
if (specifier === 'bar') {
assert.strictEqual(module, foo);
return bar;
}
assert.strictEqual(specifier, 'foo');
assert.strictEqual(module, bar);
assert.strictEqual(foo.status, 'linking');
return foo;
}, 2));
assert.strictEqual(bar.status, 'linked');
await foo.evaluate();
assert.strictEqual(foo.namespace.default, 42);
}
async function circular2() {
const sourceMap = {
'root': `
import * as a from './a.mjs';
import * as b from './b.mjs';
if (!('fromA' in a))
throw new Error();
if (!('fromB' in a))
throw new Error();
if (!('fromA' in b))
throw new Error();
if (!('fromB' in b))
throw new Error();
`,
'./a.mjs': `
export * from './b.mjs';
export let fromA;
`,
'./b.mjs': `
export * from './a.mjs';
export let fromB;
`
};
const moduleMap = new Map();
const rootModule = new SourceTextModule(sourceMap.root, {
identifier: 'vm:root',
});
async function link(specifier, referencingModule) {
if (moduleMap.has(specifier)) {
return moduleMap.get(specifier);
}
const mod = new SourceTextModule(sourceMap[specifier], {
identifier: new URL(specifier, 'file:///').href,
});
moduleMap.set(specifier, mod);
return mod;
}
await rootModule.link(link);
await rootModule.evaluate();
}
async function asserts() {
const m = new SourceTextModule(`
import "foo" assert { n1: 'v1', n2: 'v2' };
`, { identifier: 'm' });
await m.link((s, r, p) => {
assert.strictEqual(s, 'foo');
assert.strictEqual(r.identifier, 'm');
assert.strictEqual(p.assert.n1, 'v1');
assert.strictEqual(p.assert.n2, 'v2');
return new SourceTextModule('');
});
}
const finished = common.mustCall();
(async function main() {
await simple();
await depth();
await circular();
await circular2();
await asserts();
finished();
})().then(common.mustCall());