@@ -58,6 +58,7 @@ const {
5858 ArrayPrototypeSome,
5959 ArrayPrototypeSort,
6060 ArrayPrototypeSplice,
61+ ArrayPrototypeToString,
6162 ArrayPrototypeUnshift,
6263 Boolean,
6364 Error,
@@ -104,7 +105,12 @@ const {
104105const {
105106 isIdentifierStart,
106107 isIdentifierChar,
108+ parse : acornParse ,
107109} = require ( 'internal/deps/acorn/acorn/dist/acorn' ) ;
110+
111+
112+ const acornWalk = require ( 'internal/deps/acorn/acorn-walk/dist/walk' ) ;
113+
108114const {
109115 decorateErrorStack,
110116 isError,
@@ -223,6 +229,29 @@ module.paths = CJSModule._nodeModulePaths(module.filename);
223229const writer = ( obj ) => inspect ( obj , writer . options ) ;
224230writer . options = { ...inspect . defaultOptions , showProxy : true } ;
225231
232+ // Converts static import statement to dynamic import statement
233+ const toDynamicImport = ( codeLine ) => {
234+ let dynamicImportStatement = '' ;
235+ let moduleName = '' ;
236+ const toCamelCase = ( str ) => str . replace ( / [ - _ ] ( \w ) / g, ( _ , c ) => c . toUpperCase ( ) ) ;
237+ const ast = acornParse ( codeLine , { sourceType : 'module' , ecmaVersion : 'latest' } ) ;
238+ acornWalk . ancestor ( ast , {
239+ ImportDeclaration : ( node ) => {
240+ const importedModules = node . source . value ;
241+ const importedSpecifiers = node . specifiers . map ( ( specifier ) => specifier . local . name ) ;
242+ if ( importedSpecifiers . length > 1 ) {
243+ moduleName = `{${ importedSpecifiers . join ( ',' ) } }` ;
244+ } else {
245+ const formattedSpecifiers = importedSpecifiers . length ? ArrayPrototypeToString ( importedSpecifiers ) : '' ;
246+ moduleName = toCamelCase ( formattedSpecifiers || importedModules ) ;
247+ }
248+ dynamicImportStatement += `const ${ moduleName } = await import('${ importedModules } ');` ;
249+ } ,
250+ } ) ;
251+ return dynamicImportStatement ;
252+ } ;
253+
254+
226255function REPLServer ( prompt ,
227256 stream ,
228257 eval_ ,
@@ -283,13 +312,13 @@ function REPLServer(prompt,
283312 get : pendingDeprecation ?
284313 deprecate ( ( ) => this . input ,
285314 'repl.inputStream and repl.outputStream are deprecated. ' +
286- 'Use repl.input and repl.output instead' ,
315+ 'Use repl.input and repl.output instead' ,
287316 'DEP0141' ) :
288317 ( ) => this . input ,
289318 set : pendingDeprecation ?
290319 deprecate ( ( val ) => this . input = val ,
291320 'repl.inputStream and repl.outputStream are deprecated. ' +
292- 'Use repl.input and repl.output instead' ,
321+ 'Use repl.input and repl.output instead' ,
293322 'DEP0141' ) :
294323 ( val ) => this . input = val ,
295324 enumerable : false ,
@@ -300,13 +329,13 @@ function REPLServer(prompt,
300329 get : pendingDeprecation ?
301330 deprecate ( ( ) => this . output ,
302331 'repl.inputStream and repl.outputStream are deprecated. ' +
303- 'Use repl.input and repl.output instead' ,
332+ 'Use repl.input and repl.output instead' ,
304333 'DEP0141' ) :
305334 ( ) => this . output ,
306335 set : pendingDeprecation ?
307336 deprecate ( ( val ) => this . output = val ,
308337 'repl.inputStream and repl.outputStream are deprecated. ' +
309- 'Use repl.input and repl.output instead' ,
338+ 'Use repl.input and repl.output instead' ,
310339 'DEP0141' ) :
311340 ( val ) => this . output = val ,
312341 enumerable : false ,
@@ -344,9 +373,9 @@ function REPLServer(prompt,
344373 // instance and that could trigger the `MaxListenersExceededWarning`.
345374 process . prependListener ( 'newListener' , ( event , listener ) => {
346375 if ( event === 'uncaughtException' &&
347- process . domain &&
348- listener . name !== 'domainUncaughtExceptionClear' &&
349- domainSet . has ( process . domain ) ) {
376+ process . domain &&
377+ listener . name !== 'domainUncaughtExceptionClear' &&
378+ domainSet . has ( process . domain ) ) {
350379 // Throw an error so that the event will not be added and the current
351380 // domain takes over. That way the user is notified about the error
352381 // and the current code evaluation is stopped, just as any other code
@@ -363,8 +392,8 @@ function REPLServer(prompt,
363392 const savedRegExMatches = [ '' , '' , '' , '' , '' , '' , '' , '' , '' , '' ] ;
364393 const sep = '\u0000\u0000\u0000' ;
365394 const regExMatcher = new RegExp ( `^${ sep } (.*)${ sep } (.*)${ sep } (.*)${ sep } (.*)` +
366- `${ sep } (.*)${ sep } (.*)${ sep } (.*)${ sep } (.*)` +
367- `${ sep } (.*)$` ) ;
395+ `${ sep } (.*)${ sep } (.*)${ sep } (.*)${ sep } (.*)` +
396+ `${ sep } (.*)$` ) ;
368397
369398 eval_ = eval_ || defaultEval ;
370399
@@ -417,7 +446,7 @@ function REPLServer(prompt,
417446 // an expression. Note that if the above condition changes,
418447 // lib/internal/repl/utils.js needs to be changed to match.
419448 if ( RegExpPrototypeExec ( / ^ \s * { / , code ) !== null &&
420- RegExpPrototypeExec ( / ; \s * $ / , code ) === null ) {
449+ RegExpPrototypeExec ( / ; \s * $ / , code ) === null ) {
421450 code = `(${ StringPrototypeTrim ( code ) } )\n` ;
422451 wrappedCmd = true ;
423452 }
@@ -492,7 +521,7 @@ function REPLServer(prompt,
492521 while ( true ) {
493522 try {
494523 if ( self . replMode === module . exports . REPL_MODE_STRICT &&
495- RegExpPrototypeExec ( / ^ \s * $ / , code ) === null ) {
524+ RegExpPrototypeExec ( / ^ \s * $ / , code ) === null ) {
496525 // "void 0" keeps the repl from returning "use strict" as the result
497526 // value for statements and declarations that don't return a value.
498527 code = `'use strict'; void 0;\n${ code } ` ;
@@ -684,7 +713,7 @@ function REPLServer(prompt,
684713 'module' ;
685714 if ( StringPrototypeIncludes ( e . message , importErrorStr ) ) {
686715 e . message = 'Cannot use import statement inside the Node.js ' +
687- 'REPL, alternatively use dynamic import' ;
716+ 'REPL, alternatively use dynamic import: ' + toDynamicImport ( self . lines . at ( - 1 ) ) ;
688717 e . stack = SideEffectFreeRegExpPrototypeSymbolReplace (
689718 / S y n t a x E r r o r : .* \n / ,
690719 e . stack ,
@@ -712,7 +741,7 @@ function REPLServer(prompt,
712741 }
713742
714743 if ( options [ kStandaloneREPL ] &&
715- process . listenerCount ( 'uncaughtException' ) !== 0 ) {
744+ process . listenerCount ( 'uncaughtException' ) !== 0 ) {
716745 process . nextTick ( ( ) => {
717746 process . emit ( 'uncaughtException' , e ) ;
718747 self . clearBufferedCommand ( ) ;
@@ -729,7 +758,7 @@ function REPLServer(prompt,
729758 errStack = '' ;
730759 ArrayPrototypeForEach ( lines , ( line ) => {
731760 if ( ! matched &&
732- RegExpPrototypeExec ( / ^ \[ ? ( [ A - Z ] [ a - z 0 - 9 _ ] * ) * E r r o r / , line ) !== null ) {
761+ RegExpPrototypeExec ( / ^ \[ ? ( [ A - Z ] [ a - z 0 - 9 _ ] * ) * E r r o r / , line ) !== null ) {
733762 errStack += writer . options . breakLength >= line . length ?
734763 `Uncaught ${ line } ` :
735764 `Uncaught:\n${ line } ` ;
@@ -875,8 +904,8 @@ function REPLServer(prompt,
875904 // display next prompt and return.
876905 if ( trimmedCmd ) {
877906 if ( StringPrototypeCharAt ( trimmedCmd , 0 ) === '.' &&
878- StringPrototypeCharAt ( trimmedCmd , 1 ) !== '.' &&
879- NumberIsNaN ( NumberParseFloat ( trimmedCmd ) ) ) {
907+ StringPrototypeCharAt ( trimmedCmd , 1 ) !== '.' &&
908+ NumberIsNaN ( NumberParseFloat ( trimmedCmd ) ) ) {
880909 const matches = RegExpPrototypeExec ( / ^ \. ( [ ^ \s ] + ) \s * ( .* ) $ / , trimmedCmd ) ;
881910 const keyword = matches && matches [ 1 ] ;
882911 const rest = matches && matches [ 2 ] ;
@@ -901,10 +930,10 @@ function REPLServer(prompt,
901930 ReflectApply ( _memory , self , [ cmd ] ) ;
902931
903932 if ( e && ! self [ kBufferedCommandSymbol ] &&
904- StringPrototypeStartsWith ( StringPrototypeTrim ( cmd ) , 'npm ' ) ) {
933+ StringPrototypeStartsWith ( StringPrototypeTrim ( cmd ) , 'npm ' ) ) {
905934 self . output . write ( 'npm should be run outside of the ' +
906- 'Node.js REPL, in your normal shell.\n' +
907- '(Press Ctrl+D to exit.)\n' ) ;
935+ 'Node.js REPL, in your normal shell.\n' +
936+ '(Press Ctrl+D to exit.)\n' ) ;
908937 self . displayPrompt ( ) ;
909938 return ;
910939 }
@@ -929,11 +958,11 @@ function REPLServer(prompt,
929958
930959 // If we got any output - print it (if no error)
931960 if ( ! e &&
932- // When an invalid REPL command is used, error message is printed
933- // immediately. We don't have to print anything else. So, only when
934- // the second argument to this function is there, print it.
935- arguments . length === 2 &&
936- ( ! self . ignoreUndefined || ret !== undefined ) ) {
961+ // When an invalid REPL command is used, error message is printed
962+ // immediately. We don't have to print anything else. So, only when
963+ // the second argument to this function is there, print it.
964+ arguments . length === 2 &&
965+ ( ! self . ignoreUndefined || ret !== undefined ) ) {
937966 if ( ! self . underscoreAssigned ) {
938967 self . last = ret ;
939968 }
@@ -984,7 +1013,7 @@ function REPLServer(prompt,
9841013 if ( ! self . editorMode || ! self . terminal ) {
9851014 // Before exiting, make sure to clear the line.
9861015 if ( key . ctrl && key . name === 'd' &&
987- self . cursor === 0 && self . line . length === 0 ) {
1016+ self . cursor === 0 && self . line . length === 0 ) {
9881017 self . clearLine ( ) ;
9891018 }
9901019 clearPreview ( key ) ;
@@ -1181,7 +1210,7 @@ const importRE = /\bimport\s*\(\s*['"`](([\w@./:-]+\/)?(?:[\w@./:-]*))(?![^'"`])
11811210const requireRE = / \b r e q u i r e \s * \( \s * [ ' " ` ] ( ( [ \w @ . / : - ] + \/ ) ? (?: [ \w @ . / : - ] * ) ) (? ! [ ^ ' " ` ] ) $ / ;
11821211const fsAutoCompleteRE = / f s (?: \. p r o m i s e s ) ? \. \s * [ a - z ] [ a - z A - Z ] + \( \s * [ " ' ] ( .* ) / ;
11831212const simpleExpressionRE =
1184- / (?: [ \w $ ' " ` [ { ( ] (?: \w | \$ | [ ' " ` \] } ) ] ) * \? ? \. ) * [ a - z A - Z _ $ ] (?: \w | \$ ) * \? ? \. ? $ / ;
1213+ / (?: [ \w $ ' " ` [ { ( ] (?: \w | \$ | [ ' " ` \] } ) ] ) * \? ? \. ) * [ a - z A - Z _ $ ] (?: \w | \$ ) * \? ? \. ? $ / ;
11851214const versionedFileNamesRe = / - \d + \. \d + / ;
11861215
11871216function isIdentifier ( str ) {
@@ -1337,15 +1366,15 @@ function complete(line, callback) {
13371366 const dirents = gracefulReaddir ( dir , { withFileTypes : true } ) || [ ] ;
13381367 ArrayPrototypeForEach ( dirents , ( dirent ) => {
13391368 if ( RegExpPrototypeExec ( versionedFileNamesRe , dirent . name ) !== null ||
1340- dirent . name === '.npm' ) {
1369+ dirent . name === '.npm' ) {
13411370 // Exclude versioned names that 'npm' installs.
13421371 return ;
13431372 }
13441373 const extension = path . extname ( dirent . name ) ;
13451374 const base = StringPrototypeSlice ( dirent . name , 0 , - extension . length ) ;
13461375 if ( ! dirent . isDirectory ( ) ) {
13471376 if ( StringPrototypeIncludes ( extensions , extension ) &&
1348- ( ! subdir || base !== 'index' ) ) {
1377+ ( ! subdir || base !== 'index' ) ) {
13491378 ArrayPrototypePush ( group , `${ subdir } ${ base } ` ) ;
13501379 }
13511380 return ;
@@ -1398,7 +1427,7 @@ function complete(line, callback) {
13981427 ArrayPrototypeForEach ( dirents , ( dirent ) => {
13991428 const { name } = dirent ;
14001429 if ( RegExpPrototypeExec ( versionedFileNamesRe , name ) !== null ||
1401- name === '.npm' ) {
1430+ name === '.npm' ) {
14021431 // Exclude versioned names that 'npm' installs.
14031432 return ;
14041433 }
@@ -1431,20 +1460,20 @@ function complete(line, callback) {
14311460
14321461 ArrayPrototypePush ( completionGroups , _builtinLibs , nodeSchemeBuiltinLibs ) ;
14331462 } else if ( ( match = RegExpPrototypeExec ( fsAutoCompleteRE , line ) ) !== null &&
1434- this . allowBlockingCompletions ) {
1463+ this . allowBlockingCompletions ) {
14351464 ( { 0 : completionGroups , 1 : completeOn } = completeFSFunctions ( match ) ) ;
1436- // Handle variable member lookup.
1437- // We support simple chained expressions like the following (no function
1438- // calls, etc.). That is for simplicity and also because we *eval* that
1439- // leading expression so for safety (see WARNING above) don't want to
1440- // eval function calls.
1441- //
1442- // foo.bar<|> # completions for 'foo' with filter 'bar'
1443- // spam.eggs.<|> # completions for 'spam.eggs' with filter ''
1444- // foo<|> # all scope vars with filter 'foo'
1445- // foo.<|> # completions for 'foo' with filter ''
1465+ // Handle variable member lookup.
1466+ // We support simple chained expressions like the following (no function
1467+ // calls, etc.). That is for simplicity and also because we *eval* that
1468+ // leading expression so for safety (see WARNING above) don't want to
1469+ // eval function calls.
1470+ //
1471+ // foo.bar<|> # completions for 'foo' with filter 'bar'
1472+ // spam.eggs.<|> # completions for 'spam.eggs' with filter ''
1473+ // foo<|> # all scope vars with filter 'foo'
1474+ // foo.<|> # completions for 'foo' with filter ''
14461475 } else if ( line . length === 0 ||
1447- RegExpPrototypeExec ( / \w | \. | \$ / , line [ line . length - 1 ] ) !== null ) {
1476+ RegExpPrototypeExec ( / \w | \. | \$ / , line [ line . length - 1 ] ) !== null ) {
14481477 const { 0 : match } = RegExpPrototypeExec ( simpleExpressionRE , line ) || [ '' ] ;
14491478 if ( line . length !== 0 && ! match ) {
14501479 completionGroupsLoaded ( ) ;
@@ -1495,7 +1524,7 @@ function complete(line, callback) {
14951524 try {
14961525 let p ;
14971526 if ( ( typeof obj === 'object' && obj !== null ) ||
1498- typeof obj === 'function' ) {
1527+ typeof obj === 'function' ) {
14991528 memberGroups . push ( filteredOwnPropertyNames ( obj ) ) ;
15001529 p = ObjectGetPrototypeOf ( obj ) ;
15011530 } else {
0 commit comments