mirror of
https://github.com/zebrajr/node.git
synced 2025-12-06 00:20:08 +01:00
repl: add isValidParentheses check before wrap input
PR-URL: https://github.com/nodejs/node/pull/59607 Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de> Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
This commit is contained in:
parent
83c955d8c2
commit
ebd2da6d11
|
|
@ -301,7 +301,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;
|
||||
}
|
||||
|
|
@ -754,6 +754,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.
|
||||
|
|
@ -776,4 +795,5 @@ module.exports = {
|
|||
setupPreview,
|
||||
setupReverseSearch,
|
||||
isObjectLiteral,
|
||||
isValidSyntax,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -177,6 +177,7 @@ const {
|
|||
setupPreview,
|
||||
setupReverseSearch,
|
||||
isObjectLiteral,
|
||||
isValidSyntax,
|
||||
} = require('internal/repl/utils');
|
||||
const {
|
||||
constants: {
|
||||
|
|
@ -445,7 +446,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;
|
||||
|
|
@ -2156,6 +2157,7 @@ module.exports = {
|
|||
REPL_MODE_SLOPPY,
|
||||
REPL_MODE_STRICT,
|
||||
Recoverable,
|
||||
isValidSyntax,
|
||||
};
|
||||
|
||||
ObjectDefineProperty(module.exports, 'builtinModules', {
|
||||
|
|
|
|||
|
|
@ -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 &&
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -328,6 +328,19 @@ const errorTests = [
|
|||
expect: '[Function (anonymous)]'
|
||||
},
|
||||
// Multiline object
|
||||
{
|
||||
send: '{}),({}',
|
||||
expect: '| ',
|
||||
},
|
||||
{
|
||||
send: '}',
|
||||
expect: [
|
||||
'{}),({}',
|
||||
kArrow,
|
||||
'',
|
||||
/^Uncaught SyntaxError: /,
|
||||
]
|
||||
},
|
||||
{
|
||||
send: '{ a: ',
|
||||
expect: '| '
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user