From 93b9dc0b2e0589df603f415abebad254551c9abc Mon Sep 17 00:00:00 2001 From: Prince J Wesley Date: Wed, 21 Feb 2018 17:48:23 +0530 Subject: [PATCH] repl: better handling of recoverable errors Below syntax errors are handled without force .break/clear - Unexpected Token (prefix errors) - missing ) after argument list In the multiline expression, recoverable errors are truly recoverable, otherwise syntax error will be thrown. PR-URL: https://github.com/nodejs/node/pull/18915 Reviewed-By: Anna Henningsen Reviewed-By: Shingo Inoue Reviewed-By: James M Snell Reviewed-By: Ruben Bridgewater --- lib/repl.js | 11 +++--- test/parallel/test-repl.js | 74 +++++++++++++++++++++++++++++++++++--- 2 files changed, 75 insertions(+), 10 deletions(-) diff --git a/lib/repl.js b/lib/repl.js index 3cfa1996d8c361..078bb208ae1544 100644 --- a/lib/repl.js +++ b/lib/repl.js @@ -1473,14 +1473,15 @@ function isRecoverableError(e, code) { if (e && e.name === 'SyntaxError') { var message = e.message; if (message === 'Unterminated template literal' || - message === 'Missing } in template expression') { + message === 'Unexpected end of input') { return true; } - if (message.startsWith('Unexpected end of input') || - message.startsWith('missing ) after argument list') || - message.startsWith('Unexpected token')) - return true; + if (message === 'missing ) after argument list') { + const frames = e.stack.split(/\r?\n/); + const pos = frames.findIndex((f) => f.match(/^\s*\^+$/)); + return pos > 0 && frames[pos - 1].length === frames[pos].length; + } if (message === 'Invalid or unexpected token') return isCodeRecoverable(code); diff --git a/test/parallel/test-repl.js b/test/parallel/test-repl.js index cb167372ef52fd..e14398541dd8de 100644 --- a/test/parallel/test-repl.js +++ b/test/parallel/test-repl.js @@ -163,13 +163,23 @@ const errorTests = [ send: '.break', expect: '' }, - // Template expressions can cross lines + // Template expressions { send: '`io.js ${"1.0"', + expect: [ + kSource, + kArrow, + '', + /^SyntaxError: /, + '' + ] + }, + { + send: '`io.js ${', expect: '... ' }, { - send: '+ ".2"}`', + send: '"1.0" + ".2"}`', expect: '\'io.js 1.0.2\'' }, // Dot prefix in multiline commands aren't treated as commands @@ -644,14 +654,68 @@ const errorTests = [ }, // Do not parse `...[]` as a REPL keyword { - send: '...[]\n', - expect: '... ... ' + send: '...[]', + expect: [ + kSource, + kArrow, + '', + /^SyntaxError: /, + '' + ] }, // bring back the repl to prompt { send: '.break', expect: '' - } + }, + { + send: 'console.log("Missing comma in arg list" process.version)', + expect: [ + kSource, + kArrow, + '', + /^SyntaxError: /, + '' + ] + }, + { + send: 'x = {\nfield\n{', + expect: [ + '... ... {', + kArrow, + '', + /^SyntaxError: /, + '' + ] + }, + { + send: '(2 + 3))', + expect: [ + kSource, + kArrow, + '', + /^SyntaxError: /, + '' + ] + }, + { + send: 'if (typeof process === "object"); {', + expect: '... ' + }, + { + send: 'console.log("process is defined");', + expect: '... ' + }, + { + send: '} else {', + expect: [ + kSource, + kArrow, + '', + /^SyntaxError: /, + '' + ] + }, ]; const tcpTests = [