Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 99ea08d

Browse filesBrowse files
authored
repl: add isValidParentheses check before wrap input
PR-URL: #59607 Backport-PR-URL: #60066 Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de> Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
1 parent 7e0e86c commit 99ea08d
Copy full SHA for 99ea08d

File tree

Expand file treeCollapse file tree

4 files changed

+121
-4
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

4 files changed

+121
-4
lines changed
Open diff view settings
Collapse file

‎lib/internal/repl/utils.js‎

Copy file name to clipboardExpand all lines: lib/internal/repl/utils.js
+21-1Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,7 @@ function setupPreview(repl, contextSymbol, bufferSymbol, active) {
292292
function getInputPreview(input, callback) {
293293
// For similar reasons as `defaultEval`, wrap expressions starting with a
294294
// curly brace with parenthesis.
295-
if (!wrapped && input[0] === '{' && input[input.length - 1] !== ';') {
295+
if (!wrapped && input[0] === '{' && input[input.length - 1] !== ';' && isValidSyntax(input)) {
296296
input = `(${input})`;
297297
wrapped = true;
298298
}
@@ -737,6 +737,25 @@ function setupReverseSearch(repl) {
737737

738738
const startsWithBraceRegExp = /^\s*{/;
739739
const endsWithSemicolonRegExp = /;\s*$/;
740+
function isValidSyntax(input) {
741+
try {
742+
AcornParser.parse(input, {
743+
ecmaVersion: 'latest',
744+
allowAwaitOutsideFunction: true,
745+
});
746+
return true;
747+
} catch {
748+
try {
749+
AcornParser.parse(`_=${input}`, {
750+
ecmaVersion: 'latest',
751+
allowAwaitOutsideFunction: true,
752+
});
753+
return true;
754+
} catch {
755+
return false;
756+
}
757+
}
758+
}
740759

741760
/**
742761
* Checks if some provided code represents an object literal.
@@ -759,4 +778,5 @@ module.exports = {
759778
setupPreview,
760779
setupReverseSearch,
761780
isObjectLiteral,
781+
isValidSyntax,
762782
};
Collapse file

‎lib/repl.js‎

Copy file name to clipboardExpand all lines: lib/repl.js
+3-1Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,7 @@ const {
172172
setupPreview,
173173
setupReverseSearch,
174174
isObjectLiteral,
175+
isValidSyntax,
175176
} = require('internal/repl/utils');
176177
const {
177178
constants: {
@@ -440,7 +441,7 @@ function REPLServer(prompt,
440441
let awaitPromise = false;
441442
const input = code;
442443

443-
if (isObjectLiteral(code)) {
444+
if (isObjectLiteral(code) && isValidSyntax(code)) {
444445
// Add parentheses to make sure `code` is parsed as an expression
445446
code = `(${StringPrototypeTrim(code)})\n`;
446447
wrappedCmd = true;
@@ -1859,6 +1860,7 @@ module.exports = {
18591860
REPL_MODE_SLOPPY,
18601861
REPL_MODE_STRICT,
18611862
Recoverable,
1863+
isValidSyntax,
18621864
};
18631865

18641866
ObjectDefineProperty(module.exports, 'builtinModules', {
Collapse file

‎test/parallel/test-repl-preview.js‎

Copy file name to clipboardExpand all lines: test/parallel/test-repl-preview.js
+84-2Lines changed: 84 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,83 @@ async function tests(options) {
157157
'\x1B[90m1\x1B[39m\x1B[12G\x1B[1A\x1B[1B\x1B[2K\x1B[1A\r',
158158
'\x1B[33m1\x1B[39m',
159159
]
160+
}, {
161+
input: 'aaaa',
162+
noPreview: 'Uncaught ReferenceError: aaaa is not defined',
163+
preview: [
164+
'aaaa\r',
165+
'Uncaught ReferenceError: aaaa is not defined',
166+
]
167+
}, {
168+
input: '/0',
169+
noPreview: '/0',
170+
preview: [
171+
'/0\r',
172+
'/0',
173+
'^',
174+
'',
175+
'Uncaught SyntaxError: Invalid regular expression: missing /',
176+
]
177+
}, {
178+
input: '{})',
179+
noPreview: '{})',
180+
preview: [
181+
'{})\r',
182+
'{})',
183+
' ^',
184+
'',
185+
"Uncaught SyntaxError: Unexpected token ')'",
186+
],
187+
}, {
188+
input: "{ a: '{' }",
189+
noPreview: "{ a: \x1B[32m'{'\x1B[39m }",
190+
preview: [
191+
"{ a: '{' }\r",
192+
"{ a: \x1B[32m'{'\x1B[39m }",
193+
],
194+
}, {
195+
input: "{'{':0}",
196+
noPreview: "{ \x1B[32m'{'\x1B[39m: \x1B[33m0\x1B[39m }",
197+
preview: [
198+
"{'{':0}",
199+
"\x1B[90m{ '{': 0 }\x1B[39m\x1B[15G\x1B[1A\x1B[1B\x1B[2K\x1B[1A\r",
200+
"{ \x1B[32m'{'\x1B[39m: \x1B[33m0\x1B[39m }",
201+
],
202+
}, {
203+
input: '{[Symbol.for("{")]: 0 }',
204+
noPreview: '{ [\x1B[32mSymbol({)\x1B[39m]: \x1B[33m0\x1B[39m }',
205+
preview: [
206+
'{[Symbol.for("{")]: 0 }\r',
207+
'{ [\x1B[32mSymbol({)\x1B[39m]: \x1B[33m0\x1B[39m }',
208+
],
209+
}, {
210+
input: '{},{}',
211+
noPreview: '{}',
212+
preview: [
213+
'{},{}',
214+
'\x1B[90m{}\x1B[39m\x1B[13G\x1B[1A\x1B[1B\x1B[2K\x1B[1A\r',
215+
'{}',
216+
],
217+
}, {
218+
input: '{} //',
219+
noPreview: 'repl > ',
220+
preview: [
221+
'{} //\r',
222+
],
223+
}, {
224+
input: '{} //;',
225+
noPreview: 'repl > ',
226+
preview: [
227+
'{} //;\r',
228+
],
229+
}, {
230+
input: '{throw 0}',
231+
noPreview: 'Uncaught \x1B[33m0\x1B[39m',
232+
preview: [
233+
'{throw 0}',
234+
'\x1B[90m0\x1B[39m\x1B[17G\x1B[1A\x1B[1B\x1B[2K\x1B[1A\r',
235+
'Uncaught \x1B[33m0\x1B[39m',
236+
],
160237
}];
161238

162239
const hasPreview = repl.terminal &&
@@ -177,8 +254,13 @@ async function tests(options) {
177254
assert.deepStrictEqual(lines, preview);
178255
} else {
179256
assert.ok(lines[0].includes(noPreview), lines.map(inspect));
180-
if (preview.length !== 1 || preview[0] !== `${input}\r`)
181-
assert.strictEqual(lines.length, 2);
257+
if (preview.length !== 1 || preview[0] !== `${input}\r`) {
258+
if (preview[preview.length - 1].includes('Uncaught SyntaxError')) {
259+
assert.strictEqual(lines.length, 5);
260+
} else {
261+
assert.strictEqual(lines.length, 2);
262+
}
263+
}
182264
}
183265
}
184266
}
Collapse file

‎test/parallel/test-repl.js‎

Copy file name to clipboardExpand all lines: test/parallel/test-repl.js
+13Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,19 @@ const errorTests = [
328328
expect: '[Function (anonymous)]'
329329
},
330330
// Multiline object
331+
{
332+
send: '{}),({}',
333+
expect: '... ',
334+
},
335+
{
336+
send: '}',
337+
expect: [
338+
'{}),({}',
339+
kArrow,
340+
'',
341+
/^Uncaught SyntaxError: /,
342+
]
343+
},
331344
{
332345
send: '{ a: ',
333346
expect: '... '

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.