Skip to content

Commit c440f3f

Browse files
BridgeARtargos
authored andcommittedDec 9, 2019
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 71bb026 commit c440f3f

10 files changed

+90
-87
lines changed
 

‎lib/repl.js

+21-4
Original file line numberDiff line numberDiff line change
@@ -552,11 +552,28 @@ function REPLServer(prompt,
552552
});
553553
} else {
554554
if (errStack === '') {
555-
errStack = `Thrown: ${self.writer(e)}\n`;
556-
} else {
557-
const ln = errStack.endsWith('\n') ? '' : '\n';
558-
errStack = `Thrown:\n${errStack}${ln}`;
555+
errStack = self.writer(e);
556+
}
557+
const lines = errStack.split(/(?<=\n)/);
558+
let matched = false;
559+
560+
errStack = '';
561+
for (const line of lines) {
562+
if (!matched && /^\[?([A-Z][a-z0-9_]*)*Error/.test(line)) {
563+
errStack += writer.options.breakLength >= line.length ?
564+
`Uncaught ${line}` :
565+
`Uncaught:\n${line}`;
566+
matched = true;
567+
} else {
568+
errStack += line;
569+
}
570+
}
571+
if (!matched) {
572+
const ln = lines.length === 1 ? ' ' : ':\n';
573+
errStack = `Uncaught${ln}${errStack}`;
559574
}
575+
// Normalize line endings.
576+
errStack += errStack.endsWith('\n') ? '' : '\n';
560577
top.outputStream.write(errStack);
561578
top.clearBufferedCommand();
562579
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
});

‎test/parallel/test-repl.js

+26-41
Original file line numberDiff line numberDiff line change
@@ -126,19 +126,19 @@ const unixTests = [
126126
const strictModeTests = [
127127
{
128128
send: 'ref = 1',
129-
expect: ['Thrown:', /^ReferenceError:\s/]
129+
expect: [/^Uncaught ReferenceError:\s/]
130130
}
131131
];
132132

133133
const errorTests = [
134134
// Uncaught error throws and prints out
135135
{
136136
send: 'throw new Error(\'test error\');',
137-
expect: ['Thrown:', 'Error: test error']
137+
expect: ['Uncaught Error: test error']
138138
},
139139
{
140140
send: "throw { foo: 'bar' };",
141-
expect: "Thrown: { foo: 'bar' }"
141+
expect: "Uncaught { foo: 'bar' }"
142142
},
143143
// Common syntax error is treated as multiline command
144144
{
@@ -153,7 +153,7 @@ const errorTests = [
153153
// But passing the same string to eval() should throw
154154
{
155155
send: 'eval("function test_func() {")',
156-
expect: ['Thrown:', /^SyntaxError: /]
156+
expect: [/^Uncaught SyntaxError: /]
157157
},
158158
// Can handle multiline template literals
159159
{
@@ -210,89 +210,84 @@ const errorTests = [
210210
// should throw
211211
{
212212
send: 'JSON.parse(\'{invalid: \\\'json\\\'}\');',
213-
expect: ['Thrown:', /^SyntaxError: /]
213+
expect: [/^Uncaught SyntaxError: /]
214214
},
215215
// End of input to JSON.parse error is special case of syntax error,
216216
// should throw
217217
{
218218
send: 'JSON.parse(\'066\');',
219-
expect: ['Thrown:', /^SyntaxError: /]
219+
expect: [/^Uncaught SyntaxError: /]
220220
},
221221
// should throw
222222
{
223223
send: 'JSON.parse(\'{\');',
224-
expect: ['Thrown:', /^SyntaxError: /]
224+
expect: [/^Uncaught SyntaxError: /]
225225
},
226226
// invalid RegExps are a special case of syntax error,
227227
// should throw
228228
{
229229
send: '/(/;',
230-
expect: ['Thrown:', /^SyntaxError: /]
230+
expect: [/^Uncaught SyntaxError: /]
231231
},
232232
// invalid RegExp modifiers are a special case of syntax error,
233233
// should throw (GH-4012)
234234
{
235235
send: 'new RegExp("foo", "wrong modifier");',
236-
expect: ['Thrown:', /^SyntaxError: /]
236+
expect: [/^Uncaught SyntaxError: /]
237237
},
238238
// Strict mode syntax errors should be caught (GH-5178)
239239
{
240240
send: '(function() { "use strict"; return 0755; })()',
241241
expect: [
242-
'Thrown:',
243242
kSource,
244243
kArrow,
245244
'',
246-
/^SyntaxError: /
245+
/^Uncaught SyntaxError: /
247246
]
248247
},
249248
{
250249
send: '(function(a, a, b) { "use strict"; return a + b + c; })()',
251250
expect: [
252-
'Thrown:',
253251
kSource,
254252
kArrow,
255253
'',
256-
/^SyntaxError: /
254+
/^Uncaught SyntaxError: /
257255
]
258256
},
259257
{
260258
send: '(function() { "use strict"; with (this) {} })()',
261259
expect: [
262-
'Thrown:',
263260
kSource,
264261
kArrow,
265262
'',
266-
/^SyntaxError: /
263+
/^Uncaught SyntaxError: /
267264
]
268265
},
269266
{
270267
send: '(function() { "use strict"; var x; delete x; })()',
271268
expect: [
272-
'Thrown:',
273269
kSource,
274270
kArrow,
275271
'',
276-
/^SyntaxError: /
272+
/^Uncaught SyntaxError: /
277273
]
278274
},
279275
{
280276
send: '(function() { "use strict"; eval = 17; })()',
281277
expect: [
282-
'Thrown:',
283278
kSource,
284279
kArrow,
285280
'',
286-
/^SyntaxError: /
281+
/^Uncaught SyntaxError: /
287282
]
288283
},
289284
{
290285
send: '(function() { "use strict"; if (true) function f() { } })()',
291286
expect: [
292-
'Thrown:',
293287
kSource,
294288
kArrow,
295289
'',
290+
'Uncaught:',
296291
/^SyntaxError: /
297292
]
298293
},
@@ -413,11 +408,10 @@ const errorTests = [
413408
{
414409
send: '[] \\',
415410
expect: [
416-
'Thrown:',
417411
kSource,
418412
kArrow,
419413
'',
420-
/^SyntaxError: /
414+
/^Uncaught SyntaxError: /
421415
]
422416
},
423417
// Do not fail when a String is created with line continuation
@@ -548,8 +542,7 @@ const errorTests = [
548542
{
549543
send: 'require("internal/repl")',
550544
expect: [
551-
'Thrown:',
552-
/^Error: Cannot find module 'internal\/repl'/,
545+
/^Uncaught Error: Cannot find module 'internal\/repl'/,
553546
/^Require stack:/,
554547
/^- <repl>/,
555548
/^ at .*/,
@@ -587,11 +580,10 @@ const errorTests = [
587580
{
588581
send: 'a = 3.5e',
589582
expect: [
590-
'Thrown:',
591583
kSource,
592584
kArrow,
593585
'',
594-
/^SyntaxError: /
586+
/^Uncaught SyntaxError: /
595587
]
596588
},
597589
// Mitigate https://github.com/nodejs/node/issues/548
@@ -607,22 +599,20 @@ const errorTests = [
607599
{
608600
send: 'a = 3.5e',
609601
expect: [
610-
'Thrown:',
611602
kSource,
612603
kArrow,
613604
'',
614-
/^SyntaxError: /
605+
/^Uncaught SyntaxError: /
615606
]
616607
},
617608
// Avoid emitting stack trace
618609
{
619610
send: 'a = 3.5e',
620611
expect: [
621-
'Thrown:',
622612
kSource,
623613
kArrow,
624614
'',
625-
/^SyntaxError: /
615+
/^Uncaught SyntaxError: /
626616
]
627617
},
628618

@@ -687,11 +677,10 @@ const errorTests = [
687677
{
688678
send: '...[]',
689679
expect: [
690-
'Thrown:',
691680
kSource,
692681
kArrow,
693682
'',
694-
/^SyntaxError: /
683+
/^Uncaught SyntaxError: /
695684
]
696685
},
697686
// Bring back the repl to prompt
@@ -702,31 +691,28 @@ const errorTests = [
702691
{
703692
send: 'console.log("Missing comma in arg list" process.version)',
704693
expect: [
705-
'Thrown:',
706694
kSource,
707695
kArrow,
708696
'',
709-
/^SyntaxError: /
697+
/^Uncaught SyntaxError: /
710698
]
711699
},
712700
{
713701
send: 'x = {\nfield\n{',
714702
expect: [
715-
'... ... Thrown:',
716-
'{',
703+
'... ... {',
717704
kArrow,
718705
'',
719-
/^SyntaxError: /
706+
/^Uncaught SyntaxError: /
720707
]
721708
},
722709
{
723710
send: '(2 + 3))',
724711
expect: [
725-
'Thrown:',
726712
kSource,
727713
kArrow,
728714
'',
729-
/^SyntaxError: /
715+
/^Uncaught SyntaxError: /
730716
]
731717
},
732718
{
@@ -740,11 +726,10 @@ const errorTests = [
740726
{
741727
send: '} else {',
742728
expect: [
743-
'Thrown:',
744729
kSource,
745730
kArrow,
746731
'',
747-
/^SyntaxError: /
732+
/^Uncaught SyntaxError: /
748733
]
749734
},
750735
];

0 commit comments

Comments
 (0)
Please sign in to comment.