fix(ptc-runtime-node): preserve native then-export results

This commit is contained in:
_Kerman committed 2026-10-21 13:24:39 +08:00
1 parent c61f117ba0
commit 55cef1caf7
2 files changed
+13 -1

No files matched your search

@@ -1,5 +1,6 @@
/** Adapt runner-local import decisions to Node's VM module callbacks. */
import * as vm from 'node:vm'
import { types } from 'node:util'
import type { ImportAttributes } from 'node:module'
import type { ProgramImportHandler } from '../evaluators/types.ts'
@@ -56,7 +57,10 @@ export class VmModuleImportLoader {
nativeImport ??= vm.compileFunction('return import(specifier, { with: attributes })', ['specifier', 'attributes'], {
filename, importModuleDynamically: vm.constants.USE_MAIN_CONTEXT_DEFAULT_LOADER,
}) as NativeImport
return nativeImport(specifier, attributes)
const value = await nativeImport(specifier, attributes)
if (types.isModuleNamespaceObject(value)) return value
// A native then export can settle to any value; the VM callback still requires a module.
return this.module({ then(resolve: (result: unknown) => void) { resolve(value) } })
}
// Node accepts namespace objects as well as vm.Module; the Node types declare only vm.Module.
return load as vm.DynamicModuleLoader<object>
@@ -125,6 +125,14 @@ it.each(formats)('preserves JavaScript then-export assimilation in %s', async (f
else expect(await e.expression('import("runner:then")')).toBe(42)
})
it.each(['default', 'redirect'] as const)('preserves native then-export results through Script %s loading', async (decision) => {
const specifier = 'data:text/javascript,export function then(resolve) { resolve({ answer() { return 42 } }) }'
const handler = vi.fn((): ProgramImportResult => decision === 'default' ? { type: 'default' } : { type: 'redirect', specifier })
const e = evaluator('script', handler)
expect(await e.expression(`(await import(${JSON.stringify(decision === 'default' ? specifier : 'runner:then')})).answer()`)).toBe(42)
expect(handler).toHaveBeenCalledTimes(1)
})
it('keeps async-function grammar and parameter semantics when imports are intercepted', async () => {
const e = evaluator('function-body', () => ({ type: 'default' }))
e.globals.answer = 42