node/test/parallel/test-vm-module-linkmodulerequests-circular.js
Chengzhong Wu 95bef5af88
vm: sync-ify SourceTextModule linkage
Split `module.link(linker)` into two synchronous step
`sourceTextModule.linkRequests()` and
`sourceTextModule.instantiate()`. This allows creating vm modules and
resolving the dependencies in a complete synchronous procedure.

This also makes `syntheticModule.link()` redundant. The link step for a
SyntheticModule is no-op and is already taken care in the constructor
by initializing the binding slots with the given export names.

PR-URL: https://github.com/nodejs/node/pull/59000
Refs: https://github.com/nodejs/node/issues/37648
Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
2025-08-29 12:17:18 +00:00

73 lines
1.8 KiB
JavaScript

'use strict';
// Flags: --experimental-vm-modules --js-source-phase-imports
require('../common');
const assert = require('assert');
const { SourceTextModule } = require('vm');
const test = require('node:test');
test('basic circular linking', 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;
}
`);
foo.linkRequests([bar]);
bar.linkRequests([foo]);
foo.instantiate();
assert.strictEqual(foo.status, 'linked');
assert.strictEqual(bar.status, 'linked');
await foo.evaluate();
assert.strictEqual(foo.namespace.default, 42);
});
test('circular linking graph', 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();
for (const [specifier, source] of Object.entries(sourceMap)) {
moduleMap.set(specifier, new SourceTextModule(source, {
identifier: new URL(specifier, 'file:///').href,
}));
}
for (const mod of moduleMap.values()) {
mod.linkRequests(mod.moduleRequests.map((request) => {
return moduleMap.get(request.specifier);
}));
}
const rootModule = moduleMap.get('root');
rootModule.instantiate();
await rootModule.evaluate();
});