@@ -1046,7 +1046,7 @@ REPLServer.prototype.turnOffEditorMode = deprecate(
1046
1046
'REPLServer.turnOffEditorMode() is deprecated' ,
1047
1047
'DEP0078' ) ;
1048
1048
1049
- const requireRE = / \b r e q u i r e \s * \( [ ' " ] ( ( [ \w @ . / - ] + \/ ) ? (?: [ \w @ . / - ] * ) ) / ;
1049
+ const requireRE = / \b r e q u i r e \s * \( \s * [ ' " ` ] ( ( [ \w @ . / - ] + \/ ) ? (?: [ \w @ . / - ] * ) ) (? ! [ ^ ' " ` ] ) $ / ;
1050
1050
const fsAutoCompleteRE = / f s (?: \. p r o m i s e s ) ? \. \s * [ a - z ] [ a - z A - Z ] + \( \s * [ " ' ] ( .* ) / ;
1051
1051
const simpleExpressionRE =
1052
1052
/ (?: [ a - z A - Z _ $ ] (?: \w | \$ ) * \. ) * [ a - z A - Z _ $ ] (?: \w | \$ ) * \. ? $ / ;
@@ -1094,8 +1094,13 @@ REPLServer.prototype.complete = function() {
1094
1094
this . completer . apply ( this , arguments ) ;
1095
1095
} ;
1096
1096
1097
- // TODO: Native module names should be auto-resolved.
1098
- // That improves the auto completion.
1097
+ function gracefulOperation ( fn , args , alternative ) {
1098
+ try {
1099
+ return fn ( ...args ) ;
1100
+ } catch {
1101
+ return alternative ;
1102
+ }
1103
+ }
1099
1104
1100
1105
// Provide a list of completions for the given leading text. This is
1101
1106
// given to the readline interface for handling tab completion.
@@ -1117,26 +1122,25 @@ function complete(line, callback) {
1117
1122
1118
1123
// REPL commands (e.g. ".break").
1119
1124
let filter ;
1120
- let match = line . match ( / ^ \s * \. ( \w * ) $ / ) ;
1121
- if ( match ) {
1125
+ if ( / ^ \s * \. ( \w * ) $ / . test ( line ) ) {
1122
1126
completionGroups . push ( ObjectKeys ( this . commands ) ) ;
1123
- completeOn = match [ 1 ] ;
1124
- if ( match [ 1 ] . length ) {
1125
- filter = match [ 1 ] ;
1127
+ completeOn = line . match ( / ^ \s * \. ( \w * ) $ / ) [ 1 ] ;
1128
+ if ( completeOn . length ) {
1129
+ filter = completeOn ;
1126
1130
}
1127
1131
1128
1132
completionGroupsLoaded ( ) ;
1129
- } else if ( match = line . match ( requireRE ) ) {
1133
+ } else if ( requireRE . test ( line ) ) {
1130
1134
// require('...<Tab>')
1131
- const exts = ObjectKeys ( this . context . require . extensions ) ;
1132
- const indexRe = new RegExp ( '^index(?:' + exts . map ( regexpEscape ) . join ( '|' ) +
1133
- ')$ ') ;
1135
+ const extensions = ObjectKeys ( this . context . require . extensions ) ;
1136
+ const indexes = extensions . map ( ( extension ) => `index ${ extension } ` ) ;
1137
+ indexes . push ( 'package.json' , 'index ') ;
1134
1138
const versionedFileNamesRe = / - \d + \. \d + / ;
1135
1139
1140
+ const match = line . match ( requireRE ) ;
1136
1141
completeOn = match [ 1 ] ;
1137
1142
const subdir = match [ 2 ] || '' ;
1138
- filter = match [ 1 ] ;
1139
- let dir , files , subfiles , isDirectory ;
1143
+ filter = completeOn ;
1140
1144
group = [ ] ;
1141
1145
let paths = [ ] ;
1142
1146
@@ -1150,41 +1154,34 @@ function complete(line, callback) {
1150
1154
paths = module . paths . concat ( CJSModule . globalPaths ) ;
1151
1155
}
1152
1156
1153
- for ( let i = 0 ; i < paths . length ; i ++ ) {
1154
- dir = path . resolve ( paths [ i ] , subdir ) ;
1155
- try {
1156
- files = fs . readdirSync ( dir ) ;
1157
- } catch {
1158
- continue ;
1159
- }
1160
- for ( let f = 0 ; f < files . length ; f ++ ) {
1161
- const name = files [ f ] ;
1162
- const ext = path . extname ( name ) ;
1163
- const base = name . slice ( 0 , - ext . length ) ;
1164
- if ( versionedFileNamesRe . test ( base ) || name === '.npm' ) {
1157
+ for ( let dir of paths ) {
1158
+ dir = path . resolve ( dir , subdir ) ;
1159
+ const dirents = gracefulOperation (
1160
+ fs . readdirSync ,
1161
+ [ dir , { withFileTypes : true } ] ,
1162
+ [ ]
1163
+ ) ;
1164
+ for ( const dirent of dirents ) {
1165
+ if ( versionedFileNamesRe . test ( dirent . name ) || dirent . name === '.npm' ) {
1165
1166
// Exclude versioned names that 'npm' installs.
1166
1167
continue ;
1167
1168
}
1168
- const abs = path . resolve ( dir , name ) ;
1169
- try {
1170
- isDirectory = fs . statSync ( abs ) . isDirectory ( ) ;
1171
- } catch {
1169
+ const extension = path . extname ( dirent . name ) ;
1170
+ const base = dirent . name . slice ( 0 , - extension . length ) ;
1171
+ if ( ! dirent . isDirectory ( ) ) {
1172
+ if ( extensions . includes ( extension ) && ( ! subdir || base !== 'index' ) ) {
1173
+ group . push ( `${ subdir } ${ base } ` ) ;
1174
+ }
1172
1175
continue ;
1173
1176
}
1174
- if ( isDirectory ) {
1175
- group . push ( subdir + name + '/' ) ;
1176
- try {
1177
- subfiles = fs . readdirSync ( abs ) ;
1178
- } catch {
1179
- continue ;
1177
+ group . push ( `${ subdir } ${ dirent . name } /` ) ;
1178
+ const absolute = path . resolve ( dir , dirent . name ) ;
1179
+ const subfiles = gracefulOperation ( fs . readdirSync , [ absolute ] , [ ] ) ;
1180
+ for ( const subfile of subfiles ) {
1181
+ if ( indexes . includes ( subfile ) ) {
1182
+ group . push ( `${ subdir } ${ dirent . name } ` ) ;
1183
+ break ;
1180
1184
}
1181
- for ( let s = 0 ; s < subfiles . length ; s ++ ) {
1182
- if ( indexRe . test ( subfiles [ s ] ) ) {
1183
- group . push ( subdir + name ) ;
1184
- }
1185
- }
1186
- } else if ( exts . includes ( ext ) && ( ! subdir || base !== 'index' ) ) {
1187
- group . push ( subdir + base ) ;
1188
1185
}
1189
1186
}
1190
1187
}
@@ -1197,11 +1194,10 @@ function complete(line, callback) {
1197
1194
}
1198
1195
1199
1196
completionGroupsLoaded ( ) ;
1200
- } else if ( match = line . match ( fsAutoCompleteRE ) ) {
1201
-
1202
- let filePath = match [ 1 ] ;
1203
- let fileList ;
1197
+ } else if ( fsAutoCompleteRE . test ( line ) ) {
1204
1198
filter = '' ;
1199
+ let filePath = line . match ( fsAutoCompleteRE ) [ 1 ] ;
1200
+ let fileList ;
1205
1201
1206
1202
try {
1207
1203
fileList = fs . readdirSync ( filePath , { withFileTypes : true } ) ;
@@ -1232,7 +1228,7 @@ function complete(line, callback) {
1232
1228
// foo<|> # all scope vars with filter 'foo'
1233
1229
// foo.<|> # completions for 'foo' with filter ''
1234
1230
} else if ( line . length === 0 || / \w | \. | \$ / . test ( line [ line . length - 1 ] ) ) {
1235
- match = simpleExpressionRE . exec ( line ) ;
1231
+ const match = simpleExpressionRE . exec ( line ) ;
1236
1232
if ( line . length !== 0 && ! match ) {
1237
1233
completionGroupsLoaded ( ) ;
1238
1234
return ;
@@ -1582,10 +1578,6 @@ function defineDefaultCommands(repl) {
1582
1578
}
1583
1579
}
1584
1580
1585
- function regexpEscape ( s ) {
1586
- return s . replace ( / [ - [ \] { } ( ) * + ? . , \\ ^ $ | # \s ] / g, '\\$&' ) ;
1587
- }
1588
-
1589
1581
function Recoverable ( err ) {
1590
1582
this . err = err ;
1591
1583
}
0 commit comments