mirror of
https://github.com/oven-sh/bun
synced 2026-02-10 02:48:50 +00:00
1505 lines
59 KiB
Zig
1505 lines
59 KiB
Zig
pub const js = @import("./JavaScriptCore.zig");
|
|
const std = @import("std");
|
|
pub usingnamespace @import("../../global.zig");
|
|
usingnamespace @import("./javascript.zig");
|
|
usingnamespace @import("./webcore/response.zig");
|
|
const Router = @import("./api/router.zig");
|
|
|
|
const TaggedPointerTypes = @import("../../tagged_pointer.zig");
|
|
const TaggedPointerUnion = TaggedPointerTypes.TaggedPointerUnion;
|
|
|
|
pub const ExceptionValueRef = [*c]js.JSValueRef;
|
|
pub const JSValueRef = js.JSValueRef;
|
|
|
|
fn ObjectPtrType(comptime Type: type) type {
|
|
if (Type == void) return Type;
|
|
return *Type;
|
|
}
|
|
|
|
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: ObjectPtrType(ZigContextType),
|
|
name: js.JSStringRef,
|
|
ctx: js.JSContextRef,
|
|
comptime callback: fn (
|
|
obj: ObjectPtrType(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);
|
|
std.debug.assert(js.JSObjectSetPrivate(
|
|
function,
|
|
JSPrivateDataPtr.init(zig).ptr(),
|
|
));
|
|
return function;
|
|
}
|
|
|
|
pub fn Finalize(
|
|
comptime ZigContextType: type,
|
|
comptime ctxfn: fn (
|
|
this: ObjectPtrType(ZigContextType),
|
|
) void,
|
|
) type {
|
|
return struct {
|
|
pub fn rfn(
|
|
object: js.JSObjectRef,
|
|
) callconv(.C) void {
|
|
return ctxfn(
|
|
GetJSPrivateData(ZigContextType, object) orelse return,
|
|
);
|
|
}
|
|
};
|
|
}
|
|
|
|
pub fn Constructor(
|
|
comptime ctxfn: fn (
|
|
ctx: js.JSContextRef,
|
|
function: js.JSObjectRef,
|
|
arguments: []const js.JSValueRef,
|
|
exception: js.ExceptionRef,
|
|
) js.JSValueRef,
|
|
) type {
|
|
return struct {
|
|
pub fn rfn(
|
|
ctx: js.JSContextRef,
|
|
function: js.JSObjectRef,
|
|
argumentCount: usize,
|
|
arguments: [*c]const js.JSValueRef,
|
|
exception: js.ExceptionRef,
|
|
) callconv(.C) js.JSValueRef {
|
|
return ctxfn(
|
|
ctx,
|
|
function,
|
|
if (arguments) |args| args[0..argumentCount] else &[_]js.JSValueRef{},
|
|
exception,
|
|
);
|
|
}
|
|
};
|
|
}
|
|
pub fn ConstructorCallback(
|
|
comptime ctxfn: fn (
|
|
ctx: js.JSContextRef,
|
|
function: js.JSObjectRef,
|
|
arguments: []const js.JSValueRef,
|
|
exception: js.ExceptionRef,
|
|
) js.JSValueRef,
|
|
) type {
|
|
return struct {
|
|
pub fn rfn(
|
|
ctx: js.JSContextRef,
|
|
function: js.JSObjectRef,
|
|
argumentCount: usize,
|
|
arguments: [*c]const js.JSValueRef,
|
|
exception: js.ExceptionRef,
|
|
) callconv(.C) js.JSValueRef {
|
|
return ctxfn(
|
|
ctx,
|
|
function,
|
|
if (arguments) |args| args[0..argumentCount] else &[_]js.JSValueRef{},
|
|
exception,
|
|
);
|
|
}
|
|
};
|
|
}
|
|
|
|
pub fn Callback(
|
|
comptime ZigContextType: type,
|
|
comptime ctxfn: fn (
|
|
obj: ObjectPtrType(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: *c_void = undefined;
|
|
|
|
if (comptime ZigContextType == c_void) {
|
|
return ctxfn(
|
|
js.JSObjectGetPrivate(function) or js.jsObjectGetPrivate(thisObject),
|
|
ctx,
|
|
function,
|
|
thisObject,
|
|
if (arguments) |args| args[0..argumentCount] else &[_]js.JSValueRef{},
|
|
exception,
|
|
);
|
|
} else if (comptime ZigContextType == void) {
|
|
return ctxfn(
|
|
void{},
|
|
ctx,
|
|
function,
|
|
thisObject,
|
|
if (arguments) |args| args[0..argumentCount] else &[_]js.JSValueRef{},
|
|
exception,
|
|
);
|
|
} else {
|
|
return ctxfn(
|
|
GetJSPrivateData(ZigContextType, function) orelse GetJSPrivateData(ZigContextType, thisObject) orelse return js.JSValueMakeUndefined(ctx),
|
|
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 inline fn ptr(comptime StructType: type, obj: js.JSObjectRef) *StructType {
|
|
return GetJSPrivateData(StructType, obj).?;
|
|
}
|
|
};
|
|
};
|
|
|
|
pub const Properties = struct {
|
|
pub const UTF8 = struct {
|
|
pub var filepath: string = "filepath";
|
|
|
|
pub const module: string = "module";
|
|
pub const globalThis: string = "globalThis";
|
|
pub const exports: string = "exports";
|
|
pub const log: string = "log";
|
|
pub const debug: string = "debug";
|
|
pub const name: string = "name";
|
|
pub const info: string = "info";
|
|
pub const error_: string = "error";
|
|
pub const warn: string = "warn";
|
|
pub const console: string = "console";
|
|
pub const require: string = "require";
|
|
pub const description: string = "description";
|
|
pub const initialize_bundled_module: string = "$$m";
|
|
pub const load_module_function: string = "$lOaDuRcOdE$";
|
|
pub const window: string = "window";
|
|
pub const default: string = "default";
|
|
pub const include: string = "include";
|
|
|
|
pub const env: string = "env";
|
|
|
|
pub const GET = "GET";
|
|
pub const PUT = "PUT";
|
|
pub const POST = "POST";
|
|
pub const PATCH = "PATCH";
|
|
pub const HEAD = "HEAD";
|
|
pub const OPTIONS = "OPTIONS";
|
|
|
|
pub const navigate = "navigate";
|
|
pub const follow = "follow";
|
|
};
|
|
|
|
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 default: []c_ushort = std.unicode.utf8ToUtf16LeStringLiteral(UTF8.default);
|
|
pub const include: []c_ushort = std.unicode.utf8ToUtf16LeStringLiteral(UTF8.include);
|
|
|
|
pub const GET: []c_ushort = std.unicode.utf8ToUtf16LeStringLiteral(UTF8.GET);
|
|
pub const PUT: []c_ushort = std.unicode.utf8ToUtf16LeStringLiteral(UTF8.PUT);
|
|
pub const POST: []c_ushort = std.unicode.utf8ToUtf16LeStringLiteral(UTF8.POST);
|
|
pub const PATCH: []c_ushort = std.unicode.utf8ToUtf16LeStringLiteral(UTF8.PATCH);
|
|
pub const HEAD: []c_ushort = std.unicode.utf8ToUtf16LeStringLiteral(UTF8.HEAD);
|
|
pub const OPTIONS: []c_ushort = std.unicode.utf8ToUtf16LeStringLiteral(UTF8.OPTIONS);
|
|
|
|
pub const navigate: []c_ushort = std.unicode.utf8ToUtf16LeStringLiteral(UTF8.navigate);
|
|
pub const follow: []c_ushort = std.unicode.utf8ToUtf16LeStringLiteral(UTF8.follow);
|
|
};
|
|
|
|
pub const Refs = struct {
|
|
pub var filepath: js.JSStringRef = undefined;
|
|
|
|
pub var module: js.JSStringRef = undefined;
|
|
pub var globalThis: js.JSStringRef = undefined;
|
|
pub var exports: js.JSStringRef = undefined;
|
|
pub var log: js.JSStringRef = undefined;
|
|
pub var debug: js.JSStringRef = undefined;
|
|
pub var info: js.JSStringRef = undefined;
|
|
pub var error_: js.JSStringRef = undefined;
|
|
pub var warn: js.JSStringRef = undefined;
|
|
pub var console: js.JSStringRef = undefined;
|
|
pub var require: js.JSStringRef = undefined;
|
|
pub var description: js.JSStringRef = undefined;
|
|
pub var name: js.JSStringRef = undefined;
|
|
pub var initialize_bundled_module: js.JSStringRef = undefined;
|
|
pub var load_module_function: js.JSStringRef = undefined;
|
|
pub var window: js.JSStringRef = undefined;
|
|
pub var default: js.JSStringRef = undefined;
|
|
pub var include: js.JSStringRef = undefined;
|
|
pub var GET: js.JSStringRef = undefined;
|
|
pub var PUT: js.JSStringRef = undefined;
|
|
pub var POST: js.JSStringRef = undefined;
|
|
pub var PATCH: js.JSStringRef = undefined;
|
|
pub var HEAD: js.JSStringRef = undefined;
|
|
pub var OPTIONS: js.JSStringRef = undefined;
|
|
|
|
pub var empty_string_ptr = [_]u8{0};
|
|
pub var empty_string: js.JSStringRef = undefined;
|
|
|
|
pub var navigate: js.JSStringRef = undefined;
|
|
pub var follow: js.JSStringRef = undefined;
|
|
|
|
pub const env: js.JSStringRef = undefined;
|
|
};
|
|
|
|
pub fn init() void {
|
|
inline for (std.meta.fieldNames(UTF8)) |name| {
|
|
@field(Refs, name) = js.JSStringCreateStatic(
|
|
@field(UTF8, name).ptr,
|
|
@field(UTF8, name).len,
|
|
);
|
|
|
|
if (comptime isDebug) {
|
|
std.debug.assert(
|
|
js.JSStringIsEqualToString(@field(Refs, name), @field(UTF8, name).ptr, @field(UTF8, name).len),
|
|
);
|
|
}
|
|
}
|
|
|
|
Refs.empty_string = js.JSStringCreateWithUTF8CString(&Refs.empty_string_ptr);
|
|
}
|
|
};
|
|
|
|
const hasSetter = std.meta.trait.hasField("set");
|
|
const hasReadOnly = std.meta.trait.hasField("ro");
|
|
const hasFinalize = std.meta.trait.hasField("finalize");
|
|
|
|
const hasTypeScriptField = std.meta.trait.hasField("ts");
|
|
fn hasTypeScript(comptime Type: type) bool {
|
|
if (hasTypeScriptField(Type)) {
|
|
return true;
|
|
}
|
|
|
|
return @hasDecl(Type, "ts");
|
|
}
|
|
|
|
fn getTypeScript(comptime Type: type, value: Type) d.ts.or_decl {
|
|
if (comptime hasTypeScriptField(Type)) {
|
|
if (@TypeOf(Type.ts) == d.ts.decl) {
|
|
return d.ts.or_decl{ .decl = value };
|
|
} else {
|
|
return d.ts.or_decl{ .ts = value.ts };
|
|
}
|
|
}
|
|
|
|
if (@TypeOf(Type.ts) == d.ts.decl) {
|
|
return d.ts.or_decl{ .decl = Type.ts };
|
|
} else {
|
|
return d.ts.or_decl{ .ts = value.ts };
|
|
}
|
|
}
|
|
|
|
pub const d = struct {
|
|
pub const ts = struct {
|
|
@"return": string = "unknown",
|
|
tsdoc: string = "",
|
|
name: string = "",
|
|
read_only: ?bool = null,
|
|
args: []const arg = &[_]arg{},
|
|
splat_args: bool = false,
|
|
|
|
pub const or_decl = union(Tag) {
|
|
ts: ts,
|
|
decl: decl,
|
|
pub const Tag = enum { ts, decl };
|
|
};
|
|
|
|
pub const decl = union(Tag) {
|
|
module: module,
|
|
class: class,
|
|
empty: u0,
|
|
pub const Tag = enum { module, class, empty };
|
|
};
|
|
|
|
pub const module = struct {
|
|
tsdoc: string = "",
|
|
read_only: ?bool = null,
|
|
path: string = "",
|
|
global: bool = false,
|
|
|
|
properties: []ts = &[_]ts{},
|
|
functions: []ts = &[_]ts{},
|
|
classes: []class = &[_]class{},
|
|
};
|
|
|
|
pub const class = struct {
|
|
name: string = "",
|
|
tsdoc: string = "",
|
|
@"return": string = "",
|
|
read_only: ?bool = null,
|
|
interface: bool = true,
|
|
default_export: bool = false,
|
|
|
|
properties: []ts = &[_]ts{},
|
|
functions: []ts = &[_]ts{},
|
|
|
|
pub const Printer = struct {
|
|
const indent_level = 2;
|
|
pub fn printIndented(comptime fmt: string, args: anytype, comptime indent: usize) string {
|
|
comptime var buf: string = "";
|
|
comptime buf = buf ++ " " ** indent;
|
|
|
|
return comptime buf ++ std.fmt.comptimePrint(fmt, args);
|
|
}
|
|
|
|
pub fn printVar(comptime property: d.ts, comptime indent: usize) string {
|
|
comptime var buf: string = "";
|
|
comptime buf = buf ++ " " ** indent;
|
|
|
|
comptime {
|
|
if (property.read_only orelse false) {
|
|
buf = buf ++ "readonly ";
|
|
}
|
|
|
|
buf = buf ++ "var ";
|
|
buf = buf ++ property.name;
|
|
buf = buf ++ ": ";
|
|
|
|
if (property.@"return".len > 0) {
|
|
buf = buf ++ property.@"return";
|
|
} else {
|
|
buf = buf ++ "any";
|
|
}
|
|
|
|
buf = buf ++ ";\n";
|
|
}
|
|
|
|
comptime {
|
|
if (property.tsdoc.len > 0) {
|
|
buf = printTSDoc(property.tsdoc, indent) ++ buf;
|
|
}
|
|
}
|
|
|
|
return buf;
|
|
}
|
|
|
|
pub fn printProperty(comptime property: d.ts, comptime indent: usize) string {
|
|
comptime var buf: string = "";
|
|
comptime buf = buf ++ " " ** indent;
|
|
|
|
comptime {
|
|
if (property.read_only orelse false) {
|
|
buf = buf ++ "readonly ";
|
|
}
|
|
|
|
buf = buf ++ property.name;
|
|
buf = buf ++ ": ";
|
|
|
|
if (property.@"return".len > 0) {
|
|
buf = buf ++ property.@"return";
|
|
} else {
|
|
buf = buf ++ "any";
|
|
}
|
|
|
|
buf = buf ++ ";\n";
|
|
}
|
|
|
|
comptime {
|
|
if (property.tsdoc.len > 0) {
|
|
buf = printTSDoc(property.tsdoc, indent) ++ buf;
|
|
}
|
|
}
|
|
|
|
return buf;
|
|
}
|
|
pub fn printInstanceFunction(comptime func: d.ts, comptime _indent: usize, comptime no_type: bool) string {
|
|
comptime var indent = _indent;
|
|
comptime var buf: string = "";
|
|
|
|
comptime {
|
|
var args: string = "";
|
|
for (func.args) |a, i| {
|
|
if (i > 0) {
|
|
args = args ++ ", ";
|
|
}
|
|
args = args ++ printArg(a);
|
|
}
|
|
|
|
if (no_type) {
|
|
buf = buf ++ printIndented("{s}({s});\n", .{
|
|
func.name,
|
|
args,
|
|
}, indent);
|
|
} else {
|
|
buf = buf ++ printIndented("{s}({s}): {s};\n", .{
|
|
func.name,
|
|
args,
|
|
func.@"return",
|
|
}, indent);
|
|
}
|
|
}
|
|
|
|
comptime {
|
|
if (func.tsdoc.len > 0) {
|
|
buf = printTSDoc(func.tsdoc, indent) ++ buf;
|
|
}
|
|
}
|
|
|
|
return buf;
|
|
}
|
|
pub fn printFunction(comptime func: d.ts, comptime _indent: usize, comptime no_type: bool) string {
|
|
comptime var indent = _indent;
|
|
comptime var buf: string = "";
|
|
|
|
comptime {
|
|
var args: string = "";
|
|
for (func.args) |a, i| {
|
|
if (i > 0) {
|
|
args = args ++ ", ";
|
|
}
|
|
args = args ++ printArg(a);
|
|
}
|
|
|
|
if (no_type) {
|
|
buf = buf ++ printIndented("function {s}({s});\n", .{
|
|
func.name,
|
|
args,
|
|
}, indent);
|
|
} else {
|
|
buf = buf ++ printIndented("function {s}({s}): {s};\n", .{
|
|
func.name,
|
|
args,
|
|
func.@"return",
|
|
}, indent);
|
|
}
|
|
}
|
|
|
|
comptime {
|
|
if (func.tsdoc.len > 0) {
|
|
buf = printTSDoc(func.tsdoc, indent) ++ buf;
|
|
}
|
|
}
|
|
|
|
return buf;
|
|
}
|
|
pub fn printArg(
|
|
comptime _arg: d.ts.arg,
|
|
) string {
|
|
comptime var buf: string = "";
|
|
comptime {
|
|
buf = buf ++ _arg.name;
|
|
buf = buf ++ ": ";
|
|
|
|
if (_arg.@"return".len == 0) {
|
|
buf = buf ++ "any";
|
|
} else {
|
|
buf = buf ++ _arg.@"return";
|
|
}
|
|
}
|
|
|
|
return buf;
|
|
}
|
|
|
|
pub fn printDecl(comptime klass: d.ts.decl, comptime _indent: usize) string {
|
|
return comptime switch (klass) {
|
|
.module => |mod| printModule(mod, _indent),
|
|
.class => |cla| printClass(cla, _indent),
|
|
.empty => "",
|
|
};
|
|
}
|
|
|
|
pub fn printModule(comptime klass: d.ts.module, comptime _indent: usize) string {
|
|
comptime var indent = _indent;
|
|
comptime var buf: string = "";
|
|
comptime brk: {
|
|
if (klass.tsdoc.len > 0) {
|
|
buf = buf ++ printTSDoc(klass.tsdoc, indent);
|
|
}
|
|
|
|
if (klass.global) {
|
|
buf = buf ++ printIndented("declare global {{\n", .{}, indent);
|
|
} else {
|
|
buf = buf ++ printIndented("declare module \"{s}\" {{\n", .{klass.path}, indent);
|
|
}
|
|
|
|
indent += indent_level;
|
|
|
|
for (klass.properties) |property, i| {
|
|
if (i > 0) {
|
|
buf = buf ++ "\n";
|
|
}
|
|
|
|
buf = buf ++ printVar(property, indent);
|
|
}
|
|
|
|
buf = buf ++ "\n";
|
|
|
|
for (klass.functions) |func, i| {
|
|
if (i > 0) {
|
|
buf = buf ++ "\n";
|
|
}
|
|
|
|
buf = buf ++ printFunction(
|
|
func,
|
|
indent,
|
|
false,
|
|
);
|
|
}
|
|
|
|
for (klass.classes) |func, i| {
|
|
if (i > 0) {
|
|
buf = buf ++ "\n";
|
|
}
|
|
|
|
buf = buf ++ printClass(
|
|
func,
|
|
indent,
|
|
);
|
|
}
|
|
|
|
indent -= indent_level;
|
|
|
|
buf = buf ++ printIndented("}}\n", .{}, indent);
|
|
|
|
break :brk;
|
|
}
|
|
return comptime buf;
|
|
}
|
|
|
|
pub fn printClass(comptime klass: d.ts.class, comptime _indent: usize) string {
|
|
comptime var indent = _indent;
|
|
comptime var buf: string = "";
|
|
comptime brk: {
|
|
if (klass.tsdoc.len > 0) {
|
|
buf = buf ++ printTSDoc(klass.tsdoc, indent);
|
|
}
|
|
|
|
const qualifier = if (!klass.default_export) "export " else "";
|
|
var stmt: string = qualifier;
|
|
|
|
if (klass.interface) {
|
|
buf = buf ++ printIndented("export interface {s} {{\n", .{klass.name}, indent);
|
|
} else {
|
|
buf = buf ++ printIndented("{s}class {s} {{\n", .{ qualifier, klass.name }, indent);
|
|
}
|
|
|
|
indent += indent_level;
|
|
|
|
var did_print_constructor = false;
|
|
for (klass.functions) |func, i| {
|
|
if (!strings.eqlComptime(func.name, "constructor")) continue;
|
|
did_print_constructor = true;
|
|
buf = buf ++ printInstanceFunction(
|
|
func,
|
|
indent,
|
|
!klass.interface,
|
|
);
|
|
}
|
|
|
|
for (klass.properties) |property, i| {
|
|
if (i > 0 or did_print_constructor) {
|
|
buf = buf ++ "\n";
|
|
}
|
|
|
|
buf = buf ++ printProperty(property, indent);
|
|
}
|
|
|
|
buf = buf ++ "\n";
|
|
|
|
for (klass.functions) |func, i| {
|
|
if (i > 0) {
|
|
buf = buf ++ "\n";
|
|
}
|
|
|
|
if (strings.eqlComptime(func.name, "constructor")) continue;
|
|
|
|
buf = buf ++ printInstanceFunction(
|
|
func,
|
|
indent,
|
|
false,
|
|
);
|
|
}
|
|
|
|
indent -= indent_level;
|
|
|
|
buf = buf ++ printIndented("}}\n", .{}, indent);
|
|
|
|
if (klass.default_export) {
|
|
buf = buf ++ printIndented("export = {s};\n", .{klass.name}, indent);
|
|
}
|
|
|
|
break :brk;
|
|
}
|
|
return comptime buf;
|
|
}
|
|
|
|
pub fn printTSDoc(comptime str: string, comptime indent: usize) string {
|
|
comptime var buf: string = "";
|
|
|
|
comptime brk: {
|
|
var splitter = std.mem.split(str, "\n");
|
|
|
|
const first = splitter.next() orelse break :brk;
|
|
const second = splitter.next() orelse {
|
|
buf = buf ++ printIndented("/** {s} */\n", .{std.mem.trim(u8, first, " ")}, indent);
|
|
break :brk;
|
|
};
|
|
buf = buf ++ printIndented("/**\n", .{}, indent);
|
|
buf = buf ++ printIndented(" * {s}\n", .{std.mem.trim(u8, first, " ")}, indent);
|
|
buf = buf ++ printIndented(" * {s}\n", .{std.mem.trim(u8, second, " ")}, indent);
|
|
while (splitter.next()) |line| {
|
|
buf = buf ++ printIndented(" * {s}\n", .{std.mem.trim(u8, line, " ")}, indent);
|
|
}
|
|
buf = buf ++ printIndented("*/\n", .{}, indent);
|
|
}
|
|
|
|
return buf;
|
|
}
|
|
};
|
|
};
|
|
|
|
pub const arg = struct {
|
|
name: string = "",
|
|
@"return": string = "any",
|
|
optional: bool = false,
|
|
};
|
|
};
|
|
};
|
|
|
|
// This should only exist at compile-time.
|
|
pub const ClassOptions = struct {
|
|
name: string,
|
|
|
|
read_only: bool = false,
|
|
singleton: bool = false,
|
|
ts: d.ts.decl = d.ts.decl{ .empty = 0 },
|
|
};
|
|
|
|
pub fn NewClass(
|
|
comptime ZigType: type,
|
|
comptime options: ClassOptions,
|
|
comptime staticFunctions: anytype,
|
|
comptime properties: anytype,
|
|
) type {
|
|
const read_only = options.read_only;
|
|
const singleton = options.singleton;
|
|
|
|
return struct {
|
|
const name = options.name;
|
|
const ClassDefinitionCreator = @This();
|
|
const function_names = std.meta.fieldNames(@TypeOf(staticFunctions));
|
|
const function_name_literals = function_names;
|
|
var function_name_refs: [function_names.len]js.JSStringRef = undefined;
|
|
var class_name_str = name[0.. :0].ptr;
|
|
|
|
var static_functions = brk: {
|
|
var funcs: [function_name_refs.len + 1]js.JSStaticFunction = undefined;
|
|
std.mem.set(js.JSStaticFunction, &funcs, js.JSStaticFunction{
|
|
.name = @intToPtr([*c]const u8, 0),
|
|
.callAsFunction = null,
|
|
.attributes = js.JSPropertyAttributes.kJSPropertyAttributeNone,
|
|
},);
|
|
break :brk funcs;
|
|
};
|
|
var instance_functions = std.mem.zeroes([function_names.len]js.JSObjectRef);
|
|
const property_names = std.meta.fieldNames(@TypeOf(properties));
|
|
var property_name_refs = std.mem.zeroes([property_names.len]js.JSStringRef);
|
|
const property_name_literals = property_names;
|
|
var static_properties = brk: {
|
|
var props: [property_names.len]js.JSStaticValue = undefined;
|
|
std.mem.set(js.JSStaticValue, &props, js.JSStaticValue{
|
|
.name = @intToPtr([*c]const u8, 0),
|
|
.getProperty = null,
|
|
.setProperty = null,
|
|
.attributes = js.JSPropertyAttributes.kJSPropertyAttributeNone,
|
|
},);
|
|
break :brk props;
|
|
};
|
|
|
|
pub var ref: js.JSClassRef = null;
|
|
pub var loaded = false;
|
|
pub var definition: js.JSClassDefinition =.{
|
|
.version = 0,
|
|
.attributes = js.JSClassAttributes.kJSClassAttributeNone,
|
|
.className = name[0..:0].ptr,
|
|
.parentClass = null,
|
|
.staticValues = null,
|
|
.staticFunctions = null,
|
|
.initialize = null,
|
|
.finalize = null,
|
|
.hasProperty = null,
|
|
.getProperty = null,
|
|
.setProperty = null,
|
|
.deleteProperty = null,
|
|
.getPropertyNames = null,
|
|
.callAsFunction = null,
|
|
.callAsConstructor = null,
|
|
.hasInstance = null,
|
|
.convertToType = null,
|
|
};
|
|
const ConstructorWrapper = 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 {
|
|
return definition.callAsConstructor.?(ctx, function, argumentCount, arguments, exception);
|
|
}
|
|
};
|
|
|
|
pub fn throwInvalidConstructorError(ctx: js.JSContextRef, obj: js.JSObjectRef, c: usize, a: [*c]const js.JSValueRef, exception: js.ExceptionRef) callconv(.C) js.JSObjectRef {
|
|
JSError(getAllocator(ctx), "" ++ name ++ " is not a constructor", .{}, ctx, exception);
|
|
return null;
|
|
}
|
|
|
|
pub fn throwInvalidFunctionError(
|
|
ctx: js.JSContextRef,
|
|
function: js.JSObjectRef,
|
|
thisObject: js.JSObjectRef,
|
|
argumentCount: usize,
|
|
arguments: [*c]const js.JSValueRef,
|
|
exception: js.ExceptionRef,
|
|
) callconv(.C) js.JSValueRef {
|
|
JSError(getAllocator(ctx), "" ++ name ++ " is not a function", .{}, ctx, exception);
|
|
return null;
|
|
}
|
|
|
|
pub const Constructor = ConstructorWrapper.rfn;
|
|
|
|
pub const static_value_count = static_properties.len;
|
|
|
|
pub fn get() callconv(.C) [*c]js.JSClassRef {
|
|
if (!loaded) {
|
|
loaded = true;
|
|
definition = define();
|
|
ref = js.JSClassCreate(&definition);
|
|
}
|
|
|
|
_ = js.JSClassRetain(ref);
|
|
|
|
return &ref;
|
|
}
|
|
|
|
pub fn RawGetter(comptime ReceiverType: type) type {
|
|
const ClassGetter = struct {
|
|
pub fn getter(
|
|
ctx: js.JSContextRef,
|
|
obj: js.JSObjectRef,
|
|
prop: js.JSStringRef,
|
|
exception: js.ExceptionRef,
|
|
) callconv(.C) js.JSValueRef {
|
|
return js.JSObjectMake(ctx, get().*, null);
|
|
}
|
|
};
|
|
|
|
return ClassGetter;
|
|
}
|
|
|
|
pub fn customHasInstance(ctx: js.JSContextRef, obj: js.JSObjectRef, value: js.JSValueRef, exception: js.ExceptionRef) callconv(.C) bool {
|
|
return js.JSValueIsObjectOfClass(ctx, value, get().*);
|
|
}
|
|
|
|
pub fn make(ctx: js.JSContextRef, ptr: *ZigType) js.JSObjectRef {
|
|
var real_ptr = JSPrivateDataPtr.init(ptr).ptr();
|
|
if (comptime isDebug) {
|
|
std.debug.assert(JSPrivateDataPtr.isValidPtr(real_ptr));
|
|
std.debug.assert(JSPrivateDataPtr.from(real_ptr).get(ZigType).? == ptr);
|
|
}
|
|
|
|
var result = js.JSObjectMake(
|
|
ctx,
|
|
get().*,
|
|
real_ptr,
|
|
);
|
|
|
|
if (comptime isDebug) {
|
|
std.debug.assert(JSPrivateDataPtr.from(js.JSObjectGetPrivate(result)).ptr() == real_ptr);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
pub fn GetClass(comptime ReceiverType: type) type {
|
|
const ClassGetter = struct {
|
|
get: fn (
|
|
*ReceiverType,
|
|
js.JSContextRef,
|
|
js.JSObjectRef,
|
|
js.ExceptionRef,
|
|
) js.JSValueRef = rfn,
|
|
|
|
pub const ts = typescriptDeclaration();
|
|
|
|
pub fn rfn(
|
|
receiver: *ReceiverType,
|
|
ctx: js.JSContextRef,
|
|
obj: js.JSObjectRef,
|
|
exception: js.ExceptionRef,
|
|
) js.JSValueRef {
|
|
return js.JSObjectMake(ctx, get().*, null);
|
|
}
|
|
};
|
|
|
|
return ClassGetter;
|
|
}
|
|
|
|
pub fn getPropertyCallback(
|
|
ctx: js.JSContextRef,
|
|
obj: js.JSObjectRef,
|
|
prop: js.JSStringRef,
|
|
exception: js.ExceptionRef,
|
|
) callconv(.C) js.JSValueRef {
|
|
var pointer = GetJSPrivateData(ZigType, obj) orelse return js.JSValueMakeUndefined(ctx);
|
|
|
|
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 this: ObjectPtrType(ZigType) = if (comptime ZigType == void) void{} else GetJSPrivateData(ZigType, obj) orelse return js.JSValueMakeUndefined(ctx);
|
|
|
|
var exc: js.JSValueRef = null;
|
|
const Field = @TypeOf(@field(
|
|
properties,
|
|
property_names[id],
|
|
));
|
|
switch (comptime @typeInfo(Field)) {
|
|
.Fn => {
|
|
return @field(
|
|
properties,
|
|
property_names[id],
|
|
)(
|
|
this,
|
|
ctx,
|
|
obj,
|
|
exception,
|
|
);
|
|
},
|
|
.Struct => {
|
|
const func = @field(
|
|
@field(
|
|
properties,
|
|
property_names[id],
|
|
),
|
|
"get",
|
|
);
|
|
|
|
const Func = @typeInfo(@TypeOf(func));
|
|
const WithPropFn = fn (
|
|
ObjectPtrType(ZigType),
|
|
js.JSContextRef,
|
|
js.JSObjectRef,
|
|
js.JSStringRef,
|
|
js.ExceptionRef,
|
|
) js.JSValueRef;
|
|
|
|
const WithoutPropFn = fn (
|
|
ObjectPtrType(ZigType),
|
|
js.JSContextRef,
|
|
js.JSObjectRef,
|
|
js.ExceptionRef,
|
|
) js.JSValueRef;
|
|
|
|
if (Func.Fn.args.len == @typeInfo(WithPropFn).Fn.args.len) {
|
|
return func(
|
|
this,
|
|
ctx,
|
|
obj,
|
|
prop,
|
|
exception,
|
|
);
|
|
} else {
|
|
return func(
|
|
this,
|
|
ctx,
|
|
obj,
|
|
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 this = GetJSPrivateData(ZigType, obj) orelse return js.JSValueMakeUndefined(ctx);
|
|
|
|
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,
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
// This should only be run at comptime
|
|
pub fn typescriptModuleDeclaration() d.ts.module {
|
|
comptime var class = options.ts.module;
|
|
comptime {
|
|
if (class.read_only == null) {
|
|
class.read_only = options.read_only;
|
|
}
|
|
|
|
if (static_functions.len > 0) {
|
|
var count: usize = 0;
|
|
inline for (function_name_literals) |function_name, i| {
|
|
const func = @field(staticFunctions, function_names[i]);
|
|
const Func = @TypeOf(func);
|
|
|
|
switch (@typeInfo(Func)) {
|
|
.Struct => {
|
|
if (hasTypeScript(Func)) {
|
|
if (std.meta.trait.isIndexable(@TypeOf(func.ts))) {
|
|
count += func.ts.len;
|
|
} else {
|
|
count += 1;
|
|
}
|
|
}
|
|
},
|
|
else => continue,
|
|
}
|
|
}
|
|
|
|
var funcs = std.mem.zeroes([count]d.ts);
|
|
class.functions = std.mem.span(&funcs);
|
|
var func_i: usize = 0;
|
|
|
|
inline for (function_name_literals) |function_name, i| {
|
|
const func = @field(staticFunctions, function_names[i]);
|
|
const Func = @TypeOf(func);
|
|
|
|
switch (@typeInfo(Func)) {
|
|
.Struct => {
|
|
if (hasTypeScript(Func)) {
|
|
var ts_functions: []const d.ts = &[_]d.ts{};
|
|
|
|
if (std.meta.trait.isIndexable(@TypeOf(func.ts))) {
|
|
ts_functions = std.mem.span(func.ts);
|
|
} else {
|
|
var funcs1 = std.mem.zeroes([1]d.ts);
|
|
funcs1[0] = func.ts;
|
|
ts_functions = std.mem.span(&funcs1);
|
|
}
|
|
|
|
for (ts_functions) |ts_function_| {
|
|
var ts_function = ts_function_;
|
|
if (ts_function.name.len == 0) {
|
|
ts_function.name = function_names[i];
|
|
}
|
|
|
|
if (ts_function.read_only == null) {
|
|
ts_function.read_only = class.read_only;
|
|
}
|
|
|
|
class.functions[func_i] = ts_function;
|
|
|
|
func_i += 1;
|
|
}
|
|
}
|
|
},
|
|
else => continue,
|
|
}
|
|
}
|
|
}
|
|
|
|
if (property_names.len > 0) {
|
|
var count: usize = 0;
|
|
var class_count: usize = 0;
|
|
|
|
inline for (property_names) |property_name, i| {
|
|
const field = @field(properties, property_names[i]);
|
|
const Field = @TypeOf(field);
|
|
|
|
if (hasTypeScript(Field)) {
|
|
switch (getTypeScript(Field, field)) {
|
|
.decl => |dec| {
|
|
switch (dec) {
|
|
.class => {
|
|
class_count += 1;
|
|
},
|
|
else => {},
|
|
}
|
|
},
|
|
.ts => {
|
|
count += 1;
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
var props = std.mem.zeroes([count]d.ts);
|
|
class.properties = std.mem.span(&props);
|
|
var property_i: usize = 0;
|
|
|
|
var classes = std.mem.zeroes([class_count + class.classes.len]d.ts.class);
|
|
if (class.classes.len > 0) {
|
|
std.mem.copy(d.ts.class, classes, class.classes);
|
|
}
|
|
|
|
var class_i: usize = class.classes.len;
|
|
class.classes = std.mem.span(&classes);
|
|
|
|
inline for (property_names) |property_name, i| {
|
|
const field = @field(properties, property_names[i]);
|
|
const Field = @TypeOf(field);
|
|
|
|
if (hasTypeScript(Field)) {
|
|
switch (getTypeScript(Field, field)) {
|
|
.decl => |dec| {
|
|
switch (dec) {
|
|
.class => |ts_class| {
|
|
class.classes[class_i] = ts_class;
|
|
class_i += 1;
|
|
},
|
|
else => {},
|
|
}
|
|
},
|
|
.ts => |ts_field_| {
|
|
var ts_field: d.ts = ts_field_;
|
|
if (ts_field.name.len == 0) {
|
|
ts_field.name = property_name;
|
|
}
|
|
|
|
if (ts_field.read_only == null) {
|
|
if (hasReadOnly(Field)) {
|
|
ts_field.read_only = field.ro;
|
|
} else {
|
|
ts_field.read_only = class.read_only;
|
|
}
|
|
}
|
|
|
|
class.properties[property_i] = ts_field;
|
|
|
|
property_i += 1;
|
|
},
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return class;
|
|
}
|
|
|
|
pub fn typescriptDeclaration() d.ts.decl {
|
|
comptime var decl = options.ts;
|
|
comptime switch (decl) {
|
|
.module => {
|
|
decl.module = typescriptModuleDeclaration();
|
|
},
|
|
.class => {
|
|
decl.class = typescriptClassDeclaration();
|
|
},
|
|
.empty => {},
|
|
};
|
|
|
|
return decl;
|
|
}
|
|
|
|
// This should only be run at comptime
|
|
pub fn typescriptClassDeclaration() d.ts.class {
|
|
comptime var class = options.ts.class;
|
|
|
|
comptime {
|
|
if (class.name.len == 0) {
|
|
class.name = options.name;
|
|
}
|
|
|
|
if (class.read_only == null) {
|
|
class.read_only = options.read_only;
|
|
}
|
|
|
|
if (static_functions.len > 0) {
|
|
var count: usize = 0;
|
|
inline for (function_name_literals) |function_name, i| {
|
|
const func = @field(staticFunctions, function_names[i]);
|
|
const Func = @TypeOf(func);
|
|
|
|
switch (@typeInfo(Func)) {
|
|
.Struct => {
|
|
if (hasTypeScript(Func)) {
|
|
if (std.meta.trait.isIndexable(@TypeOf(func.ts))) {
|
|
count += func.ts.len;
|
|
} else {
|
|
count += 1;
|
|
}
|
|
}
|
|
},
|
|
else => continue,
|
|
}
|
|
}
|
|
|
|
var funcs = std.mem.zeroes([count]d.ts);
|
|
class.functions = std.mem.span(&funcs);
|
|
var func_i: usize = 0;
|
|
|
|
inline for (function_name_literals) |function_name, i| {
|
|
const func = @field(staticFunctions, function_names[i]);
|
|
const Func = @TypeOf(func);
|
|
|
|
switch (@typeInfo(Func)) {
|
|
.Struct => {
|
|
if (hasTypeScript(Func)) {
|
|
var ts_functions: []const d.ts = &[_]d.ts{};
|
|
|
|
if (std.meta.trait.isIndexable(@TypeOf(func.ts))) {
|
|
ts_functions = std.mem.span(func.ts);
|
|
} else {
|
|
var funcs1 = std.mem.zeroes([1]d.ts);
|
|
funcs1[0] = func.ts;
|
|
ts_functions = std.mem.span(&funcs1);
|
|
}
|
|
|
|
for (ts_functions) |ts_function_| {
|
|
var ts_function = ts_function_;
|
|
if (ts_function.name.len == 0) {
|
|
ts_function.name = function_names[i];
|
|
}
|
|
|
|
if (class.interface and strings.eqlComptime(ts_function.name, "constructor")) {
|
|
ts_function.name = "new";
|
|
}
|
|
|
|
if (ts_function.read_only == null) {
|
|
ts_function.read_only = class.read_only;
|
|
}
|
|
|
|
class.functions[func_i] = ts_function;
|
|
|
|
func_i += 1;
|
|
}
|
|
}
|
|
},
|
|
else => continue,
|
|
}
|
|
}
|
|
}
|
|
|
|
if (property_names.len > 0) {
|
|
var count: usize = 0;
|
|
inline for (property_names) |property_name, i| {
|
|
const field = @field(properties, property_names[i]);
|
|
|
|
if (hasTypeScript(@TypeOf(field))) {
|
|
count += 1;
|
|
}
|
|
}
|
|
|
|
var props = std.mem.zeroes([count]d.ts);
|
|
class.properties = std.mem.span(&props);
|
|
var property_i: usize = 0;
|
|
|
|
inline for (property_names) |property_name, i| {
|
|
const field = @field(properties, property_names[i]);
|
|
|
|
if (hasTypeScript(@TypeOf(field))) {
|
|
var ts_field: d.ts = field.ts;
|
|
if (ts_field.name.len == 0) {
|
|
ts_field.name = property_name;
|
|
}
|
|
|
|
if (ts_field.read_only == null) {
|
|
if (hasReadOnly(@TypeOf(field))) {
|
|
ts_field.read_only = field.ro;
|
|
} else {
|
|
ts_field.read_only = class.read_only;
|
|
}
|
|
}
|
|
|
|
class.properties[property_i] = ts_field;
|
|
|
|
property_i += 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return comptime class;
|
|
}
|
|
|
|
pub fn define() js.JSClassDefinition {
|
|
var def = js.JSClassDefinition{
|
|
.version = 0,
|
|
.attributes = js.JSClassAttributes.kJSClassAttributeNone,
|
|
.className = class_name_str,
|
|
.parentClass = null,
|
|
.staticValues = null,
|
|
.staticFunctions = null,
|
|
.initialize = null,
|
|
.finalize = null,
|
|
.hasProperty = null,
|
|
.getProperty = null,
|
|
.setProperty = null,
|
|
.deleteProperty = null,
|
|
.getPropertyNames = null,
|
|
.callAsFunction = null,
|
|
.callAsConstructor = null,
|
|
.hasInstance = null,
|
|
.convertToType = null,
|
|
};
|
|
|
|
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| {
|
|
switch (comptime @typeInfo(@TypeOf(@field(staticFunctions, function_names[i])))) {
|
|
.Struct => {
|
|
if (comptime strings.eqlComptime(function_names[i], "constructor")) {
|
|
def.callAsConstructor = To.JS.Constructor(staticFunctions.constructor.rfn).rfn;
|
|
} else if (comptime strings.eqlComptime(function_names[i], "finalize")) {
|
|
def.finalize = To.JS.Finalize(ZigType, staticFunctions.finalize.rfn).rfn;
|
|
} else if (comptime strings.eqlComptime(function_names[i], "callAsFunction")) {
|
|
const ctxfn = @field(staticFunctions, function_names[i]).rfn;
|
|
const Func: std.builtin.TypeInfo.Fn = @typeInfo(@TypeOf(ctxfn)).Fn;
|
|
|
|
const PointerType = std.meta.Child(Func.args[0].arg_type.?);
|
|
|
|
var callback = if (Func.calling_convention == .C) ctxfn else To.JS.Callback(
|
|
PointerType,
|
|
ctxfn,
|
|
).rfn;
|
|
|
|
def.callAsFunction = callback;
|
|
} else {
|
|
const CtxField = @field(staticFunctions, function_names[i]);
|
|
if (comptime !@hasField(@TypeOf(CtxField), "rfn")) {
|
|
@compileError("Expected " ++ options.name ++ "." ++ function_names[i] ++ " to have .rfn");
|
|
}
|
|
const ctxfn = CtxField.rfn;
|
|
const Func: std.builtin.TypeInfo.Fn = @typeInfo(@TypeOf(ctxfn)).Fn;
|
|
|
|
const PointerType = if (Func.args[0].arg_type.? == void) void else std.meta.Child(Func.args[0].arg_type.?);
|
|
|
|
var callback = if (Func.calling_convention == .C) ctxfn else To.JS.Callback(
|
|
PointerType,
|
|
ctxfn,
|
|
).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,
|
|
};
|
|
|
|
count += 1;
|
|
}
|
|
},
|
|
.Fn => {
|
|
if (comptime strings.eqlComptime(function_names[i], "constructor")) {
|
|
def.callAsConstructor = To.JS.Constructor(staticFunctions.constructor).rfn;
|
|
} else if (comptime strings.eqlComptime(function_names[i], "finalize")) {
|
|
def.finalize = To.JS.Finalize(ZigType, staticFunctions.finalize).rfn;
|
|
} else {
|
|
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,
|
|
};
|
|
|
|
count += 1;
|
|
}
|
|
},
|
|
else => unreachable,
|
|
}
|
|
|
|
// 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.JSStringCreateStatic(
|
|
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]);
|
|
|
|
if (comptime hasSetter(@TypeOf(field))) {
|
|
static_properties[i].setProperty = StaticProperty(i).setter;
|
|
}
|
|
static_properties[i].name = property_names[i][0.. :0].ptr;
|
|
}
|
|
def.staticValues = (&static_properties);
|
|
}
|
|
|
|
def.className = class_name_str;
|
|
// def.getProperty = getPropertyCallback;
|
|
|
|
if (def.callAsConstructor == null) {
|
|
def.callAsConstructor = throwInvalidConstructorError;
|
|
}
|
|
|
|
if (def.callAsFunction == null) {
|
|
def.callAsFunction = throwInvalidFunctionError;
|
|
}
|
|
|
|
if (!singleton)
|
|
def.hasInstance = customHasInstance;
|
|
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;
|
|
defer allocator.free(buf);
|
|
|
|
var message = js.JSStringCreateWithUTF8CString(buf);
|
|
defer js.JSStringRelease(message);
|
|
|
|
error_args[0] = js.JSValueMakeString(ctx, message);
|
|
exception.* = js.JSObjectMakeError(ctx, 1, &error_args, null);
|
|
}
|
|
}
|
|
|
|
pub fn getAllocator(ctx: js.JSContextRef) *std.mem.Allocator {
|
|
return default_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,
|
|
};
|
|
|
|
pub fn castObj(obj: js.JSObjectRef, comptime Type: type) *Type {
|
|
return JSPrivateDataPtr.from(js.JSObjectGetPrivate(obj)).as(Type);
|
|
}
|
|
|
|
pub const JSPrivateDataPtr = TaggedPointerUnion(.{
|
|
ResolveError,
|
|
BuildError,
|
|
Response,
|
|
Request,
|
|
FetchEvent,
|
|
Headers,
|
|
Body,
|
|
Router,
|
|
});
|
|
|
|
pub inline fn GetJSPrivateData(comptime Type: type, ref: js.JSObjectRef) ?*Type {
|
|
return JSPrivateDataPtr.from(js.JSObjectGetPrivate(ref)).get(Type);
|
|
}
|