aboutsummaryrefslogtreecommitdiff
path: root/src/bun.js/javascript.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/bun.js/javascript.zig')
-rw-r--r--src/bun.js/javascript.zig950
1 files changed, 564 insertions, 386 deletions
diff --git a/src/bun.js/javascript.zig b/src/bun.js/javascript.zig
index 2dd7a9d3f..4053b89d5 100644
--- a/src/bun.js/javascript.zig
+++ b/src/bun.js/javascript.zig
@@ -325,6 +325,8 @@ pub const VirtualMachine = struct {
timer: Bun.Timer = Bun.Timer{},
uws_event_loop: ?*uws.Loop = null,
+ is_printing_plugin: bool = false,
+
plugin_runner: ?PluginRunner = null,
/// Do not access this field directly
@@ -596,7 +598,7 @@ pub const VirtualMachine = struct {
// }
- threadlocal var source_code_printer: ?*js_printer.BufferPrinter = null;
+ pub threadlocal var source_code_printer: ?*js_printer.BufferPrinter = null;
pub fn clearRefString(_: *anyopaque, ref_string: *JSC.RefString) void {
_ = VirtualMachine.vm.ref_strings.remove(ref_string.hash);
@@ -676,27 +678,8 @@ pub const VirtualMachine = struct {
const shared_library_suffix = if (Environment.isMac) "dylib" else if (Environment.isLinux) "so" else "";
- const FetchFlags = enum {
- transpile,
- print_source,
- print_source_and_clone,
-
- pub fn disableTranspiling(this: FetchFlags) bool {
- return this != .transpile;
- }
- };
-
- fn _fetch(
- jsc_vm: *VirtualMachine,
- globalObject: *JSGlobalObject,
- _specifier: string,
- _: string,
- log: *logger.Log,
- comptime flags: FetchFlags,
- ) !ResolvedSource {
- std.debug.assert(VirtualMachine.vm_loaded);
- const disable_transpilying = comptime flags.disableTranspiling();
- if (jsc_vm.node_modules != null and strings.eqlComptime(_specifier, bun_file_import_path)) {
+ pub fn fetchBuiltinModule(jsc_vm: *VirtualMachine, specifier: string, log: *logger.Log, comptime disable_transpilying: bool) !?ResolvedSource {
+ if (jsc_vm.node_modules != null and strings.eqlComptime(specifier, bun_file_import_path)) {
// We kind of need an abstraction around this.
// Basically we should subclass JSC::SourceCode with:
// - hash
@@ -712,7 +695,7 @@ pub const VirtualMachine = struct {
.source_url = ZigString.init(bun_file_import_path[1..]),
.hash = 0, // TODO
};
- } else if (jsc_vm.node_modules == null and strings.eqlComptime(_specifier, Runtime.Runtime.Imports.Name)) {
+ } else if (jsc_vm.node_modules == null and strings.eqlComptime(specifier, Runtime.Runtime.Imports.Name)) {
return ResolvedSource{
.allocator = null,
.source_code = ZigString.init(Runtime.Runtime.sourceContentBun()),
@@ -720,7 +703,7 @@ pub const VirtualMachine = struct {
.source_url = ZigString.init(Runtime.Runtime.Imports.Name),
.hash = Runtime.Runtime.versionHash(),
};
- } else if (HardcodedModule.Map.get(_specifier)) |hardcoded| {
+ } else if (HardcodedModule.Map.get(specifier)) |hardcoded| {
switch (hardcoded) {
// This is all complicated because the imports have to be linked and we want to run the printer on it
// so it consistently handles bundled imports
@@ -1011,356 +994,61 @@ pub const VirtualMachine = struct {
};
},
}
- } else if (_specifier.len > js_ast.Macro.namespaceWithColon.len and
- strings.eqlComptimeIgnoreLen(_specifier[0..js_ast.Macro.namespaceWithColon.len], js_ast.Macro.namespaceWithColon))
+ } else if (specifier.len > js_ast.Macro.namespaceWithColon.len and
+ strings.eqlComptimeIgnoreLen(specifier[0..js_ast.Macro.namespaceWithColon.len], js_ast.Macro.namespaceWithColon))
{
if (comptime !disable_transpilying) {
- if (jsc_vm.macro_entry_points.get(MacroEntryPoint.generateIDFromSpecifier(_specifier))) |entry| {
+ if (jsc_vm.macro_entry_points.get(MacroEntryPoint.generateIDFromSpecifier(specifier))) |entry| {
return ResolvedSource{
.allocator = null,
.source_code = ZigString.init(entry.source.contents),
- .specifier = ZigString.init(_specifier),
- .source_url = ZigString.init(_specifier),
+ .specifier = ZigString.init(specifier),
+ .source_url = ZigString.init(specifier),
.hash = 0,
};
}
}
}
- var specifier = normalizeSpecifier(_specifier);
+ return null;
+ }
+
+ pub fn fetchWithoutOnLoadPlugins(
+ jsc_vm: *VirtualMachine,
+ _specifier: string,
+ log: *logger.Log,
+ ret: *ErrorableResolvedSource,
+ comptime flags: FetchFlags,
+ ) !ResolvedSource {
+ std.debug.assert(VirtualMachine.vm_loaded);
+
+ if (try fetchBuiltinModule(jsc_vm, _specifier, log, comptime flags.disableTranspiling())) |builtin| {
+ return builtin;
+ }
+
+ var specifier = ModuleLoader.normalizeSpecifier(jsc_vm, _specifier);
var path = Fs.Path.init(specifier);
- const default_loader = jsc_vm.bundler.options.loaders.get(path.name.ext) orelse brk: {
+ const loader = jsc_vm.bundler.options.loaders.get(path.name.ext) orelse brk: {
if (strings.eqlLong(specifier, jsc_vm.main, true)) {
break :brk options.Loader.js;
}
break :brk options.Loader.file;
};
- var loader = default_loader;
- var virtual_source: logger.Source = undefined;
- var has_virtual_source = false;
- var source_code_slice: ZigString.Slice = ZigString.Slice.empty;
- defer source_code_slice.deinit();
-
- if (jsc_vm.plugin_runner != null) {
- const namespace = PluginRunner.extractNamespace(_specifier);
- const after_namespace = if (namespace.len == 0)
- specifier
- else
- _specifier[@minimum(namespace.len + 1, _specifier.len)..];
-
- if (PluginRunner.couldBePlugin(_specifier)) {
- if (globalObject.runOnLoadPlugins(ZigString.init(namespace), ZigString.init(after_namespace), .bun)) |plugin_result| {
- if (plugin_result.isException(globalObject.vm()) or plugin_result.isAnyError(globalObject)) {
- jsc_vm.runErrorHandler(plugin_result, null);
- log.addError(null, logger.Loc.Empty, "Failed to run plugin") catch unreachable;
- return error.PluginError;
- }
-
- if (comptime Environment.allow_assert)
- std.debug.assert(plugin_result.isObject());
-
- if (plugin_result.get(globalObject, "loader")) |loader_value| {
- if (!loader_value.isUndefinedOrNull()) {
- const loader_string = loader_value.getZigString(globalObject);
- if (comptime Environment.allow_assert)
- std.debug.assert(loader_string.len > 0);
-
- if (loader_string.eqlComptime("js")) {
- loader = options.Loader.js;
- } else if (loader_string.eqlComptime("jsx")) {
- loader = options.Loader.jsx;
- } else if (loader_string.eqlComptime("tsx")) {
- loader = options.Loader.tsx;
- } else if (loader_string.eqlComptime("ts")) {
- loader = options.Loader.ts;
- } else if (loader_string.eqlComptime("json")) {
- loader = options.Loader.json;
- } else if (loader_string.eqlComptime("toml")) {
- loader = options.Loader.toml;
- } else if (loader_string.eqlComptime("object")) {
- const exports_object: JSValue = @as(?JSValue, brk: {
- const exports_value = plugin_result.get(globalObject, "exports") orelse break :brk null;
- if (!exports_value.isObject()) {
- break :brk null;
- }
- break :brk exports_value;
- }) orelse {
- log.addError(null, logger.Loc.Empty, "Expected object loader to return an \"exports\" object") catch unreachable;
- return error.PluginError;
- };
- return ResolvedSource{
- .allocator = null,
- .source_code = ZigString{
- .ptr = @ptrCast([*]const u8, exports_object.asVoid()),
- .len = 0,
- },
- .specifier = ZigString.init(_specifier),
- .source_url = ZigString.init(_specifier),
- .hash = 0,
- .tag = .object,
- };
- } else {
- log.addErrorFmt(
- null,
- logger.Loc.Empty,
- jsc_vm.allocator,
- "Expected onLoad() plugin \"loader\" to be one of \"js\", \"jsx\", \"tsx\", \"ts\", \"json\", or \"toml\" but received \"{any}\"",
- .{loader_string},
- ) catch unreachable;
- return error.PluginError;
- }
- }
- }
-
- if (plugin_result.get(globalObject, "contents")) |code| {
- if (code.asArrayBuffer(globalObject)) |array_buffer| {
- virtual_source = .{
- .path = path,
- .key_path = path,
- .contents = array_buffer.byteSlice(),
- };
- has_virtual_source = true;
- } else if (code.isString()) {
- source_code_slice = code.toSlice(globalObject, jsc_vm.allocator);
- if (!source_code_slice.allocated) {
- if (!strings.isAllASCII(source_code_slice.slice())) {
- var allocated = try strings.allocateLatin1IntoUTF8(jsc_vm.allocator, []const u8, source_code_slice.slice());
- source_code_slice.ptr = allocated.ptr;
- source_code_slice.len = @truncate(u32, allocated.len);
- source_code_slice.allocated = true;
- source_code_slice.allocator = jsc_vm.allocator;
- }
- }
- virtual_source = .{
- .path = path,
- .key_path = path,
- .contents = source_code_slice.slice(),
- };
- has_virtual_source = true;
- }
- }
-
- if (!has_virtual_source) {
- log.addError(null, logger.Loc.Empty, "Expected onLoad() plugin to return \"contents\" as a string or ArrayBufferView") catch unreachable;
- return error.PluginError;
- }
- } else {
- std.debug.assert(std.fs.path.isAbsolute(specifier)); // if this crashes, it means the resolver was skipped.
- }
- }
- }
-
- const transpiled_result = transpileSourceCode(
+ return try ModuleLoader.transpileSourceCode(
jsc_vm,
specifier,
path,
loader,
log,
- if (has_virtual_source) &virtual_source else null,
+ null,
+ ret,
+ VirtualMachine.source_code_printer.?,
flags,
);
- return transpiled_result;
}
- fn transpileSourceCode(
- jsc_vm: *VirtualMachine,
- specifier: string,
- path: Fs.Path,
- loader: options.Loader,
- log: *logger.Log,
- virtual_source: ?*const logger.Source,
- comptime flags: FetchFlags,
- ) !ResolvedSource {
- const disable_transpilying = comptime flags.disableTranspiling();
-
- switch (loader) {
- .js, .jsx, .ts, .tsx, .json, .toml => {
- jsc_vm.transpiled_count += 1;
- jsc_vm.bundler.resetStore();
- const hash = http.Watcher.getHash(path.text);
-
- var allocator = if (jsc_vm.has_loaded) jsc_vm.arena.allocator() else jsc_vm.allocator;
-
- var fd: ?StoredFileDescriptorType = null;
- var package_json: ?*PackageJSON = null;
-
- if (jsc_vm.watcher) |watcher| {
- if (watcher.indexOf(hash)) |index| {
- const _fd = watcher.watchlist.items(.fd)[index];
- fd = if (_fd > 0) _fd else null;
- package_json = watcher.watchlist.items(.package_json)[index];
- }
- }
-
- var old = jsc_vm.bundler.log;
- jsc_vm.bundler.log = log;
- jsc_vm.bundler.linker.log = log;
- jsc_vm.bundler.resolver.log = log;
-
- defer {
- jsc_vm.bundler.log = old;
- jsc_vm.bundler.linker.log = old;
- jsc_vm.bundler.resolver.log = old;
- }
-
- // this should be a cheap lookup because 24 bytes == 8 * 3 so it's read 3 machine words
- const is_node_override = specifier.len > "/bun-vfs/node_modules/".len and strings.eqlComptimeIgnoreLen(specifier[0.."/bun-vfs/node_modules/".len], "/bun-vfs/node_modules/");
-
- const macro_remappings = if (jsc_vm.macro_mode or !jsc_vm.has_any_macro_remappings or is_node_override)
- MacroRemap{}
- else
- jsc_vm.bundler.options.macro_remap;
-
- var fallback_source: logger.Source = undefined;
-
- var parse_options = Bundler.ParseOptions{
- .allocator = allocator,
- .path = path,
- .loader = loader,
- .dirname_fd = 0,
- .file_descriptor = fd,
- .file_hash = hash,
- .macro_remappings = macro_remappings,
- .jsx = jsc_vm.bundler.options.jsx,
- .virtual_source = virtual_source,
- };
-
- if (is_node_override) {
- if (NodeFallbackModules.contentsFromPath(specifier)) |code| {
- const fallback_path = Fs.Path.initWithNamespace(specifier, "node");
- fallback_source = logger.Source{ .path = fallback_path, .contents = code, .key_path = fallback_path };
- parse_options.virtual_source = &fallback_source;
- }
- }
-
- var parse_result = jsc_vm.bundler.parseMaybeReturnFileOnly(
- parse_options,
- null,
- disable_transpilying,
- ) orelse {
- return error.ParseError;
- };
-
- if (comptime disable_transpilying) {
- return ResolvedSource{
- .allocator = null,
- .source_code = switch (comptime flags) {
- .print_source_and_clone => ZigString.init(jsc_vm.allocator.dupe(u8, parse_result.source.contents) catch unreachable),
- .print_source => ZigString.init(parse_result.source.contents),
- else => unreachable,
- },
- .specifier = ZigString.init(specifier),
- .source_url = ZigString.init(path.text),
- .hash = 0,
- };
- }
-
- const start_count = jsc_vm.bundler.linker.import_counter;
- // We _must_ link because:
- // - node_modules bundle won't be properly
- try jsc_vm.bundler.linker.link(
- path,
- &parse_result,
- jsc_vm.origin,
- .absolute_path,
- false,
- true,
- );
-
- if (!jsc_vm.macro_mode)
- jsc_vm.resolved_count += jsc_vm.bundler.linker.import_counter - start_count;
- jsc_vm.bundler.linker.import_counter = 0;
-
- var printer = source_code_printer.?.*;
- printer.ctx.reset();
-
- const written = brk: {
- defer source_code_printer.?.* = printer;
- break :brk try jsc_vm.bundler.printWithSourceMap(
- parse_result,
- @TypeOf(&printer),
- &printer,
- .esm_ascii,
- SavedSourceMap.SourceMapHandler.init(&jsc_vm.source_mappings),
- );
- };
-
- if (written == 0) {
- return error.PrintingErrorWriteFailed;
- }
-
- if (jsc_vm.has_loaded) {
- return jsc_vm.refCountedResolvedSource(printer.ctx.written, specifier, path.text, null);
- }
-
- return ResolvedSource{
- .allocator = null,
- .source_code = ZigString.init(try default_allocator.dupe(u8, printer.ctx.getWritten())),
- .specifier = ZigString.init(specifier),
- .source_url = ZigString.init(path.text),
- // // TODO: change hash to a bitfield
- // .hash = 1,
-
- // having JSC own the memory causes crashes
- .hash = 0,
- };
- },
- // provideFetch() should be called
- .napi => unreachable,
- // .wasm => {
- // jsc_vm.transpiled_count += 1;
- // var fd: ?StoredFileDescriptorType = null;
-
- // var allocator = if (jsc_vm.has_loaded) jsc_vm.arena.allocator() else jsc_vm.allocator;
-
- // const hash = http.Watcher.getHash(path.text);
- // if (jsc_vm.watcher) |watcher| {
- // if (watcher.indexOf(hash)) |index| {
- // const _fd = watcher.watchlist.items(.fd)[index];
- // fd = if (_fd > 0) _fd else null;
- // }
- // }
-
- // var parse_options = Bundler.ParseOptions{
- // .allocator = allocator,
- // .path = path,
- // .loader = loader,
- // .dirname_fd = 0,
- // .file_descriptor = fd,
- // .file_hash = hash,
- // .macro_remappings = MacroRemap{},
- // .jsx = jsc_vm.bundler.options.jsx,
- // };
-
- // var parse_result = jsc_vm.bundler.parse(
- // parse_options,
- // null,
- // ) orelse {
- // return error.ParseError;
- // };
-
- // return ResolvedSource{
- // .allocator = if (jsc_vm.has_loaded) &jsc_vm.allocator else null,
- // .source_code = ZigString.init(jsc_vm.allocator.dupe(u8, parse_result.source.contents) catch unreachable),
- // .specifier = ZigString.init(specifier),
- // .source_url = ZigString.init(path.text),
- // .hash = 0,
- // .tag = ResolvedSource.Tag.wasm,
- // };
- // },
- else => {
- return ResolvedSource{
- .allocator = &vm.allocator,
- .source_code = ZigString.init(try strings.quotedAlloc(jsc_vm.allocator, path.pretty)),
- .specifier = ZigString.init(path.text),
- .source_url = ZigString.init(path.text),
- .hash = 0,
- };
- },
- }
- }
pub const ResolveFunctionResult = struct {
result: ?Resolver.Result,
path: string,
@@ -1546,42 +1234,6 @@ pub const VirtualMachine = struct {
res.* = ErrorableZigString.ok(ZigString.init(result.path));
}
- pub fn normalizeSpecifier(slice_: string) string {
- var vm_ = VirtualMachine.vm;
-
- var slice = slice_;
- if (slice.len == 0) return slice;
- var was_http = false;
- if (strings.hasPrefixComptime(slice, "https://")) {
- slice = slice["https://".len..];
- was_http = true;
- } else if (strings.hasPrefixComptime(slice, "http://")) {
- slice = slice["http://".len..];
- was_http = true;
- }
-
- if (strings.hasPrefix(slice, vm_.origin.host)) {
- slice = slice[vm_.origin.host.len..];
- } else if (was_http) {
- if (strings.indexOfChar(slice, '/')) |i| {
- slice = slice[i..];
- }
- }
-
- if (vm_.origin.path.len > 1) {
- if (strings.hasPrefix(slice, vm_.origin.path)) {
- slice = slice[vm_.origin.path.len..];
- }
- }
-
- if (vm_.bundler.options.routes.asset_prefix_path.len > 0) {
- if (strings.hasPrefix(slice, vm_.bundler.options.routes.asset_prefix_path)) {
- slice = slice[vm_.bundler.options.routes.asset_prefix_path.len..];
- }
- }
-
- return slice;
- }
// // This double prints
// pub fn promiseRejectionTracker(global: *JSGlobalObject, promise: *JSPromise, _: JSPromiseRejectionOperation) callconv(.C) JSValue {
@@ -1605,12 +1257,12 @@ pub const VirtualMachine = struct {
global.bunVM();
const result = if (!jsc_vm.bundler.options.disable_transpilation)
- @call(.{ .modifier = .always_inline }, _fetch, .{ jsc_vm, global, spec, source.slice(), &log, .transpile }) catch |err| {
+ @call(.{ .modifier = .always_inline }, fetchWithoutOnLoadPlugins, .{ jsc_vm, spec, &log, ret, .transpile }) catch |err| {
processFetchLog(global, specifier, source, &log, ret, err);
return;
}
else
- _fetch(jsc_vm, global, spec, source.slice(), &log, .print_source_and_clone) catch |err| {
+ fetchWithoutOnLoadPlugins(jsc_vm, spec, &log, ret, .print_source_and_clone) catch |err| {
processFetchLog(global, specifier, source, &log, ret, err);
return;
};
@@ -1657,7 +1309,7 @@ pub const VirtualMachine = struct {
ret.success = true;
}
- fn processFetchLog(globalThis: *JSGlobalObject, specifier: ZigString, referrer: ZigString, log: *logger.Log, ret: *ErrorableResolvedSource, err: anyerror) void {
+ pub fn processFetchLog(globalThis: *JSGlobalObject, specifier: ZigString, referrer: ZigString, log: *logger.Log, ret: *ErrorableResolvedSource, err: anyerror) void {
switch (log.msgs.items.len) {
0 => {
const msg = logger.Msg{
@@ -2074,7 +1726,8 @@ pub const VirtualMachine = struct {
@maximum(top.position.column_start, 0),
)) |mapping| {
var log = logger.Log.init(default_allocator);
- var original_source = _fetch(this, this.global, top.source_url.slice(), "", &log, .print_source) catch return;
+ var errorable: ErrorableResolvedSource = undefined;
+ var original_source = fetchWithoutOnLoadPlugins(this, top.source_url.slice(), &log, &errorable, .print_source) catch return;
const code = original_source.source_code.slice();
top.position.line = mapping.original.lines;
top.position.line_start = mapping.original.lines;
@@ -3091,3 +2744,528 @@ inline fn jsSyntheticModule(comptime name: ResolvedSource.Tag) ResolvedSource {
.tag = name,
};
}
+
+fn dumpSource(specifier: string, printer: anytype) !void {
+ const BunDebugHolder = struct {
+ pub var dir: ?std.fs.Dir = null;
+ };
+ if (BunDebugHolder.dir == null) {
+ BunDebugHolder.dir = try std.fs.cwd().makeOpenPath("/tmp/bun-debug-src/", .{ .iterate = true });
+ }
+
+ if (std.fs.path.dirname(specifier)) |dir_path| {
+ var parent = try BunDebugHolder.dir.?.makeOpenPath(dir_path[1..], .{ .iterate = true });
+ defer parent.close();
+ try parent.writeFile(std.fs.path.basename(specifier), printer.ctx.getWritten());
+ } else {
+ try BunDebugHolder.dir.?.writeFile(std.fs.path.basename(specifier), printer.ctx.getWritten());
+ }
+}
+
+pub const ModuleLoader = struct {
+ pub fn transpileSourceCode(
+ jsc_vm: *VirtualMachine,
+ specifier: string,
+ path: Fs.Path,
+ loader: options.Loader,
+ log: *logger.Log,
+ virtual_source: ?*const logger.Source,
+ ret: *ErrorableResolvedSource,
+ source_code_printer: *js_printer.BufferPrinter,
+ comptime flags: FetchFlags,
+ ) !ResolvedSource {
+ const disable_transpilying = comptime flags.disableTranspiling();
+
+ switch (loader) {
+ .js, .jsx, .ts, .tsx, .json, .toml => {
+ jsc_vm.transpiled_count += 1;
+ jsc_vm.bundler.resetStore();
+ const hash = http.Watcher.getHash(path.text);
+
+ var allocator = if (jsc_vm.has_loaded) jsc_vm.arena.allocator() else jsc_vm.allocator;
+
+ var fd: ?StoredFileDescriptorType = null;
+ var package_json: ?*PackageJSON = null;
+
+ if (jsc_vm.watcher) |watcher| {
+ if (watcher.indexOf(hash)) |index| {
+ const _fd = watcher.watchlist.items(.fd)[index];
+ fd = if (_fd > 0) _fd else null;
+ package_json = watcher.watchlist.items(.package_json)[index];
+ }
+ }
+
+ var old = jsc_vm.bundler.log;
+ jsc_vm.bundler.log = log;
+ jsc_vm.bundler.linker.log = log;
+ jsc_vm.bundler.resolver.log = log;
+
+ defer {
+ jsc_vm.bundler.log = old;
+ jsc_vm.bundler.linker.log = old;
+ jsc_vm.bundler.resolver.log = old;
+ }
+
+ // this should be a cheap lookup because 24 bytes == 8 * 3 so it's read 3 machine words
+ const is_node_override = specifier.len > "/bun-vfs/node_modules/".len and strings.eqlComptimeIgnoreLen(specifier[0.."/bun-vfs/node_modules/".len], "/bun-vfs/node_modules/");
+
+ const macro_remappings = if (jsc_vm.macro_mode or !jsc_vm.has_any_macro_remappings or is_node_override)
+ MacroRemap{}
+ else
+ jsc_vm.bundler.options.macro_remap;
+
+ var fallback_source: logger.Source = undefined;
+
+ var parse_options = Bundler.ParseOptions{
+ .allocator = allocator,
+ .path = path,
+ .loader = loader,
+ .dirname_fd = 0,
+ .file_descriptor = fd,
+ .file_hash = hash,
+ .macro_remappings = macro_remappings,
+ .jsx = jsc_vm.bundler.options.jsx,
+ .virtual_source = virtual_source,
+ .hoist_bun_plugin = true,
+ };
+
+ if (is_node_override) {
+ if (NodeFallbackModules.contentsFromPath(specifier)) |code| {
+ const fallback_path = Fs.Path.initWithNamespace(specifier, "node");
+ fallback_source = logger.Source{ .path = fallback_path, .contents = code, .key_path = fallback_path };
+ parse_options.virtual_source = &fallback_source;
+ }
+ }
+
+ var parse_result = jsc_vm.bundler.parseMaybeReturnFileOnly(
+ parse_options,
+ null,
+ disable_transpilying,
+ ) orelse {
+ return error.ParseError;
+ };
+
+ if (comptime disable_transpilying) {
+ return ResolvedSource{
+ .allocator = null,
+ .source_code = switch (comptime flags) {
+ .print_source_and_clone => ZigString.init(jsc_vm.allocator.dupe(u8, parse_result.source.contents) catch unreachable),
+ .print_source => ZigString.init(parse_result.source.contents),
+ else => unreachable,
+ },
+ .specifier = ZigString.init(specifier),
+ .source_url = ZigString.init(path.text),
+ .hash = 0,
+ };
+ }
+
+ const has_bun_plugin = parse_result.ast.bun_plugin.hoisted_stmts.items.len > 0;
+
+ if (has_bun_plugin) {
+ try ModuleLoader.runBunPlugin(jsc_vm, source_code_printer, &parse_result, ret);
+ }
+
+ var printer = source_code_printer.*;
+ printer.ctx.reset();
+
+ const start_count = jsc_vm.bundler.linker.import_counter;
+ // We _must_ link because:
+ // - node_modules bundle won't be properly
+ try jsc_vm.bundler.linker.link(
+ path,
+ &parse_result,
+ jsc_vm.origin,
+ .absolute_path,
+ false,
+ true,
+ );
+
+ if (!jsc_vm.macro_mode)
+ jsc_vm.resolved_count += jsc_vm.bundler.linker.import_counter - start_count;
+ jsc_vm.bundler.linker.import_counter = 0;
+
+ const written = brk: {
+ defer source_code_printer.* = printer;
+ break :brk try jsc_vm.bundler.printWithSourceMap(
+ parse_result,
+ @TypeOf(&printer),
+ &printer,
+ .esm_ascii,
+ SavedSourceMap.SourceMapHandler.init(&jsc_vm.source_mappings),
+ );
+ };
+
+ if (written == 0) {
+ // if it's an empty file but there were plugins
+ // we don't want it to break if you try to import from it
+ if (has_bun_plugin) {
+ return ResolvedSource{
+ .allocator = null,
+ .source_code = ZigString.init("// auto-generated plugin stub\nexport default undefined\n"),
+ .specifier = ZigString.init(specifier),
+ .source_url = ZigString.init(path.text),
+ // // TODO: change hash to a bitfield
+ // .hash = 1,
+
+ // having JSC own the memory causes crashes
+ .hash = 0,
+ };
+ }
+ return error.PrintingErrorWriteFailed;
+ }
+
+ if (jsc_vm.has_loaded) {
+ return jsc_vm.refCountedResolvedSource(printer.ctx.written, specifier, path.text, null);
+ }
+
+ if (comptime Environment.dump_source) {
+ try dumpSource(specifier, &printer);
+ }
+
+ return ResolvedSource{
+ .allocator = null,
+ .source_code = ZigString.init(try default_allocator.dupe(u8, printer.ctx.getWritten())),
+ .specifier = ZigString.init(specifier),
+ .source_url = ZigString.init(path.text),
+ // // TODO: change hash to a bitfield
+ // .hash = 1,
+
+ // having JSC own the memory causes crashes
+ .hash = 0,
+ };
+ },
+ // provideFetch() should be called
+ .napi => unreachable,
+ // .wasm => {
+ // jsc_vm.transpiled_count += 1;
+ // var fd: ?StoredFileDescriptorType = null;
+
+ // var allocator = if (jsc_vm.has_loaded) jsc_vm.arena.allocator() else jsc_vm.allocator;
+
+ // const hash = http.Watcher.getHash(path.text);
+ // if (jsc_vm.watcher) |watcher| {
+ // if (watcher.indexOf(hash)) |index| {
+ // const _fd = watcher.watchlist.items(.fd)[index];
+ // fd = if (_fd > 0) _fd else null;
+ // }
+ // }
+
+ // var parse_options = Bundler.ParseOptions{
+ // .allocator = allocator,
+ // .path = path,
+ // .loader = loader,
+ // .dirname_fd = 0,
+ // .file_descriptor = fd,
+ // .file_hash = hash,
+ // .macro_remappings = MacroRemap{},
+ // .jsx = jsc_vm.bundler.options.jsx,
+ // };
+
+ // var parse_result = jsc_vm.bundler.parse(
+ // parse_options,
+ // null,
+ // ) orelse {
+ // return error.ParseError;
+ // };
+
+ // return ResolvedSource{
+ // .allocator = if (jsc_vm.has_loaded) &jsc_vm.allocator else null,
+ // .source_code = ZigString.init(jsc_vm.allocator.dupe(u8, parse_result.source.contents) catch unreachable),
+ // .specifier = ZigString.init(specifier),
+ // .source_url = ZigString.init(path.text),
+ // .hash = 0,
+ // .tag = ResolvedSource.Tag.wasm,
+ // };
+ // },
+ else => {
+ return ResolvedSource{
+ .allocator = &jsc_vm.allocator,
+ .source_code = ZigString.init(try strings.quotedAlloc(jsc_vm.allocator, path.pretty)),
+ .specifier = ZigString.init(path.text),
+ .source_url = ZigString.init(path.text),
+ .hash = 0,
+ };
+ },
+ }
+ }
+
+ pub fn runBunPlugin(
+ jsc_vm: *VirtualMachine,
+ source_code_printer: *js_printer.BufferPrinter,
+ parse_result: *ParseResult,
+ ret: *ErrorableResolvedSource,
+ ) !void {
+ var printer = source_code_printer.*;
+ printer.ctx.reset();
+
+ defer printer.ctx.reset();
+ // If we start transpiling in the middle of an existing transpilation session
+ // we will hit undefined memory bugs
+ // unless we disable resetting the store until we are done transpiling
+ const prev_disable_reset = js_ast.Stmt.Data.Store.disable_reset;
+ js_ast.Stmt.Data.Store.disable_reset = true;
+ js_ast.Expr.Data.Store.disable_reset = true;
+
+ // flip the source code we use
+ // unless we're already transpiling a plugin
+ // that case could happen when
+ const was_printing_plugin = jsc_vm.is_printing_plugin;
+ const prev = jsc_vm.bundler.resolver.caches.fs.use_alternate_source_cache;
+ jsc_vm.is_printing_plugin = true;
+ defer {
+ js_ast.Stmt.Data.Store.disable_reset = prev_disable_reset;
+ js_ast.Expr.Data.Store.disable_reset = prev_disable_reset;
+ if (!was_printing_plugin) jsc_vm.bundler.resolver.caches.fs.use_alternate_source_cache = prev;
+ jsc_vm.is_printing_plugin = was_printing_plugin;
+ }
+ // we flip use_alternate_source_cache
+ if (!was_printing_plugin) jsc_vm.bundler.resolver.caches.fs.use_alternate_source_cache = !prev;
+
+ // this is a bad idea, but it should work for now.
+ const original_name = parse_result.ast.symbols[parse_result.ast.bun_plugin.ref.innerIndex()].original_name;
+ parse_result.ast.symbols[parse_result.ast.bun_plugin.ref.innerIndex()].original_name = "globalThis.Bun.plugin";
+ defer {
+ parse_result.ast.symbols[parse_result.ast.bun_plugin.ref.innerIndex()].original_name = original_name;
+ }
+ const hoisted_stmts = parse_result.ast.bun_plugin.hoisted_stmts.items;
+
+ var parts = [1]js_ast.Part{
+ js_ast.Part{
+ .stmts = hoisted_stmts,
+ },
+ };
+ var ast_copy = parse_result.ast;
+ ast_copy.parts = &parts;
+ ast_copy.prepend_part = null;
+ var temporary_source = parse_result.source;
+ var source_name = try std.fmt.allocPrint(jsc_vm.allocator, "{s}.plugin.{s}", .{ temporary_source.path.text, temporary_source.path.name.ext[1..] });
+ temporary_source.path = Fs.Path.init(source_name);
+
+ _ = brk: {
+ defer source_code_printer.* = printer;
+ break :brk try jsc_vm.bundler.printWithSourceMapMaybe(
+ ast_copy,
+ &temporary_source,
+ @TypeOf(&printer),
+ &printer,
+ .esm_ascii,
+ true,
+ SavedSourceMap.SourceMapHandler.init(&jsc_vm.source_mappings),
+ );
+ };
+ const wrote = printer.ctx.getWritten();
+
+ if (wrote.len > 0) {
+ if (comptime Environment.dump_source)
+ try dumpSource(temporary_source.path.text, &printer);
+
+ var exception = [1]JSC.JSValue{JSC.JSValue.zero};
+ _ = JSC.JSModuleLoader.evaluate(
+ jsc_vm.global,
+ wrote.ptr,
+ wrote.len,
+ temporary_source.path.text.ptr,
+ temporary_source.path.text.len,
+ JSC.JSValue.jsUndefined(),
+ &exception,
+ );
+ if (!exception[0].isEmpty()) {
+ ret.* = JSC.ErrorableResolvedSource.err(
+ error.JSErrorObject,
+ exception[0].asVoid(),
+ );
+ return error.PluginError;
+ }
+ }
+ }
+ pub fn normalizeSpecifier(jsc_vm: *VirtualMachine, slice_: string) string {
+ var slice = slice_;
+ if (slice.len == 0) return slice;
+ var was_http = false;
+ if (strings.hasPrefixComptime(slice, "https://")) {
+ slice = slice["https://".len..];
+ was_http = true;
+ } else if (strings.hasPrefixComptime(slice, "http://")) {
+ slice = slice["http://".len..];
+ was_http = true;
+ }
+
+ if (strings.hasPrefix(slice, jsc_vm.origin.host)) {
+ slice = slice[jsc_vm.origin.host.len..];
+ } else if (was_http) {
+ if (strings.indexOfChar(slice, '/')) |i| {
+ slice = slice[i..];
+ }
+ }
+
+ if (jsc_vm.origin.path.len > 1) {
+ if (strings.hasPrefix(slice, jsc_vm.origin.path)) {
+ slice = slice[jsc_vm.origin.path.len..];
+ }
+ }
+
+ if (jsc_vm.bundler.options.routes.asset_prefix_path.len > 0) {
+ if (strings.hasPrefix(slice, jsc_vm.bundler.options.routes.asset_prefix_path)) {
+ slice = slice[jsc_vm.bundler.options.routes.asset_prefix_path.len..];
+ }
+ }
+
+ return slice;
+ }
+
+ pub export fn Bun__fetchBuiltinModule(
+ jsc_vm: *VirtualMachine,
+ globalObject: *JSC.JSGlobalObject,
+ specifier: *ZigString,
+ referrer: *ZigString,
+ ret: *ErrorableResolvedSource,
+ ) bool {
+ JSC.markBinding();
+ var log = logger.Log.init(jsc_vm.bundler.allocator);
+ defer log.deinit();
+ if (jsc_vm.fetchBuiltinModule(specifier.slice(), &log, true) catch |err| {
+ VirtualMachine.processFetchLog(globalObject, specifier.*, referrer.*, &log, ret, err);
+ return true;
+ }) |builtin| {
+ ret.* = ErrorableResolvedSource.ok(builtin);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ pub export fn Bun__transpileFile(
+ jsc_vm: *VirtualMachine,
+ globalObject: *JSC.JSGlobalObject,
+ specifier_ptr: *ZigString,
+ referrer: *ZigString,
+ ret: *ErrorableResolvedSource,
+ ) bool {
+ JSC.markBinding();
+ var log = logger.Log.init(jsc_vm.bundler.allocator);
+ defer log.deinit();
+ var _specifier = specifier_ptr.toSlice(jsc_vm.allocator);
+ defer _specifier.deinit();
+ var specifier = normalizeSpecifier(jsc_vm, _specifier.slice());
+ const path = Fs.Path.init(specifier);
+ const loader = jsc_vm.bundler.options.loaders.get(path.name.ext) orelse brk: {
+ if (strings.eqlLong(specifier, jsc_vm.main, true)) {
+ break :brk options.Loader.js;
+ }
+
+ break :brk options.Loader.file;
+ };
+ ret.* = ErrorableResolvedSource.ok(
+ ModuleLoader.transpileSourceCode(
+ jsc_vm,
+ specifier,
+ path,
+ loader,
+ &log,
+ null,
+ ret,
+ VirtualMachine.source_code_printer.?,
+ FetchFlags.transpile,
+ ) catch |err| {
+ if (err == error.PluginERror) {
+ return true;
+ }
+ VirtualMachine.processFetchLog(globalObject, specifier_ptr.*, referrer.*, &log, ret, err);
+ return true;
+ },
+ );
+ return true;
+ }
+
+ export fn Bun__runVirtualModule(globalObject: *JSC.JSGlobalObject, specifier_ptr: *ZigString) JSValue {
+ JSC.markBinding();
+ if (globalObject.bunVM().plugin_runner == null) return JSValue.zero;
+
+ const specifier = specifier_ptr.slice();
+
+ if (!PluginRunner.couldBePlugin(specifier)) {
+ return JSValue.zero;
+ }
+
+ const namespace = PluginRunner.extractNamespace(specifier);
+ const after_namespace = if (namespace.len == 0)
+ specifier
+ else
+ specifier[@minimum(namespace.len + 1, specifier.len)..];
+
+ return globalObject.runOnLoadPlugins(ZigString.init(namespace), ZigString.init(after_namespace), .bun) orelse return JSValue.zero;
+ }
+
+ export fn Bun__transpileVirtualModule(
+ globalObject: *JSC.JSGlobalObject,
+ specifier_ptr: *ZigString,
+ referrer_ptr: *ZigString,
+ source_code: *ZigString,
+ loader_: Api.Loader,
+ ret: *ErrorableResolvedSource,
+ ) bool {
+ JSC.markBinding();
+ const jsc_vm = globalObject.bunVM();
+ std.debug.assert(jsc_vm.plugin_runner != null);
+
+ var specifier_slice = specifier_ptr.toSlice(jsc_vm.allocator);
+ const specifier = specifier_slice.slice();
+ defer specifier_slice.deinit();
+ var source_code_slice = source_code.toSlice(jsc_vm.allocator);
+ defer source_code_slice.deinit();
+
+ var virtual_source = logger.Source.initPathString(specifier, source_code_slice.slice());
+ var log = logger.Log.init(jsc_vm.allocator);
+ const path = Fs.Path.init(specifier);
+
+ const loader = if (loader_ != ._none)
+ options.Loader.fromString(@tagName(loader_)).?
+ else
+ jsc_vm.bundler.options.loaders.get(path.name.ext) orelse brk: {
+ if (strings.eqlLong(specifier, jsc_vm.main, true)) {
+ break :brk options.Loader.js;
+ }
+
+ break :brk options.Loader.file;
+ };
+
+ defer log.deinit();
+ ret.* = ErrorableResolvedSource.ok(
+ ModuleLoader.transpileSourceCode(
+ jsc_vm,
+ specifier,
+ path,
+ options.Loader.fromString(@tagName(loader)).?,
+ &log,
+ &virtual_source,
+ ret,
+ VirtualMachine.source_code_printer.?,
+ FetchFlags.transpile,
+ ) catch |err| {
+ if (err == error.PluginError) {
+ return true;
+ }
+ VirtualMachine.processFetchLog(globalObject, specifier_ptr.*, referrer_ptr.*, &log, ret, err);
+ return true;
+ },
+ );
+ return true;
+ }
+
+ comptime {
+ _ = Bun__transpileVirtualModule;
+ _ = Bun__runVirtualModule;
+ _ = Bun__transpileFile;
+ _ = Bun__fetchBuiltinModule;
+ }
+};
+
+const FetchFlags = enum {
+ transpile,
+ print_source,
+ print_source_and_clone,
+
+ pub fn disableTranspiling(this: FetchFlags) bool {
+ return this != .transpile;
+ }
+};