Skip to content

Commit c978396

Browse files
BridgeARBethGriggs
authored andcommitted
repl: use better uncaught exceptions indicator
This switches "Thrown:" with "Uncaught" to outline clearer that the thrown error is not caught. PR-URL: #29676 Reviewed-By: Gus Caplan <me@gus.host> Reviewed-By: James M Snell <jasnell@gmail.com>
1 parent d66996c commit c978396

10 files changed

Lines changed: 90 additions & 87 deletions

‎lib/repl.js‎

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -567,11 +567,28 @@ function REPLServer(prompt,
567567
});
568568
}else{
569569
if(errStack===''){
570-
errStack=`Thrown: ${self.writer(e)}\n`;
571-
}else{
572-
constln=errStack.endsWith('\n') ? '' : '\n';
573-
errStack=`Thrown:\n${errStack}${ln}`;
570+
errStack=self.writer(e);
571+
}
572+
constlines=errStack.split(/(?<=\n)/);
573+
letmatched=false;
574+
575+
errStack='';
576+
for(constlineoflines){
577+
if(!matched&&/^\[?([A-Z][a-z0-9_]*)*Error/.test(line)){
578+
errStack+=writer.options.breakLength>=line.length ?
579+
`Uncaught ${line}` :
580+
`Uncaught:\n${line}`;
581+
matched=true;
582+
}else{
583+
errStack+=line;
584+
}
585+
}
586+
if(!matched){
587+
constln=lines.length===1 ? ' ' : ':\n';
588+
errStack=`Uncaught${ln}${errStack}`;
574589
}
590+
// Normalize line endings.
591+
errStack+=errStack.endsWith('\n') ? '' : '\n';
575592
top.outputStream.write(errStack);
576593
top.clearBufferedCommand();
577594
top.lines.level=[];

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ const child = spawn(process.execPath, args);
3030
constinput='(function(){"use strict"; const y=1;y=2})()\n';
3131
// This message will vary based on JavaScript engine, so don't check the message
3232
// contents beyond confirming that the `Error` is a `TypeError`.
33-
constexpectOut=/>Thrown:\nTypeError:/;
33+
constexpectOut=/>UncaughtTypeError:/;
3434

3535
child.stderr.setEncoding('utf8');
3636
child.stderr.on('data',(d)=>{

‎test/parallel/test-repl-null-thrown.js‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,5 +20,5 @@ replserver.emit('line', '.exit');
2020

2121
setTimeout(()=>{
2222
console.log(text);
23-
assert(text.includes('Thrown: null'));
23+
assert(text.includes('Uncaught null'));
2424
},0);

‎test/parallel/test-repl-pretty-custom-stack.js‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,26 +48,26 @@ const tests = [
4848
{
4949
// test .load for a file that throws
5050
command: `.load ${fixtures.path('repl-pretty-stack.js')}`,
51-
expected: 'Thrown:\nError: Whoops!--->\nrepl:*:*--->\nd (repl:*:*)'+
51+
expected: 'Uncaught Error: Whoops!--->\nrepl:*:*--->\nd (repl:*:*)'+
5252
'--->\nc (repl:*:*)--->\nb (repl:*:*)--->\na (repl:*:*)\n'
5353
},
5454
{
5555
command: 'let x y;',
56-
expected: 'Thrown:\n'+
57-
'let x y;\n ^\n\nSyntaxError: Unexpected identifier\n'
56+
expected: 'let x y;\n ^\n\n'+
57+
'Uncaught SyntaxError: Unexpected identifier\n'
5858
},
5959
{
6060
command: 'throw new Error(\'Whoops!\')',
61-
expected: 'Thrown:\nError: Whoops!\n'
61+
expected: 'Uncaught Error: Whoops!\n'
6262
},
6363
{
6464
command: 'foo = bar;',
65-
expected: 'Thrown:\nReferenceError: bar is not defined\n'
65+
expected: 'Uncaught ReferenceError: bar is not defined\n'
6666
},
6767
// test anonymous IIFE
6868
{
6969
command: '(function() { throw new Error(\'Whoops!\'); })()',
70-
expected: 'Thrown:\nError: Whoops!--->\nrepl:*:*\n'
70+
expected: 'Uncaught Error: Whoops!--->\nrepl:*:*\n'
7171
}
7272
];
7373

‎test/parallel/test-repl-pretty-stack.js‎

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ const repl = require('repl');
77

88
conststackRegExp=/(at.*repl:)[0-9]+:[0-9]+/g;
99

10-
functionrun({ command, expected, ...extraREPLOptions}){
10+
functionrun({ command, expected, ...extraREPLOptions},i){
1111
letaccum='';
1212

1313
constinputStream=newArrayStream();
@@ -25,6 +25,7 @@ function run({ command, expected, ...extraREPLOptions }) {
2525
});
2626

2727
r.write(`${command}\n`);
28+
console.log(i);
2829
assert.strictEqual(
2930
accum.replace(stackRegExp,'$1*:*'),
3031
expected.replace(stackRegExp,'$1*:*')
@@ -36,39 +37,39 @@ const tests = [
3637
{
3738
// Test .load for a file that throws.
3839
command: `.load ${fixtures.path('repl-pretty-stack.js')}`,
39-
expected: 'Thrown:\nError: Whoops!\n at repl:*:*\n'+
40+
expected: 'Uncaught Error: Whoops!\n at repl:*:*\n'+
4041
' at d (repl:*:*)\n at c (repl:*:*)\n'+
4142
' at b (repl:*:*)\n at a (repl:*:*)\n'
4243
},
4344
{
4445
command: 'let x y;',
45-
expected: 'Thrown:\n'+
46-
'let x y;\n ^\n\nSyntaxError: Unexpected identifier\n'
46+
expected: 'let x y;\n ^\n\n'+
47+
'Uncaught SyntaxError: Unexpected identifier\n'
4748
},
4849
{
4950
command: 'throw new Error(\'Whoops!\')',
50-
expected: 'Thrown:\nError: Whoops!\n'
51+
expected: 'Uncaught Error: Whoops!\n'
5152
},
5253
{
5354
command: '(() => { const err = Error(\'Whoops!\'); '+
5455
'err.foo = \'bar\'; throw err; })()',
55-
expected: "Thrown:\nError: Whoops!\n at repl:*:* {\n foo: 'bar'\n}\n",
56+
expected: "Uncaught Error: Whoops!\n at repl:*:* {\n foo: 'bar'\n}\n",
5657
},
5758
{
5859
command: '(() => { const err = Error(\'Whoops!\'); '+
5960
'err.foo = \'bar\'; throw err; })()',
60-
expected: 'Thrown:\nError: Whoops!\n at repl:*:* {\n foo: '+
61+
expected: 'Uncaught Error: Whoops!\n at repl:*:* {\n foo: '+
6162
"\u001b[32m'bar'\u001b[39m\n}\n",
6263
useColors: true
6364
},
6465
{
6566
command: 'foo = bar;',
66-
expected: 'Thrown:\nReferenceError: bar is not defined\n'
67+
expected: 'Uncaught ReferenceError: bar is not defined\n'
6768
},
6869
// Test anonymous IIFE.
6970
{
7071
command: '(function() { throw new Error(\'Whoops!\'); })()',
71-
expected: 'Thrown:\nError: Whoops!\n at repl:*:*\n'
72+
expected: 'Uncaught Error: Whoops!\n at repl:*:*\n'
7273
}
7374
];
7475

‎test/parallel/test-repl-top-level-await.js‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -118,15 +118,15 @@ async function ordinaryTests() {
118118
['if (await true) { function bar() {}; }','undefined'],
119119
['bar','[Function: bar]'],
120120
['if (await true) { class Bar {}; }','undefined'],
121-
['Bar','ReferenceError: Bar is not defined',{line: 1}],
121+
['Bar','Uncaught ReferenceError: Bar is not defined'],
122122
['await 0; function* gen(){}','undefined'],
123123
['for (var i = 0; i < 10; ++i) { await i; }','undefined'],
124124
['i','10'],
125125
['for (let j = 0; j < 5; ++j) { await j; }','undefined'],
126-
['j','ReferenceError: j is not defined',{line: 1}],
126+
['j','Uncaught ReferenceError: j is not defined'],
127127
['gen','[GeneratorFunction: gen]'],
128-
['return 42; await 5;','SyntaxError: Illegal return statement',
129-
{line: 4}],
128+
['return 42; await 5;','Uncaught SyntaxError: Illegal return statement',
129+
{line: 3}],
130130
['let o = await 1, p','undefined'],
131131
['p','undefined'],
132132
['let q = 1, s = await 2','undefined'],
@@ -160,7 +160,7 @@ async function ctrlCTest() {
160160
{ctrl: true,name: 'c'}
161161
]),[
162162
'await timeout(100000)\r',
163-
'Thrown:',
163+
'Uncaught:',
164164
'[Error [ERR_SCRIPT_EXECUTION_INTERRUPTED]: '+
165165
'Script execution was interrupted by `SIGINT`] {',
166166
" code: 'ERR_SCRIPT_EXECUTION_INTERRUPTED'",

‎test/parallel/test-repl-uncaught-exception-standalone.js‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,7 @@ child.on('exit', common.mustCall(() => {
1818
[
1919
'Type ".help" for more information.',
2020
// x\n
21-
'> Thrown:',
22-
'ReferenceError: x is not defined',
21+
'> Uncaught ReferenceError: x is not defined',
2322
// Added `uncaughtException` listener.
2423
'> short',
2524
'undefined',

‎test/parallel/test-repl-uncaught-exception.js‎

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ const repl = require('repl');
66

77
letcount=0;
88

9-
functionrun({ command, expected }){
9+
functionrun({ command, expected, useColors =false}){
1010
letaccum='';
1111

1212
constoutput=newArrayStream();
@@ -17,7 +17,7 @@ function run({ command, expected }) {
1717
input: newArrayStream(),
1818
output,
1919
terminal: false,
20-
useColors: false
20+
useColors
2121
});
2222

2323
r.write(`${command}\n`);
@@ -30,35 +30,40 @@ function run({ command, expected }) {
3030
// Verify that the repl is still working as expected.
3131
accum='';
3232
r.write('1 + 1\n');
33-
assert.strictEqual(accum,'2\n');
33+
// eslint-disable-next-line no-control-regex
34+
assert.strictEqual(accum.replace(/\u001b\[[0-9]+m/g,''),'2\n');
3435
r.close();
3536
count++;
3637
}
3738

3839
consttests=[
3940
{
41+
useColors: true,
4042
command: 'x',
41-
expected: 'Thrown:\n'+
42-
'ReferenceError: x is not defined\n'
43+
expected: 'Uncaught ReferenceError: x is not defined\n'
44+
},
45+
{
46+
useColors: true,
47+
command: 'throw { foo: "test" }',
48+
expected: "Uncaught { foo: \x1B[32m'test'\x1B[39m }\n"
4349
},
4450
{
4551
command: 'process.on("uncaughtException", () => console.log("Foobar"));\n',
46-
expected: /^Thrown:\nTypeError\[ERR_INVALID_REPL_INPUT]:Listenersfor`/
52+
expected: /^Uncaught:\nTypeError\[ERR_INVALID_REPL_INPUT]:Listenersfor`/
4753
},
4854
{
4955
command: 'x;\n',
50-
expected: 'Thrown:\n'+
51-
'ReferenceError: x is not defined\n'
56+
expected: 'Uncaught ReferenceError: x is not defined\n'
5257
},
5358
{
5459
command: 'process.on("uncaughtException", () => console.log("Foobar"));'+
5560
'console.log("Baz");\n',
56-
expected: /^Thrown:\nTypeError\[ERR_INVALID_REPL_INPUT]:Listenersfor`/
61+
expected: /^Uncaught:\nTypeError\[ERR_INVALID_REPL_INPUT]:Listenersfor`/
5762
},
5863
{
5964
command: 'console.log("Baz");'+
6065
'process.on("uncaughtException", () => console.log("Foobar"));\n',
61-
expected: /^Baz\nThrown:\nTypeError\[ERR_INVALID_REPL_INPUT]:.*uncaughtException/
66+
expected: /^Baz\nUncaught:\nTypeError\[ERR_INVALID_REPL_INPUT]:.*uncaughtException/
6267
}
6368
];
6469

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

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -173,13 +173,11 @@ function testError() {
173173
'undefined',
174174

175175
// The error, both from the original throw and the `_error` echo.
176-
'Thrown:',
177-
'Error: foo',
176+
'Uncaught Error: foo',
178177
'[Error: foo]',
179178

180179
// The sync error, with individual property echoes
181-
'Thrown:',
182-
/^Error:ENOENT:nosuchfileordirectory,scandir'.*nonexistent\?'/,
180+
/^UncaughtError:ENOENT:nosuchfileordirectory,scandir'.*nonexistent\?'/,
183181
/Object\.readdirSync/,
184182
/^errno:-(2|4058),$/,
185183
" syscall: 'scandir',",
@@ -194,8 +192,7 @@ function testError() {
194192
'undefined',
195193

196194
// The message from the original throw
197-
'Thrown:',
198-
'Error: baz',
195+
'Uncaught Error: baz',
199196
];
200197
for(constlineoflines){
201198
constexpected=expectedLines.shift();
@@ -218,8 +215,7 @@ function testError() {
218215
"'baz'",
219216
'Expression assignment to _error now disabled.',
220217
'0',
221-
'Thrown:',
222-
'Error: quux',
218+
'Uncaught Error: quux',
223219
'0'
224220
]);
225221
});

0 commit comments

Comments
 (0)