mirror of
https://github.com/oven-sh/bun
synced 2026-02-10 10:58:56 +00:00
1676 lines
54 KiB
Zig
1676 lines
54 KiB
Zig
const Bun = @This();
|
|
const default_allocator = @import("../../../global.zig").default_allocator;
|
|
const bun = @import("../../../global.zig");
|
|
const Environment = bun.Environment;
|
|
const NetworkThread = @import("http").NetworkThread;
|
|
const Global = bun.Global;
|
|
const strings = bun.strings;
|
|
const string = bun.string;
|
|
const Output = @import("../../../global.zig").Output;
|
|
const MutableString = @import("../../../global.zig").MutableString;
|
|
const std = @import("std");
|
|
const Allocator = std.mem.Allocator;
|
|
const IdentityContext = @import("../../../identity_context.zig").IdentityContext;
|
|
const Fs = @import("../../../fs.zig");
|
|
const Resolver = @import("../../../resolver/resolver.zig");
|
|
const ast = @import("../../../import_record.zig");
|
|
const NodeModuleBundle = @import("../../../node_module_bundle.zig").NodeModuleBundle;
|
|
const MacroEntryPoint = @import("../../../bundler.zig").MacroEntryPoint;
|
|
const logger = @import("../../../logger.zig");
|
|
const Api = @import("../../../api/schema.zig").Api;
|
|
const options = @import("../../../options.zig");
|
|
const Bundler = @import("../../../bundler.zig").Bundler;
|
|
const ServerEntryPoint = @import("../../../bundler.zig").ServerEntryPoint;
|
|
const js_printer = @import("../../../js_printer.zig");
|
|
const js_parser = @import("../../../js_parser.zig");
|
|
const js_ast = @import("../../../js_ast.zig");
|
|
const hash_map = @import("../../../hash_map.zig");
|
|
const http = @import("../../../http.zig");
|
|
const NodeFallbackModules = @import("../../../node_fallbacks.zig");
|
|
const ImportKind = ast.ImportKind;
|
|
const Analytics = @import("../../../analytics/analytics_thread.zig");
|
|
const ZigString = @import("../../../jsc.zig").ZigString;
|
|
const Runtime = @import("../../../runtime.zig");
|
|
const Router = @import("./router.zig");
|
|
const ImportRecord = ast.ImportRecord;
|
|
const DotEnv = @import("../../../env_loader.zig");
|
|
const ParseResult = @import("../../../bundler.zig").ParseResult;
|
|
const PackageJSON = @import("../../../resolver/package_json.zig").PackageJSON;
|
|
const MacroRemap = @import("../../../resolver/package_json.zig").MacroMap;
|
|
const WebCore = @import("../../../jsc.zig").WebCore;
|
|
const Request = WebCore.Request;
|
|
const Response = WebCore.Response;
|
|
const Headers = WebCore.Headers;
|
|
const Fetch = WebCore.Fetch;
|
|
const FetchEvent = WebCore.FetchEvent;
|
|
const js = @import("../../../jsc.zig").C;
|
|
const JSC = @import("../../../jsc.zig");
|
|
const JSError = @import("../base.zig").JSError;
|
|
const d = @import("../base.zig").d;
|
|
const MarkedArrayBuffer = @import("../base.zig").MarkedArrayBuffer;
|
|
const getAllocator = @import("../base.zig").getAllocator;
|
|
const JSValue = @import("../../../jsc.zig").JSValue;
|
|
const NewClass = @import("../base.zig").NewClass;
|
|
const Microtask = @import("../../../jsc.zig").Microtask;
|
|
const JSGlobalObject = @import("../../../jsc.zig").JSGlobalObject;
|
|
const ExceptionValueRef = @import("../../../jsc.zig").ExceptionValueRef;
|
|
const JSPrivateDataPtr = @import("../../../jsc.zig").JSPrivateDataPtr;
|
|
const ZigConsoleClient = @import("../../../jsc.zig").ZigConsoleClient;
|
|
const Node = @import("../../../jsc.zig").Node;
|
|
const ZigException = @import("../../../jsc.zig").ZigException;
|
|
const ZigStackTrace = @import("../../../jsc.zig").ZigStackTrace;
|
|
const ErrorableResolvedSource = @import("../../../jsc.zig").ErrorableResolvedSource;
|
|
const ResolvedSource = @import("../../../jsc.zig").ResolvedSource;
|
|
const JSPromise = @import("../../../jsc.zig").JSPromise;
|
|
const JSInternalPromise = @import("../../../jsc.zig").JSInternalPromise;
|
|
const JSModuleLoader = @import("../../../jsc.zig").JSModuleLoader;
|
|
const JSPromiseRejectionOperation = @import("../../../jsc.zig").JSPromiseRejectionOperation;
|
|
const Exception = @import("../../../jsc.zig").Exception;
|
|
const ErrorableZigString = @import("../../../jsc.zig").ErrorableZigString;
|
|
const ZigGlobalObject = @import("../../../jsc.zig").ZigGlobalObject;
|
|
const VM = @import("../../../jsc.zig").VM;
|
|
const JSFunction = @import("../../../jsc.zig").JSFunction;
|
|
const Config = @import("../config.zig");
|
|
const URL = @import("../../../url.zig").URL;
|
|
const Transpiler = @import("./transpiler.zig");
|
|
const VirtualMachine = @import("../javascript.zig").VirtualMachine;
|
|
const IOTask = JSC.IOTask;
|
|
const is_bindgen = JSC.is_bindgen;
|
|
|
|
threadlocal var css_imports_list_strings: [512]ZigString = undefined;
|
|
threadlocal var css_imports_list: [512]Api.StringPointer = undefined;
|
|
threadlocal var css_imports_list_tail: u16 = 0;
|
|
threadlocal var css_imports_buf: std.ArrayList(u8) = undefined;
|
|
threadlocal var css_imports_buf_loaded: bool = false;
|
|
|
|
threadlocal var routes_list_strings: [1024]ZigString = undefined;
|
|
|
|
pub fn onImportCSS(
|
|
resolve_result: *const Resolver.Result,
|
|
import_record: *ImportRecord,
|
|
origin: URL,
|
|
) void {
|
|
if (!css_imports_buf_loaded) {
|
|
css_imports_buf = std.ArrayList(u8).initCapacity(
|
|
VirtualMachine.vm.allocator,
|
|
import_record.path.text.len,
|
|
) catch unreachable;
|
|
css_imports_buf_loaded = true;
|
|
}
|
|
|
|
var writer = css_imports_buf.writer();
|
|
const offset = css_imports_buf.items.len;
|
|
css_imports_list[css_imports_list_tail] = .{
|
|
.offset = @truncate(u32, offset),
|
|
.length = 0,
|
|
};
|
|
getPublicPath(resolve_result.path_pair.primary.text, origin, @TypeOf(writer), writer);
|
|
const length = css_imports_buf.items.len - offset;
|
|
css_imports_list[css_imports_list_tail].length = @truncate(u32, length);
|
|
css_imports_list_tail += 1;
|
|
}
|
|
|
|
pub fn flushCSSImports() void {
|
|
if (css_imports_buf_loaded) {
|
|
css_imports_buf.clearRetainingCapacity();
|
|
css_imports_list_tail = 0;
|
|
}
|
|
}
|
|
|
|
pub fn getCSSImports() []ZigString {
|
|
var i: u16 = 0;
|
|
const tail = css_imports_list_tail;
|
|
while (i < tail) : (i += 1) {
|
|
ZigString.fromStringPointer(css_imports_list[i], css_imports_buf.items, &css_imports_list_strings[i]);
|
|
}
|
|
return css_imports_list_strings[0..tail];
|
|
}
|
|
|
|
pub fn inspect(
|
|
// this
|
|
_: void,
|
|
ctx: js.JSContextRef,
|
|
// function
|
|
_: js.JSObjectRef,
|
|
// thisObject
|
|
_: js.JSObjectRef,
|
|
arguments: []const js.JSValueRef,
|
|
_: js.ExceptionRef,
|
|
) js.JSValueRef {
|
|
if (arguments.len == 0)
|
|
return ZigString.Empty.toValue(ctx.ptr()).asObjectRef();
|
|
|
|
for (arguments) |arg| {
|
|
JSC.C.JSValueProtect(ctx, arg);
|
|
}
|
|
defer {
|
|
for (arguments) |arg| {
|
|
JSC.C.JSValueUnprotect(ctx, arg);
|
|
}
|
|
}
|
|
|
|
// very stable memory address
|
|
var array = MutableString.init(getAllocator(ctx), 0) catch unreachable;
|
|
var buffered_writer_ = MutableString.BufferedWriter{ .context = &array };
|
|
var buffered_writer = &buffered_writer_;
|
|
|
|
var writer = buffered_writer.writer();
|
|
const Writer = @TypeOf(writer);
|
|
// we buffer this because it'll almost always be < 4096
|
|
// when it's under 4096, we want to avoid the dynamic allocation
|
|
ZigConsoleClient.format(
|
|
.Debug,
|
|
ctx.ptr(),
|
|
@ptrCast([*]const JSValue, arguments.ptr),
|
|
arguments.len,
|
|
Writer,
|
|
Writer,
|
|
writer,
|
|
false,
|
|
false,
|
|
false,
|
|
);
|
|
|
|
// when it's a small thing, rely on GC to manage the memory
|
|
if (writer.context.pos < 2048 and array.list.items.len == 0) {
|
|
var slice = writer.context.buffer[0..writer.context.pos];
|
|
if (slice.len == 0) {
|
|
return ZigString.Empty.toValue(ctx.ptr()).asObjectRef();
|
|
}
|
|
|
|
var zig_str = ZigString.init(slice).withEncoding();
|
|
return zig_str.toValueGC(ctx.ptr()).asObjectRef();
|
|
}
|
|
|
|
// when it's a big thing, we will manage it
|
|
{
|
|
writer.context.flush() catch {};
|
|
var slice = writer.context.context.toOwnedSlice();
|
|
|
|
var zig_str = ZigString.init(slice).withEncoding();
|
|
if (!zig_str.isUTF8()) {
|
|
return zig_str.toExternalValue(ctx.ptr()).asObjectRef();
|
|
} else {
|
|
return zig_str.toValueGC(ctx.ptr()).asObjectRef();
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn registerMacro(
|
|
// this
|
|
_: void,
|
|
ctx: js.JSContextRef,
|
|
// function
|
|
_: js.JSObjectRef,
|
|
// thisObject
|
|
_: js.JSObjectRef,
|
|
arguments: []const js.JSValueRef,
|
|
exception: js.ExceptionRef,
|
|
) js.JSValueRef {
|
|
if (arguments.len != 2 or !js.JSValueIsNumber(ctx, arguments[0])) {
|
|
JSError(getAllocator(ctx), "Internal error registering macros: invalid args", .{}, ctx, exception);
|
|
return js.JSValueMakeUndefined(ctx);
|
|
}
|
|
// TODO: make this faster
|
|
const id = @truncate(i32, @floatToInt(i64, js.JSValueToNumber(ctx, arguments[0], exception)));
|
|
if (id == -1 or id == 0) {
|
|
JSError(getAllocator(ctx), "Internal error registering macros: invalid id", .{}, ctx, exception);
|
|
return js.JSValueMakeUndefined(ctx);
|
|
}
|
|
|
|
if (!js.JSValueIsObject(ctx, arguments[1]) or !js.JSObjectIsFunction(ctx, arguments[1])) {
|
|
JSError(getAllocator(ctx), "Macro must be a function. Received: {s}", .{@tagName(js.JSValueGetType(ctx, arguments[1]))}, ctx, exception);
|
|
return js.JSValueMakeUndefined(ctx);
|
|
}
|
|
|
|
var get_or_put_result = VirtualMachine.vm.macros.getOrPut(id) catch unreachable;
|
|
if (get_or_put_result.found_existing) {
|
|
js.JSValueUnprotect(ctx, get_or_put_result.value_ptr.*);
|
|
}
|
|
|
|
js.JSValueProtect(ctx, arguments[1]);
|
|
get_or_put_result.value_ptr.* = arguments[1];
|
|
|
|
return js.JSValueMakeUndefined(ctx);
|
|
}
|
|
|
|
pub fn getCWD(
|
|
_: void,
|
|
ctx: js.JSContextRef,
|
|
_: js.JSValueRef,
|
|
_: js.JSStringRef,
|
|
_: js.ExceptionRef,
|
|
) js.JSValueRef {
|
|
return ZigString.init(VirtualMachine.vm.bundler.fs.top_level_dir).toValue(ctx.ptr()).asRef();
|
|
}
|
|
|
|
pub fn getOrigin(
|
|
_: void,
|
|
ctx: js.JSContextRef,
|
|
_: js.JSValueRef,
|
|
_: js.JSStringRef,
|
|
_: js.ExceptionRef,
|
|
) js.JSValueRef {
|
|
return ZigString.init(VirtualMachine.vm.origin.origin).toValue(ctx.ptr()).asRef();
|
|
}
|
|
|
|
pub fn enableANSIColors(
|
|
_: void,
|
|
ctx: js.JSContextRef,
|
|
_: js.JSValueRef,
|
|
_: js.JSStringRef,
|
|
_: js.ExceptionRef,
|
|
) js.JSValueRef {
|
|
return js.JSValueMakeBoolean(ctx, Output.enable_ansi_colors);
|
|
}
|
|
pub fn getMain(
|
|
_: void,
|
|
ctx: js.JSContextRef,
|
|
_: js.JSValueRef,
|
|
_: js.JSStringRef,
|
|
_: js.ExceptionRef,
|
|
) js.JSValueRef {
|
|
return ZigString.init(VirtualMachine.vm.main).toValue(ctx.ptr()).asRef();
|
|
}
|
|
|
|
pub fn getAssetPrefix(
|
|
_: void,
|
|
ctx: js.JSContextRef,
|
|
_: js.JSValueRef,
|
|
_: js.JSStringRef,
|
|
_: js.ExceptionRef,
|
|
) js.JSValueRef {
|
|
return ZigString.init(VirtualMachine.vm.bundler.options.routes.asset_prefix_path).toValue(ctx.ptr()).asRef();
|
|
}
|
|
|
|
pub fn getArgv(
|
|
_: void,
|
|
ctx: js.JSContextRef,
|
|
_: js.JSValueRef,
|
|
_: js.JSStringRef,
|
|
_: js.ExceptionRef,
|
|
) js.JSValueRef {
|
|
if (comptime Environment.isWindows) {
|
|
@compileError("argv not supported on windows");
|
|
}
|
|
|
|
var argv_list = std.heap.stackFallback(128, getAllocator(ctx));
|
|
var allocator = argv_list.get();
|
|
var argv = allocator.alloc(ZigString, std.os.argv.len) catch unreachable;
|
|
defer if (argv.len > 128) allocator.free(argv);
|
|
for (std.os.argv) |arg, i| {
|
|
argv[i] = ZigString.init(std.mem.span(arg));
|
|
}
|
|
|
|
return JSValue.createStringArray(ctx.ptr(), argv.ptr, argv.len, true).asObjectRef();
|
|
}
|
|
|
|
pub fn getRoutesDir(
|
|
_: void,
|
|
ctx: js.JSContextRef,
|
|
_: js.JSValueRef,
|
|
_: js.JSStringRef,
|
|
_: js.ExceptionRef,
|
|
) js.JSValueRef {
|
|
if (!VirtualMachine.vm.bundler.options.routes.routes_enabled or VirtualMachine.vm.bundler.options.routes.dir.len == 0) {
|
|
return js.JSValueMakeUndefined(ctx);
|
|
}
|
|
|
|
return ZigString.init(VirtualMachine.vm.bundler.options.routes.dir).toValue(ctx.ptr()).asRef();
|
|
}
|
|
|
|
pub fn getFilePath(ctx: js.JSContextRef, arguments: []const js.JSValueRef, buf: []u8, exception: js.ExceptionRef) ?string {
|
|
if (arguments.len != 1) {
|
|
JSError(getAllocator(ctx), "Expected a file path as a string or an array of strings to be part of a file path.", .{}, ctx, exception);
|
|
return null;
|
|
}
|
|
|
|
const value = arguments[0];
|
|
if (js.JSValueIsString(ctx, value)) {
|
|
var out = ZigString.Empty;
|
|
JSValue.toZigString(JSValue.fromRef(value), &out, ctx.ptr());
|
|
var out_slice = out.slice();
|
|
|
|
// The dots are kind of unnecessary. They'll be normalized.
|
|
if (out.len == 0 or @ptrToInt(out.ptr) == 0 or std.mem.eql(u8, out_slice, ".") or std.mem.eql(u8, out_slice, "..") or std.mem.eql(u8, out_slice, "../")) {
|
|
JSError(getAllocator(ctx), "Expected a file path as a string or an array of strings to be part of a file path.", .{}, ctx, exception);
|
|
return null;
|
|
}
|
|
|
|
var parts = [_]string{out_slice};
|
|
// This does the equivalent of Node's path.normalize(path.join(cwd, out_slice))
|
|
var res = VirtualMachine.vm.bundler.fs.absBuf(&parts, buf);
|
|
|
|
return res;
|
|
} else if (js.JSValueIsArray(ctx, value)) {
|
|
var temp_strings_list: [32]string = undefined;
|
|
var temp_strings_list_len: u8 = 0;
|
|
defer {
|
|
for (temp_strings_list[0..temp_strings_list_len]) |_, i| {
|
|
temp_strings_list[i] = "";
|
|
}
|
|
}
|
|
|
|
var iter = JSValue.fromRef(value).arrayIterator(ctx.ptr());
|
|
while (iter.next()) |item| {
|
|
if (temp_strings_list_len >= temp_strings_list.len) {
|
|
break;
|
|
}
|
|
|
|
if (!item.isString()) {
|
|
JSError(getAllocator(ctx), "Expected a file path as a string or an array of strings to be part of a file path.", .{}, ctx, exception);
|
|
return null;
|
|
}
|
|
|
|
var out = ZigString.Empty;
|
|
JSValue.toZigString(item, &out, ctx.ptr());
|
|
const out_slice = out.slice();
|
|
|
|
temp_strings_list[temp_strings_list_len] = out_slice;
|
|
// The dots are kind of unnecessary. They'll be normalized.
|
|
if (out.len == 0 or @ptrToInt(out.ptr) == 0 or std.mem.eql(u8, out_slice, ".") or std.mem.eql(u8, out_slice, "..") or std.mem.eql(u8, out_slice, "../")) {
|
|
JSError(getAllocator(ctx), "Expected a file path as a string or an array of strings to be part of a file path.", .{}, ctx, exception);
|
|
return null;
|
|
}
|
|
temp_strings_list_len += 1;
|
|
}
|
|
|
|
if (temp_strings_list_len == 0) {
|
|
JSError(getAllocator(ctx), "Expected a file path as a string or an array of strings to be part of a file path.", .{}, ctx, exception);
|
|
return null;
|
|
}
|
|
|
|
return VirtualMachine.vm.bundler.fs.absBuf(temp_strings_list[0..temp_strings_list_len], buf);
|
|
} else {
|
|
JSError(getAllocator(ctx), "Expected a file path as a string or an array of strings to be part of a file path.", .{}, ctx, exception);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
pub fn getImportedStyles(
|
|
_: void,
|
|
ctx: js.JSContextRef,
|
|
_: js.JSObjectRef,
|
|
_: js.JSObjectRef,
|
|
_: []const js.JSValueRef,
|
|
_: js.ExceptionRef,
|
|
) js.JSValueRef {
|
|
defer flushCSSImports();
|
|
const styles = getCSSImports();
|
|
if (styles.len == 0) {
|
|
return js.JSObjectMakeArray(ctx, 0, null, null);
|
|
}
|
|
|
|
return JSValue.createStringArray(ctx.ptr(), styles.ptr, styles.len, true).asRef();
|
|
}
|
|
|
|
pub fn newPath(
|
|
_: void,
|
|
ctx: js.JSContextRef,
|
|
_: js.JSObjectRef,
|
|
_: js.JSObjectRef,
|
|
args: []const js.JSValueRef,
|
|
_: js.ExceptionRef,
|
|
) js.JSValueRef {
|
|
const is_windows = args.len == 1 and JSValue.fromRef(args[0]).toBoolean();
|
|
return Node.Path.create(ctx.ptr(), is_windows).asObjectRef();
|
|
}
|
|
|
|
pub fn readFileAsStringCallback(
|
|
ctx: js.JSContextRef,
|
|
buf_z: [:0]const u8,
|
|
exception: js.ExceptionRef,
|
|
) js.JSValueRef {
|
|
const path = buf_z.ptr[0..buf_z.len];
|
|
var file = std.fs.cwd().openFileZ(buf_z, .{ .mode = .read_only }) catch |err| {
|
|
JSError(getAllocator(ctx), "Opening file {s} for path: \"{s}\"", .{ @errorName(err), path }, ctx, exception);
|
|
return js.JSValueMakeUndefined(ctx);
|
|
};
|
|
|
|
defer file.close();
|
|
|
|
const stat = file.stat() catch |err| {
|
|
JSError(getAllocator(ctx), "Getting file size {s} for \"{s}\"", .{ @errorName(err), path }, ctx, exception);
|
|
return js.JSValueMakeUndefined(ctx);
|
|
};
|
|
|
|
if (stat.kind != .File) {
|
|
JSError(getAllocator(ctx), "Can't read a {s} as a string (\"{s}\")", .{ @tagName(stat.kind), path }, ctx, exception);
|
|
return js.JSValueMakeUndefined(ctx);
|
|
}
|
|
|
|
var contents_buf = VirtualMachine.vm.allocator.alloc(u8, stat.size + 2) catch unreachable; // OOM
|
|
defer VirtualMachine.vm.allocator.free(contents_buf);
|
|
const contents_len = file.readAll(contents_buf) catch |err| {
|
|
JSError(getAllocator(ctx), "{s} reading file (\"{s}\")", .{ @errorName(err), path }, ctx, exception);
|
|
return js.JSValueMakeUndefined(ctx);
|
|
};
|
|
|
|
contents_buf[contents_len] = 0;
|
|
|
|
// Very slow to do it this way. We're copying the string twice.
|
|
// But it's important that this string is garbage collected instead of manually managed.
|
|
// We can't really recycle this one.
|
|
// TODO: use external string
|
|
return js.JSValueMakeString(ctx, js.JSStringCreateWithUTF8CString(contents_buf.ptr));
|
|
}
|
|
|
|
pub fn readFileAsBytesCallback(
|
|
ctx: js.JSContextRef,
|
|
buf_z: [:0]const u8,
|
|
exception: js.ExceptionRef,
|
|
) js.JSValueRef {
|
|
const path = buf_z.ptr[0..buf_z.len];
|
|
|
|
var file = std.fs.cwd().openFileZ(buf_z, .{ .mode = .read_only }) catch |err| {
|
|
JSError(getAllocator(ctx), "Opening file {s} for path: \"{s}\"", .{ @errorName(err), path }, ctx, exception);
|
|
return js.JSValueMakeUndefined(ctx);
|
|
};
|
|
|
|
defer file.close();
|
|
|
|
const stat = file.stat() catch |err| {
|
|
JSError(getAllocator(ctx), "Getting file size {s} for \"{s}\"", .{ @errorName(err), path }, ctx, exception);
|
|
return js.JSValueMakeUndefined(ctx);
|
|
};
|
|
|
|
if (stat.kind != .File) {
|
|
JSError(getAllocator(ctx), "Can't read a {s} as a string (\"{s}\")", .{ @tagName(stat.kind), path }, ctx, exception);
|
|
return js.JSValueMakeUndefined(ctx);
|
|
}
|
|
|
|
var contents_buf = VirtualMachine.vm.allocator.alloc(u8, stat.size + 2) catch unreachable; // OOM
|
|
errdefer VirtualMachine.vm.allocator.free(contents_buf);
|
|
const contents_len = file.readAll(contents_buf) catch |err| {
|
|
JSError(getAllocator(ctx), "{s} reading file (\"{s}\")", .{ @errorName(err), path }, ctx, exception);
|
|
return js.JSValueMakeUndefined(ctx);
|
|
};
|
|
|
|
contents_buf[contents_len] = 0;
|
|
|
|
var marked_array_buffer = VirtualMachine.vm.allocator.create(MarkedArrayBuffer) catch unreachable;
|
|
marked_array_buffer.* = MarkedArrayBuffer.fromBytes(
|
|
contents_buf[0..contents_len],
|
|
VirtualMachine.vm.allocator,
|
|
.Uint8Array,
|
|
);
|
|
|
|
return marked_array_buffer.toJSObjectRef(ctx, exception);
|
|
}
|
|
|
|
pub fn getRouteFiles(
|
|
_: void,
|
|
ctx: js.JSContextRef,
|
|
_: js.JSObjectRef,
|
|
_: js.JSObjectRef,
|
|
_: []const js.JSValueRef,
|
|
_: js.ExceptionRef,
|
|
) js.JSValueRef {
|
|
if (VirtualMachine.vm.bundler.router == null) return js.JSObjectMakeArray(ctx, 0, null, null);
|
|
|
|
const router = &VirtualMachine.vm.bundler.router.?;
|
|
const list = router.getPublicPaths() catch unreachable;
|
|
|
|
for (routes_list_strings[0..@minimum(list.len, routes_list_strings.len)]) |_, i| {
|
|
routes_list_strings[i] = ZigString.init(list[i]);
|
|
}
|
|
|
|
const ref = JSValue.createStringArray(ctx.ptr(), &routes_list_strings, list.len, true).asRef();
|
|
return ref;
|
|
}
|
|
|
|
pub fn getRouteNames(
|
|
_: void,
|
|
ctx: js.JSContextRef,
|
|
_: js.JSObjectRef,
|
|
_: js.JSObjectRef,
|
|
_: []const js.JSValueRef,
|
|
_: js.ExceptionRef,
|
|
) js.JSValueRef {
|
|
if (VirtualMachine.vm.bundler.router == null) return js.JSObjectMakeArray(ctx, 0, null, null);
|
|
|
|
const router = &VirtualMachine.vm.bundler.router.?;
|
|
const list = router.getNames() catch unreachable;
|
|
|
|
for (routes_list_strings[0..@minimum(list.len, routes_list_strings.len)]) |_, i| {
|
|
routes_list_strings[i] = ZigString.init(list[i]);
|
|
}
|
|
|
|
const ref = JSValue.createStringArray(ctx.ptr(), &routes_list_strings, list.len, true).asRef();
|
|
return ref;
|
|
}
|
|
|
|
pub fn readFileAsBytes(
|
|
_: void,
|
|
ctx: js.JSContextRef,
|
|
_: js.JSObjectRef,
|
|
_: js.JSObjectRef,
|
|
arguments: []const js.JSValueRef,
|
|
exception: js.ExceptionRef,
|
|
) js.JSValueRef {
|
|
var buf: [bun.MAX_PATH_BYTES]u8 = undefined;
|
|
const path = getFilePath(ctx, arguments, &buf, exception) orelse return null;
|
|
buf[path.len] = 0;
|
|
|
|
const buf_z: [:0]const u8 = buf[0..path.len :0];
|
|
const result = readFileAsBytesCallback(ctx, buf_z, exception);
|
|
return result;
|
|
}
|
|
|
|
pub fn readFileAsString(
|
|
_: void,
|
|
ctx: js.JSContextRef,
|
|
_: js.JSObjectRef,
|
|
_: js.JSObjectRef,
|
|
arguments: []const js.JSValueRef,
|
|
exception: js.ExceptionRef,
|
|
) js.JSValueRef {
|
|
var buf: [bun.MAX_PATH_BYTES]u8 = undefined;
|
|
const path = getFilePath(ctx, arguments, &buf, exception) orelse return null;
|
|
buf[path.len] = 0;
|
|
|
|
const buf_z: [:0]const u8 = buf[0..path.len :0];
|
|
const result = readFileAsStringCallback(ctx, buf_z, exception);
|
|
return result;
|
|
}
|
|
|
|
pub fn getPublicPath(to: string, origin: URL, comptime Writer: type, writer: Writer) void {
|
|
const relative_path = VirtualMachine.vm.bundler.fs.relativeTo(to);
|
|
if (origin.isAbsolute()) {
|
|
if (strings.hasPrefix(relative_path, "..") or strings.hasPrefix(relative_path, "./")) {
|
|
writer.writeAll(origin.origin) catch return;
|
|
writer.writeAll("/abs:") catch return;
|
|
if (std.fs.path.isAbsolute(to)) {
|
|
writer.writeAll(to) catch return;
|
|
} else {
|
|
writer.writeAll(VirtualMachine.vm.bundler.fs.abs(&[_]string{to})) catch return;
|
|
}
|
|
} else {
|
|
origin.joinWrite(
|
|
Writer,
|
|
writer,
|
|
VirtualMachine.vm.bundler.options.routes.asset_prefix_path,
|
|
"",
|
|
relative_path,
|
|
"",
|
|
) catch return;
|
|
}
|
|
} else {
|
|
writer.writeAll(std.mem.trimLeft(u8, relative_path, "/")) catch unreachable;
|
|
}
|
|
}
|
|
|
|
pub fn sleepSync(
|
|
_: void,
|
|
ctx: js.JSContextRef,
|
|
_: js.JSObjectRef,
|
|
_: js.JSObjectRef,
|
|
arguments: []const js.JSValueRef,
|
|
_: js.ExceptionRef,
|
|
) js.JSValueRef {
|
|
if (js.JSValueIsNumber(ctx, arguments[0])) {
|
|
const seconds = JSValue.fromRef(arguments[0]).asNumber();
|
|
if (seconds > 0 and std.math.isFinite(seconds)) std.time.sleep(@floatToInt(u64, seconds * 1000) * std.time.ns_per_ms);
|
|
}
|
|
|
|
return js.JSValueMakeUndefined(ctx);
|
|
}
|
|
|
|
pub fn createNodeFS(
|
|
_: void,
|
|
ctx: js.JSContextRef,
|
|
_: js.JSObjectRef,
|
|
_: js.JSObjectRef,
|
|
_: []const js.JSValueRef,
|
|
_: js.ExceptionRef,
|
|
) js.JSValueRef {
|
|
return Node.NodeFSBindings.make(
|
|
ctx,
|
|
VirtualMachine.vm.node_fs orelse brk: {
|
|
VirtualMachine.vm.node_fs = bun.default_allocator.create(Node.NodeFS) catch unreachable;
|
|
VirtualMachine.vm.node_fs.?.* = Node.NodeFS{ .async_io = undefined };
|
|
break :brk VirtualMachine.vm.node_fs.?;
|
|
},
|
|
);
|
|
}
|
|
|
|
pub fn generateHeapSnapshot(
|
|
_: void,
|
|
ctx: js.JSContextRef,
|
|
_: js.JSObjectRef,
|
|
_: js.JSObjectRef,
|
|
_: []const js.JSValueRef,
|
|
_: js.ExceptionRef,
|
|
) js.JSValueRef {
|
|
return ctx.ptr().generateHeapSnapshot().asObjectRef();
|
|
}
|
|
|
|
pub fn runGC(
|
|
_: void,
|
|
ctx: js.JSContextRef,
|
|
_: js.JSObjectRef,
|
|
_: js.JSObjectRef,
|
|
arguments: []const js.JSValueRef,
|
|
_: js.ExceptionRef,
|
|
) js.JSValueRef {
|
|
// it should only force cleanup on thread exit
|
|
|
|
Global.mimalloc_cleanup(false);
|
|
|
|
return ctx.ptr().vm().runGC(arguments.len > 0 and JSValue.fromRef(arguments[0]).toBoolean()).asRef();
|
|
}
|
|
|
|
pub fn shrink(
|
|
_: void,
|
|
ctx: js.JSContextRef,
|
|
_: js.JSObjectRef,
|
|
_: js.JSObjectRef,
|
|
_: []const js.JSValueRef,
|
|
_: js.ExceptionRef,
|
|
) js.JSValueRef {
|
|
ctx.ptr().vm().shrinkFootprint();
|
|
return JSValue.jsUndefined().asRef();
|
|
}
|
|
|
|
fn doResolve(
|
|
ctx: js.JSContextRef,
|
|
arguments: []const js.JSValueRef,
|
|
exception: js.ExceptionRef,
|
|
) ?JSC.JSValue {
|
|
var args = JSC.Node.ArgumentsSlice.from(arguments);
|
|
const specifier = args.nextEat() orelse {
|
|
JSC.throwInvalidArguments("Expected a specifier and a from path", .{}, ctx, exception);
|
|
return null;
|
|
};
|
|
|
|
if (specifier.isUndefinedOrNull()) {
|
|
JSC.throwInvalidArguments("specifier must be a string", .{}, ctx, exception);
|
|
return null;
|
|
}
|
|
|
|
const from = args.nextEat() orelse {
|
|
JSC.throwInvalidArguments("Expected a from path", .{}, ctx, exception);
|
|
return null;
|
|
};
|
|
|
|
if (from.isUndefinedOrNull()) {
|
|
JSC.throwInvalidArguments("from must be a string", .{}, ctx, exception);
|
|
return null;
|
|
}
|
|
|
|
return doResolveWithArgs(ctx, specifier.getZigString(ctx.ptr()), from.getZigString(ctx.ptr()), exception, false);
|
|
}
|
|
|
|
fn doResolveWithArgs(
|
|
ctx: js.JSContextRef,
|
|
specifier: ZigString,
|
|
from: ZigString,
|
|
exception: js.ExceptionRef,
|
|
comptime is_file_path: bool,
|
|
) ?JSC.JSValue {
|
|
var errorable: ErrorableZigString = undefined;
|
|
|
|
if (comptime is_file_path) {
|
|
VirtualMachine.resolve(
|
|
&errorable,
|
|
ctx.ptr(),
|
|
specifier,
|
|
from,
|
|
);
|
|
} else {
|
|
VirtualMachine.resolveForAPI(
|
|
&errorable,
|
|
ctx.ptr(),
|
|
specifier,
|
|
from,
|
|
);
|
|
}
|
|
|
|
if (!errorable.success) {
|
|
exception.* = bun.cast(JSC.JSValueRef, errorable.result.err.ptr.?);
|
|
return null;
|
|
}
|
|
|
|
return errorable.result.value.toValue(ctx.ptr());
|
|
}
|
|
|
|
pub fn resolveSync(
|
|
_: void,
|
|
ctx: js.JSContextRef,
|
|
_: js.JSObjectRef,
|
|
_: js.JSObjectRef,
|
|
arguments: []const js.JSValueRef,
|
|
exception: js.ExceptionRef,
|
|
) js.JSValueRef {
|
|
const value = doResolve(ctx, arguments, exception) orelse return null;
|
|
return value.asObjectRef();
|
|
}
|
|
|
|
pub fn resolve(
|
|
_: void,
|
|
ctx: js.JSContextRef,
|
|
_: js.JSObjectRef,
|
|
_: js.JSObjectRef,
|
|
arguments: []const js.JSValueRef,
|
|
exception: js.ExceptionRef,
|
|
) js.JSValueRef {
|
|
const value = doResolve(ctx, arguments, exception) orelse {
|
|
var exception_value = exception.*.?;
|
|
exception.* = null;
|
|
return JSC.JSPromise.rejectedPromiseValue(ctx.ptr(), JSC.JSValue.fromRef(exception_value)).asObjectRef();
|
|
};
|
|
return JSC.JSPromise.resolvedPromiseValue(ctx.ptr(), value).asObjectRef();
|
|
}
|
|
|
|
export fn Bun__resolve(
|
|
global: *JSGlobalObject,
|
|
specifier: JSValue,
|
|
source: JSValue,
|
|
) JSC.JSValue {
|
|
var exception_ = [1]JSC.JSValueRef{null};
|
|
var exception = &exception_;
|
|
const value = doResolveWithArgs(global.ref(), specifier.getZigString(global), source.getZigString(global), exception, true) orelse {
|
|
return JSC.JSPromise.rejectedPromiseValue(global, JSC.JSValue.fromRef(exception[0]));
|
|
};
|
|
return JSC.JSPromise.resolvedPromiseValue(global, value);
|
|
}
|
|
|
|
comptime {
|
|
if (!is_bindgen) {
|
|
_ = Bun__resolve;
|
|
}
|
|
}
|
|
|
|
pub fn readAllStdinSync(
|
|
_: void,
|
|
ctx: js.JSContextRef,
|
|
_: js.JSObjectRef,
|
|
_: js.JSObjectRef,
|
|
_: []const js.JSValueRef,
|
|
exception: js.ExceptionRef,
|
|
) js.JSValueRef {
|
|
var stack = std.heap.stackFallback(2048, getAllocator(ctx));
|
|
var allocator = stack.get();
|
|
|
|
var stdin = std.io.getStdIn();
|
|
var result = stdin.readToEndAlloc(allocator, std.math.maxInt(u32)) catch |err| {
|
|
JSError(undefined, "{s} reading stdin", .{@errorName(err)}, ctx, exception);
|
|
return null;
|
|
};
|
|
var out = ZigString.init(result);
|
|
out.detectEncoding();
|
|
return out.toValueGC(ctx.ptr()).asObjectRef();
|
|
}
|
|
|
|
var public_path_temp_str: [bun.MAX_PATH_BYTES]u8 = undefined;
|
|
|
|
pub fn getPublicPathJS(
|
|
_: void,
|
|
ctx: js.JSContextRef,
|
|
_: js.JSObjectRef,
|
|
_: js.JSObjectRef,
|
|
arguments: []const js.JSValueRef,
|
|
_: js.ExceptionRef,
|
|
) js.JSValueRef {
|
|
var zig_str: ZigString = ZigString.Empty;
|
|
JSValue.toZigString(JSValue.fromRef(arguments[0]), &zig_str, ctx.ptr());
|
|
|
|
const to = zig_str.slice();
|
|
|
|
var stream = std.io.fixedBufferStream(&public_path_temp_str);
|
|
var writer = stream.writer();
|
|
getPublicPath(to, VirtualMachine.vm.origin, @TypeOf(&writer), &writer);
|
|
|
|
return ZigString.init(stream.buffer[0..stream.pos]).toValueGC(ctx.ptr()).asObjectRef();
|
|
}
|
|
|
|
pub const Class = NewClass(
|
|
void,
|
|
.{
|
|
.name = "Bun",
|
|
.read_only = true,
|
|
.ts = .{
|
|
.module = .{
|
|
.path = "bun.js/router",
|
|
.tsdoc = "Filesystem Router supporting dynamic routes, exact routes, catch-all routes, and optional catch-all routes. Implemented in native code and only available with Bun.js.",
|
|
},
|
|
},
|
|
},
|
|
.{
|
|
.match = .{
|
|
.rfn = Router.match,
|
|
.ts = Router.match_type_definition,
|
|
},
|
|
|
|
.sleepSync = .{
|
|
.rfn = sleepSync,
|
|
},
|
|
.fetch = .{
|
|
.rfn = Fetch.call,
|
|
.ts = d.ts{},
|
|
},
|
|
.getImportedStyles = .{
|
|
.rfn = Bun.getImportedStyles,
|
|
.ts = d.ts{
|
|
.name = "getImportedStyles",
|
|
.@"return" = "string[]",
|
|
},
|
|
},
|
|
.inspect = .{
|
|
.rfn = Bun.inspect,
|
|
.ts = d.ts{
|
|
.name = "inspect",
|
|
.@"return" = "string",
|
|
},
|
|
},
|
|
.getRouteFiles = .{
|
|
.rfn = Bun.getRouteFiles,
|
|
.ts = d.ts{
|
|
.name = "getRouteFiles",
|
|
.@"return" = "string[]",
|
|
},
|
|
},
|
|
._Path = .{
|
|
.rfn = Bun.newPath,
|
|
.ts = d.ts{},
|
|
},
|
|
.getRouteNames = .{
|
|
.rfn = Bun.getRouteNames,
|
|
.ts = d.ts{
|
|
.name = "getRouteNames",
|
|
.@"return" = "string[]",
|
|
},
|
|
},
|
|
.readFile = .{
|
|
.rfn = Bun.readFileAsString,
|
|
.ts = d.ts{
|
|
.name = "readFile",
|
|
.@"return" = "string",
|
|
},
|
|
},
|
|
.resolveSync = .{
|
|
.rfn = Bun.resolveSync,
|
|
.ts = d.ts{
|
|
.name = "resolveSync",
|
|
.@"return" = "string",
|
|
},
|
|
},
|
|
.resolve = .{
|
|
.rfn = Bun.resolve,
|
|
.ts = d.ts{
|
|
.name = "resolve",
|
|
.@"return" = "string",
|
|
},
|
|
},
|
|
.readFileBytes = .{
|
|
.rfn = Bun.readFileAsBytes,
|
|
.ts = d.ts{
|
|
.name = "readFile",
|
|
.@"return" = "Uint8Array",
|
|
},
|
|
},
|
|
.getPublicPath = .{
|
|
.rfn = Bun.getPublicPathJS,
|
|
.ts = d.ts{
|
|
.name = "getPublicPath",
|
|
.@"return" = "string",
|
|
},
|
|
},
|
|
.registerMacro = .{
|
|
.rfn = Bun.registerMacro,
|
|
.ts = d.ts{
|
|
.name = "registerMacro",
|
|
.@"return" = "undefined",
|
|
},
|
|
.enumerable = false,
|
|
},
|
|
.fs = .{
|
|
.rfn = Bun.createNodeFS,
|
|
.ts = d.ts{},
|
|
.enumerable = false,
|
|
},
|
|
.jest = .{
|
|
.rfn = @import("../test/jest.zig").Jest.call,
|
|
.ts = d.ts{},
|
|
.enumerable = false,
|
|
},
|
|
.gc = .{
|
|
.rfn = Bun.runGC,
|
|
.ts = d.ts{},
|
|
},
|
|
.allocUnsafe = .{
|
|
.rfn = Bun.allocUnsafe,
|
|
.ts = .{},
|
|
},
|
|
.generateHeapSnapshot = .{
|
|
.rfn = Bun.generateHeapSnapshot,
|
|
.ts = d.ts{},
|
|
},
|
|
.shrink = .{
|
|
.rfn = Bun.shrink,
|
|
.ts = d.ts{},
|
|
},
|
|
.readAllStdinSync = .{
|
|
.rfn = Bun.readAllStdinSync,
|
|
.ts = d.ts{},
|
|
},
|
|
.startServer = .{
|
|
.rfn = Bun.startServer,
|
|
.ts = d.ts{},
|
|
},
|
|
.file = .{
|
|
.rfn = JSC.WebCore.Blob.constructFile,
|
|
.ts = d.ts{},
|
|
},
|
|
},
|
|
.{
|
|
.main = .{
|
|
.get = getMain,
|
|
.ts = d.ts{ .name = "main", .@"return" = "string" },
|
|
},
|
|
.cwd = .{
|
|
.get = getCWD,
|
|
.ts = d.ts{ .name = "cwd", .@"return" = "string" },
|
|
},
|
|
.origin = .{
|
|
.get = getOrigin,
|
|
.ts = d.ts{ .name = "origin", .@"return" = "string" },
|
|
},
|
|
.routesDir = .{
|
|
.get = getRoutesDir,
|
|
.ts = d.ts{ .name = "routesDir", .@"return" = "string" },
|
|
},
|
|
.assetPrefix = .{
|
|
.get = getAssetPrefix,
|
|
.ts = d.ts{ .name = "assetPrefix", .@"return" = "string" },
|
|
},
|
|
.argv = .{
|
|
.get = getArgv,
|
|
.ts = d.ts{ .name = "argv", .@"return" = "string[]" },
|
|
},
|
|
.env = .{
|
|
.get = EnvironmentVariables.getter,
|
|
},
|
|
|
|
.enableANSIColors = .{
|
|
.get = enableANSIColors,
|
|
},
|
|
.Transpiler = .{
|
|
.get = getTranspilerConstructor,
|
|
.ts = d.ts{ .name = "Transpiler", .@"return" = "Transpiler.prototype" },
|
|
},
|
|
.TOML = .{
|
|
.get = getTOMLObject,
|
|
.ts = d.ts{ .name = "TOML", .@"return" = "TOML.prototype" },
|
|
},
|
|
.unsafe = .{
|
|
.get = getUnsafe,
|
|
},
|
|
},
|
|
);
|
|
|
|
pub fn startServer(
|
|
_: void,
|
|
ctx: js.JSContextRef,
|
|
_: js.JSObjectRef,
|
|
_: js.JSObjectRef,
|
|
arguments: []const js.JSValueRef,
|
|
_: js.ExceptionRef,
|
|
) js.JSValueRef {
|
|
var vm = JSC.VirtualMachine.vm;
|
|
const handler = if (arguments.len > 0) JSC.JSValue.fromRef(arguments[0]) else JSC.JSValue.zero;
|
|
if (handler.isEmpty() or handler.isUndefinedOrNull() or !handler.isCell() or !handler.isCallable(ctx.ptr().vm())) {
|
|
Output.prettyWarnln("\"serverless\" export should be a function", .{});
|
|
Output.flush();
|
|
return JSC.JSValue.jsUndefined().asObjectRef();
|
|
}
|
|
|
|
JSC.C.JSValueProtect(ctx.ptr().ref(), handler.asObjectRef());
|
|
var server = JSC.API.Server.init(vm.bundler.options.origin.getPortAuto(), handler, ctx.ptr());
|
|
server.listen();
|
|
return JSC.JSValue.jsUndefined().asObjectRef();
|
|
}
|
|
|
|
pub fn allocUnsafe(
|
|
_: void,
|
|
ctx: js.JSContextRef,
|
|
_: js.JSObjectRef,
|
|
_: js.JSObjectRef,
|
|
arguments: []const js.JSValueRef,
|
|
exception: js.ExceptionRef,
|
|
) js.JSValueRef {
|
|
var args = JSC.Node.ArgumentsSlice.from(arguments);
|
|
|
|
const length = @intCast(
|
|
usize,
|
|
@minimum(
|
|
@maximum(1, (args.nextEat() orelse JSC.JSValue.jsNumber(@as(i32, 1))).toInt32()),
|
|
std.math.maxInt(i32),
|
|
),
|
|
);
|
|
var bytes = bun.default_allocator.alloc(u8, length) catch {
|
|
JSC.JSError(bun.default_allocator, "OOM! Out of memory", .{}, ctx, exception);
|
|
return null;
|
|
};
|
|
|
|
return JSC.MarkedArrayBuffer.fromBytes(
|
|
bytes,
|
|
bun.default_allocator,
|
|
.Uint8Array,
|
|
).toJSObjectRef(ctx, null);
|
|
}
|
|
|
|
pub fn getTranspilerConstructor(
|
|
_: void,
|
|
ctx: js.JSContextRef,
|
|
_: js.JSValueRef,
|
|
_: js.JSStringRef,
|
|
_: js.ExceptionRef,
|
|
) js.JSValueRef {
|
|
return Transpiler.Constructor.constructor(ctx);
|
|
}
|
|
|
|
pub fn getTOMLObject(
|
|
_: void,
|
|
ctx: js.JSContextRef,
|
|
_: js.JSValueRef,
|
|
_: js.JSStringRef,
|
|
_: js.ExceptionRef,
|
|
) js.JSValueRef {
|
|
return js.JSObjectMake(ctx, TOML.Class.get().?[0], null);
|
|
}
|
|
|
|
pub fn getUnsafe(
|
|
_: void,
|
|
ctx: js.JSContextRef,
|
|
_: js.JSValueRef,
|
|
_: js.JSStringRef,
|
|
_: js.ExceptionRef,
|
|
) js.JSValueRef {
|
|
return js.JSObjectMake(ctx, Unsafe.Class.get().?[0], null);
|
|
}
|
|
|
|
pub const Unsafe = struct {
|
|
pub const Class = NewClass(
|
|
void,
|
|
.{ .name = "Unsafe", .read_only = true },
|
|
.{
|
|
.segfault = .{
|
|
.rfn = __debug__doSegfault,
|
|
},
|
|
.arrayBufferToString = .{
|
|
.rfn = arrayBufferToString,
|
|
},
|
|
},
|
|
.{},
|
|
);
|
|
|
|
// For testing the segfault handler
|
|
pub fn __debug__doSegfault(
|
|
_: void,
|
|
ctx: js.JSContextRef,
|
|
_: js.JSObjectRef,
|
|
_: js.JSObjectRef,
|
|
_: []const js.JSValueRef,
|
|
_: js.ExceptionRef,
|
|
) js.JSValueRef {
|
|
_ = ctx;
|
|
const Reporter = @import("../../../report.zig");
|
|
Reporter.globalError(error.SegfaultTest);
|
|
}
|
|
|
|
pub fn arrayBufferToString(
|
|
_: void,
|
|
ctx: js.JSContextRef,
|
|
_: js.JSObjectRef,
|
|
_: js.JSObjectRef,
|
|
args: []const js.JSValueRef,
|
|
exception: js.ExceptionRef,
|
|
) js.JSValueRef {
|
|
const array_buffer = JSC.ArrayBuffer.fromTypedArray(ctx, JSC.JSValue.fromRef(args[0]), exception);
|
|
switch (array_buffer.typed_array_type) {
|
|
.Uint16Array, .Int16Array => {
|
|
var zig_str = ZigString.init("");
|
|
zig_str.ptr = @ptrCast([*]const u8, @alignCast(@alignOf([*]align(1) const u16), array_buffer.ptr));
|
|
zig_str.len = array_buffer.len;
|
|
zig_str.markUTF16();
|
|
return ZigString.toValue(&zig_str, ctx.ptr()).asObjectRef();
|
|
},
|
|
else => {
|
|
return ZigString.init(array_buffer.slice()).toValue(ctx.ptr()).asObjectRef();
|
|
},
|
|
}
|
|
}
|
|
};
|
|
|
|
// pub const Lockfile = struct {
|
|
// const BunLockfile = @import("../../../install/install.zig").Lockfile;
|
|
// lockfile: *BunLockfile,
|
|
|
|
// pub const RefCountedLockfile = bun.RefCount(Lockfile, true);
|
|
|
|
// pub const StaticClass = NewClass(
|
|
// void,
|
|
// .{
|
|
// .name = "Lockfile",
|
|
// .read_only = true,
|
|
// },
|
|
// .{
|
|
// .load = .{
|
|
// .rfn = BunLockfile.load,
|
|
// },
|
|
// },
|
|
// .{},
|
|
// );
|
|
|
|
// pub const Class = NewClass(
|
|
// RefCountedLockfile,
|
|
// .{
|
|
// .name = "Lockfile",
|
|
// .read_only = true,
|
|
// },
|
|
// .{
|
|
// .findPackagesByName = .{
|
|
// .rfn = BunLockfile.load,
|
|
// },
|
|
// .dependencies = .{
|
|
// .rfn = BunLockfile.load,
|
|
// },
|
|
// },
|
|
// .{},
|
|
// );
|
|
|
|
// pub fn deinit(this: *Lockfile) void {
|
|
// this.lockfile.deinit();
|
|
// }
|
|
|
|
// pub fn load(
|
|
// // this
|
|
// _: void,
|
|
// ctx: js.JSContextRef,
|
|
// // function
|
|
// _: js.JSObjectRef,
|
|
// // thisObject
|
|
// _: js.JSObjectRef,
|
|
// arguments: []const js.JSValueRef,
|
|
// exception: js.ExceptionRef,
|
|
// ) js.JSValueRef {
|
|
// if (arguments.len == 0) {
|
|
// JSError(undefined, "Expected file path string or buffer", .{}, ctx, exception);
|
|
// return null;
|
|
// }
|
|
|
|
// var lockfile: *BunLockfile = getAllocator(ctx).create(BunLockfile) catch return JSValue.jsUndefined().asRef();
|
|
|
|
// var log = logger.Log.init(default_allocator);
|
|
// var args_slice = @ptrCast([*]const JSValue, arguments.ptr)[0..arguments.len];
|
|
|
|
// var arguments_slice = Node.ArgumentsSlice.init(args_slice);
|
|
// var path_or_buffer = Node.PathLike.fromJS(ctx, &arguments_slice, exception) orelse {
|
|
// getAllocator(ctx).destroy(lockfile);
|
|
// JSError(undefined, "Expected file path string or buffer", .{}, ctx, exception);
|
|
// return null;
|
|
// };
|
|
|
|
// const load_from_disk_result = switch (path_or_buffer) {
|
|
// Node.PathLike.Tag.string => lockfile.loadFromDisk(getAllocator(ctx), &log, path_or_buffer.string),
|
|
// Node.PathLike.Tag.buffer => lockfile.loadFromBytes(getAllocator(ctx), path_or_buffer.buffer.slice(), &log),
|
|
// else => {
|
|
// getAllocator(ctx).destroy(lockfile);
|
|
// JSError(undefined, "Expected file path string or buffer", .{}, ctx, exception);
|
|
// return null;
|
|
// },
|
|
// };
|
|
|
|
// switch (load_from_disk_result) {
|
|
// .err => |cause| {
|
|
// defer getAllocator(ctx).destroy(lockfile);
|
|
// switch (cause.step) {
|
|
// .open_file => {
|
|
// JSError(undefined, "error opening lockfile: {s}", .{
|
|
// @errorName(cause.value),
|
|
// }, ctx, exception);
|
|
// return null;
|
|
// },
|
|
// .parse_file => {
|
|
// JSError(undefined, "error parsing lockfile: {s}", .{
|
|
// @errorName(cause.value),
|
|
// }, ctx, exception);
|
|
// return null;
|
|
// },
|
|
// .read_file => {
|
|
// JSError(undefined, "error reading lockfile: {s}", .{
|
|
// @errorName(cause.value),
|
|
// }, ctx, exception);
|
|
// return null;
|
|
// },
|
|
// }
|
|
// },
|
|
// .ok => {},
|
|
// }
|
|
// }
|
|
// };
|
|
|
|
pub const TOML = struct {
|
|
const TOMLParser = @import("../../../toml/toml_parser.zig").TOML;
|
|
pub const Class = NewClass(
|
|
void,
|
|
.{
|
|
.name = "TOML",
|
|
.read_only = true,
|
|
},
|
|
.{
|
|
.parse = .{
|
|
.rfn = TOML.parse,
|
|
},
|
|
},
|
|
.{},
|
|
);
|
|
|
|
pub fn parse(
|
|
// this
|
|
_: void,
|
|
ctx: js.JSContextRef,
|
|
// function
|
|
_: js.JSObjectRef,
|
|
// thisObject
|
|
_: js.JSObjectRef,
|
|
arguments: []const js.JSValueRef,
|
|
exception: js.ExceptionRef,
|
|
) js.JSValueRef {
|
|
var arena = std.heap.ArenaAllocator.init(getAllocator(ctx));
|
|
var allocator = arena.allocator();
|
|
defer arena.deinit();
|
|
var log = logger.Log.init(default_allocator);
|
|
var input_str = ZigString.init("");
|
|
JSValue.fromRef(arguments[0]).toZigString(&input_str, ctx.ptr());
|
|
var needs_deinit = false;
|
|
var input = input_str.slice();
|
|
if (input_str.is16Bit()) {
|
|
input = std.fmt.allocPrint(allocator, "{}", .{input_str}) catch unreachable;
|
|
needs_deinit = true;
|
|
}
|
|
var source = logger.Source.initPathString("input.toml", input);
|
|
var parse_result = TOMLParser.parse(&source, &log, allocator) catch {
|
|
exception.* = log.toJS(ctx.ptr(), default_allocator, "Failed to parse toml").asObjectRef();
|
|
return null;
|
|
};
|
|
|
|
// for now...
|
|
var buffer_writer = try js_printer.BufferWriter.init(allocator);
|
|
var writer = js_printer.BufferPrinter.init(buffer_writer);
|
|
_ = js_printer.printJSON(*js_printer.BufferPrinter, &writer, parse_result, &source) catch {
|
|
exception.* = log.toJS(ctx.ptr(), default_allocator, "Failed to print toml").asObjectRef();
|
|
return null;
|
|
};
|
|
|
|
var slice = writer.ctx.buffer.toOwnedSliceLeaky();
|
|
var out = ZigString.init(slice);
|
|
|
|
const out_value = js.JSValueMakeFromJSONString(ctx, out.toJSStringRef());
|
|
return out_value;
|
|
}
|
|
};
|
|
|
|
pub const Timer = struct {
|
|
last_id: i32 = 0,
|
|
warned: bool = false,
|
|
active: u32 = 0,
|
|
timeouts: TimeoutMap = TimeoutMap{},
|
|
|
|
const TimeoutMap = std.AutoArrayHashMapUnmanaged(i32, *Timeout);
|
|
|
|
pub fn getNextID() callconv(.C) i32 {
|
|
VirtualMachine.vm.timer.last_id += 1;
|
|
return VirtualMachine.vm.timer.last_id;
|
|
}
|
|
|
|
pub const Timeout = struct {
|
|
id: i32 = 0,
|
|
callback: JSValue,
|
|
interval: i32 = 0,
|
|
completion: NetworkThread.Completion = undefined,
|
|
repeat: bool = false,
|
|
io_task: ?*TimeoutTask = null,
|
|
cancelled: bool = false,
|
|
|
|
pub const TimeoutTask = IOTask(Timeout);
|
|
|
|
pub fn run(this: *Timeout, _task: *TimeoutTask) void {
|
|
this.io_task = _task;
|
|
NetworkThread.global.pool.io.?.timeout(
|
|
*Timeout,
|
|
this,
|
|
onCallback,
|
|
&this.completion,
|
|
std.time.ns_per_ms * @intCast(
|
|
u63,
|
|
@maximum(
|
|
this.interval,
|
|
1,
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
pub fn onCallback(this: *Timeout, _: *NetworkThread.Completion, _: NetworkThread.AsyncIO.TimeoutError!void) void {
|
|
this.io_task.?.onFinish();
|
|
}
|
|
|
|
pub fn then(this: *Timeout, global: *JSGlobalObject) void {
|
|
if (comptime JSC.is_bindgen)
|
|
unreachable;
|
|
|
|
if (!this.cancelled) {
|
|
if (this.repeat) {
|
|
this.io_task.?.deinit();
|
|
var task = Timeout.TimeoutTask.createOnJSThread(VirtualMachine.vm.allocator, global, this) catch unreachable;
|
|
this.io_task = task;
|
|
task.schedule();
|
|
}
|
|
|
|
_ = JSC.C.JSObjectCallAsFunction(global.ref(), this.callback.asObjectRef(), null, 0, null, null);
|
|
|
|
if (this.repeat)
|
|
return;
|
|
}
|
|
|
|
this.clear(global);
|
|
}
|
|
|
|
pub fn clear(this: *Timeout, global: *JSGlobalObject) void {
|
|
if (comptime JSC.is_bindgen)
|
|
unreachable;
|
|
|
|
this.cancelled = true;
|
|
JSC.C.JSValueUnprotect(global.ref(), this.callback.asObjectRef());
|
|
_ = VirtualMachine.vm.timer.timeouts.swapRemove(this.id);
|
|
if (this.io_task) |task| {
|
|
task.deinit();
|
|
}
|
|
VirtualMachine.vm.allocator.destroy(this);
|
|
VirtualMachine.vm.timer.active -|= 1;
|
|
VirtualMachine.vm.active_tasks -|= 1;
|
|
}
|
|
};
|
|
|
|
fn set(
|
|
id: i32,
|
|
globalThis: *JSGlobalObject,
|
|
callback: JSValue,
|
|
countdown: JSValue,
|
|
repeat: bool,
|
|
) !void {
|
|
if (comptime is_bindgen) unreachable;
|
|
var timeout = try VirtualMachine.vm.allocator.create(Timeout);
|
|
js.JSValueProtect(globalThis.ref(), callback.asObjectRef());
|
|
timeout.* = Timeout{ .id = id, .callback = callback, .interval = countdown.toInt32(), .repeat = repeat };
|
|
var task = try Timeout.TimeoutTask.createOnJSThread(VirtualMachine.vm.allocator, globalThis, timeout);
|
|
VirtualMachine.vm.timer.timeouts.put(VirtualMachine.vm.allocator, id, timeout) catch unreachable;
|
|
VirtualMachine.vm.timer.active +|= 1;
|
|
VirtualMachine.vm.active_tasks +|= 1;
|
|
task.schedule();
|
|
}
|
|
|
|
pub fn setTimeout(
|
|
globalThis: *JSGlobalObject,
|
|
callback: JSValue,
|
|
countdown: JSValue,
|
|
) callconv(.C) JSValue {
|
|
if (comptime is_bindgen) unreachable;
|
|
const id = VirtualMachine.vm.timer.last_id;
|
|
VirtualMachine.vm.timer.last_id +%= 1;
|
|
|
|
Timer.set(id, globalThis, callback, countdown, false) catch
|
|
return JSValue.jsUndefined();
|
|
|
|
return JSValue.jsNumberWithType(i32, id);
|
|
}
|
|
pub fn setInterval(
|
|
globalThis: *JSGlobalObject,
|
|
callback: JSValue,
|
|
countdown: JSValue,
|
|
) callconv(.C) JSValue {
|
|
if (comptime is_bindgen) unreachable;
|
|
const id = VirtualMachine.vm.timer.last_id;
|
|
VirtualMachine.vm.timer.last_id +%= 1;
|
|
|
|
Timer.set(id, globalThis, callback, countdown, true) catch
|
|
return JSValue.jsUndefined();
|
|
|
|
return JSValue.jsNumberWithType(i32, id);
|
|
}
|
|
|
|
pub fn clearTimer(id: JSValue, _: *JSGlobalObject) void {
|
|
if (comptime is_bindgen) unreachable;
|
|
var timer: *Timeout = VirtualMachine.vm.timer.timeouts.get(id.toInt32()) orelse return;
|
|
timer.cancelled = true;
|
|
}
|
|
|
|
pub fn clearTimeout(
|
|
globalThis: *JSGlobalObject,
|
|
id: JSValue,
|
|
) callconv(.C) JSValue {
|
|
if (comptime is_bindgen) unreachable;
|
|
Timer.clearTimer(id, globalThis);
|
|
return JSValue.jsUndefined();
|
|
}
|
|
pub fn clearInterval(
|
|
globalThis: *JSGlobalObject,
|
|
id: JSValue,
|
|
) callconv(.C) JSValue {
|
|
if (comptime is_bindgen) unreachable;
|
|
Timer.clearTimer(id, globalThis);
|
|
return JSValue.jsUndefined();
|
|
}
|
|
|
|
const Shimmer = @import("../bindings/shimmer.zig").Shimmer;
|
|
|
|
pub const shim = Shimmer("Bun", "Timer", @This());
|
|
pub const name = "Bun__Timer";
|
|
pub const include = "";
|
|
pub const namespace = shim.namespace;
|
|
|
|
pub const Export = shim.exportFunctions(.{
|
|
.@"setTimeout" = setTimeout,
|
|
.@"setInterval" = setInterval,
|
|
.@"clearTimeout" = clearTimeout,
|
|
.@"clearInterval" = clearInterval,
|
|
.@"getNextID" = getNextID,
|
|
});
|
|
|
|
comptime {
|
|
if (!JSC.is_bindgen) {
|
|
@export(setTimeout, .{ .name = Export[0].symbol_name });
|
|
@export(setInterval, .{ .name = Export[1].symbol_name });
|
|
@export(clearTimeout, .{ .name = Export[2].symbol_name });
|
|
@export(clearInterval, .{ .name = Export[3].symbol_name });
|
|
@export(getNextID, .{ .name = Export[4].symbol_name });
|
|
}
|
|
}
|
|
};
|
|
|
|
/// EnvironmentVariables is runtime defined.
|
|
/// Also, you can't iterate over process.env normally since it only exists at build-time otherwise
|
|
// This is aliased to Bun.env
|
|
pub const EnvironmentVariables = struct {
|
|
pub const Class = NewClass(
|
|
void,
|
|
.{
|
|
.name = "DotEnv",
|
|
.read_only = true,
|
|
},
|
|
.{
|
|
.getProperty = .{
|
|
.rfn = getProperty,
|
|
},
|
|
.setProperty = .{
|
|
.rfn = setProperty,
|
|
},
|
|
.deleteProperty = .{
|
|
.rfn = deleteProperty,
|
|
},
|
|
.convertToType = .{ .rfn = convertToType },
|
|
.hasProperty = .{
|
|
.rfn = hasProperty,
|
|
},
|
|
.getPropertyNames = .{
|
|
.rfn = getPropertyNames,
|
|
},
|
|
.toJSON = .{
|
|
.rfn = toJSON,
|
|
.name = "toJSON",
|
|
},
|
|
},
|
|
.{},
|
|
);
|
|
|
|
pub fn getter(
|
|
_: void,
|
|
ctx: js.JSContextRef,
|
|
_: js.JSValueRef,
|
|
_: js.JSStringRef,
|
|
_: js.ExceptionRef,
|
|
) js.JSValueRef {
|
|
return js.JSObjectMake(ctx, EnvironmentVariables.Class.get().*, null);
|
|
}
|
|
|
|
pub const BooleanString = struct {
|
|
pub const @"true": string = "true";
|
|
pub const @"false": string = "false";
|
|
};
|
|
|
|
pub fn getProperty(
|
|
ctx: js.JSContextRef,
|
|
_: js.JSObjectRef,
|
|
propertyName: js.JSStringRef,
|
|
_: js.ExceptionRef,
|
|
) callconv(.C) js.JSValueRef {
|
|
const len = js.JSStringGetLength(propertyName);
|
|
var ptr = js.JSStringGetCharacters8Ptr(propertyName);
|
|
var name = ptr[0..len];
|
|
if (VirtualMachine.vm.bundler.env.map.get(name)) |value| {
|
|
return ZigString.toRef(value, ctx.ptr());
|
|
}
|
|
|
|
if (Output.enable_ansi_colors) {
|
|
// https://github.com/chalk/supports-color/blob/main/index.js
|
|
if (strings.eqlComptime(name, "FORCE_COLOR")) {
|
|
return ZigString.toRef(BooleanString.@"true", ctx.ptr());
|
|
}
|
|
}
|
|
|
|
return js.JSValueMakeUndefined(ctx);
|
|
}
|
|
|
|
pub fn toJSON(
|
|
_: void,
|
|
ctx: js.JSContextRef,
|
|
_: js.JSObjectRef,
|
|
_: js.JSObjectRef,
|
|
_: []const js.JSValueRef,
|
|
_: js.ExceptionRef,
|
|
) js.JSValueRef {
|
|
var map = VirtualMachine.vm.bundler.env.map.map;
|
|
var keys = map.keys();
|
|
var values = map.values();
|
|
const StackFallback = std.heap.StackFallbackAllocator(32 * 2 * @sizeOf(ZigString));
|
|
var stack = StackFallback{
|
|
.buffer = undefined,
|
|
.fallback_allocator = bun.default_allocator,
|
|
.fixed_buffer_allocator = undefined,
|
|
};
|
|
var allocator = stack.get();
|
|
var key_strings_ = allocator.alloc(ZigString, keys.len * 2) catch unreachable;
|
|
var key_strings = key_strings_[0..keys.len];
|
|
var value_strings = key_strings_[keys.len..];
|
|
|
|
for (keys) |key, i| {
|
|
key_strings[i] = ZigString.init(key);
|
|
key_strings[i].detectEncoding();
|
|
value_strings[i] = ZigString.init(values[i]);
|
|
value_strings[i].detectEncoding();
|
|
}
|
|
|
|
var result = JSValue.fromEntries(ctx.ptr(), key_strings.ptr, value_strings.ptr, keys.len, false).asObjectRef();
|
|
allocator.free(key_strings_);
|
|
return result;
|
|
// }
|
|
// ZigConsoleClient.Formatter.format(this: *Formatter, result: Tag.Result, comptime Writer: type, writer: Writer, value: JSValue, globalThis: *JSGlobalObject, comptime enable_ansi_colors: bool)
|
|
}
|
|
|
|
pub fn deleteProperty(
|
|
_: js.JSContextRef,
|
|
_: js.JSObjectRef,
|
|
propertyName: js.JSStringRef,
|
|
_: js.ExceptionRef,
|
|
) callconv(.C) bool {
|
|
const len = js.JSStringGetLength(propertyName);
|
|
var ptr = js.JSStringGetCharacters8Ptr(propertyName);
|
|
var name = ptr[0..len];
|
|
_ = VirtualMachine.vm.bundler.env.map.map.swapRemove(name);
|
|
return true;
|
|
}
|
|
|
|
pub fn setProperty(
|
|
ctx: js.JSContextRef,
|
|
_: js.JSObjectRef,
|
|
propertyName: js.JSStringRef,
|
|
value: js.JSValueRef,
|
|
exception: js.ExceptionRef,
|
|
) callconv(.C) bool {
|
|
const len = js.JSStringGetLength(propertyName);
|
|
var ptr = js.JSStringGetCharacters8Ptr(propertyName);
|
|
var name = ptr[0..len];
|
|
var val = ZigString.init("");
|
|
JSValue.fromRef(value).toZigString(&val, ctx.ptr());
|
|
if (exception.* != null) return false;
|
|
var result = std.fmt.allocPrint(VirtualMachine.vm.allocator, "{}", .{val}) catch unreachable;
|
|
VirtualMachine.vm.bundler.env.map.put(name, result) catch unreachable;
|
|
|
|
return true;
|
|
}
|
|
|
|
pub fn hasProperty(
|
|
_: js.JSContextRef,
|
|
_: js.JSObjectRef,
|
|
propertyName: js.JSStringRef,
|
|
) callconv(.C) bool {
|
|
const len = js.JSStringGetLength(propertyName);
|
|
const ptr = js.JSStringGetCharacters8Ptr(propertyName);
|
|
const name = ptr[0..len];
|
|
return VirtualMachine.vm.bundler.env.map.get(name) != null or (Output.enable_ansi_colors and strings.eqlComptime(name, "FORCE_COLOR"));
|
|
}
|
|
|
|
pub fn convertToType(ctx: js.JSContextRef, obj: js.JSObjectRef, kind: js.JSType, exception: js.ExceptionRef) callconv(.C) js.JSValueRef {
|
|
_ = ctx;
|
|
_ = obj;
|
|
_ = kind;
|
|
_ = exception;
|
|
return obj;
|
|
}
|
|
|
|
pub fn getPropertyNames(
|
|
_: js.JSContextRef,
|
|
_: js.JSObjectRef,
|
|
props: js.JSPropertyNameAccumulatorRef,
|
|
) callconv(.C) void {
|
|
var iter = VirtualMachine.vm.bundler.env.map.iter();
|
|
|
|
while (iter.next()) |item| {
|
|
const str = item.key_ptr.*;
|
|
js.JSPropertyNameAccumulatorAddName(props, js.JSStringCreateStatic(str.ptr, str.len));
|
|
}
|
|
}
|
|
};
|
|
|
|
export fn Bun__reportError(_: *JSGlobalObject, err: JSC.JSValue) void {
|
|
JSC.VirtualMachine.vm.defaultErrorHandler(err, null);
|
|
}
|
|
|
|
comptime {
|
|
if (!is_bindgen) {
|
|
_ = Bun__reportError;
|
|
}
|
|
}
|