in src/bun.js/bindings/ModuleLoader.cpp [658:835]
static JSValue fetchESMSourceCode(
Zig::GlobalObject* globalObject,
JSC::JSValue specifierJS,
ErrorableResolvedSource* res,
BunString* specifier,
BunString* referrer,
BunString* typeAttribute)
{
void* bunVM = globalObject->bunVM();
auto& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
ResolvedSourceCodeHolder sourceCodeHolder(res);
const auto reject = [&](JSC::JSValue exception) -> JSValue {
if constexpr (allowPromise) {
return rejectedInternalPromise(globalObject, exception);
} else {
throwException(globalObject, scope, exception);
return {};
}
};
const auto rejectOrResolve = [&](JSValue code) -> JSValue {
if (auto* exception = scope.exception()) {
if constexpr (!allowPromise) {
scope.release();
return {};
}
scope.clearException();
return rejectedInternalPromise(globalObject, exception);
}
if constexpr (allowPromise) {
auto* ret = resolvedInternalPromise(globalObject, code);
scope.release();
return ret;
} else {
return code;
}
};
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)) {
return handleVirtualModuleResult<allowPromise>(globalObject, virtualModuleResult, res, specifier, referrer, wasModuleMock);
}
}
if (Bun__fetchBuiltinModule(bunVM, globalObject, specifier, referrer, res)) {
if (!res->success) {
throwException(scope, res->result.err, globalObject);
auto* exception = scope.exception();
scope.clearException();
return reject(exception);
}
auto moduleKey = specifier->toWTFString(BunString::ZeroCopy);
auto tag = res->result.value.tag;
switch (tag) {
case SyntheticModuleType::ESM: {
auto&& provider = Zig::SourceProvider::create(globalObject, res->result.value, JSC::SourceProviderSourceType::Module, true);
return rejectOrResolve(JSSourceCode::create(vm, JSC::SourceCode(provider)));
}
#define CASE(str, name) \
case (SyntheticModuleType::name): { \
auto source = JSC::SourceCode(JSC::SyntheticSourceProvider::create(generateNativeModule_##name, JSC::SourceOrigin(), WTFMove(moduleKey))); \
return rejectOrResolve(JSSourceCode::create(vm, WTFMove(source))); \
}
BUN_FOREACH_NATIVE_MODULE(CASE)
#undef CASE
// CommonJS modules from src/js/*
default: {
if (tag & SyntheticModuleType::InternalModuleRegistryFlag) {
constexpr auto mask = (SyntheticModuleType::InternalModuleRegistryFlag - 1);
auto source = JSC::SourceCode(JSC::SyntheticSourceProvider::create(generateInternalModuleSourceCode(globalObject, static_cast<InternalModuleRegistry::Field>(tag & mask)), JSC::SourceOrigin(URL(makeString("builtins://"_s, moduleKey))), moduleKey));
return rejectOrResolve(JSSourceCode::create(vm, WTFMove(source)));
} else {
auto&& provider = Zig::SourceProvider::create(globalObject, res->result.value, JSC::SourceProviderSourceType::Module, true);
return rejectOrResolve(JSC::JSSourceCode::create(vm, JSC::SourceCode(provider)));
}
}
}
}
// When "bun test" is NOT enabled, disable users from overriding builtin modules
if (!isBunTest) {
if (JSC::JSValue virtualModuleResult = Bun::runVirtualModule(globalObject, specifier, wasModuleMock)) {
return handleVirtualModuleResult<allowPromise>(globalObject, virtualModuleResult, res, specifier, referrer, wasModuleMock);
}
}
if constexpr (allowPromise) {
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);
}
if (res->success && res->result.value.isCommonJSModule) {
auto created = Bun::createCommonJSModule(globalObject, specifierJS, res->result.value);
if (created.has_value()) {
return rejectOrResolve(JSSourceCode::create(vm, WTFMove(created.value())));
}
if constexpr (allowPromise) {
auto* exception = scope.exception();
scope.clearException();
return rejectedInternalPromise(globalObject, exception);
} else {
return {};
}
}
if (!res->success) {
throwException(scope, res->result.err, globalObject);
auto* exception = scope.exception();
scope.clearException();
return reject(exception);
}
// The JSONForObjectLoader tag is source code returned from Bun that needs
// to go through the JSON parser in JSC.
//
// We don't use JSON.parse directly in JS because we want the top-level keys of the JSON
// object to be accessible as named imports.
//
// We don't use Bun's JSON parser because JSON.parse is faster and
// handles stack overflow better.
//
// When parsing tsconfig.*.json or jsconfig.*.json, we go through Bun's JSON
// parser instead to support comments and trailing commas.
if (res->result.value.tag == SyntheticModuleType::JSONForObjectLoader) {
JSC::JSValue value = JSC::JSONParse(globalObject, res->result.value.source_code.toWTFString(BunString::ZeroCopy));
if (!value) {
return reject(JSC::JSValue(JSC::createSyntaxError(globalObject, "Failed to parse JSON"_s)));
}
// JSON can become strings, null, numbers, booleans so we must handle "export default 123"
auto function = generateJSValueModuleSourceCode(
globalObject,
value);
auto source = JSC::SourceCode(
JSC::SyntheticSourceProvider::create(WTFMove(function),
JSC::SourceOrigin(), specifier->toWTFString(BunString::ZeroCopy)));
JSC::ensureStillAliveHere(value);
return rejectOrResolve(JSSourceCode::create(globalObject->vm(), WTFMove(source)));
}
// TOML and JSONC may go through here
else if (res->result.value.tag == SyntheticModuleType::ExportsObject) {
JSC::JSValue value = JSC::JSValue::decode(res->result.value.jsvalue_for_export);
if (!value) {
return reject(JSC::JSValue(JSC::createSyntaxError(globalObject, "Failed to parse Object"_s)));
}
// JSON can become strings, null, numbers, booleans so we must handle "export default 123"
auto function = generateJSValueModuleSourceCode(
globalObject,
value);
auto source = JSC::SourceCode(
JSC::SyntheticSourceProvider::create(WTFMove(function),
JSC::SourceOrigin(), specifier->toWTFString(BunString::ZeroCopy)));
JSC::ensureStillAliveHere(value);
return rejectOrResolve(JSSourceCode::create(globalObject->vm(), WTFMove(source)));
}
return rejectOrResolve(JSC::JSSourceCode::create(vm,
JSC::SourceCode(Zig::SourceProvider::create(globalObject, res->result.value))));
}