aboutsummaryrefslogtreecommitdiff
path: root/src/bun.js/bindings/ModuleLoader.cpp
diff options
context:
space:
mode:
authorGravatar Jarred Sumner <jarred@jarredsumner.com> 2023-09-10 22:15:35 -0800
committerGravatar GitHub <noreply@github.com> 2023-09-10 23:15:35 -0700
commit51d3d4382281f789f8175079ed426a63529eb3e7 (patch)
tree14f6fe77a1e3b300488e9343d8e9d54f64bde376 /src/bun.js/bindings/ModuleLoader.cpp
parentedea4f095a3bebf54f986c0fa038482316f4cde8 (diff)
downloadbun-51d3d4382281f789f8175079ed426a63529eb3e7.tar.gz
bun-51d3d4382281f789f8175079ed426a63529eb3e7.tar.zst
bun-51d3d4382281f789f8175079ed426a63529eb3e7.zip
Support named imports for json & toml files at runtime (#4783)
* Support named exports in json imports * Support named imports for `*.json` files * Remove stale comments * Don't export arrays as non-default * Add test for default exports * Don't break webpack --------- Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
Diffstat (limited to 'src/bun.js/bindings/ModuleLoader.cpp')
-rw-r--r--src/bun.js/bindings/ModuleLoader.cpp51
1 files changed, 51 insertions, 0 deletions
diff --git a/src/bun.js/bindings/ModuleLoader.cpp b/src/bun.js/bindings/ModuleLoader.cpp
index 4e2de9294..252c446b1 100644
--- a/src/bun.js/bindings/ModuleLoader.cpp
+++ b/src/bun.js/bindings/ModuleLoader.cpp
@@ -516,6 +516,29 @@ JSValue fetchCommonJSModule(
RELEASE_AND_RETURN(scope, {});
}
+ // 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, Bun::toWTFString(res->result.value.source_code));
+ if (!value) {
+ JSC::throwException(globalObject, scope, JSC::createSyntaxError(globalObject, "Failed to parse JSON"_s));
+ RELEASE_AND_RETURN(scope, {});
+ }
+
+ target->putDirect(vm, WebCore::clientData(vm)->builtinNames().exportsPublicName(), value, value.isCell() && value.isCallable() ? JSC::PropertyAttribute::Function | 0 : 0);
+ target->hasEvaluated = true;
+ RELEASE_AND_RETURN(scope, target);
+ }
+
auto&& provider = Zig::SourceProvider::create(globalObject, res->result.value);
globalObject->moduleLoader()->provideFetch(globalObject, specifierValue, JSC::SourceCode(provider));
RETURN_IF_EXCEPTION(scope, {});
@@ -647,6 +670,34 @@ static JSValue fetchESMSourceCode(
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, Bun::toWTFString(res->result.value.source_code));
+ 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(), Bun::toWTFString(*specifier)));
+ JSC::ensureStillAliveHere(value);
+ return rejectOrResolve(JSSourceCode::create(globalObject->vm(), WTFMove(source)));
+ }
+
auto&& provider = Zig::SourceProvider::create(globalObject, res->result.value);
return rejectOrResolve(JSC::JSSourceCode::create(vm, JSC::SourceCode(provider)));
}