repl: do not swallow errors in nested REPLs
For tab completion, a REPLServer instance will sometimes create another REPLServer instance. If a callback is sent to the `.complete()` function and that callback throws an error, it will be swallowed by the nested REPLs domain. Re-throw the error so that processes don't silently exit without any indication of an error (including a status code). Fixes: https://github.com/nodejs/node/issues/21586 PR-URL: https://github.com/nodejs/node/pull/23004 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com> Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de> Reviewed-By: Ujjwal Sharma <usharma1998@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
This commit is contained in:
parent
b3b3f53a33
commit
83d0404971
@ -1002,6 +1002,7 @@ function complete(line, callback) {
|
|||||||
// all this is only profitable if the nested REPL
|
// all this is only profitable if the nested REPL
|
||||||
// does not have a bufferedCommand
|
// does not have a bufferedCommand
|
||||||
if (!magic[kBufferedCommandSymbol]) {
|
if (!magic[kBufferedCommandSymbol]) {
|
||||||
|
magic._domain.on('error', (err) => { throw err; });
|
||||||
return magic.complete(line, callback);
|
return magic.complete(line, callback);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
50
test/fixtures/repl-tab-completion-nested-repls.js
vendored
Normal file
50
test/fixtures/repl-tab-completion-nested-repls.js
vendored
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
// Tab completion sometimes uses a separate REPL instance under the hood.
|
||||||
|
// That REPL instance has its own domain. Make sure domain errors trickle back
|
||||||
|
// up to the main REPL.
|
||||||
|
//
|
||||||
|
// Ref: https://github.com/nodejs/node/issues/21586
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const { Stream } = require('stream');
|
||||||
|
const { inherits } = require('util');
|
||||||
|
function noop() {}
|
||||||
|
|
||||||
|
// A stream to push an array into a REPL
|
||||||
|
function ArrayStream() {
|
||||||
|
this.run = function(data) {
|
||||||
|
data.forEach((line) => {
|
||||||
|
this.emit('data', `${line}\n`);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
inherits(ArrayStream, Stream);
|
||||||
|
ArrayStream.prototype.readable = true;
|
||||||
|
ArrayStream.prototype.writable = true;
|
||||||
|
ArrayStream.prototype.pause = noop;
|
||||||
|
ArrayStream.prototype.resume = noop;
|
||||||
|
ArrayStream.prototype.write = noop;
|
||||||
|
|
||||||
|
const repl = require('repl');
|
||||||
|
|
||||||
|
const putIn = new ArrayStream();
|
||||||
|
const testMe = repl.start('', putIn);
|
||||||
|
|
||||||
|
// Some errors are passed to the domain, but do not callback
|
||||||
|
testMe._domain.on('error', function(err) {
|
||||||
|
throw err;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Nesting of structures causes REPL to use a nested REPL for completion.
|
||||||
|
putIn.run([
|
||||||
|
'var top = function() {',
|
||||||
|
'r = function test (',
|
||||||
|
' one, two) {',
|
||||||
|
'var inner = {',
|
||||||
|
' one:1',
|
||||||
|
'};'
|
||||||
|
]);
|
||||||
|
|
||||||
|
// In Node.js 10.11.0, this next line will terminate the repl silently...
|
||||||
|
testMe.complete('inner.o', () => { throw new Error('fhqwhgads'); });
|
21
test/parallel/test-repl-tab-complete-nested-repls.js
Normal file
21
test/parallel/test-repl-tab-complete-nested-repls.js
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
// Tab completion sometimes uses a separate REPL instance under the hood.
|
||||||
|
// That REPL instance has its own domain. Make sure domain errors trickle back
|
||||||
|
// up to the main REPL.
|
||||||
|
//
|
||||||
|
// Ref: https://github.com/nodejs/node/issues/21586
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
require('../common');
|
||||||
|
const fixtures = require('../common/fixtures');
|
||||||
|
|
||||||
|
const assert = require('assert');
|
||||||
|
const { spawnSync } = require('child_process');
|
||||||
|
|
||||||
|
const testFile = fixtures.path('repl-tab-completion-nested-repls.js');
|
||||||
|
const result = spawnSync(process.execPath, [testFile]);
|
||||||
|
|
||||||
|
// The spawned process will fail. In Node.js 10.11.0, it will fail silently. The
|
||||||
|
// test here is to make sure that the error information bubbles up to the
|
||||||
|
// calling process.
|
||||||
|
assert.ok(result.status, 'testFile swallowed its error');
|
@ -154,9 +154,8 @@ putIn.run([
|
|||||||
' one:1',
|
' one:1',
|
||||||
'};'
|
'};'
|
||||||
]);
|
]);
|
||||||
// See: https://github.com/nodejs/node/issues/21586
|
|
||||||
// testMe.complete('inner.o', getNoResultsFunction());
|
|
||||||
testMe.complete('inner.o', common.mustCall(function(error, data) {
|
testMe.complete('inner.o', common.mustCall(function(error, data) {
|
||||||
|
assert.deepStrictEqual(data, works);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
putIn.run(['.clear']);
|
putIn.run(['.clear']);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user