aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--.vscode/c_cpp_properties.json48
-rw-r--r--.vscode/settings.json33
-rw-r--r--Makefile33
-rw-r--r--build.zig146
-rw-r--r--src/feature_flags.zig3
-rw-r--r--src/global.zig4
-rw-r--r--src/http.zig3
-rw-r--r--src/javascript/jsc/JavascriptCore.zig269
m---------src/javascript/jsc/WebKit0
-rw-r--r--src/javascript/jsc/api/router.zig105
-rw-r--r--src/javascript/jsc/base.zig194
-rw-r--r--src/javascript/jsc/bindings/DefaultGlobal.cpp162
-rw-r--r--src/javascript/jsc/bindings/DefaultGlobal.h65
-rw-r--r--src/javascript/jsc/bindings/DefaultGlobal.zig272
-rw-r--r--src/javascript/jsc/bindings/JSCInlines.h57
-rw-r--r--src/javascript/jsc/bindings/JSValue.zig0
-rw-r--r--src/javascript/jsc/bindings/bindings-generator.zig32
-rw-r--r--src/javascript/jsc/bindings/bindings.cpp10
-rw-r--r--src/javascript/jsc/bindings/bindings.zig2
-rw-r--r--src/javascript/jsc/bindings/header-gen.zig368
-rw-r--r--src/javascript/jsc/bindings/headers.h42
-rw-r--r--src/javascript/jsc/bindings/imports.zig1
-rw-r--r--src/javascript/jsc/bindings/inlines.cpp0
-rw-r--r--src/javascript/jsc/bindings/root.h71
-rw-r--r--src/javascript/jsc/javascript.zig157
-rw-r--r--src/javascript/jsc/typescript.zig59
-rw-r--r--src/js_printer.zig1
-rw-r--r--src/router.zig58
-rw-r--r--src/test/fixtures/console.log.js4
-rw-r--r--types/globals.d.ts21
-rw-r--r--types/index.d.ts4
-rw-r--r--types/modules.d.ts48
33 files changed, 1985 insertions, 290 deletions
diff --git a/.gitignore b/.gitignore
index 6e368a684..09eed84b8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -43,4 +43,5 @@ esbuilddir
outdir/
outcss
.next
-txt.js \ No newline at end of file
+txt.js
+.idea \ No newline at end of file
diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json
new file mode 100644
index 000000000..708574d8d
--- /dev/null
+++ b/.vscode/c_cpp_properties.json
@@ -0,0 +1,48 @@
+{
+ "configurations": [
+ {
+ "name": "Mac",
+ "forcedInclude": [
+ "${workspaceFolder}/src/javascript/jsc/bindings/root.h"
+ ],
+ "includePath": [
+ "${workspaceFolder}/src/JavaScript/jsc/WebKit/WebKitBuild/Release/JavaScriptCore/PrivateHeaders/",
+ "${workspaceFolder}/src/JavaScript/jsc/WebKit/WebKitBuild/Release/WTF/Headers/**",
+ "${workspaceFolder}/src/JavaScript/jsc/WebKit/WebKitBuild/Release/*",
+ "${workspaceFolder}/src/JavaScript/jsc/bindings/**",
+ "${workspaceFolder}/src/JavaScript/jsc/WebKit/Source/bmalloc/**",
+ "${workspaceFolder}/src/javascript/jsc/WebKit/WebKitBuild/Release/ICU/Headers/"
+ ],
+ "browse": {
+ "path": [
+ "${workspaceFolder}/src/javascript/jsc/bindings/*",
+ "${workspaceFolder}/src/JavaScript/jsc/WebKit/WebKitBuild/Release/JavaScriptCore/PrivateHeaders/",
+ "${workspaceFolder}/src/JavaScript/jsc/WebKit/WebKitBuild/Release/WTF/Headers/**",
+ "${workspaceFolder}/src/JavaScript/jsc/WebKit/WebKitBuild/Release/*",
+ "${workspaceFolder}/src/JavaScript/jsc/bindings/**",
+ "${workspaceFolder}/src/JavaScript/jsc/WebKit/Source/bmalloc/**",
+ "${workspaceFolder}/src/javascript/jsc/WebKit/WebKitBuild/Release/ICU/Headers/"
+ ],
+ "limitSymbolsToIncludedHeaders": true,
+ "databaseFilename": ""
+ },
+ "defines": [
+ "STATICALLY_LINKED_WITH_JavaScriptCore=1",
+ "STATICALLY_LINKED_WITH_WTF=1",
+ "BUILDING_WITH_CMAKE=1",
+ "NOMINMAX",
+ "ENABLE_INSPECTOR_ALTERNATE_DISPATCHERS=0",
+ "BUILDING_JSCONLY__",
+ "USE_FOUNDATION=1"
+ ],
+ "macFrameworkPath": [
+ // "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.3.sdk/System/Library/Frameworks"
+ ],
+ "compilerPath": "/usr/local/opt/llvm/bin/clang",
+ "cStandard": "c17",
+ "cppStandard": "c++17",
+ "intelliSenseMode": "macos-clang-x64"
+ }
+ ],
+ "version": 4
+}
diff --git a/.vscode/settings.json b/.vscode/settings.json
index e69de29bb..735e3098c 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -0,0 +1,33 @@
+{
+ "git.autoRepositoryDetection": "openEditors",
+ "search.quickOpen.includeSymbols": true,
+ "search.seedWithNearestWord": true,
+ "search.smartCase": true,
+ "search.exclude": {
+ "src/javascript/jsc/WebKit/**/*": true
+ },
+ "search.followSymlinks": false,
+ "search.useIgnoreFiles": true,
+
+ "C_Cpp.files.exclude": {
+ "**/.vscode": true,
+ "src/javascript/jsc/WebKit/JSTests": true,
+ "src/javascript/jsc/WebKit/Tools": true,
+ "src/javascript/jsc/WebKit/WebDriverTests": true,
+ "src/javascript/jsc/WebKit/WebKit.xcworkspace": true,
+ "src/javascript/jsc/WebKit/WebKitLibraries": true,
+ "src/javascript/jsc/WebKit/Websites": true,
+ "src/javascript/jsc/WebKit/resources": true,
+ "src/javascript/jsc/WebKit/LayoutTests": true,
+ "src/javascript/jsc/WebKit/ManualTests": true,
+ "src/javascript/jsc/WebKit/PerformanceTests": true,
+ "src/javascript/jsc/WebKit/WebKitLegacy": true,
+ "src/javascript/jsc/WebKit/WebCore": true,
+ "src/javascript/jsc/WebKit/WebDriver": true,
+ "src/javascript/jsc/WebKit/WebKitBuild": true,
+ "src/javascript/jsc/WebKit/WebInspectorUI": true
+ },
+ "files.associations": {
+ "*.idl": "cpp"
+ }
+}
diff --git a/Makefile b/Makefile
index 705766537..6e977e34a 100644
--- a/Makefile
+++ b/Makefile
@@ -4,7 +4,38 @@ speedy: speedy-prod-native speedy-prod-wasi speedy-prod-wasm
api:
peechy --schema src/api/schema.peechy --esm src/api/schema.js --ts src/api/schema.d.ts --zig src/api/schema.zig
-
+jsc:
+ jsc-mac
+
+jsc-mac: jsc-build-mac jsc-bindings-mac
+
+jsc-build-mac:
+ cd src/javascript/jsc/WebKit && ICU_INCLUDE_DIRS="/usr/local/opt/icu4c/include" ./Tools/Scripts/build-jsc --jsc-only --cmakeargs="-DENABLE_STATIC_JSC=ON -DCMAKE_BUILD_TYPE=relwithdebinfo" && echo "Ignore the \"has no symbols\" errors"
+
+SRC_DIR := src/javascript/jsc/bindings
+OBJ_DIR := src/javascript/jsc/bindings-obj
+SRC_FILES := $(wildcard $(SRC_DIR)/*.cpp)
+OBJ_FILES := $(patsubst $(SRC_DIR)/%.cpp,$(OBJ_DIR)/%.o,$(SRC_FILES))
+
+jsc-bindings-mac: $(OBJ_FILES)
+
+$(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp
+ clang++ -c -o $@ $< \
+ -Isrc/JavaScript/jsc/WebKit/WebKitBuild/Release/JavaScriptCore/PrivateHeaders \
+ -Isrc/JavaScript/jsc/WebKit/WebKitBuild/Release/WTF/Headers \
+ -Isrc/javascript/jsc/WebKit/WebKitBuild/Release/ICU/Headers \
+ -DSTATICALLY_LINKED_WITH_JavaScriptCore=1 \
+ -DSTATICALLY_LINKED_WITH_WTF=1 \
+ -DBUILDING_WITH_CMAKE=1 \
+ -DNOMINMAX \
+ -DENABLE_INSPECTOR_ALTERNATE_DISPATCHERS=0 \
+ -DBUILDING_JSCONLY__ \
+ -DASSERT_ENABLED=0\
+ -Isrc/JavaScript/jsc/WebKit/WebKitBuild/Release/ \
+ -Isrc/JavaScript/jsc/bindings/ \
+ -Isrc/javascript/jsc/WebKit/Source/bmalloc \
+ -std=gnu++17
+
speedy-prod-native-macos:
cd src/deps; clang -c picohttpparser.c; cd ../../
zig build -Drelease-fast -Dtarget=x86_64-macos-gnu
diff --git a/build.zig b/build.zig
index 77a567a6b..e691ae3a5 100644
--- a/build.zig
+++ b/build.zig
@@ -7,13 +7,14 @@ pub fn addPicoHTTP(step: *std.build.LibExeObjStep) void {
.path = .{ .path = "src/deps/picohttp.zig" },
});
- step.addObjectFile(
- "src/deps/picohttpparser.o",
- );
+ step.addObjectFile("src/deps/picohttpparser.o");
step.addIncludeDir("src/deps");
-}
+ // step.add("/Users/jarred/Code/WebKit/WebKitBuild/Release/lib/libWTF.a");
-const ENABLE_JAVASCRIPT_BUILD = false;
+ // ./Tools/Scripts/build-jsc --jsc-only --cmakeargs="-DENABLE_STATIC_JSC=ON"
+ // set -gx ICU_INCLUDE_DIRS "/usr/local/opt/icu4c/include"
+ // homebrew-provided icu4c
+}
pub fn build(b: *std.build.Builder) void {
// Standard target options allows the person running `zig build` to choose
@@ -21,15 +22,13 @@ pub fn build(b: *std.build.Builder) void {
// means any target is allowed, and the default is native. Other options
// for restricting supported target set are available.
const target = b.standardTargetOptions(.{});
-
// Standard release options allow the person running `zig build` to select
// between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall.
const mode = b.standardReleaseOptions();
var cwd_buf: [std.fs.MAX_PATH_BYTES]u8 = undefined;
- var cwd = std.os.getFdPath(std.fs.cwd().fd, &cwd_buf) catch unreachable;
+ const cwd: []const u8 = b.pathFromRoot(".");
var exe: *std.build.LibExeObjStep = undefined;
-
var output_dir_buf = std.mem.zeroes([4096]u8);
var bin_label = if (mode == std.builtin.Mode.Debug) "/debug/" else "/";
const output_dir = std.fmt.bufPrint(&output_dir_buf, "build{s}{s}-{s}", .{ bin_label, @tagName(target.getOs().tag), @tagName(target.getCpuArch()) }) catch unreachable;
@@ -70,7 +69,7 @@ pub fn build(b: *std.build.Builder) void {
lib.setTarget(target);
lib.setBuildMode(mode);
- std.fs.deleteTreeAbsolute(std.fs.path.join(std.heap.page_allocator, &.{ cwd, lib.getOutputSource().getPath(b) }) catch unreachable) catch {};
+ std.fs.deleteTreeAbsolute(std.fs.path.join(b.allocator, &.{ cwd, lib.getOutputSource().getPath(b) }) catch unreachable) catch {};
var install = b.getInstallStep();
lib.strip = false;
lib.install();
@@ -98,7 +97,7 @@ pub fn build(b: *std.build.Builder) void {
exe.setOutputDir(output_dir);
- var walker = std.fs.walkPath(std.heap.page_allocator, cwd) catch unreachable;
+ var walker = std.fs.walkPath(b.allocator, cwd) catch unreachable;
if (std.builtin.is_test) {
while (walker.next() catch unreachable) |entry| {
if (std.mem.endsWith(u8, entry.basename, "_test.zig")) {
@@ -116,44 +115,102 @@ pub fn build(b: *std.build.Builder) void {
exe.setTarget(target);
exe.setBuildMode(mode);
b.install_path = output_dir;
- var javascript: @TypeOf(exe) = undefined;
+
+ var javascript = b.addExecutable("spjs", "src/main_javascript.zig");
+ var typings_exe = b.addExecutable("typescript-decls", "src/javascript/jsc/typescript.zig");
+
// exe.want_lto = true;
if (!target.getCpuArch().isWasm()) {
- addPicoHTTP(
- exe,
- );
- if (ENABLE_JAVASCRIPT_BUILD) {
- javascript = b.addExecutable("spjs", "src/main_javascript.zig");
+ b.default_step.dependOn(&exe.step);
+
+ const bindings_dir = std.fs.path.join(
+ b.allocator,
+ &.{
+ cwd,
+ "src",
+ "javascript",
+ "jsc",
+ "bindings-obj",
+ },
+ ) catch unreachable;
+
+ var bindings_walker = std.fs.walkPath(b.allocator, bindings_dir) catch unreachable;
+ var bindings_files = std.ArrayList([]const u8).init(b.allocator);
+
+ while (bindings_walker.next() catch unreachable) |entry| {
+ if (std.mem.eql(u8, std.fs.path.extension(entry.basename), ".o")) {
+ bindings_files.append(b.allocator.dupe(u8, entry.path) catch unreachable) catch unreachable;
+ }
+ }
+
+ // // References:
+ // // - https://github.com/mceSystems/node-jsc/blob/master/deps/jscshim/webkit.gyp
+ // // - https://github.com/mceSystems/node-jsc/blob/master/deps/jscshim/docs/webkit_fork_and_compilation.md#webkit-port-and-compilation
+ // const flags = [_][]const u8{
+ // "-Isrc/JavaScript/jsc/WebKit/WebKitBuild/Release/JavaScriptCore/PrivateHeaders",
+ // "-Isrc/JavaScript/jsc/WebKit/WebKitBuild/Release/WTF/Headers",
+ // "-Isrc/javascript/jsc/WebKit/WebKitBuild/Release/ICU/Headers",
+ // "-DSTATICALLY_LINKED_WITH_JavaScriptCore=1",
+ // "-DSTATICALLY_LINKED_WITH_WTF=1",
+ // "-DBUILDING_WITH_CMAKE=1",
+ // "-DNOMINMAX",
+ // "-DENABLE_INSPECTOR_ALTERNATE_DISPATCHERS=0",
+ // "-DBUILDING_JSCONLY__",
+ // "-DASSERT_ENABLED=0", // missing symbol errors like this will happen "JSC::DFG::DoesGCCheck::verifyCanGC(JSC::VM&)"
+ // "-Isrc/JavaScript/jsc/WebKit/WebKitBuild/Release/", // config.h,
+ // "-Isrc/JavaScript/jsc/bindings/",
+ // "-Isrc/javascript/jsc/WebKit/Source/bmalloc",
+ // "-std=gnu++17",
+ // if (target.getOsTag() == .macos) "-DUSE_FOUNDATION=1" else "",
+ // if (target.getOsTag() == .macos) "-DUSE_CF_RETAIN_PTR=1" else "",
+ // };
+ const headers_step = b.step("headers", "JSC headers");
+ var headers_exec: *std.build.LibExeObjStep = b.addExecutable("headers", "src/javascript/jsc/bindings/bindings-generator.zig");
+ var headers_runner = headers_exec.run();
+ headers_step.dependOn(&headers_runner.step);
+
+ b.default_step.dependOn(&exe.step);
+
+ var steps = [_]*std.build.LibExeObjStep{ exe, javascript, typings_exe };
+
+ for (steps) |step| {
+ step.linkLibC();
+ step.linkLibCpp();
addPicoHTTP(
- javascript,
+ step,
);
- 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);
- javascript.linkLibC();
- }
- // javascript.linkLibCpp();
+ step.addObjectFile("src/JavaScript/jsc/WebKit/WebKitBuild/Release/lib/libJavaScriptCore.a");
+ step.addObjectFile("src/JavaScript/jsc/WebKit/WebKitBuild/Release/lib/libWTF.a");
+ step.addObjectFile("src/JavaScript/jsc/WebKit/WebKitBuild/Release/lib/libbmalloc.a");
- if (target.getOsTag() == .macos) {
- if (ENABLE_JAVASCRIPT_BUILD) {
- javascript.linkFramework("JavaScriptCore");
- }
- exe.linkFramework("JavascriptCore");
- }
- if (ENABLE_JAVASCRIPT_BUILD) {
- javascript.strip = false;
- }
- }
+ // We must link ICU statically
+ step.addObjectFile("/usr/local/opt/icu4c/lib/libicudata.a");
+ step.addObjectFile("/usr/local/opt/icu4c/lib/libicui18n.a");
+ step.addObjectFile("/usr/local/opt/icu4c/lib/libicuuc.a");
- b.default_step.dependOn(&exe.step);
+ if (target.getOsTag() == .macos) {
+ // icucore is a weird macOS only library
+ step.linkSystemLibrary("icucore");
+ step.addLibPath("/usr/local/opt/icu4c/lib");
+ step.addIncludeDir("/usr/local/opt/icu4c/include");
+ }
- if (!target.getCpuArch().isWasm()) {
- if (ENABLE_JAVASCRIPT_BUILD) {
- javascript.install();
+ for (bindings_files.items) |binding| {
+ step.addObjectFile(
+ binding,
+ );
+ }
}
+ } else {
+ b.default_step.dependOn(&exe.step);
}
+ javascript.strip = false;
+ javascript.packages = std.ArrayList(std.build.Pkg).fromOwnedSlice(b.allocator, b.allocator.dupe(std.build.Pkg, exe.packages.items) catch unreachable);
+ javascript.setOutputDir(output_dir);
+ javascript.setBuildMode(mode);
+
const run_cmd = exe.run();
run_cmd.step.dependOn(b.getInstallStep());
if (b.args) |args| {
@@ -166,22 +223,19 @@ pub fn build(b: *std.build.Builder) void {
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: *std.build.RunStep = typings_exe.run();
typings_cmd.cwd = cwd;
typings_cmd.addArg(cwd);
typings_cmd.addArg("types");
-
typings_cmd.step.dependOn(&typings_exe.step);
typings_exe.linkLibC();
+ typings_exe.linkLibCpp();
typings_exe.setMainPkgPath(cwd);
- if (target.getOsTag() == .macos) {
- typings_exe.linkFramework("JavascriptCore");
- }
- addPicoHTTP(
- typings_exe,
- );
- const typings_step = b.step("types", "Build TypeScript types");
+
+ var typings_step = b.step("types", "Build TypeScript types");
typings_step.dependOn(&typings_cmd.step);
+
+ var javascript_cmd = b.step("spjs", "Build standalone JavaScript runtime. Must run \"make jsc\" first.");
+ javascript_cmd.dependOn(&javascript.step);
}
diff --git a/src/feature_flags.zig b/src/feature_flags.zig
index 16adec042..828bae1fd 100644
--- a/src/feature_flags.zig
+++ b/src/feature_flags.zig
@@ -38,3 +38,6 @@ pub const CSSModulePolyfill = enum {
// Just return whatever the property key they referenced was
facade,
};
+
+// having issues compiling WebKit with this enabled
+pub const remote_inspector = false;
diff --git a/src/global.zig b/src/global.zig
index 5a1428049..16a515086 100644
--- a/src/global.zig
+++ b/src/global.zig
@@ -7,7 +7,7 @@ pub usingnamespace @import("env.zig");
pub const FeatureFlags = @import("feature_flags.zig");
pub const Output = struct {
- threadlocal var source: *Source = undefined;
+ threadlocal var source: Source = undefined;
pub const Source = struct {
const StreamType = {
if (isWasm) {
@@ -41,7 +41,7 @@ pub const Output = struct {
}
pub fn set(_source: *Source) void {
- source = _source;
+ source = _source.*;
}
};
pub var enable_ansi_colors = isNative;
diff --git a/src/http.zig b/src/http.zig
index f9d1acf0e..0514e88aa 100644
--- a/src/http.zig
+++ b/src/http.zig
@@ -44,7 +44,7 @@ threadlocal var res_headers_buf: [100]picohttp.Header = undefined;
const sync = @import("./sync.zig");
const JavaScript = @import("./javascript/jsc/JavaScript.zig");
const js = @import("javascript/jsc/javascript.zig");
-
+const Router = @import("./router.zig");
pub const Watcher = watcher.NewWatcher(*Server);
const ENABLE_LOGGER = false;
@@ -193,6 +193,7 @@ pub const RequestContext = struct {
controlled: bool = false,
watcher: *Watcher,
timer: std.time.Timer,
+ matched_route: ?Router.Match = null,
full_url: [:0]const u8 = "",
res_headers_count: usize = 0,
diff --git a/src/javascript/jsc/JavascriptCore.zig b/src/javascript/jsc/JavascriptCore.zig
index 0f1a624ce..d1a3a9f22 100644
--- a/src/javascript/jsc/JavascriptCore.zig
+++ b/src/javascript/jsc/JavascriptCore.zig
@@ -240,6 +240,15 @@ pub const OpaqueJSPropertyNameArray = struct_OpaqueJSPropertyNameArray;
pub const OpaqueJSPropertyNameAccumulator = struct_OpaqueJSPropertyNameAccumulator;
pub const OpaqueJSValue = struct_OpaqueJSValue;
+// const JSProcessID = ;
+pub extern fn JSRemoteInspectorDisableAutoStart() void;
+pub extern fn JSRemoteInspectorStart() void;
+// JS_EXPORT void JSRemoteInspectorSetParentProcessInformation(JSProcessID, const uint8_t* auditData, size_t auditLength) JSC_API_AVAILABLE(macos(10.11), ios(9.0));
+
+pub extern fn JSRemoteInspectorSetLogToSystemConsole(enabled: bool) void;
+pub extern fn JSRemoteInspectorGetInspectionEnabledByDefault(void) bool;
+pub extern fn JSRemoteInspectorSetInspectionEnabledByDefault(enabled: bool) void;
+
// -- Manual --
// StringImpl::createWithoutCopying
@@ -266,6 +275,262 @@ pub fn isObjectOfClassAndResolveIfNeeded(ctx: JSContextRef, obj: JSObjectRef, cl
if (prop == null) {
return null;
}
-
-
}
+
+pub const UTF8Ptr = [*c]const u8;
+pub const UTF16Ptr = [*c]const u16;
+
+// --- Custom Methods! ----
+pub const Encoding = enum(u8) {
+ empty = 0,
+ char8 = 8,
+ char16 = 16,
+};
+pub const JSCellValue = u64;
+pub const CellType = enum(u8) {
+ CellType = 0,
+ StringType = 1,
+ HeapBigIntType = 2,
+ LastMaybeFalsyCellPrimitive = 2,
+ SymbolType = 3,
+ GetterSetterType = 4,
+ CustomGetterSetterType = 5,
+ APIValueWrapperType = 6,
+ NativeExecutableType = 7,
+ ProgramExecutableType = 8,
+ ModuleProgramExecutableType = 9,
+ EvalExecutableType = 10,
+ FunctionExecutableType = 11,
+ UnlinkedFunctionExecutableType = 12,
+ UnlinkedProgramCodeBlockType = 13,
+ UnlinkedModuleProgramCodeBlockType = 14,
+ UnlinkedEvalCodeBlockType = 15,
+ UnlinkedFunctionCodeBlockType = 16,
+ CodeBlockType = 17,
+ JSImmutableButterflyType = 18,
+ JSSourceCodeType = 19,
+ JSScriptFetcherType = 20,
+ JSScriptFetchParametersType = 21,
+ ObjectType = 22,
+ FinalObjectType = 23,
+ JSCalleeType = 24,
+ JSFunctionType = 25,
+ InternalFunctionType = 26,
+ NullSetterFunctionType = 27,
+ BooleanObjectType = 28,
+ NumberObjectType = 29,
+ ErrorInstanceType = 30,
+ PureForwardingProxyType = 31,
+ DirectArgumentsType = 32,
+ ScopedArgumentsType = 33,
+ ClonedArgumentsType = 34,
+ ArrayType = 35,
+ DerivedArrayType = 36,
+ ArrayBufferType = 37,
+ Int8ArrayType = 38,
+ Uint8ArrayType = 39,
+ Uint8ClampedArrayType = 40,
+ Int16ArrayType = 41,
+ Uint16ArrayType = 42,
+ Int32ArrayType = 43,
+ Uint32ArrayType = 44,
+ Float32ArrayType = 45,
+ Float64ArrayType = 46,
+ BigInt64ArrayType = 47,
+ BigUint64ArrayType = 48,
+ DataViewType = 49,
+ GlobalObjectType = 50,
+ GlobalLexicalEnvironmentType = 51,
+ LexicalEnvironmentType = 52,
+ ModuleEnvironmentType = 53,
+ StrictEvalActivationType = 54,
+ WithScopeType = 55,
+ ModuleNamespaceObjectType = 56,
+ RegExpObjectType = 57,
+ JSDateType = 58,
+ ProxyObjectType = 59,
+ JSGeneratorType = 60,
+ JSAsyncGeneratorType = 61,
+ JSArrayIteratorType = 62,
+ JSMapIteratorType = 63,
+ JSSetIteratorType = 64,
+ JSStringIteratorType = 65,
+ JSPromiseType = 66,
+ JSMapType = 67,
+ JSSetType = 68,
+ JSWeakMapType = 69,
+ JSWeakSetType = 70,
+ WebAssemblyModuleType = 71,
+ StringObjectType = 72,
+ DerivedStringObjectType = 73,
+ LastJSCObjectType = 73,
+ MaxJSType = 255,
+ _,
+
+ pub fn isString(this: CellType) bool {
+ return switch (this) {
+ .StringType => true,
+ else => false,
+ };
+ }
+};
+pub const ExternalStringFinalizer = fn (finalize_ptr: ?*c_void, ref: JSStringRef, buffer: *c_void, byteLength: usize) callconv(.C) void;
+pub extern fn JSStringCreate(string: UTF8Ptr, length: usize) JSStringRef;
+pub extern fn JSStringCreateStatic(string: UTF8Ptr, length: usize) JSStringRef;
+pub extern fn JSStringCreateExternal(string: UTF8Ptr, length: usize, finalize_ptr: ?*c_void, finalizer: ExternalStringFinalizer) JSStringRef;
+pub extern fn JSStringIsEqualToString(a: JSStringRef, string: UTF8Ptr, length: usize) bool;
+pub extern fn JSStringEncoding(string: JSStringRef) Encoding;
+pub extern fn JSStringGetCharacters8Ptr(string: JSStringRef) UTF8Ptr;
+extern fn JSStringIterate(string: JSCellValue, iter: *JSStringIterator_) void;
+pub extern fn JSCellType(cell: JSCellValue) CellType;
+pub extern fn JSStringIsStatic(ref: JSStringRef) bool;
+pub extern fn JSStringIsExternal(ref: JSStringRef) bool;
+
+pub const JStringIteratorAppendCallback = fn (ctx: *JSStringIterator_, ptr: *c_void, length: u32) callconv(.C) c_void;
+pub const JStringIteratorWriteCallback = fn (ctx: *JSStringIterator_, ptr: *c_void, length: u32, offset: u32) callconv(.C) c_void;
+const JSStringIterator_ = extern struct {
+ ctx: *c_void,
+ stop: u8,
+
+ append8: JStringIteratorAppendCallback,
+ append16: JStringIteratorAppendCallback,
+ write8: JStringIteratorWriteCallback,
+ write16: JStringIteratorWriteCallback,
+};
+
+pub const JSString = struct {
+ pub const Callback = fn (finalize_ptr_: ?*c_void, ref: JSStringRef, buffer: *c_void, byteLength: usize) callconv(.C) void;
+ _ref: JSStringRef = null,
+ backing: Backing = .{ .gc = 0 },
+
+ pub const Backing = union(Ownership) {
+ external: ExternalString,
+ static: []const u8,
+ gc: u0,
+ };
+
+ pub fn deref(this: *JSString) void {
+ if (this._ref == null) return;
+
+ JSStringRetain(this._ref);
+ }
+
+ const ExternalString = struct {
+ callback: Callback,
+ external_callback: *c_void,
+ external_ptr: ?*c_void = null,
+ slice: []const u8,
+ };
+
+ pub fn External(comptime ExternalType: type, external_type: *ExternalType, str: []const u8, callback: fn (this: *ExternalType, buffer: []const u8) void) JSString {
+ const CallbackFunctionType = @TypeOf(callback);
+
+ const ExternalWrapper = struct {
+ pub fn finalizer_callback(finalize_ptr_: ?*c_void, buffer: *c_void, byteLength: usize) callconv(.C) void {
+ var finalize_ptr = finalize_ptr_ orelse return;
+
+ var jsstring = @ptrCast(
+ *JSString,
+ @alignCast(
+ @alignOf(
+ *JSString,
+ ),
+ finalize_ptr,
+ ),
+ );
+
+ var cb = @as(CallbackFunctionType, jsstring.external_callback orelse return);
+ var raw_external_ptr = jsstring.external_ptr orelse return;
+
+ var external_ptr = @ptrCast(
+ *ExternalType,
+ @alignCast(
+ @alignOf(
+ *ExternalType,
+ ),
+ raw_external_ptr,
+ ),
+ );
+
+ cb(external_ptr, @ptrCast([*]u8, buffer)[0..byteLength]);
+ }
+ };
+
+ return JSString{
+ .backing = .{
+ .external = .{
+ .slice = str,
+ .external_callback = callback,
+ .external_ptr = external_type,
+ .callback = ExternalWrapper.finalizer_callback,
+ },
+ },
+ };
+ }
+
+ // pub fn Iterator(comptime WriterType: type) type {
+ // return struct {
+
+ // };
+ // }
+
+ pub const Ownership = enum { external, static, gc };
+
+ pub fn Static(str: []const u8) JSString {
+ return JSString{ ._ref = null, .backing = .{ .static = str } };
+ }
+
+ pub fn ref(this: *JSString) JSStringRef {
+ if (this._ref == null) {
+ switch (this.backing) {
+ .External => |external| {
+ this._ref = JSStringCreateExternal(external.slice, external.slice.len, this, this.external_callback.?);
+ },
+ .Static => |slice| {
+ this._ref = JSStringCreateStatic(slice.ptr, slice.len);
+ },
+ .gc => {
+ return null;
+ },
+ }
+ }
+
+ JSStringRetain(this._ref);
+
+ return this._ref;
+ }
+
+ pub fn fromStringRef(string_ref: JSStringRef) JSString {}
+
+ pub fn init(str: []const u8) JSString {}
+
+ pub fn static(str: []const u8) JSString {}
+
+ pub fn finalize(this: *JSString) void {
+ this.loaded = false;
+ }
+
+ pub fn value(this: *JSString, ctx: JSContextRef) JSValueRef {
+ return JSValueMakeString(ctx, this.ref());
+ }
+
+ pub fn len(this: *const JSString) usize {
+ return JSStringGetLength(this.ref);
+ }
+
+ pub fn encoding(this: *const JSString) Encoding {
+ return JSStringEncoding(this.ref);
+ }
+
+ // pub fn eql(this: *const JSString, str: string) {
+
+ // }
+
+ pub fn eqlJS(this: *const JSString, ctx: JSContextRef, comptime Type: type, that: Type) bool {
+ switch (comptime Type) {
+ JSValueRef => {},
+ JSStringRef => {},
+ JSString => {},
+ }
+ }
+};
diff --git a/src/javascript/jsc/WebKit b/src/javascript/jsc/WebKit
-Subproject 26db06f4db00380b673808316cb959e2c0d0160
+Subproject 7d494581249d31ff34d65436f077e76ea2516b9
diff --git a/src/javascript/jsc/api/router.zig b/src/javascript/jsc/api/router.zig
index b37cdf55e..84dad71ef 100644
--- a/src/javascript/jsc/api/router.zig
+++ b/src/javascript/jsc/api/router.zig
@@ -2,40 +2,57 @@ usingnamespace @import("../base.zig");
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");
usingnamespace @import("../webcore/response.zig");
const Router = @This();
-match: FilesystemRouter.RouteMap.MatchedRoute,
+route: *const FilesystemRouter.Match,
file_path_str: js.JSStringRef = null,
pathname_str: js.JSStringRef = null,
-pub fn constructor(
+pub fn importRoute(
+ this: *Router,
ctx: js.JSContextRef,
function: js.JSObjectRef,
+ thisObject: js.JSObjectRef,
arguments: []const js.JSValueRef,
exception: js.ExceptionRef,
) js.JSObjectRef {
- return null;
+ return JavaScript.VirtualMachine.instance.require(
+ ctx,
+ std.fs.path.dirname(this.route.file_path).?,
+ this.route.file_path,
+ exception,
+ );
}
pub fn match(
obj: *c_void,
ctx: js.JSContextRef,
function: js.JSObjectRef,
+ thisObject: js.JSObjectRef,
arguments: []const js.JSValueRef,
exception: js.ExceptionRef,
) js.JSObjectRef {
- return null;
-}
+ if (arguments.len == 0) {
+ JSError(getAllocator(ctx), "Expected string, FetchEvent, or Request but there were no arguments", .{}, ctx, exception);
+ return null;
+ }
+
+ if (js.JSValueIsObjectOfClass(ctx, arguments[0], FetchEvent.Class.get().*)) {
+ return matchFetchEvent(ctx, To.Zig.ptr(FetchEvent, arguments[0]), exception);
+ }
+
+ if (js.JSValueIsString(ctx, arguments[0])) {
+ return matchPathName(ctx, arguments[0], exception);
+ }
+
+ if (js.JSValueIsObjectOfClass(ctx, arguments[0], Request.Class.get().*)) {
+ return matchRequest(ctx, To.Zig.ptr(Request, arguments[0]), exception);
+ }
-fn matcher(
- obj: *c_void,
- ctx: js.JSContextRef,
- arg: js.JSValueRef,
- exception: js.ExceptionRef,
-) js.JSObjectRef {
return null;
}
@@ -44,13 +61,19 @@ fn matchRequest(
request: *const Request,
exception: js.ExceptionRef,
) js.JSObjectRef {
- return null;
+ return createRouteObject(ctx, request.request_context, exception);
}
-fn matchPathName(
+fn matchPathNameString(
ctx: js.JSContextRef,
pathname: string,
exception: js.ExceptionRef,
+) js.JSObjectRef {}
+
+fn matchPathName(
+ ctx: js.JSContextRef,
+ pathname: js.JSStringRef,
+ exception: js.ExceptionRef,
) js.JSObjectRef {
return null;
}
@@ -60,36 +83,49 @@ fn matchFetchEvent(
fetch_event: *const FetchEvent,
exception: js.ExceptionRef,
) js.JSObjectRef {
- return null;
+ return createRouteObject(ctx, fetch_event.request_context, exception);
+}
+
+fn createRouteObject(ctx: js.JSContextRef, req: *const http.RequestContext, exception: js.ExceptionRef) js.JSValueRef {
+ const route = &(req.matched_route orelse {
+ return js.JSValueMakeNull(ctx);
+ });
+
+ var router = getAllocator(ctx).create(Router) catch unreachable;
+ router.* = Router{
+ .route = route,
+ };
+
+ return Class.new(ctx, router);
}
const match_type_definition = &[_]d.ts{
.{
- .tsdoc = "Match a {@link https://developer.mozilla.org/en-US/docs/Web/API/Request Request} to a Route from the local filesystem.",
+ .tsdoc = "Match a {@link https://developer.mozilla.org/en-US/docs/Web/API/FetchEvent FetchEvent} to a `Route` from the local filesystem. Returns `null` if there is no match.",
.args = &[_]d.ts.arg{
.{
- .name = "request",
- .@"return" = "Request",
+ .name = "event",
+ .@"return" = "FetchEvent",
},
},
.@"return" = "Route | null",
},
.{
- .tsdoc = "Match a {@link https://developer.mozilla.org/en-US/docs/Web/API/FetchEvent FetchEvent} to a Route from the local filesystem.",
+ .tsdoc = "Match a `pathname` to a `Route` from the local filesystem. Returns `null` if there is no match.",
.args = &[_]d.ts.arg{
.{
- .name = "event",
- .@"return" = "FetchEvent",
+ .name = "pathname",
+ .@"return" = "string",
},
},
.@"return" = "Route | null",
},
.{
- .tsdoc = "Match a `pathname` to a Route from the local filesystem.",
+ .tsdoc = "Match a {@link https://developer.mozilla.org/en-US/docs/Web/API/Request Request} to a `Route` from the local filesystem. Returns `null` if there is no match.",
.args = &[_]d.ts.arg{
.{
- .name = "pathname",
- .@"return" = "string",
+ .name = "request",
+ .@"return" = "Request",
},
},
.@"return" = "Route | null",
@@ -110,7 +146,7 @@ pub const Class = NewClass(
},
.{
.match = .{
- .get = match,
+ .rfn = match,
.ts = match_type_definition,
},
},
@@ -136,9 +172,14 @@ pub const Instance = NewClass(
.finalize = .{
.rfn = finalize,
},
- .constructor = .{
- .rfn = constructor,
- .ts = match_type_definition,
+ .import = .{
+ .rfn = importRoute,
+ .ts = d.ts{
+ .@"return" = "Object",
+ .tsdoc =
+ \\Synchronously load & evaluate the file corresponding to the route. Returns the exports of the route. This is similar to `await import(route.filepath)`, except it's synchronous. It is recommended to use this function instead of `import`.
+ ,
+ },
},
},
.{
@@ -156,11 +197,7 @@ pub const Instance = NewClass(
.ts = d.ts{
.@"return" = "string",
.tsdoc =
- \\Project-relative filesystem path to the route file. Useful for importing.
- \\
- \\@example ```tsx
- \\await import(route.filepath);
- \\```
+ \\Project-relative filesystem path to the route file.
,
},
},
@@ -213,7 +250,7 @@ pub fn getFilePath(
exception: js.ExceptionRef,
) js.JSValueRef {
if (this.file_path_str == null) {
- this.file_path_str = js.JSStringCreateWithUTF8CString(this.match.file_path.ptr);
+ this.file_path_str = js.JSStringCreateWithUTF8CString(this.route.file_path.ptr);
}
return js.JSValueMakeString(ctx, this.file_path_str);
@@ -234,7 +271,7 @@ pub fn getPathname(
exception: js.ExceptionRef,
) js.JSValueRef {
if (this.pathname_str == null) {
- this.pathname_str = js.JSStringCreateWithUTF8CString(this.match.pathname.ptr);
+ this.pathname_str = js.JSStringCreateWithUTF8CString(this.route.pathname.ptr);
}
return js.JSValueMakeString(ctx, this.pathname_str);
diff --git a/src/javascript/jsc/base.zig b/src/javascript/jsc/base.zig
index f0c5dc4b6..36567000a 100644
--- a/src/javascript/jsc/base.zig
+++ b/src/javascript/jsc/base.zig
@@ -163,6 +163,17 @@ pub const To = 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 @ptrCast(
+ *StructType,
+ @alignCast(
+ @alignOf(
+ *StructType,
+ ),
+ js.JSObjectGetPrivate(obj).?,
+ ),
+ );
+ }
};
};
@@ -194,23 +205,23 @@ pub const RuntimeImports = struct {
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 default = "default";
- pub const include = "include";
+ 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 GET = "GET";
pub const PUT = "PUT";
@@ -287,16 +298,14 @@ pub const Properties = struct {
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,
- ),
+ @field(Refs, name) = js.JSStringCreateStatic(
+ @field(UTF8, name).ptr,
+ @field(UTF8, name).len,
);
if (isDebug) {
std.debug.assert(
- js.JSStringIsEqualToUTF8CString(@field(Refs, name), @field(UTF8, name)[0.. :0]),
+ js.JSStringIsEqualToString(@field(Refs, name), @field(UTF8, name).ptr, @field(UTF8, name).len),
);
}
}
@@ -315,22 +324,22 @@ fn hasTypeScript(comptime Type: type) bool {
return true;
}
- return @hasDecl(d.ts, "ts");
+ return @hasDecl(Type, "ts");
}
fn getTypeScript(comptime Type: type, value: Type) d.ts.or_decl {
if (comptime hasTypeScriptField(Type)) {
- if (comptime Type.ts == d.ts.decl) {
+ if (@TypeOf(Type.ts) == d.ts.decl) {
return d.ts.or_decl{ .decl = value };
} else {
- return d.ts.or_decl{ .ts = value };
+ return d.ts.or_decl{ .ts = value.ts };
}
}
- if (comptime Type.ts == d.ts.decl) {
- return d.ts.or_decl{ .decl = value };
+ if (@TypeOf(Type.ts) == d.ts.decl) {
+ return d.ts.or_decl{ .decl = Type.ts };
} else {
- return d.ts.or_decl{ .ts = value };
+ return d.ts.or_decl{ .ts = value.ts };
}
}
@@ -723,30 +732,7 @@ pub fn NewClass(
const name = options.name;
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;
- };
+ const function_name_literals = function_names;
var function_name_refs: [function_names.len]js.JSStringRef = undefined;
var class_name_str = name[0.. :0].ptr;
@@ -755,13 +741,7 @@ pub fn NewClass(
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;
- };
+ const property_name_literals = property_names;
var static_properties: [property_names.len]js.JSStaticValue = undefined;
pub var ref: js.JSClassRef = null;
@@ -784,15 +764,19 @@ pub fn NewClass(
pub const static_value_count = static_properties.len;
- /// only use with singletons
- pub fn make(ctx: js.JSContextRef) js.JSObjectRef {}
+ pub fn new(ctx: js.JSContextRef, ptr: ?*ZigType) js.JSObjectRef {
+ return js.JSObjectMake(ctx, get().*, ptr);
+ }
pub fn get() callconv(.C) [*c]js.JSClassRef {
if (!loaded) {
loaded = true;
definition = define();
- ref = js.JSClassRetain(js.JSClassCreate(&definition));
+ ref = js.JSClassCreate(&definition);
}
+
+ _ = js.JSClassRetain(ref);
+
return &ref;
}
@@ -905,11 +889,11 @@ pub fn NewClass(
);
var exc: js.JSValueRef = null;
-
- switch (comptime @typeInfo(@TypeOf(@field(
+ const Field = @TypeOf(@field(
properties,
property_names[id],
- )))) {
+ ));
+ switch (comptime @typeInfo(Field)) {
.Fn => {
return @field(
properties,
@@ -922,19 +906,46 @@ pub fn NewClass(
);
},
.Struct => {
- return @field(
+ const func = @field(
@field(
properties,
property_names[id],
),
"get",
- )(
- this,
- ctx,
- obj,
- prop,
- exception,
);
+
+ const Func = @typeInfo(@TypeOf(func));
+ const WithPropFn = fn (
+ *ZigType,
+ js.JSContextRef,
+ js.JSObjectRef,
+ js.JSStringRef,
+ js.ExceptionRef,
+ ) js.JSValueRef;
+
+ const WithoutPropFn = fn (
+ *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,
}
@@ -1026,12 +1037,14 @@ pub fn NewClass(
switch (@typeInfo(Func)) {
.Struct => {
if (hasTypeScript(Func)) {
- var ts_functions: if (std.meta.trait.isIndexable(@TypeOf(func.ts))) @TypeOf(func.ts) else [1]@TypeOf(func.ts) = undefined;
+ var ts_functions: []const d.ts = &[_]d.ts{};
if (std.meta.trait.isIndexable(@TypeOf(func.ts))) {
- ts_functions = func.ts;
+ ts_functions = std.mem.span(func.ts);
} else {
- ts_functions = .{func.ts};
+ var funcs1 = std.mem.zeroes([1]d.ts);
+ funcs1[0] = func.ts;
+ ts_functions = std.mem.span(&funcs1);
}
for (ts_functions) |ts_function_| {
@@ -1193,11 +1206,14 @@ pub fn NewClass(
switch (@typeInfo(Func)) {
.Struct => {
if (hasTypeScript(Func)) {
- var ts_functions = std.mem.zeroes([count]d.ts);
+ var ts_functions: []const d.ts = &[_]d.ts{};
+
if (std.meta.trait.isIndexable(@TypeOf(func.ts))) {
- ts_functions = func.ts;
+ ts_functions = std.mem.span(func.ts);
} else {
- ts_functions[0] = func.ts;
+ var funcs1 = std.mem.zeroes([1]d.ts);
+ funcs1[0] = func.ts;
+ ts_functions = std.mem.span(&funcs1);
}
for (ts_functions) |ts_function_| {
@@ -1206,6 +1222,10 @@ pub fn NewClass(
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;
}
@@ -1277,10 +1297,16 @@ pub fn NewClass(
} 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,
+ 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;
+
static_functions[count] = js.JSStaticFunction{
.name = (function_names[i][0.. :0]).ptr,
.callAsFunction = callback,
@@ -1323,7 +1349,7 @@ pub fn NewClass(
if (property_names.len > 0) {
inline for (comptime property_name_literals) |prop_name, i| {
- property_name_refs[i] = js.JSStringCreateWithCharactersNoCopy(
+ property_name_refs[i] = js.JSStringCreateStatic(
prop_name.ptr,
prop_name.len,
);
@@ -1335,7 +1361,7 @@ pub fn NewClass(
if (comptime hasSetter(@TypeOf(field))) {
static_properties[i].setProperty = StaticProperty(i).setter;
}
- static_properties[i].name = property_names[i][0.. :0];
+ static_properties[i].name = property_names[i][0.. :0].ptr;
}
def.staticValues = (&static_properties);
diff --git a/src/javascript/jsc/bindings/DefaultGlobal.cpp b/src/javascript/jsc/bindings/DefaultGlobal.cpp
new file mode 100644
index 000000000..2c83c0e3c
--- /dev/null
+++ b/src/javascript/jsc/bindings/DefaultGlobal.cpp
@@ -0,0 +1,162 @@
+
+#include "root.h"
+#include "DefaultGlobal.h"
+
+#include <wtf/text/AtomStringImpl.h>
+
+#include <JavaScriptCore/APICast.h>
+#include <JavaScriptCore/CallFrameInlines.h>
+#include <JavaScriptCore/CatchScope.h>
+#include <JavaScriptCore/Completion.h>
+#include <JavaScriptCore/Error.h>
+#include <JavaScriptCore/Exception.h>
+#include <JavaScriptCore/JSContextInternal.h>
+#include <JavaScriptCore/JSInternalPromise.h>
+#include <JavaScriptCore/JSModuleLoader.h>
+#include <JavaScriptCore/JSNativeStdFunction.h>
+#include <JavaScriptCore/JSPromise.h>
+#include <JavaScriptCore/JSSourceCode.h>
+#include <JavaScriptCore/JSValueInternal.h>
+#include <JavaScriptCore/JSVirtualMachineInternal.h>
+#include <JavaScriptCore/JavaScriptCore.h>
+#include <JavaScriptCore/ObjectConstructor.h>
+#include <JavaScriptCore/SourceOrigin.h>
+#include <wtf/URL.h>
+
+#include "JSCInlines.h"
+
+
+
+class Script;
+namespace JSC {
+ class Identifier;
+ class JSObject;
+ class JSString;
+
+}
+
+
+
+
+
+namespace Wundle {
+
+
+
+const ClassInfo DefaultGlobal::s_info = { "GlobalObject", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(DefaultGlobal) };
+const GlobalObjectMethodTable DefaultGlobal::s_globalObjectMethodTable = {
+ &supportsRichSourceInfo,
+ &shouldInterruptScript,
+ &javaScriptRuntimeFlags,
+ nullptr, // queueTaskToEventLoop
+ &shouldInterruptScriptBeforeTimeout,
+ &moduleLoaderImportModule, // moduleLoaderImportModule
+ &moduleLoaderResolve, // moduleLoaderResolve
+ &moduleLoaderFetch, // moduleLoaderFetch
+ &moduleLoaderCreateImportMetaProperties, // moduleLoaderCreateImportMetaProperties
+ &moduleLoaderEvaluate, // moduleLoaderEvaluate
+ nullptr, // promiseRejectionTracker
+ &reportUncaughtExceptionAtEventLoop,
+ &currentScriptExecutionOwner,
+ &scriptExecutionStatus,
+ nullptr, // defaultLanguage
+ nullptr, // compileStreaming
+ nullptr, // instantiateStreaming
+};
+
+
+void DefaultGlobal::reportUncaughtExceptionAtEventLoop(JSGlobalObject* globalObject, Exception* exception) {}
+JSC::Identifier DefaultGlobal::moduleLoaderResolve(JSGlobalObject* globalObject, JSModuleLoader* loader, JSValue key, JSValue referrer, JSValue val) {
+ String string = key.toWTFString(globalObject);
+ return JSC::Identifier::fromString(globalObject->vm(), string );
+}
+JSInternalPromise* DefaultGlobal::moduleLoaderImportModule(JSGlobalObject* globalObject, JSModuleLoader*, JSString* specifierValue, JSValue, const SourceOrigin& sourceOrigin) {
+ return nullptr;
+}
+JSInternalPromise* DefaultGlobal::moduleLoaderFetch(JSGlobalObject* globalObject, JSModuleLoader*, JSValue key, JSValue, JSValue) {
+ return nullptr;
+}
+JSC::JSObject* DefaultGlobal::moduleLoaderCreateImportMetaProperties(JSGlobalObject* globalObject, JSModuleLoader*loader, JSValue key, JSModuleRecord* record, JSValue value) {
+ return nullptr;
+}
+JSValue DefaultGlobal::moduleLoaderEvaluate(JSGlobalObject* globalObject, JSModuleLoader* moduleLoader, JSValue key, JSValue moduleRecordValue, JSValue scriptFetcher, JSValue sentValue, JSValue resumeMode) {
+ return jsNull();
+}
+
+using namespace JSC;
+
+
+JSC::ObjectPrototype* DefaultGlobal__objectPrototype(Wundle::DefaultGlobal* arg0) {
+ return arg0->objectPrototype();
+}
+JSC::FunctionPrototype* DefaultGlobal__functionPrototype(Wundle::DefaultGlobal* arg0) {
+ return arg0->functionPrototype();
+}
+JSC::ArrayPrototype* DefaultGlobal__arrayPrototype(Wundle::DefaultGlobal* arg0) {
+ return arg0->arrayPrototype();
+}
+JSC::JSObject* DefaultGlobal__booleanPrototype(Wundle::DefaultGlobal* arg0) {
+ return arg0->booleanPrototype();
+}
+JSC::StringPrototype* DefaultGlobal__stringPrototype(Wundle::DefaultGlobal* arg0) {
+ return arg0->stringPrototype();
+}
+JSC::JSObject* DefaultGlobal__numberPrototype(Wundle::DefaultGlobal* arg0) {
+ return arg0->numberPrototype();
+}
+JSC::BigIntPrototype* DefaultGlobal__bigIntPrototype(Wundle::DefaultGlobal* arg0) {
+ return arg0->bigIntPrototype();
+}
+JSC::JSObject* DefaultGlobal__datePrototype(Wundle::DefaultGlobal* arg0) {
+ return arg0->datePrototype();
+}
+JSC::JSObject* DefaultGlobal__symbolPrototype(Wundle::DefaultGlobal* arg0) {
+ return arg0->symbolPrototype();
+}
+JSC::RegExpPrototype* DefaultGlobal__regExpPrototype(Wundle::DefaultGlobal* arg0) {
+ return arg0->regExpPrototype();
+}
+JSC::JSObject* DefaultGlobal__errorPrototype(Wundle::DefaultGlobal* arg0) {
+ return arg0->errorPrototype();
+}
+JSC::IteratorPrototype* DefaultGlobal__iteratorPrototype(Wundle::DefaultGlobal* arg0) {
+ return arg0->iteratorPrototype();
+}
+JSC::AsyncIteratorPrototype* DefaultGlobal__asyncIteratorPrototype(Wundle::DefaultGlobal* arg0) {
+ return arg0->asyncIteratorPrototype();
+}
+JSC::GeneratorFunctionPrototype* DefaultGlobal__generatorFunctionPrototype(Wundle::DefaultGlobal* arg0) {
+ return arg0->generatorFunctionPrototype();
+}
+JSC::GeneratorPrototype* DefaultGlobal__generatorPrototype(Wundle::DefaultGlobal* arg0) {
+ return arg0->generatorPrototype();
+}
+JSC::AsyncFunctionPrototype* DefaultGlobal__asyncFunctionPrototype(Wundle::DefaultGlobal* arg0) {
+ return arg0->asyncFunctionPrototype();
+}
+JSC::ArrayIteratorPrototype* DefaultGlobal__arrayIteratorPrototype(Wundle::DefaultGlobal* arg0) {
+ return arg0->arrayIteratorPrototype();
+}
+JSC::MapIteratorPrototype* DefaultGlobal__mapIteratorPrototype(Wundle::DefaultGlobal* arg0) {
+ return arg0->mapIteratorPrototype();
+}
+JSC::SetIteratorPrototype* DefaultGlobal__setIteratorPrototype(Wundle::DefaultGlobal* arg0) {
+ return arg0->setIteratorPrototype();
+}
+JSC::JSObject* DefaultGlobal__mapPrototype(Wundle::DefaultGlobal* arg0) {
+ return arg0->mapPrototype();
+}
+JSC::JSObject* DefaultGlobal__jsSetPrototype(Wundle::DefaultGlobal* arg0) {
+ return arg0->jsSetPrototype();
+}
+JSC::JSPromisePrototype* DefaultGlobal__promisePrototype(Wundle::DefaultGlobal* arg0) {
+ return arg0->promisePrototype();
+}
+JSC::AsyncGeneratorPrototype* DefaultGlobal__asyncGeneratorPrototype(Wundle::DefaultGlobal* arg0) {
+ return arg0->asyncGeneratorPrototype();
+}
+JSC::AsyncGeneratorFunctionPrototype* DefaultGlobal__asyncGeneratorFunctionPrototype(Wundle::DefaultGlobal* arg0) {
+ return arg0->asyncGeneratorFunctionPrototype();
+}
+
+}
diff --git a/src/javascript/jsc/bindings/DefaultGlobal.h b/src/javascript/jsc/bindings/DefaultGlobal.h
new file mode 100644
index 000000000..6bc5eb0c9
--- /dev/null
+++ b/src/javascript/jsc/bindings/DefaultGlobal.h
@@ -0,0 +1,65 @@
+#pragma once
+
+namespace JSC {
+ class Structure;
+ class Identifier;
+
+}
+
+#include "root.h"
+#include <JavaScriptCore/JSGlobalObject.h>
+#include "JSCInlines.h"
+
+using namespace JSC;
+
+
+namespace Wundle {
+
+class Script;
+
+class DefaultGlobal final : public JSC::JSGlobalObject {
+public:
+ using Base = JSC::JSGlobalObject;
+
+ DECLARE_EXPORT_INFO;
+ static const JSC::GlobalObjectMethodTable s_globalObjectMethodTable;
+
+ static constexpr bool needsDestruction = true;
+ template<typename CellType, SubspaceAccess mode>
+ static JSC::IsoSubspace* subspaceFor(JSC::VM& vm)
+ {
+ return vm.apiGlobalObjectSpace<mode>();
+ }
+
+ static DefaultGlobal* create(JSC::VM& vm, JSC::Structure* structure)
+ {
+ auto* object = new (NotNull, allocateCell<DefaultGlobal>(vm.heap)) DefaultGlobal(vm, structure);
+ object->finishCreation(vm);
+ return object;
+ }
+
+ static Structure* createStructure(JSC::VM& vm, JSC::JSValue prototype)
+ {
+ auto* result = Structure::create(vm, nullptr, prototype, TypeInfo(GlobalObjectType, StructureFlags), info());
+ result->setTransitionWatchpointIsLikelyToBeFired(true);
+ return result;
+ }
+
+ static void reportUncaughtExceptionAtEventLoop(JSGlobalObject*, Exception*);
+
+ static JSInternalPromise* moduleLoaderImportModule(JSGlobalObject*, JSModuleLoader*, JSC::JSString* moduleNameValue, JSValue parameters, const SourceOrigin&);
+ static JSC::Identifier moduleLoaderResolve(JSGlobalObject*, JSModuleLoader*, JSValue keyValue, JSValue referrerValue, JSValue);
+ static JSInternalPromise* moduleLoaderFetch(JSGlobalObject*, JSModuleLoader*, JSValue, JSValue, JSValue);
+ static JSC::JSObject* moduleLoaderCreateImportMetaProperties(JSGlobalObject*, JSModuleLoader*, JSValue, JSModuleRecord*, JSValue);
+ static JSValue moduleLoaderEvaluate(JSGlobalObject*, JSModuleLoader*, JSValue, JSValue, JSValue, JSValue, JSValue);
+
+
+private:
+ DefaultGlobal(JSC::VM& vm, JSC::Structure* structure)
+ : Base(vm, structure, &s_globalObjectMethodTable)
+ { }
+};
+
+
+}
+
diff --git a/src/javascript/jsc/bindings/DefaultGlobal.zig b/src/javascript/jsc/bindings/DefaultGlobal.zig
new file mode 100644
index 000000000..dfc931efb
--- /dev/null
+++ b/src/javascript/jsc/bindings/DefaultGlobal.zig
@@ -0,0 +1,272 @@
+usingnamespace @import("./imports.zig");
+
+const std = @import("std");
+const main = @import("root");
+const is_bindgen = std.meta.trait.hasDecls(main, .{"bindgen"});
+
+fn Shimmer(comptime name: []const u8, comptime Parent: type) type {
+ return struct {
+ pub inline fn cppFn(comptime typeName: []const u8, args: anytype) (@typeInfo(@TypeOf(@field(Parent.C, typeName))).Fn.return_type orelse void) {
+ if (comptime is_bindgen) {
+ return .{};
+ } else {
+ const func = @field(Parent, typeName);
+ const Func = @TypeOf(func);
+ // const Func: std.builtin.TypeInfo = brk: {
+ // var FuncType: std.builtin.TypeInfo = @typeInfo(@TypeOf(func));
+ // var decl = std.meta.declarationInfo(Parent, name);
+ // var argument_field_list: [function_info.args.len]std.builtin.TypeInfo.StructField = undefined;
+ // inline for (function_info.args) |arg, i| {
+ // const T = arg.arg_type.?;
+ // @setEvalBranchQuota(10_000);
+ // var num_buf: [128]u8 = undefined;
+ // argument_field_list[i] = std.builtin.TypeInfo.StructField{
+ // .name = std.fmt.bufPrint(&num_buf, "{d}", .{i}) catch unreachable,
+ // .field_type = T,
+ // .default_value = @as(?T, null),
+ // .is_comptime = false,
+ // .alignment = if (@sizeOf(T) > 0) @alignOf(T) else 0,
+ // };
+ // }
+
+ // std.builtin.TypeInfo{
+ // .Struct = std.builtin.TypeInfo.Struct{
+ // .is_tuple = true,
+ // .layout = .Auto,
+ // .decls = &[_]std.builtin.TypeInfo.Declaration{},
+ // .fields = &argument_field_list,
+ // },
+ // });
+ // };
+
+ const identifier = comptime std.fmt.comptimePrint("{s}__{s}", .{ name, typeName });
+ const Outgoing = comptime @extern(Func, std.builtin.ExternOptions{ .name = identifier });
+ const Decl: std.builtin.TypeInfo.Fn = @typeInfo(Func).Fn;
+ if (comptime Decl.return_type) |ReturnType| {
+ if (comptime @typeInfo(ReturnType) == .Pointer) {
+ const Ptr: std.builtin.TypeInfo.Pointer = comptime @typeInfo(ReturnType).Pointer;
+ const ChildType: type = brk: {
+ if (@typeInfo(ChildType) == .Struct) {
+ const Struct: std.builtin.TypeInfo.Struct = ChildType.Struct;
+ for (Struct.fields) |field| {
+ if (std.mem.eql(u8, field.name, "ref")) {
+ break :brk field.field_type;
+ }
+ }
+ }
+ break :brk Ptr.child;
+ };
+
+ if (comptime Ptr.is_const) {
+ const return_type = @call(.{}, comptime Outgoing, args);
+ return @ptrCast(*const ChildType, @alignCast(alignment, return_type));
+ } else {
+ var return_type = @call(.{}, comptime Outgoing, args);
+ return @ptrCast(*ChildType, @alignCast(alignment, return_type));
+ }
+ }
+
+ return @as(ReturnType, @call(.{}, comptime Outgoing, args));
+ } else {
+ @call(.{}, comptime Outgoing, args);
+ }
+ }
+ }
+ };
+}
+
+pub const JSCell = packed struct {
+ ref: Type,
+ pub const shim = Shimmer("JSCell", @This());
+ const cppFn = shim.cppFn;
+ pub const include = "\"GenericBindings.h\"";
+ pub const name = "JSC::JSCell";
+
+ pub const Type = *c_void;
+
+ pub fn getObject(this: *const JSCell) ?JSObject {
+ return shim.cppFn("getObject", .{this.ref});
+ }
+
+ pub fn getString(this: *const JSCell, globalObject: *DefaultGlobal) ?String {
+ return shim.cppFn("getString", .{ this.ref, globalObject.ref });
+ }
+
+ pub fn getType(this: *const JSCell) u8 {
+ return @intCast(CellType, shim.cppFn("getType", .{
+ this.ref,
+ }));
+ }
+};
+
+pub const JSString = packed struct {
+ ref: Type,
+ pub const shim = Shimmer("JSString", @This());
+ const cppFn = shim.cppFn;
+ pub const include = "\"GenericBindings.h\"";
+ pub const name = "JSC::JSString";
+
+ pub const Type = *c_void;
+
+ pub fn getObject(this: *const JSCell) ?JSObject {
+
+ return shim.cppFn("getObject", .{this.ref});
+ }
+
+ pub fn getString(this: *const JSCell, globalObject: *DefaultGlobal) ?String {
+ return shim.cppFn("getString", .{ this.ref, globalObject.ref });
+ }
+
+
+};
+
+pub const DefaultGlobal = struct {
+ pub const shim = Shimmer("DefaultGlobal", @This());
+
+ ref: Type,
+ pub const Type = *c_void;
+
+ pub const include = "\"DefaultGlobal.h\"";
+ pub const name = "Wundle::DefaultGlobal";
+
+ const cppFn = shim.cppFn;
+
+ pub fn objectPrototype(instance: *DefaultGlobal) ObjectPrototype {
+ return cppFn("objectPrototype", .{instance.ref});
+ }
+ pub fn functionPrototype(instance: *DefaultGlobal) FunctionPrototype {
+ return cppFn("functionPrototype", .{instance.ref});
+ }
+ pub fn arrayPrototype(instance: *DefaultGlobal) ArrayPrototype {
+ return cppFn("arrayPrototype", .{instance.ref});
+ }
+ pub fn booleanPrototype(instance: *DefaultGlobal) JSObject {
+ return cppFn("booleanPrototype", .{instance.ref});
+ }
+ pub fn stringPrototype(instance: *DefaultGlobal) StringPrototype {
+ return cppFn("stringPrototype", .{instance.ref});
+ }
+ pub fn numberPrototype(instance: *DefaultGlobal) JSObject {
+ return cppFn("numberPrototype", .{instance.ref});
+ }
+ pub fn bigIntPrototype(instance: *DefaultGlobal) BigIntPrototype {
+ return cppFn("bigIntPrototype", .{instance.ref});
+ }
+ pub fn datePrototype(instance: *DefaultGlobal) JSObject {
+ return cppFn("datePrototype", .{instance.ref});
+ }
+ pub fn symbolPrototype(instance: *DefaultGlobal) JSObject {
+ return cppFn("symbolPrototype", .{instance.ref});
+ }
+ pub fn regExpPrototype(instance: *DefaultGlobal) RegExpPrototype {
+ return cppFn("regExpPrototype", .{instance.ref});
+ }
+ pub fn errorPrototype(instance: *DefaultGlobal) JSObject {
+ return cppFn("errorPrototype", .{instance.ref});
+ }
+ pub fn iteratorPrototype(instance: *DefaultGlobal) IteratorPrototype {
+ return cppFn("iteratorPrototype", .{instance.ref});
+ }
+ pub fn asyncIteratorPrototype(instance: *DefaultGlobal) AsyncIteratorPrototype {
+ return cppFn("asyncIteratorPrototype", .{instance.ref});
+ }
+ pub fn generatorFunctionPrototype(instance: *DefaultGlobal) GeneratorFunctionPrototype {
+ return cppFn("generatorFunctionPrototype", .{instance.ref});
+ }
+ pub fn generatorPrototype(instance: *DefaultGlobal) GeneratorPrototype {
+ return cppFn("generatorPrototype", .{instance.ref});
+ }
+ pub fn asyncFunctionPrototype(instance: *DefaultGlobal) AsyncFunctionPrototype {
+ return cppFn("asyncFunctionPrototype", .{instance.ref});
+ }
+ pub fn arrayIteratorPrototype(instance: *DefaultGlobal) ArrayIteratorPrototype {
+ return cppFn("arrayIteratorPrototype", .{instance.ref});
+ }
+ pub fn mapIteratorPrototype(instance: *DefaultGlobal) MapIteratorPrototype {
+ return cppFn("mapIteratorPrototype", .{instance.ref});
+ }
+ pub fn setIteratorPrototype(instance: *DefaultGlobal) SetIteratorPrototype {
+ return cppFn("setIteratorPrototype", .{instance.ref});
+ }
+ pub fn mapPrototype(instance: *DefaultGlobal) JSObject {
+ return cppFn("mapPrototype", .{instance.ref});
+ }
+ pub fn jsSetPrototype(instance: *DefaultGlobal) JSObject {
+ return cppFn("jsSetPrototype", .{instance.ref});
+ }
+ pub fn promisePrototype(instance: *DefaultGlobal) JSPromisePrototype {
+ return cppFn("promisePrototype", .{instance.ref});
+ }
+ pub fn asyncGeneratorPrototype(instance: *DefaultGlobal) AsyncGeneratorPrototype {
+ return cppFn("asyncGeneratorPrototype", .{instance.ref});
+ }
+ pub fn asyncGeneratorFunctionPrototype(instance: *DefaultGlobal) AsyncGeneratorFunctionPrototype {
+ return cppFn("asyncGeneratorFunctionPrototype", .{instance.ref});
+ }
+};
+
+fn _JSCellStub(comptime str: []const u8) type {
+ if (is_bindgen) {
+ return struct {
+ pub const C = struct {
+ pub const name = "JSC::" ++ str ++ "*";
+ ref: ?*c_void = null,
+ };
+ };
+ } else {
+ return struct {
+ pub const C = *c_void;
+ };
+ }
+}
+
+fn _Wundle(comptime str: []const u8) type {
+ if (is_bindgen) {
+ return struct {
+ pub const C = struct {
+ pub const name = "Wundle::" ++ str ++ "*";
+ ref: ?*c_void = null,
+ };
+ };
+ } else {
+ return struct {
+ pub const C = *c_void;
+ };
+ }
+}
+
+fn _WTF(comptime str: []const u8) type {
+ if (is_bindgen) {
+ return struct {
+ pub const C = struct {
+ pub const name = "WTF::" ++ str ++ "*";
+ ref: ?*c_void = null,
+ };
+ };
+ } else {
+ return struct {
+ pub const C = *c_void;
+ };
+ }
+}
+
+const _DefaultGlobal = _Wundle("DefaultGlobal");
+const ObjectPrototype = _JSCellStub("ObjectPrototype");
+const FunctionPrototype = _JSCellStub("FunctionPrototype");
+const ArrayPrototype = _JSCellStub("ArrayPrototype");
+const JSObject = _JSCellStub("JSObject");
+const StringPrototype = _JSCellStub("StringPrototype");
+const BigIntPrototype = _JSCellStub("BigIntPrototype");
+const RegExpPrototype = _JSCellStub("RegExpPrototype");
+const IteratorPrototype = _JSCellStub("IteratorPrototype");
+const AsyncIteratorPrototype = _JSCellStub("AsyncIteratorPrototype");
+const GeneratorFunctionPrototype = _JSCellStub("GeneratorFunctionPrototype");
+const GeneratorPrototype = _JSCellStub("GeneratorPrototype");
+const AsyncFunctionPrototype = _JSCellStub("AsyncFunctionPrototype");
+const ArrayIteratorPrototype = _JSCellStub("ArrayIteratorPrototype");
+const MapIteratorPrototype = _JSCellStub("MapIteratorPrototype");
+const SetIteratorPrototype = _JSCellStub("SetIteratorPrototype");
+const JSPromisePrototype = _JSCellStub("JSPromisePrototype");
+const AsyncGeneratorPrototype = _JSCellStub("AsyncGeneratorPrototype");
+const AsyncGeneratorFunctionPrototype = _JSCellStub("AsyncGeneratorFunctionPrototype");
+const String = _WTF("String");
diff --git a/src/javascript/jsc/bindings/JSCInlines.h b/src/javascript/jsc/bindings/JSCInlines.h
new file mode 100644
index 000000000..f45088ecc
--- /dev/null
+++ b/src/javascript/jsc/bindings/JSCInlines.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2014-2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+// This file's only purpose is to collect commonly used *Inlines.h files, so that you don't
+// have to include all of them in every .cpp file. Instead you just include this. It's good
+// style to make sure that every .cpp file includes JSCInlines.h.
+//
+// JSC should never include this file, or any *Inline.h file, from interface headers, since
+// this could lead to a circular dependency.
+//
+// WebCore, or any other downstream client of JSC, is allowed to include this file in headers.
+// In fact, it can make a lot of sense: outside of JSC, this file becomes a kind of umbrella
+// header that pulls in most (all?) of the interesting things in JSC.
+
+#include <JavaScriptCore/ExceptionHelpers.h>
+#include <JavaScriptCore/GCIncomingRefCountedInlines.h>
+#include <JavaScriptCore/HeapInlines.h>
+#include <JavaScriptCore/IdentifierInlines.h>
+#include <JavaScriptCore/JSArrayBufferViewInlines.h>
+#include <JavaScriptCore/JSCJSValueInlines.h>
+#include <JavaScriptCore/JSCellInlines.h>
+#include <JavaScriptCore/JSFunctionInlines.h>
+#include <JavaScriptCore/JSGlobalObjectInlines.h>
+#include <JavaScriptCore/JSObjectInlines.h>
+#include <JavaScriptCore/JSProxy.h>
+#include <JavaScriptCore/JSString.h>
+#include <JavaScriptCore/Operations.h>
+#include <JavaScriptCore/SlotVisitorInlines.h>
+#include <JavaScriptCore/StrongInlines.h>
+#include <JavaScriptCore/StructureInlines.h>
+#include <JavaScriptCore/ThrowScope.h>
+#include <JavaScriptCore/WeakGCMapInlines.h>
+#include <JavaScriptCore/WeakGCSetInlines.h>
diff --git a/src/javascript/jsc/bindings/JSValue.zig b/src/javascript/jsc/bindings/JSValue.zig
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/src/javascript/jsc/bindings/JSValue.zig
diff --git a/src/javascript/jsc/bindings/bindings-generator.zig b/src/javascript/jsc/bindings/bindings-generator.zig
new file mode 100644
index 000000000..ac6fbe738
--- /dev/null
+++ b/src/javascript/jsc/bindings/bindings-generator.zig
@@ -0,0 +1,32 @@
+const Bindings = @import("bindings.zig");
+const HeaderGen = @import("./header-gen.zig").HeaderGen;
+
+const std = @import("std");
+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;
+
+pub const bindgen = true;
+
+pub fn main() anyerror!void {
+ var allocator = std.heap.c_allocator;
+ var stdout = std.io.getStdOut();
+ var writer = stdout.writer();
+ const src: std.builtin.SourceLocation = @src();
+ const paths = [_][]const u8{ std.fs.path.dirname(src.file) orelse return error.BadPath, "headers.h" };
+ const file = try std.fs.createFileAbsolute(try std.fs.path.join(allocator, &paths), .{});
+
+ const HeaderGenerator = HeaderGen(
+ Bindings,
+ "src/javascript/jsc/bindings/bindings.zig",
+ );
+
+ HeaderGenerator.exec(HeaderGenerator{}, file);
+}
diff --git a/src/javascript/jsc/bindings/bindings.cpp b/src/javascript/jsc/bindings/bindings.cpp
new file mode 100644
index 000000000..ad35863e2
--- /dev/null
+++ b/src/javascript/jsc/bindings/bindings.cpp
@@ -0,0 +1,10 @@
+#include "root.h"
+
+
+// namespace Bundler {
+// class CustomGlobalObject : public JSC::JSGlobalObject {
+
+// };
+
+// }
+
diff --git a/src/javascript/jsc/bindings/bindings.zig b/src/javascript/jsc/bindings/bindings.zig
new file mode 100644
index 000000000..016de2ab9
--- /dev/null
+++ b/src/javascript/jsc/bindings/bindings.zig
@@ -0,0 +1,2 @@
+pub usingnamespace @import("./JSValue.zig");
+pub usingnamespace @import("./DefaultGlobal.zig");
diff --git a/src/javascript/jsc/bindings/header-gen.zig b/src/javascript/jsc/bindings/header-gen.zig
new file mode 100644
index 000000000..e0ea96a21
--- /dev/null
+++ b/src/javascript/jsc/bindings/header-gen.zig
@@ -0,0 +1,368 @@
+const std = @import("std");
+const Dir = std.fs.Dir;
+const FnMeta = std.builtin.TypeInfo.Fn;
+const FnDecl = std.builtin.TypeInfo.Declaration.Data.FnDecl;
+const StructMeta = std.builtin.TypeInfo.Struct;
+const EnumMeta = std.builtin.TypeInfo.Enum;
+const UnionMeta = std.builtin.TypeInfo.Union;
+const warn = std.debug.warn;
+
+pub const C_Generator = struct {
+ file: std.fs.File,
+ filebase: []const u8,
+ const Self = @This();
+
+ pub fn init(comptime src_file: []const u8, file: std.fs.File) Self {
+ var res = Self{ .file = file, .filebase = src_file };
+
+ file.writeAll("\n/**** " ++ src_file ++ " /*****/\n\n") catch unreachable;
+ return res;
+ }
+
+ pub fn deinit(self: *Self) void {
+ self.file.writeAll("\n/***** ") catch unreachable;
+ self.file.writeAll(self.filebase) catch unreachable;
+ self.file.writeAll(" *****/") catch unreachable;
+ }
+
+ pub fn gen_func(self: *Self, comptime name: []const u8, comptime func: FnDecl, comptime meta: FnMeta, comptime arg_names: []const []const u8) void {
+ switch (meta.calling_convention) {
+ .Naked => self.write("__attribute__((naked)) "),
+ .Stdcall => self.write("__attribute__((stdcall)) "),
+ .Fastcall => self.write("__attribute__((fastcall)) "),
+ .Thiscall => self.write("__attribute__((thiscall)) "),
+ else => {},
+ }
+
+ self.write("extern \"C\" ");
+ self.writeType(func.return_type);
+ self.write(" " ++ name ++ "(");
+
+ inline for (meta.args) |arg, i| {
+ self.writeType(arg.arg_type.?);
+ if (func.arg_names.len > i) {
+ self.write(comptime arg_names[i]);
+ } else {
+ self.write(comptime std.fmt.comptimePrint(" arg{d}", .{i}));
+ }
+
+ //TODO: Figure out how to get arg names; for now just do arg0..argN
+ if (i != meta.args.len - 1)
+ self.write(", ");
+ }
+
+ self.write(");\n");
+ }
+
+ pub fn gen_struct(self: *Self, comptime name: []const u8, comptime meta: StructMeta) void {
+ self.write("typedef struct ");
+
+ if (meta.layout == .Packed)
+ self.write("__attribute__((__packed__)) ");
+
+ self.write(name ++ " {\n");
+
+ inline for (meta.fields) |field| {
+ self.write(" ");
+
+ const info = @typeInfo(field.field_type);
+
+ if (info == .Array) {
+ self.writeType(info.Array.child);
+ } else {
+ self.writeType(field.field_type);
+ }
+
+ self.write(" " ++ field.name);
+
+ if (info == .Array) {
+ _ = self.file.writer().print("[{}]", .{info.Array.len}) catch unreachable;
+ }
+
+ self.write(";\n");
+ }
+ self.write("} " ++ name ++ "_t;\n\n");
+ }
+
+ pub fn gen_enum(self: *Self, comptime name: []const u8, comptime meta: EnumMeta) void {
+ self.write("enum " ++ name ++ " {\n");
+
+ comptime var last = 0;
+ inline for (meta.fields) |field, i| {
+ self.write(" " ++ field.name);
+
+ // if field value is unexpected/custom, manually define it
+ if ((i == 0 and field.value != 0) or (i > 0 and field.value > last + 1)) {
+ _ = self.file.writer().print(" = {}", .{field.value}) catch unreachable;
+ }
+
+ self.write(",\n");
+
+ last = field.value;
+ }
+
+ self.write("};\n\n");
+ }
+
+ pub fn gen_union(self: *Self, comptime name: []const u8, comptime meta: UnionMeta) void {
+ self.write("typedef union ");
+
+ self.write(name ++ " {\n");
+
+ inline for (meta.fields) |field| {
+ self.write(" ");
+ self.writeType(field.field_type);
+ self.write(" " ++ field.name ++ ";\n");
+ }
+ self.write("} " ++ name ++ "_t;\n\n");
+ }
+
+ fn writeType(self: *Self, comptime T: type) void {
+ const TT = if (@typeInfo(T) == .Pointer) @typeInfo(T).Pointer.child else T;
+
+ if (comptime std.meta.trait.hasDecls(TT, .{"C"}) and std.meta.trait.hasDecls(TT.C, .{"name"})) {
+ writeType(self, TT.C);
+ if (std.meta.trait.isSingleItemPtr(T)) {
+ write(self, "*");
+ }
+ return;
+ }
+
+ if (comptime std.meta.trait.hasDecls(TT, .{"name"})) {
+ self.write(comptime T.name);
+ if (std.meta.trait.isSingleItemPtr(T)) {
+ write(self, "*");
+ }
+ return;
+ }
+
+ switch (T) {
+ void => self.write("void"),
+ bool => self.write("bool"),
+ usize => self.write("size_t"),
+ isize => self.write("int"),
+ u8 => self.write("uint8_t"),
+ u16 => self.write("uint16_t"),
+ u32 => self.write("uint32_t"),
+ u64 => self.write("uint64_t"),
+ i8 => self.write("int8_t"),
+ i16 => self.write("int16_t"),
+ i24 => self.write("int24_t"),
+ i32 => self.write("int32_t"),
+ i64 => self.write("int64_t"),
+ [*]bool => self.write("bool*"),
+ [*]usize => self.write("size_t*"),
+ [*]isize => self.write("int*"),
+ [*]u8 => self.write("uint8_t*"),
+ [*]u16 => self.write("uint16_t*"),
+ [*]u32 => self.write("uint32_t*"),
+ [*]u64 => self.write("uint64_t*"),
+ [*]i8 => self.write("int8_t*"),
+ [*]i16 => self.write("int16_t*"),
+ [*]i32 => self.write("int32_t*"),
+ [*]i64 => self.write("int64_t*"),
+ else => {
+ const meta = @typeInfo(T);
+ switch (meta) {
+ .Pointer => {
+ const child = meta.Pointer.child;
+ const childmeta = @typeInfo(child);
+ // if (childmeta == .Struct and childmeta.Struct.layout != .Extern) {
+ // self.write("void");
+ // } else {
+ self.writeType(child);
+ // }
+ self.write("*");
+ },
+ .Optional => self.writeType(meta.Optional.child),
+ .Array => @compileError("Handle goofy looking C Arrays in the calling function"),
+ else => self.write(@typeName(T) ++ "_t"),
+ }
+ },
+ }
+ }
+
+ fn write(self: *Self, comptime str: []const u8) void {
+ _ = self.file.writeAll(str) catch {};
+ }
+};
+
+const builtin = std.builtin;
+const TypeInfo = builtin.TypeInfo;
+const Declaration = TypeInfo.Declaration;
+
+const GeneratorInterface = struct {
+ fn init() void {}
+ fn deinit() void {}
+ fn gen_func() void {}
+ fn gen_struct() void {}
+ fn gen_enum() void {}
+ fn gen_union() void {}
+};
+
+fn validateGenerator(comptime Generator: type) void {
+ comptime {
+ const interface = @typeInfo(GeneratorInterface).Struct.decls;
+
+ for (interface) |decl| {
+ if (@hasDecl(Generator, decl.name) == false) {
+ @compileError("Generator: '" ++
+ @typeName(Generator) ++
+ "' is missing function: " ++
+ decl.name);
+ }
+ }
+ }
+}
+
+const NamedStruct = struct {
+ name: []const u8,
+ Type: type,
+};
+
+pub fn getCStruct(comptime T: type) ?NamedStruct {
+ if (!std.meta.trait.isContainer(T) or (std.meta.trait.isSingleItemPtr(T) and !std.meta.trait.isContainer(std.meta.Child(T)))) {
+ return null;
+ }
+
+ inline for (std.meta.declarations(T)) |decl| {
+ if (std.mem.eql(u8, decl.name, "C")) {
+ switch (decl.data) {
+ .Type => |TT| {
+ return NamedStruct{ .Type = TT, .name = @typeName(T) };
+ },
+ else => {},
+ }
+ }
+ }
+
+ return null;
+}
+
+pub fn HeaderGen(comptime import: type, comptime fname: []const u8) type {
+ const all_decls = std.meta.declarations(import);
+
+ return struct {
+ source_file: []const u8 = fname,
+
+ const Self = @This();
+
+ pub fn init() Self {
+ return Self{};
+ }
+
+ pub fn processDecls(
+ comptime self: Self,
+ file: std.fs.File,
+ comptime Parent: type,
+ comptime Type: type,
+ comptime prefix: []const u8,
+ ) void {
+ const decls = std.meta.declarations(Type);
+ var gen = C_Generator.init(prefix, file);
+ defer gen.deinit();
+
+ if (comptime std.meta.trait.hasDecls(Type, .{"include"})) {
+ comptime var new_name = std.mem.zeroes([Type.include.len]u8);
+
+ comptime {
+ _ = std.mem.replace(u8, Type.include, "/", "_", std.mem.span(&new_name));
+ _ = std.mem.replace(u8, &new_name, ".", "_", std.mem.span(&new_name));
+ }
+ const inner_name = comptime std.mem.trim(u8, &new_name, "<>\"");
+ file.writeAll("#ifndef BINDINGS__decls__" ++ inner_name ++ "\n") catch {};
+ file.writeAll("#define BINDINGS__decls__" ++ inner_name ++ "\n") catch {};
+ file.writeAll("#include " ++ Type.include ++ "\n") catch {};
+ file.writeAll("namespace Wundle {\n class " ++ prefix ++ ";\n}\n") catch {};
+ file.writeAll("#endif\n\n") catch {};
+ }
+
+ // iterate exported enums
+ // do this first in case target lang needs enums defined before use
+ inline for (decls) |decl| {
+ if (decl.is_pub and decl.data == .Type and comptime std.ascii.isUpper(decl.name[0])) {
+ const T = decl.data.Type;
+ const info = @typeInfo(T);
+ if (info == .Enum and decl.is_pub) {
+ const layout = info.Enum.layout;
+ gen.gen_enum(prefix ++ "__" ++ decl.name, info.Enum);
+ }
+ }
+ }
+
+ // iterate exported structs
+ inline for (decls) |decl| {
+ if (decl.is_pub and decl.data == .Type and decl.is_pub and comptime std.ascii.isUpper(decl.name[0])) {
+ const T = decl.data.Type;
+ const info = @typeInfo(T);
+ if (info == .Struct and decl.is_pub) {
+ gen.gen_struct(decl.name, @typeInfo(T).Struct);
+ }
+ }
+ }
+
+ inline for (decls) |decl| {
+ if (decl.is_pub and decl.data == .Type and decl.is_pub) {
+ const T = decl.data.Type;
+ const info = @typeInfo(T);
+ if (info == .Union and comptime std.ascii.isUpper(decl.name[0])) {
+ const layout = info.Union.layout;
+ gen.gen_union(prefix ++ "__" ++ decl.name, info.Union);
+ }
+ }
+ }
+
+ // iterate exported fns
+ inline for (decls) |decl, decl_i| {
+ if (decl.is_pub and decl.data == .Fn and decl.is_pub) {
+ const func = decl.data.Fn;
+ // if (func.) {
+ const fn_meta = @typeInfo(func.fn_type).Fn;
+ const info = @typeInfo(Type);
+ const struct_decl = info.Struct.decls[decl_i];
+ // blocked by https://github.com/ziglang/zig/issues/8259
+ gen.gen_func(
+ prefix ++ "__" ++ decl.name,
+ func,
+ fn_meta,
+ struct_decl.data.Fn.arg_names,
+ );
+ // }
+ }
+ }
+ }
+
+ pub fn exec(comptime self: Self, file: std.fs.File) void {
+ const Generator = C_Generator;
+ validateGenerator(Generator);
+
+ file.writeAll("#pragma once\n#include <stddef.h>\n#include <stdint.h>\n#include <stdbool.h>\n\n") catch {};
+
+ inline for (all_decls) |_decls| {
+ if (comptime _decls.is_pub) {
+ switch (_decls.data) {
+ .Type => |Type| {
+ if (getCStruct(Type)) |CStruct| {
+ processDecls(
+ self,
+ file,
+ Type,
+ CStruct.Type,
+ CStruct.name,
+ );
+ }
+ },
+ else => {},
+ }
+ }
+ }
+
+ // processDecls(
+ // self,
+ // file,
+ // import,
+ // "Bindings",
+ // );
+ }
+ };
+}
diff --git a/src/javascript/jsc/bindings/headers.h b/src/javascript/jsc/bindings/headers.h
new file mode 100644
index 000000000..231c6697e
--- /dev/null
+++ b/src/javascript/jsc/bindings/headers.h
@@ -0,0 +1,42 @@
+#pragma once
+#include <stddef.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+
+/**** DefaultGlobal /*****/
+
+#ifndef BINDINGS__decls__DefaultGlobal_h
+#define BINDINGS__decls__DefaultGlobal_h
+#include "DefaultGlobal.h"
+namespace Wundle {
+ class DefaultGlobal;
+}
+#endif
+
+extern "C" JSC::ObjectPrototype* DefaultGlobal__objectPrototype(Wundle::DefaultGlobal* arg0);
+extern "C" JSC::FunctionPrototype* DefaultGlobal__functionPrototype(Wundle::DefaultGlobal* arg0);
+extern "C" JSC::ArrayPrototype* DefaultGlobal__arrayPrototype(Wundle::DefaultGlobal* arg0);
+extern "C" JSC::JSObject* DefaultGlobal__booleanPrototype(Wundle::DefaultGlobal* arg0);
+extern "C" JSC::StringPrototype* DefaultGlobal__stringPrototype(Wundle::DefaultGlobal* arg0);
+extern "C" JSC::JSObject* DefaultGlobal__numberPrototype(Wundle::DefaultGlobal* arg0);
+extern "C" JSC::BigIntPrototype* DefaultGlobal__bigIntPrototype(Wundle::DefaultGlobal* arg0);
+extern "C" JSC::JSObject* DefaultGlobal__datePrototype(Wundle::DefaultGlobal* arg0);
+extern "C" JSC::JSObject* DefaultGlobal__symbolPrototype(Wundle::DefaultGlobal* arg0);
+extern "C" JSC::RegExpPrototype* DefaultGlobal__regExpPrototype(Wundle::DefaultGlobal* arg0);
+extern "C" JSC::JSObject* DefaultGlobal__errorPrototype(Wundle::DefaultGlobal* arg0);
+extern "C" JSC::IteratorPrototype* DefaultGlobal__iteratorPrototype(Wundle::DefaultGlobal* arg0);
+extern "C" JSC::AsyncIteratorPrototype* DefaultGlobal__asyncIteratorPrototype(Wundle::DefaultGlobal* arg0);
+extern "C" JSC::GeneratorFunctionPrototype* DefaultGlobal__generatorFunctionPrototype(Wundle::DefaultGlobal* arg0);
+extern "C" JSC::GeneratorPrototype* DefaultGlobal__generatorPrototype(Wundle::DefaultGlobal* arg0);
+extern "C" JSC::AsyncFunctionPrototype* DefaultGlobal__asyncFunctionPrototype(Wundle::DefaultGlobal* arg0);
+extern "C" JSC::ArrayIteratorPrototype* DefaultGlobal__arrayIteratorPrototype(Wundle::DefaultGlobal* arg0);
+extern "C" JSC::MapIteratorPrototype* DefaultGlobal__mapIteratorPrototype(Wundle::DefaultGlobal* arg0);
+extern "C" JSC::SetIteratorPrototype* DefaultGlobal__setIteratorPrototype(Wundle::DefaultGlobal* arg0);
+extern "C" JSC::JSObject* DefaultGlobal__mapPrototype(Wundle::DefaultGlobal* arg0);
+extern "C" JSC::JSObject* DefaultGlobal__jsSetPrototype(Wundle::DefaultGlobal* arg0);
+extern "C" JSC::JSPromisePrototype* DefaultGlobal__promisePrototype(Wundle::DefaultGlobal* arg0);
+extern "C" JSC::AsyncGeneratorPrototype* DefaultGlobal__asyncGeneratorPrototype(Wundle::DefaultGlobal* arg0);
+extern "C" JSC::AsyncGeneratorFunctionPrototype* DefaultGlobal__asyncGeneratorFunctionPrototype(Wundle::DefaultGlobal* arg0);
+
+/***** DefaultGlobal *****/ \ No newline at end of file
diff --git a/src/javascript/jsc/bindings/imports.zig b/src/javascript/jsc/bindings/imports.zig
new file mode 100644
index 000000000..8b1378917
--- /dev/null
+++ b/src/javascript/jsc/bindings/imports.zig
@@ -0,0 +1 @@
+
diff --git a/src/javascript/jsc/bindings/inlines.cpp b/src/javascript/jsc/bindings/inlines.cpp
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/src/javascript/jsc/bindings/inlines.cpp
diff --git a/src/javascript/jsc/bindings/root.h b/src/javascript/jsc/bindings/root.h
new file mode 100644
index 000000000..2ac4c15bc
--- /dev/null
+++ b/src/javascript/jsc/bindings/root.h
@@ -0,0 +1,71 @@
+#pragma once
+
+/*
+ * Copyright (C) 2006-2021 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+#define HAVE_CONFIG_H 1
+#define BUILDING_WITH_CMAKE 1
+
+#if defined(HAVE_CONFIG_H) && HAVE_CONFIG_H && defined(BUILDING_WITH_CMAKE)
+#include "cmakeconfig.h"
+#endif
+
+#define JSC_API_AVAILABLE(...)
+#define JSC_CLASS_AVAILABLE(...) JS_EXPORT
+#define JSC_API_DEPRECATED(...)
+// Use zero since it will be less than any possible version number.
+#define JSC_MAC_VERSION_TBA 0
+#define JSC_IOS_VERSION_TBA 0
+
+#include <wtf/ExportMacros.h>
+
+#if !defined(JS_EXPORT_PRIVATE)
+
+#if defined(BUILDING_JavaScriptCore) || defined(STATICALLY_LINKED_WITH_JavaScriptCore)
+#define JS_EXPORT_PRIVATE WTF_EXPORT_DECLARATION
+#else
+#define JS_EXPORT_PRIVATE WTF_IMPORT_DECLARATION
+#endif
+
+#endif
+
+
+#ifdef __cplusplus
+#undef new
+#undef delete
+#include <wtf/FastMalloc.h>
+#endif
+
+#include <wtf/DisallowCType.h>
+
+/* Disabling warning C4206: nonstandard extension used: translation unit is empty.
+ By design, we rely on #define flags to make some translation units empty.
+ Make sure this warning does not turn into an error.
+*/
+#if COMPILER(MSVC)
+#pragma warning(disable:4206)
+#endif
+
+#ifdef USE_FOUNDATION
+#include <CoreFoundation/CoreFoundation.h>
+#endif
+
+
+#include <JavaScriptCore/Heap.h> \ No newline at end of file
diff --git a/src/javascript/jsc/javascript.zig b/src/javascript/jsc/javascript.zig
index 416897ccf..e984ccbb1 100644
--- a/src/javascript/jsc/javascript.zig
+++ b/src/javascript/jsc/javascript.zig
@@ -163,6 +163,10 @@ pub const VirtualMachine = struct {
log = try allocator.create(logger.Log);
}
+ if (FeatureFlags.remote_inspector) {
+ js.JSRemoteInspectorSetInspectionEnabledByDefault(true);
+ }
+
var vm = try allocator.create(VirtualMachine);
var global = try allocator.create(GlobalObject);
vm.* = .{
@@ -188,10 +192,9 @@ pub const VirtualMachine = struct {
global.* = GlobalObject{ .vm = vm };
try vm.global.boot();
vm.ctx = vm.global.ctx;
-
+ Properties.init();
Module.boot(vm);
- Properties.init();
if (vm.bundler.options.node_modules_bundle) |bundle| {
vm.node_modules = bundle;
vm.node_module_list = try allocator.create(Module.NodeModuleList);
@@ -201,6 +204,47 @@ pub const VirtualMachine = struct {
return vm;
}
+
+ pub fn require(
+ vm: *VirtualMachine,
+ ctx: js.JSContextRef,
+ source_dir: string,
+ import_path: string,
+ exception: js.ExceptionRef,
+ ) js.JSObjectRef {
+ if (vm.bundler.linker.resolver.resolve(source_dir, import_path, .require)) |resolved| {
+ var load_result = Module.loadFromResolveResult(vm, ctx, resolved, exception) catch |err| {
+ return null;
+ };
+
+ switch (load_result) {
+ .Module => |new_module| {
+ return new_module.internalGetExports(js.JSContextGetGlobalContext(ctx));
+ },
+ .Path => |path| {
+ return js.JSValueMakeString(ctx, js.JSStringCreateWithUTF8CString(path.text.ptr));
+ },
+ }
+ } else |err| {
+ Output.prettyErrorln(
+ "<r><red>RequireError<r>: Failed to load module <b>\"{s}\"<r> at \"{s}\": <red>{s}<r>",
+ .{ import_path, source_dir, @errorName(err) },
+ );
+ Output.flush();
+ JSError(
+ getAllocator(ctx),
+ "{s}: failed to load module \"{s}\" from \"{s}\"",
+ .{
+ @errorName(err),
+ import_path,
+ source_dir,
+ },
+ ctx,
+ exception,
+ );
+ return null;
+ }
+ }
};
pub const Object = struct {
@@ -517,7 +561,8 @@ pub const Module = struct {
);
if (this.console == null) {
- this.console = js.JSObjectMake(js.JSContextGetGlobalContext(ctx), this.vm.global.console_class, this.vm.global);
+ this.console = js.JSObjectMake(js.JSContextGetGlobalContext(ctx), GlobalObject.ConsoleClass.get().*, this.vm.global);
+ js.JSValueProtect(ctx, this.console);
}
return this.console;
@@ -611,8 +656,7 @@ pub const Module = struct {
var node_module_global_class_def = js.kJSClassDefinitionEmpty;
node_module_global_class_def.staticValues = static_properties.ptr;
node_module_global_class_def.className = node_module_global_class_name[0.. :0];
- node_module_global_class_def.staticFunctions = GlobalObject.GlobalClass.definition.staticFunctions;
- // node_module_global_class_def.parentClass = vm.global.global_class;
+ node_module_global_class_def.parentClass = GlobalObject.GlobalClass.get().*;
var property_getters = try vm.allocator.alloc(js.JSObjectRef, bundle.bundle.modules.len);
std.mem.set(js.JSObjectRef, property_getters, null);
@@ -637,7 +681,6 @@ pub const Module = struct {
// .callAsFunction = To.JS.Callback(NodeModuleList, initializeNodeModule),
// };
// node_module_global_class_def.staticFunctions = &node_module_list.static_functions;
- node_module_list.node_module_global_class_def = node_module_global_class_def;
node_module_list.node_module_global_class = js.JSClassRetain(js.JSClassCreate(&node_module_list.node_module_global_class_def));
node_module_list.bundle_ctx = js.JSGlobalContextRetain(js.JSGlobalContextCreateInGroup(vm.group, node_module_list.node_module_global_class));
_ = js.JSObjectSetPrivate(js.JSContextGetGlobalObject(node_module_list.bundle_ctx), node_module_list);
@@ -708,45 +751,7 @@ pub const Module = struct {
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;
- };
-
- switch (load_result) {
- .Module => |new_module| {
- // if (isDebug) {
- // Output.prettyln(
- // "Input: {s}\nOutput: {s}",
- // .{ import_path, load_result.Module.path.text },
- // );
- // Output.flush();
- // }
- return new_module.internalGetExports(js.JSContextGetGlobalContext(ctx));
- },
- .Path => |path| {
- return js.JSStringCreateWithUTF8CString(path.text.ptr);
- },
- }
- } else |err| {
- Output.prettyErrorln(
- "<r><red>RequireError<r>: Failed to load module <b>\"{s}\"<r> at \"{s}\": <red>{s}<r>",
- .{ import_path, module.path.name.dirWithTrailingSlash(), @errorName(err) },
- );
- Output.flush();
- JSError(
- getAllocator(ctx),
- "{s}: failed to load module \"{s}\" from \"{s}\"",
- .{
- @errorName(err),
- import_path,
- module.path.name.dirWithTrailingSlash(),
- },
- ctx,
- exception,
- );
- return null;
- }
+ return this.vm.require(ctx, module.path.name.dirWithTrailingSlash(), import_path, exception);
}
pub fn requireFirst(
@@ -853,9 +858,9 @@ pub const Module = struct {
return null;
}
- const ModuleClass = NewClass(
+ pub const ModuleClass = NewClass(
Module,
- .{ .name = "Module" },
+ .{ .name = Properties.UTF8.module },
.{
.@"require" = require,
.@"requireFirst" = requireFirst,
@@ -888,6 +893,7 @@ pub const Module = struct {
// ExportsClass.callAsConstructor = To.JS.Callback(Module, callExportsAsConstructor);
exports_class_ref = js.JSClassRetain(js.JSClassCreate(&ExportsClass));
+ _ = Module.ModuleClass.get().*;
}
pub const LoadResult = union(Tag) {
@@ -907,13 +913,26 @@ pub const Module = struct {
threadlocal var module_wrapper_params: [2]js.JSStringRef = undefined;
threadlocal var module_wrapper_loaded = false;
- pub fn load(module: *Module, vm: *VirtualMachine, allocator: *std.mem.Allocator, log: *logger.Log, source: [:0]u8, path: Fs.Path, global_ctx: js.JSContextRef, call_ctx: js.JSContextRef, function_ctx: js.JSContextRef, exception: js.ExceptionRef, comptime is_reload: bool) !void {
- var source_code_ref = js.JSStringCreateWithUTF8CString(source.ptr);
- defer js.JSStringRelease(source_code_ref);
- var source_url = try allocator.dupeZ(u8, path.text);
- defer allocator.free(source_url);
- var source_url_ref = js.JSStringCreateWithUTF8CString(source_url.ptr);
- defer js.JSStringRelease(source_url_ref);
+ pub fn load(
+ module: *Module,
+ vm: *VirtualMachine,
+ allocator: *std.mem.Allocator,
+ log: *logger.Log,
+ source: string,
+ path: Fs.Path,
+ global_ctx: js.JSContextRef,
+ call_ctx: js.JSContextRef,
+ function_ctx: js.JSContextRef,
+ exception: js.ExceptionRef,
+ comptime is_reload: bool,
+ ) !void {
+ var source_code_ref = js.JSStringCreateStatic(source.ptr, source.len - 1);
+ var source_url_raw = try std.fmt.allocPrintZ(allocator, "file://{s}", .{path.text});
+ var source_url = js.JSStringCreateStatic(source_url_raw.ptr, source_url_raw.len);
+
+ if (FeatureFlags.remote_inspector) {
+ js.JSGlobalContextSetName(js.JSContextGetGlobalContext(global_ctx), source_url);
+ }
if (isDebug) {
Output.print("// {s}\n{s}", .{ path.pretty, source });
@@ -926,16 +945,16 @@ pub const Module = struct {
.ref = undefined,
.vm = vm,
};
- module.ref = js.JSObjectMake(global_ctx, Module.ModuleClass.get(), module);
+ module.ref = js.JSObjectMake(global_ctx, Module.ModuleClass.get().*, module);
js.JSValueProtect(global_ctx, module.ref);
} else {
js.JSValueUnprotect(global_ctx, module.exports.?);
}
// if (!module_wrapper_loaded) {
- module_wrapper_params[0] = js.JSStringRetain(js.JSStringCreateWithUTF8CString(Properties.UTF8.module[0.. :0]));
- module_wrapper_params[1] = js.JSStringRetain(js.JSStringCreateWithUTF8CString(Properties.UTF8.exports[0.. :0]));
- // module_wrapper_loaded = true;
+ module_wrapper_params[0] = js.JSStringCreateStatic(Properties.UTF8.module.ptr, Properties.UTF8.module.len);
+ module_wrapper_params[1] = js.JSStringCreateStatic(Properties.UTF8.exports.ptr, Properties.UTF8.exports.len);
+ // module_wrapper_loaded = true;
// }
var module_wrapper_args: [2]js.JSValueRef = undefined;
@@ -951,7 +970,7 @@ pub const Module = struct {
@truncate(c_uint, module_wrapper_params.len),
&module_wrapper_params,
source_code_ref,
- null,
+ source_url,
1,
&except,
);
@@ -1140,7 +1159,7 @@ pub const Module = struct {
vm,
vm.allocator,
vm.log,
- source_code_printer.ctx.sentinel,
+ source_code_printer.ctx.written,
path,
js.JSContextGetGlobalContext(ctx),
ctx,
@@ -1154,7 +1173,7 @@ pub const Module = struct {
vm,
vm.allocator,
vm.log,
- source_code_printer.ctx.sentinel,
+ source_code_printer.ctx.written,
path,
js.JSContextGetGlobalContext(ctx),
ctx,
@@ -1245,7 +1264,7 @@ pub const Module = struct {
exception: js.ExceptionRef,
) callconv(.C) js.JSValueRef {
if (this.id == null) {
- this.id = js.JSStringCreateWithUTF8CString(this.path.text.ptr);
+ this.id = js.JSStringCreateStatic(this.path.text.ptr, this.path.text.len);
}
return this.id;
@@ -1475,9 +1494,7 @@ pub const GlobalObject = struct {
ref: js.JSObjectRef = undefined,
vm: *VirtualMachine,
ctx: js.JSGlobalContextRef = undefined,
- console_class: js.JSClassRef = undefined,
- console: js.JSObjectRef = undefined,
- console_definition: js.JSClassDefinition = undefined,
+ console: js.JSObjectRef = null,
global_class_def: js.JSClassDefinition = undefined,
global_class: js.JSClassRef = undefined,
@@ -1530,12 +1547,12 @@ pub const GlobalObject = struct {
obj: js.JSObjectRef,
exception: js.ExceptionRef,
) js.JSValueRef {
- // if (global.console == null) {
- // global.console = js.JSObjectMake(js.JSContextGetGlobalContext(ctx), global.console_class, global);
- // js.JSValueProtect(js.JSContextGetGlobalContext(ctx), global.console);
- // }
+ if (global.console == null) {
+ global.console = js.JSObjectMake(js.JSContextGetGlobalContext(ctx), ConsoleClass.get().*, global);
+ js.JSValueProtect(ctx, global.console);
+ }
- return js.JSObjectMake(js.JSContextGetGlobalContext(ctx), ConsoleClass.get().*, global);
+ return global.console;
}
pub fn boot(global: *GlobalObject) !void {
diff --git a/src/javascript/jsc/typescript.zig b/src/javascript/jsc/typescript.zig
index da22fc88c..e10df2b2f 100644
--- a/src/javascript/jsc/typescript.zig
+++ b/src/javascript/jsc/typescript.zig
@@ -27,43 +27,66 @@ const hidden_globals = [_]d.ts.decl{
const global = JavaScript.GlobalObject.GlobalClass.typescriptDeclaration();
pub fn main() anyerror!void {
+ var allocator = std.heap.c_allocator;
var argv = std.mem.span(std.os.argv);
- var dest = [_]string{ argv[argv.len - 2], argv[argv.len - 1] };
-
- var dir_path = resolve_path.joinAbs(std.process.getCwdAlloc(allocator), .auto, &dest);
+ var dest = [_]string{ std.mem.span(argv[argv.len - 2]), std.mem.span(argv[argv.len - 1]) };
+ var stdout = std.io.getStdOut();
+ var writer = stdout.writer();
+ try writer.print("{s}/{s}\n", .{ dest[0], dest[1] });
+ var dir_path = resolve_path.joinAbsString(try std.process.getCwdAlloc(allocator), &dest, .auto);
std.debug.assert(dir_path.len > 0 and strings.eqlComptime(std.fs.path.basename(dir_path), "types"));
- try std.fs.deleteTreeAbsolute(dir_path);
+ std.fs.deleteTreeAbsolute(dir_path) catch {};
try std.fs.makeDirAbsolute(dir_path);
var dir = try std.fs.openDirAbsolute(dir_path, std.fs.Dir.OpenDirOptions{});
+ var index_file = try dir.createFile("index.d.ts", .{});
+ try index_file.writeAll(
+ \\/// <reference no-default-lib="true" />
+ \\/// <reference lib="esnext" />
+ \\/// <reference types="speedy.js/types/globals" />
+ \\/// <reference types="speedy.js/types/modules" />
+ \\
+ );
+
+ var global_file = try dir.createFile("globals.d.ts", .{});
+ try global_file.writeAll(
+ \\// Speedy.js v
+ \\
+ \\
+ );
+ try global_file.writeAll(comptime d.ts.class.Printer.printDecl(global, 0));
- var index_file = dir.openFile("index.d.ts", .{ .write = true });
- try index_file.writeAll(comptime d.ts.class.Printer.printDecl(global, 0));
+ var module_file = try dir.createFile("modules.d.ts", .{});
+ try module_file.writeAll(
+ \\// Speedy.js v
+ \\
+ \\
+ );
- try index_file.writeAll("\n");
+ try global_file.writeAll("\n");
- try index_file.writeAll("declare global {\n");
+ try global_file.writeAll("declare global {\n");
inline for (hidden_globals) |module, i| {
if (i > 0) {
- try index_file.writeAll("\n");
+ try global_file.writeAll("\n");
}
- try index_file.writeAll(comptime d.ts.class.Printer.printDecl(module, 2));
+ try global_file.writeAll(comptime d.ts.class.Printer.printDecl(module, 2));
}
- try index_file.writeAll("}\n");
- var stdout = std.io.getStdOut();
- try stdout.writeAll("✔️ index.d.ts");
+ try global_file.writeAll("}\n\n");
+ try stdout.writeAll(" ✔️ index.d.ts\n");
inline for (modules) |decl| {
- var module: d.ts.module = comptime decl.module;
+ comptime var module: d.ts.module = decl.module;
const basepath = comptime module.path["speedy.js/".len..];
if (std.fs.path.dirname(basepath)) |dirname| {
- dir.makePath(dirname);
+ try dir.makePath(dirname);
}
- var file = try dir.openFile(comptime basepath ++ ".d.ts", .{ .write = true });
- try file.writeAll(comptime d.ts.class.Printer.printDecl(module, 0));
- try stdout.writeAll(comptime "✔️ " ++ basepath);
+ try module_file.writeAll(comptime d.ts.class.Printer.printDecl(decl, 0));
+ try stdout.writeAll(comptime " ✔️ " ++ basepath ++ " - modules.d.ts\n");
}
+
+ try global_file.writeAll("export {};\n");
}
diff --git a/src/js_printer.zig b/src/js_printer.zig
index 6cbd1a931..fbdff279a 100644
--- a/src/js_printer.zig
+++ b/src/js_printer.zig
@@ -3790,6 +3790,7 @@ pub const BufferWriter = struct {
) anyerror!void {
if (ctx.append_null_byte) {
ctx.sentinel = ctx.buffer.toOwnedSentinelLeaky();
+ ctx.written = ctx.buffer.toOwnedSliceLeaky();
} else {
ctx.written = ctx.buffer.toOwnedSliceLeaky();
}
diff --git a/src/router.zig b/src/router.zig
index 67a203d09..40deb4349 100644
--- a/src/router.zig
+++ b/src/router.zig
@@ -180,6 +180,7 @@ const TinyPtr = packed struct {
const Param = struct {
key: string,
+ kind: RoutePart.Tag,
value: string,
pub const List = std.MultiArrayList(Param);
@@ -302,25 +303,6 @@ pub const RouteMap = struct {
return written;
}
- pub const MatchedRoute = struct {
- /// normalized url path from the request
- path: string,
- /// raw url path from the request
- pathname: string,
- /// absolute filesystem path to the entry point
- file_path: string,
- /// route name, like `"posts/[id]"`
- name: string,
-
- /// basename of the route in the file system, including file extension
- basename: string,
-
- hash: u32,
- params: *Param.List,
- redirect_path: ?string = null,
- query_string: string = "",
- };
-
const MatchContext = struct {
params: *Param.List,
segments: []string,
@@ -339,7 +321,7 @@ pub const RouteMap = struct {
this: *MatchContext,
head_i: u16,
segment_i: u16,
- ) ?MatchedRoute {
+ ) ?Match {
var match = this._matchDynamicRoute(head_i, segment_i) orelse return null;
this.matched_route_name.append("/");
this.matched_route_name.append(match.name);
@@ -350,7 +332,7 @@ pub const RouteMap = struct {
this: *MatchContext,
head_i: u16,
segment_i: u16,
- ) ?MatchedRoute {
+ ) ?Match {
const start_len = this.params.len;
var head = this.map.routes.get(head_i);
const segment = this.segments[segment_i];
@@ -369,7 +351,7 @@ pub const RouteMap = struct {
else => {},
}
- var match_result: MatchedRoute = undefined;
+ var match_result: Match = undefined;
if (head.children.len > 0 and remaining.len > 0) {
var child_i = head.children.offset;
const last = child_i + head.children.len;
@@ -391,7 +373,7 @@ pub const RouteMap = struct {
this.params.shrinkRetainingCapacity(start_len);
return null;
} else {
- match_result = MatchedRoute{
+ match_result = Match{
.path = head.path,
.name = head.name,
.params = this.params,
@@ -412,9 +394,10 @@ pub const RouteMap = struct {
.param => {
this.params.append(
this.allocator,
- .{
+ Param{
.key = head.part.str(head.name),
.value = segment,
+ .kind = head.part.tag,
},
) catch unreachable;
},
@@ -427,7 +410,7 @@ pub const RouteMap = struct {
// This makes many passes over the list of routes
// However, most of those passes are basically array.indexOf(number) and then smallerArray.indexOf(number)
- pub fn matchPage(this: *RouteMap, url_path: URLPath, params: *Param.List) ?MatchedRoute {
+ pub fn matchPage(this: *RouteMap, url_path: URLPath, params: *Param.List) ?Match {
// Trim trailing slash
var path = url_path.path;
var redirect = false;
@@ -454,7 +437,7 @@ pub const RouteMap = struct {
if (path.len == 0) {
if (this.index) |index| {
- return MatchedRoute{
+ return Match{
.params = params,
.name = "index",
.path = this.routes.items(.path)[index],
@@ -479,7 +462,7 @@ pub const RouteMap = struct {
const children = this.routes.items(.hash)[route.children.offset .. route.children.offset + route.children.len];
for (children) |child_hash, i| {
if (child_hash == index_route_hash) {
- return MatchedRoute{
+ return Match{
.params = params,
.name = this.routes.items(.name)[i],
.path = this.routes.items(.path)[i],
@@ -492,7 +475,7 @@ pub const RouteMap = struct {
// It's an exact route, there are no params
// /foo/bar => /foo/bar.js
} else {
- return MatchedRoute{
+ return Match{
.params = params,
.name = route.name,
.path = route.path,
@@ -642,3 +625,22 @@ pub fn match(app: *Router, comptime RequestContextType: type, ctx: *RequestConte
try ctx.handleRequest();
}
+
+pub const Match = struct {
+ /// normalized url path from the request
+ path: string,
+ /// raw url path from the request
+ pathname: string,
+ /// absolute filesystem path to the entry point
+ file_path: string,
+ /// route name, like `"posts/[id]"`
+ name: string,
+
+ /// basename of the route in the file system, including file extension
+ basename: string,
+
+ hash: u32,
+ params: *Param.List,
+ redirect_path: ?string = null,
+ query_string: string = "",
+};
diff --git a/src/test/fixtures/console.log.js b/src/test/fixtures/console.log.js
index cb95413ed..3088f90d5 100644
--- a/src/test/fixtures/console.log.js
+++ b/src/test/fixtures/console.log.js
@@ -1,3 +1 @@
-import React from "react";
-
-console.log("Is this JavaScriptCore?", JSON.stringify(<div>hello</div>));
+console.log("Waiting for debugger.");
diff --git a/types/globals.d.ts b/types/globals.d.ts
new file mode 100644
index 000000000..3d6c0c07c
--- /dev/null
+++ b/types/globals.d.ts
@@ -0,0 +1,21 @@
+// Speedy.js v
+
+declare global {
+
+ function addEventListener(name: "fetch", callback: (event: FetchEvent) => void): void;
+}
+
+declare global {
+ export interface FetchEvent {
+ /** HTTP client metadata. This is not implemented yet, do not use. */
+ readonly client: undefined;
+
+ /** HTTP request */
+ readonly request: InstanceType<Request>;
+
+ /** Render the response in the active HTTP request */
+ respondWith(response: Response): void;
+ }
+}
+
+export {};
diff --git a/types/index.d.ts b/types/index.d.ts
new file mode 100644
index 000000000..4e2dfc32c
--- /dev/null
+++ b/types/index.d.ts
@@ -0,0 +1,4 @@
+/// <reference no-default-lib="true" />
+/// <reference lib="esnext" />
+/// <reference types="speedy.js/types/globals" />
+/// <reference types="speedy.js/types/modules" />
diff --git a/types/modules.d.ts b/types/modules.d.ts
new file mode 100644
index 000000000..3ea7d0437
--- /dev/null
+++ b/types/modules.d.ts
@@ -0,0 +1,48 @@
+// Speedy.js v
+
+/** 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. */
+declare module "speedy.js/router" {
+
+ /** Match a {@link https://developer.mozilla.org/en-US/docs/Web/API/FetchEvent FetchEvent} to a `Route` from the local filesystem. Returns `null` if there is no match. */
+ function match(event: FetchEvent): Route | null;
+
+ /** Match a `pathname` to a `Route` from the local filesystem. Returns `null` if there is no match. */
+ function match(pathname: string): Route | null;
+
+ /** Match a {@link https://developer.mozilla.org/en-US/docs/Web/API/Request Request} to a `Route` from the local filesystem. Returns `null` if there is no match. */
+ function match(request: Request): Route | null;
+ /** Route matched from the filesystem. */
+ export interface Route {
+ /** URL path as appears in a web browser's address bar */
+ readonly pathname: string;
+
+ /** Project-relative filesystem path to the route file. */
+ readonly filepath: string;
+
+ readonly kind: "exact" | "dynamic" | "catch-all" | "optional-catch-all";
+
+ /**
+ * Route name
+ * @example
+ * `"blog/posts/[id]"`
+ * `"blog/posts/[id]/[[...slug]]"`
+ * `"blog"`
+ */
+ readonly name: string;
+
+ /**
+ * 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]");
+ * ```
+ */
+ readonly query: Record<string, string | string[]>;
+
+ /** Synchronously load & evaluate the file corresponding to the route. Returns the exports of the route. This is similar to `await import(route.filepath)`, except it's synchronous. It is recommended to use this function instead of `import`. */
+ import(): Object;
+ }
+}