This commit is contained in:
Jarred Sumner
2022-03-11 04:49:25 -08:00
parent 313ad01e42
commit 64f1af0aa6
7 changed files with 437 additions and 0 deletions

View File

@@ -0,0 +1,410 @@
const std = @import("std");
const Api = @import("../../../api/schema.zig").Api;
const FilesystemRouter = @import("../../../router.zig");
const http = @import("../../../http.zig");
const JavaScript = @import("../javascript.zig");
const QueryStringMap = @import("../../../query_string_map.zig").QueryStringMap;
const CombinedScanner = @import("../../../query_string_map.zig").CombinedScanner;
const bun = @import("../../../global.zig");
const string = bun.string;
const JSC = @import("../../../jsc.zig");
const js = JSC.C;
const WebCore = @import("../webcore/response.zig");
const Router = @This();
const Bundler = @import("../../../bundler.zig");
const VirtualMachine = JavaScript.VirtualMachine;
const ScriptSrcStream = std.io.FixedBufferStream([]u8);
const ZigString = JSC.ZigString;
const Fs = @import("../../../fs.zig");
const Base = @import("../base.zig");
const getAllocator = Base.getAllocator;
const JSObject = JSC.JSObject;
const JSError = Base.JSError;
const JSValue = JSC.JSValue;
const JSGlobalObject = JSC.JSGlobalObject;
const strings = @import("strings");
const NewClass = Base.NewClass;
const To = Base.To;
const Request = WebCore.Request;
const d = Base.d;
const FetchEvent = WebCore.FetchEvent;
const Response = WebCore.Response;
pub const HTMLRewriter = struct {
listeners: *anyopaque,
built: bool = false,
pub const Class = NewClass(
HTMLRewriter,
.{ .name = "HTMLRewriter" },
.{
.constructor = constructor,
.on = .{
.rfn = wrap(HTMLRewriter, "on"),
},
.onDocument = .{
.rfn = wrap(HTMLRewriter, "onDocument"),
},
.transform = .{
.rfn = wrap(HTMLRewriter, "transform"),
},
},
.{},
);
pub fn constructor(
ctx: js.JSContextRef,
_: js.JSObjectRef,
_: []const js.JSValueRef,
_: js.ExceptionRef,
) js.JSObjectRef {
var rewriter = bun.default_allocator.create(HTMLRewriter) catch unreachable;
rewriter.* = HTMLRewriter{ .listeners = undefined };
return HTMLRewriter.Class.make(ctx, rewriter);
}
pub fn on(
this: *HTMLRewriter,
global: *JSGlobalObject,
event: ZigString,
listener: JSValue,
) JSValue {
_ = this;
_ = global;
_ = event;
_ = listener;
return undefined;
}
pub fn onDocument(
this: *HTMLRewriter,
global: *JSGlobalObject,
event: ZigString,
listener: JSValue,
) JSValue {
_ = this;
_ = global;
_ = event;
_ = listener;
return undefined;
}
pub fn transform(this: *HTMLRewriter, global: *JSGlobalObject, response: *Response) JSValue {
_ = this;
_ = global;
_ = response;
return undefined;
}
};
const ContentOptions = struct {
html: bool = false,
};
fn MethodType(comptime Container: type) type {
return fn (
this: *Container,
ctx: js.JSContextRef,
thisObject: js.JSObjectRef,
target: js.JSObjectRef,
args: []const js.JSValueRef,
exception: js.ExceptionRef,
) js.JSObjectRef;
}
fn GetterType(comptime Container: type) type {
return fn (
this: *Container,
ctx: js.JSContextRef,
_: js.JSObjectRef,
_: js.JSStringRef,
exception: js.ExceptionRef,
) js.JSObjectRef;
}
pub fn wrap(comptime Container: type, comptime name: string) MethodType(Container) {
return struct {
const FunctionType = @TypeOf(@field(Container, name));
const FunctionTypeInfo: std.builtin.TypeInfo.Fn = @typeInfo(FunctionType).Fn;
pub fn callback(
this: *Container,
ctx: js.JSContextRef,
_: js.JSObjectRef,
_: js.JSObjectRef,
arguments: []const js.JSValueRef,
exception: js.ExceptionRef,
) js.JSObjectRef {
var iter = JSC.Node.ArgumentsSlice.from(arguments);
var args: std.meta.ArgsTuple(FunctionType) = undefined;
comptime var i: usize = 0;
inline while (i < FunctionTypeInfo.args.len) : (i += 1) {
const ArgType = FunctionTypeInfo.args[i].arg_type.?;
switch (ArgType) {
*Container => {
args[i] = this;
},
*JSGlobalObject => {
args[i] = ctx.ptr();
},
ZigString => {
var arg: ?JSC.JSValue = iter.next();
args[i] = (arg orelse {
JSC.throwInvalidArguments("Expected string", .{}, ctx, exception);
return null;
}).getZigString(ctx.ptr());
},
?ContentOptions => {
var arg: ?JSC.JSValue = iter.next();
if (arg) |content_arg| {
if (content_arg.get("html")) |html_val| {
args[i] = .{ .html = html_val.toBoolean() };
}
} else {
args[i] = null;
}
},
*Response => {
var arg: ?JSC.JSValue = iter.next();
args[i] = (arg orelse {
JSC.throwInvalidArguments("Missing Response object", .{}, ctx, exception);
return null;
}).as(Response) orelse {
JSC.throwInvalidArguments("Expected Response object", .{}, ctx, exception);
return null;
};
},
JSValue => {
var arg: ?JSC.JSValue = iter.next();
args[i] = arg orelse {
JSC.throwInvalidArguments("Missing argument", .{}, ctx, exception);
return null;
};
},
else => @compileError("Unexpected Type" ++ @typeName(ArgType)),
}
}
const result: JSValue = @call(.{}, @field(Container, name), args);
if (result.isError()) {
exception.* = result.asObjectRef();
return null;
}
return result.asObjectRef();
}
}.callback;
}
pub fn getterWrap(comptime Container: type, comptime name: string) GetterType(Container) {
return struct {
const FunctionType = @TypeOf(@field(Container, name));
const FunctionTypeInfo: std.builtin.TypeInfo.Fn = @typeInfo(FunctionType).Fn;
pub fn callback(
this: *Container,
ctx: js.JSContextRef,
_: js.JSObjectRef,
_: js.JSStringRef,
exception: js.ExceptionRef,
) js.JSObjectRef {
const result: JSValue = @call(.{}, @field(Container, name), .{ this, ctx.ptr() });
if (result.isError()) {
exception.* = result.asObjectRef();
return null;
}
return result.asObjectRef();
}
}.callback;
}
pub const Element = struct {
global: *JSGlobalObject,
removed: bool = false,
pub const Class = NewClass(
Element,
.{ .name = "Element" },
.{
.getAttribute = .{
.rfn = wrap(Element, "getAttribute"),
},
.hasAttribute = .{
.rfn = wrap(Element, "hasAttribute"),
},
.setAttribute = .{
.rfn = wrap(Element, "setAttribute"),
},
.removeAttribute = .{
.rfn = wrap(Element, "removeAttribute"),
},
.before = .{
.rfn = wrap(Element, "before"),
},
.after = .{
.rfn = wrap(Element, "after"),
},
.prepend = .{
.rfn = wrap(Element, "prepend"),
},
.append = .{
.rfn = wrap(Element, "append"),
},
.replace = .{
.rfn = wrap(Element, "replace"),
},
.setInnerContent = .{
.rfn = wrap(Element, "setInnerContent"),
},
.remove = .{
.rfn = wrap(Element, "remove"),
},
.removeAndKeepContent = .{
.rfn = wrap(Element, "removeAndKeepContent"),
},
},
.{
.tagName = .{
.get = getterWrap(Element, "getTagName"),
},
.removed = .{
.get = getterWrap(Element, "getRemoved"),
},
.namespaceUri = .{
.get = getterWrap(Element, "getNamespaceURI"),
},
},
);
// // fn wrap(comptime name: string)
/// Returns the value for a given attribute name: ZigString on the element, or null if it is not found.
pub fn getAttribute(this: *Element, globalObject: *JSGlobalObject, name: ZigString) JSValue {
_ = this;
_ = name;
_ = globalObject;
return undefined;
}
/// Returns a boolean indicating whether an attribute exists on the element.
pub fn hasAttribute(this: *Element, globalObject: *JSGlobalObject, name: ZigString) JSValue {
_ = this;
_ = name;
_ = globalObject;
return undefined;
}
/// Sets an attribute to a provided value, creating the attribute if it does not exist.
pub fn setAttribute(this: *Element, globalObject: *JSGlobalObject, name: ZigString, value: ZigString) JSValue {
_ = this;
_ = name;
_ = globalObject;
_ = value;
return undefined;
}
/// Removes the attribute.
pub fn removeAttribute(this: *Element, globalObject: *JSGlobalObject, name: ZigString) JSValue {
_ = this;
_ = name;
_ = globalObject;
return undefined;
}
/// Inserts content before the element.
pub fn before(this: *Element, globalObject: *JSGlobalObject, content: ZigString, contentOptions: ?ContentOptions) JSValue {
_ = this;
_ = content;
_ = globalObject;
_ = contentOptions;
return undefined;
}
/// Inserts content right after the element.
pub fn after(this: *Element, globalObject: *JSGlobalObject, content: ZigString, contentOptions: ?ContentOptions) JSValue {
_ = this;
_ = content;
_ = globalObject;
_ = contentOptions;
return undefined;
}
/// nserts content right after the start tag of the element.
pub fn prepend(this: *Element, globalObject: *JSGlobalObject, content: ZigString, contentOptions: ?ContentOptions) JSValue {
_ = this;
_ = content;
_ = globalObject;
_ = contentOptions;
return undefined;
}
/// Inserts content right before the end tag of the element.
pub fn append(this: *Element, globalObject: *JSGlobalObject, content: ZigString, contentOptions: ?ContentOptions) JSValue {
_ = this;
_ = content;
_ = globalObject;
_ = contentOptions;
return undefined;
}
/// Removes the element and inserts content in place of it.
pub fn replace(this: *Element, globalObject: *JSGlobalObject, content: ZigString, contentOptions: ?ContentOptions) JSValue {
_ = this;
_ = content;
_ = globalObject;
_ = contentOptions;
return undefined;
}
/// Replaces content of the element.
pub fn setInnerContent(this: *Element, globalObject: *JSGlobalObject, content: ZigString, contentOptions: ?ContentOptions) JSValue {
_ = this;
_ = content;
_ = globalObject;
_ = contentOptions;
return undefined;
}
/// Removes the element with all its content.
pub fn remove(this: *Element, globalObject: *JSGlobalObject) JSValue {
_ = this;
_ = globalObject;
return undefined;
}
/// Removes the start tag and end tag of the element but keeps its inner content intact.
pub fn removeAndKeepContent(this: *Element, globalObject: *JSGlobalObject) JSValue {
_ = this;
_ = globalObject;
return undefined;
}
pub fn getTagName(this: *Element, globalObject: *JSGlobalObject) JSValue {
_ = this;
_ = globalObject;
return undefined;
}
pub fn getRemoved(this: *Element, globalObject: *JSGlobalObject) JSValue {
_ = this;
_ = globalObject;
return undefined;
}
pub fn getNamespaceURI(this: *Element, globalObject: *JSGlobalObject) JSValue {
_ = this;
_ = globalObject;
return undefined;
}
};

View File

@@ -1857,6 +1857,9 @@ const Transpiler = @import("./api/transpiler.zig");
const TextEncoder = WebCore.TextEncoder;
const TextDecoder = WebCore.TextDecoder;
const TimeoutTask = JSC.BunTimer.Timeout.TimeoutTask;
const HTMLRewriter = JSC.Cloudflare.HTMLRewriter;
const Element = JSC.Cloudflare.Element;
pub const JSPrivateDataPtr = TaggedPointerUnion(.{
ResolveError,
BuildError,
@@ -1881,6 +1884,8 @@ pub const JSPrivateDataPtr = TaggedPointerUnion(.{
TextEncoder,
TextDecoder,
TimeoutTask,
HTMLRewriter,
Element,
});
pub inline fn GetJSPrivateData(comptime Type: type, ref: js.JSObjectRef) ?*Type {

View File

@@ -14,6 +14,7 @@ const ZigException = Exports.ZigException;
const ZigStackTrace = Exports.ZigStackTrace;
const is_bindgen: bool = std.meta.globalOption("bindgen", bool) orelse false;
const ArrayBuffer = @import("../base.zig").ArrayBuffer;
const JSC = @import("../../../jsc.zig");
pub const JSObject = extern struct {
pub const shim = Shimmer("JSC", "JSObject", @This());
bytes: shim.Bytes,
@@ -1822,6 +1823,10 @@ pub const JSValue = enum(i64) {
return cppFn("putRecord", .{ value, global, key, values, values_len });
}
pub fn as(value: JSValue, comptime ZigType: type) ?*ZigType {
return JSC.GetJSPrivateData(ZigType, value.asObjectRef());
}
/// Create an object with exactly two properties
pub fn createObject2(global: *JSGlobalObject, key1: *const ZigString, key2: *const ZigString, value1: JSValue, value2: JSValue) JSValue {
return cppFn("createObject2", .{ global, key1, key2, value1, value2 });

View File

@@ -101,6 +101,8 @@ pub const GlobalClasses = [_]type{
WebCore.TextEncoder.Constructor.Class,
WebCore.TextDecoder.Constructor.Class,
JSC.Cloudflare.HTMLRewriter.Class,
// The last item in this array becomes "process.env"
Bun.EnvironmentVariables.Class,
};

View File

@@ -392,6 +392,9 @@ pub const ArgumentsSlice = struct {
arena: std.heap.ArenaAllocator = std.heap.ArenaAllocator.init(bun.default_allocator),
all: []const JSC.JSValue,
pub fn from(arguments: []const JSC.JSValueRef) ArgumentsSlice {
return init(@ptrCast([*]const JSC.JSValue, arguments.ptr)[0..arguments.len]);
}
pub fn init(arguments: []const JSC.JSValue) ArgumentsSlice {
return ArgumentsSlice{
.remaining = arguments,