mirror of
https://github.com/nodejs/node.git
synced 2025-08-15 13:48:44 +02:00
repl: handle errors from getters during completion
PR-URL: https://github.com/nodejs/node/pull/59044 Reviewed-By: Dario Piotrowicz <dario.piotrowicz@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
This commit is contained in:
parent
35e599b3d0
commit
c8d5b394e4
2 changed files with 63 additions and 3 deletions
15
lib/repl.js
15
lib/repl.js
|
@ -1837,7 +1837,7 @@ function includesProxiesOrGetters(expr, exprStr, evalFn, ctx, callback) {
|
|||
if (astProp.type === 'Literal') {
|
||||
// We have something like `obj['foo'].x` where `x` is the literal
|
||||
|
||||
if (isProxy(obj[astProp.value])) {
|
||||
if (safeIsProxyAccess(obj, astProp.value)) {
|
||||
return cb(true);
|
||||
}
|
||||
|
||||
|
@ -1855,7 +1855,7 @@ function includesProxiesOrGetters(expr, exprStr, evalFn, ctx, callback) {
|
|||
) {
|
||||
// We have something like `obj.foo.x` where `foo` is the identifier
|
||||
|
||||
if (isProxy(obj[astProp.name])) {
|
||||
if (safeIsProxyAccess(obj, astProp.name)) {
|
||||
return cb(true);
|
||||
}
|
||||
|
||||
|
@ -1882,7 +1882,7 @@ function includesProxiesOrGetters(expr, exprStr, evalFn, ctx, callback) {
|
|||
}
|
||||
|
||||
if (typeof evaledProp === 'string') {
|
||||
if (isProxy(obj[evaledProp])) {
|
||||
if (safeIsProxyAccess(obj, evaledProp)) {
|
||||
return cb(true);
|
||||
}
|
||||
|
||||
|
@ -1899,6 +1899,15 @@ function includesProxiesOrGetters(expr, exprStr, evalFn, ctx, callback) {
|
|||
);
|
||||
}
|
||||
|
||||
function safeIsProxyAccess(obj, prop) {
|
||||
// Accessing `prop` may trigger a getter that throws, so we use try-catch to guard against it
|
||||
try {
|
||||
return isProxy(obj[prop]);
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return callback(false);
|
||||
}
|
||||
|
||||
|
|
51
test/parallel/test-repl-tab-complete-getter-error.js
Normal file
51
test/parallel/test-repl-tab-complete-getter-error.js
Normal file
|
@ -0,0 +1,51 @@
|
|||
'use strict';
|
||||
|
||||
const common = require('../common');
|
||||
const repl = require('repl');
|
||||
const ArrayStream = require('../common/arraystream');
|
||||
const assert = require('assert');
|
||||
|
||||
(async function() {
|
||||
await runTest();
|
||||
})().then(common.mustCall());
|
||||
|
||||
async function runTest() {
|
||||
const input = new ArrayStream();
|
||||
const output = new ArrayStream();
|
||||
|
||||
const replServer = repl.start({
|
||||
prompt: '',
|
||||
input,
|
||||
output: output,
|
||||
allowBlockingCompletions: true,
|
||||
terminal: true
|
||||
});
|
||||
|
||||
replServer._domain.on('error', (e) => {
|
||||
assert.fail(`Error in REPL domain: ${e}`);
|
||||
});
|
||||
|
||||
await new Promise((resolve, reject) => {
|
||||
replServer.eval(`
|
||||
const getNameText = () => "name";
|
||||
const foo = { get name() { throw new Error(); } };
|
||||
`, replServer.context, '', (err) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
['foo.name.', 'foo["name"].', 'foo[getNameText()].'].forEach((test) => {
|
||||
replServer.complete(
|
||||
test,
|
||||
common.mustCall((error, data) => {
|
||||
assert.strictEqual(error, null);
|
||||
assert.strictEqual(data.length, 2);
|
||||
assert.strictEqual(data[1], test);
|
||||
})
|
||||
);
|
||||
});
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue