From a58c2a90508ecb2a12cbc58cc47b713bcd95dfda Mon Sep 17 00:00:00 2001 From: Kai Tamkun Date: Fri, 2 May 2025 19:38:22 -0700 Subject: [PATCH] getModuleRequests --- src/bun.js/bindings/NodeVM.cpp | 22 ++++++++++++++++++---- src/bun.js/bindings/NodeVM.h | 1 + src/js/internal/primordials.js | 23 +++++++++++++++++++++++ src/js/node/vm.ts | 6 +++--- 4 files changed, 45 insertions(+), 7 deletions(-) diff --git a/src/bun.js/bindings/NodeVM.cpp b/src/bun.js/bindings/NodeVM.cpp index 89cbc6d52a..29bcf467a5 100644 --- a/src/bun.js/bindings/NodeVM.cpp +++ b/src/bun.js/bindings/NodeVM.cpp @@ -1916,10 +1916,14 @@ public: JSObject* namespace_() const { return m_namespace.get(); } void namespace_(VM& vm, JSObject* value) { m_namespace.set(vm, this, value); } + const WTF::Vector& moduleRequests() const { return m_moduleRequests; } + void addModuleRequest(NodeVMModuleRequest request) { m_moduleRequests.append(WTFMove(request)); } + protected: WTF::String m_identifier; Status m_status = Status::Unlinked; mutable WriteBarrier m_namespace; + WTF::Vector m_moduleRequests; NodeVMModule(JSC::VM& vm, JSC::Structure* structure, WTF::String identifier) : Base(vm, structure) @@ -2005,8 +2009,10 @@ NodeVMSourceTextModule* NodeVMSourceTextModule::create(VM& vm, JSGlobalObject* g } JSValue contextValue = args.at(1); - if (!contextValue.isObject()) { - // TODO(@heimskr): if undefined, use current execution context + if (contextValue.isUndefined()) { + // TODO(@heimskr): should this be `globalObject->globalThis()` instead? + contextValue = globalObject; + } else if (!contextValue.isObject()) { throwArgumentTypeError(*globalObject, scope, 1, "context"_s, "Module"_s, "Module"_s, "object"_s); return nullptr; } @@ -2108,8 +2114,16 @@ JSC_DEFINE_HOST_FUNCTION(jsNodeVmModuleGetError, (JSC::JSGlobalObject * globalOb JSC_DEFINE_HOST_FUNCTION(jsNodeVmModuleGetModuleRequests, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) { - // auto* thisObject = jsCast(callFrame->thisValue()); - return JSC::encodedJSUndefined(); + auto* thisObject = jsCast(callFrame->thisValue()); + const WTF::Vector& requests = thisObject->moduleRequests(); + + JSArray* array = constructEmptyArray(globalObject, nullptr, requests.size()); + + for (unsigned i = 0; const NodeVMModuleRequest& request : requests) { + array->putDirectIndex(globalObject, i++, request.toJS(globalObject)); + } + + return JSValue::encode(array); } JSC_DEFINE_HOST_FUNCTION(jsNodeVmModuleEvaluate, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) diff --git a/src/bun.js/bindings/NodeVM.h b/src/bun.js/bindings/NodeVM.h index 5e0e692170..bebac6c878 100644 --- a/src/bun.js/bindings/NodeVM.h +++ b/src/bun.js/bindings/NodeVM.h @@ -32,6 +32,7 @@ public: void finishCreation(JSC::VM&); static void destroy(JSCell* cell); void setContextifiedObject(JSC::JSObject* contextifiedObject); + JSC::JSObject* contextifiedObject() const { return m_sandbox.get(); } void clearContextifiedObject(); // Override property access to delegate to contextified object diff --git a/src/js/internal/primordials.js b/src/js/internal/primordials.js index d478237597..9c9a79148d 100644 --- a/src/js/internal/primordials.js +++ b/src/js/internal/primordials.js @@ -94,7 +94,29 @@ const arrayToSafePromiseIterable = (promises, mapFn) => ), ); const PromiseAll = Promise.all; +const PromiseResolve = Promise.resolve; const SafePromiseAll = (promises, mapFn) => PromiseAll(arrayToSafePromiseIterable(promises, mapFn)); +const SafePromiseAllReturnArrayLike = (promises, mapFn) => + new Promise((resolve, reject) => { + const { length } = promises; + + const returnVal = Array(length); + ObjectSetPrototypeOf(returnVal, null); + if (length === 0) resolve(returnVal); + + let pendingPromises = length; + for (let i = 0; i < length; i++) { + const promise = mapFn != null ? mapFn(promises[i], i) : promises[i]; + PromisePrototypeThen( + PromiseResolve(promise), + result => { + returnVal[i] = result; + if (--pendingPromises === 0) resolve(returnVal); + }, + reject, + ); + } + }); export default { Array, @@ -113,6 +135,7 @@ export default { }, ), SafePromiseAll, + SafePromiseAllReturnArrayLike, SafeSet: makeSafe( Set, class SafeSet extends Set { diff --git a/src/js/node/vm.ts b/src/js/node/vm.ts index e14cb839dc..558a69c752 100644 --- a/src/js/node/vm.ts +++ b/src/js/node/vm.ts @@ -9,7 +9,7 @@ const { validateBuffer, validateFunction, } = require("internal/validators"); -const { SafePromiseAll } = require("internal/primordials"); +const { SafePromiseAllReturnArrayLike } = require("internal/primordials"); const vm = $cpp("NodeVM.cpp", "Bun::createNodeVMBinding"); @@ -267,7 +267,7 @@ class SourceTextModule extends Module { } try { - const modules = await SafePromiseAll(modulePromises); + const modules = await SafePromiseAllReturnArrayLike(modulePromises); this[kNative].link(specifiers, modules); } catch (e) { this.#error = e; @@ -279,7 +279,7 @@ class SourceTextModule extends Module { get dependencySpecifiers() { this[kDependencySpecifiers] ??= ObjectFreeze( - ArrayPrototypeMap.$call(this[kNative].getModuleRequests(), request => request.specifier), + ArrayPrototypeMap.$call(this[kNative].getModuleRequests(), request => request[0]), ); return this[kDependencySpecifiers]; }