@@ -58,6 +58,7 @@ const {
58
58
ArrayPrototypeSome,
59
59
ArrayPrototypeSort,
60
60
ArrayPrototypeSplice,
61
+ ArrayPrototypeToString,
61
62
ArrayPrototypeUnshift,
62
63
Boolean,
63
64
Error,
@@ -104,7 +105,12 @@ const {
104
105
const {
105
106
isIdentifierStart,
106
107
isIdentifierChar,
108
+ parse : acornParse ,
107
109
} = require ( 'internal/deps/acorn/acorn/dist/acorn' ) ;
110
+
111
+
112
+ const acornWalk = require ( 'internal/deps/acorn/acorn-walk/dist/walk' ) ;
113
+
108
114
const {
109
115
decorateErrorStack,
110
116
isError,
@@ -223,6 +229,29 @@ module.paths = CJSModule._nodeModulePaths(module.filename);
223
229
const writer = ( obj ) => inspect ( obj , writer . options ) ;
224
230
writer . options = { ...inspect . defaultOptions , showProxy : true } ;
225
231
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
+
226
255
function REPLServer ( prompt ,
227
256
stream ,
228
257
eval_ ,
@@ -283,13 +312,13 @@ function REPLServer(prompt,
283
312
get : pendingDeprecation ?
284
313
deprecate ( ( ) => this . input ,
285
314
'repl.inputStream and repl.outputStream are deprecated. ' +
286
- 'Use repl.input and repl.output instead' ,
315
+ 'Use repl.input and repl.output instead' ,
287
316
'DEP0141' ) :
288
317
( ) => this . input ,
289
318
set : pendingDeprecation ?
290
319
deprecate ( ( val ) => this . input = val ,
291
320
'repl.inputStream and repl.outputStream are deprecated. ' +
292
- 'Use repl.input and repl.output instead' ,
321
+ 'Use repl.input and repl.output instead' ,
293
322
'DEP0141' ) :
294
323
( val ) => this . input = val ,
295
324
enumerable : false ,
@@ -300,13 +329,13 @@ function REPLServer(prompt,
300
329
get : pendingDeprecation ?
301
330
deprecate ( ( ) => this . output ,
302
331
'repl.inputStream and repl.outputStream are deprecated. ' +
303
- 'Use repl.input and repl.output instead' ,
332
+ 'Use repl.input and repl.output instead' ,
304
333
'DEP0141' ) :
305
334
( ) => this . output ,
306
335
set : pendingDeprecation ?
307
336
deprecate ( ( val ) => this . output = val ,
308
337
'repl.inputStream and repl.outputStream are deprecated. ' +
309
- 'Use repl.input and repl.output instead' ,
338
+ 'Use repl.input and repl.output instead' ,
310
339
'DEP0141' ) :
311
340
( val ) => this . output = val ,
312
341
enumerable : false ,
@@ -344,9 +373,9 @@ function REPLServer(prompt,
344
373
// instance and that could trigger the `MaxListenersExceededWarning`.
345
374
process . prependListener ( 'newListener' , ( event , listener ) => {
346
375
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 ) ) {
350
379
// Throw an error so that the event will not be added and the current
351
380
// domain takes over. That way the user is notified about the error
352
381
// and the current code evaluation is stopped, just as any other code
@@ -363,8 +392,8 @@ function REPLServer(prompt,
363
392
const savedRegExMatches = [ '' , '' , '' , '' , '' , '' , '' , '' , '' , '' ] ;
364
393
const sep = '\u0000\u0000\u0000' ;
365
394
const regExMatcher = new RegExp ( `^${ sep } (.*)${ sep } (.*)${ sep } (.*)${ sep } (.*)` +
366
- `${ sep } (.*)${ sep } (.*)${ sep } (.*)${ sep } (.*)` +
367
- `${ sep } (.*)$` ) ;
395
+ `${ sep } (.*)${ sep } (.*)${ sep } (.*)${ sep } (.*)` +
396
+ `${ sep } (.*)$` ) ;
368
397
369
398
eval_ = eval_ || defaultEval ;
370
399
@@ -417,7 +446,7 @@ function REPLServer(prompt,
417
446
// an expression. Note that if the above condition changes,
418
447
// lib/internal/repl/utils.js needs to be changed to match.
419
448
if ( RegExpPrototypeExec ( / ^ \s * { / , code ) !== null &&
420
- RegExpPrototypeExec ( / ; \s * $ / , code ) === null ) {
449
+ RegExpPrototypeExec ( / ; \s * $ / , code ) === null ) {
421
450
code = `(${ StringPrototypeTrim ( code ) } )\n` ;
422
451
wrappedCmd = true ;
423
452
}
@@ -492,7 +521,7 @@ function REPLServer(prompt,
492
521
while ( true ) {
493
522
try {
494
523
if ( self . replMode === module . exports . REPL_MODE_STRICT &&
495
- RegExpPrototypeExec ( / ^ \s * $ / , code ) === null ) {
524
+ RegExpPrototypeExec ( / ^ \s * $ / , code ) === null ) {
496
525
// "void 0" keeps the repl from returning "use strict" as the result
497
526
// value for statements and declarations that don't return a value.
498
527
code = `'use strict'; void 0;\n${ code } ` ;
@@ -684,7 +713,7 @@ function REPLServer(prompt,
684
713
'module' ;
685
714
if ( StringPrototypeIncludes ( e . message , importErrorStr ) ) {
686
715
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 ) ) ;
688
717
e . stack = SideEffectFreeRegExpPrototypeSymbolReplace (
689
718
/ S y n t a x E r r o r : .* \n / ,
690
719
e . stack ,
@@ -712,7 +741,7 @@ function REPLServer(prompt,
712
741
}
713
742
714
743
if ( options [ kStandaloneREPL ] &&
715
- process . listenerCount ( 'uncaughtException' ) !== 0 ) {
744
+ process . listenerCount ( 'uncaughtException' ) !== 0 ) {
716
745
process . nextTick ( ( ) => {
717
746
process . emit ( 'uncaughtException' , e ) ;
718
747
self . clearBufferedCommand ( ) ;
@@ -729,7 +758,7 @@ function REPLServer(prompt,
729
758
errStack = '' ;
730
759
ArrayPrototypeForEach ( lines , ( line ) => {
731
760
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 ) {
733
762
errStack += writer . options . breakLength >= line . length ?
734
763
`Uncaught ${ line } ` :
735
764
`Uncaught:\n${ line } ` ;
@@ -875,8 +904,8 @@ function REPLServer(prompt,
875
904
// display next prompt and return.
876
905
if ( trimmedCmd ) {
877
906
if ( StringPrototypeCharAt ( trimmedCmd , 0 ) === '.' &&
878
- StringPrototypeCharAt ( trimmedCmd , 1 ) !== '.' &&
879
- NumberIsNaN ( NumberParseFloat ( trimmedCmd ) ) ) {
907
+ StringPrototypeCharAt ( trimmedCmd , 1 ) !== '.' &&
908
+ NumberIsNaN ( NumberParseFloat ( trimmedCmd ) ) ) {
880
909
const matches = RegExpPrototypeExec ( / ^ \. ( [ ^ \s ] + ) \s * ( .* ) $ / , trimmedCmd ) ;
881
910
const keyword = matches && matches [ 1 ] ;
882
911
const rest = matches && matches [ 2 ] ;
@@ -901,10 +930,10 @@ function REPLServer(prompt,
901
930
ReflectApply ( _memory , self , [ cmd ] ) ;
902
931
903
932
if ( e && ! self [ kBufferedCommandSymbol ] &&
904
- StringPrototypeStartsWith ( StringPrototypeTrim ( cmd ) , 'npm ' ) ) {
933
+ StringPrototypeStartsWith ( StringPrototypeTrim ( cmd ) , 'npm ' ) ) {
905
934
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' ) ;
908
937
self . displayPrompt ( ) ;
909
938
return ;
910
939
}
@@ -929,11 +958,11 @@ function REPLServer(prompt,
929
958
930
959
// If we got any output - print it (if no error)
931
960
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 ) ) {
937
966
if ( ! self . underscoreAssigned ) {
938
967
self . last = ret ;
939
968
}
@@ -984,7 +1013,7 @@ function REPLServer(prompt,
984
1013
if ( ! self . editorMode || ! self . terminal ) {
985
1014
// Before exiting, make sure to clear the line.
986
1015
if ( key . ctrl && key . name === 'd' &&
987
- self . cursor === 0 && self . line . length === 0 ) {
1016
+ self . cursor === 0 && self . line . length === 0 ) {
988
1017
self . clearLine ( ) ;
989
1018
}
990
1019
clearPreview ( key ) ;
@@ -1181,7 +1210,7 @@ const importRE = /\bimport\s*\(\s*['"`](([\w@./:-]+\/)?(?:[\w@./:-]*))(?![^'"`])
1181
1210
const requireRE = / \b r e q u i r e \s * \( \s * [ ' " ` ] ( ( [ \w @ . / : - ] + \/ ) ? (?: [ \w @ . / : - ] * ) ) (? ! [ ^ ' " ` ] ) $ / ;
1182
1211
const fsAutoCompleteRE = / f s (?: \. p r o m i s e s ) ? \. \s * [ a - z ] [ a - z A - Z ] + \( \s * [ " ' ] ( .* ) / ;
1183
1212
const simpleExpressionRE =
1184
- / (?: [ \w $ ' " ` [ { ( ] (?: \w | \$ | [ ' " ` \] } ) ] ) * \? ? \. ) * [ a - z A - Z _ $ ] (?: \w | \$ ) * \? ? \. ? $ / ;
1213
+ / (?: [ \w $ ' " ` [ { ( ] (?: \w | \$ | [ ' " ` \] } ) ] ) * \? ? \. ) * [ a - z A - Z _ $ ] (?: \w | \$ ) * \? ? \. ? $ / ;
1185
1214
const versionedFileNamesRe = / - \d + \. \d + / ;
1186
1215
1187
1216
function isIdentifier ( str ) {
@@ -1337,15 +1366,15 @@ function complete(line, callback) {
1337
1366
const dirents = gracefulReaddir ( dir , { withFileTypes : true } ) || [ ] ;
1338
1367
ArrayPrototypeForEach ( dirents , ( dirent ) => {
1339
1368
if ( RegExpPrototypeExec ( versionedFileNamesRe , dirent . name ) !== null ||
1340
- dirent . name === '.npm' ) {
1369
+ dirent . name === '.npm' ) {
1341
1370
// Exclude versioned names that 'npm' installs.
1342
1371
return ;
1343
1372
}
1344
1373
const extension = path . extname ( dirent . name ) ;
1345
1374
const base = StringPrototypeSlice ( dirent . name , 0 , - extension . length ) ;
1346
1375
if ( ! dirent . isDirectory ( ) ) {
1347
1376
if ( StringPrototypeIncludes ( extensions , extension ) &&
1348
- ( ! subdir || base !== 'index' ) ) {
1377
+ ( ! subdir || base !== 'index' ) ) {
1349
1378
ArrayPrototypePush ( group , `${ subdir } ${ base } ` ) ;
1350
1379
}
1351
1380
return ;
@@ -1398,7 +1427,7 @@ function complete(line, callback) {
1398
1427
ArrayPrototypeForEach ( dirents , ( dirent ) => {
1399
1428
const { name } = dirent ;
1400
1429
if ( RegExpPrototypeExec ( versionedFileNamesRe , name ) !== null ||
1401
- name === '.npm' ) {
1430
+ name === '.npm' ) {
1402
1431
// Exclude versioned names that 'npm' installs.
1403
1432
return ;
1404
1433
}
@@ -1431,20 +1460,20 @@ function complete(line, callback) {
1431
1460
1432
1461
ArrayPrototypePush ( completionGroups , _builtinLibs , nodeSchemeBuiltinLibs ) ;
1433
1462
} else if ( ( match = RegExpPrototypeExec ( fsAutoCompleteRE , line ) ) !== null &&
1434
- this . allowBlockingCompletions ) {
1463
+ this . allowBlockingCompletions ) {
1435
1464
( { 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 ''
1446
1475
} else if ( line . length === 0 ||
1447
- RegExpPrototypeExec ( / \w | \. | \$ / , line [ line . length - 1 ] ) !== null ) {
1476
+ RegExpPrototypeExec ( / \w | \. | \$ / , line [ line . length - 1 ] ) !== null ) {
1448
1477
const { 0 : match } = RegExpPrototypeExec ( simpleExpressionRE , line ) || [ '' ] ;
1449
1478
if ( line . length !== 0 && ! match ) {
1450
1479
completionGroupsLoaded ( ) ;
@@ -1495,7 +1524,7 @@ function complete(line, callback) {
1495
1524
try {
1496
1525
let p ;
1497
1526
if ( ( typeof obj === 'object' && obj !== null ) ||
1498
- typeof obj === 'function' ) {
1527
+ typeof obj === 'function' ) {
1499
1528
memberGroups . push ( filteredOwnPropertyNames ( obj ) ) ;
1500
1529
p = ObjectGetPrototypeOf ( obj ) ;
1501
1530
} else {
0 commit comments