diff options
author | 2021-08-31 15:03:40 -0700 | |
---|---|---|
committer | 2021-08-31 15:03:40 -0700 | |
commit | 6a5f34a6bc0546a8f17b8fc0af7688a831a797ad (patch) | |
tree | 8ed040425ccac8a7e4b04a9f12c2d1174b4cb5b5 /src | |
parent | bd9f137b1bfb5bc3b215515ff9305e70a638daf9 (diff) | |
download | bun-6a5f34a6bc0546a8f17b8fc0af7688a831a797ad.tar.gz bun-6a5f34a6bc0546a8f17b8fc0af7688a831a797ad.tar.zst bun-6a5f34a6bc0546a8f17b8fc0af7688a831a797ad.zip |
Fallback, fragments, printer compat, better errors
Former-commit-id: 486e8c9d460eeebea024e96dbabcb7f2bfaffafb
Diffstat (limited to 'src')
-rw-r--r-- | src/.prettierignore | 1 | ||||
-rw-r--r-- | src/api/schema.d.ts | 183 | ||||
-rw-r--r-- | src/api/schema.js | 757 | ||||
-rw-r--r-- | src/api/schema.peechy | 132 | ||||
-rw-r--r-- | src/api/schema.zig | 3487 | ||||
-rw-r--r-- | src/bundler.zig | 165 | ||||
-rw-r--r-- | src/cli/bun_command.zig | 4 | ||||
-rw-r--r-- | src/fallback.html | 17 | ||||
-rw-r--r-- | src/fallback.ts | 24 | ||||
-rw-r--r-- | src/fallback.version | 1 | ||||
-rw-r--r-- | src/http.zig | 452 | ||||
-rw-r--r-- | src/javascript/jsc/bindings/exports.zig | 185 | ||||
-rw-r--r-- | src/javascript/jsc/javascript.zig | 169 | ||||
-rw-r--r-- | src/javascript/jsc/webcore/response.zig | 19 | ||||
-rw-r--r-- | src/js_ast.zig | 2 | ||||
-rw-r--r-- | src/js_parser/js_parser.zig | 9 | ||||
-rw-r--r-- | src/js_printer.zig | 20 | ||||
-rw-r--r-- | src/lock.zig | 162 | ||||
-rw-r--r-- | src/logger.zig | 67 | ||||
-rw-r--r-- | src/node_module_bundle.zig | 1 | ||||
-rw-r--r-- | src/options.zig | 213 | ||||
-rw-r--r-- | src/resolver/package_json.zig | 41 | ||||
-rw-r--r-- | src/resolver/resolver.zig | 20 | ||||
-rw-r--r-- | src/router.zig | 2 | ||||
-rw-r--r-- | src/runtime.version | 2 | ||||
-rw-r--r-- | src/runtime.zig | 109 | ||||
-rw-r--r-- | src/runtime/hmr.ts | 2 | ||||
-rw-r--r-- | src/test/fixtures/fragment.jsx | 1 |
28 files changed, 4319 insertions, 1928 deletions
diff --git a/src/.prettierignore b/src/.prettierignore new file mode 100644 index 000000000..b50b4c262 --- /dev/null +++ b/src/.prettierignore @@ -0,0 +1 @@ +fallback.html
\ No newline at end of file diff --git a/src/api/schema.d.ts b/src/api/schema.d.ts index fc03c82b0..d7e66820e 100644 --- a/src/api/schema.d.ts +++ b/src/api/schema.d.ts @@ -37,6 +37,69 @@ type uint32 = number; 7: "json", json: "json" } + export enum FrameworkEntryPointType { + client = 1, + server = 2, + fallback = 3 + } + export const FrameworkEntryPointTypeKeys = { + 1: "client", + client: "client", + 2: "server", + server: "server", + 3: "fallback", + fallback: "fallback" + } + export enum StackFrameScope { + Eval = 1, + Module = 2, + Function = 3, + Global = 4, + Wasm = 5, + Constructor = 6 + } + export const StackFrameScopeKeys = { + 1: "Eval", + Eval: "Eval", + 2: "Module", + Module: "Module", + 3: "Function", + Function: "Function", + 4: "Global", + Global: "Global", + 5: "Wasm", + Wasm: "Wasm", + 6: "Constructor", + Constructor: "Constructor" + } + export enum FallbackStep { + ssr_disabled = 1, + create_vm = 2, + configure_router = 3, + configure_defines = 4, + resolve_entry_point = 5, + load_entry_point = 6, + eval_entry_point = 7, + fetch_event_handler = 8 + } + export const FallbackStepKeys = { + 1: "ssr_disabled", + ssr_disabled: "ssr_disabled", + 2: "create_vm", + create_vm: "create_vm", + 3: "configure_router", + configure_router: "configure_router", + 4: "configure_defines", + configure_defines: "configure_defines", + 5: "resolve_entry_point", + resolve_entry_point: "resolve_entry_point", + 6: "load_entry_point", + load_entry_point: "load_entry_point", + 7: "eval_entry_point", + eval_entry_point: "eval_entry_point", + 8: "fetch_event_handler", + fetch_event_handler: "fetch_event_handler" + } export enum ResolveMode { disable = 1, lazy = 2, @@ -132,13 +195,13 @@ type uint32 = number; 2: "fail", fail: "fail" } - export enum MessageKind { + export enum MessageLevel { err = 1, warn = 2, note = 3, debug = 4 } - export const MessageKindKeys = { + export const MessageLevelKeys = { 1: "err", err: "err", 2: "warn", @@ -193,6 +256,62 @@ type uint32 = number; 2: "manifest", manifest: "manifest" } + export interface StackFrame { + function_name: string; + file: string; + position: StackFramePosition; + scope: StackFrameScope; + } + + export interface StackFramePosition { + source_offset: int32; + line: int32; + line_start: int32; + line_stop: int32; + column_start: int32; + column_stop: int32; + expression_start: int32; + expression_stop: int32; + } + + export interface SourceLine { + line: int32; + text: string; + } + + export interface StackTrace { + source_lines: SourceLine[]; + frames: StackFrame[]; + } + + export interface JSException { + name?: string; + message?: string; + runtime_type?: uint16; + code?: uint8; + stack?: StackTrace; + } + + export interface Problems { + code: uint16; + name: string; + exceptions: JSException[]; + build: Log; + } + + export interface Router { + routes: string[]; + route: int32; + params: StringMap; + } + + export interface FallbackMessageContainer { + message?: string; + router?: Router; + reason?: FallbackStep; + problems?: Problems; + } + export interface JSX { factory: string; runtime: JSXRuntime; @@ -275,20 +394,34 @@ type uint32 = number; export interface FrameworkConfig { package?: string; - client?: string; - server?: string; + client?: FrameworkEntryPointMessage; + server?: FrameworkEntryPointMessage; + fallback?: FrameworkEntryPointMessage; development?: boolean; - client_env?: EnvConfig; - server_env?: EnvConfig; client_css_in_js?: CSSInJSBehavior; } + export interface FrameworkEntryPoint { + kind: FrameworkEntryPointType; + path: string; + env: LoadedEnvConfig; + } + + export interface FrameworkEntryPointMap { + client?: FrameworkEntryPoint; + server?: FrameworkEntryPoint; + fallback?: FrameworkEntryPoint; + } + + export interface FrameworkEntryPointMessage { + path?: string; + env?: EnvConfig; + } + export interface LoadedFramework { - entry_point: string; package: string; development: boolean; - client: boolean; - env: LoadedEnvConfig; + entry_points: FrameworkEntryPointMap; client_css_in_js: CSSInJSBehavior; } @@ -372,10 +505,16 @@ type uint32 = number; location?: Location; } + export interface MessageMeta { + resolve?: string; + build?: boolean; + } + export interface Message { - kind: MessageKind; + level: MessageLevel; data: MessageData; notes: MessageData[]; + on: MessageMeta; } export interface Log { @@ -461,6 +600,22 @@ type uint32 = number; log: Log; } + export declare function encodeStackFrame(message: StackFrame, bb: ByteBuffer): void; + export declare function decodeStackFrame(buffer: ByteBuffer): StackFrame; + export declare function encodeStackFramePosition(message: StackFramePosition, bb: ByteBuffer): void; + export declare function decodeStackFramePosition(buffer: ByteBuffer): StackFramePosition; + export declare function encodeSourceLine(message: SourceLine, bb: ByteBuffer): void; + export declare function decodeSourceLine(buffer: ByteBuffer): SourceLine; + export declare function encodeStackTrace(message: StackTrace, bb: ByteBuffer): void; + export declare function decodeStackTrace(buffer: ByteBuffer): StackTrace; + export declare function encodeJSException(message: JSException, bb: ByteBuffer): void; + export declare function decodeJSException(buffer: ByteBuffer): JSException; + export declare function encodeProblems(message: Problems, bb: ByteBuffer): void; + export declare function decodeProblems(buffer: ByteBuffer): Problems; + export declare function encodeRouter(message: Router, bb: ByteBuffer): void; + export declare function decodeRouter(buffer: ByteBuffer): Router; + export declare function encodeFallbackMessageContainer(message: FallbackMessageContainer, bb: ByteBuffer): void; + export declare function decodeFallbackMessageContainer(buffer: ByteBuffer): FallbackMessageContainer; export declare function encodeJSX(message: JSX, bb: ByteBuffer): void; export declare function decodeJSX(buffer: ByteBuffer): JSX; export declare function encodeStringPointer(message: StringPointer, bb: ByteBuffer): void; @@ -487,6 +642,12 @@ type uint32 = number; export declare function decodeLoadedEnvConfig(buffer: ByteBuffer): LoadedEnvConfig; export declare function encodeFrameworkConfig(message: FrameworkConfig, bb: ByteBuffer): void; export declare function decodeFrameworkConfig(buffer: ByteBuffer): FrameworkConfig; + export declare function encodeFrameworkEntryPoint(message: FrameworkEntryPoint, bb: ByteBuffer): void; + export declare function decodeFrameworkEntryPoint(buffer: ByteBuffer): FrameworkEntryPoint; + export declare function encodeFrameworkEntryPointMap(message: FrameworkEntryPointMap, bb: ByteBuffer): void; + export declare function decodeFrameworkEntryPointMap(buffer: ByteBuffer): FrameworkEntryPointMap; + export declare function encodeFrameworkEntryPointMessage(message: FrameworkEntryPointMessage, bb: ByteBuffer): void; + export declare function decodeFrameworkEntryPointMessage(buffer: ByteBuffer): FrameworkEntryPointMessage; export declare function encodeLoadedFramework(message: LoadedFramework, bb: ByteBuffer): void; export declare function decodeLoadedFramework(buffer: ByteBuffer): LoadedFramework; export declare function encodeLoadedRouteConfig(message: LoadedRouteConfig, bb: ByteBuffer): void; @@ -507,6 +668,8 @@ type uint32 = number; export declare function decodeLocation(buffer: ByteBuffer): Location; export declare function encodeMessageData(message: MessageData, bb: ByteBuffer): void; export declare function decodeMessageData(buffer: ByteBuffer): MessageData; + export declare function encodeMessageMeta(message: MessageMeta, bb: ByteBuffer): void; + export declare function decodeMessageMeta(buffer: ByteBuffer): MessageMeta; export declare function encodeMessage(message: Message, bb: ByteBuffer): void; export declare function decodeMessage(buffer: ByteBuffer): Message; export declare function encodeLog(message: Log, bb: ByteBuffer): void; diff --git a/src/api/schema.js b/src/api/schema.js index 0ae493e20..73e7e20c7 100644 --- a/src/api/schema.js +++ b/src/api/schema.js @@ -30,6 +30,490 @@ const LoaderKeys = { "file": "file", "json": "json" }; +const FrameworkEntryPointType = { + "1": 1, + "2": 2, + "3": 3, + "client": 1, + "server": 2, + "fallback": 3 +}; +const FrameworkEntryPointTypeKeys = { + "1": "client", + "2": "server", + "3": "fallback", + "client": "client", + "server": "server", + "fallback": "fallback" +}; +const StackFrameScope = { + "1": 1, + "2": 2, + "3": 3, + "4": 4, + "5": 5, + "6": 6, + "Eval": 1, + "Module": 2, + "Function": 3, + "Global": 4, + "Wasm": 5, + "Constructor": 6 +}; +const StackFrameScopeKeys = { + "1": "Eval", + "2": "Module", + "3": "Function", + "4": "Global", + "5": "Wasm", + "6": "Constructor", + "Eval": "Eval", + "Module": "Module", + "Function": "Function", + "Global": "Global", + "Wasm": "Wasm", + "Constructor": "Constructor" +}; + +function decodeStackFrame(bb) { + var result = {}; + + result["function_name"] = bb.readString(); + result["file"] = bb.readString(); + result["position"] = decodeStackFramePosition(bb); + result["scope"] = StackFrameScope[bb.readByte()]; + return result; +} + +function encodeStackFrame(message, bb) { + + var value = message["function_name"]; + if (value != null) { + bb.writeString(value); + } else { + throw new Error("Missing required field \"function_name\""); + } + + var value = message["file"]; + if (value != null) { + bb.writeString(value); + } else { + throw new Error("Missing required field \"file\""); + } + + var value = message["position"]; + if (value != null) { + encodeStackFramePosition(value, bb); + } else { + throw new Error("Missing required field \"position\""); + } + + var value = message["scope"]; + if (value != null) { + var encoded = StackFrameScope[value]; +if (encoded === void 0) throw new Error("Invalid value " + JSON.stringify(value) + " for enum \"StackFrameScope\""); +bb.writeByte(encoded); + } else { + throw new Error("Missing required field \"scope\""); + } + +} + +function decodeStackFramePosition(bb) { + var result = {}; + + result["source_offset"] = bb.readInt32(); + result["line"] = bb.readInt32(); + result["line_start"] = bb.readInt32(); + result["line_stop"] = bb.readInt32(); + result["column_start"] = bb.readInt32(); + result["column_stop"] = bb.readInt32(); + result["expression_start"] = bb.readInt32(); + result["expression_stop"] = bb.readInt32(); + return result; +} + +function encodeStackFramePosition(message, bb) { + + var value = message["source_offset"]; + if (value != null) { + bb.writeInt32(value); + } else { + throw new Error("Missing required field \"source_offset\""); + } + + var value = message["line"]; + if (value != null) { + bb.writeInt32(value); + } else { + throw new Error("Missing required field \"line\""); + } + + var value = message["line_start"]; + if (value != null) { + bb.writeInt32(value); + } else { + throw new Error("Missing required field \"line_start\""); + } + + var value = message["line_stop"]; + if (value != null) { + bb.writeInt32(value); + } else { + throw new Error("Missing required field \"line_stop\""); + } + + var value = message["column_start"]; + if (value != null) { + bb.writeInt32(value); + } else { + throw new Error("Missing required field \"column_start\""); + } + + var value = message["column_stop"]; + if (value != null) { + bb.writeInt32(value); + } else { + throw new Error("Missing required field \"column_stop\""); + } + + var value = message["expression_start"]; + if (value != null) { + bb.writeInt32(value); + } else { + throw new Error("Missing required field \"expression_start\""); + } + + var value = message["expression_stop"]; + if (value != null) { + bb.writeInt32(value); + } else { + throw new Error("Missing required field \"expression_stop\""); + } + +} + +function decodeSourceLine(bb) { + var result = {}; + + result["line"] = bb.readInt32(); + result["text"] = bb.readString(); + return result; +} + +function encodeSourceLine(message, bb) { + + var value = message["line"]; + if (value != null) { + bb.writeInt32(value); + } else { + throw new Error("Missing required field \"line\""); + } + + var value = message["text"]; + if (value != null) { + bb.writeString(value); + } else { + throw new Error("Missing required field \"text\""); + } + +} + +function decodeStackTrace(bb) { + var result = {}; + + var length = bb.readVarUint(); + var values = result["source_lines"] = Array(length); + for (var i = 0; i < length; i++) values[i] = decodeSourceLine(bb); + var length = bb.readVarUint(); + var values = result["frames"] = Array(length); + for (var i = 0; i < length; i++) values[i] = decodeStackFrame(bb); + return result; +} + +function encodeStackTrace(message, bb) { + + var value = message["source_lines"]; + if (value != null) { + var values = value, n = values.length; + bb.writeVarUint(n); + for (var i = 0; i < n; i++) { + value = values[i]; + encodeSourceLine(value, bb); + } + } else { + throw new Error("Missing required field \"source_lines\""); + } + + var value = message["frames"]; + if (value != null) { + var values = value, n = values.length; + bb.writeVarUint(n); + for (var i = 0; i < n; i++) { + value = values[i]; + encodeStackFrame(value, bb); + } + } else { + throw new Error("Missing required field \"frames\""); + } + +} + +function decodeJSException(bb) { + var result = {}; + + while (true) { + switch (bb.readByte()) { + case 0: + return result; + + case 1: + result["name"] = bb.readString(); + break; + + case 2: + result["message"] = bb.readString(); + break; + + case 3: + result["runtime_type"] = bb.readUint16(); + break; + + case 4: + result["code"] = bb.readByte(); + break; + + case 5: + result["stack"] = decodeStackTrace(bb); + break; + + default: + throw new Error("Attempted to parse invalid message"); + } + } +} + +function encodeJSException(message, bb) { + + var value = message["name"]; + if (value != null) { + bb.writeByte(1); + bb.writeString(value); + } + + var value = message["message"]; + if (value != null) { + bb.writeByte(2); + bb.writeString(value); + } + + var value = message["runtime_type"]; + if (value != null) { + bb.writeByte(3); + bb.writeUint16(value); + } + + var value = message["code"]; + if (value != null) { + bb.writeByte(4); + bb.writeByte(value); + } + + var value = message["stack"]; + if (value != null) { + bb.writeByte(5); + encodeStackTrace(value, bb); + } + bb.writeByte(0); + +} +const FallbackStep = { + "1": 1, + "2": 2, + "3": 3, + "4": 4, + "5": 5, + "6": 6, + "7": 7, + "8": 8, + "ssr_disabled": 1, + "create_vm": 2, + "configure_router": 3, + "configure_defines": 4, + "resolve_entry_point": 5, + "load_entry_point": 6, + "eval_entry_point": 7, + "fetch_event_handler": 8 +}; +const FallbackStepKeys = { + "1": "ssr_disabled", + "2": "create_vm", + "3": "configure_router", + "4": "configure_defines", + "5": "resolve_entry_point", + "6": "load_entry_point", + "7": "eval_entry_point", + "8": "fetch_event_handler", + "ssr_disabled": "ssr_disabled", + "create_vm": "create_vm", + "configure_router": "configure_router", + "configure_defines": "configure_defines", + "resolve_entry_point": "resolve_entry_point", + "load_entry_point": "load_entry_point", + "eval_entry_point": "eval_entry_point", + "fetch_event_handler": "fetch_event_handler" +}; + +function decodeProblems(bb) { + var result = {}; + + result["code"] = bb.readUint16(); + result["name"] = bb.readString(); + var length = bb.readVarUint(); + var values = result["exceptions"] = Array(length); + for (var i = 0; i < length; i++) values[i] = decodeJSException(bb); + result["build"] = decodeLog(bb); + return result; +} + +function encodeProblems(message, bb) { + + var value = message["code"]; + if (value != null) { + bb.writeUint16(value); + } else { + throw new Error("Missing required field \"code\""); + } + + var value = message["name"]; + if (value != null) { + bb.writeString(value); + } else { + throw new Error("Missing required field \"name\""); + } + + var value = message["exceptions"]; + if (value != null) { + var values = value, n = values.length; + bb.writeVarUint(n); + for (var i = 0; i < n; i++) { + value = values[i]; + encodeJSException(value, bb); + } + } else { + throw new Error("Missing required field \"exceptions\""); + } + + var value = message["build"]; + if (value != null) { + encodeLog(value, bb); + } else { + throw new Error("Missing required field \"build\""); + } + +} + +function decodeRouter(bb) { + var result = {}; + + var length = bb.readVarUint(); + var values = result["routes"] = Array(length); + for (var i = 0; i < length; i++) values[i] = bb.readString(); + result["route"] = bb.readInt32(); + result["params"] = decodeStringMap(bb); + return result; +} + +function encodeRouter(message, bb) { + + var value = message["routes"]; + if (value != null) { + var values = value, n = values.length; + bb.writeVarUint(n); + for (var i = 0; i < n; i++) { + value = values[i]; + bb.writeString(value); + } + } else { + throw new Error("Missing required field \"routes\""); + } + + var value = message["route"]; + if (value != null) { + bb.writeInt32(value); + } else { + throw new Error("Missing required field \"route\""); + } + + var value = message["params"]; + if (value != null) { + encodeStringMap(value, bb); + } else { + throw new Error("Missing required field \"params\""); + } + +} + +function decodeFallbackMessageContainer(bb) { + var result = {}; + + while (true) { + switch (bb.readByte()) { + case 0: + return result; + + case 1: + result["message"] = bb.readString(); + break; + + case 2: + result["router"] = decodeRouter(bb); + break; + + case 3: + result["reason"] = FallbackStep[bb.readByte()]; + break; + + case 4: + result["problems"] = decodeProblems(bb); + break; + + default: + throw new Error("Attempted to parse invalid message"); + } + } +} + +function encodeFallbackMessageContainer(message, bb) { + + var value = message["message"]; + if (value != null) { + bb.writeByte(1); + bb.writeString(value); + } + + var value = message["router"]; + if (value != null) { + bb.writeByte(2); + encodeRouter(value, bb); + } + + var value = message["reason"]; + if (value != null) { + bb.writeByte(3); + var encoded = FallbackStep[value]; +if (encoded === void 0) throw new Error("Invalid value " + JSON.stringify(value) + " for enum \"FallbackStep\""); +bb.writeByte(encoded); + } + + var value = message["problems"]; + if (value != null) { + bb.writeByte(4); + encodeProblems(value, bb); + } + bb.writeByte(0); + +} const ResolveMode = { "1": 1, "2": 2, @@ -709,26 +1193,22 @@ function decodeFrameworkConfig(bb) { break; case 2: - result["client"] = bb.readString(); + result["client"] = decodeFrameworkEntryPointMessage(bb); break; case 3: - result["server"] = bb.readString(); + result["server"] = decodeFrameworkEntryPointMessage(bb); break; case 4: - result["development"] = !!bb.readByte(); + result["fallback"] = decodeFrameworkEntryPointMessage(bb); break; case 5: - result["client_env"] = decodeEnvConfig(bb); + result["development"] = !!bb.readByte(); break; case 6: - result["server_env"] = decodeEnvConfig(bb); - break; - - case 7: result["client_css_in_js"] = CSSInJSBehavior[bb.readByte()]; break; @@ -749,36 +1229,30 @@ function encodeFrameworkConfig(message, bb) { var value = message["client"]; if (value != null) { bb.writeByte(2); - bb.writeString(value); + encodeFrameworkEntryPointMessage(value, bb); } var value = message["server"]; if (value != null) { bb.writeByte(3); - bb.writeString(value); + encodeFrameworkEntryPointMessage(value, bb); } - var value = message["development"]; + var value = message["fallback"]; if (value != null) { bb.writeByte(4); - bb.writeByte(value); + encodeFrameworkEntryPointMessage(value, bb); } - var value = message["client_env"]; + var value = message["development"]; if (value != null) { bb.writeByte(5); - encodeEnvConfig(value, bb); - } - - var value = message["server_env"]; - if (value != null) { - bb.writeByte(6); - encodeEnvConfig(value, bb); + bb.writeByte(value); } var value = message["client_css_in_js"]; if (value != null) { - bb.writeByte(7); + bb.writeByte(6); var encoded = CSSInJSBehavior[value]; if (encoded === void 0) throw new Error("Invalid value " + JSON.stringify(value) + " for enum \"CSSInJSBehavior\""); bb.writeByte(encoded); @@ -787,53 +1261,161 @@ bb.writeByte(encoded); } -function decodeLoadedFramework(bb) { +function decodeFrameworkEntryPoint(bb) { var result = {}; - result["entry_point"] = bb.readString(); - result["package"] = bb.readString(); - result["development"] = !!bb.readByte(); - result["client"] = !!bb.readByte(); + result["kind"] = FrameworkEntryPointType[bb.readByte()]; + result["path"] = bb.readString(); result["env"] = decodeLoadedEnvConfig(bb); - result["client_css_in_js"] = CSSInJSBehavior[bb.readByte()]; return result; } -function encodeLoadedFramework(message, bb) { +function encodeFrameworkEntryPoint(message, bb) { - var value = message["entry_point"]; + var value = message["kind"]; if (value != null) { - bb.writeString(value); + var encoded = FrameworkEntryPointType[value]; +if (encoded === void 0) throw new Error("Invalid value " + JSON.stringify(value) + " for enum \"FrameworkEntryPointType\""); +bb.writeByte(encoded); } else { - throw new Error("Missing required field \"entry_point\""); + throw new Error("Missing required field \"kind\""); } - var value = message["package"]; + var value = message["path"]; if (value != null) { bb.writeString(value); } else { - throw new Error("Missing required field \"package\""); + throw new Error("Missing required field \"path\""); } - var value = message["development"]; + var value = message["env"]; if (value != null) { - bb.writeByte(value); + encodeLoadedEnvConfig(value, bb); } else { - throw new Error("Missing required field \"development\""); + throw new Error("Missing required field \"env\""); + } + +} + +function decodeFrameworkEntryPointMap(bb) { + var result = {}; + + while (true) { + switch (bb.readByte()) { + case 0: + return result; + + case 1: + result["client"] = decodeFrameworkEntryPoint(bb); + break; + + case 2: + result["server"] = decodeFrameworkEntryPoint(bb); + break; + + case 3: + result["fallback"] = decodeFrameworkEntryPoint(bb); + break; + + default: + throw new Error("Attempted to parse invalid message"); + } } +} + +function encodeFrameworkEntryPointMap(message, bb) { var value = message["client"]; if (value != null) { + bb.writeByte(1); + encodeFrameworkEntryPoint(value, bb); + } + + var value = message["server"]; + if (value != null) { + bb.writeByte(2); + encodeFrameworkEntryPoint(value, bb); + } + + var value = message["fallback"]; + if (value != null) { + bb.writeByte(3); + encodeFrameworkEntryPoint(value, bb); + } + bb.writeByte(0); + +} + +function decodeFrameworkEntryPointMessage(bb) { + var result = {}; + + while (true) { + switch (bb.readByte()) { + case 0: + return result; + + case 1: + result["path"] = bb.readString(); + break; + + case 2: + result["env"] = decodeEnvConfig(bb); + break; + + default: + throw new Error("Attempted to parse invalid message"); + } + } +} + +function encodeFrameworkEntryPointMessage(message, bb) { + + var value = message["path"]; + if (value != null) { + bb.writeByte(1); + bb.writeString(value); + } + + var value = message["env"]; + if (value != null) { + bb.writeByte(2); + encodeEnvConfig(value, bb); + } + bb.writeByte(0); + +} + +function decodeLoadedFramework(bb) { + var result = {}; + + result["package"] = bb.readString(); + result["development"] = !!bb.readByte(); + result["entry_points"] = decodeFrameworkEntryPointMap(bb); + result["client_css_in_js"] = CSSInJSBehavior[bb.readByte()]; + return result; +} + +function encodeLoadedFramework(message, bb) { + + var value = message["package"]; + if (value != null) { + bb.writeString(value); + } else { + throw new Error("Missing required field \"package\""); + } + + var value = message["development"]; + if (value != null) { bb.writeByte(value); } else { - throw new Error("Missing required field \"client\""); + throw new Error("Missing required field \"development\""); } - var value = message["env"]; + var value = message["entry_points"]; if (value != null) { - encodeLoadedEnvConfig(value, bb); + encodeFrameworkEntryPointMap(value, bb); } else { - throw new Error("Missing required field \"env\""); + throw new Error("Missing required field \"entry_points\""); } var value = message["client_css_in_js"]; @@ -1449,7 +2031,7 @@ bb.writeVarUint(encoded); } } -const MessageKind = { +const MessageLevel = { "1": 1, "2": 2, "3": 3, @@ -1459,7 +2041,7 @@ const MessageKind = { "note": 3, "debug": 4 }; -const MessageKindKeys = { +const MessageLevelKeys = { "1": "err", "2": "warn", "3": "note", @@ -1575,26 +2157,66 @@ function encodeMessageData(message, bb) { } +function decodeMessageMeta(bb) { + var result = {}; + + while (true) { + switch (bb.readByte()) { + case 0: + return result; + + case 1: + result["resolve"] = bb.readString(); + break; + + case 2: + result["build"] = !!bb.readByte(); + break; + + default: + throw new Error("Attempted to parse invalid message"); + } + } +} + +function encodeMessageMeta(message, bb) { + + var value = message["resolve"]; + if (value != null) { + bb.writeByte(1); + bb.writeString(value); + } + + var value = message["build"]; + if (value != null) { + bb.writeByte(2); + bb.writeByte(value); + } + bb.writeByte(0); + +} + function decodeMessage(bb) { var result = {}; - result["kind"] = MessageKind[bb.readVarUint()]; + result["level"] = MessageLevel[bb.readVarUint()]; result["data"] = decodeMessageData(bb); var length = bb.readVarUint(); var values = result["notes"] = Array(length); for (var i = 0; i < length; i++) values[i] = decodeMessageData(bb); + result["on"] = decodeMessageMeta(bb); return result; } function encodeMessage(message, bb) { - var value = message["kind"]; + var value = message["level"]; if (value != null) { - var encoded = MessageKind[value]; -if (encoded === void 0) throw new Error("Invalid value " + JSON.stringify(value) + " for enum \"MessageKind\""); + var encoded = MessageLevel[value]; +if (encoded === void 0) throw new Error("Invalid value " + JSON.stringify(value) + " for enum \"MessageLevel\""); bb.writeVarUint(encoded); } else { - throw new Error("Missing required field \"kind\""); + throw new Error("Missing required field \"level\""); } var value = message["data"]; @@ -1616,6 +2238,13 @@ bb.writeVarUint(encoded); throw new Error("Missing required field \"notes\""); } + var value = message["on"]; + if (value != null) { + encodeMessageMeta(value, bb); + } else { + throw new Error("Missing required field \"on\""); + } + } function decodeLog(bb) { @@ -2167,6 +2796,28 @@ bb.writeByte(encoded); export { Loader } export { LoaderKeys } +export { FrameworkEntryPointType } +export { FrameworkEntryPointTypeKeys } +export { StackFrameScope } +export { StackFrameScopeKeys } +export { decodeStackFrame } +export { encodeStackFrame } +export { decodeStackFramePosition } +export { encodeStackFramePosition } +export { decodeSourceLine } +export { encodeSourceLine } +export { decodeStackTrace } +export { encodeStackTrace } +export { decodeJSException } +export { encodeJSException } +export { FallbackStep } +export { FallbackStepKeys } +export { decodeProblems } +export { encodeProblems } +export { decodeRouter } +export { encodeRouter } +export { decodeFallbackMessageContainer } +export { encodeFallbackMessageContainer } export { ResolveMode } export { ResolveModeKeys } export { Platform } @@ -2207,6 +2858,12 @@ export { decodeLoadedEnvConfig } export { encodeLoadedEnvConfig } export { decodeFrameworkConfig } export { encodeFrameworkConfig } +export { decodeFrameworkEntryPoint } +export { encodeFrameworkEntryPoint } +export { decodeFrameworkEntryPointMap } +export { encodeFrameworkEntryPointMap } +export { decodeFrameworkEntryPointMessage } +export { encodeFrameworkEntryPointMessage } export { decodeLoadedFramework } export { encodeLoadedFramework } export { decodeLoadedRouteConfig } @@ -2225,12 +2882,14 @@ export { decodeOutputFile } export { encodeOutputFile } export { decodeTransformResponse } export { encodeTransformResponse } -export { MessageKind } -export { MessageKindKeys } +export { MessageLevel } +export { MessageLevelKeys } export { decodeLocation } export { encodeLocation } export { decodeMessageData } export { encodeMessageData } +export { decodeMessageMeta } +export { encodeMessageMeta } export { decodeMessage } export { encodeMessage } export { decodeLog } diff --git a/src/api/schema.peechy b/src/api/schema.peechy index fd0b81fd2..3b7b2669e 100644 --- a/src/api/schema.peechy +++ b/src/api/schema.peechy @@ -10,6 +10,93 @@ smol Loader { json = 7; } +smol FrameworkEntryPointType { + client = 1; + server = 2; + fallback = 3; +} + +smol StackFrameScope { + Eval = 1; + Module = 2; + Function = 3; + Global = 4; + Wasm = 5; + Constructor = 6; +} + +struct StackFrame { + string function_name; + string file; + StackFramePosition position; + StackFrameScope scope; +} + +struct StackFramePosition { + int32 source_offset; + int32 line; + int32 line_start; + int32 line_stop; + int32 column_start; + int32 column_stop; + int32 expression_start; + int32 expression_stop; +} + +struct SourceLine { + int32 line; + string text; +} + +struct StackTrace { + SourceLine[] source_lines; + StackFrame[] frames; +} + + +message JSException { + string name = 1; + string message = 2; + + uint16 runtime_type = 3; + uint8 code = 4; + + StackTrace stack = 5; +} + +smol FallbackStep { + ssr_disabled = 1; + create_vm = 2; + configure_router = 3; + configure_defines = 4; + resolve_entry_point = 5; + load_entry_point = 6; + eval_entry_point = 7; + fetch_event_handler = 8; +} + +struct Problems { + uint16 code; + string name; + + JSException[] exceptions; + Log build; +} + +struct Router { + string[] routes; + int32 route; + StringMap params; +} + +message FallbackMessageContainer { + string message = 1; + Router router = 2; + FallbackStep reason = 3; + Problems problems = 4; +} + + smol ResolveMode { disable = 1; lazy = 2; @@ -161,22 +248,35 @@ struct LoadedEnvConfig { message FrameworkConfig { string package = 1; - string client = 2; - string server = 3; - bool development = 4; - EnvConfig client_env = 5; - EnvConfig server_env = 6; + FrameworkEntryPointMessage client = 2; + FrameworkEntryPointMessage server = 3; + FrameworkEntryPointMessage fallback = 4; + bool development = 5; + + CSSInJSBehavior client_css_in_js = 6; +} - CSSInJSBehavior client_css_in_js = 7; +struct FrameworkEntryPoint { + FrameworkEntryPointType kind; + string path; + LoadedEnvConfig env; +} + +message FrameworkEntryPointMap { + FrameworkEntryPoint client = 1; + FrameworkEntryPoint server = 2; + FrameworkEntryPoint fallback = 3; +} + +message FrameworkEntryPointMessage { + string path = 1; + EnvConfig env = 2; } struct LoadedFramework { - string entry_point; string package; bool development; - bool client; - LoadedEnvConfig env; - + FrameworkEntryPointMap entry_points; CSSInJSBehavior client_css_in_js; } @@ -264,7 +364,7 @@ struct TransformResponse { Message[] errors; } -enum MessageKind { +enum MessageLevel { err = 1; warn =2; note = 3; @@ -286,10 +386,18 @@ message MessageData { Location location = 2; } + + +message MessageMeta { + string resolve = 1; + bool build = 2; +} + struct Message { - MessageKind kind; + MessageLevel level; MessageData data; MessageData[] notes; + MessageMeta on; } struct Log { diff --git a/src/api/schema.zig b/src/api/schema.zig index 639eeae98..bd0873540 100644 --- a/src/api/schema.zig +++ b/src/api/schema.zig @@ -1,3 +1,4 @@ + const std = @import("std"); pub const Reader = struct { @@ -281,1762 +282,2440 @@ 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 FrameworkEntryPointType = enum(u8) { - /// node - node, +_none, + /// client + client, - /// bun - bun, + /// server + server, - _, + /// fallback + fallback, - pub fn jsonStringify(self: *const @This(), opts: anytype, o: anytype) !void { - return try std.json.stringify(@tagName(self), opts, o); - } - }; +_, - pub const CssInJsBehavior = enum(u8) { - _none, - /// facade - facade, + pub fn jsonStringify(self: *const @This(), opts: anytype, o: anytype) !void { + return try std.json.stringify(@tagName(self), opts, o); + } - /// facade_onimportcss - facade_onimportcss, + +}; - /// auto_onimportcss - auto_onimportcss, +pub const StackFrameScope = enum(u8) { - _, +_none, + /// Eval + eval, - pub fn jsonStringify(self: *const @This(), opts: anytype, o: anytype) !void { - return try std.json.stringify(@tagName(self), opts, o); - } - }; + /// Module + module, - pub const JsxRuntime = enum(u8) { - _none, - /// automatic - automatic, + /// Function + function, - /// classic - classic, + /// Global + global, - _, + /// Wasm + wasm, - pub fn jsonStringify(self: *const @This(), opts: anytype, o: anytype) !void { - return try std.json.stringify(@tagName(self), opts, o); - } - }; + /// Constructor + constructor, - pub const Jsx = struct { - /// factory - factory: []const u8, +_, - /// runtime - runtime: JsxRuntime, + pub fn jsonStringify(self: *const @This(), opts: anytype, o: anytype) !void { + return try std.json.stringify(@tagName(self), opts, o); + } - /// fragment - fragment: []const u8, + +}; - /// development - development: bool = false, +pub const StackFrame = struct { +/// function_name +function_name: []const u8, - /// import_source - import_source: []const u8, +/// file +file: []const u8, - /// react_fast_refresh - react_fast_refresh: bool = false, +/// position +position: StackFramePosition, - pub fn decode(reader: anytype) anyerror!Jsx { - var this = std.mem.zeroes(Jsx); +/// scope +scope: StackFrameScope, - 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 fn decode(reader: anytype) anyerror!StackFrame { + var this = std.mem.zeroes(StackFrame); - pub const StringPointer = packed struct { - /// offset - offset: u32 = 0, + this.function_name = try reader.readValue([]const u8); + this.file = try reader.readValue([]const u8); + this.position = try reader.readValue(StackFramePosition); + this.scope = try reader.readValue(StackFrameScope); + return this; +} - /// length - length: u32 = 0, +pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeValue(this.function_name); + try writer.writeValue(this.file); + try writer.writeValue(this.position); + try writer.writeEnum(this.scope); +} - pub fn decode(reader: anytype) anyerror!StringPointer { - var this = std.mem.zeroes(StringPointer); +}; - this.offset = try reader.readValue(u32); - this.length = try reader.readValue(u32); - return this; - } +pub const StackFramePosition = packed struct { +/// source_offset +source_offset: i32 = 0, - pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - try writer.writeInt(this.offset); - try writer.writeInt(this.length); - } - }; +/// line +line: i32 = 0, - pub const JavascriptBundledModule = struct { - /// path - path: StringPointer, +/// line_start +line_start: i32 = 0, - /// code - code: StringPointer, +/// line_stop +line_stop: i32 = 0, - /// package_id - package_id: u32 = 0, +/// column_start +column_start: i32 = 0, - /// id - id: u32 = 0, +/// column_stop +column_stop: i32 = 0, - /// path_extname_length - path_extname_length: u8 = 0, +/// expression_start +expression_start: i32 = 0, - pub fn decode(reader: anytype) anyerror!JavascriptBundledModule { - var this = std.mem.zeroes(JavascriptBundledModule); +/// expression_stop +expression_stop: i32 = 0, - 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!StackFramePosition { + var this = std.mem.zeroes(StackFramePosition); - pub const JavascriptBundledPackage = struct { - /// name - name: StringPointer, + this.source_offset = try reader.readValue(i32); + this.line = try reader.readValue(i32); + this.line_start = try reader.readValue(i32); + this.line_stop = try reader.readValue(i32); + this.column_start = try reader.readValue(i32); + this.column_stop = try reader.readValue(i32); + this.expression_start = try reader.readValue(i32); + this.expression_stop = try reader.readValue(i32); + return this; +} - /// version - version: StringPointer, +pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeInt(this.source_offset); + try writer.writeInt(this.line); + try writer.writeInt(this.line_start); + try writer.writeInt(this.line_stop); + try writer.writeInt(this.column_start); + try writer.writeInt(this.column_stop); + try writer.writeInt(this.expression_start); + try writer.writeInt(this.expression_stop); +} - /// hash - hash: u32 = 0, +}; - /// modules_offset - modules_offset: u32 = 0, +pub const SourceLine = struct { +/// line +line: i32 = 0, - /// modules_length - modules_length: u32 = 0, +/// text +text: []const u8, - 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!SourceLine { + var this = std.mem.zeroes(SourceLine); - 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.line = try reader.readValue(i32); + this.text = try reader.readValue([]const u8); + return this; +} - pub const JavascriptBundle = struct { - /// modules - modules: []const JavascriptBundledModule, +pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeInt(this.line); + try writer.writeValue(this.text); +} - /// packages - packages: []const JavascriptBundledPackage, +}; - /// etag - etag: []const u8, +pub const StackTrace = struct { +/// source_lines +source_lines: []const SourceLine, - /// generated_at - generated_at: u32 = 0, +/// frames +frames: []const StackFrame, - /// app_package_json_dependencies_hash - app_package_json_dependencies_hash: []const u8, - /// import_from_name - import_from_name: []const u8, +pub fn decode(reader: anytype) anyerror!StackTrace { + var this = std.mem.zeroes(StackTrace); - /// manifest_string - manifest_string: []const u8, + this.source_lines = try reader.readArray(SourceLine); + this.frames = try reader.readArray(StackFrame); + return this; +} - pub fn decode(reader: anytype) anyerror!JavascriptBundle { - var this = std.mem.zeroes(JavascriptBundle); +pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeArray(SourceLine, this.source_lines); + try writer.writeArray(StackFrame, this.frames); +} - this.modules = try reader.readArray(JavascriptBundledModule); - this.packages = try reader.readArray(JavascriptBundledPackage); - this.etag = try reader.readArray(u8); - this.generated_at = try reader.readValue(u32); - this.app_package_json_dependencies_hash = try reader.readArray(u8); - this.import_from_name = try reader.readArray(u8); - this.manifest_string = try reader.readArray(u8); - return this; - } +}; - pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - try writer.writeArray(JavascriptBundledModule, this.modules); - try writer.writeArray(JavascriptBundledPackage, this.packages); - try writer.writeArray(u8, this.etag); - try writer.writeInt(this.generated_at); - try writer.writeArray(u8, this.app_package_json_dependencies_hash); - try writer.writeArray(u8, this.import_from_name); - try writer.writeArray(u8, this.manifest_string); - } - }; +pub const JsException = struct { +/// name +name: ?[]const u8 = null, + +/// message +message: ?[]const u8 = null, + +/// runtime_type +runtime_type: ?u16 = null, + +/// code +code: ?u8 = null, + +/// stack +stack: ?StackTrace = null, + + +pub fn decode(reader: anytype) anyerror!JsException { + var this = std.mem.zeroes(JsException); + + while(true) { + switch (try reader.readByte()) { + 0 => { return this; }, + + 1 => { + this.name = try reader.readValue([]const u8); +}, + 2 => { + this.message = try reader.readValue([]const u8); +}, + 3 => { + this.runtime_type = try reader.readValue(u16); +}, + 4 => { + this.code = try reader.readValue(u8); +}, + 5 => { + this.stack = try reader.readValue(StackTrace); +}, + else => { + return error.InvalidMessage; + }, + } + } +unreachable; +} - pub const JavascriptBundleContainer = struct { - /// bundle_format_version - bundle_format_version: ?u32 = null, +pub fn encode(this: *const @This(), writer: anytype) anyerror!void { +if (this.name) |name| { + try writer.writeFieldID(1); + try writer.writeValue(name); +} +if (this.message) |message| { + try writer.writeFieldID(2); + try writer.writeValue(message); +} +if (this.runtime_type) |runtime_type| { + try writer.writeFieldID(3); + try writer.writeInt(runtime_type); +} +if (this.code) |code| { + try writer.writeFieldID(4); + try writer.writeInt(code); +} +if (this.stack) |stack| { + try writer.writeFieldID(5); + try writer.writeValue(stack); +} +try writer.endMessage(); +} - /// routes - routes: ?LoadedRouteConfig = null, +}; - /// framework - framework: ?LoadedFramework = null, +pub const FallbackStep = enum(u8) { - /// bundle - bundle: ?JavascriptBundle = null, +_none, + /// ssr_disabled + ssr_disabled, - /// code_length - code_length: ?u32 = null, + /// create_vm + create_vm, - pub fn decode(reader: anytype) anyerror!JavascriptBundleContainer { - var this = std.mem.zeroes(JavascriptBundleContainer); + /// configure_router + configure_router, - while (true) { - switch (try reader.readByte()) { - 0 => { - return this; - }, + /// configure_defines + configure_defines, - 1 => { - this.bundle_format_version = try reader.readValue(u32); - }, - 2 => { - this.routes = try reader.readValue(LoadedRouteConfig); - }, - 3 => { - this.framework = try reader.readValue(LoadedFramework); - }, - 4 => { - this.bundle = try reader.readValue(JavascriptBundle); - }, - 5 => { - this.code_length = try reader.readValue(u32); - }, - else => { - return error.InvalidMessage; - }, + /// resolve_entry_point + resolve_entry_point, + + /// load_entry_point + load_entry_point, + + /// eval_entry_point + eval_entry_point, + + /// fetch_event_handler + fetch_event_handler, + +_, + + pub fn jsonStringify(self: *const @This(), opts: anytype, o: anytype) !void { + return try std.json.stringify(@tagName(self), opts, o); } - } - unreachable; - } - pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - if (this.bundle_format_version) |bundle_format_version| { - try writer.writeFieldID(1); - try writer.writeInt(bundle_format_version); - } - if (this.routes) |routes| { - try writer.writeFieldID(2); - try writer.writeValue(routes); - } - if (this.framework) |framework| { - try writer.writeFieldID(3); - try writer.writeValue(framework); - } - if (this.bundle) |bundle| { - try writer.writeFieldID(4); - try writer.writeValue(bundle); - } - if (this.code_length) |code_length| { - try writer.writeFieldID(5); - try writer.writeInt(code_length); - } - try writer.endMessage(); - } - }; + +}; - pub const ScanDependencyMode = enum(u8) { - _none, - /// app - app, +pub const Problems = struct { +/// code +code: u16 = 0, - /// all - all, +/// name +name: []const u8, - _, +/// exceptions +exceptions: []const JsException, - pub fn jsonStringify(self: *const @This(), opts: anytype, o: anytype) !void { - return try std.json.stringify(@tagName(self), opts, o); - } - }; +/// build +build: Log, - pub const ModuleImportType = enum(u8) { - _none, - /// import - import, - /// require - require, +pub fn decode(reader: anytype) anyerror!Problems { + var this = std.mem.zeroes(Problems); - _, + this.code = try reader.readValue(u16); + this.name = try reader.readValue([]const u8); + this.exceptions = try reader.readArray(JsException); + this.build = try reader.readValue(Log); + 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.code); + try writer.writeValue(this.name); + try writer.writeArray(JsException, this.exceptions); + try writer.writeValue(this.build); +} - pub const ModuleImportRecord = struct { - /// kind - kind: ModuleImportType, +}; - /// path - path: []const u8, +pub const Router = struct { +/// routes +routes: []const []const u8, - /// dynamic - dynamic: bool = false, +/// route +route: i32 = 0, - pub fn decode(reader: anytype) anyerror!ModuleImportRecord { - var this = std.mem.zeroes(ModuleImportRecord); +/// params +params: StringMap, - this.kind = try reader.readValue(ModuleImportType); - this.path = try reader.readValue([]const u8); - this.dynamic = try reader.readValue(bool); - return this; - } - pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - try writer.writeEnum(this.kind); - try writer.writeValue(this.path); - try writer.writeInt(@intCast(u8, @boolToInt(this.dynamic))); - } - }; +pub fn decode(reader: anytype) anyerror!Router { + var this = std.mem.zeroes(Router); - pub const Module = struct { - /// path - path: []const u8, + this.routes = try reader.readArray([]const u8); + this.route = try reader.readValue(i32); + this.params = try reader.readValue(StringMap); + return this; +} - /// imports - imports: []const ModuleImportRecord, +pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeArray([]const u8, this.routes); + try writer.writeInt(this.route); + try writer.writeValue(this.params); +} - pub fn decode(reader: anytype) anyerror!Module { - var this = std.mem.zeroes(Module); +}; - this.path = try reader.readValue([]const u8); - this.imports = try reader.readArray(ModuleImportRecord); - return this; - } +pub const FallbackMessageContainer = struct { +/// message +message: ?[]const u8 = null, + +/// router +router: ?Router = null, + +/// reason +reason: ?FallbackStep = null, + +/// problems +problems: ?Problems = null, + + +pub fn decode(reader: anytype) anyerror!FallbackMessageContainer { + var this = std.mem.zeroes(FallbackMessageContainer); + + while(true) { + switch (try reader.readByte()) { + 0 => { return this; }, + + 1 => { + this.message = try reader.readValue([]const u8); +}, + 2 => { + this.router = try reader.readValue(Router); +}, + 3 => { + this.reason = try reader.readValue(FallbackStep); +}, + 4 => { + this.problems = try reader.readValue(Problems); +}, + else => { + return error.InvalidMessage; + }, + } + } +unreachable; +} - pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - try writer.writeValue(this.path); - try writer.writeArray(ModuleImportRecord, this.imports); - } - }; +pub fn encode(this: *const @This(), writer: anytype) anyerror!void { +if (this.message) |message| { + try writer.writeFieldID(1); + try writer.writeValue(message); +} +if (this.router) |router| { + try writer.writeFieldID(2); + try writer.writeValue(router); +} +if (this.reason) |reason| { + try writer.writeFieldID(3); + try writer.writeEnum(reason); +} +if (this.problems) |problems| { + try writer.writeFieldID(4); + try writer.writeValue(problems); +} +try writer.endMessage(); +} - pub const StringMap = struct { - /// keys - keys: []const []const u8, +}; - /// values - values: []const []const u8, +pub const ResolveMode = enum(u8) { - pub fn decode(reader: anytype) anyerror!StringMap { - var this = std.mem.zeroes(StringMap); +_none, + /// disable + disable, - this.keys = try reader.readArray([]const u8); - this.values = try reader.readArray([]const u8); - return this; - } + /// lazy + lazy, - pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - try writer.writeArray([]const u8, this.keys); - try writer.writeArray([]const u8, this.values); - } - }; + /// dev + dev, - pub const LoaderMap = struct { - /// extensions - extensions: []const []const u8, + /// bundle + bundle, - /// loaders - loaders: []const Loader, +_, - pub fn decode(reader: anytype) anyerror!LoaderMap { - var this = std.mem.zeroes(LoaderMap); + pub fn jsonStringify(self: *const @This(), opts: anytype, o: anytype) !void { + return try std.json.stringify(@tagName(self), opts, o); + } - 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 Platform = enum(u8) { - pub const DotEnvBehavior = enum(u32) { - _none, - /// disable - disable, +_none, + /// browser + browser, - /// prefix - prefix, + /// node + node, - /// load_all - load_all, + /// bun + bun, - _, +_, - 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 EnvConfig = struct { - /// prefix - prefix: ?[]const u8 = null, + +}; - /// defaults - defaults: ?StringMap = null, +pub const CssInJsBehavior = enum(u8) { - pub fn decode(reader: anytype) anyerror!EnvConfig { - var this = std.mem.zeroes(EnvConfig); +_none, + /// facade + facade, - while (true) { - switch (try reader.readByte()) { - 0 => { - return this; - }, + /// facade_onimportcss + facade_onimportcss, - 1 => { - this.prefix = try reader.readValue([]const u8); - }, - 2 => { - this.defaults = try reader.readValue(StringMap); - }, - else => { - return error.InvalidMessage; - }, + /// auto_onimportcss + auto_onimportcss, + +_, + + 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.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(); - } - }; + +}; - pub const LoadedEnvConfig = struct { - /// dotenv - dotenv: DotEnvBehavior, +pub const JsxRuntime = enum(u8) { - /// defaults - defaults: StringMap, +_none, + /// automatic + automatic, - /// prefix - prefix: []const u8, + /// classic + classic, - pub fn decode(reader: anytype) anyerror!LoadedEnvConfig { - var this = std.mem.zeroes(LoadedEnvConfig); +_, - this.dotenv = try reader.readValue(DotEnvBehavior); - this.defaults = try reader.readValue(StringMap); - this.prefix = try reader.readValue([]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.writeEnum(this.dotenv); - try writer.writeValue(this.defaults); - try writer.writeValue(this.prefix); - } - }; + +}; - pub const FrameworkConfig = struct { - /// package - package: ?[]const u8 = null, +pub const Jsx = struct { +/// factory +factory: []const u8, - /// client - client: ?[]const u8 = null, +/// runtime +runtime: JsxRuntime, - /// server - server: ?[]const u8 = null, +/// fragment +fragment: []const u8, - /// development - development: ?bool = null, +/// development +development: bool = false, - /// client_env - client_env: ?EnvConfig = null, +/// import_source +import_source: []const u8, - /// server_env - server_env: ?EnvConfig = null, +/// react_fast_refresh +react_fast_refresh: bool = false, - /// client_css_in_js - client_css_in_js: ?CssInJsBehavior = null, - pub fn decode(reader: anytype) anyerror!FrameworkConfig { - var this = std.mem.zeroes(FrameworkConfig); +pub fn decode(reader: anytype) anyerror!Jsx { + var this = std.mem.zeroes(Jsx); - while (true) { - switch (try reader.readByte()) { - 0 => { - return this; - }, + this.factory = try reader.readValue([]const u8); + this.runtime = try reader.readValue(JsxRuntime); + this.fragment = try reader.readValue([]const u8); + this.development = try reader.readValue(bool); + this.import_source = try reader.readValue([]const u8); + this.react_fast_refresh = try reader.readValue(bool); + return this; +} - 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 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 StringPointer = packed struct { +/// offset +offset: u32 = 0, + +/// length +length: u32 = 0, + + +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 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, + +/// code +code: StringPointer, + +/// package_id +package_id: u32 = 0, + +/// id +id: u32 = 0, + +/// path_extname_length +path_extname_length: u8 = 0, + + +pub fn decode(reader: anytype) anyerror!JavascriptBundledModule { + var this = std.mem.zeroes(JavascriptBundledModule); + + 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 const JavascriptBundledPackage = struct { +/// name +name: StringPointer, + +/// version +version: StringPointer, + +/// hash +hash: u32 = 0, + +/// modules_offset +modules_offset: u32 = 0, + +/// modules_length +modules_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 encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeValue(this.name); + try writer.writeValue(this.version); + try writer.writeInt(this.hash); + try writer.writeInt(this.modules_offset); + try writer.writeInt(this.modules_length); +} + +}; + +pub const JavascriptBundle = struct { +/// modules +modules: []const JavascriptBundledModule, + +/// packages +packages: []const JavascriptBundledPackage, + +/// etag +etag: []const u8, + +/// generated_at +generated_at: u32 = 0, + +/// app_package_json_dependencies_hash +app_package_json_dependencies_hash: []const u8, + +/// import_from_name +import_from_name: []const u8, + +/// manifest_string +manifest_string: []const u8, + + +pub fn decode(reader: anytype) anyerror!JavascriptBundle { + var this = std.mem.zeroes(JavascriptBundle); + + this.modules = try reader.readArray(JavascriptBundledModule); + this.packages = try reader.readArray(JavascriptBundledPackage); + this.etag = try reader.readArray(u8); + this.generated_at = try reader.readValue(u32); + this.app_package_json_dependencies_hash = try reader.readArray(u8); + this.import_from_name = try reader.readArray(u8); + this.manifest_string = try reader.readArray(u8); + return this; +} + +pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeArray(JavascriptBundledModule, this.modules); + try writer.writeArray(JavascriptBundledPackage, this.packages); + try writer.writeArray(u8, this.etag); + try writer.writeInt(this.generated_at); + try writer.writeArray(u8, this.app_package_json_dependencies_hash); + try writer.writeArray(u8, this.import_from_name); + try writer.writeArray(u8, this.manifest_string); +} + +}; + +pub const JavascriptBundleContainer = struct { +/// bundle_format_version +bundle_format_version: ?u32 = null, + +/// routes +routes: ?LoadedRouteConfig = null, + +/// framework +framework: ?LoadedFramework = null, + +/// bundle +bundle: ?JavascriptBundle = 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.routes = try reader.readValue(LoadedRouteConfig); +}, + 3 => { + this.framework = try reader.readValue(LoadedFramework); +}, + 4 => { + this.bundle = try reader.readValue(JavascriptBundle); +}, + 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.routes) |routes| { + try writer.writeFieldID(2); + try writer.writeValue(routes); +} +if (this.framework) |framework| { + try writer.writeFieldID(3); + try writer.writeValue(framework); +} +if (this.bundle) |bundle| { + try writer.writeFieldID(4); + try writer.writeValue(bundle); +} +if (this.code_length) |code_length| { + try writer.writeFieldID(5); + try writer.writeInt(code_length); +} +try writer.endMessage(); +} + +}; + +pub const ScanDependencyMode = enum(u8) { + +_none, + /// app + app, + + /// all + all, + +_, + + pub fn jsonStringify(self: *const @This(), opts: anytype, o: anytype) !void { + return try std.json.stringify(@tagName(self), opts, o); } - } - unreachable; - } - pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - if (this.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 ModuleImportType = enum(u8) { - /// package - package: []const u8, +_none, + /// import + import, - /// development - development: bool = false, + /// require + require, - /// client - client: bool = false, +_, - /// env - env: LoadedEnvConfig, + pub fn jsonStringify(self: *const @This(), opts: anytype, o: anytype) !void { + return try std.json.stringify(@tagName(self), opts, o); + } - /// client_css_in_js - client_css_in_js: CssInJsBehavior, + +}; - pub fn decode(reader: anytype) anyerror!LoadedFramework { - var this = std.mem.zeroes(LoadedFramework); +pub const ModuleImportRecord = struct { +/// kind +kind: ModuleImportType, - 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; - } +/// path +path: []const u8, - 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); - } - }; +/// dynamic +dynamic: bool = false, - pub const LoadedRouteConfig = struct { - /// dir - dir: []const u8, - /// extensions - extensions: []const []const u8, +pub fn decode(reader: anytype) anyerror!ModuleImportRecord { + var this = std.mem.zeroes(ModuleImportRecord); - /// static_dir - static_dir: []const u8, + this.kind = try reader.readValue(ModuleImportType); + this.path = try reader.readValue([]const u8); + this.dynamic = try reader.readValue(bool); + return this; +} - /// asset_prefix - asset_prefix: []const u8, +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 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 Module = struct { +/// path +path: []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); - } - }; +/// imports +imports: []const ModuleImportRecord, - pub const RouteConfig = struct { - /// dir - dir: []const []const u8, - /// extensions - extensions: []const []const u8, +pub fn decode(reader: anytype) anyerror!Module { + var this = std.mem.zeroes(Module); - /// static_dir - static_dir: ?[]const u8 = null, + this.path = try reader.readValue([]const u8); + this.imports = try reader.readArray(ModuleImportRecord); + return this; +} - /// asset_prefix - asset_prefix: ?[]const u8 = null, +pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeValue(this.path); + try writer.writeArray(ModuleImportRecord, this.imports); +} - pub fn decode(reader: anytype) anyerror!RouteConfig { - var this = std.mem.zeroes(RouteConfig); +}; - while (true) { - switch (try reader.readByte()) { - 0 => { - return this; - }, +pub const StringMap = struct { +/// keys +keys: []const []const u8, - 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; - }, +/// values +values: []const []const u8, + + +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 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, + +/// loaders +loaders: []const Loader, + + +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.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 const TransformOptions = struct { - /// jsx - jsx: ?Jsx = null, +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; +} - /// tsconfig_override - tsconfig_override: ?[]const u8 = null, +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(); +} - /// resolve - resolve: ?ResolveMode = null, +}; - /// origin - origin: ?[]const u8 = null, +pub const LoadedEnvConfig = struct { +/// dotenv +dotenv: DotEnvBehavior, - /// absolute_working_dir - absolute_working_dir: ?[]const u8 = null, +/// defaults +defaults: StringMap, - /// define - define: ?StringMap = null, +/// prefix +prefix: []const u8, - /// preserve_symlinks - preserve_symlinks: ?bool = null, - /// entry_points - entry_points: []const []const u8, +pub fn decode(reader: anytype) anyerror!LoadedEnvConfig { + var this = std.mem.zeroes(LoadedEnvConfig); - /// write - write: ?bool = null, + this.dotenv = try reader.readValue(DotEnvBehavior); + this.defaults = try reader.readValue(StringMap); + this.prefix = try reader.readValue([]const u8); + return this; +} - /// inject - inject: []const []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); +} - /// output_dir - output_dir: ?[]const u8 = null, +}; - /// external - external: []const []const u8, +pub const FrameworkConfig = struct { +/// package +package: ?[]const u8 = null, + +/// client +client: ?FrameworkEntryPointMessage = null, + +/// server +server: ?FrameworkEntryPointMessage = null, + +/// fallback +fallback: ?FrameworkEntryPointMessage = null, + +/// development +development: ?bool = 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(FrameworkEntryPointMessage); +}, + 3 => { + this.server = try reader.readValue(FrameworkEntryPointMessage); +}, + 4 => { + this.fallback = try reader.readValue(FrameworkEntryPointMessage); +}, + 5 => { + this.development = try reader.readValue(bool); +}, + 6 => { + this.client_css_in_js = try reader.readValue(CssInJsBehavior); +}, + else => { + return error.InvalidMessage; + }, + } + } +unreachable; +} - /// loaders - loaders: ?LoaderMap = null, +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.fallback) |fallback| { + try writer.writeFieldID(4); + try writer.writeValue(fallback); +} +if (this.development) |development| { + try writer.writeFieldID(5); + try writer.writeInt(@intCast(u8, @boolToInt(development))); +} +if (this.client_css_in_js) |client_css_in_js| { + try writer.writeFieldID(6); + try writer.writeEnum(client_css_in_js); +} +try writer.endMessage(); +} - /// main_fields - main_fields: []const []const u8, +}; - /// platform - platform: ?Platform = null, +pub const FrameworkEntryPoint = struct { +/// kind +kind: FrameworkEntryPointType, - /// serve - serve: ?bool = null, +/// path +path: []const u8, - /// extension_order - extension_order: []const []const u8, +/// env +env: LoadedEnvConfig, - /// generate_node_module_bundle - generate_node_module_bundle: ?bool = null, - /// node_modules_bundle_path - node_modules_bundle_path: ?[]const u8 = null, +pub fn decode(reader: anytype) anyerror!FrameworkEntryPoint { + var this = std.mem.zeroes(FrameworkEntryPoint); - /// node_modules_bundle_path_server - node_modules_bundle_path_server: ?[]const u8 = null, + this.kind = try reader.readValue(FrameworkEntryPointType); + this.path = try reader.readValue([]const u8); + this.env = try reader.readValue(LoadedEnvConfig); + return this; +} - /// framework - framework: ?FrameworkConfig = null, +pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeEnum(this.kind); + try writer.writeValue(this.path); + try writer.writeValue(this.env); +} - /// router - router: ?RouteConfig = null, +}; - /// no_summary - no_summary: ?bool = null, +pub const FrameworkEntryPointMap = struct { +/// client +client: ?FrameworkEntryPoint = null, + +/// server +server: ?FrameworkEntryPoint = null, + +/// fallback +fallback: ?FrameworkEntryPoint = null, + + +pub fn decode(reader: anytype) anyerror!FrameworkEntryPointMap { + var this = std.mem.zeroes(FrameworkEntryPointMap); + + while(true) { + switch (try reader.readByte()) { + 0 => { return this; }, + + 1 => { + this.client = try reader.readValue(FrameworkEntryPoint); +}, + 2 => { + this.server = try reader.readValue(FrameworkEntryPoint); +}, + 3 => { + this.fallback = try reader.readValue(FrameworkEntryPoint); +}, + else => { + return error.InvalidMessage; + }, + } + } +unreachable; +} - pub fn decode(reader: anytype) anyerror!TransformOptions { - var this = std.mem.zeroes(TransformOptions); +pub fn encode(this: *const @This(), writer: anytype) anyerror!void { +if (this.client) |client| { + try writer.writeFieldID(1); + try writer.writeValue(client); +} +if (this.server) |server| { + try writer.writeFieldID(2); + try writer.writeValue(server); +} +if (this.fallback) |fallback| { + try writer.writeFieldID(3); + try writer.writeValue(fallback); +} +try writer.endMessage(); +} - 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; - }, +pub const FrameworkEntryPointMessage = struct { +/// path +path: ?[]const u8 = null, + +/// env +env: ?EnvConfig = null, + + +pub fn decode(reader: anytype) anyerror!FrameworkEntryPointMessage { + var this = std.mem.zeroes(FrameworkEntryPointMessage); + + while(true) { + switch (try reader.readByte()) { + 0 => { return this; }, + + 1 => { + this.path = try reader.readValue([]const u8); +}, + 2 => { + this.env = try reader.readValue(EnvConfig); +}, + else => { + return error.InvalidMessage; + }, + } + } +unreachable; +} + +pub fn encode(this: *const @This(), writer: anytype) anyerror!void { +if (this.path) |path| { + try writer.writeFieldID(1); + try writer.writeValue(path); +} +if (this.env) |env| { + try writer.writeFieldID(2); + try writer.writeValue(env); +} +try writer.endMessage(); +} + +}; + +pub const LoadedFramework = struct { +/// package +package: []const u8, + +/// development +development: bool = false, + +/// entry_points +entry_points: FrameworkEntryPointMap, + +/// client_css_in_js +client_css_in_js: CssInJsBehavior, + + +pub fn decode(reader: anytype) anyerror!LoadedFramework { + var this = std.mem.zeroes(LoadedFramework); + + this.package = try reader.readValue([]const u8); + this.development = try reader.readValue(bool); + this.entry_points = try reader.readValue(FrameworkEntryPointMap); + this.client_css_in_js = try reader.readValue(CssInJsBehavior); + return this; +} + +pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeValue(this.package); + try writer.writeInt(@intCast(u8, @boolToInt(this.development))); + try writer.writeValue(this.entry_points); + try writer.writeEnum(this.client_css_in_js); +} + +}; + +pub const LoadedRouteConfig = struct { +/// dir +dir: []const u8, + +/// extensions +extensions: []const []const u8, + +/// static_dir +static_dir: []const u8, + +/// asset_prefix +asset_prefix: []const u8, + + +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 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); +} + +}; + +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; +} + +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 const TransformOptions = struct { +/// jsx +jsx: ?Jsx = null, + +/// tsconfig_override +tsconfig_override: ?[]const u8 = null, + +/// resolve +resolve: ?ResolveMode = null, + +/// origin +origin: ?[]const u8 = null, + +/// absolute_working_dir +absolute_working_dir: ?[]const u8 = null, + +/// define +define: ?StringMap = null, + +/// preserve_symlinks +preserve_symlinks: ?bool = null, + +/// entry_points +entry_points: []const []const u8, + +/// write +write: ?bool = null, + +/// inject +inject: []const []const u8, + +/// output_dir +output_dir: ?[]const u8 = null, + +/// external +external: []const []const u8, + +/// loaders +loaders: ?LoaderMap = null, + +/// main_fields +main_fields: []const []const u8, + +/// platform +platform: ?Platform = null, + +/// serve +serve: ?bool = null, + +/// extension_order +extension_order: []const []const u8, + +/// 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; +} + +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(); +} + +}; + +pub const FileHandle = struct { +/// path +path: []const u8, + +/// size +size: u32 = 0, + +/// fd +fd: u32 = 0, + + +pub fn decode(reader: anytype) anyerror!FileHandle { + var this = std.mem.zeroes(FileHandle); + + 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); - } - if (this.no_summary) |no_summary| { - try writer.writeFieldID(23); - try writer.writeInt(@intCast(u8, @boolToInt(no_summary))); - } - try writer.endMessage(); - } - }; + +}; - pub const FileHandle = struct { - /// path - path: []const u8, +pub const OutputFile = struct { +/// data +data: []const u8, - /// size - size: u32 = 0, +/// path +path: []const u8, - /// fd - fd: u32 = 0, - pub fn decode(reader: anytype) anyerror!FileHandle { - var this = std.mem.zeroes(FileHandle); +pub fn decode(reader: anytype) anyerror!OutputFile { + var this = std.mem.zeroes(OutputFile); - this.path = try reader.readValue([]const u8); - this.size = try reader.readValue(u32); - this.fd = try reader.readValue(u32); - return this; - } + this.data = try reader.readArray(u8); + this.path = try reader.readValue([]const u8); + return this; +} - pub fn encode(this: *const @This(), writer: anytype) anyerror!void { - try writer.writeValue(this.path); - try writer.writeInt(this.size); - try writer.writeInt(this.fd); - } - }; +pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeArray(u8, this.data); + try writer.writeValue(this.path); +} - pub const Transform = struct { - /// handle - handle: ?FileHandle = null, +}; - /// path - path: ?[]const u8 = null, +pub const TransformResponse = struct { +/// status +status: TransformResponseStatus, - /// contents - contents: []const u8, +/// files +files: []const OutputFile, - /// loader - loader: ?Loader = null, +/// errors +errors: []const Message, - /// options - options: ?TransformOptions = null, - pub fn decode(reader: anytype) anyerror!Transform { - var this = std.mem.zeroes(Transform); +pub fn decode(reader: anytype) anyerror!TransformResponse { + var this = std.mem.zeroes(TransformResponse); - while (true) { - switch (try reader.readByte()) { - 0 => { - return this; - }, + this.status = try reader.readValue(TransformResponseStatus); + this.files = try reader.readArray(OutputFile); + this.errors = try reader.readArray(Message); + return this; +} - 1 => { - this.handle = try reader.readValue(FileHandle); - }, - 2 => { - this.path = try reader.readValue([]const u8); - }, - 3 => { - this.contents = try reader.readArray(u8); - }, - 4 => { - this.loader = try reader.readValue(Loader); - }, - 5 => { - this.options = try reader.readValue(TransformOptions); - }, - else => { - return error.InvalidMessage; - }, +pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeEnum(this.status); + try writer.writeArray(OutputFile, this.files); + try writer.writeArray(Message, this.errors); +} + +}; + +pub const MessageLevel = 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 MessageMeta = struct { +/// resolve +resolve: ?[]const u8 = null, + +/// build +build: ?bool = null, + + +pub fn decode(reader: anytype) anyerror!MessageMeta { + var this = std.mem.zeroes(MessageMeta); + + while(true) { + switch (try reader.readByte()) { + 0 => { return this; }, + + 1 => { + this.resolve = try reader.readValue([]const u8); +}, + 2 => { + this.build = try reader.readValue(bool); +}, + else => { + return error.InvalidMessage; + }, + } + } +unreachable; +} - /// warn - warn, +pub fn encode(this: *const @This(), writer: anytype) anyerror!void { +if (this.resolve) |resolve| { + try writer.writeFieldID(1); + try writer.writeValue(resolve); +} +if (this.build) |build| { + try writer.writeFieldID(2); + try writer.writeInt(@intCast(u8, @boolToInt(build))); +} +try writer.endMessage(); +} - /// note - note, +}; - /// debug - debug, +pub const Message = struct { +/// level +level: MessageLevel, - _, +/// data +data: MessageData, - pub fn jsonStringify(self: *const @This(), opts: anytype, o: anytype) !void { - return try std.json.stringify(@tagName(self), opts, o); - } - }; +/// notes +notes: []const MessageData, - pub const Location = struct { - /// file - file: []const u8, +/// on +on: MessageMeta, - /// namespace - namespace: []const u8, - /// line - line: i32 = 0, +pub fn decode(reader: anytype) anyerror!Message { + var this = std.mem.zeroes(Message); - /// column - column: i32 = 0, + this.level = try reader.readValue(MessageLevel); + this.data = try reader.readValue(MessageData); + this.notes = try reader.readArray(MessageData); + this.on = try reader.readValue(MessageMeta); + return this; +} - /// line_text - line_text: []const u8, +pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + try writer.writeEnum(this.level); + try writer.writeValue(this.data); + try writer.writeArray(MessageData, this.notes); + try writer.writeValue(this.on); +} - /// suggestion - suggestion: []const u8, +}; - /// offset - offset: u32 = 0, +pub const Log = struct { +/// warnings +warnings: u32 = 0, - pub fn decode(reader: anytype) anyerror!Location { - var this = std.mem.zeroes(Location); +/// errors +errors: u32 = 0, - 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; - } +/// msgs +msgs: []const Message, - 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 fn decode(reader: anytype) anyerror!Log { + var this = std.mem.zeroes(Log); - /// location - location: ?Location = null, + this.warnings = try reader.readValue(u32); + this.errors = try reader.readValue(u32); + this.msgs = try reader.readArray(Message); + return this; +} - pub fn decode(reader: anytype) anyerror!MessageData { - var this = std.mem.zeroes(MessageData); +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); +} - 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; - }, +pub const Reloader = enum(u8) { + +_none, + /// disable + disable, + + /// 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); } - } - 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 483b5d09b..f308fc204 100644 --- a/src/bundler.zig +++ b/src/bundler.zig @@ -89,6 +89,7 @@ pub const ParseResult = struct { loader: options.Loader, ast: js_ast.Ast, input_fd: ?StoredFileDescriptorType = null, + empty: bool = false, }; pub fn NewBundler(cache_files: bool) type { @@ -242,9 +243,9 @@ pub fn NewBundler(cache_files: bool) type { if (this.options.framework) |framework| { if (this.options.platform.isClient()) { - try this.options.loadDefines(this.allocator, this.env, &framework.client_env); + try this.options.loadDefines(this.allocator, this.env, &framework.client.env); } else { - try this.options.loadDefines(this.allocator, this.env, &framework.server_env); + try this.options.loadDefines(this.allocator, this.env, &framework.server.env); } } else { try this.options.loadDefines(this.allocator, this.env, &this.options.env); @@ -268,9 +269,9 @@ pub fn NewBundler(cache_files: bool) type { if (this.options.areDefinesUnset()) { if (this.options.platform.isClient()) { - this.options.env = framework.client_env; + this.options.env = framework.client.env; } else { - this.options.env = framework.server_env; + this.options.env = framework.server.env; } } @@ -289,11 +290,15 @@ pub fn NewBundler(cache_files: bool) type { if (this.options.framework != null) { try this.configureFramework(true); if (comptime client) { - if (this.options.framework.?.client.len > 0) { - return try this.resolver.resolve(this.fs.top_level_dir, this.options.framework.?.client, .stmt); + if (this.options.framework.?.client.isEnabled()) { + return try this.resolver.resolve(this.fs.top_level_dir, this.options.framework.?.client.path, .stmt); + } + + if (this.options.framework.?.fallback.isEnabled()) { + return try this.resolver.resolve(this.fs.top_level_dir, this.options.framework.?.fallback.path, .stmt); } } else { - if (this.options.framework.?.server.len > 0) { + if (this.options.framework.?.server.isEnabled()) { return try this.resolver.resolve(this.fs.top_level_dir, this.options.framework.?.server, .stmt); } } @@ -732,20 +737,38 @@ pub fn NewBundler(cache_files: bool) type { if (framework_config) |conf| { defer this.bundler.resetStore(); - if (conf.client) { - if (bundler.configureFrameworkWithResolveResult(true)) |result_| { - if (result_) |result| { - try this.enqueueItem(result); + try this.bundler.configureFramework(true); + if (bundler.options.framework) |framework| { + if (bundler.options.platform == .bun) { + if (framework.server.isEnabled()) { + const resolved = try bundler.linker.resolver.resolve( + bundler.fs.top_level_dir, + framework.server.path, + .entry_point, + ); + try this.enqueueItem(resolved); } - } else |err| {} - } else { - if (bundler.configureFrameworkWithResolveResult(false)) |result_| { - if (result_) |result| { - try this.enqueueItem(result); + } else { + if (framework.client.isEnabled()) { + const resolved = try bundler.linker.resolver.resolve( + bundler.fs.top_level_dir, + framework.client.path, + .entry_point, + ); + try this.enqueueItem(resolved); } - } else |err| {} + + if (framework.fallback.isEnabled()) { + const resolved = try bundler.linker.resolver.resolve( + bundler.fs.top_level_dir, + framework.fallback.path, + .entry_point, + ); + try this.enqueueItem(resolved); + } + } } - } + } else {} // Normally, this is automatic // However, since we only do the parsing pass, it may not get imported automatically. @@ -1537,7 +1560,12 @@ pub fn NewBundler(cache_files: bool) type { file_path.pretty = allocator.dupe(u8, bundler.fs.relativeTo(file_path.text)) catch unreachable; } - bundler.setAllocator(allocator); + var old_bundler_allocator = bundler.allocator; + bundler.allocator = allocator; + defer bundler.allocator = old_bundler_allocator; + var old_linker_allocator = bundler.linker.allocator; + defer bundler.linker.allocator = old_linker_allocator; + bundler.linker.allocator = allocator; switch (loader) { .css => { @@ -1593,8 +1621,6 @@ pub fn NewBundler(cache_files: bool) type { }; }, else => { - var old_allocator = bundler.allocator; - bundler.setAllocator(allocator); var result = bundler.parse( allocator, file_path, @@ -1604,14 +1630,16 @@ pub fn NewBundler(cache_files: bool) type { filepath_hash, client_entry_point, ) orelse { - bundler.setAllocator(old_allocator); bundler.resetStore(); return BuildResolveResultPair{ .written = 0, .input_fd = null, }; }; - bundler.setAllocator(old_allocator); + + if (result.empty) { + return BuildResolveResultPair{ .written = 0, .input_fd = result.input_fd }; + } try bundler.linker.link(file_path, &result, import_path_format, false); @@ -1838,7 +1866,7 @@ pub fn NewBundler(cache_files: bool) type { dirname_fd: StoredFileDescriptorType, file_descriptor: ?StoredFileDescriptorType, file_hash: ?u32, - client_entry_point_: ?*ClientEntryPoint, + client_entry_point_: anytype, ) ?ParseResult { if (FeatureFlags.tracing) { bundler.timer.start(); @@ -1854,20 +1882,26 @@ pub fn NewBundler(cache_files: bool) type { const source: logger.Source = brk: { if (client_entry_point_) |client_entry_point| { - break :brk client_entry_point.source; - } else { - const entry = bundler.resolver.caches.fs.readFile( - bundler.fs, - path.text, - dirname_fd, - true, - file_descriptor, - ) catch return null; - input_fd = entry.fd; - break :brk logger.Source.initRecycledFile(Fs.File{ .path = path, .contents = entry.contents }, bundler.allocator) catch return null; + if (@hasField(std.meta.Child(@TypeOf(client_entry_point)), "source")) { + break :brk client_entry_point.source; + } } + + const entry = bundler.resolver.caches.fs.readFile( + bundler.fs, + path.text, + dirname_fd, + true, + file_descriptor, + ) catch return null; + input_fd = entry.fd; + break :brk logger.Source.initRecycledFile(Fs.File{ .path = path, .contents = entry.contents }, bundler.allocator) catch return null; }; + if (source.contents.len == 0 or (source.contents.len < 33 and std.mem.trim(u8, source.contents, "\n\r ").len == 0)) { + return ParseResult{ .source = source, .input_fd = input_fd, .loader = loader, .empty = true, .ast = js_ast.Ast.empty }; + } + switch (loader) { .js, .jsx, @@ -2140,7 +2174,7 @@ pub fn NewBundler(cache_files: bool) type { if (load_from_routes) { if (bundler.options.framework) |*framework| { - if (framework.client.len > 0) { + if (framework.client.isEnabled()) { did_start = true; try switch (bundler.options.import_path_format) { .relative => bundler.processResolveQueue(.relative, true, @TypeOf(outstream), outstream), @@ -2171,7 +2205,7 @@ pub fn NewBundler(cache_files: bool) type { if (load_from_routes) { if (bundler.options.framework) |*framework| { - if (framework.client.len > 0) { + if (framework.client.isEnabled()) { did_start = true; try switch (bundler.options.import_path_format) { .relative => bundler.processResolveQueue(.relative, true, std.fs.Dir, output_dir), @@ -2245,7 +2279,7 @@ pub fn NewBundler(cache_files: bool) type { if (item.import_kind == .entry_point and loader.supportsClientEntryPoint()) { var client_entry_point = try bundler.allocator.create(ClientEntryPoint); client_entry_point.* = ClientEntryPoint{}; - try client_entry_point.generate(ThisBundler, bundler, path.name, bundler.options.framework.?.client); + try client_entry_point.generate(ThisBundler, bundler, path.name, bundler.options.framework.?.client.path); try bundler.virtual_modules.append(client_entry_point); const entry_point_output_file = bundler.buildWithResolveResultEager( @@ -2577,6 +2611,61 @@ pub const ServeResult = struct { mime_type: MimeType, }; +pub const FallbackEntryPoint = struct { + code_buffer: [8096]u8 = undefined, + path_buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined, + source: logger.Source = undefined, + built_code: string = "", + + pub fn generate( + entry: *FallbackEntryPoint, + input_path: string, + comptime BundlerType: type, + bundler: *BundlerType, + ) !void { + // This is *extremely* naive. + // The basic idea here is this: + // -- + // import * as EntryPoint from 'entry-point'; + // import boot from 'framework'; + // boot(EntryPoint); + // -- + // We go through the steps of printing the code -- only to then parse/transpile it because + // we want it to go through the linker and the rest of the transpilation process + + const dir_to_use: string = bundler.fs.top_level_dir; + const disable_css_imports = bundler.options.framework.?.client_css_in_js != .auto_onimportcss; + + var code: string = undefined; + + if (disable_css_imports) { + code = try std.fmt.bufPrint( + &entry.code_buffer, + \\globalThis.Bun_disableCSSImports = true; + \\import boot from '{s}'; + \\boot(globalThis.__BUN_DATA__); + , + .{ + input_path, + }, + ); + } else { + code = try std.fmt.bufPrint( + &entry.code_buffer, + \\import boot from '{s}'; + \\boot(globalThis.__BUN_DATA__); + , + .{ + input_path, + }, + ); + } + + entry.source = logger.Source.initPathString(input_path, code); + entry.source.path.namespace = "fallback-entry"; + } +}; + pub const ClientEntryPoint = struct { code_buffer: [8096]u8 = undefined, path_buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined, diff --git a/src/cli/bun_command.zig b/src/cli/bun_command.zig index 1a63a140d..a3e56f82a 100644 --- a/src/cli/bun_command.zig +++ b/src/cli/bun_command.zig @@ -105,7 +105,7 @@ pub const BunCommand = struct { }; var loaded_framework: ?Api.LoadedFramework = brk: { if (this_bundler.options.framework) |*conf| { - break :brk conf.toAPI(allocator, this_bundler.fs.top_level_dir, true); + break :brk try conf.toAPI(allocator, this_bundler.fs.top_level_dir); } break :brk null; }; @@ -114,7 +114,7 @@ pub const BunCommand = struct { var server_bundler_generator_thread: ?std.Thread = null; var generated_server = false; if (this_bundler.options.framework) |*framework| { - if (framework.toAPI(allocator, this_bundler.fs.top_level_dir, false)) |_server_conf| { + if (framework.toAPI(allocator, this_bundler.fs.top_level_dir) catch null) |_server_conf| { if (FeatureFlags.parallel_bun) { wait_group.add(); server_bundler_generator_thread = try std.Thread.spawn( diff --git a/src/fallback.html b/src/fallback.html new file mode 100644 index 000000000..6d40584c3 --- /dev/null +++ b/src/fallback.html @@ -0,0 +1,17 @@ +<!DOCTYPE html> +<html> + <head> + <meta charset="utf-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <!-- prettier-ignore --> + <script id="__bunfallback" type="binary/peechy">{[blob]s}</script> + {[preload]s} + </head> + <body style="visibility: hidden"></body> + + <!-- prettier-ignore --> + <script id='__bun_fallback_script' type="application/javascript">{[fallback]s}</script> + + <!-- prettier-ignore --> + <script async type="module">{[entry_point]s}</script> +</html> diff --git a/src/fallback.ts b/src/fallback.ts new file mode 100644 index 000000000..cf4195c4d --- /dev/null +++ b/src/fallback.ts @@ -0,0 +1,24 @@ +import { ByteBuffer } from "peechy"; +import { FallbackStep } from "./api/schema"; +import { + decodeFallbackMessageContainer, + FallbackMessageContainer, +} from "./api/schema"; + +function getFallbackInfo(): FallbackMessageContainer { + var binary_string = window.atob( + document.querySelector("#__bunfallback").textContent.trim() + ); + document.querySelector("#__bunfallback").remove(); + + var len = binary_string.length; + var bytes = new Uint8Array(len); + for (var i = 0; i < len; i++) { + bytes[i] = binary_string.charCodeAt(i); + } + + return decodeFallbackMessageContainer(new ByteBuffer(bytes)); +} + +globalThis.__BUN_DATA__ = getFallbackInfo(); +document.getElementById("__bun_fallback_script")?.remove(); diff --git a/src/fallback.version b/src/fallback.version new file mode 100644 index 000000000..3b2d7e4b9 --- /dev/null +++ b/src/fallback.version @@ -0,0 +1 @@ +8bf9555fd27e865d
\ No newline at end of file diff --git a/src/http.zig b/src/http.zig index 27eba24ba..d70daf2e0 100644 --- a/src/http.zig +++ b/src/http.zig @@ -11,6 +11,7 @@ const bundler = @import("bundler.zig"); const logger = @import("logger.zig"); const Fs = @import("./fs.zig"); const Options = @import("./options.zig"); +const Fallback = @import("./runtime.zig").Fallback; const Css = @import("css_scanner.zig"); const NodeModuleBundle = @import("./node_module_bundle.zig").NodeModuleBundle; const resolve_path = @import("./resolver/resolve_path.zig"); @@ -162,6 +163,129 @@ pub const RequestContext = struct { return null; } + pub fn renderFallback( + this: *RequestContext, + allocator: *std.mem.Allocator, + bundler_: *Bundler, + step: Api.FallbackStep, + log: *logger.Log, + err: anyerror, + exceptions: []Api.JsException, + comptime fmt: string, + args: anytype, + ) !void { + var route_index: i32 = -1; + const routes: []const string = if (bundler_.router != null) brk: { + const router = &bundler_.router.?; + var list = try router.getEntryPointsWithBuffer(allocator, false); + break :brk list.entry_points; + } else &([_]string{}); + var preload: string = ""; + + var params: Api.StringMap = std.mem.zeroes(Api.StringMap); + if (fallback_entry_point_created == false) { + defer fallback_entry_point_created = true; + defer bundler_.resetStore(); + + // You'd think: hey we're just importing a file + // Do we really need to run it through the transpiler and linking and printing? + // The answer, however, is yes. + // What if you're importing a fallback that's in node_modules? + try fallback_entry_point.generate(bundler_.options.framework.?.fallback.path, Bundler, bundler_); + if (bundler_.parse( + default_allocator, + fallback_entry_point.source.path, + .js, + 0, + null, + null, + @as(?*bundler.FallbackEntryPoint, &fallback_entry_point), + )) |*result| { + try bundler_.linker.link(fallback_entry_point.source.path, result, .absolute_url, false); + var buffer_writer = try js_printer.BufferWriter.init(default_allocator); + var writer = js_printer.BufferPrinter.init(buffer_writer); + _ = try bundler_.print( + result.*, + @TypeOf(&writer), + &writer, + .esm, + ); + var slice = writer.ctx.buffer.toOwnedSliceLeaky(); + + fallback_entry_point.built_code = try default_allocator.dupe(u8, slice); + + writer.ctx.buffer.deinit(); + } + } + + if (this.matched_route) |match| { + if (match.params.len > 0) { + var all = try allocator.alloc(string, match.params.len * 2); + var keys = all[0..match.params.len]; + var values = all[match.params.len..]; + var slice = match.params.slice(); + + var _keys: []Router.TinyPtr = slice.items(.key); + var _values: []Router.TinyPtr = slice.items(.value); + + for (_keys) |key, i| { + keys[i] = key.str(match.name); + values[i] = _values[i].str(match.pathnameWithoutLeadingSlash()); + } + + params.keys = keys; + params.values = values; + } + + for (routes) |route, i| { + var comparator = route; + if (comparator[0] == '/') comparator = comparator[1..]; + + if (this.bundler.router.?.config.asset_prefix_path.len > 0) { + comparator = comparator[this.bundler.router.?.config.asset_prefix_path.len..]; + } + + if (strings.endsWith(match.file_path, comparator)) { + route_index = @truncate(i32, @intCast(i64, i)); + break; + } + } + } + + var fallback_container = try allocator.create(Api.FallbackMessageContainer); + defer allocator.destroy(fallback_container); + fallback_container.* = Api.FallbackMessageContainer{ + .message = try std.fmt.allocPrint(allocator, fmt, args), + .router = if (routes.len > 0) Api.Router{ .route = route_index, .params = params, .routes = routes } else null, + .reason = step, + .problems = Api.Problems{ + .code = @truncate(u16, @errorToInt(err)), + .name = @errorName(err), + .exceptions = exceptions, + .build = try log.toAPI(allocator), + }, + }; + + defer this.done(); + try this.writeStatus(500); + + this.appendHeader("Content-Type", MimeType.html.value); + var bb = std.ArrayList(u8).init(allocator); + defer bb.deinit(); + var bb_writer = bb.writer(); + + try Fallback.render( + allocator, + fallback_container, + preload, + fallback_entry_point.built_code, + @TypeOf(bb_writer), + bb_writer, + ); + try this.prepareToSendBody(bb.items.len, false); + try this.writeBodyBuf(bb.items); + } + fn matchPublicFolder(this: *RequestContext) ?bundler.ServeResult { if (!this.bundler.options.routes.static_dir_enabled) return null; const relative_path = this.url.path; @@ -703,10 +827,134 @@ pub const RequestContext = struct { args: Api.TransformOptions, framework: Options.Framework, existing_bundle: ?*NodeModuleBundle, - log: ?*logger.Log = null, + log: *logger.Log = undefined, watcher: *Watcher, env_loader: *DotEnv.Loader, origin: ZigURL, + client_bundler: Bundler, + + pub fn handleJSError( + this: *HandlerThread, + comptime step: Api.FallbackStep, + err: anyerror, + ) !void { + return try this.handleJSErrorFmt( + step, + err, + + "<r>JavaScript VM failed to start due to <red>{s}<r>.", + .{ + @errorName(err), + }, + ); + } + + pub fn handleJSErrorFmt(this: *HandlerThread, comptime step: Api.FallbackStep, err: anyerror, comptime fmt: string, args: anytype) !void { + var arena = std.heap.ArenaAllocator.init(default_allocator); + var allocator = &arena.allocator; + defer arena.deinit(); + + defer this.log.msgs.clearRetainingCapacity(); + + if (this.log.msgs.items.len > 0) { + for (this.log.msgs.items) |msg| { + msg.writeFormat(Output.errorWriter()) catch continue; + } + } + + Output.prettyErrorln(fmt, args); + Output.flush(); + + while (channel.tryReadItem() catch null) |item| { + item.ctx.renderFallback( + allocator, + &this.client_bundler, + step, + this.log, + err, + &[_]Api.JsException{}, + comptime Output.prettyFmt(fmt, false), + args, + ) catch {}; + } + } + + pub fn handleRuntimeJSError(this: *HandlerThread, js_value: JSValue, comptime step: Api.FallbackStep, comptime fmt: string, args: anytype) !void { + var arena = std.heap.ArenaAllocator.init(default_allocator); + var allocator = &arena.allocator; + defer arena.deinit(); + defer this.log.msgs.clearRetainingCapacity(); + + var exception_list: std.ArrayList(Api.JsException) = std.ArrayList(Api.JsException).init(allocator); + defer exception_list.deinit(); + + if (!js_value.isUndefinedOrNull()) { + javascript_vm.?.defaultErrorHandler( + js_value, + &exception_list, + ); + } else { + if (this.log.msgs.items.len > 0) { + for (this.log.msgs.items) |msg| { + msg.writeFormat(Output.errorWriter()) catch continue; + } + } + + Output.flush(); + } + + while (channel.tryReadItem() catch null) |item| { + item.ctx.renderFallback( + allocator, + &this.client_bundler, + step, + this.log, + error.JSError, + exception_list.items, + comptime Output.prettyFmt(fmt, false), + args, + ) catch {}; + } + } + + pub fn handleFetchEventError(this: *HandlerThread, err: anyerror, js_value: JSValue, ctx: *RequestContext) !void { + var arena = std.heap.ArenaAllocator.init(default_allocator); + var allocator = &arena.allocator; + defer arena.deinit(); + + defer this.log.msgs.clearRetainingCapacity(); + + var exception_list: std.ArrayList(Api.JsException) = std.ArrayList(Api.JsException).init(allocator); + defer exception_list.deinit(); + var did_log_messages = false; + if (!js_value.isUndefinedOrNull()) { + var start_count = this.log.msgs.items.len; + javascript_vm.?.defaultErrorHandler( + js_value, + &exception_list, + ); + did_log_messages = start_count != this.log.msgs.items.len and exception_list.items.len == 0; + } else { + if (this.log.msgs.items.len > 0) { + for (this.log.msgs.items) |msg| { + msg.writeFormat(Output.errorWriter()) catch continue; + } + } + + Output.flush(); + } + + ctx.renderFallback( + allocator, + &this.client_bundler, + Api.FallbackStep.fetch_event_handler, + this.log, + if (did_log_messages) error.BuildTimeError else err, + exception_list.items, + "", + .{}, + ) catch {}; + } }; pub const Channel = sync.Channel(*JavaScriptHandler, .{ .Static = 100 }); @@ -714,15 +962,14 @@ pub const RequestContext = struct { var has_loaded_channel = false; pub var javascript_disabled = false; - pub fn spawnThread(handler: HandlerThread) !void { + pub fn spawnThread(handler: *HandlerThread) !void { var thread = try std.Thread.spawn(.{}, spawn, .{handler}); thread.setName("WebSocket") catch {}; thread.detach(); } - pub fn spawn(handler: HandlerThread) void { - var _handler = handler; - _spawn(&_handler) catch {}; + pub fn spawn(handler: *HandlerThread) void { + _spawn(handler) catch {}; } pub fn _spawn(handler: *HandlerThread) !void { @@ -750,62 +997,49 @@ pub const RequestContext = struct { handler.log, handler.env_loader, ) catch |err| { - Output.prettyErrorln( - "JavaScript VM failed to start: <r><red>{s}<r>", - .{@errorName(err)}, - ); - Output.flush(); + handler.handleJSError(.create_vm, err) catch {}; return; }; - + vm.bundler.log = handler.log; std.debug.assert(JavaScript.VirtualMachine.vm_loaded); javascript_vm = vm; vm.bundler.options.origin = handler.origin; - const boot = vm.bundler.options.framework.?.server; + const boot = vm.bundler.options.framework.?.server.path; std.debug.assert(boot.len > 0); errdefer vm.deinit(); vm.watcher = handler.watcher; { defer vm.flush(); - vm.bundler.configureRouter(false) catch {}; + vm.bundler.configureRouter(false) catch |err| { + handler.handleJSError(.configure_router, err) catch {}; + return; + }; vm.bundler.configureDefines() catch |err| { - if (vm.log.msgs.items.len > 0) { - for (vm.log.msgs.items) |msg| { - msg.writeFormat(Output.errorWriter()) catch continue; - } - } - - Output.prettyErrorln( - "<r>JavaScript VM failed to start due to <red>{s}<r>.", - .{ - @errorName(err), - }, - ); - - Output.flush(); - - if (channel.tryReadItem() catch null) |item| { - item.ctx.sendInternalError(error.JSFailedToStart) catch {}; - } + handler.handleJSError(.configure_defines, err) catch {}; return; }; var entry_point = boot; if (!std.fs.path.isAbsolute(entry_point)) { - const resolved_entry_point = try vm.bundler.resolver.resolve( + const resolved_entry_point = vm.bundler.resolver.resolve( std.fs.path.dirname(boot) orelse vm.bundler.fs.top_level_dir, vm.bundler.normalizeEntryPointPath(boot), .entry_point, - ); + ) catch |err| { + try handler.handleJSError( + .resolve_entry_point, + err, + ); + return; + }; entry_point = (resolved_entry_point.pathConst() orelse { - Output.prettyErrorln( + handler.handleJSErrorFmt( + .resolve_entry_point, + error.EntryPointDisabled, "<r>JavaScript VM failed to start due to disabled entry point: <r><b>\"{s}\"", .{resolved_entry_point.path_pair.primary.text}, - ); + ) catch {}; - if (channel.tryReadItem() catch null) |item| { - item.ctx.sendInternalError(error.JSFailedToStart) catch {}; - } return; }).text; } @@ -813,42 +1047,38 @@ pub const RequestContext = struct { var load_result = vm.loadEntryPoint( entry_point, ) catch |err| { - Output.prettyErrorln( + handler.handleJSErrorFmt( + .load_entry_point, + err, "<r>JavaScript VM failed to start.\n<red>{s}:<r> while loading <r><b>\"{s}\"", .{ @errorName(err), entry_point }, - ); + ) catch {}; - if (channel.tryReadItem() catch null) |item| { - item.ctx.sendInternalError(error.JSFailedToStart) catch {}; - item.ctx.arena.deinit(); - } return; }; switch (load_result.status(vm.global.vm())) { JSPromise.Status.Fulfilled => {}, else => { - Output.prettyErrorln( - "JavaScript VM failed to start", - .{}, - ); var result = load_result.result(vm.global.vm()); - vm.defaultErrorHandler(result); - - if (channel.tryReadItem() catch null) |item| { - item.ctx.sendInternalError(error.JSFailedToStart) catch {}; - item.ctx.arena.deinit(); - } + handler.handleRuntimeJSError( + result, + .eval_entry_point, + "<r>JavaScript VM failed to start.\nwhile loading <r><b>\"{s}\"", + .{entry_point}, + ) catch {}; return; }, } if (vm.event_listeners.count() == 0) { - Output.prettyErrorln("<r><red>error<r>: Framework didn't run <b><cyan>addEventListener(\"fetch\", callback)<r>, which means it can't accept HTTP requests.\nShutting down JS.", .{}); - if (channel.tryReadItem() catch null) |item| { - item.ctx.sendInternalError(error.JSFailedToStart) catch {}; - } + handler.handleJSErrorFmt( + .eval_entry_point, + error.MissingFetchHandler, + "<r><red>error<r>: Framework didn't run <b><cyan>addEventListener(\"fetch\", callback)<r>, which means it can't accept HTTP requests.\nShutting down JS.", + .{}, + ) catch {}; return; } } @@ -858,10 +1088,10 @@ pub const RequestContext = struct { JavaScript.Bun.flushCSSImports(); vm.flush(); - try runLoop(vm); + try runLoop(vm, handler); } - pub fn runLoop(vm: *JavaScript.VirtualMachine) !void { + pub fn runLoop(vm: *JavaScript.VirtualMachine, thread: *HandlerThread) !void { var module_map = ZigGlobalObject.getModuleRegistryMap(vm.global); JavaScript.VirtualMachine.vm.has_loaded = true; while (true) { @@ -875,7 +1105,13 @@ pub const RequestContext = struct { var handler: *JavaScriptHandler = try channel.readItem(); JavaScript.VirtualMachine.vm.preflush(); - try JavaScript.EventListenerMixin.emitFetchEvent(vm, &handler.ctx); + JavaScript.EventListenerMixin.emitFetchEvent( + vm, + &handler.ctx, + HandlerThread, + thread, + HandlerThread.handleFetchEventError, + ) catch |err| {}; } } @@ -899,36 +1135,43 @@ pub const RequestContext = struct { std.mem.copy(u8, &clone.ctx.match_file_path_buf, filepath_buf[0..ctx.matched_route.?.file_path.len]); if (!has_loaded_channel) { + var handler_thread = try server.allocator.create(HandlerThread); + has_loaded_channel = true; channel = Channel.init(); var transform_options = server.transform_options; if (server.transform_options.node_modules_bundle_path_server) |bundle_path| { transform_options.node_modules_bundle_path = bundle_path; transform_options.node_modules_bundle_path_server = null; - try JavaScriptHandler.spawnThread( - HandlerThread{ - .args = transform_options, - .framework = server.bundler.options.framework.?, - .existing_bundle = null, - .log = &server.log, - .watcher = server.watcher, - .env_loader = server.bundler.env, - .origin = server.bundler.options.origin, - }, - ); + handler_thread.* = HandlerThread{ + .args = transform_options, + .framework = server.bundler.options.framework.?, + .existing_bundle = null, + .log = undefined, + .watcher = server.watcher, + .env_loader = server.bundler.env, + .origin = server.bundler.options.origin, + .client_bundler = server.bundler, + }; } else { - try JavaScriptHandler.spawnThread( - HandlerThread{ - .args = server.transform_options, - .framework = server.bundler.options.framework.?, - .existing_bundle = server.bundler.options.node_modules_bundle, - .log = &server.log, - .watcher = server.watcher, - .env_loader = server.bundler.env, - .origin = server.bundler.options.origin, - }, - ); + handler_thread.* = HandlerThread{ + .args = server.transform_options, + .framework = server.bundler.options.framework.?, + .existing_bundle = server.bundler.options.node_modules_bundle, + .watcher = server.watcher, + .env_loader = server.bundler.env, + .log = undefined, + .origin = server.bundler.options.origin, + .client_bundler = server.bundler, + }; } + + handler_thread.log = try server.allocator.create(logger.Log); + handler_thread.log.* = logger.Log.init(server.allocator); + + try server.bundler.clone(server.allocator, &handler_thread.client_bundler); + + try JavaScriptHandler.spawnThread(handler_thread); } defer ctx.controlled = true; @@ -1335,6 +1578,8 @@ pub const RequestContext = struct { } threadlocal var client_entry_point: bundler.ClientEntryPoint = undefined; + threadlocal var fallback_entry_point: bundler.FallbackEntryPoint = undefined; + threadlocal var fallback_entry_point_created: bool = false; pub fn renderServeResult(ctx: *RequestContext, result: bundler.ServeResult) !void { if (ctx.keep_alive) { @@ -1465,10 +1710,10 @@ pub const RequestContext = struct { var client_entry_point_: ?*bundler.ClientEntryPoint = null; if (resolve_result.import_kind == .entry_point and loader.supportsClientEntryPoint()) { if (ctx.bundler.options.framework) |*framework| { - if (framework.client.len > 0) { + if (framework.client.isEnabled()) { client_entry_point = bundler.ClientEntryPoint{}; - try client_entry_point.generate(Bundler, ctx.bundler, path.name, framework.client); + try client_entry_point.generate(Bundler, ctx.bundler, path.name, framework.client.path); client_entry_point_ = &client_entry_point; } } @@ -1633,7 +1878,7 @@ pub const RequestContext = struct { fn handleBlobURL(ctx: *RequestContext, server: *Server) !void { var id = ctx.url.path["blob:".len..]; - // This lets us print + // This makes it Just Work if you pass a line/column number if (strings.indexOfChar(id, ':')) |colon| { id = id[0..colon]; } @@ -1651,19 +1896,46 @@ pub const RequestContext = struct { try ctx.writeBodyBuf(blob.ptr[0..blob.len]); } + fn handleBunURL(ctx: *RequestContext, server: *Server) !void { + const path = ctx.url.path["bun:".len..]; + + if (strings.eqlComptime(path, "_api.hmr")) { + try ctx.handleWebsocket(server); + return; + } + + if (strings.eqlComptime(path, "fallback")) { + const resolved = try ctx.bundler.resolver.resolve(ctx.bundler.fs.top_level_dir, ctx.bundler.options.framework.?.fallback.path, .stmt); + const resolved_path = resolved.pathConst() orelse return try ctx.sendNotFound(); + const mime_type_ext = ctx.bundler.options.out_extensions.get(resolved_path.name.ext) orelse resolved_path.name.ext; + const loader = ctx.bundler.options.loader(resolved_path.name.ext); + try ctx.renderServeResult(bundler.ServeResult{ + .file = Options.OutputFile.initPending(loader, resolved), + .mime_type = MimeType.byLoader( + loader, + mime_type_ext[1..], + ), + }); + return; + } + + try ctx.sendNotFound(); + return; + } + pub fn handleReservedRoutes(ctx: *RequestContext, server: *Server) !bool { if (strings.eqlComptime(ctx.url.extname, "bun") and ctx.bundler.options.node_modules_bundle != null) { try ctx.sendJSB(); return true; } - if (strings.eqlComptime(ctx.url.path, "_api.hmr")) { - try ctx.handleWebsocket(server); + if (ctx.url.path.len > "blob:".len and strings.eqlComptime(ctx.url.path[0.."blob:".len], "blob:")) { + try ctx.handleBlobURL(server); return true; } - if (ctx.url.path.len > "blob:".len and strings.eqlComptime(ctx.url.path[0.."blob:".len], "blob:")) { - try ctx.handleBlobURL(server); + if (ctx.url.path.len > "bun:".len and strings.eqlComptime(ctx.url.path[0.."bun:".len], "bun:")) { + try ctx.handleBunURL(server); return true; } diff --git a/src/javascript/jsc/bindings/exports.zig b/src/javascript/jsc/bindings/exports.zig index 6a8c6328b..c6a6c2b88 100644 --- a/src/javascript/jsc/bindings/exports.zig +++ b/src/javascript/jsc/bindings/exports.zig @@ -5,6 +5,7 @@ const CAPI = @import("../JavaScriptCore.zig"); const JS = @import("../javascript.zig"); const JSBase = @import("../base.zig"); const ZigURL = @import("../../../query_string_map.zig").URL; +const Api = @import("../../../api/schema.zig").Api; const Handler = struct { pub export fn global_signal_handler_fn(sig: i32, info: *const std.os.siginfo_t, ctx_ptr: ?*const c_void) callconv(.C) void { var stdout = std.io.getStdOut(); @@ -169,40 +170,6 @@ pub const ZigErrorType = extern struct { } }; -pub const JSErrorCode = enum(u8) { - Error = 0, - EvalError = 1, - RangeError = 2, - ReferenceError = 3, - SyntaxError = 4, - TypeError = 5, - URIError = 6, - AggregateError = 7, - - // StackOverflow & OutOfMemoryError is not an ErrorType in <JavaScriptCore/ErrorType.h> within JSC, so the number here is just totally made up - OutOfMemoryError = 8, - BundlerError = 252, - StackOverflow = 253, - UserErrorCode = 254, - _, -}; - -pub const JSRuntimeType = enum(u16) { - Nothing = 0x0, - Function = 0x1, - Undefined = 0x2, - Null = 0x4, - Boolean = 0x8, - AnyInt = 0x10, - Number = 0x20, - String = 0x40, - Object = 0x80, - Symbol = 0x100, - BigInt = 0x200, - - _, -}; - pub fn Errorable(comptime Type: type) type { return extern struct { result: Result, @@ -251,6 +218,40 @@ pub const ResolvedSource = extern struct { bytecodecache_fd: u64, }; +pub const JSErrorCode = enum(u8) { + Error = 0, + EvalError = 1, + RangeError = 2, + ReferenceError = 3, + SyntaxError = 4, + TypeError = 5, + URIError = 6, + AggregateError = 7, + + // StackOverflow & OutOfMemoryError is not an ErrorType in <JavaScriptCore/ErrorType.h> within JSC, so the number here is just totally made up + OutOfMemoryError = 8, + BundlerError = 252, + StackOverflow = 253, + UserErrorCode = 254, + _, +}; + +pub const JSRuntimeType = enum(u16) { + Nothing = 0x0, + Function = 0x1, + Undefined = 0x2, + Null = 0x4, + Boolean = 0x8, + AnyInt = 0x10, + Number = 0x20, + String = 0x40, + Object = 0x80, + Symbol = 0x100, + BigInt = 0x200, + + _, +}; + pub const ZigStackFrameCode = enum(u8) { None = 0, // 🏃 @@ -301,6 +302,49 @@ pub const ZigStackTrace = extern struct { frames_ptr: [*c]ZigStackFrame, frames_len: u8, + pub fn toAPI(this: *const ZigStackTrace, allocator: *std.mem.Allocator) !Api.StackTrace { + var stack_trace: Api.StackTrace = std.mem.zeroes(Api.StackTrace); + { + var source_lines_iter = this.sourceLineIterator(); + + var source_line_len: usize = 0; + var count: usize = 0; + while (source_lines_iter.next()) |source| { + count += 1; + source_line_len += source.text.len; + } + + if (count > 0 and source_line_len > 0) { + var source_lines = try allocator.alloc(Api.SourceLine, count); + var source_line_buf = try allocator.alloc(u8, source_line_len); + source_lines_iter = this.sourceLineIterator(); + var remain_buf = source_line_buf[0..]; + var i: usize = 0; + while (source_lines_iter.next()) |source| { + std.mem.copy(u8, remain_buf, source.text); + const copied_line = remain_buf[0..source.text.len]; + remain_buf = remain_buf[source.text.len..]; + source_lines[i] = .{ .text = copied_line, .line = source.line }; + i += 1; + } + stack_trace.source_lines = source_lines; + } + } + { + var _frames = this.frames(); + if (_frames.len > 0) { + var stack_frames = try allocator.alloc(Api.StackFrame, _frames.len); + stack_trace.frames = stack_frames; + + for (_frames) |frame, i| { + stack_frames[i] = try frame.toAPI(allocator); + } + } + } + + return stack_trace; + } + pub fn frames(this: *const ZigStackTrace) []const ZigStackFrame { return this.frames_ptr[0..this.frames_len]; } @@ -344,6 +388,34 @@ pub const ZigStackTrace = extern struct { }; pub const ZigStackFrame = extern struct { + function_name: ZigString, + source_url: ZigString, + position: ZigStackFramePosition, + code_type: ZigStackFrameCode, + + pub fn toAPI(this: *const ZigStackFrame, allocator: *std.mem.Allocator) !Api.StackFrame { + var frame: Api.StackFrame = std.mem.zeroes(Api.StackFrame); + if (this.function_name.len > 0) { + frame.function_name = try allocator.dupe(u8, this.function_name.slice()); + } + + if (this.source_url.len > 0) { + frame.file = try allocator.dupe(u8, this.source_url.slice()); + } + + frame.position.source_offset = this.position.source_offset; + frame.position.line = this.position.line; + frame.position.line_start = this.position.line_start; + frame.position.line_stop = this.position.line_stop; + frame.position.column_start = this.position.column_start; + frame.position.column_stop = this.position.column_stop; + frame.position.expression_start = this.position.expression_start; + frame.position.expression_stop = this.position.expression_stop; + frame.scope = @intToEnum(Api.StackFrameScope, @enumToInt(this.code_type)); + + return frame; + } + pub const SourceURLFormatter = struct { source_url: ZigString, position: ZigStackFramePosition, @@ -415,11 +487,6 @@ pub const ZigStackFrame = extern struct { .position = ZigStackFramePosition.Invalid, }; - function_name: ZigString, - source_url: ZigString, - position: ZigStackFramePosition, - code_type: ZigStackFrameCode, - pub fn nameFormatter(this: *const ZigStackFrame, comptime enable_color: bool) NameFormatter { return NameFormatter{ .function_name = this.function_name, .code_type = this.code_type, .enable_color = enable_color }; } @@ -455,10 +522,6 @@ pub const ZigStackFramePosition = extern struct { }; pub const ZigException = extern struct { - pub const shim = Shimmer("Zig", "Exception", @This()); - pub const name = "ZigException"; - pub const namespace = shim.namespace; - code: JSErrorCode, runtime_type: JSRuntimeType, name: ZigString, @@ -467,6 +530,10 @@ pub const ZigException = extern struct { exception: ?*c_void, + pub const shim = Shimmer("Zig", "Exception", @This()); + pub const name = "ZigException"; + pub const namespace = shim.namespace; + pub const Holder = extern struct { const frame_count = 24; const source_lines_count = 6; @@ -529,6 +596,36 @@ pub const ZigException = extern struct { return shim.cppFn("fromException", .{exception}); } + pub fn addToErrorList(this: *ZigException, error_list: *std.ArrayList(Api.JsException)) !void { + const _name: string = @field(this, "name").slice(); + const message: string = @field(this, "message").slice(); + + var is_empty = true; + var api_exception = Api.JsException{ + .runtime_type = @enumToInt(this.runtime_type), + .code = @enumToInt(this.code), + }; + + if (_name.len > 0) { + api_exception.name = try error_list.allocator.dupe(u8, _name); + is_empty = false; + } + + if (message.len > 0) { + api_exception.message = try error_list.allocator.dupe(u8, message); + is_empty = false; + } + + if (this.stack.frames_len > 0) { + api_exception.stack = try this.stack.toAPI(error_list.allocator); + is_empty = false; + } + + if (!is_empty) { + try error_list.append(api_exception); + } + } + pub const Extern = [_][]const u8{"fromException"}; }; @@ -656,7 +753,7 @@ pub const ZigConsoleClient = struct { switch (@intToEnum(CellType, value.asCell().getType())) { CellType.ErrorInstanceType => { - JS.VirtualMachine.printErrorlikeObject(JS.VirtualMachine.vm, value, null, enable_ansi_colors); + JS.VirtualMachine.printErrorlikeObject(JS.VirtualMachine.vm, value, null, null, enable_ansi_colors); return; }, diff --git a/src/javascript/jsc/javascript.zig b/src/javascript/jsc/javascript.zig index fa942e4a2..8bace87e9 100644 --- a/src/javascript/jsc/javascript.zig +++ b/src/javascript/jsc/javascript.zig @@ -761,8 +761,10 @@ pub const VirtualMachine = struct { return slice; } + + // This double prints pub fn promiseRejectionTracker(global: *JSGlobalObject, promise: *JSPromise, rejection: JSPromiseRejectionOperation) callconv(.C) JSValue { - VirtualMachine.vm.defaultErrorHandler(promise.result(global.vm())); + // VirtualMachine.vm.defaultErrorHandler(promise.result(global.vm()), null); return JSValue.jsUndefined(); } @@ -854,30 +856,52 @@ pub const VirtualMachine = struct { // TODO: pub fn deinit(this: *VirtualMachine) void {} - pub fn printException(this: *VirtualMachine, exception: *Exception) void { + pub const ExceptionList = std.ArrayList(Api.JsException); + + pub fn printException(this: *VirtualMachine, exception: *Exception, exception_list: ?*ExceptionList) void { if (Output.enable_ansi_colors) { - this.printErrorlikeObject(exception.value(), exception, true); + this.printErrorlikeObject(exception.value(), exception, exception_list, true); } else { - this.printErrorlikeObject(exception.value(), exception, false); + this.printErrorlikeObject(exception.value(), exception, exception_list, false); } } - pub fn defaultErrorHandler(this: *VirtualMachine, result: JSValue) void { + pub fn defaultErrorHandler(this: *VirtualMachine, result: JSValue, exception_list: ?*ExceptionList) void { if (result.isException(this.global.vm())) { var exception = @ptrCast(*Exception, result.asVoid()); - this.printException(exception); + this.printException(exception, exception_list); } else if (Output.enable_ansi_colors) { - this.printErrorlikeObject(result, null, true); + this.printErrorlikeObject(result, null, exception_list, true); } else { - this.printErrorlikeObject(result, null, false); + this.printErrorlikeObject(result, null, exception_list, false); } } pub fn loadEntryPoint(this: *VirtualMachine, entry_path: string) !*JSInternalPromise { try this.entry_point.generate(@TypeOf(this.bundler), &this.bundler, Fs.PathName.init(entry_path), main_file_name); this.main = entry_path; - var promise = JSModuleLoader.loadAndEvaluateModule(this.global, ZigString.init(std.mem.span(main_file_name))); + + var promise: *JSInternalPromise = undefined; + // We first import the node_modules bundle. This prevents any potential TDZ issues. + // The contents of the node_modules bundle are lazy, so hopefully this should be pretty quick. + if (this.node_modules != null) { + promise = JSModuleLoader.loadAndEvaluateModule(this.global, ZigString.init(std.mem.span(vm.bundler.linker.nodeModuleBundleImportPath()))); + + this.global.vm().drainMicrotasks(); + + while (promise.status(this.global.vm()) == JSPromise.Status.Pending) { + this.global.vm().drainMicrotasks(); + } + + if (promise.status(this.global.vm()) == JSPromise.Status.Rejected) { + return promise; + } + + _ = promise.result(this.global.vm()); + } + + promise = JSModuleLoader.loadAndEvaluateModule(this.global, ZigString.init(std.mem.span(main_file_name))); this.global.vm().drainMicrotasks(); @@ -896,14 +920,14 @@ pub const VirtualMachine = struct { // In that case, this function becomes recursive. // In all other cases, we will convert it to a ZigException. const errors_property = ZigString.init("errors"); - pub fn printErrorlikeObject(this: *VirtualMachine, value: JSValue, exception: ?*Exception, comptime allow_ansi_color: bool) void { + pub fn printErrorlikeObject(this: *VirtualMachine, value: JSValue, exception: ?*Exception, exception_list: ?*ExceptionList, comptime allow_ansi_color: bool) void { var was_internal = false; defer { if (was_internal) { if (exception) |exception_| { var holder = ZigException.Holder.init(); - var zig_exception = holder.zigException(); + var zig_exception: *ZigException = holder.zigException(); exception_.getStackTrace(&zig_exception.stack); if (zig_exception.stack.frames_len > 0) { var buffered_writer = std.io.bufferedWriter(Output.errorWriter()); @@ -917,12 +941,17 @@ pub const VirtualMachine = struct { buffered_writer.flush() catch {}; } + + if (exception_list) |list| { + zig_exception.addToErrorList(list) catch {}; + } } } } if (value.isAggregateError(this.global)) { const AggregateErrorIterator = struct { + pub var current_exception_list: ?*ExceptionList = null; pub fn iteratorWithColor(_vm: [*c]VM, globalObject: [*c]JSGlobalObject, nextValue: JSValue) callconv(.C) void { iterator(_vm, globalObject, nextValue, true); } @@ -930,9 +959,11 @@ pub const VirtualMachine = struct { iterator(_vm, globalObject, nextValue, false); } inline fn iterator(_vm: [*c]VM, globalObject: [*c]JSGlobalObject, nextValue: JSValue, comptime color: bool) void { - VirtualMachine.vm.printErrorlikeObject(nextValue, null, color); + VirtualMachine.vm.printErrorlikeObject(nextValue, null, current_exception_list, color); } }; + AggregateErrorIterator.current_exception_list = exception_list; + defer AggregateErrorIterator.current_exception_list = null; if (comptime allow_ansi_color) { value.getErrorsProperty(this.global).forEach(this.global, AggregateErrorIterator.iteratorWithColor); } else { @@ -943,34 +974,51 @@ pub const VirtualMachine = struct { if (js.JSValueIsObject(vm.global.ref(), value.asRef())) { if (js.JSObjectGetPrivate(value.asRef())) |priv| { - was_internal = this.printErrorFromMaybePrivateData(priv, allow_ansi_color); + was_internal = this.printErrorFromMaybePrivateData(priv, exception_list, allow_ansi_color); return; } } - was_internal = this.printErrorFromMaybePrivateData(value.asRef(), allow_ansi_color); + was_internal = this.printErrorFromMaybePrivateData(value.asRef(), exception_list, allow_ansi_color); } - pub fn printErrorFromMaybePrivateData(this: *VirtualMachine, value: ?*c_void, comptime allow_ansi_color: bool) bool { + pub fn printErrorFromMaybePrivateData(this: *VirtualMachine, value: ?*c_void, exception_list: ?*ExceptionList, comptime allow_ansi_color: bool) bool { const private_data_ptr = JSPrivateDataPtr.from(value); switch (private_data_ptr.tag()) { .BuildError => { defer Output.flush(); - const build_error = private_data_ptr.as(BuildError); - var writer = Output.errorWriter(); - build_error.msg.formatWriter(@TypeOf(writer), writer, allow_ansi_color) catch {}; + var build_error = private_data_ptr.as(BuildError); + if (!build_error.logged) { + var writer = Output.errorWriter(); + build_error.msg.formatWriter(@TypeOf(writer), writer, allow_ansi_color) catch {}; + build_error.logged = true; + } + if (exception_list != null) { + this.log.addMsg( + build_error.msg, + ) catch {}; + } return true; }, .ResolveError => { defer Output.flush(); - const resolve_error = private_data_ptr.as(ResolveError); - var writer = Output.errorWriter(); - resolve_error.msg.formatWriter(@TypeOf(writer), writer, allow_ansi_color) catch {}; + var resolve_error = private_data_ptr.as(ResolveError); + if (!resolve_error.logged) { + var writer = Output.errorWriter(); + resolve_error.msg.formatWriter(@TypeOf(writer), writer, allow_ansi_color) catch {}; + resolve_error.logged = true; + } + + if (exception_list != null) { + this.log.addMsg( + resolve_error.msg, + ) catch {}; + } return true; }, else => { - this.printErrorInstance(@intToEnum(JSValue, @intCast(i64, (@ptrToInt(value)))), allow_ansi_color) catch |err| { + this.printErrorInstance(@intToEnum(JSValue, @intCast(i64, (@ptrToInt(value)))), exception_list, allow_ansi_color) catch |err| { if (comptime isDebug) { // yo dawg Output.printErrorln("Error while printing Error-like object: {s}", .{@errorName(err)}); @@ -1053,10 +1101,13 @@ pub const VirtualMachine = struct { } } - pub fn printErrorInstance(this: *VirtualMachine, error_instance: JSValue, comptime allow_ansi_color: bool) !void { + pub fn printErrorInstance(this: *VirtualMachine, error_instance: JSValue, exception_list: ?*ExceptionList, comptime allow_ansi_color: bool) !void { var exception_holder = ZigException.Holder.init(); var exception = exception_holder.zigException(); error_instance.toZigException(vm.global, exception); + if (exception_list) |list| { + try exception.addToErrorList(list); + } var stderr: std.fs.File = Output.errorStream(); var buffered = std.io.bufferedWriter(stderr.writer()); @@ -1223,40 +1274,36 @@ pub const EventListenerMixin = struct { } }; - pub fn emitFetchEventError( - request: *http.RequestContext, - comptime fmt: string, - args: anytype, - ) void { - Output.prettyErrorln(fmt, args); - request.sendInternalError(error.FetchEventError) catch {}; - } - pub fn emitFetchEvent( vm: *VirtualMachine, request_context: *http.RequestContext, + comptime CtxType: type, + ctx: *CtxType, + comptime onError: fn (ctx: *CtxType, err: anyerror, value: JSValue, request_ctx: *http.RequestContext) anyerror!void, ) !void { - var listeners = vm.event_listeners.get(EventType.fetch) orelse return emitFetchEventError( - request_context, - "Missing \"fetch\" handler. Did you run \"addEventListener(\"fetch\", (event) => {{}})\"?", - .{}, - ); - if (listeners.items.len == 0) return emitFetchEventError( - request_context, - "Missing \"fetch\" handler. Did you run \"addEventListener(\"fetch\", (event) => {{}})\"?", - .{}, - ); + var listeners = vm.event_listeners.get(EventType.fetch) orelse (return onError(ctx, error.NoListeners, JSValue.jsUndefined(), request_context) catch {}); + if (listeners.items.len == 0) return onError(ctx, error.NoListeners, JSValue.jsUndefined(), request_context) catch {}; + const FetchEventRejectionHandler = struct { + pub fn onRejection(_ctx: *c_void, err: anyerror, fetch_event: *FetchEvent, value: JSValue) void { + onError( + @intToPtr(*CtxType, @ptrToInt(_ctx)), + err, + value, + fetch_event.request_context, + ) catch {}; + } + }; // Rely on JS finalizer var fetch_event = try vm.allocator.create(FetchEvent); fetch_event.* = FetchEvent{ .request_context = request_context, .request = Request{ .request_context = request_context }, + .onPromiseRejectionCtx = @as(*c_void, ctx), + .onPromiseRejectionHandler = FetchEventRejectionHandler.onRejection, }; var fetch_args: [1]js.JSObjectRef = undefined; - var exception: ?*Exception = null; - const failed_str = "Failed"; for (listeners.items) |listener_ref| { var listener = @intToEnum(JSValue, @intCast(i64, @ptrToInt(listener_ref))); @@ -1266,19 +1313,11 @@ pub const EventListenerMixin = struct { var promise = JSPromise.resolvedPromise(vm.global, result); vm.global.vm().drainMicrotasks(); + if (fetch_event.rejected) return; + if (promise.status(vm.global.vm()) == .Rejected) { - if (exception == null) { - var res = promise.result(vm.global.vm()); - if (res.isException(vm.global.vm())) { - exception = @ptrCast(*Exception, res.asVoid()); - } else { - vm.defaultErrorHandler(res); - if (!request_context.has_called_done) { - request_context.sendInternalError(error.JavaScriptErrorNeedARealErrorPageSorryAboutThisSeeTheTerminal) catch {}; - } - return; - } - } + onError(ctx, error.JSError, promise.result(vm.global.vm()), request_context) catch {}; + return; } else { _ = promise.result(vm.global.vm()); } @@ -1290,21 +1329,9 @@ pub const EventListenerMixin = struct { } } - if (exception) |except| { - vm.printException(except); - - if (!request_context.has_called_done) { - request_context.sendInternalError(error.JavaScriptErrorNeedARealErrorPageSorryAboutThisSeeTheTerminal) catch {}; - } - return; - } - if (!request_context.has_called_done) { - return emitFetchEventError( - request_context, - "\"fetch\" handler never called event.respondWith()", - .{}, - ); + onError(ctx, error.FetchHandlerRespondWithNeverCalled, JSValue.jsUndefined(), request_context) catch {}; + return; } } @@ -1368,6 +1395,7 @@ pub const ResolveError = struct { msg: logger.Msg, allocator: *std.mem.Allocator, referrer: ?Fs.Path = null, + logged: bool = false, pub fn fmt(allocator: *std.mem.Allocator, specifier: string, referrer: string, err: anyerror) !string { switch (err) { @@ -1515,6 +1543,7 @@ pub const BuildError = struct { msg: logger.Msg, // resolve_result: Resolver.Result, allocator: *std.mem.Allocator, + logged: bool = false, pub const Class = NewClass( BuildError, diff --git a/src/javascript/jsc/webcore/response.zig b/src/javascript/jsc/webcore/response.zig index 09014c17f..55e4a753e 100644 --- a/src/javascript/jsc/webcore/response.zig +++ b/src/javascript/jsc/webcore/response.zig @@ -1009,6 +1009,10 @@ pub const FetchEvent = struct { request_context: *http.RequestContext, request: Request, + onPromiseRejectionCtx: *c_void = undefined, + onPromiseRejectionHandler: ?fn (ctx: *c_void, err: anyerror, fetch_event: *FetchEvent, value: JSValue) void = null, + rejected: bool = false, + pub const Class = NewClass( FetchEvent, .{ @@ -1101,8 +1105,13 @@ pub const FetchEvent = struct { switch (status) { .Fulfilled => {}, else => { - VirtualMachine.vm.defaultErrorHandler(resolved.result(VirtualMachine.vm.global.vm())); - this.request_context.sendInternalError(error.rejectedPromiseSeeConsole) catch {}; + this.rejected = true; + this.onPromiseRejectionHandler.?( + this.onPromiseRejectionCtx, + error.PromiseRejection, + this, + resolved.result(VirtualMachine.vm.global.vm()), + ); return js.JSValueMakeUndefined(ctx); }, } @@ -1110,14 +1119,16 @@ pub const FetchEvent = struct { var arg = resolved.result(VirtualMachine.vm.global.vm()).asObjectRef(); if (!js.JSValueIsObjectOfClass(ctx, arg, Response.Class.ref)) { + this.rejected = true; JSError(getAllocator(ctx), "event.respondWith() must be a Response or a Promise<Response>.", .{}, ctx, exception); - this.request_context.sendInternalError(error.respondWithWasEmpty) catch {}; + this.onPromiseRejectionHandler.?(this.onPromiseRejectionCtx, error.RespondWithInvalidType, this, JSValue.fromRef(exception.*)); return js.JSValueMakeUndefined(ctx); } var response: *Response = GetJSPrivateData(Response, arg) orelse { + this.rejected = true; JSError(getAllocator(ctx), "event.respondWith()'s Response object was invalid. This may be an internal error.", .{}, ctx, exception); - this.request_context.sendInternalError(error.respondWithWasInvalid) catch {}; + this.onPromiseRejectionHandler.?(this.onPromiseRejectionCtx, error.RespondWithInvalidTypeInternal, this, JSValue.fromRef(exception.*)); return js.JSValueMakeUndefined(ctx); }; diff --git a/src/js_ast.zig b/src/js_ast.zig index be84afb08..746fb5796 100644 --- a/src/js_ast.zig +++ b/src/js_ast.zig @@ -3656,6 +3656,8 @@ pub const Ast = struct { }; } + pub const empty = Ast{ .parts = &[_]Part{}, .runtime_imports = undefined }; + pub fn toJSON(self: *const Ast, allocator: *std.mem.Allocator, stream: anytype) !void { const opts = std.json.StringifyOptions{ .whitespace = std.json.StringifyOptions.Whitespace{ .separator = true, diff --git a/src/js_parser/js_parser.zig b/src/js_parser/js_parser.zig index 83a1b0127..62bf836e7 100644 --- a/src/js_parser/js_parser.zig +++ b/src/js_parser/js_parser.zig @@ -10623,18 +10623,19 @@ pub fn NewParser( switch (runtime) { .classic => { // Arguments to createElement() - const args = p.allocator.alloc(Expr, 1 + children_count) catch unreachable; + const args = p.allocator.alloc(Expr, 2 + children_count) catch unreachable; var i: usize = 1; + args[0] = tag; if (e_.properties.len > 0) { if (e_.key) |key| { var props = List(G.Property).fromOwnedSlice(p.allocator, e_.properties); props.append(G.Property{ .key = Expr{ .loc = key.loc, .data = keyExprData }, .value = key }) catch unreachable; - args[0] = p.e(E.Object{ .properties = props.toOwnedSlice() }, expr.loc); + args[1] = p.e(E.Object{ .properties = props.toOwnedSlice() }, expr.loc); } else { - args[0] = p.e(E.Object{ .properties = e_.properties }, expr.loc); + args[1] = p.e(E.Object{ .properties = e_.properties }, expr.loc); } } else { - args[0] = p.e(E.Null{}, expr.loc); + args[1] = p.e(E.Null{}, expr.loc); } for (e_.children[0..children_count]) |child| { diff --git a/src/js_printer.zig b/src/js_printer.zig index 42af0cd63..0f0a493de 100644 --- a/src/js_printer.zig +++ b/src/js_printer.zig @@ -2333,7 +2333,7 @@ pub fn NewPrinter( switch (s.value) { .expr => |expr| { if (rewrite_esm_to_cjs) { - p.printSymbol(p.options.runtime_imports.__export.?); + p.printModuleExportSymbol(); p.print(".default = "); } @@ -2354,7 +2354,7 @@ pub fn NewPrinter( // p.printSymbol(name.ref.?); // p.print(" = "); } else { - p.printSymbol(p.options.runtime_imports.__export.?); + p.printModuleExportSymbol(); p.print(".default = "); } } @@ -2400,7 +2400,7 @@ pub fn NewPrinter( // p.printSymbol(name.ref.?); // p.print(" = "); } else { - p.printSymbol(p.options.runtime_imports.__export.?); + p.printModuleExportSymbol(); p.print(".default = "); } } @@ -2448,7 +2448,7 @@ pub fn NewPrinter( } else { p.printSymbol(p.options.runtime_imports.__reExport.?); p.print("("); - p.printSymbol(p.options.runtime_imports.__export.?); + p.printModuleExportSymbol(); p.print(","); p.printLoadFromBundle(s.import_record_index); @@ -2506,7 +2506,7 @@ pub fn NewPrinter( else => { p.print("Object.assign"); p.print("("); - p.printSymbol(p.options.runtime_imports.__export.?); + p.printModuleExportSymbol(); p.print(", {"); const last = s.items.len - 1; for (s.items) |item, i| { @@ -2583,7 +2583,7 @@ pub fn NewPrinter( const item = s.items[0]; p.printSymbol(p.options.runtime_imports.lazy_export.?); p.print("("); - p.printSymbol(p.options.runtime_imports.__export.?); + p.printModuleExportSymbol(); p.print(","); // Avoid initializing an entire component library because you imported one icon p.printLoadFromBundleWithoutCall(s.import_record_index); @@ -2599,7 +2599,7 @@ pub fn NewPrinter( } else { p.printSymbol(p.options.runtime_imports.lazy_export.?); p.print("("); - p.printSymbol(p.options.runtime_imports.__export.?); + p.printModuleExportSymbol(); p.print(","); // Avoid initializing an entire component library because you imported one icon @@ -3243,6 +3243,10 @@ pub fn NewPrinter( } } + pub fn printModuleExportSymbol(p: *Printer) void { + p.print("module.exports"); + } + pub fn printBundledImport(p: *Printer, record: importRecord.ImportRecord, s: *S.Import, stmt: Stmt) void { if (record.is_internal) { return; @@ -3617,7 +3621,7 @@ pub fn NewPrinter( p.printIndent(); p.printSpaceBeforeIdentifier(); p.print("Object.defineProperties("); - p.printSymbol(p.options.runtime_imports.__export.?); + p.printModuleExportSymbol(); p.print(",{"); for (decls) |decl, i| { p.print("'"); diff --git a/src/lock.zig b/src/lock.zig index 73dfdebd2..4ae9444e0 100644 --- a/src/lock.zig +++ b/src/lock.zig @@ -6,118 +6,101 @@ const Futex = std.Thread.Futex; pub const Mutex = struct { state: Atomic(u32) = Atomic(u32).init(UNLOCKED), - const UNLOCKED: u32 = 0; - const LOCKED: u32 = 1; - const CONTENDED: u32 = 2; + const UNLOCKED = 0; + const LOCKED = 0b01; + const CONTENDED = 0b11; + const is_x86 = std.Target.current.cpu.arch.isX86(); pub fn tryAcquire(self: *Mutex) bool { - return self.state.compareAndSwap( - UNLOCKED, - LOCKED, - .Acquire, - .Monotonic, - ) == null; + return self.acquireFast(true); } pub fn acquire(self: *Mutex) void { - if (self.state.tryCompareAndSwap( - UNLOCKED, - LOCKED, - .Acquire, - .Monotonic, - )) |updated| { + if (!self.acquireFast(false)) { self.acquireSlow(); } } - fn acquireSlow(self: *Mutex) void { - @setCold(true); + inline fn acquireFast(self: *Mutex, comptime strong: bool) bool { + // On x86, "lock bts" uses less i-cache & can be faster than "lock cmpxchg" below. + if (comptime is_x86) { + return self.state.bitSet(@ctz(u32, LOCKED), .Acquire) == UNLOCKED; + } - // true if the cpu's atomic swap instruction should be preferred - const has_fast_swap = comptime blk: { - const arch = std.Target.current.cpu.arch; - break :blk arch.isX86() or arch.isRISCV(); + const cas_fn = comptime switch (strong) { + true => "compareAndSwap", + else => "tryCompareAndSwap", }; - var acquire_state = LOCKED; - var state = self.state.load(.Monotonic); - var spin: u8 = if (comptime has_fast_swap) 100 else 10; - - while (true) { - // Try to lock the Mutex if its unlocked. - // acquire_state is changed to CONTENDED if this thread goes to sleep. - // - // We acquire with CONTENDED instead of LOCKED in that scenario - // to make sure that we wake another thread sleeping in release() - // which didn't see the transition to UNLOCKED since it was asleep. - // - // A CONTENDED acquire unfortunately results in one extra wake() - // if there were no other sleeping threads at the time of the acquire. - if (state == UNLOCKED) { - state = self.state.tryCompareAndSwap( - state, - acquire_state, + return @field(self.state, cas_fn)( + UNLOCKED, + LOCKED, + .Acquire, + .Monotonic, + ) == null; + } + + noinline fn acquireSlow(self: *Mutex) void { + // Spin a little bit on the Mutex state in the hopes that + // we can acquire it without having to call Futex.wait(). + // Give up spinning if the Mutex is contended. + // This helps acquire() latency under micro-contention. + // + // Only spin on x86 as other platforms are assumed to + // prioritize power efficiency over strict performance. + var spin: u8 = comptime if (is_x86) 100 else 0; + while (spin > 0) : (spin -= 1) { + std.atomic.spinLoopHint(); + + switch (self.state.load(.Monotonic)) { + UNLOCKED => _ = self.state.tryCompareAndSwap( + UNLOCKED, + LOCKED, .Acquire, .Monotonic, - ) orelse return; - continue; + ) orelse return, + LOCKED => continue, + CONTENDED => break, + else => unreachable, // invalid Mutex state } + } - if (state != CONTENDED) uncontended: { - // If there's no pending threads, try to spin on the Mutex a few times. - // This makes the throughput close to a spinlock when under micro-contention. - if (spin > 0) { - spin -= 1; - std.atomic.spinLoopHint(); - state = self.state.load(.Monotonic); - continue; - } - - // Indicate that there will be a waiting thread by updating to CONTENDED. - // Acquire barrier as this swap could also possibly lock the Mutex. - if (comptime has_fast_swap) { - state = self.state.swap(CONTENDED, .Acquire); - if (state == UNLOCKED) return; - break :uncontended; - } - - // For other platforms, mark the Mutex as CONTENDED if it's not already. - // This just indicates that there's waiting threads so no Acquire barrier needed. - if (self.state.tryCompareAndSwap( - state, - CONTENDED, - .Monotonic, - .Monotonic, - )) |updated| { - state = updated; - continue; + // Make sure the state is CONTENDED before sleeping with Futex so release() can wake us up. + // Transitioning to CONTENDED may also acquire the mutex in the process. + // + // If we sleep, we must acquire the Mutex with CONTENDED to ensure that other threads + // sleeping on the Futex having seen CONTENDED before are eventually woken up by release(). + // This unfortunately ends up in an extra Futex.wake() for the last thread but that's ok. + while (true) : (Futex.wait(&self.state, CONTENDED, null) catch unreachable) { + // On x86, "xchg" can be faster than "lock cmpxchg" below. + if (comptime is_x86) { + switch (self.state.swap(CONTENDED, .Acquire)) { + UNLOCKED => return, + LOCKED, CONTENDED => continue, + else => unreachable, // invalid Mutex state } } - Futex.wait(&self.state, CONTENDED, null) catch unreachable; - state = self.state.load(.Monotonic); - acquire_state = CONTENDED; + var state = self.state.load(.Monotonic); + while (state != CONTENDED) { + state = switch (state) { + UNLOCKED => self.state.tryCompareAndSwap(state, CONTENDED, .Acquire, .Monotonic) orelse return, + LOCKED => self.state.tryCompareAndSwap(state, CONTENDED, .Monotonic, .Monotonic) orelse break, + CONTENDED => unreachable, // checked above + else => unreachable, // invalid Mutex state + }; + } } } pub fn release(self: *Mutex) void { - const state = self.state.swap(UNLOCKED, .Release); - - // Wake up a sleeping thread if it was previously CONTENDED. - // The woken up thread would acquire by updating the state to CONTENDED again. - // This is to make sure a future release() wouldn't miss waking up threads that - // don't see the reset to UNLOCKED above due to them being asleep. - if (state == CONTENDED) { - self.releaseSlow(); + switch (self.state.swap(UNLOCKED, .Release)) { + UNLOCKED => unreachable, // released without being acquired + LOCKED => {}, + CONTENDED => Futex.wake(&self.state, 1), + else => unreachable, // invalid Mutex state } } - - fn releaseSlow(self: *Mutex) void { - @setCold(true); - - const num_waiters = 1; - Futex.wake(&self.state, num_waiters); - } }; pub const Lock = struct { @@ -136,7 +119,4 @@ pub const Lock = struct { } }; - -pub fn spinCycle() void { - -}
\ No newline at end of file +pub fn spinCycle() void {} diff --git a/src/logger.zig b/src/logger.zig index cf9fb6960..8ccffd06f 100644 --- a/src/logger.zig +++ b/src/logger.zig @@ -43,13 +43,12 @@ pub const Kind = enum(i8) { }; } - pub inline fn toAPI(kind: Kind) Api.MessageKind { + pub inline fn toAPI(kind: Kind) Api.MessageLevel { return switch (kind) { - .err => err, - .warn => warn, - .note => note, - .debug => debug, - .verbose => verbose, + .err => .err, + .warn => .warn, + .note => .note, + else => .debug, }; } }; @@ -92,6 +91,18 @@ pub const Location = struct { suggestion: ?string = null, offset: usize = 0, + pub fn toAPI(this: *const Location) Api.Location { + return Api.Location{ + .file = this.file, + .namespace = this.namespace, + .line = this.line, + .column = this.column, + .line_text = this.line_text orelse "", + .suggestion = this.suggestion orelse "", + .offset = @truncate(u32, this.offset), + }; + } + // don't really know what's safe to deinit here! pub fn deinit(l: *Location, allocator: *std.mem.Allocator) void {} @@ -151,6 +162,13 @@ pub const Data = struct { allocator.free(text); } + pub fn toAPI(this: *const Data) Api.MessageData { + return Api.MessageData{ + .text = this.text, + .location = if (this.location != null) this.location.?.toAPI() else null, + }; + } + pub fn writeFormat( this: *const Data, to: anytype, @@ -213,17 +231,26 @@ pub const Msg = struct { }; }; - pub fn toAPI(this: *const Msg, allocator: *std.mem.Allocator) Api.Message { + pub fn toAPI(this: *const Msg, allocator: *std.mem.Allocator) !Api.Message { + const notes_len = if (this.notes != null) this.notes.?.len else 0; + var _notes = try allocator.alloc( + Api.MessageData, + notes_len, + ); var msg = Api.Message{ - .kind = this.kind.toAPI(), + .level = this.kind.toAPI(), .data = this.data.toAPI(), + .notes = _notes, + .on = Api.MessageMeta{ + .resolve = if (this.metadata == .resolve) this.metadata.resolve.specifier.slice(this.data.text) else "", + .build = this.metadata == .build, + }, }; if (this.notes) |notes| { if (notes.len > 0) { - msg.notes = try allocator.alloc(Api.MessageData, notes.len); for (notes) |note, i| { - msg.notes[i] = note.toAPI(); + _notes[i] = note.toAPI(); } } } @@ -232,7 +259,7 @@ pub const Msg = struct { } pub fn toAPIFromList(comptime ListType: type, list: ListType, allocator: *std.mem.Allocator) ![]Api.Message { - var out_list = try allocator.alloc(Api.Msg, list.items.len); + var out_list = try allocator.alloc(Api.Message, list.items.len); for (list.items) |item, i| { out_list[i] = try item.toAPI(allocator); } @@ -341,9 +368,16 @@ pub const Log = struct { level: Level = if (isDebug) Level.info else Level.warn, pub fn toAPI(this: *const Log, allocator: *std.mem.Allocator) !Api.Log { + var warnings: u32 = 0; + var errors: u32 = 0; + for (this.msgs.items) |msg, i| { + errors += @intCast(u32, @boolToInt(msg.kind == .err)); + warnings += @intCast(u32, @boolToInt(msg.kind == .warn)); + } + return Api.Log{ - .warnings = this.warnings, - .errors = this.errors, + .warnings = warnings, + .errors = errors, .msgs = try Msg.toAPIFromList(@TypeOf(this.msgs), this.msgs, allocator), }; } @@ -392,7 +426,12 @@ pub const Log = struct { const msg = self.msgs.items[i]; if (msg.data.location) |location| { if (location.line_text) |line_text| { - other.msgs.items[j].data.location.?.line_text = try other.msgs.allocator.dupe(u8, line_text); + other.msgs.items[j].data.location.?.line_text = try other.msgs.allocator.dupe( + u8, + // Naively truncate to 690 characters per line. + // This doesn't catch where an error occurred for extremely long, minified lines. + line_text[0..std.math.min(line_text.len, 690)], + ); } } } diff --git a/src/node_module_bundle.zig b/src/node_module_bundle.zig index 979c1bba5..4fd781829 100644 --- a/src/node_module_bundle.zig +++ b/src/node_module_bundle.zig @@ -297,6 +297,7 @@ pub const NodeModuleBundle = struct { var read_bytes = file_bytes[0..read_count]; var reader = schema.Reader.init(read_bytes, allocator); var container = try Api.JavascriptBundleContainer.decode(&reader); + if (container.bundle == null) return error.InvalidBundle; var bundle = NodeModuleBundle{ .allocator = allocator, .container = container, diff --git a/src/options.zig b/src/options.zig index 05a32cc28..f5b636d5f 100644 --- a/src/options.zig +++ b/src/options.zig @@ -851,7 +851,7 @@ pub const BundleOptions = struct { pub fn isFrontendFrameworkEnabled(this: *const BundleOptions) bool { const framework: *const Framework = &(this.framework orelse return false); - return framework.resolved and framework.client.len > 0; + return framework.resolved and (framework.client.isEnabled() or framework.fallback.isEnabled()); } pub const ImportPathFormat = enum { @@ -999,15 +999,17 @@ pub const BundleOptions = struct { if (transform.framework == null) { if (bundle.container.framework) |loaded_framework| { - opts.framework = Framework.fromLoadedFramework(loaded_framework, allocator); - opts.framework.?.client_env.allocator = allocator; - opts.framework.?.server_env.allocator = allocator; + opts.framework = try Framework.fromLoadedFramework(loaded_framework, allocator); if (transform.define == null) { if (opts.platform.isClient()) { - opts.env = opts.framework.?.client_env; + if (opts.framework.?.client.kind != .disabled) { + opts.env = opts.framework.?.client.env; + } else if (opts.framework.?.fallback.kind != .disabled) { + opts.env = opts.framework.?.fallback.env; + } } else { - opts.env = opts.framework.?.server_env; + opts.env = opts.framework.?.server.env; } } } @@ -1034,17 +1036,7 @@ pub const BundleOptions = struct { // } if (transform.framework) |_framework| { - opts.framework = try Framework.fromApi(_framework); - - if (_framework.client_env) |env| { - opts.framework.?.client_env.allocator = allocator; - try opts.framework.?.client_env.setFromAPI(env); - } - - if (_framework.server_env) |env| { - opts.framework.?.server_env.allocator = allocator; - try opts.framework.?.server_env.setFromAPI(env); - } + opts.framework = try Framework.fromApi(_framework, allocator); } if (transform.router) |routes| { @@ -1520,22 +1512,41 @@ pub const Env = struct { } }; -pub const Framework = struct { - client: string, - server: string, - package: string = "", - development: bool = true, - resolved: bool = false, - from_bundle: bool = false, +pub const EntryPoint = struct { + path: string = "", + env: Env = Env{}, + kind: Kind = Kind.disabled, - client_env: Env = Env{}, - server_env: Env = Env{}, + pub fn isEnabled(this: *const EntryPoint) bool { + return this.kind != .disabled and this.path.len > 0; + } - client_css_in_js: Api.CssInJsBehavior = .auto_onimportcss, + pub const Kind = enum { + client, + server, + fallback, + disabled, + + pub fn toAPI(this: Kind) Api.FrameworkEntryPointType { + return switch (this) { + .client => .client, + .server => .server, + .fallback => .fallback, + else => unreachable, + }; + } + }; + + pub fn toAPI(this: *const EntryPoint, allocator: *std.mem.Allocator, toplevel_path: string, kind: Kind) !?Api.FrameworkEntryPoint { + if (this.kind == .disabled) + return null; + + return Api.FrameworkEntryPoint{ .kind = kind.toAPI(), .env = this.env.toAPI(), .path = try this.normalizedPath(allocator, toplevel_path) }; + } - fn normalizedPath(allocator: *std.mem.Allocator, toplevel_path: string, path: string) !string { - std.debug.assert(std.fs.path.isAbsolute(path)); - var str = path; + fn normalizedPath(this: *const EntryPoint, allocator: *std.mem.Allocator, toplevel_path: string) !string { + std.debug.assert(std.fs.path.isAbsolute(this.path)); + var str = this.path; if (strings.indexOf(str, toplevel_path)) |top| { str = str[top + toplevel_path.len ..]; } @@ -1554,53 +1565,103 @@ pub const Framework = struct { } } - pub fn fromLoadedFramework(loaded: Api.LoadedFramework, allocator: *std.mem.Allocator) Framework { - const client = if (loaded.client) loaded.entry_point else ""; - const server = if (!loaded.client) loaded.entry_point else ""; + pub fn fromLoaded( + this: *EntryPoint, + framework_entry_point: Api.FrameworkEntryPoint, + allocator: *std.mem.Allocator, + kind: Kind, + ) !void { + this.path = framework_entry_point.path; + this.kind = kind; + this.env.setFromLoaded(framework_entry_point.env, allocator) catch {}; + } + + pub fn fromAPI( + this: *EntryPoint, + framework_entry_point: Api.FrameworkEntryPointMessage, + allocator: *std.mem.Allocator, + kind: Kind, + ) !void { + this.path = framework_entry_point.path orelse ""; + this.kind = kind; + + if (this.path.len == 0) { + this.kind = .disabled; + return; + } + + if (framework_entry_point.env) |env| { + this.env.allocator = allocator; + try this.env.setFromAPI(env); + } + } +}; + +pub const Framework = struct { + client: EntryPoint = EntryPoint{}, + server: EntryPoint = EntryPoint{}, + fallback: EntryPoint = EntryPoint{}, + + package: string = "", + development: bool = true, + resolved: bool = false, + from_bundle: bool = false, + + client_css_in_js: Api.CssInJsBehavior = .auto_onimportcss, + + pub const fallback_html: string = @embedFile("./fallback.html"); + + pub fn platformEntryPoint(this: *const Framework, platform: Platform) ?*const EntryPoint { + const entry: *const EntryPoint = switch (platform) { + .neutral, .browser => &this.client, + .bun => &this.server, + .node => return null, + }; + + if (entry.kind == .disabled) return null; + return entry; + } + + pub fn fromLoadedFramework(loaded: Api.LoadedFramework, allocator: *std.mem.Allocator) !Framework { var framework = Framework{ - .client = client, - .server = server, .package = loaded.package, .development = loaded.development, .from_bundle = true, .client_css_in_js = loaded.client_css_in_js, }; - if (loaded.client) { - framework.client_env.setFromLoaded(loaded.env, allocator) catch {}; - } else { - framework.server_env.setFromLoaded(loaded.env, allocator) catch {}; + if (loaded.entry_points.fallback) |fallback| { + try framework.fallback.fromLoaded(fallback, allocator, .fallback); } - return framework; - } + if (loaded.entry_points.client) |client| { + try framework.client.fromLoaded(client, allocator, .client); + } - pub fn toAPI(this: *const Framework, allocator: *std.mem.Allocator, toplevel_path: string, comptime client: bool) ?Api.LoadedFramework { - if (comptime client) { - if (this.client.len > 0) { - return Api.LoadedFramework{ - .entry_point = normalizedPath(allocator, toplevel_path, this.client) catch unreachable, - .package = this.package, - .development = this.development, - .client = true, - .env = this.client_env.toAPI(), - .client_css_in_js = this.client_css_in_js, - }; - } - } else { - if (this.server.len > 0) { - return Api.LoadedFramework{ - .entry_point = normalizedPath(allocator, toplevel_path, this.server) catch unreachable, - .package = this.package, - .development = this.development, - .client = false, - .env = this.server_env.toAPI(), - .client_css_in_js = this.client_css_in_js, - }; - } + if (loaded.entry_points.server) |server| { + try framework.server.fromLoaded(server, allocator, .server); } - return null; + return framework; + } + + pub fn toAPI( + this: *const Framework, + allocator: *std.mem.Allocator, + toplevel_path: string, + ) !?Api.LoadedFramework { + if (this.client.kind == .disabled and this.server.kind == .disabled and this.fallback.kind == .disabled) return null; + + return Api.LoadedFramework{ + .package = this.package, + .development = this.development, + .entry_points = .{ + .client = try this.client.toAPI(allocator, toplevel_path, .client), + .fallback = try this.fallback.toAPI(allocator, toplevel_path, .fallback), + .server = try this.server.toAPI(allocator, toplevel_path, .server), + }, + .client_css_in_js = this.client_css_in_js, + }; } pub fn needsResolveFromPackage(this: *const Framework) bool { @@ -1609,10 +1670,28 @@ pub const Framework = struct { pub fn fromApi( transform: Api.FrameworkConfig, + allocator: *std.mem.Allocator, ) !Framework { + var client = EntryPoint{}; + var server = EntryPoint{}; + var fallback = EntryPoint{}; + + if (transform.client) |_client| { + try client.fromAPI(_client, allocator, .client); + } + + if (transform.server) |_server| { + try server.fromAPI(_server, allocator, .server); + } + + if (transform.fallback) |_fallback| { + try fallback.fromAPI(_fallback, allocator, .fallback); + } + return Framework{ - .client = transform.client orelse "", - .server = transform.server orelse "", + .client = client, + .server = server, + .fallback = fallback, .package = transform.package orelse "", .development = transform.development orelse true, .resolved = false, diff --git a/src/resolver/package_json.zig b/src/resolver/package_json.zig index b3b484a84..13ac223e5 100644 --- a/src/resolver/package_json.zig +++ b/src/resolver/package_json.zig @@ -153,7 +153,17 @@ pub const PackageJSON = struct { if (json.asProperty("client")) |client| { if (client.expr.asString(allocator)) |str| { if (str.len > 0) { - framework.client = str; + framework.client.path = str; + framework.client.kind = .client; + } + } + } + + if (json.asProperty("fallback")) |client| { + if (client.expr.asString(allocator)) |str| { + if (str.len > 0) { + framework.fallback.path = str; + framework.fallback.kind = .fallback; } } } @@ -170,25 +180,41 @@ pub const PackageJSON = struct { if (comptime read_define) { if (json.asProperty("define")) |defines| { + var skip_fallback = false; if (defines.expr.asProperty("client")) |client| { if (client.expr.data == .e_object) { const object = client.expr.data.e_object; - framework.client_env = options.Env.init( + framework.client.env = options.Env.init( allocator, ); - loadDefineExpression(&framework.client_env, object, allocator) catch {}; + loadDefineExpression(&framework.client.env, object, allocator) catch {}; + framework.fallback.env = framework.client.env; + skip_fallback = true; + } + } + + if (!skip_fallback) { + if (defines.expr.asProperty("fallback")) |client| { + if (client.expr.data == .e_object) { + const object = client.expr.data.e_object; + framework.fallback.env = options.Env.init( + allocator, + ); + + loadDefineExpression(&framework.fallback.env, object, allocator) catch {}; + } } } if (defines.expr.asProperty("server")) |server| { if (server.expr.data == .e_object) { const object = server.expr.data.e_object; - framework.server_env = options.Env.init( + framework.server.env = options.Env.init( allocator, ); - loadDefineExpression(&framework.server_env, object, allocator) catch {}; + loadDefineExpression(&framework.server.env, object, allocator) catch {}; } } } @@ -197,12 +223,13 @@ pub const PackageJSON = struct { if (json.asProperty("server")) |server| { if (server.expr.asString(allocator)) |str| { if (str.len > 0) { - framework.server = str; + framework.server.path = str; + framework.server.kind = .server; } } } - return framework.client.len > 0; + return framework.client.isEnabled() or framework.server.isEnabled() or framework.fallback.isEnabled(); } pub fn loadFrameworkWithPreference( diff --git a/src/resolver/resolver.zig b/src/resolver/resolver.zig index c44608d3b..8dffbb497 100644 --- a/src/resolver/resolver.zig +++ b/src/resolver/resolver.zig @@ -502,17 +502,25 @@ pub fn NewResolver(cache_files: bool) type { pkg.loadFrameworkWithPreference(pair, json, r.allocator, load_defines, preference); const dir = pkg.source.path.name.dirWithTrailingSlash(); var buf: [std.fs.MAX_PATH_BYTES]u8 = undefined; - if (pair.framework.client.len > 0) { - var parts = [_]string{ dir, pair.framework.client }; + + if (pair.framework.client.isEnabled()) { + var parts = [_]string{ dir, pair.framework.client.path }; + const abs = r.fs.abs(&parts); + pair.framework.client.path = try r.allocator.dupe(u8, try std.os.realpath(abs, &buf)); + pair.framework.resolved = true; + } + + if (pair.framework.server.isEnabled()) { + var parts = [_]string{ dir, pair.framework.server.path }; const abs = r.fs.abs(&parts); - pair.framework.client = try r.allocator.dupe(u8, try std.os.realpath(abs, &buf)); + pair.framework.server.path = try r.allocator.dupe(u8, try std.os.realpath(abs, &buf)); pair.framework.resolved = true; } - if (pair.framework.server.len > 0) { - var parts = [_]string{ dir, pair.framework.server }; + if (pair.framework.fallback.isEnabled()) { + var parts = [_]string{ dir, pair.framework.fallback.path }; const abs = r.fs.abs(&parts); - pair.framework.server = try r.allocator.dupe(u8, try std.os.realpath(abs, &buf)); + pair.framework.fallback.path = try r.allocator.dupe(u8, try std.os.realpath(abs, &buf)); pair.framework.resolved = true; } diff --git a/src/router.zig b/src/router.zig index 4959fd5cc..53c7f126f 100644 --- a/src/router.zig +++ b/src/router.zig @@ -208,7 +208,7 @@ pub fn loadRoutes( } } -const TinyPtr = packed struct { +pub const TinyPtr = packed struct { offset: u16 = 0, len: u16 = 0, diff --git a/src/runtime.version b/src/runtime.version index 1d355c2cd..866b687de 100644 --- a/src/runtime.version +++ b/src/runtime.version @@ -1 +1 @@ -ffa36d1436d2546f
\ No newline at end of file +f763299933041bd3
\ No newline at end of file diff --git a/src/runtime.zig b/src/runtime.zig index 72b97154c..b694aa41a 100644 --- a/src/runtime.zig +++ b/src/runtime.zig @@ -2,11 +2,110 @@ const options = @import("./options.zig"); usingnamespace @import("ast/base.zig"); usingnamespace @import("global.zig"); const std = @import("std"); -pub const ProdSourceContent = @embedFile("./runtime.out.js"); const resolve_path = @import("./resolver/resolve_path.zig"); const Fs = @import("./fs.zig"); +const Schema = @import("./api/schema.zig"); + +const Api = Schema.Api; + +pub const Fallback = struct { + pub const ProdSourceContent = @embedFile("./fallback.out.js"); + pub const HTMLTemplate = @embedFile("./fallback.html"); + + const Base64FallbackMessage = struct { + msg: *const Api.FallbackMessageContainer, + allocator: *std.mem.Allocator, + pub fn format(this: Base64FallbackMessage, comptime fmt: []const u8, opts_: std.fmt.FormatOptions, writer: anytype) !void { + var bb = std.ArrayList(u8).init(this.allocator); + defer bb.deinit(); + var bb_writer = bb.writer(); + const Encoder = Schema.Writer(@TypeOf(bb_writer)); + var encoder = Encoder.init(bb_writer); + this.msg.encode(&encoder) catch {}; + + Base64Encoder.encode(bb.items, @TypeOf(writer), writer) catch {}; + } + + pub const Base64Encoder = struct { + const alphabet_chars = std.base64.standard_alphabet_chars; + + pub fn encode(source: []const u8, comptime Writer: type, writer: Writer) !void { + var acc: u12 = 0; + var acc_len: u4 = 0; + for (source) |v| { + acc = (acc << 8) + v; + acc_len += 8; + while (acc_len >= 6) { + acc_len -= 6; + try writer.writeByte(alphabet_chars[@truncate(u6, (acc >> acc_len))]); + } + } + if (acc_len > 0) { + try writer.writeByte(alphabet_chars[@truncate(u6, (acc << 6 - acc_len))]); + } + } + }; + }; + + pub inline fn scriptContent() string { + if (comptime isDebug) { + var dirpath = std.fs.path.dirname(@src().file).?; + var env = std.process.getEnvMap(default_allocator) catch unreachable; + + const dir = std.mem.replaceOwned( + u8, + default_allocator, + dirpath, + "jarred", + env.get("USER").?, + ) catch unreachable; + var runtime_path = std.fs.path.join(default_allocator, &[_]string{ dir, "fallback.out.js" }) catch unreachable; + const file = std.fs.openFileAbsolute(runtime_path, .{}) catch unreachable; + defer file.close(); + return file.readToEndAlloc(default_allocator, (file.stat() catch unreachable).size) catch unreachable; + } else { + return ProdSourceContent; + } + } + pub const version_hash = @embedFile("./fallback.version"); + var version_hash_int: u32 = 0; + pub fn versionHash() u32 { + if (version_hash_int == 0) { + version_hash_int = @truncate(u32, std.fmt.parseInt(u64, version(), 16) catch unreachable); + } + return version_hash_int; + } + + pub fn version() string { + return version_hash; + } + + pub fn render( + allocator: *std.mem.Allocator, + msg: *const Api.FallbackMessageContainer, + preload: string, + entry_point: string, + comptime WriterType: type, + writer: WriterType, + ) !void { + const PrintArgs = struct { + blob: Base64FallbackMessage, + preload: string, + fallback: string, + entry_point: string, + }; + try writer.print(HTMLTemplate, PrintArgs{ + .blob = Base64FallbackMessage{ .msg = msg, .allocator = allocator }, + .preload = preload, + .fallback = scriptContent(), + .entry_point = entry_point, + }); + } +}; pub const Runtime = struct { + pub const ProdSourceContent = @embedFile("./runtime.out.js"); + pub fn sourceContent() string { if (comptime isDebug) { var dirpath = std.fs.path.dirname(@src().file).?; @@ -36,6 +135,10 @@ pub const Runtime = struct { return version_hash_int; } + pub fn version() string { + return version_hash; + } + const bytecodeCacheFilename = std.fmt.comptimePrint("__runtime.{s}", .{version_hash}); var bytecodeCacheFetcher = Fs.BytecodeCacheFetcher{}; @@ -43,10 +146,6 @@ pub const Runtime = struct { return bytecodeCacheFetcher.fetch(bytecodeCacheFilename, fs); } - pub fn version() string { - return version_hash; - } - pub const Features = struct { react_fast_refresh: bool = false, hot_module_reloading: bool = false, diff --git a/src/runtime/hmr.ts b/src/runtime/hmr.ts index ecd3aadb2..46b841b7a 100644 --- a/src/runtime/hmr.ts +++ b/src/runtime/hmr.ts @@ -435,7 +435,7 @@ if (typeof window !== "undefined") { clientStartTime = performance.now(); - const baseURL = new URL(location.origin + "/_api.hmr"); + const baseURL = new URL(location.origin + "/bun:_api.hmr"); baseURL.protocol = location.protocol === "https:" ? "wss" : "ws"; this.socket = new WebSocket(baseURL.toString(), ["bun-hmr"]); this.socket.binaryType = "arraybuffer"; diff --git a/src/test/fixtures/fragment.jsx b/src/test/fixtures/fragment.jsx new file mode 100644 index 000000000..3f5615368 --- /dev/null +++ b/src/test/fixtures/fragment.jsx @@ -0,0 +1 @@ +const Foo = <>hi</>; |