From 9c9f4ed6ad39f92cb331e21a6b6dc0847e66510e Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Wed, 13 Sep 2023 17:31:59 -0700 Subject: Make --watch instant (#5236) Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com> --- src/bun.js/module_loader.zig | 59 ++++++++++++++++++-------------------------- 1 file changed, 24 insertions(+), 35 deletions(-) (limited to 'src/bun.js/module_loader.zig') diff --git a/src/bun.js/module_loader.zig b/src/bun.js/module_loader.zig index cf86cb460..db8df00c2 100644 --- a/src/bun.js/module_loader.zig +++ b/src/bun.js/module_loader.zig @@ -363,18 +363,15 @@ pub const RuntimeTranspilerStore = struct { var package_json: ?*PackageJSON = null; const hash = JSC.Watcher.getHash(path.text); - if (vm.bun_dev_watcher) |watcher| { - if (watcher.indexOf(hash)) |index| { - const _fd = watcher.watchlist.items(.fd)[index]; - fd = if (_fd > 0) _fd else null; - package_json = watcher.watchlist.items(.package_json)[index]; - } - } else if (vm.bun_watcher) |watcher| { - if (watcher.indexOf(hash)) |index| { - const _fd = watcher.watchlist.items(.fd)[index]; - fd = if (_fd > 0) _fd else null; - package_json = watcher.watchlist.items(.package_json)[index]; - } + switch (vm.bun_watcher) { + .hot, .watch => { + if (vm.bun_watcher.indexOf(hash)) |index| { + const _fd = vm.bun_watcher.watchlist().items(.fd)[index]; + fd = if (_fd > 0) _fd else null; + package_json = vm.bun_watcher.watchlist().items(.package_json)[index]; + } + }, + else => {}, } // this should be a cheap lookup because 24 bytes == 8 * 3 so it's read 3 machine words @@ -438,9 +435,9 @@ pub const RuntimeTranspilerStore = struct { ) orelse { if (vm.isWatcherEnabled()) { if (input_file_fd != 0) { - if (vm.bun_watcher != null and !is_node_override and std.fs.path.isAbsolute(path.text) and !strings.contains(path.text, "node_modules")) { + if (!is_node_override and std.fs.path.isAbsolute(path.text) and !strings.contains(path.text, "node_modules")) { should_close_input_file_fd = false; - vm.bun_watcher.?.addFile( + vm.bun_watcher.addFile( input_file_fd, path.text, hash, @@ -459,11 +456,11 @@ pub const RuntimeTranspilerStore = struct { if (vm.isWatcherEnabled()) { if (input_file_fd != 0) { - if (vm.bun_watcher != null and !is_node_override and + if (!is_node_override and std.fs.path.isAbsolute(path.text) and !strings.contains(path.text, "node_modules")) { should_close_input_file_fd = false; - vm.bun_watcher.?.addFile( + vm.bun_watcher.addFile( input_file_fd, path.text, hash, @@ -1244,8 +1241,8 @@ pub const ModuleLoader = struct { var resolved_source = jsc_vm.refCountedResolvedSource(printer.ctx.written, bun.String.init(specifier), path.text, null, false); if (parse_result.input_fd) |fd_| { - if (jsc_vm.bun_watcher != null and std.fs.path.isAbsolute(path.text) and !strings.contains(path.text, "node_modules")) { - jsc_vm.bun_watcher.?.addFile( + if (std.fs.path.isAbsolute(path.text) and !strings.contains(path.text, "node_modules")) { + jsc_vm.bun_watcher.addFile( fd_, path.text, this.hash, @@ -1379,18 +1376,10 @@ pub const ModuleLoader = struct { var fd: ?StoredFileDescriptorType = null; var package_json: ?*PackageJSON = null; - if (jsc_vm.bun_dev_watcher) |watcher| { - if (watcher.indexOf(hash)) |index| { - const _fd = watcher.watchlist.items(.fd)[index]; - fd = if (_fd > 0) _fd else null; - package_json = watcher.watchlist.items(.package_json)[index]; - } - } else if (jsc_vm.bun_watcher) |watcher| { - if (watcher.indexOf(hash)) |index| { - const _fd = watcher.watchlist.items(.fd)[index]; - fd = if (_fd > 0) _fd else null; - package_json = watcher.watchlist.items(.package_json)[index]; - } + if (jsc_vm.bun_watcher.indexOf(hash)) |index| { + const _fd = jsc_vm.bun_watcher.watchlist().items(.fd)[index]; + fd = if (_fd > 0) _fd else null; + package_json = jsc_vm.bun_watcher.watchlist().items(.package_json)[index]; } var old = jsc_vm.bundler.log; @@ -1470,9 +1459,9 @@ pub const ModuleLoader = struct { if (comptime !disable_transpilying) { if (jsc_vm.isWatcherEnabled()) { if (input_file_fd != 0) { - if (jsc_vm.bun_watcher != null and !is_node_override and std.fs.path.isAbsolute(path.text) and !strings.contains(path.text, "node_modules")) { + if (!is_node_override and std.fs.path.isAbsolute(path.text) and !strings.contains(path.text, "node_modules")) { should_close_input_file_fd = false; - jsc_vm.bun_watcher.?.addFile( + jsc_vm.bun_watcher.addFile( input_file_fd, path.text, hash, @@ -1513,9 +1502,9 @@ pub const ModuleLoader = struct { if (comptime !disable_transpilying) { if (jsc_vm.isWatcherEnabled()) { if (input_file_fd != 0) { - if (jsc_vm.bun_watcher != null and !is_node_override and std.fs.path.isAbsolute(path.text) and !strings.contains(path.text, "node_modules")) { + if (!is_node_override and std.fs.path.isAbsolute(path.text) and !strings.contains(path.text, "node_modules")) { should_close_input_file_fd = false; - jsc_vm.bun_watcher.?.addFile( + jsc_vm.bun_watcher.addFile( input_file_fd, path.text, hash, @@ -1715,7 +1704,7 @@ pub const ModuleLoader = struct { // const hash = http.Watcher.getHash(path.text); // if (jsc_vm.watcher) |watcher| { // if (watcher.indexOf(hash)) |index| { - // const _fd = watcher.watchlist.items(.fd)[index]; + // const _fd = watcher.watchlist().items(.fd)[index]; // fd = if (_fd > 0) _fd else null; // } // } -- cgit v1.2.3 From 689b28455c943897a3d286271e6f182afb17848f Mon Sep 17 00:00:00 2001 From: Dylan Conway <35280289+dylan-conway@users.noreply.github.com> Date: Wed, 20 Sep 2023 08:10:03 -0700 Subject: add `emitDecoratorMetadata` (#5777) * some progess * needs more tests * make tests easier to debug * get metadata for constructor arg decorators * fix some things * merge `emitDecoratorMetadata` option * remove `^` * bundler tests and get option from tsconfig earlier * remove spaces * fix tests --- src/bun.js/module_loader.zig | 2 + src/bundler.zig | 16 +- src/bundler/bundle_v2.zig | 3 + src/js_ast.zig | 7 + src/js_parser.zig | 890 +++++++++++++++++++++--- src/options.zig | 1 + src/resolver/resolver.zig | 4 + src/resolver/tsconfig_json.zig | 9 + src/runtime.footer.bun.js | 5 +- src/runtime.footer.js | 5 +- src/runtime.footer.node.js | 5 +- src/runtime.footer.with-refresh.js | 5 +- src/runtime.js | 22 +- src/runtime.zig | 18 +- test/bundler/bundler_decorator_metadata.test.ts | 505 ++++++++++++++ test/package.json | 1 + test/transpiler/decorator-metadata.test.ts | 494 +++++++++++++ test/tsconfig.json | 1 + tsconfig.json | 1 + 19 files changed, 1884 insertions(+), 110 deletions(-) create mode 100644 test/bundler/bundler_decorator_metadata.test.ts create mode 100644 test/transpiler/decorator-metadata.test.ts (limited to 'src/bun.js/module_loader.zig') diff --git a/src/bun.js/module_loader.zig b/src/bun.js/module_loader.zig index db8df00c2..135bd5e94 100644 --- a/src/bun.js/module_loader.zig +++ b/src/bun.js/module_loader.zig @@ -402,6 +402,7 @@ pub const RuntimeTranspilerStore = struct { .file_hash = hash, .macro_remappings = macro_remappings, .jsx = bundler.options.jsx, + .emit_decorator_metadata = bundler.options.emit_decorator_metadata, .virtual_source = null, .dont_bundle_twice = true, .allow_commonjs = true, @@ -1427,6 +1428,7 @@ pub const ModuleLoader = struct { .file_hash = hash, .macro_remappings = macro_remappings, .jsx = jsc_vm.bundler.options.jsx, + .emit_decorator_metadata = jsc_vm.bundler.options.emit_decorator_metadata, .virtual_source = virtual_source, .dont_bundle_twice = true, .allow_commonjs = true, diff --git a/src/bundler.zig b/src/bundler.zig index 76fbc02ee..15089e241 100644 --- a/src/bundler.zig +++ b/src/bundler.zig @@ -435,13 +435,14 @@ pub const Bundler = struct { ); if (auto_jsx) { - // If we don't explicitly pass JSX, try to get it from the root tsconfig - if (bundler.options.transform_options.jsx == null) { - // Most of the time, this will already be cached - if (bundler.resolver.readDirInfo(bundler.fs.top_level_dir) catch null) |root_dir| { - if (root_dir.tsconfig_json) |tsconfig| { + // Most of the time, this will already be cached + if (bundler.resolver.readDirInfo(bundler.fs.top_level_dir) catch null) |root_dir| { + if (root_dir.tsconfig_json) |tsconfig| { + // If we don't explicitly pass JSX, try to get it from the root tsconfig + if (bundler.options.transform_options.jsx == null) { bundler.options.jsx = tsconfig.jsx; } + bundler.options.emit_decorator_metadata = tsconfig.emit_decorator_metadata; } } } @@ -780,6 +781,7 @@ pub const Bundler = struct { .file_descriptor = file_descriptor, .file_hash = filepath_hash, .macro_remappings = bundler.options.macro_remap, + .emit_decorator_metadata = resolve_result.emit_decorator_metadata, .jsx = resolve_result.jsx, }, client_entry_point, @@ -899,6 +901,7 @@ pub const Bundler = struct { .file_hash = null, .macro_remappings = bundler.options.macro_remap, .jsx = resolve_result.jsx, + .emit_decorator_metadata = resolve_result.emit_decorator_metadata, }, client_entry_point_, ) orelse { @@ -1188,6 +1191,7 @@ pub const Bundler = struct { replace_exports: runtime.Runtime.Features.ReplaceableExport.Map = .{}, inject_jest_globals: bool = false, set_breakpoint_on_first_line: bool = false, + emit_decorator_metadata: bool = false, dont_bundle_twice: bool = false, allow_commonjs: bool = false, @@ -1300,7 +1304,9 @@ pub const Bundler = struct { jsx.parse = loader.isJSX(); var opts = js_parser.Parser.Options.init(jsx, loader); + opts.legacy_transform_require_to_import = bundler.options.allow_runtime and !bundler.options.target.isBun(); + opts.features.emit_decorator_metadata = this_parse.emit_decorator_metadata; opts.features.allow_runtime = bundler.options.allow_runtime; opts.features.set_breakpoint_on_first_line = this_parse.set_breakpoint_on_first_line; opts.features.trim_unused_imports = bundler.options.trim_unused_imports orelse loader.isTypeScript(); diff --git a/src/bundler/bundle_v2.zig b/src/bundler/bundle_v2.zig index 359272e5f..e5b73814c 100644 --- a/src/bundler/bundle_v2.zig +++ b/src/bundler/bundle_v2.zig @@ -2276,6 +2276,7 @@ pub const ParseTask = struct { tree_shaking: bool = false, known_target: ?options.Target = null, module_type: options.ModuleType = .unknown, + emit_decorator_metadata: bool = false, ctx: *BundleV2, package_version: string = "", @@ -2298,6 +2299,7 @@ pub const ParseTask = struct { .jsx = resolve_result.jsx, .source_index = source_index orelse Index.invalid, .module_type = resolve_result.module_type, + .emit_decorator_metadata = resolve_result.emit_decorator_metadata, .package_version = if (resolve_result.package_json) |package_json| package_json.version else "", }; } @@ -2600,6 +2602,7 @@ pub const ParseTask = struct { opts.features.minify_syntax = bundler.options.minify_syntax; opts.features.minify_identifiers = bundler.options.minify_identifiers; opts.features.should_fold_typescript_constant_expressions = opts.features.inlining or loader.isTypeScript(); + opts.features.emit_decorator_metadata = bundler.options.emit_decorator_metadata; opts.tree_shaking = if (source.index.isRuntime()) true else bundler.options.tree_shaking; opts.module_type = task.module_type; diff --git a/src/js_ast.zig b/src/js_ast.zig index 7811541f4..b9e34d279 100644 --- a/src/js_ast.zig +++ b/src/js_ast.zig @@ -26,6 +26,7 @@ const is_bindgen = std.meta.globalOption("bindgen", bool) orelse false; const ComptimeStringMap = bun.ComptimeStringMap; const JSPrinter = @import("./js_printer.zig"); const js_lexer = @import("./js_lexer.zig"); +const TypeScript = @import("./js_parser.zig").TypeScript; const ThreadlocalArena = @import("./mimalloc_arena.zig").Arena; /// This is the index to the automatically-generated part containing code that @@ -834,6 +835,8 @@ pub const G = struct { // This is omitted for class fields value: ?ExprNodeIndex = null, + ts_metadata: TypeScript.Metadata = .m_none, + pub const List = BabyList(Property); pub const Kind = enum(u3) { @@ -865,6 +868,8 @@ pub const G = struct { arguments_ref: ?Ref = null, flags: Flags.Function.Set = Flags.Function.None, + + return_ts_metadata: TypeScript.Metadata = .m_none, }; pub const Arg = struct { ts_decorators: ExprNodeList = ExprNodeList{}, @@ -873,6 +878,8 @@ pub const G = struct { // "constructor(public x: boolean) {}" is_typescript_ctor_field: bool = false, + + ts_metadata: TypeScript.Metadata = .m_none, }; }; diff --git a/src/js_parser.zig b/src/js_parser.zig index a61657128..a9f346caf 100644 --- a/src/js_parser.zig +++ b/src/js_parser.zig @@ -70,7 +70,7 @@ const RefHashCtx = @import("./ast/base.zig").RefHashCtx; pub const StringHashMap = bun.StringHashMap; pub const AutoHashMap = std.AutoHashMap; -const StringHashMapUnamanged = bun.StringHashMapUnmanaged; +const StringHashMapUnmanaged = bun.StringHashMapUnmanaged; const ObjectPool = @import("./pool.zig").ObjectPool; const NodeFallbackModules = @import("./node_fallbacks.zig"); @@ -439,6 +439,155 @@ pub const TypeScript = struct { }; } + pub const Metadata = union(enum) { + m_none: void, + + m_never: void, + m_unknown: void, + m_any: void, + m_void: void, + m_null: void, + m_undefined: void, + m_function: void, + m_array: void, + m_boolean: void, + m_string: void, + m_object: void, + m_number: void, + m_bigint: void, + m_symbol: void, + m_promise: void, + m_identifier: Ref, + m_dot: List(Ref), + + pub const default: @This() = .m_none; + + // the logic in finishUnion, mergeUnion, finishIntersection and mergeIntersection is + // translated from: + // https://github.com/microsoft/TypeScript/blob/e0a324b0503be479f2b33fd2e17c6e86c94d1297/src/compiler/transformers/typeSerializer.ts#L402 + + /// Return the final union type if possible, or return null to continue merging. + /// + /// If the current type is m_never, m_null, or m_undefined assign the current type + /// to m_none and return null to ensure it's always replaced by the next type. + pub fn finishUnion(current: *@This(), p: anytype) ?@This() { + return switch (current.*) { + .m_identifier => |ref| { + if (strings.eqlComptime(p.loadNameFromRef(ref), "Object")) { + return .m_object; + } + return null; + }, + + .m_unknown, + .m_any, + .m_object, + => .m_object, + + .m_never, + .m_null, + .m_undefined, + => { + current.* = .m_none; + return null; + }, + + else => null, + }; + } + + pub fn mergeUnion(result: *@This(), left: @This()) void { + if (left != .m_none) { + if (std.meta.activeTag(result.*) != std.meta.activeTag(left)) { + result.* = switch (result.*) { + .m_never, + .m_undefined, + .m_null, + => left, + + else => .m_object, + }; + } else { + switch (result.*) { + .m_identifier => |ref| { + if (!ref.eql(left.m_identifier)) { + result.* = .m_object; + } + }, + else => {}, + } + } + } else { + // always take the next value if left is m_none + } + } + + /// Return the final intersection type if possible, or return null to continue merging. + /// + /// If the current type is m_unknown, m_null, or m_undefined assign the current type + /// to m_none and return null to ensure it's always replaced by the next type. + pub fn finishIntersection(current: *@This(), p: anytype) ?@This() { + return switch (current.*) { + .m_identifier => |ref| { + if (strings.eqlComptime(p.loadNameFromRef(ref), "Object")) { + return .m_object; + } + return null; + }, + + // ensure m_never is the final type + .m_never => .m_never, + + .m_any, + .m_object, + => .m_object, + + .m_unknown, + .m_null, + .m_undefined, + => { + current.* = .m_none; + return null; + }, + + else => null, + }; + } + + pub fn mergeIntersection(result: *@This(), left: @This()) void { + if (left != .m_none) { + if (std.meta.activeTag(result.*) != std.meta.activeTag(left)) { + result.* = switch (result.*) { + .m_unknown, + .m_undefined, + .m_null, + => left, + + // ensure m_never is the final type + .m_never => .m_never, + + else => .m_object, + }; + } else { + switch (result.*) { + .m_identifier => |ref| { + if (!ref.eql(left.m_identifier)) { + result.* = .m_object; + } + }, + else => {}, + } + } + } else { + // make sure intersection of only m_unknown serializes to "undefined" + // instead of "Object" + if (result.* == .m_unknown) { + result.* = .m_undefined; + } + } + } + }; + pub fn isTSArrowFnJSX(p: anytype) !bool { var oldLexer = std.mem.toBytes(p.lexer); @@ -664,19 +813,19 @@ pub const TypeScript = struct { .{ "abstract", .abstract }, .{ "asserts", .asserts }, - .{ "keyof", .prefix }, - .{ "readonly", .prefix }, + .{ "keyof", .prefix_keyof }, + .{ "readonly", .prefix_readonly }, - .{ "any", .primitive }, - .{ "never", .primitive }, - .{ "unknown", .primitive }, - .{ "undefined", .primitive }, - .{ "object", .primitive }, - .{ "number", .primitive }, - .{ "string", .primitive }, - .{ "boolean", .primitive }, - .{ "bigint", .primitive }, - .{ "symbol", .primitive }, + .{ "any", .primitive_any }, + .{ "never", .primitive_never }, + .{ "unknown", .primitive_unknown }, + .{ "undefined", .primitive_undefined }, + .{ "object", .primitive_object }, + .{ "number", .primitive_number }, + .{ "string", .primitive_string }, + .{ "boolean", .primitive_boolean }, + .{ "bigint", .primitive_bigint }, + .{ "symbol", .primitive_symbol }, .{ "infer", .infer }, }); @@ -685,17 +834,30 @@ pub const TypeScript = struct { unique, abstract, asserts, - prefix, - primitive, + prefix_keyof, + prefix_readonly, + primitive_any, + primitive_never, + primitive_unknown, + primitive_undefined, + primitive_object, + primitive_number, + primitive_string, + primitive_boolean, + primitive_bigint, + primitive_symbol, infer, }; }; - pub const SkipTypeOptions = struct { - is_return_type: bool = false, - is_index_signature: bool = false, - allow_tuple_labels: bool = false, - disallow_conditional_types: bool = false, + pub const SkipTypeOptions = enum { + is_return_type, + is_index_signature, + allow_tuple_labels, + disallow_conditional_types, + + pub const Bitset = std.enums.EnumSet(@This()); + pub const empty = Bitset.initEmpty(); }; }; @@ -1398,8 +1560,9 @@ const StaticSymbolName = struct { pub const __HMRClient = NewStaticSymbol("Bun"); pub const __FastRefreshModule = NewStaticSymbol("FastHMR"); pub const __FastRefreshRuntime = NewStaticSymbol("FastRefresh"); - pub const __decorateClass = NewStaticSymbol("__decorateClass"); - pub const __decorateParam = NewStaticSymbol("__decorateParam"); + pub const __legacyDecorateClassTS = NewStaticSymbol("__legacyDecorateClassTS"); + pub const __legacyDecorateParamTS = NewStaticSymbol("__legacyDecorateParamTS"); + pub const __legacyMetadataTS = NewStaticSymbol("__legacyMetadataTS"); pub const @"$$typeof" = NewStaticSymbol("$$typeof"); pub const @"$$m" = NewStaticSymbol("$$m"); @@ -2437,6 +2600,7 @@ const FnOrArrowDataParse = struct { is_typescript_declare: bool = false, has_argument_decorators: bool = false, + has_decorators: bool = false, is_return_disallowed: bool = false, is_this_disallowed: bool = false, @@ -2573,6 +2737,7 @@ const PropertyOpts = struct { is_ts_abstract: bool = false, ts_decorators: []Expr = &[_]Expr{}, has_argument_decorators: bool = false, + has_class_decorators: bool = false, }; pub const ScanPassResult = struct { @@ -4304,7 +4469,7 @@ fn NewParser_( emitted_namespace_vars: RefMap = RefMap{}, is_exported_inside_namespace: RefRefMap = .{}, - known_enum_values: Map(Ref, StringHashMapUnamanged(f64)) = .{}, + known_enum_values: Map(Ref, StringHashMapUnmanaged(f64)) = .{}, local_type_names: StringBoolMap = StringBoolMap{}, // This is the reference to the generated function argument for the namespace, @@ -6737,7 +6902,7 @@ fn NewParser_( try p.lexer.next(); if (p.lexer.token == T.t_colon) { try p.lexer.next(); - try p.skipTypeScriptType(js_ast.Op.Level.lowest); + try p.skipTypeScriptType(.lowest); } if (p.lexer.token != T.t_comma) { break; @@ -6765,6 +6930,7 @@ fn NewParser_( var is_identifier = p.lexer.token == T.t_identifier; var text = p.lexer.identifier; var arg = try p.parseBinding(); + var ts_metadata = TypeScript.Metadata.default; if (comptime is_typescript_enabled) { if (is_identifier and opts.is_constructor) { @@ -6804,7 +6970,11 @@ fn NewParser_( // "function foo(a: any) {}" if (p.lexer.token == .t_colon) { try p.lexer.next(); - try p.skipTypeScriptType(.lowest); + if (p.options.features.emit_decorator_metadata and opts.allow_ts_decorators and (opts.has_argument_decorators or opts.has_decorators or arg_has_decorators)) { + ts_metadata = try p.skipTypeScriptTypeWithMetadata(.lowest); + } else { + try p.skipTypeScriptType(.lowest); + } } } @@ -6825,6 +6995,7 @@ fn NewParser_( // We need to track this because it affects code generation .is_typescript_ctor_field = is_typescript_ctor_field, + .ts_metadata = ts_metadata, }) catch unreachable; if (p.lexer.token != .t_comma) { @@ -6864,9 +7035,18 @@ fn NewParser_( p.fn_or_arrow_data_parse.has_argument_decorators = arg_has_decorators; // "function foo(): any {}" - if (is_typescript_enabled and p.lexer.token == .t_colon) { - try p.lexer.next(); - try p.skipTypescriptReturnType(); + if (is_typescript_enabled) { + if (p.lexer.token == .t_colon) { + try p.lexer.next(); + + if (p.options.features.emit_decorator_metadata and opts.allow_ts_decorators and (opts.has_argument_decorators or opts.has_decorators)) { + func.return_ts_metadata = try p.skipTypescriptReturnTypeWithMetadata(); + } else { + try p.skipTypescriptReturnType(); + } + } else if (func.flags.contains(.is_async) and p.options.features.emit_decorator_metadata and opts.allow_ts_decorators and (opts.has_argument_decorators or opts.has_decorators)) { + func.return_ts_metadata = .m_promise; + } } // "function foo(): any;" @@ -6881,10 +7061,15 @@ fn NewParser_( return func; } - // pub fn parseBinding(p: *P) - pub inline fn skipTypescriptReturnType(p: *P) anyerror!void { - try p.skipTypeScriptTypeWithOpts(.lowest, .{ .is_return_type = true }); + var result = TypeScript.Metadata.default; + try p.skipTypeScriptTypeWithOpts(.lowest, TypeScript.SkipTypeOptions.Bitset.initOne(.is_return_type), false, &result); + } + + pub inline fn skipTypescriptReturnTypeWithMetadata(p: *P) anyerror!TypeScript.Metadata { + var result = TypeScript.Metadata.default; + try p.skipTypeScriptTypeWithOpts(.lowest, TypeScript.SkipTypeOptions.Bitset.initOne(.is_return_type), true, &result); + return result; } pub fn parseTypeScriptDecorators(p: *P) ![]ExprNodeIndex { @@ -6912,7 +7097,15 @@ fn NewParser_( inline fn skipTypeScriptType(p: *P, level: js_ast.Op.Level) anyerror!void { p.markTypeScriptOnly(); - try p.skipTypeScriptTypeWithOpts(level, .{}); + var result = TypeScript.Metadata.default; + try p.skipTypeScriptTypeWithOpts(level, TypeScript.SkipTypeOptions.empty, false, &result); + } + + inline fn skipTypeScriptTypeWithMetadata(p: *P, level: js_ast.Op.Level) anyerror!TypeScript.Metadata { + p.markTypeScriptOnly(); + var result = TypeScript.Metadata.default; + try p.skipTypeScriptTypeWithOpts(level, TypeScript.SkipTypeOptions.empty, true, &result); + return result; } fn skipTypeScriptBinding(p: *P) anyerror!void { @@ -7057,41 +7250,77 @@ fn NewParser_( // let x = (y: any): (y) => {return 0}; // let x = (y: any): asserts y is (y) => {}; // - fn skipTypeScriptParenOrFnType(p: *P) anyerror!void { + fn skipTypeScriptParenOrFnType(p: *P, comptime get_metadata: bool, result: *TypeScript.Metadata) anyerror!void { p.markTypeScriptOnly(); if (p.trySkipTypeScriptArrowArgsWithBacktracking()) { try p.skipTypescriptReturnType(); + if (comptime get_metadata) + result.* = .m_function; } else { try p.lexer.expect(.t_open_paren); - try p.skipTypeScriptType(.lowest); + if (comptime get_metadata) { + result.* = try p.skipTypeScriptTypeWithMetadata(.lowest); + } else { + try p.skipTypeScriptType(.lowest); + } try p.lexer.expect(.t_close_paren); } } - fn skipTypeScriptTypeWithOpts(p: *P, level: js_ast.Op.Level, opts: TypeScript.SkipTypeOptions) anyerror!void { + fn skipTypeScriptTypeWithOpts( + p: *P, + level: js_ast.Op.Level, + opts: TypeScript.SkipTypeOptions.Bitset, + comptime get_metadata: bool, + result: *TypeScript.Metadata, + ) anyerror!void { p.markTypeScriptOnly(); while (true) { switch (p.lexer.token) { - .t_numeric_literal, - .t_big_integer_literal, - .t_string_literal, - .t_no_substitution_template_literal, - .t_true, - .t_false, - .t_null, - .t_void, - => { + .t_numeric_literal => { try p.lexer.next(); + if (comptime get_metadata) { + result.* = .m_number; + } + }, + .t_big_integer_literal => { + try p.lexer.next(); + if (comptime get_metadata) { + result.* = .m_bigint; + } + }, + .t_string_literal, .t_no_substitution_template_literal => { + try p.lexer.next(); + if (comptime get_metadata) { + result.* = .m_string; + } + }, + .t_true, .t_false => { + try p.lexer.next(); + if (comptime get_metadata) { + result.* = .m_boolean; + } + }, + .t_null => { + try p.lexer.next(); + if (comptime get_metadata) { + result.* = .m_null; + } + }, + .t_void => { + try p.lexer.next(); + if (comptime get_metadata) { + result.* = .m_void; + } }, - .t_const => { const r = p.lexer.range(); try p.lexer.next(); // ["const: number]" - if (opts.allow_tuple_labels and p.lexer.token == .t_colon) { + if (opts.contains(.allow_tuple_labels) and p.lexer.token == .t_colon) { try p.log.addRangeError(p.source, r, "Unexpected \"const\""); } }, @@ -7105,6 +7334,10 @@ fn NewParser_( try p.skipTypeScriptType(.lowest); return; } + + if (comptime get_metadata) { + result.* = .m_object; + } }, .t_minus => { // "-123" @@ -7113,8 +7346,14 @@ fn NewParser_( if (p.lexer.token == .t_big_integer_literal) { try p.lexer.next(); + if (comptime get_metadata) { + result.* = .m_bigint; + } } else { try p.lexer.expect(.t_numeric_literal); + if (comptime get_metadata) { + result.* = .m_number; + } } }, .t_ampersand, .t_bar => { @@ -7127,7 +7366,7 @@ fn NewParser_( try p.lexer.next(); // "[import: number]" - if (opts.allow_tuple_labels and p.lexer.token == .t_colon) { + if (opts.contains(.allow_tuple_labels) and p.lexer.token == .t_colon) { return; } @@ -7155,21 +7394,21 @@ fn NewParser_( try p.lexer.next(); // "[new: number]" - if (opts.allow_tuple_labels and p.lexer.token == .t_colon) { + if (opts.contains(.allow_tuple_labels) and p.lexer.token == .t_colon) { return; } _ = try p.skipTypeScriptTypeParameters(.{ .allow_const_modifier = true }); - try p.skipTypeScriptParenOrFnType(); + try p.skipTypeScriptParenOrFnType(get_metadata, result); }, .t_less_than => { // "() => Foo" _ = try p.skipTypeScriptTypeParameters(.{ .allow_const_modifier = true }); - try p.skipTypeScriptParenOrFnType(); + try p.skipTypeScriptParenOrFnType(get_metadata, result); }, .t_open_paren => { // "(number | string)" - try p.skipTypeScriptParenOrFnType(); + try p.skipTypeScriptParenOrFnType(get_metadata, result); }, .t_identifier => { const kind = TypeScript.Identifier.IMap.get(p.lexer.identifier) orelse .normal; @@ -7177,7 +7416,7 @@ fn NewParser_( var check_type_parameters = true; switch (kind) { - .prefix => { + .prefix_keyof => { try p.lexer.next(); // Valid: @@ -7188,10 +7427,28 @@ fn NewParser_( // Invalid: // "A extends B ? keyof : string" // - if ((p.lexer.token != .t_colon and p.lexer.token != .t_in) or (!opts.is_index_signature and !opts.allow_tuple_labels)) { + if ((p.lexer.token != .t_colon and p.lexer.token != .t_in) or (!opts.contains(.is_index_signature) and !opts.contains(.allow_tuple_labels))) { try p.skipTypeScriptType(.prefix); } + if (comptime get_metadata) { + result.* = .m_object; + } + + break; + }, + .prefix_readonly => { + try p.lexer.next(); + + if ((p.lexer.token != .t_colon and p.lexer.token != .t_in) or (!opts.contains(.is_index_signature) and !opts.contains(.allow_tuple_labels))) { + try p.skipTypeScriptType(.prefix); + } + + // assume array or tuple literal + if (comptime get_metadata) { + result.* = .m_array; + } + break; }, .infer => { @@ -7201,7 +7458,7 @@ fn NewParser_( // "type Foo = Bar extends [infer T extends string] ? T : null" // "type Foo = Bar extends [infer T extends string ? infer T : never] ? T : null" // "type Foo = { [infer in Bar]: number }" - if ((p.lexer.token != .t_colon and p.lexer.token != .t_in) or (!opts.is_index_signature and !opts.allow_tuple_labels)) { + if ((p.lexer.token != .t_colon and p.lexer.token != .t_in) or (!opts.contains(.is_index_signature) and !opts.contains(.allow_tuple_labels))) { try p.lexer.expect(.t_identifier); if (p.lexer.token == .t_extends) { _ = p.trySkipTypeScriptConstraintOfInferTypeWithBacktracking(opts); @@ -7232,15 +7489,90 @@ fn NewParser_( // "function assert(x: boolean): asserts x" // "function assert(x: boolean): asserts x is boolean" - if (opts.is_return_type and !p.lexer.has_newline_before and (p.lexer.token == .t_identifier or p.lexer.token == .t_this)) { + if (opts.contains(.is_return_type) and !p.lexer.has_newline_before and (p.lexer.token == .t_identifier or p.lexer.token == .t_this)) { try p.lexer.next(); } }, - .primitive => { + .primitive_any => { + try p.lexer.next(); + check_type_parameters = false; + if (comptime get_metadata) { + result.* = .m_any; + } + }, + .primitive_never => { try p.lexer.next(); check_type_parameters = false; + if (comptime get_metadata) { + result.* = .m_never; + } + }, + .primitive_unknown => { + try p.lexer.next(); + check_type_parameters = false; + if (comptime get_metadata) { + result.* = .m_unknown; + } + }, + .primitive_undefined => { + try p.lexer.next(); + check_type_parameters = false; + if (comptime get_metadata) { + result.* = .m_undefined; + } + }, + .primitive_object => { + try p.lexer.next(); + check_type_parameters = false; + if (comptime get_metadata) { + result.* = .m_object; + } + }, + .primitive_number => { + try p.lexer.next(); + check_type_parameters = false; + if (comptime get_metadata) { + result.* = .m_number; + } + }, + .primitive_string => { + try p.lexer.next(); + check_type_parameters = false; + if (comptime get_metadata) { + result.* = .m_string; + } + }, + .primitive_boolean => { + try p.lexer.next(); + check_type_parameters = false; + if (comptime get_metadata) { + result.* = .m_boolean; + } + }, + .primitive_bigint => { + try p.lexer.next(); + check_type_parameters = false; + if (comptime get_metadata) { + result.* = .m_bigint; + } + }, + .primitive_symbol => { + try p.lexer.next(); + check_type_parameters = false; + if (comptime get_metadata) { + result.* = .m_symbol; + } }, else => { + if (comptime get_metadata) { + const find_result = p.findSymbol(logger.Loc.Empty, p.lexer.identifier) catch unreachable; + if (p.known_enum_values.contains(find_result.ref)) { + result.* = .m_number; + } else { + result.* = .{ .m_identifier = find_result.ref }; + } + } + try p.lexer.next(); }, } @@ -7261,10 +7593,15 @@ fn NewParser_( try p.lexer.next(); // "[typeof: number]" - if (opts.allow_tuple_labels and p.lexer.token == .t_colon) { + if (opts.contains(.allow_tuple_labels) and p.lexer.token == .t_colon) { return; } + // always `Object` + if (comptime get_metadata) { + result.* = .m_object; + } + if (p.lexer.token == .t_import) { // "typeof import('fs')" continue; @@ -7296,13 +7633,16 @@ fn NewParser_( // "[first: number, second: string]" try p.lexer.next(); + if (comptime get_metadata) { + result.* = .m_array; + } + while (p.lexer.token != .t_close_bracket) { if (p.lexer.token == .t_dot_dot_dot) { try p.lexer.next(); } - try p.skipTypeScriptTypeWithOpts(.lowest, TypeScript.SkipTypeOptions{ - .allow_tuple_labels = true, - }); + var dummy_result = TypeScript.Metadata.default; + try p.skipTypeScriptTypeWithOpts(.lowest, TypeScript.SkipTypeOptions.Bitset.initOne(.allow_tuple_labels), false, &dummy_result); if (p.lexer.token == .t_question) { try p.lexer.next(); } @@ -7319,10 +7659,12 @@ fn NewParser_( }, .t_open_brace => { try p.skipTypeScriptObjectType(); + if (comptime get_metadata) { + result.* = .m_object; + } }, .t_template_head => { // "`${'a' | 'b'}-${'c' | 'd'}`" - while (true) { try p.lexer.next(); try p.skipTypeScriptType(.lowest); @@ -7333,11 +7675,14 @@ fn NewParser_( break; } } + if (comptime get_metadata) { + result.* = .m_string; + } }, else => { // "[function: number]" - if (opts.allow_tuple_labels and p.lexer.isIdentifierOrKeyword()) { + if (opts.contains(.allow_tuple_labels) and p.lexer.isIdentifierOrKeyword()) { if (p.lexer.token != .t_function) { try p.lexer.unexpected(); } @@ -7362,8 +7707,22 @@ fn NewParser_( if (level.gte(.bitwise_or)) { return; } + try p.lexer.next(); - try p.skipTypeScriptType(.bitwise_or); + + if (comptime get_metadata) { + var left = result.*; + if (left.finishUnion(p)) |final| { + // finish skipping the rest of the type without collecting type metadata. + result.* = final; + try p.skipTypeScriptType(.bitwise_or); + } else { + try p.skipTypeScriptTypeWithOpts(.bitwise_or, TypeScript.SkipTypeOptions.empty, get_metadata, result); + result.mergeUnion(left); + } + } else { + try p.skipTypeScriptType(.bitwise_or); + } }, .t_ampersand => { if (level.gte(.bitwise_and)) { @@ -7371,7 +7730,20 @@ fn NewParser_( } try p.lexer.next(); - try p.skipTypeScriptType(.bitwise_and); + + if (comptime get_metadata) { + var left = result.*; + if (left.finishIntersection(p)) |final| { + // finish skipping the rest of the type without collecting type metadata. + result.* = final; + try p.skipTypeScriptType(.bitwise_and); + } else { + try p.skipTypeScriptTypeWithOpts(.bitwise_and, TypeScript.SkipTypeOptions.empty, get_metadata, result); + result.mergeIntersection(left); + } + } else { + try p.skipTypeScriptType(.bitwise_and); + } }, .t_exclamation => { // A postfix "!" is allowed in JSDoc types in TypeScript, which are only @@ -7390,6 +7762,22 @@ fn NewParser_( if (!p.lexer.isIdentifierOrKeyword()) { try p.lexer.expect(.t_identifier); } + + if (comptime get_metadata) { + if (result.* == .m_identifier) { + var dot = List(Ref).initCapacity(p.allocator, 2) catch unreachable; + dot.appendAssumeCapacity(result.m_identifier); + const find_result = p.findSymbol(logger.Loc.Empty, p.lexer.identifier) catch unreachable; + dot.appendAssumeCapacity(find_result.ref); + result.* = .{ .m_dot = dot }; + } else if (result.* == .m_dot) { + if (p.lexer.isIdentifierOrKeyword()) { + const find_result = p.findSymbol(logger.Loc.Empty, p.lexer.identifier) catch unreachable; + result.m_dot.append(p.allocator, find_result.ref) catch unreachable; + } + } + } + try p.lexer.next(); // "{ (): c.d \n (): g.h }" must not become a single type @@ -7403,26 +7791,56 @@ fn NewParser_( return; } try p.lexer.next(); + var skipped = false; if (p.lexer.token != .t_close_bracket) { + skipped = true; try p.skipTypeScriptType(.lowest); } try p.lexer.expect(.t_close_bracket); + + if (comptime get_metadata) { + if (result.* == .m_none) { + result.* = .m_array; + } else { + // if something was skipped, it is object type + if (skipped) { + result.* = .m_object; + } else { + result.* = .m_array; + } + } + } }, .t_extends => { // "{ x: number \n extends: boolean }" must not become a single type - if (p.lexer.has_newline_before or opts.disallow_conditional_types) { + if (p.lexer.has_newline_before or opts.contains(.disallow_conditional_types)) { return; } try p.lexer.next(); // The type following "extends" is not permitted to be another conditional type - try p.skipTypeScriptTypeWithOpts(.lowest, .{ .disallow_conditional_types = true }); + var extends_type = TypeScript.Metadata.default; + try p.skipTypeScriptTypeWithOpts(.lowest, TypeScript.SkipTypeOptions.Bitset.initOne(.disallow_conditional_types), get_metadata, &extends_type); - try p.lexer.expect(.t_question); - try p.skipTypeScriptType(.lowest); - try p.lexer.expect(.t_colon); - try p.skipTypeScriptType(.lowest); + if (comptime get_metadata) { + // intersection + try p.lexer.expect(.t_question); + var left = try p.skipTypeScriptTypeWithMetadata(.lowest); + try p.lexer.expect(.t_colon); + if (left.finishIntersection(p)) |final| { + result.* = final; + try p.skipTypeScriptType(.lowest); + } else { + try p.skipTypeScriptTypeWithOpts(.bitwise_and, TypeScript.SkipTypeOptions.empty, get_metadata, result); + result.mergeIntersection(left); + } + } else { + try p.lexer.expect(.t_question); + try p.skipTypeScriptType(.lowest); + try p.lexer.expect(.t_colon); + try p.skipTypeScriptType(.lowest); + } }, else => { return; @@ -7452,7 +7870,8 @@ fn NewParser_( if (p.lexer.token == .t_open_bracket) { // Index signature or computed property try p.lexer.next(); - try p.skipTypeScriptTypeWithOpts(.lowest, .{ .is_index_signature = true }); + var metadata = TypeScript.Metadata.default; + try p.skipTypeScriptTypeWithOpts(.lowest, TypeScript.SkipTypeOptions.Bitset.initOne(.is_index_signature), false, &metadata); // "{ [key: string]: number }" // "{ readonly [K in keyof T]: T[K] }" @@ -11122,13 +11541,12 @@ fn NewParser_( return result; } - pub fn skipTypeScriptConstraintOfInferTypeWithBacktracking(p: *P, flags: TypeScript.SkipTypeOptions) anyerror!bool { + pub fn skipTypeScriptConstraintOfInferTypeWithBacktracking(p: *P, flags: TypeScript.SkipTypeOptions.Bitset) anyerror!bool { try p.lexer.expect(.t_extends); - try p.skipTypeScriptTypeWithOpts(.prefix, TypeScript.SkipTypeOptions{ - .disallow_conditional_types = true, - }); + var metadata = TypeScript.Metadata.default; + try p.skipTypeScriptTypeWithOpts(.prefix, TypeScript.SkipTypeOptions.Bitset.initOne(.disallow_conditional_types), false, &metadata); - if (!flags.disallow_conditional_types and p.lexer.token == .t_question) { + if (!flags.contains(.disallow_conditional_types) and p.lexer.token == .t_question) { return error.Backtrack; } @@ -11181,7 +11599,7 @@ fn NewParser_( return Backtracking.lexerBacktracker(p, Backtracking.skipTypeScriptArrowArgsWithBacktracking, bool); } - pub fn trySkipTypeScriptConstraintOfInferTypeWithBacktracking(p: *P, flags: TypeScript.SkipTypeOptions) bool { + pub fn trySkipTypeScriptConstraintOfInferTypeWithBacktracking(p: *P, flags: TypeScript.SkipTypeOptions.Bitset) bool { return Backtracking.lexerBacktrackerWithArgs(p, Backtracking.skipTypeScriptConstraintOfInferTypeWithBacktracking, .{ p, flags }, bool); } @@ -11621,6 +12039,7 @@ fn NewParser_( (p.lexer.token != .t_open_paren or has_definite_assignment_assertion_operator)) { var initializer: ?Expr = null; + var ts_metadata = TypeScript.Metadata.default; // Forbid the names "constructor" and "prototype" in some cases if (!is_computed) { @@ -11639,7 +12058,11 @@ fn NewParser_( // Skip over types if (p.lexer.token == .t_colon) { try p.lexer.next(); - try p.skipTypeScriptType(.lowest); + if (p.options.features.emit_decorator_metadata and opts.is_class and opts.ts_decorators.len > 0) { + ts_metadata = try p.skipTypeScriptTypeWithMetadata(.lowest); + } else { + try p.skipTypeScriptType(.lowest); + } } } @@ -11693,6 +12116,7 @@ fn NewParser_( }), .key = key, .initializer = initializer, + .ts_metadata = ts_metadata, }; } @@ -11739,6 +12163,7 @@ fn NewParser_( .allow_super_property = true, .allow_ts_decorators = opts.allow_ts_decorators, .is_constructor = is_constructor, + .has_decorators = opts.ts_decorators.len > 0 or (opts.has_class_decorators and is_constructor), // Only allow omitting the body if we're parsing TypeScript class .allow_missing_body_for_type_script = is_typescript_enabled and opts.is_class, @@ -11816,6 +12241,7 @@ fn NewParser_( }), .key = key, .value = value, + .ts_metadata = .m_function, }; } @@ -11895,6 +12321,7 @@ fn NewParser_( const first_decorator_loc = p.lexer.loc(); if (opts.allow_ts_decorators) { opts.ts_decorators = try p.parseTypeScriptDecorators(); + opts.has_class_decorators = class_opts.ts_decorators.len > 0; has_decorators = has_decorators or opts.ts_decorators.len > 0; } else { opts.ts_decorators = &[_]Expr{}; @@ -18123,7 +18550,7 @@ fn NewParser_( // Track values so they can be used by constant folding. We need to follow // links here in case the enum was merged with a preceding namespace - var values_so_far = StringHashMapUnamanged(f64){}; + var values_so_far = StringHashMapUnmanaged(f64){}; p.known_enum_values.put(allocator, data.name.ref orelse p.panic("Expected data.name.ref", .{}), values_so_far) catch unreachable; p.known_enum_values.put(allocator, data.arg, values_so_far) catch unreachable; @@ -18765,7 +19192,7 @@ fn NewParser_( const args = p.allocator.alloc(Expr, 2) catch unreachable; args[0] = p.newExpr(E.Number{ .value = @as(f64, @floatFromInt(i)) }, arg_decorator.loc); args[1] = arg_decorator; - decorators.append(p.callRuntime(arg_decorator.loc, "__decorateParam", args)) catch unreachable; + decorators.append(p.callRuntime(arg_decorator.loc, "__legacyDecorateParamTS", args)) catch unreachable; if (is_constructor) { class.ts_decorators.update(decorators); } else { @@ -18792,7 +19219,12 @@ fn NewParser_( else => bun.unreachablePanic("Unexpected AST node type {any}", .{prop.key.?}), }; - const descriptor_kind: f64 = if (!prop.flags.contains(.is_method)) 2 else 1; + // TODO: when we have the `accessor` modifier, add `and !prop.flags.contains(.has_accessor_modifier)` to + // the if statement. + const descriptor_kind: Expr = if (!prop.flags.contains(.is_method)) + p.newExpr(E.Undefined{}, loc) + else + p.newExpr(E.Null{}, loc); var target: Expr = undefined; if (prop.flags.contains(.is_static)) { @@ -18802,13 +19234,60 @@ fn NewParser_( target = p.newExpr(E.Dot{ .target = p.newExpr(E.Identifier{ .ref = class.class_name.?.ref.? }, class.class_name.?.loc), .name = "prototype", .name_loc = loc }, loc); } + var array = prop.ts_decorators.listManaged(p.allocator); + + if (p.options.features.emit_decorator_metadata) { + { + // design:type + var args = p.allocator.alloc(Expr, 2) catch unreachable; + args[0] = p.newExpr(E.String{ .data = "design:type" }, logger.Loc.Empty); + args[1] = p.serializeMetadata(prop.ts_metadata) catch unreachable; + array.append(p.callRuntime(loc, "__legacyMetadataTS", args)) catch unreachable; + } + { + // design:paramtypes and design:returntype if method + if (prop.flags.contains(.is_method)) { + if (prop.value) |prop_value| { + { + var args = p.allocator.alloc(Expr, 2) catch unreachable; + args[0] = p.newExpr(E.String{ .data = "design:paramtypes" }, logger.Loc.Empty); + + const method_args = prop_value.data.e_function.func.args; + + if (method_args.len > 0) { + var args_array = p.allocator.alloc(Expr, method_args.len) catch unreachable; + + for (method_args, 0..) |method_arg, i| { + args_array[i] = p.serializeMetadata(method_arg.ts_metadata) catch unreachable; + } + + args[1] = p.newExpr(E.Array{ .items = ExprNodeList.init(args_array) }, logger.Loc.Empty); + } else { + args[1] = p.newExpr(E.Array{ .items = ExprNodeList.init(&[_]Expr{}) }, logger.Loc.Empty); + } + + array.append(p.callRuntime(loc, "__legacyMetadataTS", args)) catch unreachable; + } + { + var args = p.allocator.alloc(Expr, 2) catch unreachable; + args[0] = p.newExpr(E.String{ .data = "design:returntype" }, logger.Loc.Empty); + + args[1] = p.serializeMetadata(prop_value.data.e_function.func.return_ts_metadata) catch unreachable; + + array.append(p.callRuntime(loc, "__legacyMetadataTS", args)) catch unreachable; + } + } + } + } + } + const args = p.allocator.alloc(Expr, 4) catch unreachable; - args[0] = p.newExpr(E.Array{ .items = prop.ts_decorators }, loc); + args[0] = p.newExpr(E.Array{ .items = ExprNodeList.init(array.items) }, loc); args[1] = target; args[2] = descriptor_key; - args[3] = p.newExpr(E.Number{ .value = descriptor_kind }, loc); + args[3] = descriptor_kind; - const decorator = p.callRuntime(prop.key.?.loc, "__decorateClass", args); + const decorator = p.callRuntime(prop.key.?.loc, "__legacyDecorateClassTS", args); const decorator_stmt = p.s(S.SExpr{ .value = decorator }, decorator.loc); if (prop.flags.contains(.is_static)) { @@ -18916,13 +19395,38 @@ fn NewParser_( stmts.appendSliceAssumeCapacity(instance_decorators.items); stmts.appendSliceAssumeCapacity(static_decorators.items); if (class.ts_decorators.len > 0) { + var array = class.ts_decorators.listManaged(p.allocator); + + if (p.options.features.emit_decorator_metadata) { + if (constructor_function != null) { + // design:paramtypes + var args = p.allocator.alloc(Expr, 2) catch unreachable; + args[0] = p.newExpr(E.String{ .data = "design:paramtypes" }, logger.Loc.Empty); + + const constructor_args = constructor_function.?.func.args; + if (constructor_args.len > 0) { + var param_array = p.allocator.alloc(Expr, constructor_args.len) catch unreachable; + + for (constructor_args, 0..) |constructor_arg, i| { + param_array[i] = p.serializeMetadata(constructor_arg.ts_metadata) catch unreachable; + } + + args[1] = p.newExpr(E.Array{ .items = ExprNodeList.init(param_array) }, logger.Loc.Empty); + } else { + args[1] = p.newExpr(E.Array{ .items = ExprNodeList.init(&[_]Expr{}) }, logger.Loc.Empty); + } + + array.append(p.callRuntime(stmt.loc, "__legacyMetadataTS", args)) catch unreachable; + } + } + const args = p.allocator.alloc(Expr, 2) catch unreachable; - args[0] = p.newExpr(E.Array{ .items = class.ts_decorators }, stmt.loc); + args[0] = p.newExpr(E.Array{ .items = ExprNodeList.init(array.items) }, stmt.loc); args[1] = p.newExpr(E.Identifier{ .ref = class.class_name.?.ref.? }, class.class_name.?.loc); stmts.appendAssumeCapacity(Stmt.assign( p.newExpr(E.Identifier{ .ref = class.class_name.?.ref.? }, class.class_name.?.loc), - p.callRuntime(stmt.loc, "__decorateClass", args), + p.callRuntime(stmt.loc, "__legacyDecorateClassTS", args), p.allocator, )); @@ -18939,6 +19443,220 @@ fn NewParser_( } } + fn serializeMetadata(p: *P, ts_metadata: TypeScript.Metadata) !Expr { + return switch (ts_metadata) { + .m_none => p.newExpr( + E.Undefined{}, + logger.Loc.Empty, + ), + + .m_any, + .m_unknown, + .m_object, + => p.newExpr( + E.Identifier{ + .ref = (p.findSymbol(logger.Loc.Empty, "Object") catch unreachable).ref, + }, + logger.Loc.Empty, + ), + + .m_never, + .m_undefined, + .m_null, + .m_void, + => p.newExpr( + E.Undefined{}, + logger.Loc.Empty, + ), + + .m_string => p.newExpr( + E.Identifier{ + .ref = (p.findSymbol(logger.Loc.Empty, "String") catch unreachable).ref, + }, + logger.Loc.Empty, + ), + .m_number => p.newExpr( + E.Identifier{ + .ref = (p.findSymbol(logger.Loc.Empty, "Number") catch unreachable).ref, + }, + logger.Loc.Empty, + ), + .m_function => p.newExpr( + E.Identifier{ + .ref = (p.findSymbol(logger.Loc.Empty, "Function") catch unreachable).ref, + }, + logger.Loc.Empty, + ), + .m_boolean => p.newExpr( + E.Identifier{ + .ref = (p.findSymbol(logger.Loc.Empty, "Boolean") catch unreachable).ref, + }, + logger.Loc.Empty, + ), + .m_array => p.newExpr( + E.Identifier{ + .ref = (p.findSymbol(logger.Loc.Empty, "Array") catch unreachable).ref, + }, + logger.Loc.Empty, + ), + + .m_bigint => p.maybeDefinedHelper( + p.newExpr( + E.Identifier{ + .ref = (p.findSymbol(logger.Loc.Empty, "BigInt") catch unreachable).ref, + }, + logger.Loc.Empty, + ), + ), + + .m_symbol => p.maybeDefinedHelper( + p.newExpr( + E.Identifier{ + .ref = (p.findSymbol(logger.Loc.Empty, "Symbol") catch unreachable).ref, + }, + logger.Loc.Empty, + ), + ), + + .m_promise => p.newExpr( + E.Identifier{ + .ref = (p.findSymbol(logger.Loc.Empty, "Promise") catch unreachable).ref, + }, + logger.Loc.Empty, + ), + + .m_identifier => |ref| { + p.recordUsage(ref); + return p.maybeDefinedHelper(p.newExpr( + E.Identifier{ .ref = ref }, + logger.Loc.Empty, + )); + }, + + .m_dot => |_refs| { + var refs = _refs; + std.debug.assert(refs.items.len >= 2); + defer refs.deinit(p.allocator); + + var dots = p.newExpr( + E.Dot{ + .name = p.loadNameFromRef(refs.items[refs.items.len - 1]), + .name_loc = logger.Loc.Empty, + .target = undefined, + }, + logger.Loc.Empty, + ); + + var current_expr = &dots.data.e_dot.target; + var i: usize = refs.items.len - 2; + while (i > 0) { + current_expr.* = p.newExpr(E.Dot{ + .name = p.loadNameFromRef(refs.items[i]), + .name_loc = logger.Loc.Empty, + .target = undefined, + }, logger.Loc.Empty); + current_expr = ¤t_expr.data.e_dot.target; + i -= 1; + } + + current_expr.* = p.newExpr( + E.Identifier{ + .ref = refs.items[0], + }, + logger.Loc.Empty, + ); + + const dot_identifier = current_expr.*; + var current_dot = dots; + + var maybe_defined_dots = p.newExpr( + E.Binary{ + .op = .bin_logical_or, + .right = try p.checkIfDefinedHelper(current_dot), + .left = undefined, + }, + logger.Loc.Empty, + ); + + if (i < refs.items.len - 2) { + current_dot = current_dot.data.e_dot.target; + } + current_expr = &maybe_defined_dots.data.e_binary.left; + + while (i < refs.items.len - 2) { + current_expr.* = p.newExpr( + E.Binary{ + .op = .bin_logical_or, + .right = try p.checkIfDefinedHelper(current_dot), + .left = undefined, + }, + logger.Loc.Empty, + ); + + current_expr = ¤t_expr.data.e_binary.left; + i += 1; + if (i < refs.items.len - 2) { + current_dot = current_dot.data.e_dot.target; + } + } + + current_expr.* = try p.checkIfDefinedHelper(dot_identifier); + + var root = p.newExpr( + E.If{ + .yes = p.newExpr( + E.Identifier{ + .ref = (p.findSymbol(logger.Loc.Empty, "Object") catch unreachable).ref, + }, + logger.Loc.Empty, + ), + .no = dots, + .test_ = maybe_defined_dots, + }, + logger.Loc.Empty, + ); + + return root; + }, + }; + } + + fn checkIfDefinedHelper(p: *P, expr: Expr) !Expr { + return p.newExpr( + E.Binary{ + .op = .bin_strict_eq, + .left = p.newExpr( + E.Unary{ + .op = .un_typeof, + .value = expr, + }, + logger.Loc.Empty, + ), + .right = p.newExpr( + E.String{ .data = "undefined" }, + logger.Loc.Empty, + ), + }, + logger.Loc.Empty, + ); + } + + fn maybeDefinedHelper(p: *P, identifier_expr: Expr) !Expr { + return p.newExpr( + E.If{ + .test_ = try p.checkIfDefinedHelper(identifier_expr), + .yes = p.newExpr( + E.Identifier{ + .ref = (p.findSymbol(logger.Loc.Empty, "Object") catch unreachable).ref, + }, + logger.Loc.Empty, + ), + .no = identifier_expr, + }, + logger.Loc.Empty, + ); + } + fn visitForLoopInit(p: *P, stmt: Stmt, is_in_or_of: bool) Stmt { switch (stmt.data) { .s_expr => |st| { diff --git a/src/options.zig b/src/options.zig index aaeb1fce8..73ca9a64b 100644 --- a/src/options.zig +++ b/src/options.zig @@ -1364,6 +1364,7 @@ pub const BundleOptions = struct { loaders: Loader.HashTable, resolve_dir: string = "/", jsx: JSX.Pragma = JSX.Pragma{}, + emit_decorator_metadata: bool = false, auto_import_jsx: bool = true, allow_runtime: bool = true, diff --git a/src/resolver/resolver.zig b/src/resolver/resolver.zig index b6f571e23..4ddd97dca 100644 --- a/src/resolver/resolver.zig +++ b/src/resolver/resolver.zig @@ -187,6 +187,8 @@ pub const Result = struct { // This is the "type" field from "package.json" module_type: options.ModuleType = options.ModuleType.unknown, + emit_decorator_metadata: bool = false, + debug_meta: ?DebugMeta = null, dirname_fd: StoredFileDescriptorType = 0, @@ -965,6 +967,7 @@ pub const Resolver = struct { if (dir.enclosing_tsconfig_json) |tsconfig| { result.jsx = tsconfig.mergeJSX(result.jsx); + result.emit_decorator_metadata = result.emit_decorator_metadata or tsconfig.emit_decorator_metadata; } // If you use mjs or mts, then you're using esm @@ -3904,6 +3907,7 @@ pub const Resolver = struct { // starting from the base config (end of the list) // successively apply the inheritable attributes to the next config while (parent_configs.popOrNull()) |parent_config| { + merged_config.emit_decorator_metadata = merged_config.emit_decorator_metadata or parent_config.emit_decorator_metadata; if (parent_config.base_url.len > 0) { merged_config.base_url = parent_config.base_url; merged_config.base_url_for_paths = parent_config.base_url_for_paths; diff --git a/src/resolver/tsconfig_json.zig b/src/resolver/tsconfig_json.zig index 3f7be00ba..ba85fc965 100644 --- a/src/resolver/tsconfig_json.zig +++ b/src/resolver/tsconfig_json.zig @@ -56,6 +56,8 @@ pub const TSConfigJSON = struct { preserve_imports_not_used_as_values: ?bool = false, + emit_decorator_metadata: bool = false, + pub fn hasBaseURL(tsconfig: *const TSConfigJSON) bool { return tsconfig.base_url.len > 0; } @@ -137,6 +139,13 @@ pub const TSConfigJSON = struct { } } + // Parse "emitDecoratorMetadata" + if (compiler_opts.expr.asProperty("emitDecoratorMetadata")) |emit_decorator_metadata_prop| { + if (emit_decorator_metadata_prop.expr.asBool()) |val| { + result.emit_decorator_metadata = val; + } + } + // Parse "jsxFactory" if (compiler_opts.expr.asProperty("jsxFactory")) |jsx_prop| { if (jsx_prop.expr.asString(allocator)) |str| { diff --git a/src/runtime.footer.bun.js b/src/runtime.footer.bun.js index fdf7cdefa..810525af7 100644 --- a/src/runtime.footer.bun.js +++ b/src/runtime.footer.bun.js @@ -11,8 +11,9 @@ export var regeneratorRuntime = BUN_RUNTIME.regeneratorRuntime; export var __exportValue = BUN_RUNTIME.__exportValue; export var __exportDefault = BUN_RUNTIME.__exportDefault; export var __merge = BUN_RUNTIME.__merge; -export var __decorateClass = BUN_RUNTIME.__decorateClass; -export var __decorateParam = BUN_RUNTIME.__decorateParam; +export var __legacyDecorateClassTS = BUN_RUNTIME.__legacyDecorateClassTS; +export var __legacyDecorateParamTS = BUN_RUNTIME.__legacyDecorateParamTS; +export var __legacyMetadataTS = BUN_RUNTIME.__legacyMetadataTS; export var $$bun_runtime_json_parse = JSON.parse; export var __internalIsCommonJSNamespace = BUN_RUNTIME.__internalIsCommonJSNamespace; export var $$typeof = BUN_RUNTIME.$$typeof; diff --git a/src/runtime.footer.js b/src/runtime.footer.js index ceeab055d..48c86f47b 100644 --- a/src/runtime.footer.js +++ b/src/runtime.footer.js @@ -18,8 +18,9 @@ export var regeneratorRuntime = BUN_RUNTIME.regeneratorRuntime; export var __exportValue = BUN_RUNTIME.__exportValue; export var __exportDefault = BUN_RUNTIME.__exportDefault; export var __merge = BUN_RUNTIME.__merge; -export var __decorateClass = BUN_RUNTIME.__decorateClass; -export var __decorateParam = BUN_RUNTIME.__decorateParam; +export var __legacyDecorateClassTS = BUN_RUNTIME.__legacyDecorateClassTS; +export var __legacyDecorateParamTS = BUN_RUNTIME.__legacyDecorateParamTS; +export var __legacyMetadataTS = BUN_RUNTIME.__legacyMetadataTS; export var $$bun_runtime_json_parse = JSON.parse; export var __internalIsCommonJSNamespace = BUN_RUNTIME.__internalIsCommonJSNamespace; diff --git a/src/runtime.footer.node.js b/src/runtime.footer.node.js index ef28d3b31..4318195c5 100644 --- a/src/runtime.footer.node.js +++ b/src/runtime.footer.node.js @@ -12,8 +12,9 @@ export var __cJS2eSM = BUN_RUNTIME.__cJS2eSM; export var regeneratorRuntime = BUN_RUNTIME.regeneratorRuntime; export var __exportValue = BUN_RUNTIME.__exportValue; export var __exportDefault = BUN_RUNTIME.__exportDefault; -export var __decorateClass = BUN_RUNTIME.__decorateClass; -export var __decorateParam = BUN_RUNTIME.__decorateParam; +export var __legacyDecorateClassTS = BUN_RUNTIME.__legacyDecorateClassTS; +export var __legacyDecorateParamTS = BUN_RUNTIME.__legacyDecorateParamTS; +export var __legacyMetadataTS = BUN_RUNTIME.__legacyMetadataTS; export var $$bun_runtime_json_parse = JSON.parse; export var __internalIsCommonJSNamespace = BUN_RUNTIME.__internalIsCommonJSNamespace; var require = __$module.createRequire(import.meta.url); diff --git a/src/runtime.footer.with-refresh.js b/src/runtime.footer.with-refresh.js index 784f5f8fa..9aa9472e9 100644 --- a/src/runtime.footer.with-refresh.js +++ b/src/runtime.footer.with-refresh.js @@ -17,8 +17,9 @@ export var __cJS2eSM = BUN_RUNTIME.__cJS2eSM; export var regeneratorRuntime = BUN_RUNTIME.regeneratorRuntime; export var __exportValue = BUN_RUNTIME.__exportValue; export var __exportDefault = BUN_RUNTIME.__exportDefault; -export var __decorateClass = BUN_RUNTIME.__decorateClass; -export var __decorateParam = BUN_RUNTIME.__decorateParam; +export var __legacyDecorateClassTS = BUN_RUNTIME.__legacyDecorateClassTS; +export var __legacyDecorateParamTS = BUN_RUNTIME.__legacyDecorateParamTS; +export var __legacyMetadataTS = BUN_RUNTIME.__legacyMetadataTS; export var $$bun_runtime_json_parse = JSON.parse; export var __FastRefreshRuntime = BUN_RUNTIME.__FastRefreshRuntime; export var __internalIsCommonJSNamespace = BUN_RUNTIME.__internalIsCommonJSNamespace; diff --git a/src/runtime.js b/src/runtime.js index 41242637b..fb1d5e70e 100644 --- a/src/runtime.js +++ b/src/runtime.js @@ -250,15 +250,23 @@ export var __merge = (props, defaultProps) => { : mergeDefaultProps(props, defaultProps); }; -export var __decorateClass = (decorators, target, key, kind) => { - var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target; - for (var i = decorators.length - 1, decorator; i >= 0; i--) - if ((decorator = decorators[i])) result = (kind ? decorator(target, key, result) : decorator(result)) || result; - if (kind && result) __defProp(target, key, result); - return result; +export var __legacyDecorateClassTS = function (decorators, target, key, desc) { + var c = arguments.length, + r = c < 3 ? target : desc === null ? (desc = Object.getOwnPropertyDescriptor(target, key)) : desc, + d; + if (typeof Reflect === "object" && typeof Reflect.decorate === "function") + r = Reflect.decorate(decorators, target, key, desc); + else + for (var i = decorators.length - 1; i >= 0; i--) + if ((d = decorators[i])) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; + return c > 3 && r && Object.defineProperty(target, key, r), r; }; -export var __decorateParam = (index, decorator) => (target, key) => decorator(target, key, index); +export var __legacyDecorateParamTS = (index, decorator) => (target, key) => decorator(target, key, index); + +export var __legacyMetadataTS = (k, v) => { + if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); +}; export var __esm = (fn, res) => () => (fn && (res = fn((fn = 0))), res); diff --git a/src/runtime.zig b/src/runtime.zig index cf9f1d208..a9a88f979 100644 --- a/src/runtime.zig +++ b/src/runtime.zig @@ -328,6 +328,8 @@ pub const Runtime = struct { commonjs_at_runtime: bool = false, + emit_decorator_metadata: bool = false, + pub fn shouldUnwrapRequire(this: *const Features, package_name: string) bool { return package_name.len > 0 and strings.indexEqualAny(this.unwrap_commonjs_packages, package_name) != null; } @@ -372,8 +374,9 @@ pub const Runtime = struct { __exportDefault: ?GeneratedSymbol = null, __FastRefreshRuntime: ?GeneratedSymbol = null, __merge: ?GeneratedSymbol = null, - __decorateClass: ?GeneratedSymbol = null, - __decorateParam: ?GeneratedSymbol = null, + __legacyDecorateClassTS: ?GeneratedSymbol = null, + __legacyDecorateParamTS: ?GeneratedSymbol = null, + __legacyMetadataTS: ?GeneratedSymbol = null, @"$$typeof": ?GeneratedSymbol = null, pub const all = [_][]const u8{ @@ -395,8 +398,9 @@ pub const Runtime = struct { "__exportDefault", "__FastRefreshRuntime", "__merge", - "__decorateClass", - "__decorateParam", + "__legacyDecorateClassTS", + "__legacyDecorateParamTS", + "__legacyMetadataTS", "$$typeof", }; const all_sorted: [all.len]string = brk: { @@ -540,6 +544,11 @@ pub const Runtime = struct { return Entry{ .key = 18, .value = val.ref }; } }, + 19 => { + if (@field(this.runtime_imports, all[19])) |val| { + return Entry{ .key = 19, .value = val.ref }; + } + }, else => { return null; }, @@ -603,6 +612,7 @@ pub const Runtime = struct { 16 => (@field(imports, all[16]) orelse return null).ref, 17 => (@field(imports, all[17]) orelse return null).ref, 18 => (@field(imports, all[18]) orelse return null).ref, + 19 => (@field(imports, all[19]) orelse return null).ref, else => null, }; } diff --git a/test/bundler/bundler_decorator_metadata.test.ts b/test/bundler/bundler_decorator_metadata.test.ts new file mode 100644 index 000000000..54bbdd6a5 --- /dev/null +++ b/test/bundler/bundler_decorator_metadata.test.ts @@ -0,0 +1,505 @@ +import assert from "assert"; +import { itBundled, testForFile } from "./expectBundled"; +var { describe, test, expect } = testForFile(import.meta.path); + +itBundled("decorator_metadata/TypeSerialization", { + files: { + "/entry.ts": /* ts */ ` + import "reflect-metadata"; + function d1() {} + class Known {} + class Swag {} + class A_1 {} + + // @ts-ignore + @d1 + class Yolo { + constructor( + p0: any, + p1: unknown, + p2: never, + p3: void, + p4: null, + p5: undefined, + p6: number, + p7: string, + p8: boolean, + p9: symbol, + p10: bigint, + p11: object, + p12: () => {}, + p13: [], + p14: {}, + p15: 123, + p16: 123n, + p17: "123", + p18: \`123\`, + p19: true, + p20: false, + // @ts-ignore + p21: Map, + // @ts-ignore + p22: Set, + p23: Known, + // @ts-ignore + p24: Unknown, + p25: never & string, + p26: string & never, + p27: null & string, + p28: string & null, + p29: undefined & string, + p30: string & undefined, + p31: void & string, + p32: string & void, + p33: unknown & string, + p34: string & unknown, + p35: any & string, + p36: string & any, + p37: never | string, + p38: string | never, + p39: null | string, + p40: string | null, + p41: undefined | string, + p42: string | undefined, + p43: void | string, + p44: string | void, + p45: unknown | string, + p46: string | unknown, + p47: any | string, + p48: string | any, + p49: string | string, + p50: string & string, + p51: Known | Swag, + p52: Swag | Known, + p53: Known & Swag, + p54: Swag & Known, + p55: never | Swag, + p56: Swag | never, + p57: null | Swag, + p58: Swag | null, + p59: undefined | Swag, + p60: Swag | undefined, + p61: void | Swag, + p62: Swag | void, + p63: unknown | Swag, + p64: Swag | unknown, + p65: any | Swag, + p66: Swag | any, + p67: never & Swag, + p68: Swag & never, + p69: null & Swag, + p70: Swag & null, + p71: undefined & Swag, + p72: Swag & undefined, + p73: void & Swag, + p74: Swag & void, + p75: unknown & Swag, + p76: Swag & unknown, + p77: any & Swag, + p78: Swag & any, + p79: Swag | Swag, + p80: Swag & Swag, + // @ts-ignore + p81: Unknown | Known, + // @ts-ignore + p82: Known | Unknown, + // @ts-ignore + p83: Unknown & Known, + // @ts-ignore + p84: Known & Unknown, + // @ts-ignore + p85: Unknown | Unknown, + // @ts-ignore + p86: Unknown & Unknown, + p87: never | never, + p88: never & never, + p89: null | null, + p90: null & null, + p91: undefined | undefined, + p92: undefined & undefined, + p93: void | void, + p94: void & void, + p95: unknown | unknown, + p96: unknown & unknown, + p97: any | any, + p98: any & any, + p99: never | void, + p100: void | never, + p101: null | void, + p102: void | null, + p103: undefined | void, + p104: void | undefined, + p105: void | void, + p106: void & void, + p107: unknown | void, + p108: void | unknown, + p109: any | void, + p110: void | any, + p111: never | unknown, + p112: unknown | never, + p113: null | unknown, + p114: unknown | null, + p115: undefined | unknown, + p116: unknown | undefined, + p117: void | unknown, + p118: unknown | void, + p119: unknown | unknown, + p120: unknown & unknown, + p121: any | unknown, + p122: unknown | any, + p123: never | any, + p124: any | never, + p125: null | any, + p126: any | null, + p127: undefined | any, + p128: any | undefined, + p129: void | any, + p130: any | void, + p131: unknown | any, + p132: any | unknown, + p133: any | any, + p134: never & void, + p135: void & never, + p136: null & void, + p137: void & null, + p138: undefined & void, + p139: void & undefined, + p140: void & void, + p141: void | void, + p142: unknown & void, + p143: void & unknown, + p144: any & void, + p145: void & any, + p146: never & unknown, + p147: unknown & never, + p148: null & unknown, + p149: unknown & null, + p150: undefined & unknown, + p151: unknown & undefined, + p152: void & unknown, + p153: unknown & void, + p154: unknown & unknown, + p155: unknown | unknown, + p156: any & unknown, + p157: unknown & any, + p158: never & any, + p159: any & never, + p160: null & any, + p161: any & null, + p162: undefined & any, + p163: any & undefined, + p164: void & any, + p165: any & void, + p166: unknown & any, + p167: any & unknown, + p168: any & any, + p169: string & number & boolean & never & symbol, + p170: "foo" | A_1, + p171: true | boolean, + p172: "foo" | boolean, + p173: A_1 | "foo", + ){} + } + + const received = Reflect.getMetadata("design:paramtypes", Yolo); + console.log(received.length === 174); + console.log(received[0] === Object); + console.log(received[1] === Object); + console.log(received[2] === void 0); + console.log(received[3] === void 0); + console.log(received[4] === void 0); + console.log(received[5] === void 0); + console.log(received[6] === Number); + console.log(received[7] === String); + console.log(received[8] === Boolean); + console.log(received[9] === (typeof Symbol === "function" ? Symbol : Object)); + console.log(received[10] === (typeof BigInt === "function" ? BigInt : Object)); + console.log(received[11] === Object); + console.log(received[12] === Function); + console.log(received[13] === Array); + console.log(received[14] === Object); + console.log(received[15] === Number); + console.log(received[16] === (typeof BigInt === "function" ? BigInt : Object)); + console.log(received[17] === String); + console.log(received[18] === String); + console.log(received[19] === Boolean); + console.log(received[20] === Boolean); + console.log(received[21] === Map); + console.log(received[22] === Set); + console.log(received[23] === Known); + console.log(received[24] === Object); + console.log(received[25] === void 0); + console.log(received[26] === void 0); + console.log(received[27] === String); + console.log(received[28] === String); + console.log(received[29] === String); + console.log(received[30] === String); + console.log(received[31] === Object); + console.log(received[32] === Object); + console.log(received[33] === String); + console.log(received[34] === String); + console.log(received[35] === Object); + console.log(received[36] === Object); + console.log(received[37] === String); + console.log(received[38] === String); + console.log(received[39] === String); + console.log(received[40] === String); + console.log(received[41] === String); + console.log(received[42] === String); + console.log(received[43] === Object); + console.log(received[44] === Object); + console.log(received[45] === Object); + console.log(received[46] === Object); + console.log(received[47] === Object); + console.log(received[48] === Object); + console.log(received[49] === String); + console.log(received[50] === String); + console.log(received[51] === Object); + console.log(received[52] === Object); + console.log(received[53] === Object); + console.log(received[54] === Object); + console.log(received[55] === Swag); + console.log(received[56] === Swag); + console.log(received[57] === Swag); + console.log(received[58] === Swag); + console.log(received[59] === Swag); + console.log(received[60] === Swag); + console.log(received[61] === Object); + console.log(received[62] === Object); + console.log(received[63] === Object); + console.log(received[64] === Object); + console.log(received[65] === Object); + console.log(received[66] === Object); + console.log(received[67] === void 0); + console.log(received[68] === void 0); + console.log(received[69] === Swag); + console.log(received[70] === Swag); + console.log(received[71] === Swag); + console.log(received[72] === Swag); + console.log(received[73] === Object); + console.log(received[74] === Object); + console.log(received[75] === Swag); + console.log(received[76] === Swag); + console.log(received[77] === Object); + console.log(received[78] === Object); + console.log(received[79] === Swag); + console.log(received[80] === Swag); + console.log(received[81] === Object); + console.log(received[82] === Object); + console.log(received[83] === Object); + console.log(received[84] === Object); + console.log(received[85] === Object); + console.log(received[86] === Object); + console.log(received[87] === void 0); + console.log(received[88] === void 0); + console.log(received[89] === void 0); + console.log(received[90] === void 0); + console.log(received[91] === void 0); + console.log(received[92] === void 0); + console.log(received[93] === void 0); + console.log(received[94] === void 0); + console.log(received[95] === Object); + console.log(received[96] === void 0); + console.log(received[97] === Object); + console.log(received[98] === Object); + console.log(received[99] === void 0); + console.log(received[100] === void 0); + console.log(received[101] === void 0); + console.log(received[102] === void 0); + console.log(received[103] === void 0); + console.log(received[104] === void 0); + console.log(received[105] === void 0); + console.log(received[106] === void 0); + console.log(received[107] === Object); + console.log(received[108] === Object); + console.log(received[109] === Object); + console.log(received[110] === Object); + console.log(received[111] === Object); + console.log(received[112] === Object); + console.log(received[113] === Object); + console.log(received[114] === Object); + console.log(received[115] === Object); + console.log(received[116] === Object); + console.log(received[117] === Object); + console.log(received[118] === Object); + console.log(received[119] === Object); + console.log(received[120] === void 0); + console.log(received[121] === Object); + console.log(received[122] === Object); + console.log(received[123] === Object); + console.log(received[124] === Object); + console.log(received[125] === Object); + console.log(received[126] === Object); + console.log(received[127] === Object); + console.log(received[128] === Object); + console.log(received[129] === Object); + console.log(received[130] === Object); + console.log(received[131] === Object); + console.log(received[132] === Object); + console.log(received[133] === Object); + console.log(received[134] === void 0); + console.log(received[135] === void 0); + console.log(received[136] === void 0); + console.log(received[137] === void 0); + console.log(received[138] === void 0); + console.log(received[139] === void 0); + console.log(received[140] === void 0); + console.log(received[141] === void 0); + console.log(received[142] === void 0); + console.log(received[143] === void 0); + console.log(received[144] === Object); + console.log(received[145] === Object); + console.log(received[146] === void 0); + console.log(received[147] === void 0); + console.log(received[148] === void 0); + console.log(received[149] === void 0); + console.log(received[150] === void 0); + console.log(received[151] === void 0); + console.log(received[152] === void 0); + console.log(received[153] === void 0); + console.log(received[154] === void 0); + console.log(received[155] === Object); + console.log(received[156] === Object); + console.log(received[157] === Object); + console.log(received[158] === void 0); + console.log(received[159] === Object); + console.log(received[160] === Object); + console.log(received[161] === Object); + console.log(received[162] === Object); + console.log(received[163] === Object); + console.log(received[164] === Object); + console.log(received[165] === Object); + console.log(received[166] === Object); + console.log(received[167] === Object); + console.log(received[168] === Object); + console.log(received[169] === Object); + console.log(received[170] === Object); + console.log(received[171] === Boolean); + console.log(received[172] === Object); + console.log(received[173] === Object); + + // @ts-ignore + @d1 + class A { + // @ts-ignore + constructor(@d1 arg1: string) {} + // @ts-ignore + @d1 + // @ts-ignore + method1(@d1 arg1: number): boolean { + return true; + } + // @ts-ignore + @d1 + prop1: () => {}; + // @ts-ignore + @d1 + prop2: "foo" = "foo"; + // @ts-ignore + @d1 + prop3: symbol; + } + + console.log(Reflect.getMetadata("design:type", A) === undefined); + console.log(Reflect.getMetadata("design:paramtypes", A)[0] === String); + console.log(Reflect.getMetadata("design:returntype", A) === undefined); + + console.log(Reflect.getMetadata("design:type", A.prototype) === undefined); + console.log(Reflect.getMetadata("design:paramtypes", A.prototype) === undefined); + console.log(Reflect.getMetadata("design:returntype", A.prototype) === undefined); + + console.log(Reflect.getMetadata("design:type", A.prototype.method1) === undefined); + console.log(Reflect.getMetadata("design:paramtypes", A.prototype.method1) === undefined); + console.log(Reflect.getMetadata("design:returntype", A.prototype.method1) === undefined); + + console.log(Reflect.getMetadata("design:type", A.prototype, "method1") === Function); + console.log(Reflect.getMetadata("design:paramtypes", A.prototype, "method1")[0] === Number); + console.log(Reflect.getMetadata("design:returntype", A.prototype, "method1") === Boolean); + + console.log(Reflect.getMetadata("design:type", A.prototype, "prop1") === Function); + console.log(Reflect.getMetadata("design:paramtypes", A.prototype, "prop1") === undefined); + console.log(Reflect.getMetadata("design:returntype", A.prototype, "prop1") === undefined); + + console.log(Reflect.getMetadata("design:type", A.prototype, "prop2") === String); + console.log(Reflect.getMetadata("design:paramtypes", A.prototype, "prop2") === undefined); + console.log(Reflect.getMetadata("design:returntype", A.prototype, "prop2") === undefined); + + console.log(Reflect.getMetadata("design:type", A.prototype, "prop3") === Symbol); + console.log(Reflect.getMetadata("design:paramtypes", A.prototype, "prop3") === undefined); + console.log(Reflect.getMetadata("design:returntype", A.prototype, "prop3") === undefined); + + class HelloWorld { + // @ts-ignore + constructor(@d1 arg1: string) {} + } + + console.log(Reflect.getMetadata("design:type", HelloWorld) === undefined); + console.log(Reflect.getMetadata("design:paramtypes", HelloWorld)[0] === String); + console.log(Reflect.getMetadata("design:returntype", HelloWorld) === undefined); + + type B = "hello" | "world"; + const b = 2; + const c = ["hello", "world"] as const; + type Loser = \`hello \${B}\`; // "hello hello" | "hello world" + function d1() {} + + class AClass { + constructor( + // @ts-ignore + @d1 p0: \`hello \${B}\`, + // @ts-ignore + p1: keyof Something, + p2: typeof b, + p3: readonly ["hello", "world"], + p4: typeof c, + p5: readonly [number, string], + // prettier-ignore + p6: (string | string), + // prettier-ignore + p7: (string & string), + p8: boolean extends true ? "a" : "b", + // @ts-ignore + p9: Loser extends Loser ? string : Foo, + p10: { [keyof in string]: number }, + // @ts-ignore + p11: blah extends blahblah ? number : void, + ) {} + + // @ts-ignore + @d1 + async method1() { + return true; + } + } + + const paramtypes = Reflect.getMetadata("design:paramtypes", AClass); + console.log(paramtypes[0] === String); + console.log(paramtypes[1] === Object); + console.log(paramtypes[2] === Object); + console.log(paramtypes[3] === Array); + console.log(paramtypes[4] === Object); + console.log(paramtypes[5] === Array); + console.log(paramtypes[6] === String); + console.log(paramtypes[7] === String); + console.log(paramtypes[8] === String); + console.log(paramtypes[9] === Object); + console.log(paramtypes[10] === Object); + console.log(paramtypes[11] === Object); + + console.log(Reflect.getMetadata("design:returntype", AClass.prototype, "method1") === Promise); + `, + "/tsconfig.json": /* json */ ` + { + "compilerOptions": { + "experimentalDecorators": true, + "emitDecoratorMetadata": true, + } + } + `, + }, + install: ["reflect-metadata"], + bundling: true, + run: { + stdout: "true\n".repeat(212), + }, +}); diff --git a/test/package.json b/test/package.json index ad28f114a..9e55cc543 100644 --- a/test/package.json +++ b/test/package.json @@ -9,6 +9,7 @@ }, "dependencies": { "@prisma/client": "5.1.1", + "reflect-metadata": "0.1.13", "@resvg/resvg-js": "2.4.1", "@swc/core": "1.3.38", "body-parser": "1.20.2", diff --git a/test/transpiler/decorator-metadata.test.ts b/test/transpiler/decorator-metadata.test.ts new file mode 100644 index 000000000..861604430 --- /dev/null +++ b/test/transpiler/decorator-metadata.test.ts @@ -0,0 +1,494 @@ +import "reflect-metadata"; + +describe("decorator metadata", () => { + test("type serialization", () => { + function d1() {} + class Known {} + class Swag {} + class A_1 {} + + // @ts-ignore + @d1 + class A { + constructor( + p0: any, + p1: unknown, + p2: never, + p3: void, + p4: null, + p5: undefined, + p6: number, + p7: string, + p8: boolean, + p9: symbol, + p10: bigint, + p11: object, + p12: () => {}, + p13: [], + p14: {}, + p15: 123, + p16: 123n, + p17: "123", + p18: `123`, + p19: true, + p20: false, + // @ts-ignore + p21: Map, + // @ts-ignore + p22: Set, + p23: Known, + // @ts-ignore + p24: Unknown, + p25: never & string, + p26: string & never, + p27: null & string, + p28: string & null, + p29: undefined & string, + p30: string & undefined, + p31: void & string, + p32: string & void, + p33: unknown & string, + p34: string & unknown, + p35: any & string, + p36: string & any, + p37: never | string, + p38: string | never, + p39: null | string, + p40: string | null, + p41: undefined | string, + p42: string | undefined, + p43: void | string, + p44: string | void, + p45: unknown | string, + p46: string | unknown, + p47: any | string, + p48: string | any, + p49: string | string, + p50: string & string, + p51: Known | Swag, + p52: Swag | Known, + p53: Known & Swag, + p54: Swag & Known, + p55: never | Swag, + p56: Swag | never, + p57: null | Swag, + p58: Swag | null, + p59: undefined | Swag, + p60: Swag | undefined, + p61: void | Swag, + p62: Swag | void, + p63: unknown | Swag, + p64: Swag | unknown, + p65: any | Swag, + p66: Swag | any, + p67: never & Swag, + p68: Swag & never, + p69: null & Swag, + p70: Swag & null, + p71: undefined & Swag, + p72: Swag & undefined, + p73: void & Swag, + p74: Swag & void, + p75: unknown & Swag, + p76: Swag & unknown, + p77: any & Swag, + p78: Swag & any, + p79: Swag | Swag, + p80: Swag & Swag, + // @ts-ignore + p81: Unknown | Known, + // @ts-ignore + p82: Known | Unknown, + // @ts-ignore + p83: Unknown & Known, + // @ts-ignore + p84: Known & Unknown, + // @ts-ignore + p85: Unknown | Unknown, + // @ts-ignore + p86: Unknown & Unknown, + p87: never | never, + p88: never & never, + p89: null | null, + p90: null & null, + p91: undefined | undefined, + p92: undefined & undefined, + p93: void | void, + p94: void & void, + p95: unknown | unknown, + p96: unknown & unknown, + p97: any | any, + p98: any & any, + p99: never | void, + p100: void | never, + p101: null | void, + p102: void | null, + p103: undefined | void, + p104: void | undefined, + p105: void | void, + p106: void & void, + p107: unknown | void, + p108: void | unknown, + p109: any | void, + p110: void | any, + p111: never | unknown, + p112: unknown | never, + p113: null | unknown, + p114: unknown | null, + p115: undefined | unknown, + p116: unknown | undefined, + p117: void | unknown, + p118: unknown | void, + p119: unknown | unknown, + p120: unknown & unknown, + p121: any | unknown, + p122: unknown | any, + p123: never | any, + p124: any | never, + p125: null | any, + p126: any | null, + p127: undefined | any, + p128: any | undefined, + p129: void | any, + p130: any | void, + p131: unknown | any, + p132: any | unknown, + p133: any | any, + p134: never & void, + p135: void & never, + p136: null & void, + p137: void & null, + p138: undefined & void, + p139: void & undefined, + p140: void & void, + p141: void | void, + p142: unknown & void, + p143: void & unknown, + p144: any & void, + p145: void & any, + p146: never & unknown, + p147: unknown & never, + p148: null & unknown, + p149: unknown & null, + p150: undefined & unknown, + p151: unknown & undefined, + p152: void & unknown, + p153: unknown & void, + p154: unknown & unknown, + p155: unknown | unknown, + p156: any & unknown, + p157: unknown & any, + p158: never & any, + p159: any & never, + p160: null & any, + p161: any & null, + p162: undefined & any, + p163: any & undefined, + p164: void & any, + p165: any & void, + p166: unknown & any, + p167: any & unknown, + p168: any & any, + p169: string & number & boolean & never & symbol, + p170: "foo" | A_1, + p171: true | boolean, + p172: "foo" | boolean, + p173: A_1 | "foo", + ) {} + } + + const received = Reflect.getMetadata("design:paramtypes", A); + expect(received.length).toBe(174); + expect(received[0]).toBe(Object); + expect(received[1]).toBe(Object); + expect(received[2]).toBe(void 0); + expect(received[3]).toBe(void 0); + expect(received[4]).toBe(void 0); + expect(received[5]).toBe(void 0); + expect(received[6]).toBe(Number); + expect(received[7]).toBe(String); + expect(received[8]).toBe(Boolean); + expect(received[9]).toBe(typeof Symbol === "function" ? Symbol : Object); + expect(received[10]).toBe(typeof BigInt === "function" ? BigInt : Object); + expect(received[11]).toBe(Object); + expect(received[12]).toBe(Function); + expect(received[13]).toBe(Array); + expect(received[14]).toBe(Object); + expect(received[15]).toBe(Number); + expect(received[16]).toBe(typeof BigInt === "function" ? BigInt : Object); + expect(received[17]).toBe(String); + expect(received[18]).toBe(String); + expect(received[19]).toBe(Boolean); + expect(received[20]).toBe(Boolean); + expect(received[21]).toBe(Map); + expect(received[22]).toBe(Set); + expect(received[23]).toBe(Known); + expect(received[24]).toBe(Object); + expect(received[25]).toBe(void 0); + expect(received[26]).toBe(void 0); + expect(received[27]).toBe(String); + expect(received[28]).toBe(String); + expect(received[29]).toBe(String); + expect(received[30]).toBe(String); + expect(received[31]).toBe(Object); + expect(received[32]).toBe(Object); + expect(received[33]).toBe(String); + expect(received[34]).toBe(String); + expect(received[35]).toBe(Object); + expect(received[36]).toBe(Object); + expect(received[37]).toBe(String); + expect(received[38]).toBe(String); + expect(received[39]).toBe(String); + expect(received[40]).toBe(String); + expect(received[41]).toBe(String); + expect(received[42]).toBe(String); + expect(received[43]).toBe(Object); + expect(received[44]).toBe(Object); + expect(received[45]).toBe(Object); + expect(received[46]).toBe(Object); + expect(received[47]).toBe(Object); + expect(received[48]).toBe(Object); + expect(received[49]).toBe(String); + expect(received[50]).toBe(String); + expect(received[51]).toBe(Object); + expect(received[52]).toBe(Object); + expect(received[53]).toBe(Object); + expect(received[54]).toBe(Object); + expect(received[55]).toBe(Swag); + expect(received[56]).toBe(Swag); + expect(received[57]).toBe(Swag); + expect(received[58]).toBe(Swag); + expect(received[59]).toBe(Swag); + expect(received[60]).toBe(Swag); + expect(received[61]).toBe(Object); + expect(received[62]).toBe(Object); + expect(received[63]).toBe(Object); + expect(received[64]).toBe(Object); + expect(received[65]).toBe(Object); + expect(received[66]).toBe(Object); + expect(received[67]).toBe(void 0); + expect(received[68]).toBe(void 0); + expect(received[69]).toBe(Swag); + expect(received[70]).toBe(Swag); + expect(received[71]).toBe(Swag); + expect(received[72]).toBe(Swag); + expect(received[73]).toBe(Object); + expect(received[74]).toBe(Object); + expect(received[75]).toBe(Swag); + expect(received[76]).toBe(Swag); + expect(received[77]).toBe(Object); + expect(received[78]).toBe(Object); + expect(received[79]).toBe(Swag); + expect(received[80]).toBe(Swag); + expect(received[81]).toBe(Object); + expect(received[82]).toBe(Object); + expect(received[83]).toBe(Object); + expect(received[84]).toBe(Object); + expect(received[85]).toBe(Object); + expect(received[86]).toBe(Object); + expect(received[87]).toBe(void 0); + expect(received[88]).toBe(void 0); + expect(received[89]).toBe(void 0); + expect(received[90]).toBe(void 0); + expect(received[91]).toBe(void 0); + expect(received[92]).toBe(void 0); + expect(received[93]).toBe(void 0); + expect(received[94]).toBe(void 0); + expect(received[95]).toBe(Object); + expect(received[96]).toBe(void 0); + expect(received[97]).toBe(Object); + expect(received[98]).toBe(Object); + expect(received[99]).toBe(void 0); + expect(received[100]).toBe(void 0); + expect(received[101]).toBe(void 0); + expect(received[102]).toBe(void 0); + expect(received[103]).toBe(void 0); + expect(received[104]).toBe(void 0); + expect(received[105]).toBe(void 0); + expect(received[106]).toBe(void 0); + expect(received[107]).toBe(Object); + expect(received[108]).toBe(Object); + expect(received[109]).toBe(Object); + expect(received[110]).toBe(Object); + expect(received[111]).toBe(Object); + expect(received[112]).toBe(Object); + expect(received[113]).toBe(Object); + expect(received[114]).toBe(Object); + expect(received[115]).toBe(Object); + expect(received[116]).toBe(Object); + expect(received[117]).toBe(Object); + expect(received[118]).toBe(Object); + expect(received[119]).toBe(Object); + expect(received[120]).toBe(void 0); + expect(received[121]).toBe(Object); + expect(received[122]).toBe(Object); + expect(received[123]).toBe(Object); + expect(received[124]).toBe(Object); + expect(received[125]).toBe(Object); + expect(received[126]).toBe(Object); + expect(received[127]).toBe(Object); + expect(received[128]).toBe(Object); + expect(received[129]).toBe(Object); + expect(received[130]).toBe(Object); + expect(received[131]).toBe(Object); + expect(received[132]).toBe(Object); + expect(received[133]).toBe(Object); + expect(received[134]).toBe(void 0); + expect(received[135]).toBe(void 0); + expect(received[136]).toBe(void 0); + expect(received[137]).toBe(void 0); + expect(received[138]).toBe(void 0); + expect(received[139]).toBe(void 0); + expect(received[140]).toBe(void 0); + expect(received[141]).toBe(void 0); + expect(received[142]).toBe(void 0); + expect(received[143]).toBe(void 0); + expect(received[144]).toBe(Object); + expect(received[145]).toBe(Object); + expect(received[146]).toBe(void 0); + expect(received[147]).toBe(void 0); + expect(received[148]).toBe(void 0); + expect(received[149]).toBe(void 0); + expect(received[150]).toBe(void 0); + expect(received[151]).toBe(void 0); + expect(received[152]).toBe(void 0); + expect(received[153]).toBe(void 0); + expect(received[154]).toBe(void 0); + expect(received[155]).toBe(Object); + expect(received[156]).toBe(Object); + expect(received[157]).toBe(Object); + expect(received[158]).toBe(void 0); + expect(received[159]).toBe(Object); + expect(received[160]).toBe(Object); + expect(received[161]).toBe(Object); + expect(received[162]).toBe(Object); + expect(received[163]).toBe(Object); + expect(received[164]).toBe(Object); + expect(received[165]).toBe(Object); + expect(received[166]).toBe(Object); + expect(received[167]).toBe(Object); + expect(received[168]).toBe(Object); + expect(received[169]).toBe(Object); + expect(received[170]).toBe(Object); + expect(received[171]).toBe(Boolean); + expect(received[172]).toBe(Object); + expect(received[173]).toBe(Object); + }); + test("design: type, paramtypes, returntype", () => { + function d1() {} + // @ts-ignore + @d1 + class A { + // @ts-ignore + constructor(@d1 arg1: string) {} + // @ts-ignore + @d1 + // @ts-ignore + method1(@d1 arg1: number): boolean { + return true; + } + // @ts-ignore + @d1 + prop1: () => {}; + // @ts-ignore + @d1 + prop2: "foo" = "foo"; + // @ts-ignore + @d1 + prop3: symbol; + } + + expect(Reflect.getMetadata("design:type", A)).toBeUndefined(); + expect(Reflect.getMetadata("design:paramtypes", A)[0]).toBe(String); + expect(Reflect.getMetadata("design:returntype", A)).toBeUndefined(); + + expect(Reflect.getMetadata("design:type", A.prototype)).toBeUndefined(); + expect(Reflect.getMetadata("design:paramtypes", A.prototype)).toBeUndefined(); + expect(Reflect.getMetadata("design:returntype", A.prototype)).toBeUndefined(); + + expect(Reflect.getMetadata("design:type", A.prototype.method1)).toBeUndefined(); + expect(Reflect.getMetadata("design:paramtypes", A.prototype.method1)).toBeUndefined(); + expect(Reflect.getMetadata("design:returntype", A.prototype.method1)).toBeUndefined(); + + expect(Reflect.getMetadata("design:type", A.prototype, "method1")).toBe(Function); + expect(Reflect.getMetadata("design:paramtypes", A.prototype, "method1")[0]).toBe(Number); + expect(Reflect.getMetadata("design:returntype", A.prototype, "method1")).toBe(Boolean); + + expect(Reflect.getMetadata("design:type", A.prototype, "prop1")).toBe(Function); + expect(Reflect.getMetadata("design:paramtypes", A.prototype, "prop1")).toBeUndefined(); + expect(Reflect.getMetadata("design:returntype", A.prototype, "prop1")).toBeUndefined(); + + expect(Reflect.getMetadata("design:type", A.prototype, "prop2")).toBe(String); + expect(Reflect.getMetadata("design:paramtypes", A.prototype, "prop2")).toBeUndefined(); + expect(Reflect.getMetadata("design:returntype", A.prototype, "prop2")).toBeUndefined(); + + expect(Reflect.getMetadata("design:type", A.prototype, "prop3")).toBe(Symbol); + expect(Reflect.getMetadata("design:paramtypes", A.prototype, "prop3")).toBeUndefined(); + expect(Reflect.getMetadata("design:returntype", A.prototype, "prop3")).toBeUndefined(); + }); + + test("class with only constructor argument decorators", () => { + function d1() {} + class A { + // @ts-ignore + constructor(@d1 arg1: string) {} + } + + expect(Reflect.getMetadata("design:type", A)).toBeUndefined(); + expect(Reflect.getMetadata("design:paramtypes", A)[0]).toBe(String); + expect(Reflect.getMetadata("design:returntype", A)).toBeUndefined(); + }); + + test("more types", () => { + type B = "hello" | "world"; + const b = 2; + const c = ["hello", "world"] as const; + type Loser = `hello ${B}`; // "hello hello" | "hello world" + function d1() {} + + class A { + constructor( + // @ts-ignore + @d1 p0: `hello ${B}`, + // @ts-ignore + p1: keyof Something, + p2: typeof b, + p3: readonly ["hello", "world"], + p4: typeof c, + p5: readonly [number, string], + // prettier-ignore + p6: (string | string), + // prettier-ignore + p7: (string & string), + p8: boolean extends true ? "a" : "b", + // @ts-ignore + p9: Loser extends Loser ? string : Foo, + p10: { [keyof in string]: number }, + // @ts-ignore + p11: blah extends blahblah ? number : void, + ) {} + + // @ts-ignore + @d1 + async method1() { + return true; + } + } + + const paramtypes = Reflect.getMetadata("design:paramtypes", A); + expect(paramtypes[0]).toBe(String); + expect(paramtypes[1]).toBe(Object); + expect(paramtypes[2]).toBe(Object); + expect(paramtypes[3]).toBe(Array); + expect(paramtypes[4]).toBe(Object); + expect(paramtypes[5]).toBe(Array); + expect(paramtypes[6]).toBe(String); + expect(paramtypes[7]).toBe(String); + expect(paramtypes[8]).toBe(String); + expect(paramtypes[9]).toBe(Object); + expect(paramtypes[10]).toBe(Object); + expect(paramtypes[11]).toBe(Object); + + expect(Reflect.getMetadata("design:returntype", A.prototype, "method1")).toBe(Promise); + }); +}); diff --git a/test/tsconfig.json b/test/tsconfig.json index af2af2bb5..d308b40b7 100644 --- a/test/tsconfig.json +++ b/test/tsconfig.json @@ -7,6 +7,7 @@ "moduleResolution": "bundler", "moduleDetection": "force", "allowImportingTsExtensions": true, + "experimentalDecorators": true, "noEmit": true, "composite": true, "strict": true, diff --git a/tsconfig.json b/tsconfig.json index e8b7322b4..b19b46d1f 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,6 +2,7 @@ "extends": "./tsconfig.base.json", "compilerOptions": { "experimentalDecorators": true, + "emitDecoratorMetadata": true, // "skipLibCheck": true, "allowJs": true }, -- cgit v1.2.3 From 365fc0d39ddfaed8683eb6ee75013a0fe3adcae2 Mon Sep 17 00:00:00 2001 From: dave caruso Date: Wed, 20 Sep 2023 21:31:57 -0400 Subject: implement `Module.prototype._compile` (#5840) --- src/bun.js/bindings/CommonJSModuleRecord.cpp | 58 ++++++++++++++++++++++++++ src/bun.js/bindings/ZigGlobalObject.h | 1 + src/bun.js/module_loader.zig | 4 +- test/js/node/module/node-module-module.test.js | 17 ++++++++ 4 files changed, 78 insertions(+), 2 deletions(-) (limited to 'src/bun.js/module_loader.zig') diff --git a/src/bun.js/bindings/CommonJSModuleRecord.cpp b/src/bun.js/bindings/CommonJSModuleRecord.cpp index 8fbb780a8..e4fb1939c 100644 --- a/src/bun.js/bindings/CommonJSModuleRecord.cpp +++ b/src/bun.js/bindings/CommonJSModuleRecord.cpp @@ -346,6 +346,63 @@ static JSValue createChildren(VM& vm, JSObject* object) return constructEmptyArray(object->globalObject(), nullptr, 0); } +JSC_DEFINE_HOST_FUNCTION(functionCommonJSModuleRecord_compile, (JSGlobalObject * globalObject, CallFrame* callframe)) +{ + auto* moduleObject = jsDynamicCast(callframe->thisValue()); + if (!moduleObject) { + return JSValue::encode(jsUndefined()); + } + + auto& vm = globalObject->vm(); + auto throwScope = DECLARE_THROW_SCOPE(vm); + + String sourceString = callframe->argument(0).toWTFString(globalObject); + RETURN_IF_EXCEPTION(throwScope, JSValue::encode({})); + + String filenameString = callframe->argument(1).toWTFString(globalObject); + RETURN_IF_EXCEPTION(throwScope, JSValue::encode({})); + + String wrappedString = makeString( + "(function(module,exports,require,__dirname,__filename){"_s, + sourceString, + "\n}).call($_BunCommonJSModule_$.module.exports, $_BunCommonJSModule_$.module, $_BunCommonJSModule_$.module.exports, ($_BunCommonJSModule_$.module.require = $_BunCommonJSModule_$.module.require.bind($_BunCommonJSModule_$.module), $_BunCommonJSModule_$.module.require.path = $_BunCommonJSModule_$.module.id, $_BunCommonJSModule_$.module.require.resolve = $_BunCommonJSModule_$.module.require.resolve.bind($_BunCommonJSModule_$.module.id), $_BunCommonJSModule_$.module.require), $_BunCommonJSModule_$.__dirname, $_BunCommonJSModule_$.__filename);"_s); + + SourceCode sourceCode = makeSource( + WTFMove(wrappedString), + SourceOrigin(URL::fileURLWithFileSystemPath(filenameString)), + JSC::SourceTaintedOrigin::Untainted, + filenameString, + WTF::TextPosition(), + JSC::SourceProviderSourceType::Program); + JSSourceCode* jsSourceCode = JSSourceCode::create(vm, WTFMove(sourceCode)); + moduleObject->sourceCode.set(vm, moduleObject, jsSourceCode); + + auto index = filenameString.reverseFind('/', filenameString.length()); + String dirnameString; + if (index != WTF::notFound) { + dirnameString = filenameString.substring(0, index); + } else { + dirnameString = "/"_s; + } + + WTF::NakedPtr exception; + evaluateCommonJSModuleOnce( + vm, + jsCast(globalObject), + moduleObject, + jsString(vm, dirnameString), + jsString(vm, filenameString), + exception); + + if (exception) { + throwException(globalObject, throwScope, exception.get()); + exception.clear(); + return JSValue::encode({}); + } + + return JSValue::encode(jsUndefined()); +} + static const struct HashTableValue JSCommonJSModulePrototypeTableValues[] = { { "children"_s, static_cast(PropertyAttribute::PropertyCallback | PropertyAttribute::DontEnum | 0), NoIntrinsic, { HashTableValue::LazyPropertyType, createChildren } }, { "filename"_s, static_cast(PropertyAttribute::CustomAccessor), NoIntrinsic, { HashTableValue::GetterSetterType, getterFilename, setterFilename } }, @@ -354,6 +411,7 @@ static const struct HashTableValue JSCommonJSModulePrototypeTableValues[] = { { "parent"_s, static_cast(PropertyAttribute::PropertyCallback | PropertyAttribute::DontEnum | 0), NoIntrinsic, { HashTableValue::LazyPropertyType, createParent } }, { "path"_s, static_cast(PropertyAttribute::CustomAccessor), NoIntrinsic, { HashTableValue::GetterSetterType, getterPath, setterPath } }, { "paths"_s, static_cast(PropertyAttribute::CustomAccessor), NoIntrinsic, { HashTableValue::GetterSetterType, getterPaths, setterPaths } }, + { "_compile"_s, static_cast(PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, functionCommonJSModuleRecord_compile, 2 } }, }; class JSCommonJSModulePrototype final : public JSC::JSNonFinalObject { diff --git a/src/bun.js/bindings/ZigGlobalObject.h b/src/bun.js/bindings/ZigGlobalObject.h index 031dc4a13..e27b3bffa 100644 --- a/src/bun.js/bindings/ZigGlobalObject.h +++ b/src/bun.js/bindings/ZigGlobalObject.h @@ -346,6 +346,7 @@ public: mutable WriteBarrier m_nodeModuleOverriddenResolveFilename; mutable WriteBarrier m_nextTickQueue; + // Value of $_BunCommonJSModule_$ mutable WriteBarrier m_BunCommonJSModuleValue; // mutable WriteBarrier m_JSBunDebuggerValue; diff --git a/src/bun.js/module_loader.zig b/src/bun.js/module_loader.zig index 135bd5e94..a54b42825 100644 --- a/src/bun.js/module_loader.zig +++ b/src/bun.js/module_loader.zig @@ -2143,7 +2143,7 @@ pub const ModuleLoader = struct { const path = Fs.Path.init(specifier); const loader = if (loader_ != ._none) - options.Loader.fromString(@tagName(loader_)).? + options.Loader.fromAPI(loader_) else jsc_vm.bundler.options.loaders.get(path.name.ext) orelse brk: { if (strings.eqlLong(specifier, jsc_vm.main, true)) { @@ -2162,7 +2162,7 @@ pub const ModuleLoader = struct { referrer_slice.slice(), specifier_ptr.*, path, - options.Loader.fromString(@tagName(loader)).?, + loader, &log, &virtual_source, ret, diff --git a/test/js/node/module/node-module-module.test.js b/test/js/node/module/node-module-module.test.js index e5e21c981..1363636ac 100644 --- a/test/js/node/module/node-module-module.test.js +++ b/test/js/node/module/node-module-module.test.js @@ -70,3 +70,20 @@ test("Overwriting _resolveFilename", () => { expect(stdout.toString().trim().endsWith("--pass--")).toBe(true); expect(exitCode).toBe(0); }); + +test("Module.prototype._compile", () => { + const module = new Module("module id goes here"); + const starting_exports = module.exports; + const r = module._compile( + "module.exports = { module, exports, require, __filename, __dirname }", + "/file/path/goes/here.js", + ); + expect(r).toBe(undefined); + expect(module.exports).not.toBe(starting_exports); + const { module: m, exports: e, require: req, __filename: fn, __dirname: dn } = module.exports; + expect(m).toBe(module); + expect(e).toBe(starting_exports); + expect(req).toBe(module.require); + expect(fn).toBe("/file/path/goes/here.js"); + expect(dn).toBe("/file/path/goes"); +}); -- cgit v1.2.3 From b7951511a3926b1ffe008c12ec712096cf53997f Mon Sep 17 00:00:00 2001 From: dave caruso Date: Wed, 20 Sep 2023 22:48:46 -0400 Subject: fix(run): interpret extensionless files as typescript (#5711) * test * gadsgsagdsa * add better err msg * r * oops * ok --- packages/bun-types/bun.d.ts | 4 ++++ src/bun.js/bindings/JSBuffer.lut.h | 4 ++-- src/bun.js/module_loader.zig | 23 +++++++++++++------- src/fs.zig | 9 +++++--- src/js/node/child_process.js | 2 +- src/js/out/InternalModuleRegistryConstants.h | 6 +++--- test.js | 1 + test/bun.lockb | Bin 163146 -> 162926 bytes test/cli/run/run-cjs.test.ts | 2 +- test/cli/run/run-extensionless.test.ts | 31 +++++++++++++++++++++++++++ test/js/third_party/yargs/package.json | 7 ++++++ test/js/third_party/yargs/yargs-cjs.test.js | 4 ++++ test/package.json | 2 +- 13 files changed, 76 insertions(+), 19 deletions(-) create mode 100644 test.js create mode 100644 test/cli/run/run-extensionless.test.ts create mode 100644 test/js/third_party/yargs/package.json create mode 100644 test/js/third_party/yargs/yargs-cjs.test.js (limited to 'src/bun.js/module_loader.zig') diff --git a/packages/bun-types/bun.d.ts b/packages/bun-types/bun.d.ts index f55ab0f03..35f206634 100644 --- a/packages/bun-types/bun.d.ts +++ b/packages/bun-types/bun.d.ts @@ -150,6 +150,10 @@ declare module "bun" { export function write( destination: BunFile | PathLike, input: Blob | TypedArray | ArrayBufferLike | string | BlobPart[], + options?: { + /** If writing to a PathLike, set the permissions of the file. */ + mode?: number; + }, ): Promise; /** diff --git a/src/bun.js/bindings/JSBuffer.lut.h b/src/bun.js/bindings/JSBuffer.lut.h index 47e8cb984..35a3acea9 100644 --- a/src/bun.js/bindings/JSBuffer.lut.h +++ b/src/bun.js/bindings/JSBuffer.lut.h @@ -37,8 +37,8 @@ static const struct CompactHashIndex jsBufferConstructorTableIndex[33] = { static const struct HashTableValue jsBufferConstructorTableValues[10] = { { "alloc"_s, static_cast(PropertyAttribute::Constructable|PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsBufferConstructorFunction_alloc, 1 } }, - { "allocUnsafe"_s, static_cast(PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsBufferConstructorFunction_allocUnsafe, 1 } }, - { "allocUnsafeSlow"_s, static_cast(PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsBufferConstructorFunction_allocUnsafeSlow, 1 } }, + { "allocUnsafe"_s, static_cast(PropertyAttribute::Constructable|PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsBufferConstructorFunction_allocUnsafe, 1 } }, + { "allocUnsafeSlow"_s, static_cast(PropertyAttribute::Constructable|PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsBufferConstructorFunction_allocUnsafeSlow, 1 } }, { "byteLength"_s, static_cast(PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsBufferConstructorFunction_byteLength, 2 } }, { "compare"_s, static_cast(PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsBufferConstructorFunction_compare, 2 } }, { "concat"_s, static_cast(PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsBufferConstructorFunction_concat, 2 } }, diff --git a/src/bun.js/module_loader.zig b/src/bun.js/module_loader.zig index a54b42825..ca066450d 100644 --- a/src/bun.js/module_loader.zig +++ b/src/bun.js/module_loader.zig @@ -1937,14 +1937,21 @@ pub const ModuleLoader = struct { } } - const synchronous_loader = loader orelse - // Unknown extensions are to be treated as file loader - if (jsc_vm.has_loaded or jsc_vm.is_in_preload) - options.Loader.file - else - // Unless it's potentially the main module - // This is important so that "bun run ./foo-i-have-no-extension" works - options.Loader.js; + const synchronous_loader = loader orelse loader: { + if (jsc_vm.has_loaded or jsc_vm.is_in_preload) { + // Extensionless files in this context are treated as the JS loader + if (path.name.ext.len == 0) { + break :loader options.Loader.tsx; + } + + // Unknown extensions are to be treated as file loader + break :loader options.Loader.file; + } else { + // Unless it's potentially the main module + // This is important so that "bun run ./foo-i-have-no-extension" works + break :loader options.Loader.tsx; + } + }; var promise: ?*JSC.JSInternalPromise = null; ret.* = ErrorableResolvedSource.ok( diff --git a/src/fs.zig b/src/fs.zig index d062bd0c3..9c0114f49 100644 --- a/src/fs.zig +++ b/src/fs.zig @@ -1338,8 +1338,10 @@ pub const PathName = struct { base: string, dir: string, /// includes the leading . + /// extensionless files report "" ext: string, filename: string, + pub fn nonUniqueNameStringBase(self: *const PathName) string { // /bar/foo/index.js -> foo if (self.dir.len > 0 and strings.eqlComptime(self.base, "index")) { @@ -1398,7 +1400,7 @@ pub const PathName = struct { pub fn init(_path: string) PathName { var path = _path; var base = path; - var ext = path; + var ext: []const u8 = undefined; var dir = path; var is_absolute = true; @@ -1419,10 +1421,11 @@ pub const PathName = struct { } // Strip off the extension - var _dot = strings.lastIndexOfChar(base, '.'); - if (_dot) |dot| { + if (strings.lastIndexOfChar(base, '.')) |dot| { ext = base[dot..]; base = base[0..dot]; + } else { + ext = ""; } if (is_absolute) { diff --git a/src/js/node/child_process.js b/src/js/node/child_process.js index 859e01aa7..9da15389f 100644 --- a/src/js/node/child_process.js +++ b/src/js/node/child_process.js @@ -1298,7 +1298,7 @@ function nodeToBun(item) { return item; } else { const result = nodeToBunLookup[item]; - if (result === undefined) throw new Error("Invalid stdio option"); + if (result === undefined) throw new Error(`Invalid stdio option "${item}"`); return result; } } diff --git a/src/js/out/InternalModuleRegistryConstants.h b/src/js/out/InternalModuleRegistryConstants.h index f96dcec64..a4e1e29d6 100644 --- a/src/js/out/InternalModuleRegistryConstants.h +++ b/src/js/out/InternalModuleRegistryConstants.h @@ -42,7 +42,7 @@ static constexpr ASCIILiteral NodeAsyncHooksCode = "(function (){\"use strict\"; // // -static constexpr ASCIILiteral NodeChildProcessCode = "(function (){\"use strict\";// src/js/out/tmp/node/child_process.ts\nvar spawn = function(file, args, options) {\n options = normalizeSpawnArguments(file, args, options), validateTimeout(options.timeout), validateAbortSignal(options.signal, \"options.signal\");\n const killSignal2 = sanitizeKillSignal(options.killSignal), child = new ChildProcess;\n if (child.spawn(options), options.timeout > 0) {\n let timeoutId = setTimeout(() => {\n if (timeoutId) {\n try {\n child.kill(killSignal2);\n } catch (err) {\n child.emit(\"error\", err);\n }\n timeoutId = null;\n }\n });\n child.once(\"exit\", () => {\n if (timeoutId)\n clearTimeout(timeoutId), timeoutId = null;\n });\n }\n if (options.signal) {\n let onAbortListener2 = function() {\n abortChildProcess(child, killSignal2, options.signal.reason);\n };\n var onAbortListener = onAbortListener2;\n const signal = options.signal;\n if (signal.aborted)\n process.nextTick(onAbortListener2);\n else\n signal.addEventListener(\"abort\", onAbortListener2, { once: !0 }), child.once(\"exit\", () => signal.removeEventListener(\"abort\", onAbortListener2));\n }\n return child;\n}, execFile = function(file, args, options, callback) {\n ({ file, args, options, callback } = normalizeExecFileArgs(file, args, options, callback)), options = {\n encoding: \"utf8\",\n timeout: 0,\n maxBuffer: MAX_BUFFER,\n killSignal: \"SIGTERM\",\n cwd: null,\n env: null,\n shell: !1,\n ...options\n };\n const maxBuffer = options.maxBuffer;\n validateTimeout(options.timeout), validateMaxBuffer(maxBuffer), options.killSignal = sanitizeKillSignal(options.killSignal);\n const child = spawn(file, args, {\n cwd: options.cwd,\n env: options.env,\n shell: options.shell,\n signal: options.signal\n });\n let encoding;\n const _stdout = [], _stderr = [];\n if (options.encoding !== \"buffer\" && BufferIsEncoding(options.encoding))\n encoding = options.encoding;\n else\n encoding = null;\n let stdoutLen = 0, stderrLen = 0, killed = !1, exited = !1, timeoutId, encodedStdoutLen, encodedStderrLen, ex = null, cmd = file;\n function exitHandler(code, signal) {\n if (exited)\n return;\n if (exited = !0, timeoutId)\n clearTimeout(timeoutId), timeoutId = null;\n if (!callback)\n return;\n const readableEncoding = child\?.stdout\?.readableEncoding;\n let stdout, stderr;\n if (encoding || child.stdout && readableEncoding)\n stdout = ArrayPrototypeJoin.call(_stdout, \"\");\n else\n stdout = BufferConcat(_stdout);\n if (encoding || child.stderr && readableEncoding)\n stderr = ArrayPrototypeJoin.call(_stderr, \"\");\n else\n stderr = BufferConcat(_stderr);\n if (!ex && code === 0 && signal === null) {\n callback(null, stdout, stderr);\n return;\n }\n if (args\?.length)\n cmd += ` ${ArrayPrototypeJoin.call(args, \" \")}`;\n if (!ex) {\n let message = `Command failed: ${cmd}`;\n if (stderr)\n message += `\\n${stderr}`;\n ex = genericNodeError(message, {\n code,\n killed: child.killed || killed,\n signal\n });\n }\n ex.cmd = cmd, callback(ex, stdout, stderr);\n }\n function errorHandler(e) {\n if (ex = e, child.stdout)\n child.stdout.destroy();\n if (child.stderr)\n child.stderr.destroy();\n exitHandler();\n }\n function kill() {\n if (child.stdout)\n child.stdout.destroy();\n if (child.stderr)\n child.stderr.destroy();\n killed = !0;\n try {\n child.kill(options.killSignal);\n } catch (e) {\n ex = e, exitHandler();\n }\n }\n if (options.timeout > 0)\n timeoutId = setTimeout(function delayedKill() {\n kill(), timeoutId = null;\n }, options.timeout);\n if (child.stdout) {\n if (encoding)\n child.stdout.setEncoding(encoding);\n child.stdout.on(\"data\", maxBuffer === @Infinity \? function onUnlimitedSizeBufferedData(chunk) {\n ArrayPrototypePush.call(_stdout, chunk);\n } : encoding \? function onChildStdoutEncoded(chunk) {\n if (stdoutLen += chunk.length, stdoutLen * 4 > maxBuffer) {\n const encoding2 = child.stdout.readableEncoding, actualLen = @Buffer.byteLength(chunk, encoding2);\n if (encodedStdoutLen === @undefined)\n for (let i = 0;i < _stdout.length; i++)\n encodedStdoutLen += @Buffer.byteLength(_stdout[i], encoding2);\n else\n encodedStdoutLen += actualLen;\n const truncatedLen = maxBuffer - (encodedStdoutLen - actualLen);\n ArrayPrototypePush.call(_stdout, StringPrototypeSlice.apply(chunk, 0, truncatedLen)), ex = new ERR_CHILD_PROCESS_STDIO_MAXBUFFER(\"stdout\"), kill();\n } else\n ArrayPrototypePush.call(_stdout, chunk);\n } : function onChildStdoutRaw(chunk) {\n if (stdoutLen += chunk.length, stdoutLen > maxBuffer) {\n const truncatedLen = maxBuffer - (stdoutLen - chunk.length);\n ArrayPrototypePush.call(_stdout, chunk.slice(0, truncatedLen)), ex = new ERR_CHILD_PROCESS_STDIO_MAXBUFFER(\"stdout\"), kill();\n } else\n ArrayPrototypePush.call(_stdout, chunk);\n });\n }\n if (child.stderr) {\n if (encoding)\n child.stderr.setEncoding(encoding);\n child.stderr.on(\"data\", maxBuffer === @Infinity \? function onUnlimitedSizeBufferedData(chunk) {\n ArrayPrototypePush.call(_stderr, chunk);\n } : encoding \? function onChildStderrEncoded(chunk) {\n if (stderrLen += chunk.length, stderrLen * 4 > maxBuffer) {\n const encoding2 = child.stderr.readableEncoding, actualLen = @Buffer.byteLength(chunk, encoding2);\n if (encodedStderrLen === @undefined)\n for (let i = 0;i < _stderr.length; i++)\n encodedStderrLen += @Buffer.byteLength(_stderr[i], encoding2);\n else\n encodedStderrLen += actualLen;\n const truncatedLen = maxBuffer - (encodedStderrLen - actualLen);\n ArrayPrototypePush.call(_stderr, StringPrototypeSlice.call(chunk, 0, truncatedLen)), ex = new ERR_CHILD_PROCESS_STDIO_MAXBUFFER(\"stderr\"), kill();\n } else\n ArrayPrototypePush.call(_stderr, chunk);\n } : function onChildStderrRaw(chunk) {\n if (stderrLen += chunk.length, stderrLen > maxBuffer) {\n const truncatedLen = maxBuffer - (stderrLen - chunk.length);\n ArrayPrototypePush.call(_stderr, StringPrototypeSlice.call(chunk, 0, truncatedLen)), ex = new ERR_CHILD_PROCESS_STDIO_MAXBUFFER(\"stderr\"), kill();\n } else\n ArrayPrototypePush.call(_stderr, chunk);\n });\n }\n return child.addListener(\"close\", exitHandler), child.addListener(\"error\", errorHandler), child;\n}, exec = function(command, options, callback) {\n const opts = normalizeExecArgs(command, options, callback);\n return execFile(opts.file, opts.options, opts.callback);\n}, spawnSync = function(file, args, options) {\n options = {\n maxBuffer: MAX_BUFFER,\n ...normalizeSpawnArguments(file, args, options)\n };\n const { maxBuffer, encoding } = options;\n validateTimeout(options.timeout), validateMaxBuffer(maxBuffer), options.killSignal = sanitizeKillSignal(options.killSignal);\n const stdio = options.stdio || \"pipe\", bunStdio = getBunStdioFromOptions(stdio);\n var { input } = options;\n if (input)\n if (ArrayBufferIsView(input))\n bunStdio[0] = input;\n else if (typeof input === \"string\")\n bunStdio[0] = @Buffer.from(input, encoding || \"utf8\");\n else\n throw new ERR_INVALID_ARG_TYPE(\"options.stdio[0]\", [\"Buffer\", \"TypedArray\", \"DataView\", \"string\"], input);\n const { stdout, stderr, success, exitCode } = Bun.spawnSync({\n cmd: options.args,\n env: options.env || @undefined,\n cwd: options.cwd || @undefined,\n stdin: bunStdio[0],\n stdout: bunStdio[1],\n stderr: bunStdio[2]\n }), result = {\n signal: null,\n status: exitCode,\n output: [null, stdout, stderr]\n };\n if (stdout && encoding && encoding !== \"buffer\")\n result.output[1] = result.output[1]\?.toString(encoding);\n if (stderr && encoding && encoding !== \"buffer\")\n result.output[2] = result.output[2]\?.toString(encoding);\n if (result.stdout = result.output[1], result.stderr = result.output[2], !success)\n result.error = new SystemError(result.output[2], options.file, \"spawnSync\", -1, result.status), result.error.spawnargs = ArrayPrototypeSlice.call(options.args, 1);\n return result;\n}, execFileSync = function(file, args, options) {\n ({ file, args, options } = normalizeExecFileArgs(file, args, options));\n const ret = spawnSync(file, args, options), errArgs = [options.argv0 || file];\n ArrayPrototypePush.apply(errArgs, args);\n const err = checkExecSyncError(ret, errArgs);\n if (err)\n throw err;\n return ret.stdout;\n}, execSync = function(command, options) {\n const opts = normalizeExecArgs(command, options, null), ret = spawnSync(opts.file, opts.options), err = checkExecSyncError(ret, @undefined, command);\n if (err)\n throw err;\n return ret.stdout;\n}, stdioStringToArray = function(stdio, channel) {\n const options = [];\n switch (stdio) {\n case \"ignore\":\n case \"overlapped\":\n case \"pipe\":\n ArrayPrototypePush.call(options, stdio, stdio, stdio);\n break;\n case \"inherit\":\n ArrayPrototypePush.call(options, 0, 1, 2);\n break;\n default:\n throw new ERR_INVALID_ARG_VALUE(\"stdio\", stdio);\n }\n if (channel)\n ArrayPrototypePush.call(options, channel);\n return options;\n}, fork = function(modulePath, args = [], options) {\n modulePath = getValidatedPath(modulePath, \"modulePath\");\n let execArgv;\n if (args == null)\n args = [];\n else if (typeof args === \"object\" && !ArrayIsArray(args))\n options = args, args = [];\n else\n validateArray(args, \"args\");\n if (options != null)\n validateObject(options, \"options\");\n if (options = { __proto__: null, ...options, shell: !1 }, options.execPath = options.execPath || process.execPath, validateArgumentNullCheck(options.execPath, \"options.execPath\"), execArgv = options.execArgv || process.execArgv, validateArgumentsNullCheck(execArgv, \"options.execArgv\"), execArgv === process.execArgv && process._eval != null) {\n const index = ArrayPrototypeLastIndexOf.call(execArgv, process._eval);\n if (index > 0)\n execArgv = ArrayPrototypeSlice.call(execArgv), ArrayPrototypeSplice.call(execArgv, index - 1, 2);\n }\n if (args = [...execArgv, modulePath, ...args], typeof options.stdio === \"string\")\n options.stdio = stdioStringToArray(options.stdio, \"ipc\");\n else if (!ArrayIsArray(options.stdio))\n options.stdio = stdioStringToArray(options.silent \? \"pipe\" : \"inherit\", \"ipc\");\n else if (!ArrayPrototypeIncludes.call(options.stdio, \"ipc\"))\n throw new ERR_CHILD_PROCESS_IPC_REQUIRED(\"options.stdio\");\n return spawn(options.execPath, args, options);\n}, convertToValidSignal = function(signal) {\n if (typeof signal === \"number\" && getSignalsToNamesMapping()[signal])\n return signal;\n if (typeof signal === \"string\") {\n const signalName = signals[StringPrototypeToUpperCase.call(signal)];\n if (signalName)\n return signalName;\n }\n throw new ERR_UNKNOWN_SIGNAL(signal);\n}, sanitizeKillSignal = function(killSignal2) {\n if (typeof killSignal2 === \"string\" || typeof killSignal2 === \"number\")\n return convertToValidSignal(killSignal2);\n else if (killSignal2 != null)\n throw new ERR_INVALID_ARG_TYPE(\"options.killSignal\", [\"string\", \"number\"], killSignal2);\n}, getSignalsToNamesMapping = function() {\n if (signalsToNamesMapping !== @undefined)\n return signalsToNamesMapping;\n signalsToNamesMapping = ObjectCreate(null);\n for (let key in signals)\n signalsToNamesMapping[signals[key]] = key;\n return signalsToNamesMapping;\n}, normalizeExecFileArgs = function(file, args, options, callback) {\n if (ArrayIsArray(args))\n args = ArrayPrototypeSlice.call(args);\n else if (args != null && typeof args === \"object\")\n callback = options, options = args, args = null;\n else if (typeof args === \"function\")\n callback = args, options = null, args = null;\n if (args == null)\n args = [];\n if (typeof options === \"function\")\n callback = options;\n else if (options != null)\n validateObject(options, \"options\");\n if (options == null)\n options = kEmptyObject;\n if (callback != null)\n validateFunction(callback, \"callback\");\n if (options.argv0 != null)\n validateString(options.argv0, \"options.argv0\"), validateArgumentNullCheck(options.argv0, \"options.argv0\");\n return { file, args, options, callback };\n}, normalizeExecArgs = function(command, options, callback) {\n if (validateString(command, \"command\"), validateArgumentNullCheck(command, \"command\"), typeof options === \"function\")\n callback = options, options = @undefined;\n return options = { ...options }, options.shell = typeof options.shell === \"string\" \? options.shell : !0, {\n file: command,\n options,\n callback\n };\n}, normalizeSpawnArguments = function(file, args, options) {\n if (validateString(file, \"file\"), validateArgumentNullCheck(file, \"file\"), file.length === 0)\n throw new ERR_INVALID_ARG_VALUE(\"file\", file, \"cannot be empty\");\n if (ArrayIsArray(args))\n args = ArrayPrototypeSlice.call(args);\n else if (args == null)\n args = [];\n else if (typeof args !== \"object\")\n throw new ERR_INVALID_ARG_TYPE(\"args\", \"object\", args);\n else\n options = args, args = [];\n if (validateArgumentsNullCheck(args, \"args\"), options === @undefined)\n options = {};\n else\n validateObject(options, \"options\");\n let cwd = options.cwd;\n if (cwd != null)\n cwd = getValidatedPath(cwd, \"options.cwd\");\n var detached = !1;\n const { detached: detachedOption } = options;\n if (detachedOption != null)\n detached = !!detachedOption;\n if (options.shell != null && typeof options.shell !== \"boolean\" && typeof options.shell !== \"string\")\n throw new ERR_INVALID_ARG_TYPE(\"options.shell\", [\"boolean\", \"string\"], options.shell);\n if (options.argv0 != null)\n validateString(options.argv0, \"options.argv0\"), validateArgumentNullCheck(options.argv0, \"options.argv0\");\n if (options.shell) {\n validateArgumentNullCheck(options.shell, \"options.shell\");\n const command = ArrayPrototypeJoin.call([file, ...args], \" \");\n if (typeof options.shell === \"string\")\n file = options.shell;\n else\n file = \"sh\";\n args = [\"-c\", command];\n }\n if (typeof options.argv0 === \"string\")\n ArrayPrototypeUnshift.call(args, options.argv0);\n else\n ArrayPrototypeUnshift.call(args, file);\n const envPairs = options.env || process.env;\n return { ...options, detached, file, args, cwd, envPairs };\n}, checkExecSyncError = function(ret, args, cmd) {\n let err;\n if (ret.error)\n err = ret.error, ObjectAssign(err, ret);\n else if (ret.status !== 0) {\n let msg = \"Command failed: \";\n if (msg += cmd || ArrayPrototypeJoin.call(args, \" \"), ret.stderr && ret.stderr.length > 0)\n msg += `\\n${ret.stderr.toString()}`;\n err = genericNodeError(msg, ret);\n }\n return err;\n}, nodeToBun = function(item) {\n if (typeof item === \"number\")\n return item;\n else {\n const result = nodeToBunLookup[item];\n if (result === @undefined)\n throw new Error(\"Invalid stdio option\");\n return result;\n }\n}, fdToStdioName = function(fd) {\n switch (fd) {\n case 0:\n return \"stdin\";\n case 1:\n return \"stdout\";\n case 2:\n return \"stderr\";\n default:\n return null;\n }\n}, getBunStdioFromOptions = function(stdio) {\n return normalizeStdio(stdio).map((item) => nodeToBun(item));\n}, normalizeStdio = function(stdio) {\n if (typeof stdio === \"string\")\n switch (stdio) {\n case \"ignore\":\n return [\"ignore\", \"ignore\", \"ignore\"];\n case \"pipe\":\n return [\"pipe\", \"pipe\", \"pipe\"];\n case \"inherit\":\n return [\"inherit\", \"inherit\", \"inherit\"];\n default:\n throw new ERR_INVALID_OPT_VALUE(\"stdio\", stdio);\n }\n else if (ArrayIsArray(stdio)) {\n let processedStdio;\n if (stdio.length === 0)\n processedStdio = [\"pipe\", \"pipe\", \"pipe\"];\n else if (stdio.length === 1)\n processedStdio = [stdio[0], \"pipe\", \"pipe\"];\n else if (stdio.length === 2)\n processedStdio = [stdio[0], stdio[1], \"pipe\"];\n else if (stdio.length >= 3)\n processedStdio = [stdio[0], stdio[1], stdio[2]];\n return processedStdio.map((item) => !item \? \"pipe\" : item);\n } else\n throw new ERR_INVALID_OPT_VALUE(\"stdio\", stdio);\n}, flushStdio = function(subprocess) {\n const stdio = subprocess.stdio;\n if (stdio == null)\n return;\n for (let i = 0;i < stdio.length; i++) {\n const stream = stdio[i];\n if (!stream || !stream.readable)\n continue;\n stream.resume();\n }\n}, onSpawnNT = function(self) {\n self.emit(\"spawn\");\n}, abortChildProcess = function(child, killSignal2, reason) {\n if (!child)\n return;\n try {\n if (child.kill(killSignal2))\n child.emit(\"error\", new AbortError(@undefined, { cause: reason }));\n } catch (err) {\n child.emit(\"error\", err);\n }\n}, validateMaxBuffer = function(maxBuffer) {\n if (maxBuffer != null && !(typeof maxBuffer === \"number\" && maxBuffer >= 0))\n throw new ERR_OUT_OF_RANGE(\"options.maxBuffer\", \"a positive number\", maxBuffer);\n}, validateArgumentNullCheck = function(arg, propName) {\n if (typeof arg === \"string\" && StringPrototypeIncludes.call(arg, \"\\0\"))\n throw new ERR_INVALID_ARG_VALUE(propName, arg, \"must be a string without null bytes\");\n}, validateArgumentsNullCheck = function(args, propName) {\n for (let i = 0;i < args.length; ++i)\n validateArgumentNullCheck(args[i], `${propName}[${i}]`);\n}, validateTimeout = function(timeout) {\n if (timeout != null && !(NumberIsInteger(timeout) && timeout >= 0))\n throw new ERR_OUT_OF_RANGE(\"timeout\", \"an unsigned integer\", timeout);\n};\nvar validateFunction = function(value, name) {\n if (typeof value !== \"function\")\n throw new ERR_INVALID_ARG_TYPE(name, \"Function\", value);\n}, validateString = function(value, name) {\n if (typeof value !== \"string\")\n throw new ERR_INVALID_ARG_TYPE(name, \"string\", value);\n}, nullCheck = function(path, propName, throwError = !0) {\n const pathIsString = typeof path === \"string\", pathIsUint8Array = isUint8Array(path);\n if (!pathIsString && !pathIsUint8Array || pathIsString && !StringPrototypeIncludes.call(path, \"\\0\") || pathIsUint8Array && !Uint8ArrayPrototypeIncludes.call(path, 0))\n return;\n const err = new ERR_INVALID_ARG_VALUE(propName, path, \"must be a string or Uint8Array without null bytes\");\n if (throwError)\n throw err;\n return err;\n}, validatePath = function(path, propName = \"path\") {\n if (typeof path !== \"string\" && !isUint8Array(path))\n throw new ERR_INVALID_ARG_TYPE(propName, [\"string\", \"Buffer\", \"URL\"], path);\n const err = nullCheck(path, propName, !1);\n if (err !== @undefined)\n throw err;\n}, getValidatedPath = function(fileURLOrPath, propName = \"path\") {\n const path = toPathIfFileURL(fileURLOrPath);\n return validatePath(path, propName), path;\n}, isUint8Array = function(value) {\n return typeof value === \"object\" && value !== null && value instanceof @Uint8Array;\n}, isURLInstance = function(fileURLOrPath) {\n return fileURLOrPath != null && fileURLOrPath.href && fileURLOrPath.origin;\n}, toPathIfFileURL = function(fileURLOrPath) {\n if (!isURLInstance(fileURLOrPath))\n return fileURLOrPath;\n return Bun.fileURLToPath(fileURLOrPath);\n}, genericNodeError = function(message, options) {\n const err = new Error(message);\n return err.code = options.code, err.killed = options.killed, err.signal = options.signal, err;\n}, ERR_OUT_OF_RANGE = function(str, range, input, replaceDefaultBoolean = !1) {\n return new RangeError(`The value of ${str} is out of range. It must be ${range}. Received ${input}`);\n}, ERR_CHILD_PROCESS_STDIO_MAXBUFFER = function(stdio) {\n return Error(`${stdio} maxBuffer length exceeded`);\n}, ERR_UNKNOWN_SIGNAL = function(name) {\n const err = @makeTypeError(`Unknown signal: ${name}`);\n return err.code = \"ERR_UNKNOWN_SIGNAL\", err;\n}, ERR_INVALID_ARG_TYPE = function(name, type, value) {\n const err = @makeTypeError(`The \"${name}\" argument must be of type ${type}. Received ${value\?.toString()}`);\n return err.code = \"ERR_INVALID_ARG_TYPE\", err;\n}, ERR_INVALID_OPT_VALUE = function(name, value) {\n return @makeTypeError(`The value \"${value}\" is invalid for option \"${name}\"`);\n}, ERR_INVALID_ARG_VALUE = function(name, value, reason) {\n return new Error(`The value \"${value}\" is invalid for argument '${name}'. Reason: ${reason}`);\n}, ERR_CHILD_PROCESS_IPC_REQUIRED = function(name) {\n const err = @makeTypeError(`Forked processes must have an IPC channel, missing value 'ipc' in ${name}`);\n return err.code = \"ERR_CHILD_PROCESS_IPC_REQUIRED\", err;\n}, $, EventEmitter = @getInternalField(@internalModuleRegistry, 18) || @createInternalModuleById(18), StreamModule = @getInternalField(@internalModuleRegistry, 37) || @createInternalModuleById(37), {\n constants: { signals }\n} = @getInternalField(@internalModuleRegistry, 26) || @createInternalModuleById(26), { promisify } = @getInternalField(@internalModuleRegistry, 46) || @createInternalModuleById(46), ObjectCreate = Object.create, ObjectAssign = Object.assign, ObjectDefineProperty = Object.defineProperty, BufferConcat = @Buffer.concat, BufferIsEncoding = @Buffer.isEncoding, kEmptyObject = ObjectCreate(null), ArrayPrototypePush = @Array.prototype.push, ArrayPrototypeJoin = @Array.prototype.join, ArrayPrototypeMap = @Array.prototype.map, ArrayPrototypeIncludes = @Array.prototype.includes, ArrayPrototypeSlice = @Array.prototype.slice, ArrayPrototypeUnshift = @Array.prototype.unshift, ArrayPrototypeLastIndexOf = @Array.prototype.lastIndexOf, ArrayPrototypeSplice = @Array.prototype.splice, ArrayIsArray = @Array.isArray, ArrayBufferIsView = @ArrayBuffer.isView, NumberIsInteger = Number.isInteger;\nvar StringPrototypeToUpperCase = @String.prototype.toUpperCase, StringPrototypeIncludes = @String.prototype.includes, StringPrototypeSlice = @String.prototype.slice, Uint8ArrayPrototypeIncludes = @Uint8Array.prototype.includes, MAX_BUFFER = 1048576, NativeWritable, ReadableFromWeb, customPromiseExecFunction = (orig) => {\n return (...args) => {\n let resolve, reject;\n const promise = new @Promise((res, rej) => {\n resolve = res, reject = rej;\n });\n return promise.child = orig(...args, (err, stdout, stderr) => {\n if (err !== null)\n err.stdout = stdout, err.stderr = stderr, reject(err);\n else\n resolve({ stdout, stderr });\n }), promise;\n };\n};\nObjectDefineProperty(exec, promisify.custom, {\n __proto__: null,\n enumerable: !1,\n value: customPromiseExecFunction(exec)\n});\nvar signalsToNamesMapping;\n\nclass ChildProcess extends EventEmitter {\n constructor() {\n super(...arguments);\n }\n #handle;\n #exited = !1;\n #closesNeeded = 1;\n #closesGot = 0;\n connected = !1;\n signalCode = null;\n exitCode = null;\n spawnfile;\n spawnargs;\n pid;\n channel;\n get killed() {\n if (this.#handle == null)\n return !1;\n }\n #handleOnExit(exitCode, signalCode, err) {\n if (this.#exited)\n return;\n if (signalCode)\n this.signalCode = signalCode;\n else\n this.exitCode = exitCode;\n if (this.#stdin)\n this.#stdin.destroy();\n if (this.#handle)\n this.#handle = null;\n if (exitCode < 0) {\n const err2 = new SystemError(`Spawned process exited with error code: ${exitCode}`, @undefined, \"spawn\", \"EUNKNOWN\", \"ERR_CHILD_PROCESS_UNKNOWN_ERROR\");\n if (this.spawnfile)\n err2.path = this.spawnfile;\n err2.spawnargs = ArrayPrototypeSlice.call(this.spawnargs, 1), this.emit(\"error\", err2);\n } else\n this.emit(\"exit\", this.exitCode, this.signalCode);\n process.nextTick(flushStdio, this), this.#maybeClose(), this.#exited = !0, this.#stdioOptions = [\"destroyed\", \"destroyed\", \"destroyed\"];\n }\n #getBunSpawnIo(i, encoding) {\n NativeWritable ||= StreamModule.NativeWritable, ReadableFromWeb ||= StreamModule.Readable.fromWeb;\n const io = this.#stdioOptions[i];\n switch (i) {\n case 0:\n switch (io) {\n case \"pipe\":\n return new NativeWritable(this.#handle.stdin);\n case \"inherit\":\n return process.stdin || null;\n case \"destroyed\":\n return new ShimmedStdin;\n default:\n return null;\n }\n case 2:\n case 1:\n switch (io) {\n case \"pipe\":\n return ReadableFromWeb(this.#handle[fdToStdioName(i)], { encoding });\n case \"inherit\":\n return process[fdToStdioName(i)] || null;\n case \"destroyed\":\n return new ShimmedStdioOutStream;\n default:\n return null;\n }\n }\n }\n #stdin;\n #stdout;\n #stderr;\n #stdioObject;\n #encoding;\n #stdioOptions;\n #createStdioObject() {\n return Object.create(null, {\n 0: {\n get: () => this.stdin\n },\n 1: {\n get: () => this.stdout\n },\n 2: {\n get: () => this.stderr\n }\n });\n }\n get stdin() {\n return this.#stdin \?\?= this.#getBunSpawnIo(0, this.#encoding);\n }\n get stdout() {\n return this.#stdout \?\?= this.#getBunSpawnIo(1, this.#encoding);\n }\n get stderr() {\n return this.#stderr \?\?= this.#getBunSpawnIo(2, this.#encoding);\n }\n get stdio() {\n return this.#stdioObject \?\?= this.#createStdioObject();\n }\n spawn(options) {\n validateObject(options, \"options\"), validateString(options.file, \"options.file\");\n var file = this.spawnfile = options.file, spawnargs;\n if (options.args == null)\n spawnargs = this.spawnargs = [];\n else\n validateArray(options.args, \"options.args\"), spawnargs = this.spawnargs = options.args;\n const stdio = options.stdio || [\"pipe\", \"pipe\", \"pipe\"], bunStdio = getBunStdioFromOptions(stdio), ipc = @isArray(stdio) && stdio[3] === \"ipc\";\n var env = options.envPairs || @undefined;\n const detachedOption = options.detached;\n if (this.#encoding = options.encoding || @undefined, this.#stdioOptions = bunStdio, this.#handle = Bun.spawn({\n cmd: spawnargs,\n stdin: bunStdio[0],\n stdout: bunStdio[1],\n stderr: bunStdio[2],\n cwd: options.cwd || @undefined,\n env: env || process.env,\n detached: typeof detachedOption !== \"undefined\" \? !!detachedOption : !1,\n onExit: (handle, exitCode, signalCode, err) => {\n this.#handle = handle, this.pid = this.#handle.pid, process.nextTick((exitCode2, signalCode2, err2) => this.#handleOnExit(exitCode2, signalCode2, err2), exitCode, signalCode, err);\n },\n lazy: !0,\n ipc: ipc \? this.#emitIpcMessage.bind(this) : @undefined\n }), this.pid = this.#handle.pid, onSpawnNT(this), ipc)\n this.send = this.#send, this.disconnect = this.#disconnect;\n }\n #emitIpcMessage(message) {\n this.emit(\"message\", message);\n }\n #send(message, handle, options, callback) {\n if (typeof handle === \"function\")\n callback = handle, handle = @undefined, options = @undefined;\n else if (typeof options === \"function\")\n callback = options, options = @undefined;\n else if (options !== @undefined) {\n if (typeof options !== \"object\" || options === null)\n throw new ERR_INVALID_ARG_TYPE(\"options\", \"Object\", options);\n }\n if (!this.#handle) {\n if (callback)\n process.nextTick(callback, @makeTypeError(\"Process was closed while trying to send message\"));\n else\n this.emit(\"error\", @makeTypeError(\"Process was closed while trying to send message\"));\n return !1;\n }\n try {\n if (this.#handle.send(message), callback)\n process.nextTick(callback);\n return !0;\n } catch (error) {\n if (callback)\n process.nextTick(callback, error);\n else\n this.emit(\"error\", error);\n return !1;\n }\n }\n #disconnect() {\n if (!this.connected) {\n this.emit(\"error\", @makeTypeError(\"Process was closed while trying to send message\"));\n return;\n }\n this.connected = !1, this.#handle.disconnect();\n }\n kill(sig) {\n const signal = sig === 0 \? sig : convertToValidSignal(sig === @undefined \? \"SIGTERM\" : sig);\n if (this.#handle)\n this.#handle.kill(signal);\n return this.#maybeClose(), !0;\n }\n #maybeClose() {\n if (this.#closesGot++, this.#closesGot === this.#closesNeeded)\n this.emit(\"close\", this.exitCode, this.signalCode);\n }\n ref() {\n if (this.#handle)\n this.#handle.ref();\n }\n unref() {\n if (this.#handle)\n this.#handle.unref();\n }\n}\nvar nodeToBunLookup = {\n ignore: null,\n pipe: \"pipe\",\n overlapped: \"pipe\",\n inherit: \"inherit\"\n};\n\nclass ShimmedStdin extends EventEmitter {\n constructor() {\n super();\n }\n write() {\n return !1;\n }\n destroy() {\n }\n end() {\n }\n pipe() {\n }\n}\n\nclass ShimmedStdioOutStream extends EventEmitter {\n constructor() {\n super(...arguments);\n }\n pipe() {\n }\n}\nvar validateAbortSignal = (signal, name) => {\n if (signal !== @undefined && (signal === null || typeof signal !== \"object\" || !(\"aborted\" in signal)))\n throw new ERR_INVALID_ARG_TYPE(name, \"AbortSignal\", signal);\n};\nvar validateObject = (value, name, options = null) => {\n const allowArray = options\?.allowArray \?\? !1, allowFunction = options\?.allowFunction \?\? !1;\n if (!(options\?.nullable \?\? !1) && value === null || !allowArray && ArrayIsArray.call(value) || typeof value !== \"object\" && (!allowFunction || typeof value !== \"function\"))\n throw new ERR_INVALID_ARG_TYPE(name, \"object\", value);\n}, validateArray = (value, name, minLength = 0) => {\n if (!ArrayIsArray(value))\n throw new ERR_INVALID_ARG_TYPE(name, \"Array\", value);\n if (value.length < minLength) {\n const reason = `must be longer than ${minLength}`;\n throw new ERR_INVALID_ARG_VALUE(name, value, reason);\n }\n}, Error = globalThis.Error, TypeError = globalThis.TypeError, RangeError = globalThis.RangeError;\n\nclass AbortError extends Error {\n code = \"ABORT_ERR\";\n name = \"AbortError\";\n constructor(message = \"The operation was aborted\", options = @undefined) {\n if (options !== @undefined && typeof options !== \"object\")\n throw new ERR_INVALID_ARG_TYPE(\"options\", \"Object\", options);\n super(message, options);\n }\n}\n\nclass SystemError extends Error {\n path;\n syscall;\n errno;\n code;\n constructor(message, path, syscall, errno, code) {\n super(message);\n this.path = path, this.syscall = syscall, this.errno = errno, this.code = code;\n }\n get name() {\n return \"SystemError\";\n }\n}\n$ = {\n ChildProcess,\n spawn,\n execFile,\n exec,\n fork,\n spawnSync,\n execFileSync,\n execSync\n};\nreturn $})\n"_s; +static constexpr ASCIILiteral NodeChildProcessCode = "(function (){\"use strict\";// src/js/out/tmp/node/child_process.ts\nvar spawn = function(file, args, options) {\n options = normalizeSpawnArguments(file, args, options), validateTimeout(options.timeout), validateAbortSignal(options.signal, \"options.signal\");\n const killSignal2 = sanitizeKillSignal(options.killSignal), child = new ChildProcess;\n if (child.spawn(options), options.timeout > 0) {\n let timeoutId = setTimeout(() => {\n if (timeoutId) {\n try {\n child.kill(killSignal2);\n } catch (err) {\n child.emit(\"error\", err);\n }\n timeoutId = null;\n }\n });\n child.once(\"exit\", () => {\n if (timeoutId)\n clearTimeout(timeoutId), timeoutId = null;\n });\n }\n if (options.signal) {\n let onAbortListener2 = function() {\n abortChildProcess(child, killSignal2, options.signal.reason);\n };\n var onAbortListener = onAbortListener2;\n const signal = options.signal;\n if (signal.aborted)\n process.nextTick(onAbortListener2);\n else\n signal.addEventListener(\"abort\", onAbortListener2, { once: !0 }), child.once(\"exit\", () => signal.removeEventListener(\"abort\", onAbortListener2));\n }\n return child;\n}, execFile = function(file, args, options, callback) {\n ({ file, args, options, callback } = normalizeExecFileArgs(file, args, options, callback)), options = {\n encoding: \"utf8\",\n timeout: 0,\n maxBuffer: MAX_BUFFER,\n killSignal: \"SIGTERM\",\n cwd: null,\n env: null,\n shell: !1,\n ...options\n };\n const maxBuffer = options.maxBuffer;\n validateTimeout(options.timeout), validateMaxBuffer(maxBuffer), options.killSignal = sanitizeKillSignal(options.killSignal);\n const child = spawn(file, args, {\n cwd: options.cwd,\n env: options.env,\n shell: options.shell,\n signal: options.signal\n });\n let encoding;\n const _stdout = [], _stderr = [];\n if (options.encoding !== \"buffer\" && BufferIsEncoding(options.encoding))\n encoding = options.encoding;\n else\n encoding = null;\n let stdoutLen = 0, stderrLen = 0, killed = !1, exited = !1, timeoutId, encodedStdoutLen, encodedStderrLen, ex = null, cmd = file;\n function exitHandler(code, signal) {\n if (exited)\n return;\n if (exited = !0, timeoutId)\n clearTimeout(timeoutId), timeoutId = null;\n if (!callback)\n return;\n const readableEncoding = child\?.stdout\?.readableEncoding;\n let stdout, stderr;\n if (encoding || child.stdout && readableEncoding)\n stdout = ArrayPrototypeJoin.call(_stdout, \"\");\n else\n stdout = BufferConcat(_stdout);\n if (encoding || child.stderr && readableEncoding)\n stderr = ArrayPrototypeJoin.call(_stderr, \"\");\n else\n stderr = BufferConcat(_stderr);\n if (!ex && code === 0 && signal === null) {\n callback(null, stdout, stderr);\n return;\n }\n if (args\?.length)\n cmd += ` ${ArrayPrototypeJoin.call(args, \" \")}`;\n if (!ex) {\n let message = `Command failed: ${cmd}`;\n if (stderr)\n message += `\\n${stderr}`;\n ex = genericNodeError(message, {\n code,\n killed: child.killed || killed,\n signal\n });\n }\n ex.cmd = cmd, callback(ex, stdout, stderr);\n }\n function errorHandler(e) {\n if (ex = e, child.stdout)\n child.stdout.destroy();\n if (child.stderr)\n child.stderr.destroy();\n exitHandler();\n }\n function kill() {\n if (child.stdout)\n child.stdout.destroy();\n if (child.stderr)\n child.stderr.destroy();\n killed = !0;\n try {\n child.kill(options.killSignal);\n } catch (e) {\n ex = e, exitHandler();\n }\n }\n if (options.timeout > 0)\n timeoutId = setTimeout(function delayedKill() {\n kill(), timeoutId = null;\n }, options.timeout);\n if (child.stdout) {\n if (encoding)\n child.stdout.setEncoding(encoding);\n child.stdout.on(\"data\", maxBuffer === @Infinity \? function onUnlimitedSizeBufferedData(chunk) {\n ArrayPrototypePush.call(_stdout, chunk);\n } : encoding \? function onChildStdoutEncoded(chunk) {\n if (stdoutLen += chunk.length, stdoutLen * 4 > maxBuffer) {\n const encoding2 = child.stdout.readableEncoding, actualLen = @Buffer.byteLength(chunk, encoding2);\n if (encodedStdoutLen === @undefined)\n for (let i = 0;i < _stdout.length; i++)\n encodedStdoutLen += @Buffer.byteLength(_stdout[i], encoding2);\n else\n encodedStdoutLen += actualLen;\n const truncatedLen = maxBuffer - (encodedStdoutLen - actualLen);\n ArrayPrototypePush.call(_stdout, StringPrototypeSlice.apply(chunk, 0, truncatedLen)), ex = new ERR_CHILD_PROCESS_STDIO_MAXBUFFER(\"stdout\"), kill();\n } else\n ArrayPrototypePush.call(_stdout, chunk);\n } : function onChildStdoutRaw(chunk) {\n if (stdoutLen += chunk.length, stdoutLen > maxBuffer) {\n const truncatedLen = maxBuffer - (stdoutLen - chunk.length);\n ArrayPrototypePush.call(_stdout, chunk.slice(0, truncatedLen)), ex = new ERR_CHILD_PROCESS_STDIO_MAXBUFFER(\"stdout\"), kill();\n } else\n ArrayPrototypePush.call(_stdout, chunk);\n });\n }\n if (child.stderr) {\n if (encoding)\n child.stderr.setEncoding(encoding);\n child.stderr.on(\"data\", maxBuffer === @Infinity \? function onUnlimitedSizeBufferedData(chunk) {\n ArrayPrototypePush.call(_stderr, chunk);\n } : encoding \? function onChildStderrEncoded(chunk) {\n if (stderrLen += chunk.length, stderrLen * 4 > maxBuffer) {\n const encoding2 = child.stderr.readableEncoding, actualLen = @Buffer.byteLength(chunk, encoding2);\n if (encodedStderrLen === @undefined)\n for (let i = 0;i < _stderr.length; i++)\n encodedStderrLen += @Buffer.byteLength(_stderr[i], encoding2);\n else\n encodedStderrLen += actualLen;\n const truncatedLen = maxBuffer - (encodedStderrLen - actualLen);\n ArrayPrototypePush.call(_stderr, StringPrototypeSlice.call(chunk, 0, truncatedLen)), ex = new ERR_CHILD_PROCESS_STDIO_MAXBUFFER(\"stderr\"), kill();\n } else\n ArrayPrototypePush.call(_stderr, chunk);\n } : function onChildStderrRaw(chunk) {\n if (stderrLen += chunk.length, stderrLen > maxBuffer) {\n const truncatedLen = maxBuffer - (stderrLen - chunk.length);\n ArrayPrototypePush.call(_stderr, StringPrototypeSlice.call(chunk, 0, truncatedLen)), ex = new ERR_CHILD_PROCESS_STDIO_MAXBUFFER(\"stderr\"), kill();\n } else\n ArrayPrototypePush.call(_stderr, chunk);\n });\n }\n return child.addListener(\"close\", exitHandler), child.addListener(\"error\", errorHandler), child;\n}, exec = function(command, options, callback) {\n const opts = normalizeExecArgs(command, options, callback);\n return execFile(opts.file, opts.options, opts.callback);\n}, spawnSync = function(file, args, options) {\n options = {\n maxBuffer: MAX_BUFFER,\n ...normalizeSpawnArguments(file, args, options)\n };\n const { maxBuffer, encoding } = options;\n validateTimeout(options.timeout), validateMaxBuffer(maxBuffer), options.killSignal = sanitizeKillSignal(options.killSignal);\n const stdio = options.stdio || \"pipe\", bunStdio = getBunStdioFromOptions(stdio);\n var { input } = options;\n if (input)\n if (ArrayBufferIsView(input))\n bunStdio[0] = input;\n else if (typeof input === \"string\")\n bunStdio[0] = @Buffer.from(input, encoding || \"utf8\");\n else\n throw new ERR_INVALID_ARG_TYPE(\"options.stdio[0]\", [\"Buffer\", \"TypedArray\", \"DataView\", \"string\"], input);\n const { stdout, stderr, success, exitCode } = Bun.spawnSync({\n cmd: options.args,\n env: options.env || @undefined,\n cwd: options.cwd || @undefined,\n stdin: bunStdio[0],\n stdout: bunStdio[1],\n stderr: bunStdio[2]\n }), result = {\n signal: null,\n status: exitCode,\n output: [null, stdout, stderr]\n };\n if (stdout && encoding && encoding !== \"buffer\")\n result.output[1] = result.output[1]\?.toString(encoding);\n if (stderr && encoding && encoding !== \"buffer\")\n result.output[2] = result.output[2]\?.toString(encoding);\n if (result.stdout = result.output[1], result.stderr = result.output[2], !success)\n result.error = new SystemError(result.output[2], options.file, \"spawnSync\", -1, result.status), result.error.spawnargs = ArrayPrototypeSlice.call(options.args, 1);\n return result;\n}, execFileSync = function(file, args, options) {\n ({ file, args, options } = normalizeExecFileArgs(file, args, options));\n const ret = spawnSync(file, args, options), errArgs = [options.argv0 || file];\n ArrayPrototypePush.apply(errArgs, args);\n const err = checkExecSyncError(ret, errArgs);\n if (err)\n throw err;\n return ret.stdout;\n}, execSync = function(command, options) {\n const opts = normalizeExecArgs(command, options, null), ret = spawnSync(opts.file, opts.options), err = checkExecSyncError(ret, @undefined, command);\n if (err)\n throw err;\n return ret.stdout;\n}, stdioStringToArray = function(stdio, channel) {\n const options = [];\n switch (stdio) {\n case \"ignore\":\n case \"overlapped\":\n case \"pipe\":\n ArrayPrototypePush.call(options, stdio, stdio, stdio);\n break;\n case \"inherit\":\n ArrayPrototypePush.call(options, 0, 1, 2);\n break;\n default:\n throw new ERR_INVALID_ARG_VALUE(\"stdio\", stdio);\n }\n if (channel)\n ArrayPrototypePush.call(options, channel);\n return options;\n}, fork = function(modulePath, args = [], options) {\n modulePath = getValidatedPath(modulePath, \"modulePath\");\n let execArgv;\n if (args == null)\n args = [];\n else if (typeof args === \"object\" && !ArrayIsArray(args))\n options = args, args = [];\n else\n validateArray(args, \"args\");\n if (options != null)\n validateObject(options, \"options\");\n if (options = { __proto__: null, ...options, shell: !1 }, options.execPath = options.execPath || process.execPath, validateArgumentNullCheck(options.execPath, \"options.execPath\"), execArgv = options.execArgv || process.execArgv, validateArgumentsNullCheck(execArgv, \"options.execArgv\"), execArgv === process.execArgv && process._eval != null) {\n const index = ArrayPrototypeLastIndexOf.call(execArgv, process._eval);\n if (index > 0)\n execArgv = ArrayPrototypeSlice.call(execArgv), ArrayPrototypeSplice.call(execArgv, index - 1, 2);\n }\n if (args = [...execArgv, modulePath, ...args], typeof options.stdio === \"string\")\n options.stdio = stdioStringToArray(options.stdio, \"ipc\");\n else if (!ArrayIsArray(options.stdio))\n options.stdio = stdioStringToArray(options.silent \? \"pipe\" : \"inherit\", \"ipc\");\n else if (!ArrayPrototypeIncludes.call(options.stdio, \"ipc\"))\n throw new ERR_CHILD_PROCESS_IPC_REQUIRED(\"options.stdio\");\n return spawn(options.execPath, args, options);\n}, convertToValidSignal = function(signal) {\n if (typeof signal === \"number\" && getSignalsToNamesMapping()[signal])\n return signal;\n if (typeof signal === \"string\") {\n const signalName = signals[StringPrototypeToUpperCase.call(signal)];\n if (signalName)\n return signalName;\n }\n throw new ERR_UNKNOWN_SIGNAL(signal);\n}, sanitizeKillSignal = function(killSignal2) {\n if (typeof killSignal2 === \"string\" || typeof killSignal2 === \"number\")\n return convertToValidSignal(killSignal2);\n else if (killSignal2 != null)\n throw new ERR_INVALID_ARG_TYPE(\"options.killSignal\", [\"string\", \"number\"], killSignal2);\n}, getSignalsToNamesMapping = function() {\n if (signalsToNamesMapping !== @undefined)\n return signalsToNamesMapping;\n signalsToNamesMapping = ObjectCreate(null);\n for (let key in signals)\n signalsToNamesMapping[signals[key]] = key;\n return signalsToNamesMapping;\n}, normalizeExecFileArgs = function(file, args, options, callback) {\n if (ArrayIsArray(args))\n args = ArrayPrototypeSlice.call(args);\n else if (args != null && typeof args === \"object\")\n callback = options, options = args, args = null;\n else if (typeof args === \"function\")\n callback = args, options = null, args = null;\n if (args == null)\n args = [];\n if (typeof options === \"function\")\n callback = options;\n else if (options != null)\n validateObject(options, \"options\");\n if (options == null)\n options = kEmptyObject;\n if (callback != null)\n validateFunction(callback, \"callback\");\n if (options.argv0 != null)\n validateString(options.argv0, \"options.argv0\"), validateArgumentNullCheck(options.argv0, \"options.argv0\");\n return { file, args, options, callback };\n}, normalizeExecArgs = function(command, options, callback) {\n if (validateString(command, \"command\"), validateArgumentNullCheck(command, \"command\"), typeof options === \"function\")\n callback = options, options = @undefined;\n return options = { ...options }, options.shell = typeof options.shell === \"string\" \? options.shell : !0, {\n file: command,\n options,\n callback\n };\n}, normalizeSpawnArguments = function(file, args, options) {\n if (validateString(file, \"file\"), validateArgumentNullCheck(file, \"file\"), file.length === 0)\n throw new ERR_INVALID_ARG_VALUE(\"file\", file, \"cannot be empty\");\n if (ArrayIsArray(args))\n args = ArrayPrototypeSlice.call(args);\n else if (args == null)\n args = [];\n else if (typeof args !== \"object\")\n throw new ERR_INVALID_ARG_TYPE(\"args\", \"object\", args);\n else\n options = args, args = [];\n if (validateArgumentsNullCheck(args, \"args\"), options === @undefined)\n options = {};\n else\n validateObject(options, \"options\");\n let cwd = options.cwd;\n if (cwd != null)\n cwd = getValidatedPath(cwd, \"options.cwd\");\n var detached = !1;\n const { detached: detachedOption } = options;\n if (detachedOption != null)\n detached = !!detachedOption;\n if (options.shell != null && typeof options.shell !== \"boolean\" && typeof options.shell !== \"string\")\n throw new ERR_INVALID_ARG_TYPE(\"options.shell\", [\"boolean\", \"string\"], options.shell);\n if (options.argv0 != null)\n validateString(options.argv0, \"options.argv0\"), validateArgumentNullCheck(options.argv0, \"options.argv0\");\n if (options.shell) {\n validateArgumentNullCheck(options.shell, \"options.shell\");\n const command = ArrayPrototypeJoin.call([file, ...args], \" \");\n if (typeof options.shell === \"string\")\n file = options.shell;\n else\n file = \"sh\";\n args = [\"-c\", command];\n }\n if (typeof options.argv0 === \"string\")\n ArrayPrototypeUnshift.call(args, options.argv0);\n else\n ArrayPrototypeUnshift.call(args, file);\n const envPairs = options.env || process.env;\n return { ...options, detached, file, args, cwd, envPairs };\n}, checkExecSyncError = function(ret, args, cmd) {\n let err;\n if (ret.error)\n err = ret.error, ObjectAssign(err, ret);\n else if (ret.status !== 0) {\n let msg = \"Command failed: \";\n if (msg += cmd || ArrayPrototypeJoin.call(args, \" \"), ret.stderr && ret.stderr.length > 0)\n msg += `\\n${ret.stderr.toString()}`;\n err = genericNodeError(msg, ret);\n }\n return err;\n}, nodeToBun = function(item) {\n if (typeof item === \"number\")\n return item;\n else {\n const result = nodeToBunLookup[item];\n if (result === @undefined)\n throw new Error(`Invalid stdio option \"${item}\"`);\n return result;\n }\n}, fdToStdioName = function(fd) {\n switch (fd) {\n case 0:\n return \"stdin\";\n case 1:\n return \"stdout\";\n case 2:\n return \"stderr\";\n default:\n return null;\n }\n}, getBunStdioFromOptions = function(stdio) {\n return normalizeStdio(stdio).map((item) => nodeToBun(item));\n}, normalizeStdio = function(stdio) {\n if (typeof stdio === \"string\")\n switch (stdio) {\n case \"ignore\":\n return [\"ignore\", \"ignore\", \"ignore\"];\n case \"pipe\":\n return [\"pipe\", \"pipe\", \"pipe\"];\n case \"inherit\":\n return [\"inherit\", \"inherit\", \"inherit\"];\n default:\n throw new ERR_INVALID_OPT_VALUE(\"stdio\", stdio);\n }\n else if (ArrayIsArray(stdio)) {\n let processedStdio;\n if (stdio.length === 0)\n processedStdio = [\"pipe\", \"pipe\", \"pipe\"];\n else if (stdio.length === 1)\n processedStdio = [stdio[0], \"pipe\", \"pipe\"];\n else if (stdio.length === 2)\n processedStdio = [stdio[0], stdio[1], \"pipe\"];\n else if (stdio.length >= 3)\n processedStdio = [stdio[0], stdio[1], stdio[2]];\n return processedStdio.map((item) => !item \? \"pipe\" : item);\n } else\n throw new ERR_INVALID_OPT_VALUE(\"stdio\", stdio);\n}, flushStdio = function(subprocess) {\n const stdio = subprocess.stdio;\n if (stdio == null)\n return;\n for (let i = 0;i < stdio.length; i++) {\n const stream = stdio[i];\n if (!stream || !stream.readable)\n continue;\n stream.resume();\n }\n}, onSpawnNT = function(self) {\n self.emit(\"spawn\");\n}, abortChildProcess = function(child, killSignal2, reason) {\n if (!child)\n return;\n try {\n if (child.kill(killSignal2))\n child.emit(\"error\", new AbortError(@undefined, { cause: reason }));\n } catch (err) {\n child.emit(\"error\", err);\n }\n}, validateMaxBuffer = function(maxBuffer) {\n if (maxBuffer != null && !(typeof maxBuffer === \"number\" && maxBuffer >= 0))\n throw new ERR_OUT_OF_RANGE(\"options.maxBuffer\", \"a positive number\", maxBuffer);\n}, validateArgumentNullCheck = function(arg, propName) {\n if (typeof arg === \"string\" && StringPrototypeIncludes.call(arg, \"\\0\"))\n throw new ERR_INVALID_ARG_VALUE(propName, arg, \"must be a string without null bytes\");\n}, validateArgumentsNullCheck = function(args, propName) {\n for (let i = 0;i < args.length; ++i)\n validateArgumentNullCheck(args[i], `${propName}[${i}]`);\n}, validateTimeout = function(timeout) {\n if (timeout != null && !(NumberIsInteger(timeout) && timeout >= 0))\n throw new ERR_OUT_OF_RANGE(\"timeout\", \"an unsigned integer\", timeout);\n};\nvar validateFunction = function(value, name) {\n if (typeof value !== \"function\")\n throw new ERR_INVALID_ARG_TYPE(name, \"Function\", value);\n}, validateString = function(value, name) {\n if (typeof value !== \"string\")\n throw new ERR_INVALID_ARG_TYPE(name, \"string\", value);\n}, nullCheck = function(path, propName, throwError = !0) {\n const pathIsString = typeof path === \"string\", pathIsUint8Array = isUint8Array(path);\n if (!pathIsString && !pathIsUint8Array || pathIsString && !StringPrototypeIncludes.call(path, \"\\0\") || pathIsUint8Array && !Uint8ArrayPrototypeIncludes.call(path, 0))\n return;\n const err = new ERR_INVALID_ARG_VALUE(propName, path, \"must be a string or Uint8Array without null bytes\");\n if (throwError)\n throw err;\n return err;\n}, validatePath = function(path, propName = \"path\") {\n if (typeof path !== \"string\" && !isUint8Array(path))\n throw new ERR_INVALID_ARG_TYPE(propName, [\"string\", \"Buffer\", \"URL\"], path);\n const err = nullCheck(path, propName, !1);\n if (err !== @undefined)\n throw err;\n}, getValidatedPath = function(fileURLOrPath, propName = \"path\") {\n const path = toPathIfFileURL(fileURLOrPath);\n return validatePath(path, propName), path;\n}, isUint8Array = function(value) {\n return typeof value === \"object\" && value !== null && value instanceof @Uint8Array;\n}, isURLInstance = function(fileURLOrPath) {\n return fileURLOrPath != null && fileURLOrPath.href && fileURLOrPath.origin;\n}, toPathIfFileURL = function(fileURLOrPath) {\n if (!isURLInstance(fileURLOrPath))\n return fileURLOrPath;\n return Bun.fileURLToPath(fileURLOrPath);\n}, genericNodeError = function(message, options) {\n const err = new Error(message);\n return err.code = options.code, err.killed = options.killed, err.signal = options.signal, err;\n}, ERR_OUT_OF_RANGE = function(str, range, input, replaceDefaultBoolean = !1) {\n return new RangeError(`The value of ${str} is out of range. It must be ${range}. Received ${input}`);\n}, ERR_CHILD_PROCESS_STDIO_MAXBUFFER = function(stdio) {\n return Error(`${stdio} maxBuffer length exceeded`);\n}, ERR_UNKNOWN_SIGNAL = function(name) {\n const err = @makeTypeError(`Unknown signal: ${name}`);\n return err.code = \"ERR_UNKNOWN_SIGNAL\", err;\n}, ERR_INVALID_ARG_TYPE = function(name, type, value) {\n const err = @makeTypeError(`The \"${name}\" argument must be of type ${type}. Received ${value\?.toString()}`);\n return err.code = \"ERR_INVALID_ARG_TYPE\", err;\n}, ERR_INVALID_OPT_VALUE = function(name, value) {\n return @makeTypeError(`The value \"${value}\" is invalid for option \"${name}\"`);\n}, ERR_INVALID_ARG_VALUE = function(name, value, reason) {\n return new Error(`The value \"${value}\" is invalid for argument '${name}'. Reason: ${reason}`);\n}, ERR_CHILD_PROCESS_IPC_REQUIRED = function(name) {\n const err = @makeTypeError(`Forked processes must have an IPC channel, missing value 'ipc' in ${name}`);\n return err.code = \"ERR_CHILD_PROCESS_IPC_REQUIRED\", err;\n}, $, EventEmitter = @getInternalField(@internalModuleRegistry, 18) || @createInternalModuleById(18), StreamModule = @getInternalField(@internalModuleRegistry, 37) || @createInternalModuleById(37), {\n constants: { signals }\n} = @getInternalField(@internalModuleRegistry, 26) || @createInternalModuleById(26), { promisify } = @getInternalField(@internalModuleRegistry, 46) || @createInternalModuleById(46), ObjectCreate = Object.create, ObjectAssign = Object.assign, ObjectDefineProperty = Object.defineProperty, BufferConcat = @Buffer.concat, BufferIsEncoding = @Buffer.isEncoding, kEmptyObject = ObjectCreate(null), ArrayPrototypePush = @Array.prototype.push, ArrayPrototypeJoin = @Array.prototype.join, ArrayPrototypeMap = @Array.prototype.map, ArrayPrototypeIncludes = @Array.prototype.includes, ArrayPrototypeSlice = @Array.prototype.slice, ArrayPrototypeUnshift = @Array.prototype.unshift, ArrayPrototypeLastIndexOf = @Array.prototype.lastIndexOf, ArrayPrototypeSplice = @Array.prototype.splice, ArrayIsArray = @Array.isArray, ArrayBufferIsView = @ArrayBuffer.isView, NumberIsInteger = Number.isInteger;\nvar StringPrototypeToUpperCase = @String.prototype.toUpperCase, StringPrototypeIncludes = @String.prototype.includes, StringPrototypeSlice = @String.prototype.slice, Uint8ArrayPrototypeIncludes = @Uint8Array.prototype.includes, MAX_BUFFER = 1048576, NativeWritable, ReadableFromWeb, customPromiseExecFunction = (orig) => {\n return (...args) => {\n let resolve, reject;\n const promise = new @Promise((res, rej) => {\n resolve = res, reject = rej;\n });\n return promise.child = orig(...args, (err, stdout, stderr) => {\n if (err !== null)\n err.stdout = stdout, err.stderr = stderr, reject(err);\n else\n resolve({ stdout, stderr });\n }), promise;\n };\n};\nObjectDefineProperty(exec, promisify.custom, {\n __proto__: null,\n enumerable: !1,\n value: customPromiseExecFunction(exec)\n});\nvar signalsToNamesMapping;\n\nclass ChildProcess extends EventEmitter {\n constructor() {\n super(...arguments);\n }\n #handle;\n #exited = !1;\n #closesNeeded = 1;\n #closesGot = 0;\n connected = !1;\n signalCode = null;\n exitCode = null;\n spawnfile;\n spawnargs;\n pid;\n channel;\n get killed() {\n if (this.#handle == null)\n return !1;\n }\n #handleOnExit(exitCode, signalCode, err) {\n if (this.#exited)\n return;\n if (signalCode)\n this.signalCode = signalCode;\n else\n this.exitCode = exitCode;\n if (this.#stdin)\n this.#stdin.destroy();\n if (this.#handle)\n this.#handle = null;\n if (exitCode < 0) {\n const err2 = new SystemError(`Spawned process exited with error code: ${exitCode}`, @undefined, \"spawn\", \"EUNKNOWN\", \"ERR_CHILD_PROCESS_UNKNOWN_ERROR\");\n if (this.spawnfile)\n err2.path = this.spawnfile;\n err2.spawnargs = ArrayPrototypeSlice.call(this.spawnargs, 1), this.emit(\"error\", err2);\n } else\n this.emit(\"exit\", this.exitCode, this.signalCode);\n process.nextTick(flushStdio, this), this.#maybeClose(), this.#exited = !0, this.#stdioOptions = [\"destroyed\", \"destroyed\", \"destroyed\"];\n }\n #getBunSpawnIo(i, encoding) {\n NativeWritable ||= StreamModule.NativeWritable, ReadableFromWeb ||= StreamModule.Readable.fromWeb;\n const io = this.#stdioOptions[i];\n switch (i) {\n case 0:\n switch (io) {\n case \"pipe\":\n return new NativeWritable(this.#handle.stdin);\n case \"inherit\":\n return process.stdin || null;\n case \"destroyed\":\n return new ShimmedStdin;\n default:\n return null;\n }\n case 2:\n case 1:\n switch (io) {\n case \"pipe\":\n return ReadableFromWeb(this.#handle[fdToStdioName(i)], { encoding });\n case \"inherit\":\n return process[fdToStdioName(i)] || null;\n case \"destroyed\":\n return new ShimmedStdioOutStream;\n default:\n return null;\n }\n }\n }\n #stdin;\n #stdout;\n #stderr;\n #stdioObject;\n #encoding;\n #stdioOptions;\n #createStdioObject() {\n return Object.create(null, {\n 0: {\n get: () => this.stdin\n },\n 1: {\n get: () => this.stdout\n },\n 2: {\n get: () => this.stderr\n }\n });\n }\n get stdin() {\n return this.#stdin \?\?= this.#getBunSpawnIo(0, this.#encoding);\n }\n get stdout() {\n return this.#stdout \?\?= this.#getBunSpawnIo(1, this.#encoding);\n }\n get stderr() {\n return this.#stderr \?\?= this.#getBunSpawnIo(2, this.#encoding);\n }\n get stdio() {\n return this.#stdioObject \?\?= this.#createStdioObject();\n }\n spawn(options) {\n validateObject(options, \"options\"), validateString(options.file, \"options.file\");\n var file = this.spawnfile = options.file, spawnargs;\n if (options.args == null)\n spawnargs = this.spawnargs = [];\n else\n validateArray(options.args, \"options.args\"), spawnargs = this.spawnargs = options.args;\n const stdio = options.stdio || [\"pipe\", \"pipe\", \"pipe\"], bunStdio = getBunStdioFromOptions(stdio), ipc = @isArray(stdio) && stdio[3] === \"ipc\";\n var env = options.envPairs || @undefined;\n const detachedOption = options.detached;\n if (this.#encoding = options.encoding || @undefined, this.#stdioOptions = bunStdio, this.#handle = Bun.spawn({\n cmd: spawnargs,\n stdin: bunStdio[0],\n stdout: bunStdio[1],\n stderr: bunStdio[2],\n cwd: options.cwd || @undefined,\n env: env || process.env,\n detached: typeof detachedOption !== \"undefined\" \? !!detachedOption : !1,\n onExit: (handle, exitCode, signalCode, err) => {\n this.#handle = handle, this.pid = this.#handle.pid, process.nextTick((exitCode2, signalCode2, err2) => this.#handleOnExit(exitCode2, signalCode2, err2), exitCode, signalCode, err);\n },\n lazy: !0,\n ipc: ipc \? this.#emitIpcMessage.bind(this) : @undefined\n }), this.pid = this.#handle.pid, onSpawnNT(this), ipc)\n this.send = this.#send, this.disconnect = this.#disconnect;\n }\n #emitIpcMessage(message) {\n this.emit(\"message\", message);\n }\n #send(message, handle, options, callback) {\n if (typeof handle === \"function\")\n callback = handle, handle = @undefined, options = @undefined;\n else if (typeof options === \"function\")\n callback = options, options = @undefined;\n else if (options !== @undefined) {\n if (typeof options !== \"object\" || options === null)\n throw new ERR_INVALID_ARG_TYPE(\"options\", \"Object\", options);\n }\n if (!this.#handle) {\n if (callback)\n process.nextTick(callback, @makeTypeError(\"Process was closed while trying to send message\"));\n else\n this.emit(\"error\", @makeTypeError(\"Process was closed while trying to send message\"));\n return !1;\n }\n try {\n if (this.#handle.send(message), callback)\n process.nextTick(callback);\n return !0;\n } catch (error) {\n if (callback)\n process.nextTick(callback, error);\n else\n this.emit(\"error\", error);\n return !1;\n }\n }\n #disconnect() {\n if (!this.connected) {\n this.emit(\"error\", @makeTypeError(\"Process was closed while trying to send message\"));\n return;\n }\n this.connected = !1, this.#handle.disconnect();\n }\n kill(sig) {\n const signal = sig === 0 \? sig : convertToValidSignal(sig === @undefined \? \"SIGTERM\" : sig);\n if (this.#handle)\n this.#handle.kill(signal);\n return this.#maybeClose(), !0;\n }\n #maybeClose() {\n if (this.#closesGot++, this.#closesGot === this.#closesNeeded)\n this.emit(\"close\", this.exitCode, this.signalCode);\n }\n ref() {\n if (this.#handle)\n this.#handle.ref();\n }\n unref() {\n if (this.#handle)\n this.#handle.unref();\n }\n}\nvar nodeToBunLookup = {\n ignore: null,\n pipe: \"pipe\",\n overlapped: \"pipe\",\n inherit: \"inherit\"\n};\n\nclass ShimmedStdin extends EventEmitter {\n constructor() {\n super();\n }\n write() {\n return !1;\n }\n destroy() {\n }\n end() {\n }\n pipe() {\n }\n}\n\nclass ShimmedStdioOutStream extends EventEmitter {\n constructor() {\n super(...arguments);\n }\n pipe() {\n }\n}\nvar validateAbortSignal = (signal, name) => {\n if (signal !== @undefined && (signal === null || typeof signal !== \"object\" || !(\"aborted\" in signal)))\n throw new ERR_INVALID_ARG_TYPE(name, \"AbortSignal\", signal);\n};\nvar validateObject = (value, name, options = null) => {\n const allowArray = options\?.allowArray \?\? !1, allowFunction = options\?.allowFunction \?\? !1;\n if (!(options\?.nullable \?\? !1) && value === null || !allowArray && ArrayIsArray.call(value) || typeof value !== \"object\" && (!allowFunction || typeof value !== \"function\"))\n throw new ERR_INVALID_ARG_TYPE(name, \"object\", value);\n}, validateArray = (value, name, minLength = 0) => {\n if (!ArrayIsArray(value))\n throw new ERR_INVALID_ARG_TYPE(name, \"Array\", value);\n if (value.length < minLength) {\n const reason = `must be longer than ${minLength}`;\n throw new ERR_INVALID_ARG_VALUE(name, value, reason);\n }\n}, Error = globalThis.Error, TypeError = globalThis.TypeError, RangeError = globalThis.RangeError;\n\nclass AbortError extends Error {\n code = \"ABORT_ERR\";\n name = \"AbortError\";\n constructor(message = \"The operation was aborted\", options = @undefined) {\n if (options !== @undefined && typeof options !== \"object\")\n throw new ERR_INVALID_ARG_TYPE(\"options\", \"Object\", options);\n super(message, options);\n }\n}\n\nclass SystemError extends Error {\n path;\n syscall;\n errno;\n code;\n constructor(message, path, syscall, errno, code) {\n super(message);\n this.path = path, this.syscall = syscall, this.errno = errno, this.code = code;\n }\n get name() {\n return \"SystemError\";\n }\n}\n$ = {\n ChildProcess,\n spawn,\n execFile,\n exec,\n fork,\n spawnSync,\n execFileSync,\n execSync\n};\nreturn $})\n"_s; // // @@ -283,7 +283,7 @@ static constexpr ASCIILiteral NodeAsyncHooksCode = "(function (){\"use strict\"; // // -static constexpr ASCIILiteral NodeChildProcessCode = "(function (){\"use strict\";// src/js/out/tmp/node/child_process.ts\nvar spawn = function(file, args, options) {\n options = normalizeSpawnArguments(file, args, options), validateTimeout(options.timeout), validateAbortSignal(options.signal, \"options.signal\");\n const killSignal2 = sanitizeKillSignal(options.killSignal), child = new ChildProcess;\n if (child.spawn(options), options.timeout > 0) {\n let timeoutId = setTimeout(() => {\n if (timeoutId) {\n try {\n child.kill(killSignal2);\n } catch (err) {\n child.emit(\"error\", err);\n }\n timeoutId = null;\n }\n });\n child.once(\"exit\", () => {\n if (timeoutId)\n clearTimeout(timeoutId), timeoutId = null;\n });\n }\n if (options.signal) {\n let onAbortListener2 = function() {\n abortChildProcess(child, killSignal2, options.signal.reason);\n };\n var onAbortListener = onAbortListener2;\n const signal = options.signal;\n if (signal.aborted)\n process.nextTick(onAbortListener2);\n else\n signal.addEventListener(\"abort\", onAbortListener2, { once: !0 }), child.once(\"exit\", () => signal.removeEventListener(\"abort\", onAbortListener2));\n }\n return child;\n}, execFile = function(file, args, options, callback) {\n ({ file, args, options, callback } = normalizeExecFileArgs(file, args, options, callback)), options = {\n encoding: \"utf8\",\n timeout: 0,\n maxBuffer: MAX_BUFFER,\n killSignal: \"SIGTERM\",\n cwd: null,\n env: null,\n shell: !1,\n ...options\n };\n const maxBuffer = options.maxBuffer;\n validateTimeout(options.timeout), validateMaxBuffer(maxBuffer), options.killSignal = sanitizeKillSignal(options.killSignal);\n const child = spawn(file, args, {\n cwd: options.cwd,\n env: options.env,\n shell: options.shell,\n signal: options.signal\n });\n let encoding;\n const _stdout = [], _stderr = [];\n if (options.encoding !== \"buffer\" && BufferIsEncoding(options.encoding))\n encoding = options.encoding;\n else\n encoding = null;\n let stdoutLen = 0, stderrLen = 0, killed = !1, exited = !1, timeoutId, encodedStdoutLen, encodedStderrLen, ex = null, cmd = file;\n function exitHandler(code, signal) {\n if (exited)\n return;\n if (exited = !0, timeoutId)\n clearTimeout(timeoutId), timeoutId = null;\n if (!callback)\n return;\n const readableEncoding = child\?.stdout\?.readableEncoding;\n let stdout, stderr;\n if (encoding || child.stdout && readableEncoding)\n stdout = ArrayPrototypeJoin.call(_stdout, \"\");\n else\n stdout = BufferConcat(_stdout);\n if (encoding || child.stderr && readableEncoding)\n stderr = ArrayPrototypeJoin.call(_stderr, \"\");\n else\n stderr = BufferConcat(_stderr);\n if (!ex && code === 0 && signal === null) {\n callback(null, stdout, stderr);\n return;\n }\n if (args\?.length)\n cmd += ` ${ArrayPrototypeJoin.call(args, \" \")}`;\n if (!ex) {\n let message = `Command failed: ${cmd}`;\n if (stderr)\n message += `\\n${stderr}`;\n ex = genericNodeError(message, {\n code,\n killed: child.killed || killed,\n signal\n });\n }\n ex.cmd = cmd, callback(ex, stdout, stderr);\n }\n function errorHandler(e) {\n if (ex = e, child.stdout)\n child.stdout.destroy();\n if (child.stderr)\n child.stderr.destroy();\n exitHandler();\n }\n function kill() {\n if (child.stdout)\n child.stdout.destroy();\n if (child.stderr)\n child.stderr.destroy();\n killed = !0;\n try {\n child.kill(options.killSignal);\n } catch (e) {\n ex = e, exitHandler();\n }\n }\n if (options.timeout > 0)\n timeoutId = setTimeout(function delayedKill() {\n kill(), timeoutId = null;\n }, options.timeout);\n if (child.stdout) {\n if (encoding)\n child.stdout.setEncoding(encoding);\n child.stdout.on(\"data\", maxBuffer === @Infinity \? function onUnlimitedSizeBufferedData(chunk) {\n ArrayPrototypePush.call(_stdout, chunk);\n } : encoding \? function onChildStdoutEncoded(chunk) {\n if (stdoutLen += chunk.length, stdoutLen * 4 > maxBuffer) {\n const encoding2 = child.stdout.readableEncoding, actualLen = @Buffer.byteLength(chunk, encoding2);\n if (encodedStdoutLen === @undefined)\n for (let i = 0;i < _stdout.length; i++)\n encodedStdoutLen += @Buffer.byteLength(_stdout[i], encoding2);\n else\n encodedStdoutLen += actualLen;\n const truncatedLen = maxBuffer - (encodedStdoutLen - actualLen);\n ArrayPrototypePush.call(_stdout, StringPrototypeSlice.apply(chunk, 0, truncatedLen)), ex = new ERR_CHILD_PROCESS_STDIO_MAXBUFFER(\"stdout\"), kill();\n } else\n ArrayPrototypePush.call(_stdout, chunk);\n } : function onChildStdoutRaw(chunk) {\n if (stdoutLen += chunk.length, stdoutLen > maxBuffer) {\n const truncatedLen = maxBuffer - (stdoutLen - chunk.length);\n ArrayPrototypePush.call(_stdout, chunk.slice(0, truncatedLen)), ex = new ERR_CHILD_PROCESS_STDIO_MAXBUFFER(\"stdout\"), kill();\n } else\n ArrayPrototypePush.call(_stdout, chunk);\n });\n }\n if (child.stderr) {\n if (encoding)\n child.stderr.setEncoding(encoding);\n child.stderr.on(\"data\", maxBuffer === @Infinity \? function onUnlimitedSizeBufferedData(chunk) {\n ArrayPrototypePush.call(_stderr, chunk);\n } : encoding \? function onChildStderrEncoded(chunk) {\n if (stderrLen += chunk.length, stderrLen * 4 > maxBuffer) {\n const encoding2 = child.stderr.readableEncoding, actualLen = @Buffer.byteLength(chunk, encoding2);\n if (encodedStderrLen === @undefined)\n for (let i = 0;i < _stderr.length; i++)\n encodedStderrLen += @Buffer.byteLength(_stderr[i], encoding2);\n else\n encodedStderrLen += actualLen;\n const truncatedLen = maxBuffer - (encodedStderrLen - actualLen);\n ArrayPrototypePush.call(_stderr, StringPrototypeSlice.call(chunk, 0, truncatedLen)), ex = new ERR_CHILD_PROCESS_STDIO_MAXBUFFER(\"stderr\"), kill();\n } else\n ArrayPrototypePush.call(_stderr, chunk);\n } : function onChildStderrRaw(chunk) {\n if (stderrLen += chunk.length, stderrLen > maxBuffer) {\n const truncatedLen = maxBuffer - (stderrLen - chunk.length);\n ArrayPrototypePush.call(_stderr, StringPrototypeSlice.call(chunk, 0, truncatedLen)), ex = new ERR_CHILD_PROCESS_STDIO_MAXBUFFER(\"stderr\"), kill();\n } else\n ArrayPrototypePush.call(_stderr, chunk);\n });\n }\n return child.addListener(\"close\", exitHandler), child.addListener(\"error\", errorHandler), child;\n}, exec = function(command, options, callback) {\n const opts = normalizeExecArgs(command, options, callback);\n return execFile(opts.file, opts.options, opts.callback);\n}, spawnSync = function(file, args, options) {\n options = {\n maxBuffer: MAX_BUFFER,\n ...normalizeSpawnArguments(file, args, options)\n };\n const { maxBuffer, encoding } = options;\n validateTimeout(options.timeout), validateMaxBuffer(maxBuffer), options.killSignal = sanitizeKillSignal(options.killSignal);\n const stdio = options.stdio || \"pipe\", bunStdio = getBunStdioFromOptions(stdio);\n var { input } = options;\n if (input)\n if (ArrayBufferIsView(input))\n bunStdio[0] = input;\n else if (typeof input === \"string\")\n bunStdio[0] = @Buffer.from(input, encoding || \"utf8\");\n else\n throw new ERR_INVALID_ARG_TYPE(\"options.stdio[0]\", [\"Buffer\", \"TypedArray\", \"DataView\", \"string\"], input);\n const { stdout, stderr, success, exitCode } = Bun.spawnSync({\n cmd: options.args,\n env: options.env || @undefined,\n cwd: options.cwd || @undefined,\n stdin: bunStdio[0],\n stdout: bunStdio[1],\n stderr: bunStdio[2]\n }), result = {\n signal: null,\n status: exitCode,\n output: [null, stdout, stderr]\n };\n if (stdout && encoding && encoding !== \"buffer\")\n result.output[1] = result.output[1]\?.toString(encoding);\n if (stderr && encoding && encoding !== \"buffer\")\n result.output[2] = result.output[2]\?.toString(encoding);\n if (result.stdout = result.output[1], result.stderr = result.output[2], !success)\n result.error = new SystemError(result.output[2], options.file, \"spawnSync\", -1, result.status), result.error.spawnargs = ArrayPrototypeSlice.call(options.args, 1);\n return result;\n}, execFileSync = function(file, args, options) {\n ({ file, args, options } = normalizeExecFileArgs(file, args, options));\n const ret = spawnSync(file, args, options), errArgs = [options.argv0 || file];\n ArrayPrototypePush.apply(errArgs, args);\n const err = checkExecSyncError(ret, errArgs);\n if (err)\n throw err;\n return ret.stdout;\n}, execSync = function(command, options) {\n const opts = normalizeExecArgs(command, options, null), ret = spawnSync(opts.file, opts.options), err = checkExecSyncError(ret, @undefined, command);\n if (err)\n throw err;\n return ret.stdout;\n}, stdioStringToArray = function(stdio, channel) {\n const options = [];\n switch (stdio) {\n case \"ignore\":\n case \"overlapped\":\n case \"pipe\":\n ArrayPrototypePush.call(options, stdio, stdio, stdio);\n break;\n case \"inherit\":\n ArrayPrototypePush.call(options, 0, 1, 2);\n break;\n default:\n throw new ERR_INVALID_ARG_VALUE(\"stdio\", stdio);\n }\n if (channel)\n ArrayPrototypePush.call(options, channel);\n return options;\n}, fork = function(modulePath, args = [], options) {\n modulePath = getValidatedPath(modulePath, \"modulePath\");\n let execArgv;\n if (args == null)\n args = [];\n else if (typeof args === \"object\" && !ArrayIsArray(args))\n options = args, args = [];\n else\n validateArray(args, \"args\");\n if (options != null)\n validateObject(options, \"options\");\n if (options = { __proto__: null, ...options, shell: !1 }, options.execPath = options.execPath || process.execPath, validateArgumentNullCheck(options.execPath, \"options.execPath\"), execArgv = options.execArgv || process.execArgv, validateArgumentsNullCheck(execArgv, \"options.execArgv\"), execArgv === process.execArgv && process._eval != null) {\n const index = ArrayPrototypeLastIndexOf.call(execArgv, process._eval);\n if (index > 0)\n execArgv = ArrayPrototypeSlice.call(execArgv), ArrayPrototypeSplice.call(execArgv, index - 1, 2);\n }\n if (args = [...execArgv, modulePath, ...args], typeof options.stdio === \"string\")\n options.stdio = stdioStringToArray(options.stdio, \"ipc\");\n else if (!ArrayIsArray(options.stdio))\n options.stdio = stdioStringToArray(options.silent \? \"pipe\" : \"inherit\", \"ipc\");\n else if (!ArrayPrototypeIncludes.call(options.stdio, \"ipc\"))\n throw new ERR_CHILD_PROCESS_IPC_REQUIRED(\"options.stdio\");\n return spawn(options.execPath, args, options);\n}, convertToValidSignal = function(signal) {\n if (typeof signal === \"number\" && getSignalsToNamesMapping()[signal])\n return signal;\n if (typeof signal === \"string\") {\n const signalName = signals[StringPrototypeToUpperCase.call(signal)];\n if (signalName)\n return signalName;\n }\n throw new ERR_UNKNOWN_SIGNAL(signal);\n}, sanitizeKillSignal = function(killSignal2) {\n if (typeof killSignal2 === \"string\" || typeof killSignal2 === \"number\")\n return convertToValidSignal(killSignal2);\n else if (killSignal2 != null)\n throw new ERR_INVALID_ARG_TYPE(\"options.killSignal\", [\"string\", \"number\"], killSignal2);\n}, getSignalsToNamesMapping = function() {\n if (signalsToNamesMapping !== @undefined)\n return signalsToNamesMapping;\n signalsToNamesMapping = ObjectCreate(null);\n for (let key in signals)\n signalsToNamesMapping[signals[key]] = key;\n return signalsToNamesMapping;\n}, normalizeExecFileArgs = function(file, args, options, callback) {\n if (ArrayIsArray(args))\n args = ArrayPrototypeSlice.call(args);\n else if (args != null && typeof args === \"object\")\n callback = options, options = args, args = null;\n else if (typeof args === \"function\")\n callback = args, options = null, args = null;\n if (args == null)\n args = [];\n if (typeof options === \"function\")\n callback = options;\n else if (options != null)\n validateObject(options, \"options\");\n if (options == null)\n options = kEmptyObject;\n if (callback != null)\n validateFunction(callback, \"callback\");\n if (options.argv0 != null)\n validateString(options.argv0, \"options.argv0\"), validateArgumentNullCheck(options.argv0, \"options.argv0\");\n return { file, args, options, callback };\n}, normalizeExecArgs = function(command, options, callback) {\n if (validateString(command, \"command\"), validateArgumentNullCheck(command, \"command\"), typeof options === \"function\")\n callback = options, options = @undefined;\n return options = { ...options }, options.shell = typeof options.shell === \"string\" \? options.shell : !0, {\n file: command,\n options,\n callback\n };\n}, normalizeSpawnArguments = function(file, args, options) {\n if (validateString(file, \"file\"), validateArgumentNullCheck(file, \"file\"), file.length === 0)\n throw new ERR_INVALID_ARG_VALUE(\"file\", file, \"cannot be empty\");\n if (ArrayIsArray(args))\n args = ArrayPrototypeSlice.call(args);\n else if (args == null)\n args = [];\n else if (typeof args !== \"object\")\n throw new ERR_INVALID_ARG_TYPE(\"args\", \"object\", args);\n else\n options = args, args = [];\n if (validateArgumentsNullCheck(args, \"args\"), options === @undefined)\n options = {};\n else\n validateObject(options, \"options\");\n let cwd = options.cwd;\n if (cwd != null)\n cwd = getValidatedPath(cwd, \"options.cwd\");\n var detached = !1;\n const { detached: detachedOption } = options;\n if (detachedOption != null)\n detached = !!detachedOption;\n if (options.shell != null && typeof options.shell !== \"boolean\" && typeof options.shell !== \"string\")\n throw new ERR_INVALID_ARG_TYPE(\"options.shell\", [\"boolean\", \"string\"], options.shell);\n if (options.argv0 != null)\n validateString(options.argv0, \"options.argv0\"), validateArgumentNullCheck(options.argv0, \"options.argv0\");\n if (options.shell) {\n validateArgumentNullCheck(options.shell, \"options.shell\");\n const command = ArrayPrototypeJoin.call([file, ...args], \" \");\n if (typeof options.shell === \"string\")\n file = options.shell;\n else\n file = \"sh\";\n args = [\"-c\", command];\n }\n if (typeof options.argv0 === \"string\")\n ArrayPrototypeUnshift.call(args, options.argv0);\n else\n ArrayPrototypeUnshift.call(args, file);\n const envPairs = options.env || process.env;\n return { ...options, detached, file, args, cwd, envPairs };\n}, checkExecSyncError = function(ret, args, cmd) {\n let err;\n if (ret.error)\n err = ret.error, ObjectAssign(err, ret);\n else if (ret.status !== 0) {\n let msg = \"Command failed: \";\n if (msg += cmd || ArrayPrototypeJoin.call(args, \" \"), ret.stderr && ret.stderr.length > 0)\n msg += `\\n${ret.stderr.toString()}`;\n err = genericNodeError(msg, ret);\n }\n return err;\n}, nodeToBun = function(item) {\n if (typeof item === \"number\")\n return item;\n else {\n const result = nodeToBunLookup[item];\n if (result === @undefined)\n throw new Error(\"Invalid stdio option\");\n return result;\n }\n}, fdToStdioName = function(fd) {\n switch (fd) {\n case 0:\n return \"stdin\";\n case 1:\n return \"stdout\";\n case 2:\n return \"stderr\";\n default:\n return null;\n }\n}, getBunStdioFromOptions = function(stdio) {\n return normalizeStdio(stdio).map((item) => nodeToBun(item));\n}, normalizeStdio = function(stdio) {\n if (typeof stdio === \"string\")\n switch (stdio) {\n case \"ignore\":\n return [\"ignore\", \"ignore\", \"ignore\"];\n case \"pipe\":\n return [\"pipe\", \"pipe\", \"pipe\"];\n case \"inherit\":\n return [\"inherit\", \"inherit\", \"inherit\"];\n default:\n throw new ERR_INVALID_OPT_VALUE(\"stdio\", stdio);\n }\n else if (ArrayIsArray(stdio)) {\n let processedStdio;\n if (stdio.length === 0)\n processedStdio = [\"pipe\", \"pipe\", \"pipe\"];\n else if (stdio.length === 1)\n processedStdio = [stdio[0], \"pipe\", \"pipe\"];\n else if (stdio.length === 2)\n processedStdio = [stdio[0], stdio[1], \"pipe\"];\n else if (stdio.length >= 3)\n processedStdio = [stdio[0], stdio[1], stdio[2]];\n return processedStdio.map((item) => !item \? \"pipe\" : item);\n } else\n throw new ERR_INVALID_OPT_VALUE(\"stdio\", stdio);\n}, flushStdio = function(subprocess) {\n const stdio = subprocess.stdio;\n if (stdio == null)\n return;\n for (let i = 0;i < stdio.length; i++) {\n const stream = stdio[i];\n if (!stream || !stream.readable)\n continue;\n stream.resume();\n }\n}, onSpawnNT = function(self) {\n self.emit(\"spawn\");\n}, abortChildProcess = function(child, killSignal2, reason) {\n if (!child)\n return;\n try {\n if (child.kill(killSignal2))\n child.emit(\"error\", new AbortError(@undefined, { cause: reason }));\n } catch (err) {\n child.emit(\"error\", err);\n }\n}, validateMaxBuffer = function(maxBuffer) {\n if (maxBuffer != null && !(typeof maxBuffer === \"number\" && maxBuffer >= 0))\n throw new ERR_OUT_OF_RANGE(\"options.maxBuffer\", \"a positive number\", maxBuffer);\n}, validateArgumentNullCheck = function(arg, propName) {\n if (typeof arg === \"string\" && StringPrototypeIncludes.call(arg, \"\\0\"))\n throw new ERR_INVALID_ARG_VALUE(propName, arg, \"must be a string without null bytes\");\n}, validateArgumentsNullCheck = function(args, propName) {\n for (let i = 0;i < args.length; ++i)\n validateArgumentNullCheck(args[i], `${propName}[${i}]`);\n}, validateTimeout = function(timeout) {\n if (timeout != null && !(NumberIsInteger(timeout) && timeout >= 0))\n throw new ERR_OUT_OF_RANGE(\"timeout\", \"an unsigned integer\", timeout);\n};\nvar validateFunction = function(value, name) {\n if (typeof value !== \"function\")\n throw new ERR_INVALID_ARG_TYPE(name, \"Function\", value);\n}, validateString = function(value, name) {\n if (typeof value !== \"string\")\n throw new ERR_INVALID_ARG_TYPE(name, \"string\", value);\n}, nullCheck = function(path, propName, throwError = !0) {\n const pathIsString = typeof path === \"string\", pathIsUint8Array = isUint8Array(path);\n if (!pathIsString && !pathIsUint8Array || pathIsString && !StringPrototypeIncludes.call(path, \"\\0\") || pathIsUint8Array && !Uint8ArrayPrototypeIncludes.call(path, 0))\n return;\n const err = new ERR_INVALID_ARG_VALUE(propName, path, \"must be a string or Uint8Array without null bytes\");\n if (throwError)\n throw err;\n return err;\n}, validatePath = function(path, propName = \"path\") {\n if (typeof path !== \"string\" && !isUint8Array(path))\n throw new ERR_INVALID_ARG_TYPE(propName, [\"string\", \"Buffer\", \"URL\"], path);\n const err = nullCheck(path, propName, !1);\n if (err !== @undefined)\n throw err;\n}, getValidatedPath = function(fileURLOrPath, propName = \"path\") {\n const path = toPathIfFileURL(fileURLOrPath);\n return validatePath(path, propName), path;\n}, isUint8Array = function(value) {\n return typeof value === \"object\" && value !== null && value instanceof @Uint8Array;\n}, isURLInstance = function(fileURLOrPath) {\n return fileURLOrPath != null && fileURLOrPath.href && fileURLOrPath.origin;\n}, toPathIfFileURL = function(fileURLOrPath) {\n if (!isURLInstance(fileURLOrPath))\n return fileURLOrPath;\n return Bun.fileURLToPath(fileURLOrPath);\n}, genericNodeError = function(message, options) {\n const err = new Error(message);\n return err.code = options.code, err.killed = options.killed, err.signal = options.signal, err;\n}, ERR_OUT_OF_RANGE = function(str, range, input, replaceDefaultBoolean = !1) {\n return new RangeError(`The value of ${str} is out of range. It must be ${range}. Received ${input}`);\n}, ERR_CHILD_PROCESS_STDIO_MAXBUFFER = function(stdio) {\n return Error(`${stdio} maxBuffer length exceeded`);\n}, ERR_UNKNOWN_SIGNAL = function(name) {\n const err = @makeTypeError(`Unknown signal: ${name}`);\n return err.code = \"ERR_UNKNOWN_SIGNAL\", err;\n}, ERR_INVALID_ARG_TYPE = function(name, type, value) {\n const err = @makeTypeError(`The \"${name}\" argument must be of type ${type}. Received ${value\?.toString()}`);\n return err.code = \"ERR_INVALID_ARG_TYPE\", err;\n}, ERR_INVALID_OPT_VALUE = function(name, value) {\n return @makeTypeError(`The value \"${value}\" is invalid for option \"${name}\"`);\n}, ERR_INVALID_ARG_VALUE = function(name, value, reason) {\n return new Error(`The value \"${value}\" is invalid for argument '${name}'. Reason: ${reason}`);\n}, ERR_CHILD_PROCESS_IPC_REQUIRED = function(name) {\n const err = @makeTypeError(`Forked processes must have an IPC channel, missing value 'ipc' in ${name}`);\n return err.code = \"ERR_CHILD_PROCESS_IPC_REQUIRED\", err;\n}, $, EventEmitter = @getInternalField(@internalModuleRegistry, 18) || @createInternalModuleById(18), StreamModule = @getInternalField(@internalModuleRegistry, 37) || @createInternalModuleById(37), {\n constants: { signals }\n} = @getInternalField(@internalModuleRegistry, 26) || @createInternalModuleById(26), { promisify } = @getInternalField(@internalModuleRegistry, 46) || @createInternalModuleById(46), ObjectCreate = Object.create, ObjectAssign = Object.assign, ObjectDefineProperty = Object.defineProperty, BufferConcat = @Buffer.concat, BufferIsEncoding = @Buffer.isEncoding, kEmptyObject = ObjectCreate(null), ArrayPrototypePush = @Array.prototype.push, ArrayPrototypeJoin = @Array.prototype.join, ArrayPrototypeMap = @Array.prototype.map, ArrayPrototypeIncludes = @Array.prototype.includes, ArrayPrototypeSlice = @Array.prototype.slice, ArrayPrototypeUnshift = @Array.prototype.unshift, ArrayPrototypeLastIndexOf = @Array.prototype.lastIndexOf, ArrayPrototypeSplice = @Array.prototype.splice, ArrayIsArray = @Array.isArray, ArrayBufferIsView = @ArrayBuffer.isView, NumberIsInteger = Number.isInteger;\nvar StringPrototypeToUpperCase = @String.prototype.toUpperCase, StringPrototypeIncludes = @String.prototype.includes, StringPrototypeSlice = @String.prototype.slice, Uint8ArrayPrototypeIncludes = @Uint8Array.prototype.includes, MAX_BUFFER = 1048576, NativeWritable, ReadableFromWeb, customPromiseExecFunction = (orig) => {\n return (...args) => {\n let resolve, reject;\n const promise = new @Promise((res, rej) => {\n resolve = res, reject = rej;\n });\n return promise.child = orig(...args, (err, stdout, stderr) => {\n if (err !== null)\n err.stdout = stdout, err.stderr = stderr, reject(err);\n else\n resolve({ stdout, stderr });\n }), promise;\n };\n};\nObjectDefineProperty(exec, promisify.custom, {\n __proto__: null,\n enumerable: !1,\n value: customPromiseExecFunction(exec)\n});\nvar signalsToNamesMapping;\n\nclass ChildProcess extends EventEmitter {\n constructor() {\n super(...arguments);\n }\n #handle;\n #exited = !1;\n #closesNeeded = 1;\n #closesGot = 0;\n connected = !1;\n signalCode = null;\n exitCode = null;\n spawnfile;\n spawnargs;\n pid;\n channel;\n get killed() {\n if (this.#handle == null)\n return !1;\n }\n #handleOnExit(exitCode, signalCode, err) {\n if (this.#exited)\n return;\n if (signalCode)\n this.signalCode = signalCode;\n else\n this.exitCode = exitCode;\n if (this.#stdin)\n this.#stdin.destroy();\n if (this.#handle)\n this.#handle = null;\n if (exitCode < 0) {\n const err2 = new SystemError(`Spawned process exited with error code: ${exitCode}`, @undefined, \"spawn\", \"EUNKNOWN\", \"ERR_CHILD_PROCESS_UNKNOWN_ERROR\");\n if (this.spawnfile)\n err2.path = this.spawnfile;\n err2.spawnargs = ArrayPrototypeSlice.call(this.spawnargs, 1), this.emit(\"error\", err2);\n } else\n this.emit(\"exit\", this.exitCode, this.signalCode);\n process.nextTick(flushStdio, this), this.#maybeClose(), this.#exited = !0, this.#stdioOptions = [\"destroyed\", \"destroyed\", \"destroyed\"];\n }\n #getBunSpawnIo(i, encoding) {\n NativeWritable ||= StreamModule.NativeWritable, ReadableFromWeb ||= StreamModule.Readable.fromWeb;\n const io = this.#stdioOptions[i];\n switch (i) {\n case 0:\n switch (io) {\n case \"pipe\":\n return new NativeWritable(this.#handle.stdin);\n case \"inherit\":\n return process.stdin || null;\n case \"destroyed\":\n return new ShimmedStdin;\n default:\n return null;\n }\n case 2:\n case 1:\n switch (io) {\n case \"pipe\":\n return ReadableFromWeb(this.#handle[fdToStdioName(i)], { encoding });\n case \"inherit\":\n return process[fdToStdioName(i)] || null;\n case \"destroyed\":\n return new ShimmedStdioOutStream;\n default:\n return null;\n }\n }\n }\n #stdin;\n #stdout;\n #stderr;\n #stdioObject;\n #encoding;\n #stdioOptions;\n #createStdioObject() {\n return Object.create(null, {\n 0: {\n get: () => this.stdin\n },\n 1: {\n get: () => this.stdout\n },\n 2: {\n get: () => this.stderr\n }\n });\n }\n get stdin() {\n return this.#stdin \?\?= this.#getBunSpawnIo(0, this.#encoding);\n }\n get stdout() {\n return this.#stdout \?\?= this.#getBunSpawnIo(1, this.#encoding);\n }\n get stderr() {\n return this.#stderr \?\?= this.#getBunSpawnIo(2, this.#encoding);\n }\n get stdio() {\n return this.#stdioObject \?\?= this.#createStdioObject();\n }\n spawn(options) {\n validateObject(options, \"options\"), validateString(options.file, \"options.file\");\n var file = this.spawnfile = options.file, spawnargs;\n if (options.args == null)\n spawnargs = this.spawnargs = [];\n else\n validateArray(options.args, \"options.args\"), spawnargs = this.spawnargs = options.args;\n const stdio = options.stdio || [\"pipe\", \"pipe\", \"pipe\"], bunStdio = getBunStdioFromOptions(stdio), ipc = @isArray(stdio) && stdio[3] === \"ipc\";\n var env = options.envPairs || @undefined;\n const detachedOption = options.detached;\n if (this.#encoding = options.encoding || @undefined, this.#stdioOptions = bunStdio, this.#handle = Bun.spawn({\n cmd: spawnargs,\n stdin: bunStdio[0],\n stdout: bunStdio[1],\n stderr: bunStdio[2],\n cwd: options.cwd || @undefined,\n env: env || process.env,\n detached: typeof detachedOption !== \"undefined\" \? !!detachedOption : !1,\n onExit: (handle, exitCode, signalCode, err) => {\n this.#handle = handle, this.pid = this.#handle.pid, process.nextTick((exitCode2, signalCode2, err2) => this.#handleOnExit(exitCode2, signalCode2, err2), exitCode, signalCode, err);\n },\n lazy: !0,\n ipc: ipc \? this.#emitIpcMessage.bind(this) : @undefined\n }), this.pid = this.#handle.pid, onSpawnNT(this), ipc)\n this.send = this.#send, this.disconnect = this.#disconnect;\n }\n #emitIpcMessage(message) {\n this.emit(\"message\", message);\n }\n #send(message, handle, options, callback) {\n if (typeof handle === \"function\")\n callback = handle, handle = @undefined, options = @undefined;\n else if (typeof options === \"function\")\n callback = options, options = @undefined;\n else if (options !== @undefined) {\n if (typeof options !== \"object\" || options === null)\n throw new ERR_INVALID_ARG_TYPE(\"options\", \"Object\", options);\n }\n if (!this.#handle) {\n if (callback)\n process.nextTick(callback, @makeTypeError(\"Process was closed while trying to send message\"));\n else\n this.emit(\"error\", @makeTypeError(\"Process was closed while trying to send message\"));\n return !1;\n }\n try {\n if (this.#handle.send(message), callback)\n process.nextTick(callback);\n return !0;\n } catch (error) {\n if (callback)\n process.nextTick(callback, error);\n else\n this.emit(\"error\", error);\n return !1;\n }\n }\n #disconnect() {\n if (!this.connected) {\n this.emit(\"error\", @makeTypeError(\"Process was closed while trying to send message\"));\n return;\n }\n this.connected = !1, this.#handle.disconnect();\n }\n kill(sig) {\n const signal = sig === 0 \? sig : convertToValidSignal(sig === @undefined \? \"SIGTERM\" : sig);\n if (this.#handle)\n this.#handle.kill(signal);\n return this.#maybeClose(), !0;\n }\n #maybeClose() {\n if (this.#closesGot++, this.#closesGot === this.#closesNeeded)\n this.emit(\"close\", this.exitCode, this.signalCode);\n }\n ref() {\n if (this.#handle)\n this.#handle.ref();\n }\n unref() {\n if (this.#handle)\n this.#handle.unref();\n }\n}\nvar nodeToBunLookup = {\n ignore: null,\n pipe: \"pipe\",\n overlapped: \"pipe\",\n inherit: \"inherit\"\n};\n\nclass ShimmedStdin extends EventEmitter {\n constructor() {\n super();\n }\n write() {\n return !1;\n }\n destroy() {\n }\n end() {\n }\n pipe() {\n }\n}\n\nclass ShimmedStdioOutStream extends EventEmitter {\n constructor() {\n super(...arguments);\n }\n pipe() {\n }\n}\nvar validateAbortSignal = (signal, name) => {\n if (signal !== @undefined && (signal === null || typeof signal !== \"object\" || !(\"aborted\" in signal)))\n throw new ERR_INVALID_ARG_TYPE(name, \"AbortSignal\", signal);\n};\nvar validateObject = (value, name, options = null) => {\n const allowArray = options\?.allowArray \?\? !1, allowFunction = options\?.allowFunction \?\? !1;\n if (!(options\?.nullable \?\? !1) && value === null || !allowArray && ArrayIsArray.call(value) || typeof value !== \"object\" && (!allowFunction || typeof value !== \"function\"))\n throw new ERR_INVALID_ARG_TYPE(name, \"object\", value);\n}, validateArray = (value, name, minLength = 0) => {\n if (!ArrayIsArray(value))\n throw new ERR_INVALID_ARG_TYPE(name, \"Array\", value);\n if (value.length < minLength) {\n const reason = `must be longer than ${minLength}`;\n throw new ERR_INVALID_ARG_VALUE(name, value, reason);\n }\n}, Error = globalThis.Error, TypeError = globalThis.TypeError, RangeError = globalThis.RangeError;\n\nclass AbortError extends Error {\n code = \"ABORT_ERR\";\n name = \"AbortError\";\n constructor(message = \"The operation was aborted\", options = @undefined) {\n if (options !== @undefined && typeof options !== \"object\")\n throw new ERR_INVALID_ARG_TYPE(\"options\", \"Object\", options);\n super(message, options);\n }\n}\n\nclass SystemError extends Error {\n path;\n syscall;\n errno;\n code;\n constructor(message, path, syscall, errno, code) {\n super(message);\n this.path = path, this.syscall = syscall, this.errno = errno, this.code = code;\n }\n get name() {\n return \"SystemError\";\n }\n}\n$ = {\n ChildProcess,\n spawn,\n execFile,\n exec,\n fork,\n spawnSync,\n execFileSync,\n execSync\n};\nreturn $})\n"_s; +static constexpr ASCIILiteral NodeChildProcessCode = "(function (){\"use strict\";// src/js/out/tmp/node/child_process.ts\nvar spawn = function(file, args, options) {\n options = normalizeSpawnArguments(file, args, options), validateTimeout(options.timeout), validateAbortSignal(options.signal, \"options.signal\");\n const killSignal2 = sanitizeKillSignal(options.killSignal), child = new ChildProcess;\n if (child.spawn(options), options.timeout > 0) {\n let timeoutId = setTimeout(() => {\n if (timeoutId) {\n try {\n child.kill(killSignal2);\n } catch (err) {\n child.emit(\"error\", err);\n }\n timeoutId = null;\n }\n });\n child.once(\"exit\", () => {\n if (timeoutId)\n clearTimeout(timeoutId), timeoutId = null;\n });\n }\n if (options.signal) {\n let onAbortListener2 = function() {\n abortChildProcess(child, killSignal2, options.signal.reason);\n };\n var onAbortListener = onAbortListener2;\n const signal = options.signal;\n if (signal.aborted)\n process.nextTick(onAbortListener2);\n else\n signal.addEventListener(\"abort\", onAbortListener2, { once: !0 }), child.once(\"exit\", () => signal.removeEventListener(\"abort\", onAbortListener2));\n }\n return child;\n}, execFile = function(file, args, options, callback) {\n ({ file, args, options, callback } = normalizeExecFileArgs(file, args, options, callback)), options = {\n encoding: \"utf8\",\n timeout: 0,\n maxBuffer: MAX_BUFFER,\n killSignal: \"SIGTERM\",\n cwd: null,\n env: null,\n shell: !1,\n ...options\n };\n const maxBuffer = options.maxBuffer;\n validateTimeout(options.timeout), validateMaxBuffer(maxBuffer), options.killSignal = sanitizeKillSignal(options.killSignal);\n const child = spawn(file, args, {\n cwd: options.cwd,\n env: options.env,\n shell: options.shell,\n signal: options.signal\n });\n let encoding;\n const _stdout = [], _stderr = [];\n if (options.encoding !== \"buffer\" && BufferIsEncoding(options.encoding))\n encoding = options.encoding;\n else\n encoding = null;\n let stdoutLen = 0, stderrLen = 0, killed = !1, exited = !1, timeoutId, encodedStdoutLen, encodedStderrLen, ex = null, cmd = file;\n function exitHandler(code, signal) {\n if (exited)\n return;\n if (exited = !0, timeoutId)\n clearTimeout(timeoutId), timeoutId = null;\n if (!callback)\n return;\n const readableEncoding = child\?.stdout\?.readableEncoding;\n let stdout, stderr;\n if (encoding || child.stdout && readableEncoding)\n stdout = ArrayPrototypeJoin.call(_stdout, \"\");\n else\n stdout = BufferConcat(_stdout);\n if (encoding || child.stderr && readableEncoding)\n stderr = ArrayPrototypeJoin.call(_stderr, \"\");\n else\n stderr = BufferConcat(_stderr);\n if (!ex && code === 0 && signal === null) {\n callback(null, stdout, stderr);\n return;\n }\n if (args\?.length)\n cmd += ` ${ArrayPrototypeJoin.call(args, \" \")}`;\n if (!ex) {\n let message = `Command failed: ${cmd}`;\n if (stderr)\n message += `\\n${stderr}`;\n ex = genericNodeError(message, {\n code,\n killed: child.killed || killed,\n signal\n });\n }\n ex.cmd = cmd, callback(ex, stdout, stderr);\n }\n function errorHandler(e) {\n if (ex = e, child.stdout)\n child.stdout.destroy();\n if (child.stderr)\n child.stderr.destroy();\n exitHandler();\n }\n function kill() {\n if (child.stdout)\n child.stdout.destroy();\n if (child.stderr)\n child.stderr.destroy();\n killed = !0;\n try {\n child.kill(options.killSignal);\n } catch (e) {\n ex = e, exitHandler();\n }\n }\n if (options.timeout > 0)\n timeoutId = setTimeout(function delayedKill() {\n kill(), timeoutId = null;\n }, options.timeout);\n if (child.stdout) {\n if (encoding)\n child.stdout.setEncoding(encoding);\n child.stdout.on(\"data\", maxBuffer === @Infinity \? function onUnlimitedSizeBufferedData(chunk) {\n ArrayPrototypePush.call(_stdout, chunk);\n } : encoding \? function onChildStdoutEncoded(chunk) {\n if (stdoutLen += chunk.length, stdoutLen * 4 > maxBuffer) {\n const encoding2 = child.stdout.readableEncoding, actualLen = @Buffer.byteLength(chunk, encoding2);\n if (encodedStdoutLen === @undefined)\n for (let i = 0;i < _stdout.length; i++)\n encodedStdoutLen += @Buffer.byteLength(_stdout[i], encoding2);\n else\n encodedStdoutLen += actualLen;\n const truncatedLen = maxBuffer - (encodedStdoutLen - actualLen);\n ArrayPrototypePush.call(_stdout, StringPrototypeSlice.apply(chunk, 0, truncatedLen)), ex = new ERR_CHILD_PROCESS_STDIO_MAXBUFFER(\"stdout\"), kill();\n } else\n ArrayPrototypePush.call(_stdout, chunk);\n } : function onChildStdoutRaw(chunk) {\n if (stdoutLen += chunk.length, stdoutLen > maxBuffer) {\n const truncatedLen = maxBuffer - (stdoutLen - chunk.length);\n ArrayPrototypePush.call(_stdout, chunk.slice(0, truncatedLen)), ex = new ERR_CHILD_PROCESS_STDIO_MAXBUFFER(\"stdout\"), kill();\n } else\n ArrayPrototypePush.call(_stdout, chunk);\n });\n }\n if (child.stderr) {\n if (encoding)\n child.stderr.setEncoding(encoding);\n child.stderr.on(\"data\", maxBuffer === @Infinity \? function onUnlimitedSizeBufferedData(chunk) {\n ArrayPrototypePush.call(_stderr, chunk);\n } : encoding \? function onChildStderrEncoded(chunk) {\n if (stderrLen += chunk.length, stderrLen * 4 > maxBuffer) {\n const encoding2 = child.stderr.readableEncoding, actualLen = @Buffer.byteLength(chunk, encoding2);\n if (encodedStderrLen === @undefined)\n for (let i = 0;i < _stderr.length; i++)\n encodedStderrLen += @Buffer.byteLength(_stderr[i], encoding2);\n else\n encodedStderrLen += actualLen;\n const truncatedLen = maxBuffer - (encodedStderrLen - actualLen);\n ArrayPrototypePush.call(_stderr, StringPrototypeSlice.call(chunk, 0, truncatedLen)), ex = new ERR_CHILD_PROCESS_STDIO_MAXBUFFER(\"stderr\"), kill();\n } else\n ArrayPrototypePush.call(_stderr, chunk);\n } : function onChildStderrRaw(chunk) {\n if (stderrLen += chunk.length, stderrLen > maxBuffer) {\n const truncatedLen = maxBuffer - (stderrLen - chunk.length);\n ArrayPrototypePush.call(_stderr, StringPrototypeSlice.call(chunk, 0, truncatedLen)), ex = new ERR_CHILD_PROCESS_STDIO_MAXBUFFER(\"stderr\"), kill();\n } else\n ArrayPrototypePush.call(_stderr, chunk);\n });\n }\n return child.addListener(\"close\", exitHandler), child.addListener(\"error\", errorHandler), child;\n}, exec = function(command, options, callback) {\n const opts = normalizeExecArgs(command, options, callback);\n return execFile(opts.file, opts.options, opts.callback);\n}, spawnSync = function(file, args, options) {\n options = {\n maxBuffer: MAX_BUFFER,\n ...normalizeSpawnArguments(file, args, options)\n };\n const { maxBuffer, encoding } = options;\n validateTimeout(options.timeout), validateMaxBuffer(maxBuffer), options.killSignal = sanitizeKillSignal(options.killSignal);\n const stdio = options.stdio || \"pipe\", bunStdio = getBunStdioFromOptions(stdio);\n var { input } = options;\n if (input)\n if (ArrayBufferIsView(input))\n bunStdio[0] = input;\n else if (typeof input === \"string\")\n bunStdio[0] = @Buffer.from(input, encoding || \"utf8\");\n else\n throw new ERR_INVALID_ARG_TYPE(\"options.stdio[0]\", [\"Buffer\", \"TypedArray\", \"DataView\", \"string\"], input);\n const { stdout, stderr, success, exitCode } = Bun.spawnSync({\n cmd: options.args,\n env: options.env || @undefined,\n cwd: options.cwd || @undefined,\n stdin: bunStdio[0],\n stdout: bunStdio[1],\n stderr: bunStdio[2]\n }), result = {\n signal: null,\n status: exitCode,\n output: [null, stdout, stderr]\n };\n if (stdout && encoding && encoding !== \"buffer\")\n result.output[1] = result.output[1]\?.toString(encoding);\n if (stderr && encoding && encoding !== \"buffer\")\n result.output[2] = result.output[2]\?.toString(encoding);\n if (result.stdout = result.output[1], result.stderr = result.output[2], !success)\n result.error = new SystemError(result.output[2], options.file, \"spawnSync\", -1, result.status), result.error.spawnargs = ArrayPrototypeSlice.call(options.args, 1);\n return result;\n}, execFileSync = function(file, args, options) {\n ({ file, args, options } = normalizeExecFileArgs(file, args, options));\n const ret = spawnSync(file, args, options), errArgs = [options.argv0 || file];\n ArrayPrototypePush.apply(errArgs, args);\n const err = checkExecSyncError(ret, errArgs);\n if (err)\n throw err;\n return ret.stdout;\n}, execSync = function(command, options) {\n const opts = normalizeExecArgs(command, options, null), ret = spawnSync(opts.file, opts.options), err = checkExecSyncError(ret, @undefined, command);\n if (err)\n throw err;\n return ret.stdout;\n}, stdioStringToArray = function(stdio, channel) {\n const options = [];\n switch (stdio) {\n case \"ignore\":\n case \"overlapped\":\n case \"pipe\":\n ArrayPrototypePush.call(options, stdio, stdio, stdio);\n break;\n case \"inherit\":\n ArrayPrototypePush.call(options, 0, 1, 2);\n break;\n default:\n throw new ERR_INVALID_ARG_VALUE(\"stdio\", stdio);\n }\n if (channel)\n ArrayPrototypePush.call(options, channel);\n return options;\n}, fork = function(modulePath, args = [], options) {\n modulePath = getValidatedPath(modulePath, \"modulePath\");\n let execArgv;\n if (args == null)\n args = [];\n else if (typeof args === \"object\" && !ArrayIsArray(args))\n options = args, args = [];\n else\n validateArray(args, \"args\");\n if (options != null)\n validateObject(options, \"options\");\n if (options = { __proto__: null, ...options, shell: !1 }, options.execPath = options.execPath || process.execPath, validateArgumentNullCheck(options.execPath, \"options.execPath\"), execArgv = options.execArgv || process.execArgv, validateArgumentsNullCheck(execArgv, \"options.execArgv\"), execArgv === process.execArgv && process._eval != null) {\n const index = ArrayPrototypeLastIndexOf.call(execArgv, process._eval);\n if (index > 0)\n execArgv = ArrayPrototypeSlice.call(execArgv), ArrayPrototypeSplice.call(execArgv, index - 1, 2);\n }\n if (args = [...execArgv, modulePath, ...args], typeof options.stdio === \"string\")\n options.stdio = stdioStringToArray(options.stdio, \"ipc\");\n else if (!ArrayIsArray(options.stdio))\n options.stdio = stdioStringToArray(options.silent \? \"pipe\" : \"inherit\", \"ipc\");\n else if (!ArrayPrototypeIncludes.call(options.stdio, \"ipc\"))\n throw new ERR_CHILD_PROCESS_IPC_REQUIRED(\"options.stdio\");\n return spawn(options.execPath, args, options);\n}, convertToValidSignal = function(signal) {\n if (typeof signal === \"number\" && getSignalsToNamesMapping()[signal])\n return signal;\n if (typeof signal === \"string\") {\n const signalName = signals[StringPrototypeToUpperCase.call(signal)];\n if (signalName)\n return signalName;\n }\n throw new ERR_UNKNOWN_SIGNAL(signal);\n}, sanitizeKillSignal = function(killSignal2) {\n if (typeof killSignal2 === \"string\" || typeof killSignal2 === \"number\")\n return convertToValidSignal(killSignal2);\n else if (killSignal2 != null)\n throw new ERR_INVALID_ARG_TYPE(\"options.killSignal\", [\"string\", \"number\"], killSignal2);\n}, getSignalsToNamesMapping = function() {\n if (signalsToNamesMapping !== @undefined)\n return signalsToNamesMapping;\n signalsToNamesMapping = ObjectCreate(null);\n for (let key in signals)\n signalsToNamesMapping[signals[key]] = key;\n return signalsToNamesMapping;\n}, normalizeExecFileArgs = function(file, args, options, callback) {\n if (ArrayIsArray(args))\n args = ArrayPrototypeSlice.call(args);\n else if (args != null && typeof args === \"object\")\n callback = options, options = args, args = null;\n else if (typeof args === \"function\")\n callback = args, options = null, args = null;\n if (args == null)\n args = [];\n if (typeof options === \"function\")\n callback = options;\n else if (options != null)\n validateObject(options, \"options\");\n if (options == null)\n options = kEmptyObject;\n if (callback != null)\n validateFunction(callback, \"callback\");\n if (options.argv0 != null)\n validateString(options.argv0, \"options.argv0\"), validateArgumentNullCheck(options.argv0, \"options.argv0\");\n return { file, args, options, callback };\n}, normalizeExecArgs = function(command, options, callback) {\n if (validateString(command, \"command\"), validateArgumentNullCheck(command, \"command\"), typeof options === \"function\")\n callback = options, options = @undefined;\n return options = { ...options }, options.shell = typeof options.shell === \"string\" \? options.shell : !0, {\n file: command,\n options,\n callback\n };\n}, normalizeSpawnArguments = function(file, args, options) {\n if (validateString(file, \"file\"), validateArgumentNullCheck(file, \"file\"), file.length === 0)\n throw new ERR_INVALID_ARG_VALUE(\"file\", file, \"cannot be empty\");\n if (ArrayIsArray(args))\n args = ArrayPrototypeSlice.call(args);\n else if (args == null)\n args = [];\n else if (typeof args !== \"object\")\n throw new ERR_INVALID_ARG_TYPE(\"args\", \"object\", args);\n else\n options = args, args = [];\n if (validateArgumentsNullCheck(args, \"args\"), options === @undefined)\n options = {};\n else\n validateObject(options, \"options\");\n let cwd = options.cwd;\n if (cwd != null)\n cwd = getValidatedPath(cwd, \"options.cwd\");\n var detached = !1;\n const { detached: detachedOption } = options;\n if (detachedOption != null)\n detached = !!detachedOption;\n if (options.shell != null && typeof options.shell !== \"boolean\" && typeof options.shell !== \"string\")\n throw new ERR_INVALID_ARG_TYPE(\"options.shell\", [\"boolean\", \"string\"], options.shell);\n if (options.argv0 != null)\n validateString(options.argv0, \"options.argv0\"), validateArgumentNullCheck(options.argv0, \"options.argv0\");\n if (options.shell) {\n validateArgumentNullCheck(options.shell, \"options.shell\");\n const command = ArrayPrototypeJoin.call([file, ...args], \" \");\n if (typeof options.shell === \"string\")\n file = options.shell;\n else\n file = \"sh\";\n args = [\"-c\", command];\n }\n if (typeof options.argv0 === \"string\")\n ArrayPrototypeUnshift.call(args, options.argv0);\n else\n ArrayPrototypeUnshift.call(args, file);\n const envPairs = options.env || process.env;\n return { ...options, detached, file, args, cwd, envPairs };\n}, checkExecSyncError = function(ret, args, cmd) {\n let err;\n if (ret.error)\n err = ret.error, ObjectAssign(err, ret);\n else if (ret.status !== 0) {\n let msg = \"Command failed: \";\n if (msg += cmd || ArrayPrototypeJoin.call(args, \" \"), ret.stderr && ret.stderr.length > 0)\n msg += `\\n${ret.stderr.toString()}`;\n err = genericNodeError(msg, ret);\n }\n return err;\n}, nodeToBun = function(item) {\n if (typeof item === \"number\")\n return item;\n else {\n const result = nodeToBunLookup[item];\n if (result === @undefined)\n throw new Error(`Invalid stdio option \"${item}\"`);\n return result;\n }\n}, fdToStdioName = function(fd) {\n switch (fd) {\n case 0:\n return \"stdin\";\n case 1:\n return \"stdout\";\n case 2:\n return \"stderr\";\n default:\n return null;\n }\n}, getBunStdioFromOptions = function(stdio) {\n return normalizeStdio(stdio).map((item) => nodeToBun(item));\n}, normalizeStdio = function(stdio) {\n if (typeof stdio === \"string\")\n switch (stdio) {\n case \"ignore\":\n return [\"ignore\", \"ignore\", \"ignore\"];\n case \"pipe\":\n return [\"pipe\", \"pipe\", \"pipe\"];\n case \"inherit\":\n return [\"inherit\", \"inherit\", \"inherit\"];\n default:\n throw new ERR_INVALID_OPT_VALUE(\"stdio\", stdio);\n }\n else if (ArrayIsArray(stdio)) {\n let processedStdio;\n if (stdio.length === 0)\n processedStdio = [\"pipe\", \"pipe\", \"pipe\"];\n else if (stdio.length === 1)\n processedStdio = [stdio[0], \"pipe\", \"pipe\"];\n else if (stdio.length === 2)\n processedStdio = [stdio[0], stdio[1], \"pipe\"];\n else if (stdio.length >= 3)\n processedStdio = [stdio[0], stdio[1], stdio[2]];\n return processedStdio.map((item) => !item \? \"pipe\" : item);\n } else\n throw new ERR_INVALID_OPT_VALUE(\"stdio\", stdio);\n}, flushStdio = function(subprocess) {\n const stdio = subprocess.stdio;\n if (stdio == null)\n return;\n for (let i = 0;i < stdio.length; i++) {\n const stream = stdio[i];\n if (!stream || !stream.readable)\n continue;\n stream.resume();\n }\n}, onSpawnNT = function(self) {\n self.emit(\"spawn\");\n}, abortChildProcess = function(child, killSignal2, reason) {\n if (!child)\n return;\n try {\n if (child.kill(killSignal2))\n child.emit(\"error\", new AbortError(@undefined, { cause: reason }));\n } catch (err) {\n child.emit(\"error\", err);\n }\n}, validateMaxBuffer = function(maxBuffer) {\n if (maxBuffer != null && !(typeof maxBuffer === \"number\" && maxBuffer >= 0))\n throw new ERR_OUT_OF_RANGE(\"options.maxBuffer\", \"a positive number\", maxBuffer);\n}, validateArgumentNullCheck = function(arg, propName) {\n if (typeof arg === \"string\" && StringPrototypeIncludes.call(arg, \"\\0\"))\n throw new ERR_INVALID_ARG_VALUE(propName, arg, \"must be a string without null bytes\");\n}, validateArgumentsNullCheck = function(args, propName) {\n for (let i = 0;i < args.length; ++i)\n validateArgumentNullCheck(args[i], `${propName}[${i}]`);\n}, validateTimeout = function(timeout) {\n if (timeout != null && !(NumberIsInteger(timeout) && timeout >= 0))\n throw new ERR_OUT_OF_RANGE(\"timeout\", \"an unsigned integer\", timeout);\n};\nvar validateFunction = function(value, name) {\n if (typeof value !== \"function\")\n throw new ERR_INVALID_ARG_TYPE(name, \"Function\", value);\n}, validateString = function(value, name) {\n if (typeof value !== \"string\")\n throw new ERR_INVALID_ARG_TYPE(name, \"string\", value);\n}, nullCheck = function(path, propName, throwError = !0) {\n const pathIsString = typeof path === \"string\", pathIsUint8Array = isUint8Array(path);\n if (!pathIsString && !pathIsUint8Array || pathIsString && !StringPrototypeIncludes.call(path, \"\\0\") || pathIsUint8Array && !Uint8ArrayPrototypeIncludes.call(path, 0))\n return;\n const err = new ERR_INVALID_ARG_VALUE(propName, path, \"must be a string or Uint8Array without null bytes\");\n if (throwError)\n throw err;\n return err;\n}, validatePath = function(path, propName = \"path\") {\n if (typeof path !== \"string\" && !isUint8Array(path))\n throw new ERR_INVALID_ARG_TYPE(propName, [\"string\", \"Buffer\", \"URL\"], path);\n const err = nullCheck(path, propName, !1);\n if (err !== @undefined)\n throw err;\n}, getValidatedPath = function(fileURLOrPath, propName = \"path\") {\n const path = toPathIfFileURL(fileURLOrPath);\n return validatePath(path, propName), path;\n}, isUint8Array = function(value) {\n return typeof value === \"object\" && value !== null && value instanceof @Uint8Array;\n}, isURLInstance = function(fileURLOrPath) {\n return fileURLOrPath != null && fileURLOrPath.href && fileURLOrPath.origin;\n}, toPathIfFileURL = function(fileURLOrPath) {\n if (!isURLInstance(fileURLOrPath))\n return fileURLOrPath;\n return Bun.fileURLToPath(fileURLOrPath);\n}, genericNodeError = function(message, options) {\n const err = new Error(message);\n return err.code = options.code, err.killed = options.killed, err.signal = options.signal, err;\n}, ERR_OUT_OF_RANGE = function(str, range, input, replaceDefaultBoolean = !1) {\n return new RangeError(`The value of ${str} is out of range. It must be ${range}. Received ${input}`);\n}, ERR_CHILD_PROCESS_STDIO_MAXBUFFER = function(stdio) {\n return Error(`${stdio} maxBuffer length exceeded`);\n}, ERR_UNKNOWN_SIGNAL = function(name) {\n const err = @makeTypeError(`Unknown signal: ${name}`);\n return err.code = \"ERR_UNKNOWN_SIGNAL\", err;\n}, ERR_INVALID_ARG_TYPE = function(name, type, value) {\n const err = @makeTypeError(`The \"${name}\" argument must be of type ${type}. Received ${value\?.toString()}`);\n return err.code = \"ERR_INVALID_ARG_TYPE\", err;\n}, ERR_INVALID_OPT_VALUE = function(name, value) {\n return @makeTypeError(`The value \"${value}\" is invalid for option \"${name}\"`);\n}, ERR_INVALID_ARG_VALUE = function(name, value, reason) {\n return new Error(`The value \"${value}\" is invalid for argument '${name}'. Reason: ${reason}`);\n}, ERR_CHILD_PROCESS_IPC_REQUIRED = function(name) {\n const err = @makeTypeError(`Forked processes must have an IPC channel, missing value 'ipc' in ${name}`);\n return err.code = \"ERR_CHILD_PROCESS_IPC_REQUIRED\", err;\n}, $, EventEmitter = @getInternalField(@internalModuleRegistry, 18) || @createInternalModuleById(18), StreamModule = @getInternalField(@internalModuleRegistry, 37) || @createInternalModuleById(37), {\n constants: { signals }\n} = @getInternalField(@internalModuleRegistry, 26) || @createInternalModuleById(26), { promisify } = @getInternalField(@internalModuleRegistry, 46) || @createInternalModuleById(46), ObjectCreate = Object.create, ObjectAssign = Object.assign, ObjectDefineProperty = Object.defineProperty, BufferConcat = @Buffer.concat, BufferIsEncoding = @Buffer.isEncoding, kEmptyObject = ObjectCreate(null), ArrayPrototypePush = @Array.prototype.push, ArrayPrototypeJoin = @Array.prototype.join, ArrayPrototypeMap = @Array.prototype.map, ArrayPrototypeIncludes = @Array.prototype.includes, ArrayPrototypeSlice = @Array.prototype.slice, ArrayPrototypeUnshift = @Array.prototype.unshift, ArrayPrototypeLastIndexOf = @Array.prototype.lastIndexOf, ArrayPrototypeSplice = @Array.prototype.splice, ArrayIsArray = @Array.isArray, ArrayBufferIsView = @ArrayBuffer.isView, NumberIsInteger = Number.isInteger;\nvar StringPrototypeToUpperCase = @String.prototype.toUpperCase, StringPrototypeIncludes = @String.prototype.includes, StringPrototypeSlice = @String.prototype.slice, Uint8ArrayPrototypeIncludes = @Uint8Array.prototype.includes, MAX_BUFFER = 1048576, NativeWritable, ReadableFromWeb, customPromiseExecFunction = (orig) => {\n return (...args) => {\n let resolve, reject;\n const promise = new @Promise((res, rej) => {\n resolve = res, reject = rej;\n });\n return promise.child = orig(...args, (err, stdout, stderr) => {\n if (err !== null)\n err.stdout = stdout, err.stderr = stderr, reject(err);\n else\n resolve({ stdout, stderr });\n }), promise;\n };\n};\nObjectDefineProperty(exec, promisify.custom, {\n __proto__: null,\n enumerable: !1,\n value: customPromiseExecFunction(exec)\n});\nvar signalsToNamesMapping;\n\nclass ChildProcess extends EventEmitter {\n constructor() {\n super(...arguments);\n }\n #handle;\n #exited = !1;\n #closesNeeded = 1;\n #closesGot = 0;\n connected = !1;\n signalCode = null;\n exitCode = null;\n spawnfile;\n spawnargs;\n pid;\n channel;\n get killed() {\n if (this.#handle == null)\n return !1;\n }\n #handleOnExit(exitCode, signalCode, err) {\n if (this.#exited)\n return;\n if (signalCode)\n this.signalCode = signalCode;\n else\n this.exitCode = exitCode;\n if (this.#stdin)\n this.#stdin.destroy();\n if (this.#handle)\n this.#handle = null;\n if (exitCode < 0) {\n const err2 = new SystemError(`Spawned process exited with error code: ${exitCode}`, @undefined, \"spawn\", \"EUNKNOWN\", \"ERR_CHILD_PROCESS_UNKNOWN_ERROR\");\n if (this.spawnfile)\n err2.path = this.spawnfile;\n err2.spawnargs = ArrayPrototypeSlice.call(this.spawnargs, 1), this.emit(\"error\", err2);\n } else\n this.emit(\"exit\", this.exitCode, this.signalCode);\n process.nextTick(flushStdio, this), this.#maybeClose(), this.#exited = !0, this.#stdioOptions = [\"destroyed\", \"destroyed\", \"destroyed\"];\n }\n #getBunSpawnIo(i, encoding) {\n NativeWritable ||= StreamModule.NativeWritable, ReadableFromWeb ||= StreamModule.Readable.fromWeb;\n const io = this.#stdioOptions[i];\n switch (i) {\n case 0:\n switch (io) {\n case \"pipe\":\n return new NativeWritable(this.#handle.stdin);\n case \"inherit\":\n return process.stdin || null;\n case \"destroyed\":\n return new ShimmedStdin;\n default:\n return null;\n }\n case 2:\n case 1:\n switch (io) {\n case \"pipe\":\n return ReadableFromWeb(this.#handle[fdToStdioName(i)], { encoding });\n case \"inherit\":\n return process[fdToStdioName(i)] || null;\n case \"destroyed\":\n return new ShimmedStdioOutStream;\n default:\n return null;\n }\n }\n }\n #stdin;\n #stdout;\n #stderr;\n #stdioObject;\n #encoding;\n #stdioOptions;\n #createStdioObject() {\n return Object.create(null, {\n 0: {\n get: () => this.stdin\n },\n 1: {\n get: () => this.stdout\n },\n 2: {\n get: () => this.stderr\n }\n });\n }\n get stdin() {\n return this.#stdin \?\?= this.#getBunSpawnIo(0, this.#encoding);\n }\n get stdout() {\n return this.#stdout \?\?= this.#getBunSpawnIo(1, this.#encoding);\n }\n get stderr() {\n return this.#stderr \?\?= this.#getBunSpawnIo(2, this.#encoding);\n }\n get stdio() {\n return this.#stdioObject \?\?= this.#createStdioObject();\n }\n spawn(options) {\n validateObject(options, \"options\"), validateString(options.file, \"options.file\");\n var file = this.spawnfile = options.file, spawnargs;\n if (options.args == null)\n spawnargs = this.spawnargs = [];\n else\n validateArray(options.args, \"options.args\"), spawnargs = this.spawnargs = options.args;\n const stdio = options.stdio || [\"pipe\", \"pipe\", \"pipe\"], bunStdio = getBunStdioFromOptions(stdio), ipc = @isArray(stdio) && stdio[3] === \"ipc\";\n var env = options.envPairs || @undefined;\n const detachedOption = options.detached;\n if (this.#encoding = options.encoding || @undefined, this.#stdioOptions = bunStdio, this.#handle = Bun.spawn({\n cmd: spawnargs,\n stdin: bunStdio[0],\n stdout: bunStdio[1],\n stderr: bunStdio[2],\n cwd: options.cwd || @undefined,\n env: env || process.env,\n detached: typeof detachedOption !== \"undefined\" \? !!detachedOption : !1,\n onExit: (handle, exitCode, signalCode, err) => {\n this.#handle = handle, this.pid = this.#handle.pid, process.nextTick((exitCode2, signalCode2, err2) => this.#handleOnExit(exitCode2, signalCode2, err2), exitCode, signalCode, err);\n },\n lazy: !0,\n ipc: ipc \? this.#emitIpcMessage.bind(this) : @undefined\n }), this.pid = this.#handle.pid, onSpawnNT(this), ipc)\n this.send = this.#send, this.disconnect = this.#disconnect;\n }\n #emitIpcMessage(message) {\n this.emit(\"message\", message);\n }\n #send(message, handle, options, callback) {\n if (typeof handle === \"function\")\n callback = handle, handle = @undefined, options = @undefined;\n else if (typeof options === \"function\")\n callback = options, options = @undefined;\n else if (options !== @undefined) {\n if (typeof options !== \"object\" || options === null)\n throw new ERR_INVALID_ARG_TYPE(\"options\", \"Object\", options);\n }\n if (!this.#handle) {\n if (callback)\n process.nextTick(callback, @makeTypeError(\"Process was closed while trying to send message\"));\n else\n this.emit(\"error\", @makeTypeError(\"Process was closed while trying to send message\"));\n return !1;\n }\n try {\n if (this.#handle.send(message), callback)\n process.nextTick(callback);\n return !0;\n } catch (error) {\n if (callback)\n process.nextTick(callback, error);\n else\n this.emit(\"error\", error);\n return !1;\n }\n }\n #disconnect() {\n if (!this.connected) {\n this.emit(\"error\", @makeTypeError(\"Process was closed while trying to send message\"));\n return;\n }\n this.connected = !1, this.#handle.disconnect();\n }\n kill(sig) {\n const signal = sig === 0 \? sig : convertToValidSignal(sig === @undefined \? \"SIGTERM\" : sig);\n if (this.#handle)\n this.#handle.kill(signal);\n return this.#maybeClose(), !0;\n }\n #maybeClose() {\n if (this.#closesGot++, this.#closesGot === this.#closesNeeded)\n this.emit(\"close\", this.exitCode, this.signalCode);\n }\n ref() {\n if (this.#handle)\n this.#handle.ref();\n }\n unref() {\n if (this.#handle)\n this.#handle.unref();\n }\n}\nvar nodeToBunLookup = {\n ignore: null,\n pipe: \"pipe\",\n overlapped: \"pipe\",\n inherit: \"inherit\"\n};\n\nclass ShimmedStdin extends EventEmitter {\n constructor() {\n super();\n }\n write() {\n return !1;\n }\n destroy() {\n }\n end() {\n }\n pipe() {\n }\n}\n\nclass ShimmedStdioOutStream extends EventEmitter {\n constructor() {\n super(...arguments);\n }\n pipe() {\n }\n}\nvar validateAbortSignal = (signal, name) => {\n if (signal !== @undefined && (signal === null || typeof signal !== \"object\" || !(\"aborted\" in signal)))\n throw new ERR_INVALID_ARG_TYPE(name, \"AbortSignal\", signal);\n};\nvar validateObject = (value, name, options = null) => {\n const allowArray = options\?.allowArray \?\? !1, allowFunction = options\?.allowFunction \?\? !1;\n if (!(options\?.nullable \?\? !1) && value === null || !allowArray && ArrayIsArray.call(value) || typeof value !== \"object\" && (!allowFunction || typeof value !== \"function\"))\n throw new ERR_INVALID_ARG_TYPE(name, \"object\", value);\n}, validateArray = (value, name, minLength = 0) => {\n if (!ArrayIsArray(value))\n throw new ERR_INVALID_ARG_TYPE(name, \"Array\", value);\n if (value.length < minLength) {\n const reason = `must be longer than ${minLength}`;\n throw new ERR_INVALID_ARG_VALUE(name, value, reason);\n }\n}, Error = globalThis.Error, TypeError = globalThis.TypeError, RangeError = globalThis.RangeError;\n\nclass AbortError extends Error {\n code = \"ABORT_ERR\";\n name = \"AbortError\";\n constructor(message = \"The operation was aborted\", options = @undefined) {\n if (options !== @undefined && typeof options !== \"object\")\n throw new ERR_INVALID_ARG_TYPE(\"options\", \"Object\", options);\n super(message, options);\n }\n}\n\nclass SystemError extends Error {\n path;\n syscall;\n errno;\n code;\n constructor(message, path, syscall, errno, code) {\n super(message);\n this.path = path, this.syscall = syscall, this.errno = errno, this.code = code;\n }\n get name() {\n return \"SystemError\";\n }\n}\n$ = {\n ChildProcess,\n spawn,\n execFile,\n exec,\n fork,\n spawnSync,\n execFileSync,\n execSync\n};\nreturn $})\n"_s; // // @@ -525,7 +525,7 @@ static constexpr ASCIILiteral NodeAsyncHooksCode = "(function (){\"use strict\"; // // -static constexpr ASCIILiteral NodeChildProcessCode = "(function (){\"use strict\";// src/js/out/tmp/node/child_process.ts\nvar spawn = function(file, args, options) {\n options = normalizeSpawnArguments(file, args, options), validateTimeout(options.timeout), validateAbortSignal(options.signal, \"options.signal\");\n const killSignal2 = sanitizeKillSignal(options.killSignal), child = new ChildProcess;\n if (child.spawn(options), options.timeout > 0) {\n let timeoutId = setTimeout(() => {\n if (timeoutId) {\n try {\n child.kill(killSignal2);\n } catch (err) {\n child.emit(\"error\", err);\n }\n timeoutId = null;\n }\n });\n child.once(\"exit\", () => {\n if (timeoutId)\n clearTimeout(timeoutId), timeoutId = null;\n });\n }\n if (options.signal) {\n let onAbortListener2 = function() {\n abortChildProcess(child, killSignal2, options.signal.reason);\n };\n var onAbortListener = onAbortListener2;\n const signal = options.signal;\n if (signal.aborted)\n process.nextTick(onAbortListener2);\n else\n signal.addEventListener(\"abort\", onAbortListener2, { once: !0 }), child.once(\"exit\", () => signal.removeEventListener(\"abort\", onAbortListener2));\n }\n return child;\n}, execFile = function(file, args, options, callback) {\n ({ file, args, options, callback } = normalizeExecFileArgs(file, args, options, callback)), options = {\n encoding: \"utf8\",\n timeout: 0,\n maxBuffer: MAX_BUFFER,\n killSignal: \"SIGTERM\",\n cwd: null,\n env: null,\n shell: !1,\n ...options\n };\n const maxBuffer = options.maxBuffer;\n validateTimeout(options.timeout), validateMaxBuffer(maxBuffer), options.killSignal = sanitizeKillSignal(options.killSignal);\n const child = spawn(file, args, {\n cwd: options.cwd,\n env: options.env,\n shell: options.shell,\n signal: options.signal\n });\n let encoding;\n const _stdout = [], _stderr = [];\n if (options.encoding !== \"buffer\" && BufferIsEncoding(options.encoding))\n encoding = options.encoding;\n else\n encoding = null;\n let stdoutLen = 0, stderrLen = 0, killed = !1, exited = !1, timeoutId, encodedStdoutLen, encodedStderrLen, ex = null, cmd = file;\n function exitHandler(code, signal) {\n if (exited)\n return;\n if (exited = !0, timeoutId)\n clearTimeout(timeoutId), timeoutId = null;\n if (!callback)\n return;\n const readableEncoding = child\?.stdout\?.readableEncoding;\n let stdout, stderr;\n if (encoding || child.stdout && readableEncoding)\n stdout = ArrayPrototypeJoin.call(_stdout, \"\");\n else\n stdout = BufferConcat(_stdout);\n if (encoding || child.stderr && readableEncoding)\n stderr = ArrayPrototypeJoin.call(_stderr, \"\");\n else\n stderr = BufferConcat(_stderr);\n if (!ex && code === 0 && signal === null) {\n callback(null, stdout, stderr);\n return;\n }\n if (args\?.length)\n cmd += ` ${ArrayPrototypeJoin.call(args, \" \")}`;\n if (!ex) {\n let message = `Command failed: ${cmd}`;\n if (stderr)\n message += `\\n${stderr}`;\n ex = genericNodeError(message, {\n code,\n killed: child.killed || killed,\n signal\n });\n }\n ex.cmd = cmd, callback(ex, stdout, stderr);\n }\n function errorHandler(e) {\n if (ex = e, child.stdout)\n child.stdout.destroy();\n if (child.stderr)\n child.stderr.destroy();\n exitHandler();\n }\n function kill() {\n if (child.stdout)\n child.stdout.destroy();\n if (child.stderr)\n child.stderr.destroy();\n killed = !0;\n try {\n child.kill(options.killSignal);\n } catch (e) {\n ex = e, exitHandler();\n }\n }\n if (options.timeout > 0)\n timeoutId = setTimeout(function delayedKill() {\n kill(), timeoutId = null;\n }, options.timeout);\n if (child.stdout) {\n if (encoding)\n child.stdout.setEncoding(encoding);\n child.stdout.on(\"data\", maxBuffer === @Infinity \? function onUnlimitedSizeBufferedData(chunk) {\n ArrayPrototypePush.call(_stdout, chunk);\n } : encoding \? function onChildStdoutEncoded(chunk) {\n if (stdoutLen += chunk.length, stdoutLen * 4 > maxBuffer) {\n const encoding2 = child.stdout.readableEncoding, actualLen = @Buffer.byteLength(chunk, encoding2);\n if (encodedStdoutLen === @undefined)\n for (let i = 0;i < _stdout.length; i++)\n encodedStdoutLen += @Buffer.byteLength(_stdout[i], encoding2);\n else\n encodedStdoutLen += actualLen;\n const truncatedLen = maxBuffer - (encodedStdoutLen - actualLen);\n ArrayPrototypePush.call(_stdout, StringPrototypeSlice.apply(chunk, 0, truncatedLen)), ex = new ERR_CHILD_PROCESS_STDIO_MAXBUFFER(\"stdout\"), kill();\n } else\n ArrayPrototypePush.call(_stdout, chunk);\n } : function onChildStdoutRaw(chunk) {\n if (stdoutLen += chunk.length, stdoutLen > maxBuffer) {\n const truncatedLen = maxBuffer - (stdoutLen - chunk.length);\n ArrayPrototypePush.call(_stdout, chunk.slice(0, truncatedLen)), ex = new ERR_CHILD_PROCESS_STDIO_MAXBUFFER(\"stdout\"), kill();\n } else\n ArrayPrototypePush.call(_stdout, chunk);\n });\n }\n if (child.stderr) {\n if (encoding)\n child.stderr.setEncoding(encoding);\n child.stderr.on(\"data\", maxBuffer === @Infinity \? function onUnlimitedSizeBufferedData(chunk) {\n ArrayPrototypePush.call(_stderr, chunk);\n } : encoding \? function onChildStderrEncoded(chunk) {\n if (stderrLen += chunk.length, stderrLen * 4 > maxBuffer) {\n const encoding2 = child.stderr.readableEncoding, actualLen = @Buffer.byteLength(chunk, encoding2);\n if (encodedStderrLen === @undefined)\n for (let i = 0;i < _stderr.length; i++)\n encodedStderrLen += @Buffer.byteLength(_stderr[i], encoding2);\n else\n encodedStderrLen += actualLen;\n const truncatedLen = maxBuffer - (encodedStderrLen - actualLen);\n ArrayPrototypePush.call(_stderr, StringPrototypeSlice.call(chunk, 0, truncatedLen)), ex = new ERR_CHILD_PROCESS_STDIO_MAXBUFFER(\"stderr\"), kill();\n } else\n ArrayPrototypePush.call(_stderr, chunk);\n } : function onChildStderrRaw(chunk) {\n if (stderrLen += chunk.length, stderrLen > maxBuffer) {\n const truncatedLen = maxBuffer - (stderrLen - chunk.length);\n ArrayPrototypePush.call(_stderr, StringPrototypeSlice.call(chunk, 0, truncatedLen)), ex = new ERR_CHILD_PROCESS_STDIO_MAXBUFFER(\"stderr\"), kill();\n } else\n ArrayPrototypePush.call(_stderr, chunk);\n });\n }\n return child.addListener(\"close\", exitHandler), child.addListener(\"error\", errorHandler), child;\n}, exec = function(command, options, callback) {\n const opts = normalizeExecArgs(command, options, callback);\n return execFile(opts.file, opts.options, opts.callback);\n}, spawnSync = function(file, args, options) {\n options = {\n maxBuffer: MAX_BUFFER,\n ...normalizeSpawnArguments(file, args, options)\n };\n const { maxBuffer, encoding } = options;\n validateTimeout(options.timeout), validateMaxBuffer(maxBuffer), options.killSignal = sanitizeKillSignal(options.killSignal);\n const stdio = options.stdio || \"pipe\", bunStdio = getBunStdioFromOptions(stdio);\n var { input } = options;\n if (input)\n if (ArrayBufferIsView(input))\n bunStdio[0] = input;\n else if (typeof input === \"string\")\n bunStdio[0] = @Buffer.from(input, encoding || \"utf8\");\n else\n throw new ERR_INVALID_ARG_TYPE(\"options.stdio[0]\", [\"Buffer\", \"TypedArray\", \"DataView\", \"string\"], input);\n const { stdout, stderr, success, exitCode } = Bun.spawnSync({\n cmd: options.args,\n env: options.env || @undefined,\n cwd: options.cwd || @undefined,\n stdin: bunStdio[0],\n stdout: bunStdio[1],\n stderr: bunStdio[2]\n }), result = {\n signal: null,\n status: exitCode,\n output: [null, stdout, stderr]\n };\n if (stdout && encoding && encoding !== \"buffer\")\n result.output[1] = result.output[1]\?.toString(encoding);\n if (stderr && encoding && encoding !== \"buffer\")\n result.output[2] = result.output[2]\?.toString(encoding);\n if (result.stdout = result.output[1], result.stderr = result.output[2], !success)\n result.error = new SystemError(result.output[2], options.file, \"spawnSync\", -1, result.status), result.error.spawnargs = ArrayPrototypeSlice.call(options.args, 1);\n return result;\n}, execFileSync = function(file, args, options) {\n ({ file, args, options } = normalizeExecFileArgs(file, args, options));\n const ret = spawnSync(file, args, options), errArgs = [options.argv0 || file];\n ArrayPrototypePush.apply(errArgs, args);\n const err = checkExecSyncError(ret, errArgs);\n if (err)\n throw err;\n return ret.stdout;\n}, execSync = function(command, options) {\n const opts = normalizeExecArgs(command, options, null), ret = spawnSync(opts.file, opts.options), err = checkExecSyncError(ret, @undefined, command);\n if (err)\n throw err;\n return ret.stdout;\n}, stdioStringToArray = function(stdio, channel) {\n const options = [];\n switch (stdio) {\n case \"ignore\":\n case \"overlapped\":\n case \"pipe\":\n ArrayPrototypePush.call(options, stdio, stdio, stdio);\n break;\n case \"inherit\":\n ArrayPrototypePush.call(options, 0, 1, 2);\n break;\n default:\n throw new ERR_INVALID_ARG_VALUE(\"stdio\", stdio);\n }\n if (channel)\n ArrayPrototypePush.call(options, channel);\n return options;\n}, fork = function(modulePath, args = [], options) {\n modulePath = getValidatedPath(modulePath, \"modulePath\");\n let execArgv;\n if (args == null)\n args = [];\n else if (typeof args === \"object\" && !ArrayIsArray(args))\n options = args, args = [];\n else\n validateArray(args, \"args\");\n if (options != null)\n validateObject(options, \"options\");\n if (options = { __proto__: null, ...options, shell: !1 }, options.execPath = options.execPath || process.execPath, validateArgumentNullCheck(options.execPath, \"options.execPath\"), execArgv = options.execArgv || process.execArgv, validateArgumentsNullCheck(execArgv, \"options.execArgv\"), execArgv === process.execArgv && process._eval != null) {\n const index = ArrayPrototypeLastIndexOf.call(execArgv, process._eval);\n if (index > 0)\n execArgv = ArrayPrototypeSlice.call(execArgv), ArrayPrototypeSplice.call(execArgv, index - 1, 2);\n }\n if (args = [...execArgv, modulePath, ...args], typeof options.stdio === \"string\")\n options.stdio = stdioStringToArray(options.stdio, \"ipc\");\n else if (!ArrayIsArray(options.stdio))\n options.stdio = stdioStringToArray(options.silent \? \"pipe\" : \"inherit\", \"ipc\");\n else if (!ArrayPrototypeIncludes.call(options.stdio, \"ipc\"))\n throw new ERR_CHILD_PROCESS_IPC_REQUIRED(\"options.stdio\");\n return spawn(options.execPath, args, options);\n}, convertToValidSignal = function(signal) {\n if (typeof signal === \"number\" && getSignalsToNamesMapping()[signal])\n return signal;\n if (typeof signal === \"string\") {\n const signalName = signals[StringPrototypeToUpperCase.call(signal)];\n if (signalName)\n return signalName;\n }\n throw new ERR_UNKNOWN_SIGNAL(signal);\n}, sanitizeKillSignal = function(killSignal2) {\n if (typeof killSignal2 === \"string\" || typeof killSignal2 === \"number\")\n return convertToValidSignal(killSignal2);\n else if (killSignal2 != null)\n throw new ERR_INVALID_ARG_TYPE(\"options.killSignal\", [\"string\", \"number\"], killSignal2);\n}, getSignalsToNamesMapping = function() {\n if (signalsToNamesMapping !== @undefined)\n return signalsToNamesMapping;\n signalsToNamesMapping = ObjectCreate(null);\n for (let key in signals)\n signalsToNamesMapping[signals[key]] = key;\n return signalsToNamesMapping;\n}, normalizeExecFileArgs = function(file, args, options, callback) {\n if (ArrayIsArray(args))\n args = ArrayPrototypeSlice.call(args);\n else if (args != null && typeof args === \"object\")\n callback = options, options = args, args = null;\n else if (typeof args === \"function\")\n callback = args, options = null, args = null;\n if (args == null)\n args = [];\n if (typeof options === \"function\")\n callback = options;\n else if (options != null)\n validateObject(options, \"options\");\n if (options == null)\n options = kEmptyObject;\n if (callback != null)\n validateFunction(callback, \"callback\");\n if (options.argv0 != null)\n validateString(options.argv0, \"options.argv0\"), validateArgumentNullCheck(options.argv0, \"options.argv0\");\n return { file, args, options, callback };\n}, normalizeExecArgs = function(command, options, callback) {\n if (validateString(command, \"command\"), validateArgumentNullCheck(command, \"command\"), typeof options === \"function\")\n callback = options, options = @undefined;\n return options = { ...options }, options.shell = typeof options.shell === \"string\" \? options.shell : !0, {\n file: command,\n options,\n callback\n };\n}, normalizeSpawnArguments = function(file, args, options) {\n if (validateString(file, \"file\"), validateArgumentNullCheck(file, \"file\"), file.length === 0)\n throw new ERR_INVALID_ARG_VALUE(\"file\", file, \"cannot be empty\");\n if (ArrayIsArray(args))\n args = ArrayPrototypeSlice.call(args);\n else if (args == null)\n args = [];\n else if (typeof args !== \"object\")\n throw new ERR_INVALID_ARG_TYPE(\"args\", \"object\", args);\n else\n options = args, args = [];\n if (validateArgumentsNullCheck(args, \"args\"), options === @undefined)\n options = {};\n else\n validateObject(options, \"options\");\n let cwd = options.cwd;\n if (cwd != null)\n cwd = getValidatedPath(cwd, \"options.cwd\");\n var detached = !1;\n const { detached: detachedOption } = options;\n if (detachedOption != null)\n detached = !!detachedOption;\n if (options.shell != null && typeof options.shell !== \"boolean\" && typeof options.shell !== \"string\")\n throw new ERR_INVALID_ARG_TYPE(\"options.shell\", [\"boolean\", \"string\"], options.shell);\n if (options.argv0 != null)\n validateString(options.argv0, \"options.argv0\"), validateArgumentNullCheck(options.argv0, \"options.argv0\");\n if (options.shell) {\n validateArgumentNullCheck(options.shell, \"options.shell\");\n const command = ArrayPrototypeJoin.call([file, ...args], \" \");\n if (typeof options.shell === \"string\")\n file = options.shell;\n else\n file = \"sh\";\n args = [\"-c\", command];\n }\n if (typeof options.argv0 === \"string\")\n ArrayPrototypeUnshift.call(args, options.argv0);\n else\n ArrayPrototypeUnshift.call(args, file);\n const envPairs = options.env || process.env;\n return { ...options, detached, file, args, cwd, envPairs };\n}, checkExecSyncError = function(ret, args, cmd) {\n let err;\n if (ret.error)\n err = ret.error, ObjectAssign(err, ret);\n else if (ret.status !== 0) {\n let msg = \"Command failed: \";\n if (msg += cmd || ArrayPrototypeJoin.call(args, \" \"), ret.stderr && ret.stderr.length > 0)\n msg += `\\n${ret.stderr.toString()}`;\n err = genericNodeError(msg, ret);\n }\n return err;\n}, nodeToBun = function(item) {\n if (typeof item === \"number\")\n return item;\n else {\n const result = nodeToBunLookup[item];\n if (result === @undefined)\n throw new Error(\"Invalid stdio option\");\n return result;\n }\n}, fdToStdioName = function(fd) {\n switch (fd) {\n case 0:\n return \"stdin\";\n case 1:\n return \"stdout\";\n case 2:\n return \"stderr\";\n default:\n return null;\n }\n}, getBunStdioFromOptions = function(stdio) {\n return normalizeStdio(stdio).map((item) => nodeToBun(item));\n}, normalizeStdio = function(stdio) {\n if (typeof stdio === \"string\")\n switch (stdio) {\n case \"ignore\":\n return [\"ignore\", \"ignore\", \"ignore\"];\n case \"pipe\":\n return [\"pipe\", \"pipe\", \"pipe\"];\n case \"inherit\":\n return [\"inherit\", \"inherit\", \"inherit\"];\n default:\n throw new ERR_INVALID_OPT_VALUE(\"stdio\", stdio);\n }\n else if (ArrayIsArray(stdio)) {\n let processedStdio;\n if (stdio.length === 0)\n processedStdio = [\"pipe\", \"pipe\", \"pipe\"];\n else if (stdio.length === 1)\n processedStdio = [stdio[0], \"pipe\", \"pipe\"];\n else if (stdio.length === 2)\n processedStdio = [stdio[0], stdio[1], \"pipe\"];\n else if (stdio.length >= 3)\n processedStdio = [stdio[0], stdio[1], stdio[2]];\n return processedStdio.map((item) => !item \? \"pipe\" : item);\n } else\n throw new ERR_INVALID_OPT_VALUE(\"stdio\", stdio);\n}, flushStdio = function(subprocess) {\n const stdio = subprocess.stdio;\n if (stdio == null)\n return;\n for (let i = 0;i < stdio.length; i++) {\n const stream = stdio[i];\n if (!stream || !stream.readable)\n continue;\n stream.resume();\n }\n}, onSpawnNT = function(self) {\n self.emit(\"spawn\");\n}, abortChildProcess = function(child, killSignal2, reason) {\n if (!child)\n return;\n try {\n if (child.kill(killSignal2))\n child.emit(\"error\", new AbortError(@undefined, { cause: reason }));\n } catch (err) {\n child.emit(\"error\", err);\n }\n}, validateMaxBuffer = function(maxBuffer) {\n if (maxBuffer != null && !(typeof maxBuffer === \"number\" && maxBuffer >= 0))\n throw new ERR_OUT_OF_RANGE(\"options.maxBuffer\", \"a positive number\", maxBuffer);\n}, validateArgumentNullCheck = function(arg, propName) {\n if (typeof arg === \"string\" && StringPrototypeIncludes.call(arg, \"\\0\"))\n throw new ERR_INVALID_ARG_VALUE(propName, arg, \"must be a string without null bytes\");\n}, validateArgumentsNullCheck = function(args, propName) {\n for (let i = 0;i < args.length; ++i)\n validateArgumentNullCheck(args[i], `${propName}[${i}]`);\n}, validateTimeout = function(timeout) {\n if (timeout != null && !(NumberIsInteger(timeout) && timeout >= 0))\n throw new ERR_OUT_OF_RANGE(\"timeout\", \"an unsigned integer\", timeout);\n};\nvar validateFunction = function(value, name) {\n if (typeof value !== \"function\")\n throw new ERR_INVALID_ARG_TYPE(name, \"Function\", value);\n}, validateString = function(value, name) {\n if (typeof value !== \"string\")\n throw new ERR_INVALID_ARG_TYPE(name, \"string\", value);\n}, nullCheck = function(path, propName, throwError = !0) {\n const pathIsString = typeof path === \"string\", pathIsUint8Array = isUint8Array(path);\n if (!pathIsString && !pathIsUint8Array || pathIsString && !StringPrototypeIncludes.call(path, \"\\0\") || pathIsUint8Array && !Uint8ArrayPrototypeIncludes.call(path, 0))\n return;\n const err = new ERR_INVALID_ARG_VALUE(propName, path, \"must be a string or Uint8Array without null bytes\");\n if (throwError)\n throw err;\n return err;\n}, validatePath = function(path, propName = \"path\") {\n if (typeof path !== \"string\" && !isUint8Array(path))\n throw new ERR_INVALID_ARG_TYPE(propName, [\"string\", \"Buffer\", \"URL\"], path);\n const err = nullCheck(path, propName, !1);\n if (err !== @undefined)\n throw err;\n}, getValidatedPath = function(fileURLOrPath, propName = \"path\") {\n const path = toPathIfFileURL(fileURLOrPath);\n return validatePath(path, propName), path;\n}, isUint8Array = function(value) {\n return typeof value === \"object\" && value !== null && value instanceof @Uint8Array;\n}, isURLInstance = function(fileURLOrPath) {\n return fileURLOrPath != null && fileURLOrPath.href && fileURLOrPath.origin;\n}, toPathIfFileURL = function(fileURLOrPath) {\n if (!isURLInstance(fileURLOrPath))\n return fileURLOrPath;\n return Bun.fileURLToPath(fileURLOrPath);\n}, genericNodeError = function(message, options) {\n const err = new Error(message);\n return err.code = options.code, err.killed = options.killed, err.signal = options.signal, err;\n}, ERR_OUT_OF_RANGE = function(str, range, input, replaceDefaultBoolean = !1) {\n return new RangeError(`The value of ${str} is out of range. It must be ${range}. Received ${input}`);\n}, ERR_CHILD_PROCESS_STDIO_MAXBUFFER = function(stdio) {\n return Error(`${stdio} maxBuffer length exceeded`);\n}, ERR_UNKNOWN_SIGNAL = function(name) {\n const err = @makeTypeError(`Unknown signal: ${name}`);\n return err.code = \"ERR_UNKNOWN_SIGNAL\", err;\n}, ERR_INVALID_ARG_TYPE = function(name, type, value) {\n const err = @makeTypeError(`The \"${name}\" argument must be of type ${type}. Received ${value\?.toString()}`);\n return err.code = \"ERR_INVALID_ARG_TYPE\", err;\n}, ERR_INVALID_OPT_VALUE = function(name, value) {\n return @makeTypeError(`The value \"${value}\" is invalid for option \"${name}\"`);\n}, ERR_INVALID_ARG_VALUE = function(name, value, reason) {\n return new Error(`The value \"${value}\" is invalid for argument '${name}'. Reason: ${reason}`);\n}, ERR_CHILD_PROCESS_IPC_REQUIRED = function(name) {\n const err = @makeTypeError(`Forked processes must have an IPC channel, missing value 'ipc' in ${name}`);\n return err.code = \"ERR_CHILD_PROCESS_IPC_REQUIRED\", err;\n}, $, EventEmitter = @getInternalField(@internalModuleRegistry, 18) || @createInternalModuleById(18), StreamModule = @getInternalField(@internalModuleRegistry, 37) || @createInternalModuleById(37), {\n constants: { signals }\n} = @getInternalField(@internalModuleRegistry, 26) || @createInternalModuleById(26), { promisify } = @getInternalField(@internalModuleRegistry, 46) || @createInternalModuleById(46), ObjectCreate = Object.create, ObjectAssign = Object.assign, ObjectDefineProperty = Object.defineProperty, BufferConcat = @Buffer.concat, BufferIsEncoding = @Buffer.isEncoding, kEmptyObject = ObjectCreate(null), ArrayPrototypePush = @Array.prototype.push, ArrayPrototypeJoin = @Array.prototype.join, ArrayPrototypeMap = @Array.prototype.map, ArrayPrototypeIncludes = @Array.prototype.includes, ArrayPrototypeSlice = @Array.prototype.slice, ArrayPrototypeUnshift = @Array.prototype.unshift, ArrayPrototypeLastIndexOf = @Array.prototype.lastIndexOf, ArrayPrototypeSplice = @Array.prototype.splice, ArrayIsArray = @Array.isArray, ArrayBufferIsView = @ArrayBuffer.isView, NumberIsInteger = Number.isInteger;\nvar StringPrototypeToUpperCase = @String.prototype.toUpperCase, StringPrototypeIncludes = @String.prototype.includes, StringPrototypeSlice = @String.prototype.slice, Uint8ArrayPrototypeIncludes = @Uint8Array.prototype.includes, MAX_BUFFER = 1048576, NativeWritable, ReadableFromWeb, customPromiseExecFunction = (orig) => {\n return (...args) => {\n let resolve, reject;\n const promise = new @Promise((res, rej) => {\n resolve = res, reject = rej;\n });\n return promise.child = orig(...args, (err, stdout, stderr) => {\n if (err !== null)\n err.stdout = stdout, err.stderr = stderr, reject(err);\n else\n resolve({ stdout, stderr });\n }), promise;\n };\n};\nObjectDefineProperty(exec, promisify.custom, {\n __proto__: null,\n enumerable: !1,\n value: customPromiseExecFunction(exec)\n});\nvar signalsToNamesMapping;\n\nclass ChildProcess extends EventEmitter {\n constructor() {\n super(...arguments);\n }\n #handle;\n #exited = !1;\n #closesNeeded = 1;\n #closesGot = 0;\n connected = !1;\n signalCode = null;\n exitCode = null;\n spawnfile;\n spawnargs;\n pid;\n channel;\n get killed() {\n if (this.#handle == null)\n return !1;\n }\n #handleOnExit(exitCode, signalCode, err) {\n if (this.#exited)\n return;\n if (signalCode)\n this.signalCode = signalCode;\n else\n this.exitCode = exitCode;\n if (this.#stdin)\n this.#stdin.destroy();\n if (this.#handle)\n this.#handle = null;\n if (exitCode < 0) {\n const err2 = new SystemError(`Spawned process exited with error code: ${exitCode}`, @undefined, \"spawn\", \"EUNKNOWN\", \"ERR_CHILD_PROCESS_UNKNOWN_ERROR\");\n if (this.spawnfile)\n err2.path = this.spawnfile;\n err2.spawnargs = ArrayPrototypeSlice.call(this.spawnargs, 1), this.emit(\"error\", err2);\n } else\n this.emit(\"exit\", this.exitCode, this.signalCode);\n process.nextTick(flushStdio, this), this.#maybeClose(), this.#exited = !0, this.#stdioOptions = [\"destroyed\", \"destroyed\", \"destroyed\"];\n }\n #getBunSpawnIo(i, encoding) {\n NativeWritable ||= StreamModule.NativeWritable, ReadableFromWeb ||= StreamModule.Readable.fromWeb;\n const io = this.#stdioOptions[i];\n switch (i) {\n case 0:\n switch (io) {\n case \"pipe\":\n return new NativeWritable(this.#handle.stdin);\n case \"inherit\":\n return process.stdin || null;\n case \"destroyed\":\n return new ShimmedStdin;\n default:\n return null;\n }\n case 2:\n case 1:\n switch (io) {\n case \"pipe\":\n return ReadableFromWeb(this.#handle[fdToStdioName(i)], { encoding });\n case \"inherit\":\n return process[fdToStdioName(i)] || null;\n case \"destroyed\":\n return new ShimmedStdioOutStream;\n default:\n return null;\n }\n }\n }\n #stdin;\n #stdout;\n #stderr;\n #stdioObject;\n #encoding;\n #stdioOptions;\n #createStdioObject() {\n return Object.create(null, {\n 0: {\n get: () => this.stdin\n },\n 1: {\n get: () => this.stdout\n },\n 2: {\n get: () => this.stderr\n }\n });\n }\n get stdin() {\n return this.#stdin \?\?= this.#getBunSpawnIo(0, this.#encoding);\n }\n get stdout() {\n return this.#stdout \?\?= this.#getBunSpawnIo(1, this.#encoding);\n }\n get stderr() {\n return this.#stderr \?\?= this.#getBunSpawnIo(2, this.#encoding);\n }\n get stdio() {\n return this.#stdioObject \?\?= this.#createStdioObject();\n }\n spawn(options) {\n validateObject(options, \"options\"), validateString(options.file, \"options.file\");\n var file = this.spawnfile = options.file, spawnargs;\n if (options.args == null)\n spawnargs = this.spawnargs = [];\n else\n validateArray(options.args, \"options.args\"), spawnargs = this.spawnargs = options.args;\n const stdio = options.stdio || [\"pipe\", \"pipe\", \"pipe\"], bunStdio = getBunStdioFromOptions(stdio), ipc = @isArray(stdio) && stdio[3] === \"ipc\";\n var env = options.envPairs || @undefined;\n const detachedOption = options.detached;\n if (this.#encoding = options.encoding || @undefined, this.#stdioOptions = bunStdio, this.#handle = Bun.spawn({\n cmd: spawnargs,\n stdin: bunStdio[0],\n stdout: bunStdio[1],\n stderr: bunStdio[2],\n cwd: options.cwd || @undefined,\n env: env || process.env,\n detached: typeof detachedOption !== \"undefined\" \? !!detachedOption : !1,\n onExit: (handle, exitCode, signalCode, err) => {\n this.#handle = handle, this.pid = this.#handle.pid, process.nextTick((exitCode2, signalCode2, err2) => this.#handleOnExit(exitCode2, signalCode2, err2), exitCode, signalCode, err);\n },\n lazy: !0,\n ipc: ipc \? this.#emitIpcMessage.bind(this) : @undefined\n }), this.pid = this.#handle.pid, onSpawnNT(this), ipc)\n this.send = this.#send, this.disconnect = this.#disconnect;\n }\n #emitIpcMessage(message) {\n this.emit(\"message\", message);\n }\n #send(message, handle, options, callback) {\n if (typeof handle === \"function\")\n callback = handle, handle = @undefined, options = @undefined;\n else if (typeof options === \"function\")\n callback = options, options = @undefined;\n else if (options !== @undefined) {\n if (typeof options !== \"object\" || options === null)\n throw new ERR_INVALID_ARG_TYPE(\"options\", \"Object\", options);\n }\n if (!this.#handle) {\n if (callback)\n process.nextTick(callback, @makeTypeError(\"Process was closed while trying to send message\"));\n else\n this.emit(\"error\", @makeTypeError(\"Process was closed while trying to send message\"));\n return !1;\n }\n try {\n if (this.#handle.send(message), callback)\n process.nextTick(callback);\n return !0;\n } catch (error) {\n if (callback)\n process.nextTick(callback, error);\n else\n this.emit(\"error\", error);\n return !1;\n }\n }\n #disconnect() {\n if (!this.connected) {\n this.emit(\"error\", @makeTypeError(\"Process was closed while trying to send message\"));\n return;\n }\n this.connected = !1, this.#handle.disconnect();\n }\n kill(sig) {\n const signal = sig === 0 \? sig : convertToValidSignal(sig === @undefined \? \"SIGTERM\" : sig);\n if (this.#handle)\n this.#handle.kill(signal);\n return this.#maybeClose(), !0;\n }\n #maybeClose() {\n if (this.#closesGot++, this.#closesGot === this.#closesNeeded)\n this.emit(\"close\", this.exitCode, this.signalCode);\n }\n ref() {\n if (this.#handle)\n this.#handle.ref();\n }\n unref() {\n if (this.#handle)\n this.#handle.unref();\n }\n}\nvar nodeToBunLookup = {\n ignore: null,\n pipe: \"pipe\",\n overlapped: \"pipe\",\n inherit: \"inherit\"\n};\n\nclass ShimmedStdin extends EventEmitter {\n constructor() {\n super();\n }\n write() {\n return !1;\n }\n destroy() {\n }\n end() {\n }\n pipe() {\n }\n}\n\nclass ShimmedStdioOutStream extends EventEmitter {\n constructor() {\n super(...arguments);\n }\n pipe() {\n }\n}\nvar validateAbortSignal = (signal, name) => {\n if (signal !== @undefined && (signal === null || typeof signal !== \"object\" || !(\"aborted\" in signal)))\n throw new ERR_INVALID_ARG_TYPE(name, \"AbortSignal\", signal);\n};\nvar validateObject = (value, name, options = null) => {\n const allowArray = options\?.allowArray \?\? !1, allowFunction = options\?.allowFunction \?\? !1;\n if (!(options\?.nullable \?\? !1) && value === null || !allowArray && ArrayIsArray.call(value) || typeof value !== \"object\" && (!allowFunction || typeof value !== \"function\"))\n throw new ERR_INVALID_ARG_TYPE(name, \"object\", value);\n}, validateArray = (value, name, minLength = 0) => {\n if (!ArrayIsArray(value))\n throw new ERR_INVALID_ARG_TYPE(name, \"Array\", value);\n if (value.length < minLength) {\n const reason = `must be longer than ${minLength}`;\n throw new ERR_INVALID_ARG_VALUE(name, value, reason);\n }\n}, Error = globalThis.Error, TypeError = globalThis.TypeError, RangeError = globalThis.RangeError;\n\nclass AbortError extends Error {\n code = \"ABORT_ERR\";\n name = \"AbortError\";\n constructor(message = \"The operation was aborted\", options = @undefined) {\n if (options !== @undefined && typeof options !== \"object\")\n throw new ERR_INVALID_ARG_TYPE(\"options\", \"Object\", options);\n super(message, options);\n }\n}\n\nclass SystemError extends Error {\n path;\n syscall;\n errno;\n code;\n constructor(message, path, syscall, errno, code) {\n super(message);\n this.path = path, this.syscall = syscall, this.errno = errno, this.code = code;\n }\n get name() {\n return \"SystemError\";\n }\n}\n$ = {\n ChildProcess,\n spawn,\n execFile,\n exec,\n fork,\n spawnSync,\n execFileSync,\n execSync\n};\nreturn $})\n"_s; +static constexpr ASCIILiteral NodeChildProcessCode = "(function (){\"use strict\";// src/js/out/tmp/node/child_process.ts\nvar spawn = function(file, args, options) {\n options = normalizeSpawnArguments(file, args, options), validateTimeout(options.timeout), validateAbortSignal(options.signal, \"options.signal\");\n const killSignal2 = sanitizeKillSignal(options.killSignal), child = new ChildProcess;\n if (child.spawn(options), options.timeout > 0) {\n let timeoutId = setTimeout(() => {\n if (timeoutId) {\n try {\n child.kill(killSignal2);\n } catch (err) {\n child.emit(\"error\", err);\n }\n timeoutId = null;\n }\n });\n child.once(\"exit\", () => {\n if (timeoutId)\n clearTimeout(timeoutId), timeoutId = null;\n });\n }\n if (options.signal) {\n let onAbortListener2 = function() {\n abortChildProcess(child, killSignal2, options.signal.reason);\n };\n var onAbortListener = onAbortListener2;\n const signal = options.signal;\n if (signal.aborted)\n process.nextTick(onAbortListener2);\n else\n signal.addEventListener(\"abort\", onAbortListener2, { once: !0 }), child.once(\"exit\", () => signal.removeEventListener(\"abort\", onAbortListener2));\n }\n return child;\n}, execFile = function(file, args, options, callback) {\n ({ file, args, options, callback } = normalizeExecFileArgs(file, args, options, callback)), options = {\n encoding: \"utf8\",\n timeout: 0,\n maxBuffer: MAX_BUFFER,\n killSignal: \"SIGTERM\",\n cwd: null,\n env: null,\n shell: !1,\n ...options\n };\n const maxBuffer = options.maxBuffer;\n validateTimeout(options.timeout), validateMaxBuffer(maxBuffer), options.killSignal = sanitizeKillSignal(options.killSignal);\n const child = spawn(file, args, {\n cwd: options.cwd,\n env: options.env,\n shell: options.shell,\n signal: options.signal\n });\n let encoding;\n const _stdout = [], _stderr = [];\n if (options.encoding !== \"buffer\" && BufferIsEncoding(options.encoding))\n encoding = options.encoding;\n else\n encoding = null;\n let stdoutLen = 0, stderrLen = 0, killed = !1, exited = !1, timeoutId, encodedStdoutLen, encodedStderrLen, ex = null, cmd = file;\n function exitHandler(code, signal) {\n if (exited)\n return;\n if (exited = !0, timeoutId)\n clearTimeout(timeoutId), timeoutId = null;\n if (!callback)\n return;\n const readableEncoding = child\?.stdout\?.readableEncoding;\n let stdout, stderr;\n if (encoding || child.stdout && readableEncoding)\n stdout = ArrayPrototypeJoin.call(_stdout, \"\");\n else\n stdout = BufferConcat(_stdout);\n if (encoding || child.stderr && readableEncoding)\n stderr = ArrayPrototypeJoin.call(_stderr, \"\");\n else\n stderr = BufferConcat(_stderr);\n if (!ex && code === 0 && signal === null) {\n callback(null, stdout, stderr);\n return;\n }\n if (args\?.length)\n cmd += ` ${ArrayPrototypeJoin.call(args, \" \")}`;\n if (!ex) {\n let message = `Command failed: ${cmd}`;\n if (stderr)\n message += `\\n${stderr}`;\n ex = genericNodeError(message, {\n code,\n killed: child.killed || killed,\n signal\n });\n }\n ex.cmd = cmd, callback(ex, stdout, stderr);\n }\n function errorHandler(e) {\n if (ex = e, child.stdout)\n child.stdout.destroy();\n if (child.stderr)\n child.stderr.destroy();\n exitHandler();\n }\n function kill() {\n if (child.stdout)\n child.stdout.destroy();\n if (child.stderr)\n child.stderr.destroy();\n killed = !0;\n try {\n child.kill(options.killSignal);\n } catch (e) {\n ex = e, exitHandler();\n }\n }\n if (options.timeout > 0)\n timeoutId = setTimeout(function delayedKill() {\n kill(), timeoutId = null;\n }, options.timeout);\n if (child.stdout) {\n if (encoding)\n child.stdout.setEncoding(encoding);\n child.stdout.on(\"data\", maxBuffer === @Infinity \? function onUnlimitedSizeBufferedData(chunk) {\n ArrayPrototypePush.call(_stdout, chunk);\n } : encoding \? function onChildStdoutEncoded(chunk) {\n if (stdoutLen += chunk.length, stdoutLen * 4 > maxBuffer) {\n const encoding2 = child.stdout.readableEncoding, actualLen = @Buffer.byteLength(chunk, encoding2);\n if (encodedStdoutLen === @undefined)\n for (let i = 0;i < _stdout.length; i++)\n encodedStdoutLen += @Buffer.byteLength(_stdout[i], encoding2);\n else\n encodedStdoutLen += actualLen;\n const truncatedLen = maxBuffer - (encodedStdoutLen - actualLen);\n ArrayPrototypePush.call(_stdout, StringPrototypeSlice.apply(chunk, 0, truncatedLen)), ex = new ERR_CHILD_PROCESS_STDIO_MAXBUFFER(\"stdout\"), kill();\n } else\n ArrayPrototypePush.call(_stdout, chunk);\n } : function onChildStdoutRaw(chunk) {\n if (stdoutLen += chunk.length, stdoutLen > maxBuffer) {\n const truncatedLen = maxBuffer - (stdoutLen - chunk.length);\n ArrayPrototypePush.call(_stdout, chunk.slice(0, truncatedLen)), ex = new ERR_CHILD_PROCESS_STDIO_MAXBUFFER(\"stdout\"), kill();\n } else\n ArrayPrototypePush.call(_stdout, chunk);\n });\n }\n if (child.stderr) {\n if (encoding)\n child.stderr.setEncoding(encoding);\n child.stderr.on(\"data\", maxBuffer === @Infinity \? function onUnlimitedSizeBufferedData(chunk) {\n ArrayPrototypePush.call(_stderr, chunk);\n } : encoding \? function onChildStderrEncoded(chunk) {\n if (stderrLen += chunk.length, stderrLen * 4 > maxBuffer) {\n const encoding2 = child.stderr.readableEncoding, actualLen = @Buffer.byteLength(chunk, encoding2);\n if (encodedStderrLen === @undefined)\n for (let i = 0;i < _stderr.length; i++)\n encodedStderrLen += @Buffer.byteLength(_stderr[i], encoding2);\n else\n encodedStderrLen += actualLen;\n const truncatedLen = maxBuffer - (encodedStderrLen - actualLen);\n ArrayPrototypePush.call(_stderr, StringPrototypeSlice.call(chunk, 0, truncatedLen)), ex = new ERR_CHILD_PROCESS_STDIO_MAXBUFFER(\"stderr\"), kill();\n } else\n ArrayPrototypePush.call(_stderr, chunk);\n } : function onChildStderrRaw(chunk) {\n if (stderrLen += chunk.length, stderrLen > maxBuffer) {\n const truncatedLen = maxBuffer - (stderrLen - chunk.length);\n ArrayPrototypePush.call(_stderr, StringPrototypeSlice.call(chunk, 0, truncatedLen)), ex = new ERR_CHILD_PROCESS_STDIO_MAXBUFFER(\"stderr\"), kill();\n } else\n ArrayPrototypePush.call(_stderr, chunk);\n });\n }\n return child.addListener(\"close\", exitHandler), child.addListener(\"error\", errorHandler), child;\n}, exec = function(command, options, callback) {\n const opts = normalizeExecArgs(command, options, callback);\n return execFile(opts.file, opts.options, opts.callback);\n}, spawnSync = function(file, args, options) {\n options = {\n maxBuffer: MAX_BUFFER,\n ...normalizeSpawnArguments(file, args, options)\n };\n const { maxBuffer, encoding } = options;\n validateTimeout(options.timeout), validateMaxBuffer(maxBuffer), options.killSignal = sanitizeKillSignal(options.killSignal);\n const stdio = options.stdio || \"pipe\", bunStdio = getBunStdioFromOptions(stdio);\n var { input } = options;\n if (input)\n if (ArrayBufferIsView(input))\n bunStdio[0] = input;\n else if (typeof input === \"string\")\n bunStdio[0] = @Buffer.from(input, encoding || \"utf8\");\n else\n throw new ERR_INVALID_ARG_TYPE(\"options.stdio[0]\", [\"Buffer\", \"TypedArray\", \"DataView\", \"string\"], input);\n const { stdout, stderr, success, exitCode } = Bun.spawnSync({\n cmd: options.args,\n env: options.env || @undefined,\n cwd: options.cwd || @undefined,\n stdin: bunStdio[0],\n stdout: bunStdio[1],\n stderr: bunStdio[2]\n }), result = {\n signal: null,\n status: exitCode,\n output: [null, stdout, stderr]\n };\n if (stdout && encoding && encoding !== \"buffer\")\n result.output[1] = result.output[1]\?.toString(encoding);\n if (stderr && encoding && encoding !== \"buffer\")\n result.output[2] = result.output[2]\?.toString(encoding);\n if (result.stdout = result.output[1], result.stderr = result.output[2], !success)\n result.error = new SystemError(result.output[2], options.file, \"spawnSync\", -1, result.status), result.error.spawnargs = ArrayPrototypeSlice.call(options.args, 1);\n return result;\n}, execFileSync = function(file, args, options) {\n ({ file, args, options } = normalizeExecFileArgs(file, args, options));\n const ret = spawnSync(file, args, options), errArgs = [options.argv0 || file];\n ArrayPrototypePush.apply(errArgs, args);\n const err = checkExecSyncError(ret, errArgs);\n if (err)\n throw err;\n return ret.stdout;\n}, execSync = function(command, options) {\n const opts = normalizeExecArgs(command, options, null), ret = spawnSync(opts.file, opts.options), err = checkExecSyncError(ret, @undefined, command);\n if (err)\n throw err;\n return ret.stdout;\n}, stdioStringToArray = function(stdio, channel) {\n const options = [];\n switch (stdio) {\n case \"ignore\":\n case \"overlapped\":\n case \"pipe\":\n ArrayPrototypePush.call(options, stdio, stdio, stdio);\n break;\n case \"inherit\":\n ArrayPrototypePush.call(options, 0, 1, 2);\n break;\n default:\n throw new ERR_INVALID_ARG_VALUE(\"stdio\", stdio);\n }\n if (channel)\n ArrayPrototypePush.call(options, channel);\n return options;\n}, fork = function(modulePath, args = [], options) {\n modulePath = getValidatedPath(modulePath, \"modulePath\");\n let execArgv;\n if (args == null)\n args = [];\n else if (typeof args === \"object\" && !ArrayIsArray(args))\n options = args, args = [];\n else\n validateArray(args, \"args\");\n if (options != null)\n validateObject(options, \"options\");\n if (options = { __proto__: null, ...options, shell: !1 }, options.execPath = options.execPath || process.execPath, validateArgumentNullCheck(options.execPath, \"options.execPath\"), execArgv = options.execArgv || process.execArgv, validateArgumentsNullCheck(execArgv, \"options.execArgv\"), execArgv === process.execArgv && process._eval != null) {\n const index = ArrayPrototypeLastIndexOf.call(execArgv, process._eval);\n if (index > 0)\n execArgv = ArrayPrototypeSlice.call(execArgv), ArrayPrototypeSplice.call(execArgv, index - 1, 2);\n }\n if (args = [...execArgv, modulePath, ...args], typeof options.stdio === \"string\")\n options.stdio = stdioStringToArray(options.stdio, \"ipc\");\n else if (!ArrayIsArray(options.stdio))\n options.stdio = stdioStringToArray(options.silent \? \"pipe\" : \"inherit\", \"ipc\");\n else if (!ArrayPrototypeIncludes.call(options.stdio, \"ipc\"))\n throw new ERR_CHILD_PROCESS_IPC_REQUIRED(\"options.stdio\");\n return spawn(options.execPath, args, options);\n}, convertToValidSignal = function(signal) {\n if (typeof signal === \"number\" && getSignalsToNamesMapping()[signal])\n return signal;\n if (typeof signal === \"string\") {\n const signalName = signals[StringPrototypeToUpperCase.call(signal)];\n if (signalName)\n return signalName;\n }\n throw new ERR_UNKNOWN_SIGNAL(signal);\n}, sanitizeKillSignal = function(killSignal2) {\n if (typeof killSignal2 === \"string\" || typeof killSignal2 === \"number\")\n return convertToValidSignal(killSignal2);\n else if (killSignal2 != null)\n throw new ERR_INVALID_ARG_TYPE(\"options.killSignal\", [\"string\", \"number\"], killSignal2);\n}, getSignalsToNamesMapping = function() {\n if (signalsToNamesMapping !== @undefined)\n return signalsToNamesMapping;\n signalsToNamesMapping = ObjectCreate(null);\n for (let key in signals)\n signalsToNamesMapping[signals[key]] = key;\n return signalsToNamesMapping;\n}, normalizeExecFileArgs = function(file, args, options, callback) {\n if (ArrayIsArray(args))\n args = ArrayPrototypeSlice.call(args);\n else if (args != null && typeof args === \"object\")\n callback = options, options = args, args = null;\n else if (typeof args === \"function\")\n callback = args, options = null, args = null;\n if (args == null)\n args = [];\n if (typeof options === \"function\")\n callback = options;\n else if (options != null)\n validateObject(options, \"options\");\n if (options == null)\n options = kEmptyObject;\n if (callback != null)\n validateFunction(callback, \"callback\");\n if (options.argv0 != null)\n validateString(options.argv0, \"options.argv0\"), validateArgumentNullCheck(options.argv0, \"options.argv0\");\n return { file, args, options, callback };\n}, normalizeExecArgs = function(command, options, callback) {\n if (validateString(command, \"command\"), validateArgumentNullCheck(command, \"command\"), typeof options === \"function\")\n callback = options, options = @undefined;\n return options = { ...options }, options.shell = typeof options.shell === \"string\" \? options.shell : !0, {\n file: command,\n options,\n callback\n };\n}, normalizeSpawnArguments = function(file, args, options) {\n if (validateString(file, \"file\"), validateArgumentNullCheck(file, \"file\"), file.length === 0)\n throw new ERR_INVALID_ARG_VALUE(\"file\", file, \"cannot be empty\");\n if (ArrayIsArray(args))\n args = ArrayPrototypeSlice.call(args);\n else if (args == null)\n args = [];\n else if (typeof args !== \"object\")\n throw new ERR_INVALID_ARG_TYPE(\"args\", \"object\", args);\n else\n options = args, args = [];\n if (validateArgumentsNullCheck(args, \"args\"), options === @undefined)\n options = {};\n else\n validateObject(options, \"options\");\n let cwd = options.cwd;\n if (cwd != null)\n cwd = getValidatedPath(cwd, \"options.cwd\");\n var detached = !1;\n const { detached: detachedOption } = options;\n if (detachedOption != null)\n detached = !!detachedOption;\n if (options.shell != null && typeof options.shell !== \"boolean\" && typeof options.shell !== \"string\")\n throw new ERR_INVALID_ARG_TYPE(\"options.shell\", [\"boolean\", \"string\"], options.shell);\n if (options.argv0 != null)\n validateString(options.argv0, \"options.argv0\"), validateArgumentNullCheck(options.argv0, \"options.argv0\");\n if (options.shell) {\n validateArgumentNullCheck(options.shell, \"options.shell\");\n const command = ArrayPrototypeJoin.call([file, ...args], \" \");\n if (typeof options.shell === \"string\")\n file = options.shell;\n else\n file = \"sh\";\n args = [\"-c\", command];\n }\n if (typeof options.argv0 === \"string\")\n ArrayPrototypeUnshift.call(args, options.argv0);\n else\n ArrayPrototypeUnshift.call(args, file);\n const envPairs = options.env || process.env;\n return { ...options, detached, file, args, cwd, envPairs };\n}, checkExecSyncError = function(ret, args, cmd) {\n let err;\n if (ret.error)\n err = ret.error, ObjectAssign(err, ret);\n else if (ret.status !== 0) {\n let msg = \"Command failed: \";\n if (msg += cmd || ArrayPrototypeJoin.call(args, \" \"), ret.stderr && ret.stderr.length > 0)\n msg += `\\n${ret.stderr.toString()}`;\n err = genericNodeError(msg, ret);\n }\n return err;\n}, nodeToBun = function(item) {\n if (typeof item === \"number\")\n return item;\n else {\n const result = nodeToBunLookup[item];\n if (result === @undefined)\n throw new Error(`Invalid stdio option \"${item}\"`);\n return result;\n }\n}, fdToStdioName = function(fd) {\n switch (fd) {\n case 0:\n return \"stdin\";\n case 1:\n return \"stdout\";\n case 2:\n return \"stderr\";\n default:\n return null;\n }\n}, getBunStdioFromOptions = function(stdio) {\n return normalizeStdio(stdio).map((item) => nodeToBun(item));\n}, normalizeStdio = function(stdio) {\n if (typeof stdio === \"string\")\n switch (stdio) {\n case \"ignore\":\n return [\"ignore\", \"ignore\", \"ignore\"];\n case \"pipe\":\n return [\"pipe\", \"pipe\", \"pipe\"];\n case \"inherit\":\n return [\"inherit\", \"inherit\", \"inherit\"];\n default:\n throw new ERR_INVALID_OPT_VALUE(\"stdio\", stdio);\n }\n else if (ArrayIsArray(stdio)) {\n let processedStdio;\n if (stdio.length === 0)\n processedStdio = [\"pipe\", \"pipe\", \"pipe\"];\n else if (stdio.length === 1)\n processedStdio = [stdio[0], \"pipe\", \"pipe\"];\n else if (stdio.length === 2)\n processedStdio = [stdio[0], stdio[1], \"pipe\"];\n else if (stdio.length >= 3)\n processedStdio = [stdio[0], stdio[1], stdio[2]];\n return processedStdio.map((item) => !item \? \"pipe\" : item);\n } else\n throw new ERR_INVALID_OPT_VALUE(\"stdio\", stdio);\n}, flushStdio = function(subprocess) {\n const stdio = subprocess.stdio;\n if (stdio == null)\n return;\n for (let i = 0;i < stdio.length; i++) {\n const stream = stdio[i];\n if (!stream || !stream.readable)\n continue;\n stream.resume();\n }\n}, onSpawnNT = function(self) {\n self.emit(\"spawn\");\n}, abortChildProcess = function(child, killSignal2, reason) {\n if (!child)\n return;\n try {\n if (child.kill(killSignal2))\n child.emit(\"error\", new AbortError(@undefined, { cause: reason }));\n } catch (err) {\n child.emit(\"error\", err);\n }\n}, validateMaxBuffer = function(maxBuffer) {\n if (maxBuffer != null && !(typeof maxBuffer === \"number\" && maxBuffer >= 0))\n throw new ERR_OUT_OF_RANGE(\"options.maxBuffer\", \"a positive number\", maxBuffer);\n}, validateArgumentNullCheck = function(arg, propName) {\n if (typeof arg === \"string\" && StringPrototypeIncludes.call(arg, \"\\0\"))\n throw new ERR_INVALID_ARG_VALUE(propName, arg, \"must be a string without null bytes\");\n}, validateArgumentsNullCheck = function(args, propName) {\n for (let i = 0;i < args.length; ++i)\n validateArgumentNullCheck(args[i], `${propName}[${i}]`);\n}, validateTimeout = function(timeout) {\n if (timeout != null && !(NumberIsInteger(timeout) && timeout >= 0))\n throw new ERR_OUT_OF_RANGE(\"timeout\", \"an unsigned integer\", timeout);\n};\nvar validateFunction = function(value, name) {\n if (typeof value !== \"function\")\n throw new ERR_INVALID_ARG_TYPE(name, \"Function\", value);\n}, validateString = function(value, name) {\n if (typeof value !== \"string\")\n throw new ERR_INVALID_ARG_TYPE(name, \"string\", value);\n}, nullCheck = function(path, propName, throwError = !0) {\n const pathIsString = typeof path === \"string\", pathIsUint8Array = isUint8Array(path);\n if (!pathIsString && !pathIsUint8Array || pathIsString && !StringPrototypeIncludes.call(path, \"\\0\") || pathIsUint8Array && !Uint8ArrayPrototypeIncludes.call(path, 0))\n return;\n const err = new ERR_INVALID_ARG_VALUE(propName, path, \"must be a string or Uint8Array without null bytes\");\n if (throwError)\n throw err;\n return err;\n}, validatePath = function(path, propName = \"path\") {\n if (typeof path !== \"string\" && !isUint8Array(path))\n throw new ERR_INVALID_ARG_TYPE(propName, [\"string\", \"Buffer\", \"URL\"], path);\n const err = nullCheck(path, propName, !1);\n if (err !== @undefined)\n throw err;\n}, getValidatedPath = function(fileURLOrPath, propName = \"path\") {\n const path = toPathIfFileURL(fileURLOrPath);\n return validatePath(path, propName), path;\n}, isUint8Array = function(value) {\n return typeof value === \"object\" && value !== null && value instanceof @Uint8Array;\n}, isURLInstance = function(fileURLOrPath) {\n return fileURLOrPath != null && fileURLOrPath.href && fileURLOrPath.origin;\n}, toPathIfFileURL = function(fileURLOrPath) {\n if (!isURLInstance(fileURLOrPath))\n return fileURLOrPath;\n return Bun.fileURLToPath(fileURLOrPath);\n}, genericNodeError = function(message, options) {\n const err = new Error(message);\n return err.code = options.code, err.killed = options.killed, err.signal = options.signal, err;\n}, ERR_OUT_OF_RANGE = function(str, range, input, replaceDefaultBoolean = !1) {\n return new RangeError(`The value of ${str} is out of range. It must be ${range}. Received ${input}`);\n}, ERR_CHILD_PROCESS_STDIO_MAXBUFFER = function(stdio) {\n return Error(`${stdio} maxBuffer length exceeded`);\n}, ERR_UNKNOWN_SIGNAL = function(name) {\n const err = @makeTypeError(`Unknown signal: ${name}`);\n return err.code = \"ERR_UNKNOWN_SIGNAL\", err;\n}, ERR_INVALID_ARG_TYPE = function(name, type, value) {\n const err = @makeTypeError(`The \"${name}\" argument must be of type ${type}. Received ${value\?.toString()}`);\n return err.code = \"ERR_INVALID_ARG_TYPE\", err;\n}, ERR_INVALID_OPT_VALUE = function(name, value) {\n return @makeTypeError(`The value \"${value}\" is invalid for option \"${name}\"`);\n}, ERR_INVALID_ARG_VALUE = function(name, value, reason) {\n return new Error(`The value \"${value}\" is invalid for argument '${name}'. Reason: ${reason}`);\n}, ERR_CHILD_PROCESS_IPC_REQUIRED = function(name) {\n const err = @makeTypeError(`Forked processes must have an IPC channel, missing value 'ipc' in ${name}`);\n return err.code = \"ERR_CHILD_PROCESS_IPC_REQUIRED\", err;\n}, $, EventEmitter = @getInternalField(@internalModuleRegistry, 18) || @createInternalModuleById(18), StreamModule = @getInternalField(@internalModuleRegistry, 37) || @createInternalModuleById(37), {\n constants: { signals }\n} = @getInternalField(@internalModuleRegistry, 26) || @createInternalModuleById(26), { promisify } = @getInternalField(@internalModuleRegistry, 46) || @createInternalModuleById(46), ObjectCreate = Object.create, ObjectAssign = Object.assign, ObjectDefineProperty = Object.defineProperty, BufferConcat = @Buffer.concat, BufferIsEncoding = @Buffer.isEncoding, kEmptyObject = ObjectCreate(null), ArrayPrototypePush = @Array.prototype.push, ArrayPrototypeJoin = @Array.prototype.join, ArrayPrototypeMap = @Array.prototype.map, ArrayPrototypeIncludes = @Array.prototype.includes, ArrayPrototypeSlice = @Array.prototype.slice, ArrayPrototypeUnshift = @Array.prototype.unshift, ArrayPrototypeLastIndexOf = @Array.prototype.lastIndexOf, ArrayPrototypeSplice = @Array.prototype.splice, ArrayIsArray = @Array.isArray, ArrayBufferIsView = @ArrayBuffer.isView, NumberIsInteger = Number.isInteger;\nvar StringPrototypeToUpperCase = @String.prototype.toUpperCase, StringPrototypeIncludes = @String.prototype.includes, StringPrototypeSlice = @String.prototype.slice, Uint8ArrayPrototypeIncludes = @Uint8Array.prototype.includes, MAX_BUFFER = 1048576, NativeWritable, ReadableFromWeb, customPromiseExecFunction = (orig) => {\n return (...args) => {\n let resolve, reject;\n const promise = new @Promise((res, rej) => {\n resolve = res, reject = rej;\n });\n return promise.child = orig(...args, (err, stdout, stderr) => {\n if (err !== null)\n err.stdout = stdout, err.stderr = stderr, reject(err);\n else\n resolve({ stdout, stderr });\n }), promise;\n };\n};\nObjectDefineProperty(exec, promisify.custom, {\n __proto__: null,\n enumerable: !1,\n value: customPromiseExecFunction(exec)\n});\nvar signalsToNamesMapping;\n\nclass ChildProcess extends EventEmitter {\n constructor() {\n super(...arguments);\n }\n #handle;\n #exited = !1;\n #closesNeeded = 1;\n #closesGot = 0;\n connected = !1;\n signalCode = null;\n exitCode = null;\n spawnfile;\n spawnargs;\n pid;\n channel;\n get killed() {\n if (this.#handle == null)\n return !1;\n }\n #handleOnExit(exitCode, signalCode, err) {\n if (this.#exited)\n return;\n if (signalCode)\n this.signalCode = signalCode;\n else\n this.exitCode = exitCode;\n if (this.#stdin)\n this.#stdin.destroy();\n if (this.#handle)\n this.#handle = null;\n if (exitCode < 0) {\n const err2 = new SystemError(`Spawned process exited with error code: ${exitCode}`, @undefined, \"spawn\", \"EUNKNOWN\", \"ERR_CHILD_PROCESS_UNKNOWN_ERROR\");\n if (this.spawnfile)\n err2.path = this.spawnfile;\n err2.spawnargs = ArrayPrototypeSlice.call(this.spawnargs, 1), this.emit(\"error\", err2);\n } else\n this.emit(\"exit\", this.exitCode, this.signalCode);\n process.nextTick(flushStdio, this), this.#maybeClose(), this.#exited = !0, this.#stdioOptions = [\"destroyed\", \"destroyed\", \"destroyed\"];\n }\n #getBunSpawnIo(i, encoding) {\n NativeWritable ||= StreamModule.NativeWritable, ReadableFromWeb ||= StreamModule.Readable.fromWeb;\n const io = this.#stdioOptions[i];\n switch (i) {\n case 0:\n switch (io) {\n case \"pipe\":\n return new NativeWritable(this.#handle.stdin);\n case \"inherit\":\n return process.stdin || null;\n case \"destroyed\":\n return new ShimmedStdin;\n default:\n return null;\n }\n case 2:\n case 1:\n switch (io) {\n case \"pipe\":\n return ReadableFromWeb(this.#handle[fdToStdioName(i)], { encoding });\n case \"inherit\":\n return process[fdToStdioName(i)] || null;\n case \"destroyed\":\n return new ShimmedStdioOutStream;\n default:\n return null;\n }\n }\n }\n #stdin;\n #stdout;\n #stderr;\n #stdioObject;\n #encoding;\n #stdioOptions;\n #createStdioObject() {\n return Object.create(null, {\n 0: {\n get: () => this.stdin\n },\n 1: {\n get: () => this.stdout\n },\n 2: {\n get: () => this.stderr\n }\n });\n }\n get stdin() {\n return this.#stdin \?\?= this.#getBunSpawnIo(0, this.#encoding);\n }\n get stdout() {\n return this.#stdout \?\?= this.#getBunSpawnIo(1, this.#encoding);\n }\n get stderr() {\n return this.#stderr \?\?= this.#getBunSpawnIo(2, this.#encoding);\n }\n get stdio() {\n return this.#stdioObject \?\?= this.#createStdioObject();\n }\n spawn(options) {\n validateObject(options, \"options\"), validateString(options.file, \"options.file\");\n var file = this.spawnfile = options.file, spawnargs;\n if (options.args == null)\n spawnargs = this.spawnargs = [];\n else\n validateArray(options.args, \"options.args\"), spawnargs = this.spawnargs = options.args;\n const stdio = options.stdio || [\"pipe\", \"pipe\", \"pipe\"], bunStdio = getBunStdioFromOptions(stdio), ipc = @isArray(stdio) && stdio[3] === \"ipc\";\n var env = options.envPairs || @undefined;\n const detachedOption = options.detached;\n if (this.#encoding = options.encoding || @undefined, this.#stdioOptions = bunStdio, this.#handle = Bun.spawn({\n cmd: spawnargs,\n stdin: bunStdio[0],\n stdout: bunStdio[1],\n stderr: bunStdio[2],\n cwd: options.cwd || @undefined,\n env: env || process.env,\n detached: typeof detachedOption !== \"undefined\" \? !!detachedOption : !1,\n onExit: (handle, exitCode, signalCode, err) => {\n this.#handle = handle, this.pid = this.#handle.pid, process.nextTick((exitCode2, signalCode2, err2) => this.#handleOnExit(exitCode2, signalCode2, err2), exitCode, signalCode, err);\n },\n lazy: !0,\n ipc: ipc \? this.#emitIpcMessage.bind(this) : @undefined\n }), this.pid = this.#handle.pid, onSpawnNT(this), ipc)\n this.send = this.#send, this.disconnect = this.#disconnect;\n }\n #emitIpcMessage(message) {\n this.emit(\"message\", message);\n }\n #send(message, handle, options, callback) {\n if (typeof handle === \"function\")\n callback = handle, handle = @undefined, options = @undefined;\n else if (typeof options === \"function\")\n callback = options, options = @undefined;\n else if (options !== @undefined) {\n if (typeof options !== \"object\" || options === null)\n throw new ERR_INVALID_ARG_TYPE(\"options\", \"Object\", options);\n }\n if (!this.#handle) {\n if (callback)\n process.nextTick(callback, @makeTypeError(\"Process was closed while trying to send message\"));\n else\n this.emit(\"error\", @makeTypeError(\"Process was closed while trying to send message\"));\n return !1;\n }\n try {\n if (this.#handle.send(message), callback)\n process.nextTick(callback);\n return !0;\n } catch (error) {\n if (callback)\n process.nextTick(callback, error);\n else\n this.emit(\"error\", error);\n return !1;\n }\n }\n #disconnect() {\n if (!this.connected) {\n this.emit(\"error\", @makeTypeError(\"Process was closed while trying to send message\"));\n return;\n }\n this.connected = !1, this.#handle.disconnect();\n }\n kill(sig) {\n const signal = sig === 0 \? sig : convertToValidSignal(sig === @undefined \? \"SIGTERM\" : sig);\n if (this.#handle)\n this.#handle.kill(signal);\n return this.#maybeClose(), !0;\n }\n #maybeClose() {\n if (this.#closesGot++, this.#closesGot === this.#closesNeeded)\n this.emit(\"close\", this.exitCode, this.signalCode);\n }\n ref() {\n if (this.#handle)\n this.#handle.ref();\n }\n unref() {\n if (this.#handle)\n this.#handle.unref();\n }\n}\nvar nodeToBunLookup = {\n ignore: null,\n pipe: \"pipe\",\n overlapped: \"pipe\",\n inherit: \"inherit\"\n};\n\nclass ShimmedStdin extends EventEmitter {\n constructor() {\n super();\n }\n write() {\n return !1;\n }\n destroy() {\n }\n end() {\n }\n pipe() {\n }\n}\n\nclass ShimmedStdioOutStream extends EventEmitter {\n constructor() {\n super(...arguments);\n }\n pipe() {\n }\n}\nvar validateAbortSignal = (signal, name) => {\n if (signal !== @undefined && (signal === null || typeof signal !== \"object\" || !(\"aborted\" in signal)))\n throw new ERR_INVALID_ARG_TYPE(name, \"AbortSignal\", signal);\n};\nvar validateObject = (value, name, options = null) => {\n const allowArray = options\?.allowArray \?\? !1, allowFunction = options\?.allowFunction \?\? !1;\n if (!(options\?.nullable \?\? !1) && value === null || !allowArray && ArrayIsArray.call(value) || typeof value !== \"object\" && (!allowFunction || typeof value !== \"function\"))\n throw new ERR_INVALID_ARG_TYPE(name, \"object\", value);\n}, validateArray = (value, name, minLength = 0) => {\n if (!ArrayIsArray(value))\n throw new ERR_INVALID_ARG_TYPE(name, \"Array\", value);\n if (value.length < minLength) {\n const reason = `must be longer than ${minLength}`;\n throw new ERR_INVALID_ARG_VALUE(name, value, reason);\n }\n}, Error = globalThis.Error, TypeError = globalThis.TypeError, RangeError = globalThis.RangeError;\n\nclass AbortError extends Error {\n code = \"ABORT_ERR\";\n name = \"AbortError\";\n constructor(message = \"The operation was aborted\", options = @undefined) {\n if (options !== @undefined && typeof options !== \"object\")\n throw new ERR_INVALID_ARG_TYPE(\"options\", \"Object\", options);\n super(message, options);\n }\n}\n\nclass SystemError extends Error {\n path;\n syscall;\n errno;\n code;\n constructor(message, path, syscall, errno, code) {\n super(message);\n this.path = path, this.syscall = syscall, this.errno = errno, this.code = code;\n }\n get name() {\n return \"SystemError\";\n }\n}\n$ = {\n ChildProcess,\n spawn,\n execFile,\n exec,\n fork,\n spawnSync,\n execFileSync,\n execSync\n};\nreturn $})\n"_s; // // diff --git a/test.js b/test.js new file mode 100644 index 000000000..4c43634c0 --- /dev/null +++ b/test.js @@ -0,0 +1 @@ +Bun.write("/tmp/bun-write-permission-test.txt", "test", { mode: 0o777 }); diff --git a/test/bun.lockb b/test/bun.lockb index f4097bda9..8abf35b6f 100755 Binary files a/test/bun.lockb and b/test/bun.lockb differ diff --git a/test/cli/run/run-cjs.test.ts b/test/cli/run/run-cjs.test.ts index 34c77d106..4c0d37002 100644 --- a/test/cli/run/run-cjs.test.ts +++ b/test/cli/run/run-cjs.test.ts @@ -4,7 +4,7 @@ import { bunEnv, bunExe } from "harness"; import { tmpdir } from "os"; import { join } from "path"; -test.todo("running a commonjs module works", async () => { +test("running a commonjs module works", async () => { const dir = join(realpathSync(tmpdir()), "bun-run-test1"); mkdirSync(dir, { recursive: true }); await Bun.write(join(dir, "index1.js"), "module.exports = 1; console.log('hello world');"); diff --git a/test/cli/run/run-extensionless.test.ts b/test/cli/run/run-extensionless.test.ts new file mode 100644 index 000000000..642c274d9 --- /dev/null +++ b/test/cli/run/run-extensionless.test.ts @@ -0,0 +1,31 @@ +import { expect, test } from "bun:test"; +import { mkdirSync, realpathSync } from "fs"; +import { bunEnv, bunExe } from "harness"; +import { writeFileSync } from "fs"; +import { tmpdir } from "os"; +import { join } from "path"; + +test("running extensionless file works", async () => { + const dir = join(realpathSync(tmpdir()), "bun-run-test1"); + mkdirSync(dir, { recursive: true }); + await Bun.write(join(dir, "cool"), "const x: Test = 2; console.log('hello world');"); + let { stdout } = Bun.spawnSync({ + cmd: [bunExe(), join(dir, "./cool")], + cwd: dir, + env: bunEnv, + }); + expect(stdout.toString("utf8")).toEqual("hello world\n"); +}); + +test("running shebang typescript file works", async () => { + const dir = join(realpathSync(tmpdir()), "bun-run-test2"); + mkdirSync(dir, { recursive: true }); + writeFileSync(join(dir, "cool"), `#!${bunExe()}\nconst x: Test = 2; console.log('hello world');`, { mode: 0o777 }); + + let { stdout } = Bun.spawnSync({ + cmd: [join(dir, "./cool")], + cwd: dir, + env: bunEnv, + }); + expect(stdout.toString("utf8")).toEqual("hello world\n"); +}); diff --git a/test/js/third_party/yargs/package.json b/test/js/third_party/yargs/package.json new file mode 100644 index 000000000..dd7ab02b0 --- /dev/null +++ b/test/js/third_party/yargs/package.json @@ -0,0 +1,7 @@ +{ + "name": "yargs-test", + "version": "1.0.0", + "dependencies": { + "yargs": "17.7.2" + } +} diff --git a/test/js/third_party/yargs/yargs-cjs.test.js b/test/js/third_party/yargs/yargs-cjs.test.js new file mode 100644 index 000000000..06e4d9cb8 --- /dev/null +++ b/test/js/third_party/yargs/yargs-cjs.test.js @@ -0,0 +1,4 @@ +test("yargs/yargs works", () => { + const yargs = require("yargs/yargs"); + expect(yargs).toBeFunction(); +}); diff --git a/test/package.json b/test/package.json index 9e55cc543..07bb9fc37 100644 --- a/test/package.json +++ b/test/package.json @@ -38,7 +38,7 @@ "vitest": "0.32.2", "webpack": "5.88.0", "webpack-cli": "4.7.2", - "mongodb": "6.0.0" + "yargs": "17.7.2" }, "private": true, "scripts": { -- cgit v1.2.3 From 387f1260c9dc0cea667b44ec0152fff0cd4def25 Mon Sep 17 00:00:00 2001 From: dave caruso Date: Thu, 28 Sep 2023 03:53:24 -0700 Subject: Get Next.js Pages Router to work (#6095) * hell * make it so bun-debug-src * teag * wild * yippee * fas * fix async hooks assertions * yap * yeah that's wild * aa * a * increase time allowed * so trivial --- packages/bun-types/bun.d.ts | 2 +- src/bun.js/WebKit | 2 +- src/bun.js/bindings/CommonJSModuleRecord.cpp | 69 +++---- src/bun.js/bindings/CommonJSModuleRecord.h | 6 +- src/bun.js/bindings/ZigGlobalObject.cpp | 34 +++- src/bun.js/bindings/ZigGlobalObject.lut.h | 107 +++++----- src/bun.js/bindings/ZigGlobalObject.lut.txt | 2 - src/bun.js/module_loader.zig | 22 ++- src/bun.js/modules/NodeModuleModule.h | 44 ++++- src/bundler.zig | 2 + src/js/_codegen/builtin-parser.ts | 6 +- src/js/_codegen/client-js.ts | 12 +- src/js/_codegen/replacements.ts | 17 +- src/js/builtins.d.ts | 6 +- src/js/builtins/BunBuiltinNames.h | 7 +- src/js/builtins/Module.ts | 5 + src/js/builtins/ProcessObjectInternals.ts | 3 +- src/js/node/async_hooks.ts | 117 +++++++++-- src/js/node/tty.js | 16 +- src/js/out/InternalModuleRegistryConstants.h | 12 +- src/js/out/WebCoreJSBuiltins.cpp | 16 +- src/js/out/WebCoreJSBuiltins.h | 11 ++ src/js_ast.zig | 1 + src/js_parser.zig | 216 ++++++++------------- src/js_printer.zig | 16 +- src/string.zig | 22 +-- test/.gitignore | 1 - test/README.md | 83 -------- test/bun.lockb | Bin 163311 -> 163310 bytes .../next/default-pages-dir/.eslintrc.json | 3 + test/integration/next/default-pages-dir/.gitignore | 38 ++++ test/integration/next/default-pages-dir/README.md | 40 ++++ test/integration/next/default-pages-dir/bun.lockb | Bin 0 -> 167519 bytes .../next/default-pages-dir/next.config.js | 10 + .../next/default-pages-dir/package.json | 28 +++ .../next/default-pages-dir/postcss.config.js | 6 + .../next/default-pages-dir/public/favicon.ico | Bin 0 -> 25931 bytes .../next/default-pages-dir/public/next.svg | 1 + .../next/default-pages-dir/public/vercel.svg | 1 + .../next/default-pages-dir/src/Counter1.txt | 27 +++ .../next/default-pages-dir/src/Counter2.txt | 27 +++ .../next/default-pages-dir/src/pages/_app.tsx | 6 + .../next/default-pages-dir/src/pages/_document.tsx | 13 ++ .../next/default-pages-dir/src/pages/api/hello.ts | 10 + .../next/default-pages-dir/src/pages/index.tsx | 128 ++++++++++++ .../next/default-pages-dir/src/styles/globals.css | 27 +++ .../next/default-pages-dir/tailwind.config.ts | 19 ++ .../default-pages-dir/test/dev-server-puppeteer.ts | 101 ++++++++++ .../next/default-pages-dir/test/dev-server.test.ts | 79 ++++++++ .../next/default-pages-dir/test/next-build.test.ts | 141 ++++++++++++++ .../next/default-pages-dir/tsconfig.json | 22 +++ .../next/default-pages-dir/tsconfig_for_build.json | 23 +++ test/js/node/async_hooks/async_hooks.node.test.ts | 28 ++- .../module/modulePrototypeOverwrite-fixture.cjs | 1 + test/js/node/module/modulePrototypeOverwrite.cjs | 17 ++ test/js/node/module/node-module-module.test.js | 11 ++ test/js/node/process/process-stdio.test.ts | 2 +- test/js/node/stream/node-stream.test.js | 12 +- test/js/third_party/got/bun.lockb | Bin 0 -> 9072 bytes test/js/third_party/prisma/bun.lockb | Bin 0 -> 2951 bytes test/js/third_party/yargs/bun.lockb | Bin 0 -> 6747 bytes 61 files changed, 1284 insertions(+), 394 deletions(-) delete mode 100644 test/.gitignore delete mode 100644 test/README.md create mode 100644 test/integration/next/default-pages-dir/.eslintrc.json create mode 100644 test/integration/next/default-pages-dir/.gitignore create mode 100644 test/integration/next/default-pages-dir/README.md create mode 100755 test/integration/next/default-pages-dir/bun.lockb create mode 100644 test/integration/next/default-pages-dir/next.config.js create mode 100644 test/integration/next/default-pages-dir/package.json create mode 100644 test/integration/next/default-pages-dir/postcss.config.js create mode 100644 test/integration/next/default-pages-dir/public/favicon.ico create mode 100644 test/integration/next/default-pages-dir/public/next.svg create mode 100644 test/integration/next/default-pages-dir/public/vercel.svg create mode 100644 test/integration/next/default-pages-dir/src/Counter1.txt create mode 100644 test/integration/next/default-pages-dir/src/Counter2.txt create mode 100644 test/integration/next/default-pages-dir/src/pages/_app.tsx create mode 100644 test/integration/next/default-pages-dir/src/pages/_document.tsx create mode 100644 test/integration/next/default-pages-dir/src/pages/api/hello.ts create mode 100644 test/integration/next/default-pages-dir/src/pages/index.tsx create mode 100644 test/integration/next/default-pages-dir/src/styles/globals.css create mode 100644 test/integration/next/default-pages-dir/tailwind.config.ts create mode 100644 test/integration/next/default-pages-dir/test/dev-server-puppeteer.ts create mode 100644 test/integration/next/default-pages-dir/test/dev-server.test.ts create mode 100644 test/integration/next/default-pages-dir/test/next-build.test.ts create mode 100644 test/integration/next/default-pages-dir/tsconfig.json create mode 100644 test/integration/next/default-pages-dir/tsconfig_for_build.json create mode 100644 test/js/node/module/modulePrototypeOverwrite-fixture.cjs create mode 100644 test/js/node/module/modulePrototypeOverwrite.cjs create mode 100755 test/js/third_party/got/bun.lockb create mode 100755 test/js/third_party/prisma/bun.lockb create mode 100755 test/js/third_party/yargs/bun.lockb (limited to 'src/bun.js/module_loader.zig') diff --git a/packages/bun-types/bun.d.ts b/packages/bun-types/bun.d.ts index a74274667..bd8b75023 100644 --- a/packages/bun-types/bun.d.ts +++ b/packages/bun-types/bun.d.ts @@ -3827,7 +3827,7 @@ declare module "bun" { : undefined; type ReadableToSyncIO = X extends "pipe" | undefined - ? Uint8Array + ? Buffer : undefined; type WritableIO = FileSink | number | undefined; diff --git a/src/bun.js/WebKit b/src/bun.js/WebKit index e1aa0a58e..6ee85cc2d 160000 --- a/src/bun.js/WebKit +++ b/src/bun.js/WebKit @@ -1 +1 @@ -Subproject commit e1aa0a58e282b53fc20503d6e7ec93c621bc5570 +Subproject commit 6ee85cc2dc431e146723885bc73ac14f33e0d82b diff --git a/src/bun.js/bindings/CommonJSModuleRecord.cpp b/src/bun.js/bindings/CommonJSModuleRecord.cpp index eea3b2a6f..38b55ba4d 100644 --- a/src/bun.js/bindings/CommonJSModuleRecord.cpp +++ b/src/bun.js/bindings/CommonJSModuleRecord.cpp @@ -8,7 +8,7 @@ * Then, at runtime, we create a JSCommonJSModule object. * * On this special object, we override the setter for the "exports" property in - * a non-observable way (`static bool put ...`) + * a non-observable way using a CustomGetterSetter. * * When the setter is called, we set the internal "exports" property to the * value passed in and we also update the requireMap with the new value. @@ -20,17 +20,13 @@ * * If an exception occurs, we remove the entry from the requireMap. * - * We tried using a CustomGetterSetter instead of overriding `put`, but it led - * to returning the getter itself - * - * How cyclical dependencies are handled + * How cyclical dependencies are handled: * * Before executing the CommonJS module, we set the exports object in the * requireMap to an empty object. When the CommonJS module is required again, we * return the exports object from the requireMap. The values should be in sync * while the module is being executed, unless module.exports is re-assigned to a * different value. In that case, it will have a stale value. - * */ #include "root.h" @@ -98,29 +94,35 @@ static bool canPerformFastEnumeration(Structure* s) static bool evaluateCommonJSModuleOnce(JSC::VM& vm, Zig::GlobalObject* globalObject, JSCommonJSModule* moduleObject, JSString* dirname, JSValue filename, WTF::NakedPtr& exception) { JSC::Structure* thisObjectStructure = globalObject->commonJSFunctionArgumentsStructure(); - JSC::JSObject* thisObject = JSC::constructEmptyObject( - vm, - thisObjectStructure); - thisObject->putDirectOffset( - vm, - 0, - moduleObject); - thisObject->putDirectOffset( - vm, - 1, - dirname); + JSFunction* resolveFunction = JSC::JSBoundFunction::create(vm, + globalObject, + globalObject->requireResolveFunctionUnbound(), + moduleObject->id(), + ArgList(), 1, jsString(vm, String("resolve"_s))); + JSFunction* requireFunction = JSC::JSBoundFunction::create(vm, + globalObject, + globalObject->requireFunctionUnbound(), + moduleObject, + ArgList(), 1, jsString(vm, String("require"_s))); + requireFunction->putDirect(vm, vm.propertyNames->resolve, resolveFunction, 0); + moduleObject->putDirect(vm, WebCore::clientData(vm)->builtinNames().requirePublicName(), requireFunction, 0); - thisObject->putDirectOffset( - vm, - 2, - filename); + JSC::JSObject* thisObject = JSC::constructEmptyObject(vm, thisObjectStructure); + thisObject->putDirectOffset(vm, 0, moduleObject); + thisObject->putDirectOffset(vm, 1, requireFunction); + thisObject->putDirectOffset(vm, 2, resolveFunction); + thisObject->putDirectOffset(vm, 3, dirname); + thisObject->putDirectOffset(vm, 4, filename); moduleObject->hasEvaluated = true; + // TODO: try to not use this write barrier. it needs some extensive testing. + // there is some possible GC issue where `thisObject` is gc'd before it should be globalObject->m_BunCommonJSModuleValue.set(vm, globalObject, thisObject); JSValue empty = JSC::evaluate(globalObject, moduleObject->sourceCode.get()->sourceCode(), thisObject, exception); + ensureStillAliveHere(thisObject); globalObject->m_BunCommonJSModuleValue.clear(); moduleObject->sourceCode.clear(); @@ -398,9 +400,9 @@ JSC_DEFINE_HOST_FUNCTION(functionCommonJSModuleRecord_compile, (JSGlobalObject * RETURN_IF_EXCEPTION(throwScope, JSValue::encode({})); String wrappedString = makeString( - "(function(module,exports,require,__dirname,__filename){"_s, + "(function(exports,require,module,__filename,__dirname){"_s, sourceString, - "\n}).call($_BunCommonJSModule_$.module.exports, $_BunCommonJSModule_$.module, $_BunCommonJSModule_$.module.exports, ($_BunCommonJSModule_$.module.require = $_BunCommonJSModule_$.module.require.bind($_BunCommonJSModule_$.module), $_BunCommonJSModule_$.module.require.path = $_BunCommonJSModule_$.module.id, $_BunCommonJSModule_$.module.require.resolve = $_BunCommonJSModule_$.module.require.resolve.bind($_BunCommonJSModule_$.module.id), $_BunCommonJSModule_$.module.require), $_BunCommonJSModule_$.__dirname, $_BunCommonJSModule_$.__filename);"_s); + "\n}).call(this.module.exports,this.module.exports,this.require,this.module,this.__filename,this.__dirname)"_s); SourceCode sourceCode = makeSource( WTFMove(wrappedString), @@ -483,14 +485,12 @@ public: ASSERT(inherits(vm, info())); reifyStaticProperties(vm, JSCommonJSModule::info(), JSCommonJSModulePrototypeTableValues, *this); - this->putDirect(vm, clientData(vm)->builtinNames().requirePublicName(), (static_cast(globalObject))->requireFunctionUnbound(), PropertyAttribute::Builtin | PropertyAttribute::Function | 0); - this->putDirectNativeFunction( vm, globalObject, clientData(vm)->builtinNames().requirePrivateName(), 2, - jsFunctionRequireCommonJS, ImplementationVisibility::Public, NoIntrinsic, JSC::PropertyAttribute::ReadOnly | 0); + jsFunctionRequireCommonJS, ImplementationVisibility::Public, NoIntrinsic, JSC::PropertyAttribute::ReadOnly | JSC::PropertyAttribute::DontDelete); } }; @@ -774,21 +774,6 @@ JSValue JSCommonJSModule::id() return m_id.get(); } -bool JSCommonJSModule::put( - JSC::JSCell* cell, - JSC::JSGlobalObject* globalObject, - JSC::PropertyName propertyName, - JSC::JSValue value, - JSC::PutPropertySlot& slot) -{ - - auto& vm = globalObject->vm(); - auto* clientData = WebCore::clientData(vm); - auto throwScope = DECLARE_THROW_SCOPE(vm); - - RELEASE_AND_RETURN(throwScope, Base::put(cell, globalObject, propertyName, value, slot)); -} - template JSC::GCClient::IsoSubspace* JSCommonJSModule::subspaceFor(JSC::VM& vm) { if constexpr (mode == JSC::SubspaceAccess::Concurrently) @@ -1022,7 +1007,7 @@ JSObject* JSCommonJSModule::createBoundRequireFunction(VM& vm, JSGlobalObject* l globalObject, globalObject->requireResolveFunctionUnbound(), moduleObject, - ArgList(), 1, jsString(vm, String("require"_s))); + ArgList(), 1, jsString(vm, String("resolve"_s))); requireFunction->putDirect(vm, builtinNames.resolvePublicName(), resolveFunction, PropertyAttribute::Function | 0); diff --git a/src/bun.js/bindings/CommonJSModuleRecord.h b/src/bun.js/bindings/CommonJSModuleRecord.h index 14d045478..2f9ba648f 100644 --- a/src/bun.js/bindings/CommonJSModuleRecord.h +++ b/src/bun.js/bindings/CommonJSModuleRecord.h @@ -20,7 +20,7 @@ JSC_DECLARE_HOST_FUNCTION(jsFunctionLoadModule); class JSCommonJSModule final : public JSC::JSDestructibleObject { public: using Base = JSC::JSDestructibleObject; - static constexpr unsigned StructureFlags = Base::StructureFlags | JSC::OverridesPut; + static constexpr unsigned StructureFlags = Base::StructureFlags; mutable JSC::WriteBarrier m_id; mutable JSC::WriteBarrier m_filename; @@ -74,10 +74,6 @@ public: DECLARE_VISIT_CHILDREN; - static bool put(JSC::JSCell* cell, JSC::JSGlobalObject* globalObject, - JSC::PropertyName propertyName, JSC::JSValue value, - JSC::PutPropertySlot& slot); - DECLARE_INFO; template static JSC::GCClient::IsoSubspace* subspaceFor(JSC::VM& vm); diff --git a/src/bun.js/bindings/ZigGlobalObject.cpp b/src/bun.js/bindings/ZigGlobalObject.cpp index 54fb58776..7ffd75ccf 100644 --- a/src/bun.js/bindings/ZigGlobalObject.cpp +++ b/src/bun.js/bindings/ZigGlobalObject.cpp @@ -1948,6 +1948,11 @@ JSC_DECLARE_HOST_FUNCTION(getInternalWritableStream); JSC_DECLARE_HOST_FUNCTION(whenSignalAborted); JSC_DECLARE_HOST_FUNCTION(isAbortSignal); +JSC_DEFINE_HOST_FUNCTION(jsCreateCJSImportMeta, (JSGlobalObject * globalObject, CallFrame* callFrame)) +{ + return JSValue::encode(Zig::ImportMetaObject::create(globalObject, callFrame->argument(0).toString(globalObject))); +} + JSC_DEFINE_HOST_FUNCTION(makeThisTypeErrorForBuiltins, (JSGlobalObject * globalObject, CallFrame* callFrame)) { ASSERT(callFrame); @@ -2825,11 +2830,20 @@ void GlobalObject::finishCreation(VM& vm) m_commonJSFunctionArgumentsStructure.initLater( [](const Initializer& init) { auto* globalObject = reinterpret_cast(init.owner); + + auto prototype = JSC::constructEmptyObject(init.owner, globalObject->objectPrototype(), 1); + prototype->putDirect( + init.vm, + Identifier::fromString(init.vm, "createImportMeta"_s), + JSFunction::create(init.vm, init.owner, 2, ""_s, jsCreateCJSImportMeta, ImplementationVisibility::Public), + PropertyAttribute::DontDelete | PropertyAttribute::DontEnum | 0); + JSC::Structure* structure = globalObject->structureCache().emptyObjectStructureForPrototype( globalObject, - globalObject->objectPrototype(), - 3); + prototype, + 5); JSC::PropertyOffset offset; + auto& vm = globalObject->vm(); structure = structure->addPropertyTransition( @@ -2839,6 +2853,20 @@ void GlobalObject::finishCreation(VM& vm) 0, offset); + structure = structure->addPropertyTransition( + vm, + structure, + JSC::Identifier::fromString(vm, "require"_s), + 0, + offset); + + structure = structure->addPropertyTransition( + vm, + structure, + JSC::Identifier::fromString(vm, "resolve"_s), + 0, + offset); + structure = structure->addPropertyTransition( vm, structure, @@ -3647,6 +3675,8 @@ void GlobalObject::addBuiltinGlobals(JSC::VM& vm) putDirectBuiltinFunction(vm, this, builtinNames.internalRequirePrivateName(), importMetaObjectInternalRequireCodeGenerator(vm), PropertyAttribute::Builtin | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly); putDirectBuiltinFunction(vm, this, builtinNames.requireNativeModulePrivateName(), moduleRequireNativeModuleCodeGenerator(vm), PropertyAttribute::Builtin | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly); + putDirectBuiltinFunction(vm, this, builtinNames.overridableRequirePrivateName(), moduleOverridableRequireCodeGenerator(vm), 0); + putDirectNativeFunction(vm, this, builtinNames.createUninitializedArrayBufferPrivateName(), 1, functionCreateUninitializedArrayBuffer, ImplementationVisibility::Public, NoIntrinsic, PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly | PropertyAttribute::Function); putDirectNativeFunction(vm, this, builtinNames.resolveSyncPrivateName(), 1, functionImportMeta__resolveSyncPrivate, ImplementationVisibility::Public, NoIntrinsic, PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly | PropertyAttribute::Function); putDirectNativeFunction(vm, this, builtinNames.createInternalModuleByIdPrivateName(), 1, InternalModuleRegistry::jsCreateInternalModuleById, ImplementationVisibility::Public, NoIntrinsic, PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly | PropertyAttribute::Function); diff --git a/src/bun.js/bindings/ZigGlobalObject.lut.h b/src/bun.js/bindings/ZigGlobalObject.lut.h index 8363a994d..6516648e8 100644 --- a/src/bun.js/bindings/ZigGlobalObject.lut.h +++ b/src/bun.js/bindings/ZigGlobalObject.lut.h @@ -4,7 +4,7 @@ static const struct CompactHashIndex bunGlobalObjectTableIndex[260] = { { -1, -1 }, { -1, -1 }, { -1, -1 }, - { 43, -1 }, + { 42, -1 }, { -1, -1 }, { -1, -1 }, { -1, -1 }, @@ -13,7 +13,7 @@ static const struct CompactHashIndex bunGlobalObjectTableIndex[260] = { { 6, -1 }, { 3, -1 }, { -1, -1 }, - { 35, -1 }, + { 34, -1 }, { -1, -1 }, { -1, -1 }, { -1, -1 }, @@ -21,10 +21,10 @@ static const struct CompactHashIndex bunGlobalObjectTableIndex[260] = { { -1, -1 }, { -1, -1 }, { -1, -1 }, - { 30, 258 }, + { 29, 258 }, { -1, -1 }, { -1, -1 }, - { 55, 257 }, + { 54, 257 }, { -1, -1 }, { -1, -1 }, { -1, -1 }, @@ -33,7 +33,7 @@ static const struct CompactHashIndex bunGlobalObjectTableIndex[260] = { { -1, -1 }, { -1, -1 }, { -1, -1 }, - { 52, -1 }, + { 51, -1 }, { -1, -1 }, { -1, -1 }, { -1, -1 }, @@ -45,7 +45,7 @@ static const struct CompactHashIndex bunGlobalObjectTableIndex[260] = { { -1, -1 }, { -1, -1 }, { 18, -1 }, - { 57, -1 }, + { 56, -1 }, { -1, -1 }, { -1, -1 }, { 14, -1 }, @@ -57,25 +57,25 @@ static const struct CompactHashIndex bunGlobalObjectTableIndex[260] = { { -1, -1 }, { -1, -1 }, { -1, -1 }, - { 42, -1 }, - { 48, -1 }, + { 41, -1 }, + { 47, -1 }, { -1, -1 }, { -1, -1 }, { -1, -1 }, { -1, -1 }, - { 70, -1 }, + { 69, -1 }, { -1, -1 }, { -1, -1 }, { -1, -1 }, { -1, -1 }, { -1, -1 }, - { 40, -1 }, + { 39, -1 }, { -1, -1 }, { -1, -1 }, - { 39, -1 }, - { 64, -1 }, + { 38, -1 }, + { 63, -1 }, { -1, -1 }, - { 58, -1 }, + { 57, -1 }, { -1, -1 }, { -1, -1 }, { -1, -1 }, @@ -83,47 +83,47 @@ static const struct CompactHashIndex bunGlobalObjectTableIndex[260] = { { -1, -1 }, { -1, -1 }, { -1, -1 }, - { 50, -1 }, + { 49, -1 }, { -1, -1 }, { -1, -1 }, { -1, -1 }, { -1, -1 }, { -1, -1 }, { -1, -1 }, - { 59, -1 }, + { 58, -1 }, { 11, -1 }, { -1, -1 }, { -1, -1 }, { 0, -1 }, { -1, -1 }, - { 38, -1 }, - { 22, -1 }, - { 67, -1 }, + { 37, -1 }, + { 21, -1 }, + { 66, -1 }, { -1, -1 }, { -1, -1 }, - { 71, -1 }, + { 70, -1 }, { -1, -1 }, - { 46, -1 }, + { 45, -1 }, { -1, -1 }, - { 49, -1 }, + { 48, -1 }, { -1, -1 }, { -1, -1 }, - { 25, -1 }, + { 24, -1 }, { -1, -1 }, { -1, -1 }, { -1, -1 }, - { 34, -1 }, + { 33, -1 }, { -1, -1 }, { -1, -1 }, { -1, -1 }, { -1, -1 }, - { 51, -1 }, - { 47, -1 }, + { 50, -1 }, + { 46, -1 }, { -1, -1 }, { 13, -1 }, { -1, -1 }, { -1, -1 }, - { 44, -1 }, + { 43, -1 }, { -1, -1 }, { 1, -1 }, { -1, -1 }, @@ -131,35 +131,35 @@ static const struct CompactHashIndex bunGlobalObjectTableIndex[260] = { { -1, -1 }, { -1, -1 }, { -1, -1 }, - { 21, -1 }, { -1, -1 }, { -1, -1 }, { -1, -1 }, - { 33, -1 }, { -1, -1 }, + { 32, -1 }, { -1, -1 }, { -1, -1 }, { -1, -1 }, - { 29, -1 }, { -1, -1 }, + { 28, -1 }, { -1, -1 }, { -1, -1 }, { -1, -1 }, - { 27, -1 }, + { -1, -1 }, + { 26, -1 }, { -1, -1 }, { -1, -1 }, { 17, -1 }, { -1, -1 }, - { 32, -1 }, + { 31, -1 }, { -1, -1 }, { -1, -1 }, - { 36, -1 }, - { 72, -1 }, + { 35, -1 }, + { 71, -1 }, { -1, -1 }, { -1, -1 }, { -1, -1 }, { -1, -1 }, - { 23, -1 }, + { 22, -1 }, { -1, -1 }, { -1, -1 }, { 4, -1 }, @@ -167,15 +167,15 @@ static const struct CompactHashIndex bunGlobalObjectTableIndex[260] = { { -1, -1 }, { -1, -1 }, { -1, -1 }, - { 24, -1 }, + { 23, -1 }, { -1, -1 }, { -1, -1 }, - { 56, -1 }, + { 55, -1 }, { -1, -1 }, - { 54, -1 }, + { 53, -1 }, { -1, -1 }, { 12, -1 }, - { 26, -1 }, + { 25, -1 }, { 7, -1 }, { -1, -1 }, { 9, -1 }, @@ -186,16 +186,16 @@ static const struct CompactHashIndex bunGlobalObjectTableIndex[260] = { { -1, -1 }, { -1, -1 }, { -1, -1 }, - { 62, -1 }, { 61, -1 }, + { 60, -1 }, { -1, -1 }, { 5, 256 }, { -1, -1 }, - { 65, -1 }, + { 64, -1 }, { -1, -1 }, { -1, -1 }, { -1, -1 }, - { 37, -1 }, + { 36, -1 }, { -1, -1 }, { 15, -1 }, { -1, -1 }, @@ -204,10 +204,10 @@ static const struct CompactHashIndex bunGlobalObjectTableIndex[260] = { { -1, -1 }, { -1, -1 }, { -1, -1 }, - { 41, 259 }, + { 40, 259 }, { -1, -1 }, { -1, -1 }, - { 69, -1 }, + { 68, -1 }, { -1, -1 }, { -1, -1 }, { -1, -1 }, @@ -217,7 +217,7 @@ static const struct CompactHashIndex bunGlobalObjectTableIndex[260] = { { -1, -1 }, { -1, -1 }, { -1, -1 }, - { 53, -1 }, + { 52, -1 }, { -1, -1 }, { -1, -1 }, { -1, -1 }, @@ -228,19 +228,19 @@ static const struct CompactHashIndex bunGlobalObjectTableIndex[260] = { { -1, -1 }, { -1, -1 }, { -1, -1 }, - { 31, -1 }, + { 30, -1 }, { -1, -1 }, { -1, -1 }, { -1, -1 }, { -1, -1 }, - { 28, -1 }, + { 27, -1 }, { -1, -1 }, { -1, -1 }, { -1, -1 }, - { 45, -1 }, + { 44, -1 }, { -1, -1 }, { -1, -1 }, - { 66, -1 }, + { 65, -1 }, { -1, -1 }, { -1, -1 }, { -1, -1 }, @@ -257,12 +257,12 @@ static const struct CompactHashIndex bunGlobalObjectTableIndex[260] = { { 19, -1 }, { -1, -1 }, { 8, -1 }, - { 60, -1 }, - { 63, -1 }, - { 68, -1 }, + { 59, -1 }, + { 62, -1 }, + { 67, -1 }, }; -static const struct HashTableValue bunGlobalObjectTableValues[73] = { +static const struct HashTableValue bunGlobalObjectTableValues[72] = { { "addEventListener"_s, static_cast(PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, jsFunctionAddEventListener, 2 } }, { "alert"_s, static_cast(PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, WebCore__alert, 1 } }, { "atob"_s, static_cast(PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, functionATOB, 1 } }, @@ -284,7 +284,6 @@ static const struct HashTableValue bunGlobalObjectTableValues[73] = { { "structuredClone"_s, static_cast(PropertyAttribute::Function), NoIntrinsic, { HashTableValue::NativeFunctionType, functionStructuredClone, 2 } }, { "global"_s, static_cast(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, GlobalObject_getGlobalThis } }, { "EventSource"_s, static_cast(PropertyAttribute::PropertyCallback), NoIntrinsic, { HashTableValue::LazyPropertyType, getEventSourceConstructor } }, - { "$_BunCommonJSModule_$"_s, static_cast(PropertyAttribute::CustomAccessor|PropertyAttribute::DontDelete|PropertyAttribute::ReadOnly), NoIntrinsic, { HashTableValue::GetterSetterType, BunCommonJSModule_getter, 0 } }, { "Bun"_s, static_cast(PropertyAttribute::CellProperty|PropertyAttribute::DontDelete|PropertyAttribute::ReadOnly), NoIntrinsic, { HashTableValue::LazyCellPropertyType, OBJECT_OFFSETOF(GlobalObject, m_bunObject) } }, { "File"_s, static_cast(PropertyAttribute::CellProperty), NoIntrinsic, { HashTableValue::LazyCellPropertyType, OBJECT_OFFSETOF(GlobalObject, m_JSDOMFileConstructor) } }, { "crypto"_s, static_cast(PropertyAttribute::CellProperty), NoIntrinsic, { HashTableValue::LazyCellPropertyType, OBJECT_OFFSETOF(GlobalObject, m_cryptoObject) } }, @@ -339,4 +338,4 @@ static const struct HashTableValue bunGlobalObjectTableValues[73] = { }; static const struct HashTable bunGlobalObjectTable = - { 73, 255, true, nullptr, bunGlobalObjectTableValues, bunGlobalObjectTableIndex }; + { 72, 255, false, nullptr, bunGlobalObjectTableValues, bunGlobalObjectTableIndex }; diff --git a/src/bun.js/bindings/ZigGlobalObject.lut.txt b/src/bun.js/bindings/ZigGlobalObject.lut.txt index 7700dcc8d..aadaee92a 100644 --- a/src/bun.js/bindings/ZigGlobalObject.lut.txt +++ b/src/bun.js/bindings/ZigGlobalObject.lut.txt @@ -25,8 +25,6 @@ global GlobalObject_getGlobalThis PropertyCallback EventSource getEventSourceConstructor PropertyCallback - $_BunCommonJSModule_$ BunCommonJSModule_getter CustomAccessor|DontDelete|ReadOnly - Bun GlobalObject::m_bunObject CellProperty|DontDelete|ReadOnly File GlobalObject::m_JSDOMFileConstructor CellProperty crypto GlobalObject::m_cryptoObject CellProperty diff --git a/src/bun.js/module_loader.zig b/src/bun.js/module_loader.zig index ca066450d..89dca35b0 100644 --- a/src/bun.js/module_loader.zig +++ b/src/bun.js/module_loader.zig @@ -154,21 +154,26 @@ const BunDebugHolder = struct { pub var lock: bun.Lock = undefined; }; -fn dumpSource(specifier: string, printer: anytype) !void { +/// Dumps the module source to a file in /tmp/bun-debug-src/{filepath} +/// +/// This can technically fail if concurrent access across processes happens, or permission issues. +/// Errors here should always be ignored. +fn dumpSource(specifier: string, printer: anytype) void { if (BunDebugHolder.dir == null) { - BunDebugHolder.dir = try std.fs.cwd().makeOpenPathIterable("/tmp/bun-debug-src/", .{}); + BunDebugHolder.dir = std.fs.cwd().makeOpenPathIterable("/tmp/bun-debug-src/", .{}) catch return; BunDebugHolder.lock = bun.Lock.init(); } BunDebugHolder.lock.lock(); defer BunDebugHolder.lock.unlock(); + const dir = BunDebugHolder.dir orelse return; if (std.fs.path.dirname(specifier)) |dir_path| { - var parent = try BunDebugHolder.dir.?.dir.makeOpenPathIterable(dir_path[1..], .{}); + var parent = dir.dir.makeOpenPathIterable(dir_path[1..], .{}) catch return; defer parent.close(); - try parent.dir.writeFile(std.fs.path.basename(specifier), printer.ctx.getWritten()); + parent.dir.writeFile(std.fs.path.basename(specifier), printer.ctx.getWritten()) catch return; } else { - try BunDebugHolder.dir.?.dir.writeFile(std.fs.path.basename(specifier), printer.ctx.getWritten()); + dir.dir.writeFile(std.fs.path.basename(specifier), printer.ctx.getWritten()) catch return; } } @@ -545,7 +550,7 @@ pub const RuntimeTranspilerStore = struct { } if (comptime Environment.dump_source) { - dumpSource(specifier, &printer) catch {}; + dumpSource(specifier, &printer); } this.resolved_source = ResolvedSource{ @@ -1230,7 +1235,7 @@ pub const ModuleLoader = struct { } if (comptime Environment.dump_source) { - try dumpSource(specifier, &printer); + dumpSource(specifier, &printer); } var commonjs_exports = try bun.default_allocator.alloc(ZigString, parse_result.ast.commonjs_export_names.len); @@ -1626,7 +1631,7 @@ pub const ModuleLoader = struct { }; if (comptime Environment.dump_source) { - try dumpSource(specifier, &printer); + dumpSource(specifier, &printer); } var commonjs_exports = try bun.default_allocator.alloc(ZigString, parse_result.ast.commonjs_export_names.len); @@ -1979,6 +1984,7 @@ pub const ModuleLoader = struct { if (err == error.PluginError) { return null; } + VirtualMachine.processFetchLog(globalObject, specifier_ptr.*, referrer.*, &log, ret, err); return null; }, diff --git a/src/bun.js/modules/NodeModuleModule.h b/src/bun.js/modules/NodeModuleModule.h index 6d8654024..ddb273de4 100644 --- a/src/bun.js/modules/NodeModuleModule.h +++ b/src/bun.js/modules/NodeModuleModule.h @@ -304,6 +304,39 @@ JSC_DEFINE_CUSTOM_SETTER(set_resolveFilename, return false; } +// These two setters are only used if you directly hit +// `Module.prototype.require` or `module.require`. When accessing the cjs +// require argument, this is a bound version of `require`, which calls into the +// overridden one. +// +// This require function also intentionally does not have .resolve on it, nor +// does it have any of the other properties. +// +// Note: allowing require to be overridable at all is only needed for Next.js to +// work (they do Module.prototype.require = ...) + +JSC_DEFINE_CUSTOM_GETTER(getterRequireFunction, + (JSC::JSGlobalObject * globalObject, + JSC::EncodedJSValue thisValue, JSC::PropertyName)) { + return JSValue::encode(globalObject->getDirect( + globalObject->vm(), WebCore::clientData(globalObject->vm()) + ->builtinNames() + .overridableRequirePrivateName())); +} + +JSC_DEFINE_CUSTOM_SETTER(setterRequireFunction, + (JSC::JSGlobalObject * globalObject, + JSC::EncodedJSValue thisValue, + JSC::EncodedJSValue value, + JSC::PropertyName propertyName)) { + globalObject->putDirect(globalObject->vm(), + WebCore::clientData(globalObject->vm()) + ->builtinNames() + .overridableRequirePrivateName(), + JSValue::decode(value), 0); + return true; +} + namespace Zig { DEFINE_NATIVE_MODULE(NodeModule) { @@ -371,8 +404,15 @@ DEFINE_NATIVE_MODULE(NodeModule) { put(Identifier::fromString(vm, "globalPaths"_s), constructEmptyArray(globalObject, nullptr, 0)); - put(Identifier::fromString(vm, "prototype"_s), - constructEmptyObject(globalObject)); + auto prototype = + constructEmptyObject(globalObject, globalObject->objectPrototype(), 1); + prototype->putDirectCustomAccessor( + vm, JSC::Identifier::fromString(vm, "require"_s), + JSC::CustomGetterSetter::create(vm, getterRequireFunction, + setterRequireFunction), + 0); + + defaultObject->putDirect(vm, vm.propertyNames->prototype, prototype); JSC::JSArray *builtinModules = JSC::JSArray::create( vm, diff --git a/src/bundler.zig b/src/bundler.zig index cf0e0a4f8..479843bcd 100644 --- a/src/bundler.zig +++ b/src/bundler.zig @@ -1106,6 +1106,7 @@ pub const Bundler = struct { .minify_syntax = bundler.options.minify_syntax, .minify_identifiers = bundler.options.minify_identifiers, .transform_only = bundler.options.transform_only, + .import_meta_ref = ast.import_meta_ref, }, enable_source_map, ), @@ -1129,6 +1130,7 @@ pub const Bundler = struct { .transform_only = bundler.options.transform_only, .module_type = if (ast.exports_kind == .cjs) .cjs else .esm, .inline_require_and_import_errors = false, + .import_meta_ref = ast.import_meta_ref, }, enable_source_map, ), diff --git a/src/js/_codegen/builtin-parser.ts b/src/js/_codegen/builtin-parser.ts index ffd5671c1..4e35f13dd 100644 --- a/src/js/_codegen/builtin-parser.ts +++ b/src/js/_codegen/builtin-parser.ts @@ -79,12 +79,14 @@ export function sliceSourceCode( i = 1; } else if (endOnComma && contents.startsWith(",")) { if (bracketCount <= 1) { - result += ","; contents = contents.slice(1); - // if the next non-whitespace character is ), also consume + // if the next non-whitespace character is ), we will treat it like a ) let match = contents.match(/^\s*\)/); if (match) { contents = contents.slice(match[0].length); + result += ")"; + } else { + result += ","; } break; } diff --git a/src/js/_codegen/client-js.ts b/src/js/_codegen/client-js.ts index 2db3305fa..bd9ed63f4 100644 --- a/src/js/_codegen/client-js.ts +++ b/src/js/_codegen/client-js.ts @@ -27,10 +27,18 @@ export function createAssertClientJS(publicName: string) { return ` let $assert = function(check, sourceString, ...message) { if (!check) { - console.error('[${publicName}] ASSERTION FAILED: ' + sourceString); - if(message.length)console.warn (' ${" ".repeat(publicName.length)}', ...message); + const prevPrepareStackTrace = Error.prepareStackTrace; + Error.prepareStackTrace = (e, stack) => { + return e.name + ': ' + e.message + '\\n' + stack.slice(1).map(x => ' at ' + x.toString()).join('\\n'); + }; const e = new Error(sourceString); + e.stack; // materialize stack e.name = 'AssertionError'; + Error.prepareStackTrace = prevPrepareStackTrace; + console.error('[${publicName}] ASSERTION FAILED: ' + sourceString); + if (message.length) console.warn(...message); + console.warn(e.stack.split('\\n')[1] + '\\n'); + if (Bun.env.ASSERT === 'CRASH') process.exit(0xAA); throw e; } } diff --git a/src/js/_codegen/replacements.ts b/src/js/_codegen/replacements.ts index 5ce646ad5..45f2426b5 100644 --- a/src/js/_codegen/replacements.ts +++ b/src/js/_codegen/replacements.ts @@ -141,14 +141,27 @@ export function applyReplacements(src: string, length: number) { ]; } else if (name === "assert") { const checkSlice = sliceSourceCode(rest, true, undefined, true); + let rest2 = checkSlice.rest; + let extraArgs = ""; + if (checkSlice.result.at(-1) === ",") { + const sliced = sliceSourceCode("(" + rest2.slice(1), true, undefined, false); + extraArgs = ", " + sliced.result.slice(1, -1); + rest2 = sliced.rest; + } return [ slice.slice(0, match.index) + "(IS_BUN_DEVELOPMENT?$assert(" + checkSlice.result.slice(1, -1) + "," + - JSON.stringify(checkSlice.result.slice(1, -1).replace(/__intrinsic__/g, "$")) + + JSON.stringify( + checkSlice.result + .slice(1, -1) + .replace(/__intrinsic__/g, "$") + .trim(), + ) + + extraArgs + "):void 0)", - checkSlice.rest, + rest2, true, ]; } diff --git a/src/js/builtins.d.ts b/src/js/builtins.d.ts index cdda3ffe1..ee7bd68cf 100644 --- a/src/js/builtins.d.ts +++ b/src/js/builtins.d.ts @@ -12,7 +12,9 @@ declare function $debug(...args: any[]): void; /** $assert is a preprocessor macro that only runs in debug mode. it throws an error if the first argument is falsy. * The source code passed to `check` is inlined in the message, but in addition you can pass additional messages. */ -declare function $assert(check: any, ...message: any[]): void; +declare function $assert(check: any, ...message: any[]): asserts check; + +declare const IS_BUN_DEVELOPMENT: boolean; /** Place this directly above a function declaration (like a decorator) to make it a getter. */ declare const $getter: never; @@ -439,6 +441,8 @@ declare function $createCommonJSModule( parent: CommonJSModuleRecord, ): CommonJSModuleRecord; +declare function $overridableRequire(this: CommonJSModuleRecord, id: string): any; + // The following I cannot find any definitions of, but they are functional. declare function $toLength(length: number): number; declare function $isTypedArrayView(obj: unknown): obj is ArrayBufferView | DataView | Uint8Array; diff --git a/src/js/builtins/BunBuiltinNames.h b/src/js/builtins/BunBuiltinNames.h index caaba1738..d124a7683 100644 --- a/src/js/builtins/BunBuiltinNames.h +++ b/src/js/builtins/BunBuiltinNames.h @@ -69,6 +69,7 @@ using namespace JSC; macro(createCommonJSModule) \ macro(createEmptyReadableStream) \ macro(createFIFO) \ + macro(createInternalModuleById) \ macro(createNativeReadableStream) \ macro(createReadableStream) \ macro(createUninitializedArrayBuffer) \ @@ -119,6 +120,7 @@ using namespace JSC; macro(inFlightCloseRequest) \ macro(inFlightWriteRequest) \ macro(initializeWith) \ + macro(internalModuleRegistry) \ macro(internalRequire) \ macro(internalStream) \ macro(internalWritable) \ @@ -145,6 +147,7 @@ using namespace JSC; macro(once) \ macro(options) \ macro(origin) \ + macro(overridableRequire) \ macro(ownerReadableStream) \ macro(parse) \ macro(password) \ @@ -185,6 +188,7 @@ using namespace JSC; macro(require) \ macro(requireESM) \ macro(requireMap) \ + macro(requireNativeModule) \ macro(resolve) \ macro(resolveSync) \ macro(resume) \ @@ -238,9 +242,6 @@ using namespace JSC; macro(writer) \ macro(writing) \ macro(written) \ - macro(createInternalModuleById) \ - macro(internalModuleRegistry) \ - macro(requireNativeModule) \ class BunBuiltinNames { public: diff --git a/src/js/builtins/Module.ts b/src/js/builtins/Module.ts index 3d88f2484..b074d3488 100644 --- a/src/js/builtins/Module.ts +++ b/src/js/builtins/Module.ts @@ -4,6 +4,11 @@ export function main() { } export function require(this: CommonJSModuleRecord, id: string) { + return $overridableRequire.$call(this, id); +} + +// overridableRequire can be overridden by setting `Module.prototype.require` +export function overridableRequire(this: CommonJSModuleRecord, id: string) { const existing = $requireMap.$get(id) || $requireMap.$get((id = $resolveSync(id, this.path, false))); if (existing) { // Scenario where this is necessary: diff --git a/src/js/builtins/ProcessObjectInternals.ts b/src/js/builtins/ProcessObjectInternals.ts index ef8f1f9ce..aa7c9b783 100644 --- a/src/js/builtins/ProcessObjectInternals.ts +++ b/src/js/builtins/ProcessObjectInternals.ts @@ -89,7 +89,8 @@ export function getStdinStream(fd) { const tty = require("node:tty"); - const stream = new tty.ReadStream(fd); + const ReadStream = tty.isatty(fd) ? tty.ReadStream : require("node:fs").ReadStream; + const stream = new ReadStream(fd); const originalOn = stream.on; stream.on = function (event, listener) { diff --git a/src/js/node/async_hooks.ts b/src/js/node/async_hooks.ts index ef77b79f7..83b313912 100644 --- a/src/js/node/async_hooks.ts +++ b/src/js/node/async_hooks.ts @@ -19,17 +19,53 @@ // use. But the nature of this approach makes the implementation *itself* very low-impact on performance. // // AsyncContextData is an immutable array managed in here, formatted [key, value, key, value] where -// each key is an AsyncLocalStorage object and the value is the associated value. +// each key is an AsyncLocalStorage object and the value is the associated value. There are a ton of +// calls to $assert which will verify this invariant (only during bun-debug) // const { cleanupLater, setAsyncHooksEnabled } = $lazy("async_hooks"); +// Only run during debug +function assertValidAsyncContextArray(array: unknown): array is ReadonlyArray | undefined { + // undefined is OK + if (array === undefined) return true; + // Otherwise, it must be an array + $assert( + Array.isArray(array), + "AsyncContextData must be an array or undefined, got", + Bun.inspect(array, { depth: 1 }), + ); + // the array has to be even + $assert(array.length % 2 === 0, "AsyncContextData should be even-length, got", Bun.inspect(array, { depth: 1 })); + // if it is zero-length, use undefined instead + $assert(array.length > 0, "AsyncContextData should be undefined if empty, got", Bun.inspect(array, { depth: 1 })); + for (var i = 0; i < array.length; i += 2) { + $assert( + array[i] instanceof AsyncLocalStorage, + `Odd indexes in AsyncContextData should be an array of AsyncLocalStorage\nIndex %s was %s`, + i, + array[i], + ); + } + return true; +} + +// Only run during debug +function debugFormatContextValue(value: ReadonlyArray | undefined) { + if (value === undefined) return "{}"; + let str = "{\n"; + for (var i = 0; i < value.length; i += 2) { + str += ` ${value[i].__id__}: ${Bun.inspect(value[i + 1], { depth: 1, colors: Bun.enableANSIColors })}\n`; + } +} + function get(): ReadonlyArray | undefined { - $debug("get", $getInternalField($asyncContext, 0)); + $debug("get", debugFormatContextValue($getInternalField($asyncContext, 0))); return $getInternalField($asyncContext, 0); } function set(contextValue: ReadonlyArray | undefined) { - $debug("set", contextValue); + $assert(assertValidAsyncContextArray(contextValue)); + $debug("set", debugFormatContextValue(contextValue)); return $putInternalField($asyncContext, 0, contextValue); } @@ -38,6 +74,14 @@ class AsyncLocalStorage { constructor() { setAsyncHooksEnabled(true); + + // In debug mode assign every AsyncLocalStorage a unique ID + if (IS_BUN_DEVELOPMENT) { + (this as any).__id__ = + Math.random().toString(36).slice(2, 8) + + "@" + + require("node:path").basename(require("bun:jsc").callerSourceOrigin()); + } } static bind(fn, ...args: any) { @@ -67,8 +111,11 @@ class AsyncLocalStorage { return; } var { length } = context; + $assert(length > 0); + $assert(length % 2 === 0); for (var i = 0; i < length; i += 2) { if (context[i] === this) { + $assert(length > i + 1); const clone = context.slice(); clone[i + 1] = store; set(clone); @@ -76,33 +123,42 @@ class AsyncLocalStorage { } } set(context.concat(this, store)); + $assert(this.getStore() === store); } exit(cb, ...args) { return this.run(undefined, cb, ...args); } - run(store, callback, ...args) { + // This function is literred with $asserts to ensure that everything that + // is assumed to be true is *actually* true. + run(store_value, callback, ...args) { var context = get() as any[]; // we make sure to .slice() before mutating var hasPrevious = false; - var previous; + var previous_value; var i = 0; - var contextWasInit = !context; - if (contextWasInit) { - set((context = [this, store])); + var contextWasAlreadyInit = !context; + if (contextWasAlreadyInit) { + set((context = [this, store_value])); } else { // it's safe to mutate context now that it was cloned context = context!.slice(); i = context.indexOf(this); if (i > -1) { + $assert(i % 2 === 0); hasPrevious = true; - previous = context[i + 1]; - context[i + 1] = store; + previous_value = context[i + 1]; + context[i + 1] = store_value; } else { - context.push(this, store); + i = context.length; + context.push(this, store_value); + $assert(i % 2 === 0); + $assert(context.length % 2 === 0); } set(context); } + $assert(i > -1, "i was not set"); + $assert(this.getStore() === store_value, "run: store_value was not set"); try { return callback(...args); } catch (e) { @@ -111,24 +167,36 @@ class AsyncLocalStorage { // Note: early `return` will prevent `throw` above from working. I think... // Set AsyncContextFrame to undefined if we are out of context values if (!this.#disableCalled) { - var context2 = get()! as any[]; - if (context2 === context && contextWasInit) { + var context2 = get()! as any[]; // we make sure to .slice() before mutating + if (context2 === context && contextWasAlreadyInit) { + $assert(context2.length === 2, "context was mutated without copy"); set(undefined); } else { context2 = context2.slice(); // array is cloned here + $assert(context2[i] === this); if (hasPrevious) { - context2[i + 1] = previous; + context2[i + 1] = previous_value; set(context2); } else { + // i wonder if this is a fair assert to make context2.splice(i, 2); + $assert(context2.length % 2 === 0); set(context2.length ? context2 : undefined); } } + $assert( + this.getStore() === previous_value, + "run: previous_value", + Bun.inspect(previous_value), + "was not restored, i see", + this.getStore(), + ); } } } disable() { + $debug("disable " + (this as any).__id__); // In this case, we actually do want to mutate the context state if (!this.#disableCalled) { var context = get() as any[]; @@ -156,11 +224,21 @@ class AsyncLocalStorage { } } +if (IS_BUN_DEVELOPMENT) { + AsyncLocalStorage.prototype[Bun.inspect.custom] = function (depth, options) { + if (depth < 0) return `AsyncLocalStorage { ${Bun.inspect((this as any).__id__, options)} }`; + return `AsyncLocalStorage { [${options.stylize("debug id", "special")}]: ${Bun.inspect( + (this as any).__id__, + options, + )} }`; + }; +} + class AsyncResource { type; #snapshot; - constructor(type, options) { + constructor(type, options?) { if (typeof type !== "string") { throw new TypeError('The "type" argument must be of type string. Received type ' + typeof type); } @@ -200,6 +278,15 @@ class AsyncResource { set(prev); } } + + bind(fn, thisArg) { + return this.runInAsyncScope.bind(this, fn, thisArg ?? this); + } + + static bind(fn, type, thisArg) { + type = type || fn.name; + return new AsyncResource(type || "bound-anonymous-fn").bind(fn, thisArg); + } } // The rest of async_hooks is not implemented and is stubbed with no-ops and warnings. diff --git a/src/js/node/tty.js b/src/js/node/tty.js index 2ffc2d764..1c3fb2fac 100644 --- a/src/js/node/tty.js +++ b/src/js/node/tty.js @@ -11,30 +11,34 @@ function ReadStream(fd) { const stream = require("node:fs").ReadStream.call(this, "", { fd, }); + Object.setPrototypeOf(stream, ReadStream.prototype); stream.isRaw = false; - stream.isTTY = isatty(stream.fd); + stream.isTTY = true; + + $assert(stream instanceof ReadStream); return stream; } Object.defineProperty(ReadStream, "prototype", { get() { - const Real = require("node:fs").ReadStream.prototype; + const Prototype = Object.create(require("node:fs").ReadStream.prototype); - Object.defineProperty(ReadStream, "prototype", { value: Real }); - ReadStream.prototype.setRawMode = function (flag) { + Prototype.setRawMode = function (flag) { const mode = flag ? 1 : 0; const err = ttySetMode(this.fd, mode); if (err) { - this.emit("error", new Error("setRawMode failed with errno:", err)); + this.emit("error", new Error("setRawMode failed with errno: " + err)); return this; } this.isRaw = flag; return this; }; - return Real; + Object.defineProperty(ReadStream, "prototype", { value: Prototype }); + + return Prototype; }, enumerable: true, configurable: true, diff --git a/src/js/out/InternalModuleRegistryConstants.h b/src/js/out/InternalModuleRegistryConstants.h index 344433952..b4a181d60 100644 --- a/src/js/out/InternalModuleRegistryConstants.h +++ b/src/js/out/InternalModuleRegistryConstants.h @@ -46,7 +46,7 @@ static constexpr ASCIILiteral NodeAssertStrictCode = "(function (){\"use strict\ // // -static constexpr ASCIILiteral NodeAsyncHooksCode = "(function (){\"use strict\";// src/js/out/tmp/node/async_hooks.ts\nvar get = function() {\n return @getInternalField(@asyncContext, 0);\n}, set = function(contextValue) {\n return @putInternalField(@asyncContext, 0, contextValue);\n}, createWarning = function(message) {\n let warned = !1;\n var wrapped = function() {\n if (warned)\n return;\n if (new Error().stack.includes(\"zx/build/core.js\"))\n return;\n warned = !0, console.warn(\"[bun] Warning:\", message);\n };\n return wrapped;\n}, createHook = function(callbacks) {\n return {\n enable: createHookNotImpl,\n disable: createHookNotImpl\n };\n}, executionAsyncId = function() {\n return executionAsyncIdNotImpl(), 0;\n}, triggerAsyncId = function() {\n return 0;\n}, executionAsyncResource = function() {\n return executionAsyncResourceWarning(), process.stdin;\n}, $, { cleanupLater, setAsyncHooksEnabled } = @lazy(\"async_hooks\");\n\nclass AsyncLocalStorage {\n #disableCalled = !1;\n constructor() {\n setAsyncHooksEnabled(!0);\n }\n static bind(fn, ...args) {\n return this.snapshot().bind(null, fn, ...args);\n }\n static snapshot() {\n var context = get();\n return (fn, ...args) => {\n var prev = get();\n set(context);\n try {\n return fn(...args);\n } catch (error) {\n throw error;\n } finally {\n set(prev);\n }\n };\n }\n enterWith(store) {\n cleanupLater();\n var context = get();\n if (!context) {\n set([this, store]);\n return;\n }\n var { length } = context;\n for (var i = 0;i < length; i += 2)\n if (context[i] === this) {\n const clone = context.slice();\n clone[i + 1] = store, set(clone);\n return;\n }\n set(context.concat(this, store));\n }\n exit(cb, ...args) {\n return this.run(@undefined, cb, ...args);\n }\n run(store, callback, ...args) {\n var context = get(), hasPrevious = !1, previous, i = 0, contextWasInit = !context;\n if (contextWasInit)\n set(context = [this, store]);\n else {\n if (context = context.slice(), i = context.indexOf(this), i > -1)\n hasPrevious = !0, previous = context[i + 1], context[i + 1] = store;\n else\n context.push(this, store);\n set(context);\n }\n try {\n return callback(...args);\n } catch (e) {\n throw e;\n } finally {\n if (!this.#disableCalled) {\n var context2 = get();\n if (context2 === context && contextWasInit)\n set(@undefined);\n else if (context2 = context2.slice(), hasPrevious)\n context2[i + 1] = previous, set(context2);\n else\n context2.splice(i, 2), set(context2.length \? context2 : @undefined);\n }\n }\n }\n disable() {\n if (!this.#disableCalled) {\n var context = get();\n if (context) {\n var { length } = context;\n for (var i = 0;i < length; i += 2)\n if (context[i] === this) {\n context.splice(i, 2), set(context.length \? context : @undefined);\n break;\n }\n }\n this.#disableCalled = !0;\n }\n }\n getStore() {\n var context = get();\n if (!context)\n return;\n var { length } = context;\n for (var i = 0;i < length; i += 2)\n if (context[i] === this)\n return context[i + 1];\n }\n}\n\nclass AsyncResource {\n type;\n #snapshot;\n constructor(type, options) {\n if (typeof type !== \"string\")\n @throwTypeError('The \"type\" argument must be of type string. Received type ' + typeof type);\n setAsyncHooksEnabled(!0), this.type = type, this.#snapshot = get();\n }\n emitBefore() {\n return !0;\n }\n emitAfter() {\n return !0;\n }\n asyncId() {\n return 0;\n }\n triggerAsyncId() {\n return 0;\n }\n emitDestroy() {\n }\n runInAsyncScope(fn, thisArg, ...args) {\n var prev = get();\n set(this.#snapshot);\n try {\n return fn.apply(thisArg, args);\n } catch (error) {\n throw error;\n } finally {\n set(prev);\n }\n }\n}\nvar createHookNotImpl = createWarning(\"async_hooks.createHook is not implemented in Bun. Hooks can still be created but will never be called.\"), executionAsyncIdNotImpl = createWarning(\"async_hooks.executionAsyncId/triggerAsyncId are not implemented in Bun. It will return 0 every time.\"), executionAsyncResourceWarning = createWarning(\"async_hooks.executionAsyncResource is not implemented in Bun. It returns a reference to process.stdin every time.\"), asyncWrapProviders = {\n NONE: 0,\n DIRHANDLE: 1,\n DNSCHANNEL: 2,\n ELDHISTOGRAM: 3,\n FILEHANDLE: 4,\n FILEHANDLECLOSEREQ: 5,\n FIXEDSIZEBLOBCOPY: 6,\n FSEVENTWRAP: 7,\n FSREQCALLBACK: 8,\n FSREQPROMISE: 9,\n GETADDRINFOREQWRAP: 10,\n GETNAMEINFOREQWRAP: 11,\n HEAPSNAPSHOT: 12,\n HTTP2SESSION: 13,\n HTTP2STREAM: 14,\n HTTP2PING: 15,\n HTTP2SETTINGS: 16,\n HTTPINCOMINGMESSAGE: 17,\n HTTPCLIENTREQUEST: 18,\n JSSTREAM: 19,\n JSUDPWRAP: 20,\n MESSAGEPORT: 21,\n PIPECONNECTWRAP: 22,\n PIPESERVERWRAP: 23,\n PIPEWRAP: 24,\n PROCESSWRAP: 25,\n PROMISE: 26,\n QUERYWRAP: 27,\n SHUTDOWNWRAP: 28,\n SIGNALWRAP: 29,\n STATWATCHER: 30,\n STREAMPIPE: 31,\n TCPCONNECTWRAP: 32,\n TCPSERVERWRAP: 33,\n TCPWRAP: 34,\n TTYWRAP: 35,\n UDPSENDWRAP: 36,\n UDPWRAP: 37,\n SIGINTWATCHDOG: 38,\n WORKER: 39,\n WORKERHEAPSNAPSHOT: 40,\n WRITEWRAP: 41,\n ZLIB: 42,\n CHECKPRIMEREQUEST: 43,\n PBKDF2REQUEST: 44,\n KEYPAIRGENREQUEST: 45,\n KEYGENREQUEST: 46,\n KEYEXPORTREQUEST: 47,\n CIPHERREQUEST: 48,\n DERIVEBITSREQUEST: 49,\n HASHREQUEST: 50,\n RANDOMBYTESREQUEST: 51,\n RANDOMPRIMEREQUEST: 52,\n SCRYPTREQUEST: 53,\n SIGNREQUEST: 54,\n TLSWRAP: 55,\n VERIFYREQUEST: 56,\n INSPECTORJSBINDING: 57\n};\n$ = {\n AsyncLocalStorage,\n createHook,\n executionAsyncId,\n triggerAsyncId,\n executionAsyncResource,\n asyncWrapProviders,\n AsyncResource\n};\nreturn $})\n"_s; +static constexpr ASCIILiteral NodeAsyncHooksCode = "(function (){\"use strict\";// src/js/out/tmp/node/async_hooks.ts\nvar get = function() {\n return @getInternalField(@asyncContext, 0);\n}, set = function(contextValue) {\n return @putInternalField(@asyncContext, 0, contextValue);\n}, createWarning = function(message) {\n let warned = !1;\n var wrapped = function() {\n if (warned)\n return;\n if (new Error().stack.includes(\"zx/build/core.js\"))\n return;\n warned = !0, console.warn(\"[bun] Warning:\", message);\n };\n return wrapped;\n}, createHook = function(callbacks) {\n return {\n enable: createHookNotImpl,\n disable: createHookNotImpl\n };\n}, executionAsyncId = function() {\n return executionAsyncIdNotImpl(), 0;\n}, triggerAsyncId = function() {\n return 0;\n}, executionAsyncResource = function() {\n return executionAsyncResourceWarning(), process.stdin;\n}, $, { cleanupLater, setAsyncHooksEnabled } = @lazy(\"async_hooks\");\n\nclass AsyncLocalStorage {\n #disableCalled = !1;\n constructor() {\n setAsyncHooksEnabled(!0);\n }\n static bind(fn, ...args) {\n return this.snapshot().bind(null, fn, ...args);\n }\n static snapshot() {\n var context = get();\n return (fn, ...args) => {\n var prev = get();\n set(context);\n try {\n return fn(...args);\n } catch (error) {\n throw error;\n } finally {\n set(prev);\n }\n };\n }\n enterWith(store) {\n cleanupLater();\n var context = get();\n if (!context) {\n set([this, store]);\n return;\n }\n var { length } = context;\n for (var i = 0;i < length; i += 2)\n if (context[i] === this) {\n const clone = context.slice();\n clone[i + 1] = store, set(clone);\n return;\n }\n set(context.concat(this, store));\n }\n exit(cb, ...args) {\n return this.run(@undefined, cb, ...args);\n }\n run(store_value, callback, ...args) {\n var context = get(), hasPrevious = !1, previous_value, i = 0, contextWasAlreadyInit = !context;\n if (contextWasAlreadyInit)\n set(context = [this, store_value]);\n else {\n if (context = context.slice(), i = context.indexOf(this), i > -1)\n hasPrevious = !0, previous_value = context[i + 1], context[i + 1] = store_value;\n else\n i = context.length, context.push(this, store_value);\n set(context);\n }\n try {\n return callback(...args);\n } catch (e) {\n throw e;\n } finally {\n if (!this.#disableCalled) {\n var context2 = get();\n if (context2 === context && contextWasAlreadyInit)\n set(@undefined);\n else if (context2 = context2.slice(), hasPrevious)\n context2[i + 1] = previous_value, set(context2);\n else\n context2.splice(i, 2), set(context2.length \? context2 : @undefined);\n }\n }\n }\n disable() {\n if (!this.#disableCalled) {\n var context = get();\n if (context) {\n var { length } = context;\n for (var i = 0;i < length; i += 2)\n if (context[i] === this) {\n context.splice(i, 2), set(context.length \? context : @undefined);\n break;\n }\n }\n this.#disableCalled = !0;\n }\n }\n getStore() {\n var context = get();\n if (!context)\n return;\n var { length } = context;\n for (var i = 0;i < length; i += 2)\n if (context[i] === this)\n return context[i + 1];\n }\n}\n\nclass AsyncResource {\n type;\n #snapshot;\n constructor(type, options) {\n if (typeof type !== \"string\")\n @throwTypeError('The \"type\" argument must be of type string. Received type ' + typeof type);\n setAsyncHooksEnabled(!0), this.type = type, this.#snapshot = get();\n }\n emitBefore() {\n return !0;\n }\n emitAfter() {\n return !0;\n }\n asyncId() {\n return 0;\n }\n triggerAsyncId() {\n return 0;\n }\n emitDestroy() {\n }\n runInAsyncScope(fn, thisArg, ...args) {\n var prev = get();\n set(this.#snapshot);\n try {\n return fn.apply(thisArg, args);\n } catch (error) {\n throw error;\n } finally {\n set(prev);\n }\n }\n bind(fn, thisArg) {\n return this.runInAsyncScope.bind(this, fn, thisArg \?\? this);\n }\n static bind(fn, type, thisArg) {\n return type = type || fn.name, new AsyncResource(type || \"bound-anonymous-fn\").bind(fn, thisArg);\n }\n}\nvar createHookNotImpl = createWarning(\"async_hooks.createHook is not implemented in Bun. Hooks can still be created but will never be called.\"), executionAsyncIdNotImpl = createWarning(\"async_hooks.executionAsyncId/triggerAsyncId are not implemented in Bun. It will return 0 every time.\"), executionAsyncResourceWarning = createWarning(\"async_hooks.executionAsyncResource is not implemented in Bun. It returns a reference to process.stdin every time.\"), asyncWrapProviders = {\n NONE: 0,\n DIRHANDLE: 1,\n DNSCHANNEL: 2,\n ELDHISTOGRAM: 3,\n FILEHANDLE: 4,\n FILEHANDLECLOSEREQ: 5,\n FIXEDSIZEBLOBCOPY: 6,\n FSEVENTWRAP: 7,\n FSREQCALLBACK: 8,\n FSREQPROMISE: 9,\n GETADDRINFOREQWRAP: 10,\n GETNAMEINFOREQWRAP: 11,\n HEAPSNAPSHOT: 12,\n HTTP2SESSION: 13,\n HTTP2STREAM: 14,\n HTTP2PING: 15,\n HTTP2SETTINGS: 16,\n HTTPINCOMINGMESSAGE: 17,\n HTTPCLIENTREQUEST: 18,\n JSSTREAM: 19,\n JSUDPWRAP: 20,\n MESSAGEPORT: 21,\n PIPECONNECTWRAP: 22,\n PIPESERVERWRAP: 23,\n PIPEWRAP: 24,\n PROCESSWRAP: 25,\n PROMISE: 26,\n QUERYWRAP: 27,\n SHUTDOWNWRAP: 28,\n SIGNALWRAP: 29,\n STATWATCHER: 30,\n STREAMPIPE: 31,\n TCPCONNECTWRAP: 32,\n TCPSERVERWRAP: 33,\n TCPWRAP: 34,\n TTYWRAP: 35,\n UDPSENDWRAP: 36,\n UDPWRAP: 37,\n SIGINTWATCHDOG: 38,\n WORKER: 39,\n WORKERHEAPSNAPSHOT: 40,\n WRITEWRAP: 41,\n ZLIB: 42,\n CHECKPRIMEREQUEST: 43,\n PBKDF2REQUEST: 44,\n KEYPAIRGENREQUEST: 45,\n KEYGENREQUEST: 46,\n KEYEXPORTREQUEST: 47,\n CIPHERREQUEST: 48,\n DERIVEBITSREQUEST: 49,\n HASHREQUEST: 50,\n RANDOMBYTESREQUEST: 51,\n RANDOMPRIMEREQUEST: 52,\n SCRYPTREQUEST: 53,\n SIGNREQUEST: 54,\n TLSWRAP: 55,\n VERIFYREQUEST: 56,\n INSPECTORJSBINDING: 57\n};\n$ = {\n AsyncLocalStorage,\n createHook,\n executionAsyncId,\n triggerAsyncId,\n executionAsyncResource,\n asyncWrapProviders,\n AsyncResource\n};\nreturn $})\n"_s; // // @@ -190,7 +190,7 @@ static constexpr ASCIILiteral NodeTraceEventsCode = "(function (){\"use strict\" // // -static constexpr ASCIILiteral NodeTtyCode = "(function (){\"use strict\";// src/js/out/tmp/node/tty.ts\nvar ReadStream = function(fd) {\n if (!(this instanceof ReadStream))\n return new ReadStream(fd);\n if (fd >> 0 !== fd || fd < 0)\n @throwRangeError(\"fd must be a positive integer\");\n const stream = (@getInternalField(@internalModuleRegistry, 21) || @createInternalModuleById(21)).ReadStream.call(this, \"\", {\n fd\n });\n return stream.isRaw = !1, stream.isTTY = isatty(stream.fd), stream;\n}, warnOnDeactivatedColors = function(env) {\n if (warned)\n return;\n let name = \"\";\n if (env.NODE_DISABLE_COLORS !== @undefined)\n name = \"NODE_DISABLE_COLORS\";\n if (env.NO_COLOR !== @undefined) {\n if (name !== \"\")\n name += \"' and '\";\n name += \"NO_COLOR\";\n }\n if (name !== \"\")\n process.emitWarning(`The '${name}' env is ignored due to the 'FORCE_COLOR' env being set.`, \"Warning\"), warned = !0;\n}, WriteStream = function(fd) {\n if (!(this instanceof WriteStream))\n return new WriteStream(fd);\n if (fd >> 0 !== fd || fd < 0)\n @throwRangeError(\"fd must be a positive integer\");\n const stream = (@getInternalField(@internalModuleRegistry, 21) || @createInternalModuleById(21)).WriteStream.call(this, \"\", {\n fd\n });\n if (stream.columns = @undefined, stream.rows = @undefined, stream.isTTY = isatty(stream.fd), stream.isTTY) {\n const windowSizeArray = [0, 0];\n if (_getWindowSize(fd, windowSizeArray) === !0)\n stream.columns = windowSizeArray[0], stream.rows = windowSizeArray[1];\n }\n return stream;\n}, { ttySetMode, isatty, getWindowSize: _getWindowSize } = @lazy(\"tty\"), StringPrototypeSplit = Function.prototype.call.bind(@String.prototype.split), RegExpPrototypeExec = Function.prototype.call.bind(@RegExp.prototype.exec), StringPrototypeToLowerCase = Function.prototype.call.bind(@String.prototype.toLowerCase), ArrayPrototypeSome = Function.prototype.call.bind(@Array.prototype.some), NumberIsInteger = Number.isInteger;\nObject.defineProperty(ReadStream, \"prototype\", {\n get() {\n const Real = (@getInternalField(@internalModuleRegistry, 21) || @createInternalModuleById(21)).ReadStream.prototype;\n return Object.defineProperty(ReadStream, \"prototype\", { value: Real }), ReadStream.prototype.setRawMode = function(flag) {\n const mode = flag \? 1 : 0, err = ttySetMode(this.fd, mode);\n if (err)\n return this.emit(\"error\", new Error(\"setRawMode failed with errno:\", err)), this;\n return this.isRaw = flag, this;\n }, Real;\n },\n enumerable: !0,\n configurable: !0\n});\nvar COLORS_2 = 1, COLORS_16 = 4, COLORS_256 = 8, COLORS_16m = 24, TERM_ENVS = {\n eterm: COLORS_16,\n cons25: COLORS_16,\n console: COLORS_16,\n cygwin: COLORS_16,\n dtterm: COLORS_16,\n gnome: COLORS_16,\n hurd: COLORS_16,\n jfbterm: COLORS_16,\n konsole: COLORS_16,\n kterm: COLORS_16,\n mlterm: COLORS_16,\n mosh: COLORS_16m,\n putty: COLORS_16,\n st: COLORS_16,\n \"rxvt-unicode-24bit\": COLORS_16m,\n terminator: COLORS_16m\n}, TERM_ENVS_REG_EXP = [/ansi/, /color/, /linux/, /^con[0-9]*x[0-9]/, /^rxvt/, /^screen/, /^xterm/, /^vt100/], warned = !1;\nObject.defineProperty(WriteStream, \"prototype\", {\n get() {\n const Real = (@getInternalField(@internalModuleRegistry, 21) || @createInternalModuleById(21)).WriteStream.prototype;\n Object.defineProperty(WriteStream, \"prototype\", { value: Real }), WriteStream.prototype._refreshSize = function() {\n const oldCols = this.columns, oldRows = this.rows, windowSizeArray = [0, 0];\n if (_getWindowSize(this.fd, windowSizeArray) === !0) {\n if (oldCols !== windowSizeArray[0] || oldRows !== windowSizeArray[1])\n this.columns = windowSizeArray[0], this.rows = windowSizeArray[1], this.emit(\"resize\");\n }\n };\n var readline = @undefined;\n return WriteStream.prototype.clearLine = function(dir, cb) {\n return (readline \?\?= @getInternalField(@internalModuleRegistry, 35) || @createInternalModuleById(35)).clearLine(this, dir, cb);\n }, WriteStream.prototype.clearScreenDown = function(cb) {\n return (readline \?\?= @getInternalField(@internalModuleRegistry, 35) || @createInternalModuleById(35)).clearScreenDown(this, cb);\n }, WriteStream.prototype.cursorTo = function(x, y, cb) {\n return (readline \?\?= @getInternalField(@internalModuleRegistry, 35) || @createInternalModuleById(35)).cursorTo(this, x, y, cb);\n }, WriteStream.prototype.getColorDepth = function(env = process.env) {\n if (env.FORCE_COLOR !== @undefined)\n switch (env.FORCE_COLOR) {\n case \"\":\n case \"1\":\n case \"true\":\n return warnOnDeactivatedColors(env), COLORS_16;\n case \"2\":\n return warnOnDeactivatedColors(env), COLORS_256;\n case \"3\":\n return warnOnDeactivatedColors(env), COLORS_16m;\n default:\n return COLORS_2;\n }\n if (env.NODE_DISABLE_COLORS !== @undefined || env.NO_COLOR !== @undefined || env.TERM === \"dumb\")\n return COLORS_2;\n if (env.TMUX)\n return COLORS_256;\n if (env.CI) {\n if ([\"APPVEYOR\", \"BUILDKITE\", \"CIRCLECI\", \"DRONE\", \"GITHUB_ACTIONS\", \"GITLAB_CI\", \"TRAVIS\"].some((sign) => (sign in env)) || env.CI_NAME === \"codeship\")\n return COLORS_256;\n return COLORS_2;\n }\n if (\"TEAMCITY_VERSION\" in env)\n return /^(9\\.(0*[1-9]\\d*)\\.|\\d{2,}\\.)/.test(env.TEAMCITY_VERSION) \? COLORS_16 : COLORS_2;\n switch (env.TERM_PROGRAM) {\n case \"iTerm.app\":\n if (!env.TERM_PROGRAM_VERSION || /^[0-2]\\./.test(env.TERM_PROGRAM_VERSION))\n return COLORS_256;\n return COLORS_16m;\n case \"HyperTerm\":\n case \"MacTerm\":\n return COLORS_16m;\n case \"Apple_Terminal\":\n return COLORS_256;\n }\n if (env.COLORTERM === \"truecolor\" || env.COLORTERM === \"24bit\")\n return COLORS_16m;\n if (env.TERM) {\n if (/^xterm-256/.test(env.TERM) !== null)\n return COLORS_256;\n const termEnv = env.TERM.toLowerCase();\n if (TERM_ENVS[termEnv])\n return TERM_ENVS[termEnv];\n if (TERM_ENVS_REG_EXP.some((term) => term.test(termEnv)))\n return COLORS_16;\n }\n if (env.COLORTERM)\n return COLORS_16;\n return COLORS_2;\n }, WriteStream.prototype.getWindowSize = function() {\n return [this.columns, this.rows];\n }, WriteStream.prototype.hasColors = function(count, env) {\n if (env === @undefined && (count === @undefined || typeof count === \"object\" && count !== null))\n env = count, count = 16;\n else\n validateInteger(count, \"count\", 2);\n return count <= 2 ** this.getColorDepth(env);\n }, WriteStream.prototype.moveCursor = function(dx, dy, cb) {\n return (readline \?\?= @getInternalField(@internalModuleRegistry, 35) || @createInternalModuleById(35)).moveCursor(this, dx, dy, cb);\n }, Real;\n },\n enumerable: !0,\n configurable: !0\n});\nvar validateInteger = (value, name, min = Number.MIN_SAFE_INTEGER, max = Number.MAX_SAFE_INTEGER) => {\n if (typeof value !== \"number\")\n throw new ERR_INVALID_ARG_TYPE(name, \"number\", value);\n if (!NumberIsInteger(value))\n throw new ERR_OUT_OF_RANGE(name, \"an integer\", value);\n if (value < min || value > max)\n throw new ERR_OUT_OF_RANGE(name, `>= ${min} && <= ${max}`, value);\n};\nreturn { ReadStream, WriteStream, isatty }})\n"_s; +static constexpr ASCIILiteral NodeTtyCode = "(function (){\"use strict\";// src/js/out/tmp/node/tty.ts\nvar ReadStream = function(fd) {\n if (!(this instanceof ReadStream))\n return new ReadStream(fd);\n if (fd >> 0 !== fd || fd < 0)\n @throwRangeError(\"fd must be a positive integer\");\n const stream = (@getInternalField(@internalModuleRegistry, 21) || @createInternalModuleById(21)).ReadStream.call(this, \"\", {\n fd\n });\n return Object.setPrototypeOf(stream, ReadStream.prototype), stream.isRaw = !1, stream.isTTY = !0, stream;\n}, warnOnDeactivatedColors = function(env) {\n if (warned)\n return;\n let name = \"\";\n if (env.NODE_DISABLE_COLORS !== @undefined)\n name = \"NODE_DISABLE_COLORS\";\n if (env.NO_COLOR !== @undefined) {\n if (name !== \"\")\n name += \"' and '\";\n name += \"NO_COLOR\";\n }\n if (name !== \"\")\n process.emitWarning(`The '${name}' env is ignored due to the 'FORCE_COLOR' env being set.`, \"Warning\"), warned = !0;\n}, WriteStream = function(fd) {\n if (!(this instanceof WriteStream))\n return new WriteStream(fd);\n if (fd >> 0 !== fd || fd < 0)\n @throwRangeError(\"fd must be a positive integer\");\n const stream = (@getInternalField(@internalModuleRegistry, 21) || @createInternalModuleById(21)).WriteStream.call(this, \"\", {\n fd\n });\n if (stream.columns = @undefined, stream.rows = @undefined, stream.isTTY = isatty(stream.fd), stream.isTTY) {\n const windowSizeArray = [0, 0];\n if (_getWindowSize(fd, windowSizeArray) === !0)\n stream.columns = windowSizeArray[0], stream.rows = windowSizeArray[1];\n }\n return stream;\n}, { ttySetMode, isatty, getWindowSize: _getWindowSize } = @lazy(\"tty\"), StringPrototypeSplit = Function.prototype.call.bind(@String.prototype.split), NumberIsInteger = Number.isInteger;\nObject.defineProperty(ReadStream, \"prototype\", {\n get() {\n const Prototype = Object.create((@getInternalField(@internalModuleRegistry, 21) || @createInternalModuleById(21)).ReadStream.prototype);\n return Prototype.setRawMode = function(flag) {\n const mode = flag \? 1 : 0, err = ttySetMode(this.fd, mode);\n if (err)\n return this.emit(\"error\", new Error(\"setRawMode failed with errno: \" + err)), this;\n return this.isRaw = flag, this;\n }, Object.defineProperty(ReadStream, \"prototype\", { value: Prototype }), Prototype;\n },\n enumerable: !0,\n configurable: !0\n});\nvar COLORS_2 = 1, COLORS_16 = 4, COLORS_256 = 8, COLORS_16m = 24, TERM_ENVS = {\n eterm: COLORS_16,\n cons25: COLORS_16,\n console: COLORS_16,\n cygwin: COLORS_16,\n dtterm: COLORS_16,\n gnome: COLORS_16,\n hurd: COLORS_16,\n jfbterm: COLORS_16,\n konsole: COLORS_16,\n kterm: COLORS_16,\n mlterm: COLORS_16,\n mosh: COLORS_16m,\n putty: COLORS_16,\n st: COLORS_16,\n \"rxvt-unicode-24bit\": COLORS_16m,\n terminator: COLORS_16m\n}, TERM_ENVS_REG_EXP = [/ansi/, /color/, /linux/, /^con[0-9]*x[0-9]/, /^rxvt/, /^screen/, /^xterm/, /^vt100/], warned = !1;\nObject.defineProperty(WriteStream, \"prototype\", {\n get() {\n const Real = (@getInternalField(@internalModuleRegistry, 21) || @createInternalModuleById(21)).WriteStream.prototype;\n Object.defineProperty(WriteStream, \"prototype\", { value: Real }), WriteStream.prototype._refreshSize = function() {\n const oldCols = this.columns, oldRows = this.rows, windowSizeArray = [0, 0];\n if (_getWindowSize(this.fd, windowSizeArray) === !0) {\n if (oldCols !== windowSizeArray[0] || oldRows !== windowSizeArray[1])\n this.columns = windowSizeArray[0], this.rows = windowSizeArray[1], this.emit(\"resize\");\n }\n };\n var readline = @undefined;\n return WriteStream.prototype.clearLine = function(dir, cb) {\n return (readline \?\?= @getInternalField(@internalModuleRegistry, 35) || @createInternalModuleById(35)).clearLine(this, dir, cb);\n }, WriteStream.prototype.clearScreenDown = function(cb) {\n return (readline \?\?= @getInternalField(@internalModuleRegistry, 35) || @createInternalModuleById(35)).clearScreenDown(this, cb);\n }, WriteStream.prototype.cursorTo = function(x, y, cb) {\n return (readline \?\?= @getInternalField(@internalModuleRegistry, 35) || @createInternalModuleById(35)).cursorTo(this, x, y, cb);\n }, WriteStream.prototype.getColorDepth = function(env = process.env) {\n if (env.FORCE_COLOR !== @undefined)\n switch (env.FORCE_COLOR) {\n case \"\":\n case \"1\":\n case \"true\":\n return warnOnDeactivatedColors(env), COLORS_16;\n case \"2\":\n return warnOnDeactivatedColors(env), COLORS_256;\n case \"3\":\n return warnOnDeactivatedColors(env), COLORS_16m;\n default:\n return COLORS_2;\n }\n if (env.NODE_DISABLE_COLORS !== @undefined || env.NO_COLOR !== @undefined || env.TERM === \"dumb\")\n return COLORS_2;\n if (env.TMUX)\n return COLORS_256;\n if (env.CI) {\n if ([\"APPVEYOR\", \"BUILDKITE\", \"CIRCLECI\", \"DRONE\", \"GITHUB_ACTIONS\", \"GITLAB_CI\", \"TRAVIS\"].some((sign) => (sign in env)) || env.CI_NAME === \"codeship\")\n return COLORS_256;\n return COLORS_2;\n }\n if (\"TEAMCITY_VERSION\" in env)\n return /^(9\\.(0*[1-9]\\d*)\\.|\\d{2,}\\.)/.test(env.TEAMCITY_VERSION) \? COLORS_16 : COLORS_2;\n switch (env.TERM_PROGRAM) {\n case \"iTerm.app\":\n if (!env.TERM_PROGRAM_VERSION || /^[0-2]\\./.test(env.TERM_PROGRAM_VERSION))\n return COLORS_256;\n return COLORS_16m;\n case \"HyperTerm\":\n case \"MacTerm\":\n return COLORS_16m;\n case \"Apple_Terminal\":\n return COLORS_256;\n }\n if (env.COLORTERM === \"truecolor\" || env.COLORTERM === \"24bit\")\n return COLORS_16m;\n if (env.TERM) {\n if (/^xterm-256/.test(env.TERM) !== null)\n return COLORS_256;\n const termEnv = env.TERM.toLowerCase();\n if (TERM_ENVS[termEnv])\n return TERM_ENVS[termEnv];\n if (TERM_ENVS_REG_EXP.some((term) => term.test(termEnv)))\n return COLORS_16;\n }\n if (env.COLORTERM)\n return COLORS_16;\n return COLORS_2;\n }, WriteStream.prototype.getWindowSize = function() {\n return [this.columns, this.rows];\n }, WriteStream.prototype.hasColors = function(count, env) {\n if (env === @undefined && (count === @undefined || typeof count === \"object\" && count !== null))\n env = count, count = 16;\n else\n validateInteger(count, \"count\", 2);\n return count <= 2 ** this.getColorDepth(env);\n }, WriteStream.prototype.moveCursor = function(dx, dy, cb) {\n return (readline \?\?= @getInternalField(@internalModuleRegistry, 35) || @createInternalModuleById(35)).moveCursor(this, dx, dy, cb);\n }, Real;\n },\n enumerable: !0,\n configurable: !0\n});\nvar validateInteger = (value, name, min = Number.MIN_SAFE_INTEGER, max = Number.MAX_SAFE_INTEGER) => {\n if (typeof value !== \"number\")\n throw new ERR_INVALID_ARG_TYPE(name, \"number\", value);\n if (!NumberIsInteger(value))\n throw new ERR_OUT_OF_RANGE(name, \"an integer\", value);\n if (value < min || value > max)\n throw new ERR_OUT_OF_RANGE(name, `>= ${min} && <= ${max}`, value);\n};\nreturn { ReadStream, WriteStream, isatty }})\n"_s; // // @@ -295,7 +295,7 @@ static constexpr ASCIILiteral NodeAssertStrictCode = "(function (){\"use strict\ // // -static constexpr ASCIILiteral NodeAsyncHooksCode = "(function (){\"use strict\";// src/js/out/tmp/node/async_hooks.ts\nvar get = function() {\n return @getInternalField(@asyncContext, 0);\n}, set = function(contextValue) {\n return @putInternalField(@asyncContext, 0, contextValue);\n}, createWarning = function(message) {\n let warned = !1;\n var wrapped = function() {\n if (warned)\n return;\n if (new Error().stack.includes(\"zx/build/core.js\"))\n return;\n warned = !0, console.warn(\"[bun] Warning:\", message);\n };\n return wrapped;\n}, createHook = function(callbacks) {\n return {\n enable: createHookNotImpl,\n disable: createHookNotImpl\n };\n}, executionAsyncId = function() {\n return executionAsyncIdNotImpl(), 0;\n}, triggerAsyncId = function() {\n return 0;\n}, executionAsyncResource = function() {\n return executionAsyncResourceWarning(), process.stdin;\n}, $, { cleanupLater, setAsyncHooksEnabled } = @lazy(\"async_hooks\");\n\nclass AsyncLocalStorage {\n #disableCalled = !1;\n constructor() {\n setAsyncHooksEnabled(!0);\n }\n static bind(fn, ...args) {\n return this.snapshot().bind(null, fn, ...args);\n }\n static snapshot() {\n var context = get();\n return (fn, ...args) => {\n var prev = get();\n set(context);\n try {\n return fn(...args);\n } catch (error) {\n throw error;\n } finally {\n set(prev);\n }\n };\n }\n enterWith(store) {\n cleanupLater();\n var context = get();\n if (!context) {\n set([this, store]);\n return;\n }\n var { length } = context;\n for (var i = 0;i < length; i += 2)\n if (context[i] === this) {\n const clone = context.slice();\n clone[i + 1] = store, set(clone);\n return;\n }\n set(context.concat(this, store));\n }\n exit(cb, ...args) {\n return this.run(@undefined, cb, ...args);\n }\n run(store, callback, ...args) {\n var context = get(), hasPrevious = !1, previous, i = 0, contextWasInit = !context;\n if (contextWasInit)\n set(context = [this, store]);\n else {\n if (context = context.slice(), i = context.indexOf(this), i > -1)\n hasPrevious = !0, previous = context[i + 1], context[i + 1] = store;\n else\n context.push(this, store);\n set(context);\n }\n try {\n return callback(...args);\n } catch (e) {\n throw e;\n } finally {\n if (!this.#disableCalled) {\n var context2 = get();\n if (context2 === context && contextWasInit)\n set(@undefined);\n else if (context2 = context2.slice(), hasPrevious)\n context2[i + 1] = previous, set(context2);\n else\n context2.splice(i, 2), set(context2.length \? context2 : @undefined);\n }\n }\n }\n disable() {\n if (!this.#disableCalled) {\n var context = get();\n if (context) {\n var { length } = context;\n for (var i = 0;i < length; i += 2)\n if (context[i] === this) {\n context.splice(i, 2), set(context.length \? context : @undefined);\n break;\n }\n }\n this.#disableCalled = !0;\n }\n }\n getStore() {\n var context = get();\n if (!context)\n return;\n var { length } = context;\n for (var i = 0;i < length; i += 2)\n if (context[i] === this)\n return context[i + 1];\n }\n}\n\nclass AsyncResource {\n type;\n #snapshot;\n constructor(type, options) {\n if (typeof type !== \"string\")\n @throwTypeError('The \"type\" argument must be of type string. Received type ' + typeof type);\n setAsyncHooksEnabled(!0), this.type = type, this.#snapshot = get();\n }\n emitBefore() {\n return !0;\n }\n emitAfter() {\n return !0;\n }\n asyncId() {\n return 0;\n }\n triggerAsyncId() {\n return 0;\n }\n emitDestroy() {\n }\n runInAsyncScope(fn, thisArg, ...args) {\n var prev = get();\n set(this.#snapshot);\n try {\n return fn.apply(thisArg, args);\n } catch (error) {\n throw error;\n } finally {\n set(prev);\n }\n }\n}\nvar createHookNotImpl = createWarning(\"async_hooks.createHook is not implemented in Bun. Hooks can still be created but will never be called.\"), executionAsyncIdNotImpl = createWarning(\"async_hooks.executionAsyncId/triggerAsyncId are not implemented in Bun. It will return 0 every time.\"), executionAsyncResourceWarning = createWarning(\"async_hooks.executionAsyncResource is not implemented in Bun. It returns a reference to process.stdin every time.\"), asyncWrapProviders = {\n NONE: 0,\n DIRHANDLE: 1,\n DNSCHANNEL: 2,\n ELDHISTOGRAM: 3,\n FILEHANDLE: 4,\n FILEHANDLECLOSEREQ: 5,\n FIXEDSIZEBLOBCOPY: 6,\n FSEVENTWRAP: 7,\n FSREQCALLBACK: 8,\n FSREQPROMISE: 9,\n GETADDRINFOREQWRAP: 10,\n GETNAMEINFOREQWRAP: 11,\n HEAPSNAPSHOT: 12,\n HTTP2SESSION: 13,\n HTTP2STREAM: 14,\n HTTP2PING: 15,\n HTTP2SETTINGS: 16,\n HTTPINCOMINGMESSAGE: 17,\n HTTPCLIENTREQUEST: 18,\n JSSTREAM: 19,\n JSUDPWRAP: 20,\n MESSAGEPORT: 21,\n PIPECONNECTWRAP: 22,\n PIPESERVERWRAP: 23,\n PIPEWRAP: 24,\n PROCESSWRAP: 25,\n PROMISE: 26,\n QUERYWRAP: 27,\n SHUTDOWNWRAP: 28,\n SIGNALWRAP: 29,\n STATWATCHER: 30,\n STREAMPIPE: 31,\n TCPCONNECTWRAP: 32,\n TCPSERVERWRAP: 33,\n TCPWRAP: 34,\n TTYWRAP: 35,\n UDPSENDWRAP: 36,\n UDPWRAP: 37,\n SIGINTWATCHDOG: 38,\n WORKER: 39,\n WORKERHEAPSNAPSHOT: 40,\n WRITEWRAP: 41,\n ZLIB: 42,\n CHECKPRIMEREQUEST: 43,\n PBKDF2REQUEST: 44,\n KEYPAIRGENREQUEST: 45,\n KEYGENREQUEST: 46,\n KEYEXPORTREQUEST: 47,\n CIPHERREQUEST: 48,\n DERIVEBITSREQUEST: 49,\n HASHREQUEST: 50,\n RANDOMBYTESREQUEST: 51,\n RANDOMPRIMEREQUEST: 52,\n SCRYPTREQUEST: 53,\n SIGNREQUEST: 54,\n TLSWRAP: 55,\n VERIFYREQUEST: 56,\n INSPECTORJSBINDING: 57\n};\n$ = {\n AsyncLocalStorage,\n createHook,\n executionAsyncId,\n triggerAsyncId,\n executionAsyncResource,\n asyncWrapProviders,\n AsyncResource\n};\nreturn $})\n"_s; +static constexpr ASCIILiteral NodeAsyncHooksCode = "(function (){\"use strict\";// src/js/out/tmp/node/async_hooks.ts\nvar get = function() {\n return @getInternalField(@asyncContext, 0);\n}, set = function(contextValue) {\n return @putInternalField(@asyncContext, 0, contextValue);\n}, createWarning = function(message) {\n let warned = !1;\n var wrapped = function() {\n if (warned)\n return;\n if (new Error().stack.includes(\"zx/build/core.js\"))\n return;\n warned = !0, console.warn(\"[bun] Warning:\", message);\n };\n return wrapped;\n}, createHook = function(callbacks) {\n return {\n enable: createHookNotImpl,\n disable: createHookNotImpl\n };\n}, executionAsyncId = function() {\n return executionAsyncIdNotImpl(), 0;\n}, triggerAsyncId = function() {\n return 0;\n}, executionAsyncResource = function() {\n return executionAsyncResourceWarning(), process.stdin;\n}, $, { cleanupLater, setAsyncHooksEnabled } = @lazy(\"async_hooks\");\n\nclass AsyncLocalStorage {\n #disableCalled = !1;\n constructor() {\n setAsyncHooksEnabled(!0);\n }\n static bind(fn, ...args) {\n return this.snapshot().bind(null, fn, ...args);\n }\n static snapshot() {\n var context = get();\n return (fn, ...args) => {\n var prev = get();\n set(context);\n try {\n return fn(...args);\n } catch (error) {\n throw error;\n } finally {\n set(prev);\n }\n };\n }\n enterWith(store) {\n cleanupLater();\n var context = get();\n if (!context) {\n set([this, store]);\n return;\n }\n var { length } = context;\n for (var i = 0;i < length; i += 2)\n if (context[i] === this) {\n const clone = context.slice();\n clone[i + 1] = store, set(clone);\n return;\n }\n set(context.concat(this, store));\n }\n exit(cb, ...args) {\n return this.run(@undefined, cb, ...args);\n }\n run(store_value, callback, ...args) {\n var context = get(), hasPrevious = !1, previous_value, i = 0, contextWasAlreadyInit = !context;\n if (contextWasAlreadyInit)\n set(context = [this, store_value]);\n else {\n if (context = context.slice(), i = context.indexOf(this), i > -1)\n hasPrevious = !0, previous_value = context[i + 1], context[i + 1] = store_value;\n else\n i = context.length, context.push(this, store_value);\n set(context);\n }\n try {\n return callback(...args);\n } catch (e) {\n throw e;\n } finally {\n if (!this.#disableCalled) {\n var context2 = get();\n if (context2 === context && contextWasAlreadyInit)\n set(@undefined);\n else if (context2 = context2.slice(), hasPrevious)\n context2[i + 1] = previous_value, set(context2);\n else\n context2.splice(i, 2), set(context2.length \? context2 : @undefined);\n }\n }\n }\n disable() {\n if (!this.#disableCalled) {\n var context = get();\n if (context) {\n var { length } = context;\n for (var i = 0;i < length; i += 2)\n if (context[i] === this) {\n context.splice(i, 2), set(context.length \? context : @undefined);\n break;\n }\n }\n this.#disableCalled = !0;\n }\n }\n getStore() {\n var context = get();\n if (!context)\n return;\n var { length } = context;\n for (var i = 0;i < length; i += 2)\n if (context[i] === this)\n return context[i + 1];\n }\n}\n\nclass AsyncResource {\n type;\n #snapshot;\n constructor(type, options) {\n if (typeof type !== \"string\")\n @throwTypeError('The \"type\" argument must be of type string. Received type ' + typeof type);\n setAsyncHooksEnabled(!0), this.type = type, this.#snapshot = get();\n }\n emitBefore() {\n return !0;\n }\n emitAfter() {\n return !0;\n }\n asyncId() {\n return 0;\n }\n triggerAsyncId() {\n return 0;\n }\n emitDestroy() {\n }\n runInAsyncScope(fn, thisArg, ...args) {\n var prev = get();\n set(this.#snapshot);\n try {\n return fn.apply(thisArg, args);\n } catch (error) {\n throw error;\n } finally {\n set(prev);\n }\n }\n bind(fn, thisArg) {\n return this.runInAsyncScope.bind(this, fn, thisArg \?\? this);\n }\n static bind(fn, type, thisArg) {\n return type = type || fn.name, new AsyncResource(type || \"bound-anonymous-fn\").bind(fn, thisArg);\n }\n}\nvar createHookNotImpl = createWarning(\"async_hooks.createHook is not implemented in Bun. Hooks can still be created but will never be called.\"), executionAsyncIdNotImpl = createWarning(\"async_hooks.executionAsyncId/triggerAsyncId are not implemented in Bun. It will return 0 every time.\"), executionAsyncResourceWarning = createWarning(\"async_hooks.executionAsyncResource is not implemented in Bun. It returns a reference to process.stdin every time.\"), asyncWrapProviders = {\n NONE: 0,\n DIRHANDLE: 1,\n DNSCHANNEL: 2,\n ELDHISTOGRAM: 3,\n FILEHANDLE: 4,\n FILEHANDLECLOSEREQ: 5,\n FIXEDSIZEBLOBCOPY: 6,\n FSEVENTWRAP: 7,\n FSREQCALLBACK: 8,\n FSREQPROMISE: 9,\n GETADDRINFOREQWRAP: 10,\n GETNAMEINFOREQWRAP: 11,\n HEAPSNAPSHOT: 12,\n HTTP2SESSION: 13,\n HTTP2STREAM: 14,\n HTTP2PING: 15,\n HTTP2SETTINGS: 16,\n HTTPINCOMINGMESSAGE: 17,\n HTTPCLIENTREQUEST: 18,\n JSSTREAM: 19,\n JSUDPWRAP: 20,\n MESSAGEPORT: 21,\n PIPECONNECTWRAP: 22,\n PIPESERVERWRAP: 23,\n PIPEWRAP: 24,\n PROCESSWRAP: 25,\n PROMISE: 26,\n QUERYWRAP: 27,\n SHUTDOWNWRAP: 28,\n SIGNALWRAP: 29,\n STATWATCHER: 30,\n STREAMPIPE: 31,\n TCPCONNECTWRAP: 32,\n TCPSERVERWRAP: 33,\n TCPWRAP: 34,\n TTYWRAP: 35,\n UDPSENDWRAP: 36,\n UDPWRAP: 37,\n SIGINTWATCHDOG: 38,\n WORKER: 39,\n WORKERHEAPSNAPSHOT: 40,\n WRITEWRAP: 41,\n ZLIB: 42,\n CHECKPRIMEREQUEST: 43,\n PBKDF2REQUEST: 44,\n KEYPAIRGENREQUEST: 45,\n KEYGENREQUEST: 46,\n KEYEXPORTREQUEST: 47,\n CIPHERREQUEST: 48,\n DERIVEBITSREQUEST: 49,\n HASHREQUEST: 50,\n RANDOMBYTESREQUEST: 51,\n RANDOMPRIMEREQUEST: 52,\n SCRYPTREQUEST: 53,\n SIGNREQUEST: 54,\n TLSWRAP: 55,\n VERIFYREQUEST: 56,\n INSPECTORJSBINDING: 57\n};\n$ = {\n AsyncLocalStorage,\n createHook,\n executionAsyncId,\n triggerAsyncId,\n executionAsyncResource,\n asyncWrapProviders,\n AsyncResource\n};\nreturn $})\n"_s; // // @@ -439,7 +439,7 @@ static constexpr ASCIILiteral NodeTraceEventsCode = "(function (){\"use strict\" // // -static constexpr ASCIILiteral NodeTtyCode = "(function (){\"use strict\";// src/js/out/tmp/node/tty.ts\nvar ReadStream = function(fd) {\n if (!(this instanceof ReadStream))\n return new ReadStream(fd);\n if (fd >> 0 !== fd || fd < 0)\n @throwRangeError(\"fd must be a positive integer\");\n const stream = (@getInternalField(@internalModuleRegistry, 21) || @createInternalModuleById(21)).ReadStream.call(this, \"\", {\n fd\n });\n return stream.isRaw = !1, stream.isTTY = isatty(stream.fd), stream;\n}, warnOnDeactivatedColors = function(env) {\n if (warned)\n return;\n let name = \"\";\n if (env.NODE_DISABLE_COLORS !== @undefined)\n name = \"NODE_DISABLE_COLORS\";\n if (env.NO_COLOR !== @undefined) {\n if (name !== \"\")\n name += \"' and '\";\n name += \"NO_COLOR\";\n }\n if (name !== \"\")\n process.emitWarning(`The '${name}' env is ignored due to the 'FORCE_COLOR' env being set.`, \"Warning\"), warned = !0;\n}, WriteStream = function(fd) {\n if (!(this instanceof WriteStream))\n return new WriteStream(fd);\n if (fd >> 0 !== fd || fd < 0)\n @throwRangeError(\"fd must be a positive integer\");\n const stream = (@getInternalField(@internalModuleRegistry, 21) || @createInternalModuleById(21)).WriteStream.call(this, \"\", {\n fd\n });\n if (stream.columns = @undefined, stream.rows = @undefined, stream.isTTY = isatty(stream.fd), stream.isTTY) {\n const windowSizeArray = [0, 0];\n if (_getWindowSize(fd, windowSizeArray) === !0)\n stream.columns = windowSizeArray[0], stream.rows = windowSizeArray[1];\n }\n return stream;\n}, { ttySetMode, isatty, getWindowSize: _getWindowSize } = @lazy(\"tty\"), StringPrototypeSplit = Function.prototype.call.bind(@String.prototype.split), RegExpPrototypeExec = Function.prototype.call.bind(@RegExp.prototype.exec), StringPrototypeToLowerCase = Function.prototype.call.bind(@String.prototype.toLowerCase), ArrayPrototypeSome = Function.prototype.call.bind(@Array.prototype.some), NumberIsInteger = Number.isInteger;\nObject.defineProperty(ReadStream, \"prototype\", {\n get() {\n const Real = (@getInternalField(@internalModuleRegistry, 21) || @createInternalModuleById(21)).ReadStream.prototype;\n return Object.defineProperty(ReadStream, \"prototype\", { value: Real }), ReadStream.prototype.setRawMode = function(flag) {\n const mode = flag \? 1 : 0, err = ttySetMode(this.fd, mode);\n if (err)\n return this.emit(\"error\", new Error(\"setRawMode failed with errno:\", err)), this;\n return this.isRaw = flag, this;\n }, Real;\n },\n enumerable: !0,\n configurable: !0\n});\nvar OSRelease, COLORS_2 = 1, COLORS_16 = 4, COLORS_256 = 8, COLORS_16m = 24, TERM_ENVS = {\n eterm: COLORS_16,\n cons25: COLORS_16,\n console: COLORS_16,\n cygwin: COLORS_16,\n dtterm: COLORS_16,\n gnome: COLORS_16,\n hurd: COLORS_16,\n jfbterm: COLORS_16,\n konsole: COLORS_16,\n kterm: COLORS_16,\n mlterm: COLORS_16,\n mosh: COLORS_16m,\n putty: COLORS_16,\n st: COLORS_16,\n \"rxvt-unicode-24bit\": COLORS_16m,\n terminator: COLORS_16m\n}, TERM_ENVS_REG_EXP = [/ansi/, /color/, /linux/, /^con[0-9]*x[0-9]/, /^rxvt/, /^screen/, /^xterm/, /^vt100/], warned = !1;\nObject.defineProperty(WriteStream, \"prototype\", {\n get() {\n const Real = (@getInternalField(@internalModuleRegistry, 21) || @createInternalModuleById(21)).WriteStream.prototype;\n Object.defineProperty(WriteStream, \"prototype\", { value: Real }), WriteStream.prototype._refreshSize = function() {\n const oldCols = this.columns, oldRows = this.rows, windowSizeArray = [0, 0];\n if (_getWindowSize(this.fd, windowSizeArray) === !0) {\n if (oldCols !== windowSizeArray[0] || oldRows !== windowSizeArray[1])\n this.columns = windowSizeArray[0], this.rows = windowSizeArray[1], this.emit(\"resize\");\n }\n };\n var readline = @undefined;\n return WriteStream.prototype.clearLine = function(dir, cb) {\n return (readline \?\?= @getInternalField(@internalModuleRegistry, 35) || @createInternalModuleById(35)).clearLine(this, dir, cb);\n }, WriteStream.prototype.clearScreenDown = function(cb) {\n return (readline \?\?= @getInternalField(@internalModuleRegistry, 35) || @createInternalModuleById(35)).clearScreenDown(this, cb);\n }, WriteStream.prototype.cursorTo = function(x, y, cb) {\n return (readline \?\?= @getInternalField(@internalModuleRegistry, 35) || @createInternalModuleById(35)).cursorTo(this, x, y, cb);\n }, WriteStream.prototype.getColorDepth = function(env = process.env) {\n if (env.FORCE_COLOR !== @undefined)\n switch (env.FORCE_COLOR) {\n case \"\":\n case \"1\":\n case \"true\":\n return warnOnDeactivatedColors(env), COLORS_16;\n case \"2\":\n return warnOnDeactivatedColors(env), COLORS_256;\n case \"3\":\n return warnOnDeactivatedColors(env), COLORS_16m;\n default:\n return COLORS_2;\n }\n if (env.NODE_DISABLE_COLORS !== @undefined || env.NO_COLOR !== @undefined || env.TERM === \"dumb\")\n return COLORS_2;\n if (OSRelease === @undefined) {\n const { release } = @getInternalField(@internalModuleRegistry, 28) || @createInternalModuleById(28);\n OSRelease = StringPrototypeSplit(release(), \".\");\n }\n if (+OSRelease[0] >= 10) {\n const build = +OSRelease[2];\n if (build >= 14931)\n return COLORS_16m;\n if (build >= 10586)\n return COLORS_256;\n }\n return COLORS_16;\n switch (env.TERM_PROGRAM) {\n case \"iTerm.app\":\n if (!env.TERM_PROGRAM_VERSION || /^[0-2]\\./.test(env.TERM_PROGRAM_VERSION))\n return COLORS_256;\n return COLORS_16m;\n case \"HyperTerm\":\n case \"MacTerm\":\n return COLORS_16m;\n case \"Apple_Terminal\":\n return COLORS_256;\n }\n }, WriteStream.prototype.getWindowSize = function() {\n return [this.columns, this.rows];\n }, WriteStream.prototype.hasColors = function(count, env) {\n if (env === @undefined && (count === @undefined || typeof count === \"object\" && count !== null))\n env = count, count = 16;\n else\n validateInteger(count, \"count\", 2);\n return count <= 2 ** this.getColorDepth(env);\n }, WriteStream.prototype.moveCursor = function(dx, dy, cb) {\n return (readline \?\?= @getInternalField(@internalModuleRegistry, 35) || @createInternalModuleById(35)).moveCursor(this, dx, dy, cb);\n }, Real;\n },\n enumerable: !0,\n configurable: !0\n});\nvar validateInteger = (value, name, min = Number.MIN_SAFE_INTEGER, max = Number.MAX_SAFE_INTEGER) => {\n if (typeof value !== \"number\")\n throw new ERR_INVALID_ARG_TYPE(name, \"number\", value);\n if (!NumberIsInteger(value))\n throw new ERR_OUT_OF_RANGE(name, \"an integer\", value);\n if (value < min || value > max)\n throw new ERR_OUT_OF_RANGE(name, `>= ${min} && <= ${max}`, value);\n};\nreturn { ReadStream, WriteStream, isatty }})\n"_s; +static constexpr ASCIILiteral NodeTtyCode = "(function (){\"use strict\";// src/js/out/tmp/node/tty.ts\nvar ReadStream = function(fd) {\n if (!(this instanceof ReadStream))\n return new ReadStream(fd);\n if (fd >> 0 !== fd || fd < 0)\n @throwRangeError(\"fd must be a positive integer\");\n const stream = (@getInternalField(@internalModuleRegistry, 21) || @createInternalModuleById(21)).ReadStream.call(this, \"\", {\n fd\n });\n return Object.setPrototypeOf(stream, ReadStream.prototype), stream.isRaw = !1, stream.isTTY = !0, stream;\n}, warnOnDeactivatedColors = function(env) {\n if (warned)\n return;\n let name = \"\";\n if (env.NODE_DISABLE_COLORS !== @undefined)\n name = \"NODE_DISABLE_COLORS\";\n if (env.NO_COLOR !== @undefined) {\n if (name !== \"\")\n name += \"' and '\";\n name += \"NO_COLOR\";\n }\n if (name !== \"\")\n process.emitWarning(`The '${name}' env is ignored due to the 'FORCE_COLOR' env being set.`, \"Warning\"), warned = !0;\n}, WriteStream = function(fd) {\n if (!(this instanceof WriteStream))\n return new WriteStream(fd);\n if (fd >> 0 !== fd || fd < 0)\n @throwRangeError(\"fd must be a positive integer\");\n const stream = (@getInternalField(@internalModuleRegistry, 21) || @createInternalModuleById(21)).WriteStream.call(this, \"\", {\n fd\n });\n if (stream.columns = @undefined, stream.rows = @undefined, stream.isTTY = isatty(stream.fd), stream.isTTY) {\n const windowSizeArray = [0, 0];\n if (_getWindowSize(fd, windowSizeArray) === !0)\n stream.columns = windowSizeArray[0], stream.rows = windowSizeArray[1];\n }\n return stream;\n}, { ttySetMode, isatty, getWindowSize: _getWindowSize } = @lazy(\"tty\"), StringPrototypeSplit = Function.prototype.call.bind(@String.prototype.split), NumberIsInteger = Number.isInteger;\nObject.defineProperty(ReadStream, \"prototype\", {\n get() {\n const Prototype = Object.create((@getInternalField(@internalModuleRegistry, 21) || @createInternalModuleById(21)).ReadStream.prototype);\n return Prototype.setRawMode = function(flag) {\n const mode = flag \? 1 : 0, err = ttySetMode(this.fd, mode);\n if (err)\n return this.emit(\"error\", new Error(\"setRawMode failed with errno: \" + err)), this;\n return this.isRaw = flag, this;\n }, Object.defineProperty(ReadStream, \"prototype\", { value: Prototype }), Prototype;\n },\n enumerable: !0,\n configurable: !0\n});\nvar OSRelease, COLORS_2 = 1, COLORS_16 = 4, COLORS_256 = 8, COLORS_16m = 24, TERM_ENVS = {\n eterm: COLORS_16,\n cons25: COLORS_16,\n console: COLORS_16,\n cygwin: COLORS_16,\n dtterm: COLORS_16,\n gnome: COLORS_16,\n hurd: COLORS_16,\n jfbterm: COLORS_16,\n konsole: COLORS_16,\n kterm: COLORS_16,\n mlterm: COLORS_16,\n mosh: COLORS_16m,\n putty: COLORS_16,\n st: COLORS_16,\n \"rxvt-unicode-24bit\": COLORS_16m,\n terminator: COLORS_16m\n}, TERM_ENVS_REG_EXP = [/ansi/, /color/, /linux/, /^con[0-9]*x[0-9]/, /^rxvt/, /^screen/, /^xterm/, /^vt100/], warned = !1;\nObject.defineProperty(WriteStream, \"prototype\", {\n get() {\n const Real = (@getInternalField(@internalModuleRegistry, 21) || @createInternalModuleById(21)).WriteStream.prototype;\n Object.defineProperty(WriteStream, \"prototype\", { value: Real }), WriteStream.prototype._refreshSize = function() {\n const oldCols = this.columns, oldRows = this.rows, windowSizeArray = [0, 0];\n if (_getWindowSize(this.fd, windowSizeArray) === !0) {\n if (oldCols !== windowSizeArray[0] || oldRows !== windowSizeArray[1])\n this.columns = windowSizeArray[0], this.rows = windowSizeArray[1], this.emit(\"resize\");\n }\n };\n var readline = @undefined;\n return WriteStream.prototype.clearLine = function(dir, cb) {\n return (readline \?\?= @getInternalField(@internalModuleRegistry, 35) || @createInternalModuleById(35)).clearLine(this, dir, cb);\n }, WriteStream.prototype.clearScreenDown = function(cb) {\n return (readline \?\?= @getInternalField(@internalModuleRegistry, 35) || @createInternalModuleById(35)).clearScreenDown(this, cb);\n }, WriteStream.prototype.cursorTo = function(x, y, cb) {\n return (readline \?\?= @getInternalField(@internalModuleRegistry, 35) || @createInternalModuleById(35)).cursorTo(this, x, y, cb);\n }, WriteStream.prototype.getColorDepth = function(env = process.env) {\n if (env.FORCE_COLOR !== @undefined)\n switch (env.FORCE_COLOR) {\n case \"\":\n case \"1\":\n case \"true\":\n return warnOnDeactivatedColors(env), COLORS_16;\n case \"2\":\n return warnOnDeactivatedColors(env), COLORS_256;\n case \"3\":\n return warnOnDeactivatedColors(env), COLORS_16m;\n default:\n return COLORS_2;\n }\n if (env.NODE_DISABLE_COLORS !== @undefined || env.NO_COLOR !== @undefined || env.TERM === \"dumb\")\n return COLORS_2;\n if (OSRelease === @undefined) {\n const { release } = @getInternalField(@internalModuleRegistry, 28) || @createInternalModuleById(28);\n OSRelease = StringPrototypeSplit(release(), \".\");\n }\n if (+OSRelease[0] >= 10) {\n const build = +OSRelease[2];\n if (build >= 14931)\n return COLORS_16m;\n if (build >= 10586)\n return COLORS_256;\n }\n return COLORS_16;\n switch (env.TERM_PROGRAM) {\n case \"iTerm.app\":\n if (!env.TERM_PROGRAM_VERSION || /^[0-2]\\./.test(env.TERM_PROGRAM_VERSION))\n return COLORS_256;\n return COLORS_16m;\n case \"HyperTerm\":\n case \"MacTerm\":\n return COLORS_16m;\n case \"Apple_Terminal\":\n return COLORS_256;\n }\n }, WriteStream.prototype.getWindowSize = function() {\n return [this.columns, this.rows];\n }, WriteStream.prototype.hasColors = function(count, env) {\n if (env === @undefined && (count === @undefined || typeof count === \"object\" && count !== null))\n env = count, count = 16;\n else\n validateInteger(count, \"count\", 2);\n return count <= 2 ** this.getColorDepth(env);\n }, WriteStream.prototype.moveCursor = function(dx, dy, cb) {\n return (readline \?\?= @getInternalField(@internalModuleRegistry, 35) || @createInternalModuleById(35)).moveCursor(this, dx, dy, cb);\n }, Real;\n },\n enumerable: !0,\n configurable: !0\n});\nvar validateInteger = (value, name, min = Number.MIN_SAFE_INTEGER, max = Number.MAX_SAFE_INTEGER) => {\n if (typeof value !== \"number\")\n throw new ERR_INVALID_ARG_TYPE(name, \"number\", value);\n if (!NumberIsInteger(value))\n throw new ERR_OUT_OF_RANGE(name, \"an integer\", value);\n if (value < min || value > max)\n throw new ERR_OUT_OF_RANGE(name, `>= ${min} && <= ${max}`, value);\n};\nreturn { ReadStream, WriteStream, isatty }})\n"_s; // // @@ -545,7 +545,7 @@ static constexpr ASCIILiteral NodeAssertStrictCode = "(function (){\"use strict\ // // -static constexpr ASCIILiteral NodeAsyncHooksCode = "(function (){\"use strict\";// src/js/out/tmp/node/async_hooks.ts\nvar get = function() {\n return @getInternalField(@asyncContext, 0);\n}, set = function(contextValue) {\n return @putInternalField(@asyncContext, 0, contextValue);\n}, createWarning = function(message) {\n let warned = !1;\n var wrapped = function() {\n if (warned)\n return;\n if (new Error().stack.includes(\"zx/build/core.js\"))\n return;\n warned = !0, console.warn(\"[bun] Warning:\", message);\n };\n return wrapped;\n}, createHook = function(callbacks) {\n return {\n enable: createHookNotImpl,\n disable: createHookNotImpl\n };\n}, executionAsyncId = function() {\n return executionAsyncIdNotImpl(), 0;\n}, triggerAsyncId = function() {\n return 0;\n}, executionAsyncResource = function() {\n return executionAsyncResourceWarning(), process.stdin;\n}, $, { cleanupLater, setAsyncHooksEnabled } = @lazy(\"async_hooks\");\n\nclass AsyncLocalStorage {\n #disableCalled = !1;\n constructor() {\n setAsyncHooksEnabled(!0);\n }\n static bind(fn, ...args) {\n return this.snapshot().bind(null, fn, ...args);\n }\n static snapshot() {\n var context = get();\n return (fn, ...args) => {\n var prev = get();\n set(context);\n try {\n return fn(...args);\n } catch (error) {\n throw error;\n } finally {\n set(prev);\n }\n };\n }\n enterWith(store) {\n cleanupLater();\n var context = get();\n if (!context) {\n set([this, store]);\n return;\n }\n var { length } = context;\n for (var i = 0;i < length; i += 2)\n if (context[i] === this) {\n const clone = context.slice();\n clone[i + 1] = store, set(clone);\n return;\n }\n set(context.concat(this, store));\n }\n exit(cb, ...args) {\n return this.run(@undefined, cb, ...args);\n }\n run(store, callback, ...args) {\n var context = get(), hasPrevious = !1, previous, i = 0, contextWasInit = !context;\n if (contextWasInit)\n set(context = [this, store]);\n else {\n if (context = context.slice(), i = context.indexOf(this), i > -1)\n hasPrevious = !0, previous = context[i + 1], context[i + 1] = store;\n else\n context.push(this, store);\n set(context);\n }\n try {\n return callback(...args);\n } catch (e) {\n throw e;\n } finally {\n if (!this.#disableCalled) {\n var context2 = get();\n if (context2 === context && contextWasInit)\n set(@undefined);\n else if (context2 = context2.slice(), hasPrevious)\n context2[i + 1] = previous, set(context2);\n else\n context2.splice(i, 2), set(context2.length \? context2 : @undefined);\n }\n }\n }\n disable() {\n if (!this.#disableCalled) {\n var context = get();\n if (context) {\n var { length } = context;\n for (var i = 0;i < length; i += 2)\n if (context[i] === this) {\n context.splice(i, 2), set(context.length \? context : @undefined);\n break;\n }\n }\n this.#disableCalled = !0;\n }\n }\n getStore() {\n var context = get();\n if (!context)\n return;\n var { length } = context;\n for (var i = 0;i < length; i += 2)\n if (context[i] === this)\n return context[i + 1];\n }\n}\n\nclass AsyncResource {\n type;\n #snapshot;\n constructor(type, options) {\n if (typeof type !== \"string\")\n @throwTypeError('The \"type\" argument must be of type string. Received type ' + typeof type);\n setAsyncHooksEnabled(!0), this.type = type, this.#snapshot = get();\n }\n emitBefore() {\n return !0;\n }\n emitAfter() {\n return !0;\n }\n asyncId() {\n return 0;\n }\n triggerAsyncId() {\n return 0;\n }\n emitDestroy() {\n }\n runInAsyncScope(fn, thisArg, ...args) {\n var prev = get();\n set(this.#snapshot);\n try {\n return fn.apply(thisArg, args);\n } catch (error) {\n throw error;\n } finally {\n set(prev);\n }\n }\n}\nvar createHookNotImpl = createWarning(\"async_hooks.createHook is not implemented in Bun. Hooks can still be created but will never be called.\"), executionAsyncIdNotImpl = createWarning(\"async_hooks.executionAsyncId/triggerAsyncId are not implemented in Bun. It will return 0 every time.\"), executionAsyncResourceWarning = createWarning(\"async_hooks.executionAsyncResource is not implemented in Bun. It returns a reference to process.stdin every time.\"), asyncWrapProviders = {\n NONE: 0,\n DIRHANDLE: 1,\n DNSCHANNEL: 2,\n ELDHISTOGRAM: 3,\n FILEHANDLE: 4,\n FILEHANDLECLOSEREQ: 5,\n FIXEDSIZEBLOBCOPY: 6,\n FSEVENTWRAP: 7,\n FSREQCALLBACK: 8,\n FSREQPROMISE: 9,\n GETADDRINFOREQWRAP: 10,\n GETNAMEINFOREQWRAP: 11,\n HEAPSNAPSHOT: 12,\n HTTP2SESSION: 13,\n HTTP2STREAM: 14,\n HTTP2PING: 15,\n HTTP2SETTINGS: 16,\n HTTPINCOMINGMESSAGE: 17,\n HTTPCLIENTREQUEST: 18,\n JSSTREAM: 19,\n JSUDPWRAP: 20,\n MESSAGEPORT: 21,\n PIPECONNECTWRAP: 22,\n PIPESERVERWRAP: 23,\n PIPEWRAP: 24,\n PROCESSWRAP: 25,\n PROMISE: 26,\n QUERYWRAP: 27,\n SHUTDOWNWRAP: 28,\n SIGNALWRAP: 29,\n STATWATCHER: 30,\n STREAMPIPE: 31,\n TCPCONNECTWRAP: 32,\n TCPSERVERWRAP: 33,\n TCPWRAP: 34,\n TTYWRAP: 35,\n UDPSENDWRAP: 36,\n UDPWRAP: 37,\n SIGINTWATCHDOG: 38,\n WORKER: 39,\n WORKERHEAPSNAPSHOT: 40,\n WRITEWRAP: 41,\n ZLIB: 42,\n CHECKPRIMEREQUEST: 43,\n PBKDF2REQUEST: 44,\n KEYPAIRGENREQUEST: 45,\n KEYGENREQUEST: 46,\n KEYEXPORTREQUEST: 47,\n CIPHERREQUEST: 48,\n DERIVEBITSREQUEST: 49,\n HASHREQUEST: 50,\n RANDOMBYTESREQUEST: 51,\n RANDOMPRIMEREQUEST: 52,\n SCRYPTREQUEST: 53,\n SIGNREQUEST: 54,\n TLSWRAP: 55,\n VERIFYREQUEST: 56,\n INSPECTORJSBINDING: 57\n};\n$ = {\n AsyncLocalStorage,\n createHook,\n executionAsyncId,\n triggerAsyncId,\n executionAsyncResource,\n asyncWrapProviders,\n AsyncResource\n};\nreturn $})\n"_s; +static constexpr ASCIILiteral NodeAsyncHooksCode = "(function (){\"use strict\";// src/js/out/tmp/node/async_hooks.ts\nvar get = function() {\n return @getInternalField(@asyncContext, 0);\n}, set = function(contextValue) {\n return @putInternalField(@asyncContext, 0, contextValue);\n}, createWarning = function(message) {\n let warned = !1;\n var wrapped = function() {\n if (warned)\n return;\n if (new Error().stack.includes(\"zx/build/core.js\"))\n return;\n warned = !0, console.warn(\"[bun] Warning:\", message);\n };\n return wrapped;\n}, createHook = function(callbacks) {\n return {\n enable: createHookNotImpl,\n disable: createHookNotImpl\n };\n}, executionAsyncId = function() {\n return executionAsyncIdNotImpl(), 0;\n}, triggerAsyncId = function() {\n return 0;\n}, executionAsyncResource = function() {\n return executionAsyncResourceWarning(), process.stdin;\n}, $, { cleanupLater, setAsyncHooksEnabled } = @lazy(\"async_hooks\");\n\nclass AsyncLocalStorage {\n #disableCalled = !1;\n constructor() {\n setAsyncHooksEnabled(!0);\n }\n static bind(fn, ...args) {\n return this.snapshot().bind(null, fn, ...args);\n }\n static snapshot() {\n var context = get();\n return (fn, ...args) => {\n var prev = get();\n set(context);\n try {\n return fn(...args);\n } catch (error) {\n throw error;\n } finally {\n set(prev);\n }\n };\n }\n enterWith(store) {\n cleanupLater();\n var context = get();\n if (!context) {\n set([this, store]);\n return;\n }\n var { length } = context;\n for (var i = 0;i < length; i += 2)\n if (context[i] === this) {\n const clone = context.slice();\n clone[i + 1] = store, set(clone);\n return;\n }\n set(context.concat(this, store));\n }\n exit(cb, ...args) {\n return this.run(@undefined, cb, ...args);\n }\n run(store_value, callback, ...args) {\n var context = get(), hasPrevious = !1, previous_value, i = 0, contextWasAlreadyInit = !context;\n if (contextWasAlreadyInit)\n set(context = [this, store_value]);\n else {\n if (context = context.slice(), i = context.indexOf(this), i > -1)\n hasPrevious = !0, previous_value = context[i + 1], context[i + 1] = store_value;\n else\n i = context.length, context.push(this, store_value);\n set(context);\n }\n try {\n return callback(...args);\n } catch (e) {\n throw e;\n } finally {\n if (!this.#disableCalled) {\n var context2 = get();\n if (context2 === context && contextWasAlreadyInit)\n set(@undefined);\n else if (context2 = context2.slice(), hasPrevious)\n context2[i + 1] = previous_value, set(context2);\n else\n context2.splice(i, 2), set(context2.length \? context2 : @undefined);\n }\n }\n }\n disable() {\n if (!this.#disableCalled) {\n var context = get();\n if (context) {\n var { length } = context;\n for (var i = 0;i < length; i += 2)\n if (context[i] === this) {\n context.splice(i, 2), set(context.length \? context : @undefined);\n break;\n }\n }\n this.#disableCalled = !0;\n }\n }\n getStore() {\n var context = get();\n if (!context)\n return;\n var { length } = context;\n for (var i = 0;i < length; i += 2)\n if (context[i] === this)\n return context[i + 1];\n }\n}\n\nclass AsyncResource {\n type;\n #snapshot;\n constructor(type, options) {\n if (typeof type !== \"string\")\n @throwTypeError('The \"type\" argument must be of type string. Received type ' + typeof type);\n setAsyncHooksEnabled(!0), this.type = type, this.#snapshot = get();\n }\n emitBefore() {\n return !0;\n }\n emitAfter() {\n return !0;\n }\n asyncId() {\n return 0;\n }\n triggerAsyncId() {\n return 0;\n }\n emitDestroy() {\n }\n runInAsyncScope(fn, thisArg, ...args) {\n var prev = get();\n set(this.#snapshot);\n try {\n return fn.apply(thisArg, args);\n } catch (error) {\n throw error;\n } finally {\n set(prev);\n }\n }\n bind(fn, thisArg) {\n return this.runInAsyncScope.bind(this, fn, thisArg \?\? this);\n }\n static bind(fn, type, thisArg) {\n return type = type || fn.name, new AsyncResource(type || \"bound-anonymous-fn\").bind(fn, thisArg);\n }\n}\nvar createHookNotImpl = createWarning(\"async_hooks.createHook is not implemented in Bun. Hooks can still be created but will never be called.\"), executionAsyncIdNotImpl = createWarning(\"async_hooks.executionAsyncId/triggerAsyncId are not implemented in Bun. It will return 0 every time.\"), executionAsyncResourceWarning = createWarning(\"async_hooks.executionAsyncResource is not implemented in Bun. It returns a reference to process.stdin every time.\"), asyncWrapProviders = {\n NONE: 0,\n DIRHANDLE: 1,\n DNSCHANNEL: 2,\n ELDHISTOGRAM: 3,\n FILEHANDLE: 4,\n FILEHANDLECLOSEREQ: 5,\n FIXEDSIZEBLOBCOPY: 6,\n FSEVENTWRAP: 7,\n FSREQCALLBACK: 8,\n FSREQPROMISE: 9,\n GETADDRINFOREQWRAP: 10,\n GETNAMEINFOREQWRAP: 11,\n HEAPSNAPSHOT: 12,\n HTTP2SESSION: 13,\n HTTP2STREAM: 14,\n HTTP2PING: 15,\n HTTP2SETTINGS: 16,\n HTTPINCOMINGMESSAGE: 17,\n HTTPCLIENTREQUEST: 18,\n JSSTREAM: 19,\n JSUDPWRAP: 20,\n MESSAGEPORT: 21,\n PIPECONNECTWRAP: 22,\n PIPESERVERWRAP: 23,\n PIPEWRAP: 24,\n PROCESSWRAP: 25,\n PROMISE: 26,\n QUERYWRAP: 27,\n SHUTDOWNWRAP: 28,\n SIGNALWRAP: 29,\n STATWATCHER: 30,\n STREAMPIPE: 31,\n TCPCONNECTWRAP: 32,\n TCPSERVERWRAP: 33,\n TCPWRAP: 34,\n TTYWRAP: 35,\n UDPSENDWRAP: 36,\n UDPWRAP: 37,\n SIGINTWATCHDOG: 38,\n WORKER: 39,\n WORKERHEAPSNAPSHOT: 40,\n WRITEWRAP: 41,\n ZLIB: 42,\n CHECKPRIMEREQUEST: 43,\n PBKDF2REQUEST: 44,\n KEYPAIRGENREQUEST: 45,\n KEYGENREQUEST: 46,\n KEYEXPORTREQUEST: 47,\n CIPHERREQUEST: 48,\n DERIVEBITSREQUEST: 49,\n HASHREQUEST: 50,\n RANDOMBYTESREQUEST: 51,\n RANDOMPRIMEREQUEST: 52,\n SCRYPTREQUEST: 53,\n SIGNREQUEST: 54,\n TLSWRAP: 55,\n VERIFYREQUEST: 56,\n INSPECTORJSBINDING: 57\n};\n$ = {\n AsyncLocalStorage,\n createHook,\n executionAsyncId,\n triggerAsyncId,\n executionAsyncResource,\n asyncWrapProviders,\n AsyncResource\n};\nreturn $})\n"_s; // // @@ -689,7 +689,7 @@ static constexpr ASCIILiteral NodeTraceEventsCode = "(function (){\"use strict\" // // -static constexpr ASCIILiteral NodeTtyCode = "(function (){\"use strict\";// src/js/out/tmp/node/tty.ts\nvar ReadStream = function(fd) {\n if (!(this instanceof ReadStream))\n return new ReadStream(fd);\n if (fd >> 0 !== fd || fd < 0)\n @throwRangeError(\"fd must be a positive integer\");\n const stream = (@getInternalField(@internalModuleRegistry, 21) || @createInternalModuleById(21)).ReadStream.call(this, \"\", {\n fd\n });\n return stream.isRaw = !1, stream.isTTY = isatty(stream.fd), stream;\n}, warnOnDeactivatedColors = function(env) {\n if (warned)\n return;\n let name = \"\";\n if (env.NODE_DISABLE_COLORS !== @undefined)\n name = \"NODE_DISABLE_COLORS\";\n if (env.NO_COLOR !== @undefined) {\n if (name !== \"\")\n name += \"' and '\";\n name += \"NO_COLOR\";\n }\n if (name !== \"\")\n process.emitWarning(`The '${name}' env is ignored due to the 'FORCE_COLOR' env being set.`, \"Warning\"), warned = !0;\n}, WriteStream = function(fd) {\n if (!(this instanceof WriteStream))\n return new WriteStream(fd);\n if (fd >> 0 !== fd || fd < 0)\n @throwRangeError(\"fd must be a positive integer\");\n const stream = (@getInternalField(@internalModuleRegistry, 21) || @createInternalModuleById(21)).WriteStream.call(this, \"\", {\n fd\n });\n if (stream.columns = @undefined, stream.rows = @undefined, stream.isTTY = isatty(stream.fd), stream.isTTY) {\n const windowSizeArray = [0, 0];\n if (_getWindowSize(fd, windowSizeArray) === !0)\n stream.columns = windowSizeArray[0], stream.rows = windowSizeArray[1];\n }\n return stream;\n}, { ttySetMode, isatty, getWindowSize: _getWindowSize } = @lazy(\"tty\"), StringPrototypeSplit = Function.prototype.call.bind(@String.prototype.split), RegExpPrototypeExec = Function.prototype.call.bind(@RegExp.prototype.exec), StringPrototypeToLowerCase = Function.prototype.call.bind(@String.prototype.toLowerCase), ArrayPrototypeSome = Function.prototype.call.bind(@Array.prototype.some), NumberIsInteger = Number.isInteger;\nObject.defineProperty(ReadStream, \"prototype\", {\n get() {\n const Real = (@getInternalField(@internalModuleRegistry, 21) || @createInternalModuleById(21)).ReadStream.prototype;\n return Object.defineProperty(ReadStream, \"prototype\", { value: Real }), ReadStream.prototype.setRawMode = function(flag) {\n const mode = flag \? 1 : 0, err = ttySetMode(this.fd, mode);\n if (err)\n return this.emit(\"error\", new Error(\"setRawMode failed with errno:\", err)), this;\n return this.isRaw = flag, this;\n }, Real;\n },\n enumerable: !0,\n configurable: !0\n});\nvar COLORS_2 = 1, COLORS_16 = 4, COLORS_256 = 8, COLORS_16m = 24, TERM_ENVS = {\n eterm: COLORS_16,\n cons25: COLORS_16,\n console: COLORS_16,\n cygwin: COLORS_16,\n dtterm: COLORS_16,\n gnome: COLORS_16,\n hurd: COLORS_16,\n jfbterm: COLORS_16,\n konsole: COLORS_16,\n kterm: COLORS_16,\n mlterm: COLORS_16,\n mosh: COLORS_16m,\n putty: COLORS_16,\n st: COLORS_16,\n \"rxvt-unicode-24bit\": COLORS_16m,\n terminator: COLORS_16m\n}, TERM_ENVS_REG_EXP = [/ansi/, /color/, /linux/, /^con[0-9]*x[0-9]/, /^rxvt/, /^screen/, /^xterm/, /^vt100/], warned = !1;\nObject.defineProperty(WriteStream, \"prototype\", {\n get() {\n const Real = (@getInternalField(@internalModuleRegistry, 21) || @createInternalModuleById(21)).WriteStream.prototype;\n Object.defineProperty(WriteStream, \"prototype\", { value: Real }), WriteStream.prototype._refreshSize = function() {\n const oldCols = this.columns, oldRows = this.rows, windowSizeArray = [0, 0];\n if (_getWindowSize(this.fd, windowSizeArray) === !0) {\n if (oldCols !== windowSizeArray[0] || oldRows !== windowSizeArray[1])\n this.columns = windowSizeArray[0], this.rows = windowSizeArray[1], this.emit(\"resize\");\n }\n };\n var readline = @undefined;\n return WriteStream.prototype.clearLine = function(dir, cb) {\n return (readline \?\?= @getInternalField(@internalModuleRegistry, 35) || @createInternalModuleById(35)).clearLine(this, dir, cb);\n }, WriteStream.prototype.clearScreenDown = function(cb) {\n return (readline \?\?= @getInternalField(@internalModuleRegistry, 35) || @createInternalModuleById(35)).clearScreenDown(this, cb);\n }, WriteStream.prototype.cursorTo = function(x, y, cb) {\n return (readline \?\?= @getInternalField(@internalModuleRegistry, 35) || @createInternalModuleById(35)).cursorTo(this, x, y, cb);\n }, WriteStream.prototype.getColorDepth = function(env = process.env) {\n if (env.FORCE_COLOR !== @undefined)\n switch (env.FORCE_COLOR) {\n case \"\":\n case \"1\":\n case \"true\":\n return warnOnDeactivatedColors(env), COLORS_16;\n case \"2\":\n return warnOnDeactivatedColors(env), COLORS_256;\n case \"3\":\n return warnOnDeactivatedColors(env), COLORS_16m;\n default:\n return COLORS_2;\n }\n if (env.NODE_DISABLE_COLORS !== @undefined || env.NO_COLOR !== @undefined || env.TERM === \"dumb\")\n return COLORS_2;\n if (env.TMUX)\n return COLORS_256;\n if (env.CI) {\n if ([\"APPVEYOR\", \"BUILDKITE\", \"CIRCLECI\", \"DRONE\", \"GITHUB_ACTIONS\", \"GITLAB_CI\", \"TRAVIS\"].some((sign) => (sign in env)) || env.CI_NAME === \"codeship\")\n return COLORS_256;\n return COLORS_2;\n }\n if (\"TEAMCITY_VERSION\" in env)\n return /^(9\\.(0*[1-9]\\d*)\\.|\\d{2,}\\.)/.test(env.TEAMCITY_VERSION) \? COLORS_16 : COLORS_2;\n switch (env.TERM_PROGRAM) {\n case \"iTerm.app\":\n if (!env.TERM_PROGRAM_VERSION || /^[0-2]\\./.test(env.TERM_PROGRAM_VERSION))\n return COLORS_256;\n return COLORS_16m;\n case \"HyperTerm\":\n case \"MacTerm\":\n return COLORS_16m;\n case \"Apple_Terminal\":\n return COLORS_256;\n }\n if (env.COLORTERM === \"truecolor\" || env.COLORTERM === \"24bit\")\n return COLORS_16m;\n if (env.TERM) {\n if (/^xterm-256/.test(env.TERM) !== null)\n return COLORS_256;\n const termEnv = env.TERM.toLowerCase();\n if (TERM_ENVS[termEnv])\n return TERM_ENVS[termEnv];\n if (TERM_ENVS_REG_EXP.some((term) => term.test(termEnv)))\n return COLORS_16;\n }\n if (env.COLORTERM)\n return COLORS_16;\n return COLORS_2;\n }, WriteStream.prototype.getWindowSize = function() {\n return [this.columns, this.rows];\n }, WriteStream.prototype.hasColors = function(count, env) {\n if (env === @undefined && (count === @undefined || typeof count === \"object\" && count !== null))\n env = count, count = 16;\n else\n validateInteger(count, \"count\", 2);\n return count <= 2 ** this.getColorDepth(env);\n }, WriteStream.prototype.moveCursor = function(dx, dy, cb) {\n return (readline \?\?= @getInternalField(@internalModuleRegistry, 35) || @createInternalModuleById(35)).moveCursor(this, dx, dy, cb);\n }, Real;\n },\n enumerable: !0,\n configurable: !0\n});\nvar validateInteger = (value, name, min = Number.MIN_SAFE_INTEGER, max = Number.MAX_SAFE_INTEGER) => {\n if (typeof value !== \"number\")\n throw new ERR_INVALID_ARG_TYPE(name, \"number\", value);\n if (!NumberIsInteger(value))\n throw new ERR_OUT_OF_RANGE(name, \"an integer\", value);\n if (value < min || value > max)\n throw new ERR_OUT_OF_RANGE(name, `>= ${min} && <= ${max}`, value);\n};\nreturn { ReadStream, WriteStream, isatty }})\n"_s; +static constexpr ASCIILiteral NodeTtyCode = "(function (){\"use strict\";// src/js/out/tmp/node/tty.ts\nvar ReadStream = function(fd) {\n if (!(this instanceof ReadStream))\n return new ReadStream(fd);\n if (fd >> 0 !== fd || fd < 0)\n @throwRangeError(\"fd must be a positive integer\");\n const stream = (@getInternalField(@internalModuleRegistry, 21) || @createInternalModuleById(21)).ReadStream.call(this, \"\", {\n fd\n });\n return Object.setPrototypeOf(stream, ReadStream.prototype), stream.isRaw = !1, stream.isTTY = !0, stream;\n}, warnOnDeactivatedColors = function(env) {\n if (warned)\n return;\n let name = \"\";\n if (env.NODE_DISABLE_COLORS !== @undefined)\n name = \"NODE_DISABLE_COLORS\";\n if (env.NO_COLOR !== @undefined) {\n if (name !== \"\")\n name += \"' and '\";\n name += \"NO_COLOR\";\n }\n if (name !== \"\")\n process.emitWarning(`The '${name}' env is ignored due to the 'FORCE_COLOR' env being set.`, \"Warning\"), warned = !0;\n}, WriteStream = function(fd) {\n if (!(this instanceof WriteStream))\n return new WriteStream(fd);\n if (fd >> 0 !== fd || fd < 0)\n @throwRangeError(\"fd must be a positive integer\");\n const stream = (@getInternalField(@internalModuleRegistry, 21) || @createInternalModuleById(21)).WriteStream.call(this, \"\", {\n fd\n });\n if (stream.columns = @undefined, stream.rows = @undefined, stream.isTTY = isatty(stream.fd), stream.isTTY) {\n const windowSizeArray = [0, 0];\n if (_getWindowSize(fd, windowSizeArray) === !0)\n stream.columns = windowSizeArray[0], stream.rows = windowSizeArray[1];\n }\n return stream;\n}, { ttySetMode, isatty, getWindowSize: _getWindowSize } = @lazy(\"tty\"), StringPrototypeSplit = Function.prototype.call.bind(@String.prototype.split), NumberIsInteger = Number.isInteger;\nObject.defineProperty(ReadStream, \"prototype\", {\n get() {\n const Prototype = Object.create((@getInternalField(@internalModuleRegistry, 21) || @createInternalModuleById(21)).ReadStream.prototype);\n return Prototype.setRawMode = function(flag) {\n const mode = flag \? 1 : 0, err = ttySetMode(this.fd, mode);\n if (err)\n return this.emit(\"error\", new Error(\"setRawMode failed with errno: \" + err)), this;\n return this.isRaw = flag, this;\n }, Object.defineProperty(ReadStream, \"prototype\", { value: Prototype }), Prototype;\n },\n enumerable: !0,\n configurable: !0\n});\nvar COLORS_2 = 1, COLORS_16 = 4, COLORS_256 = 8, COLORS_16m = 24, TERM_ENVS = {\n eterm: COLORS_16,\n cons25: COLORS_16,\n console: COLORS_16,\n cygwin: COLORS_16,\n dtterm: COLORS_16,\n gnome: COLORS_16,\n hurd: COLORS_16,\n jfbterm: COLORS_16,\n konsole: COLORS_16,\n kterm: COLORS_16,\n mlterm: COLORS_16,\n mosh: COLORS_16m,\n putty: COLORS_16,\n st: COLORS_16,\n \"rxvt-unicode-24bit\": COLORS_16m,\n terminator: COLORS_16m\n}, TERM_ENVS_REG_EXP = [/ansi/, /color/, /linux/, /^con[0-9]*x[0-9]/, /^rxvt/, /^screen/, /^xterm/, /^vt100/], warned = !1;\nObject.defineProperty(WriteStream, \"prototype\", {\n get() {\n const Real = (@getInternalField(@internalModuleRegistry, 21) || @createInternalModuleById(21)).WriteStream.prototype;\n Object.defineProperty(WriteStream, \"prototype\", { value: Real }), WriteStream.prototype._refreshSize = function() {\n const oldCols = this.columns, oldRows = this.rows, windowSizeArray = [0, 0];\n if (_getWindowSize(this.fd, windowSizeArray) === !0) {\n if (oldCols !== windowSizeArray[0] || oldRows !== windowSizeArray[1])\n this.columns = windowSizeArray[0], this.rows = windowSizeArray[1], this.emit(\"resize\");\n }\n };\n var readline = @undefined;\n return WriteStream.prototype.clearLine = function(dir, cb) {\n return (readline \?\?= @getInternalField(@internalModuleRegistry, 35) || @createInternalModuleById(35)).clearLine(this, dir, cb);\n }, WriteStream.prototype.clearScreenDown = function(cb) {\n return (readline \?\?= @getInternalField(@internalModuleRegistry, 35) || @createInternalModuleById(35)).clearScreenDown(this, cb);\n }, WriteStream.prototype.cursorTo = function(x, y, cb) {\n return (readline \?\?= @getInternalField(@internalModuleRegistry, 35) || @createInternalModuleById(35)).cursorTo(this, x, y, cb);\n }, WriteStream.prototype.getColorDepth = function(env = process.env) {\n if (env.FORCE_COLOR !== @undefined)\n switch (env.FORCE_COLOR) {\n case \"\":\n case \"1\":\n case \"true\":\n return warnOnDeactivatedColors(env), COLORS_16;\n case \"2\":\n return warnOnDeactivatedColors(env), COLORS_256;\n case \"3\":\n return warnOnDeactivatedColors(env), COLORS_16m;\n default:\n return COLORS_2;\n }\n if (env.NODE_DISABLE_COLORS !== @undefined || env.NO_COLOR !== @undefined || env.TERM === \"dumb\")\n return COLORS_2;\n if (env.TMUX)\n return COLORS_256;\n if (env.CI) {\n if ([\"APPVEYOR\", \"BUILDKITE\", \"CIRCLECI\", \"DRONE\", \"GITHUB_ACTIONS\", \"GITLAB_CI\", \"TRAVIS\"].some((sign) => (sign in env)) || env.CI_NAME === \"codeship\")\n return COLORS_256;\n return COLORS_2;\n }\n if (\"TEAMCITY_VERSION\" in env)\n return /^(9\\.(0*[1-9]\\d*)\\.|\\d{2,}\\.)/.test(env.TEAMCITY_VERSION) \? COLORS_16 : COLORS_2;\n switch (env.TERM_PROGRAM) {\n case \"iTerm.app\":\n if (!env.TERM_PROGRAM_VERSION || /^[0-2]\\./.test(env.TERM_PROGRAM_VERSION))\n return COLORS_256;\n return COLORS_16m;\n case \"HyperTerm\":\n case \"MacTerm\":\n return COLORS_16m;\n case \"Apple_Terminal\":\n return COLORS_256;\n }\n if (env.COLORTERM === \"truecolor\" || env.COLORTERM === \"24bit\")\n return COLORS_16m;\n if (env.TERM) {\n if (/^xterm-256/.test(env.TERM) !== null)\n return COLORS_256;\n const termEnv = env.TERM.toLowerCase();\n if (TERM_ENVS[termEnv])\n return TERM_ENVS[termEnv];\n if (TERM_ENVS_REG_EXP.some((term) => term.test(termEnv)))\n return COLORS_16;\n }\n if (env.COLORTERM)\n return COLORS_16;\n return COLORS_2;\n }, WriteStream.prototype.getWindowSize = function() {\n return [this.columns, this.rows];\n }, WriteStream.prototype.hasColors = function(count, env) {\n if (env === @undefined && (count === @undefined || typeof count === \"object\" && count !== null))\n env = count, count = 16;\n else\n validateInteger(count, \"count\", 2);\n return count <= 2 ** this.getColorDepth(env);\n }, WriteStream.prototype.moveCursor = function(dx, dy, cb) {\n return (readline \?\?= @getInternalField(@internalModuleRegistry, 35) || @createInternalModuleById(35)).moveCursor(this, dx, dy, cb);\n }, Real;\n },\n enumerable: !0,\n configurable: !0\n});\nvar validateInteger = (value, name, min = Number.MIN_SAFE_INTEGER, max = Number.MAX_SAFE_INTEGER) => {\n if (typeof value !== \"number\")\n throw new ERR_INVALID_ARG_TYPE(name, \"number\", value);\n if (!NumberIsInteger(value))\n throw new ERR_OUT_OF_RANGE(name, \"an integer\", value);\n if (value < min || value > max)\n throw new ERR_OUT_OF_RANGE(name, `>= ${min} && <= ${max}`, value);\n};\nreturn { ReadStream, WriteStream, isatty }})\n"_s; // // diff --git a/src/js/out/WebCoreJSBuiltins.cpp b/src/js/out/WebCoreJSBuiltins.cpp index 4940ed1f5..a60dfc281 100644 --- a/src/js/out/WebCoreJSBuiltins.cpp +++ b/src/js/out/WebCoreJSBuiltins.cpp @@ -786,13 +786,21 @@ const int s_moduleMainCodeLength = 68; static const JSC::Intrinsic s_moduleMainCodeIntrinsic = JSC::NoIntrinsic; const char* const s_moduleMainCode = "(function () {\"use strict\";\n return @requireMap.@get(Bun.main);\n})\n"; +// overridableRequire +const JSC::ConstructAbility s_moduleOverridableRequireCodeConstructAbility = JSC::ConstructAbility::CannotConstruct; +const JSC::ConstructorKind s_moduleOverridableRequireCodeConstructorKind = JSC::ConstructorKind::None; +const JSC::ImplementationVisibility s_moduleOverridableRequireCodeImplementationVisibility = JSC::ImplementationVisibility::Public; +const int s_moduleOverridableRequireCodeLength = 888; +static const JSC::Intrinsic s_moduleOverridableRequireCodeIntrinsic = JSC::NoIntrinsic; +const char* const s_moduleOverridableRequireCode = "(function (id) {\"use strict\";\n const existing = @requireMap.@get(id) || @requireMap.@get(id = @resolveSync(id, this.path, !1));\n if (existing)\n return @evaluateCommonJSModule(existing), existing.exports;\n if (id.endsWith(\".node\"))\n return @internalRequire(id);\n const mod = @createCommonJSModule(id, {}, !1, this);\n @requireMap.@set(id, mod);\n var out = this.@require(id, mod);\n if (out === -1) {\n try {\n out = @requireESM(id);\n } catch (exception) {\n throw @requireMap.@delete(id), exception;\n }\n const esm = @Loader.registry.@get(id);\n if (esm\?.evaluated && (esm.state \?\? 0) >= @ModuleReady) {\n const namespace = @Loader.getModuleNamespaceObject(esm.module);\n return mod.exports = namespace.__esModule \? namespace : Object.create(namespace, { __esModule: { value: !0 } });\n }\n }\n return @evaluateCommonJSModule(mod), mod.exports;\n})\n"; + // require const JSC::ConstructAbility s_moduleRequireCodeConstructAbility = JSC::ConstructAbility::CannotConstruct; const JSC::ConstructorKind s_moduleRequireCodeConstructorKind = JSC::ConstructorKind::None; const JSC::ImplementationVisibility s_moduleRequireCodeImplementationVisibility = JSC::ImplementationVisibility::Public; -const int s_moduleRequireCodeLength = 888; +const int s_moduleRequireCodeLength = 79; static const JSC::Intrinsic s_moduleRequireCodeIntrinsic = JSC::NoIntrinsic; -const char* const s_moduleRequireCode = "(function (id) {\"use strict\";\n const existing = @requireMap.@get(id) || @requireMap.@get(id = @resolveSync(id, this.path, !1));\n if (existing)\n return @evaluateCommonJSModule(existing), existing.exports;\n if (id.endsWith(\".node\"))\n return @internalRequire(id);\n const mod = @createCommonJSModule(id, {}, !1, this);\n @requireMap.@set(id, mod);\n var out = this.@require(id, mod);\n if (out === -1) {\n try {\n out = @requireESM(id);\n } catch (exception) {\n throw @requireMap.@delete(id), exception;\n }\n const esm = @Loader.registry.@get(id);\n if (esm\?.evaluated && (esm.state \?\? 0) >= @ModuleReady) {\n const namespace = @Loader.getModuleNamespaceObject(esm.module);\n return mod.exports = namespace.__esModule \? namespace : Object.create(namespace, { __esModule: { value: !0 } });\n }\n }\n return @evaluateCommonJSModule(mod), mod.exports;\n})\n"; +const char* const s_moduleRequireCode = "(function (id) {\"use strict\";\n return @overridableRequire.@call(this, id);\n})\n"; // requireNativeModule const JSC::ConstructAbility s_moduleRequireNativeModuleCodeConstructAbility = JSC::ConstructAbility::CannotConstruct; @@ -824,9 +832,9 @@ WEBCORE_FOREACH_MODULE_BUILTIN_CODE(DEFINE_BUILTIN_GENERATOR) const JSC::ConstructAbility s_processObjectInternalsGetStdinStreamCodeConstructAbility = JSC::ConstructAbility::CannotConstruct; const JSC::ConstructorKind s_processObjectInternalsGetStdinStreamCodeConstructorKind = JSC::ConstructorKind::None; const JSC::ImplementationVisibility s_processObjectInternalsGetStdinStreamCodeImplementationVisibility = JSC::ImplementationVisibility::Public; -const int s_processObjectInternalsGetStdinStreamCodeLength = 1820; +const int s_processObjectInternalsGetStdinStreamCodeLength = 1945; static const JSC::Intrinsic s_processObjectInternalsGetStdinStreamCodeIntrinsic = JSC::NoIntrinsic; -const char* const s_processObjectInternalsGetStdinStreamCode = "(function (fd) {\"use strict\";\n var reader, readerRef;\n function ref() {\n reader \?\?= Bun.stdin.stream().getReader(), readerRef \?\?= setInterval(() => {\n }, 1 << 30);\n }\n function unref() {\n if (readerRef)\n clearInterval(readerRef), readerRef = @undefined;\n if (reader)\n reader.cancel(), reader = @undefined;\n }\n const stream = new ((@getInternalField(@internalModuleRegistry, 46)) || (@createInternalModuleById(46))).ReadStream(fd), originalOn = stream.on;\n stream.on = function(event, listener) {\n if (event === \"readable\")\n ref();\n return originalOn.call(this, event, listener);\n }, stream.fd = fd;\n const originalPause = stream.pause;\n stream.pause = function() {\n return unref(), originalPause.call(this);\n };\n const originalResume = stream.resume;\n stream.resume = function() {\n return ref(), originalResume.call(this);\n };\n async function internalRead(stream2) {\n try {\n var done, value;\n const read = reader\?.readMany();\n if (@isPromise(read))\n ({ done, value } = await read);\n else\n ({ done, value } = read);\n if (!done) {\n stream2.push(value[0]);\n const length = value.length;\n for (let i = 1;i < length; i++)\n stream2.push(value[i]);\n } else\n stream2.emit(\"end\"), stream2.pause();\n } catch (err) {\n stream2.destroy(err);\n }\n }\n return stream._read = function(size) {\n internalRead(this);\n }, stream.on(\"resume\", () => {\n ref(), stream._undestroy();\n }), stream._readableState.reading = !1, stream.on(\"pause\", () => {\n process.nextTick(() => {\n if (!stream.readableFlowing)\n stream._readableState.reading = !1;\n });\n }), stream.on(\"close\", () => {\n process.nextTick(() => {\n stream.destroy(), unref();\n });\n }), stream;\n})\n"; +const char* const s_processObjectInternalsGetStdinStreamCode = "(function (fd) {\"use strict\";\n var reader, readerRef;\n function ref() {\n reader \?\?= Bun.stdin.stream().getReader(), readerRef \?\?= setInterval(() => {\n }, 1 << 30);\n }\n function unref() {\n if (readerRef)\n clearInterval(readerRef), readerRef = @undefined;\n if (reader)\n reader.cancel(), reader = @undefined;\n }\n const tty = @getInternalField(@internalModuleRegistry, 46) || @createInternalModuleById(46), stream = new ((tty.isatty(fd)) \? tty.ReadStream : ((@getInternalField(@internalModuleRegistry, 21)) || (@createInternalModuleById(21))).ReadStream)(fd), originalOn = stream.on;\n stream.on = function(event, listener) {\n if (event === \"readable\")\n ref();\n return originalOn.call(this, event, listener);\n }, stream.fd = fd;\n const originalPause = stream.pause;\n stream.pause = function() {\n return unref(), originalPause.call(this);\n };\n const originalResume = stream.resume;\n stream.resume = function() {\n return ref(), originalResume.call(this);\n };\n async function internalRead(stream2) {\n try {\n var done, value;\n const read = reader\?.readMany();\n if (@isPromise(read))\n ({ done, value } = await read);\n else\n ({ done, value } = read);\n if (!done) {\n stream2.push(value[0]);\n const length = value.length;\n for (let i = 1;i < length; i++)\n stream2.push(value[i]);\n } else\n stream2.emit(\"end\"), stream2.pause();\n } catch (err) {\n stream2.destroy(err);\n }\n }\n return stream._read = function(size) {\n internalRead(this);\n }, stream.on(\"resume\", () => {\n ref(), stream._undestroy();\n }), stream._readableState.reading = !1, stream.on(\"pause\", () => {\n process.nextTick(() => {\n if (!stream.readableFlowing)\n stream._readableState.reading = !1;\n });\n }), stream.on(\"close\", () => {\n process.nextTick(() => {\n stream.destroy(), unref();\n });\n }), stream;\n})\n"; // getStdioWriteStream const JSC::ConstructAbility s_processObjectInternalsGetStdioWriteStreamCodeConstructAbility = JSC::ConstructAbility::CannotConstruct; diff --git a/src/js/out/WebCoreJSBuiltins.h b/src/js/out/WebCoreJSBuiltins.h index 70401c088..3c6ade197 100644 --- a/src/js/out/WebCoreJSBuiltins.h +++ b/src/js/out/WebCoreJSBuiltins.h @@ -1506,6 +1506,14 @@ extern const JSC::ConstructAbility s_moduleMainCodeConstructAbility; extern const JSC::ConstructorKind s_moduleMainCodeConstructorKind; extern const JSC::ImplementationVisibility s_moduleMainCodeImplementationVisibility; +// overridableRequire +#define WEBCORE_BUILTIN_MODULE_OVERRIDABLEREQUIRE 1 +extern const char* const s_moduleOverridableRequireCode; +extern const int s_moduleOverridableRequireCodeLength; +extern const JSC::ConstructAbility s_moduleOverridableRequireCodeConstructAbility; +extern const JSC::ConstructorKind s_moduleOverridableRequireCodeConstructorKind; +extern const JSC::ImplementationVisibility s_moduleOverridableRequireCodeImplementationVisibility; + // require #define WEBCORE_BUILTIN_MODULE_REQUIRE 1 extern const char* const s_moduleRequireCode; @@ -1532,18 +1540,21 @@ extern const JSC::ImplementationVisibility s_moduleRequireResolveCodeImplementat #define WEBCORE_FOREACH_MODULE_BUILTIN_DATA(macro) \ macro(main, moduleMain, 0) \ + macro(overridableRequire, moduleOverridableRequire, 1) \ macro(require, moduleRequire, 1) \ macro(requireNativeModule, moduleRequireNativeModule, 1) \ macro(requireResolve, moduleRequireResolve, 1) \ #define WEBCORE_FOREACH_MODULE_BUILTIN_CODE(macro) \ macro(moduleMainCode, main, "get main"_s, s_moduleMainCodeLength) \ + macro(moduleOverridableRequireCode, overridableRequire, ASCIILiteral(), s_moduleOverridableRequireCodeLength) \ macro(moduleRequireCode, require, ASCIILiteral(), s_moduleRequireCodeLength) \ macro(moduleRequireNativeModuleCode, requireNativeModule, ASCIILiteral(), s_moduleRequireNativeModuleCodeLength) \ macro(moduleRequireResolveCode, requireResolve, ASCIILiteral(), s_moduleRequireResolveCodeLength) \ #define WEBCORE_FOREACH_MODULE_BUILTIN_FUNCTION_NAME(macro) \ macro(main) \ + macro(overridableRequire) \ macro(require) \ macro(requireNativeModule) \ macro(requireResolve) \ diff --git a/src/js_ast.zig b/src/js_ast.zig index b9e34d279..46c204e69 100644 --- a/src/js_ast.zig +++ b/src/js_ast.zig @@ -5994,6 +5994,7 @@ pub const Ast = struct { /// This is a list of named exports that may exist in a CommonJS module /// We use this with `commonjs_at_runtime` to re-export CommonJS commonjs_export_names: []string = &([_]string{}), + import_meta_ref: Ref = Ref.None, pub const CommonJSNamedExport = struct { loc_ref: LocRef, diff --git a/src/js_parser.zig b/src/js_parser.zig index 449d1cbab..fce928a6e 100644 --- a/src/js_parser.zig +++ b/src/js_parser.zig @@ -21241,42 +21241,50 @@ fn NewParser_( parts[parts.len - 1].stmts = new_stmts_list; }, - // This becomes + // This transforms the user's code into. // - // (function (module, exports, require) { + // (function (exports, require, module, __filename, __dirname) { + // ... + // }).call( + // this.module.exports, + // this.module.exports, + // this.require, + // this.module, + // this.__filename, + // this.__dirname, + // ); // - // })(module, exports, require); + // `this` is a `CommonJSFunctionArgumentsStructure` + // which is initialized in `evaluateCommonJSModuleOnce` .bun_js => { var args = allocator.alloc(Arg, 5) catch unreachable; args[0..5].* = .{ - Arg{ - .binding = p.b(B.Identifier{ .ref = p.module_ref }, logger.Loc.Empty), - }, - Arg{ - .binding = p.b(B.Identifier{ .ref = p.exports_ref }, logger.Loc.Empty), - }, - Arg{ - .binding = p.b(B.Identifier{ .ref = p.require_ref }, logger.Loc.Empty), - }, - Arg{ - .binding = p.b(B.Identifier{ .ref = p.dirname_ref }, logger.Loc.Empty), - }, - Arg{ - .binding = p.b(B.Identifier{ .ref = p.filename_ref }, logger.Loc.Empty), - }, + Arg{ .binding = p.b(B.Identifier{ .ref = p.exports_ref }, logger.Loc.Empty) }, + Arg{ .binding = p.b(B.Identifier{ .ref = p.require_ref }, logger.Loc.Empty) }, + Arg{ .binding = p.b(B.Identifier{ .ref = p.module_ref }, logger.Loc.Empty) }, + Arg{ .binding = p.b(B.Identifier{ .ref = p.filename_ref }, logger.Loc.Empty) }, + Arg{ .binding = p.b(B.Identifier{ .ref = p.dirname_ref }, logger.Loc.Empty) }, + }; + + const cjsArguments = Expr{ + .data = .{ .e_this = .{} }, + .loc = logger.Loc.Empty, }; + var total_stmts_count: usize = 0; for (parts) |part| { total_stmts_count += part.stmts.len; } var stmts_to_copy = allocator.alloc(Stmt, total_stmts_count) catch unreachable; - var remaining_stmts = stmts_to_copy; - for (parts) |part| { - for (part.stmts, remaining_stmts[0..part.stmts.len]) |src, *dest| { - dest.* = src; + { + var remaining_stmts = stmts_to_copy; + for (parts) |part| { + for (part.stmts, remaining_stmts[0..part.stmts.len]) |src, *dest| { + dest.* = src; + } + remaining_stmts = remaining_stmts[part.stmts.len..]; } - remaining_stmts = remaining_stmts[part.stmts.len..]; } const wrapper = p.newExpr( @@ -21284,147 +21292,57 @@ fn NewParser_( .func = G.Fn{ .name = null, .open_parens_loc = logger.Loc.Empty, - .args = args, + .args = args[0..5], .body = .{ .loc = logger.Loc.Empty, .stmts = stmts_to_copy }, .flags = Flags.Function.init(.{ .is_export = false }), }, }, logger.Loc.Empty, ); - const cjsGlobal = p.newSymbol(.unbound, "$_BunCommonJSModule_$") catch unreachable; - var all_call_args = allocator.alloc(Expr, 8) catch unreachable; + const this_module = p.newExpr( E.Dot{ .name = "module", - .target = p.newExpr(E.Identifier{ .ref = cjsGlobal }, logger.Loc.Empty), + .target = cjsArguments, .name_loc = logger.Loc.Empty, }, logger.Loc.Empty, ); - var bind_args = all_call_args[0..1]; - bind_args[0] = this_module; - var bind_resolve_args = all_call_args[1..2]; - var call_args = all_call_args[2..]; - - const module_id = p.newExpr(E.Dot{ - .name = "id", - .target = this_module, - .name_loc = logger.Loc.Empty, - }, logger.Loc.Empty); - - bind_resolve_args[0] = module_id; - const get_require = p.newExpr( + const module_exports = p.newExpr( E.Dot{ - .name = "require", + .name = "exports", .target = this_module, .name_loc = logger.Loc.Empty, }, logger.Loc.Empty, ); - const create_binding = p.newExpr( - E.Call{ - .target = p.newExpr(E.Dot{ - .name = "bind", - .name_loc = logger.Loc.Empty, - .target = get_require, - }, logger.Loc.Empty), - .args = bun.BabyList(Expr).init(bind_args), - }, - logger.Loc.Empty, - ); - - const get_resolve = p.newExpr(E.Dot{ - .name = "resolve", - .name_loc = logger.Loc.Empty, - .target = get_require, - }, logger.Loc.Empty); - - const create_resolve_binding = p.newExpr( - E.Call{ - .target = p.newExpr(E.Dot{ - .name = "bind", - .name_loc = logger.Loc.Empty, - .target = get_resolve, - }, logger.Loc.Empty), - .args = bun.BabyList(Expr).init(bind_resolve_args), - }, - logger.Loc.Empty, - ); - - const require_path = p.newExpr( - E.Dot{ - .name = "path", - .target = get_require, - .name_loc = logger.Loc.Empty, - }, - logger.Loc.Empty, - ); - const assign_binding = p.newExpr( - E.Binary{ - .left = get_require, - .right = create_binding, - .op = .bin_assign, - }, - logger.Loc.Empty, - ); - - const assign_resolve_binding = p.newExpr( - E.Binary{ - .left = get_resolve, - .right = create_resolve_binding, - .op = .bin_assign, - }, - logger.Loc.Empty, - ); - - const assign_id = p.newExpr(E.Binary{ - .left = require_path, - .right = module_id, - .op = .bin_assign, - }, logger.Loc.Empty); - - var create_require = [4]Expr{ - assign_binding, - assign_id, - assign_resolve_binding, - get_require, - }; - - // - // (function(module, exports, require, __dirname, __filename) {}).call(this.exports, this.module, this.exports, this.module.require = this.module.require.bind(module), (this.module.require.id = this.module.id, this.module.require), __dirname, __filename) + var call_args = allocator.alloc(Expr, 6) catch unreachable; call_args[0..6].* = .{ + module_exports, // this.module.exports (this value inside fn) + module_exports, // this.module.exports (arg 1) p.newExpr( E.Dot{ - .name = "exports", - .target = this_module, + .name = "require", + .target = cjsArguments, .name_loc = logger.Loc.Empty, }, logger.Loc.Empty, ), - this_module, + this_module, // this.module p.newExpr( E.Dot{ - .name = "exports", - .target = this_module, + .name = "__filename", + .target = cjsArguments, .name_loc = logger.Loc.Empty, }, logger.Loc.Empty, ), - Expr.joinAllWithComma(&create_require, p.allocator), p.newExpr( E.Dot{ .name = "__dirname", - .target = p.newExpr(E.Identifier{ .ref = cjsGlobal }, logger.Loc.Empty), - .name_loc = logger.Loc.Empty, - }, - logger.Loc.Empty, - ), - p.newExpr( - E.Dot{ - .name = "__filename", - .target = p.newExpr(E.Identifier{ .ref = cjsGlobal }, logger.Loc.Empty), + .target = cjsArguments, .name_loc = logger.Loc.Empty, }, logger.Loc.Empty, @@ -21446,14 +21364,50 @@ fn NewParser_( logger.Loc.Empty, ); - var only_stmt = try p.allocator.alloc(Stmt, 1); - only_stmt[0] = p.s( + var top_level_stmts = p.allocator.alloc(Stmt, 1 + @as(usize, @intFromBool(p.has_import_meta))) catch unreachable; + parts[0].stmts = top_level_stmts; + + // var $Bun_import_meta = this.createImportMeta(this.filename); + if (p.has_import_meta) { + p.import_meta_ref = p.newSymbol(.other, "$Bun_import_meta") catch unreachable; + var decl = allocator.alloc(Decl, 1) catch unreachable; + decl[0] = Decl{ + .binding = Binding.alloc( + p.allocator, + B.Identifier{ + .ref = p.import_meta_ref, + }, + logger.Loc.Empty, + ), + .value = p.newExpr( + E.Call{ + .target = p.newExpr(E.Dot{ + .target = cjsArguments, + .name = "createImportMeta", + .name_loc = logger.Loc.Empty, + }, logger.Loc.Empty), + // reuse the `this.__filename` argument + .args = ExprNodeList.init(call_args[5..6]), + }, + logger.Loc.Empty, + ), + }; + + top_level_stmts[0] = p.s( + S.Local{ + .decls = G.Decl.List.init(decl), + .kind = .k_var, + }, + logger.Loc.Empty, + ); + top_level_stmts = top_level_stmts[1..]; + } + top_level_stmts[0] = p.s( S.SExpr{ .value = call, }, logger.Loc.Empty, ); - parts[0].stmts = only_stmt; parts.len = 1; }, @@ -21984,6 +21938,8 @@ fn NewParser_( // TODO: // .const_values = p.const_values, + + .import_meta_ref = p.import_meta_ref, }; } diff --git a/src/js_printer.zig b/src/js_printer.zig index 15f5218ae..8202eac80 100644 --- a/src/js_printer.zig +++ b/src/js_printer.zig @@ -482,6 +482,7 @@ pub const Options = struct { to_commonjs_ref: Ref = Ref.None, to_esm_ref: Ref = Ref.None, require_ref: ?Ref = null, + import_meta_ref: Ref = Ref.None, indent: usize = 0, externals: []u32 = &[_]u32{}, runtime_imports: runtime.Runtime.Imports = runtime.Runtime.Imports{}, @@ -2051,7 +2052,20 @@ fn NewPrinter( .e_import_meta => { p.printSpaceBeforeIdentifier(); p.addSourceMapping(expr.loc); - p.print("import.meta"); + if (!p.options.import_meta_ref.isValid()) { + // Most of the time, leave it in there + p.print("import.meta"); + } else { + // Note: The bundler will not hit this code path. The bundler will replace + // the ImportMeta AST node with a regular Identifier AST node. + // + // This is currently only used in Bun's runtime for CommonJS modules + // referencing import.meta + if (comptime Environment.allow_assert) + std.debug.assert(p.options.module_type == .cjs); + + p.printSymbol(p.options.import_meta_ref); + } }, .e_commonjs_export_identifier => |id| { p.printSpaceBeforeIdentifier(); diff --git a/src/string.zig b/src/string.zig index 7928ad97b..1305e5884 100644 --- a/src/string.zig +++ b/src/string.zig @@ -855,17 +855,17 @@ pub const SliceWithUnderlyingString = struct { underlying: String, pub fn toThreadSafe(this: *SliceWithUnderlyingString) void { - std.debug.assert(this.underlying.tag == .WTFStringImpl); - - var orig = this.underlying.value.WTFStringImpl; - this.underlying.toThreadSafe(); - if (this.underlying.value.WTFStringImpl != orig) { - orig.deref(); - - if (this.utf8.allocator.get()) |allocator| { - if (String.isWTFAllocator(allocator)) { - this.utf8.deinit(); - this.utf8 = this.underlying.toUTF8(bun.default_allocator); + if (this.underlying.tag == .WTFStringImpl) { + var orig = this.underlying.value.WTFStringImpl; + this.underlying.toThreadSafe(); + if (this.underlying.value.WTFStringImpl != orig) { + orig.deref(); + + if (this.utf8.allocator.get()) |allocator| { + if (String.isWTFAllocator(allocator)) { + this.utf8.deinit(); + this.utf8 = this.underlying.toUTF8(bun.default_allocator); + } } } } diff --git a/test/.gitignore b/test/.gitignore deleted file mode 100644 index 60f986255..000000000 --- a/test/.gitignore +++ /dev/null @@ -1 +0,0 @@ -bun.lockb diff --git a/test/README.md b/test/README.md deleted file mode 100644 index 03f9c97af..000000000 --- a/test/README.md +++ /dev/null @@ -1,83 +0,0 @@ -# Tests - -## Finding tests - -Tests are located in the [`test/`](test/) directory and are organized using the following structure: - -* `test/` - * `js/` - tests for JavaScript APIs. - * `cli/` - tests for commands, configs, and stdout. - * `bundler/` - tests for the transpiler/bundler. - * `regression/` - tests that reproduce a specific issue. - * `harness.ts` - utility functions that can be imported from any test. - -The tests in [`test/js/`](test/js/) directory are further categorized by the type of API. - -* `test/js/` - * `bun/` - tests for `Bun`-specific APIs. - * `node/` - tests for Node.js APIs. - * `web/` - tests for Web APIs, like `fetch()`. - * `first_party/` - tests for npm packages that are built-in, like `undici`. - * `third_party/` - tests for npm packages that are not built-in, but are popular, like `esbuild`. - -## Running tests - -To run a test, use Bun's built-in test command: `bun test`. - -```sh -bun test # Run all tests -bun test js/bun # Only run tests in a directory -bun test sqlite.test.ts # Only run a specific test -``` - -If you encounter lots of errors, try running `bun install`, then trying again. - -## Writing tests - -Tests are written in TypeScript (preferred) or JavaScript using Jest's `describe()`, `test()`, and `expect()` APIs. - -```ts -import { describe, test, expect } from "bun:test"; -import { gcTick } from "harness"; - -describe("TextEncoder", () => { - test("can encode a string", async () => { - const encoder = new TextEncoder(); - const actual = encoder.encode("bun"); - await gcTick(); - expect(actual).toBe(new Uint8Array([0x62, 0x75, 0x6E])); - }); -}); -``` - -If you are fixing a bug that was reported from a GitHub issue, remember to add a test in the `test/regression/` directory. - -```ts -// test/regression/issue/02005.test.ts - -import { it, expect } from "bun:test"; - -it("regex literal should work with non-latin1", () => { - const text = "这是一段要替换的文字"; - expect(text.replace(new RegExp("要替换"), "")).toBe("这是一段的文字"); - expect(text.replace(/要替换/, "")).toBe("这是一段的文字"); -}); -``` - -In the future, a bot will automatically close or re-open issues when a regression is detected or resolved. - -## Zig tests - -These tests live in various `.zig` files throughout Bun's codebase, leveraging Zig's builtin `test` keyword. - -Currently, they're not run automatically nor is there a simple way to run all of them. We will make this better soon. - -## TypeScript - -Test files should be written in TypeScript. The types in `packages/bun-types` should be updated to support all new APIs. Changes to the `.d.ts` files in `packages/bun-types` will be immediately reflected in test files; no build step is necessary. - -Writing a test will often require using invalid syntax, e.g. when checking for errors when an invalid input is passed to a function. TypeScript provides a number of escape hatches here. - -- `// @ts-expect-error` - This should be your first choice. It tells TypeScript that the next line *should* fail typechecking. -- `// @ts-ignore` - Ignore the next line entirely. -- `// @ts-nocheck` - Put this at the top of the file to disable typechecking on the entire file. Useful for autogenerated test files, or when ignoring/disabling type checks an a per-line basis is too onerous. diff --git a/test/bun.lockb b/test/bun.lockb index b68c3f550..13d6e0866 100755 Binary files a/test/bun.lockb and b/test/bun.lockb differ diff --git a/test/integration/next/default-pages-dir/.eslintrc.json b/test/integration/next/default-pages-dir/.eslintrc.json new file mode 100644 index 000000000..bffb357a7 --- /dev/null +++ b/test/integration/next/default-pages-dir/.eslintrc.json @@ -0,0 +1,3 @@ +{ + "extends": "next/core-web-vitals" +} diff --git a/test/integration/next/default-pages-dir/.gitignore b/test/integration/next/default-pages-dir/.gitignore new file mode 100644 index 000000000..412289e0b --- /dev/null +++ b/test/integration/next/default-pages-dir/.gitignore @@ -0,0 +1,38 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# local env files +.env*.local + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts + +# fixtures +src/Counter.tsx \ No newline at end of file diff --git a/test/integration/next/default-pages-dir/README.md b/test/integration/next/default-pages-dir/README.md new file mode 100644 index 000000000..a75ac5248 --- /dev/null +++ b/test/integration/next/default-pages-dir/README.md @@ -0,0 +1,40 @@ +This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). + +## Getting Started + +First, run the development server: + +```bash +npm run dev +# or +yarn dev +# or +pnpm dev +# or +bun dev +``` + +Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. + +You can start editing the page by modifying `pages/index.tsx`. The page auto-updates as you edit the file. + +[API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.ts`. + +The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages. + +This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font. + +## Learn More + +To learn more about Next.js, take a look at the following resources: + +- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. +- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. + +You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! + +## Deploy on Vercel + +The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. + +Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. diff --git a/test/integration/next/default-pages-dir/bun.lockb b/test/integration/next/default-pages-dir/bun.lockb new file mode 100755 index 000000000..4c97b0398 Binary files /dev/null and b/test/integration/next/default-pages-dir/bun.lockb differ diff --git a/test/integration/next/default-pages-dir/next.config.js b/test/integration/next/default-pages-dir/next.config.js new file mode 100644 index 000000000..5a35883f4 --- /dev/null +++ b/test/integration/next/default-pages-dir/next.config.js @@ -0,0 +1,10 @@ +/** @type {import('next').NextConfig} */ +const nextConfig = { + reactStrictMode: true, + generateBuildId: async () => { + // You can, for example, get the latest git commit hash here + return "bun!"; + }, +}; + +module.exports = nextConfig; diff --git a/test/integration/next/default-pages-dir/package.json b/test/integration/next/default-pages-dir/package.json new file mode 100644 index 000000000..b3f1d3616 --- /dev/null +++ b/test/integration/next/default-pages-dir/package.json @@ -0,0 +1,28 @@ +{ + "name": "default-create-template", + "version": "0.1.0", + "private": true, + "scripts": { + "dev": "next dev", + "build": "next build", + "start": "next start", + "lint": "next lint", + "postinstall": "cd node_modules/puppeteer && bun install.mjs" + }, + "dependencies": { + "@types/node": "20.7.0", + "@types/react": "18.2.22", + "@types/react-dom": "18.2.7", + "autoprefixer": "10.4.16", + "bun-types": "^1.0.3", + "eslint": "8.50.0", + "eslint-config-next": "13.5.3", + "next": "13.5.3", + "postcss": "8.4.30", + "puppeteer": "21.3.4", + "react": "18.2.0", + "react-dom": "18.2.0", + "tailwindcss": "3.3.3", + "typescript": "5.2.2" + } +} diff --git a/test/integration/next/default-pages-dir/postcss.config.js b/test/integration/next/default-pages-dir/postcss.config.js new file mode 100644 index 000000000..12a703d90 --- /dev/null +++ b/test/integration/next/default-pages-dir/postcss.config.js @@ -0,0 +1,6 @@ +module.exports = { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +}; diff --git a/test/integration/next/default-pages-dir/public/favicon.ico b/test/integration/next/default-pages-dir/public/favicon.ico new file mode 100644 index 000000000..718d6fea4 Binary files /dev/null and b/test/integration/next/default-pages-dir/public/favicon.ico differ diff --git a/test/integration/next/default-pages-dir/public/next.svg b/test/integration/next/default-pages-dir/public/next.svg new file mode 100644 index 000000000..5174b28c5 --- /dev/null +++ b/test/integration/next/default-pages-dir/public/next.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/test/integration/next/default-pages-dir/public/vercel.svg b/test/integration/next/default-pages-dir/public/vercel.svg new file mode 100644 index 000000000..d2f842227 --- /dev/null +++ b/test/integration/next/default-pages-dir/public/vercel.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/test/integration/next/default-pages-dir/src/Counter1.txt b/test/integration/next/default-pages-dir/src/Counter1.txt new file mode 100644 index 000000000..3973e0125 --- /dev/null +++ b/test/integration/next/default-pages-dir/src/Counter1.txt @@ -0,0 +1,27 @@ +import { useState } from "react"; + +export function Counter() { + console.log('counter a'); + + const [count, setCount] = useState(0); + + function increment() { + setCount(count + 1); + } + + function decrement() { + setCount(count - 1); + } + + return ( +
+

Count A: {count}

+ + +
+ ); +} diff --git a/test/integration/next/default-pages-dir/src/Counter2.txt b/test/integration/next/default-pages-dir/src/Counter2.txt new file mode 100644 index 000000000..67541a78b --- /dev/null +++ b/test/integration/next/default-pages-dir/src/Counter2.txt @@ -0,0 +1,27 @@ +import { useState } from "react"; + +export function Counter() { + console.log('counter b loaded'); + + const [count, setCount] = useState(0); + + function increment() { + setCount(count + 2); + } + + function decrement() { + setCount(count - 2); + } + + return ( +
+

Count B: {count}

+ + +
+ ); +} diff --git a/test/integration/next/default-pages-dir/src/pages/_app.tsx b/test/integration/next/default-pages-dir/src/pages/_app.tsx new file mode 100644 index 000000000..a7a790fba --- /dev/null +++ b/test/integration/next/default-pages-dir/src/pages/_app.tsx @@ -0,0 +1,6 @@ +import "@/styles/globals.css"; +import type { AppProps } from "next/app"; + +export default function App({ Component, pageProps }: AppProps) { + return ; +} diff --git a/test/integration/next/default-pages-dir/src/pages/_document.tsx b/test/integration/next/default-pages-dir/src/pages/_document.tsx new file mode 100644 index 000000000..b2fff8b42 --- /dev/null +++ b/test/integration/next/default-pages-dir/src/pages/_document.tsx @@ -0,0 +1,13 @@ +import { Html, Head, Main, NextScript } from "next/document"; + +export default function Document() { + return ( + + + +
+ + + + ); +} diff --git a/test/integration/next/default-pages-dir/src/pages/api/hello.ts b/test/integration/next/default-pages-dir/src/pages/api/hello.ts new file mode 100644 index 000000000..a8d68697c --- /dev/null +++ b/test/integration/next/default-pages-dir/src/pages/api/hello.ts @@ -0,0 +1,10 @@ +// Next.js API route support: https://nextjs.org/docs/api-routes/introduction +import type { NextApiRequest, NextApiResponse } from "next"; + +type Data = { + name: string; +}; + +export default function handler(req: NextApiRequest, res: NextApiResponse) { + res.status(200).json({ name: "John Doe" }); +} diff --git a/test/integration/next/default-pages-dir/src/pages/index.tsx b/test/integration/next/default-pages-dir/src/pages/index.tsx new file mode 100644 index 000000000..109f5e5e2 --- /dev/null +++ b/test/integration/next/default-pages-dir/src/pages/index.tsx @@ -0,0 +1,128 @@ +import Image from "next/image"; +import { Inter } from "next/font/google"; +import Head from "next/head"; +import { Counter } from "@/Counter"; + +const inter = Inter({ subsets: ["latin"] }); + +export default function Home({ bunVersion }: any) { + return ( +
+ + + Create Next App + + + + +
+ Next.js Logo +
+ + + + +
+ ); +} + +export async function getStaticProps() { + return { + props: { + bunVersion: + process.env.NODE_ENV === "production" + ? "[production needs a constant string]" + : process.versions.bun ?? "not in bun", + }, + }; +} diff --git a/test/integration/next/default-pages-dir/src/styles/globals.css b/test/integration/next/default-pages-dir/src/styles/globals.css new file mode 100644 index 000000000..fd81e8858 --- /dev/null +++ b/test/integration/next/default-pages-dir/src/styles/globals.css @@ -0,0 +1,27 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +:root { + --foreground-rgb: 0, 0, 0; + --background-start-rgb: 214, 219, 220; + --background-end-rgb: 255, 255, 255; +} + +@media (prefers-color-scheme: dark) { + :root { + --foreground-rgb: 255, 255, 255; + --background-start-rgb: 0, 0, 0; + --background-end-rgb: 0, 0, 0; + } +} + +body { + color: rgb(var(--foreground-rgb)); + background: linear-gradient( + to bottom, + transparent, + rgb(var(--background-end-rgb)) + ) + rgb(var(--background-start-rgb)); +} diff --git a/test/integration/next/default-pages-dir/tailwind.config.ts b/test/integration/next/default-pages-dir/tailwind.config.ts new file mode 100644 index 000000000..168556c68 --- /dev/null +++ b/test/integration/next/default-pages-dir/tailwind.config.ts @@ -0,0 +1,19 @@ +import type { Config } from "tailwindcss"; + +const config: Config = { + content: [ + // './src/pages/**/*.{js,ts,jsx,tsx,mdx}', + "./src/**/*.{js,ts,jsx,tsx,mdx}", + // './src/app/**/*.{js,ts,jsx,tsx,mdx}', + ], + theme: { + extend: { + backgroundImage: { + "gradient-radial": "radial-gradient(var(--tw-gradient-stops))", + "gradient-conic": "conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))", + }, + }, + }, + plugins: [], +}; +export default config; diff --git a/test/integration/next/default-pages-dir/test/dev-server-puppeteer.ts b/test/integration/next/default-pages-dir/test/dev-server-puppeteer.ts new file mode 100644 index 000000000..9bebeb614 --- /dev/null +++ b/test/integration/next/default-pages-dir/test/dev-server-puppeteer.ts @@ -0,0 +1,101 @@ +import { ConsoleMessage, Page, launch } from "puppeteer"; +import assert from "assert"; +import { copyFileSync } from "fs"; +import { join } from "path"; + +const root = join(import.meta.dir, "../"); + +copyFileSync(join(root, "src/Counter1.txt"), join(root, "src/Counter.tsx")); + +let url = "http://localhost:3000"; +if (process.argv.length > 2) { + url = process.argv[2]; +} + +const b = await launch({ + headless: "new", +}); + +const p = await b.newPage(); +// p.on("console", msg => console.log("[browser]", msg.text())); + +function waitForConsoleMessage(page: Page, regex: RegExp) { + const { resolve, promise } = Promise.withResolvers(); + function onMessage(msg: ConsoleMessage) { + const text = msg.text(); + if (regex.test(text)) { + page.off("console", onMessage); + resolve(); + } + } + p.on("console", onMessage); + return promise; +} + +await p.goto(url); +await waitForConsoleMessage(p, /counter a/); + +assert.strictEqual(await p.$eval("code.font-bold", x => x.innerText), Bun.version); + +let counter_root = (await p.$("#counter-fixture"))!; + +{ + const [has_class, style_json_string] = await counter_root.evaluate( + x => [(x as HTMLElement).classList.contains("rounded-bl-full"), JSON.stringify(getComputedStyle(x))] as const, + ); + assert.strictEqual(has_class, true); + const decoded_style = JSON.parse(style_json_string); + assert.strictEqual(decoded_style.borderTopLeftRadius, "0px"); + assert.strictEqual(decoded_style.borderTopRightRadius, "0px"); + assert.strictEqual(decoded_style.borderBottomRightRadius, "0px"); + assert.strictEqual(decoded_style.borderBottomLeftRadius, "9999px"); +} + +const getCount = () => counter_root.$eval("p", x => x.innerText); + +assert.strictEqual(await getCount(), "Count A: 0"); +await counter_root.$eval(".inc", x => (x as HTMLElement).click()); +assert.strictEqual(await getCount(), "Count A: 1"); +await counter_root.$eval(".inc", x => (x as HTMLElement).click()); +assert.strictEqual(await getCount(), "Count A: 2"); +await counter_root.$eval(".dec", x => (x as HTMLElement).click()); +assert.strictEqual(await getCount(), "Count A: 1"); + +p.reload({}); +await waitForConsoleMessage(p, /counter a/); + +assert.strictEqual(await p.$eval("code.font-bold", x => x.innerText), Bun.version); + +counter_root = (await p.$("#counter-fixture"))!; + +assert.strictEqual(await getCount(), "Count A: 0"); +await counter_root.$eval(".inc", x => (x as HTMLElement).click()); +assert.strictEqual(await getCount(), "Count A: 1"); +await counter_root.$eval(".inc", x => (x as HTMLElement).click()); +assert.strictEqual(await getCount(), "Count A: 2"); +await counter_root.$eval(".dec", x => (x as HTMLElement).click()); +assert.strictEqual(await getCount(), "Count A: 1"); + +copyFileSync(join(root, "src/Counter2.txt"), join(root, "src/Counter.tsx")); +await waitForConsoleMessage(p, /counter b loaded/); +assert.strictEqual(await getCount(), "Count B: 1"); +await counter_root.$eval(".inc", x => (x as HTMLElement).click()); +assert.strictEqual(await getCount(), "Count B: 3"); +await counter_root.$eval(".inc", x => (x as HTMLElement).click()); +assert.strictEqual(await getCount(), "Count B: 5"); +await counter_root.$eval(".dec", x => (x as HTMLElement).click()); +assert.strictEqual(await getCount(), "Count B: 3"); + +{ + const [has_class, style_json_string] = await counter_root.evaluate( + x => [(x as HTMLElement).classList.contains("rounded-br-full"), JSON.stringify(getComputedStyle(x))] as const, + ); + assert.strictEqual(has_class, true); + const decoded_style = JSON.parse(style_json_string); + assert.strictEqual(decoded_style.borderTopLeftRadius, "0px"); + assert.strictEqual(decoded_style.borderTopRightRadius, "0px"); + assert.strictEqual(decoded_style.borderBottomRightRadius, "9999px"); + assert.strictEqual(decoded_style.borderBottomLeftRadius, "0px"); +} + +await b.close(); diff --git a/test/integration/next/default-pages-dir/test/dev-server.test.ts b/test/integration/next/default-pages-dir/test/dev-server.test.ts new file mode 100644 index 000000000..8723a91c2 --- /dev/null +++ b/test/integration/next/default-pages-dir/test/dev-server.test.ts @@ -0,0 +1,79 @@ +import { afterAll, beforeAll, describe, expect, test } from "bun:test"; +import { bunEnv, bunExe } from "../../../../harness"; +import { Subprocess } from "bun"; +import { copyFileSync, rmSync } from "fs"; +import { join } from "path"; + +const root = join(import.meta.dir, "../"); +let dev_server: undefined | Subprocess<"ignore", "pipe", "inherit">; +let baseUrl: string; + +test("the dev server can start", async () => { + rmSync(join(root, ".next"), { recursive: true, force: true }); + copyFileSync(join(root, "src/Counter1.txt"), join(root, "src/Counter.tsx")); + + const install = Bun.spawnSync([bunExe(), "i"], { cwd: root, env: bunEnv }); + if (install.exitCode !== 0) { + throw new Error("Failed to install dependencies"); + } + dev_server = Bun.spawn([bunExe(), "--bun", "node_modules/.bin/next", "dev"], { + cwd: root, + env: bunEnv, + stdio: ["ignore", "pipe", "inherit"], + }); + dev_server.exited.then(() => { + dev_server = undefined; + }); + for await (const chunk of dev_server.stdout) { + console.error({ chunk }); + const str = new TextDecoder().decode(chunk); + let match = str.match(/http:\/\/localhost:\d+/); + if (match) { + baseUrl = match[0]; + } + if (str.toLowerCase().includes("ready")) { + return; + } + } + console.error("Failed to start dev server :/"); + dev_server.kill(); + dev_server = undefined; +}, 30000); + +test("ssr works for 100 requests", async () => { + expect(dev_server).not.toBeUndefined(); + expect(baseUrl).not.toBeUndefined(); + + const promises = []; + for (let i = 0; i < 100; i++) { + promises.push( + (async () => { + const x = await fetch(`${baseUrl}/`); + expect(x.status).toBe(200); + const text = await x.text(); + expect(text).toContain(`>${Bun.version}`); + })(), + ); + } + + const x = await Promise.allSettled(promises); + for (const y of x) { + expect(y.status).toBe("fulfilled"); + } +}, 10000); + +test("hot reloading works on the client (+ tailwind hmr)", async () => { + expect(dev_server).not.toBeUndefined(); + expect(baseUrl).not.toBeUndefined(); + + const result = Bun.spawnSync([bunExe(), "test/dev-server-puppeteer.ts", baseUrl], { + cwd: root, + env: bunEnv, + stdio: ["ignore", "inherit", "inherit"], + }); + expect(result.exitCode).toBe(0); +}, 30000); + +afterAll(() => { + Bun.spawnSync(["pkill", "-P", dev_server!.pid.toString()]); +}); diff --git a/test/integration/next/default-pages-dir/test/next-build.test.ts b/test/integration/next/default-pages-dir/test/next-build.test.ts new file mode 100644 index 000000000..0a00c158e --- /dev/null +++ b/test/integration/next/default-pages-dir/test/next-build.test.ts @@ -0,0 +1,141 @@ +import { afterAll, beforeAll, describe, expect, test } from "bun:test"; +import { bunEnv, bunExe } from "../../../../harness"; +import { copyFileSync, cpSync, mkdtempSync, readFileSync, readdirSync, rmSync, symlinkSync, writeFileSync } from "fs"; +import { tmpdir } from "os"; +import { join } from "path"; +import { cp } from "fs/promises"; + +const root = join(import.meta.dir, "../"); + +let build_passed = false; + +async function tempDirToBuildIn() { + const dir = mkdtempSync(join(tmpdir(), "bun-next-build-")); + const copy = [ + ".eslintrc.json", + "bun.lockb", + "next.config.js", + "next.config.js", + "package.json", + "postcss.config.js", + "public", + "src", + "tailwind.config.ts", + ]; + await Promise.all(copy.map(x => cp(join(root, x), join(dir, x), { recursive: true }))); + cpSync(join(root, "src/Counter1.txt"), join(dir, "src/Counter.tsx")); + cpSync(join(root, "tsconfig_for_build.json"), join(dir, "tsconfig.json")); + symlinkSync(join(root, "node_modules"), join(dir, "node_modules")); + return dir; +} + +function readdirRecursive(dir: string) { + let results: string[] = []; + + readdirSync(dir, { withFileTypes: true }).forEach(file => { + if (file.isDirectory()) { + results = results.concat(readdirRecursive(join(dir, file.name)).map(x => join(file.name, x))); + } else { + results.push(file.name); + } + }); + + return results; +} + +function hashAllFiles(dir: string) { + const files = readdirRecursive(dir).sort(); + const hashes: Record = {}; + for (const file of files) { + const hash = new Bun.CryptoHasher("sha256"); + hash.update(readFileSync(join(dir, file))); + hashes[file] = hash.digest("hex"); + } + return hashes; +} + +test("next build works", async () => { + copyFileSync(join(root, "src/Counter1.txt"), join(root, "src/Counter.tsx")); + + const install = Bun.spawnSync([bunExe(), "i"], { cwd: root, env: bunEnv }); + if (install.exitCode !== 0) { + throw new Error("Failed to install dependencies"); + } + + const bunDir = await tempDirToBuildIn(); + const nodeDir = await tempDirToBuildIn(); + + const bunBuild = await Bun.spawn([bunExe(), "--bun", "node_modules/.bin/next", "build"], { + cwd: bunDir, + // env: bunEnv, + stdio: ["ignore", "pipe", "inherit"], + env: { + ...bunEnv, + NODE_ENV: "production", + }, + }); + const nodeBuild = await Bun.spawn(["node", "node_modules/.bin/next", "build"], { + cwd: nodeDir, + env: bunEnv, + stdio: ["ignore", "pipe", "inherit"], + }); + await Promise.all([bunBuild.exited, nodeBuild.exited]); + expect(nodeBuild.exitCode).toBe(0); + expect(bunBuild.exitCode).toBe(0); + + const bunCliOutput = await Bun.readableStreamToText(bunBuild.stdout); + const nodeCliOutput = await Bun.readableStreamToText(nodeBuild.stdout); + + expect(bunCliOutput).toBe(nodeCliOutput); + + const bunBuildDir = join(bunDir, ".next"); + const nodeBuildDir = join(nodeDir, ".next"); + + const toRemove = [ + // these have timestamps and absolute paths in them + "trace", + "cache", + "required-server-files.json", + // these have "signing keys", not sure what they are tbh + "prerender-manifest.json", + "prerender-manifest.js", + // these are similar but i feel like there might be something we can fix to make them the same + "next-minimal-server.js.nft.json", + "next-server.js.nft.json", + // not sorted lol + "server/pages-manifest.json", + ]; + for (const key of toRemove) { + rmSync(join(bunBuildDir, key), { recursive: true }); + rmSync(join(nodeBuildDir, key), { recursive: true }); + } + + const bunBuildHash = hashAllFiles(bunBuildDir); + const nodeBuildHash = hashAllFiles(nodeBuildDir); + + try { + expect(bunBuildHash).toEqual(nodeBuildHash); + } catch (error) { + console.log("bunBuildDir", bunBuildDir); + console.log("nodeBuildDir", nodeBuildDir); + + // print diffs for every file if not the same + for (const key in bunBuildHash) { + if (bunBuildHash[key] !== nodeBuildHash[key]) { + console.log(key + ":"); + try { + expect(readFileSync(join(bunBuildDir, key)).toString()).toBe( + readFileSync(join(nodeBuildDir, key)).toString(), + ); + } catch (error) { + console.error(error); + } + } + } + throw error; + } + + build_passed = true; +}, 300000); + +const version_string = "[production needs a constant string]"; diff --git a/test/integration/next/default-pages-dir/tsconfig.json b/test/integration/next/default-pages-dir/tsconfig.json new file mode 100644 index 000000000..b8629571f --- /dev/null +++ b/test/integration/next/default-pages-dir/tsconfig.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "target": "ESNext", + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": true, + "skipLibCheck": true, + "strict": true, + "noEmit": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "bundler", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "preserve", + "incremental": true, + "paths": { + "@/*": ["./src/*"] + } + }, + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "../../../../packages/bun-types/dist/types.d.ts"], + "exclude": ["node_modules"] +} diff --git a/test/integration/next/default-pages-dir/tsconfig_for_build.json b/test/integration/next/default-pages-dir/tsconfig_for_build.json new file mode 100644 index 000000000..476ee3ebc --- /dev/null +++ b/test/integration/next/default-pages-dir/tsconfig_for_build.json @@ -0,0 +1,23 @@ +{ + "compilerOptions": { + "target": "ESNext", + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": true, + "skipLibCheck": true, + "strict": true, + "noEmit": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "bundler", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "preserve", + "incremental": true, + "paths": { + "@/*": ["./src/*"] + }, + "types": ["bun-types"] + }, + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], + "exclude": ["node_modules"] +} diff --git a/test/js/node/async_hooks/async_hooks.node.test.ts b/test/js/node/async_hooks/async_hooks.node.test.ts index 3d6183948..5fc56a39b 100644 --- a/test/js/node/async_hooks/async_hooks.node.test.ts +++ b/test/js/node/async_hooks/async_hooks.node.test.ts @@ -1,13 +1,13 @@ -import { AsyncLocalStorage } from "async_hooks"; +import { AsyncLocalStorage, AsyncResource } from "async_hooks"; import assert from "assert"; test("node async_hooks.AsyncLocalStorage enable disable", async done => { - const asyncLocalStorage = new AsyncLocalStorage(); + const asyncLocalStorage = new AsyncLocalStorage>(); asyncLocalStorage.run(new Map(), () => { - asyncLocalStorage.getStore().set("foo", "bar"); + asyncLocalStorage.getStore()!.set("foo", "bar"); process.nextTick(() => { - assert.strictEqual(asyncLocalStorage.getStore().get("foo"), "bar"); + assert.strictEqual(asyncLocalStorage.getStore()!.get("foo"), "bar"); process.nextTick(() => { assert.strictEqual(asyncLocalStorage.getStore(), undefined); }); @@ -24,7 +24,7 @@ test("node async_hooks.AsyncLocalStorage enable disable", async done => { process.nextTick(() => { assert.strictEqual(asyncLocalStorage.getStore(), undefined); asyncLocalStorage.run(new Map().set("bar", "foo"), () => { - assert.strictEqual(asyncLocalStorage.getStore().get("bar"), "foo"); + assert.strictEqual(asyncLocalStorage.getStore()!.get("bar"), "foo"); done(); }); @@ -32,3 +32,21 @@ test("node async_hooks.AsyncLocalStorage enable disable", async done => { }); }); }); + +test("AsyncResource.prototype.bind", () => { + const localStorage = new AsyncLocalStorage(); + let ar!: AsyncResource; + localStorage.run(true, () => { + ar = new AsyncResource("test"); + }); + expect(ar.bind(() => localStorage.getStore())()).toBe(true); +}); + +test("AsyncResource.bind", () => { + const localStorage = new AsyncLocalStorage(); + let fn!: () => true | undefined; + localStorage.run(true, () => { + fn = AsyncResource.bind(() => localStorage.getStore()); + }); + expect(fn()).toBe(true); +}); diff --git a/test/js/node/module/modulePrototypeOverwrite-fixture.cjs b/test/js/node/module/modulePrototypeOverwrite-fixture.cjs new file mode 100644 index 000000000..eecab81c1 --- /dev/null +++ b/test/js/node/module/modulePrototypeOverwrite-fixture.cjs @@ -0,0 +1 @@ +module.exports = require("hook"); diff --git a/test/js/node/module/modulePrototypeOverwrite.cjs b/test/js/node/module/modulePrototypeOverwrite.cjs new file mode 100644 index 000000000..4e84026a6 --- /dev/null +++ b/test/js/node/module/modulePrototypeOverwrite.cjs @@ -0,0 +1,17 @@ +// This behavior is required for Next.js to work +const eql = require("assert").deepStrictEqual; +const Module = require("module"); + +const old = Module.prototype.require; +Module.prototype.require = function (str) { + if (str === "hook") return "winner"; + return { + wrap: old.call(this, str), + }; +}; + +// this context has the new require +const result = require("./modulePrototypeOverwrite-fixture.cjs"); +eql(result, { wrap: "winner" }); + +console.log("--pass--"); diff --git a/test/js/node/module/node-module-module.test.js b/test/js/node/module/node-module-module.test.js index 26fbb6fab..5ac48d426 100644 --- a/test/js/node/module/node-module-module.test.js +++ b/test/js/node/module/node-module-module.test.js @@ -71,6 +71,17 @@ test("Overwriting _resolveFilename", () => { expect(exitCode).toBe(0); }); +test("Overwriting Module.prototype.require", () => { + const { stdout, exitCode } = Bun.spawnSync({ + cmd: [bunExe(), "run", path.join(import.meta.dir, "modulePrototypeOverwrite.cjs")], + env: bunEnv, + stderr: "inherit", + }); + + expect(stdout.toString().trim().endsWith("--pass--")).toBe(true); + expect(exitCode).toBe(0); +}); + test("Module.prototype._compile", () => { const module = new Module("module id goes here"); const starting_exports = module.exports; diff --git a/test/js/node/process/process-stdio.test.ts b/test/js/node/process/process-stdio.test.ts index 463ab5fda..5349587af 100644 --- a/test/js/node/process/process-stdio.test.ts +++ b/test/js/node/process/process-stdio.test.ts @@ -5,7 +5,7 @@ import { isatty } from "tty"; test("process.stdin", () => { expect(process.stdin).toBeDefined(); - expect(process.stdout.isTTY).toBe(isatty(0)); + expect(process.stdin.isTTY).toBe(isatty(0) ? true : undefined); expect(process.stdin.on("close", function () {})).toBe(process.stdin); expect(process.stdin.once("end", function () {})).toBe(process.stdin); }); diff --git a/test/js/node/stream/node-stream.test.js b/test/js/node/stream/node-stream.test.js index bc6a4fcfb..ddbd2bc7a 100644 --- a/test/js/node/stream/node-stream.test.js +++ b/test/js/node/stream/node-stream.test.js @@ -197,6 +197,7 @@ describe("PassThrough", () => { const ttyStreamsTest = ` import tty from "tty"; +import fs from "fs"; import { dlopen } from "bun:ffi"; @@ -278,10 +279,11 @@ describe("TTY", () => { close(child_fd); }); it("process.stdio tty", () => { - expect(process.stdin instanceof tty.ReadStream).toBe(true); + // this isnt run in a tty, so stdin will not appear to be a tty + expect(process.stdin instanceof fs.ReadStream).toBe(true); expect(process.stdout instanceof tty.WriteStream).toBe(true); expect(process.stderr instanceof tty.WriteStream).toBe(true); - expect(process.stdin.isTTY).toBeDefined(); + expect(process.stdin.isTTY).toBeUndefined(); expect(process.stdout.isTTY).toBeDefined(); expect(process.stderr.isTTY).toBeDefined(); }); @@ -311,7 +313,11 @@ it("TTY streams", () => { }); expect(stdout.toString()).toBe(""); - expect(stderr.toString()).toContain("0 fail"); + try { + expect(stderr.toString()).toContain("0 fail"); + } catch (error) { + throw new Error(stderr.toString()); + } expect(exitCode).toBe(0); }); diff --git a/test/js/third_party/got/bun.lockb b/test/js/third_party/got/bun.lockb new file mode 100755 index 000000000..7dbe60317 Binary files /dev/null and b/test/js/third_party/got/bun.lockb differ diff --git a/test/js/third_party/prisma/bun.lockb b/test/js/third_party/prisma/bun.lockb new file mode 100755 index 000000000..65d0238e5 Binary files /dev/null and b/test/js/third_party/prisma/bun.lockb differ diff --git a/test/js/third_party/yargs/bun.lockb b/test/js/third_party/yargs/bun.lockb new file mode 100755 index 000000000..6b527d00f Binary files /dev/null and b/test/js/third_party/yargs/bun.lockb differ -- cgit v1.2.3 From 05781dd91e9c17d6d963e692aee0f0325da9d42e Mon Sep 17 00:00:00 2001 From: Dylan Conway <35280289+dylan-conway@users.noreply.github.com> Date: Tue, 10 Oct 2023 20:05:58 -0700 Subject: make peer dependencies install by default (#6396) * peer dependencies * default true * add test * cleanup * some tests * skip peer deps if they are non optional * remove debug print, fix build * iterate peer dependencies --- docs/runtime/bunfig.md | 2 +- src/bun.js/module_loader.zig | 2 + src/install/dependency.zig | 2 +- src/install/install.zig | 136 +++++++++++++++++++--- test/cli/install/boba-0.0.2.tgz | Bin 0 -> 221 bytes test/cli/install/bun-install.test.ts | 219 ++++++++++++++++++++++++++++++++++- test/cli/install/peer-0.0.1.tgz | Bin 0 -> 194 bytes test/cli/install/peer-0.0.2.tgz | Bin 0 -> 194 bytes 8 files changed, 344 insertions(+), 17 deletions(-) create mode 100644 test/cli/install/boba-0.0.2.tgz create mode 100644 test/cli/install/peer-0.0.1.tgz create mode 100644 test/cli/install/peer-0.0.2.tgz (limited to 'src/bun.js/module_loader.zig') diff --git a/docs/runtime/bunfig.md b/docs/runtime/bunfig.md index 83f66b1b1..6950d8233 100644 --- a/docs/runtime/bunfig.md +++ b/docs/runtime/bunfig.md @@ -209,7 +209,7 @@ dev = true ### `install.peer` -Whether to install peer dependencies. Default `false`. +Whether to install peer dependencies. Default `true`. ```toml [install] diff --git a/src/bun.js/module_loader.zig b/src/bun.js/module_loader.zig index 89dca35b0..9a46d403b 100644 --- a/src/bun.js/module_loader.zig +++ b/src/bun.js/module_loader.zig @@ -692,6 +692,7 @@ pub const ModuleLoader = struct { .onPackageDownloadError = onPackageDownloadError, .progress_bar = true, }, + true, PackageManager.Options.LogLevel.default, ) catch unreachable; } else { @@ -704,6 +705,7 @@ pub const ModuleLoader = struct { .onPackageManifestError = onPackageManifestError, .onPackageDownloadError = onPackageDownloadError, }, + true, PackageManager.Options.LogLevel.default_no_progress, ) catch unreachable; } diff --git a/src/install/dependency.zig b/src/install/dependency.zig index cb73c04e1..b621dfae9 100644 --- a/src/install/dependency.zig +++ b/src/install/dependency.zig @@ -52,7 +52,7 @@ version: Dependency.Version = .{}, behavior: Behavior = .uninitialized, /// Sorting order for dependencies is: -/// 1. [`dependencies`, `devDependencies`, `optionalDependencies`, `peerDependencies`] +/// 1. [ `peerDependencies`, `optionalDependencies`, `devDependencies`, `dependencies` ] /// 2. name ASC /// "name" must be ASC so that later, when we rebuild the lockfile /// we insert it back in reverse order without an extra sorting pass diff --git a/src/install/install.zig b/src/install/install.zig index abac43493..218dace5c 100644 --- a/src/install/install.zig +++ b/src/install/install.zig @@ -1702,6 +1702,8 @@ pub const PackageManager = struct { onWake: WakeHandler = .{}, ci_mode: bun.LazyBool(computeIsContinuousIntegration, @This(), "ci_mode") = .{}, + peer_dependencies: std.ArrayListUnmanaged(DependencyID) = .{}, + const PreallocatedNetworkTasks = std.BoundedArray(NetworkTask, 1024); const NetworkTaskQueue = std.HashMapUnmanaged(u64, void, IdentityContext(u64), 80); pub var verbose_install = false; @@ -1818,6 +1820,7 @@ pub const PackageManager = struct { dep_id, &this.lockfile.buffers.dependencies.items[dep_id], invalid_package_id, + false, assignRootResolution, failRootResolution, ) catch |err| { @@ -1842,6 +1845,7 @@ pub const PackageManager = struct { .onPackageManifestError = {}, .onPackageDownloadError = {}, }, + false, log_level, ) catch |err| { return .{ .failure = err }; @@ -2486,13 +2490,14 @@ pub const PackageManager = struct { behavior: Behavior, manifest: *const Npm.PackageManifest, find_result: Npm.PackageManifest.FindResult, + install_peer: bool, comptime successFn: SuccessFn, ) !?ResolvedPackageResult { // Was this package already allocated? Let's reuse the existing one. if (this.lockfile.getPackageID( name_hash, - if (behavior.isPeer()) version else null, + if (behavior.isPeer() and !install_peer) version else null, &.{ .tag = .npm, .value = .{ @@ -2508,7 +2513,7 @@ pub const PackageManager = struct { .package = this.lockfile.packages.get(id), .is_first_time = false, }; - } else if (behavior.isPeer()) { + } else if (behavior.isPeer() and !install_peer) { return null; } @@ -2648,6 +2653,7 @@ pub const PackageManager = struct { behavior: Behavior, dependency_id: DependencyID, resolution: PackageID, + install_peer: bool, comptime successFn: SuccessFn, ) !?ResolvedPackageResult { name.assertDefined(); @@ -2699,6 +2705,7 @@ pub const PackageManager = struct { behavior, manifest, find_result, + install_peer, successFn, ); }, @@ -2972,11 +2979,13 @@ pub const PackageManager = struct { /// This must be a *const to prevent UB dependency: *const Dependency, resolution: PackageID, + install_peer: bool, ) !void { return this.enqueueDependencyWithMainAndSuccessFn( id, dependency, resolution, + install_peer, assignResolution, null, ); @@ -2992,6 +3001,7 @@ pub const PackageManager = struct { /// This must be a *const to prevent UB dependency: *const Dependency, resolution: PackageID, + install_peer: bool, comptime successFn: SuccessFn, comptime failFn: ?FailFn, ) !void { @@ -3014,6 +3024,7 @@ pub const PackageManager = struct { dependency.behavior, id, resolution, + install_peer, successFn, ); @@ -3140,7 +3151,7 @@ pub const PackageManager = struct { }, ); - if (!dependency.behavior.isPeer()) { + if (!dependency.behavior.isPeer() or install_peer) { var network_entry = try this.network_dedupe_map.getOrPutContext(this.allocator, task_id, .{}); if (!network_entry.found_existing) { if (this.options.enable.manifest_cache) { @@ -3164,6 +3175,7 @@ pub const PackageManager = struct { dependency.behavior, &loaded_manifest.?, find_result, + install_peer, successFn, ) catch null) |new_resolve_result| { resolve_result_ = new_resolve_result; @@ -3201,6 +3213,10 @@ pub const PackageManager = struct { ); this.enqueueNetworkTask(network_task); } + } else { + if (this.options.do.install_peer_dependencies) { + try this.peer_dependencies.append(this.allocator, id); + } } var manifest_entry_parse = try this.task_queue.getOrPutContext(this.allocator, task_id, .{}); @@ -3350,6 +3366,7 @@ pub const PackageManager = struct { dependency.behavior, id, resolution, + install_peer, successFn, ) catch |err| brk: { if (err == error.MissingPackageJSON) { @@ -3554,6 +3571,7 @@ pub const PackageManager = struct { i, &dependency, lockfile.buffers.resolutions.items[i], + false, ) catch {}; } } @@ -3593,8 +3611,36 @@ pub const PackageManager = struct { const lockfile = this.lockfile; // Step 1. Go through main dependencies - var i = dependencies_list.off; + var begin = dependencies_list.off; const end = dependencies_list.off +| dependencies_list.len; + + // if dependency is peer and is going to be installed + // through "dependencies", skip it + if (end - begin > 1 and lockfile.buffers.dependencies.items[0].behavior.isPeer()) { + var peer_i: usize = 0; + var peer = &lockfile.buffers.dependencies.items[peer_i]; + while (peer.behavior.isPeer()) { + var dep_i: usize = end - 1; + var dep = lockfile.buffers.dependencies.items[dep_i]; + while (!dep.behavior.isPeer()) { + if (!dep.behavior.isDev()) { + if (peer.name_hash == dep.name_hash) { + peer.* = lockfile.buffers.dependencies.items[begin]; + begin += 1; + break; + } + } + dep_i -= 1; + dep = lockfile.buffers.dependencies.items[dep_i]; + } + peer_i += 1; + if (peer_i == end) break; + peer = &lockfile.buffers.dependencies.items[peer_i]; + } + } + + var i = begin; + // we have to be very careful with pointers here while (i < end) : (i += 1) { const dependency = lockfile.buffers.dependencies.items[i]; @@ -3603,6 +3649,7 @@ pub const PackageManager = struct { i, &dependency, resolution, + false, ) catch |err| { const note = .{ .fmt = "error occured while resolving {s}", @@ -3633,7 +3680,12 @@ pub const PackageManager = struct { _ = this.scheduleTasks(); } - fn processDependencyListItem(this: *PackageManager, item: TaskCallbackContext, any_root: ?*bool) !void { + fn processDependencyListItem( + this: *PackageManager, + item: TaskCallbackContext, + any_root: ?*bool, + install_peer: bool, + ) !void { switch (item) { .dependency => |dependency_id| { const dependency = this.lockfile.buffers.dependencies.items[dependency_id]; @@ -3643,6 +3695,7 @@ pub const PackageManager = struct { dependency_id, &dependency, resolution, + install_peer, ); }, .root_dependency => |dependency_id| { @@ -3653,6 +3706,7 @@ pub const PackageManager = struct { dependency_id, &dependency, resolution, + install_peer, assignRootResolution, failRootResolution, ); @@ -3667,18 +3721,37 @@ pub const PackageManager = struct { } } + fn processPeerDependencyList( + this: *PackageManager, + ) !void { + if (this.peer_dependencies.items.len > 0) { + for (this.peer_dependencies.items) |peer_dependency_id| { + try this.processDependencyListItem(.{ .dependency = peer_dependency_id }, null, true); + const dependency = this.lockfile.buffers.dependencies.items[peer_dependency_id]; + const resolution = this.lockfile.buffers.resolutions.items[peer_dependency_id]; + try this.enqueueDependencyWithMain( + peer_dependency_id, + &dependency, + resolution, + true, + ); + } + } + } + fn processDependencyList( this: *PackageManager, dep_list: TaskCallbackList, comptime Context: type, ctx: Context, comptime callbacks: anytype, + install_peer: bool, ) !void { if (dep_list.items.len > 0) { var dependency_list = dep_list; var any_root = false; for (dependency_list.items) |item| { - try this.processDependencyListItem(item, &any_root); + try this.processDependencyListItem(item, &any_root, install_peer); } if (comptime @TypeOf(callbacks) != void and @TypeOf(callbacks.onResolve) != void) { @@ -3877,6 +3950,7 @@ pub const PackageManager = struct { comptime ExtractCompletionContext: type, extract_ctx: ExtractCompletionContext, comptime callbacks: anytype, + install_peer: bool, comptime log_level: Options.LogLevel, ) anyerror!void { var has_updated_this_run = false; @@ -4072,7 +4146,7 @@ pub const PackageManager = struct { var dependency_list = dependency_list_entry.value_ptr.*; dependency_list_entry.value_ptr.* = .{}; - try manager.processDependencyList(dependency_list, ExtractCompletionContext, extract_ctx, callbacks); + try manager.processDependencyList(dependency_list, ExtractCompletionContext, extract_ctx, callbacks, install_peer); continue; } @@ -4249,7 +4323,7 @@ pub const PackageManager = struct { var dependency_list = dependency_list_entry.value_ptr.*; dependency_list_entry.value_ptr.* = .{}; - try manager.processDependencyList(dependency_list, ExtractCompletionContext, extract_ctx, callbacks); + try manager.processDependencyList(dependency_list, ExtractCompletionContext, extract_ctx, callbacks, install_peer); if (comptime log_level.showProgress()) { if (!has_updated_this_run) { @@ -4335,7 +4409,7 @@ pub const PackageManager = struct { }, else => unreachable, } - try manager.processDependencyListItem(dep, &any_root); + try manager.processDependencyListItem(dep, &any_root, install_peer); }, else => { // if it's a node_module folder to install, handle that after we process all the dependencies within the onExtract callback. @@ -4350,7 +4424,7 @@ pub const PackageManager = struct { var dependency_list = dependency_list_entry.value_ptr.*; dependency_list_entry.value_ptr.* = .{}; - try manager.processDependencyList(dependency_list, void, {}, {}); + try manager.processDependencyList(dependency_list, void, {}, {}, install_peer); } manager.setPreinstallState(package_id, manager.lockfile, .done); @@ -4401,7 +4475,7 @@ pub const PackageManager = struct { var dependency_list = dependency_list_entry.value_ptr.*; dependency_list_entry.value_ptr.* = .{}; - try manager.processDependencyList(dependency_list, ExtractCompletionContext, extract_ctx, callbacks); + try manager.processDependencyList(dependency_list, ExtractCompletionContext, extract_ctx, callbacks, install_peer); if (comptime log_level.showProgress()) { if (!has_updated_this_run) { @@ -4461,7 +4535,7 @@ pub const PackageManager = struct { var repo = &manager.lockfile.buffers.dependencies.items[id].version.value.git; repo.resolved = pkg.resolution.value.git.resolved; repo.package_name = pkg.name; - try manager.processDependencyListItem(dep, &any_root); + try manager.processDependencyListItem(dep, &any_root, install_peer); }, else => { // if it's a node_module folder to install, handle that after we process all the dependencies within the onExtract callback. @@ -4725,6 +4799,7 @@ pub const PackageManager = struct { } if (bun_install.save_peer) |save| { + this.do.install_peer_dependencies = save; this.remote_package_features.peer_dependencies = save; } @@ -4995,6 +5070,7 @@ pub const PackageManager = struct { print_meta_hash_string: bool = false, verify_integrity: bool = true, summary: bool = true, + install_peer_dependencies: bool = true, }; pub const Enable = struct { @@ -7460,6 +7536,7 @@ pub const PackageManager = struct { .onPackageManifestError = {}, .onPackageDownloadError = {}, }, + true, log_level, ); if (!installer.options.do.install_packages) return error.InstallFailed; @@ -7479,6 +7556,7 @@ pub const PackageManager = struct { .onPackageManifestError = {}, .onPackageDownloadError = {}, }, + true, log_level, ); if (!installer.options.do.install_packages) return error.InstallFailed; @@ -7494,6 +7572,7 @@ pub const PackageManager = struct { .onPackageManifestError = {}, .onPackageDownloadError = {}, }, + true, log_level, ); @@ -7808,6 +7887,7 @@ pub const PackageManager = struct { dependency_i, &dependency, manager.lockfile.buffers.resolutions.items[dependency_i], + false, ); } } @@ -7861,7 +7941,7 @@ pub const PackageManager = struct { manager.drainDependencyList(); } - if (manager.pending_tasks > 0) { + if (manager.pending_tasks > 0 or manager.peer_dependencies.items.len > 0) { if (root.dependencies.len > 0) { _ = manager.getCacheDirectory(); _ = manager.getTemporaryDirectory(); @@ -7885,6 +7965,7 @@ pub const PackageManager = struct { .onPackageDownloadError = {}, .progress_bar = true, }, + false, log_level, ); @@ -7896,6 +7977,35 @@ pub const PackageManager = struct { manager.sleep(); } + if (manager.options.do.install_peer_dependencies) { + try manager.processPeerDependencyList(); + + manager.drainDependencyList(); + + while (manager.pending_tasks > 0) { + try manager.runTasks( + *PackageManager, + manager, + .{ + .onExtract = {}, + .onResolve = {}, + .onPackageManifestError = {}, + .onPackageDownloadError = {}, + .progress_bar = true, + }, + true, + log_level, + ); + + if (PackageManager.verbose_install and manager.pending_tasks > 0) { + Output.prettyErrorln("[PackageManager] waiting for {d} tasks\n", .{manager.pending_tasks}); + } + + if (manager.pending_tasks > 0) + manager.sleep(); + } + } + if (comptime log_level.showProgress()) { manager.endProgressBar(); } else if (comptime log_level != .silent) { diff --git a/test/cli/install/boba-0.0.2.tgz b/test/cli/install/boba-0.0.2.tgz new file mode 100644 index 000000000..4308f02c4 Binary files /dev/null and b/test/cli/install/boba-0.0.2.tgz differ diff --git a/test/cli/install/bun-install.test.ts b/test/cli/install/bun-install.test.ts index 9ee77be8c..0c8ce5789 100644 --- a/test/cli/install/bun-install.test.ts +++ b/test/cli/install/bun-install.test.ts @@ -659,6 +659,13 @@ it("should ignore peerDependencies within workspaces", async () => { }, }), ); + await writeFile( + join(package_dir, "bunfig.toml"), + ` + [install] + peer = false + `, + ); const { stdout, stderr, exited } = spawn({ cmd: [bunExe(), "install"], cwd: package_dir, @@ -679,11 +686,87 @@ it("should ignore peerDependencies within workspaces", async () => { ]); expect(await exited).toBe(0); expect(requested).toBe(0); - expect(await readdirSorted(join(package_dir, "node_modules"))).toEqual([".cache", "Baz"]); + expect(await readdirSorted(join(package_dir, "node_modules"))).toEqual(["Baz"]); expect(await readlink(join(package_dir, "node_modules", "Baz"))).toBe(join("..", "packages", "baz")); await access(join(package_dir, "bun.lockb")); }); +it("should handle installing the same peerDependency with different versions", async () => { + const urls: string[] = []; + setHandler(dummyRegistry(urls)); + await writeFile( + join(package_dir, "package.json"), + JSON.stringify({ + name: "foo", + version: "0.0.1", + peerDependencies: { + peer: "0.0.2", + }, + dependencies: { + boba: "0.0.2", + }, + }), + ); + + const { stdout, stderr, exited } = spawn({ + cmd: [bunExe(), "install"], + cwd: package_dir, + stdout: null, + stdin: "pipe", + stderr: "pipe", + env, + }); + expect(requested).toBe(0); + expect(stderr).toBeDefined(); + const err = await new Response(stderr).text(); + expect(err).toContain("Saved lockfile"); + expect(stdout).toBeDefined(); + const out = await new Response(stdout).text(); + expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + " + boba@0.0.2", + "", + " 2 packages installed", + ]); +}); + +it("should handle installing the same peerDependency with the same version", async () => { + const urls: string[] = []; + setHandler(dummyRegistry(urls)); + await writeFile( + join(package_dir, "package.json"), + JSON.stringify({ + name: "foo", + version: "0.0.1", + peerDependencies: { + peer: "0.0.1", + }, + dependencies: { + boba: "0.0.2", + }, + }), + ); + + const { stdout, stderr, exited } = spawn({ + cmd: [bunExe(), "install"], + cwd: package_dir, + stdout: null, + stdin: "pipe", + stderr: "pipe", + env, + }); + expect(requested).toBe(0); + expect(stderr).toBeDefined(); + const err = await new Response(stderr).text(); + expect(err).toContain("Saved lockfile"); + expect(stdout).toBeDefined(); + const out = await new Response(stdout).text(); + expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + " + boba@0.0.2", + "", + " 1 package installed", + ]); +}); + it("should handle life-cycle scripts within workspaces", async () => { await writeFile( join(package_dir, "package.json"), @@ -3396,7 +3479,7 @@ it("should consider peerDependencies during hoisting", async () => { }), ); const { stdout, stderr, exited } = spawn({ - cmd: [bunExe(), "install", "--peer"], + cmd: [bunExe(), "install"], cwd: package_dir, stdout: null, stdin: "pipe", @@ -3447,6 +3530,105 @@ it("should consider peerDependencies during hoisting", async () => { await access(join(package_dir, "bun.lockb")); }); +it("should install peerDependencies when needed", async () => { + const urls: string[] = []; + setHandler( + dummyRegistry(urls, { + "0.0.3": { + bin: { + "baz-run": "index.js", + }, + }, + "0.0.5": { + bin: { + "baz-exec": "index.js", + }, + }, + }), + ); + await writeFile( + join(package_dir, "package.json"), + JSON.stringify({ + name: "foo", + version: "0.0.1", + peerDependencies: { + baz: ">=0.0.3", + }, + workspaces: ["bar", "moo"], + }), + ); + await mkdir(join(package_dir, "bar")); + await writeFile( + join(package_dir, "bar", "package.json"), + JSON.stringify({ + name: "bar", + version: "0.0.2", + dependencies: { + baz: "0.0.3", + }, + }), + ); + await mkdir(join(package_dir, "moo")); + await writeFile( + join(package_dir, "moo", "package.json"), + JSON.stringify({ + name: "moo", + version: "0.0.4", + dependencies: { + baz: "0.0.5", + }, + }), + ); + const { stdout, stderr, exited } = spawn({ + cmd: [bunExe(), "install"], + cwd: package_dir, + stdout: null, + stdin: "pipe", + stderr: "pipe", + env, + }); + expect(stderr).toBeDefined(); + const err = await new Response(stderr).text(); + expect(err).toContain("Saved lockfile"); + expect(stdout).toBeDefined(); + const out = await new Response(stdout).text(); + expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + " + bar@workspace:bar", + " + moo@workspace:moo", + "", + " 4 packages installed", + ]); + expect(await exited).toBe(0); + expect(urls.sort()).toEqual([`${root_url}/baz`, `${root_url}/baz-0.0.3.tgz`, `${root_url}/baz-0.0.5.tgz`]); + expect(requested).toBe(3); + expect(await readdirSorted(join(package_dir, "node_modules"))).toEqual([".bin", ".cache", "bar", "baz", "moo"]); + expect(await readdirSorted(join(package_dir, "node_modules", ".bin"))).toEqual(["baz-exec", "baz-run"]); + expect(await readlink(join(package_dir, "node_modules", ".bin", "baz-exec"))).toBe( + join("..", "..", "moo", "node_modules", "baz", "index.js"), + ); + expect(await readlink(join(package_dir, "node_modules", ".bin", "baz-run"))).toBe(join("..", "baz", "index.js")); + expect(await readlink(join(package_dir, "node_modules", "bar"))).toBe(join("..", "bar")); + expect(await readdirSorted(join(package_dir, "bar"))).toEqual(["package.json"]); + expect(await readdirSorted(join(package_dir, "node_modules", "baz"))).toEqual(["index.js", "package.json"]); + expect(await file(join(package_dir, "node_modules", "baz", "package.json")).json()).toEqual({ + name: "baz", + version: "0.0.3", + bin: { + "baz-run": "index.js", + }, + }); + expect(await readlink(join(package_dir, "node_modules", "moo"))).toBe(join("..", "moo")); + expect(await readdirSorted(join(package_dir, "moo"))).toEqual(["node_modules", "package.json"]); + expect(await file(join(package_dir, "moo", "node_modules", "baz", "package.json")).json()).toEqual({ + name: "baz", + version: "0.0.5", + bin: { + "baz-exec": "index.js", + }, + }); + await access(join(package_dir, "bun.lockb")); +}); + it("should not regard peerDependencies declarations as duplicates", async () => { const urls: string[] = []; setHandler(dummyRegistry(urls)); @@ -6928,6 +7110,39 @@ it("should handle `workspace:*` on both root & child", async () => { await access(join(package_dir, "bun.lockb")); }); +it("should install peer dependencies from root package", async () => { + const urls: string[] = []; + setHandler(dummyRegistry(urls)); + await writeFile( + join(package_dir, "package.json"), + JSON.stringify({ + name: "foo", + peerDependencies: { + bar: "0.0.2", + }, + }), + ); + const { stdout, stderr, exited } = spawn({ + cmd: [bunExe(), "install"], + cwd: package_dir, + env, + stdout: null, + stdin: "pipe", + stderr: "pipe", + }); + expect(stderr).toBeDefined(); + const err = await new Response(stderr).text(); + expect(err).toContain("Saved lockfile"); + expect(stdout).toBeDefined(); + const out = await new Response(stdout).text(); + expect(out.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual(["", " 1 package installed"]); + expect(await exited).toBe(0); + expect(urls.sort()).toEqual([`${root_url}/bar`, `${root_url}/bar-0.0.2.tgz`]); + expect(requested).toBe(2); + + await access(join(package_dir, "bun.lockb")); +}); + describe("Registry URLs", () => { // Some of the non failing URLs are invalid, but bun's URL parser ignores // the validation error and returns a valid serialized URL anyway. diff --git a/test/cli/install/peer-0.0.1.tgz b/test/cli/install/peer-0.0.1.tgz new file mode 100644 index 000000000..f2839613d Binary files /dev/null and b/test/cli/install/peer-0.0.1.tgz differ diff --git a/test/cli/install/peer-0.0.2.tgz b/test/cli/install/peer-0.0.2.tgz new file mode 100644 index 000000000..c707b2d7a Binary files /dev/null and b/test/cli/install/peer-0.0.2.tgz differ -- cgit v1.2.3