Skip to content

Commit 7108179

Browse files
repl: fix getters triggering side effects during completion
1 parent 4f24aff commit 7108179

File tree

3 files changed

+56
-62
lines changed

3 files changed

+56
-62
lines changed

lib/internal/repl/completion.js

Lines changed: 29 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -732,16 +732,20 @@ function includesProxiesOrGetters(expr, exprStr, evalFn, ctx, callback) {
732732
if (astProp.type === 'Literal') {
733733
// We have something like `obj['foo'].x` where `x` is the literal
734734

735-
if (safeIsProxyAccess(obj, astProp.value)) {
736-
return cb(true);
737-
}
738-
739735
const propDescriptor = ObjectGetOwnPropertyDescriptor(
740736
obj,
741737
`${astProp.value}`,
742738
);
743739
const propHasGetter = typeof propDescriptor?.get === 'function';
744-
return cb(propHasGetter);
740+
if (propHasGetter) {
741+
return cb(true);
742+
}
743+
744+
if (isProxy(obj[astProp.value])) {
745+
return cb(true);
746+
}
747+
748+
return cb(false);
745749
}
746750

747751
if (
@@ -750,16 +754,20 @@ function includesProxiesOrGetters(expr, exprStr, evalFn, ctx, callback) {
750754
) {
751755
// We have something like `obj.foo.x` where `foo` is the identifier
752756

753-
if (safeIsProxyAccess(obj, astProp.name)) {
754-
return cb(true);
755-
}
756-
757757
const propDescriptor = ObjectGetOwnPropertyDescriptor(
758758
obj,
759759
`${astProp.name}`,
760760
);
761761
const propHasGetter = typeof propDescriptor?.get === 'function';
762-
return cb(propHasGetter);
762+
if (propHasGetter) {
763+
return cb(true);
764+
}
765+
766+
if (isProxy(obj[astProp.name])) {
767+
return cb(true);
768+
}
769+
770+
return cb(false);
763771
}
764772

765773
return evalFn(
@@ -773,36 +781,31 @@ function includesProxiesOrGetters(expr, exprStr, evalFn, ctx, callback) {
773781
getREPLResourceName(),
774782
(err, evaledProp) => {
775783
if (err) {
776-
return callback(false);
784+
return cb(false);
777785
}
778786

779787
if (typeof evaledProp === 'string') {
780-
if (safeIsProxyAccess(obj, evaledProp)) {
781-
return cb(true);
782-
}
783-
784788
const propDescriptor = ObjectGetOwnPropertyDescriptor(
785789
obj,
786790
evaledProp,
787791
);
788792
const propHasGetter = typeof propDescriptor?.get === 'function';
789-
return cb(propHasGetter);
793+
if (propHasGetter) {
794+
return cb(true);
795+
}
796+
797+
if (isProxy(obj[evaledProp])) {
798+
return cb(true);
799+
}
800+
801+
return cb(false);
790802
}
791803

792-
return callback(false);
804+
return cb(false);
793805
},
794806
);
795807
}
796808

797-
function safeIsProxyAccess(obj, prop) {
798-
// Accessing `prop` may trigger a getter that throws, so we use try-catch to guard against it
799-
try {
800-
return isProxy(obj[prop]);
801-
} catch {
802-
return false;
803-
}
804-
}
805-
806809
return callback(false);
807810
}
808811

test/parallel/test-repl-completion-on-getters-disabled.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,33 @@ describe('REPL completion in relation of getters', () => {
115115
['objWithGetters[getGFooKey()].b', []],
116116
]);
117117
});
118+
119+
test('no side effects are triggered for getters during completion', async () => {
120+
const { replServer } = startNewREPLServer();
121+
122+
await new Promise((resolve, reject) => {
123+
replServer.eval('const foo = { get name() { globalThis.nameGetterRun = true; throw new Error(); } };',
124+
replServer.context, '', (err) => {
125+
if (err) {
126+
reject(err);
127+
} else {
128+
resolve();
129+
}
130+
});
131+
});
132+
133+
['foo.name.', 'foo["name"].'].forEach((test) => {
134+
replServer.complete(
135+
test,
136+
common.mustCall((error, data) => {
137+
// The context's nameGetterRun variable hasn't been set
138+
assert.strictEqual(replServer.context.nameGetterRun, undefined);
139+
// No errors has been thrown
140+
assert.strictEqual(error, null);
141+
})
142+
);
143+
});
144+
});
118145
});
119146

120147
describe('completions on proxies', () => {

test/parallel/test-repl-tab-complete-getter-error.js

Lines changed: 0 additions & 36 deletions
This file was deleted.

0 commit comments

Comments
 (0)