diff options
author | 2021-08-14 02:39:44 -0700 | |
---|---|---|
committer | 2021-08-14 02:39:44 -0700 | |
commit | 16c76743048ef905269e2711cb0148ecc4e57f3f (patch) | |
tree | a8fb11b55767945a47e92120179f2f762b1f8e99 /src | |
parent | f59892f647ceef1c05e40c9cdef4f79d0a530c2f (diff) | |
download | bun-16c76743048ef905269e2711cb0148ecc4e57f3f.tar.gz bun-16c76743048ef905269e2711cb0148ecc4e57f3f.tar.zst bun-16c76743048ef905269e2711cb0148ecc4e57f3f.zip |
lots
Former-commit-id: 0b8128cb3b4db02f9d33331b4c2c1b595156e6c8
Diffstat (limited to 'src')
-rw-r--r-- | src/api/schema.d.ts | 9 | ||||
-rw-r--r-- | src/api/schema.js | 82 | ||||
-rw-r--r-- | src/api/schema.peechy | 13 | ||||
-rw-r--r-- | src/api/schema.zig | 2725 | ||||
-rw-r--r-- | src/env_loader.zig | 330 | ||||
-rw-r--r-- | src/feature_flags.zig | 1 | ||||
-rw-r--r-- | src/http.zig | 104 | ||||
-rw-r--r-- | src/http/url_path.zig | 8 | ||||
-rw-r--r-- | src/javascript/jsc/api/router.zig | 40 | ||||
-rw-r--r-- | src/javascript/jsc/javascript.zig | 103 | ||||
-rw-r--r-- | src/js_ast.zig | 40 | ||||
-rw-r--r-- | src/js_lexer.zig | 1 | ||||
-rw-r--r-- | src/js_lexer_tables.zig | 20 | ||||
-rw-r--r-- | src/js_parser/js_parser.zig | 26 | ||||
-rw-r--r-- | src/js_printer.zig | 20 | ||||
-rw-r--r-- | src/linker.zig | 37 | ||||
-rw-r--r-- | src/logger.zig | 2 | ||||
-rw-r--r-- | src/options.zig | 83 | ||||
-rw-r--r-- | src/query_string_map.zig | 417 | ||||
-rw-r--r-- | src/resolver/package_json.zig | 60 | ||||
-rw-r--r-- | src/router.zig | 23 | ||||
-rw-r--r-- | src/string_immutable.zig | 17 |
22 files changed, 2719 insertions, 1442 deletions
diff --git a/src/api/schema.d.ts b/src/api/schema.d.ts index 58207e2f9..1077a34f2 100644 --- a/src/api/schema.d.ts +++ b/src/api/schema.d.ts @@ -241,6 +241,10 @@ type uint32 = number; client?: string; server?: string; development?: boolean; + client_defines?: StringMap; + server_defines?: StringMap; + client_defines_prefix?: string; + server_defines_prefix?: string; } export interface LoadedFramework { @@ -248,18 +252,23 @@ type uint32 = number; package: string; development: boolean; client: boolean; + define_defaults: StringMap; + define_prefix: string; + has_define_prefix: boolean; } export interface LoadedRouteConfig { dir: string; extensions: string[]; static_dir: string; + asset_prefix: string; } export interface RouteConfig { dir?: string; extensions?: string[]; static_dir?: string; + asset_prefix?: string; } export interface TransformOptions { diff --git a/src/api/schema.js b/src/api/schema.js index 40a6f132e..178d95662 100644 --- a/src/api/schema.js +++ b/src/api/schema.js @@ -613,6 +613,22 @@ function decodeFrameworkConfig(bb) { result["development"] = !!bb.readByte(); break; + case 5: + result["client_defines"] = decodeStringMap(bb); + break; + + case 6: + result["server_defines"] = decodeStringMap(bb); + break; + + case 7: + result["client_defines_prefix"] = bb.readString(); + break; + + case 8: + result["server_defines_prefix"] = bb.readString(); + break; + default: throw new Error("Attempted to parse invalid message"); } @@ -644,6 +660,30 @@ function encodeFrameworkConfig(message, bb) { bb.writeByte(4); bb.writeByte(value); } + + var value = message["client_defines"]; + if (value != null) { + bb.writeByte(5); + encodeStringMap(value, bb); + } + + var value = message["server_defines"]; + if (value != null) { + bb.writeByte(6); + encodeStringMap(value, bb); + } + + var value = message["client_defines_prefix"]; + if (value != null) { + bb.writeByte(7); + bb.writeString(value); + } + + var value = message["server_defines_prefix"]; + if (value != null) { + bb.writeByte(8); + bb.writeString(value); + } bb.writeByte(0); } @@ -655,6 +695,9 @@ function decodeLoadedFramework(bb) { result["package"] = bb.readString(); result["development"] = !!bb.readByte(); result["client"] = !!bb.readByte(); + result["define_defaults"] = decodeStringMap(bb); + result["define_prefix"] = bb.readString(); + result["has_define_prefix"] = !!bb.readByte(); return result; } @@ -688,6 +731,27 @@ function encodeLoadedFramework(message, bb) { throw new Error("Missing required field \"client\""); } + var value = message["define_defaults"]; + if (value != null) { + encodeStringMap(value, bb); + } else { + throw new Error("Missing required field \"define_defaults\""); + } + + var value = message["define_prefix"]; + if (value != null) { + bb.writeString(value); + } else { + throw new Error("Missing required field \"define_prefix\""); + } + + var value = message["has_define_prefix"]; + if (value != null) { + bb.writeByte(value); + } else { + throw new Error("Missing required field \"has_define_prefix\""); + } + } function decodeLoadedRouteConfig(bb) { @@ -698,6 +762,7 @@ function decodeLoadedRouteConfig(bb) { var values = result["extensions"] = Array(length); for (var i = 0; i < length; i++) values[i] = bb.readString(); result["static_dir"] = bb.readString(); + result["asset_prefix"] = bb.readString(); return result; } @@ -729,6 +794,13 @@ function encodeLoadedRouteConfig(message, bb) { throw new Error("Missing required field \"static_dir\""); } + var value = message["asset_prefix"]; + if (value != null) { + bb.writeString(value); + } else { + throw new Error("Missing required field \"asset_prefix\""); + } + } function decodeRouteConfig(bb) { @@ -753,6 +825,10 @@ function decodeRouteConfig(bb) { result["static_dir"] = bb.readString(); break; + case 4: + result["asset_prefix"] = bb.readString(); + break; + default: throw new Error("Attempted to parse invalid message"); } @@ -783,6 +859,12 @@ function encodeRouteConfig(message, bb) { bb.writeByte(3); bb.writeString(value); } + + var value = message["asset_prefix"]; + if (value != null) { + bb.writeByte(4); + bb.writeString(value); + } bb.writeByte(0); } diff --git a/src/api/schema.peechy b/src/api/schema.peechy index 52d661619..864c6b114 100644 --- a/src/api/schema.peechy +++ b/src/api/schema.peechy @@ -140,6 +140,10 @@ message FrameworkConfig { string client = 2; string server = 3; bool development = 4; + StringMap client_defines = 5; + StringMap server_defines = 6; + string client_defines_prefix = 7; + string server_defines_prefix = 8; } struct LoadedFramework { @@ -147,18 +151,23 @@ struct LoadedFramework { string package; bool development; bool client; + StringMap define_defaults; + string define_prefix; + bool has_define_prefix; } struct LoadedRouteConfig { string dir; string[] extensions; string static_dir; + string asset_prefix; } message RouteConfig { string dir = 1; string[] extensions = 2; string static_dir = 3; + string asset_prefix = 4; } message TransformOptions { @@ -384,4 +393,6 @@ struct WebsocketMessageManifestFailure { uint32 from_timestamp; Loader loader; Log log; -}
\ No newline at end of file +} + + diff --git a/src/api/schema.zig b/src/api/schema.zig index 33bc54bcb..344a60a28 100644 --- a/src/api/schema.zig +++ b/src/api/schema.zig @@ -1,3 +1,4 @@ + const std = @import("std"); pub const Reader = struct { @@ -281,1602 +282,1774 @@ pub fn Writer(comptime WritableStream: type) type { pub const ByteWriter = Writer(*std.io.FixedBufferStream([]u8)); pub const FileWriter = Writer(std.fs.File); -pub const Api = struct { - pub const Loader = enum(u8) { - _none, - /// jsx - jsx, - /// js - js, - /// ts - ts, - /// tsx - tsx, +pub const Api = struct { - /// css - css, +pub const Loader = enum(u8) { - /// file - file, +_none, + /// jsx + jsx, - /// json - json, + /// js + js, - _, + /// ts + ts, - pub fn jsonStringify(self: *const @This(), opts: anytype, o: anytype) !void { - return try std.json.stringify(@tagName(self), opts, o); - } - }; + /// tsx + tsx, - pub const ResolveMode = enum(u8) { - _none, - /// disable - disable, + /// css + css, - /// lazy - lazy, + /// file + file, - /// dev - dev, + /// json + json, - /// bundle - bundle, +_, - _, + pub fn jsonStringify(self: *const @This(), opts: anytype, o: anytype) !void { + return try std.json.stringify(@tagName(self), opts, o); + } - pub fn jsonStringify(self: *const @This(), opts: anytype, o: anytype) !void { - return try std.json.stringify(@tagName(self), opts, o); - } - }; + +}; - pub const Platform = enum(u8) { - _none, - /// browser - browser, +pub const ResolveMode = enum(u8) { - /// node - node, +_none, + /// disable + disable, - /// speedy - speedy, + /// lazy + lazy, - _, + /// dev + dev, - pub fn jsonStringify(self: *const @This(), opts: anytype, o: anytype) !void { - return try std.json.stringify(@tagName(self), opts, o); - } - }; + /// bundle + bundle, - pub const JsxRuntime = enum(u8) { - _none, - /// automatic - automatic, +_, - /// classic - classic, + pub fn jsonStringify(self: *const @This(), opts: anytype, o: anytype) !void { + return try std.json.stringify(@tagName(self), opts, o); + } - _, + +}; - pub fn jsonStringify(self: *const @This(), opts: anytype, o: anytype) !void { - return try std.json.stringify(@tagName(self), opts, o); - } - }; +pub const Platform = enum(u8) { - pub const Jsx = struct { - /// factory - factory: []const u8, +_none, + /// browser + browser, - /// runtime - runtime: JsxRuntime, + /// node + node, - /// fragment - fragment: []const u8, + /// speedy + speedy, - /// development - development: bool = false, +_, - /// import_source - import_source: []const u8, + pub fn jsonStringify(self: *const @This(), opts: anytype, o: anytype) !void { + return try std.json.stringify(@tagName(self), opts, o); + } - /// react_fast_refresh - react_fast_refresh: bool = false, + +}; - pub fn decode(reader: anytype) anyerror!Jsx { - var this = std.mem.zeroes(Jsx); +pub const JsxRuntime = enum(u8) { - this.factory = try reader.readValue([]const u8); - this.runtime = try reader.readValue(JsxRuntime); - this.fragment = try reader.readValue([]const u8); - this.development = try reader.readValue(bool); - this.import_source = try reader.readValue([]const u8); - this.react_fast_refresh = try reader.readValue(bool); - return this; - } +_none, + /// automatic + automatic, - pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - try writer.writeValue(this.factory); - try writer.writeEnum(this.runtime); - try writer.writeValue(this.fragment); - try writer.writeInt(@intCast(u8, @boolToInt(this.development))); - try writer.writeValue(this.import_source); - try writer.writeInt(@intCast(u8, @boolToInt(this.react_fast_refresh))); - } - }; + /// classic + classic, - pub const StringPointer = packed struct { - /// offset - offset: u32 = 0, +_, - /// length - length: u32 = 0, + pub fn jsonStringify(self: *const @This(), opts: anytype, o: anytype) !void { + return try std.json.stringify(@tagName(self), opts, o); + } - pub fn decode(reader: anytype) anyerror!StringPointer { - var this = std.mem.zeroes(StringPointer); + +}; - this.offset = try reader.readValue(u32); - this.length = try reader.readValue(u32); - return this; - } +pub const Jsx = struct { +/// factory +factory: []const u8, - pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - try writer.writeInt(this.offset); - try writer.writeInt(this.length); - } - }; +/// runtime +runtime: JsxRuntime, - pub const JavascriptBundledModule = struct { - /// path - path: StringPointer, +/// fragment +fragment: []const u8, - /// code - code: StringPointer, +/// development +development: bool = false, - /// package_id - package_id: u32 = 0, +/// import_source +import_source: []const u8, - /// id - id: u32 = 0, +/// react_fast_refresh +react_fast_refresh: bool = false, - /// path_extname_length - path_extname_length: u8 = 0, - pub fn decode(reader: anytype) anyerror!JavascriptBundledModule { - var this = std.mem.zeroes(JavascriptBundledModule); +pub fn decode(reader: anytype) anyerror!Jsx { + var this = std.mem.zeroes(Jsx); - this.path = try reader.readValue(StringPointer); - this.code = try reader.readValue(StringPointer); - this.package_id = try reader.readValue(u32); - this.id = try reader.readValue(u32); - this.path_extname_length = try reader.readValue(u8); - return this; - } + this.factory = try reader.readValue([]const u8); + this.runtime = try reader.readValue(JsxRuntime); + this.fragment = try reader.readValue([]const u8); + this.development = try reader.readValue(bool); + this.import_source = try reader.readValue([]const u8); + this.react_fast_refresh = try reader.readValue(bool); + return this; +} - pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - try writer.writeValue(this.path); - try writer.writeValue(this.code); - try writer.writeInt(this.package_id); - try writer.writeInt(this.id); - try writer.writeInt(this.path_extname_length); - } - }; +pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeValue(this.factory); + try writer.writeEnum(this.runtime); + try writer.writeValue(this.fragment); + try writer.writeInt(@intCast(u8, @boolToInt(this.development))); + try writer.writeValue(this.import_source); + try writer.writeInt(@intCast(u8, @boolToInt(this.react_fast_refresh))); +} + +}; - pub const JavascriptBundledPackage = struct { - /// name - name: StringPointer, +pub const StringPointer = packed struct { +/// offset +offset: u32 = 0, - /// version - version: StringPointer, +/// length +length: u32 = 0, - /// hash - hash: u32 = 0, - /// modules_offset - modules_offset: u32 = 0, +pub fn decode(reader: anytype) anyerror!StringPointer { + var this = std.mem.zeroes(StringPointer); - /// modules_length - modules_length: u32 = 0, + this.offset = try reader.readValue(u32); + this.length = try reader.readValue(u32); + return this; +} - pub fn decode(reader: anytype) anyerror!JavascriptBundledPackage { - var this = std.mem.zeroes(JavascriptBundledPackage); +pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeInt(this.offset); + try writer.writeInt(this.length); +} - this.name = try reader.readValue(StringPointer); - this.version = try reader.readValue(StringPointer); - this.hash = try reader.readValue(u32); - this.modules_offset = try reader.readValue(u32); - this.modules_length = try reader.readValue(u32); - return this; - } +}; - pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - try writer.writeValue(this.name); - try writer.writeValue(this.version); - try writer.writeInt(this.hash); - try writer.writeInt(this.modules_offset); - try writer.writeInt(this.modules_length); - } - }; +pub const JavascriptBundledModule = struct { +/// path +path: StringPointer, - pub const JavascriptBundle = struct { - /// modules - modules: []const JavascriptBundledModule, +/// code +code: StringPointer, - /// packages - packages: []const JavascriptBundledPackage, +/// package_id +package_id: u32 = 0, - /// etag - etag: []const u8, +/// id +id: u32 = 0, - /// generated_at - generated_at: u32 = 0, +/// path_extname_length +path_extname_length: u8 = 0, - /// app_package_json_dependencies_hash - app_package_json_dependencies_hash: []const u8, - /// import_from_name - import_from_name: []const u8, +pub fn decode(reader: anytype) anyerror!JavascriptBundledModule { + var this = std.mem.zeroes(JavascriptBundledModule); - /// manifest_string - manifest_string: []const u8, + this.path = try reader.readValue(StringPointer); + this.code = try reader.readValue(StringPointer); + this.package_id = try reader.readValue(u32); + this.id = try reader.readValue(u32); + this.path_extname_length = try reader.readValue(u8); + return this; +} - pub fn decode(reader: anytype) anyerror!JavascriptBundle { - var this = std.mem.zeroes(JavascriptBundle); +pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeValue(this.path); + try writer.writeValue(this.code); + try writer.writeInt(this.package_id); + try writer.writeInt(this.id); + try writer.writeInt(this.path_extname_length); +} - this.modules = try reader.readArray(JavascriptBundledModule); - this.packages = try reader.readArray(JavascriptBundledPackage); - this.etag = try reader.readArray(u8); - this.generated_at = try reader.readValue(u32); - this.app_package_json_dependencies_hash = try reader.readArray(u8); - this.import_from_name = try reader.readArray(u8); - this.manifest_string = try reader.readArray(u8); - return this; - } +}; - pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - try writer.writeArray(JavascriptBundledModule, this.modules); - try writer.writeArray(JavascriptBundledPackage, this.packages); - try writer.writeArray(u8, this.etag); - try writer.writeInt(this.generated_at); - try writer.writeArray(u8, this.app_package_json_dependencies_hash); - try writer.writeArray(u8, this.import_from_name); - try writer.writeArray(u8, this.manifest_string); - } - }; +pub const JavascriptBundledPackage = struct { +/// name +name: StringPointer, - pub const JavascriptBundleContainer = struct { - /// bundle_format_version - bundle_format_version: ?u32 = null, +/// version +version: StringPointer, - /// bundle - bundle: ?JavascriptBundle = null, +/// hash +hash: u32 = 0, - /// framework - framework: ?LoadedFramework = null, +/// modules_offset +modules_offset: u32 = 0, - /// routes - routes: ?LoadedRouteConfig = null, +/// modules_length +modules_length: u32 = 0, - /// code_length - code_length: ?u32 = null, - pub fn decode(reader: anytype) anyerror!JavascriptBundleContainer { - var this = std.mem.zeroes(JavascriptBundleContainer); +pub fn decode(reader: anytype) anyerror!JavascriptBundledPackage { + var this = std.mem.zeroes(JavascriptBundledPackage); - while (true) { - switch (try reader.readByte()) { - 0 => { - return this; - }, + this.name = try reader.readValue(StringPointer); + this.version = try reader.readValue(StringPointer); + this.hash = try reader.readValue(u32); + this.modules_offset = try reader.readValue(u32); + this.modules_length = try reader.readValue(u32); + return this; +} - 1 => { - this.bundle_format_version = try reader.readValue(u32); - }, - 2 => { - this.bundle = try reader.readValue(JavascriptBundle); - }, - 3 => { - this.framework = try reader.readValue(LoadedFramework); - }, - 4 => { - this.routes = try reader.readValue(LoadedRouteConfig); - }, - 5 => { - this.code_length = try reader.readValue(u32); - }, - else => { - return error.InvalidMessage; - }, +pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeValue(this.name); + try writer.writeValue(this.version); + try writer.writeInt(this.hash); + try writer.writeInt(this.modules_offset); + try writer.writeInt(this.modules_length); +} + +}; + +pub const JavascriptBundle = struct { +/// modules +modules: []const JavascriptBundledModule, + +/// packages +packages: []const JavascriptBundledPackage, + +/// etag +etag: []const u8, + +/// generated_at +generated_at: u32 = 0, + +/// app_package_json_dependencies_hash +app_package_json_dependencies_hash: []const u8, + +/// import_from_name +import_from_name: []const u8, + +/// manifest_string +manifest_string: []const u8, + + +pub fn decode(reader: anytype) anyerror!JavascriptBundle { + var this = std.mem.zeroes(JavascriptBundle); + + this.modules = try reader.readArray(JavascriptBundledModule); + this.packages = try reader.readArray(JavascriptBundledPackage); + this.etag = try reader.readArray(u8); + this.generated_at = try reader.readValue(u32); + this.app_package_json_dependencies_hash = try reader.readArray(u8); + this.import_from_name = try reader.readArray(u8); + this.manifest_string = try reader.readArray(u8); + return this; +} + +pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeArray(JavascriptBundledModule, this.modules); + try writer.writeArray(JavascriptBundledPackage, this.packages); + try writer.writeArray(u8, this.etag); + try writer.writeInt(this.generated_at); + try writer.writeArray(u8, this.app_package_json_dependencies_hash); + try writer.writeArray(u8, this.import_from_name); + try writer.writeArray(u8, this.manifest_string); +} + +}; + +pub const JavascriptBundleContainer = struct { +/// bundle_format_version +bundle_format_version: ?u32 = null, + +/// bundle +bundle: ?JavascriptBundle = null, + +/// framework +framework: ?LoadedFramework = null, + +/// routes +routes: ?LoadedRouteConfig = null, + +/// code_length +code_length: ?u32 = null, + + +pub fn decode(reader: anytype) anyerror!JavascriptBundleContainer { + var this = std.mem.zeroes(JavascriptBundleContainer); + + while(true) { + switch (try reader.readByte()) { + 0 => { return this; }, + + 1 => { + this.bundle_format_version = try reader.readValue(u32); +}, + 2 => { + this.bundle = try reader.readValue(JavascriptBundle); +}, + 3 => { + this.framework = try reader.readValue(LoadedFramework); +}, + 4 => { + this.routes = try reader.readValue(LoadedRouteConfig); +}, + 5 => { + this.code_length = try reader.readValue(u32); +}, + else => { + return error.InvalidMessage; + }, + } + } +unreachable; +} + +pub fn encode(this: *const @This(), writer: anytype) anyerror!void { +if (this.bundle_format_version) |bundle_format_version| { + try writer.writeFieldID(1); + try writer.writeInt(bundle_format_version); +} +if (this.bundle) |bundle| { + try writer.writeFieldID(2); + try writer.writeValue(bundle); +} +if (this.framework) |framework| { + try writer.writeFieldID(3); + try writer.writeValue(framework); +} +if (this.routes) |routes| { + try writer.writeFieldID(4); + try writer.writeValue(routes); +} +if (this.code_length) |code_length| { + try writer.writeFieldID(5); + try writer.writeInt(code_length); +} +try writer.endMessage(); +} + +}; + +pub const ScanDependencyMode = enum(u8) { + +_none, + /// app + app, + + /// all + all, + +_, + + pub fn jsonStringify(self: *const @This(), opts: anytype, o: anytype) !void { + return try std.json.stringify(@tagName(self), opts, o); } - } - unreachable; - } - pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - if (this.bundle_format_version) |bundle_format_version| { - try writer.writeFieldID(1); - try writer.writeInt(bundle_format_version); - } - if (this.bundle) |bundle| { - try writer.writeFieldID(2); - try writer.writeValue(bundle); - } - if (this.framework) |framework| { - try writer.writeFieldID(3); - try writer.writeValue(framework); - } - if (this.routes) |routes| { - try writer.writeFieldID(4); - try writer.writeValue(routes); - } - if (this.code_length) |code_length| { - try writer.writeFieldID(5); - try writer.writeInt(code_length); - } - try writer.endMessage(); - } - }; + +}; - pub const ScanDependencyMode = enum(u8) { - _none, - /// app - app, +pub const ModuleImportType = enum(u8) { - /// all - all, +_none, + /// import + import, - _, + /// require + require, - pub fn jsonStringify(self: *const @This(), opts: anytype, o: anytype) !void { - return try std.json.stringify(@tagName(self), opts, o); - } - }; +_, - pub const ModuleImportType = enum(u8) { - _none, - /// import - import, + pub fn jsonStringify(self: *const @This(), opts: anytype, o: anytype) !void { + return try std.json.stringify(@tagName(self), opts, o); + } - /// require - require, + +}; - _, +pub const ModuleImportRecord = struct { +/// kind +kind: ModuleImportType, - pub fn jsonStringify(self: *const @This(), opts: anytype, o: anytype) !void { - return try std.json.stringify(@tagName(self), opts, o); - } - }; +/// path +path: []const u8, - pub const ModuleImportRecord = struct { - /// kind - kind: ModuleImportType, +/// dynamic +dynamic: bool = false, - /// path - path: []const u8, - /// dynamic - dynamic: bool = false, +pub fn decode(reader: anytype) anyerror!ModuleImportRecord { + var this = std.mem.zeroes(ModuleImportRecord); - pub fn decode(reader: anytype) anyerror!ModuleImportRecord { - var this = std.mem.zeroes(ModuleImportRecord); + this.kind = try reader.readValue(ModuleImportType); + this.path = try reader.readValue([]const u8); + this.dynamic = try reader.readValue(bool); + return this; +} - this.kind = try reader.readValue(ModuleImportType); - this.path = try reader.readValue([]const u8); - this.dynamic = try reader.readValue(bool); - return this; - } +pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeEnum(this.kind); + try writer.writeValue(this.path); + try writer.writeInt(@intCast(u8, @boolToInt(this.dynamic))); +} - pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - try writer.writeEnum(this.kind); - try writer.writeValue(this.path); - try writer.writeInt(@intCast(u8, @boolToInt(this.dynamic))); - } - }; +}; - pub const Module = struct { - /// path - path: []const u8, +pub const Module = struct { +/// path +path: []const u8, - /// imports - imports: []const ModuleImportRecord, +/// imports +imports: []const ModuleImportRecord, - pub fn decode(reader: anytype) anyerror!Module { - var this = std.mem.zeroes(Module); - this.path = try reader.readValue([]const u8); - this.imports = try reader.readArray(ModuleImportRecord); - return this; - } +pub fn decode(reader: anytype) anyerror!Module { + var this = std.mem.zeroes(Module); - pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - try writer.writeValue(this.path); - try writer.writeArray(ModuleImportRecord, this.imports); - } - }; + this.path = try reader.readValue([]const u8); + this.imports = try reader.readArray(ModuleImportRecord); + return this; +} - pub const StringMap = struct { - /// keys - keys: []const []const u8, +pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeValue(this.path); + try writer.writeArray(ModuleImportRecord, this.imports); +} - /// values - values: []const []const u8, +}; - pub fn decode(reader: anytype) anyerror!StringMap { - var this = std.mem.zeroes(StringMap); +pub const StringMap = struct { +/// keys +keys: []const []const u8, - this.keys = try reader.readArray([]const u8); - this.values = try reader.readArray([]const u8); - return this; - } +/// values +values: []const []const u8, - pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - try writer.writeArray([]const u8, this.keys); - try writer.writeArray([]const u8, this.values); - } - }; - pub const LoaderMap = struct { - /// extensions - extensions: []const []const u8, +pub fn decode(reader: anytype) anyerror!StringMap { + var this = std.mem.zeroes(StringMap); - /// loaders - loaders: []const Loader, + this.keys = try reader.readArray([]const u8); + this.values = try reader.readArray([]const u8); + return this; +} - pub fn decode(reader: anytype) anyerror!LoaderMap { - var this = std.mem.zeroes(LoaderMap); +pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeArray([]const u8, this.keys); + try writer.writeArray([]const u8, this.values); +} - this.extensions = try reader.readArray([]const u8); - this.loaders = try reader.readArray(Loader); - return this; - } +}; - pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - try writer.writeArray([]const u8, this.extensions); - try writer.writeArray(Loader, this.loaders); - } - }; +pub const LoaderMap = struct { +/// extensions +extensions: []const []const u8, - pub const FrameworkConfig = struct { - /// package - package: ?[]const u8 = null, +/// loaders +loaders: []const Loader, - /// client - client: ?[]const u8 = null, - /// server - server: ?[]const u8 = null, +pub fn decode(reader: anytype) anyerror!LoaderMap { + var this = std.mem.zeroes(LoaderMap); - /// development - development: ?bool = null, + this.extensions = try reader.readArray([]const u8); + this.loaders = try reader.readArray(Loader); + return this; +} - pub fn decode(reader: anytype) anyerror!FrameworkConfig { - var this = std.mem.zeroes(FrameworkConfig); +pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeArray([]const u8, this.extensions); + try writer.writeArray(Loader, this.loaders); +} - while (true) { - switch (try reader.readByte()) { - 0 => { - return this; - }, +}; - 1 => { - this.package = try reader.readValue([]const u8); - }, - 2 => { - this.client = try reader.readValue([]const u8); - }, - 3 => { - this.server = try reader.readValue([]const u8); - }, - 4 => { - this.development = try reader.readValue(bool); - }, - else => { - return error.InvalidMessage; - }, - } - } - unreachable; - } +pub const FrameworkConfig = struct { +/// package +package: ?[]const u8 = null, + +/// client +client: ?[]const u8 = null, + +/// server +server: ?[]const u8 = null, + +/// development +development: ?bool = null, + +/// client_defines +client_defines: ?StringMap = null, + +/// server_defines +server_defines: ?StringMap = null, + +/// client_defines_prefix +client_defines_prefix: ?[]const u8 = null, + +/// server_defines_prefix +server_defines_prefix: ?[]const u8 = null, + + +pub fn decode(reader: anytype) anyerror!FrameworkConfig { + var this = std.mem.zeroes(FrameworkConfig); + + while(true) { + switch (try reader.readByte()) { + 0 => { return this; }, + + 1 => { + this.package = try reader.readValue([]const u8); +}, + 2 => { + this.client = try reader.readValue([]const u8); +}, + 3 => { + this.server = try reader.readValue([]const u8); +}, + 4 => { + this.development = try reader.readValue(bool); +}, + 5 => { + this.client_defines = try reader.readValue(StringMap); +}, + 6 => { + this.server_defines = try reader.readValue(StringMap); +}, + 7 => { + this.client_defines_prefix = try reader.readValue([]const u8); +}, + 8 => { + this.server_defines_prefix = try reader.readValue([]const u8); +}, + else => { + return error.InvalidMessage; + }, + } + } +unreachable; +} - pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - if (this.package) |package| { - try writer.writeFieldID(1); - try writer.writeValue(package); - } - if (this.client) |client| { - try writer.writeFieldID(2); - try writer.writeValue(client); - } - if (this.server) |server| { - try writer.writeFieldID(3); - try writer.writeValue(server); - } - if (this.development) |development| { - try writer.writeFieldID(4); - try writer.writeInt(@intCast(u8, @boolToInt(development))); - } - try writer.endMessage(); - } - }; +pub fn encode(this: *const @This(), writer: anytype) anyerror!void { +if (this.package) |package| { + try writer.writeFieldID(1); + try writer.writeValue(package); +} +if (this.client) |client| { + try writer.writeFieldID(2); + try writer.writeValue(client); +} +if (this.server) |server| { + try writer.writeFieldID(3); + try writer.writeValue(server); +} +if (this.development) |development| { + try writer.writeFieldID(4); + try writer.writeInt(@intCast(u8, @boolToInt(development))); +} +if (this.client_defines) |client_defines| { + try writer.writeFieldID(5); + try writer.writeValue(client_defines); +} +if (this.server_defines) |server_defines| { + try writer.writeFieldID(6); + try writer.writeValue(server_defines); +} +if (this.client_defines_prefix) |client_defines_prefix| { + try writer.writeFieldID(7); + try writer.writeValue(client_defines_prefix); +} +if (this.server_defines_prefix) |server_defines_prefix| { + try writer.writeFieldID(8); + try writer.writeValue(server_defines_prefix); +} +try writer.endMessage(); +} - pub const LoadedFramework = struct { - /// entry_point - entry_point: []const u8, +}; - /// package - package: []const u8, +pub const LoadedFramework = struct { +/// entry_point +entry_point: []const u8, - /// development - development: bool = false, +/// package +package: []const u8, - /// client - client: bool = false, +/// development +development: bool = false, - pub fn decode(reader: anytype) anyerror!LoadedFramework { - var this = std.mem.zeroes(LoadedFramework); +/// client +client: bool = false, - this.entry_point = try reader.readValue([]const u8); - this.package = try reader.readValue([]const u8); - this.development = try reader.readValue(bool); - this.client = try reader.readValue(bool); - return this; - } +/// define_defaults +define_defaults: StringMap, - pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - try writer.writeValue(this.entry_point); - try writer.writeValue(this.package); - try writer.writeInt(@intCast(u8, @boolToInt(this.development))); - try writer.writeInt(@intCast(u8, @boolToInt(this.client))); - } - }; +/// define_prefix +define_prefix: []const u8, - pub const LoadedRouteConfig = struct { - /// dir - dir: []const u8, +/// has_define_prefix +has_define_prefix: bool = false, - /// extensions - extensions: []const []const u8, - /// static_dir - static_dir: []const u8, +pub fn decode(reader: anytype) anyerror!LoadedFramework { + var this = std.mem.zeroes(LoadedFramework); - pub fn decode(reader: anytype) anyerror!LoadedRouteConfig { - var this = std.mem.zeroes(LoadedRouteConfig); + this.entry_point = try reader.readValue([]const u8); + this.package = try reader.readValue([]const u8); + this.development = try reader.readValue(bool); + this.client = try reader.readValue(bool); + this.define_defaults = try reader.readValue(StringMap); + this.define_prefix = try reader.readValue([]const u8); + this.has_define_prefix = try reader.readValue(bool); + return this; +} - this.dir = try reader.readValue([]const u8); - this.extensions = try reader.readArray([]const u8); - this.static_dir = try reader.readValue([]const u8); - return this; - } +pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeValue(this.entry_point); + try writer.writeValue(this.package); + try writer.writeInt(@intCast(u8, @boolToInt(this.development))); + try writer.writeInt(@intCast(u8, @boolToInt(this.client))); + try writer.writeValue(this.define_defaults); + try writer.writeValue(this.define_prefix); + try writer.writeInt(@intCast(u8, @boolToInt(this.has_define_prefix))); +} - pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - try writer.writeValue(this.dir); - try writer.writeArray([]const u8, this.extensions); - try writer.writeValue(this.static_dir); - } - }; +}; - pub const RouteConfig = struct { - /// dir - dir: ?[]const u8 = null, +pub const LoadedRouteConfig = struct { +/// dir +dir: []const u8, - /// extensions - extensions: []const []const u8, +/// extensions +extensions: []const []const u8, - /// static_dir - static_dir: ?[]const u8 = null, +/// static_dir +static_dir: []const u8, - pub fn decode(reader: anytype) anyerror!RouteConfig { - var this = std.mem.zeroes(RouteConfig); +/// asset_prefix +asset_prefix: []const u8, - while (true) { - switch (try reader.readByte()) { - 0 => { - return this; - }, - 1 => { - this.dir = try reader.readValue([]const u8); - }, - 2 => { - this.extensions = try reader.readArray([]const u8); - }, - 3 => { - this.static_dir = try reader.readValue([]const u8); - }, - else => { - return error.InvalidMessage; - }, - } - } - unreachable; - } +pub fn decode(reader: anytype) anyerror!LoadedRouteConfig { + var this = std.mem.zeroes(LoadedRouteConfig); - pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - if (this.dir) |dir| { - try writer.writeFieldID(1); - try writer.writeValue(dir); - } - if (this.extensions) |extensions| { - try writer.writeFieldID(2); - try writer.writeArray([]const u8, extensions); - } - if (this.static_dir) |static_dir| { - try writer.writeFieldID(3); - try writer.writeValue(static_dir); - } - try writer.endMessage(); - } - }; + this.dir = try reader.readValue([]const u8); + this.extensions = try reader.readArray([]const u8); + this.static_dir = try reader.readValue([]const u8); + this.asset_prefix = try reader.readValue([]const u8); + return this; +} - pub const TransformOptions = struct { - /// jsx - jsx: ?Jsx = null, +pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeValue(this.dir); + try writer.writeArray([]const u8, this.extensions); + try writer.writeValue(this.static_dir); + try writer.writeValue(this.asset_prefix); +} - /// tsconfig_override - tsconfig_override: ?[]const u8 = null, +}; - /// resolve - resolve: ?ResolveMode = null, +pub const RouteConfig = struct { +/// dir +dir: ?[]const u8 = null, + +/// extensions +extensions: []const []const u8, + +/// static_dir +static_dir: ?[]const u8 = null, + +/// asset_prefix +asset_prefix: ?[]const u8 = null, + + +pub fn decode(reader: anytype) anyerror!RouteConfig { + var this = std.mem.zeroes(RouteConfig); + + while(true) { + switch (try reader.readByte()) { + 0 => { return this; }, + + 1 => { + this.dir = try reader.readValue([]const u8); +}, + 2 => { + this.extensions = try reader.readArray([]const u8); +}, + 3 => { + this.static_dir = try reader.readValue([]const u8); +}, + 4 => { + this.asset_prefix = try reader.readValue([]const u8); +}, + else => { + return error.InvalidMessage; + }, + } + } +unreachable; +} - /// origin - origin: ?[]const u8 = null, +pub fn encode(this: *const @This(), writer: anytype) anyerror!void { +if (this.dir) |dir| { + try writer.writeFieldID(1); + try writer.writeValue(dir); +} +if (this.extensions) |extensions| { + try writer.writeFieldID(2); + try writer.writeArray([]const u8, extensions); +} +if (this.static_dir) |static_dir| { + try writer.writeFieldID(3); + try writer.writeValue(static_dir); +} +if (this.asset_prefix) |asset_prefix| { + try writer.writeFieldID(4); + try writer.writeValue(asset_prefix); +} +try writer.endMessage(); +} - /// absolute_working_dir - absolute_working_dir: ?[]const u8 = null, +}; - /// define - define: ?StringMap = null, +pub const TransformOptions = struct { +/// jsx +jsx: ?Jsx = null, - /// preserve_symlinks - preserve_symlinks: ?bool = null, +/// tsconfig_override +tsconfig_override: ?[]const u8 = null, - /// entry_points - entry_points: []const []const u8, +/// resolve +resolve: ?ResolveMode = null, - /// write - write: ?bool = null, +/// origin +origin: ?[]const u8 = null, + +/// absolute_working_dir +absolute_working_dir: ?[]const u8 = null, + +/// define +define: ?StringMap = null, + +/// preserve_symlinks +preserve_symlinks: ?bool = null, + +/// entry_points +entry_points: []const []const u8, + +/// write +write: ?bool = null, + +/// inject +inject: []const []const u8, + +/// output_dir +output_dir: ?[]const u8 = null, + +/// external +external: []const []const u8, + +/// loaders +loaders: ?LoaderMap = null, + +/// main_fields +main_fields: []const []const u8, + +/// platform +platform: ?Platform = null, + +/// serve +serve: ?bool = null, + +/// extension_order +extension_order: []const []const u8, + +/// only_scan_dependencies +only_scan_dependencies: ?ScanDependencyMode = null, + +/// generate_node_module_bundle +generate_node_module_bundle: ?bool = null, + +/// node_modules_bundle_path +node_modules_bundle_path: ?[]const u8 = null, + +/// node_modules_bundle_path_server +node_modules_bundle_path_server: ?[]const u8 = null, + +/// framework +framework: ?FrameworkConfig = null, + +/// router +router: ?RouteConfig = null, + + +pub fn decode(reader: anytype) anyerror!TransformOptions { + var this = std.mem.zeroes(TransformOptions); + + while(true) { + switch (try reader.readByte()) { + 0 => { return this; }, + + 1 => { + this.jsx = try reader.readValue(Jsx); +}, + 2 => { + this.tsconfig_override = try reader.readValue([]const u8); +}, + 3 => { + this.resolve = try reader.readValue(ResolveMode); +}, + 4 => { + this.origin = try reader.readValue([]const u8); +}, + 5 => { + this.absolute_working_dir = try reader.readValue([]const u8); +}, + 6 => { + this.define = try reader.readValue(StringMap); +}, + 7 => { + this.preserve_symlinks = try reader.readValue(bool); +}, + 8 => { + this.entry_points = try reader.readArray([]const u8); +}, + 9 => { + this.write = try reader.readValue(bool); +}, + 10 => { + this.inject = try reader.readArray([]const u8); +}, + 11 => { + this.output_dir = try reader.readValue([]const u8); +}, + 12 => { + this.external = try reader.readArray([]const u8); +}, + 13 => { + this.loaders = try reader.readValue(LoaderMap); +}, + 14 => { + this.main_fields = try reader.readArray([]const u8); +}, + 15 => { + this.platform = try reader.readValue(Platform); +}, + 16 => { + this.serve = try reader.readValue(bool); +}, + 17 => { + this.extension_order = try reader.readArray([]const u8); +}, + 18 => { + this.only_scan_dependencies = try reader.readValue(ScanDependencyMode); +}, + 19 => { + this.generate_node_module_bundle = try reader.readValue(bool); +}, + 20 => { + this.node_modules_bundle_path = try reader.readValue([]const u8); +}, + 21 => { + this.node_modules_bundle_path_server = try reader.readValue([]const u8); +}, + 22 => { + this.framework = try reader.readValue(FrameworkConfig); +}, + 23 => { + this.router = try reader.readValue(RouteConfig); +}, + else => { + return error.InvalidMessage; + }, + } + } +unreachable; +} - /// inject - inject: []const []const u8, +pub fn encode(this: *const @This(), writer: anytype) anyerror!void { +if (this.jsx) |jsx| { + try writer.writeFieldID(1); + try writer.writeValue(jsx); +} +if (this.tsconfig_override) |tsconfig_override| { + try writer.writeFieldID(2); + try writer.writeValue(tsconfig_override); +} +if (this.resolve) |resolve| { + try writer.writeFieldID(3); + try writer.writeEnum(resolve); +} +if (this.origin) |origin| { + try writer.writeFieldID(4); + try writer.writeValue(origin); +} +if (this.absolute_working_dir) |absolute_working_dir| { + try writer.writeFieldID(5); + try writer.writeValue(absolute_working_dir); +} +if (this.define) |define| { + try writer.writeFieldID(6); + try writer.writeValue(define); +} +if (this.preserve_symlinks) |preserve_symlinks| { + try writer.writeFieldID(7); + try writer.writeInt(@intCast(u8, @boolToInt(preserve_symlinks))); +} +if (this.entry_points) |entry_points| { + try writer.writeFieldID(8); + try writer.writeArray([]const u8, entry_points); +} +if (this.write) |write| { + try writer.writeFieldID(9); + try writer.writeInt(@intCast(u8, @boolToInt(write))); +} +if (this.inject) |inject| { + try writer.writeFieldID(10); + try writer.writeArray([]const u8, inject); +} +if (this.output_dir) |output_dir| { + try writer.writeFieldID(11); + try writer.writeValue(output_dir); +} +if (this.external) |external| { + try writer.writeFieldID(12); + try writer.writeArray([]const u8, external); +} +if (this.loaders) |loaders| { + try writer.writeFieldID(13); + try writer.writeValue(loaders); +} +if (this.main_fields) |main_fields| { + try writer.writeFieldID(14); + try writer.writeArray([]const u8, main_fields); +} +if (this.platform) |platform| { + try writer.writeFieldID(15); + try writer.writeEnum(platform); +} +if (this.serve) |serve| { + try writer.writeFieldID(16); + try writer.writeInt(@intCast(u8, @boolToInt(serve))); +} +if (this.extension_order) |extension_order| { + try writer.writeFieldID(17); + try writer.writeArray([]const u8, extension_order); +} +if (this.only_scan_dependencies) |only_scan_dependencies| { + try writer.writeFieldID(18); + try writer.writeEnum(only_scan_dependencies); +} +if (this.generate_node_module_bundle) |generate_node_module_bundle| { + try writer.writeFieldID(19); + try writer.writeInt(@intCast(u8, @boolToInt(generate_node_module_bundle))); +} +if (this.node_modules_bundle_path) |node_modules_bundle_path| { + try writer.writeFieldID(20); + try writer.writeValue(node_modules_bundle_path); +} +if (this.node_modules_bundle_path_server) |node_modules_bundle_path_server| { + try writer.writeFieldID(21); + try writer.writeValue(node_modules_bundle_path_server); +} +if (this.framework) |framework| { + try writer.writeFieldID(22); + try writer.writeValue(framework); +} +if (this.router) |router| { + try writer.writeFieldID(23); + try writer.writeValue(router); +} +try writer.endMessage(); +} - /// output_dir - output_dir: ?[]const u8 = null, +}; - /// external - external: []const []const u8, +pub const FileHandle = struct { +/// path +path: []const u8, - /// loaders - loaders: ?LoaderMap = null, +/// size +size: u32 = 0, - /// main_fields - main_fields: []const []const u8, +/// fd +fd: u32 = 0, - /// platform - platform: ?Platform = null, - /// serve - serve: ?bool = null, +pub fn decode(reader: anytype) anyerror!FileHandle { + var this = std.mem.zeroes(FileHandle); - /// extension_order - extension_order: []const []const u8, + this.path = try reader.readValue([]const u8); + this.size = try reader.readValue(u32); + this.fd = try reader.readValue(u32); + return this; +} - /// only_scan_dependencies - only_scan_dependencies: ?ScanDependencyMode = null, +pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeValue(this.path); + try writer.writeInt(this.size); + try writer.writeInt(this.fd); +} - /// generate_node_module_bundle - generate_node_module_bundle: ?bool = null, +}; - /// node_modules_bundle_path - node_modules_bundle_path: ?[]const u8 = null, +pub const Transform = struct { +/// handle +handle: ?FileHandle = null, + +/// path +path: ?[]const u8 = null, + +/// contents +contents: []const u8, + +/// loader +loader: ?Loader = null, + +/// options +options: ?TransformOptions = null, + + +pub fn decode(reader: anytype) anyerror!Transform { + var this = std.mem.zeroes(Transform); + + while(true) { + switch (try reader.readByte()) { + 0 => { return this; }, + + 1 => { + this.handle = try reader.readValue(FileHandle); +}, + 2 => { + this.path = try reader.readValue([]const u8); +}, + 3 => { + this.contents = try reader.readArray(u8); +}, + 4 => { + this.loader = try reader.readValue(Loader); +}, + 5 => { + this.options = try reader.readValue(TransformOptions); +}, + else => { + return error.InvalidMessage; + }, + } + } +unreachable; +} - /// node_modules_bundle_path_server - node_modules_bundle_path_server: ?[]const u8 = null, +pub fn encode(this: *const @This(), writer: anytype) anyerror!void { +if (this.handle) |handle| { + try writer.writeFieldID(1); + try writer.writeValue(handle); +} +if (this.path) |path| { + try writer.writeFieldID(2); + try writer.writeValue(path); +} +if (this.contents) |contents| { + try writer.writeFieldID(3); + try writer.writeArray(u8, contents); +} +if (this.loader) |loader| { + try writer.writeFieldID(4); + try writer.writeEnum(loader); +} +if (this.options) |options| { + try writer.writeFieldID(5); + try writer.writeValue(options); +} +try writer.endMessage(); +} - /// framework - framework: ?FrameworkConfig = null, +}; - /// router - router: ?RouteConfig = null, +pub const TransformResponseStatus = enum(u32) { - pub fn decode(reader: anytype) anyerror!TransformOptions { - var this = std.mem.zeroes(TransformOptions); +_none, + /// success + success, - while (true) { - switch (try reader.readByte()) { - 0 => { - return this; - }, + /// fail + fail, - 1 => { - this.jsx = try reader.readValue(Jsx); - }, - 2 => { - this.tsconfig_override = try reader.readValue([]const u8); - }, - 3 => { - this.resolve = try reader.readValue(ResolveMode); - }, - 4 => { - this.origin = try reader.readValue([]const u8); - }, - 5 => { - this.absolute_working_dir = try reader.readValue([]const u8); - }, - 6 => { - this.define = try reader.readValue(StringMap); - }, - 7 => { - this.preserve_symlinks = try reader.readValue(bool); - }, - 8 => { - this.entry_points = try reader.readArray([]const u8); - }, - 9 => { - this.write = try reader.readValue(bool); - }, - 10 => { - this.inject = try reader.readArray([]const u8); - }, - 11 => { - this.output_dir = try reader.readValue([]const u8); - }, - 12 => { - this.external = try reader.readArray([]const u8); - }, - 13 => { - this.loaders = try reader.readValue(LoaderMap); - }, - 14 => { - this.main_fields = try reader.readArray([]const u8); - }, - 15 => { - this.platform = try reader.readValue(Platform); - }, - 16 => { - this.serve = try reader.readValue(bool); - }, - 17 => { - this.extension_order = try reader.readArray([]const u8); - }, - 18 => { - this.only_scan_dependencies = try reader.readValue(ScanDependencyMode); - }, - 19 => { - this.generate_node_module_bundle = try reader.readValue(bool); - }, - 20 => { - this.node_modules_bundle_path = try reader.readValue([]const u8); - }, - 21 => { - this.node_modules_bundle_path_server = try reader.readValue([]const u8); - }, - 22 => { - this.framework = try reader.readValue(FrameworkConfig); - }, - 23 => { - this.router = try reader.readValue(RouteConfig); - }, - else => { - return error.InvalidMessage; - }, +_, + + pub fn jsonStringify(self: *const @This(), opts: anytype, o: anytype) !void { + return try std.json.stringify(@tagName(self), opts, o); } - } - unreachable; - } - pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - if (this.jsx) |jsx| { - try writer.writeFieldID(1); - try writer.writeValue(jsx); - } - if (this.tsconfig_override) |tsconfig_override| { - try writer.writeFieldID(2); - try writer.writeValue(tsconfig_override); - } - if (this.resolve) |resolve| { - try writer.writeFieldID(3); - try writer.writeEnum(resolve); - } - if (this.origin) |origin| { - try writer.writeFieldID(4); - try writer.writeValue(origin); - } - if (this.absolute_working_dir) |absolute_working_dir| { - try writer.writeFieldID(5); - try writer.writeValue(absolute_working_dir); - } - if (this.define) |define| { - try writer.writeFieldID(6); - try writer.writeValue(define); - } - if (this.preserve_symlinks) |preserve_symlinks| { - try writer.writeFieldID(7); - try writer.writeInt(@intCast(u8, @boolToInt(preserve_symlinks))); - } - if (this.entry_points) |entry_points| { - try writer.writeFieldID(8); - try writer.writeArray([]const u8, entry_points); - } - if (this.write) |write| { - try writer.writeFieldID(9); - try writer.writeInt(@intCast(u8, @boolToInt(write))); - } - if (this.inject) |inject| { - try writer.writeFieldID(10); - try writer.writeArray([]const u8, inject); - } - if (this.output_dir) |output_dir| { - try writer.writeFieldID(11); - try writer.writeValue(output_dir); - } - if (this.external) |external| { - try writer.writeFieldID(12); - try writer.writeArray([]const u8, external); - } - if (this.loaders) |loaders| { - try writer.writeFieldID(13); - try writer.writeValue(loaders); - } - if (this.main_fields) |main_fields| { - try writer.writeFieldID(14); - try writer.writeArray([]const u8, main_fields); - } - if (this.platform) |platform| { - try writer.writeFieldID(15); - try writer.writeEnum(platform); - } - if (this.serve) |serve| { - try writer.writeFieldID(16); - try writer.writeInt(@intCast(u8, @boolToInt(serve))); - } - if (this.extension_order) |extension_order| { - try writer.writeFieldID(17); - try writer.writeArray([]const u8, extension_order); - } - if (this.only_scan_dependencies) |only_scan_dependencies| { - try writer.writeFieldID(18); - try writer.writeEnum(only_scan_dependencies); - } - if (this.generate_node_module_bundle) |generate_node_module_bundle| { - try writer.writeFieldID(19); - try writer.writeInt(@intCast(u8, @boolToInt(generate_node_module_bundle))); - } - if (this.node_modules_bundle_path) |node_modules_bundle_path| { - try writer.writeFieldID(20); - try writer.writeValue(node_modules_bundle_path); - } - if (this.node_modules_bundle_path_server) |node_modules_bundle_path_server| { - try writer.writeFieldID(21); - try writer.writeValue(node_modules_bundle_path_server); - } - if (this.framework) |framework| { - try writer.writeFieldID(22); - try writer.writeValue(framework); - } - if (this.router) |router| { - try writer.writeFieldID(23); - try writer.writeValue(router); - } - try writer.endMessage(); - } - }; + +}; - pub const FileHandle = struct { - /// path - path: []const u8, +pub const OutputFile = struct { +/// data +data: []const u8, - /// size - size: u32 = 0, +/// path +path: []const u8, - /// fd - fd: u32 = 0, - pub fn decode(reader: anytype) anyerror!FileHandle { - var this = std.mem.zeroes(FileHandle); +pub fn decode(reader: anytype) anyerror!OutputFile { + var this = std.mem.zeroes(OutputFile); - this.path = try reader.readValue([]const u8); - this.size = try reader.readValue(u32); - this.fd = try reader.readValue(u32); - return this; - } + this.data = try reader.readArray(u8); + this.path = try reader.readValue([]const u8); + return this; +} - pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - try writer.writeValue(this.path); - try writer.writeInt(this.size); - try writer.writeInt(this.fd); - } - }; +pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeArray(u8, this.data); + try writer.writeValue(this.path); +} - pub const Transform = struct { - /// handle - handle: ?FileHandle = null, +}; - /// path - path: ?[]const u8 = null, +pub const TransformResponse = struct { +/// status +status: TransformResponseStatus, - /// contents - contents: []const u8, +/// files +files: []const OutputFile, - /// loader - loader: ?Loader = null, +/// errors +errors: []const Message, - /// options - options: ?TransformOptions = null, - pub fn decode(reader: anytype) anyerror!Transform { - var this = std.mem.zeroes(Transform); +pub fn decode(reader: anytype) anyerror!TransformResponse { + var this = std.mem.zeroes(TransformResponse); - while (true) { - switch (try reader.readByte()) { - 0 => { - return this; - }, + this.status = try reader.readValue(TransformResponseStatus); + this.files = try reader.readArray(OutputFile); + this.errors = try reader.readArray(Message); + return this; +} - 1 => { - this.handle = try reader.readValue(FileHandle); - }, - 2 => { - this.path = try reader.readValue([]const u8); - }, - 3 => { - this.contents = try reader.readArray(u8); - }, - 4 => { - this.loader = try reader.readValue(Loader); - }, - 5 => { - this.options = try reader.readValue(TransformOptions); - }, - else => { - return error.InvalidMessage; - }, +pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeEnum(this.status); + try writer.writeArray(OutputFile, this.files); + try writer.writeArray(Message, this.errors); +} + +}; + +pub const MessageKind = enum(u32) { + +_none, + /// err + err, + + /// warn + warn, + + /// note + note, + + /// debug + debug, + +_, + + pub fn jsonStringify(self: *const @This(), opts: anytype, o: anytype) !void { + return try std.json.stringify(@tagName(self), opts, o); } - } - unreachable; - } - pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - if (this.handle) |handle| { - try writer.writeFieldID(1); - try writer.writeValue(handle); - } - if (this.path) |path| { - try writer.writeFieldID(2); - try writer.writeValue(path); - } - if (this.contents) |contents| { - try writer.writeFieldID(3); - try writer.writeArray(u8, contents); - } - if (this.loader) |loader| { - try writer.writeFieldID(4); - try writer.writeEnum(loader); - } - if (this.options) |options| { - try writer.writeFieldID(5); - try writer.writeValue(options); - } - try writer.endMessage(); - } - }; + +}; - pub const TransformResponseStatus = enum(u32) { - _none, - /// success - success, +pub const Location = struct { +/// file +file: []const u8, - /// fail - fail, +/// namespace +namespace: []const u8, - _, +/// line +line: i32 = 0, - pub fn jsonStringify(self: *const @This(), opts: anytype, o: anytype) !void { - return try std.json.stringify(@tagName(self), opts, o); - } - }; +/// column +column: i32 = 0, - pub const OutputFile = struct { - /// data - data: []const u8, +/// line_text +line_text: []const u8, - /// path - path: []const u8, +/// suggestion +suggestion: []const u8, - pub fn decode(reader: anytype) anyerror!OutputFile { - var this = std.mem.zeroes(OutputFile); +/// offset +offset: u32 = 0, - this.data = try reader.readArray(u8); - this.path = try reader.readValue([]const u8); - return this; - } - pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - try writer.writeArray(u8, this.data); - try writer.writeValue(this.path); - } - }; +pub fn decode(reader: anytype) anyerror!Location { + var this = std.mem.zeroes(Location); - pub const TransformResponse = struct { - /// status - status: TransformResponseStatus, + this.file = try reader.readValue([]const u8); + this.namespace = try reader.readValue([]const u8); + this.line = try reader.readValue(i32); + this.column = try reader.readValue(i32); + this.line_text = try reader.readValue([]const u8); + this.suggestion = try reader.readValue([]const u8); + this.offset = try reader.readValue(u32); + return this; +} - /// files - files: []const OutputFile, +pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeValue(this.file); + try writer.writeValue(this.namespace); + try writer.writeInt(this.line); + try writer.writeInt(this.column); + try writer.writeValue(this.line_text); + try writer.writeValue(this.suggestion); + try writer.writeInt(this.offset); +} - /// errors - errors: []const Message, +}; - pub fn decode(reader: anytype) anyerror!TransformResponse { - var this = std.mem.zeroes(TransformResponse); +pub const MessageData = struct { +/// text +text: ?[]const u8 = null, + +/// location +location: ?Location = null, + + +pub fn decode(reader: anytype) anyerror!MessageData { + var this = std.mem.zeroes(MessageData); + + while(true) { + switch (try reader.readByte()) { + 0 => { return this; }, + + 1 => { + this.text = try reader.readValue([]const u8); +}, + 2 => { + this.location = try reader.readValue(Location); +}, + else => { + return error.InvalidMessage; + }, + } + } +unreachable; +} - this.status = try reader.readValue(TransformResponseStatus); - this.files = try reader.readArray(OutputFile); - this.errors = try reader.readArray(Message); - return this; - } +pub fn encode(this: *const @This(), writer: anytype) anyerror!void { +if (this.text) |text| { + try writer.writeFieldID(1); + try writer.writeValue(text); +} +if (this.location) |location| { + try writer.writeFieldID(2); + try writer.writeValue(location); +} +try writer.endMessage(); +} - pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - try writer.writeEnum(this.status); - try writer.writeArray(OutputFile, this.files); - try writer.writeArray(Message, this.errors); - } - }; +}; - pub const MessageKind = enum(u32) { - _none, - /// err - err, +pub const Message = struct { +/// kind +kind: MessageKind, - /// warn - warn, +/// data +data: MessageData, - /// note - note, +/// notes +notes: []const MessageData, - /// debug - debug, - _, +pub fn decode(reader: anytype) anyerror!Message { + var this = std.mem.zeroes(Message); - pub fn jsonStringify(self: *const @This(), opts: anytype, o: anytype) !void { - return try std.json.stringify(@tagName(self), opts, o); - } - }; + this.kind = try reader.readValue(MessageKind); + this.data = try reader.readValue(MessageData); + this.notes = try reader.readArray(MessageData); + return this; +} - pub const Location = struct { - /// file - file: []const u8, +pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeEnum(this.kind); + try writer.writeValue(this.data); + try writer.writeArray(MessageData, this.notes); +} - /// namespace - namespace: []const u8, +}; - /// line - line: i32 = 0, +pub const Log = struct { +/// warnings +warnings: u32 = 0, - /// column - column: i32 = 0, +/// errors +errors: u32 = 0, - /// line_text - line_text: []const u8, +/// msgs +msgs: []const Message, - /// suggestion - suggestion: []const u8, - /// offset - offset: u32 = 0, +pub fn decode(reader: anytype) anyerror!Log { + var this = std.mem.zeroes(Log); - pub fn decode(reader: anytype) anyerror!Location { - var this = std.mem.zeroes(Location); + this.warnings = try reader.readValue(u32); + this.errors = try reader.readValue(u32); + this.msgs = try reader.readArray(Message); + return this; +} - this.file = try reader.readValue([]const u8); - this.namespace = try reader.readValue([]const u8); - this.line = try reader.readValue(i32); - this.column = try reader.readValue(i32); - this.line_text = try reader.readValue([]const u8); - this.suggestion = try reader.readValue([]const u8); - this.offset = try reader.readValue(u32); - return this; - } +pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeInt(this.warnings); + try writer.writeInt(this.errors); + try writer.writeArray(Message, this.msgs); +} - pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - try writer.writeValue(this.file); - try writer.writeValue(this.namespace); - try writer.writeInt(this.line); - try writer.writeInt(this.column); - try writer.writeValue(this.line_text); - try writer.writeValue(this.suggestion); - try writer.writeInt(this.offset); - } - }; +}; - pub const MessageData = struct { - /// text - text: ?[]const u8 = null, +pub const Reloader = enum(u8) { - /// location - location: ?Location = null, +_none, + /// disable + disable, - pub fn decode(reader: anytype) anyerror!MessageData { - var this = std.mem.zeroes(MessageData); + /// live + live, - while (true) { - switch (try reader.readByte()) { - 0 => { - return this; - }, + /// fast_refresh + fast_refresh, - 1 => { - this.text = try reader.readValue([]const u8); - }, - 2 => { - this.location = try reader.readValue(Location); - }, - else => { - return error.InvalidMessage; - }, +_, + + pub fn jsonStringify(self: *const @This(), opts: anytype, o: anytype) !void { + return try std.json.stringify(@tagName(self), opts, o); } - } - unreachable; - } - pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - if (this.text) |text| { - try writer.writeFieldID(1); - try writer.writeValue(text); - } - if (this.location) |location| { - try writer.writeFieldID(2); - try writer.writeValue(location); - } - try writer.endMessage(); - } - }; + +}; - pub const Message = struct { - /// kind - kind: MessageKind, +pub const WebsocketMessageKind = enum(u8) { - /// data - data: MessageData, +_none, + /// welcome + welcome, - /// notes - notes: []const MessageData, + /// file_change_notification + file_change_notification, - pub fn decode(reader: anytype) anyerror!Message { - var this = std.mem.zeroes(Message); + /// build_success + build_success, - this.kind = try reader.readValue(MessageKind); - this.data = try reader.readValue(MessageData); - this.notes = try reader.readArray(MessageData); - return this; - } + /// build_fail + build_fail, - pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - try writer.writeEnum(this.kind); - try writer.writeValue(this.data); - try writer.writeArray(MessageData, this.notes); - } - }; + /// manifest_success + manifest_success, - pub const Log = struct { - /// warnings - warnings: u32 = 0, + /// manifest_fail + manifest_fail, - /// errors - errors: u32 = 0, +_, - /// msgs - msgs: []const Message, + pub fn jsonStringify(self: *const @This(), opts: anytype, o: anytype) !void { + return try std.json.stringify(@tagName(self), opts, o); + } - pub fn decode(reader: anytype) anyerror!Log { - var this = std.mem.zeroes(Log); + +}; - this.warnings = try reader.readValue(u32); - this.errors = try reader.readValue(u32); - this.msgs = try reader.readArray(Message); - return this; - } +pub const WebsocketCommandKind = enum(u8) { - pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - try writer.writeInt(this.warnings); - try writer.writeInt(this.errors); - try writer.writeArray(Message, this.msgs); - } - }; +_none, + /// build + build, - pub const Reloader = enum(u8) { - _none, - /// disable - disable, + /// manifest + manifest, - /// live - live, +_, - /// fast_refresh - fast_refresh, + pub fn jsonStringify(self: *const @This(), opts: anytype, o: anytype) !void { + return try std.json.stringify(@tagName(self), opts, o); + } - _, + +}; - pub fn jsonStringify(self: *const @This(), opts: anytype, o: anytype) !void { - return try std.json.stringify(@tagName(self), opts, o); - } - }; +pub const WebsocketMessage = struct { +/// timestamp +timestamp: u32 = 0, - pub const WebsocketMessageKind = enum(u8) { - _none, - /// welcome - welcome, +/// kind +kind: WebsocketMessageKind, - /// file_change_notification - file_change_notification, - /// build_success - build_success, +pub fn decode(reader: anytype) anyerror!WebsocketMessage { + var this = std.mem.zeroes(WebsocketMessage); - /// build_fail - build_fail, + this.timestamp = try reader.readValue(u32); + this.kind = try reader.readValue(WebsocketMessageKind); + return this; +} - /// manifest_success - manifest_success, +pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeInt(this.timestamp); + try writer.writeEnum(this.kind); +} - /// manifest_fail - manifest_fail, +}; - _, +pub const WebsocketMessageWelcome = struct { +/// epoch +epoch: u32 = 0, - pub fn jsonStringify(self: *const @This(), opts: anytype, o: anytype) !void { - return try std.json.stringify(@tagName(self), opts, o); - } - }; +/// javascriptReloader +javascript_reloader: Reloader, - pub const WebsocketCommandKind = enum(u8) { - _none, - /// build - build, - /// manifest - manifest, +pub fn decode(reader: anytype) anyerror!WebsocketMessageWelcome { + var this = std.mem.zeroes(WebsocketMessageWelcome); - _, + this.epoch = try reader.readValue(u32); + this.javascript_reloader = try reader.readValue(Reloader); + return this; +} - pub fn jsonStringify(self: *const @This(), opts: anytype, o: anytype) !void { - return try std.json.stringify(@tagName(self), opts, o); - } - }; +pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeInt(this.epoch); + try writer.writeEnum(this.javascript_reloader); +} - pub const WebsocketMessage = struct { - /// timestamp - timestamp: u32 = 0, +}; - /// kind - kind: WebsocketMessageKind, +pub const WebsocketMessageFileChangeNotification = struct { +/// id +id: u32 = 0, - pub fn decode(reader: anytype) anyerror!WebsocketMessage { - var this = std.mem.zeroes(WebsocketMessage); +/// loader +loader: Loader, - this.timestamp = try reader.readValue(u32); - this.kind = try reader.readValue(WebsocketMessageKind); - return this; - } - pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - try writer.writeInt(this.timestamp); - try writer.writeEnum(this.kind); - } - }; +pub fn decode(reader: anytype) anyerror!WebsocketMessageFileChangeNotification { + var this = std.mem.zeroes(WebsocketMessageFileChangeNotification); - pub const WebsocketMessageWelcome = struct { - /// epoch - epoch: u32 = 0, + this.id = try reader.readValue(u32); + this.loader = try reader.readValue(Loader); + return this; +} - /// javascriptReloader - javascript_reloader: Reloader, +pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeInt(this.id); + try writer.writeEnum(this.loader); +} - pub fn decode(reader: anytype) anyerror!WebsocketMessageWelcome { - var this = std.mem.zeroes(WebsocketMessageWelcome); +}; - this.epoch = try reader.readValue(u32); - this.javascript_reloader = try reader.readValue(Reloader); - return this; - } +pub const WebsocketCommand = struct { +/// kind +kind: WebsocketCommandKind, - pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - try writer.writeInt(this.epoch); - try writer.writeEnum(this.javascript_reloader); - } - }; +/// timestamp +timestamp: u32 = 0, - pub const WebsocketMessageFileChangeNotification = struct { - /// id - id: u32 = 0, - /// loader - loader: Loader, +pub fn decode(reader: anytype) anyerror!WebsocketCommand { + var this = std.mem.zeroes(WebsocketCommand); - pub fn decode(reader: anytype) anyerror!WebsocketMessageFileChangeNotification { - var this = std.mem.zeroes(WebsocketMessageFileChangeNotification); + this.kind = try reader.readValue(WebsocketCommandKind); + this.timestamp = try reader.readValue(u32); + return this; +} - this.id = try reader.readValue(u32); - this.loader = try reader.readValue(Loader); - return this; - } +pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeEnum(this.kind); + try writer.writeInt(this.timestamp); +} - pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - try writer.writeInt(this.id); - try writer.writeEnum(this.loader); - } - }; +}; - pub const WebsocketCommand = struct { - /// kind - kind: WebsocketCommandKind, +pub const WebsocketCommandBuild = packed struct { +/// id +id: u32 = 0, - /// timestamp - timestamp: u32 = 0, - pub fn decode(reader: anytype) anyerror!WebsocketCommand { - var this = std.mem.zeroes(WebsocketCommand); +pub fn decode(reader: anytype) anyerror!WebsocketCommandBuild { + var this = std.mem.zeroes(WebsocketCommandBuild); - this.kind = try reader.readValue(WebsocketCommandKind); - this.timestamp = try reader.readValue(u32); - return this; - } + this.id = try reader.readValue(u32); + return this; +} - pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - try writer.writeEnum(this.kind); - try writer.writeInt(this.timestamp); - } - }; +pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeInt(this.id); +} - pub const WebsocketCommandBuild = packed struct { - /// id - id: u32 = 0, +}; - pub fn decode(reader: anytype) anyerror!WebsocketCommandBuild { - var this = std.mem.zeroes(WebsocketCommandBuild); +pub const WebsocketCommandManifest = packed struct { +/// id +id: u32 = 0, - this.id = try reader.readValue(u32); - return this; - } - pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - try writer.writeInt(this.id); - } - }; +pub fn decode(reader: anytype) anyerror!WebsocketCommandManifest { + var this = std.mem.zeroes(WebsocketCommandManifest); - pub const WebsocketCommandManifest = packed struct { - /// id - id: u32 = 0, + this.id = try reader.readValue(u32); + return this; +} - pub fn decode(reader: anytype) anyerror!WebsocketCommandManifest { - var this = std.mem.zeroes(WebsocketCommandManifest); +pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeInt(this.id); +} - this.id = try reader.readValue(u32); - return this; - } +}; - pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - try writer.writeInt(this.id); - } - }; +pub const WebsocketMessageBuildSuccess = struct { +/// id +id: u32 = 0, - pub const WebsocketMessageBuildSuccess = struct { - /// id - id: u32 = 0, +/// from_timestamp +from_timestamp: u32 = 0, - /// from_timestamp - from_timestamp: u32 = 0, +/// loader +loader: Loader, - /// loader - loader: Loader, +/// module_path +module_path: []const u8, - /// module_path - module_path: []const u8, +/// blob_length +blob_length: u32 = 0, - /// blob_length - blob_length: u32 = 0, - pub fn decode(reader: anytype) anyerror!WebsocketMessageBuildSuccess { - var this = std.mem.zeroes(WebsocketMessageBuildSuccess); +pub fn decode(reader: anytype) anyerror!WebsocketMessageBuildSuccess { + var this = std.mem.zeroes(WebsocketMessageBuildSuccess); - this.id = try reader.readValue(u32); - this.from_timestamp = try reader.readValue(u32); - this.loader = try reader.readValue(Loader); - this.module_path = try reader.readValue([]const u8); - this.blob_length = try reader.readValue(u32); - return this; - } + this.id = try reader.readValue(u32); + this.from_timestamp = try reader.readValue(u32); + this.loader = try reader.readValue(Loader); + this.module_path = try reader.readValue([]const u8); + this.blob_length = try reader.readValue(u32); + return this; +} - pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - try writer.writeInt(this.id); - try writer.writeInt(this.from_timestamp); - try writer.writeEnum(this.loader); - try writer.writeValue(this.module_path); - try writer.writeInt(this.blob_length); - } - }; +pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeInt(this.id); + try writer.writeInt(this.from_timestamp); + try writer.writeEnum(this.loader); + try writer.writeValue(this.module_path); + try writer.writeInt(this.blob_length); +} - pub const WebsocketMessageBuildFailure = struct { - /// id - id: u32 = 0, +}; - /// from_timestamp - from_timestamp: u32 = 0, +pub const WebsocketMessageBuildFailure = struct { +/// id +id: u32 = 0, - /// loader - loader: Loader, +/// from_timestamp +from_timestamp: u32 = 0, - /// module_path - module_path: []const u8, +/// loader +loader: Loader, - /// log - log: Log, +/// module_path +module_path: []const u8, - pub fn decode(reader: anytype) anyerror!WebsocketMessageBuildFailure { - var this = std.mem.zeroes(WebsocketMessageBuildFailure); +/// log +log: Log, - this.id = try reader.readValue(u32); - this.from_timestamp = try reader.readValue(u32); - this.loader = try reader.readValue(Loader); - this.module_path = try reader.readValue([]const u8); - this.log = try reader.readValue(Log); - return this; - } - pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - try writer.writeInt(this.id); - try writer.writeInt(this.from_timestamp); - try writer.writeEnum(this.loader); - try writer.writeValue(this.module_path); - try writer.writeValue(this.log); - } - }; +pub fn decode(reader: anytype) anyerror!WebsocketMessageBuildFailure { + var this = std.mem.zeroes(WebsocketMessageBuildFailure); - pub const DependencyManifest = struct { - /// ids - ids: []const u32, + this.id = try reader.readValue(u32); + this.from_timestamp = try reader.readValue(u32); + this.loader = try reader.readValue(Loader); + this.module_path = try reader.readValue([]const u8); + this.log = try reader.readValue(Log); + return this; +} - pub fn decode(reader: anytype) anyerror!DependencyManifest { - var this = std.mem.zeroes(DependencyManifest); +pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeInt(this.id); + try writer.writeInt(this.from_timestamp); + try writer.writeEnum(this.loader); + try writer.writeValue(this.module_path); + try writer.writeValue(this.log); +} - this.ids = try reader.readArray(u32); - return this; - } +}; - pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - try writer.writeArray(u32, this.ids); - } - }; +pub const DependencyManifest = struct { +/// ids +ids: []const u32, - pub const FileList = struct { - /// ptrs - ptrs: []const StringPointer, - /// files - files: []const u8, +pub fn decode(reader: anytype) anyerror!DependencyManifest { + var this = std.mem.zeroes(DependencyManifest); - pub fn decode(reader: anytype) anyerror!FileList { - var this = std.mem.zeroes(FileList); + this.ids = try reader.readArray(u32); + return this; +} - this.ptrs = try reader.readArray(StringPointer); - this.files = try reader.readValue([]const u8); - return this; - } +pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeArray(u32, this.ids); +} - pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - try writer.writeArray(StringPointer, this.ptrs); - try writer.writeValue(this.files); - } - }; +}; - pub const WebsocketMessageResolveIDs = struct { - /// id - id: []const u32, +pub const FileList = struct { +/// ptrs +ptrs: []const StringPointer, - /// list - list: FileList, +/// files +files: []const u8, - pub fn decode(reader: anytype) anyerror!WebsocketMessageResolveIDs { - var this = std.mem.zeroes(WebsocketMessageResolveIDs); - this.id = try reader.readArray(u32); - this.list = try reader.readValue(FileList); - return this; - } +pub fn decode(reader: anytype) anyerror!FileList { + var this = std.mem.zeroes(FileList); - pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - try writer.writeArray(u32, this.id); - try writer.writeValue(this.list); - } - }; + this.ptrs = try reader.readArray(StringPointer); + this.files = try reader.readValue([]const u8); + return this; +} - pub const WebsocketCommandResolveIDs = struct { - /// ptrs - ptrs: []const StringPointer, +pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeArray(StringPointer, this.ptrs); + try writer.writeValue(this.files); +} - /// files - files: []const u8, +}; - pub fn decode(reader: anytype) anyerror!WebsocketCommandResolveIDs { - var this = std.mem.zeroes(WebsocketCommandResolveIDs); +pub const WebsocketMessageResolveIDs = struct { +/// id +id: []const u32, - this.ptrs = try reader.readArray(StringPointer); - this.files = try reader.readValue([]const u8); - return this; - } +/// list +list: FileList, - pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - try writer.writeArray(StringPointer, this.ptrs); - try writer.writeValue(this.files); - } - }; - pub const WebsocketMessageManifestSuccess = struct { - /// id - id: u32 = 0, +pub fn decode(reader: anytype) anyerror!WebsocketMessageResolveIDs { + var this = std.mem.zeroes(WebsocketMessageResolveIDs); - /// module_path - module_path: []const u8, + this.id = try reader.readArray(u32); + this.list = try reader.readValue(FileList); + return this; +} - /// loader - loader: Loader, +pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeArray(u32, this.id); + try writer.writeValue(this.list); +} - /// manifest - manifest: DependencyManifest, +}; - pub fn decode(reader: anytype) anyerror!WebsocketMessageManifestSuccess { - var this = std.mem.zeroes(WebsocketMessageManifestSuccess); +pub const WebsocketCommandResolveIDs = struct { +/// ptrs +ptrs: []const StringPointer, - this.id = try reader.readValue(u32); - this.module_path = try reader.readValue([]const u8); - this.loader = try reader.readValue(Loader); - this.manifest = try reader.readValue(DependencyManifest); - return this; - } +/// files +files: []const u8, - pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - try writer.writeInt(this.id); - try writer.writeValue(this.module_path); - try writer.writeEnum(this.loader); - try writer.writeValue(this.manifest); - } - }; - pub const WebsocketMessageManifestFailure = struct { - /// id - id: u32 = 0, +pub fn decode(reader: anytype) anyerror!WebsocketCommandResolveIDs { + var this = std.mem.zeroes(WebsocketCommandResolveIDs); + + this.ptrs = try reader.readArray(StringPointer); + this.files = try reader.readValue([]const u8); + return this; +} - /// from_timestamp - from_timestamp: u32 = 0, +pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeArray(StringPointer, this.ptrs); + try writer.writeValue(this.files); +} - /// loader - loader: Loader, +}; - /// log - log: Log, +pub const WebsocketMessageManifestSuccess = struct { +/// id +id: u32 = 0, - pub fn decode(reader: anytype) anyerror!WebsocketMessageManifestFailure { - var this = std.mem.zeroes(WebsocketMessageManifestFailure); +/// module_path +module_path: []const u8, - this.id = try reader.readValue(u32); - this.from_timestamp = try reader.readValue(u32); - this.loader = try reader.readValue(Loader); - this.log = try reader.readValue(Log); - return this; - } +/// loader +loader: Loader, + +/// manifest +manifest: DependencyManifest, + + +pub fn decode(reader: anytype) anyerror!WebsocketMessageManifestSuccess { + var this = std.mem.zeroes(WebsocketMessageManifestSuccess); + + this.id = try reader.readValue(u32); + this.module_path = try reader.readValue([]const u8); + this.loader = try reader.readValue(Loader); + this.manifest = try reader.readValue(DependencyManifest); + return this; +} + +pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeInt(this.id); + try writer.writeValue(this.module_path); + try writer.writeEnum(this.loader); + try writer.writeValue(this.manifest); +} - pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - try writer.writeInt(this.id); - try writer.writeInt(this.from_timestamp); - try writer.writeEnum(this.loader); - try writer.writeValue(this.log); - } - }; }; +pub const WebsocketMessageManifestFailure = struct { +/// id +id: u32 = 0, + +/// from_timestamp +from_timestamp: u32 = 0, + +/// loader +loader: Loader, + +/// log +log: Log, + + +pub fn decode(reader: anytype) anyerror!WebsocketMessageManifestFailure { + var this = std.mem.zeroes(WebsocketMessageManifestFailure); + + this.id = try reader.readValue(u32); + this.from_timestamp = try reader.readValue(u32); + this.loader = try reader.readValue(Loader); + this.log = try reader.readValue(Log); + return this; +} + +pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeInt(this.id); + try writer.writeInt(this.from_timestamp); + try writer.writeEnum(this.loader); + try writer.writeValue(this.log); +} + +}; + + +}; + + const ExamplePackedStruct = packed struct { len: u32 = 0, offset: u32 = 0, diff --git a/src/env_loader.zig b/src/env_loader.zig new file mode 100644 index 000000000..9a4c6dde7 --- /dev/null +++ b/src/env_loader.zig @@ -0,0 +1,330 @@ +const std = @import("std"); +const logger = @import("./logger.zig"); +usingnamespace @import("./global.zig"); +const CodepointIterator = @import("./string_immutable.zig").CodepointIterator; + +const Variable = struct { + key: string, + value: string, +}; + +// i don't expect anyone to actually use the escape line feed character +const escLineFeed = 0x0C; +// arbitrary character that is invalid in a real text file +const implicitQuoteCharacter = 8; + +pub const Lexer = struct { + source: *const logger.Source, + iter: CodepointIterator, + _codepoint: CodePoint = 0, + current: usize = 0, + start: usize = 0, + end: usize = 0, + has_nested_values: bool = false, + has_newline_before: bool = true, + + pub inline fn codepoint(this: *Lexer) CodePoint { + return this._codepoint; + } + + pub fn step(this: *Lexer) void { + @call(.{ .modifier = .always_inline }, CodepointIterator.nextCodepointNoReturn, .{&this.iter}); + this._codepoint = this.iter.c; + this.current += 1; + } + + pub fn eatValue( + lexer: *Lexer, + comptime quote: CodePoint, + ) string { + const start = lexer.current - 1; + lexer.step(); + + var last_non_space: usize = 0; + while (true) { + switch (lexer.codepoint()) { + '\\' => { + lexer.step(); + // Handle Windows CRLF + last_non_space += 1; + if (lexer.codepoint() == '\r') { + lexer.step(); + last_non_space += 1; + if (lexer.codepoint() == '\n') { + lexer.step(); + last_non_space += 1; + } + continue; + } + }, + -1 => { + lexer.end = lexer.current; + + return lexer.source.contents[start..][0 .. last_non_space + 1]; + }, + '$' => { + lexer.has_nested_values = true; + last_non_space += 1; + }, + + '#' => { + lexer.step(); + lexer.eatComment(); + + return lexer.source.contents[start..][0 .. last_non_space + 1]; + }, + + '\n', '\r', escLineFeed => { + switch (comptime quote) { + '\'' => { + lexer.end = lexer.current; + lexer.step(); + return lexer.source.contents[start .. lexer.end - 1]; + }, + implicitQuoteCharacter => { + lexer.end = lexer.current; + lexer.step(); + + return lexer.source.contents[start..][0 .. last_non_space + 1]; + }, + '"' => { + // We keep going + + }, + else => {}, + } + }, + quote => { + lexer.end = lexer.current; + lexer.step(); + return lexer.source.contents[start..lexer.end]; + }, + ' ' => {}, + else => { + last_non_space += 1; + }, + } + + lexer.step(); + } + unreachable; + } + + pub fn eatComment(this: *Lexer) void { + while (true) { + switch (this.codepoint()) { + '\r' => { + this.step(); + if (this.codepoint() == '\n') { + return; + } + }, + '\n' => { + this.step(); + return; + }, + -1 => { + return; + }, + else => { + this.step(); + }, + } + } + } + + // const NEWLINE = '\n' + // const RE_INI_KEY_VAL = /^\s*([\w.-]+)\s*=\s*(.*)?\s*$/ + // const RE_NEWLINES = /\\n/g + // const NEWLINES_MATCH = /\r\n|\n|\r/ + pub fn next(this: *Lexer) ?Variable { + if (this.end == 0) this.step(); + + const start = this.start; + + this.has_newline_before = this.end == 0; + + restart: while (true) { + switch (this.codepoint()) { + 0, -1 => { + return null; + }, + '#' => { + this.step(); + + this.eatComment(); + continue :restart; + }, + '\r', '\n', 0x2028, 0x2029 => { + this.step(); + this.has_newline_before = true; + continue; + }, + + // Valid keys: + 'a'...'z', 'A'...'Z', '0'...'9', '_', '-', '.' => { + this.start = this.current - 1; + this.step(); + var last_non_space: usize = 0; + while (true) { + switch (this.codepoint()) { + + // to match npm's "dotenv" behavior, we ignore lines that don't have an equals + '\r', '\n', escLineFeed => { + this.end = this.current; + this.step(); + continue :restart; + }, + 0, -1 => { + this.end = this.current; + return Variable{ .key = this.source.contents[this.start..][0 .. last_non_space + 1], .value = "" }; + }, + 'a'...'z', 'A'...'Z', '0'...'9', '_', '-', '.' => { + last_non_space += 1; + }, + '=' => { + this.end = this.current; + const key = this.source.contents[this.start..][0 .. last_non_space + 1]; + if (key.len == 0) return null; + this.step(); + + inner: while (true) { + switch (this.codepoint()) { + '"' => { + const value = this.eatValue('"'); + return Variable{ .key = key, .value = value }; + }, + '\'' => { + const value = this.eatValue('\''); + return Variable{ .key = key, .value = value }; + }, + 0, -1 => { + return Variable{ .key = key, .value = "" }; + }, + '\r', '\n', escLineFeed => { + this.step(); + return Variable{ .key = key, .value = "" }; + }, + // consume unquoted leading spaces + ' ' => { + this.step(); + continue :inner; + }, + // we treat everything else the same as if it were wrapped in single quotes + // except we don't terminate on that character + else => { + const value = this.eatValue(implicitQuoteCharacter); + return Variable{ .key = key, .value = value }; + }, + } + } + }, + ' ' => {}, + else => { + last_non_space += 1; + }, + } + this.step(); + } + }, + else => {}, + } + + this.step(); + } + } + + pub fn init(source: *const logger.Source) Lexer { + return Lexer{ + .source = source, + .iter = CodepointIterator{ .bytes = source.contents, .i = 0 }, + }; + } +}; + +pub const Parser = struct { + pub fn parse(source: *const logger.Source, allocator: *std.mem.Allocator) Map { + var map = Map.init(allocator); + + var lexer = Lexer.init(source); + while (lexer.next()) |variable| { + map.put(variable.key, variable.value) catch {}; + } + + return map; + } +}; + +pub const Map = struct { + const HashTable = std.StringArrayHashMap(string); + + map: HashTable, + + pub inline fn init(allocator: *std.mem.Allocator) Map { + return Map{ .map = HashTable.init(allocator) }; + } + + pub inline fn iter(this: *Map) !HashTable.Iterator { + return this.map.iterator(); + } + + pub inline fn put(this: *Map, key: string, value: string) !void { + try this.map.put(key, value); + } + + pub inline fn get( + this: *const Map, + key: string, + ) ?string { + return this.map.get(key); + } + + pub inline fn putDefault(this: *Map, key: string, value: string) !void { + _ = try this.map.getOrPutValue(key, value); + } +}; + +const expectString = std.testing.expectEqualStrings; +const expect = std.testing.expect; +test "DotEnv Loader" { + const VALID_ENV = + \\API_KEY=verysecure + \\process.env.WAT=ABCDEFGHIJKLMNOPQRSTUVWXYZZ10239457123 + \\DOUBLE-QUOTED_SHOULD_PRESERVE_NEWLINES=" + \\ya + \\" + \\DOUBLE_QUOTES_ESCAPABLE="\"yoooo\"" + \\SINGLE_QUOTED_SHOULDNT_PRESERVE_NEWLINES='yo + \\' + \\ + \\SINGLE_QUOTED_PRESERVES_QUOTES='yo' + \\ + \\# Line Comment + \\UNQUOTED_SHOULDNT_PRESERVE_NEWLINES_AND_TRIMS_TRAILING_SPACE=yo # Inline Comment + \\ + \\ LEADING_SPACE_IS_TRIMMED=yes + \\ + \\LEADING_SPACE_IN_UNQUOTED_VALUE_IS_TRIMMED= yes + \\ + \\LINES_WITHOUT_EQUAL_ARE_IGNORED + \\ + \\NO_VALUE_IS_EMPTY_STRING= + \\LINES_WITHOUT_EQUAL_ARE_IGNORED + \\ + \\IGNORING_DOESNT_BREAK_OTHER_LINES='yes' + \\ + ; + const source = logger.Source.initPathString(".env", VALID_ENV); + const map = Parser.parse(&source, std.heap.c_allocator); + try expectString(map.get("API_KEY").?, "verysecure"); + try expectString(map.get("process.env.WAT").?, "ABCDEFGHIJKLMNOPQRSTUVWXYZZ10239457123"); + try expectString(map.get("DOUBLE-QUOTED_SHOULD_PRESERVE_NEWLINES").?, "\"\nya\n\""); + try expectString(map.get("SINGLE_QUOTED_SHOULDNT_PRESERVE_NEWLINES").?, "'yo"); + try expectString(map.get("SINGLE_QUOTED_PRESERVES_QUOTES").?, "'yo'"); + try expectString(map.get("UNQUOTED_SHOULDNT_PRESERVE_NEWLINES_AND_TRIMS_TRAILING_SPACE").?, "yo"); + try expect(map.get("LINES_WITHOUT_EQUAL_ARE_IGNORED") == null); + try expectString(map.get("LEADING_SPACE_IS_TRIMMED").?, "yes"); + try expect(map.get("NO_VALUE_IS_EMPTY_STRING").?.len == 0); + try expectString(map.get("IGNORING_DOESNT_BREAK_OTHER_LINES").?, "'yes'"); + try expectString(map.get("LEADING_SPACE_IN_UNQUOTED_VALUE_IS_TRIMMED").?, "yes"); +} diff --git a/src/feature_flags.zig b/src/feature_flags.zig index f2fa69884..3cbd5787a 100644 --- a/src/feature_flags.zig +++ b/src/feature_flags.zig @@ -34,6 +34,7 @@ pub const css_supports_fence = true; pub const disable_entry_cache = false; pub const enable_bytecode_caching = false; +pub const react_specific_warnings = true; // Disabled due to concurrency bug I don't have time to fix right now. // I suspect it's like 3 undefined memory issues. // This was the command I ran to reproduce it: diff --git a/src/http.zig b/src/http.zig index ffb7a3d72..b60487fbc 100644 --- a/src/http.zig +++ b/src/http.zig @@ -134,8 +134,8 @@ pub const RequestContext = struct { pub fn getFullURL(this: *RequestContext) [:0]const u8 { if (this.full_url.len == 0) { - if (this.bundler.options.origin.len > 0) { - this.full_url = std.fmt.allocPrintZ(this.allocator, "{s}{s}", .{ this.bundler.options.origin, this.request.path }) catch unreachable; + if (this.bundler.options.origin.isAbsolute()) { + this.full_url = std.fmt.allocPrintZ(this.allocator, "{s}{s}", .{ this.bundler.options.origin.origin, this.request.path }) catch unreachable; } else { this.full_url = this.allocator.dupeZ(u8, this.request.path) catch unreachable; } @@ -733,6 +733,7 @@ pub const RequestContext = struct { Output.flush(); return; }; + vm.bundler.configureRouter() catch {}; std.debug.assert(JavaScript.VirtualMachine.vm_loaded); javascript_vm = vm; @@ -740,62 +741,67 @@ pub const RequestContext = struct { std.debug.assert(boot.len > 0); defer vm.deinit(); vm.watcher = handler.watcher; - var entry_point = boot; - if (!std.fs.path.isAbsolute(entry_point)) { - const resolved_entry_point = try vm.bundler.resolver.resolve( - std.fs.path.dirname(boot) orelse vm.bundler.fs.top_level_dir, - vm.bundler.normalizeEntryPointPath(boot), - .entry_point, - ); - entry_point = resolved_entry_point.path_pair.primary.text; - } - - var load_result = vm.loadEntryPoint( - entry_point, - ) catch |err| { - Output.prettyErrorln( - "<r>JavaScript VM failed to start.\n<red>{s}:<r> while loading <r><b>\"\"", - .{ @errorName(err), entry_point }, - ); - - if (channel.tryReadItem() catch null) |item| { - item.ctx.sendInternalError(error.JSFailedToStart) catch {}; - item.ctx.arena.deinit(); + { + defer vm.flush(); + + var entry_point = boot; + if (!std.fs.path.isAbsolute(entry_point)) { + const resolved_entry_point = try vm.bundler.resolver.resolve( + std.fs.path.dirname(boot) orelse vm.bundler.fs.top_level_dir, + vm.bundler.normalizeEntryPointPath(boot), + .entry_point, + ); + entry_point = resolved_entry_point.path_pair.primary.text; } - return; - }; - switch (load_result.status(vm.global.vm())) { - JSPromise.Status.Fulfilled => {}, - else => { + var load_result = vm.loadEntryPoint( + entry_point, + ) catch |err| { Output.prettyErrorln( - "JavaScript VM failed to start", - .{}, + "<r>JavaScript VM failed to start.\n<red>{s}:<r> while loading <r><b>\"\"", + .{ @errorName(err), entry_point }, ); - var result = load_result.result(vm.global.vm()); - - vm.defaultErrorHandler(result); if (channel.tryReadItem() catch null) |item| { item.ctx.sendInternalError(error.JSFailedToStart) catch {}; item.ctx.arena.deinit(); } return; - }, - } + }; + + switch (load_result.status(vm.global.vm())) { + JSPromise.Status.Fulfilled => {}, + else => { + Output.prettyErrorln( + "JavaScript VM failed to start", + .{}, + ); + var result = load_result.result(vm.global.vm()); + + vm.defaultErrorHandler(result); - if (vm.event_listeners.count() == 0) { - Output.prettyErrorln("<r><red>error<r>: Framework didn't run <b><cyan>addEventListener(\"fetch\", callback)<r>, which means it can't accept HTTP requests.\nShutting down JS.", .{}); - if (channel.tryReadItem() catch null) |item| { - item.ctx.sendInternalError(error.JSFailedToStart) catch {}; - item.ctx.arena.deinit(); + if (channel.tryReadItem() catch null) |item| { + item.ctx.sendInternalError(error.JSFailedToStart) catch {}; + item.ctx.arena.deinit(); + } + return; + }, + } + + if (vm.event_listeners.count() == 0) { + Output.prettyErrorln("<r><red>error<r>: Framework didn't run <b><cyan>addEventListener(\"fetch\", callback)<r>, which means it can't accept HTTP requests.\nShutting down JS.", .{}); + if (channel.tryReadItem() catch null) |item| { + item.ctx.sendInternalError(error.JSFailedToStart) catch {}; + item.ctx.arena.deinit(); + } + return; } - return; } js_ast.Stmt.Data.Store.reset(); js_ast.Expr.Data.Store.reset(); JavaScript.Wundle.flushCSSImports(); + vm.flush(); try runLoop(vm); } @@ -805,6 +811,7 @@ pub const RequestContext = struct { while (true) { defer { + JavaScript.VirtualMachine.vm.flush(); std.debug.assert(ZigGlobalObject.resetModuleRegistryMap(vm.global, module_map)); js_ast.Stmt.Data.Store.reset(); js_ast.Expr.Data.Store.reset(); @@ -1573,7 +1580,7 @@ pub const RequestContext = struct { break :brk try ctx.bundler.buildFile( &ctx.log, ctx.allocator, - ctx.url.pathWithoutOrigin(ctx.bundler.options.origin), + ctx.url.pathWithoutAssetPrefix(ctx.bundler.options.routes.asset_prefix_path), ctx.url.extname, true, ); @@ -1581,7 +1588,7 @@ pub const RequestContext = struct { break :brk try ctx.bundler.buildFile( &ctx.log, ctx.allocator, - ctx.url.pathWithoutOrigin(ctx.bundler.options.origin), + ctx.url.pathWithoutAssetPrefix(ctx.bundler.options.routes.asset_prefix_path), ctx.url.extname, false, ); @@ -1743,7 +1750,16 @@ pub const Server = struct { // try listener.ack(true); - try listener.bind(ip.Address.initIPv4(IPv4.unspecified, 9000)); + var port: u16 = 3000; + + if (server.bundler.options.origin.getPort()) |_port| { + port = _port; + } + + try listener.bind(ip.Address.initIPv4( + IPv4.unspecified, + port, + )); try listener.listen(1280); const addr = try listener.getLocalAddress(); diff --git a/src/http/url_path.zig b/src/http/url_path.zig index e82d5601a..0a4d35069 100644 --- a/src/http/url_path.zig +++ b/src/http/url_path.zig @@ -14,11 +14,11 @@ const toMutable = allocators.constStrToU8; // TODO: use a real URL parser // this treats a URL like /_next/ identically to / -pub fn pathWithoutOrigin(this: *const URLPath, _origin: string) string { - if (_origin.len == 0) return this.path; - const leading_slash_offset: usize = if (_origin[0] == '/') 1 else 0; +pub fn pathWithoutAssetPrefix(this: *const URLPath, asset_prefix: string) string { + if (asset_prefix.len == 0) return this.path; + const leading_slash_offset: usize = if (asset_prefix[0] == '/') 1 else 0; const base = this.path; - const origin = _origin[leading_slash_offset..]; + const origin = asset_prefix[leading_slash_offset..]; return if (base.len >= origin.len and strings.eql(base[0..origin.len], origin)) base[origin.len..] else base; } diff --git a/src/javascript/jsc/api/router.zig b/src/javascript/jsc/api/router.zig index 84562fee3..647dee2ea 100644 --- a/src/javascript/jsc/api/router.zig +++ b/src/javascript/jsc/api/router.zig @@ -358,6 +358,29 @@ pub fn createQueryObject(ctx: js.JSContextRef, map: *QueryStringMap, exception: } threadlocal var entry_point_tempbuf: [std.fs.MAX_PATH_BYTES]u8 = undefined; +pub fn getScriptSrcString( + comptime Writer: type, + writer: Writer, + file_path: string, + client_framework_enabled: bool, +) void { + // We don't store the framework config including the client parts in the server + // instead, we just store a boolean saying whether we should generate this whenever the script is requested + // this is kind of bad. we should consider instead a way to inline the contents of the script. + if (client_framework_enabled) { + JavaScript.Wundle.getPublicPath( + Bundler.ClientEntryPoint.generateEntryPointPath( + &entry_point_tempbuf, + Fs.PathName.init(file_path), + ), + ScriptSrcStream.Writer, + writer, + ); + } else { + JavaScript.Wundle.getPublicPath(file_path, ScriptSrcStream.Writer, writer); + } +} + pub fn getScriptSrc( this: *Router, ctx: js.JSContextRef, @@ -366,22 +389,7 @@ pub fn getScriptSrc( exception: js.ExceptionRef, ) js.JSValueRef { const src = this.script_src orelse brk: { - // We don't store the framework config including the client parts in the server - // instead, we just store a boolean saying whether we should generate this whenever the script is requested - // this is kind of bad. we should consider instead a way to inline the contents of the script. - var writer = this.script_src_buf_writer.writer(); - if (this.route.client_framework_enabled) { - JavaScript.Wundle.getPublicPath( - Bundler.ClientEntryPoint.generateEntryPointPath( - &entry_point_tempbuf, - Fs.PathName.init(this.route.file_path), - ), - ScriptSrcStream.Writer, - writer, - ); - } else { - JavaScript.Wundle.getPublicPath(this.route.file_path, ScriptSrcStream.Writer, writer); - } + getScriptSrcString(ScriptSrcStream.Writer, this.script_src_buf_writer.writer(), this.route.file_path, this.route.client_framework_enabled); break :brk this.script_src_buf[0..this.script_src_buf_writer.pos]; }; diff --git a/src/javascript/jsc/javascript.zig b/src/javascript/jsc/javascript.zig index 0b96ca3ed..9945b9283 100644 --- a/src/javascript/jsc/javascript.zig +++ b/src/javascript/jsc/javascript.zig @@ -39,6 +39,8 @@ pub const Wundle = struct { threadlocal var css_imports_buf: std.ArrayList(u8) = undefined; threadlocal var css_imports_buf_loaded: bool = false; + threadlocal var routes_list_strings: [1024]ZigString = undefined; + pub fn onImportCSS( resolve_result: *const Resolver.Result, import_record: *ImportRecord, @@ -97,7 +99,7 @@ pub const Wundle = struct { prop: js.JSStringRef, exception: js.ExceptionRef, ) js.JSValueRef { - return ZigString.init(VirtualMachine.vm.bundler.options.origin).toValue(VirtualMachine.vm.global).asRef(); + return ZigString.init(VirtualMachine.vm.bundler.options.origin.origin).toValue(VirtualMachine.vm.global).asRef(); } pub fn getMain( @@ -110,28 +112,24 @@ pub const Wundle = struct { return ZigString.init(VirtualMachine.vm.main).toValue(VirtualMachine.vm.global).asRef(); } - pub fn getRoutesDir( + pub fn getAssetPrefix( this: void, ctx: js.JSContextRef, thisObject: js.JSValueRef, prop: js.JSStringRef, exception: js.ExceptionRef, ) js.JSValueRef { - if (!VirtualMachine.vm.bundler.options.routes.routes_enabled or VirtualMachine.vm.bundler.options.routes.dir.len == 0) { - return js.JSValueMakeUndefined(ctx); - } - - return ZigString.init(VirtualMachine.vm.bundler.options.routes.dir).toValue(VirtualMachine.vm.global).asRef(); + return ZigString.init(VirtualMachine.vm.bundler.options.routes.asset_prefix_path).toValue(VirtualMachine.vm.global).asRef(); } - pub fn routeByName( + pub fn getRoutesDir( this: void, ctx: js.JSContextRef, thisObject: js.JSValueRef, prop: js.JSStringRef, exception: js.ExceptionRef, ) js.JSValueRef { - if (!VirtualMachine.vm.bundler.options.routes.routes_enabled) { + if (!VirtualMachine.vm.bundler.options.routes.routes_enabled or VirtualMachine.vm.bundler.options.routes.dir.len == 0) { return js.JSValueMakeUndefined(ctx); } @@ -155,15 +153,39 @@ pub const Wundle = struct { return JSValue.createStringArray(VirtualMachine.vm.global, styles.ptr, styles.len).asRef(); } + pub fn getRouteFiles( + this: void, + ctx: js.JSContextRef, + function: js.JSObjectRef, + thisObject: js.JSObjectRef, + arguments: []const js.JSValueRef, + exception: js.ExceptionRef, + ) js.JSValueRef { + if (VirtualMachine.vm.bundler.router == null) return js.JSValueMakeNull(ctx); + + const router = &(VirtualMachine.vm.bundler.router orelse unreachable); + const list = router.getEntryPointsWithBuffer(VirtualMachine.vm.allocator, false) catch unreachable; + VirtualMachine.vm.flush_list.append(list.buffer) catch {}; + defer VirtualMachine.vm.allocator.free(list.entry_points); + + for (routes_list_strings[0..std.math.min(list.entry_points.len, routes_list_strings.len)]) |_, i| { + routes_list_strings[i] = ZigString.init(list.entry_points[i]); + } + + const ref = JSValue.createStringArray(VirtualMachine.vm.global, &routes_list_strings, list.entry_points.len).asRef(); + return ref; + } + pub fn getPublicPath(to: string, comptime Writer: type, writer: Writer) void { const relative_path = VirtualMachine.vm.bundler.fs.relativeTo(to); - if (VirtualMachine.vm.bundler.options.origin.len > 0) { - writer.print( - "{s}/{s}", - .{ - std.mem.trimRight(u8, VirtualMachine.vm.bundler.options.origin, "/"), - std.mem.trimLeft(u8, relative_path, "/"), - }, + if (VirtualMachine.vm.bundler.options.origin.isAbsolute()) { + VirtualMachine.vm.bundler.options.origin.joinWrite( + Writer, + writer, + VirtualMachine.vm.bundler.options.routes.asset_prefix_path, + "", + relative_path, + "", ) catch unreachable; } else { writer.writeAll(std.mem.trimLeft(u8, relative_path, "/")) catch unreachable; @@ -194,6 +216,13 @@ pub const Wundle = struct { .@"return" = "string[]", }, }, + .getRouteFiles = .{ + .rfn = Wundle.getRouteFiles, + .ts = d.ts{ + .name = "getRouteFiles", + .@"return" = "string[]", + }, + }, }, .{ .Route = Router.Instance.GetClass(void){}, @@ -213,6 +242,10 @@ pub const Wundle = struct { .get = getRoutesDir, .ts = d.ts{ .name = "routesDir", .@"return" = "string" }, }, + .assetPrefix = .{ + .get = getAssetPrefix, + .ts = d.ts{ .name = "assetPrefix", .@"return" = "string" }, + }, }, ); }; @@ -240,6 +273,8 @@ pub const VirtualMachine = struct { main: string = "", process: js.JSObjectRef = null, + flush_list: std.ArrayList(string), + pub var vm_loaded = false; pub var vm: *VirtualMachine = undefined; @@ -274,6 +309,7 @@ pub const VirtualMachine = struct { .console = console, .node_modules = bundler.options.node_modules_bundle, .log = log, + .flush_list = std.ArrayList(string).init(allocator), }; VirtualMachine.vm.bundler.configureLinker(); @@ -305,6 +341,13 @@ pub const VirtualMachine = struct { threadlocal var source_code_printer: js_printer.BufferPrinter = undefined; threadlocal var source_code_printer_loaded: bool = false; + pub fn flush(this: *VirtualMachine) void { + for (this.flush_list.items) |item| { + this.allocator.free(item); + } + this.flush_list.shrinkRetainingCapacity(0); + } + inline fn _fetch( global: *JSGlobalObject, _specifier: string, @@ -537,12 +580,23 @@ pub const VirtualMachine = struct { res.* = ErrorableZigString.ok(ZigString.init(result.path)); } - pub fn normalizeSpecifier(slice: string) string { + pub fn normalizeSpecifier(slice_: string) string { + var slice = slice_; if (slice.len == 0) return slice; - if (VirtualMachine.vm.bundler.options.origin.len > 0) { - if (strings.startsWith(slice, VirtualMachine.vm.bundler.options.origin)) { - return slice[VirtualMachine.vm.bundler.options.origin.len..]; + if (strings.startsWith(slice, VirtualMachine.vm.bundler.options.origin.host)) { + slice = slice[VirtualMachine.vm.bundler.options.origin.host.len..]; + } + + if (VirtualMachine.vm.bundler.options.origin.path.len > 1) { + if (strings.startsWith(slice, VirtualMachine.vm.bundler.options.origin.path)) { + slice = slice[VirtualMachine.vm.bundler.options.origin.path.len..]; + } + } + + if (VirtualMachine.vm.bundler.options.routes.asset_prefix_path.len > 0) { + if (strings.startsWith(slice, VirtualMachine.vm.bundler.options.routes.asset_prefix_path)) { + slice = slice[VirtualMachine.vm.bundler.options.routes.asset_prefix_path.len..]; } } @@ -561,6 +615,15 @@ pub const VirtualMachine = struct { return; } + if (log.warnings > 0) { + var writer = Output.errorWriter(); + for (log.msgs.items) |msg| { + if (msg.kind == .warn) { + msg.writeFormat(writer) catch {}; + } + } + } + ret.result.value = result; ret.success = true; } diff --git a/src/js_ast.zig b/src/js_ast.zig index 8797e4c62..8e388a103 100644 --- a/src/js_ast.zig +++ b/src/js_ast.zig @@ -1042,7 +1042,7 @@ pub const E = struct { }; pub const Object = struct { - properties: []G.Property, + properties: []G.Property = &[_]G.Property{}, comma_after_spread: ?logger.Loc = null, is_single_line: bool = false, is_parenthesized: bool = false, @@ -2098,6 +2098,44 @@ pub const Expr = struct { } } + pub fn joinAllWithCommaCallback(all: []Expr, comptime Context: type, ctx: Context, callback: (fn (ctx: anytype, expr: anytype) ?Expr), allocator: *std.mem.Allocator) ?Expr { + std.debug.assert(all.len > 0); + switch (all.len) { + 1 => { + return callback(ctx, all[0]); + }, + 2 => { + return Expr.joinWithComma( + callback(ctx, all[0]) orelse Expr{ + .data = .{ .e_missing = .{} }, + .loc = all[0].loc, + }, + callback(ctx, all[1]) orelse Expr{ + .data = .{ .e_missing = .{} }, + .loc = all[1].loc, + }, + allocator, + ); + }, + else => { + var i: usize = 1; + var expr = callback(ctx, all[0]) orelse Expr{ + .data = .{ .e_missing = .{} }, + .loc = all[0].loc, + }; + + while (i < all.len) : (i += 1) { + expr = Expr.joinWithComma(expr, callback(ctx, all[i]) orelse Expr{ + .data = .{ .e_missing = .{} }, + .loc = all[i].loc, + }, allocator); + } + + return expr; + }, + } + } + pub fn jsonStringify(self: *const @This(), options: anytype, writer: anytype) !void { return try std.json.stringify(Serializable{ .@"type" = std.meta.activeTag(self.data), .object = "expr", .value = self.data, .loc = self.loc }, options, writer); } diff --git a/src/js_lexer.zig b/src/js_lexer.zig index a687739d4..ee80c6fb6 100644 --- a/src/js_lexer.zig +++ b/src/js_lexer.zig @@ -18,6 +18,7 @@ pub const StrictModeReservedWords = tables.StrictModeReservedWords; pub const PropertyModifierKeyword = tables.PropertyModifierKeyword; pub const TypescriptStmtKeyword = tables.TypescriptStmtKeyword; pub const TypeScriptAccessibilityModifier = tables.TypeScriptAccessibilityModifier; +pub const ChildlessJSXTags = tables.ChildlessJSXTags; fn notimpl() noreturn { Global.panic("not implemented yet!", .{}); diff --git a/src/js_lexer_tables.zig b/src/js_lexer_tables.zig index 0a49a268b..41d3cf352 100644 --- a/src/js_lexer_tables.zig +++ b/src/js_lexer_tables.zig @@ -535,6 +535,26 @@ pub const TypescriptStmtKeyword = enum { pub const JSXEntityMap = std.StringHashMap(CodePoint); +// Error: meta is a void element tag and must neither have `children` nor use `dangerouslySetInnerHTML`. +pub const ChildlessJSXTags = std.ComptimeStringMap(void, .{ + .{ "area", void }, + .{ "base", void }, + .{ "br", void }, + .{ "col", void }, + .{ "embed", void }, + .{ "hr", void }, + .{ "img", void }, + .{ "input", void }, + .{ "keygen", void }, + .{ "link", void }, + .{ "meta", void }, + .{ "param", void }, + .{ "source", void }, + .{ "track", void }, + .{ "wbr", void }, + .{ "menuitem", void }, +}); + pub var jsxEntity: JSXEntityMap = undefined; var has_loaded_jsx_map = false; diff --git a/src/js_parser/js_parser.zig b/src/js_parser/js_parser.zig index f6b59141c..4bc70eb01 100644 --- a/src/js_parser/js_parser.zig +++ b/src/js_parser/js_parser.zig @@ -769,7 +769,7 @@ pub const SideEffects = enum(u2) { // A call that has been marked "__PURE__" can be removed if all arguments // can be removed. The annotation causes us to ignore the target. if (call.can_be_unwrapped_if_unused) { - return Expr.joinAllWithComma(call.args, p.allocator); + return Expr.joinAllWithCommaCallback(call.args, @TypeOf(p), p, simpifyUnusedExpr, p.allocator); } }, @@ -802,7 +802,7 @@ pub const SideEffects = enum(u2) { // the right expression can be completely removed. Otherwise, the left // expression is important for the branch. bin.right = simpifyUnusedExpr(p, bin.right) orelse bin.right.toEmpty(); - if (!bin.right.isEmpty()) { + if (bin.right.isEmpty()) { return simpifyUnusedExpr(p, bin.left); } }, @@ -10374,7 +10374,7 @@ pub fn NewParser( p.panic("Unexpected private identifier. This is an internal error - not your fault.", .{}); }, .e_jsx_element => |e_| { - const tag = tagger: { + const tag: Expr = tagger: { if (e_.tag) |_tag| { break :tagger p.visitExpr(_tag); } else { @@ -10397,13 +10397,26 @@ pub fn NewParser( } const runtime = if (p.options.jsx.runtime == .automatic and !e_.flags.is_key_before_rest) options.JSX.Runtime.automatic else options.JSX.Runtime.classic; + var children_count = e_.children.len; + + const is_childless_tag = FeatureFlags.react_specific_warnings and children_count > 0 and tag.data == .e_string and tag.data.e_string.isUTF8() and js_lexer.ChildlessJSXTags.has(tag.data.e_string.utf8); + + if (is_childless_tag) { + children_count = 0; + } + + if (children_count != e_.children.len) { + // Error: meta is a void element tag and must neither have `children` nor use `dangerouslySetInnerHTML`. + // ^ from react-dom + p.log.addWarningFmt(p.source, tag.loc, p.allocator, "<{s} /> is a void element and must not have \"children\"", .{tag.data.e_string.utf8}) catch {}; + } // TODO: maybe we should split these into two different AST Nodes // That would reduce the amount of allocations a little switch (runtime) { .classic => { // Arguments to createElement() - const args = p.allocator.alloc(Expr, 1 + e_.children.len) catch unreachable; + const args = p.allocator.alloc(Expr, 1 + children_count) catch unreachable; var i: usize = 1; if (e_.properties.len > 0) { if (e_.key) |key| { @@ -10417,7 +10430,7 @@ pub fn NewParser( args[0] = p.e(E.Null{}, expr.loc); } - for (e_.children) |child| { + for (e_.children[0..children_count]) |child| { args[i] = p.visitExpr(child); i += 1; } @@ -10444,12 +10457,11 @@ pub fn NewParser( // ...props, // children: [] // } - for (e_.children) |child, i| { + for (e_.children[0..children_count]) |child, i| { e_.children[i] = p.visitExpr(child); } const children_key = Expr{ .data = jsxChildrenKeyData, .loc = expr.loc }; - // props.append(G.Property{ .key = children_key, .value = p.e(E.Array{ diff --git a/src/js_printer.zig b/src/js_printer.zig index 8a5c81c8c..fa51171d8 100644 --- a/src/js_printer.zig +++ b/src/js_printer.zig @@ -2838,12 +2838,6 @@ pub fn NewPrinter( p.printLoadFromBundleWithoutCall(s.import_record_index); - if (!record.contains_import_star) { - p.print(" as "); - - p.printSymbol(s.namespace_ref); - } - p.print("} from "); p.printQuotedUTF8(record.path.text, false); p.printSemicolonAfterStatement(); @@ -2867,11 +2861,8 @@ pub fn NewPrinter( } p.print("} = "); - if (!record.contains_import_star) { - p.printSymbol(s.namespace_ref); - } else { - p.printLoadFromBundleWithoutCall(s.import_record_index); - } + p.printLoadFromBundleWithoutCall(s.import_record_index); + p.print("()"); p.printSemicolonAfterStatement(); } else if (s.default_name) |default_name| { @@ -2883,11 +2874,7 @@ pub fn NewPrinter( p.printSymbol(default_name.ref.?); p.print("} = "); - if (!record.contains_import_star) { - p.printSymbol(s.namespace_ref); - } else { - p.printLoadFromBundleWithoutCall(s.import_record_index); - } + p.printLoadFromBundleWithoutCall(s.import_record_index); p.print("()"); p.printSemicolonAfterStatement(); @@ -2902,7 +2889,6 @@ pub fn NewPrinter( return; } - p.print("import"); p.printSpace(); diff --git a/src/linker.zig b/src/linker.zig index 5073e88cf..018db3528 100644 --- a/src/linker.zig +++ b/src/linker.zig @@ -460,6 +460,7 @@ pub fn NewLinker(comptime BundlerType: type) type { }, .relative => { var relative_name = linker.fs.relative(source_dir, source_path); + var pretty: string = undefined; if (use_hashed_name) { var basepath = Fs.Path.init(source_path); @@ -529,35 +530,13 @@ pub fn NewLinker(comptime BundlerType: type) type { basename = try linker.getHashedFilename(basepath, null); } - const needs_slash = dirname.len > 0 and dirname[dirname.len - 1] != '/'; - - if (needs_slash) { - const absolute_url = try std.fmt.allocPrint( - linker.allocator, - "{s}{s}/{s}{s}", - .{ - linker.options.origin, - dirname, - basename, - absolute_pathname.ext, - }, - ); - - return Fs.Path.initWithPretty(absolute_url, absolute_url); - } else { - const absolute_url = try std.fmt.allocPrint( - linker.allocator, - "{s}{s}{s}{s}", - .{ - linker.options.origin, - dirname, - basename, - absolute_pathname.ext, - }, - ); - - return Fs.Path.initWithPretty(absolute_url, absolute_url); - } + return Fs.Path.init(try linker.options.origin.joinAlloc( + linker.allocator, + linker.options.routes.asset_prefix_path, + dirname, + basename, + absolute_pathname.ext, + )); }, else => unreachable, diff --git a/src/logger.zig b/src/logger.zig index 08be0d70d..9d1db56e6 100644 --- a/src/logger.zig +++ b/src/logger.zig @@ -447,7 +447,7 @@ pub const Log = struct { pub fn addWarningFmt(log: *Log, source: ?*const Source, l: Loc, allocator: *std.mem.Allocator, comptime text: string, args: anytype) !void { log.warnings += 1; try log.addMsg(Msg{ - .kind = .err, + .kind = .warn, .data = rangeData(source, Range{ .loc = l }, std.fmt.allocPrint(allocator, text, args) catch unreachable), }); } diff --git a/src/options.zig b/src/options.zig index a4302a703..a9211f2a2 100644 --- a/src/options.zig +++ b/src/options.zig @@ -10,6 +10,7 @@ const Api = api.Api; const defines = @import("./defines.zig"); const resolve_path = @import("./resolver/resolve_path.zig"); const NodeModuleBundle = @import("./node_module_bundle.zig").NodeModuleBundle; +const URL = @import("./query_string_map.zig").URL; usingnamespace @import("global.zig"); const assert = std.debug.assert; @@ -593,6 +594,7 @@ pub fn definesFromTransformOptions( } var resolved_defines = try defines.DefineData.from_input(user_defines, log, allocator); + return try defines.Define.init( allocator, resolved_defines, @@ -645,7 +647,7 @@ pub const BundleOptions = struct { hot_module_reloading: bool = false, inject: ?[]string = null, - origin: string = "", + origin: URL = URL{}, output_dir: string = "", output_dir_handle: ?std.fs.Dir = null, @@ -711,8 +713,7 @@ pub const BundleOptions = struct { }; if (transform.origin) |origin| { - opts.import_path_format = ImportPathFormat.absolute_url; - opts.origin = origin; + opts.origin = URL.parse(origin); } if (transform.jsx) |jsx| { @@ -728,6 +729,29 @@ pub const BundleOptions = struct { opts.main_fields = Platform.DefaultMainFields.get(opts.platform); } + if (transform.serve orelse false) { + // When we're serving, we need some kind of URL. + if (!opts.origin.isAbsolute()) { + const protocol: string = if (opts.origin.hasHTTPLikeProtocol()) opts.origin.protocol else "http"; + + const had_valid_port = opts.origin.hasValidPort(); + const port: string = if (had_valid_port) opts.origin.port else "3000"; + + opts.origin = URL.parse( + try std.fmt.allocPrint( + allocator, + "{s}://localhost:{s}{s}", + .{ + protocol, + port, + opts.origin.path, + }, + ), + ); + opts.origin.port_was_automatically_set = !had_valid_port; + } + } + switch (opts.platform) { .node => { opts.import_path_format = .relative_nodejs; @@ -766,21 +790,9 @@ pub const BundleOptions = struct { var node_module_bundle = try allocator.create(NodeModuleBundle); node_module_bundle.* = bundle; opts.node_modules_bundle = node_module_bundle; - if (opts.origin.len > 0) { - var relative = node_module_bundle.bundle.import_from_name; - if (relative[0] == std.fs.path.sep) { - relative = relative[1..]; - } - - const buf_size = opts.origin.len + relative.len + pretty_path.len; - var buf = try allocator.alloc(u8, buf_size); - opts.node_modules_bundle_url = try std.fmt.bufPrint(buf, "{s}{s}", .{ opts.origin, relative }); - opts.node_modules_bundle_pretty_path = buf[opts.node_modules_bundle_url.len..]; - std.mem.copy( - u8, - buf[opts.node_modules_bundle_url.len..], - pretty_path, - ); + if (opts.origin.isAbsolute()) { + opts.node_modules_bundle_url = try opts.origin.joinAlloc(allocator, "", "", node_module_bundle.bundle.import_from_name, ""); + opts.node_modules_bundle_pretty_path = opts.node_modules_bundle_url[opts.node_modules_bundle_url.len - node_module_bundle.bundle.import_from_name.len - 1 ..]; } else { opts.node_modules_bundle_pretty_path = try allocator.dupe(u8, pretty_path); } @@ -838,9 +850,6 @@ pub const BundleOptions = struct { if (transform.serve orelse false) { opts.preserve_extensions = true; opts.append_package_version_in_query_string = true; - if (opts.origin.len == 0) { - opts.origin = "/"; - } opts.resolve_mode = .lazy; @@ -899,6 +908,10 @@ pub const BundleOptions = struct { opts.hot_module_reloading = opts.platform.isWebLike(); } + if (opts.origin.isAbsolute()) { + opts.import_path_format = ImportPathFormat.absolute_url; + } + if (opts.write and opts.output_dir.len > 0) { opts.output_dir_handle = try openOutputDir(opts.output_dir); } @@ -1181,6 +1194,22 @@ pub const Framework = struct { resolved: bool = false, from_bundle: bool = false, + client_env: ?Env = null, + server_env: ?Env = null, + + pub const Env = struct { + pub const Map = std.StringArrayHashMap(string); + defaults: Map, + prefix: string = "", + + pub fn init(allocator: *std.mem.Allocator, prefix: string) Env { + return Env{ + .defaults = Map.init(allocator), + .prefix = prefix, + }; + } + }; + fn normalizedPath(allocator: *std.mem.Allocator, toplevel_path: string, path: string) !string { std.debug.assert(std.fs.path.isAbsolute(path)); var str = path; @@ -1257,6 +1286,11 @@ pub const Framework = struct { pub const RouteConfig = struct { dir: string = "", + + // Frameworks like Next.js (and others) use a special prefix for bundled/transpiled assets + // This is combined with "origin" when printing import paths + asset_prefix_path: string = "", + // TODO: do we need a separate list for data-only extensions? // e.g. /foo.json just to get the data for the route, without rendering the html // I think it's fine to hardcode as .json for now, but if I personally were writing a framework @@ -1271,6 +1305,7 @@ pub const RouteConfig = struct { pub fn toAPI(this: *const RouteConfig) Api.LoadedRouteConfig { return .{ + .asset_prefix = this.asset_prefix_path, .dir = if (this.routes_enabled) this.dir else "", .extensions = this.extensions, .static_dir = if (this.static_dir_enabled) this.static_dir else "", @@ -1293,6 +1328,7 @@ pub const RouteConfig = struct { return RouteConfig{ .extensions = loaded.extensions, .dir = loaded.dir, + .asset_prefix_path = loaded.asset_prefix, .static_dir = loaded.static_dir, .routes_enabled = loaded.dir.len > 0, .static_dir_enabled = loaded.static_dir.len > 0, @@ -1304,6 +1340,7 @@ pub const RouteConfig = struct { var router_dir: string = std.mem.trimRight(u8, router_.dir orelse "", "/\\"); var static_dir: string = std.mem.trimRight(u8, router_.static_dir orelse "", "/\\"); + var asset_prefix: string = std.mem.trimRight(u8, router_.asset_prefix orelse "", "/\\"); if (router_dir.len != 0) { router.dir = router_dir; @@ -1314,6 +1351,10 @@ pub const RouteConfig = struct { router.static_dir = static_dir; } + if (asset_prefix.len > 0) { + router.asset_prefix_path = asset_prefix; + } + if (router_.extensions.len > 0) { var count: usize = 0; for (router_.extensions) |_ext| { diff --git a/src/query_string_map.zig b/src/query_string_map.zig index 2640e8a73..00b451e9a 100644 --- a/src/query_string_map.zig +++ b/src/query_string_map.zig @@ -1,7 +1,305 @@ const std = @import("std"); const Api = @import("./api/schema.zig").Api; +const resolve_path = @import("./resolver/resolve_path.zig"); usingnamespace @import("./global.zig"); +// This is close to WHATWG URL, but we don't want the validation errors +pub const URL = struct { + hash: string = "", + host: string = "", + hostname: string = "", + href: string = "", + origin: string = "", + password: string = "", + pathname: string = "/", + path: string = "/", + port: string = "", + protocol: string = "", + search: string = "", + searchParams: ?QueryStringMap = null, + username: string = "", + + port_was_automatically_set: bool = false, + + pub fn hasHTTPLikeProtocol(this: *const URL) bool { + return strings.eqlComptime(this.protocol, "http") or strings.eqlComptime(this.protocol, "https"); + } + + pub fn getPort(this: *const URL) ?u16 { + return std.fmt.parseInt(u16, this.port, 10) catch null; + } + + pub fn hasValidPort(this: *const URL) bool { + return (this.getPort() orelse 0) > 1; + } + + pub fn isEmpty(this: *const URL) bool { + return this.href.len == 0; + } + + pub fn isAbsolute(this: *const URL) bool { + return this.hostname.len > 0 and this.pathname.len > 0; + } + + pub fn joinNormalize(out: []u8, prefix: string, dirname: string, basename: string, extname: string) string { + var buf: [2048]u8 = undefined; + + var path_parts: [10]string = undefined; + var path_end: usize = 0; + + path_parts[0] = "/"; + path_end += 1; + + if (prefix.len > 0) { + path_parts[path_end] = prefix; + path_end += 1; + } + + if (dirname.len > 0) { + path_parts[path_end] = std.mem.trim(u8, dirname, "/\\"); + path_end += 1; + } + + if (basename.len > 0) { + if (dirname.len > 0) { + path_parts[path_end] = "/"; + path_end += 1; + } + + path_parts[path_end] = std.mem.trim(u8, basename, "/\\"); + path_end += 1; + } + + if (extname.len > 0) { + path_parts[path_end] = extname; + path_end += 1; + } + + var buf_i: usize = 0; + for (path_parts[0..path_end]) |part| { + std.mem.copy(u8, buf[buf_i..], part); + buf_i += part.len; + } + return resolve_path.normalizeStringBuf(buf[0..buf_i], out, false, .loose, false); + } + + pub fn joinWrite( + this: *const URL, + comptime Writer: type, + writer: Writer, + prefix: string, + dirname: string, + basename: string, + extname: string, + ) !void { + var out: [2048]u8 = undefined; + const normalized_path = joinNormalize(&out, prefix, dirname, basename, extname); + + try writer.print("{s}/{s}", .{ this.origin, normalized_path }); + } + + pub fn joinAlloc(this: *const URL, allocator: *std.mem.Allocator, prefix: string, dirname: string, basename: string, extname: string) !string { + var out: [2048]u8 = undefined; + const normalized_path = joinNormalize(&out, prefix, dirname, basename, extname); + + return try std.fmt.allocPrint(allocator, "{s}/{s}", .{ this.origin, normalized_path }); + } + + pub fn parse(base_: string) URL { + const base = std.mem.trim(u8, base_, &std.ascii.spaces); + if (base.len == 0) return URL{}; + var url = URL{}; + url.href = base; + var offset: u31 = 0; + switch (base[0]) { + '@' => { + offset += url.parsePassword(base[offset..]) orelse 0; + offset += url.parseHost(base[offset..]) orelse 0; + }, + 'a'...'z', 'A'...'Z', '0'...'9', '-', '_', ':' => { + offset += url.parseProtocol(base[offset..]) orelse 0; + + // if there's no protocol or @, it's ambiguous whether the colon is a port or a username. + if (offset > 0) { + if ((std.mem.indexOfScalar(u8, base[offset..], '@') orelse 0) > (std.mem.indexOfScalar(u8, base[offset..], ':') orelse 0)) { + offset += url.parseUsername(base[offset..]) orelse 0; + offset += url.parsePassword(base[offset..]) orelse 0; + } + } + + offset += url.parseHost(base[offset..]) orelse 0; + }, + else => {}, + } + + url.origin = base[0..offset]; + + if (offset > base.len) { + return url; + } + + const path_offset = offset; + + var can_update_path = true; + if (base.len > offset + 1 and base[offset] == '/' and base[offset..].len > 0) { + url.path = base[offset..]; + url.pathname = url.path; + } + + if (strings.indexOfChar(base[offset..], '?')) |q| { + offset += @intCast(u31, q); + url.path = base[path_offset..][0..q]; + can_update_path = false; + url.search = base[offset..]; + } + + if (strings.indexOfChar(base[offset..], '#')) |hash| { + offset += @intCast(u31, hash); + if (can_update_path) { + url.path = base[path_offset..][0..hash]; + } + url.hash = base[offset..]; + + if (url.search.len > 0) { + url.search = url.search[0 .. url.search.len - url.hash.len]; + } + } + + if (base.len > path_offset and base[path_offset] == '/' and offset > 0) { + url.pathname = base[path_offset..std.math.min(offset, base.len)]; + url.origin = base[0..path_offset]; + } + + if (url.path.len > 1) { + const trimmed = std.mem.trim(u8, url.path, "/"); + if (trimmed.len > 1) { + url.path = url.path[std.math.max(@ptrToInt(trimmed.ptr) - @ptrToInt(url.path.ptr), 1) - 1 ..]; + } else { + url.path = "/"; + } + } else { + url.path = "/"; + } + + if (url.pathname.len == 0) { + url.pathname = "/"; + } + + url.origin = std.mem.trim(u8, url.origin, "/ ?#"); + return url; + } + + pub fn parseProtocol(url: *URL, str: string) ?u31 { + var i: u31 = 0; + if (str.len < "://".len) return null; + while (i < str.len) : (i += 1) { + switch (str[i]) { + '/', '?', '%' => { + return null; + }, + ':' => { + if (i + 3 <= str.len and str[i + 1] == '/' and str[i + 2] == '/') { + url.protocol = str[0..i]; + return i + 3; + } + }, + else => {}, + } + } + + return null; + } + + pub fn parseUsername(url: *URL, str: string) ?u31 { + var i: u31 = 0; + + // reset it + url.username = ""; + + if (str.len < "@".len) return null; + + while (i < str.len) : (i += 1) { + switch (str[i]) { + ':', '@' => { + // we found a username, everything before this point in the slice is a username + url.username = str[0..i]; + return i + 1; + }, + // if we reach a slash, there's no username + '/' => { + return null; + }, + else => {}, + } + } + return null; + } + + pub fn parsePassword(url: *URL, str: string) ?u31 { + var i: u31 = 0; + + // reset it + url.password = ""; + + if (str.len < "@".len) return null; + + while (i < str.len) : (i += 1) { + switch (str[i]) { + '@' => { + // we found a password, everything before this point in the slice is a password + url.password = str[0..i]; + std.debug.assert(str[i..].len < 2 or std.mem.readIntNative(u16, str[i..][0..2]) != std.mem.readIntNative(u16, "//")); + return i + 1; + }, + // if we reach a slash, there's no password + '/' => { + return null; + }, + else => {}, + } + } + return null; + } + + pub fn parseHost(url: *URL, str: string) ?u31 { + var i: u31 = 0; + + // reset it + url.host = ""; + url.hostname = ""; + url.port = ""; + + // look for the first "/" + // if we have a slash, anything before that is the host + // anything before the colon is the hostname + // anything after the colon but before the slash is the port + // the origin is the scheme before the slash + + var colon_i: ?u31 = null; + while (i < str.len) : (i += 1) { + colon_i = if (colon_i == null and str[i] == ':') i else colon_i; + + switch (str[i]) { + // alright, we found the slash + '/' => { + break; + }, + else => {}, + } + } + + url.host = str[0..i]; + if (colon_i) |colon| { + url.hostname = str[0..colon]; + url.port = str[colon + 1 .. i]; + } else { + url.hostname = str[0..i]; + } + + return i; + } +}; + /// QueryString array-backed hash table that does few allocations and preserves the original order pub const QueryStringMap = struct { allocator: *std.mem.Allocator, @@ -825,3 +1123,122 @@ test "QueryStringMap Iterator" { try expect(iter.next(buf) == null); } + +test "URL - parse" { + var url = URL.parse("https://url.spec.whatwg.org/foo#include-credentials"); + try expectString("https", url.protocol); + try expectString("url.spec.whatwg.org", url.host); + try expectString("/foo", url.pathname); + try expectString("#include-credentials", url.hash); + + url = URL.parse("https://url.spec.whatwg.org/#include-credentials"); + try expectString("https", url.protocol); + try expectString("url.spec.whatwg.org", url.host); + try expectString("/", url.pathname); + try expectString("#include-credentials", url.hash); + + url = URL.parse("://url.spec.whatwg.org/#include-credentials"); + try expectString("", url.protocol); + try expectString("url.spec.whatwg.org", url.host); + try expectString("/", url.pathname); + try expectString("#include-credentials", url.hash); + + url = URL.parse("/#include-credentials"); + try expectString("", url.protocol); + try expectString("", url.host); + try expectString("/", url.pathname); + try expectString("#include-credentials", url.hash); + + url = URL.parse("https://username:password@url.spec.whatwg.org/#include-credentials"); + try expectString("https", url.protocol); + try expectString("username", url.username); + try expectString("password", url.password); + try expectString("url.spec.whatwg.org", url.host); + try expectString("/", url.pathname); + try expectString("#include-credentials", url.hash); + + url = URL.parse("https://username:password@url.spec.whatwg.org:3000/#include-credentials"); + try expectString("https", url.protocol); + try expectString("username", url.username); + try expectString("password", url.password); + try expectString("url.spec.whatwg.org:3000", url.host); + try expectString("3000", url.port); + try expectString("/", url.pathname); + try expectString("#include-credentials", url.hash); + + url = URL.parse("example.com/#include-credentials"); + try expectString("", url.protocol); + try expectString("", url.username); + try expectString("", url.password); + try expectString("example.com", url.host); + try expectString("/", url.pathname); + try expectString("#include-credentials", url.hash); + + url = URL.parse("example.com:8080/#include-credentials"); + try expectString("", url.protocol); + try expectString("", url.username); + try expectString("", url.password); + try expectString("example.com:8080", url.host); + try expectString("example.com", url.hostname); + try expectString("8080", url.port); + try expectString("/", url.pathname); + try expectString("#include-credentials", url.hash); + + url = URL.parse("example.com:8080/////#include-credentials"); + try expectString("", url.protocol); + try expectString("", url.username); + try expectString("", url.password); + try expectString("example.com:8080", url.host); + try expectString("example.com", url.hostname); + try expectString("8080", url.port); + try expectString("/////", url.pathname); + try expectString("/", url.path); + try expectString("#include-credentials", url.hash); + url = URL.parse("example.com:8080/////hi?wow#include-credentials"); + try expectString("", url.protocol); + try expectString("", url.username); + try expectString("", url.password); + try expectString("example.com:8080", url.host); + try expectString("example.com", url.hostname); + try expectString("8080", url.port); + try expectString("/////hi?wow", url.pathname); + try expectString("/hi", url.path); + try expectString("#include-credentials", url.hash); + try expectString("?wow", url.search); + + url = URL.parse("/src/index"); + try expectString("", url.protocol); + try expectString("", url.username); + try expectString("", url.password); + try expectString("", url.host); + try expectString("", url.hostname); + try expectString("", url.port); + try expectString("/src/index", url.path); + try expectString("/src/index", url.pathname); + + try expectString("", url.hash); + try expectString("", url.search); + + url = URL.parse("http://localhost:3000/"); + try expectString("http", url.protocol); + try expectString("", url.username); + try expectString("", url.password); + try expectString("localhost:3000", url.host); + try expectString("localhost", url.hostname); + try expectString("3000", url.port); + try expectString("/", url.path); + try expectString("/", url.pathname); +} + +test "URL - joinAlloc" { + var url = URL.parse("http://localhost:3000"); + + var absolute_url = try url.joinAlloc(std.heap.c_allocator, "/_next/", "src/components", "button", ".js"); + try expectString("http://localhost:3000/_next/src/components/button.js", absolute_url); + + absolute_url = try url.joinAlloc(std.heap.c_allocator, "compiled-", "src/components", "button", ".js"); + try expectString("http://localhost:3000/compiled-src/components/button.js", absolute_url); + + absolute_url = try url.joinAlloc(std.heap.c_allocator, "compiled-", "", "button", ".js"); + try expectString("http://localhost:3000/compiled-button.js", absolute_url); +} diff --git a/src/resolver/package_json.zig b/src/resolver/package_json.zig index 7862de15c..160f748fd 100644 --- a/src/resolver/package_json.zig +++ b/src/resolver/package_json.zig @@ -70,6 +70,57 @@ pub const PackageJSON = struct { } } + // "env": { + // "client": { + // "NEXT_TRAILING_SLASH": false, + // }, + // "clientPrefix": "NEXT_PUBLIC_", + // "server": { + // "NEXT_TRAILING_SLASH": false, + // }, + // "serverPrefix": "", + // } + + if (json.asProperty("env")) |defines| { + if (defines.expr.asProperty("client")) |client| { + if (client.expr.data == .e_object) { + const object = client.expr.data.e_object; + var i: usize = 0; + for (object.properties) |prop| { + // must be strings + const key = prop.key orelse continue; + const value = prop.value orelse continue; + i += @intCast(usize, @boolToInt(key.data == .e_string and value.data == .e_string)); + } + + if (i > 0) { + if (framework.client_env == null) { + framework.client_env = options.Framework.Env.init(allocator, ""); + } + var env = &framework.client_env.?; + try env.defaults.ensureUnusedCapacity(i); + + for (object.properties) |prop| { + // must be strings + // not for any good reason. + // we should fix this later + + const key = prop.key orelse continue; + const value = prop.value orelse continue; + if (key.data != .e_string or value.data != .e_string) continue; + + var res = try define.getOrPut(try key.asString(allocator)); + if (!res.found_existing) { + res.value_ptr.* = try value.asString(allocator); + } + } + } + } + } + + if (defines.expr.asProperty("server")) |server| {} + } + if (json.asProperty("server")) |server| { if (server.expr.asString(allocator)) |str| { if (str.len > 0) { @@ -92,6 +143,15 @@ pub const PackageJSON = struct { } } + if (framework_object.expr.asProperty("assetPrefix")) |asset_prefix| { + if (asset_prefix.expr.asString(allocator)) |_str| { + const str = std.mem.trimRight(u8, _str, " "); + if (str.len > 0) { + pair.router.asset_prefix_path = str; + } + } + } + if (!pair.router.routes_enabled) { if (framework_object.expr.asProperty("router")) |router| { if (router.expr.asProperty("dir")) |route_dir| { diff --git a/src/router.zig b/src/router.zig index 884741d3d..7e6867848 100644 --- a/src/router.zig +++ b/src/router.zig @@ -43,7 +43,11 @@ pub fn init( }; } -pub fn getEntryPoints(this: *const Router, allocator: *std.mem.Allocator) ![]const string { +pub const EntryPointList = struct { + entry_points: []const string, + buffer: []u8, +}; +pub fn getEntryPointsWithBuffer(this: *const Router, allocator: *std.mem.Allocator, comptime absolute: bool) !EntryPointList { var i: u16 = 0; const route_count: u16 = @truncate(u16, this.routes.routes.len); @@ -73,15 +77,26 @@ pub fn getEntryPoints(this: *const Router, allocator: *std.mem.Allocator) ![]con const children = this.routes.routes.items(.children)[i]; if (children.len == 0) { if (Fs.FileSystem.DirEntry.EntryStore.instance.at(this.routes.routes.items(.entry_index)[i])) |entry| { - var parts = [_]string{ entry.dir, entry.base }; - entry_points[entry_point_i] = this.fs.absBuf(&parts, remain); + if (comptime absolute) { + var parts = [_]string{ entry.dir, entry.base }; + entry_points[entry_point_i] = this.fs.absBuf(&parts, remain); + } else { + var parts = [_]string{ "/", this.config.asset_prefix_path, this.fs.relativeTo(entry.dir), entry.base }; + entry_points[entry_point_i] = this.fs.joinBuf(&parts, remain); + } + remain = remain[entry_points[entry_point_i].len..]; entry_point_i += 1; } } } - return entry_points; + return EntryPointList{ .entry_points = entry_points, .buffer = buffer }; +} + +pub fn getEntryPoints(this: *const Router, allocator: *std.mem.Allocator) ![]const string { + const list = try getEntryPointsWithBuffer(this, allocator, true); + return list.entry_points; } const banned_dirs = [_]string{ diff --git a/src/string_immutable.zig b/src/string_immutable.zig index 5e651fc5d..618657a64 100644 --- a/src/string_immutable.zig +++ b/src/string_immutable.zig @@ -217,7 +217,7 @@ pub fn eqlComptime(self: string, comptime alt: anytype) bool { return (self.len == alt.len) and first == std.mem.readIntNative(u64, self[0..8]) and second == std.mem.readIntNative(u64, self[8..16]); }, else => { - @compileError(alt ++ " is too long."); + @compileError(alt ++ " is too long."); }, } } @@ -499,6 +499,21 @@ pub const CodepointIterator = struct { return it.c; } + pub fn nextCodepointNoReturn(it: *CodepointIterator) void { + const slice = it.nextCodepointSlice(); + it.width = @intCast(u3, slice.len); + @setRuntimeSafety(false); + + it.c = switch (it.width) { + 0 => -1, + 1 => @intCast(CodePoint, slice[0]), + 2 => @intCast(CodePoint, std.unicode.utf8Decode2(slice) catch unreachable), + 3 => @intCast(CodePoint, std.unicode.utf8Decode3(slice) catch unreachable), + 4 => @intCast(CodePoint, std.unicode.utf8Decode4(slice) catch unreachable), + else => unreachable, + }; + } + /// Look ahead at the next n codepoints without advancing the iterator. /// If fewer than n codepoints are available, then return the remainder of the string. pub fn peek(it: *CodepointIterator, n: usize) []const u8 { |