mirror of
https://github.com/oven-sh/bun
synced 2026-02-16 22:01:47 +00:00
Compare commits
1 Commits
claude/fix
...
claude/sou
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
503a9280ed |
@@ -817,7 +817,110 @@ pub export fn Bun__getDefaultLoader(global: *JSGlobalObject, str: *const bun.Str
|
||||
return loader;
|
||||
}
|
||||
|
||||
pub fn transpileSourceCode(
|
||||
/// Helper: Convert ResolvedSource to ModuleResult
|
||||
fn resolvedSourceToModuleResult(resolved: ResolvedSource, input_specifier: bun.String, source_url: []const u8) ModuleResult {
|
||||
// Handle special module types (JSON/TOML/YAML that export JSValue)
|
||||
if (resolved.tag == .exports_object or resolved.tag == .export_default_object) {
|
||||
return .{
|
||||
.tag = .special,
|
||||
.value = .{
|
||||
.special = .{
|
||||
.tag = if (resolved.tag == .exports_object) .exports_object else .export_default_object,
|
||||
.jsvalue = resolved.jsvalue_for_export,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
// Handle custom extensions
|
||||
if (resolved.tag == .common_js_custom_extension) {
|
||||
return .{
|
||||
.tag = .special,
|
||||
.value = .{
|
||||
.special = .{
|
||||
.tag = .custom_extension,
|
||||
.jsvalue = resolved.cjs_custom_extension_index,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
// Handle builtin modules (ResolvedSourceTag values >= 512 are builtin IDs)
|
||||
if (@intFromEnum(resolved.tag) >= 512) {
|
||||
return .{
|
||||
.tag = .builtin,
|
||||
.value = .{ .builtin_id = @intFromEnum(resolved.tag) },
|
||||
};
|
||||
}
|
||||
|
||||
// Handle transpiled source (normal case)
|
||||
return .{
|
||||
.tag = .transpiled,
|
||||
.value = .{
|
||||
.transpiled = .{
|
||||
.source_code = resolved.source_code,
|
||||
.source_url = input_specifier.createIfDifferent(source_url),
|
||||
.bytecode_cache = resolved.bytecode_cache,
|
||||
.bytecode_cache_len = resolved.bytecode_cache_size,
|
||||
.flags = .{
|
||||
.is_commonjs = resolved.is_commonjs_module,
|
||||
.is_already_bundled = resolved.already_bundled,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/// Helper: Convert ModuleResult to ResolvedSource for backward compatibility
|
||||
pub fn moduleResultToResolvedSource(result: ModuleResult, specifier: bun.String) ResolvedSource {
|
||||
switch (result.tag) {
|
||||
.transpiled => {
|
||||
const trans = result.value.transpiled;
|
||||
return .{
|
||||
.allocator = null,
|
||||
.source_code = trans.source_code,
|
||||
.specifier = specifier,
|
||||
.source_url = trans.source_url,
|
||||
.is_commonjs_module = trans.flags.is_commonjs,
|
||||
.already_bundled = trans.flags.is_already_bundled,
|
||||
.bytecode_cache = trans.bytecode_cache,
|
||||
.bytecode_cache_size = trans.bytecode_cache_len,
|
||||
.source_code_needs_deref = true,
|
||||
};
|
||||
},
|
||||
.special => {
|
||||
const spec = result.value.special;
|
||||
return .{
|
||||
.allocator = null,
|
||||
.source_code = bun.String.empty,
|
||||
.specifier = specifier,
|
||||
.source_url = specifier,
|
||||
.jsvalue_for_export = spec.jsvalue,
|
||||
.tag = switch (spec.tag) {
|
||||
.exports_object => .exports_object,
|
||||
.export_default_object => .export_default_object,
|
||||
.custom_extension => .common_js_custom_extension,
|
||||
},
|
||||
.source_code_needs_deref = false,
|
||||
};
|
||||
},
|
||||
.builtin => {
|
||||
// Builtin modules use the ID as the tag (values >= 512)
|
||||
const tag: ResolvedSource.Tag = @enumFromInt(result.value.builtin_id);
|
||||
return .{
|
||||
.allocator = null,
|
||||
.source_code = bun.String.empty,
|
||||
.specifier = specifier,
|
||||
.source_url = bun.String.static(@tagName(tag)),
|
||||
.tag = tag,
|
||||
.source_code_needs_deref = false,
|
||||
};
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Internal implementation that still returns ResolvedSource for backward compat
|
||||
fn transpileSourceCodeInternal(
|
||||
jsc_vm: *VirtualMachine,
|
||||
specifier: string,
|
||||
referrer: string,
|
||||
@@ -1032,7 +1135,7 @@ pub fn transpileSourceCode(
|
||||
const source = &parse_result.source;
|
||||
|
||||
if (parse_result.loader == .wasm) {
|
||||
return transpileSourceCode(
|
||||
return transpileSourceCodeInternal(
|
||||
jsc_vm,
|
||||
specifier,
|
||||
referrer,
|
||||
@@ -1370,7 +1473,7 @@ pub fn transpileSourceCode(
|
||||
};
|
||||
}
|
||||
|
||||
return transpileSourceCode(
|
||||
return transpileSourceCodeInternal(
|
||||
jsc_vm,
|
||||
specifier,
|
||||
referrer,
|
||||
@@ -1581,8 +1684,9 @@ pub export fn Bun__fetchBuiltinModule(
|
||||
|
||||
VirtualMachine.processFetchLog(globalObject, specifier.*, referrer.*, &log, ret, err);
|
||||
return true;
|
||||
}) |builtin| {
|
||||
ret.* = jsc.ErrorableResolvedSource.ok(builtin);
|
||||
}) |module_result| {
|
||||
// Convert ModuleResult to ResolvedSource for C++ compatibility
|
||||
ret.* = jsc.ErrorableResolvedSource.ok(moduleResultToResolvedSource(module_result, specifier.*));
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
@@ -1796,39 +1900,40 @@ pub export fn Bun__transpileFile(
|
||||
defer jsc_vm.module_loader.resetArena(jsc_vm);
|
||||
|
||||
var promise: ?*jsc.JSInternalPromise = null;
|
||||
ret.* = jsc.ErrorableResolvedSource.ok(
|
||||
ModuleLoader.transpileSourceCode(
|
||||
jsc_vm,
|
||||
lr.specifier,
|
||||
referrer_slice.slice(),
|
||||
specifier_ptr.*,
|
||||
lr.path,
|
||||
synchronous_loader,
|
||||
module_type,
|
||||
&log,
|
||||
lr.virtual_source,
|
||||
if (allow_promise) &promise else null,
|
||||
VirtualMachine.source_code_printer.?,
|
||||
globalObject,
|
||||
FetchFlags.transpile,
|
||||
) catch |err| {
|
||||
switch (err) {
|
||||
error.AsyncModule => {
|
||||
bun.assert(promise != null);
|
||||
return promise;
|
||||
},
|
||||
error.PluginError => return null,
|
||||
error.JSError => {
|
||||
ret.* = jsc.ErrorableResolvedSource.err(error.JSError, globalObject.takeError(error.JSError));
|
||||
return null;
|
||||
},
|
||||
else => {
|
||||
VirtualMachine.processFetchLog(globalObject, specifier_ptr.*, referrer.*, &log, ret, err);
|
||||
return null;
|
||||
},
|
||||
}
|
||||
},
|
||||
);
|
||||
const module_result = ModuleLoader.transpileSourceCode(
|
||||
jsc_vm,
|
||||
lr.specifier,
|
||||
referrer_slice.slice(),
|
||||
specifier_ptr.*,
|
||||
lr.path,
|
||||
synchronous_loader,
|
||||
module_type,
|
||||
&log,
|
||||
lr.virtual_source,
|
||||
if (allow_promise) &promise else null,
|
||||
VirtualMachine.source_code_printer.?,
|
||||
globalObject,
|
||||
FetchFlags.transpile,
|
||||
) catch |err| {
|
||||
switch (err) {
|
||||
error.AsyncModule => {
|
||||
bun.assert(promise != null);
|
||||
return promise;
|
||||
},
|
||||
error.PluginError => return null,
|
||||
error.JSError => {
|
||||
ret.* = jsc.ErrorableResolvedSource.err(error.JSError, globalObject.takeError(error.JSError));
|
||||
return null;
|
||||
},
|
||||
else => {
|
||||
VirtualMachine.processFetchLog(globalObject, specifier_ptr.*, referrer.*, &log, ret, err);
|
||||
return null;
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
// Convert ModuleResult to ResolvedSource for C++ compatibility
|
||||
ret.* = jsc.ErrorableResolvedSource.ok(moduleResultToResolvedSource(module_result, specifier_ptr.*));
|
||||
return promise;
|
||||
}
|
||||
|
||||
@@ -1883,7 +1988,43 @@ fn getHardcodedModule(jsc_vm: *VirtualMachine, specifier: bun.String, hardcoded:
|
||||
};
|
||||
}
|
||||
|
||||
pub fn fetchBuiltinModule(jsc_vm: *VirtualMachine, specifier: bun.String) !?ResolvedSource {
|
||||
/// New public API that returns ModuleResult
|
||||
pub fn transpileSourceCode(
|
||||
jsc_vm: *VirtualMachine,
|
||||
specifier: string,
|
||||
referrer: string,
|
||||
input_specifier: String,
|
||||
path: Fs.Path,
|
||||
loader: options.Loader,
|
||||
module_type: options.ModuleType,
|
||||
log: *logger.Log,
|
||||
virtual_source: ?*const logger.Source,
|
||||
promise_ptr: ?*?*jsc.JSInternalPromise,
|
||||
source_code_printer: *js_printer.BufferPrinter,
|
||||
globalObject: ?*JSGlobalObject,
|
||||
comptime flags: FetchFlags,
|
||||
) !ModuleResult {
|
||||
const resolved = try transpileSourceCodeInternal(
|
||||
jsc_vm,
|
||||
specifier,
|
||||
referrer,
|
||||
input_specifier,
|
||||
path,
|
||||
loader,
|
||||
module_type,
|
||||
log,
|
||||
virtual_source,
|
||||
promise_ptr,
|
||||
source_code_printer,
|
||||
globalObject,
|
||||
flags,
|
||||
);
|
||||
|
||||
return resolvedSourceToModuleResult(resolved, input_specifier, path.text);
|
||||
}
|
||||
|
||||
/// Internal implementation that returns ResolvedSource for backward compat
|
||||
fn fetchBuiltinModuleInternal(jsc_vm: *VirtualMachine, specifier: bun.String) !?ResolvedSource {
|
||||
if (HardcodedModule.map.getWithEql(specifier, bun.String.eqlComptime)) |hardcoded| {
|
||||
return getHardcodedModule(jsc_vm, specifier, hardcoded);
|
||||
}
|
||||
@@ -1938,6 +2079,14 @@ pub fn fetchBuiltinModule(jsc_vm: *VirtualMachine, specifier: bun.String) !?Reso
|
||||
return null;
|
||||
}
|
||||
|
||||
/// New public API that returns ModuleResult for builtin modules
|
||||
pub fn fetchBuiltinModule(jsc_vm: *VirtualMachine, specifier: bun.String) !?ModuleResult {
|
||||
const resolved = try fetchBuiltinModuleInternal(jsc_vm, specifier) orelse return null;
|
||||
// Builtin modules might be special imports (macros, standalone) or actual builtins
|
||||
// For now, convert using the same logic as transpileSourceCode
|
||||
return resolvedSourceToModuleResult(resolved, specifier, specifier.byteSlice());
|
||||
}
|
||||
|
||||
export fn Bun__transpileVirtualModule(
|
||||
globalObject: *JSGlobalObject,
|
||||
specifier_ptr: *const bun.String,
|
||||
@@ -1977,35 +2126,36 @@ export fn Bun__transpileVirtualModule(
|
||||
defer log.deinit();
|
||||
defer jsc_vm.module_loader.resetArena(jsc_vm);
|
||||
|
||||
ret.* = jsc.ErrorableResolvedSource.ok(
|
||||
ModuleLoader.transpileSourceCode(
|
||||
jsc_vm,
|
||||
specifier_slice.slice(),
|
||||
referrer_slice.slice(),
|
||||
specifier_ptr.*,
|
||||
path,
|
||||
loader,
|
||||
.unknown,
|
||||
&log,
|
||||
&virtual_source,
|
||||
null,
|
||||
VirtualMachine.source_code_printer.?,
|
||||
globalObject,
|
||||
FetchFlags.transpile,
|
||||
) catch |err| {
|
||||
switch (err) {
|
||||
error.PluginError => return true,
|
||||
error.JSError => {
|
||||
ret.* = jsc.ErrorableResolvedSource.err(error.JSError, globalObject.takeError(error.JSError));
|
||||
return true;
|
||||
},
|
||||
else => {
|
||||
VirtualMachine.processFetchLog(globalObject, specifier_ptr.*, referrer_ptr.*, &log, ret, err);
|
||||
return true;
|
||||
},
|
||||
}
|
||||
},
|
||||
);
|
||||
const module_result = ModuleLoader.transpileSourceCode(
|
||||
jsc_vm,
|
||||
specifier_slice.slice(),
|
||||
referrer_slice.slice(),
|
||||
specifier_ptr.*,
|
||||
path,
|
||||
loader,
|
||||
.unknown,
|
||||
&log,
|
||||
&virtual_source,
|
||||
null,
|
||||
VirtualMachine.source_code_printer.?,
|
||||
globalObject,
|
||||
FetchFlags.transpile,
|
||||
) catch |err| {
|
||||
switch (err) {
|
||||
error.PluginError => return true,
|
||||
error.JSError => {
|
||||
ret.* = jsc.ErrorableResolvedSource.err(error.JSError, globalObject.takeError(error.JSError));
|
||||
return true;
|
||||
},
|
||||
else => {
|
||||
VirtualMachine.processFetchLog(globalObject, specifier_ptr.*, referrer_ptr.*, &log, ret, err);
|
||||
return true;
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
// Convert ModuleResult to ResolvedSource for C++ compatibility
|
||||
ret.* = jsc.ErrorableResolvedSource.ok(moduleResultToResolvedSource(module_result, specifier_ptr.*));
|
||||
analytics.Features.virtual_modules += 1;
|
||||
return true;
|
||||
}
|
||||
@@ -3098,6 +3248,9 @@ const jsc = bun.jsc;
|
||||
const JSGlobalObject = bun.jsc.JSGlobalObject;
|
||||
const JSValue = bun.jsc.JSValue;
|
||||
const ResolvedSource = bun.jsc.ResolvedSource;
|
||||
const ModuleResult = bun.jsc.ModuleResult;
|
||||
const TranspiledSource = bun.jsc.TranspiledSource;
|
||||
const SpecialModule = bun.jsc.SpecialModule;
|
||||
const VirtualMachine = bun.jsc.VirtualMachine;
|
||||
const ZigString = bun.jsc.ZigString;
|
||||
const Bun = jsc.API.Bun;
|
||||
|
||||
@@ -1522,8 +1522,9 @@ pub fn fetchWithoutOnLoadPlugins(
|
||||
) anyerror!ResolvedSource {
|
||||
bun.assert(VirtualMachine.isLoaded());
|
||||
|
||||
if (try ModuleLoader.fetchBuiltinModule(jsc_vm, _specifier)) |builtin| {
|
||||
return builtin;
|
||||
if (try ModuleLoader.fetchBuiltinModule(jsc_vm, _specifier)) |module_result| {
|
||||
// Convert ModuleResult to ResolvedSource
|
||||
return ModuleLoader.moduleResultToResolvedSource(module_result, _specifier);
|
||||
}
|
||||
|
||||
const specifier_clone = _specifier.toUTF8(bun.default_allocator);
|
||||
@@ -1545,7 +1546,7 @@ pub fn fetchWithoutOnLoadPlugins(
|
||||
defer if (flags != .print_source) jsc_vm.module_loader.resetArena(jsc_vm);
|
||||
errdefer if (flags == .print_source) jsc_vm.module_loader.resetArena(jsc_vm);
|
||||
|
||||
return try ModuleLoader.transpileSourceCode(
|
||||
const module_result = try ModuleLoader.transpileSourceCode(
|
||||
jsc_vm,
|
||||
lr.specifier,
|
||||
referrer_clone.slice(),
|
||||
@@ -1560,6 +1561,9 @@ pub fn fetchWithoutOnLoadPlugins(
|
||||
globalObject,
|
||||
flags,
|
||||
);
|
||||
|
||||
// Convert ModuleResult to ResolvedSource
|
||||
return ModuleLoader.moduleResultToResolvedSource(module_result, _specifier);
|
||||
}
|
||||
|
||||
pub const ResolveFunctionResult = struct {
|
||||
|
||||
167
src/bun.js/bindings/BunSourceProvider.cpp
Normal file
167
src/bun.js/bindings/BunSourceProvider.cpp
Normal file
@@ -0,0 +1,167 @@
|
||||
#include "root.h"
|
||||
|
||||
#include "BunSourceProvider.h"
|
||||
#include "ZigGlobalObject.h"
|
||||
#include "helpers.h"
|
||||
#include "BunString.h"
|
||||
|
||||
#include <JavaScriptCore/BytecodeCacheError.h>
|
||||
#include <wtf/text/StringHash.h>
|
||||
#include <wtf/URL.h>
|
||||
#include <mimalloc.h>
|
||||
|
||||
// Forward declare the C structs from Zig
|
||||
extern "C" {
|
||||
// Must match TranspiledSource.zig
|
||||
struct TranspiledSource {
|
||||
BunString source_code;
|
||||
BunString source_url;
|
||||
uint8_t* bytecode_cache;
|
||||
size_t bytecode_cache_len;
|
||||
uint32_t flags; // packed struct: is_commonjs:1, is_already_bundled:1, padding:30
|
||||
};
|
||||
}
|
||||
|
||||
namespace Zig {
|
||||
|
||||
using String = WTF::String;
|
||||
|
||||
// Helper functions for source providers
|
||||
JSC::SourceOrigin toSourceOrigin(const String& sourceURL, bool isBuiltin)
|
||||
{
|
||||
ASSERT_WITH_MESSAGE(!sourceURL.startsWith("file://"_s), "specifier should not already be a file URL");
|
||||
|
||||
if (isBuiltin) {
|
||||
if (sourceURL.startsWith("node:"_s)) {
|
||||
return JSC::SourceOrigin(WTF::URL(makeString("builtin://node/"_s, sourceURL.substring(5))));
|
||||
} else if (sourceURL.startsWith("bun:"_s)) {
|
||||
return JSC::SourceOrigin(WTF::URL(makeString("builtin://bun/"_s, sourceURL.substring(4))));
|
||||
} else {
|
||||
return JSC::SourceOrigin(WTF::URL(makeString("builtin://"_s, sourceURL)));
|
||||
}
|
||||
}
|
||||
return JSC::SourceOrigin(WTF::URL::fileURLWithFileSystemPath(sourceURL));
|
||||
}
|
||||
|
||||
extern "C" int ByteRangeMapping__getSourceID(void* mappings, BunString sourceURL);
|
||||
extern "C" void* ByteRangeMapping__find(BunString sourceURL);
|
||||
|
||||
void* sourceMappingForSourceURL(const WTF::String& sourceURL)
|
||||
{
|
||||
return ByteRangeMapping__find(Bun::toString(sourceURL));
|
||||
}
|
||||
|
||||
JSC::SourceID sourceIDForSourceURL(const WTF::String& sourceURL)
|
||||
{
|
||||
void* mappings = ByteRangeMapping__find(Bun::toString(sourceURL));
|
||||
if (!mappings) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ByteRangeMapping__getSourceID(mappings, Bun::toString(sourceURL));
|
||||
}
|
||||
|
||||
Ref<BunSourceProvider> BunSourceProvider::create(
|
||||
Zig::GlobalObject* globalObject,
|
||||
Ref<WTF::StringImpl>&& source,
|
||||
const WTF::String& sourceURL,
|
||||
JSC::SourceOrigin&& origin,
|
||||
JSC::SourceProviderSourceType sourceType,
|
||||
RefPtr<JSC::CachedBytecode>&& cachedBytecode)
|
||||
{
|
||||
return adoptRef(*new BunSourceProvider(
|
||||
globalObject,
|
||||
WTFMove(source),
|
||||
sourceURL,
|
||||
WTFMove(origin),
|
||||
sourceType,
|
||||
WTFMove(cachedBytecode)));
|
||||
}
|
||||
|
||||
BunSourceProvider::BunSourceProvider(
|
||||
Zig::GlobalObject* globalObject,
|
||||
Ref<WTF::StringImpl>&& source,
|
||||
const WTF::String& sourceURL,
|
||||
JSC::SourceOrigin&& origin,
|
||||
JSC::SourceProviderSourceType sourceType,
|
||||
RefPtr<JSC::CachedBytecode>&& cachedBytecode)
|
||||
: Base(origin, String(sourceURL), String(), JSC::SourceTaintedOrigin::Untainted, TextPosition(), sourceType)
|
||||
, m_globalObject(globalObject)
|
||||
, m_source(WTFMove(source))
|
||||
, m_cachedBytecode(WTFMove(cachedBytecode))
|
||||
, m_hash(0)
|
||||
{
|
||||
// m_globalObject is stored for potential future use (e.g., destructor cleanup)
|
||||
UNUSED_PARAM(m_globalObject);
|
||||
}
|
||||
|
||||
StringView BunSourceProvider::source() const
|
||||
{
|
||||
return StringView(m_source.get());
|
||||
}
|
||||
|
||||
unsigned BunSourceProvider::hash() const
|
||||
{
|
||||
if (m_hash) {
|
||||
return m_hash;
|
||||
}
|
||||
return m_source->hash();
|
||||
}
|
||||
|
||||
// Forward declare the C bridge function for registering sourcemaps
|
||||
extern "C" void Bun__addSourceProviderSourceMap(void* bun_vm, JSC::SourceProvider* opaque_source_provider, BunString* specifier);
|
||||
|
||||
// C bridge function for creating a BunSourceProvider from TranspiledSource
|
||||
extern "C" JSC::SourceProvider* Bun__createSourceProvider(
|
||||
Zig::GlobalObject* globalObject,
|
||||
const TranspiledSource* transpiled)
|
||||
{
|
||||
// Convert BunStrings to WTF strings
|
||||
auto sourceCode = transpiled->source_code.toWTFString(BunString::ZeroCopy);
|
||||
auto sourceURL = transpiled->source_url.toWTFString(BunString::ZeroCopy);
|
||||
|
||||
// Extract flags
|
||||
bool isCommonJS = (transpiled->flags & 0x1) != 0;
|
||||
bool alreadyBundled = (transpiled->flags & 0x2) != 0;
|
||||
|
||||
// Determine source type
|
||||
JSC::SourceProviderSourceType sourceType = isCommonJS
|
||||
? JSC::SourceProviderSourceType::Program
|
||||
: JSC::SourceProviderSourceType::Module;
|
||||
|
||||
// Create source origin
|
||||
JSC::SourceOrigin origin = toSourceOrigin(sourceURL, false);
|
||||
|
||||
// Handle bytecode cache if present
|
||||
RefPtr<JSC::CachedBytecode> cachedBytecode = nullptr;
|
||||
if (transpiled->bytecode_cache != nullptr && transpiled->bytecode_cache_len > 0) {
|
||||
JSC::CachePayload::Destructor destructor = [](const void* ptr) {
|
||||
mi_free(const_cast<void*>(ptr));
|
||||
};
|
||||
cachedBytecode = JSC::CachedBytecode::create(
|
||||
std::span<uint8_t>(transpiled->bytecode_cache, transpiled->bytecode_cache_len),
|
||||
WTFMove(destructor),
|
||||
{});
|
||||
}
|
||||
|
||||
// Create the source provider
|
||||
auto provider = BunSourceProvider::create(
|
||||
globalObject,
|
||||
sourceCode.isNull() ? Ref<WTF::StringImpl>(*WTF::StringImpl::empty()) : Ref<WTF::StringImpl>(*sourceCode.impl()),
|
||||
sourceURL,
|
||||
WTFMove(origin),
|
||||
sourceType,
|
||||
WTFMove(cachedBytecode));
|
||||
|
||||
// Register sourcemap if already bundled
|
||||
if (alreadyBundled) {
|
||||
auto sourceURLBun = transpiled->source_url;
|
||||
Bun__addSourceProviderSourceMap(globalObject->bunVM(), provider.ptr(), &sourceURLBun);
|
||||
}
|
||||
|
||||
// Return leaked ref (caller takes ownership)
|
||||
provider->ref();
|
||||
return provider.ptr();
|
||||
}
|
||||
|
||||
} // namespace Zig
|
||||
63
src/bun.js/bindings/BunSourceProvider.h
Normal file
63
src/bun.js/bindings/BunSourceProvider.h
Normal file
@@ -0,0 +1,63 @@
|
||||
#pragma once
|
||||
|
||||
#include "root.h"
|
||||
#include "headers.h"
|
||||
|
||||
#include <JavaScriptCore/CachedBytecode.h>
|
||||
#include <JavaScriptCore/SourceProvider.h>
|
||||
#include <JavaScriptCore/SourceOrigin.h>
|
||||
#include <wtf/RefPtr.h>
|
||||
#include <wtf/text/WTFString.h>
|
||||
|
||||
namespace Zig {
|
||||
|
||||
class GlobalObject;
|
||||
|
||||
// Helper functions for source providers
|
||||
void forEachSourceProvider(WTF::Function<void(JSC::SourceID)>);
|
||||
JSC::SourceID sourceIDForSourceURL(const WTF::String& sourceURL);
|
||||
void* sourceMappingForSourceURL(const WTF::String& sourceURL);
|
||||
JSC::SourceOrigin toSourceOrigin(const WTF::String& sourceURL, bool isBuiltin);
|
||||
|
||||
/// New cleaner SourceProvider implementation for Bun
|
||||
/// Uses TranspiledSource instead of ResolvedSource for better separation of concerns
|
||||
class BunSourceProvider final : public JSC::SourceProvider {
|
||||
WTF_DEPRECATED_MAKE_FAST_ALLOCATED(BunSourceProvider);
|
||||
using Base = JSC::SourceProvider;
|
||||
|
||||
public:
|
||||
static Ref<BunSourceProvider> create(
|
||||
Zig::GlobalObject* globalObject,
|
||||
Ref<WTF::StringImpl>&& source,
|
||||
const WTF::String& sourceURL,
|
||||
JSC::SourceOrigin&& origin,
|
||||
JSC::SourceProviderSourceType sourceType,
|
||||
RefPtr<JSC::CachedBytecode>&& cachedBytecode = nullptr);
|
||||
|
||||
virtual ~BunSourceProvider() = default;
|
||||
|
||||
// Required JSC::SourceProvider overrides
|
||||
StringView source() const override;
|
||||
unsigned hash() const override;
|
||||
|
||||
RefPtr<JSC::CachedBytecode> cachedBytecode() const final
|
||||
{
|
||||
return m_cachedBytecode;
|
||||
}
|
||||
|
||||
private:
|
||||
BunSourceProvider(
|
||||
Zig::GlobalObject* globalObject,
|
||||
Ref<WTF::StringImpl>&& source,
|
||||
const WTF::String& sourceURL,
|
||||
JSC::SourceOrigin&& origin,
|
||||
JSC::SourceProviderSourceType sourceType,
|
||||
RefPtr<JSC::CachedBytecode>&& cachedBytecode);
|
||||
|
||||
Zig::GlobalObject* m_globalObject;
|
||||
Ref<WTF::StringImpl> m_source;
|
||||
RefPtr<JSC::CachedBytecode> m_cachedBytecode;
|
||||
unsigned m_hash;
|
||||
};
|
||||
|
||||
} // namespace Zig
|
||||
@@ -1,5 +1,4 @@
|
||||
#include "root.h"
|
||||
#include "ZigSourceProvider.h"
|
||||
#include <JavaScriptCore/ControlFlowProfiler.h>
|
||||
|
||||
using namespace JSC;
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
#include <JavaScriptCore/JSInternalPromise.h>
|
||||
#include <JavaScriptCore/JSInternalFieldObjectImpl.h>
|
||||
|
||||
#include "ZigSourceProvider.h"
|
||||
#include "BunSourceProvider.h"
|
||||
|
||||
#include <JavaScriptCore/JSSourceCode.h>
|
||||
#include <JavaScriptCore/JSString.h>
|
||||
@@ -41,6 +41,39 @@
|
||||
|
||||
#include "BunProcess.h"
|
||||
|
||||
// Forward declare the new Zig C structs
|
||||
extern "C" {
|
||||
// Must match TranspiledSource.zig
|
||||
struct TranspiledSource {
|
||||
BunString source_code;
|
||||
BunString source_url;
|
||||
uint8_t* bytecode_cache;
|
||||
size_t bytecode_cache_len;
|
||||
uint32_t flags; // packed struct: is_commonjs:1, is_already_bundled:1, padding:30
|
||||
};
|
||||
|
||||
// Must match SpecialModule.zig
|
||||
struct SpecialModule {
|
||||
uint32_t tag; // exports_object=0, export_default_object=1, custom_extension=2
|
||||
JSC::EncodedJSValue jsvalue;
|
||||
};
|
||||
|
||||
// Must match ModuleResult.zig
|
||||
struct ModuleResult {
|
||||
uint32_t tag; // transpiled=0, special=1, builtin=2
|
||||
union {
|
||||
TranspiledSource transpiled;
|
||||
SpecialModule special;
|
||||
uint32_t builtin_id;
|
||||
} value;
|
||||
};
|
||||
|
||||
// Bridge function to create BunSourceProvider from TranspiledSource
|
||||
JSC::SourceProvider* Bun__createSourceProvider(
|
||||
Zig::GlobalObject* globalObject,
|
||||
const TranspiledSource* transpiled);
|
||||
}
|
||||
|
||||
namespace Bun {
|
||||
using namespace JSC;
|
||||
using namespace Zig;
|
||||
@@ -64,6 +97,24 @@ public:
|
||||
ErrorableResolvedSource* res;
|
||||
};
|
||||
|
||||
// Helper: Convert ResolvedSource to TranspiledSource
|
||||
static TranspiledSource resolvedSourceToTranspiledSource(const ResolvedSource& resolved)
|
||||
{
|
||||
TranspiledSource transpiled;
|
||||
transpiled.source_code = resolved.source_code;
|
||||
transpiled.source_url = resolved.source_url;
|
||||
transpiled.bytecode_cache = resolved.bytecode_cache;
|
||||
transpiled.bytecode_cache_len = resolved.bytecode_cache_size;
|
||||
|
||||
// Pack flags
|
||||
uint32_t flags = 0;
|
||||
if (resolved.isCommonJSModule) flags |= 0x1;
|
||||
if (resolved.already_bundled) flags |= 0x2;
|
||||
transpiled.flags = flags;
|
||||
|
||||
return transpiled;
|
||||
}
|
||||
|
||||
extern "C" BunLoaderType Bun__getDefaultLoader(JSC::JSGlobalObject*, BunString* specifier);
|
||||
|
||||
static JSC::JSInternalPromise* rejectedInternalPromise(JSC::JSGlobalObject* globalObject, JSC::JSValue value)
|
||||
@@ -389,8 +440,11 @@ static JSValue handleVirtualModuleResult(
|
||||
RELEASE_AND_RETURN(scope, reject(JSValue::decode(res->result.err.value)));
|
||||
}
|
||||
|
||||
auto provider = Zig::SourceProvider::create(globalObject, res->result.value);
|
||||
return resolve(JSC::JSSourceCode::create(vm, JSC::SourceCode(provider)));
|
||||
// Use new BunSourceProvider for virtual module transpiled code
|
||||
auto transpiled = resolvedSourceToTranspiledSource(res->result.value);
|
||||
auto* providerPtr = Bun__createSourceProvider(globalObject, &transpiled);
|
||||
Ref<JSC::SourceProvider> provider = adoptRef(*providerPtr);
|
||||
return resolve(JSC::JSSourceCode::create(vm, JSC::SourceCode(WTFMove(provider))));
|
||||
}
|
||||
case OnLoadResultTypeError: {
|
||||
RELEASE_AND_RETURN(scope, reject(onLoadResult.value.error));
|
||||
@@ -508,8 +562,11 @@ extern "C" void Bun__onFulfillAsyncModule(
|
||||
}
|
||||
}
|
||||
} else {
|
||||
auto&& provider = Zig::SourceProvider::create(jsDynamicCast<Zig::GlobalObject*>(globalObject), res->result.value);
|
||||
promise->resolve(globalObject, JSC::JSSourceCode::create(vm, JSC::SourceCode(provider)));
|
||||
// Use new BunSourceProvider for transpiled ESM code
|
||||
auto transpiled = resolvedSourceToTranspiledSource(res->result.value);
|
||||
auto* providerPtr = Bun__createSourceProvider(jsDynamicCast<Zig::GlobalObject*>(globalObject), &transpiled);
|
||||
Ref<JSC::SourceProvider> provider = adoptRef(*providerPtr);
|
||||
promise->resolve(globalObject, JSC::JSSourceCode::create(vm, JSC::SourceCode(WTFMove(provider))));
|
||||
scope.assertNoExceptionExceptTermination();
|
||||
}
|
||||
} else {
|
||||
@@ -852,8 +909,11 @@ JSValue fetchCommonJSModuleNonBuiltin(
|
||||
RELEASE_AND_RETURN(scope, target);
|
||||
}
|
||||
|
||||
auto&& provider = Zig::SourceProvider::create(globalObject, res->result.value);
|
||||
globalObject->moduleLoader()->provideFetch(globalObject, specifierValue, JSC::SourceCode(provider));
|
||||
// Use new BunSourceProvider for transpiled code
|
||||
auto transpiled = resolvedSourceToTranspiledSource(res->result.value);
|
||||
auto* providerPtr = Bun__createSourceProvider(globalObject, &transpiled);
|
||||
Ref<JSC::SourceProvider> provider = adoptRef(*providerPtr);
|
||||
globalObject->moduleLoader()->provideFetch(globalObject, specifierValue, JSC::SourceCode(WTFMove(provider)));
|
||||
RETURN_IF_EXCEPTION(scope, {});
|
||||
RELEASE_AND_RETURN(scope, jsNumber(-1));
|
||||
}
|
||||
@@ -974,8 +1034,11 @@ static JSValue fetchESMSourceCode(
|
||||
auto tag = res->result.value.tag;
|
||||
switch (tag) {
|
||||
case SyntheticModuleType::ESM: {
|
||||
auto&& provider = Zig::SourceProvider::create(globalObject, res->result.value, JSC::SourceProviderSourceType::Module, true);
|
||||
RELEASE_AND_RETURN(scope, rejectOrResolve(JSSourceCode::create(vm, JSC::SourceCode(provider))));
|
||||
// Use new BunSourceProvider for builtin ESM modules
|
||||
auto transpiled = resolvedSourceToTranspiledSource(res->result.value);
|
||||
auto* providerPtr = Bun__createSourceProvider(globalObject, &transpiled);
|
||||
Ref<JSC::SourceProvider> provider = adoptRef(*providerPtr);
|
||||
RELEASE_AND_RETURN(scope, rejectOrResolve(JSSourceCode::create(vm, JSC::SourceCode(WTFMove(provider)))));
|
||||
}
|
||||
|
||||
#define CASE(str, name) \
|
||||
@@ -993,8 +1056,11 @@ static JSValue fetchESMSourceCode(
|
||||
auto source = JSC::SourceCode(JSC::SyntheticSourceProvider::create(generateInternalModuleSourceCode(globalObject, static_cast<InternalModuleRegistry::Field>(tag & mask)), JSC::SourceOrigin(URL(makeString("builtins://"_s, moduleKey))), moduleKey));
|
||||
RELEASE_AND_RETURN(scope, rejectOrResolve(JSSourceCode::create(vm, WTFMove(source))));
|
||||
} else {
|
||||
auto&& provider = Zig::SourceProvider::create(globalObject, res->result.value, JSC::SourceProviderSourceType::Module, true);
|
||||
RELEASE_AND_RETURN(scope, rejectOrResolve(JSC::JSSourceCode::create(vm, JSC::SourceCode(provider))));
|
||||
// Use new BunSourceProvider for builtin transpiled modules
|
||||
auto transpiled = resolvedSourceToTranspiledSource(res->result.value);
|
||||
auto* providerPtr = Bun__createSourceProvider(globalObject, &transpiled);
|
||||
Ref<JSC::SourceProvider> provider = adoptRef(*providerPtr);
|
||||
RELEASE_AND_RETURN(scope, rejectOrResolve(JSC::JSSourceCode::create(vm, JSC::SourceCode(WTFMove(provider)))));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1105,7 +1171,11 @@ static JSValue fetchESMSourceCode(
|
||||
RELEASE_AND_RETURN(scope, rejectOrResolve(JSSourceCode::create(globalObject->vm(), WTFMove(source))));
|
||||
}
|
||||
|
||||
RELEASE_AND_RETURN(scope, rejectOrResolve(JSC::JSSourceCode::create(vm, JSC::SourceCode(Zig::SourceProvider::create(globalObject, res->result.value)))));
|
||||
// Use new BunSourceProvider for transpiled code
|
||||
auto transpiled = resolvedSourceToTranspiledSource(res->result.value);
|
||||
auto* providerPtr = Bun__createSourceProvider(globalObject, &transpiled);
|
||||
Ref<JSC::SourceProvider> provider = adoptRef(*providerPtr);
|
||||
RELEASE_AND_RETURN(scope, rejectOrResolve(JSC::JSSourceCode::create(vm, JSC::SourceCode(WTFMove(provider)))));
|
||||
}
|
||||
|
||||
JSValue fetchESMSourceCodeSync(
|
||||
|
||||
21
src/bun.js/bindings/ModuleResult.zig
Normal file
21
src/bun.js/bindings/ModuleResult.zig
Normal file
@@ -0,0 +1,21 @@
|
||||
const bun = @import("bun");
|
||||
const TranspiledSource = @import("./TranspiledSource.zig").TranspiledSource;
|
||||
const SpecialModule = @import("./SpecialModule.zig").SpecialModule;
|
||||
|
||||
/// Tagged union return type for module resolution
|
||||
pub const ModuleResult = extern struct {
|
||||
tag: Tag,
|
||||
value: Value,
|
||||
|
||||
pub const Tag = enum(u32) {
|
||||
transpiled,
|
||||
special,
|
||||
builtin,
|
||||
};
|
||||
|
||||
pub const Value = extern union {
|
||||
transpiled: TranspiledSource,
|
||||
special: SpecialModule,
|
||||
builtin_id: u32,
|
||||
};
|
||||
};
|
||||
15
src/bun.js/bindings/SpecialModule.zig
Normal file
15
src/bun.js/bindings/SpecialModule.zig
Normal file
@@ -0,0 +1,15 @@
|
||||
/// For special cases that need JSValue handling
|
||||
pub const SpecialModule = extern struct {
|
||||
tag: Tag,
|
||||
jsvalue: JSValue,
|
||||
|
||||
pub const Tag = enum(u32) {
|
||||
exports_object,
|
||||
export_default_object,
|
||||
custom_extension,
|
||||
};
|
||||
};
|
||||
|
||||
const bun = @import("bun");
|
||||
const jsc = bun.jsc;
|
||||
const JSValue = jsc.JSValue;
|
||||
17
src/bun.js/bindings/TranspiledSource.zig
Normal file
17
src/bun.js/bindings/TranspiledSource.zig
Normal file
@@ -0,0 +1,17 @@
|
||||
/// Minimal POD struct for transpiled source code
|
||||
/// Thread-safe - contains no JSValue fields
|
||||
pub const TranspiledSource = extern struct {
|
||||
source_code: bun.String,
|
||||
source_url: bun.String,
|
||||
bytecode_cache: ?[*]u8,
|
||||
bytecode_cache_len: usize,
|
||||
flags: Flags,
|
||||
|
||||
pub const Flags = packed struct(u32) {
|
||||
is_commonjs: bool,
|
||||
is_already_bundled: bool,
|
||||
_padding: u30 = 0,
|
||||
};
|
||||
};
|
||||
|
||||
const bun = @import("bun");
|
||||
@@ -153,7 +153,7 @@
|
||||
#include "webcrypto/JSCryptoKey.h"
|
||||
#include "webcrypto/JSSubtleCrypto.h"
|
||||
#include "ZigGeneratedClasses.h"
|
||||
#include "ZigSourceProvider.h"
|
||||
#include "BunSourceProvider.h"
|
||||
#include "UtilInspect.h"
|
||||
#include "Base64Helpers.h"
|
||||
#include "wtf/text/OrdinalNumber.h"
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "helpers.h"
|
||||
|
||||
#include "ZigSourceProvider.h"
|
||||
#include "BunSourceProvider.h"
|
||||
|
||||
#include <JavaScriptCore/BytecodeCacheError.h>
|
||||
#include "ZigGlobalObject.h"
|
||||
@@ -29,42 +30,10 @@ using SourceOrigin = JSC::SourceOrigin;
|
||||
using String = WTF::String;
|
||||
using SourceProviderSourceType = JSC::SourceProviderSourceType;
|
||||
|
||||
SourceOrigin toSourceOrigin(const String& sourceURL, bool isBuiltin)
|
||||
{
|
||||
|
||||
ASSERT_WITH_MESSAGE(!sourceURL.startsWith("file://"_s), "specifier should not already be a file URL");
|
||||
|
||||
if (isBuiltin) {
|
||||
if (sourceURL.startsWith("node:"_s)) {
|
||||
return SourceOrigin(WTF::URL(makeString("builtin://node/"_s, sourceURL.substring(5))));
|
||||
} else if (sourceURL.startsWith("bun:"_s)) {
|
||||
return SourceOrigin(WTF::URL(makeString("builtin://bun/"_s, sourceURL.substring(4))));
|
||||
} else {
|
||||
return SourceOrigin(WTF::URL(makeString("builtin://"_s, sourceURL)));
|
||||
}
|
||||
}
|
||||
return SourceOrigin(WTF::URL::fileURLWithFileSystemPath(sourceURL));
|
||||
}
|
||||
|
||||
extern "C" int ByteRangeMapping__getSourceID(void* mappings, BunString sourceURL);
|
||||
extern "C" void* ByteRangeMapping__find(BunString sourceURL);
|
||||
void* sourceMappingForSourceURL(const WTF::String& sourceURL)
|
||||
{
|
||||
return ByteRangeMapping__find(Bun::toString(sourceURL));
|
||||
}
|
||||
|
||||
// Helper functions are now defined in BunSourceProvider.cpp
|
||||
// They are declared in both headers for compatibility
|
||||
extern "C" void ByteRangeMapping__generate(BunString sourceURL, BunString code, int sourceID);
|
||||
|
||||
JSC::SourceID sourceIDForSourceURL(const WTF::String& sourceURL)
|
||||
{
|
||||
void* mappings = ByteRangeMapping__find(Bun::toString(sourceURL));
|
||||
if (!mappings) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ByteRangeMapping__getSourceID(mappings, Bun::toString(sourceURL));
|
||||
}
|
||||
|
||||
extern "C" bool BunTest__shouldGenerateCodeCoverage(BunString sourceURL);
|
||||
extern "C" void Bun__addSourceProviderSourceMap(void* bun_vm, SourceProvider* opaque_source_provider, BunString* specifier);
|
||||
extern "C" void Bun__removeSourceProviderSourceMap(void* bun_vm, SourceProvider* opaque_source_provider, BunString* specifier);
|
||||
|
||||
@@ -90,6 +90,9 @@ pub const RegularExpression = @import("./bindings/RegularExpression.zig").Regula
|
||||
// JavaScript-related
|
||||
pub const Errorable = @import("./bindings/Errorable.zig").Errorable;
|
||||
pub const ResolvedSource = @import("./bindings/ResolvedSource.zig").ResolvedSource;
|
||||
pub const ModuleResult = @import("./bindings/ModuleResult.zig").ModuleResult;
|
||||
pub const TranspiledSource = @import("./bindings/TranspiledSource.zig").TranspiledSource;
|
||||
pub const SpecialModule = @import("./bindings/SpecialModule.zig").SpecialModule;
|
||||
pub const ErrorCode = @import("./bindings/ErrorCode.zig").ErrorCode;
|
||||
pub const JSErrorCode = @import("./bindings/JSErrorCode.zig").JSErrorCode;
|
||||
pub const ZigErrorType = @import("./bindings/ZigErrorType.zig").ZigErrorType;
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
#endif
|
||||
|
||||
#include "JSDOMConvertBase.h"
|
||||
#include "ZigSourceProvider.h"
|
||||
#include "BunSourceProvider.h"
|
||||
#include "mimalloc.h"
|
||||
|
||||
#include <JavaScriptCore/ControlFlowProfiler.h>
|
||||
|
||||
Reference in New Issue
Block a user