aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar dave caruso <me@paperdave.net> 2023-10-02 15:24:38 -0700
committerGravatar dave caruso <me@paperdave.net> 2023-10-02 15:24:38 -0700
commit0160772d25105f302f84013e892fe07f9eeb6f91 (patch)
treeae69b9edf6bdbfeab84055e5fd4f93be5b46dbbd
parentabbe3916ed5d7b6adb5a4b376e5c563d36e07d31 (diff)
downloadbun-0160772d25105f302f84013e892fe07f9eeb6f91.tar.gz
bun-0160772d25105f302f84013e892fe07f9eeb6f91.tar.zst
bun-0160772d25105f302f84013e892fe07f9eeb6f91.zip
-rw-r--r--docs/runtime/nodejs-apis.md4
-rw-r--r--src/bun.js/bindings/CommonJSModuleRecord.cpp14
-rw-r--r--src/bun.js/modules/NodeModuleModule.h96
-rw-r--r--src/js/builtins.d.ts2
-rw-r--r--src/js/builtins/Module.ts15
-rw-r--r--src/js/out/WebCoreJSBuiltins.cpp12
-rw-r--r--src/js/out/WebCoreJSBuiltins.h11
-rw-r--r--src/js/private.d.ts2
8 files changed, 108 insertions, 48 deletions
diff --git a/docs/runtime/nodejs-apis.md b/docs/runtime/nodejs-apis.md
index 5c6b858da..dbd32bd43 100644
--- a/docs/runtime/nodejs-apis.md
+++ b/docs/runtime/nodejs-apis.md
@@ -50,7 +50,7 @@ This page is updated regularly to reflect compatibility status of the latest ver
### [`node:events`](https://nodejs.org/api/events.html)
-🟡 Missing `require('node:events').on`.
+🟡 Missing `events.on`.
### [`node:fs`](https://nodejs.org/api/fs.html)
@@ -74,7 +74,7 @@ This page is updated regularly to reflect compatibility status of the latest ver
### [`node:module`](https://nodejs.org/api/module.html)
-🟢 Fully implemented.
+🟡 Missing `module.register`, `module.syncBuiltinESMExports`, `module.findSourceMap`, `module.SourceMap`.
### [`node:net`](https://nodejs.org/api/net.html)
diff --git a/src/bun.js/bindings/CommonJSModuleRecord.cpp b/src/bun.js/bindings/CommonJSModuleRecord.cpp
index 38b55ba4d..103f62237 100644
--- a/src/bun.js/bindings/CommonJSModuleRecord.cpp
+++ b/src/bun.js/bindings/CommonJSModuleRecord.cpp
@@ -810,15 +810,17 @@ const JSC::ClassInfo JSCommonJSModule::s_info = { "Module"_s, &Base::s_info, nul
const JSC::ClassInfo RequireResolveFunctionPrototype::s_info = { "resolve"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(RequireResolveFunctionPrototype) };
const JSC::ClassInfo RequireFunctionPrototype::s_info = { "require"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(RequireFunctionPrototype) };
+// This is .$require on a CommonJSModuleRecord. It is used by the CJS module loader internals in `Module.ts`
JSC_DEFINE_HOST_FUNCTION(jsFunctionRequireCommonJS, (JSGlobalObject * lexicalGlobalObject, CallFrame* callframe))
{
auto* globalObject = jsCast<Zig::GlobalObject*>(lexicalGlobalObject);
auto& vm = globalObject->vm();
auto throwScope = DECLARE_THROW_SCOPE(vm);
+ ASSERT(callframe->argumentCount() == 2);
+
JSCommonJSModule* thisObject = jsDynamicCast<JSCommonJSModule*>(callframe->thisValue());
- if (!thisObject)
- return throwVMTypeError(globalObject, throwScope);
+ RELEASE_ASSERT(thisObject);
JSValue specifierValue = callframe->argument(0);
WTF::String specifier = specifierValue.toWTFString(globalObject);
@@ -826,19 +828,19 @@ JSC_DEFINE_HOST_FUNCTION(jsFunctionRequireCommonJS, (JSGlobalObject * lexicalGlo
// Special-case for "process" to just return the process object directly.
if (UNLIKELY(specifier == "process"_s || specifier == "node:process"_s)) {
- jsCast<JSCommonJSModule*>(callframe->argument(1))->putDirect(vm, builtinNames(vm).exportsPublicName(), globalObject->processObject(), 0);
+ thisObject->putDirect(vm, builtinNames(vm).exportsPublicName(), globalObject->processObject(), 0);
return JSValue::encode(globalObject->processObject());
}
- WTF::String referrer = thisObject->id().toWTFString(globalObject);
- RETURN_IF_EXCEPTION(throwScope, {});
+ JSValue referrerModule = callframe->argument(1);
+ WTF::String referrer = referrerModule.isString() ? referrerModule.toWTFString(globalObject) : MAKE_STATIC_STRING_IMPL(".");
BunString specifierStr = Bun::toString(specifier);
BunString referrerStr = Bun::toString(referrer);
JSValue fetchResult = Bun::fetchCommonJSModule(
globalObject,
- jsCast<JSCommonJSModule*>(callframe->argument(1)),
+ thisObject,
specifierValue,
&specifierStr,
&referrerStr);
diff --git a/src/bun.js/modules/NodeModuleModule.h b/src/bun.js/modules/NodeModuleModule.h
index eeac4c0ea..70eacad47 100644
--- a/src/bun.js/modules/NodeModuleModule.h
+++ b/src/bun.js/modules/NodeModuleModule.h
@@ -1,3 +1,4 @@
+// clang-format off
#pragma once
#include "CommonJSModuleRecord.h"
@@ -152,6 +153,38 @@ JSC_DEFINE_HOST_FUNCTION(jsFunctionIsBuiltinModule,
return JSValue::encode(jsBoolean(Bun::isBuiltinModule(moduleStr)));
}
+JSC_DEFINE_HOST_FUNCTION(jsFunctionDebugNoop,
+ (JSC::JSGlobalObject * globalObject,
+ JSC::CallFrame *callFrame)) {
+ return JSValue::encode(jsUndefined());
+}
+
+JSC_DEFINE_HOST_FUNCTION(jsFunctionFindPath,
+ (JSC::JSGlobalObject * globalObject,
+ JSC::CallFrame *callFrame)) {
+ JSC::VM &vm = globalObject->vm();
+
+ auto specifier = callFrame->argument(0);
+ auto paths = jsDynamicCast<JSArray*>(callFrame->argument(1));
+
+ if (!specifier.isString()) {
+ return JSValue::encode(jsBoolean(false));
+ }
+ if (!paths) {
+ return JSValue::encode(jsBoolean(false));
+ }
+
+ auto result = Bun__resolveSync(globalObject, JSC::JSValue::encode(moduleName), from, isESM);
+
+ if (JSC::JSValue::decode(result).isString()) {
+ return result;
+ }
+
+ // TODO: iterate
+
+ return JSValue::encode(jsBoolean(false));
+}
+
// Might be faster as a JS builtin
JSC_DEFINE_HOST_FUNCTION(jsFunctionNodeModulePreloadModules,
(JSC::JSGlobalObject * globalObject,
@@ -230,8 +263,10 @@ JSC_DEFINE_HOST_FUNCTION(jsFunctionFindSourceMap,
CallFrame *callFrame)) {
auto &vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
- throwException(globalObject, scope,
- createError(globalObject, "Not implemented"_s));
+ throwException(
+ globalObject, scope,
+ createError(globalObject,
+ "module.findSourceMap is not implemented in Bun"_s));
return JSValue::encode(jsUndefined());
}
@@ -241,7 +276,7 @@ JSC_DEFINE_HOST_FUNCTION(jsFunctionRegister, (JSGlobalObject * globalObject,
auto scope = DECLARE_THROW_SCOPE(vm);
throwException(
globalObject, scope,
- createError(globalObject, "Bun does not support ESM loaders"_s));
+ createError(globalObject, "Bun does not support Node.js loaders"_s));
return JSValue::encode(jsUndefined());
}
@@ -255,8 +290,10 @@ 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));
+ throwException(
+ globalObject, scope,
+ createError(globalObject,
+ "module.SourceMap is not yet implemented in Bun"_s));
return JSValue::encode(jsUndefined());
}
@@ -406,43 +443,36 @@ DEFINE_NATIVE_MODULE(NodeModule) {
put(Identifier::fromString(vm, "Module"_s), defaultObject);
// Module._extensions === require.extensions
- put(Identifier::fromString(vm, "_extensions"_s),
- globalObject->requireFunctionUnbound()->get(
- globalObject, Identifier::fromString(vm, "extensions"_s)));
+ put(
+ Identifier::fromString(vm, "_extensions"_s),
+ globalObject->requireFunctionUnbound()->get(globalObject, Identifier::fromString(vm, "extensions"_s))
+ );
- put(Identifier::fromString(vm, "_pathCache"_s),
- JSC::constructEmptyObject(globalObject));
+ put(Identifier::fromString(vm, "_pathCache"_s), JSC::constructEmptyObject(globalObject));
+ putNativeFn(Identifier::fromString(vm, "__resolveFilename"_s), jsFunctionResolveFileName);
defaultObject->putDirectCustomAccessor(
vm, JSC::Identifier::fromString(vm, "_resolveFilename"_s),
- JSC::CustomGetterSetter::create(vm, get_resolveFilename,
- set_resolveFilename),
+ JSC::CustomGetterSetter::create(vm, get_resolveFilename, set_resolveFilename),
JSC::PropertyAttribute::CustomAccessor | 0);
- putNativeFn(Identifier::fromString(vm, "__resolveFilename"_s),
- jsFunctionResolveFileName);
-
- putNativeFn(Identifier::fromString(vm, "_preloadModules"_s),
- jsFunctionNodeModulePreloadModules);
- 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, "_preloadModules"_s), jsFunctionNodeModulePreloadModules);
+ 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, "_nodeModulePaths"_s),
- Resolver__nodeModulePathsForJS);
+ putNativeFn(Identifier::fromString(vm, "isBuiltin"_s), jsFunctionIsBuiltinModule);
+ putNativeFn(Identifier::fromString(vm, "_nodeModulePaths"_s), Resolver__nodeModulePathsForJS);
putNativeFn(Identifier::fromString(vm, "wrap"_s), jsFunctionWrap);
- put(Identifier::fromString(vm, "_cache"_s),
- jsCast<Zig::GlobalObject *>(globalObject)->lazyRequireCacheObject());
+ putNativeFn(Identifier::fromString(vm, "_debug"_s), jsFunctionDebugNoop);
+
+ put(Identifier::fromString(vm, "_load"_s), JSFunction::create(vm, moduleModuleLoadCodeGenerator(vm), globalObject));
+
+ put(Identifier::fromString(vm, "_cache"_s), jsCast<Zig::GlobalObject *>(globalObject)->lazyRequireCacheObject());
- put(Identifier::fromString(vm, "globalPaths"_s),
- constructEmptyArray(globalObject, nullptr, 0));
+ put(Identifier::fromString(vm, "globalPaths"_s), constructEmptyArray(globalObject, nullptr, 0));
auto prototype =
constructEmptyObject(globalObject, globalObject->objectPrototype(), 1);
diff --git a/src/js/builtins.d.ts b/src/js/builtins.d.ts
index ee7bd68cf..99bf4d98e 100644
--- a/src/js/builtins.d.ts
+++ b/src/js/builtins.d.ts
@@ -438,7 +438,7 @@ declare function $createCommonJSModule(
id: string,
exports: any,
hasEvaluated: boolean,
- parent: CommonJSModuleRecord,
+ parent: CommonJSModuleRecord | undefined,
): CommonJSModuleRecord;
declare function $overridableRequire(this: CommonJSModuleRecord, id: string): any;
diff --git a/src/js/builtins/Module.ts b/src/js/builtins/Module.ts
index b074d3488..3c9c2f1a0 100644
--- a/src/js/builtins/Module.ts
+++ b/src/js/builtins/Module.ts
@@ -9,7 +9,7 @@ export function require(this: CommonJSModuleRecord, id: string) {
// overridableRequire can be overridden by setting `Module.prototype.require`
export function overridableRequire(this: CommonJSModuleRecord, id: string) {
- const existing = $requireMap.$get(id) || $requireMap.$get((id = $resolveSync(id, this.path, false)));
+ const existing = $requireMap.$get(id) || $requireMap.$get((id = $resolveSync(id, this?.path ?? ".", false)));
if (existing) {
// Scenario where this is necessary:
//
@@ -46,8 +46,7 @@ export function overridableRequire(this: CommonJSModuleRecord, id: string) {
//
// Note: we do not need to wrap this in a try/catch, if it throws the C++ code will
// clear the module from the map.
- //
- var out = this.$require(id, mod);
+ var out = mod.$require(id, this?.id);
// -1 means we need to lookup the module from the ESM registry.
if (out === -1) {
@@ -86,3 +85,13 @@ export function requireNativeModule(id: string) {
}
return $requireESM(id).default;
}
+
+/** require('node:module')._load */
+export function moduleLoad(request: string, parentPath: CommonJSModuleRecord, isMain: string) {
+ // TODO: `isMain` does four things in node
+ // - sets `process.mainModule`
+ // - sets `module.require.main`
+ // - sets `module.id` to "."
+ // - would pass true to the third argument of _resolveFilename if overridden
+ return $overridableRequire.$call(parentPath, request);
+}
diff --git a/src/js/out/WebCoreJSBuiltins.cpp b/src/js/out/WebCoreJSBuiltins.cpp
index 31246276b..1cea1826b 100644
--- a/src/js/out/WebCoreJSBuiltins.cpp
+++ b/src/js/out/WebCoreJSBuiltins.cpp
@@ -786,13 +786,21 @@ const int s_moduleMainCodeLength = 68;
static const JSC::Intrinsic s_moduleMainCodeIntrinsic = JSC::NoIntrinsic;
const char* const s_moduleMainCode = "(function () {\"use strict\";\n return @requireMap.@get(Bun.main);\n})\n";
+// moduleLoad
+const JSC::ConstructAbility s_moduleModuleLoadCodeConstructAbility = JSC::ConstructAbility::CannotConstruct;
+const JSC::ConstructorKind s_moduleModuleLoadCodeConstructorKind = JSC::ConstructorKind::None;
+const JSC::ImplementationVisibility s_moduleModuleLoadCodeImplementationVisibility = JSC::ImplementationVisibility::Public;
+const int s_moduleModuleLoadCodeLength = 115;
+static const JSC::Intrinsic s_moduleModuleLoadCodeIntrinsic = JSC::NoIntrinsic;
+const char* const s_moduleModuleLoadCode = "(function (request, parentPath, isMain) {\"use strict\";\n return @overridableRequire.@call(parentPath, request);\n})\n";
+
// overridableRequire
const JSC::ConstructAbility s_moduleOverridableRequireCodeConstructAbility = JSC::ConstructAbility::CannotConstruct;
const JSC::ConstructorKind s_moduleOverridableRequireCodeConstructorKind = JSC::ConstructorKind::None;
const JSC::ImplementationVisibility s_moduleOverridableRequireCodeImplementationVisibility = JSC::ImplementationVisibility::Public;
-const int s_moduleOverridableRequireCodeLength = 888;
+const int s_moduleOverridableRequireCodeLength = 900;
static const JSC::Intrinsic s_moduleOverridableRequireCodeIntrinsic = JSC::NoIntrinsic;
-const char* const s_moduleOverridableRequireCode = "(function (id) {\"use strict\";\n const existing = @requireMap.@get(id) || @requireMap.@get(id = @resolveSync(id, this.path, !1));\n if (existing)\n return @evaluateCommonJSModule(existing), existing.exports;\n if (id.endsWith(\".node\"))\n return @internalRequire(id);\n const mod = @createCommonJSModule(id, {}, !1, this);\n @requireMap.@set(id, mod);\n var out = this.@require(id, mod);\n if (out === -1) {\n try {\n out = @requireESM(id);\n } catch (exception) {\n throw @requireMap.@delete(id), exception;\n }\n const esm = @Loader.registry.@get(id);\n if (esm\?.evaluated && (esm.state \?\? 0) >= @ModuleReady) {\n const namespace = @Loader.getModuleNamespaceObject(esm.module);\n return mod.exports = namespace.__esModule \? namespace : Object.create(namespace, { __esModule: { value: !0 } });\n }\n }\n return @evaluateCommonJSModule(mod), mod.exports;\n})\n";
+const char* const s_moduleOverridableRequireCode = "(function (id) {\"use strict\";\n const existing = @requireMap.@get(id) || @requireMap.@get(id = @resolveSync(id, this\?.path \?\? \".\", !1));\n if (existing)\n return @evaluateCommonJSModule(existing), existing.exports;\n if (id.endsWith(\".node\"))\n return @internalRequire(id);\n const mod = @createCommonJSModule(id, {}, !1, this);\n @requireMap.@set(id, mod);\n var out = mod.@require(id, this\?.id);\n if (out === -1) {\n try {\n out = @requireESM(id);\n } catch (exception) {\n throw @requireMap.@delete(id), exception;\n }\n const esm = @Loader.registry.@get(id);\n if (esm\?.evaluated && (esm.state \?\? 0) >= @ModuleReady) {\n const namespace = @Loader.getModuleNamespaceObject(esm.module);\n return mod.exports = namespace.__esModule \? namespace : Object.create(namespace, { __esModule: { value: !0 } });\n }\n }\n return @evaluateCommonJSModule(mod), mod.exports;\n})\n";
// require
const JSC::ConstructAbility s_moduleRequireCodeConstructAbility = JSC::ConstructAbility::CannotConstruct;
diff --git a/src/js/out/WebCoreJSBuiltins.h b/src/js/out/WebCoreJSBuiltins.h
index 3c6ade197..5b8c0b267 100644
--- a/src/js/out/WebCoreJSBuiltins.h
+++ b/src/js/out/WebCoreJSBuiltins.h
@@ -1506,6 +1506,14 @@ extern const JSC::ConstructAbility s_moduleMainCodeConstructAbility;
extern const JSC::ConstructorKind s_moduleMainCodeConstructorKind;
extern const JSC::ImplementationVisibility s_moduleMainCodeImplementationVisibility;
+// moduleLoad
+#define WEBCORE_BUILTIN_MODULE_MODULELOAD 1
+extern const char* const s_moduleModuleLoadCode;
+extern const int s_moduleModuleLoadCodeLength;
+extern const JSC::ConstructAbility s_moduleModuleLoadCodeConstructAbility;
+extern const JSC::ConstructorKind s_moduleModuleLoadCodeConstructorKind;
+extern const JSC::ImplementationVisibility s_moduleModuleLoadCodeImplementationVisibility;
+
// overridableRequire
#define WEBCORE_BUILTIN_MODULE_OVERRIDABLEREQUIRE 1
extern const char* const s_moduleOverridableRequireCode;
@@ -1540,6 +1548,7 @@ extern const JSC::ImplementationVisibility s_moduleRequireResolveCodeImplementat
#define WEBCORE_FOREACH_MODULE_BUILTIN_DATA(macro) \
macro(main, moduleMain, 0) \
+ macro(moduleLoad, moduleModuleLoad, 3) \
macro(overridableRequire, moduleOverridableRequire, 1) \
macro(require, moduleRequire, 1) \
macro(requireNativeModule, moduleRequireNativeModule, 1) \
@@ -1547,6 +1556,7 @@ extern const JSC::ImplementationVisibility s_moduleRequireResolveCodeImplementat
#define WEBCORE_FOREACH_MODULE_BUILTIN_CODE(macro) \
macro(moduleMainCode, main, "get main"_s, s_moduleMainCodeLength) \
+ macro(moduleModuleLoadCode, moduleLoad, ASCIILiteral(), s_moduleModuleLoadCodeLength) \
macro(moduleOverridableRequireCode, overridableRequire, ASCIILiteral(), s_moduleOverridableRequireCodeLength) \
macro(moduleRequireCode, require, ASCIILiteral(), s_moduleRequireCodeLength) \
macro(moduleRequireNativeModuleCode, requireNativeModule, ASCIILiteral(), s_moduleRequireNativeModuleCodeLength) \
@@ -1554,6 +1564,7 @@ extern const JSC::ImplementationVisibility s_moduleRequireResolveCodeImplementat
#define WEBCORE_FOREACH_MODULE_BUILTIN_FUNCTION_NAME(macro) \
macro(main) \
+ macro(moduleLoad) \
macro(overridableRequire) \
macro(require) \
macro(requireNativeModule) \
diff --git a/src/js/private.d.ts b/src/js/private.d.ts
index 77f4d5536..2ca8d630f 100644
--- a/src/js/private.d.ts
+++ b/src/js/private.d.ts
@@ -215,7 +215,7 @@ interface BunLazyModules {
declare var $exports: any;
interface CommonJSModuleRecord {
- $require(id: string, mod: any): any;
+ $require(this: CommonJSModuleRecord, id: string, parent: string | undefined): any;
children: CommonJSModuleRecord[];
exports: any;
id: string;