diff options
-rw-r--r-- | src/allocators.zig | 35 | ||||
-rw-r--r-- | src/api/demo/pages/index.tsx | 2 | ||||
-rw-r--r-- | src/api/schema.d.ts | 1 | ||||
-rw-r--r-- | src/api/schema.js | 10 | ||||
-rw-r--r-- | src/api/schema.peechy | 3 | ||||
-rw-r--r-- | src/api/schema.zig | 2913 | ||||
-rw-r--r-- | src/bundler.zig | 474 | ||||
-rw-r--r-- | src/cache.zig | 90 | ||||
-rw-r--r-- | src/cli.zig | 40 | ||||
-rw-r--r-- | src/cli/bun_command.zig | 7 | ||||
-rw-r--r-- | src/darwin_c.zig | 35 | ||||
-rw-r--r-- | src/fs.zig | 146 | ||||
-rw-r--r-- | src/global.zig | 24 | ||||
-rw-r--r-- | src/js_ast.zig | 26 | ||||
-rw-r--r-- | src/js_parser/js_parser_test.zig | 4 | ||||
-rw-r--r-- | src/js_printer.zig | 74 | ||||
-rw-r--r-- | src/router.zig | 7 | ||||
-rw-r--r-- | src/string_mutable.zig | 1 |
18 files changed, 2197 insertions, 1695 deletions
diff --git a/src/allocators.zig b/src/allocators.zig index 353392b20..4b7bde391 100644 --- a/src/allocators.zig +++ b/src/allocators.zig @@ -71,7 +71,7 @@ pub const IndexType = packed struct { }; const HashKeyType = u64; -const IndexMap = std.HashMapUnmanaged(HashKeyType, IndexType, struct { +const IndexMapContext = struct { pub fn hash(ctx: @This(), key: HashKeyType) HashKeyType { return key; } @@ -79,7 +79,11 @@ const IndexMap = std.HashMapUnmanaged(HashKeyType, IndexType, struct { pub fn eql(ctx: @This(), a: HashKeyType, b: HashKeyType) bool { return a == b; } -}, 80); +}; + +pub const IndexMap = std.HashMapUnmanaged(HashKeyType, IndexType, IndexMapContext, 80); + +pub const IndexMapManaged = std.HashMap(HashKeyType, IndexType, IndexMapContext, 80); pub const Result = struct { hash: HashKeyType, index: IndexType, @@ -174,6 +178,23 @@ pub fn BSSList(comptime ValueType: type, comptime _count: anytype) type { return result; } + pub const Pair = struct { index: IndexType, value: *ValueType }; + pub fn appendGet(self: *Self, value: ValueType) !Pair { + var result = IndexType{ .index = std.math.maxInt(u31), .is_overflow = backing_buf_used > max_index }; + if (result.is_overflow) { + result.index = @intCast(u31, self.overflow_list.items.len); + try self.overflow_list.append(self.allocator, value); + return Pair{ .index = result, .value = &self.overflow_list.items[result.index] }; + } else { + result.index = backing_buf_used; + backing_buf[result.index] = value; + backing_buf_used += 1; + if (backing_buf_used >= max_index) { + self.overflow_list = try @TypeOf(self.overflow_list).initCapacity(self.allocator, count); + } + return Pair{ .index = result, .value = &backing_buf[result.index] }; + } + } pub fn update(self: *Self, result: *IndexType, value: ValueType) !*ValueType { if (result.index.index == NotFound.index or result.index.index == Unassigned.index) { @@ -274,6 +295,7 @@ pub fn BSSStringList(comptime _count: usize, comptime _item_length: usize) type .overflow_list = std.ArrayListUnmanaged(ValueType){}, }; mutex = Mutex.init(); + loaded = true; } return &instance; @@ -292,11 +314,17 @@ pub fn BSSStringList(comptime _count: usize, comptime _item_length: usize) type } pub fn append(self: *Self, comptime AppendType: type, _value: AppendType) ![]const u8 { + mutex.lock(); + defer mutex.unlock(); + return try self.doAppend(AppendType, _value); } threadlocal var lowercase_append_buf: [std.fs.MAX_PATH_BYTES]u8 = undefined; pub fn appendLowerCase(self: *Self, comptime AppendType: type, _value: AppendType) ![]const u8 { + mutex.lock(); + defer mutex.unlock(); + for (_value) |c, i| { lowercase_append_buf[i] = std.ascii.toLower(c); } @@ -313,9 +341,6 @@ pub fn BSSStringList(comptime _count: usize, comptime _item_length: usize) type comptime AppendType: type, _value: AppendType, ) ![]const u8 { - mutex.lock(); - defer mutex.unlock(); - const value_len: usize = brk: { switch (comptime AppendType) { []const u8, []u8 => { diff --git a/src/api/demo/pages/index.tsx b/src/api/demo/pages/index.tsx index 4d60b4084..6f09d0d52 100644 --- a/src/api/demo/pages/index.tsx +++ b/src/api/demo/pages/index.tsx @@ -1,6 +1,6 @@ import Head from "next/head"; import Image from "next/image"; -import styles from "../styles/Home.module.css"; +// import styles from "../styles/Home.module.css"; import "../lib/api.ts"; export default function Home() { diff --git a/src/api/schema.d.ts b/src/api/schema.d.ts index 666a0cbce..07f865983 100644 --- a/src/api/schema.d.ts +++ b/src/api/schema.d.ts @@ -326,6 +326,7 @@ type uint32 = number; node_modules_bundle_path_server?: string; framework?: FrameworkConfig; router?: RouteConfig; + no_summary?: boolean; } export interface FileHandle { diff --git a/src/api/schema.js b/src/api/schema.js index 07f643a62..bc4430489 100644 --- a/src/api/schema.js +++ b/src/api/schema.js @@ -1071,6 +1071,10 @@ function decodeTransformOptions(bb) { result["router"] = decodeRouteConfig(bb); break; + case 23: + result["no_summary"] = !!bb.readByte(); + break; + default: throw new Error("Attempted to parse invalid message"); } @@ -1239,6 +1243,12 @@ bb.writeByte(encoded); bb.writeByte(22); encodeRouteConfig(value, bb); } + + var value = message["no_summary"]; + if (value != null) { + bb.writeByte(23); + bb.writeByte(value); + } bb.writeByte(0); } diff --git a/src/api/schema.peechy b/src/api/schema.peechy index 63c8501b2..0e0680b8d 100644 --- a/src/api/schema.peechy +++ b/src/api/schema.peechy @@ -36,7 +36,7 @@ smol JSXRuntime { struct JSX { string factory; JSXRuntime runtime; - string fragment;\ + string fragment; bool development; // Probably react @@ -229,6 +229,7 @@ message TransformOptions { FrameworkConfig framework = 21; RouteConfig router = 22; + bool no_summary = 23; } struct FileHandle { diff --git a/src/api/schema.zig b/src/api/schema.zig index 9219bcaa7..a01ba641a 100644 --- a/src/api/schema.zig +++ b/src/api/schema.zig @@ -1,3 +1,4 @@ + const std = @import("std"); pub const Reader = struct { @@ -281,1749 +282,1869 @@ 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, - /// bun - bun, + /// 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 CssInJsBehavior = enum(u8) { - _none, - /// facade - facade, +_, - /// facade_onimportcss - facade_onimportcss, + 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 JsxRuntime = enum(u8) { - _none, - /// automatic - automatic, +_none, + /// browser + browser, - /// classic - classic, + /// node + node, - _, + /// bun + bun, - pub fn jsonStringify(self: *const @This(), opts: anytype, o: anytype) !void { - return try std.json.stringify(@tagName(self), opts, o); - } - }; +_, - pub const Jsx = struct { - /// factory - factory: []const u8, + pub fn jsonStringify(self: *const @This(), opts: anytype, o: anytype) !void { + return try std.json.stringify(@tagName(self), opts, o); + } - /// runtime - runtime: JsxRuntime, + +}; - /// fragment - fragment: []const u8, +pub const CssInJsBehavior = enum(u8) { - /// development - development: bool = false, +_none, + /// facade + facade, - /// import_source - import_source: []const u8, + /// facade_onimportcss + facade_onimportcss, - /// react_fast_refresh - react_fast_refresh: bool = false, +_, - pub fn decode(reader: anytype) anyerror!Jsx { - var this = std.mem.zeroes(Jsx); + pub fn jsonStringify(self: *const @This(), opts: anytype, o: anytype) !void { + return try std.json.stringify(@tagName(self), opts, o); + } - 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.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 JsxRuntime = enum(u8) { - pub const StringPointer = packed struct { - /// offset - offset: u32 = 0, +_none, + /// automatic + automatic, - /// length - length: u32 = 0, + /// classic + classic, - 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 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.offset); - try writer.writeInt(this.length); - } - }; + +}; - pub const JavascriptBundledModule = struct { - /// path - path: StringPointer, +pub const Jsx = struct { +/// factory +factory: []const u8, - /// code - code: StringPointer, +/// runtime +runtime: JsxRuntime, - /// package_id - package_id: u32 = 0, +/// fragment +fragment: []const u8, - /// id - id: u32 = 0, +/// development +development: bool = false, - /// path_extname_length - path_extname_length: u8 = 0, +/// import_source +import_source: []const u8, - pub fn decode(reader: anytype) anyerror!JavascriptBundledModule { - var this = std.mem.zeroes(JavascriptBundledModule); +/// react_fast_refresh +react_fast_refresh: bool = false, - 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 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 decode(reader: anytype) anyerror!Jsx { + var this = std.mem.zeroes(Jsx); - pub const JavascriptBundledPackage = struct { - /// name - name: StringPointer, + 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; +} - /// version - version: StringPointer, +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))); +} - /// hash - hash: u32 = 0, +}; - /// modules_offset - modules_offset: u32 = 0, +pub const StringPointer = packed struct { +/// offset +offset: u32 = 0, - /// modules_length - modules_length: u32 = 0, +/// length +length: u32 = 0, - pub fn decode(reader: anytype) anyerror!JavascriptBundledPackage { - var this = std.mem.zeroes(JavascriptBundledPackage); - 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 decode(reader: anytype) anyerror!StringPointer { + var this = std.mem.zeroes(StringPointer); - 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); - } - }; + this.offset = try reader.readValue(u32); + this.length = try reader.readValue(u32); + return this; +} - pub const JavascriptBundle = struct { - /// modules - modules: []const JavascriptBundledModule, +pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeInt(this.offset); + try writer.writeInt(this.length); +} - /// packages - packages: []const JavascriptBundledPackage, +}; - /// etag - etag: []const u8, +pub const JavascriptBundledModule = struct { +/// path +path: StringPointer, - /// generated_at - generated_at: u32 = 0, +/// code +code: StringPointer, - /// app_package_json_dependencies_hash - app_package_json_dependencies_hash: []const u8, +/// package_id +package_id: u32 = 0, - /// import_from_name - import_from_name: []const u8, +/// id +id: u32 = 0, - /// manifest_string - manifest_string: []const u8, +/// path_extname_length +path_extname_length: u8 = 0, - 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 decode(reader: anytype) anyerror!JavascriptBundledModule { + var this = std.mem.zeroes(JavascriptBundledModule); - 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); - } - }; + 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 const JavascriptBundleContainer = struct { - /// bundle_format_version - bundle_format_version: ?u32 = null, +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); +} - /// bundle - bundle: ?JavascriptBundle = null, +}; - /// framework - framework: ?LoadedFramework = null, +pub const JavascriptBundledPackage = struct { +/// name +name: StringPointer, - /// routes - routes: ?LoadedRouteConfig = null, +/// version +version: StringPointer, - /// code_length - code_length: ?u32 = null, +/// hash +hash: u32 = 0, - pub fn decode(reader: anytype) anyerror!JavascriptBundleContainer { - var this = std.mem.zeroes(JavascriptBundleContainer); +/// modules_offset +modules_offset: u32 = 0, - while (true) { - switch (try reader.readByte()) { - 0 => { - return this; - }, +/// modules_length +modules_length: u32 = 0, - 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 fn decode(reader: anytype) anyerror!JavascriptBundledPackage { + var this = std.mem.zeroes(JavascriptBundledPackage); - pub const ScanDependencyMode = enum(u8) { - _none, - /// app - app, + 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; +} - /// all - all, +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 fn jsonStringify(self: *const @This(), opts: anytype, o: anytype) !void { - return try std.json.stringify(@tagName(self), opts, o); - } - }; +pub const JavascriptBundle = struct { +/// modules +modules: []const JavascriptBundledModule, - pub const ModuleImportType = enum(u8) { - _none, - /// import - import, +/// packages +packages: []const JavascriptBundledPackage, - /// require - require, +/// etag +etag: []const u8, - _, +/// generated_at +generated_at: u32 = 0, - pub fn jsonStringify(self: *const @This(), opts: anytype, o: anytype) !void { - return try std.json.stringify(@tagName(self), opts, o); - } - }; +/// app_package_json_dependencies_hash +app_package_json_dependencies_hash: []const u8, - pub const ModuleImportRecord = struct { - /// kind - kind: ModuleImportType, +/// import_from_name +import_from_name: []const u8, - /// path - path: []const u8, +/// manifest_string +manifest_string: []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!JavascriptBundle { + var this = std.mem.zeroes(JavascriptBundle); - this.kind = try reader.readValue(ModuleImportType); - this.path = try reader.readValue([]const u8); - this.dynamic = try reader.readValue(bool); - return this; - } + 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.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.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 Module = struct { - /// path - path: []const u8, +}; - /// imports - imports: []const ModuleImportRecord, +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 decode(reader: anytype) anyerror!Module { - var this = std.mem.zeroes(Module); +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(); +} - this.path = try reader.readValue([]const u8); - this.imports = try reader.readArray(ModuleImportRecord); - return this; - } +}; - pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - try writer.writeValue(this.path); - try writer.writeArray(ModuleImportRecord, this.imports); - } - }; +pub const ScanDependencyMode = enum(u8) { - pub const StringMap = struct { - /// keys - keys: []const []const u8, +_none, + /// app + app, - /// values - values: []const []const u8, + /// all + all, - pub fn decode(reader: anytype) anyerror!StringMap { - var this = std.mem.zeroes(StringMap); +_, - this.keys = try reader.readArray([]const u8); - this.values = try reader.readArray([]const u8); - 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.writeArray([]const u8, this.keys); - try writer.writeArray([]const u8, this.values); - } - }; + +}; - pub const LoaderMap = struct { - /// extensions - extensions: []const []const u8, +pub const ModuleImportType = enum(u8) { - /// loaders - loaders: []const Loader, +_none, + /// import + import, - pub fn decode(reader: anytype) anyerror!LoaderMap { - var this = std.mem.zeroes(LoaderMap); + /// require + require, - 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 fn jsonStringify(self: *const @This(), opts: anytype, o: anytype) !void { + return try std.json.stringify(@tagName(self), opts, o); + } - pub const DotEnvBehavior = enum(u32) { - _none, - /// disable - disable, + +}; - /// prefix - prefix, +pub const ModuleImportRecord = struct { +/// kind +kind: ModuleImportType, - /// load_all - load_all, +/// path +path: []const u8, - _, +/// dynamic +dynamic: bool = false, - pub fn jsonStringify(self: *const @This(), opts: anytype, o: anytype) !void { - return try std.json.stringify(@tagName(self), opts, o); - } - }; - pub const EnvConfig = struct { - /// prefix - prefix: ?[]const u8 = null, +pub fn decode(reader: anytype) anyerror!ModuleImportRecord { + var this = std.mem.zeroes(ModuleImportRecord); - /// defaults - defaults: ?StringMap = null, + this.kind = try reader.readValue(ModuleImportType); + this.path = try reader.readValue([]const u8); + this.dynamic = try reader.readValue(bool); + return this; +} - pub fn decode(reader: anytype) anyerror!EnvConfig { - var this = std.mem.zeroes(EnvConfig); +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))); +} - while (true) { - switch (try reader.readByte()) { - 0 => { - return this; - }, +}; - 1 => { - this.prefix = try reader.readValue([]const u8); - }, - 2 => { - this.defaults = try reader.readValue(StringMap); - }, - else => { - return error.InvalidMessage; - }, - } - } - unreachable; - } +pub const Module = struct { +/// path +path: []const u8, - pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - if (this.prefix) |prefix| { - try writer.writeFieldID(1); - try writer.writeValue(prefix); - } - if (this.defaults) |defaults| { - try writer.writeFieldID(2); - try writer.writeValue(defaults); - } - try writer.endMessage(); - } - }; +/// imports +imports: []const ModuleImportRecord, - pub const LoadedEnvConfig = struct { - /// dotenv - dotenv: DotEnvBehavior, - /// defaults - defaults: StringMap, +pub fn decode(reader: anytype) anyerror!Module { + var this = std.mem.zeroes(Module); - /// prefix - prefix: []const u8, + this.path = try reader.readValue([]const u8); + this.imports = try reader.readArray(ModuleImportRecord); + return this; +} - pub fn decode(reader: anytype) anyerror!LoadedEnvConfig { - var this = std.mem.zeroes(LoadedEnvConfig); +pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeValue(this.path); + try writer.writeArray(ModuleImportRecord, this.imports); +} - this.dotenv = try reader.readValue(DotEnvBehavior); - this.defaults = try reader.readValue(StringMap); - this.prefix = try reader.readValue([]const u8); - return this; - } +}; - pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - try writer.writeEnum(this.dotenv); - try writer.writeValue(this.defaults); - try writer.writeValue(this.prefix); - } - }; +pub const StringMap = struct { +/// keys +keys: []const []const u8, - pub const FrameworkConfig = struct { - /// package - package: ?[]const u8 = null, +/// values +values: []const []const u8, - /// client - client: ?[]const u8 = null, - /// server - server: ?[]const u8 = null, +pub fn decode(reader: anytype) anyerror!StringMap { + var this = std.mem.zeroes(StringMap); - /// development - development: ?bool = null, + this.keys = try reader.readArray([]const u8); + this.values = try reader.readArray([]const u8); + return this; +} - /// client_env - client_env: ?EnvConfig = null, +pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeArray([]const u8, this.keys); + try writer.writeArray([]const u8, this.values); +} - /// server_env - server_env: ?EnvConfig = null, +}; - /// client_css_in_js - client_css_in_js: ?CssInJsBehavior = null, +pub const LoaderMap = struct { +/// extensions +extensions: []const []const u8, - pub fn decode(reader: anytype) anyerror!FrameworkConfig { - var this = std.mem.zeroes(FrameworkConfig); +/// loaders +loaders: []const Loader, - 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_env = try reader.readValue(EnvConfig); - }, - 6 => { - this.server_env = try reader.readValue(EnvConfig); - }, - 7 => { - this.client_css_in_js = try reader.readValue(CssInJsBehavior); - }, - else => { - return error.InvalidMessage; - }, +pub fn decode(reader: anytype) anyerror!LoaderMap { + var this = std.mem.zeroes(LoaderMap); + + 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 DotEnvBehavior = enum(u32) { + +_none, + /// disable + disable, + + /// prefix + prefix, + + /// load_all + load_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.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_env) |client_env| { - try writer.writeFieldID(5); - try writer.writeValue(client_env); - } - if (this.server_env) |server_env| { - try writer.writeFieldID(6); - try writer.writeValue(server_env); - } - if (this.client_css_in_js) |client_css_in_js| { - try writer.writeFieldID(7); - try writer.writeEnum(client_css_in_js); - } - try writer.endMessage(); - } - }; + +}; - pub const LoadedFramework = struct { - /// entry_point - entry_point: []const u8, +pub const EnvConfig = struct { +/// prefix +prefix: ?[]const u8 = null, + +/// defaults +defaults: ?StringMap = null, + + +pub fn decode(reader: anytype) anyerror!EnvConfig { + var this = std.mem.zeroes(EnvConfig); + + while(true) { + switch (try reader.readByte()) { + 0 => { return this; }, + + 1 => { + this.prefix = try reader.readValue([]const u8); +}, + 2 => { + this.defaults = try reader.readValue(StringMap); +}, + else => { + return error.InvalidMessage; + }, + } + } +unreachable; +} - /// package - package: []const u8, +pub fn encode(this: *const @This(), writer: anytype) anyerror!void { +if (this.prefix) |prefix| { + try writer.writeFieldID(1); + try writer.writeValue(prefix); +} +if (this.defaults) |defaults| { + try writer.writeFieldID(2); + try writer.writeValue(defaults); +} +try writer.endMessage(); +} - /// development - development: bool = false, +}; - /// client - client: bool = false, +pub const LoadedEnvConfig = struct { +/// dotenv +dotenv: DotEnvBehavior, - /// env - env: LoadedEnvConfig, +/// defaults +defaults: StringMap, - /// client_css_in_js - client_css_in_js: CssInJsBehavior, +/// prefix +prefix: []const u8, - pub fn decode(reader: anytype) anyerror!LoadedFramework { - var this = std.mem.zeroes(LoadedFramework); - 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.env = try reader.readValue(LoadedEnvConfig); - this.client_css_in_js = try reader.readValue(CssInJsBehavior); - return this; - } +pub fn decode(reader: anytype) anyerror!LoadedEnvConfig { + var this = std.mem.zeroes(LoadedEnvConfig); - 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.env); - try writer.writeEnum(this.client_css_in_js); - } - }; + this.dotenv = try reader.readValue(DotEnvBehavior); + this.defaults = try reader.readValue(StringMap); + this.prefix = try reader.readValue([]const u8); + return this; +} - pub const LoadedRouteConfig = struct { - /// dir - dir: []const u8, +pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeEnum(this.dotenv); + try writer.writeValue(this.defaults); + try writer.writeValue(this.prefix); +} - /// extensions - extensions: []const []const u8, +}; - /// static_dir - static_dir: []const u8, +pub const FrameworkConfig = struct { +/// package +package: ?[]const u8 = null, + +/// client +client: ?[]const u8 = null, + +/// server +server: ?[]const u8 = null, + +/// development +development: ?bool = null, + +/// client_env +client_env: ?EnvConfig = null, + +/// server_env +server_env: ?EnvConfig = null, + +/// client_css_in_js +client_css_in_js: ?CssInJsBehavior = 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_env = try reader.readValue(EnvConfig); +}, + 6 => { + this.server_env = try reader.readValue(EnvConfig); +}, + 7 => { + this.client_css_in_js = try reader.readValue(CssInJsBehavior); +}, + else => { + return error.InvalidMessage; + }, + } + } +unreachable; +} - /// asset_prefix - asset_prefix: []const u8, +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_env) |client_env| { + try writer.writeFieldID(5); + try writer.writeValue(client_env); +} +if (this.server_env) |server_env| { + try writer.writeFieldID(6); + try writer.writeValue(server_env); +} +if (this.client_css_in_js) |client_css_in_js| { + try writer.writeFieldID(7); + try writer.writeEnum(client_css_in_js); +} +try writer.endMessage(); +} - pub fn decode(reader: anytype) anyerror!LoadedRouteConfig { - var this = std.mem.zeroes(LoadedRouteConfig); +}; - 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 LoadedFramework = struct { +/// entry_point +entry_point: []const u8, - 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); - } - }; +/// package +package: []const u8, - pub const RouteConfig = struct { - /// dir - dir: []const []const u8, +/// development +development: bool = false, - /// extensions - extensions: []const []const u8, +/// client +client: bool = false, - /// static_dir - static_dir: ?[]const u8 = null, +/// env +env: LoadedEnvConfig, - /// asset_prefix - asset_prefix: ?[]const u8 = null, +/// client_css_in_js +client_css_in_js: CssInJsBehavior, - pub fn decode(reader: anytype) anyerror!RouteConfig { - var this = std.mem.zeroes(RouteConfig); - while (true) { - switch (try reader.readByte()) { - 0 => { - return this; - }, +pub fn decode(reader: anytype) anyerror!LoadedFramework { + var this = std.mem.zeroes(LoadedFramework); - 1 => { - this.dir = try reader.readArray([]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; - } + 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.env = try reader.readValue(LoadedEnvConfig); + this.client_css_in_js = try reader.readValue(CssInJsBehavior); + return this; +} - pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - if (this.dir) |dir| { - try writer.writeFieldID(1); - try writer.writeArray([]const u8, 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(); - } - }; +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.env); + try writer.writeEnum(this.client_css_in_js); +} - pub const TransformOptions = struct { - /// jsx - jsx: ?Jsx = null, +}; - /// tsconfig_override - tsconfig_override: ?[]const u8 = null, +pub const LoadedRouteConfig = struct { +/// dir +dir: []const u8, - /// resolve - resolve: ?ResolveMode = null, +/// extensions +extensions: []const []const u8, - /// origin - origin: ?[]const u8 = null, +/// static_dir +static_dir: []const u8, - /// absolute_working_dir - absolute_working_dir: ?[]const u8 = null, +/// asset_prefix +asset_prefix: []const u8, - /// define - define: ?StringMap = null, - /// preserve_symlinks - preserve_symlinks: ?bool = null, +pub fn decode(reader: anytype) anyerror!LoadedRouteConfig { + var this = std.mem.zeroes(LoadedRouteConfig); - /// entry_points - entry_points: []const []const u8, + 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; +} - /// write - write: ?bool = 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); +} - /// inject - inject: []const []const u8, +}; - /// output_dir - output_dir: ?[]const u8 = null, +pub const RouteConfig = struct { +/// dir +dir: []const []const u8, + +/// 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.readArray([]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; +} - /// external - external: []const []const u8, +pub fn encode(this: *const @This(), writer: anytype) anyerror!void { +if (this.dir) |dir| { + try writer.writeFieldID(1); + try writer.writeArray([]const u8, 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(); +} - /// loaders - loaders: ?LoaderMap = null, +}; - /// main_fields - main_fields: []const []const u8, +pub const TransformOptions = struct { +/// jsx +jsx: ?Jsx = null, - /// platform - platform: ?Platform = null, +/// tsconfig_override +tsconfig_override: ?[]const u8 = null, - /// serve - serve: ?bool = null, +/// resolve +resolve: ?ResolveMode = null, - /// extension_order - extension_order: []const []const u8, +/// 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, + +/// 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, + +/// no_summary +no_summary: ?bool = 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.generate_node_module_bundle = try reader.readValue(bool); +}, + 19 => { + this.node_modules_bundle_path = try reader.readValue([]const u8); +}, + 20 => { + this.node_modules_bundle_path_server = try reader.readValue([]const u8); +}, + 21 => { + this.framework = try reader.readValue(FrameworkConfig); +}, + 22 => { + this.router = try reader.readValue(RouteConfig); +}, + 23 => { + this.no_summary = try reader.readValue(bool); +}, + else => { + return error.InvalidMessage; + }, + } + } +unreachable; +} - /// generate_node_module_bundle - generate_node_module_bundle: ?bool = null, +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.generate_node_module_bundle) |generate_node_module_bundle| { + try writer.writeFieldID(18); + try writer.writeInt(@intCast(u8, @boolToInt(generate_node_module_bundle))); +} +if (this.node_modules_bundle_path) |node_modules_bundle_path| { + try writer.writeFieldID(19); + try writer.writeValue(node_modules_bundle_path); +} +if (this.node_modules_bundle_path_server) |node_modules_bundle_path_server| { + try writer.writeFieldID(20); + try writer.writeValue(node_modules_bundle_path_server); +} +if (this.framework) |framework| { + try writer.writeFieldID(21); + try writer.writeValue(framework); +} +if (this.router) |router| { + try writer.writeFieldID(22); + try writer.writeValue(router); +} +if (this.no_summary) |no_summary| { + try writer.writeFieldID(23); + try writer.writeInt(@intCast(u8, @boolToInt(no_summary))); +} +try writer.endMessage(); +} - /// node_modules_bundle_path - node_modules_bundle_path: ?[]const u8 = null, +}; - /// node_modules_bundle_path_server - node_modules_bundle_path_server: ?[]const u8 = null, +pub const FileHandle = struct { +/// path +path: []const u8, - /// framework - framework: ?FrameworkConfig = null, +/// size +size: u32 = 0, - /// router - router: ?RouteConfig = null, +/// fd +fd: u32 = 0, - pub fn decode(reader: anytype) anyerror!TransformOptions { - var this = std.mem.zeroes(TransformOptions); - while (true) { - switch (try reader.readByte()) { - 0 => { - return this; - }, +pub fn decode(reader: anytype) anyerror!FileHandle { + var this = std.mem.zeroes(FileHandle); - 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.generate_node_module_bundle = try reader.readValue(bool); - }, - 19 => { - this.node_modules_bundle_path = try reader.readValue([]const u8); - }, - 20 => { - this.node_modules_bundle_path_server = try reader.readValue([]const u8); - }, - 21 => { - this.framework = try reader.readValue(FrameworkConfig); - }, - 22 => { - this.router = try reader.readValue(RouteConfig); - }, - else => { - return error.InvalidMessage; - }, + this.path = try reader.readValue([]const u8); + this.size = try reader.readValue(u32); + this.fd = try reader.readValue(u32); + 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 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; +} + +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, + + /// fail + fail, + +_, + + 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.generate_node_module_bundle) |generate_node_module_bundle| { - try writer.writeFieldID(18); - try writer.writeInt(@intCast(u8, @boolToInt(generate_node_module_bundle))); - } - if (this.node_modules_bundle_path) |node_modules_bundle_path| { - try writer.writeFieldID(19); - try writer.writeValue(node_modules_bundle_path); - } - if (this.node_modules_bundle_path_server) |node_modules_bundle_path_server| { - try writer.writeFieldID(20); - try writer.writeValue(node_modules_bundle_path_server); - } - if (this.framework) |framework| { - try writer.writeFieldID(21); - try writer.writeValue(framework); - } - if (this.router) |router| { - try writer.writeFieldID(22); - 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, +pub const TransformResponse = struct { +/// status +status: TransformResponseStatus, - /// path - path: ?[]const u8 = null, +/// files +files: []const OutputFile, - /// contents - contents: []const u8, +/// errors +errors: []const Message, - /// loader - loader: ?Loader = null, - /// options - options: ?TransformOptions = null, +pub fn decode(reader: anytype) anyerror!TransformResponse { + var this = std.mem.zeroes(TransformResponse); - pub fn decode(reader: anytype) anyerror!Transform { - var this = std.mem.zeroes(Transform); + this.status = try reader.readValue(TransformResponseStatus); + this.files = try reader.readArray(OutputFile); + this.errors = try reader.readArray(Message); + return this; +} - while (true) { - switch (try reader.readByte()) { - 0 => { - return this; - }, +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); +} - 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 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); - /// from_timestamp - from_timestamp: u32 = 0, + this.ptrs = try reader.readArray(StringPointer); + this.files = try reader.readValue([]const u8); + return this; +} - /// loader - loader: Loader, +pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeArray(StringPointer, this.ptrs); + try writer.writeValue(this.files); +} - /// log - log: Log, +}; - pub fn decode(reader: anytype) anyerror!WebsocketMessageManifestFailure { - var this = std.mem.zeroes(WebsocketMessageManifestFailure); +pub const WebsocketMessageManifestSuccess = struct { +/// id +id: u32 = 0, - 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; - } +/// module_path +module_path: []const u8, + +/// 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 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); +} - 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/bundler.zig b/src/bundler.zig index ad95f1fe4..fcfffdd15 100644 --- a/src/bundler.zig +++ b/src/bundler.zig @@ -18,7 +18,6 @@ const schema = @import("api/schema.zig"); const Api = schema.Api; const _resolver = @import("./resolver/resolver.zig"); const sync = @import("sync.zig"); -const ThreadPool = sync.ThreadPool; const ThreadSafeHashMap = @import("./thread_safe_hash_map.zig"); const ImportRecord = @import("./import_record.zig").ImportRecord; const allocators = @import("./allocators.zig"); @@ -34,6 +33,7 @@ const Router = @import("./router.zig"); const isPackagePath = _resolver.isPackagePath; const Css = @import("css_scanner.zig"); const DotEnv = @import("./env_loader.zig"); +const Lock = @import("./lock.zig").Lock; pub const ServeResult = struct { file: options.OutputFile, mime_type: MimeType, @@ -555,13 +555,23 @@ pub fn NewBundler(cache_files: bool) type { const HashTable = std.StringHashMap(u32); backing: HashTable, + mutex: Lock, pub fn init(allocator: *std.mem.Allocator) PathMap { return PathMap{ .backing = HashTable.init(allocator), + .mutex = Lock.init(), }; } + pub inline fn lock(this: *PathMap) void { + this.mutex.lock(); + } + + pub inline fn unlock(this: *PathMap) void { + this.mutex.unlock(); + } + pub inline fn hashOf(str: string) u64 { return std.hash.Wyhash.hash(0, str); } @@ -575,22 +585,112 @@ pub fn NewBundler(cache_files: bool) type { } }; + const BunQueue = sync.Channel(_resolver.Result, .Dynamic); + + pub const ThreadPool = struct { + // Hardcode 512 as max number of threads for now. + workers: [512]Worker = undefined, + workers_used: u16 = 0, + cpu_count: u16 = 0, + wait_group: sync.WaitGroup = sync.WaitGroup.init(), + + pub fn start(this: *ThreadPool, generator: *GenerateNodeModuleBundle) !void { + this.cpu_count = @truncate(u16, @divFloor((try std.Thread.getCpuCount()) + 1, 2)); + + while (this.workers_used < this.cpu_count) : (this.workers_used += 1) { + this.workers[this.workers_used].wg = &this.wait_group; + + this.wait_group.add(); + try this.workers[this.workers_used].init(generator); + } + } + + pub fn wait(this: *ThreadPool) void { + this.wait_group.wait(); + } + + pub const Task = struct { + result: _resolver.Result, + generator: *GenerateNodeModuleBundle, + }; + + pub const Worker = struct { + thread_id: std.Thread.Id, + thread: std.Thread, + allocator: *std.mem.Allocator, + wg: *sync.WaitGroup, + generator: *GenerateNodeModuleBundle, + data: *WorkerData = undefined, + + pub const WorkerData = struct { + shared_buffer: MutableString = undefined, + scan_pass_result: js_parser.ScanPassResult = undefined, + templist: [100]_resolver.Result = undefined, + templist_used: u8 = 0, + + pub fn deinit(this: *WorkerData, allocator: *std.mem.Allocator) void { + this.shared_buffer.deinit(); + this.scan_pass_result.named_imports.deinit(); + this.scan_pass_result.import_records.deinit(); + allocator.destroy(this); + } + }; + + pub fn init(worker: *Worker, generator: *GenerateNodeModuleBundle) !void { + worker.generator = generator; + worker.thread = try std.Thread.spawn(.{}, Worker.run, .{worker}); + } + + pub fn run(this: *Worker) void { + defer this.wg.done(); + Output.Source.configureThread(); + this.thread_id = std.Thread.getCurrentId(); + defer Output.flush(); + + this.loop() catch |err| { + Output.prettyErrorln("<r><red>Error: {s}<r>", .{@errorName(err)}); + }; + } + + pub fn loop(this: *Worker) anyerror!void { + // Delay initializing until we get the first thing. + const first = (try this.generator.resolve_queue.tryReadItem()) orelse return; + js_ast.Expr.Data.Store.create(this.generator.allocator); + js_ast.Stmt.Data.Store.create(this.generator.allocator); + this.data = this.generator.allocator.create(WorkerData) catch unreachable; + this.data.* = WorkerData{}; + this.data.shared_buffer = try MutableString.init(this.generator.allocator, 0); + this.data.scan_pass_result = js_parser.ScanPassResult.init(this.generator.allocator); + defer this.data.deinit(this.generator.allocator); + + try this.generator.processFile(this, first); + + while (try this.generator.resolve_queue.tryReadItem()) |item| { + try this.generator.processFile(this, item); + } + } + }; + }; + write_lock: Lock, + module_list: std.ArrayList(Api.JavascriptBundledModule), package_list: std.ArrayList(Api.JavascriptBundledPackage), header_string_buffer: MutableString, // Just need to know if we've already enqueued this one resolved_paths: PathMap, package_list_map: std.AutoHashMap(u64, u32), - resolve_queue: std.fifo.LinearFifo(_resolver.Result, .Dynamic), + resolve_queue: *BunQueue, bundler: *ThisBundler, allocator: *std.mem.Allocator, - scan_pass_result: js_parser.ScanPassResult, tmpfile: std.fs.File, log: *logger.Log, + pool: *ThreadPool, tmpfile_byte_offset: u32 = 0, code_end_byte_offset: u32 = 0, has_jsx: bool = false, + list_lock: Lock = Lock.init(), + pub const current_version: u32 = 1; pub fn enqueueItem(this: *GenerateNodeModuleBundle, resolve: _resolver.Result) !void { @@ -602,8 +702,9 @@ pub fn NewBundler(cache_files: bool) type { this_module_resolved_path.value_ptr.* = module_data_.module_id; } } - - this.resolve_queue.writeItemAssumeCapacity(resolve); + var result = resolve; + result.path_pair.primary = Fs.Path.init(std.mem.span(try this.allocator.dupeZ(u8, resolve.path_pair.primary.text))); + try this.resolve_queue.writeItem(result); } } @@ -671,21 +772,30 @@ pub fn NewBundler(cache_files: bool) type { ); var tmpfile = try tmpdir.createFileZ(tmpname, .{ .read = isDebug, .exclusive = true }); - - var generator = GenerateNodeModuleBundle{ + var generator = try allocator.create(GenerateNodeModuleBundle); + var queue = try allocator.create(BunQueue); + queue.* = BunQueue.init(allocator); + defer allocator.destroy(generator); + generator.* = GenerateNodeModuleBundle{ .module_list = std.ArrayList(Api.JavascriptBundledModule).init(allocator), .package_list = std.ArrayList(Api.JavascriptBundledPackage).init(allocator), - .scan_pass_result = js_parser.ScanPassResult.init(allocator), .header_string_buffer = try MutableString.init(allocator, 0), .allocator = allocator, .resolved_paths = PathMap.init(allocator), - .resolve_queue = std.fifo.LinearFifo(_resolver.Result, .Dynamic).init(allocator), + .resolve_queue = queue, .bundler = bundler, .tmpfile = tmpfile, .log = bundler.log, .package_list_map = std.AutoHashMap(u64, u32).init(allocator), + .pool = undefined, + .write_lock = Lock.init(), }; - var this = &generator; + try generator.package_list_map.ensureTotalCapacity(128); + var pool = try allocator.create(ThreadPool); + pool.* = ThreadPool{}; + generator.pool = pool; + + var this = generator; // Always inline the runtime into the bundle try generator.appendBytes(&initial_header); // If we try to be smart and rely on .written, it turns out incorrect @@ -700,7 +810,6 @@ pub fn NewBundler(cache_files: bool) type { if (bundler.log.level == .verbose) { bundler.resolver.debug_logs = try DebugLogs.init(allocator); } - temp_stmts_list = @TypeOf(temp_stmts_list).init(allocator); const include_refresh_runtime = !this.bundler.options.production and this.bundler.options.jsx.supports_fast_refresh and bundler.options.platform.isWebLike(); const resolve_queue_estimate = bundler.options.entry_points.len + @@ -712,7 +821,7 @@ pub fn NewBundler(cache_files: bool) type { defer this.bundler.resetStore(); const entry_points = try router.getEntryPoints(allocator); - try this.resolve_queue.ensureUnusedCapacity(entry_points.len + resolve_queue_estimate); + try this.resolve_queue.buffer.ensureUnusedCapacity(entry_points.len + resolve_queue_estimate); for (entry_points) |entry_point| { const source_dir = bundler.fs.top_level_dir; const resolved = try bundler.linker.resolver.resolve(source_dir, entry_point, .entry_point); @@ -720,7 +829,7 @@ pub fn NewBundler(cache_files: bool) type { } this.bundler.resetStore(); } else { - try this.resolve_queue.ensureUnusedCapacity(resolve_queue_estimate); + try this.resolve_queue.buffer.ensureUnusedCapacity(resolve_queue_estimate); } for (bundler.options.entry_points) |entry_point| { @@ -776,10 +885,8 @@ pub fn NewBundler(cache_files: bool) type { } this.bundler.resetStore(); - - while (this.resolve_queue.readItem()) |resolved| { - try this.processFile(resolved); - } + try this.pool.start(this); + this.pool.wait(); if (this.log.errors > 0) { // We stop here because if there are errors we don't know if the bundle is valid @@ -980,18 +1087,19 @@ pub fn NewBundler(cache_files: bool) type { }; fn processImportRecord(this: *GenerateNodeModuleBundle, import_record: ImportRecord) !void {} - threadlocal var package_key_buf: [512]u8 = undefined; - threadlocal var file_path_buf: [4096]u8 = undefined; - threadlocal var temp_stmts_list: std.ArrayList(js_ast.Stmt) = undefined; - fn processFile(this: *GenerateNodeModuleBundle, _resolve: _resolver.Result) !void { + pub fn processFile(this: *GenerateNodeModuleBundle, worker: *ThreadPool.Worker, _resolve: _resolver.Result) !void { var resolve = _resolve; if (resolve.is_external) return; + var shared_buffer = &worker.data.shared_buffer; + var scan_pass_result = &worker.data.scan_pass_result; + const is_from_node_modules = resolve.isLikelyNodeModule(); const loader = this.bundler.options.loaders.get(resolve.path_pair.primary.name.ext) orelse .file; var bundler = this.bundler; - defer this.scan_pass_result.reset(); + defer scan_pass_result.reset(); + defer shared_buffer.reset(); defer this.bundler.resetStore(); var file_path = resolve.path_pair.primary; var hasher = std.hash.Wyhash.init(0); @@ -1006,12 +1114,12 @@ pub fn NewBundler(cache_files: bool) type { .js, .ts, => { - const entry = try bundler.resolver.caches.fs.readFile( + const entry = try bundler.resolver.caches.fs.readFileShared( bundler.fs, file_path.text, resolve.dirname_fd, - true, null, + shared_buffer, ); const source = logger.Source.initRecycledFile(Fs.File{ .path = file_path, .contents = entry.contents }, bundler.allocator) catch return null; const source_dir = file_path.name.dirWithTrailingSlash(); @@ -1023,6 +1131,7 @@ pub fn NewBundler(cache_files: bool) type { opts.transform_require_to_import = false; opts.enable_bundling = true; opts.warn_about_unbundled_modules = false; + var ast: js_ast.Ast = (try bundler.resolver.caches.js.parse( bundler.allocator, opts, @@ -1030,78 +1139,88 @@ pub fn NewBundler(cache_files: bool) type { this.log, &source, )) orelse return; + if (ast.import_records.len > 0) { + this.resolved_paths.lock(); + defer { + this.resolved_paths.unlock(); + } + { + for (ast.import_records) |*import_record, record_id| { - for (ast.import_records) |*import_record, record_id| { + // Don't resolve the runtime + if (import_record.is_internal) { + continue; + } - // Don't resolve the runtime - if (import_record.is_internal) { - continue; - } + if (bundler.linker.resolver.resolve(source_dir, import_record.path.text, import_record.kind)) |*_resolved_import| { + if (_resolved_import.is_external) { + continue; + } + _resolved_import.path_pair.primary = Fs.Path.init(std.mem.span(try this.allocator.dupeZ(u8, _resolved_import.path_pair.primary.text))); - if (bundler.linker.resolver.resolve(source_dir, import_record.path.text, import_record.kind)) |*_resolved_import| { - const resolved_import: *const _resolver.Result = _resolved_import; - if (resolved_import.is_external) { - continue; - } + const resolved_import: *const _resolver.Result = _resolved_import; - const absolute_path = resolved_import.path_pair.primary.text; - const get_or_put_result = try this.resolved_paths.getOrPut(absolute_path); + const absolute_path = resolved_import.path_pair.primary.text; - module_data = BundledModuleData.get(this, resolved_import) orelse continue; - import_record.module_id = module_data.module_id; - import_record.is_bundled = true; - import_record.path = Fs.Path.init(module_data.import_path); - get_or_put_result.value_ptr.* = import_record.module_id; + const get_or_put_result = try this.resolved_paths.getOrPut(absolute_path); - if (!get_or_put_result.found_existing) { - try this.resolve_queue.writeItem(_resolved_import.*); - } - } else |err| { - if (comptime isDebug) { - Output.prettyErrorln("\n<r><red>{s}<r> on resolving \"{s}\" from \"{s}\"", .{ - @errorName(err), - import_record.path.text, - file_path.text, - }); - } + module_data = BundledModuleData.get(this, resolved_import) orelse continue; + import_record.module_id = module_data.module_id; + import_record.is_bundled = true; + import_record.path = Fs.Path.init(module_data.import_path); + get_or_put_result.value_ptr.* = import_record.module_id; - switch (err) { - error.ModuleNotFound => { - if (isPackagePath(import_record.path.text)) { - if (this.bundler.options.platform.isWebLike() and options.ExternalModules.isNodeBuiltin(import_record.path.text)) { - try this.log.addResolveError( - &source, - import_record.range, - this.allocator, - "Could not resolve Node.js builtin: \"{s}\".", - .{import_record.path.text}, - import_record.kind, - ); - } else { - try this.log.addResolveError( - &source, - import_record.range, - this.allocator, - "Could not resolve: \"{s}\". Maybe you need to \"npm install\" (or yarn/pnpm)?", - .{import_record.path.text}, - import_record.kind, - ); - } - } else { - try this.log.addResolveError( - &source, - import_record.range, - this.allocator, - "Could not resolve: \"{s}\"", - .{ - import_record.path.text, - }, - import_record.kind, - ); + if (!get_or_put_result.found_existing) { + try this.resolve_queue.writeItem(_resolved_import.*); + } + } else |err| { + if (comptime isDebug) { + Output.prettyErrorln("\n<r><red>{s}<r> on resolving \"{s}\" from \"{s}\"", .{ + @errorName(err), + import_record.path.text, + file_path.text, + }); + } + + switch (err) { + error.ModuleNotFound => { + if (isPackagePath(import_record.path.text)) { + if (this.bundler.options.platform.isWebLike() and options.ExternalModules.isNodeBuiltin(import_record.path.text)) { + try this.log.addResolveError( + &source, + import_record.range, + this.allocator, + "Could not resolve Node.js builtin: \"{s}\".", + .{import_record.path.text}, + import_record.kind, + ); + } else { + try this.log.addResolveError( + &source, + import_record.range, + this.allocator, + "Could not resolve: \"{s}\". Maybe you need to \"npm install\" (or yarn/pnpm)?", + .{import_record.path.text}, + import_record.kind, + ); + } + } else { + try this.log.addResolveError( + &source, + import_record.range, + this.allocator, + "Could not resolve: \"{s}\"", + .{ + import_record.path.text, + }, + import_record.kind, + ); + } + }, + // assume other errors are already in the log + else => {}, } - }, - // assume other errors are already in the log - else => {}, + } } } } @@ -1211,44 +1330,56 @@ pub fn NewBundler(cache_files: bool) type { // It should only have one part. ast.parts = ast.parts[ast.parts.len - 1 ..]; - - const code_offset = @truncate(u32, try this.tmpfile.getPos()); - const written = @truncate( - u32, - try js_printer.printCommonJS( - @TypeOf(writer), - writer, - ast, - js_ast.Symbol.Map.initList(symbols), - &source, - false, - js_printer.Options{ - .to_module_ref = Ref.RuntimeRef, - .bundle_export_ref = ast.bundle_export_ref.?, - .source_path = file_path, - .externals = ast.externals, - .indent = 0, - .module_hash = module_id, - .runtime_imports = ast.runtime_imports, - .prepend_part_value = &prepend_part, - .prepend_part_key = if (needs_prepend_part) closure.body.stmts.ptr else null, - }, - Linker, - &bundler.linker, - ), + var written: usize = undefined; + var code_offset: u32 = 0; + const write_result = + try js_printer.printCommonJSThreaded( + @TypeOf(writer), + writer, + ast, + js_ast.Symbol.Map.initList(symbols), + &source, + false, + js_printer.Options{ + .to_module_ref = Ref.RuntimeRef, + .bundle_export_ref = ast.bundle_export_ref.?, + .source_path = file_path, + .externals = ast.externals, + .indent = 0, + .module_hash = module_id, + .runtime_imports = ast.runtime_imports, + .prepend_part_value = &prepend_part, + .prepend_part_key = if (needs_prepend_part) closure.body.stmts.ptr else null, + }, + Linker, + &bundler.linker, + &this.write_lock, + std.fs.File, + this.tmpfile, + std.fs.File.getPos, ); + + if (comptime isDebug) { + Output.prettyln("{s}/{s} \n", .{ package.name, package_relative_path }); + Output.flush(); + } + + code_offset = write_result.off; + written = write_result.len; + // Faster to _not_ do the syscall // But there's some off-by-one error somewhere and more reliable to just do the lseek - this.tmpfile_byte_offset = @truncate(u32, try this.tmpfile.getPos()); + this.tmpfile_byte_offset = write_result.end_off; const code_length = this.tmpfile_byte_offset - code_offset; // std.debug.assert(code_length == written); - var package_get_or_put_entry = try this.package_list_map.getOrPut(package.hash); - if (comptime isDebug) { - Output.prettyln("{s}/{s} \n", .{ package.name, package_relative_path }); - Output.flush(); + this.list_lock.lock(); + defer { + this.list_lock.unlock(); } + var package_get_or_put_entry = try this.package_list_map.getOrPut(package.hash); + if (!package_get_or_put_entry.found_existing) { package_get_or_put_entry.value_ptr.* = @truncate(u32, this.package_list.items.len); try this.package_list.append( @@ -1287,12 +1418,12 @@ pub fn NewBundler(cache_files: bool) type { .js, .ts, => { - const entry = bundler.resolver.caches.fs.readFile( + const entry = bundler.resolver.caches.fs.readFileShared( bundler.fs, file_path.text, resolve.dirname_fd, - true, null, + shared_buffer, ) catch return; const source = logger.Source.initRecycledFile(Fs.File{ .path = file_path, .contents = entry.contents }, bundler.allocator) catch return null; @@ -1304,74 +1435,81 @@ pub fn NewBundler(cache_files: bool) type { try bundler.resolver.caches.js.scan( bundler.allocator, - &this.scan_pass_result, + scan_pass_result, opts, bundler.options.define, this.log, &source, ); - for (this.scan_pass_result.import_records.items) |*import_record, i| { - if (import_record.is_internal) { - continue; - } - - if (bundler.linker.resolver.resolve(source_dir, import_record.path.text, import_record.kind)) |*_resolved_import| { - const resolved_import: *const _resolver.Result = _resolved_import; - if (resolved_import.is_external) { + { + this.resolved_paths.lock(); + defer this.resolved_paths.unlock(); + for (scan_pass_result.import_records.items) |*import_record, i| { + if (import_record.is_internal) { continue; } - const get_or_put_result = try this.resolved_paths.getOrPut(resolved_import.path_pair.primary.text); + if (bundler.linker.resolver.resolve(source_dir, import_record.path.text, import_record.kind)) |*_resolved_import| { + if (_resolved_import.is_external) { + continue; + } - if (get_or_put_result.found_existing) { - continue; - } + const resolved_import: *const _resolver.Result = _resolved_import; - // Always enqueue unwalked import paths, but if it's not a node_module, we don't care about the hash - try this.resolve_queue.writeItem(_resolved_import.*); + const get_or_put_result = try this.resolved_paths.getOrPut(resolved_import.path_pair.primary.text); - if (BundledModuleData.get(this, resolved_import)) |module| { - get_or_put_result.value_ptr.* = module.module_id; - } - } else |err| { - switch (err) { - error.ModuleNotFound => { - if (isPackagePath(import_record.path.text)) { - if (this.bundler.options.platform.isWebLike() and options.ExternalModules.isNodeBuiltin(import_record.path.text)) { - try this.log.addResolveError( - &source, - import_record.range, - this.allocator, - "Could not resolve Node.js builtin: \"{s}\".", - .{import_record.path.text}, - import_record.kind, - ); + if (get_or_put_result.found_existing) { + continue; + } + + _resolved_import.path_pair.primary = Fs.Path.init(std.mem.span(try this.allocator.dupeZ(u8, _resolved_import.path_pair.primary.text))); + + // Always enqueue unwalked import paths, but if it's not a node_module, we don't care about the hash + try this.resolve_queue.writeItem(_resolved_import.*); + + if (BundledModuleData.get(this, resolved_import)) |module| { + get_or_put_result.value_ptr.* = module.module_id; + } + } else |err| { + switch (err) { + error.ModuleNotFound => { + if (isPackagePath(import_record.path.text)) { + if (this.bundler.options.platform.isWebLike() and options.ExternalModules.isNodeBuiltin(import_record.path.text)) { + try this.log.addResolveError( + &source, + import_record.range, + this.allocator, + "Could not resolve Node.js builtin: \"{s}\".", + .{import_record.path.text}, + import_record.kind, + ); + } else { + try this.log.addResolveError( + &source, + import_record.range, + this.allocator, + "Could not resolve: \"{s}\". Maybe you need to \"npm install\" (or yarn/pnpm)?", + .{import_record.path.text}, + import_record.kind, + ); + } } else { try this.log.addResolveError( &source, import_record.range, this.allocator, - "Could not resolve: \"{s}\". Maybe you need to \"npm install\" (or yarn/pnpm)?", - .{import_record.path.text}, + "Could not resolve: \"{s}\"", + .{ + import_record.path.text, + }, import_record.kind, ); } - } else { - try this.log.addResolveError( - &source, - import_record.range, - this.allocator, - "Could not resolve: \"{s}\"", - .{ - import_record.path.text, - }, - import_record.kind, - ); - } - }, - // assume other errors are already in the log - else => {}, + }, + // assume other errors are already in the log + else => {}, + } } } } diff --git a/src/cache.zig b/src/cache.zig index 2026b0997..533e35a38 100644 --- a/src/cache.zig +++ b/src/cache.zig @@ -63,6 +63,96 @@ pub fn NewCache(comptime cache_files: bool) type { c.entries.deinit(); } + pub fn readFileShared( + c: *Fs, + _fs: *fs.FileSystem, + path: string, + dirname_fd: StoredFileDescriptorType, + _file_handle: ?StoredFileDescriptorType, + shared: *MutableString, + ) !Entry { + var rfs = _fs.fs; + + if (cache_files) { + { + c.mutex.lock(); + defer c.mutex.unlock(); + if (c.entries.get(path)) |entry| { + return entry; + } + } + } + + var file_handle: std.fs.File = if (_file_handle) |__file| std.fs.File{ .handle = __file } else undefined; + + if (_file_handle == null) { + if (FeatureFlags.store_file_descriptors and dirname_fd > 0) { + file_handle = try std.fs.Dir.openFile(std.fs.Dir{ .fd = dirname_fd }, std.fs.path.basename(path), .{ .read = true }); + } else { + file_handle = try std.fs.openFileAbsolute(path, .{ .read = true }); + } + } + + defer { + if (rfs.needToCloseFiles() and _file_handle == null) { + file_handle.close(); + } + } + + // If the file's modification key hasn't changed since it was cached, assume + // the contents of the file are also the same and skip reading the file. + var mod_key: ?fs.FileSystem.Implementation.ModKey = rfs.modKeyWithFile(path, file_handle) catch |err| handler: { + switch (err) { + error.FileNotFound, error.AccessDenied => { + return err; + }, + else => { + if (isDebug) { + Output.printError("modkey error: {s}", .{@errorName(err)}); + } + break :handler null; + }, + } + }; + + var file: fs.File = undefined; + if (mod_key) |modk| { + file = rfs.readFileWithHandle(path, modk.size, file_handle, true, shared) catch |err| { + if (isDebug) { + Output.printError("{s}: readFile error -- {s}", .{ path, @errorName(err) }); + } + return err; + }; + } else { + file = rfs.readFileWithHandle(path, null, file_handle, true, shared) catch |err| { + if (isDebug) { + Output.printError("{s}: readFile error -- {s}", .{ path, @errorName(err) }); + } + return err; + }; + } + + const entry = Entry{ + .contents = file.contents, + .mod_key = mod_key, + .fd = if (FeatureFlags.store_file_descriptors) file_handle.handle else 0, + }; + + if (cache_files) { + c.mutex.lock(); + defer c.mutex.unlock(); + var res = c.entries.getOrPut(path) catch unreachable; + + if (res.found_existing) { + res.value_ptr.*.deinit(c.entries.allocator); + } + res.value_ptr.* = entry; + return res.value_ptr.*; + } else { + return entry; + } + } + pub fn readFile( c: *Fs, _fs: *fs.FileSystem, diff --git a/src/cli.zig b/src/cli.zig index f6b444087..83ebea850 100644 --- a/src/cli.zig +++ b/src/cli.zig @@ -139,33 +139,34 @@ pub const Arguments = struct { pub const ParamType = clap.Param(clap.Help); - const params: [25]ParamType = brk: { + const params: [26]ParamType = brk: { @setEvalBranchQuota(9999); break :brk [_]ParamType{ - clap.parseParam("-r, --resolve <STR> Determine import/require behavior. \"disable\" ignores. \"dev\" bundles node_modules and builds everything else as independent entry points") catch unreachable, - clap.parseParam("-h, --help Display this help and exit. ") catch unreachable, - clap.parseParam("-d, --define <STR>... Substitute K:V while parsing, e.g. --define process.env.NODE_ENV:development") catch unreachable, - clap.parseParam("-l, --loader <STR>... Parse files with .ext:loader, e.g. --loader .js:jsx. Valid loaders: jsx, js, json, tsx (not implemented yet), ts (not implemented yet), css (not implemented yet)") catch unreachable, - clap.parseParam("-o, --outdir <STR> Save output to directory (default: \"out\" if none provided and multiple entry points passed)") catch unreachable, - clap.parseParam("-e, --external <STR>... Exclude module from transpilation (can use * wildcards). ex: -e react") catch unreachable, - clap.parseParam("-i, --inject <STR>... Inject module at the top of every file") catch unreachable, - clap.parseParam("--cwd <STR> Absolute path to resolve files & entry points from. This just changes the process' cwd.") catch unreachable, clap.parseParam("--use <STR> Choose a framework, e.g. \"--use next\". It checks first for a package named \"bun-framework-packagename\" and then \"packagename\".") catch unreachable, - clap.parseParam("--origin <STR> Rewrite import paths to start with --origin. Default: \"/\"") catch unreachable, - clap.parseParam("--static-dir <STR> Top-level directory for .html files, fonts or anything external. Defaults to \"<cwd>/public\", to match create-react-app and Next.js") catch unreachable, - clap.parseParam("--extension-order <STR>... defaults to: .tsx,.ts,.jsx,.js,.json ") catch unreachable, - clap.parseParam("--tsconfig-override <STR> Load tsconfig from path instead of cwd/tsconfig.json") catch unreachable, - clap.parseParam("--platform <STR> \"browser\" or \"node\". Defaults to \"browser\"") catch unreachable, - clap.parseParam("--main-fields <STR>... Main fields to lookup in package.json. Defaults to --platform dependent") catch unreachable, + clap.parseParam("--bunfile <STR> Use a .bun file (default: node_modules.bun)") catch unreachable, + clap.parseParam("--server-bunfile <STR> Use a .server.bun file (default: node_modules.server.bun)") catch unreachable, + clap.parseParam("--cwd <STR> Absolute path to resolve files & entry points from. This just changes the process' cwd.") catch unreachable, clap.parseParam("--disable-react-fast-refresh Disable React Fast Refresh") catch unreachable, + clap.parseParam("--extension-order <STR>... defaults to: .tsx,.ts,.jsx,.js,.json ") catch unreachable, clap.parseParam("--jsx-factory <STR> Changes the function called when compiling JSX elements using the classic JSX runtime") catch unreachable, clap.parseParam("--jsx-fragment <STR> Changes the function called when compiling JSX fragments using the classic JSX runtime") catch unreachable, clap.parseParam("--jsx-import-source <STR> Declares the module specifier to be used for importing the jsx and jsxs factory functions. Default: \"react\"") catch unreachable, - clap.parseParam("--jsx-runtime <STR> \"automatic\" (default) or \"classic\"") catch unreachable, clap.parseParam("--jsx-production Use jsx instead of jsxDEV (default) for the automatic runtime") catch unreachable, - clap.parseParam("--bunfile <STR> Use a .bun file (default: node_modules.bun)") catch unreachable, - clap.parseParam("--server-bunfile <STR> Use a .server.bun file (default: node_modules.server.bun)") catch unreachable, - clap.parseParam("--production [work in progress] generate production code") catch unreachable, + clap.parseParam("--jsx-runtime <STR> \"automatic\" (default) or \"classic\"") catch unreachable, + clap.parseParam("--main-fields <STR>... Main fields to lookup in package.json. Defaults to --platform dependent") catch unreachable, + clap.parseParam("--no-summary Don't print a summary (when generating .bun") catch unreachable, + clap.parseParam("--origin <STR> Rewrite import paths to start with --origin. Default: \"/\"") catch unreachable, + clap.parseParam("--platform <STR> \"browser\" or \"node\". Defaults to \"browser\"") catch unreachable, + clap.parseParam("--production [not implemented] generate production code") catch unreachable, + clap.parseParam("--static-dir <STR> Top-level directory for .html files, fonts or anything external. Defaults to \"<cwd>/public\", to match create-react-app and Next.js") catch unreachable, + clap.parseParam("--tsconfig-override <STR> Load tsconfig from path instead of cwd/tsconfig.json") catch unreachable, + clap.parseParam("-d, --define <STR>... Substitute K:V while parsing, e.g. --define process.env.NODE_ENV:development") catch unreachable, + clap.parseParam("-e, --external <STR>... Exclude module from transpilation (can use * wildcards). ex: -e react") catch unreachable, + clap.parseParam("-h, --help Display this help and exit. ") catch unreachable, + clap.parseParam("-i, --inject <STR>... Inject module at the top of every file") catch unreachable, + clap.parseParam("-l, --loader <STR>... Parse files with .ext:loader, e.g. --loader .js:jsx. Valid loaders: jsx, js, json, tsx (not implemented yet), ts (not implemented yet), css (not implemented yet)") catch unreachable, + clap.parseParam("-o, --outdir <STR> Save output to directory (default: \"out\" if none provided and multiple entry points passed)") catch unreachable, + clap.parseParam("-r, --resolve <STR> Determine import/require behavior. \"disable\" ignores. \"dev\" bundles node_modules and builds everything else as independent entry points") catch unreachable, clap.parseParam("<POS>... ") catch unreachable, }; @@ -213,6 +214,7 @@ pub const Arguments = struct { .inject = args.options("--inject"), .extension_order = args.options("--extension-order"), .entry_points = undefined, + .no_summary = args.flag("--no-summary"), }; const print_help = args.flag("--help"); diff --git a/src/cli/bun_command.zig b/src/cli/bun_command.zig index 169d0ab44..1a63a140d 100644 --- a/src/cli/bun_command.zig +++ b/src/cli/bun_command.zig @@ -172,8 +172,11 @@ pub const BunCommand = struct { try log.print(Output.errorWriter()); } else { var elapsed = @divTrunc(std.time.nanoTimestamp() - ctx.start_time, @as(i128, std.time.ns_per_ms)); - var bundle = NodeModuleBundle.init(node_modules, allocator); - bundle.printSummary(); + const print_summary = !(ctx.args.no_summary orelse false); + if (print_summary) { + var bundle = NodeModuleBundle.init(node_modules, allocator); + bundle.printSummary(); + } const indent = comptime " "; Output.prettyln(indent ++ "<d>{d:6}ms elapsed", .{@intCast(u32, elapsed)}); diff --git a/src/darwin_c.zig b/src/darwin_c.zig index c6fc6a1f3..ddc678a39 100644 --- a/src/darwin_c.zig +++ b/src/darwin_c.zig @@ -156,3 +156,38 @@ pub fn stat_absolute(path: [:0]const u8) StatError!Stat { .ctime = @as(i128, ctime.tv_sec) * std.time.ns_per_s + ctime.tv_nsec, }; } + +pub const struct_fstore = extern struct { + fst_flags: c_uint, + fst_posmode: c_int, + fst_offset: off_t, + fst_length: off_t, + fst_bytesalloc: off_t, +}; +pub const fstore_t = struct_fstore; + +pub const F_ALLOCATECONTIG = @as(c_int, 0x00000002); +pub const F_ALLOCATEALL = @as(c_int, 0x00000004); +pub const F_PEOFPOSMODE = @as(c_int, 3); +pub const F_VOLPOSMODE = @as(c_int, 4); + +pub fn preallocate_file(fd: os.fd_t, offset: off_t, len: off_t) !void { + var fstore = zeroes(fstore_t); + fstore.fst_flags = F_ALLOCATECONTIG; + fstore.fst_posmode = F_PEOFPOSMODE; + fstore.fst_offset = 0; + fstore.fst_length = len + offset; + + // Based on https://api.kde.org/frameworks/kcoreaddons/html/posix__fallocate__mac_8h_source.html + var rc = os.system.fcntl(fd, F_PREALLOCATE, &fstore); + + switch (rc) { + 0 => return, + else => { + fstore.fst_flags = F_ALLOCATEALL; + rc = os.system.fcntl(fd, F_PREALLOCATE, &fstore); + }, + } + + std.mem.doNotOptimizeAway(&fstore); +} diff --git a/src/fs.zig b/src/fs.zig index e35b537c1..2bf4cbeb7 100644 --- a/src/fs.zig +++ b/src/fs.zig @@ -13,8 +13,6 @@ const hash_map = @import("hash_map.zig"); // pub const FilesystemImplementation = @import("fs_impl.zig"); -threadlocal var scratch_lookup_buffer: [256]u8 = undefined; - pub const Preallocate = struct { pub const Counts = struct { pub const dir_entry: usize = 512; @@ -184,12 +182,18 @@ pub const FileSystem = struct { // entry.name only lives for the duration of the iteration const name = if (entry.name.len >= strings.StringOrTinyString.Max) + strings.StringOrTinyString.init(try FileSystem.FilenameStore.instance.append(@TypeOf(entry.name), entry.name)) + else + strings.StringOrTinyString.init(entry.name); + + const name_lowercased = if (entry.name.len >= strings.StringOrTinyString.Max) strings.StringOrTinyString.init(try FileSystem.FilenameStore.instance.appendLowerCase(@TypeOf(entry.name), entry.name)) else strings.StringOrTinyString.initLowerCase(entry.name); const result = Entry{ .base_ = name, + .base_lowercase_ = name_lowercased, .dir = dir.dir, .mutex = Mutex.init(), // Call "stat" lazily for performance. The "@material-ui/icons" package @@ -201,9 +205,18 @@ pub const FileSystem = struct { .kind = _kind, }, }; - const index = try EntryStore.instance.append(result); + const stored = try EntryStore.instance.appendGet(result); - try dir.data.put(EntryStore.instance.at(index).?.base(), index); + const stored_name = stored.value.base(); + + try dir.data.put(stored.value.base_lowercase(), stored.index); + if (comptime FeatureFlags.verbose_fs) { + if (_kind == .dir) { + Output.prettyln(" + {s}/", .{stored_name}); + } else { + Output.prettyln(" + {s}", .{stored_name}); + } + } } pub fn updateDir(i: *DirEntry, dir: string) void { @@ -219,6 +232,10 @@ pub const FileSystem = struct { } pub fn init(dir: string, allocator: *std.mem.Allocator) DirEntry { + if (comptime FeatureFlags.verbose_fs) { + Output.prettyln("\n {s}", .{dir}); + } + return DirEntry{ .dir = dir, .data = EntryMap.init(allocator) }; } @@ -240,21 +257,18 @@ pub const FileSystem = struct { pub fn get(entry: *const DirEntry, _query: string) ?Entry.Lookup { if (_query.len == 0) return null; - - var end: usize = 0; + var scratch_lookup_buffer: [256]u8 = undefined; std.debug.assert(scratch_lookup_buffer.len >= _query.len); - for (_query) |c, i| { - scratch_lookup_buffer[i] = std.ascii.toLower(c); - end = i; - } - const query = scratch_lookup_buffer[0 .. end + 1]; + + const query = strings.copyLowercase(_query, &scratch_lookup_buffer); const result_index = entry.data.get(query) orelse return null; const result = EntryStore.instance.at(result_index) orelse return null; - if (!strings.eql(result.base(), query)) { + const basename = result.base(); + if (!strings.eql(basename, _query)) { return Entry.Lookup{ .entry = result, .diff_case = Entry.Lookup.DifferentCase{ .dir = entry.dir, .query = _query, - .actual = result.base(), + .actual = basename, } }; } @@ -271,12 +285,17 @@ pub const FileSystem = struct { const result_index = entry.data.getWithHash(&query, query_hashed) orelse return null; const result = EntryStore.instance.at(result_index) orelse return null; - if (!strings.eqlComptime(result.base(), query)) { - return Entry.Lookup{ .entry = result, .diff_case = Entry.Lookup.DifferentCase{ - .dir = entry.dir, - .query = &query, - .actual = result.base(), - } }; + const basename = result.base(); + + if (!strings.eqlComptime(basename, comptime query[0..query_str.len])) { + return Entry.Lookup{ + .entry = result, + .diff_case = Entry.Lookup.DifferentCase{ + .dir = entry.dir, + .query = &query, + .actual = basename, + }, + }; } return Entry.Lookup{ .entry = result, .diff_case = null }; @@ -299,6 +318,10 @@ pub const FileSystem = struct { cache: Cache = Cache{}, dir: string, base_: strings.StringOrTinyString, + + // Necessary because the hash table uses it as a key + base_lowercase_: strings.StringOrTinyString, + mutex: Mutex, need_stat: bool = true, @@ -306,6 +329,10 @@ pub const FileSystem = struct { return this.base_.slice(); } + pub inline fn base_lowercase(this: *const Entry) string { + return this.base_lowercase_.slice(); + } + pub const Lookup = struct { entry: *Entry, diff_case: ?DifferentCase, @@ -464,7 +491,7 @@ pub const FileSystem = struct { entries_mutex: Mutex = Mutex.init(), entries: *EntriesOption.Map, allocator: *std.mem.Allocator, - limiter: *Limiter, + // limiter: *Limiter, cwd: string, parent_fs: *FileSystem = undefined, file_limit: usize = 32, @@ -533,9 +560,8 @@ pub const FileSystem = struct { return limit.cur; } - threadlocal var _entries_option_map: *EntriesOption.Map = undefined; - threadlocal var _entries_option_map_loaded: bool = false; - var __limiter: Limiter = undefined; + var _entries_option_map: *EntriesOption.Map = undefined; + var _entries_option_map_loaded: bool = false; pub fn init( allocator: *std.mem.Allocator, cwd: string, @@ -545,7 +571,6 @@ pub const FileSystem = struct { if (!_entries_option_map_loaded) { _entries_option_map = EntriesOption.Map.init(allocator); _entries_option_map_loaded = true; - __limiter = Limiter.init(allocator, file_limit); } return RealFS{ @@ -554,7 +579,6 @@ pub const FileSystem = struct { .cwd = cwd, .file_limit = file_limit, .file_quota = file_limit, - .limiter = &__limiter, }; } @@ -628,8 +652,8 @@ pub const FileSystem = struct { } pub fn modKey(fs: *RealFS, path: string) anyerror!ModKey { - fs.limiter.before(); - defer fs.limiter.after(); + // fs.limiter.before(); + // defer fs.limiter.after(); var file = try std.fs.openFileAbsolute(path, std.fs.File.OpenFlags{ .read = true }); defer { if (fs.needToCloseFiles()) { @@ -690,8 +714,8 @@ pub const FileSystem = struct { _dir: string, handle: std.fs.Dir, ) !DirEntry { - fs.limiter.before(); - defer fs.limiter.after(); + // fs.limiter.before(); + // defer fs.limiter.after(); var iter: std.fs.Dir.Iterator = handle.iterate(); var dir = DirEntry.init(_dir, fs.allocator); @@ -710,9 +734,7 @@ pub const FileSystem = struct { } fn readDirectoryError(fs: *RealFS, dir: string, err: anyerror) !*EntriesOption { - if (FeatureFlags.enable_entry_cache) { - fs.entries_mutex.lock(); - defer fs.entries_mutex.unlock(); + if (comptime FeatureFlags.enable_entry_cache) { var get_or_put_result = try fs.entries.getOrPut(dir); var opt = try fs.entries.put(&get_or_put_result, EntriesOption{ .err = DirEntry.Err{ .original_err = err, .canonical_error = err }, @@ -732,11 +754,16 @@ pub const FileSystem = struct { pub fn readDirectory(fs: *RealFS, _dir: string, _handle: ?std.fs.Dir) !*EntriesOption { var dir = _dir; var cache_result: ?allocators.Result = null; - - if (FeatureFlags.enable_entry_cache) { + if (comptime FeatureFlags.enable_entry_cache) { fs.entries_mutex.lock(); - defer fs.entries_mutex.unlock(); + } + defer { + if (comptime FeatureFlags.enable_entry_cache) { + fs.entries_mutex.unlock(); + } + } + if (comptime FeatureFlags.enable_entry_cache) { cache_result = try fs.entries.getOrPut(dir); if (cache_result.?.hasCheckedIfExists()) { @@ -767,14 +794,14 @@ pub const FileSystem = struct { return fs.readDirectoryError(dir, err) catch unreachable; }; - if (FeatureFlags.enable_entry_cache) { - fs.entries_mutex.lock(); - defer fs.entries_mutex.unlock(); + if (comptime FeatureFlags.enable_entry_cache) { const result = EntriesOption{ .entries = entries, }; - return try fs.entries.put(&cache_result.?, result); + var out = try fs.entries.put(&cache_result.?, result); + + return out; } temp_entries_option = EntriesOption{ .entries = entries }; @@ -865,8 +892,6 @@ pub const FileSystem = struct { const absolute_path_c: [:0]const u8 = outpath[0..entry_path.len :0]; - fs.limiter.before(); - defer fs.limiter.after(); var stat = try C.lstat_absolute(absolute_path_c); const is_symlink = stat.kind == std.fs.File.Kind.SymLink; var _kind = stat.kind; @@ -1018,45 +1043,6 @@ pub const Path = struct { name: string, is_parent_package: bool = false, }; - // "/foo/bar/node_modules/react/index.js" => "index.js" - // "/foo/bar/node_modules/.pnpm/react@17.0.1/node_modules/react/index.js" => "index.js" - // "/css-stress-test/node_modules/next/dist/compiled/neo-async/async.js" => "dist/compiled/neo-async/async.js " - pub fn packageRelativePathString(this: *const Path, name: string) PackageRelative { - // TODO: we don't need to print this buffer, this is inefficient - var buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined; - const search_path = std.fmt.bufPrint(&buffer, std.fs.path.sep_str ++ "node_modules" ++ std.fs.path.sep_str ++ "{s}" ++ std.fs.path.sep_str, .{name}) catch return .{ .name = name, .path = this.text }; - if (strings.lastIndexOf(this.canonicalNodeModuleText(), search_path)) |i| { - return .{ .path = this.canonicalNodeModuleText()[i + search_path.len ..], .name = name }; - } - - if (strings.lastIndexOf(this.text, search_path[0.."/node_modules/".len])) |i| { - const node_modules_relative = this.text[i + "/node_modules/".len ..]; - - if (strings.indexOfChar(node_modules_relative, std.fs.path.sep)) |j| { - return .{ .path = node_modules_relative[j + 1 ..], .name = node_modules_relative[0..j], .is_parent_package = true }; - } - } - - return .{ .path = this.text, .name = name }; - } - - pub fn nodeModulesRelativePathString( - this: *const Path, - name: string, - ) string { - // TODO: we don't need to print this buffer, this is inefficient - var buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined; - const search_path = std.fmt.bufPrint(&buffer, std.fs.path.sep_str ++ "node_modules" ++ std.fs.path.sep_str ++ "{s}" ++ std.fs.path.sep_str, .{name}) catch return this.text; - if (strings.lastIndexOf(this.canonicalNodeModuleText(), search_path)) |i| { - return this.canonicalNodeModuleText()[i + search_path.len - name.len - 1 ..]; - } - - return this.canonicalNodeModuleText(); - } - - pub inline fn canonicalNodeModuleText(this: *const Path) string { - return this.text; - } pub fn jsonStringify(self: *const @This(), options: anytype, writer: anytype) !void { return try std.json.stringify(self.text, options, writer); diff --git a/src/global.zig b/src/global.zig index 780df0f3e..cb0e351b2 100644 --- a/src/global.zig +++ b/src/global.zig @@ -9,8 +9,14 @@ pub usingnamespace @import("env.zig"); pub const FeatureFlags = @import("feature_flags.zig"); pub const Output = struct { + // These are threadlocal so we don't have stdout/stderr writing on top of each other threadlocal var source: Source = undefined; threadlocal var source_set: bool = false; + + // These are not threadlocal so we avoid opening stdout/stderr for every thread + var stderr_stream: Source.StreamType = undefined; + var stdout_stream: Source.StreamType = undefined; + var stdout_stream_set = false; pub const Source = struct { pub const StreamType: type = brk: { if (isWasm) { @@ -44,14 +50,26 @@ pub const Output = struct { }; } + pub fn configureThread() void { + std.debug.assert(stdout_stream_set); + source = Source.init(stdout_stream, stderr_stream); + } + pub fn set(_source: *Source) void { source = _source.*; source_set = true; - enable_ansi_colors = _source.error_stream.supportsAnsiEscapeCodes(); + if (!stdout_stream_set) { + stdout_stream_set = true; - is_stdout_piped = !_source.stream.isTty(); - is_stderr_piped = !_source.error_stream.isTty(); + enable_ansi_colors = _source.error_stream.supportsAnsiEscapeCodes(); + + is_stdout_piped = !_source.stream.isTty(); + is_stderr_piped = !_source.error_stream.isTty(); + + stdout_stream = _source.stream; + stderr_stream = _source.error_stream; + } } }; pub var enable_ansi_colors = isNative; diff --git a/src/js_ast.zig b/src/js_ast.zig index f6bd9e24e..52594aae0 100644 --- a/src/js_ast.zig +++ b/src/js_ast.zig @@ -46,7 +46,7 @@ pub fn NewBaseStore(comptime Union: anytype, comptime count: usize) type { }; block: Block, - overflow_ptrs: [10_000]*Block = undefined, + overflow_ptrs: [4096 * 3]*Block = undefined, overflow: []*Block = &([_]*Block{}), overflow_used: usize = 0, allocator: *Allocator, @@ -3840,6 +3840,19 @@ pub const Scope = struct { strict_mode: StrictModeKind = StrictModeKind.sloppy_mode, + pub fn reset(this: *Scope) void { + this.children.clearRetainingCapacity(); + this.generated.clearRetainingCapacity(); + this.members.clearRetainingCapacity(); + this.parent = null; + this.id = 0; + this.label_ref = null; + this.label_stmt_is_loop = false; + this.contains_direct_eval = false; + this.strict_mode = .sloppy_mode; + this.kind = .block; + } + // Do not make this a packed struct // Two hours of debugging time lost to that. // It causes a crash due to undefined memory @@ -3881,17 +3894,6 @@ pub const Scope = struct { pub fn kindStopsHoisting(s: *Scope) bool { return @enumToInt(s.kind) >= @enumToInt(Kind.entry); } - - pub fn initPtr(allocator: *std.mem.Allocator) !*Scope { - var scope = try allocator.create(Scope); - scope.* = Scope{ - .members = @TypeOf(scope.members).init(allocator), - .children = @TypeOf(scope.children).init(allocator), - .generated = @TypeOf(scope.generated).init(allocator), - .parent = null, - }; - return scope; - } }; pub fn printmem(comptime format: string, args: anytype) void { diff --git a/src/js_parser/js_parser_test.zig b/src/js_parser/js_parser_test.zig index 0d76efc37..b1771ac1c 100644 --- a/src/js_parser/js_parser_test.zig +++ b/src/js_parser/js_parser_test.zig @@ -177,7 +177,7 @@ const SymbolList = [][]Symbol; fn expectPrinted(t: *Tester, contents: string, expected: string, src: anytype) !void { if (alloc.needs_setup) { - try alloc.setup(std.heap.c_allocator); + try alloc.setup(default_allocator); var __source = Output.Source.init(std.io.getStdOut(), std.io.getStdErr()); Output.Source.set(&__source); @@ -225,7 +225,7 @@ fn expectPrinted(t: *Tester, contents: string, expected: string, src: anytype) ! const PRINT_AST = false; test "expectPrint" { - var t_ = Tester.t(std.heap.c_allocator); + var t_ = Tester.t(default_allocator); var t = &t_; // try expectPrinted(t, @embedFile("../test/fixtures/function-scope-bug.jsx"), @embedFile("../test/fixtures/function-scope-bug.jsx"), @src()); try expectPrinted(t, @embedFile("../test/fixtures/cannot-assign-to-import-bug.js"), @embedFile("../test/fixtures/cannot-assign-to-import-bug.js"), @src()); diff --git a/src/js_printer.zig b/src/js_printer.zig index 1fd6463da..9f039eb5e 100644 --- a/src/js_printer.zig +++ b/src/js_printer.zig @@ -7,7 +7,7 @@ const options = @import("options.zig"); const alloc = @import("alloc.zig"); const rename = @import("renamer.zig"); const runtime = @import("runtime.zig"); - +const Lock = @import("./lock.zig").Lock; const Api = @import("./api/schema.zig").Api; const fs = @import("fs.zig"); usingnamespace @import("global.zig"); @@ -3796,8 +3796,10 @@ const FileWriterInternal = struct { pub fn done( ctx: *FileWriterInternal, ) anyerror!void { - _ = try ctx.file.writeAll(buffer.toOwnedSliceLeaky()); - buffer.reset(); + defer buffer.reset(); + const result = buffer.toOwnedSliceLeaky(); + + _ = try ctx.file.writeAll(result); } pub fn flush( @@ -3954,3 +3956,69 @@ pub fn printCommonJS( return @intCast(usize, std.math.max(printer.writer.written, 0)); } + +pub const WriteResult = struct { + off: u32, + len: usize, + end_off: u32, +}; + +pub fn printCommonJSThreaded( + comptime Writer: type, + _writer: Writer, + tree: Ast, + symbols: js_ast.Symbol.Map, + source: *const logger.Source, + ascii_only: bool, + opts: Options, + comptime LinkerType: type, + linker: ?*LinkerType, + lock: *Lock, + comptime GetPosType: type, + getter: GetPosType, + comptime getPos: fn (ctx: GetPosType) anyerror!u64, +) !WriteResult { + const PrinterType = NewPrinter(false, Writer, LinkerType, true, false); + var writer = _writer; + var printer = try PrinterType.init( + writer, + &tree, + source, + symbols, + opts, + linker, + ); + for (tree.parts) |part| { + for (part.stmts) |stmt| { + try printer.printStmt(stmt); + if (printer.writer.getError()) {} else |err| { + return err; + } + } + } + + // Add a couple extra newlines at the end + printer.writer.print(@TypeOf("\n\n"), "\n\n"); + + var result: WriteResult = .{ .off = 0, .len = 0, .end_off = 0 }; + { + defer lock.unlock(); + lock.lock(); + result.off = @truncate(u32, try getPos(getter)); + if (comptime isMac) { + // Don't bother preallocate the file if it's less than 1 KB. Preallocating is potentially two syscalls + if (printer.writer.written > 1024) { + try C.preallocate_file( + getter.handle, + @intCast(std.os.off_t, 0), + @intCast(std.os.off_t, printer.writer.written), + ); + } + } + try printer.writer.done(); + result.end_off = @truncate(u32, try getPos(getter)); + } + + result.len = @intCast(usize, std.math.max(printer.writer.written, 0)); + return result; +} diff --git a/src/router.zig b/src/router.zig index a1f1f826b..4959fd5cc 100644 --- a/src/router.zig +++ b/src/router.zig @@ -117,7 +117,8 @@ pub fn loadRoutes( if (root_dir_info.getEntriesConst()) |entries| { var iter = entries.data.iterator(); outer: while (iter.next()) |entry_ptr| { - const entry = Fs.FileSystem.DirEntry.EntryStore.instance.at(entry_ptr.value) orelse continue; + const entry_index = entry_ptr.value; + const entry = Fs.FileSystem.DirEntry.EntryStore.instance.at(entry_index) orelse continue; if (entry.base()[0] == '.') { continue :outer; } @@ -138,7 +139,7 @@ pub fn loadRoutes( entry.base(), Fs.PathName.init(entry.dir[this.config.dir.len..]).dirWithTrailingSlash(), "", - entry_ptr.value, + entry_index, ); route.parent = parent; @@ -171,7 +172,7 @@ pub fn loadRoutes( // we extend the pointer length by one to get it's slash entry.dir.ptr[this.config.dir.len..entry.dir.len], extname, - entry_ptr.value, + entry_index, ); route.parent = parent; diff --git a/src/string_mutable.zig b/src/string_mutable.zig index 755465b55..a6149ff44 100644 --- a/src/string_mutable.zig +++ b/src/string_mutable.zig @@ -17,6 +17,7 @@ pub const MutableString = struct { } pub fn deinit(str: *MutableString) void { + str.list.expandToCapacity(); str.list.deinit(str.allocator); } |