Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 21 additions & 1 deletion lib/internal/repl/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,7 @@ function setupPreview(repl, contextSymbol, bufferSymbol, active) {
function getInputPreview(input, callback) {
// For similar reasons as `defaultEval`, wrap expressions starting with a
// curly brace with parenthesis.
if (!wrapped && input[0] === '{' && input[input.length - 1] !== ';') {
if (!wrapped && input[0] === '{' && input[input.length - 1] !== ';' && isValidSyntax(input)) {
input = `(${input})`;
wrapped = true;
}
Expand Down Expand Up @@ -737,6 +737,25 @@ function setupReverseSearch(repl) {

const startsWithBraceRegExp = /^\s*{/;
const endsWithSemicolonRegExp = /;\s*$/;
function isValidSyntax(input) {
try {
AcornParser.parse(input, {
ecmaVersion: 'latest',
allowAwaitOutsideFunction: true,
});
return true;
} catch {
try {
AcornParser.parse(`_=${input}`, {
ecmaVersion: 'latest',
allowAwaitOutsideFunction: true,
});
return true;
} catch {
return false;
}
}
}

/**
* Checks if some provided code represents an object literal.
Expand All @@ -759,4 +778,5 @@ module.exports = {
setupPreview,
setupReverseSearch,
isObjectLiteral,
isValidSyntax,
};
4 changes: 3 additions & 1 deletion lib/repl.js
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ const {
setupPreview,
setupReverseSearch,
isObjectLiteral,
isValidSyntax,
} = require('internal/repl/utils');
const {
constants: {
Expand Down Expand Up @@ -440,7 +441,7 @@ function REPLServer(prompt,
let awaitPromise = false;
const input = code;

if (isObjectLiteral(code)) {
if (isObjectLiteral(code) && isValidSyntax(code)) {
// Add parentheses to make sure `code` is parsed as an expression
code = `(${StringPrototypeTrim(code)})\n`;
wrappedCmd = true;
Expand Down Expand Up @@ -1859,6 +1860,7 @@ module.exports = {
REPL_MODE_SLOPPY,
REPL_MODE_STRICT,
Recoverable,
isValidSyntax,
};

ObjectDefineProperty(module.exports, 'builtinModules', {
Expand Down
86 changes: 84 additions & 2 deletions test/parallel/test-repl-preview.js
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,83 @@ async function tests(options) {
'\x1B[90m1\x1B[39m\x1B[12G\x1B[1A\x1B[1B\x1B[2K\x1B[1A\r',
'\x1B[33m1\x1B[39m',
]
}, {
input: 'aaaa',
noPreview: 'Uncaught ReferenceError: aaaa is not defined',
preview: [
'aaaa\r',
'Uncaught ReferenceError: aaaa is not defined',
]
}, {
input: '/0',
noPreview: '/0',
preview: [
'/0\r',
'/0',
'^',
'',
'Uncaught SyntaxError: Invalid regular expression: missing /',
]
}, {
input: '{})',
noPreview: '{})',
preview: [
'{})\r',
'{})',
' ^',
'',
"Uncaught SyntaxError: Unexpected token ')'",
],
}, {
input: "{ a: '{' }",
noPreview: "{ a: \x1B[32m'{'\x1B[39m }",
preview: [
"{ a: '{' }\r",
"{ a: \x1B[32m'{'\x1B[39m }",
],
}, {
input: "{'{':0}",
noPreview: "{ \x1B[32m'{'\x1B[39m: \x1B[33m0\x1B[39m }",
preview: [
"{'{':0}",
"\x1B[90m{ '{': 0 }\x1B[39m\x1B[15G\x1B[1A\x1B[1B\x1B[2K\x1B[1A\r",
"{ \x1B[32m'{'\x1B[39m: \x1B[33m0\x1B[39m }",
],
}, {
input: '{[Symbol.for("{")]: 0 }',
noPreview: '{ [\x1B[32mSymbol({)\x1B[39m]: \x1B[33m0\x1B[39m }',
preview: [
'{[Symbol.for("{")]: 0 }\r',
'{ [\x1B[32mSymbol({)\x1B[39m]: \x1B[33m0\x1B[39m }',
],
}, {
input: '{},{}',
noPreview: '{}',
preview: [
'{},{}',
'\x1B[90m{}\x1B[39m\x1B[13G\x1B[1A\x1B[1B\x1B[2K\x1B[1A\r',
'{}',
],
}, {
input: '{} //',
noPreview: 'repl > ',
preview: [
'{} //\r',
],
}, {
input: '{} //;',
noPreview: 'repl > ',
preview: [
'{} //;\r',
],
}, {
input: '{throw 0}',
noPreview: 'Uncaught \x1B[33m0\x1B[39m',
preview: [
'{throw 0}',
'\x1B[90m0\x1B[39m\x1B[17G\x1B[1A\x1B[1B\x1B[2K\x1B[1A\r',
'Uncaught \x1B[33m0\x1B[39m',
],
}];

const hasPreview = repl.terminal &&
Expand All @@ -177,8 +254,13 @@ async function tests(options) {
assert.deepStrictEqual(lines, preview);
} else {
assert.ok(lines[0].includes(noPreview), lines.map(inspect));
if (preview.length !== 1 || preview[0] !== `${input}\r`)
assert.strictEqual(lines.length, 2);
if (preview.length !== 1 || preview[0] !== `${input}\r`) {
if (preview[preview.length - 1].includes('Uncaught SyntaxError')) {
assert.strictEqual(lines.length, 5);
} else {
assert.strictEqual(lines.length, 2);
}
}
}
}
}
Expand Down
13 changes: 13 additions & 0 deletions test/parallel/test-repl.js
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,19 @@ const errorTests = [
expect: '[Function (anonymous)]'
},
// Multiline object
{
send: '{}),({}',
expect: '... ',
},
{
send: '}',
expect: [
'{}),({}',
kArrow,
'',
/^Uncaught SyntaxError: /,
]
},
{
send: '{ a: ',
expect: '... '
Expand Down
Loading