From c2a77cf7ec9de9eadf938046bdf78e58561c8a6d Mon Sep 17 00:00:00 2001 From: dave caruso Date: Wed, 2 Aug 2023 16:27:36 -0700 Subject: Rewrite built-in modules to use CommonJS over ESM (#3814) * stfdsafsd sadffdsa stuff finish commonjs stuff asdf not done but work not done but work not done yet but this is how far i am remove files lol update built files uncomment everything in events lol export default stuff * afdsafsd * its not perfect but almost done * okay * cool * remove temp file * finish rebase * revert settings.json * a * ch-ch-ch-ch-changes * okay * remove this check in release for now * sxdcfghnjm, * lkjhgf * fmt * filename can be null * Update NodeModuleModule.h * weee * fmt --------- Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com> --- src/bun.js/modules/NodeModuleModule.h | 324 +++++++++++++++++++++++++++++++++- 1 file changed, 316 insertions(+), 8 deletions(-) (limited to 'src/bun.js/modules/NodeModuleModule.h') diff --git a/src/bun.js/modules/NodeModuleModule.h b/src/bun.js/modules/NodeModuleModule.h index 0aefdef12..e51f2ac86 100644 --- a/src/bun.js/modules/NodeModuleModule.h +++ b/src/bun.js/modules/NodeModuleModule.h @@ -1,12 +1,320 @@ -#include "../bindings/ZigGlobalObject.h" -#include "JavaScriptCore/JSGlobalObject.h" +#include "CommonJSModuleRecord.h" +#include "ImportMetaObject.h" +#include "JavaScriptCore/JSBoundFunction.h" +#include "JavaScriptCore/ObjectConstructor.h" +#include "_NativeModule.h" + +using namespace Zig; +using namespace JSC; + +// This is a mix of bun's builtin module names and also the ones reported by +// node v20.4.0 +static constexpr ASCIILiteral builtinModuleNames[] = { + "_http_agent"_s, + "_http_client"_s, + "_http_common"_s, + "_http_incoming"_s, + "_http_outgoing"_s, + "_http_server"_s, + "_stream_duplex"_s, + "_stream_passthrough"_s, + "_stream_readable"_s, + "_stream_transform"_s, + "_stream_wrap"_s, + "_stream_writable"_s, + "_tls_common"_s, + "_tls_wrap"_s, + "assert"_s, + "assert/strict"_s, + "async_hooks"_s, + "buffer"_s, + "bun"_s, + "bun:ffi"_s, + "bun:jsc"_s, + "bun:sqlite"_s, + "bun:wrap"_s, + "child_process"_s, + "cluster"_s, + "console"_s, + "constants"_s, + "crypto"_s, + "detect-libc"_s, + "dgram"_s, + "diagnostics_channel"_s, + "dns"_s, + "dns/promises"_s, + "domain"_s, + "events"_s, + "fs"_s, + "fs/promises"_s, + "http"_s, + "http2"_s, + "https"_s, + "inspector"_s, + "inspector/promises"_s, + "module"_s, + "net"_s, + "os"_s, + "path"_s, + "path/posix"_s, + "path/win32"_s, + "perf_hooks"_s, + "process"_s, + "punycode"_s, + "querystring"_s, + "readline"_s, + "readline/promises"_s, + "repl"_s, + "stream"_s, + "stream/consumers"_s, + "stream/promises"_s, + "stream/web"_s, + "string_decoder"_s, + "sys"_s, + "timers"_s, + "timers/promises"_s, + "tls"_s, + "trace_events"_s, + "tty"_s, + "undici"_s, + "url"_s, + "util"_s, + "util/types"_s, + "v8"_s, + "vm"_s, + "wasi"_s, + "worker_threads"_s, + "ws"_s, + "zlib"_s, +}; + +static bool isBuiltinModule(const String &namePossiblyWithNodePrefix) { + String name = namePossiblyWithNodePrefix; + if (name.startsWith("node:"_s)) + name = name.substringSharingImpl(5); + + for (auto &builtinModule : builtinModuleNames) { + if (name == builtinModule) + return true; + } + return false; +} + +JSC_DEFINE_HOST_FUNCTION(jsFunctionNodeModuleModuleConstructor, + (JSC::JSGlobalObject * globalObject, + JSC::CallFrame *callFrame)) { + // In node, this is supposed to be the actual CommonJSModule constructor. + // We are cutting a huge corner by not doing all that work. + // This code is only to support babel. + JSC::VM &vm = globalObject->vm(); + JSString *idString = JSC::jsString(vm, WTF::String("."_s)); + + JSString *dirname = jsEmptyString(vm); + + // TODO: handle when JSGlobalObject !== Zig::GlobalObject, such as in node:vm + Structure *structure = static_cast(globalObject) + ->CommonJSModuleObjectStructure(); + + // TODO: handle ShadowRealm, node:vm, new.target, subclasses + JSValue idValue = callFrame->argument(0); + JSValue parentValue = callFrame->argument(1); + + auto scope = DECLARE_THROW_SCOPE(vm); + if (idValue.isString()) { + idString = idValue.toString(globalObject); + RETURN_IF_EXCEPTION(scope, JSC::JSValue::encode(JSC::jsUndefined())); + + auto index = idString->tryGetValue().reverseFind('/', idString->length()); + + if (index != WTF::notFound) { + dirname = JSC::jsSubstring(globalObject, idString, 0, index); + } + } + + auto *out = Bun::JSCommonJSModule::create(vm, structure, idString, jsNull(), + dirname, nullptr); + + if (!parentValue.isUndefined()) + out->putDirect(vm, JSC::Identifier::fromString(vm, "parent"_s), parentValue, + 0); + + return JSValue::encode(out); +} + +JSC_DEFINE_HOST_FUNCTION(jsFunctionIsBuiltinModule, + (JSC::JSGlobalObject * globalObject, + JSC::CallFrame *callFrame)) { + JSC::VM &vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + JSValue moduleName = callFrame->argument(0); + if (!moduleName.isString()) { + return JSValue::encode(jsBoolean(false)); + } + + auto moduleStr = moduleName.toWTFString(globalObject); + RETURN_IF_EXCEPTION(scope, JSValue::encode(jsBoolean(false))); + + return JSValue::encode(jsBoolean(isBuiltinModule(moduleStr))); +} + +JSC_DEFINE_HOST_FUNCTION(jsFunctionNodeModuleCreateRequire, + (JSC::JSGlobalObject * globalObject, + JSC::CallFrame *callFrame)) { + JSC::VM &vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + if (callFrame->argumentCount() < 1) { + throwTypeError(globalObject, scope, + "createRequire() requires at least one argument"_s); + RELEASE_AND_RETURN(scope, JSC::JSValue::encode(JSC::jsUndefined())); + } + + auto val = callFrame->uncheckedArgument(0).toWTFString(globalObject); + RETURN_IF_EXCEPTION(scope, JSC::JSValue::encode(JSC::jsUndefined())); + RELEASE_AND_RETURN( + scope, JSValue::encode(Bun::JSCommonJSModule::createBoundRequireFunction( + vm, globalObject, val))); +} +extern "C" EncodedJSValue Resolver__nodeModulePathsForJS(JSGlobalObject *, + CallFrame *); + +JSC_DEFINE_HOST_FUNCTION(jsFunctionFindSourceMap, + (JSGlobalObject * globalObject, + CallFrame *callFrame)) { + auto &vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + throwException(globalObject, scope, + createError(globalObject, "Not implemented"_s)); + return JSValue::encode(jsUndefined()); +} + +JSC_DEFINE_HOST_FUNCTION(jsFunctionSyncBuiltinExports, + (JSGlobalObject * globalObject, + CallFrame *callFrame)) { + return JSValue::encode(jsUndefined()); +} + +JSC_DEFINE_HOST_FUNCTION(jsFunctionSourceMap, (JSGlobalObject * globalObject, + CallFrame *callFrame)) { + auto &vm = globalObject->vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + throwException(globalObject, scope, + createError(globalObject, "Not implemented"_s)); + return JSValue::encode(jsUndefined()); +} + +JSC_DEFINE_HOST_FUNCTION(jsFunctionResolveFileName, + (JSC::JSGlobalObject * globalObject, + JSC::CallFrame *callFrame)) { + JSC::VM &vm = globalObject->vm(); + + switch (callFrame->argumentCount()) { + case 0: { + auto scope = DECLARE_THROW_SCOPE(globalObject->vm()); + // not "requires" because "require" could be confusing + JSC::throwTypeError( + globalObject, scope, + "Module._resolveFileName needs 2+ arguments (a string)"_s); + scope.release(); + return JSC::JSValue::encode(JSC::JSValue{}); + } + default: { + JSC::JSValue moduleName = callFrame->argument(0); + + if (moduleName.isUndefinedOrNull()) { + auto scope = DECLARE_THROW_SCOPE(globalObject->vm()); + JSC::throwTypeError(globalObject, scope, + "Module._resolveFileName expects a string"_s); + scope.release(); + return JSC::JSValue::encode(JSC::JSValue{}); + } + + auto result = + Bun__resolveSync(globalObject, JSC::JSValue::encode(moduleName), + JSValue::encode(callFrame->argument(1)), false); + auto scope = DECLARE_THROW_SCOPE(globalObject->vm()); + + if (!JSC::JSValue::decode(result).isString()) { + JSC::throwException(globalObject, scope, JSC::JSValue::decode(result)); + return JSC::JSValue::encode(JSC::JSValue{}); + } + + scope.release(); + return result; + } + } +} +template consteval std::size_t countof(T (&)[N]) { + return N; +} namespace Zig { -// node:module -void generateNodeModuleModule(JSC::JSGlobalObject *globalObject, - JSC::Identifier moduleKey, - Vector &exportNames, - JSC::MarkedArgumentBuffer &exportValues); +DEFINE_NATIVE_MODULE(NodeModule) { + // the default object here is a function, so we cant use the INIT_NATIVE_MODULE helper + + Zig::GlobalObject *globalObject = reinterpret_cast(lexicalGlobalObject); + JSC::VM &vm = globalObject->vm(); + JSC::JSObject *defaultObject = JSC::JSFunction::create( + vm, globalObject, 0, "Module"_s, jsFunctionNodeModuleModuleConstructor, + JSC::ImplementationVisibility::Public, JSC::NoIntrinsic, + jsFunctionNodeModuleModuleConstructor); + auto put = [&](JSC::Identifier name, JSC::JSValue value) { + defaultObject->putDirect(vm, name, value); + exportNames.append(name); + exportValues.append(value); + }; + auto putNativeFn = [&](JSC::Identifier name, JSC::NativeFunction ptr) { + JSC::JSFunction *value = JSC::JSFunction::create( + vm, globalObject, 1, name.string(), ptr, + JSC::ImplementationVisibility::Public, JSC::NoIntrinsic, ptr); + defaultObject->putDirect(vm, name, value); + exportNames.append(name); + exportValues.append(value); + }; + exportNames.reserveCapacity(13); + exportValues.ensureCapacity(13); + exportNames.append(vm.propertyNames->defaultKeyword); + exportValues.append(defaultObject); + + putNativeFn(Identifier::fromString(vm, "createRequire"_s), + jsFunctionNodeModuleCreateRequire); + putNativeFn(Identifier::fromString(vm, "paths"_s), + Resolver__nodeModulePathsForJS); + putNativeFn(Identifier::fromString(vm, "findSourceMap"_s), + jsFunctionFindSourceMap); + putNativeFn(Identifier::fromString(vm, "syncBuiltinExports"_s), + jsFunctionSyncBuiltinExports); + putNativeFn(Identifier::fromString(vm, "SourceMap"_s), jsFunctionSourceMap); + putNativeFn(Identifier::fromString(vm, "isBuiltin"_s), + jsFunctionIsBuiltinModule); + putNativeFn(Identifier::fromString(vm, "_resolveFilename"_s), + jsFunctionResolveFileName); + putNativeFn(Identifier::fromString(vm, "_nodeModulePaths"_s), + Resolver__nodeModulePathsForJS); + + put(Identifier::fromString(vm, "_cache"_s), + jsCast(globalObject)->lazyRequireCacheObject()); + + put(Identifier::fromString(vm, "globalPaths"_s), + constructEmptyArray(globalObject, nullptr, 0)); + + put(Identifier::fromString(vm, "prototype"_s), + constructEmptyObject(globalObject)); + + JSC::JSArray *builtinModules = JSC::JSArray::create( + vm, + globalObject->arrayStructureForIndexingTypeDuringAllocation( + ArrayWithContiguous), + countof(builtinModuleNames)); + + for (unsigned i = 0; i < countof(builtinModuleNames); ++i) { + builtinModules->putDirectIndex( + globalObject, i, JSC::jsString(vm, String(builtinModuleNames[i]))); + } + + put(JSC::Identifier::fromString(vm, "builtinModules"_s), builtinModules); + + RETURN_NATIVE_MODULE(); +} -} // namespace Zig \ No newline at end of file +} // namespace Zig -- cgit v1.2.3