Skip to content

Commit d4b41f6

Browse files
BridgeARtargos
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 <[email protected]> Reviewed-By: James M Snell <[email protected]>
1 parent e5e60f5 commit d4b41f6

10 files changed

+90
-87
lines changed

lib/repl.js

+21-4
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-
const ln = errStack.endsWith('\n') ? '' : '\n';
573-
errStack = `Thrown:\n${errStack}${ln}`;
570+
errStack = self.writer(e);
571+
}
572+
const lines = errStack.split(/(?<=\n)/);
573+
let matched = false;
574+
575+
errStack = '';
576+
for (const line of lines) {
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+
const ln = 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

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ const child = spawn(process.execPath, args);
3030
const input = '(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-
const expectOut = /> Thrown:\nTypeError: /;
33+
const expectOut = /> Uncaught TypeError: /;
3434

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

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

+1-1
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

+6-6
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

+10-9
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ const repl = require('repl');
77

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

10-
function run({ command, expected, ...extraREPLOptions }) {
10+
function run({ command, expected, ...extraREPLOptions }, i) {
1111
let accum = '';
1212

1313
const inputStream = new ArrayStream();
@@ -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

+5-5
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

+1-2
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

+15-10
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ const repl = require('repl');
66

77
let count = 0;
88

9-
function run({ command, expected }) {
9+
function run({ command, expected, useColors = false }) {
1010
let accum = '';
1111

1212
const output = new ArrayStream();
@@ -17,7 +17,7 @@ function run({ command, expected }) {
1717
input: new ArrayStream(),
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
const tests = [
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]: Listeners for `/
52+
expected: /^Uncaught:\nTypeError \[ERR_INVALID_REPL_INPUT]: Listeners for `/
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]: Listeners for `/
61+
expected: /^Uncaught:\nTypeError \[ERR_INVALID_REPL_INPUT]: Listeners for `/
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

+4-8
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: no such file or directory, scandir '.*nonexistent\?'/,
180+
/^Uncaught Error: ENOENT: no such file or directory, 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 (const line of lines) {
201198
const expected = 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)