Correctly handle __esModule for loader: "object" (#16885)

Co-authored-by: Jarred-Sumner <709451+Jarred-Sumner@users.noreply.github.com>
This commit is contained in:
Jarred Sumner
2025-01-31 05:24:33 -08:00
committed by GitHub
parent 25f6cbd471
commit 9acb72d2ad
4 changed files with 82 additions and 7 deletions

View File

@@ -1,4 +1,5 @@
#include "root.h"
#include "headers-handwritten.h"
#include "JavaScriptCore/JSGlobalObject.h"
#include "ModuleLoader.h"
@@ -35,7 +36,7 @@
#include "NativeModuleImpl.h"
#include "../modules/ObjectModule.h"
#include "wtf/Assertions.h"
#include "CommonJSModuleRecord.h"
namespace Bun {
using namespace JSC;
@@ -302,7 +303,8 @@ static JSValue handleVirtualModuleResult(
ErrorableResolvedSource* res,
BunString* specifier,
BunString* referrer,
bool wasModuleMock = false)
bool wasModuleMock = false,
JSCommonJSModule* commonJSModule = nullptr)
{
auto onLoadResult = handleOnLoadResult(globalObject, virtualModuleResult, specifier, wasModuleMock);
auto& vm = JSC::getVM(globalObject);
@@ -364,6 +366,21 @@ static JSValue handleVirtualModuleResult(
case OnLoadResultTypeObject: {
JSC::JSObject* object = onLoadResult.value.object.getObject();
if (commonJSModule) {
const auto& __esModuleIdentifier = vm.propertyNames->__esModule;
JSValue esModuleValue = object->getIfPropertyExists(globalObject, __esModuleIdentifier);
RETURN_IF_EXCEPTION(scope, {});
if (esModuleValue && esModuleValue.toBoolean(globalObject)) {
JSValue defaultValue = object->getIfPropertyExists(globalObject, vm.propertyNames->defaultKeyword);
RETURN_IF_EXCEPTION(scope, {});
if (defaultValue && !defaultValue.isUndefined()) {
commonJSModule->setExportsObject(defaultValue);
commonJSModule->hasEvaluated = true;
return commonJSModule;
}
}
}
JSC::ensureStillAliveHere(object);
auto function = generateObjectModuleSourceCode(
globalObject,
@@ -479,7 +496,14 @@ JSValue fetchCommonJSModule(
// This is important for being able to trivially mock things like the filesystem.
if (isBunTest) {
if (JSC::JSValue virtualModuleResult = Bun::runVirtualModule(globalObject, specifier, wasModuleMock)) {
JSPromise* promise = jsCast<JSPromise*>(handleVirtualModuleResult<true>(globalObject, virtualModuleResult, res, specifier, referrer, wasModuleMock));
JSValue promiseOrCommonJSModule = handleVirtualModuleResult<true>(globalObject, virtualModuleResult, res, specifier, referrer, wasModuleMock, target);
RETURN_IF_EXCEPTION(scope, {});
// If we assigned module.exports to the virtual module, we're done here.
if (promiseOrCommonJSModule == target) {
RELEASE_AND_RETURN(scope, target);
}
JSPromise* promise = jsCast<JSPromise*>(promiseOrCommonJSModule);
switch (promise->status(vm)) {
case JSPromise::Status::Rejected: {
uint32_t promiseFlags = promise->internalField(JSPromise::Field::Flags).get().asUInt32AsAnyInt();
@@ -561,7 +585,14 @@ 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)) {
JSPromise* promise = jsCast<JSPromise*>(handleVirtualModuleResult<true>(globalObject, virtualModuleResult, res, specifier, referrer, wasModuleMock));
JSValue promiseOrCommonJSModule = handleVirtualModuleResult<true>(globalObject, virtualModuleResult, res, specifier, referrer, wasModuleMock, target);
RETURN_IF_EXCEPTION(scope, {});
// If we assigned module.exports to the virtual module, we're done here.
if (promiseOrCommonJSModule == target) {
RELEASE_AND_RETURN(scope, target);
}
JSPromise* promise = jsCast<JSPromise*>(promiseOrCommonJSModule);
switch (promise->status(vm)) {
case JSPromise::Status::Rejected: {
uint32_t promiseFlags = promise->internalField(JSPromise::Field::Flags).get().asUInt32AsAnyInt();