diff --git a/src/bun.js/bindings/BunObject.cpp b/src/bun.js/bindings/BunObject.cpp index a694f5c86a..640e901799 100644 --- a/src/bun.js/bindings/BunObject.cpp +++ b/src/bun.js/bindings/BunObject.cpp @@ -1,3 +1,4 @@ + #include "root.h" #include "JavaScriptCore/HeapProfiler.h" @@ -37,6 +38,7 @@ #include "ErrorCode.h" #include "GeneratedBunObject.h" #include "JavaScriptCore/BunV8HeapSnapshotBuilder.h" +#include "BunObjectModule.h" #ifdef WIN32 #include @@ -67,11 +69,12 @@ BUN_DECLARE_HOST_FUNCTION(Bun__DNSResolver__cancel); BUN_DECLARE_HOST_FUNCTION(Bun__fetch); BUN_DECLARE_HOST_FUNCTION(Bun__fetchPreconnect); BUN_DECLARE_HOST_FUNCTION(Bun__randomUUIDv7); -namespace Bun { using namespace JSC; using namespace WebCore; +namespace Bun { + extern "C" bool has_bun_garbage_collector_flag_enabled; static JSValue BunObject_getter_wrap_ArrayBufferSink(VM& vm, JSObject* bunObject) @@ -728,13 +731,13 @@ JSC_DEFINE_HOST_FUNCTION(functionFileURLToPath, (JSC::JSGlobalObject * globalObj isMainThread constructIsMainThread ReadOnly|DontDelete|PropertyCallback jest BunObject_callback_jest DontEnum|DontDelete|Function 1 listen BunObject_callback_listen DontDelete|Function 1 - udpSocket BunObject_callback_udpSocket DontDelete|Function 1 + udpSocket BunObject_callback_udpSocket DontDelete|Function 1 main BunObject_getter_wrap_main DontDelete|PropertyCallback mmap BunObject_callback_mmap DontDelete|Function 1 nanoseconds functionBunNanoseconds DontDelete|Function 0 openInEditor BunObject_callback_openInEditor DontDelete|Function 1 - origin BunObject_getter_wrap_origin DontDelete|PropertyCallback - version_with_sha constructBunVersionWithSha ReadOnly|DontDelete|PropertyCallback + origin BunObject_getter_wrap_origin DontEnum|ReadOnly|DontDelete|PropertyCallback + version_with_sha constructBunVersionWithSha DontEnum|ReadOnly|DontDelete|PropertyCallback password constructPasswordObject DontDelete|PropertyCallback pathToFileURL functionPathToFileURL DontDelete|Function 1 peek constructBunPeekObject DontDelete|PropertyCallback @@ -838,4 +841,54 @@ JSC::JSObject* createBunObject(VM& vm, JSObject* globalObject) return JSBunObject::create(vm, jsCast(globalObject)); } +static void exportBunObject(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSObject* object, Vector& exportNames, JSC::MarkedArgumentBuffer& exportValues) +{ + exportNames.reserveCapacity(std::size(bunObjectTableValues) + 1); + exportValues.ensureCapacity(std::size(bunObjectTableValues) + 1); + + PropertyNameArray propertyNames(vm, PropertyNameMode::Strings, PrivateSymbolMode::Exclude); + auto scope = DECLARE_THROW_SCOPE(vm); + object->getOwnNonIndexPropertyNames(globalObject, propertyNames, DontEnumPropertiesMode::Exclude); + RETURN_IF_EXCEPTION(scope, void()); + + for (const auto& propertyName : propertyNames) { + exportNames.append(propertyName); + auto catchScope = DECLARE_CATCH_SCOPE(vm); + + // Yes, we have to call getters :( + JSValue value = object->get(globalObject, propertyName); + + if (catchScope.exception()) { + catchScope.clearException(); + value = jsUndefined(); + } + exportValues.append(value); + } + + exportNames.append(vm.propertyNames->defaultKeyword); + exportValues.append(object); +} + +} + +namespace Zig { +void generateNativeModule_BunObject(JSC::JSGlobalObject* lexicalGlobalObject, + JSC::Identifier moduleKey, + Vector& exportNames, + JSC::MarkedArgumentBuffer& exportValues) +{ + auto& vm = JSC::getVM(lexicalGlobalObject); + Zig::GlobalObject* globalObject = jsCast(lexicalGlobalObject); + + auto scope = DECLARE_THROW_SCOPE(vm); + auto* object = globalObject->bunObject(); + + // :'( + object->reifyAllStaticProperties(lexicalGlobalObject); + + RETURN_IF_EXCEPTION(scope, void()); + + Bun::exportBunObject(vm, globalObject, object, exportNames, exportValues); +} + } diff --git a/src/bun.js/bindings/ModuleLoader.cpp b/src/bun.js/bindings/ModuleLoader.cpp index df7aec6f56..fef63d1cca 100644 --- a/src/bun.js/bindings/ModuleLoader.cpp +++ b/src/bun.js/bindings/ModuleLoader.cpp @@ -539,11 +539,19 @@ JSValue fetchCommonJSModule( auto tag = res->result.value.tag; switch (tag) { + // require("bun") + case SyntheticModuleType::BunObject: { + target->setExportsObject(globalObject->bunObject()); + target->hasEvaluated = true; + RELEASE_AND_RETURN(scope, target); + } + // require("module"), require("node:module") case SyntheticModuleType::NodeModule: { target->setExportsObject(globalObject->m_nodeModuleConstructor.getInitializedOnMainThread(globalObject)); target->hasEvaluated = true; RELEASE_AND_RETURN(scope, target); } + // require("process"), require("node:process") case SyntheticModuleType::NodeProcess: { target->setExportsObject(globalObject->processObject()); target->hasEvaluated = true; diff --git a/src/bun.js/modules/BunObjectModule.cpp b/src/bun.js/modules/BunObjectModule.cpp deleted file mode 100644 index d58fbb0b78..0000000000 --- a/src/bun.js/modules/BunObjectModule.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#include "root.h" - -#include "ZigGlobalObject.h" - -#include "ObjectModule.h" - -namespace Zig { -void generateNativeModule_BunObject(JSC::JSGlobalObject* lexicalGlobalObject, - JSC::Identifier moduleKey, - Vector& exportNames, - JSC::MarkedArgumentBuffer& exportValues) -{ - // FIXME: this does not add each property as a top level export - auto& vm = JSC::getVM(lexicalGlobalObject); - Zig::GlobalObject* globalObject = jsCast(lexicalGlobalObject); - - JSObject* object = globalObject->bunObject(); - - exportNames.append(vm.propertyNames->defaultKeyword); - exportValues.append(object); -} - -} // namespace Zig diff --git a/src/bun.js/modules/_NativeModule.h b/src/bun.js/modules/_NativeModule.h index 506dd05090..7b9e89cb3e 100644 --- a/src/bun.js/modules/_NativeModule.h +++ b/src/bun.js/modules/_NativeModule.h @@ -25,7 +25,6 @@ // given is the default export #define BUN_FOREACH_ESM_AND_CJS_NATIVE_MODULE(macro) \ - macro("bun"_s, BunObject) \ macro("bun:test"_s, BunTest) \ macro("bun:jsc"_s, BunJSC) \ macro("node:buffer"_s, NodeBuffer) \ @@ -38,7 +37,8 @@ #define BUN_FOREACH_ESM_NATIVE_MODULE(macro) \ BUN_FOREACH_ESM_AND_CJS_NATIVE_MODULE(macro) \ macro("node:module"_s, NodeModule) \ - macro("node:process"_s, NodeProcess) + macro("node:process"_s, NodeProcess) \ + macro("bun"_s, BunObject) #define BUN_FOREACH_CJS_NATIVE_MODULE(macro) \ BUN_FOREACH_ESM_AND_CJS_NATIVE_MODULE(macro) diff --git a/test/js/bun/util/BunObject.test.ts b/test/js/bun/util/BunObject.test.ts new file mode 100644 index 0000000000..9b58ef98dd --- /dev/null +++ b/test/js/bun/util/BunObject.test.ts @@ -0,0 +1,21 @@ +import { expect, test } from "bun:test"; + +test("require('bun')", () => { + const str = eval("'bun'"); + expect(require(str)).toBe(Bun); +}); + +test("await import('bun')", async () => { + const str = eval("'bun'"); + const BunESM = await import(str); + + // console.log it so that we iterate through all the fields and crash if it's + // in an unexpected state. + console.log(BunESM); + + for (let property in Bun) { + expect(BunESM).toHaveProperty(property); + expect(BunESM[property]).toBe(Bun[property]); + } + expect(BunESM.default).toBe(Bun); +});