Skip to content

Commit 4134759

Browse files
authored
fix(async-rewriter): properly process dynamic import() MONGOSH-1062 (#1155)
As noted in the ticket, this only fixes the problem partially, because using `import()` from a function that is then called from another line in the REPL can crash the process (depending on garbage collection) due to a Node.js ESM bug.
1 parent 7a83ec8 commit 4134759

File tree

3 files changed

+23
-6
lines changed

3 files changed

+23
-6
lines changed

packages/async-rewriter2/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"main": "./lib/index.js",
66
"scripts": {
77
"pretest": "npm run compile-ts",
8-
"test": "mocha -r \"../../scripts/import-expansions.js\" --timeout 60000 -r ts-node/register \"./{src,lib}/**/*.spec.ts\"",
8+
"test": "mocha --experimental-vm-modules -r \"../../scripts/import-expansions.js\" --timeout 60000 -r ts-node/register \"./{src,lib}/**/*.spec.ts\"",
99
"test-ci": "node ../../scripts/run-if-package-requested.js npm test",
1010
"lint": "eslint --report-unused-disable-directives \"./{src,test}/**/*.{js,ts,tsx}\"",
1111
"check": "npm run lint && depcheck --skip-missing=true",

packages/async-rewriter2/src/async-writer-babel.spec.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,17 @@ describe('AsyncWriter', () => {
6161
return runUntranspiledCode(transpiled, context);
6262
};
6363
runUntranspiledCode = (code: string, context?: any) => {
64-
return vm.runInContext(code, context ?? ctx);
64+
return vm.runInContext(code, context ?? ctx, {
65+
async importModuleDynamically(specifier: string) {
66+
if (specifier === 'forty-two') {
67+
const mod = new (vm as any).SourceTextModule('export const value = 42');
68+
await mod.link(() => {});
69+
await mod.evaluate();
70+
return mod;
71+
}
72+
throw new Error('Module not found');
73+
}
74+
} as any);
6575
};
6676
});
6777

@@ -377,6 +387,11 @@ describe('AsyncWriter', () => {
377387
})()`)).to.equal('yes');
378388
});
379389

390+
it('works with import', async() => {
391+
const ret = runTranspiledCode('(async() => (await import("forty-two")).value)()');
392+
expect(await ret).to.equal(42);
393+
});
394+
380395
it('allows re-declaring variables in separate snippets', () => {
381396
expect(runTranspiledCode('const a = 42;')).to.equal(undefined);
382397
expect(runTranspiledCode('const a = 43;')).to.equal(undefined);

packages/async-rewriter2/src/stages/transform-maybe-await.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -415,12 +415,14 @@ export default ({ types: t }: { types: typeof BabelTypes }): babel.PluginObj<{ f
415415
// If we ever do, replacing all function calls with
416416
// Function.prototype.call.call(fn, target, ...originalArgs) might be
417417
// a feasible solution.
418-
// Additionally, skip calls to 'eval', since literal calls to it
419-
// have semantics that are different from calls to an expressio that
420-
// evaluates to 'eval'.
418+
// Additionally, skip calls to 'eval' and 'import', since literal
419+
// calls to those have semantics that are different from calls to
420+
// an expression that evaluates to 'eval'/'import'.
421421
if (path.parentPath.isCallExpression() &&
422422
path.key === 'callee' &&
423-
(path.isMemberExpression() || (path.isIdentifier() && path.node.name === 'eval'))) {
423+
(path.isMemberExpression() ||
424+
path.isImport() ||
425+
(path.isIdentifier() && path.node.name === 'eval'))) {
424426
return;
425427
}
426428

0 commit comments

Comments
 (0)