We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
There was an error while loading. Please reload this page.
1 parent 9e5edf2 commit 1e065a0Copy full SHA for 1e065a0
3 files changed
lib/internal/repl/await.js
@@ -119,7 +119,10 @@ function processTopLevelAwait(src) {
119
'^\n\n' + RegExpPrototypeSymbolReplace(/ \([^)]+\)/, e.message, '');
120
// V8 unexpected token errors include the token string.
121
if (StringPrototypeEndsWith(message, 'Unexpected token'))
122
- message += " '" + src[e.pos - wrapPrefix.length] + "'";
+ message += " '" +
123
+ // Wrapper end may cause acorn to report error position after the source
124
+ (src[e.pos - wrapPrefix.length] ?? src[src.length - 1]) +
125
+ "'";
126
// eslint-disable-next-line no-restricted-syntax
127
throw new SyntaxError(message);
128
}
lib/repl.js
@@ -78,6 +78,7 @@ const {
78
ReflectApply,
79
RegExp,
80
RegExpPrototypeExec,
81
+ RegExpPrototypeSymbolReplace,
82
RegExpPrototypeTest,
83
SafeSet,
84
SafeWeakSet,
@@ -439,8 +440,39 @@ function REPLServer(prompt,
439
440
awaitPromise = true;
441
442
} catch (e) {
- decorateErrorStack(e);
443
- err = e;
+ let recoverableError = false;
444
+ if (e.name === 'SyntaxError') {
445
+ let parentURL;
446
+ try {
447
+ const { pathToFileURL } = require('url');
448
+ // Adding `/repl` prevents dynamic imports from loading relative
449
+ // to the parent of `process.cwd()`.
450
+ parentURL = pathToFileURL(path.join(process.cwd(), 'repl')).href;
451
+ } catch {
452
+ }
453
+
454
+ // Remove all "await"s and attempt running the script
455
+ // in order to detect if error is truly non recoverable
456
+ const fallbackCode = RegExpPrototypeSymbolReplace(/\bawait\b/g, code, '');
457
458
+ vm.createScript(fallbackCode, {
459
+ filename: file,
460
+ displayErrors: true,
461
+ importModuleDynamically: async (specifier) => {
462
+ return asyncESM.ESMLoader.import(specifier, parentURL);
463
464
+ });
465
+ } catch (fallbackError) {
466
+ if (isRecoverableError(fallbackError, fallbackCode)) {
467
+ recoverableError = true;
468
+ err = new Recoverable(e);
469
470
471
472
+ if (!recoverableError) {
473
+ decorateErrorStack(e);
474
+ err = e;
475
476
477
478
test/parallel/test-repl-top-level-await.js
@@ -152,6 +152,36 @@ async function ordinaryTests() {
152
'Unexpected token \'.\'',
153
],
154
155
+ ['for (const x of [1,2,3]) {\nawait x\n}', [
156
+ 'for (const x of [1,2,3]) {\r',
157
+ '... await x\r',
158
+ '... }\r',
159
+ 'undefined',
160
+ ]],
161
+ ['for (const x of [1,2,3]) {\nawait x;\n}', [
162
163
+ '... await x;\r',
164
165
166
167
+ ['for await (const x of [1,2,3]) {\nconsole.log(x)\n}', [
168
+ 'for await (const x of [1,2,3]) {\r',
169
+ '... console.log(x)\r',
170
171
+ '1',
172
+ '2',
173
+ '3',
174
175
176
+ ['for await (const x of [1,2,3]) {\nconsole.log(x);\n}', [
177
178
+ '... console.log(x);\r',
179
180
181
182
183
184
185
];
186
187
for (const [input, expected = [`${input}\r`], options = {}] of testCases) {
0 commit comments