Skip to content

Commit 84fe811

Browse files
hemanthRafaelGSS
authored andcommitted
repl: display dynamic import variant in static import error messages
Enhance the REPL message for static import error message. ``` > import {foo, bar} from 'moo'; import {foo, bar} from 'moo'; ^^^^^^ Uncaught: SyntaxError: .* dynamic import: const {foo,bar} = await import('moo'); ``` PR-URL: #48129 Reviewed-By: Antoine du Hamel <[email protected]>
1 parent e60b6de commit 84fe811

File tree

2 files changed

+95
-2
lines changed

2 files changed

+95
-2
lines changed

lib/repl.js

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
'use strict';
4444

4545
const {
46+
ArrayPrototypeAt,
4647
ArrayPrototypeFilter,
4748
ArrayPrototypeFindIndex,
4849
ArrayPrototypeForEach,
@@ -62,6 +63,7 @@ const {
6263
Boolean,
6364
Error,
6465
FunctionPrototypeBind,
66+
JSONStringify,
6567
MathMaxApply,
6668
NumberIsNaN,
6769
NumberParseFloat,
@@ -104,7 +106,9 @@ const {
104106
const {
105107
isIdentifierStart,
106108
isIdentifierChar,
109+
parse: acornParse,
107110
} = require('internal/deps/acorn/acorn/dist/acorn');
111+
const acornWalk = require('internal/deps/acorn/acorn-walk/dist/walk');
108112
const {
109113
decorateErrorStack,
110114
isError,
@@ -223,6 +227,28 @@ module.paths = CJSModule._nodeModulePaths(module.filename);
223227
const writer = (obj) => inspect(obj, writer.options);
224228
writer.options = { ...inspect.defaultOptions, showProxy: true };
225229

230+
// Converts static import statement to dynamic import statement
231+
const toDynamicImport = (codeLine) => {
232+
let dynamicImportStatement = '';
233+
const ast = acornParse(codeLine, { __proto__: null, sourceType: 'module', ecmaVersion: 'latest' });
234+
acornWalk.ancestor(ast, {
235+
ImportDeclaration(node) {
236+
const awaitDynamicImport = `await import(${JSONStringify(node.source.value)});`;
237+
if (node.specifiers.length === 0) {
238+
dynamicImportStatement += awaitDynamicImport;
239+
} else if (node.specifiers.length === 1 && node.specifiers[0].type === 'ImportNamespaceSpecifier') {
240+
dynamicImportStatement += `const ${node.specifiers[0].local.name} = ${awaitDynamicImport}`;
241+
} else {
242+
const importNames = ArrayPrototypeJoin(ArrayPrototypeMap(node.specifiers, ({ local, imported }) =>
243+
(local.name === imported?.name ? local.name : `${imported?.name ?? 'default'}: ${local.name}`),
244+
), ', ');
245+
dynamicImportStatement += `const { ${importNames} } = ${awaitDynamicImport}`;
246+
}
247+
},
248+
});
249+
return dynamicImportStatement;
250+
};
251+
226252
function REPLServer(prompt,
227253
stream,
228254
eval_,
@@ -684,7 +710,7 @@ function REPLServer(prompt,
684710
'module';
685711
if (StringPrototypeIncludes(e.message, importErrorStr)) {
686712
e.message = 'Cannot use import statement inside the Node.js ' +
687-
'REPL, alternatively use dynamic import';
713+
'REPL, alternatively use dynamic import: ' + toDynamicImport(ArrayPrototypeAt(self.lines, -1));
688714
e.stack = SideEffectFreeRegExpPrototypeSymbolReplace(
689715
/SyntaxError:.*\n/,
690716
e.stack,

test/parallel/test-repl.js

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -818,7 +818,74 @@ const tcpTests = [
818818
kArrow,
819819
'',
820820
'Uncaught:',
821-
/^SyntaxError: .* dynamic import/,
821+
'SyntaxError: Cannot use import statement inside the Node.js REPL, \
822+
alternatively use dynamic import: const { default: comeOn } = await import("fhqwhgads");',
823+
]
824+
},
825+
{
826+
send: 'import { export1, export2 } from "module-name"',
827+
expect: [
828+
kSource,
829+
kArrow,
830+
'',
831+
'Uncaught:',
832+
'SyntaxError: Cannot use import statement inside the Node.js REPL, \
833+
alternatively use dynamic import: const { export1, export2 } = await import("module-name");',
834+
]
835+
},
836+
{
837+
send: 'import * as name from "module-name";',
838+
expect: [
839+
kSource,
840+
kArrow,
841+
'',
842+
'Uncaught:',
843+
'SyntaxError: Cannot use import statement inside the Node.js REPL, \
844+
alternatively use dynamic import: const name = await import("module-name");',
845+
]
846+
},
847+
{
848+
send: 'import "module-name";',
849+
expect: [
850+
kSource,
851+
kArrow,
852+
'',
853+
'Uncaught:',
854+
'SyntaxError: Cannot use import statement inside the Node.js REPL, \
855+
alternatively use dynamic import: await import("module-name");',
856+
]
857+
},
858+
{
859+
send: 'import { export1 as localName1, export2 } from "bar";',
860+
expect: [
861+
kSource,
862+
kArrow,
863+
'',
864+
'Uncaught:',
865+
'SyntaxError: Cannot use import statement inside the Node.js REPL, \
866+
alternatively use dynamic import: const { export1: localName1, export2 } = await import("bar");',
867+
]
868+
},
869+
{
870+
send: 'import alias from "bar";',
871+
expect: [
872+
kSource,
873+
kArrow,
874+
'',
875+
'Uncaught:',
876+
'SyntaxError: Cannot use import statement inside the Node.js REPL, \
877+
alternatively use dynamic import: const { default: alias } = await import("bar");',
878+
]
879+
},
880+
{
881+
send: 'import alias, {namedExport} from "bar";',
882+
expect: [
883+
kSource,
884+
kArrow,
885+
'',
886+
'Uncaught:',
887+
'SyntaxError: Cannot use import statement inside the Node.js REPL, \
888+
alternatively use dynamic import: const { default: alias, namedExport } = await import("bar");',
822889
]
823890
},
824891
];

0 commit comments

Comments
 (0)