mirror of
https://github.com/zebrajr/node.git
synced 2025-12-06 12:20:27 +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) {
|
function getInputPreview(input, callback) {
|
||||||
// For similar reasons as `defaultEval`, wrap expressions starting with a
|
// For similar reasons as `defaultEval`, wrap expressions starting with a
|
||||||
// curly brace with parenthesis.
|
// curly brace with parenthesis.
|
||||||
if (!wrapped && input[0] === '{' && input[input.length - 1] !== ';') {
|
if (!wrapped && input[0] === '{' && input[input.length - 1] !== ';' && isValidSyntax(input)) {
|
||||||
input = `(${input})`;
|
input = `(${input})`;
|
||||||
wrapped = true;
|
wrapped = true;
|
||||||
}
|
}
|
||||||
|
|
@ -754,6 +754,25 @@ function setupReverseSearch(repl) {
|
||||||
|
|
||||||
const startsWithBraceRegExp = /^\s*{/;
|
const startsWithBraceRegExp = /^\s*{/;
|
||||||
const endsWithSemicolonRegExp = /;\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.
|
* Checks if some provided code represents an object literal.
|
||||||
|
|
@ -776,4 +795,5 @@ module.exports = {
|
||||||
setupPreview,
|
setupPreview,
|
||||||
setupReverseSearch,
|
setupReverseSearch,
|
||||||
isObjectLiteral,
|
isObjectLiteral,
|
||||||
|
isValidSyntax,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -177,6 +177,7 @@ const {
|
||||||
setupPreview,
|
setupPreview,
|
||||||
setupReverseSearch,
|
setupReverseSearch,
|
||||||
isObjectLiteral,
|
isObjectLiteral,
|
||||||
|
isValidSyntax,
|
||||||
} = require('internal/repl/utils');
|
} = require('internal/repl/utils');
|
||||||
const {
|
const {
|
||||||
constants: {
|
constants: {
|
||||||
|
|
@ -445,7 +446,7 @@ function REPLServer(prompt,
|
||||||
let awaitPromise = false;
|
let awaitPromise = false;
|
||||||
const input = code;
|
const input = code;
|
||||||
|
|
||||||
if (isObjectLiteral(code)) {
|
if (isObjectLiteral(code) && isValidSyntax(code)) {
|
||||||
// Add parentheses to make sure `code` is parsed as an expression
|
// Add parentheses to make sure `code` is parsed as an expression
|
||||||
code = `(${StringPrototypeTrim(code)})\n`;
|
code = `(${StringPrototypeTrim(code)})\n`;
|
||||||
wrappedCmd = true;
|
wrappedCmd = true;
|
||||||
|
|
@ -2156,6 +2157,7 @@ module.exports = {
|
||||||
REPL_MODE_SLOPPY,
|
REPL_MODE_SLOPPY,
|
||||||
REPL_MODE_STRICT,
|
REPL_MODE_STRICT,
|
||||||
Recoverable,
|
Recoverable,
|
||||||
|
isValidSyntax,
|
||||||
};
|
};
|
||||||
|
|
||||||
ObjectDefineProperty(module.exports, 'builtinModules', {
|
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[90m1\x1B[39m\x1B[12G\x1B[1A\x1B[1B\x1B[2K\x1B[1A\r',
|
||||||
'\x1B[33m1\x1B[39m',
|
'\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 &&
|
const hasPreview = repl.terminal &&
|
||||||
|
|
@ -177,8 +254,13 @@ async function tests(options) {
|
||||||
assert.deepStrictEqual(lines, preview);
|
assert.deepStrictEqual(lines, preview);
|
||||||
} else {
|
} else {
|
||||||
assert.ok(lines[0].includes(noPreview), lines.map(inspect));
|
assert.ok(lines[0].includes(noPreview), lines.map(inspect));
|
||||||
if (preview.length !== 1 || preview[0] !== `${input}\r`)
|
if (preview.length !== 1 || preview[0] !== `${input}\r`) {
|
||||||
assert.strictEqual(lines.length, 2);
|
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)]'
|
expect: '[Function (anonymous)]'
|
||||||
},
|
},
|
||||||
// Multiline object
|
// Multiline object
|
||||||
|
{
|
||||||
|
send: '{}),({}',
|
||||||
|
expect: '| ',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
send: '}',
|
||||||
|
expect: [
|
||||||
|
'{}),({}',
|
||||||
|
kArrow,
|
||||||
|
'',
|
||||||
|
/^Uncaught SyntaxError: /,
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
send: '{ a: ',
|
send: '{ a: ',
|
||||||
expect: '| '
|
expect: '| '
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user