This commit is contained in:
Jarred Sumner
2021-07-14 00:14:11 -07:00
parent ab73c7b323
commit f4381bb297
7 changed files with 840 additions and 184 deletions

View File

@@ -1,7 +1,7 @@
const std = @import("std");
const resolve_path = @import("./src/resolver/resolve_path.zig");
pub fn addPicoHTTP(step: *std.build.LibExeObjStep, dir: []const u8) void {
pub fn addPicoHTTP(step: *std.build.LibExeObjStep) void {
const picohttp = step.addPackage(.{
.name = "picohttp",
.path = .{ .path = "src/deps/picohttp.zig" },
@@ -119,10 +119,14 @@ pub fn build(b: *std.build.Builder) void {
var javascript: @TypeOf(exe) = undefined;
// exe.want_lto = true;
if (!target.getCpuArch().isWasm()) {
addPicoHTTP(exe, cwd);
addPicoHTTP(
exe,
);
if (ENABLE_JAVASCRIPT_BUILD) {
javascript = b.addExecutable("spjs", "src/main_javascript.zig");
addPicoHTTP(javascript, cwd);
addPicoHTTP(
javascript,
);
javascript.packages = std.ArrayList(std.build.Pkg).fromOwnedSlice(std.heap.page_allocator, std.heap.page_allocator.dupe(std.build.Pkg, exe.packages.items) catch unreachable);
javascript.setOutputDir(output_dir);
javascript.setBuildMode(mode);
@@ -142,7 +146,7 @@ pub fn build(b: *std.build.Builder) void {
}
}
exe.install();
b.default_step.dependOn(&exe.step);
if (!target.getCpuArch().isWasm()) {
if (ENABLE_JAVASCRIPT_BUILD) {
@@ -159,5 +163,23 @@ pub fn build(b: *std.build.Builder) void {
const run_step = b.step("run", "Run the app");
run_step.dependOn(&run_cmd.step);
std.debug.print("Build: ./{s}/{s}\n", .{ output_dir, "esdev" });
var log_step = b.addLog("Destination: {s}/{s}\n", .{ output_dir, "esdev" });
log_step.step.dependOn(&exe.step);
var typings_exe = b.addExecutable("typescript-decls", "src/javascript/jsc/typescript.zig");
var typings_cmd = typings_exe.run();
typings_cmd.cwd = b.build_root;
typings_cmd.step.dependOn(&typings_exe.step);
typings_exe.linkLibC();
typings_exe.setMainPkgPath(cwd);
if (target.getOsTag() == .macos) {
typings_exe.linkFramework("JavascriptCore");
}
addPicoHTTP(
typings_exe,
);
const typings_step = b.step("types", "Build TypeScript types");
typings_step.dependOn(&typings_cmd.step);
}

View File

@@ -55,7 +55,7 @@ pub const Request = struct {
);
// Leave a sentinel value, for JavaScriptCore support.
path.ptr[path.len] = 0;
@intToPtr([*]u8, @ptrToInt(path.ptr))[path.len] = 0;
return switch (rc) {
-1 => error.BadRequest,

View File

@@ -4,131 +4,155 @@ const Api = @import("../../../api/schema.zig").Api;
const FilesystemRouter = @import("../../../router.zig");
const JavaScript = @import("../javascript.zig");
pub const Router = struct {
match: FilesystemRouter.RouteMap.MatchedRoute,
file_path_str: js.JSStringRef = null,
pathname_str: js.JSStringRef = null,
const Router = @This();
pub const Class = NewClass(
Router,
"Router",
.{
.finalize = finalize,
match: FilesystemRouter.RouteMap.MatchedRoute,
file_path_str: js.JSStringRef = null,
pathname_str: js.JSStringRef = null,
pub fn constructor(
ctx: js.JSContextRef,
function: js.JSObjectRef,
arguments: []const js.JSValueRef,
exception: js.ExceptionRef,
) js.JSObjectRef {
return null;
}
pub const Class = NewClass(
Router,
.{
.name = "Router",
.read_only = true,
.ts = d.ts.class{ .path = "speedy.js/router", .tsdoc =
\\Filesystem Router supporting dynamic routes, exact routes, catch-all routes, and optional catch-all routes. Implemented in native code and only available with Speedy.js.
},
.{
.@"pathname" = .{
.get = getPathname,
.ro = true,
.ts = .{
.@"return" = "string",
.@"tsdoc" = "URL path as appears in a web browser's address bar",
},
.{
.finalize = .{
.rfn = finalize,
},
.constructor = .{
.rfn = constructor,
.ts = d.ts{
.tsdoc =
\\Native filesystem router. Use with {@link https://developer.mozilla.org/en-US/docs/Web/API/FetchEvent FetchEvent}.
,
.@"return" = "Router",
.args = &[_]d.ts.arg{
d.ts.arg{ .name = "event", .@"return" = "FetchEvent" },
},
},
.@"filepath" = .{
.get = getPageFilePath,
.ro = true,
.ts = .{
.@"return" = "string",
.@"tsdoc" =
\\Project-relative filesystem path to the route file
\\
\\@example
\\
\\```tsx
\\const PageComponent = (await import(route.filepath)).default;
\\ReactDOMServer.renderToString(<PageComponent query={route.query} />);
\\```
,
},
},
.@"route" = .{
.@"get" = getRoute,
.ro = true,
},
.query = .{
.@"get" = getQuery,
.ro = true,
},
.pageFilePath = .{
.@"get" = getPageFilePath,
.ro = true,
},
},
.{
.@"pathname" = .{
.get = getPathname,
.ro = true,
.ts = d.ts{
.@"return" = "string",
.@"tsdoc" = "URL path as appears in a web browser's address bar",
},
},
false,
false,
);
.filepath = .{
.get = getFilePath,
.ro = true,
.ts = d.ts{
.@"return" = "string",
.tsdoc =
\\Project-relative filesystem path to the route file. Useful for importing.
\\
\\@example ```tsx
\\await import(route.filepath);
\\```
,
},
},
.@"route" = .{
.@"get" = getRoute,
.ro = true,
.ts = d.ts{
.@"return" = "string",
.tsdoc =
\\Route name
\\@example
\\`"blog/posts/[id]"`
\\`"blog/posts/[id]/[[...slug]]"`
\\`"blog"`
,
},
},
.query = .{
.@"get" = getQuery,
.ro = true,
.ts = d.ts{
.@"return" = "Record<string, string | string[]>",
.tsdoc =
\\Route parameters as a key-value object
\\
\\@example
\\```js
\\console.assert(router.query.id === "123");
\\console.assert(router.pathname === "/blog/posts/123");
\\console.assert(router.route === "blog/posts/[id]");
\\```
,
},
},
},
);
pub fn getPageFilePath(
this: *Router,
ctx: js.JSContextRef,
thisObject: js.JSObjectRef,
prop: js.JSStringRef,
exception: js.ExceptionRef,
) js.JSValueRef {
if (this.file_path_str == null) {
this.file_path_str = js.JSStringCreateWithUTF8CString(this.match.file_path[0.. :0]);
}
return js.JSValueMakeString(ctx, this.file_path_str);
pub fn getFilePath(
this: *Router,
ctx: js.JSContextRef,
thisObject: js.JSObjectRef,
prop: js.JSStringRef,
exception: js.ExceptionRef,
) js.JSValueRef {
if (this.file_path_str == null) {
this.file_path_str = js.JSStringCreateWithUTF8CString(this.match.file_path.ptr);
}
pub fn finalize(
this: *Router,
ctx: js.JSObjectRef,
) void {
// this.deinit();
return js.JSValueMakeString(ctx, this.file_path_str);
}
pub fn finalize(
this: *Router,
ctx: js.JSObjectRef,
) void {
// this.deinit();
}
pub fn getPathname(
this: *Router,
ctx: js.JSContextRef,
thisObject: js.JSObjectRef,
prop: js.JSStringRef,
exception: js.ExceptionRef,
) js.JSValueRef {
if (this.pathname_str == null) {
this.pathname_str = js.JSStringCreateWithUTF8CString(this.match.pathname.ptr);
}
pub fn requirePage(
this: *Router,
ctx: js.JSContextRef,
function: js.JSObjectRef,
thisObject: js.JSObjectRef,
arguments: []const js.JSValueRef,
exception: js.ExceptionRef,
) js.JSValueRef {}
return js.JSValueMakeString(ctx, this.pathname_str);
}
pub fn getPathname(
this: *Router,
ctx: js.JSContextRef,
thisObject: js.JSObjectRef,
prop: js.JSStringRef,
exception: js.ExceptionRef,
) js.JSValueRef {
if (this.pathname_str == null) {
this.pathname_str = js.JSStringCreateWithUTF8CString(this.match.pathname[0.. :0]);
}
pub fn getRoute(
this: *Router,
ctx: js.JSContextRef,
thisObject: js.JSObjectRef,
prop: js.JSStringRef,
exception: js.ExceptionRef,
) js.JSValueRef {
return js.JSValueMakeString(ctx, Properties.Refs.default);
}
return js.JSValueMakeString(ctx, this.pathname_str);
}
pub fn getAsPath(
this: *Router,
ctx: js.JSContextRef,
thisObject: js.JSObjectRef,
prop: js.JSStringRef,
exception: js.ExceptionRef,
) js.JSValueRef {
return js.JSValueMakeString(ctx, Properties.Refs.default);
}
pub fn getRoute(
this: *Router,
ctx: js.JSContextRef,
thisObject: js.JSObjectRef,
prop: js.JSStringRef,
exception: js.ExceptionRef,
) js.JSValueRef {
return js.JSValueMakeString(ctx, Properties.Refs.default);
}
pub fn getQuery(
this: *Router,
ctx: js.JSContextRef,
thisObject: js.JSObjectRef,
prop: js.JSStringRef,
exception: js.ExceptionRef,
) js.JSValueRef {
return js.JSValueMakeString(ctx, Properties.Refs.default);
}
};
pub fn getQuery(
this: *Router,
ctx: js.JSContextRef,
thisObject: js.JSObjectRef,
prop: js.JSStringRef,
exception: js.ExceptionRef,
) js.JSValueRef {
return js.JSValueMakeString(ctx, Properties.Refs.default);
}

View File

@@ -163,6 +163,32 @@ pub const To = struct {
};
};
pub const RuntimeImports = struct {
pub fn resolve(ctx: js.JSContextRef, str: string) ?js.JSObjectRef {
switch (ModuleList.Map.get(str) orelse ModuleList.none) {
.Router => {
const Router = @import("./api/router.zig");
return js.JSObjectMake(ctx, Router.Class.get().*, null);
},
else => {
return null;
},
}
}
pub const ModuleList = enum(u8) {
Router = 0,
none = std.math.maxInt(u8),
pub const Map = std.ComptimeStringMap(
ModuleList,
.{
.{ "speedy.js/router", ModuleList.Router },
},
);
};
};
pub const Properties = struct {
pub const UTF8 = struct {
pub const module = "module";
@@ -277,16 +303,331 @@ pub const Properties = struct {
};
const hasSetter = std.meta.trait.hasField("set");
const hasReadOnly = std.meta.trait.hasField("ro");
const hasFinalize = std.meta.trait.hasField("finalize");
const hasTypeScript = std.meta.trait.hasField("ts");
pub const d = struct {
pub const ts = struct {
@"return": string = "",
tsdoc: string = "",
name: string = "",
read_only: ?bool = null,
args: []const arg = &[_]arg{},
splat_args: bool = false,
pub const builder = struct {
classes: []class,
};
pub const class = struct {
path: string = "",
name: string = "",
tsdoc: string = "",
@"return": string = "",
read_only: ?bool = null,
interface: bool = true,
global: 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 printClass(comptime klass: d.ts.class, comptime _indent: usize) string {
comptime var indent = _indent;
comptime var buf: string = "";
comptime brk: {
if (klass.path.len > 0) {
buf = buf ++ printIndented("declare module \"{s}\" {{\n\n", .{klass.path}, indent);
indent += indent_level;
}
if (klass.tsdoc.len > 0) {
buf = buf ++ printTSDoc(klass.tsdoc, indent);
}
const qualifier = if (klass.path.len == 0 and !klass.interface) "declare " else "";
var stmt: string = qualifier;
if (!klass.global) {
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";
}
if (!klass.global) {
buf = buf ++ printProperty(property, indent);
} else {
buf = buf ++ printVar(property, indent);
}
}
buf = buf ++ "\n";
for (klass.functions) |func, i| {
if (i > 0) {
buf = buf ++ "\n";
}
if (strings.eqlComptime(func.name, "constructor")) continue;
if (!klass.global) {
buf = buf ++ printInstanceFunction(
func,
indent,
false,
);
} else {
buf = buf ++ printFunction(
func,
indent,
false,
);
}
}
indent -= indent_level;
buf = buf ++ printIndented("}}\n", .{}, indent);
if (klass.path.len > 0) {
buf = buf ++ printIndented("export = {s};\n", .{klass.name}, indent);
indent -= indent_level;
buf = buf ++ printIndented("\n}}\n", .{}, 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.class = d.ts.class{},
};
pub fn NewClass(
comptime ZigType: type,
comptime name: string,
comptime options: ClassOptions,
comptime staticFunctions: anytype,
comptime properties: anytype,
comptime read_only: bool,
comptime singleton: bool,
) 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 names_buf = brk: {
@@ -538,6 +879,107 @@ pub fn NewClass(
};
}
// This should only be run at comptime
pub fn typescriptDeclaration() d.ts.class {
comptime var class = options.ts;
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)) {
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_function: d.ts = func.ts;
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;
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.kJSClassDefinitionEmpty;
@@ -545,19 +987,46 @@ pub fn NewClass(
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 = To.JS.Constructor(@field(staticFunctions, function_names[i])).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,
};
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 {
var callback = To.JS.Callback(
ZigType,
@field(staticFunctions, function_names[i]).rfn,
).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;
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) {

View File

@@ -261,11 +261,6 @@ pub const Module = struct {
// reload_pending should not be applied to bundled modules
reload_pending: bool = false,
pub var module_class: js.JSClassRef = undefined;
pub var module_global_class: js.JSClassRef = undefined;
pub var module_global_class_def: js.JSClassDefinition = undefined;
pub var module_class_def: js.JSClassDefinition = undefined;
pub const NodeModuleList = struct {
tempbuf: []u8,
property_names: [*]u8,
@@ -709,6 +704,10 @@ pub const Module = struct {
var import_path = require_buf.list.items[0 .. end - 1];
var module = this;
if (RuntimeImports.resolve(ctx, import_path)) |ref| {
return ref;
}
if (this.vm.bundler.linker.resolver.resolve(module.path.name.dirWithTrailingSlash(), import_path, .require)) |resolved| {
var load_result = Module.loadFromResolveResult(this.vm, ctx, resolved, exception) catch |err| {
return null;
@@ -856,7 +855,7 @@ pub const Module = struct {
const ModuleClass = NewClass(
Module,
"Module",
.{ .name = "Module" },
.{
.@"require" = require,
.@"requireFirst" = requireFirst,
@@ -876,8 +875,6 @@ pub const Module = struct {
.ro = false,
},
},
false,
false,
);
const ExportsClassName = "module.exports";
@@ -891,9 +888,6 @@ pub const Module = struct {
// ExportsClass.callAsConstructor = To.JS.Callback(Module, callExportsAsConstructor);
exports_class_ref = js.JSClassRetain(js.JSClassCreate(&ExportsClass));
module_class_def = ModuleClass.define();
module_class = js.JSClassRetain(js.JSClassCreate(&module_class_def));
}
pub const LoadResult = union(Tag) {
@@ -932,7 +926,7 @@ pub const Module = struct {
.ref = undefined,
.vm = vm,
};
module.ref = js.JSObjectMake(global_ctx, Module.module_class, module);
module.ref = js.JSObjectMake(global_ctx, Module.ModuleClass.get(), module);
js.JSValueProtect(global_ctx, module.ref);
} else {
js.JSValueUnprotect(global_ctx, module.exports.?);
@@ -1489,7 +1483,7 @@ pub const GlobalObject = struct {
pub const ConsoleClass = NewClass(
GlobalObject,
"Console",
.{ .name = "Console", .singleton = true },
.{
.@"log" = stdout,
.@"info" = stdout,
@@ -1500,25 +1494,43 @@ pub const GlobalObject = struct {
.@"warn" = stderr,
},
.{},
// people sometimes modify console.log, let them.
false,
true,
);
pub const GlobalClass = NewClass(
GlobalObject,
"Global",
.{
.@"addEventListener" = EventListenerMixin.addEventListener(GlobalObject).addListener,
.name = "Global",
.ts = d.ts.class{
.global = true,
},
},
.{
.@"console" = getConsole,
.@"Request" = Request.Class.GetClass(GlobalObject).getter,
.@"Response" = Response.Class.GetClass(GlobalObject).getter,
.@"Headers" = Headers.Class.GetClass(GlobalObject).getter,
.@"addEventListener" = .{
.rfn = EventListenerMixin.addEventListener(GlobalObject).addListener,
.ts = d.ts{
.args = &[_]d.ts.arg{
.{ .name = "name", .@"return" = "\"fetch\"" },
.{ .name = "callback", .@"return" = "(event: FetchEvent) => void" },
},
.@"return" = "void",
},
},
},
.{
.@"console" = d.ts{ .@"return" = "console" },
.@"Request" = .{
.get = Request.Class.GetClass(GlobalObject).getter,
// .ts = d.ts{ .@"return" = "typeof Request" },
},
.@"Response" = .{
.get = Response.Class.GetClass(GlobalObject).getter,
// .ts = d.ts{ .@"return" = "typeof Response" },
},
.@"Headers" = .{
.get = Headers.Class.GetClass(GlobalObject).getter,
// .ts = d.ts{ .@"return" = "typeof Headers" },
},
},
false,
false,
);
pub fn getConsole(

View File

@@ -0,0 +1,76 @@
usingnamespace @import("./base.zig");
const std = @import("std");
const Api = @import("../../api/schema.zig").Api;
const Router = @import("./api/router.zig");
const JavaScript = @import("./javascript.zig");
const builtin = std.builtin;
const io = std.io;
const fs = std.fs;
const process = std.process;
const ChildProcess = std.ChildProcess;
const Progress = std.Progress;
const print = std.debug.print;
const mem = std.mem;
const testing = std.testing;
const Allocator = std.mem.Allocator;
const resolve_path = @import("../../resolver/resolve_path.zig");
usingnamespace @import("./webcore/response.zig");
pub fn main() anyerror!void {
var args_it = process.args();
var allocator = std.heap.c_allocator;
_ = args_it.skip();
var stdout = io.getStdOut();
const modules = comptime [_]d.ts.class{
Router.Class.typescriptDeclaration(),
};
inline for (modules) |class, i| {
if (i > 0) {
try stdout.writeAll("\n\n");
}
try stdout.writeAll(comptime d.ts.class.Printer.printClass(class, 0));
}
try stdout.writeAll("\n\n");
try stdout.writeAll("declare global {\n");
const global = comptime JavaScript.GlobalObject.GlobalClass.typescriptDeclaration();
inline for (global.properties) |property, i| {
if (i > 0) {
try stdout.writeAll("\n\n");
}
try stdout.writeAll(comptime d.ts.class.Printer.printVar(property, 2));
}
try stdout.writeAll("\n");
inline for (global.functions) |property, i| {
if (i > 0) {
try stdout.writeAll("\n\n");
}
try stdout.writeAll(comptime d.ts.class.Printer.printFunction(property, 2, false));
}
try stdout.writeAll("\n");
const globals = comptime [_]d.ts.class{
FetchEvent.Class.typescriptDeclaration(),
};
inline for (globals) |class, i| {
if (i > 0) {
try stdout.writeAll("\n\n");
}
try stdout.writeAll(comptime d.ts.class.Printer.printClass(class, 2));
}
try stdout.writeAll("}\n");
}

View File

@@ -6,7 +6,7 @@ const JavaScript = @import("../javascript.zig");
pub const Response = struct {
pub const Class = NewClass(
Response,
"Response",
.{ .name = "Response" },
.{
.@"constructor" = constructor,
},
@@ -24,8 +24,6 @@ pub const Response = struct {
.ro = true,
},
},
false,
false,
);
allocator: *std.mem.Allocator,
@@ -304,21 +302,47 @@ pub const Headers = struct {
};
pub const Class = NewClass(
Headers,
"Headers",
.{
.@"get" = JS.get,
.@"set" = JS.set,
.@"append" = JS.append,
.@"delete" = JS.delete,
.@"entries" = JS.entries,
.@"keys" = JS.keys,
.@"values" = JS.values,
.@"constructor" = JS.constructor,
.@"finalize" = JS.finalize,
.name = "Headers",
.read_only = true,
},
.{
.@"get" = .{
.rfn = JS.get,
},
.@"set" = .{
.rfn = JS.set,
.ts = d.ts{},
},
.@"append" = .{
.rfn = JS.append,
.ts = d.ts{},
},
.@"delete" = .{
.rfn = JS.delete,
.ts = d.ts{},
},
.@"entries" = .{
.rfn = JS.entries,
.ts = d.ts{},
},
.@"keys" = .{
.rfn = JS.keys,
.ts = d.ts{},
},
.@"values" = .{
.rfn = JS.values,
.ts = d.ts{},
},
.@"constructor" = .{
.rfn = JS.constructor,
.ts = d.ts{},
},
.@"finalize" = .{
.rfn = JS.finalize,
},
},
.{},
true,
false,
);
// https://developer.mozilla.org/en-US/docs/Glossary/Guard
@@ -807,7 +831,10 @@ pub const Request = struct {
pub const Class = NewClass(
Request,
"Request",
.{
.name = "Request",
.read_only = true,
},
.{},
.{
.@"cache" = .{
@@ -855,8 +882,6 @@ pub const Request = struct {
.@"ro" = true,
},
},
true,
false,
);
pub fn getCache(
@@ -987,14 +1012,42 @@ pub const FetchEvent = struct {
pub const Class = NewClass(
FetchEvent,
"FetchEvent",
.{ .@"respondWith" = respondWith, .@"waitUntil" = waitUntil },
.{
.@"client" = .{ .@"get" = getClient, .ro = true },
.@"request" = .{ .@"get" = getRequest, .ro = true },
.name = "FetchEvent",
.read_only = true,
.ts = d.ts.class{ .interface = true },
},
.{
.@"respondWith" = .{
.rfn = respondWith,
.ts = d.ts{
.tsdoc = "Render the response in the active HTTP request",
.@"return" = "void",
.args = &[_]d.ts.arg{
.{ .name = "response", .@"return" = "Response" },
},
},
},
.@"waitUntil" = waitUntil,
},
.{
.@"client" = .{
.@"get" = getClient,
.ro = true,
.ts = d.ts{
.tsdoc = "HTTP client metadata. This is not implemented yet, do not use.",
.@"return" = "undefined",
},
},
.@"request" = .{
.@"get" = getRequest,
.ro = true,
.ts = d.ts{
.tsdoc = "HTTP request",
.@"return" = "InstanceType<Request>",
},
},
},
true,
false,
);
pub fn getClient(