diff --git a/oxlint.json b/oxlint.json index 8749f00f9d..352d94e287 100644 --- a/oxlint.json +++ b/oxlint.json @@ -31,7 +31,8 @@ "test/bundler/native-plugin.test.ts", // parser doesn't handle import metadata "test/bundler/transpiler/with-statement-works.js", // parser doesn't allow `with` statement "test/js/node/module/extensions-fixture", // these files are not meant to be linted - "test/cli/run/module-type-fixture" + "test/cli/run/module-type-fixture", + "test/bundler/transpiler/with-statement-works.js" // parser doesn't allow `with` statement ], "overrides": [ { diff --git a/src/bun.js/bindings/JSCommonJSExtensions.cpp b/src/bun.js/bindings/JSCommonJSExtensions.cpp deleted file mode 100644 index d1c511847c..0000000000 --- a/src/bun.js/bindings/JSCommonJSExtensions.cpp +++ /dev/null @@ -1,181 +0,0 @@ -#include "JSCommonJSExtensions.h" -#include "ZigGlobalObject.h" - -namespace Bun { -using namespace JSC; - -const JSC::ClassInfo JSCommonJSExtensions::s_info = { "CommonJSExtensions"_s, &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSCommonJSExtensions) }; - -// These functions are implemented as no-ops because it doesn't seem like any -// projects call them directly. They are defined separately so that assigning -// one to the other can be detected and use the corresponding loader. -JSC_DEFINE_HOST_FUNCTION(jsLoaderJS, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) -{ - auto scope = DECLARE_THROW_SCOPE(globalObject->vm()); - throwTypeError(globalObject, scope, "Calling Module._extensions[\".js\"] directly is not implemented."_s); - return JSValue::encode({}); -} -JSC_DEFINE_HOST_FUNCTION(jsLoaderJSON, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) -{ - auto scope = DECLARE_THROW_SCOPE(globalObject->vm()); - throwTypeError(globalObject, scope, "Calling Module._extensions[\".json\"] directly is not implemented."_s); - return JSValue::encode({}); -} -JSC_DEFINE_HOST_FUNCTION(jsLoaderNode, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) -{ - auto scope = DECLARE_THROW_SCOPE(globalObject->vm()); - throwTypeError(globalObject, scope, "Calling Module._extensions[\".node\"] directly is not implemented."_s); - return JSValue::encode({}); -} -JSC_DEFINE_HOST_FUNCTION(jsLoaderTS, (JSC::JSGlobalObject * globalObject, JSC::CallFrame* callFrame)) -{ - auto scope = DECLARE_THROW_SCOPE(globalObject->vm()); - throwTypeError(globalObject, scope, "Calling Module._extensions[\".ts\"] directly is not implemented."_s); - return JSValue::encode({}); -} - -void JSCommonJSExtensions::finishCreation(JSC::VM& vm) -{ - Base::finishCreation(vm); - ASSERT(inherits(info())); - - Zig::GlobalObject* global = defaultGlobalObject(globalObject()); - JSC::JSFunction* fnLoadJS = JSC::JSFunction::create( - vm, - global, - 2, - ""_s, - jsLoaderJS, - JSC::ImplementationVisibility::Public, - JSC::Intrinsic::NoIntrinsic, - JSC::callHostFunctionAsConstructor); - JSC::JSFunction* fnLoadJSON = JSC::JSFunction::create( - vm, - global, - 2, - ""_s, - jsLoaderJSON, - JSC::ImplementationVisibility::Public, - JSC::Intrinsic::NoIntrinsic, - JSC::callHostFunctionAsConstructor); - JSC::JSFunction* fnLoadNode = JSC::JSFunction::create( - vm, - global, - 2, - ""_s, - jsLoaderNode, - JSC::ImplementationVisibility::Public, - JSC::Intrinsic::NoIntrinsic, - JSC::callHostFunctionAsConstructor); - JSC::JSFunction* fnLoadTS = JSC::JSFunction::create( - vm, - global, - 2, - ""_s, - jsLoaderTS, - JSC::ImplementationVisibility::Public, - JSC::Intrinsic::NoIntrinsic, - JSC::callHostFunctionAsConstructor); - - this->putDirect(vm, JSC::Identifier::fromString(vm, ".js"_s), fnLoadJS, 0); - this->putDirect(vm, JSC::Identifier::fromString(vm, ".json"_s), fnLoadJSON, 0); - this->putDirect(vm, JSC::Identifier::fromString(vm, ".node"_s), fnLoadNode, 0); - this->putDirect(vm, JSC::Identifier::fromString(vm, ".ts"_s), fnLoadTS, 0); - this->putDirect(vm, JSC::Identifier::fromString(vm, ".cts"_s), fnLoadTS, 0); - this->putDirect(vm, JSC::Identifier::fromString(vm, ".mjs"_s), fnLoadJS, 0); - this->putDirect(vm, JSC::Identifier::fromString(vm, ".mts"_s), fnLoadTS, 0); -} - -extern "C" void NodeModuleModule__onRequireExtensionModify( - Zig::GlobalObject* globalObject, - const BunString* key, - uint32_t kind, - JSC::JSValue value); - -void onAssign(Zig::GlobalObject* globalObject, JSC::PropertyName propertyName, JSC::JSValue value) -{ - if (propertyName.isSymbol()) return; - auto* name = propertyName.publicName(); - if (!name->startsWith("."_s)) return; - BunString ext = Bun::toString(name); - uint32_t kind = 0; - if (value.isCallable()) { - JSC::CallData callData = JSC::getCallData(value); - if (callData.type == JSC::CallData::Type::Native) { - auto* untaggedPtr = callData.native.function.untaggedPtr(); - if (untaggedPtr == &jsLoaderJS) { - kind = 1; - } else if (untaggedPtr == &jsLoaderJSON) { - kind = 2; - } else if (untaggedPtr == &jsLoaderNode) { - kind = 3; - } else if (untaggedPtr == &jsLoaderTS) { - kind = 4; - } - } - } else { - kind = -1; - } - NodeModuleModule__onRequireExtensionModify(globalObject, &ext, kind, value); -} - -bool JSCommonJSExtensions::defineOwnProperty(JSC::JSObject* object, JSC::JSGlobalObject* globalObject, JSC::PropertyName propertyName, const JSC::PropertyDescriptor& descriptor, bool shouldThrow) -{ - JSValue value = descriptor.value(); - if (value) { - onAssign(defaultGlobalObject(globalObject), propertyName, value); - } else { - onAssign(defaultGlobalObject(globalObject), propertyName, JSC::jsUndefined()); - } - return Base::defineOwnProperty(object, globalObject, propertyName, descriptor, shouldThrow); -} - -bool JSCommonJSExtensions::put(JSC::JSCell* cell, JSC::JSGlobalObject* globalObject, JSC::PropertyName propertyName, JSC::JSValue value, JSC::PutPropertySlot& slot) -{ - onAssign(defaultGlobalObject(globalObject), propertyName, value); - return Base::put(cell, globalObject, propertyName, value, slot); -} - -bool JSCommonJSExtensions::deleteProperty(JSC::JSCell* cell, JSC::JSGlobalObject* globalObject, JSC::PropertyName propertyName, JSC::DeletePropertySlot& slot) -{ - bool deleted = Base::deleteProperty(cell, globalObject, propertyName, slot); - if (deleted) { - onAssign(defaultGlobalObject(globalObject), propertyName, JSC::jsUndefined()); - } - return deleted; -} - -extern "C" uint32_t JSCommonJSExtensions__appendFunction(Zig::GlobalObject* globalObject, JSC::JSValue value) -{ - JSCommonJSExtensions* extensions = globalObject->lazyRequireExtensionsObject(); - extensions->m_registeredFunctions.append(JSC::WriteBarrier()); - extensions->m_registeredFunctions.last().set(globalObject->vm(), extensions, value); - return extensions->m_registeredFunctions.size() - 1; -} - -extern "C" void JSCommonJSExtensions__setFunction(Zig::GlobalObject* globalObject, uint32_t index, JSC::JSValue value) -{ - JSCommonJSExtensions* extensions = globalObject->lazyRequireExtensionsObject(); - extensions->m_registeredFunctions[index].set(globalObject->vm(), globalObject, value); -} - -extern "C" uint32_t JSCommonJSExtensions__swapRemove(Zig::GlobalObject* globalObject, uint32_t index) -{ - JSCommonJSExtensions* extensions = globalObject->lazyRequireExtensionsObject(); - ASSERT(extensions->m_registeredFunctions.size() > 0); - if (extensions->m_registeredFunctions.size() == 1) { - extensions->m_registeredFunctions.clear(); - return index; - } - ASSERT(index < extensions->m_registeredFunctions.size()); - if (index < (extensions->m_registeredFunctions.size() - 1)) { - JSValue last = extensions->m_registeredFunctions.takeLast().get(); - extensions->m_registeredFunctions[index].set(globalObject->vm(), globalObject, last); - return extensions->m_registeredFunctions.size(); - } else { - extensions->m_registeredFunctions.removeLast(); - return index; - } -} - -} // namespace Bun diff --git a/src/bun.js/bindings/JSCommonJSExtensions.h b/src/bun.js/bindings/JSCommonJSExtensions.h deleted file mode 100644 index 1e7f13b1e7..0000000000 --- a/src/bun.js/bindings/JSCommonJSExtensions.h +++ /dev/null @@ -1,58 +0,0 @@ -#pragma once -#include "root.h" -#include "headers-handwritten.h" -#include "BunClientData.h" - -namespace Bun { - -// require.extensions & Module._extensions -class JSCommonJSExtensions : public JSC::JSDestructibleObject { -public: - using Base = JSC::JSDestructibleObject; - static constexpr unsigned StructureFlags = Base::StructureFlags | JSC::OverridesPut; - ~JSCommonJSExtensions(); - - WTF::Vector> m_registeredFunctions; - - static JSCommonJSExtensions* create(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::Structure* structure) - { - JSCommonJSExtensions* ptr = new (NotNull, JSC::allocateCell(vm)) JSCommonJSExtensions(vm, structure); - ptr->finishCreation(vm); - return ptr; - } - - DECLARE_INFO; - - template - static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm) - { - if constexpr (mode == JSC::SubspaceAccess::Concurrently) - return nullptr; - return WebCore::subspaceForImpl( - vm, - [](auto& spaces) { return spaces.m_clientSubspaceForJSCommonJSExtensions.get(); }, - [](auto& spaces, auto&& space) { spaces.m_clientSubspaceForJSCommonJSExtensions = std::forward(space); }, - [](auto& spaces) { return spaces.m_subspaceForJSCommonJSExtensions.get(); }, - [](auto& spaces, auto&& space) { spaces.m_subspaceForJSCommonJSExtensions = std::forward(space); }); - } - - static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype) - { - return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info()); - } - -protected: - static bool defineOwnProperty(JSC::JSObject*, JSC::JSGlobalObject*, JSC::PropertyName, const JSC::PropertyDescriptor&, bool shouldThrow); - static bool put(JSC::JSCell*, JSC::JSGlobalObject*, JSC::PropertyName, JSC::JSValue, JSC::PutPropertySlot&); - static bool deleteProperty(JSC::JSCell*, JSC::JSGlobalObject*, JSC::PropertyName, JSC::DeletePropertySlot&); - -private: - JSCommonJSExtensions(JSC::VM& vm, JSC::Structure* structure) - : Base(vm, structure) - { - } - - void finishCreation(JSC::VM&); -}; - -} // namespace Bun diff --git a/src/bun.js/bindings/JSCommonJSModule.cpp b/src/bun.js/bindings/JSCommonJSModule.cpp index d22f0a78cb..6b200709e2 100644 --- a/src/bun.js/bindings/JSCommonJSModule.cpp +++ b/src/bun.js/bindings/JSCommonJSModule.cpp @@ -76,7 +76,6 @@ #include "wtf/NakedPtr.h" #include "wtf/URL.h" #include "wtf/text/StringImpl.h" -#include "JSCommonJSExtensions.h" extern "C" bool Bun__isBunMain(JSC::JSGlobalObject* global, const BunString*); @@ -299,31 +298,12 @@ JSC_DEFINE_CUSTOM_SETTER(jsRequireCacheSetter, return true; } -JSC_DEFINE_CUSTOM_GETTER(jsRequireExtensionsGetter, (JSC::JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue, JSC::PropertyName)) -{ - Zig::GlobalObject* thisObject = jsCast(globalObject); - return JSValue::encode(thisObject->lazyRequireExtensionsObject()); -} - -JSC_DEFINE_CUSTOM_SETTER(jsRequireExtensionsSetter, - (JSC::JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue, - JSC::EncodedJSValue value, JSC::PropertyName propertyName)) -{ - JSObject* thisObject = jsDynamicCast(JSValue::decode(thisValue)); - if (!thisObject) - return false; - - thisObject->putDirect(globalObject->vm(), propertyName, JSValue::decode(value), 0); - return true; -} - static const HashTableValue RequireResolveFunctionPrototypeValues[] = { { "paths"_s, static_cast(JSC::PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, requireResolvePathsFunction, 1 } }, }; static const HashTableValue RequireFunctionPrototypeValues[] = { { "cache"_s, static_cast(JSC::PropertyAttribute::CustomAccessor), NoIntrinsic, { HashTableValue::GetterSetterType, jsRequireCacheGetter, jsRequireCacheSetter } }, - { "extensions"_s, static_cast(JSC::PropertyAttribute::CustomAccessor), NoIntrinsic, { HashTableValue::GetterSetterType, jsRequireExtensionsGetter, jsRequireExtensionsSetter } }, }; Structure* RequireFunctionPrototype::createStructure( @@ -386,6 +366,13 @@ void RequireFunctionPrototype::finishCreation(JSC::VM& vm) JSC::Identifier::fromString(vm, "main"_s), JSC::GetterSetter::create(vm, globalObject, requireDotMainFunction, requireDotMainFunction), PropertyAttribute::Accessor | PropertyAttribute::ReadOnly | 0); + + auto extensions = constructEmptyObject(globalObject); + extensions->putDirect(vm, JSC::Identifier::fromString(vm, ".js"_s), jsBoolean(true), 0); + extensions->putDirect(vm, JSC::Identifier::fromString(vm, ".json"_s), jsBoolean(true), 0); + extensions->putDirect(vm, JSC::Identifier::fromString(vm, ".node"_s), jsBoolean(true), 0); + + this->putDirect(vm, JSC::Identifier::fromString(vm, "extensions"_s), extensions, 0); } JSC_DEFINE_CUSTOM_GETTER(getterFilename, (JSC::JSGlobalObject * globalObject, JSC::EncodedJSValue thisValue, JSC::PropertyName)) @@ -1164,6 +1151,7 @@ JSC_DEFINE_HOST_FUNCTION(jsFunctionRequireCommonJS, (JSGlobalObject * lexicalGlo // This is always a new JSCommonJSModule object; cast cannot fail. JSCommonJSModule* child = jsCast(callframe->uncheckedArgument(1)); + BunString specifierStr = Bun::toString(specifier); BunString referrerStr = Bun::toString(referrer); BunString typeAttributeStr = { BunStringTag::Dead }; String typeAttribute = String(); @@ -1194,7 +1182,7 @@ JSC_DEFINE_HOST_FUNCTION(jsFunctionRequireCommonJS, (JSGlobalObject * lexicalGlo globalObject, child, specifierValue, - specifier, + &specifierStr, &referrerStr, LIKELY(typeAttribute.isEmpty()) ? nullptr diff --git a/src/bun.js/bindings/ModuleLoader.cpp b/src/bun.js/bindings/ModuleLoader.cpp index ab9c46271b..baa549bf91 100644 --- a/src/bun.js/bindings/ModuleLoader.cpp +++ b/src/bun.js/bindings/ModuleLoader.cpp @@ -37,8 +37,6 @@ #include "JSCommonJSModule.h" #include "../modules/_NativeModule.h" -#include "JSCommonJSExtensions.h" - namespace Bun { using namespace JSC; using namespace Zig; @@ -569,39 +567,11 @@ JSValue resolveAndFetchBuiltinModule( return {}; } -void evaluateCommonJSCustomExtension( - Zig::GlobalObject* globalObject, - JSCommonJSModule* target, - String filename, - JSValue filenameValue, - uint32_t extensionIndex) -{ - auto& vm = globalObject->vm(); - auto scope = DECLARE_THROW_SCOPE(vm); - Bun::JSCommonJSExtensions* extensions = globalObject->lazyRequireExtensionsObject(); - JSValue extension = extensions->m_registeredFunctions[extensionIndex].get(); - - if (!extension || !extension.isCallable()) { - throwTypeError(globalObject, scope, makeString("require.extension is not a function"_s)); - return; - } - JSC::CallData callData = JSC::getCallData(extension.asCell()); - if (callData.type == JSC::CallData::Type::None) { - throwTypeError(globalObject, scope, makeString("require.extension is not a function"_s)); - return; - } - MarkedArgumentBuffer arguments; - arguments.append(target); - arguments.append(filenameValue); - JSC::profiledCall(globalObject, ProfilingReason::API, extension, callData, target, arguments); - RETURN_IF_EXCEPTION(scope, ); -} - JSValue fetchCommonJSModule( Zig::GlobalObject* globalObject, JSCommonJSModule* target, JSValue specifierValue, - String specifierWtfString, + BunString* specifier, BunString* referrer, BunString* typeAttribute) { @@ -614,15 +584,13 @@ JSValue fetchCommonJSModule( ErrorableResolvedSource* res = &resValue; ResolvedSourceCodeHolder sourceCodeHolder(res); - BunString specifier = Bun::toString(specifierWtfString); - bool wasModuleMock = false; // When "bun test" is enabled, allow users to override builtin modules // This is important for being able to trivially mock things like the filesystem. if (isBunTest) { - if (JSC::JSValue virtualModuleResult = Bun::runVirtualModule(globalObject, &specifier, wasModuleMock)) { - JSValue promiseOrCommonJSModule = handleVirtualModuleResult(globalObject, virtualModuleResult, res, &specifier, referrer, wasModuleMock, target); + if (JSC::JSValue virtualModuleResult = Bun::runVirtualModule(globalObject, specifier, wasModuleMock)) { + JSValue promiseOrCommonJSModule = handleVirtualModuleResult(globalObject, virtualModuleResult, res, specifier, referrer, wasModuleMock, target); RETURN_IF_EXCEPTION(scope, {}); // If we assigned module.exports to the virtual module, we're done here. @@ -638,7 +606,7 @@ JSValue fetchCommonJSModule( RELEASE_AND_RETURN(scope, JSValue {}); } case JSPromise::Status::Pending: { - JSC::throwTypeError(globalObject, scope, makeString("require() async module \""_s, specifierWtfString, "\" is unsupported. use \"await import()\" instead."_s)); + JSC::throwTypeError(globalObject, scope, makeString("require() async module \""_s, specifier->toWTFString(BunString::ZeroCopy), "\" is unsupported. use \"await import()\" instead."_s)); RELEASE_AND_RETURN(scope, JSValue {}); } case JSPromise::Status::Fulfilled: { @@ -657,7 +625,7 @@ JSValue fetchCommonJSModule( } } - if (auto builtin = fetchBuiltinModuleWithoutResolution(globalObject, &specifier, res)) { + if (auto builtin = fetchBuiltinModuleWithoutResolution(globalObject, specifier, res)) { if (!res->success) { RELEASE_AND_RETURN(scope, builtin); } @@ -668,8 +636,8 @@ JSValue fetchCommonJSModule( // When "bun test" is NOT enabled, disable users from overriding builtin modules if (!isBunTest) { - if (JSC::JSValue virtualModuleResult = Bun::runVirtualModule(globalObject, &specifier, wasModuleMock)) { - JSValue promiseOrCommonJSModule = handleVirtualModuleResult(globalObject, virtualModuleResult, res, &specifier, referrer, wasModuleMock, target); + if (JSC::JSValue virtualModuleResult = Bun::runVirtualModule(globalObject, specifier, wasModuleMock)) { + JSValue promiseOrCommonJSModule = handleVirtualModuleResult(globalObject, virtualModuleResult, res, specifier, referrer, wasModuleMock, target); RETURN_IF_EXCEPTION(scope, {}); // If we assigned module.exports to the virtual module, we're done here. @@ -685,7 +653,7 @@ JSValue fetchCommonJSModule( RELEASE_AND_RETURN(scope, JSValue {}); } case JSPromise::Status::Pending: { - JSC::throwTypeError(globalObject, scope, makeString("require() async module \""_s, specifierWtfString, "\" is unsupported. use \"await import()\" instead."_s)); + JSC::throwTypeError(globalObject, scope, makeString("require() async module \""_s, specifier->toWTFString(BunString::ZeroCopy), "\" is unsupported. use \"await import()\" instead."_s)); RELEASE_AND_RETURN(scope, JSValue {}); } case JSPromise::Status::Fulfilled: { @@ -721,9 +689,9 @@ JSValue fetchCommonJSModule( RELEASE_AND_RETURN(scope, jsNumber(-1)); } - Bun__transpileFile(bunVM, globalObject, &specifier, referrer, typeAttribute, res, false, true); + Bun__transpileFile(bunVM, globalObject, specifier, referrer, typeAttribute, res, false); if (res->success && res->result.value.isCommonJSModule) { - target->evaluate(globalObject, specifierWtfString, res->result.value); + target->evaluate(globalObject, specifier->toWTFString(BunString::ZeroCopy), res->result.value); RETURN_IF_EXCEPTION(scope, {}); RELEASE_AND_RETURN(scope, target); } @@ -765,10 +733,6 @@ JSValue fetchCommonJSModule( target->putDirect(vm, WebCore::clientData(vm)->builtinNames().exportsPublicName(), value, 0); target->hasEvaluated = true; RELEASE_AND_RETURN(scope, target); - } else if (res->result.value.tag == SyntheticModuleType::CommonJSCustomExtension) { - evaluateCommonJSCustomExtension(globalObject, target, specifierWtfString, specifierValue, res->result.value.cjsCustomExtensionIndex); - RETURN_IF_EXCEPTION(scope, {}); - RELEASE_AND_RETURN(scope, target); } auto&& provider = Zig::SourceProvider::create(globalObject, res->result.value); @@ -896,12 +860,12 @@ static JSValue fetchESMSourceCode( } if constexpr (allowPromise) { - auto* pendingCtx = Bun__transpileFile(bunVM, globalObject, specifier, referrer, typeAttribute, res, true, false); + auto* pendingCtx = Bun__transpileFile(bunVM, globalObject, specifier, referrer, typeAttribute, res, true); if (pendingCtx) { return pendingCtx; } } else { - Bun__transpileFile(bunVM, globalObject, specifier, referrer, typeAttribute, res, false, false); + Bun__transpileFile(bunVM, globalObject, specifier, referrer, typeAttribute, res, false); } if (res->success && res->result.value.isCommonJSModule) { diff --git a/src/bun.js/bindings/ModuleLoader.h b/src/bun.js/bindings/ModuleLoader.h index 4bcb48018a..6285d428a2 100644 --- a/src/bun.js/bindings/ModuleLoader.h +++ b/src/bun.js/bindings/ModuleLoader.h @@ -110,7 +110,7 @@ JSValue fetchCommonJSModule( Zig::GlobalObject* globalObject, JSCommonJSModule* moduleObject, JSValue specifierValue, - String specifier, + BunString* specifier, BunString* referrer, BunString* typeAttribute); diff --git a/src/bun.js/bindings/NodeModuleModule.zig b/src/bun.js/bindings/NodeModuleModule.zig index 1da4932984..b5f66759b1 100644 --- a/src/bun.js/bindings/NodeModuleModule.zig +++ b/src/bun.js/bindings/NodeModuleModule.zig @@ -81,154 +81,3 @@ pub fn _stat(path: []const u8) i32 { .directory => 1, // Returns 1 for directories. }; } - -pub const CustomLoader = union(enum) { - loader: bun.options.Loader, - /// Retrieve via WriteBarrier in `global->lazyRequireExtensionsObject().get(index)` - custom: u32, - - pub const Packed = enum(u32) { - const loader_start: u32 = std.math.maxInt(u32) - 4; - js = loader_start, - json = loader_start + 1, - napi = loader_start + 2, - ts = loader_start + 3, - /// custom - _, - - pub fn pack(loader: CustomLoader) Packed { - return switch (loader) { - .loader => |basic| switch (basic) { - .js => .js, - .json => .json, - .napi => .napi, - .ts => .ts, - else => brk: { - bun.debugAssert(false); - break :brk .js; - }, - }, - .custom => |custom| @enumFromInt(custom), - }; - } - - pub fn unpack(self: Packed) CustomLoader { - return switch (self) { - .js => .{ .loader = .js }, - .json => .{ .loader = .json }, - .napi => .{ .loader = .napi }, - .ts => .{ .loader = .ts }, - _ => .{ .custom = @intFromEnum(self) }, - }; - } - }; -}; - -extern fn JSCommonJSExtensions__appendFunction(global: *JSC.JSGlobalObject, value: JSC.JSValue) u32; -extern fn JSCommonJSExtensions__setFunction(global: *JSC.JSGlobalObject, index: u32, value: JSC.JSValue) void; -/// Returns the index of the last value, which must have it's references updated to `index` -extern fn JSCommonJSExtensions__swapRemove(global: *JSC.JSGlobalObject, index: u32) u32; - -// Memory management is complicated because JSValues are stored in gc-visitable -// WriteBarriers in C++ but the hash map for extensions is in Zig for flexibility. -fn onRequireExtensionModify(global: *JSC.JSGlobalObject, str: []const u8, kind: i32, value: JSC.JSValue) !void { - bun.assert(kind >= -1 and kind <= 4); - const vm = global.bunVM(); - const list = &vm.commonjs_custom_extensions; - defer vm.transpiler.resolver.opts.extra_cjs_extensions = list.keys(); - const is_built_in = bun.options.defaultLoaders.get(str) != null; - if (kind >= 0) { - const loader: CustomLoader = switch (kind) { - 1 => .{ .loader = .js }, - 2 => .{ .loader = .json }, - 3 => .{ .loader = .napi }, - 4 => .{ .loader = .ts }, - else => .{ .custom = undefined }, // to be filled in later - }; - const gop = try list.getOrPut(bun.default_allocator, str); - if (!gop.found_existing) { - const dupe = try bun.default_allocator.dupe(u8, str); - errdefer bun.default_allocator.free(dupe); - gop.key_ptr.* = dupe; - if (is_built_in) { - vm.has_mutated_built_in_extensions += 1; - } - gop.value_ptr.* = .pack(switch (loader) { - .loader => loader, - .custom => .{ - .custom = JSCommonJSExtensions__appendFunction(global, value), - }, - }); - } else { - const existing = gop.value_ptr.*.unpack(); - if (existing == .custom and loader != .custom) { - swapRemoveExtension(vm, existing.custom); - } - gop.value_ptr.* = .pack(switch (loader) { - .loader => loader, - .custom => .{ - .custom = if (existing == .custom) new: { - JSCommonJSExtensions__setFunction(global, existing.custom, value); - break :new existing.custom; - } else JSCommonJSExtensions__appendFunction(global, value), - }, - }); - } - } else if (list.fetchSwapRemove(str)) |prev| { - bun.default_allocator.free(prev.key); - if (is_built_in) { - vm.has_mutated_built_in_extensions -= 1; - } - switch (prev.value.unpack()) { - .loader => {}, - .custom => |index| swapRemoveExtension(vm, index), - } - } -} - -fn swapRemoveExtension(vm: *JSC.VirtualMachine, index: u32) void { - const last_index = JSCommonJSExtensions__swapRemove(vm.global, index); - if (last_index == index) return; - // Find and rewrite the last index to the new index. - // Since packed structs are sugar over the backing int, this code can use - // the simd path in the standard library search. - const find: u32 = @intFromEnum(CustomLoader.Packed.pack(.{ .custom = last_index })); - const values = vm.commonjs_custom_extensions.values(); - const values_reinterpret = bun.reinterpretSlice(u32, values); - const i = std.mem.indexOfScalar(u32, values_reinterpret, find) orelse - return bun.debugAssert(false); - values[i] = .pack(.{ .custom = last_index }); -} - -pub fn findLongestRegisteredExtension(vm: *JSC.VirtualMachine, filename: []const u8) ?CustomLoader { - const basename = std.fs.path.basename(filename); - var next: usize = 0; - while (bun.strings.indexOfCharPos(basename, '.', next)) |i| { - next = i + 1; - if (i == 0) continue; - const ext = basename[i..]; - if (vm.commonjs_custom_extensions.get(ext)) |value| { - return value.unpack(); - } - } - return null; -} - -fn onRequireExtensionModifyBinding( - global: *JSC.JSGlobalObject, - str: *const bun.String, - kind: i32, - value: JSC.JSValue, -) callconv(.c) void { - var sfa_state = std.heap.stackFallback(8192, bun.default_allocator); - const alloc = sfa_state.get(); - const str_slice = str.toUTF8(alloc); - defer str_slice.deinit(); - onRequireExtensionModify(global, str_slice.slice(), kind, value) catch |err| switch (err) { - error.OutOfMemory => bun.outOfMemory(), - }; -} - -comptime { - @export(&onRequireExtensionModifyBinding, .{ .name = "NodeModuleModule__onRequireExtensionModify" }); -} diff --git a/src/bun.js/bindings/ResolvedSource.zig b/src/bun.js/bindings/ResolvedSource.zig index f8f43999e0..ed35ac3fc1 100644 --- a/src/bun.js/bindings/ResolvedSource.zig +++ b/src/bun.js/bindings/ResolvedSource.zig @@ -13,15 +13,13 @@ pub const ResolvedSource = extern struct { is_commonjs_module: bool = false, - /// When .tag is .common_js_custom_extension, this is special-cased to hold - /// the index of the extension, since the module is stored in a WriteBarrier. - cjs_custom_extension_index: u32 = 0, + hash: u32 = 0, allocator: ?*anyopaque = null, jsvalue_for_export: JSValue = .zero, - tag: Tag = .javascript, + tag: Tag = Tag.javascript, /// This is for source_code source_code_needs_deref: bool = true, diff --git a/src/bun.js/bindings/ZigGlobalObject.cpp b/src/bun.js/bindings/ZigGlobalObject.cpp index 3e2397f1d8..1df8ff2512 100644 --- a/src/bun.js/bindings/ZigGlobalObject.cpp +++ b/src/bun.js/bindings/ZigGlobalObject.cpp @@ -2938,6 +2938,18 @@ void GlobalObject::finishCreation(VM& vm) init.set(crypto); }); + m_lazyRequireCacheObject.initLater( + [](const Initializer& init) { + JSC::VM& vm = init.vm; + JSC::JSGlobalObject* globalObject = init.owner; + + auto* function = JSFunction::create(vm, globalObject, static_cast(commonJSCreateRequireCacheCodeGenerator(vm)), globalObject); + + NakedPtr returnedException = nullptr; + auto result = JSC::profiledCall(globalObject, ProfilingReason::API, function, JSC::getCallData(function), globalObject, ArgList(), returnedException); + init.set(result.toObject(globalObject)); + }); + m_lazyTestModuleObject.initLater( [](const Initializer& init) { JSC::JSGlobalObject* globalObject = init.owner; diff --git a/src/bun.js/bindings/ZigGlobalObject.h b/src/bun.js/bindings/ZigGlobalObject.h index af5aaf95fe..7fa6cf7da1 100644 --- a/src/bun.js/bindings/ZigGlobalObject.h +++ b/src/bun.js/bindings/ZigGlobalObject.h @@ -56,13 +56,6 @@ class GlobalInternals; #include #include -namespace Bun { -class JSCommonJSExtensions; -class InternalModuleRegistry; -class JSMockModule; -class JSMockFunction; -} - namespace WebCore { class WorkerGlobalScope; class SubtleCrypto; @@ -269,7 +262,6 @@ public: JSObject* processBindingFs() const { return m_processBindingFs.getInitializedOnMainThread(this); } JSObject* lazyRequireCacheObject() const { return m_lazyRequireCacheObject.getInitializedOnMainThread(this); } - Bun::JSCommonJSExtensions* lazyRequireExtensionsObject() const { return m_lazyRequireExtensionsObject.getInitializedOnMainThread(this); } Structure* NodeVMGlobalObjectStructure() const { return m_cachedNodeVMGlobalObjectStructure.getInitializedOnMainThread(this); } Structure* globalProxyStructure() const { return m_cachedGlobalProxyStructure.getInitializedOnMainThread(this); } @@ -594,7 +586,6 @@ public: LazyProperty m_JSResizableOrGrowableSharedBufferSubclassStructure; LazyProperty m_vmModuleContextMap; LazyProperty m_lazyRequireCacheObject; - LazyProperty m_lazyRequireExtensionsObject; LazyProperty m_lazyTestModuleObject; LazyProperty m_lazyPreloadTestModuleObject; LazyProperty m_testMatcherUtilsObject; diff --git a/src/bun.js/bindings/bindings.zig b/src/bun.js/bindings/bindings.zig index 9633829240..a44efc4450 100644 --- a/src/bun.js/bindings/bindings.zig +++ b/src/bun.js/bindings/bindings.zig @@ -342,30 +342,30 @@ pub fn initialize(eval_mode: bool) void { JSCInitialize( std.os.environ.ptr, std.os.environ.len, - onJSCInvalidEnvVar, + struct { + pub fn callback(name: [*]const u8, len: usize) callconv(.C) void { + Output.prettyErrorln( + \\error: invalid JSC environment variable + \\ + \\ {s} + \\ + \\For a list of options, see this file: + \\ + \\ https://github.com/oven-sh/webkit/blob/main/Source/JavaScriptCore/runtime/OptionsList.h + \\ + \\Environment variables must be prefixed with "BUN_JSC_". This code runs before .env files are loaded, so those won't work here. + \\ + \\Warning: options change between releases of Bun and WebKit without notice. This is not a stable API, you should not rely on it beyond debugging something, and it may be removed entirely in a future version of Bun. + , + .{name[0..len]}, + ); + bun.Global.exit(1); + } + }.callback, eval_mode, ); } -pub fn onJSCInvalidEnvVar(name: [*]const u8, len: usize) callconv(.C) void { - Output.prettyErrorln( - \\error: invalid JSC environment variable - \\ - \\ {s} - \\ - \\For a list of options, see this file: - \\ - \\ https://github.com/oven-sh/webkit/blob/main/Source/JavaScriptCore/runtime/OptionsList.h - \\ - \\Environment variables must be prefixed with "BUN_JSC_". This code runs before .env files are loaded, so those won't work here. - \\ - \\Warning: options change between releases of Bun and WebKit without notice. This is not a stable API, you should not rely on it beyond debugging something, and it may be removed entirely in a future version of Bun. - , - .{name[0..len]}, - ); - bun.Global.exit(1); -} - /// Returns null on error. Use windows API to lookup the actual error. /// The reason this function is in zig is so that we can use our own utf16-conversion functions. /// diff --git a/src/bun.js/bindings/headers-handwritten.h b/src/bun.js/bindings/headers-handwritten.h index 3662a5452e..55710a0ebf 100644 --- a/src/bun.js/bindings/headers-handwritten.h +++ b/src/bun.js/bindings/headers-handwritten.h @@ -106,7 +106,7 @@ typedef struct ResolvedSource { BunString source_code; BunString source_url; bool isCommonJSModule; - uint32_t cjsCustomExtensionIndex; + uint32_t hash; void* allocator; JSC::EncodedJSValue jsvalue_for_export; uint32_t tag; @@ -347,9 +347,7 @@ extern "C" JSC::JSInternalPromise* Bun__transpileFile( BunString* specifier, BunString* referrer, const BunString* typeAttribute, - ErrorableResolvedSource* result, - bool allowPromise, - bool isCommonJSRequire); + ErrorableResolvedSource* result, bool allowPromise); extern "C" bool Bun__fetchBuiltinModule( void* bunVM, diff --git a/src/bun.js/bindings/webcore/DOMClientIsoSubspaces.h b/src/bun.js/bindings/webcore/DOMClientIsoSubspaces.h index 159d2417cd..21a4ed1392 100644 --- a/src/bun.js/bindings/webcore/DOMClientIsoSubspaces.h +++ b/src/bun.js/bindings/webcore/DOMClientIsoSubspaces.h @@ -37,7 +37,6 @@ public: std::unique_ptr m_clientSubspaceForBundlerPlugin; std::unique_ptr m_clientSubspaceForNodeVMScript; std::unique_ptr m_clientSubspaceForJSCommonJSModule; - std::unique_ptr m_clientSubspaceForJSCommonJSExtensions; std::unique_ptr m_clientSubspaceForJSMockImplementation; std::unique_ptr m_clientSubspaceForJSModuleMock; std::unique_ptr m_clientSubspaceForJSMockFunction; diff --git a/src/bun.js/bindings/webcore/DOMIsoSubspaces.h b/src/bun.js/bindings/webcore/DOMIsoSubspaces.h index 6b64f5d0f3..ea657733a0 100644 --- a/src/bun.js/bindings/webcore/DOMIsoSubspaces.h +++ b/src/bun.js/bindings/webcore/DOMIsoSubspaces.h @@ -37,7 +37,6 @@ public: std::unique_ptr m_subspaceForBundlerPlugin; std::unique_ptr m_subspaceForNodeVMScript; std::unique_ptr m_subspaceForJSCommonJSModule; - std::unique_ptr m_subspaceForJSCommonJSExtensions; std::unique_ptr m_subspaceForJSMockImplementation; std::unique_ptr m_subspaceForJSModuleMock; std::unique_ptr m_subspaceForJSMockFunction; diff --git a/src/bun.js/javascript.zig b/src/bun.js/javascript.zig index 7c4ea3f710..d72798803b 100644 --- a/src/bun.js/javascript.zig +++ b/src/bun.js/javascript.zig @@ -74,7 +74,6 @@ const PackageManager = @import("../install/install.zig").PackageManager; const IPC = @import("ipc.zig"); const DNSResolver = @import("api/bun/dns_resolver.zig").DNSResolver; const Watcher = bun.Watcher; -const node_module_module = @import("./bindings/NodeModuleModule.zig"); const ModuleLoader = JSC.ModuleLoader; const FetchFlags = JSC.FetchFlags; @@ -901,7 +900,7 @@ pub const VirtualMachine = struct { is_inside_deferred_task_queue: bool = false, - // defaults off. .on("message") will set it to true unless overridden + // defaults off. .on("message") will set it to true unles overridden // process.channel.unref() will set it to false and mark it overridden // on disconnect it will be disabled channel_ref: bun.Async.KeepAlive = .{}, @@ -910,18 +909,6 @@ pub const VirtualMachine = struct { // if one disconnect event listener should be ignored channel_ref_should_ignore_one_disconnect_event_listener: bool = false, - /// A set of extensions that exist in the require.extensions map. Keys - /// contain the leading '.'. Value is either a loader for built in - /// functions, or an index into JSCommonJSExtensions. - /// - /// `.keys() == transpiler.resolver.opts.extra_cjs_extensions`, so - /// mutations in this map must update the resolver. - commonjs_custom_extensions: bun.StringArrayHashMapUnmanaged(node_module_module.CustomLoader.Packed) = .empty, - /// Incremented when the `require.extensions` for a built-in extension is mutated. - /// An example is mutating `require.extensions['.js']` to intercept all '.js' files. - /// The value is decremented when defaults are restored. - has_mutated_built_in_extensions: u32 = 0, - pub const OnUnhandledRejection = fn (*VirtualMachine, globalObject: *JSGlobalObject, JSValue) void; pub const OnException = fn (*ZigException) void; @@ -2380,6 +2367,7 @@ pub const VirtualMachine = struct { .source_code = bun.String.init(""), .specifier = specifier, .source_url = specifier.createIfDifferent(source_url), + .hash = 0, .allocator = null, .source_code_needs_deref = false, }; @@ -2394,6 +2382,7 @@ pub const VirtualMachine = struct { .source_code = bun.String.init(source.impl), .specifier = specifier, .source_url = specifier.createIfDifferent(source_url), + .hash = source.hash, .allocator = source, .source_code_needs_deref = false, }; diff --git a/src/bun.js/module_loader.zig b/src/bun.js/module_loader.zig index 71360430ce..9ffcd0798a 100644 --- a/src/bun.js/module_loader.zig +++ b/src/bun.js/module_loader.zig @@ -42,7 +42,6 @@ const JSC = bun.JSC; const MarkedArrayBuffer = @import("./base.zig").MarkedArrayBuffer; const getAllocator = @import("./base.zig").getAllocator; const JSValue = bun.JSC.JSValue; -const node_module_module = @import("./bindings/NodeModuleModule.zig"); const JSGlobalObject = bun.JSC.JSGlobalObject; const ExceptionValueRef = bun.JSC.ExceptionValueRef; @@ -79,6 +78,7 @@ inline fn jsSyntheticModule(name: ResolvedSource.Tag, specifier: String) Resolve .source_code = bun.String.empty, .specifier = specifier, .source_url = bun.String.static(@tagName(name)), + .hash = 0, .tag = name, .source_code_needs_deref = false, }; @@ -568,6 +568,7 @@ pub const RuntimeTranspilerStore = struct { break :brk result; }, }, + .hash = 0, .is_commonjs_module = entry.metadata.module_type == .cjs, .tag = this.resolved_source.tag, }; @@ -581,6 +582,7 @@ pub const RuntimeTranspilerStore = struct { .allocator = null, .source_code = bun.String.createLatin1(parse_result.source.contents), .already_bundled = true, + .hash = 0, .bytecode_cache = if (bytecode_slice.len > 0) bytecode_slice.ptr else null, .bytecode_cache_size = bytecode_slice.len, .is_commonjs_module = parse_result.already_bundled.isCommonJS(), @@ -682,6 +684,7 @@ pub const RuntimeTranspilerStore = struct { .allocator = null, .source_code = source_code, .is_commonjs_module = parse_result.ast.has_commonjs_export_names or parse_result.ast.exports_kind == .cjs, + .hash = 0, .tag = this.resolved_source.tag, }; } @@ -1444,6 +1447,8 @@ pub const ModuleLoader = struct { .specifier = String.init(specifier), .source_url = String.init(path.text), .is_commonjs_module = parse_result.ast.has_commonjs_export_names or parse_result.ast.exports_kind == .cjs, + + .hash = 0, }; } @@ -1504,6 +1509,7 @@ pub const ModuleLoader = struct { .source_code = bun.String.empty, .specifier = input_specifier, .source_url = input_specifier.createIfDifferent(path.text), + .hash = 0, }; } } @@ -1735,6 +1741,8 @@ pub const ModuleLoader = struct { .source_code = bun.String.createUTF8(parse_result.source.contents), .specifier = input_specifier, .source_url = input_specifier.createIfDifferent(path.text), + + .hash = 0, .tag = ResolvedSource.Tag.json_for_object_loader, }; } @@ -1749,6 +1757,7 @@ pub const ModuleLoader = struct { }, .specifier = input_specifier, .source_url = input_specifier.createIfDifferent(path.text), + .hash = 0, }; } @@ -1758,6 +1767,7 @@ pub const ModuleLoader = struct { .allocator = null, .specifier = input_specifier, .source_url = input_specifier.createIfDifferent(path.text), + .hash = 0, .jsvalue_for_export = JSValue.createEmptyObject(jsc_vm.global, 0), .tag = .exports_object, }; @@ -1767,6 +1777,7 @@ pub const ModuleLoader = struct { .allocator = null, .specifier = input_specifier, .source_url = input_specifier.createIfDifferent(path.text), + .hash = 0, .jsvalue_for_export = parse_result.ast.parts.@"[0]"().stmts[0].data.s_expr.value.toJS(allocator, globalObject orelse jsc_vm.global) catch |e| panic("Unexpected JS error: {s}", .{@errorName(e)}), .tag = .exports_object, }; @@ -1780,6 +1791,7 @@ pub const ModuleLoader = struct { .specifier = input_specifier, .source_url = input_specifier.createIfDifferent(path.text), .already_bundled = true, + .hash = 0, .bytecode_cache = if (bytecode_slice.len > 0) bytecode_slice.ptr else null, .bytecode_cache_size = bytecode_slice.len, .is_commonjs_module = parse_result.already_bundled.isCommonJS(), @@ -1798,6 +1810,7 @@ pub const ModuleLoader = struct { .specifier = input_specifier, .source_url = input_specifier.createIfDifferent(path.text), .is_commonjs_module = true, + .hash = 0, .tag = .javascript, }; } @@ -1826,6 +1839,7 @@ pub const ModuleLoader = struct { }, .specifier = input_specifier, .source_url = input_specifier.createIfDifferent(path.text), + .hash = 0, .is_commonjs_module = entry.metadata.module_type == .cjs, .tag = brk: { if (entry.metadata.module_type == .cjs and parse_result.source.path.isFile()) { @@ -1956,6 +1970,7 @@ pub const ModuleLoader = struct { .specifier = input_specifier, .source_url = input_specifier.createIfDifferent(path.text), .is_commonjs_module = parse_result.ast.has_commonjs_export_names or parse_result.ast.exports_kind == .cjs, + .hash = 0, .tag = tag, }; }, @@ -1998,6 +2013,7 @@ pub const ModuleLoader = struct { // .source_code = ZigString.init(jsc_vm.allocator.dupe(u8, parse_result.source.contents) catch unreachable), // .specifier = ZigString.init(specifier), // .source_url = input_specifier.createIfDifferent(path.text), + // .hash = 0, // .tag = ResolvedSource.Tag.wasm, // }; // }, @@ -2023,6 +2039,7 @@ pub const ModuleLoader = struct { .specifier = input_specifier, .source_url = input_specifier.createIfDifferent(path.text), .tag = .esm, + .hash = 0, }; } @@ -2082,6 +2099,7 @@ pub const ModuleLoader = struct { .specifier = input_specifier, .source_url = input_specifier.createIfDifferent(path.text), .tag = .esm, + .hash = 0, }; }, @@ -2092,6 +2110,7 @@ pub const ModuleLoader = struct { .source_code = bun.String.empty, .specifier = input_specifier, .source_url = input_specifier.createIfDifferent(path.text), + .hash = 0, .tag = .esm, }; } @@ -2106,6 +2125,7 @@ pub const ModuleLoader = struct { .jsvalue_for_export = html_bundle.toJS(globalObject.?), .specifier = input_specifier, .source_url = input_specifier.createIfDifferent(path.text), + .hash = 0, .tag = .export_default_object, }; }, @@ -2117,6 +2137,7 @@ pub const ModuleLoader = struct { .source_code = bun.String.empty, .specifier = input_specifier, .source_url = input_specifier.createIfDifferent(path.text), + .hash = 0, .tag = .esm, }; } @@ -2188,6 +2209,7 @@ pub const ModuleLoader = struct { .jsvalue_for_export = value, .specifier = input_specifier, .source_url = input_specifier.createIfDifferent(path.text), + .hash = 0, .tag = .export_default_object, }; }, @@ -2255,7 +2277,6 @@ pub const ModuleLoader = struct { type_attribute: ?*const bun.String, ret: *JSC.ErrorableResolvedSource, allow_promise: bool, - is_commonjs_require: bool, ) ?*anyopaque { JSC.markBinding(@src()); var log = logger.Log.init(jsc_vm.transpiler.allocator); @@ -2273,63 +2294,13 @@ pub const ModuleLoader = struct { var virtual_source_to_use: ?logger.Source = null; var blob_to_deinit: ?JSC.WebCore.Blob = null; - var lr = options.getLoaderAndVirtualSource(_specifier.slice(), jsc_vm, &virtual_source_to_use, &blob_to_deinit, type_attribute_str) catch { + const lr = options.getLoaderAndVirtualSource(_specifier.slice(), jsc_vm, &virtual_source_to_use, &blob_to_deinit, type_attribute_str) catch { ret.* = JSC.ErrorableResolvedSource.err(error.JSErrorObject, globalObject.MODULE_NOT_FOUND("Blob not found", .{}).toJS().asVoid()); return null; }; defer if (blob_to_deinit) |*blob| blob.deinit(); - if (is_commonjs_require and jsc_vm.has_mutated_built_in_extensions > 0) brk: { - @branchHint(.unlikely); - if (node_module_module.findLongestRegisteredExtension(jsc_vm, _specifier.slice())) |entry| { - switch (entry) { - .loader => |loader| { - lr.loader = loader; - break :brk; - }, - .custom => |index| { - ret.* = JSC.ErrorableResolvedSource.ok(ResolvedSource{ - .allocator = null, - .source_code = bun.String.empty, - .specifier = .empty, - .source_url = .empty, - .cjs_custom_extension_index = index, - .tag = .common_js_custom_extension, - }); - return null; - }, - } - } - } - - const module_type: options.ModuleType = brk: { - const ext = lr.path.name.ext; - // regular expression /.[cm][jt]s$/ - if (ext.len == ".cjs".len) { - if (strings.eqlComptimeIgnoreLen(ext, ".cjs")) - break :brk .cjs; - if (strings.eqlComptimeIgnoreLen(ext, ".mjs")) - break :brk .esm; - if (strings.eqlComptimeIgnoreLen(ext, ".cts")) - break :brk .cjs; - if (strings.eqlComptimeIgnoreLen(ext, ".mts")) - break :brk .esm; - } - // regular expression /.[jt]s$/ - if (ext.len == ".ts".len) { - if (strings.eqlComptimeIgnoreLen(ext, ".js") or - strings.eqlComptimeIgnoreLen(ext, ".ts")) - { - // Use the package.json module type if it exists - break :brk if (lr.package_json) |pkg| - pkg.module_type - else - .unknown; - } - } - // For JSX TSX and other extensions, let the file contents. - break :brk .unknown; - }; + const module_type: options.ModuleType = if (lr.package_json) |pkg| pkg.module_type else .unknown; const pkg_name: ?[]const u8 = if (lr.package_json) |pkg| if (pkg.name.len > 0) pkg.name else null else @@ -2396,48 +2367,19 @@ pub const ModuleLoader = struct { } } - const synchronous_loader: options.Loader = lr.loader orelse loader: { + const synchronous_loader = lr.loader orelse loader: { if (jsc_vm.has_loaded or jsc_vm.is_in_preload) { // Extensionless files in this context are treated as the JS loader if (lr.path.name.ext.len == 0) { - break :loader .tsx; + break :loader options.Loader.tsx; } // Unknown extensions are to be treated as file loader - if (is_commonjs_require) { - if (jsc_vm.commonjs_custom_extensions.entries.len > 0 and - jsc_vm.has_mutated_built_in_extensions == 0) - { - @branchHint(.unlikely); - if (node_module_module.findLongestRegisteredExtension(jsc_vm, lr.path.text)) |entry| { - switch (entry) { - .loader => |loader| break :loader loader, - .custom => |index| { - ret.* = JSC.ErrorableResolvedSource.ok(ResolvedSource{ - .allocator = null, - .source_code = bun.String.empty, - .specifier = .empty, - .source_url = .empty, - .cjs_custom_extension_index = index, - .tag = .common_js_custom_extension, - }); - return null; - }, - } - } - } - - // For Node.js compatibility, requiring a file with an - // unknown extension will be treated as a JS file - break :loader .ts; - } - - // For ESM, Bun treats unknown extensions as file loader - break :loader .file; + break :loader options.Loader.file; } else { // Unless it's potentially the main module // This is important so that "bun run ./foo-i-have-no-extension" works - break :loader .tsx; + break :loader options.Loader.tsx; } }; @@ -2509,6 +2451,7 @@ pub const ModuleLoader = struct { .source_code = bun.String.createUTF8(jsc_vm.entry_point.source.contents), .specifier = specifier, .source_url = specifier, + .hash = 0, .tag = .esm, .source_code_needs_deref = true, }, @@ -2524,6 +2467,7 @@ pub const ModuleLoader = struct { .source_code = String.init(Runtime.Runtime.sourceCode()), .specifier = specifier, .source_url = specifier, + .hash = Runtime.Runtime.versionHash(), }, inline else => |tag| jsSyntheticModule(@field(ResolvedSource.Tag, @tagName(tag)), specifier), }; @@ -2543,6 +2487,7 @@ pub const ModuleLoader = struct { .source_code = bun.String.createUTF8(entry.source.contents), .specifier = specifier, .source_url = specifier.dupeRef(), + .hash = 0, }; } } else if (jsc_vm.standalone_module_graph) |graph| { @@ -2564,6 +2509,7 @@ pub const ModuleLoader = struct { .source_code = bun.String.static(code), .specifier = specifier, .source_url = specifier.dupeRef(), + .hash = 0, .source_code_needs_deref = false, }; } @@ -2573,6 +2519,7 @@ pub const ModuleLoader = struct { .source_code = file.toWTFString(), .specifier = specifier, .source_url = specifier.dupeRef(), + .hash = 0, .source_code_needs_deref = false, .bytecode_cache = if (file.bytecode.len > 0) file.bytecode.ptr else null, .bytecode_cache_size = file.bytecode.len, diff --git a/src/bun.js/modules/NodeModuleModule.cpp b/src/bun.js/modules/NodeModuleModule.cpp index f25ce59988..e14600539a 100644 --- a/src/bun.js/modules/NodeModuleModule.cpp +++ b/src/bun.js/modules/NodeModuleModule.cpp @@ -12,7 +12,6 @@ #include #include "JavaScriptCore/Completion.h" #include "JavaScriptCore/JSNativeStdFunction.h" -#include "JSCommonJSExtensions.h" #include "PathInlines.h" #include "ZigGlobalObject.h" @@ -563,12 +562,6 @@ static JSValue getModuleCacheObject(VM& vm, JSObject* moduleObject) ->lazyRequireCacheObject(); } -static JSValue getModuleExtensionsObject(VM& vm, JSObject* moduleObject) -{ - return jsCast(moduleObject->globalObject()) - ->lazyRequireExtensionsObject(); -} - static JSValue getModuleDebugObject(VM& vm, JSObject* moduleObject) { return JSC::constructEmptyObject(moduleObject->globalObject()); @@ -581,6 +574,13 @@ static JSValue getPathCacheObject(VM& vm, JSObject* moduleObject) vm, globalObject->nullPrototypeObjectStructure()); } +static JSValue getModuleExtensionsObject(VM& vm, JSObject* moduleObject) +{ + auto* globalObject = defaultGlobalObject(moduleObject->globalObject()); + return globalObject->requireFunctionUnbound()->getIfPropertyExists( + globalObject, Identifier::fromString(vm, "extensions"_s)); +} + static JSValue getSourceMapFunction(VM& vm, JSObject* moduleObject) { auto* globalObject = defaultGlobalObject(moduleObject->globalObject()); @@ -951,27 +951,6 @@ void addNodeModuleConstructorProperties(JSC::VM& vm, JSC::NoIntrinsic, jsFunctionResolveFileName); init.set(resolveFilenameFunction); }); - - globalObject->m_lazyRequireCacheObject.initLater( - [](const Zig::GlobalObject::Initializer& init) { - JSC::VM& vm = init.vm; - JSC::JSGlobalObject* globalObject = init.owner; - - auto* function = JSFunction::create(vm, globalObject, static_cast(commonJSCreateRequireCacheCodeGenerator(vm)), globalObject); - - NakedPtr returnedException = nullptr; - auto result = JSC::profiledCall(globalObject, ProfilingReason::API, function, JSC::getCallData(function), globalObject, ArgList(), returnedException); - ASSERT(!returnedException); - init.set(result.toObject(globalObject)); - }); - - globalObject->m_lazyRequireExtensionsObject.initLater( - [](const Zig::GlobalObject::Initializer& init) { - JSC::VM& vm = init.vm; - JSC::JSGlobalObject* globalObject = init.owner; - - init.set(JSCommonJSExtensions::create(vm, globalObject, JSCommonJSExtensions::createStructure(vm, globalObject, globalObject->nullPrototype()))); - }); } JSC_DEFINE_HOST_FUNCTION(jsFunctionIsModuleResolveFilenameSlowPathEnabled, diff --git a/src/codegen/bundle-modules.ts b/src/codegen/bundle-modules.ts index 4e954e76bd..44db6f130c 100644 --- a/src/codegen/bundle-modules.ts +++ b/src/codegen/bundle-modules.ts @@ -395,6 +395,7 @@ writeIfNotChanged( path.join(CODEGEN_DIR, "ResolvedSourceTag.zig"), `// zig fmt: off pub const ResolvedSourceTag = enum(u32) { + // Predefined javascript = 0, package_json_type_module = 1, package_json_type_commonjs = 2, @@ -403,12 +404,11 @@ pub const ResolvedSourceTag = enum(u32) { file = 5, esm = 6, json_for_object_loader = 7, - /// Generate an object with "default" set to all the exports, including a "default" property + /// Generate an object with "default" set to all the exports, including a "default" propert exports_object = 8, + /// Generate a module that only exports default the input JSValue export_default_object = 9, - /// Signal upwards that the matching value in 'require.extensions' should be used. - common_js_custom_extension = 10, // Built in modules are loaded through InternalModuleRegistry by numerical ID. // In this enum are represented as \`(1 << 9) & id\` @@ -438,7 +438,6 @@ writeIfNotChanged( JSONForObjectLoader = 7, ExportsObject = 8, ExportDefaultObject = 9, - CommonJSCustomExtension = 10, // Built in modules are loaded through InternalModuleRegistry by numerical ID. // In this enum are represented as \`(1 << 9) & id\` InternalModuleRegistryFlag = 1 << 9, diff --git a/src/js/builtins.d.ts b/src/js/builtins.d.ts index d3a34cffec..f6ae715204 100644 --- a/src/js/builtins.d.ts +++ b/src/js/builtins.d.ts @@ -484,7 +484,7 @@ declare function $createCommonJSModule( id: string, exports: any, hasEvaluated: boolean, - parent: JSCommonJSModule | undefined, + parent: ?JSCommonJSModule, ): JSCommonJSModule; declare function $evaluateCommonJSModule( moduleToEvaluate: JSCommonJSModule, diff --git a/src/js_parser.zig b/src/js_parser.zig index 93ffd6fdca..081e6ae040 100644 --- a/src/js_parser.zig +++ b/src/js_parser.zig @@ -3590,6 +3590,9 @@ pub const Parser = struct { } } + const did_import_fast_refresh = false; + _ = did_import_fast_refresh; + // This is a workaround for broken module environment checks in packages like lodash-es // https://github.com/lodash/lodash/issues/5660 var force_esm = false; @@ -3961,13 +3964,7 @@ pub const Parser = struct { switch (p.options.module_type) { // ".cjs" or ".cts" or ("type: commonjs" and (".js" or ".jsx" or ".ts" or ".tsx")) .cjs => { - // There are no commonjs-only features used (require is allowed in ESM) - bun.assert(!uses_exports_ref and - !uses_module_ref and - !p.has_top_level_return and - !p.has_with_scope); - // Use ESM if the file has ES module syntax (import) - exports_kind = if (p.has_es_module_syntax) .esm else .cjs; + exports_kind = .cjs; }, .esm => { exports_kind = .esm; diff --git a/src/options.zig b/src/options.zig index f6ceb6c525..982b128bb7 100644 --- a/src/options.zig +++ b/src/options.zig @@ -80,9 +80,9 @@ pub fn stringHashMapFromArrays(comptime t: type, allocator: std.mem.Allocator, k } pub const ExternalModules = struct { - node_modules: std.BufSet, - abs_paths: std.BufSet, - patterns: []const WildcardPattern, + node_modules: std.BufSet = undefined, + abs_paths: std.BufSet = undefined, + patterns: []const WildcardPattern = undefined, pub const WildcardPattern = struct { prefix: string, @@ -1700,7 +1700,7 @@ pub const BundleOptions = struct { main_fields: []const string = Target.DefaultMainFields.get(Target.browser), /// TODO: remove this in favor accessing bundler.log log: *logger.Log, - external: ExternalModules, + external: ExternalModules = ExternalModules{}, entry_points: []const string, entry_naming: []const u8 = "", asset_naming: []const u8 = "", @@ -1708,9 +1708,6 @@ pub const BundleOptions = struct { public_path: []const u8 = "", extension_order: ResolveFileExtensions = .{}, main_field_extension_order: []const string = &Defaults.MainFieldExtensionOrder, - /// This list applies to all extension resolution cases. The runtime uses - /// this for implementing `require.extensions` - extra_cjs_extensions: []const []const u8 = &.{}, out_extensions: bun.StringHashMap(string), import_path_format: ImportPathFormat = ImportPathFormat.relative, defines_loaded: bool = false, diff --git a/src/resolver/package_json.zig b/src/resolver/package_json.zig index 7095b69572..7e86224048 100644 --- a/src/resolver/package_json.zig +++ b/src/resolver/package_json.zig @@ -604,7 +604,7 @@ pub const PackageJSON = struct { null, ) catch |err| { if (err != error.IsDir) { - r.log.addErrorFmt(null, logger.Loc.Empty, allocator, "Cannot read file \"{s}\": {s}", .{ input_path, @errorName(err) }) catch unreachable; + r.log.addErrorFmt(null, logger.Loc.Empty, allocator, "Cannot read file \"{s}\": {s}", .{ r.prettyPath(fs.Path.init(input_path)), @errorName(err) }) catch unreachable; } return null; @@ -618,7 +618,7 @@ pub const PackageJSON = struct { const key_path = fs.Path.init(package_json_path); var json_source = logger.Source.initPathString(key_path.text, entry.contents); - json_source.path.pretty = json_source.path.text; + json_source.path.pretty = r.prettyPath(json_source.path); const json: js_ast.Expr = (r.caches.json.parsePackageJSON(r.log, json_source, allocator, true) catch |err| { if (Environment.isDebug) { diff --git a/src/resolver/resolver.zig b/src/resolver/resolver.zig index c46514b3db..d8e01b1896 100644 --- a/src/resolver/resolver.zig +++ b/src/resolver/resolver.zig @@ -2565,6 +2565,11 @@ pub const Resolver = struct { return result; } + // TODO: + pub fn prettyPath(_: *ThisResolver, path: Path) string { + return path.text; + } + pub fn binDirs(_: *const ThisResolver) []const string { if (!bin_folders_loaded) return &[_]string{}; return bin_folders.constSlice(); @@ -2828,7 +2833,7 @@ pub const Resolver = struct { r.dir_cache.markNotFound(queue_top.result); rfs.entries.markNotFound(cached_dir_entry_result); if (comptime enable_logging) { - const pretty = queue_top.unsafe_path; + const pretty = r.prettyPath(Path.init(queue_top.unsafe_path)); r.log.addErrorFmt( null, @@ -3466,68 +3471,54 @@ pub const Resolver = struct { } pub fn loadAsIndex(r: *ThisResolver, dir_info: *DirInfo, extension_order: []const string) ?MatchResult { + const rfs = &r.fs.fs; // Try the "index" file with extensions for (extension_order) |ext| { - if (loadIndexWithExtension(r, dir_info, ext)) |result| { - return result; - } - } - for (r.opts.extra_cjs_extensions) |ext| { - if (loadIndexWithExtension(r, dir_info, ext)) |result| { - return result; - } - } + var ext_buf = bufs(.extension_path); - return null; - } + var base = ext_buf[0 .. "index".len + ext.len]; + base[0.."index".len].* = "index".*; + bun.copy(u8, base["index".len..], ext); - fn loadIndexWithExtension(r: *ThisResolver, dir_info: *DirInfo, ext: string) ?MatchResult { - const rfs = &r.fs.fs; + if (dir_info.getEntries(r.generation)) |entries| { + if (entries.get(base)) |lookup| { + if (lookup.entry.kind(rfs, r.store_fd) == .file) { + const out_buf = brk: { + if (lookup.entry.abs_path.isEmpty()) { + const parts = [_]string{ dir_info.abs_path, base }; + const out_buf_ = r.fs.absBuf(&parts, bufs(.index)); + lookup.entry.abs_path = + PathString.init(r.fs.dirname_store.append(@TypeOf(out_buf_), out_buf_) catch unreachable); + } + break :brk lookup.entry.abs_path.slice(); + }; - var ext_buf = bufs(.extension_path); - - var base = ext_buf[0 .. "index".len + ext.len]; - base[0.."index".len].* = "index".*; - bun.copy(u8, base["index".len..], ext); - - if (dir_info.getEntries(r.generation)) |entries| { - if (entries.get(base)) |lookup| { - if (lookup.entry.kind(rfs, r.store_fd) == .file) { - const out_buf = brk: { - if (lookup.entry.abs_path.isEmpty()) { - const parts = [_]string{ dir_info.abs_path, base }; - const out_buf_ = r.fs.absBuf(&parts, bufs(.index)); - lookup.entry.abs_path = - PathString.init(r.fs.dirname_store.append(@TypeOf(out_buf_), out_buf_) catch unreachable); + if (r.debug_logs) |*debug| { + debug.addNoteFmt("Found file: \"{s}\"", .{out_buf}); } - break :brk lookup.entry.abs_path.slice(); - }; - if (r.debug_logs) |*debug| { - debug.addNoteFmt("Found file: \"{s}\"", .{out_buf}); - } + if (dir_info.package_json) |package_json| { + return MatchResult{ + .path_pair = .{ .primary = Path.init(out_buf) }, + .diff_case = lookup.diff_case, + .package_json = package_json, + .dirname_fd = dir_info.getFileDescriptor(), + }; + } - if (dir_info.package_json) |package_json| { return MatchResult{ .path_pair = .{ .primary = Path.init(out_buf) }, .diff_case = lookup.diff_case, - .package_json = package_json, + .dirname_fd = dir_info.getFileDescriptor(), }; } - - return MatchResult{ - .path_pair = .{ .primary = Path.init(out_buf) }, - .diff_case = lookup.diff_case, - - .dirname_fd = dir_info.getFileDescriptor(), - }; } } - } - if (r.debug_logs) |*debug| { - debug.addNoteFmt("Failed to find file: \"{s}/{s}\"", .{ dir_info.abs_path, base }); + if (r.debug_logs) |*debug| { + debug.addNoteFmt("Failed to find file: \"{s}/{s}\"", .{ dir_info.abs_path, base }); + } } return null; @@ -3751,7 +3742,7 @@ pub const Resolver = struct { } pub fn loadAsFile(r: *ThisResolver, path: string, extension_order: []const string) ?LoadResult { - const rfs: *Fs.FileSystem.RealFS = &r.fs.fs; + var rfs: *Fs.FileSystem.RealFS = &r.fs.fs; if (r.debug_logs) |*debug| { debug.addNoteFmt("Attempting to load \"{s}\" as a file", .{path}); @@ -3783,7 +3774,7 @@ pub const Resolver = struct { r.allocator, "Cannot read directory \"{s}\": {s}", .{ - dir_path, + r.prettyPath(Path.init(dir_path)), @errorName(dir_entry.err.original_err), }, ) catch {}; @@ -3827,14 +3818,35 @@ pub const Resolver = struct { // Try the path with extensions bun.copy(u8, bufs(.load_as_file), path); for (extension_order) |ext| { - if (loadExtension(r, base, path, ext, entries)) |result| { - return result; - } - } + var buffer = bufs(.load_as_file)[0 .. path.len + ext.len]; + bun.copy(u8, buffer[path.len..], ext); + const file_name = buffer[path.len - base.len .. buffer.len]; - for (r.opts.extra_cjs_extensions) |ext| { - if (loadExtension(r, base, path, ext, entries)) |result| { - return result; + if (r.debug_logs) |*debug| { + debug.addNoteFmt("Checking for file \"{s}\" ", .{buffer}); + } + + if (entries.get(file_name)) |query| { + if (query.entry.kind(rfs, r.store_fd) == .file) { + if (r.debug_logs) |*debug| { + debug.addNoteFmt("Found file \"{s}\" ", .{buffer}); + } + + // now that we've found it, we allocate it. + return LoadResult{ + .path = brk: { + query.entry.abs_path = if (query.entry.abs_path.isEmpty()) + PathString.init(r.fs.dirname_store.append(@TypeOf(buffer), buffer) catch unreachable) + else + query.entry.abs_path; + + break :brk query.entry.abs_path.slice(); + }, + .diff_case = query.diff_case, + .dirname_fd = entries.fd, + .file_fd = query.entry.cache.fd, + }; + } } } @@ -3919,42 +3931,6 @@ pub const Resolver = struct { return null; } - fn loadExtension(r: *ThisResolver, base: string, path: string, ext: string, entries: *Fs.FileSystem.DirEntry) ?LoadResult { - const rfs: *Fs.FileSystem.RealFS = &r.fs.fs; - const buffer = bufs(.load_as_file)[0 .. path.len + ext.len]; - bun.copy(u8, buffer[path.len..], ext); - const file_name = buffer[path.len - base.len .. buffer.len]; - - if (r.debug_logs) |*debug| { - debug.addNoteFmt("Checking for file \"{s}\" ", .{buffer}); - } - - if (entries.get(file_name)) |query| { - if (query.entry.kind(rfs, r.store_fd) == .file) { - if (r.debug_logs) |*debug| { - debug.addNoteFmt("Found file \"{s}\" ", .{buffer}); - } - - // now that we've found it, we allocate it. - return .{ - .path = brk: { - query.entry.abs_path = if (query.entry.abs_path.isEmpty()) - PathString.init(r.fs.dirname_store.append(@TypeOf(buffer), buffer) catch unreachable) - else - query.entry.abs_path; - - break :brk query.entry.abs_path.slice(); - }, - .diff_case = query.diff_case, - .dirname_fd = entries.fd, - .file_fd = query.entry.cache.fd, - }; - } - } - - return null; - } - fn dirInfoUncached( r: *ThisResolver, info: *DirInfo, @@ -4162,7 +4138,8 @@ pub const Resolver = struct { tsconfigpath, if (FeatureFlags.store_file_descriptors) fd else .zero, ) catch |err| brk: { - const pretty = tsconfigpath; + const pretty = r.prettyPath(Path.init(tsconfigpath)); + if (err == error.ENOENT or err == error.FileNotFound) { r.log.addErrorFmt(null, logger.Loc.Empty, r.allocator, "Cannot find tsconfig file {}", .{bun.fmt.QuotedFormatter{ .text = pretty }}) catch {}; } else if (err != error.ParseErrorAlreadyLogged and err != error.IsDir and err != error.EISDIR) { diff --git a/src/transpiler.zig b/src/transpiler.zig index 8d821df180..60470cfdf7 100644 --- a/src/transpiler.zig +++ b/src/transpiler.zig @@ -1177,21 +1177,21 @@ pub const Transpiler = struct { transpiler.log, &source, ) catch null) orelse return null) { - .ast => |value| .{ + .ast => |value| ParseResult{ .ast = value, .source = source, .loader = loader, .input_fd = input_fd, .runtime_transpiler_cache = this_parse.runtime_transpiler_cache, }, - .cached => .{ + .cached => ParseResult{ .ast = undefined, .runtime_transpiler_cache = this_parse.runtime_transpiler_cache, .source = source, .loader = loader, .input_fd = input_fd, }, - .already_bundled => |already_bundled| .{ + .already_bundled => |already_bundled| ParseResult{ .ast = undefined, .already_bundled = switch (already_bundled) { .bun => .source_code, diff --git a/test/cli/run/module-type-fixture/cjs/hello.cjs b/test/cli/run/module-type-fixture/cjs/hello.cjs deleted file mode 100644 index 248453e484..0000000000 --- a/test/cli/run/module-type-fixture/cjs/hello.cjs +++ /dev/null @@ -1 +0,0 @@ -console.log(eval("typeof module === 'undefined'")); diff --git a/test/cli/run/module-type-fixture/cjs/hello.cts b/test/cli/run/module-type-fixture/cjs/hello.cts deleted file mode 100644 index 248453e484..0000000000 --- a/test/cli/run/module-type-fixture/cjs/hello.cts +++ /dev/null @@ -1 +0,0 @@ -console.log(eval("typeof module === 'undefined'")); diff --git a/test/cli/run/module-type-fixture/cjs/hello.js b/test/cli/run/module-type-fixture/cjs/hello.js deleted file mode 100644 index 72c037e9a6..0000000000 --- a/test/cli/run/module-type-fixture/cjs/hello.js +++ /dev/null @@ -1 +0,0 @@ -console.log(eval("typeof module === 'undefined'")); \ No newline at end of file diff --git a/test/cli/run/module-type-fixture/cjs/hello.jsx b/test/cli/run/module-type-fixture/cjs/hello.jsx deleted file mode 100644 index 72c037e9a6..0000000000 --- a/test/cli/run/module-type-fixture/cjs/hello.jsx +++ /dev/null @@ -1 +0,0 @@ -console.log(eval("typeof module === 'undefined'")); \ No newline at end of file diff --git a/test/cli/run/module-type-fixture/cjs/hello.mjs b/test/cli/run/module-type-fixture/cjs/hello.mjs deleted file mode 100644 index 248453e484..0000000000 --- a/test/cli/run/module-type-fixture/cjs/hello.mjs +++ /dev/null @@ -1 +0,0 @@ -console.log(eval("typeof module === 'undefined'")); diff --git a/test/cli/run/module-type-fixture/cjs/hello.mts b/test/cli/run/module-type-fixture/cjs/hello.mts deleted file mode 100644 index 248453e484..0000000000 --- a/test/cli/run/module-type-fixture/cjs/hello.mts +++ /dev/null @@ -1 +0,0 @@ -console.log(eval("typeof module === 'undefined'")); diff --git a/test/cli/run/module-type-fixture/cjs/hello.ts b/test/cli/run/module-type-fixture/cjs/hello.ts deleted file mode 100644 index 72c037e9a6..0000000000 --- a/test/cli/run/module-type-fixture/cjs/hello.ts +++ /dev/null @@ -1 +0,0 @@ -console.log(eval("typeof module === 'undefined'")); \ No newline at end of file diff --git a/test/cli/run/module-type-fixture/cjs/hello.tsx b/test/cli/run/module-type-fixture/cjs/hello.tsx deleted file mode 100644 index 72c037e9a6..0000000000 --- a/test/cli/run/module-type-fixture/cjs/hello.tsx +++ /dev/null @@ -1 +0,0 @@ -console.log(eval("typeof module === 'undefined'")); \ No newline at end of file diff --git a/test/cli/run/module-type-fixture/cjs/import.cjs b/test/cli/run/module-type-fixture/cjs/import.cjs deleted file mode 100644 index 08c3035d60..0000000000 --- a/test/cli/run/module-type-fixture/cjs/import.cjs +++ /dev/null @@ -1,3 +0,0 @@ -import * as fs from "node:fs"; -console.log(eval("typeof module === 'undefined'")); -+fs; diff --git a/test/cli/run/module-type-fixture/cjs/package.json b/test/cli/run/module-type-fixture/cjs/package.json deleted file mode 100644 index 5bbefffbab..0000000000 --- a/test/cli/run/module-type-fixture/cjs/package.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "type": "commonjs" -} diff --git a/test/cli/run/module-type-fixture/esm/hello.cjs b/test/cli/run/module-type-fixture/esm/hello.cjs deleted file mode 100644 index 248453e484..0000000000 --- a/test/cli/run/module-type-fixture/esm/hello.cjs +++ /dev/null @@ -1 +0,0 @@ -console.log(eval("typeof module === 'undefined'")); diff --git a/test/cli/run/module-type-fixture/esm/hello.cts b/test/cli/run/module-type-fixture/esm/hello.cts deleted file mode 100644 index 248453e484..0000000000 --- a/test/cli/run/module-type-fixture/esm/hello.cts +++ /dev/null @@ -1 +0,0 @@ -console.log(eval("typeof module === 'undefined'")); diff --git a/test/cli/run/module-type-fixture/esm/hello.js b/test/cli/run/module-type-fixture/esm/hello.js deleted file mode 100644 index 72c037e9a6..0000000000 --- a/test/cli/run/module-type-fixture/esm/hello.js +++ /dev/null @@ -1 +0,0 @@ -console.log(eval("typeof module === 'undefined'")); \ No newline at end of file diff --git a/test/cli/run/module-type-fixture/esm/hello.jsx b/test/cli/run/module-type-fixture/esm/hello.jsx deleted file mode 100644 index 72c037e9a6..0000000000 --- a/test/cli/run/module-type-fixture/esm/hello.jsx +++ /dev/null @@ -1 +0,0 @@ -console.log(eval("typeof module === 'undefined'")); \ No newline at end of file diff --git a/test/cli/run/module-type-fixture/esm/hello.mjs b/test/cli/run/module-type-fixture/esm/hello.mjs deleted file mode 100644 index 248453e484..0000000000 --- a/test/cli/run/module-type-fixture/esm/hello.mjs +++ /dev/null @@ -1 +0,0 @@ -console.log(eval("typeof module === 'undefined'")); diff --git a/test/cli/run/module-type-fixture/esm/hello.mts b/test/cli/run/module-type-fixture/esm/hello.mts deleted file mode 100644 index 248453e484..0000000000 --- a/test/cli/run/module-type-fixture/esm/hello.mts +++ /dev/null @@ -1 +0,0 @@ -console.log(eval("typeof module === 'undefined'")); diff --git a/test/cli/run/module-type-fixture/esm/hello.ts b/test/cli/run/module-type-fixture/esm/hello.ts deleted file mode 100644 index 72c037e9a6..0000000000 --- a/test/cli/run/module-type-fixture/esm/hello.ts +++ /dev/null @@ -1 +0,0 @@ -console.log(eval("typeof module === 'undefined'")); \ No newline at end of file diff --git a/test/cli/run/module-type-fixture/esm/hello.tsx b/test/cli/run/module-type-fixture/esm/hello.tsx deleted file mode 100644 index 72c037e9a6..0000000000 --- a/test/cli/run/module-type-fixture/esm/hello.tsx +++ /dev/null @@ -1 +0,0 @@ -console.log(eval("typeof module === 'undefined'")); \ No newline at end of file diff --git a/test/cli/run/module-type-fixture/esm/import.cjs b/test/cli/run/module-type-fixture/esm/import.cjs deleted file mode 100644 index 08c3035d60..0000000000 --- a/test/cli/run/module-type-fixture/esm/import.cjs +++ /dev/null @@ -1,3 +0,0 @@ -import * as fs from "node:fs"; -console.log(eval("typeof module === 'undefined'")); -+fs; diff --git a/test/cli/run/module-type-fixture/esm/package.json b/test/cli/run/module-type-fixture/esm/package.json deleted file mode 100644 index 3dbc1ca591..0000000000 --- a/test/cli/run/module-type-fixture/esm/package.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "type": "module" -} diff --git a/test/cli/run/run-detect-module-type.ts b/test/cli/run/run-detect-module-type.ts deleted file mode 100644 index e9b447a198..0000000000 --- a/test/cli/run/run-detect-module-type.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { bunEnv, bunExe } from "harness"; -import { join } from "path"; -import { expect, test } from "bun:test"; - -// module type -> file extensions -> expected module type -const table = { - cjs: { - 'hello.cjs': 'commonjs', - 'hello.js': 'commonjs', - 'hello.mjs': 'module', - 'hello.ts': 'commonjs', - 'hello.tsx': 'module', - 'hello.cts': 'commonjs', - 'hello.jsx': 'module', - 'hello.mts': 'module', - // files using ES import and no exports will be detected as module - "import.cjs": "module", - }, - esm: { - 'hello.cjs': 'commonjs', - 'hello.js': 'module', - 'hello.mjs': 'module', - 'hello.ts': 'module', - 'hello.tsx': 'module', - 'hello.cts': 'commonjs', - 'hello.jsx': 'module', - 'hello.mts': 'module', - // files using ES import and no exports will be detected as module - "import.cjs": "module", - }, -}; - -test("detect module type", () => { - const expected = Object.entries(table).map(([moduleType, extensions]) => { - return Object.entries(extensions).map(([extension, expected]) => { - return `${moduleType} ${extension} -> ${expected}`; - }); - }).flat(); - - const actual = Object.entries(table).map(([moduleType, extensions]) => { - return Object.entries(extensions).map(([extension, expected]) => { - const proc = Bun.spawnSync({ - cmd: [bunExe(), "run", join(import.meta.dir, 'module-type-fixture', moduleType, extension)], - env: bunEnv, - }); - if (proc.exitCode !== 0) { - throw new Error(`Failed to run ${moduleType} ${extension}: ${proc.stderr.toString('utf8').trim()}`); - } - return `${moduleType} ${extension} -> ${proc.stdout.toString('utf8').trim() === "false" ? "commonjs" : "module"}`; - }); - }).flat(); - - expect(actual).toEqual(expected); -}); diff --git a/test/internal/ban-words.test.ts b/test/internal/ban-words.test.ts index 229bdae02c..5d84fc16fb 100644 --- a/test/internal/ban-words.test.ts +++ b/test/internal/ban-words.test.ts @@ -27,7 +27,7 @@ const words: Record "alloc.ptr !=": { reason: "The std.mem.Allocator context pointer can be undefined, which makes this comparison undefined behavior" }, "== alloc.ptr": { reason: "The std.mem.Allocator context pointer can be undefined, which makes this comparison undefined behavior" }, "!= alloc.ptr": { reason: "The std.mem.Allocator context pointer can be undefined, which makes this comparison undefined behavior" }, - [String.raw`: [a-zA-Z0-9_\.\*\?\[\]\(\)]+ = undefined,`]: { reason: "Do not default a struct field to undefined", limit: 244, regex: true }, + [String.raw`: [a-zA-Z0-9_\.\*\?\[\]\(\)]+ = undefined,`]: { reason: "Do not default a struct field to undefined", limit: 246, regex: true }, "usingnamespace": { reason: "This brings Bun away from incremental / faster compile times.", limit: 494 }, }; const words_keys = [...Object.keys(words)]; diff --git a/test/js/node/module/extensions-fixture/a.custom b/test/js/node/module/extensions-fixture/a.custom deleted file mode 100644 index e5d94c4c86..0000000000 --- a/test/js/node/module/extensions-fixture/a.custom +++ /dev/null @@ -1 +0,0 @@ -module.exports = 'fail' \ No newline at end of file diff --git a/test/js/node/module/extensions-fixture/a.js b/test/js/node/module/extensions-fixture/a.js deleted file mode 100644 index b4c5011785..0000000000 --- a/test/js/node/module/extensions-fixture/a.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = 'a unmodified'; diff --git a/test/js/node/module/extensions-fixture/a.json b/test/js/node/module/extensions-fixture/a.json deleted file mode 100644 index 6314134f33..0000000000 --- a/test/js/node/module/extensions-fixture/a.json +++ /dev/null @@ -1 +0,0 @@ -{ "hello": "world" } \ No newline at end of file diff --git a/test/js/node/module/extensions-fixture/a.ts b/test/js/node/module/extensions-fixture/a.ts deleted file mode 100644 index ae8b40fb8e..0000000000 --- a/test/js/node/module/extensions-fixture/a.ts +++ /dev/null @@ -1,4 +0,0 @@ -declare const y: string; -enum J { x = "hello " } -const hello: string = "world"; -module.exports = J.x + hello!; diff --git a/test/js/node/module/extensions-fixture/b.json b/test/js/node/module/extensions-fixture/b.json deleted file mode 100644 index 7b37d4c855..0000000000 --- a/test/js/node/module/extensions-fixture/b.json +++ /dev/null @@ -1 +0,0 @@ -{ "hello \ No newline at end of file diff --git a/test/js/node/module/extensions-fixture/c.custom b/test/js/node/module/extensions-fixture/c.custom deleted file mode 100644 index fabebadd37..0000000000 --- a/test/js/node/module/extensions-fixture/c.custom +++ /dev/null @@ -1 +0,0 @@ -module.exports = 'c dot custom' \ No newline at end of file diff --git a/test/js/node/module/extensions-fixture/d.js b/test/js/node/module/extensions-fixture/d.js deleted file mode 100644 index 608be5dd43..0000000000 --- a/test/js/node/module/extensions-fixture/d.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = 'd.js' \ No newline at end of file diff --git a/test/js/node/module/extensions-fixture/e.js b/test/js/node/module/extensions-fixture/e.js deleted file mode 100644 index 95c587acc9..0000000000 --- a/test/js/node/module/extensions-fixture/e.js +++ /dev/null @@ -1,4 +0,0 @@ -declare const y: string; -enum J { x = "hello" } -const hello: string = " world"; -module.exports = J.x + hello!; diff --git a/test/js/node/module/require-extensions.test.ts b/test/js/node/module/require-extensions.test.ts deleted file mode 100644 index 8cd5988ca9..0000000000 --- a/test/js/node/module/require-extensions.test.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { test, mock, expect } from "bun:test"; -import path from "path"; - -test("require.extensions shape makes sense", () => { - const extensions = require.extensions; - expect(extensions).toBeDefined(); - expect(typeof extensions).toBe("object"); - expect(extensions[".js"]).toBeFunction(); - expect(extensions[".json"]).toBeFunction(); - expect(extensions[".node"]).toBeFunction(); - // When --experimental-strip-types is passed, TypeScript files can be loaded. - expect(extensions[".cts"]).toBeFunction(); - expect(extensions[".ts"]).toBeFunction(); - expect(extensions[".mjs"]).toBeFunction(); - expect(extensions[".mts"]).toBeFunction(); -}); -test("custom require extension 1", () => { - const custom = require.extensions['.custom'] = mock(function (module, filename) { - expect(filename).toBe(path.join(import.meta.dir, 'extensions-fixture', 'c.custom')); - (module as any)._compile(`module.exports = 'custom';`, filename); - }); - const mod = require('./extensions-fixture/c'); - expect(mod).toBe('custom'); - expect(custom.mock.calls.length).toBe(1); - delete require.extensions['.custom']; - expect(() => require('./extensions-fixture/c')).toThrow(/Cannot find module/); - expect(require('./extensions-fixture/c.custom')).toBe('custom'); // already loaded - delete require.cache[require.resolve('./extensions-fixture/c.custom')]; - expect(custom.mock.calls.length).toBe(1); - expect(require('./extensions-fixture/c.custom')).toBe('c dot custom'); // use js loader -}); -test("custom require extension overwrite default loader", () => { - const original = require.extensions['.js']; - try { - const custom = require.extensions['.js'] = mock(function (module, filename) { - expect(filename).toBe(path.join(import.meta.dir, 'extensions-fixture', 'd.js')); - (module as any)._compile(`module.exports = 'custom';`, filename); - }); - const mod = require('./extensions-fixture/d'); - expect(mod).toBe('custom'); - expect(custom.mock.calls.length).toBe(1); - require.extensions['.js'] = original; - expect(require('./extensions-fixture/d')).toBe('custom'); // already loaded - delete require.cache[require.resolve('./extensions-fixture/d')]; - expect(custom.mock.calls.length).toBe(1); - expect(require('./extensions-fixture/d')).toBe('d.js'); // use js loader - } finally { - require.extensions['.js'] = original; - } -}); -test("custom require extension overwrite default loader with other default loader", () => { - const original = require.extensions['.js']; - try { - require.extensions['.js'] = require.extensions['.ts']!; - const mod = require('./extensions-fixture/e.js'); // should not enter JS - expect(mod).toBe('hello world'); - } finally { - require.extensions['.js'] = original; - } -}); -test("test that assigning properties weirdly wont do anything bad", () => { - const original = require.extensions['.js']; - try { - function f1() {} - function f2() {} - require.extensions['.js'] = f1; - require.extensions['.abc'] = f2; - require.extensions['.js'] = f2; - require.extensions['.js'] = undefined; - require.extensions['.abc'] = undefined; - require.extensions['.abc'] = f1; - require.extensions['.js'] = f2; - } finally { - require.extensions['.js'] = original; - } -}); \ No newline at end of file diff --git a/test/js/node/test/test-module-multi-extensions.js b/test/js/node/test/test-module-multi-extensions.js deleted file mode 100644 index 205a030c57..0000000000 --- a/test/js/node/test/test-module-multi-extensions.js +++ /dev/null @@ -1,93 +0,0 @@ -'use strict'; - -// Refs: https://github.com/nodejs/node/issues/4778 - -const common = require('../common'); -const assert = require('assert'); -const fs = require('fs'); -const Module = require('module'); -const tmpdir = require('../common/tmpdir'); -const file = tmpdir.resolve('test-extensions.foo.bar'); -const dotfile = tmpdir.resolve('.bar'); -const dotfileWithExtension = tmpdir.resolve('.foo.bar'); - -tmpdir.refresh(); -fs.writeFileSync(file, 'console.log(__filename);', 'utf8'); -fs.writeFileSync(dotfile, 'console.log(__filename);', 'utf8'); -fs.writeFileSync(dotfileWithExtension, 'console.log(__filename);', 'utf8'); - -{ - require.extensions['.bar'] = common.mustNotCall(); - require.extensions['.foo.bar'] = common.mustCall(); - const modulePath = tmpdir.resolve('test-extensions'); - require(modulePath); - require(file); - delete require.cache[file]; - delete require.extensions['.bar']; - delete require.extensions['.foo.bar']; - Module._pathCache = { __proto__: null }; -} - -{ - require.extensions['.foo.bar'] = common.mustCall(); - const modulePath = tmpdir.resolve('test-extensions'); - require(modulePath); - assert.throws( - () => require(`${modulePath}.foo`), - (err) => err.message.startsWith(`Cannot find module '${modulePath}.foo'`) - ); - require(`${modulePath}.foo.bar`); - delete require.cache[file]; - delete require.extensions['.foo.bar']; - Module._pathCache = { __proto__: null }; -} - -{ - const modulePath = tmpdir.resolve('test-extensions'); - assert.throws( - () => require(modulePath), - (err) => err.message.startsWith(`Cannot find module '${modulePath}'`) - ); - delete require.cache[file]; - Module._pathCache = { __proto__: null }; -} - -{ - require.extensions['.bar'] = common.mustNotCall(); - require.extensions['.foo.bar'] = common.mustCall(); - const modulePath = tmpdir.resolve('test-extensions.foo'); - require(modulePath); - delete require.cache[file]; - delete require.extensions['.bar']; - delete require.extensions['.foo.bar']; - Module._pathCache = { __proto__: null }; -} - -{ - require.extensions['.foo.bar'] = common.mustNotCall(); - const modulePath = tmpdir.resolve('test-extensions.foo'); - assert.throws( - () => require(modulePath), - (err) => err.message.startsWith(`Cannot find module '${modulePath}'`) - ); - delete require.extensions['.foo.bar']; - Module._pathCache = { __proto__: null }; -} - -{ - require.extensions['.bar'] = common.mustNotCall(); - require(dotfile); - delete require.cache[dotfile]; - delete require.extensions['.bar']; - Module._pathCache = { __proto__: null }; -} - -{ - require.extensions['.bar'] = common.mustCall(); - require.extensions['.foo.bar'] = common.mustNotCall(); - require(dotfileWithExtension); - delete require.cache[dotfileWithExtension]; - delete require.extensions['.bar']; - delete require.extensions['.foo.bar']; - Module._pathCache = { __proto__: null }; -}