mirror of
https://github.com/oven-sh/bun
synced 2026-02-11 03:18:53 +00:00
467
src/javascript/jsc/base.zig
Normal file
467
src/javascript/jsc/base.zig
Normal file
@@ -0,0 +1,467 @@
|
||||
pub const js = @import("./JavaScriptCore.zig");
|
||||
const std = @import("std");
|
||||
pub usingnamespace @import("../../global.zig");
|
||||
const javascript = @import("./javascript.zig");
|
||||
pub const ExceptionValueRef = [*c]js.JSValueRef;
|
||||
pub const JSValueRef = js.JSValueRef;
|
||||
|
||||
pub const To = struct {
|
||||
pub const JS = struct {
|
||||
pub inline fn str(ref: anytype, val: anytype) js.JSStringRef {
|
||||
return js.JSStringCreateWithUTF8CString(val[0.. :0]);
|
||||
}
|
||||
|
||||
pub fn functionWithCallback(
|
||||
comptime ZigContextType: type,
|
||||
zig: *ZigContextType,
|
||||
name: js.JSStringRef,
|
||||
ctx: js.JSContextRef,
|
||||
comptime callback: fn (
|
||||
obj: *ZigContextType,
|
||||
ctx: js.JSContextRef,
|
||||
function: js.JSObjectRef,
|
||||
thisObject: js.JSObjectRef,
|
||||
arguments: []const js.JSValueRef,
|
||||
exception: js.ExceptionRef,
|
||||
) js.JSValueRef,
|
||||
) js.JSObjectRef {
|
||||
var function = js.JSObjectMakeFunctionWithCallback(ctx, name, Callback(ZigContextType, callback).rfn);
|
||||
_ = js.JSObjectSetPrivate(
|
||||
function,
|
||||
@ptrCast(*c_void, @alignCast(@alignOf(*c_void), zig)),
|
||||
);
|
||||
return function;
|
||||
}
|
||||
|
||||
pub fn Callback(
|
||||
comptime ZigContextType: type,
|
||||
comptime ctxfn: fn (
|
||||
obj: *ZigContextType,
|
||||
ctx: js.JSContextRef,
|
||||
function: js.JSObjectRef,
|
||||
thisObject: js.JSObjectRef,
|
||||
arguments: []const js.JSValueRef,
|
||||
exception: js.ExceptionRef,
|
||||
) js.JSValueRef,
|
||||
) type {
|
||||
return struct {
|
||||
pub fn rfn(
|
||||
ctx: js.JSContextRef,
|
||||
function: js.JSObjectRef,
|
||||
thisObject: js.JSObjectRef,
|
||||
argumentCount: usize,
|
||||
arguments: [*c]const js.JSValueRef,
|
||||
exception: js.ExceptionRef,
|
||||
) callconv(.C) js.JSValueRef {
|
||||
var object_ptr_ = js.JSObjectGetPrivate(function);
|
||||
if (object_ptr_ == null) {
|
||||
object_ptr_ = js.JSObjectGetPrivate(thisObject);
|
||||
}
|
||||
|
||||
if (object_ptr_ == null) {
|
||||
return js.JSValueMakeUndefined(ctx);
|
||||
}
|
||||
|
||||
var object_ptr = object_ptr_.?;
|
||||
|
||||
return ctxfn(
|
||||
@ptrCast(*ZigContextType, @alignCast(@alignOf(*ZigContextType), object_ptr)),
|
||||
ctx,
|
||||
function,
|
||||
thisObject,
|
||||
if (arguments) |args| args[0..argumentCount] else &[_]js.JSValueRef{},
|
||||
exception,
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
pub const Ref = struct {
|
||||
pub inline fn str(ref: anytype) js.JSStringRef {
|
||||
return @as(js.JSStringRef, ref);
|
||||
}
|
||||
};
|
||||
|
||||
pub const Zig = struct {
|
||||
pub inline fn str(ref: anytype, buf: anytype) string {
|
||||
return buf[0..js.JSStringGetUTF8CString(Ref.str(ref), buf.ptr, buf.len)];
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
pub const Properties = struct {
|
||||
pub const UTF8 = struct {
|
||||
pub const module = "module";
|
||||
pub const globalThis = "globalThis";
|
||||
pub const exports = "exports";
|
||||
pub const log = "log";
|
||||
pub const debug = "debug";
|
||||
pub const name = "name";
|
||||
pub const info = "info";
|
||||
pub const error_ = "error";
|
||||
pub const warn = "warn";
|
||||
pub const console = "console";
|
||||
pub const require = "require";
|
||||
pub const description = "description";
|
||||
pub const initialize_bundled_module = "$$m";
|
||||
pub const load_module_function = "$lOaDuRcOdE$";
|
||||
pub const window = "window";
|
||||
};
|
||||
|
||||
pub const UTF16 = struct {
|
||||
pub const module: []c_ushort = std.unicode.utf8ToUtf16LeStringLiteral(UTF8.module);
|
||||
pub const globalThis: []c_ushort = std.unicode.utf8ToUtf16LeStringLiteral(UTF8.globalThis);
|
||||
pub const exports: []c_ushort = std.unicode.utf8ToUtf16LeStringLiteral(UTF8.exports);
|
||||
pub const log: []c_ushort = std.unicode.utf8ToUtf16LeStringLiteral(UTF8.log);
|
||||
pub const debug: []c_ushort = std.unicode.utf8ToUtf16LeStringLiteral(UTF8.debug);
|
||||
pub const info: []c_ushort = std.unicode.utf8ToUtf16LeStringLiteral(UTF8.info);
|
||||
pub const error_: []c_ushort = std.unicode.utf8ToUtf16LeStringLiteral(UTF8.error_);
|
||||
pub const warn: []c_ushort = std.unicode.utf8ToUtf16LeStringLiteral(UTF8.warn);
|
||||
pub const console: []c_ushort = std.unicode.utf8ToUtf16LeStringLiteral(UTF8.console);
|
||||
pub const require: []c_ushort = std.unicode.utf8ToUtf16LeStringLiteral(UTF8.require);
|
||||
pub const description: []c_ushort = std.unicode.utf8ToUtf16LeStringLiteral(UTF8.description);
|
||||
pub const name: []c_ushort = std.unicode.utf8ToUtf16LeStringLiteral(UTF8.name);
|
||||
pub const initialize_bundled_module = std.unicode.utf8ToUtf16LeStringLiteral(UTF8.initialize_bundled_module);
|
||||
pub const load_module_function: []c_ushort = std.unicode.utf8ToUtf16LeStringLiteral(UTF8.load_module_function);
|
||||
pub const window: []c_ushort = std.unicode.utf8ToUtf16LeStringLiteral(UTF8.window);
|
||||
};
|
||||
|
||||
pub const Refs = struct {
|
||||
pub var module: js.JSStringRef = null;
|
||||
pub var globalThis: js.JSStringRef = null;
|
||||
pub var exports: js.JSStringRef = null;
|
||||
pub var log: js.JSStringRef = null;
|
||||
pub var debug: js.JSStringRef = null;
|
||||
pub var info: js.JSStringRef = null;
|
||||
pub var error_: js.JSStringRef = null;
|
||||
pub var warn: js.JSStringRef = null;
|
||||
pub var console: js.JSStringRef = null;
|
||||
pub var require: js.JSStringRef = null;
|
||||
pub var description: js.JSStringRef = null;
|
||||
pub var name: js.JSStringRef = null;
|
||||
pub var initialize_bundled_module: js.JSStringRef = null;
|
||||
pub var load_module_function: js.JSStringRef = null;
|
||||
pub var window: js.JSStringRef = null;
|
||||
};
|
||||
|
||||
pub fn init() void {
|
||||
inline for (std.meta.fieldNames(UTF8)) |name| {
|
||||
@field(Refs, name) = js.JSStringRetain(
|
||||
js.JSStringCreateWithCharactersNoCopy(
|
||||
@field(StringStore.UTF16, name).ptr,
|
||||
@field(StringStore.UTF16, name).len - 1,
|
||||
),
|
||||
);
|
||||
|
||||
if (isDebug) {
|
||||
std.debug.assert(
|
||||
js.JSStringIsEqualToUTF8CString(@field(Refs, name), @field(UTF8, name)[0.. :0]),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
pub fn NewClass(
|
||||
comptime ZigType: type,
|
||||
comptime name: string,
|
||||
comptime staticFunctions: anytype,
|
||||
comptime properties: anytype,
|
||||
comptime read_only: bool,
|
||||
comptime singleton: bool,
|
||||
) type {
|
||||
return struct {
|
||||
const ClassDefinitionCreator = @This();
|
||||
const function_names = std.meta.fieldNames(@TypeOf(staticFunctions));
|
||||
const names_buf = brk: {
|
||||
var total_len: usize = 0;
|
||||
for (function_names) |field, i| {
|
||||
total_len += std.unicode.utf8ToUtf16LeStringLiteral(field).len;
|
||||
}
|
||||
var offset: usize = 0;
|
||||
var names_buf_ = std.mem.zeroes([total_len]u16);
|
||||
for (function_names) |field, i| {
|
||||
var name_ = std.unicode.utf8ToUtf16LeStringLiteral(field);
|
||||
std.mem.copy(u16, names_buf_[offset .. name_.len + offset], name_[0..]);
|
||||
offset += name_.len;
|
||||
}
|
||||
break :brk names_buf_;
|
||||
};
|
||||
const function_name_literals: [function_names.len][]const js.JSChar = brk: {
|
||||
var names = std.mem.zeroes([function_names.len][]const js.JSChar);
|
||||
var len: usize = 0;
|
||||
for (function_names) |field, i| {
|
||||
const end = len + std.unicode.utf8ToUtf16LeStringLiteral(field).len;
|
||||
names[i] = names_buf[len..end];
|
||||
len = end;
|
||||
}
|
||||
break :brk names;
|
||||
};
|
||||
var function_name_refs: [function_names.len]js.JSStringRef = undefined;
|
||||
var class_name_str = name[0.. :0].ptr;
|
||||
|
||||
const class_name_literal = std.unicode.utf8ToUtf16LeStringLiteral(name);
|
||||
var static_functions: [function_name_refs.len + 1]js.JSStaticFunction = undefined;
|
||||
var instance_functions: [function_names.len]js.JSObjectRef = undefined;
|
||||
const property_names = std.meta.fieldNames(@TypeOf(properties));
|
||||
var property_name_refs: [property_names.len]js.JSStringRef = undefined;
|
||||
const property_name_literals: [property_names.len][]const js.JSChar = brk: {
|
||||
var list = std.mem.zeroes([property_names.len][]const js.JSChar);
|
||||
for (property_names) |prop_name, i| {
|
||||
list[i] = std.unicode.utf8ToUtf16LeStringLiteral(prop_name);
|
||||
}
|
||||
break :brk list;
|
||||
};
|
||||
var static_properties: [property_names.len]js.JSStaticValue = undefined;
|
||||
|
||||
pub fn getPropertyCallback(
|
||||
ctx: js.JSContextRef,
|
||||
obj: js.JSObjectRef,
|
||||
prop: js.JSStringRef,
|
||||
exception: js.ExceptionRef,
|
||||
) callconv(.C) js.JSValueRef {
|
||||
var instance_pointer_ = js.JSObjectGetPrivate(obj);
|
||||
if (instance_pointer_ == null) return null;
|
||||
var instance_pointer = instance_pointer_.?;
|
||||
var ptr = @ptrCast(
|
||||
*ZigType,
|
||||
@alignCast(
|
||||
@alignOf(
|
||||
*ZigType,
|
||||
),
|
||||
instance_pointer,
|
||||
),
|
||||
);
|
||||
|
||||
if (singleton) {
|
||||
inline for (function_names) |propname, i| {
|
||||
if (js.JSStringIsEqual(prop, function_name_refs[i])) {
|
||||
return instance_functions[i];
|
||||
}
|
||||
}
|
||||
if (comptime std.meta.trait.hasFn("onMissingProperty")(ZigType)) {
|
||||
return ptr.onMissingProperty(ctx, obj, prop, exception);
|
||||
}
|
||||
} else {
|
||||
inline for (property_names) |propname, i| {
|
||||
if (js.JSStringIsEqual(prop, property_name_refs[i])) {
|
||||
return @field(
|
||||
properties,
|
||||
propname,
|
||||
)(ptr, ctx, obj, exception);
|
||||
}
|
||||
}
|
||||
|
||||
if (comptime std.meta.trait.hasFn("onMissingProperty")(ZigType)) {
|
||||
return ptr.onMissingProperty(ctx, obj, prop, exception);
|
||||
}
|
||||
}
|
||||
|
||||
return js.JSValueMakeUndefined(ctx);
|
||||
}
|
||||
|
||||
fn StaticProperty(comptime id: usize) type {
|
||||
return struct {
|
||||
pub fn getter(
|
||||
ctx: js.JSContextRef,
|
||||
obj: js.JSObjectRef,
|
||||
prop: js.JSStringRef,
|
||||
exception: js.ExceptionRef,
|
||||
) callconv(.C) js.JSValueRef {
|
||||
var instance_pointer_ = js.JSObjectGetPrivate(obj);
|
||||
if (instance_pointer_ == null) return null;
|
||||
var this: *ZigType = @ptrCast(
|
||||
*ZigType,
|
||||
@alignCast(
|
||||
@alignOf(
|
||||
*ZigType,
|
||||
),
|
||||
instance_pointer_.?,
|
||||
),
|
||||
);
|
||||
|
||||
var exc: js.ExceptionRef = null;
|
||||
|
||||
switch (comptime @typeInfo(@TypeOf(@field(
|
||||
properties,
|
||||
property_names[id],
|
||||
)))) {
|
||||
.Fn => {
|
||||
return @field(
|
||||
properties,
|
||||
property_names[id],
|
||||
)(
|
||||
this,
|
||||
ctx,
|
||||
obj,
|
||||
exception,
|
||||
);
|
||||
},
|
||||
.Struct => {
|
||||
return @field(
|
||||
@field(
|
||||
properties,
|
||||
property_names[id],
|
||||
),
|
||||
"get",
|
||||
)(
|
||||
this,
|
||||
ctx,
|
||||
obj,
|
||||
prop,
|
||||
exception,
|
||||
);
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn setter(
|
||||
ctx: js.JSContextRef,
|
||||
obj: js.JSObjectRef,
|
||||
prop: js.JSStringRef,
|
||||
value: js.JSValueRef,
|
||||
exception: js.ExceptionRef,
|
||||
) callconv(.C) bool {
|
||||
var instance_pointer_ = js.JSObjectGetPrivate(obj);
|
||||
if (instance_pointer_ == null) return false;
|
||||
var this: *ZigType = @ptrCast(
|
||||
*ZigType,
|
||||
@alignCast(
|
||||
@alignOf(
|
||||
*ZigType,
|
||||
),
|
||||
instance_pointer_.?,
|
||||
),
|
||||
);
|
||||
|
||||
var exc: js.ExceptionRef = null;
|
||||
|
||||
switch (comptime @typeInfo(@TypeOf(@field(
|
||||
properties,
|
||||
property_names[id],
|
||||
)))) {
|
||||
.Struct => {
|
||||
return @field(
|
||||
@field(
|
||||
properties,
|
||||
property_names[id],
|
||||
),
|
||||
"set",
|
||||
)(
|
||||
this,
|
||||
ctx,
|
||||
obj,
|
||||
prop,
|
||||
value,
|
||||
exception,
|
||||
);
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub fn define() js.JSClassDefinition {
|
||||
var def = js.kJSClassDefinitionEmpty;
|
||||
|
||||
if (static_functions.len > 0) {
|
||||
std.mem.set(js.JSStaticFunction, &static_functions, std.mem.zeroes(js.JSStaticFunction));
|
||||
var count: usize = 0;
|
||||
inline for (function_name_literals) |function_name, i| {
|
||||
if (comptime strings.eqlComptime(function_names[i], "constructor")) {
|
||||
def.callAsConstructor = @field(staticFunctions, function_names[i]);
|
||||
} else {
|
||||
count += 1;
|
||||
var callback = To.JS.Callback(ZigType, @field(staticFunctions, function_names[i])).rfn;
|
||||
static_functions[count] = js.JSStaticFunction{
|
||||
.name = (function_names[i][0.. :0]).ptr,
|
||||
.callAsFunction = callback,
|
||||
.attributes = comptime if (read_only) js.JSPropertyAttributes.kJSPropertyAttributeReadOnly else js.JSPropertyAttributes.kJSPropertyAttributeNone,
|
||||
};
|
||||
}
|
||||
|
||||
// if (singleton) {
|
||||
// var function = js.JSObjectMakeFunctionWithCallback(ctx, function_name_refs[i], callback);
|
||||
// instance_functions[i] = function;
|
||||
// }
|
||||
}
|
||||
|
||||
def.staticFunctions = static_functions[0..count].ptr;
|
||||
}
|
||||
|
||||
if (property_names.len > 0) {
|
||||
inline for (comptime property_name_literals) |prop_name, i| {
|
||||
property_name_refs[i] = js.JSStringCreateWithCharactersNoCopy(
|
||||
prop_name.ptr,
|
||||
prop_name.len,
|
||||
);
|
||||
static_properties[i] = std.mem.zeroes(js.JSStaticValue);
|
||||
static_properties[i].getProperty = StaticProperty(i).getter;
|
||||
|
||||
const field = comptime @field(properties, property_names[i]);
|
||||
const hasSetter = std.meta.trait.hasField("set");
|
||||
if (comptime hasSetter(@TypeOf(field))) {
|
||||
static_properties[i].setProperty = StaticProperty(i).setter;
|
||||
}
|
||||
static_properties[i].name = property_names[i][0.. :0];
|
||||
}
|
||||
|
||||
def.staticValues = (&static_properties);
|
||||
}
|
||||
|
||||
def.className = class_name_str;
|
||||
// def.getProperty = getPropertyCallback;
|
||||
|
||||
def.finalize
|
||||
|
||||
return def;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
threadlocal var error_args: [1]js.JSValueRef = undefined;
|
||||
pub fn JSError(
|
||||
allocator: *std.mem.Allocator,
|
||||
comptime fmt: string,
|
||||
args: anytype,
|
||||
ctx: js.JSContextRef,
|
||||
exception: ExceptionValueRef,
|
||||
) void {
|
||||
if (comptime std.meta.fields(@TypeOf(args)).len == 0) {
|
||||
var message = js.JSStringCreateWithUTF8CString(fmt[0.. :0]);
|
||||
defer js.JSStringRelease(message);
|
||||
error_args[0] = js.JSValueMakeString(ctx, message);
|
||||
exception.* = js.JSObjectMakeError(ctx, 1, &error_args, null);
|
||||
} else {
|
||||
var buf = std.fmt.allocPrintZ(allocator, fmt, args) catch unreachable;
|
||||
var message = js.JSStringCreateWithUTF8CString(buf);
|
||||
defer js.JSStringRelease(message);
|
||||
defer allocator.free(buf);
|
||||
error_args[0] = js.JSValueMakeString(ctx, message);
|
||||
exception.* = js.JSObjectMakeError(ctx, 1, &error_args, null);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn getAllocator(ctx: js.JSContextRef) *std.mem.Allocator {
|
||||
var global_obj = js.JSContextGetGlobalObject(ctx);
|
||||
var priv = js.JSObjectGetPrivate(global_obj).?;
|
||||
var global = @ptrCast(*javascript.GlobalObject, @alignCast(@alignOf(*javascript.GlobalObject), priv));
|
||||
|
||||
return global.vm.allocator;
|
||||
}
|
||||
|
||||
pub const JSStringList = std.ArrayList(js.JSStringRef);
|
||||
|
||||
pub const ArrayBuffer = struct {
|
||||
ptr: [*]u8 = undefined,
|
||||
offset: u32,
|
||||
// for the array type,
|
||||
len: u32,
|
||||
|
||||
byte_len: u32,
|
||||
|
||||
typed_array_type: js.JSTypedArrayType,
|
||||
};
|
||||
@@ -1,11 +1,9 @@
|
||||
const js = @import("./JavaScriptCore.zig");
|
||||
const std = @import("std");
|
||||
usingnamespace @import("../../global.zig");
|
||||
|
||||
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 WTFString = @import("../../wtf_string_mutable.zig").WTFStringMutable;
|
||||
const logger = @import("../../logger.zig");
|
||||
const Api = @import("../../api/schema.zig").Api;
|
||||
const options = @import("../../options.zig");
|
||||
@@ -13,35 +11,9 @@ const Bundler = @import("../../bundler.zig").ServeBundler;
|
||||
const js_printer = @import("../../js_printer.zig");
|
||||
const hash_map = @import("../../hash_map.zig");
|
||||
const http = @import("../../http.zig");
|
||||
|
||||
usingnamespace @import("./node_env_buf_map.zig");
|
||||
pub const ExportJavaScript = union(Tag) {
|
||||
Module: *Module,
|
||||
String: *String,
|
||||
GlobalObject: *GlobalObject,
|
||||
|
||||
pub const Tag = enum {
|
||||
Module,
|
||||
String,
|
||||
GlobalObject,
|
||||
};
|
||||
};
|
||||
|
||||
pub const ResolveFunctionType = fn (ctx: anytype, source_dir: string, import_path: string, import_kind: ast.ImportKind) anyerror!resolver.Result;
|
||||
pub const TranspileFunctionType = fn (ctx: anytype, resolve_result: resolver.Result) anyerror![:0]const u8;
|
||||
pub const ExceptionValueRef = [*c]js.JSValueRef;
|
||||
pub const JSValueRef = js.JSValueRef;
|
||||
const JSStringMapContext = struct {
|
||||
pub fn hash(self: @This(), s: js.JSStringRef) u64 {
|
||||
return hashString(s);
|
||||
}
|
||||
pub fn eql(self: @This(), a: js.JSStringRef, b: js.JSStringRef) bool {
|
||||
return eqlString(a, b);
|
||||
}
|
||||
};
|
||||
|
||||
pub fn JSStringMap(comptime V: type) type {
|
||||
return std.HashMap(js.JSStringRef, V, JSStringMapContext, 60);
|
||||
}
|
||||
usingnamespace @import("./base.zig");
|
||||
|
||||
const DefaultSpeedyDefines = struct {
|
||||
pub const Keys = struct {
|
||||
@@ -219,160 +191,7 @@ pub const VirtualMachine = struct {
|
||||
}
|
||||
};
|
||||
|
||||
pub const To = struct {
|
||||
pub const JS = struct {
|
||||
pub inline fn str(ref: anytype, val: anytype) js.JSStringRef {
|
||||
return js.JSStringCreateWithUTF8CString(val[0.. :0]);
|
||||
}
|
||||
|
||||
pub fn functionWithCallback(
|
||||
comptime ZigContextType: type,
|
||||
zig: *ZigContextType,
|
||||
name: js.JSStringRef,
|
||||
ctx: js.JSContextRef,
|
||||
comptime callback: fn (
|
||||
obj: *ZigContextType,
|
||||
ctx: js.JSContextRef,
|
||||
function: js.JSObjectRef,
|
||||
thisObject: js.JSObjectRef,
|
||||
arguments: []const js.JSValueRef,
|
||||
exception: js.ExceptionRef,
|
||||
) js.JSValueRef,
|
||||
) js.JSObjectRef {
|
||||
var function = js.JSObjectMakeFunctionWithCallback(ctx, name, Callback(ZigContextType, callback).rfn);
|
||||
_ = js.JSObjectSetPrivate(
|
||||
function,
|
||||
@ptrCast(*c_void, @alignCast(@alignOf(*c_void), zig)),
|
||||
);
|
||||
return function;
|
||||
}
|
||||
|
||||
pub fn Callback(
|
||||
comptime ZigContextType: type,
|
||||
comptime ctxfn: fn (
|
||||
obj: *ZigContextType,
|
||||
ctx: js.JSContextRef,
|
||||
function: js.JSObjectRef,
|
||||
thisObject: js.JSObjectRef,
|
||||
arguments: []const js.JSValueRef,
|
||||
exception: js.ExceptionRef,
|
||||
) js.JSValueRef,
|
||||
) type {
|
||||
return struct {
|
||||
pub fn rfn(
|
||||
ctx: js.JSContextRef,
|
||||
function: js.JSObjectRef,
|
||||
thisObject: js.JSObjectRef,
|
||||
argumentCount: usize,
|
||||
arguments: [*c]const js.JSValueRef,
|
||||
exception: js.ExceptionRef,
|
||||
) callconv(.C) js.JSValueRef {
|
||||
var object_ptr_ = js.JSObjectGetPrivate(function);
|
||||
if (object_ptr_ == null) {
|
||||
object_ptr_ = js.JSObjectGetPrivate(thisObject);
|
||||
}
|
||||
|
||||
if (object_ptr_ == null) {
|
||||
return js.JSValueMakeUndefined(ctx);
|
||||
}
|
||||
|
||||
var object_ptr = object_ptr_.?;
|
||||
|
||||
return ctxfn(
|
||||
@ptrCast(*ZigContextType, @alignCast(@alignOf(*ZigContextType), object_ptr)),
|
||||
ctx,
|
||||
function,
|
||||
thisObject,
|
||||
if (arguments) |args| args[0..argumentCount] else &[_]js.JSValueRef{},
|
||||
exception,
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
pub const Ref = struct {
|
||||
pub inline fn str(ref: anytype) js.JSStringRef {
|
||||
return @as(js.JSStringRef, ref);
|
||||
}
|
||||
};
|
||||
|
||||
pub const Zig = struct {
|
||||
pub inline fn str(ref: anytype, buf: anytype) string {
|
||||
return buf[0..js.JSStringGetUTF8CString(Ref.str(ref), buf.ptr, buf.len)];
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
pub const Properties = struct {
|
||||
pub const UTF8 = struct {
|
||||
pub const module = "module";
|
||||
pub const globalThis = "globalThis";
|
||||
pub const exports = "exports";
|
||||
pub const log = "log";
|
||||
pub const debug = "debug";
|
||||
pub const name = "name";
|
||||
pub const info = "info";
|
||||
pub const error_ = "error";
|
||||
pub const warn = "warn";
|
||||
pub const console = "console";
|
||||
pub const require = "require";
|
||||
pub const description = "description";
|
||||
pub const initialize_bundled_module = "$$m";
|
||||
pub const load_module_function = "$lOaDuRcOdE$";
|
||||
};
|
||||
|
||||
pub const UTF16 = struct {
|
||||
pub const module: []c_ushort = std.unicode.utf8ToUtf16LeStringLiteral(UTF8.module);
|
||||
pub const globalThis: []c_ushort = std.unicode.utf8ToUtf16LeStringLiteral(UTF8.globalThis);
|
||||
pub const exports: []c_ushort = std.unicode.utf8ToUtf16LeStringLiteral(UTF8.exports);
|
||||
pub const log: []c_ushort = std.unicode.utf8ToUtf16LeStringLiteral(UTF8.log);
|
||||
pub const debug: []c_ushort = std.unicode.utf8ToUtf16LeStringLiteral(UTF8.debug);
|
||||
pub const info: []c_ushort = std.unicode.utf8ToUtf16LeStringLiteral(UTF8.info);
|
||||
pub const error_: []c_ushort = std.unicode.utf8ToUtf16LeStringLiteral(UTF8.error_);
|
||||
pub const warn: []c_ushort = std.unicode.utf8ToUtf16LeStringLiteral(UTF8.warn);
|
||||
pub const console: []c_ushort = std.unicode.utf8ToUtf16LeStringLiteral(UTF8.console);
|
||||
pub const require: []c_ushort = std.unicode.utf8ToUtf16LeStringLiteral(UTF8.require);
|
||||
pub const description: []c_ushort = std.unicode.utf8ToUtf16LeStringLiteral(UTF8.description);
|
||||
pub const name: []c_ushort = std.unicode.utf8ToUtf16LeStringLiteral(UTF8.name);
|
||||
pub const initialize_bundled_module = std.unicode.utf8ToUtf16LeStringLiteral(UTF8.initialize_bundled_module);
|
||||
pub const load_module_function: []c_ushort = std.unicode.utf8ToUtf16LeStringLiteral(UTF8.load_module_function);
|
||||
};
|
||||
|
||||
pub const Refs = struct {
|
||||
pub var module: js.JSStringRef = null;
|
||||
pub var globalThis: js.JSStringRef = null;
|
||||
pub var exports: js.JSStringRef = null;
|
||||
pub var log: js.JSStringRef = null;
|
||||
pub var debug: js.JSStringRef = null;
|
||||
pub var info: js.JSStringRef = null;
|
||||
pub var error_: js.JSStringRef = null;
|
||||
pub var warn: js.JSStringRef = null;
|
||||
pub var console: js.JSStringRef = null;
|
||||
pub var require: js.JSStringRef = null;
|
||||
pub var description: js.JSStringRef = null;
|
||||
pub var name: js.JSStringRef = null;
|
||||
pub var initialize_bundled_module: js.JSStringRef = null;
|
||||
pub var load_module_function: js.JSStringRef = null;
|
||||
};
|
||||
|
||||
pub fn init() void {
|
||||
inline for (std.meta.fieldNames(UTF8)) |name| {
|
||||
@field(Refs, name) = js.JSStringRetain(
|
||||
js.JSStringCreateWithCharactersNoCopy(
|
||||
@field(StringStore.UTF16, name).ptr,
|
||||
@field(StringStore.UTF16, name).len - 1,
|
||||
),
|
||||
);
|
||||
|
||||
if (isDebug) {
|
||||
std.debug.assert(
|
||||
js.JSStringIsEqualToUTF8CString(@field(Refs, name), @field(UTF8, name)[0.. :0]),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
pub const Object = struct {
|
||||
ref: js.jsObjectRef,
|
||||
@@ -1535,255 +1354,3 @@ pub const GlobalObject = struct {
|
||||
// js.JSObjectMakeFunctionWithCallback(ctx: JSContextRef, name: JSStringRef, callAsFunction: JSObjectCallAsFunctionCallback)
|
||||
}
|
||||
};
|
||||
|
||||
pub fn NewClass(
|
||||
comptime ZigType: type,
|
||||
comptime name: string,
|
||||
comptime staticFunctions: anytype,
|
||||
comptime properties: anytype,
|
||||
comptime read_only: bool,
|
||||
comptime singleton: bool,
|
||||
) type {
|
||||
return struct {
|
||||
const ClassDefinitionCreator = @This();
|
||||
const function_names = std.meta.fieldNames(@TypeOf(staticFunctions));
|
||||
const names_buf = brk: {
|
||||
var total_len: usize = 0;
|
||||
for (function_names) |field, i| {
|
||||
total_len += std.unicode.utf8ToUtf16LeStringLiteral(field).len;
|
||||
}
|
||||
var offset: usize = 0;
|
||||
var names_buf_ = std.mem.zeroes([total_len]u16);
|
||||
for (function_names) |field, i| {
|
||||
var name_ = std.unicode.utf8ToUtf16LeStringLiteral(field);
|
||||
std.mem.copy(u16, names_buf_[offset .. name_.len + offset], name_[0..]);
|
||||
offset += name_.len;
|
||||
}
|
||||
break :brk names_buf_;
|
||||
};
|
||||
const function_name_literals: [function_names.len][]const js.JSChar = brk: {
|
||||
var names = std.mem.zeroes([function_names.len][]const js.JSChar);
|
||||
var len: usize = 0;
|
||||
for (function_names) |field, i| {
|
||||
const end = len + std.unicode.utf8ToUtf16LeStringLiteral(field).len;
|
||||
names[i] = names_buf[len..end];
|
||||
len = end;
|
||||
}
|
||||
break :brk names;
|
||||
};
|
||||
var function_name_refs: [function_names.len]js.JSStringRef = undefined;
|
||||
var class_name_str = name[0.. :0].ptr;
|
||||
|
||||
const class_name_literal = std.unicode.utf8ToUtf16LeStringLiteral(name);
|
||||
var static_functions: [function_name_refs.len + 1]js.JSStaticFunction = undefined;
|
||||
var instance_functions: [function_names.len]js.JSObjectRef = undefined;
|
||||
const property_names = std.meta.fieldNames(@TypeOf(properties));
|
||||
var property_name_refs: [property_names.len]js.JSStringRef = undefined;
|
||||
const property_name_literals: [property_names.len][]const js.JSChar = brk: {
|
||||
var list = std.mem.zeroes([property_names.len][]const js.JSChar);
|
||||
for (property_names) |prop_name, i| {
|
||||
list[i] = std.unicode.utf8ToUtf16LeStringLiteral(prop_name);
|
||||
}
|
||||
break :brk list;
|
||||
};
|
||||
var static_properties: [property_names.len]js.JSStaticValue = undefined;
|
||||
|
||||
pub fn getPropertyCallback(
|
||||
ctx: js.JSContextRef,
|
||||
obj: js.JSObjectRef,
|
||||
prop: js.JSStringRef,
|
||||
exception: js.ExceptionRef,
|
||||
) callconv(.C) js.JSValueRef {
|
||||
var instance_pointer_ = js.JSObjectGetPrivate(obj);
|
||||
if (instance_pointer_ == null) return null;
|
||||
var instance_pointer = instance_pointer_.?;
|
||||
var ptr = @ptrCast(
|
||||
*ZigType,
|
||||
@alignCast(
|
||||
@alignOf(
|
||||
*ZigType,
|
||||
),
|
||||
instance_pointer,
|
||||
),
|
||||
);
|
||||
|
||||
if (singleton) {
|
||||
inline for (function_names) |propname, i| {
|
||||
if (js.JSStringIsEqual(prop, function_name_refs[i])) {
|
||||
return instance_functions[i];
|
||||
}
|
||||
}
|
||||
if (comptime std.meta.trait.hasFn("onMissingProperty")(ZigType)) {
|
||||
return ptr.onMissingProperty(ctx, obj, prop, exception);
|
||||
}
|
||||
} else {
|
||||
inline for (property_names) |propname, i| {
|
||||
if (js.JSStringIsEqual(prop, property_name_refs[i])) {
|
||||
return @field(
|
||||
properties,
|
||||
propname,
|
||||
)(ptr, ctx, obj, exception);
|
||||
}
|
||||
}
|
||||
|
||||
if (comptime std.meta.trait.hasFn("onMissingProperty")(ZigType)) {
|
||||
return ptr.onMissingProperty(ctx, obj, prop, exception);
|
||||
}
|
||||
}
|
||||
|
||||
return js.JSValueMakeUndefined(ctx);
|
||||
}
|
||||
|
||||
fn StaticProperty(comptime id: usize) type {
|
||||
return struct {
|
||||
pub fn getter(
|
||||
ctx: js.JSContextRef,
|
||||
obj: js.JSObjectRef,
|
||||
prop: js.JSStringRef,
|
||||
exception: js.ExceptionRef,
|
||||
) callconv(.C) js.JSValueRef {
|
||||
var instance_pointer_ = js.JSObjectGetPrivate(obj);
|
||||
if (instance_pointer_ == null) return null;
|
||||
var this: *ZigType = @ptrCast(
|
||||
*ZigType,
|
||||
@alignCast(
|
||||
@alignOf(
|
||||
*ZigType,
|
||||
),
|
||||
instance_pointer_.?,
|
||||
),
|
||||
);
|
||||
|
||||
var exc: js.ExceptionRef = null;
|
||||
|
||||
switch (comptime @typeInfo(@TypeOf(@field(
|
||||
properties,
|
||||
property_names[id],
|
||||
)))) {
|
||||
.Fn => {
|
||||
return @field(
|
||||
properties,
|
||||
property_names[id],
|
||||
)(
|
||||
this,
|
||||
ctx,
|
||||
obj,
|
||||
exception,
|
||||
);
|
||||
},
|
||||
.Struct => {
|
||||
return @field(
|
||||
@field(
|
||||
properties,
|
||||
property_names[id],
|
||||
),
|
||||
"get",
|
||||
)(
|
||||
this,
|
||||
ctx,
|
||||
obj,
|
||||
prop,
|
||||
exception,
|
||||
);
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn setter(
|
||||
ctx: js.JSContextRef,
|
||||
obj: js.JSObjectRef,
|
||||
prop: js.JSStringRef,
|
||||
value: js.JSValueRef,
|
||||
exception: js.ExceptionRef,
|
||||
) callconv(.C) bool {
|
||||
var instance_pointer_ = js.JSObjectGetPrivate(obj);
|
||||
if (instance_pointer_ == null) return false;
|
||||
var this: *ZigType = @ptrCast(
|
||||
*ZigType,
|
||||
@alignCast(
|
||||
@alignOf(
|
||||
*ZigType,
|
||||
),
|
||||
instance_pointer_.?,
|
||||
),
|
||||
);
|
||||
|
||||
var exc: js.ExceptionRef = null;
|
||||
|
||||
switch (comptime @typeInfo(@TypeOf(@field(
|
||||
properties,
|
||||
property_names[id],
|
||||
)))) {
|
||||
.Struct => {
|
||||
return @field(
|
||||
@field(
|
||||
properties,
|
||||
property_names[id],
|
||||
),
|
||||
"set",
|
||||
)(
|
||||
this,
|
||||
ctx,
|
||||
obj,
|
||||
prop,
|
||||
value,
|
||||
exception,
|
||||
);
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub fn define() js.JSClassDefinition {
|
||||
var def = js.kJSClassDefinitionEmpty;
|
||||
|
||||
if (static_functions.len > 0) {
|
||||
std.mem.set(js.JSStaticFunction, &static_functions, std.mem.zeroes(js.JSStaticFunction));
|
||||
|
||||
inline for (function_name_literals) |function_name, i| {
|
||||
var callback = To.JS.Callback(ZigType, @field(staticFunctions, function_names[i])).rfn;
|
||||
|
||||
static_functions[i] = js.JSStaticFunction{
|
||||
.name = (function_names[i][0.. :0]).ptr,
|
||||
.callAsFunction = callback,
|
||||
.attributes = comptime if (read_only) js.JSPropertyAttributes.kJSPropertyAttributeReadOnly else js.JSPropertyAttributes.kJSPropertyAttributeNone,
|
||||
};
|
||||
// if (singleton) {
|
||||
// var function = js.JSObjectMakeFunctionWithCallback(ctx, function_name_refs[i], callback);
|
||||
// instance_functions[i] = function;
|
||||
// }
|
||||
}
|
||||
|
||||
def.staticFunctions = &static_functions;
|
||||
}
|
||||
|
||||
if (property_names.len > 0) {
|
||||
inline for (comptime property_name_literals) |prop_name, i| {
|
||||
property_name_refs[i] = js.JSStringCreateWithCharactersNoCopy(
|
||||
prop_name.ptr,
|
||||
prop_name.len,
|
||||
);
|
||||
static_properties[i] = std.mem.zeroes(js.JSStaticValue);
|
||||
static_properties[i].getProperty = StaticProperty(i).getter;
|
||||
|
||||
const field = comptime @field(properties, property_names[i]);
|
||||
const hasSetter = std.meta.trait.hasField("set");
|
||||
if (comptime hasSetter(@TypeOf(field))) {
|
||||
static_properties[i].setProperty = StaticProperty(i).setter;
|
||||
}
|
||||
static_properties[i].name = property_names[i][0.. :0];
|
||||
}
|
||||
|
||||
def.staticValues = (&static_properties);
|
||||
}
|
||||
|
||||
def.className = class_name_str;
|
||||
// def.getProperty = getPropertyCallback;
|
||||
|
||||
return def;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
399
src/javascript/jsc/webcore/response.zig
Normal file
399
src/javascript/jsc/webcore/response.zig
Normal file
@@ -0,0 +1,399 @@
|
||||
usingnamespace @import("../base.zig");
|
||||
const std = @import("std");
|
||||
const Api = @import("../../../api/schema.zig").Api;
|
||||
const http = @import("../../../http.zig");
|
||||
|
||||
pub const Response = struct {
|
||||
pub const Class = NewClass(
|
||||
Response,
|
||||
"Response",
|
||||
.{
|
||||
.@"constructor" = constructor,
|
||||
},
|
||||
.{
|
||||
// .@"url" = .{
|
||||
// .@"get" = getURL,
|
||||
// .ro = true,
|
||||
// },
|
||||
.@"ok" = .{
|
||||
.@"get" = getOK,
|
||||
.ro = true,
|
||||
},
|
||||
.@"status" = .{
|
||||
.@"get" = getStatus,
|
||||
.ro = true,
|
||||
},
|
||||
},
|
||||
false,
|
||||
false,
|
||||
);
|
||||
|
||||
pub var class_definition: js.JSClassDefinition = undefined;
|
||||
pub var class_ref: js.JSClassRef = undefined;
|
||||
pub var loaded = false;
|
||||
|
||||
pub fn load() void {
|
||||
if (!loaded) {
|
||||
class_definition = Class.define();
|
||||
class_ref = js.JSClassRetain(js.JSClassCreate(&class_definition));
|
||||
loaded = true;
|
||||
}
|
||||
}
|
||||
allocator: *std.mem.Allocator,
|
||||
body: Body,
|
||||
|
||||
pub const Props = struct {};
|
||||
|
||||
pub fn getOK(
|
||||
this: *Response,
|
||||
ctx: js.JSContextRef,
|
||||
thisObject: js.JSValueRef,
|
||||
prop: js.JSStringRef,
|
||||
exception: js.ExceptionRef,
|
||||
) js.JSValueRef {
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/Response/ok
|
||||
return js.JSValueMakeBoolean(ctx, this.body.init.status_code >= 200 and this.body.init.status_code <= 299);
|
||||
}
|
||||
|
||||
pub fn getStatus(
|
||||
this: *Response,
|
||||
ctx: js.JSContextRef,
|
||||
thisObject: js.JSValueRef,
|
||||
prop: js.JSStringRef,
|
||||
exception: js.ExceptionRef,
|
||||
) js.JSValueRef {
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/Response/status
|
||||
return js.JSValueMakeNumber(ctx, @intToFloat(f64, this.body.init.status_code));
|
||||
}
|
||||
|
||||
pub fn finalize(
|
||||
this: *Response,
|
||||
ctx: js.JSContextRef,
|
||||
) void {
|
||||
this.body.deinit(this.allocator);
|
||||
this.allocator.destroy(this);
|
||||
}
|
||||
|
||||
pub fn constructor(
|
||||
ctx: js.JSContextRef,
|
||||
function: js.JSObjectRef,
|
||||
arguments_len: usize,
|
||||
arguments_ptr: [*c]const js.JSValueRef,
|
||||
exception: js.ExceptionRef,
|
||||
) callconv(.C) js.JSObjectRef {
|
||||
const arguments = arguments_ptr[0..arguments_len];
|
||||
|
||||
const body = brk: {
|
||||
switch (arguments.len) {
|
||||
0 => {
|
||||
break :brk Body.@"404"(ctx);
|
||||
},
|
||||
1 => {
|
||||
break :brk Body.extract(ctx, arguments[0], exception);
|
||||
},
|
||||
else => {
|
||||
if (js.JSValueGetType(ctx, arguments[1]) == js.JSType.kJSTypeObject) {
|
||||
break :brk Body.extractWithInit(ctx, arguments[0], arguments[1], exception);
|
||||
} else {
|
||||
break :brk Body.extract(ctx, arguments[0], exception);
|
||||
}
|
||||
},
|
||||
}
|
||||
unreachable;
|
||||
};
|
||||
|
||||
if (exception != null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var allocator = getAllocator(ctx);
|
||||
var response = allocator.create(Response) catch return null;
|
||||
|
||||
response.* = Response{
|
||||
.body = body,
|
||||
.allocator = allocator,
|
||||
};
|
||||
return js.JSObjectMake(ctx, class_ref, response);
|
||||
}
|
||||
};
|
||||
|
||||
pub const Headers = struct {
|
||||
pub const Kv = struct {
|
||||
key: Api.StringPointer,
|
||||
value: Api.StringPointer,
|
||||
};
|
||||
pub const Entries = std.MultiArrayList(Kv);
|
||||
entries: Entries,
|
||||
buf: std.ArrayListUnmanaged(u8),
|
||||
allocator: *std.mem.Allocator,
|
||||
used: usize = 0,
|
||||
|
||||
fn appendString(this: *Headers, str: js.JSStringRef, comptime needs_lowercase: bool) Api.StringPointer {
|
||||
const ptr = Api.StringPointer{ .offset = this.used, .length = js.JSStringGetLength(str) };
|
||||
std.debug.assert(ptr.length > 0);
|
||||
std.debug.assert(this.buf.items.len >= ptr.offset + ptr.length);
|
||||
var slice = this.buf.items[ptr.offset][0..ptr.length];
|
||||
ptr.length = js.JSStringGetUTF8CString(this, slice.ptr, slice.len);
|
||||
if (needs_lowercase) {
|
||||
for (slice) |c, i| {
|
||||
slice[i] = std.ascii.toLower(c);
|
||||
}
|
||||
}
|
||||
|
||||
this.used += ptr.len;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
fn appendNumber(this: *Headers, num: f64) Api.StringPointer {
|
||||
const ptr = Api.StringPointer{ .offset = this.used, .length = std.fmt.count("{d}", num) };
|
||||
std.debug.assert(this.buf.items.len >= ptr.offset + ptr.length);
|
||||
var slice = this.buf.items[ptr.offset][0..ptr.length];
|
||||
ptr.length = std.fmt.bufPrint(slice, "{d}", num) catch 0;
|
||||
this.used += ptr.len;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
pub fn append(this: *Headers, ctx: js.JSContextRef, key: js.JSStringRef, comptime value_type: js.JSType, value: js.JSValueRef) !void {
|
||||
this.entries.append(this.allocator, Kv{
|
||||
.key = this.appendString(key, true),
|
||||
.value = switch (comptime value_type) {
|
||||
js.JSType.kJSTypeNumber => this.appendNumber(js.JSValueToNumber(ctx, value, null)),
|
||||
js.JSType.kJSTypeString => this.appendString(value, false),
|
||||
},
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/Body
|
||||
pub const Body = struct {
|
||||
init: Init,
|
||||
value: Value,
|
||||
|
||||
pub fn deinit(this: *Body, allocator: *std.mem.Allocator) void {
|
||||
if (this.init.headers) |headers| {
|
||||
headers.buf.deinit(headers.allocator);
|
||||
headers.entries.deinit(headers.allocator);
|
||||
}
|
||||
|
||||
switch (this.value) {
|
||||
.ArrayBuffer => {},
|
||||
.String => |str| {
|
||||
allocator.free(str);
|
||||
},
|
||||
.Empty => {},
|
||||
}
|
||||
}
|
||||
|
||||
pub const Init = struct {
|
||||
headers: ?Headers,
|
||||
status_code: u16,
|
||||
|
||||
pub fn init(allocator: *std.mem.Allocator, ctx: js.JSContextRef, init_ref: js.JSValueRef) !?Init {
|
||||
var result = Init{ .headers = null, .status_code = 0 };
|
||||
var array = js.JSObjectCopyPropertyNames(ctx, init_ref);
|
||||
defer js.JSPropertyNameArrayRelease(array);
|
||||
const count = js.JSPropertyNameArrayGetCount(array);
|
||||
var i: usize = 0;
|
||||
upper: while (i < count) : (i += 1) {
|
||||
var property_name_ref = js.JSPropertyNameArrayGetNameAtIndex(array, i);
|
||||
switch (js.JSStringGetLength(property_name_ref)) {
|
||||
"headers".len => {
|
||||
if (js.JSStringIsEqualToUTF8CString(property_name_ref, "headers")) {
|
||||
// only support headers as an object for now.
|
||||
if (js.JSObjectGetProperty(ctx, init_ref, property_name_ref, null)) |header_prop| {
|
||||
switch (js.JSValueGetType(ctx, header_prop)) {
|
||||
js.JSType.kJSTypeObject => {
|
||||
const header_keys = js.JSObjectCopyPropertyNames(ctx, header_prop);
|
||||
defer js.JSPropertyNameArrayRelease(header_keys);
|
||||
const total_header_count = js.JSPropertyNameArrayGetCount(array);
|
||||
if (total_header_count == 0) continue :upper;
|
||||
|
||||
// 2 passes through the headers
|
||||
|
||||
// Pass #1: find the "real" count.
|
||||
// The number of things which are strings or numbers.
|
||||
// Anything else should be ignored.
|
||||
// We could throw a TypeError, but ignoring silently is more JavaScript-like imo
|
||||
var real_header_count: usize = 0;
|
||||
var estimated_buffer_len: usize = 0;
|
||||
var j: usize = 0;
|
||||
while (j < total_header_count) : (j += 1) {
|
||||
var key_ref = js.JSPropertyNameArrayGetNameAtIndex(j);
|
||||
var value_ref = js.JSObjectGetProperty(ctx, header_prop, key_ref, null);
|
||||
|
||||
switch (js.JSValueGetType(ctx, value_ref)) {
|
||||
js.JSType.kJSTypeNumber => {
|
||||
const key_len = js.JSStringGetLength(key_ref);
|
||||
if (key_len > 0) {
|
||||
real_header_count += 1;
|
||||
estimated_buffer_len += key_len;
|
||||
estimated_buffer_len += std.fmt.count("{d}", .{js.JSValueToNumber(ctx, value_ref, null)});
|
||||
}
|
||||
},
|
||||
js.JSType.kJSTypeString => {
|
||||
const value_len = js.JSStringGetLength(value_ref);
|
||||
if (key_len > 0 and value_len > 0) {
|
||||
real_header_count += 1;
|
||||
estimated_buffer_len += key_len + value_len;
|
||||
}
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
|
||||
if (real_header_count == 0 or estimated_buffer_len == 0) continue :upper;
|
||||
|
||||
j = 0;
|
||||
var headers = Headers{
|
||||
.buf = try std.ArrayList(u8).initCapacity(allocator, estimated_buffer_len),
|
||||
.entries = std.mem.zeroes(Headers.Entries),
|
||||
};
|
||||
errdefer headers.deinit();
|
||||
try headers.entries.ensureTotalCapacity(allocator, real_header_count);
|
||||
|
||||
while (j < total_header_count) : (j += 1) {
|
||||
var key_ref = js.JSPropertyNameArrayGetNameAtIndex(j);
|
||||
var value_ref = js.JSObjectGetProperty(ctx, header_prop, key_ref, null);
|
||||
|
||||
switch (js.JSValueGetType(ctx, value_ref)) {
|
||||
js.JSType.kJSTypeNumber => {
|
||||
if (js.JSStringGetLength(key_ref) == 0) continue;
|
||||
try headers.append(ctx, key_ref, .kJSTypeNumber, value_ref);
|
||||
},
|
||||
js.JSType.kJSTypeString => {
|
||||
if (js.JSStringGetLength(value_ref) == 0 or js.JSStringGetLength(key_ref) == 0) continue;
|
||||
try headers.append(ctx, key_ref, .kJSTypeString, value_ref);
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
result.headers = headers;
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"statusCode".len => {
|
||||
if (js.JSStringIsEqualToUTF8CString(property_name_ref, "statusCode")) {
|
||||
var value_ref = js.JSObjectGetProperty(ctx, header_prop, key_ref, null);
|
||||
var exception: js.JSValueRef = null;
|
||||
const number = js.JSValueToNumber(ctx, value_ref, &exception);
|
||||
if (exception != null or !std.math.isFinite(number)) continue;
|
||||
result.status_code = @truncate(u16, @floatToInt(u64, number));
|
||||
}
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
|
||||
if (result.headers == null and result.status_code < 200) return null;
|
||||
return result;
|
||||
}
|
||||
};
|
||||
pub const Value = union(Tag) {
|
||||
ArrayBuffer: ArrayBuffer,
|
||||
String: string,
|
||||
Empty: u0,
|
||||
pub const Tag = enum {
|
||||
ArrayBuffer,
|
||||
String,
|
||||
Empty,
|
||||
};
|
||||
};
|
||||
|
||||
pub fn @"404"(ctx: js.JSContextRef) Body {
|
||||
return Body{ .init = Init{
|
||||
.headers = null,
|
||||
.status_code = 404,
|
||||
}, .value = .{ .Empty = 0 } };
|
||||
}
|
||||
|
||||
pub fn extract(ctx: js.JSContextRef, body_ref: js.JSObjectRef, exception: ExceptionValueRef) Body {
|
||||
return extractBody(ctx, body_ref, false, null);
|
||||
}
|
||||
|
||||
pub fn extractWithInit(ctx: js.JSContextRef, body_ref: js.JSObjectRef, init_ref: js.JSValueRef, exception: ExceptionValueRef) Body {
|
||||
return extractBody(ctx, body_ref, true, init_ref);
|
||||
}
|
||||
|
||||
// https://github.com/WebKit/webkit/blob/main/Source/WebCore/Modules/fetch/FetchBody.cpp#L45
|
||||
inline fn extractBody(
|
||||
ctx: js.JSContextRef,
|
||||
body_ref: js.JSObjectRef,
|
||||
comptime has_init: bool,
|
||||
init_ref: js.JSValueRef,
|
||||
exception: ExceptionValueRef,
|
||||
) Body {
|
||||
var body = Body{ .init = Init{ .headers = null, .status_code = 200 }, .value = .{ .Empty = 0 } };
|
||||
|
||||
switch (js.JSValueGetType(ctx, body_ref)) {
|
||||
js.kJSTypeString => {
|
||||
if (exception == null) {
|
||||
var allocator = getAllocator(ctx);
|
||||
|
||||
if (has_init) {
|
||||
body.init = Init.init(allocator, ctx, init_ref.?) catch unreachable;
|
||||
}
|
||||
const len = js.JSStringGetLength(body_ref);
|
||||
if (len == 0) {
|
||||
body.value = .{ .String = "" };
|
||||
return body;
|
||||
}
|
||||
|
||||
var str = try allocator.alloc(u8, len);
|
||||
|
||||
body.value = Value{ .String = str[0..js.JSStringGetUTF8CString(body_ref, str.ptr, len)] };
|
||||
return body;
|
||||
}
|
||||
},
|
||||
js.kJSTypeObject => {
|
||||
const typed_array = js.JSValueGetTypedArrayType(ctx, body_ref, exception);
|
||||
switch (typed_array) {
|
||||
js.JSTypedArrayType.kJSTypedArrayTypeNone => {},
|
||||
else => {
|
||||
const buffer = ArrayBuffer{
|
||||
.ptr = js.JSObjectGetTypedArrayBytesPtr(ctx, body_ref, exception),
|
||||
.offset = js.JSObjectGetTypedArrayByteOffset(ctx, body_ref, exception),
|
||||
.len = js.JSObjectGetTypedArrayLength(ctx, body_ref, exception),
|
||||
.byte_len = js.JSObjectGetTypedArrayLength(ctx, body_ref, exception),
|
||||
.typed_array_type = typed_array,
|
||||
};
|
||||
if (exception == null) {
|
||||
if (has_init) {
|
||||
body.init = Init.init(allocator, ctx, init_ref.?) catch unreachable;
|
||||
}
|
||||
body.value = Value{ .ArrayBuffer = buffer };
|
||||
return body;
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
|
||||
if (exception == null) {
|
||||
JSError(getAllocator(allocator), "Body must be a string or a TypedArray (for now)", .{}, ctx, exception);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
pub const FetchEvent = struct {
|
||||
started_waiting_at: u64 = 0,
|
||||
response: ?*Response = null,
|
||||
request_context: *http.RequestContext,
|
||||
|
||||
pub const Class = NewClass(
|
||||
FetchEvent,
|
||||
"FetchEvent",
|
||||
.{ .@"respondWith" = respondWith, .@"waitUntil" = waitUntil },
|
||||
.{
|
||||
.@"client" = getClient,
|
||||
.@"request" = getRequest,
|
||||
},
|
||||
true,
|
||||
false,
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user