Skip to content
31 changes: 22 additions & 9 deletions src/jsc/bindings/bindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6774,7 +6774,12 @@ extern "C" JSC::EncodedJSValue Bun__REPL__getCompletions(
size_t prefixLen)
{
auto& vm = JSC::getVM(globalObject);
auto scope = DECLARE_THROW_SCOPE(vm);
// The Rust caller (repl.rs) has no exception scope, so nothing may escape.
auto scope = DECLARE_TOP_EXCEPTION_SCOPE(vm);
auto clearAndEncode = [&](JSC::JSValue v) {
scope.clearException();
return JSC::JSValue::encode(v);
};

JSC::JSValue target = JSC::JSValue::decode(targetValue);
if (!target || target.isUndefined() || target.isNull()) {
Expand All @@ -6783,7 +6788,8 @@ extern "C" JSC::EncodedJSValue Bun__REPL__getCompletions(

if (!target.isObject()) {
JSObject* boxed = target.toObject(globalObject);
RETURN_IF_EXCEPTION(scope, JSC::JSValue::encode(JSC::jsUndefined()));
if (scope.exception()) [[unlikely]]
return clearAndEncode(JSC::jsUndefined());
target = boxed;
}

Expand All @@ -6794,40 +6800,47 @@ extern "C" JSC::EncodedJSValue Bun__REPL__getCompletions(
JSC::JSObject* object = target.getObject();
JSC::PropertyNameArrayBuilder propertyNames(vm, JSC::PropertyNameMode::Strings, JSC::PrivateSymbolMode::Exclude);
object->getPropertyNames(globalObject, propertyNames, DontEnumPropertiesMode::Include);
RETURN_IF_EXCEPTION(scope, JSC::JSValue::encode(JSC::jsUndefined()));
if (scope.exception()) [[unlikely]]
return clearAndEncode(JSC::jsUndefined());

JSC::JSArray* completions = JSC::constructEmptyArray(globalObject, nullptr, 0);
RETURN_IF_EXCEPTION(scope, JSC::JSValue::encode(JSC::jsUndefined()));
if (scope.exception()) [[unlikely]]
return clearAndEncode(JSC::jsUndefined());

unsigned completionIndex = 0;
for (const auto& propertyName : propertyNames) {
WTF::String name = propertyName.string();
if (prefix.isEmpty() || name.startsWith(prefix)) {
completions->putDirectIndex(globalObject, completionIndex++, JSC::jsString(vm, name));
RETURN_IF_EXCEPTION(scope, JSC::JSValue::encode(JSC::jsUndefined()));
if (scope.exception()) [[unlikely]]
return clearAndEncode(JSC::jsUndefined());
}
}

// Also check the prototype chain
JSC::JSValue proto = object->getPrototype(globalObject);
RETURN_IF_EXCEPTION(scope, JSC::JSValue::encode(completions));
if (scope.exception()) [[unlikely]]
return clearAndEncode(completions);

while (proto && proto.isObject()) {
JSC::JSObject* protoObj = proto.getObject();
JSC::PropertyNameArrayBuilder protoNames(vm, JSC::PropertyNameMode::Strings, JSC::PrivateSymbolMode::Exclude);
protoObj->getPropertyNames(globalObject, protoNames, DontEnumPropertiesMode::Include);
RETURN_IF_EXCEPTION(scope, JSC::JSValue::encode(completions));
if (scope.exception()) [[unlikely]]
return clearAndEncode(completions);

for (const auto& propertyName : protoNames) {
WTF::String name = propertyName.string();
if (prefix.isEmpty() || name.startsWith(prefix)) {
completions->putDirectIndex(globalObject, completionIndex++, JSC::jsString(vm, name));
RETURN_IF_EXCEPTION(scope, JSC::JSValue::encode(completions));
if (scope.exception()) [[unlikely]]
return clearAndEncode(completions);
}
}

proto = protoObj->getPrototype(globalObject);
RETURN_IF_EXCEPTION(scope, JSC::JSValue::encode(completions));
if (scope.exception()) [[unlikely]]
return clearAndEncode(completions);
Comment thread
claude[bot] marked this conversation as resolved.
Outdated
}

return JSC::JSValue::encode(completions);
Expand Down
Loading
Loading