const bun = @import("root").bun; const string = bun.string; const Output = bun.Output; const Global = bun.Global; const Environment = bun.Environment; const strings = bun.strings; const MutableString = bun.MutableString; const stringZ = bun.stringZ; const default_allocator = bun.default_allocator; const FeatureFlags = bun.FeatureFlags; const C = bun.C; const root = @import("root"); const std = @import("std"); const lex = bun.js_lexer; const logger = bun.logger; const options = @import("options.zig"); const js_parser = bun.js_parser; const json_parser = bun.JSON; const js_printer = bun.js_printer; const js_ast = bun.JSAst; const linker = @import("linker.zig"); const RegularExpression = bun.RegularExpression; const builtin = @import("builtin"); const File = bun.sys.File; const debug = Output.scoped(.CLI, true); const sync = @import("./sync.zig"); const Api = @import("api/schema.zig").Api; const resolve_path = @import("./resolver/resolve_path.zig"); const configureTransformOptionsForBun = @import("./bun.js/config.zig").configureTransformOptionsForBun; const clap = bun.clap; const BunJS = @import("./bun_js.zig"); const Install = @import("./install/install.zig"); const transpiler = bun.transpiler; const DotEnv = @import("./env_loader.zig"); const RunCommand_ = @import("./cli/run_command.zig").RunCommand; const CreateCommand_ = @import("./cli/create_command.zig").CreateCommand; const FilterRun = @import("./cli/filter_run.zig"); const fs = @import("fs.zig"); const Router = @import("./router.zig"); const MacroMap = @import("./resolver/package_json.zig").MacroMap; const TestCommand = @import("./cli/test_command.zig").TestCommand; pub var start_time: i128 = undefined; const Bunfig = @import("./bunfig.zig").Bunfig; const OOM = bun.OOM; export var Bun__Node__ZeroFillBuffers = false; export var Bun__Node__ProcessNoDeprecation = false; export var Bun__Node__ProcessThrowDeprecation = false; pub var Bun__Node__ProcessTitle: ?string = null; pub const Cli = struct { pub const CompileTarget = @import("./compile_target.zig"); var wait_group: sync.WaitGroup = undefined; pub var log_: logger.Log = undefined; pub fn startTransform(_: std.mem.Allocator, _: Api.TransformOptions, _: *logger.Log) anyerror!void {} pub fn start(allocator: std.mem.Allocator) void { is_main_thread = true; start_time = std.time.nanoTimestamp(); log_ = logger.Log.init(allocator); var log = &log_; // var panicker = MainPanicHandler.init(log); // MainPanicHandler.Singleton = &panicker; Command.start(allocator, log) catch |err| { log.print(Output.errorWriter()) catch {}; bun.crash_handler.handleRootError(err, @errorReturnTrace()); }; } pub var cmd: ?Command.Tag = null; pub threadlocal var is_main_thread: bool = false; }; pub const debug_flags = if (Environment.isDebug) struct { var resolve_breakpoints: []const []const u8 = &.{}; var print_breakpoints: []const []const u8 = &.{}; pub fn hasResolveBreakpoint(str: []const u8) bool { for (resolve_breakpoints) |bp| { if (strings.contains(str, bp)) { return true; } } return false; } pub fn hasPrintBreakpoint(path: fs.Path) bool { for (print_breakpoints) |bp| { if (strings.contains(path.pretty, bp)) { return true; } if (strings.contains(path.text, bp)) { return true; } } return false; } } else @compileError("Do not access this namespace in a release build"); const LoaderMatcher = strings.ExactSizeMatcher(4); const ColonListType = @import("./cli/colon_list_type.zig").ColonListType; pub const LoaderColonList = ColonListType(Api.Loader, Arguments.loader_resolver); pub const DefineColonList = ColonListType(string, Arguments.noop_resolver); fn invalidTarget(diag: *clap.Diagnostic, _target: []const u8) noreturn { @branchHint(.cold); diag.name.long = "target"; diag.arg = _target; diag.report(Output.errorWriter(), error.InvalidTarget) catch {}; std.process.exit(1); } pub const BuildCommand = @import("./cli/build_command.zig").BuildCommand; pub const AddCommand = @import("./cli/add_command.zig").AddCommand; pub const CreateCommand = @import("./cli/create_command.zig").CreateCommand; pub const CreateCommandExample = @import("./cli/create_command.zig").Example; pub const CreateListExamplesCommand = @import("./cli/create_command.zig").CreateListExamplesCommand; pub const DiscordCommand = @import("./cli/discord_command.zig").DiscordCommand; pub const InstallCommand = @import("./cli/install_command.zig").InstallCommand; pub const LinkCommand = @import("./cli/link_command.zig").LinkCommand; pub const UnlinkCommand = @import("./cli/unlink_command.zig").UnlinkCommand; pub const InstallCompletionsCommand = @import("./cli/install_completions_command.zig").InstallCompletionsCommand; pub const PackageManagerCommand = @import("./cli/package_manager_command.zig").PackageManagerCommand; pub const RemoveCommand = @import("./cli/remove_command.zig").RemoveCommand; pub const RunCommand = @import("./cli/run_command.zig").RunCommand; pub const ShellCompletions = @import("./cli/shell_completions.zig"); pub const UpdateCommand = @import("./cli/update_command.zig").UpdateCommand; pub const UpgradeCommand = @import("./cli/upgrade_command.zig").UpgradeCommand; pub const BunxCommand = @import("./cli/bunx_command.zig").BunxCommand; pub const ExecCommand = @import("./cli/exec_command.zig").ExecCommand; pub const PatchCommand = @import("./cli/patch_command.zig").PatchCommand; pub const PatchCommitCommand = @import("./cli/patch_commit_command.zig").PatchCommitCommand; pub const OutdatedCommand = @import("./cli/outdated_command.zig").OutdatedCommand; pub const PublishCommand = @import("./cli/publish_command.zig").PublishCommand; pub const PackCommand = @import("./cli/pack_command.zig").PackCommand; pub const InitCommand = @import("./cli/init_command.zig").InitCommand; pub const Arguments = struct { pub fn loader_resolver(in: string) !Api.Loader { const option_loader = options.Loader.fromString(in) orelse return error.InvalidLoader; return option_loader.toAPI(); } pub fn noop_resolver(in: string) !string { return in; } pub fn fileReadError(err: anyerror, stderr: anytype, filename: string, kind: string) noreturn { stderr.writer().print("Error reading file \"{s}\" for {s}: {s}", .{ filename, kind, @errorName(err) }) catch {}; std.process.exit(1); } pub fn readFile( allocator: std.mem.Allocator, cwd: string, filename: string, ) ![]u8 { var paths = [_]string{ cwd, filename }; const outpath = try std.fs.path.resolve(allocator, &paths); defer allocator.free(outpath); var file = try bun.openFileZ(&try std.posix.toPosixPath(outpath), std.fs.File.OpenFlags{ .mode = .read_only }); defer file.close(); const size = try file.getEndPos(); return try file.readToEndAlloc(allocator, size); } pub fn resolve_jsx_runtime(str: string) !Api.JsxRuntime { if (strings.eqlComptime(str, "automatic")) { return Api.JsxRuntime.automatic; } else if (strings.eqlComptime(str, "fallback") or strings.eqlComptime(str, "classic")) { return Api.JsxRuntime.classic; } else if (strings.eqlComptime(str, "solid")) { return Api.JsxRuntime.solid; } else { return error.InvalidJSXRuntime; } } pub const ParamType = clap.Param(clap.Help); const base_params_ = (if (Environment.isDebug) debug_params else [_]ParamType{}) ++ [_]ParamType{ clap.parseParam("--env-file ... Load environment variables from the specified file(s)") catch unreachable, clap.parseParam("--cwd Absolute path to resolve files & entry points from. This just changes the process' cwd.") catch unreachable, clap.parseParam("-c, --config ? Specify path to Bun config file. Default $cwd/bunfig.toml") catch unreachable, clap.parseParam("-h, --help Display this menu and exit") catch unreachable, } ++ (if (builtin.have_error_return_tracing) [_]ParamType{ // This will print more error return traces, as a debug aid clap.parseParam("--verbose-error-trace Dump error return traces") catch unreachable, } else [_]ParamType{}) ++ [_]ParamType{ clap.parseParam("...") catch unreachable, }; const debug_params = [_]ParamType{ clap.parseParam("--breakpoint-resolve ... DEBUG MODE: breakpoint when resolving something that includes this string") catch unreachable, clap.parseParam("--breakpoint-print ... DEBUG MODE: breakpoint when printing something that includes this string") catch unreachable, }; const transpiler_params_ = [_]ParamType{ clap.parseParam("--main-fields ... Main fields to lookup in package.json. Defaults to --target dependent") catch unreachable, clap.parseParam("--extension-order ... Defaults to: .tsx,.ts,.jsx,.js,.json ") catch unreachable, clap.parseParam("--tsconfig-override Specify custom tsconfig.json. Default $cwd/tsconfig.json") catch unreachable, clap.parseParam("-d, --define ... Substitute K:V while parsing, e.g. --define process.env.NODE_ENV:\"development\". Values are parsed as JSON.") catch unreachable, clap.parseParam("--drop ... Remove function calls, e.g. --drop=console removes all console.* calls.") catch unreachable, clap.parseParam("-l, --loader ... Parse files with .ext:loader, e.g. --loader .js:jsx. Valid loaders: js, jsx, ts, tsx, json, toml, text, file, wasm, napi") catch unreachable, clap.parseParam("--no-macros Disable macros from being executed in the bundler, transpiler and runtime") catch unreachable, clap.parseParam("--jsx-factory Changes the function called when compiling JSX elements using the classic JSX runtime") catch unreachable, clap.parseParam("--jsx-fragment Changes the function called when compiling JSX fragments") catch unreachable, clap.parseParam("--jsx-import-source Declares the module specifier to be used for importing the jsx and jsxs factory functions. Default: \"react\"") catch unreachable, clap.parseParam("--jsx-runtime \"automatic\" (default) or \"classic\"") catch unreachable, clap.parseParam("--ignore-dce-annotations Ignore tree-shaking annotations such as @__PURE__") catch unreachable, }; const runtime_params_ = [_]ParamType{ clap.parseParam("--watch Automatically restart the process on file change") catch unreachable, clap.parseParam("--hot Enable auto reload in the Bun runtime, test runner, or bundler") catch unreachable, clap.parseParam("--no-clear-screen Disable clearing the terminal screen on reload when --hot or --watch is enabled") catch unreachable, clap.parseParam("--smol Use less memory, but run garbage collection more often") catch unreachable, clap.parseParam("-r, --preload ... Import a module before other modules are loaded") catch unreachable, clap.parseParam("--inspect ? Activate Bun's debugger") catch unreachable, clap.parseParam("--inspect-wait ? Activate Bun's debugger, wait for a connection before executing") catch unreachable, clap.parseParam("--inspect-brk ? Activate Bun's debugger, set breakpoint on first line of code and wait") catch unreachable, clap.parseParam("--if-present Exit without an error if the entrypoint does not exist") catch unreachable, clap.parseParam("--no-install Disable auto install in the Bun runtime") catch unreachable, clap.parseParam("--install Configure auto-install behavior. One of \"auto\" (default, auto-installs when no node_modules), \"fallback\" (missing packages only), \"force\" (always).") catch unreachable, clap.parseParam("-i Auto-install dependencies during execution. Equivalent to --install=fallback.") catch unreachable, clap.parseParam("-e, --eval Evaluate argument as a script") catch unreachable, clap.parseParam("-p, --print Evaluate argument as a script and print the result") catch unreachable, clap.parseParam("--prefer-offline Skip staleness checks for packages in the Bun runtime and resolve from disk") catch unreachable, clap.parseParam("--prefer-latest Use the latest matching versions of packages in the Bun runtime, always checking npm") catch unreachable, clap.parseParam("--port Set the default port for Bun.serve") catch unreachable, clap.parseParam("-u, --origin ") catch unreachable, clap.parseParam("--conditions ... Pass custom conditions to resolve") catch unreachable, clap.parseParam("--fetch-preconnect ... Preconnect to a URL while code is loading") catch unreachable, clap.parseParam("--max-http-header-size Set the maximum size of HTTP headers in bytes. Default is 16KiB") catch unreachable, clap.parseParam("--dns-result-order Set the default order of DNS lookup results. Valid orders: verbatim (default), ipv4first, ipv6first") catch unreachable, clap.parseParam("--expose-gc Expose gc() on the global object. Has no effect on Bun.gc().") catch unreachable, clap.parseParam("--no-deprecation Suppress all reporting of the custom deprecation.") catch unreachable, clap.parseParam("--throw-deprecation Determine whether or not deprecation warnings result in errors.") catch unreachable, clap.parseParam("--title Set the process title") catch unreachable, clap.parseParam("--zero-fill-buffers Boolean to force Buffer.allocUnsafe(size) to be zero-filled.") catch unreachable, }; const auto_or_run_params = [_]ParamType{ clap.parseParam("-F, --filter ... Run a script in all workspace packages matching the pattern") catch unreachable, clap.parseParam("-b, --bun Force a script or package to use Bun's runtime instead of Node.js (via symlinking node)") catch unreachable, clap.parseParam("--shell Control the shell used for package.json scripts. Supports either 'bun' or 'system'") catch unreachable, }; const auto_only_params = [_]ParamType{ // clap.parseParam("--all") catch unreachable, clap.parseParam("--silent Don't print the script command") catch unreachable, clap.parseParam("--elide-lines Number of lines of script output shown when using --filter (default: 10). Set to 0 to show all lines.") catch unreachable, clap.parseParam("-v, --version Print version and exit") catch unreachable, clap.parseParam("--revision Print version with revision and exit") catch unreachable, } ++ auto_or_run_params; pub const auto_params = auto_only_params ++ runtime_params_ ++ transpiler_params_ ++ base_params_; const run_only_params = [_]ParamType{ clap.parseParam("--silent Don't print the script command") catch unreachable, clap.parseParam("--elide-lines Number of lines of script output shown when using --filter (default: 10). Set to 0 to show all lines.") catch unreachable, } ++ auto_or_run_params; pub const run_params = run_only_params ++ runtime_params_ ++ transpiler_params_ ++ base_params_; const bunx_commands = [_]ParamType{ clap.parseParam("-b, --bun Force a script or package to use Bun's runtime instead of Node.js (via symlinking node)") catch unreachable, } ++ auto_only_params; const build_only_params = [_]ParamType{ clap.parseParam("--production Set NODE_ENV=production and enable minification") catch unreachable, clap.parseParam("--compile Generate a standalone Bun executable containing your bundled code. Implies --production") catch unreachable, clap.parseParam("--bytecode Use a bytecode cache") catch unreachable, clap.parseParam("--watch Automatically restart the process on file change") catch unreachable, clap.parseParam("--no-clear-screen Disable clearing the terminal screen on reload when --watch is enabled") catch unreachable, clap.parseParam("--target The intended execution environment for the bundle. \"browser\", \"bun\" or \"node\"") catch unreachable, clap.parseParam("--outdir Default to \"dist\" if multiple files") catch unreachable, clap.parseParam("--outfile Write to a file") catch unreachable, clap.parseParam("--sourcemap ? Build with sourcemaps - 'linked', 'inline', 'external', or 'none'") catch unreachable, clap.parseParam("--banner Add a banner to the bundled output such as \"use client\"; for a bundle being used with RSCs") catch unreachable, clap.parseParam("--footer Add a footer to the bundled output such as // built with bun!") catch unreachable, clap.parseParam("--format Specifies the module format to build to. \"esm\", \"cjs\" and \"iife\" are supported. Defaults to \"esm\".") catch unreachable, clap.parseParam("--root Root directory used for multiple entry points") catch unreachable, clap.parseParam("--splitting Enable code splitting") catch unreachable, clap.parseParam("--public-path A prefix to be appended to any import paths in bundled code") catch unreachable, clap.parseParam("-e, --external ... Exclude module from transpilation (can use * wildcards). ex: -e react") catch unreachable, clap.parseParam("--packages Add dependencies to bundle or keep them external. \"external\", \"bundle\" is supported. Defaults to \"bundle\".") catch unreachable, clap.parseParam("--entry-naming Customize entry point filenames. Defaults to \"[dir]/[name].[ext]\"") catch unreachable, clap.parseParam("--chunk-naming Customize chunk filenames. Defaults to \"[name]-[hash].[ext]\"") catch unreachable, clap.parseParam("--asset-naming Customize asset filenames. Defaults to \"[name]-[hash].[ext]\"") catch unreachable, clap.parseParam("--react-fast-refresh Enable React Fast Refresh transform (does not emit hot-module code, use this for testing)") catch unreachable, clap.parseParam("--no-bundle Transpile file only, do not bundle") catch unreachable, clap.parseParam("--emit-dce-annotations Re-emit DCE annotations in bundles. Enabled by default unless --minify-whitespace is passed.") catch unreachable, clap.parseParam("--minify Enable all minification flags") catch unreachable, clap.parseParam("--minify-syntax Minify syntax and inline data") catch unreachable, clap.parseParam("--minify-whitespace Minify whitespace") catch unreachable, clap.parseParam("--minify-identifiers Minify identifiers") catch unreachable, clap.parseParam("--css-chunking Chunk CSS files together to reduce duplicated CSS loaded in a browser. Only has an effect when multiple entrypoints import CSS") catch unreachable, clap.parseParam("--dump-environment-variables") catch unreachable, clap.parseParam("--conditions ... Pass custom conditions to resolve") catch unreachable, clap.parseParam("--app (EXPERIMENTAL) Build a web app for production using Bun Bake.") catch unreachable, clap.parseParam("--server-components (EXPERIMENTAL) Enable server components") catch unreachable, clap.parseParam("--env Inline environment variables into the bundle as process.env.${name}. Defaults to 'disable'. To inline environment variables matching a prefix, use my prefix like 'FOO_PUBLIC_*'.") catch unreachable, clap.parseParam("--windows-hide-console When using --compile targeting Windows, prevent a Command prompt from opening alongside the executable") catch unreachable, clap.parseParam("--windows-icon When using --compile targeting Windows, assign an executable icon") catch unreachable, } ++ if (FeatureFlags.bake_debugging_features) [_]ParamType{ clap.parseParam("--debug-dump-server-files When --app is set, dump all server files to disk even when building statically") catch unreachable, clap.parseParam("--debug-no-minify When --app is set, do not minify anything") catch unreachable, } else .{}; pub const build_params = build_only_params ++ transpiler_params_ ++ base_params_; // TODO: update test completions const test_only_params = [_]ParamType{ clap.parseParam("--timeout Set the per-test timeout in milliseconds, default is 5000.") catch unreachable, clap.parseParam("-u, --update-snapshots Update snapshot files") catch unreachable, clap.parseParam("--rerun-each Re-run each test file times, helps catch certain bugs") catch unreachable, clap.parseParam("--only Only run tests that are marked with \"test.only()\"") catch unreachable, clap.parseParam("--todo Include tests that are marked with \"test.todo()\"") catch unreachable, clap.parseParam("--coverage Generate a coverage profile") catch unreachable, clap.parseParam("--coverage-reporter ... Report coverage in 'text' and/or 'lcov'. Defaults to 'text'.") catch unreachable, clap.parseParam("--coverage-dir Directory for coverage files. Defaults to 'coverage'.") catch unreachable, clap.parseParam("--bail ? Exit the test suite after failures. If you do not specify a number, it defaults to 1.") catch unreachable, clap.parseParam("-t, --test-name-pattern Run only tests with a name that matches the given regex.") catch unreachable, clap.parseParam("--reporter Specify the test reporter. Currently --reporter=junit is the only supported format.") catch unreachable, clap.parseParam("--reporter-outfile The output file used for the format from --reporter.") catch unreachable, }; pub const test_params = test_only_params ++ runtime_params_ ++ transpiler_params_ ++ base_params_; pub fn loadConfigPath(allocator: std.mem.Allocator, auto_loaded: bool, config_path: [:0]const u8, ctx: Command.Context, comptime cmd: Command.Tag) !void { var config_file = switch (bun.sys.openA(config_path, bun.O.RDONLY, 0)) { .result => |fd| fd.asFile(), .err => |err| { if (auto_loaded) return; Output.prettyErrorln("{}\nwhile opening config \"{s}\"", .{ err, config_path, }); Global.exit(1); }, }; defer config_file.close(); const contents = config_file.readToEndAlloc(allocator, std.math.maxInt(usize)) catch |err| { if (auto_loaded) return; Output.prettyErrorln("error: {s} reading config \"{s}\"", .{ @errorName(err), config_path, }); Global.exit(1); }; js_ast.Stmt.Data.Store.create(); js_ast.Expr.Data.Store.create(); defer { js_ast.Stmt.Data.Store.reset(); js_ast.Expr.Data.Store.reset(); } const original_level = ctx.log.level; defer { ctx.log.level = original_level; } ctx.log.level = logger.Log.Level.warn; try Bunfig.parse(allocator, logger.Source.initPathString(bun.asByteSlice(config_path), contents), ctx, cmd); } fn getHomeConfigPath(buf: *bun.PathBuffer) ?[:0]const u8 { if (bun.getenvZ("XDG_CONFIG_HOME") orelse bun.getenvZ(bun.DotEnv.home_env)) |data_dir| { var paths = [_]string{".bunfig.toml"}; return resolve_path.joinAbsStringBufZ(data_dir, buf, &paths, .auto); } return null; } pub fn loadConfig(allocator: std.mem.Allocator, user_config_path_: ?string, ctx: Command.Context, comptime cmd: Command.Tag) OOM!void { var config_buf: bun.PathBuffer = undefined; if (comptime cmd.readGlobalConfig()) { if (!ctx.has_loaded_global_config) { ctx.has_loaded_global_config = true; if (getHomeConfigPath(&config_buf)) |path| { loadConfigPath(allocator, true, path, ctx, comptime cmd) catch |err| { if (ctx.log.hasAny()) { ctx.log.print(Output.errorWriter()) catch {}; } if (ctx.log.hasAny()) Output.printError("\n", .{}); Output.err(err, "failed to load bunfig", .{}); Global.crash(); }; } } } var config_path_: []const u8 = user_config_path_ orelse ""; var auto_loaded: bool = false; if (config_path_.len == 0 and (user_config_path_ != null or Command.Tag.always_loads_config.get(cmd) or (cmd == .AutoCommand and // "bun" (ctx.positionals.len == 0 or // "bun file.js" ctx.positionals.len > 0 and options.defaultLoaders.has(std.fs.path.extension(ctx.positionals[0])))))) { config_path_ = "bunfig.toml"; auto_loaded = true; } if (config_path_.len == 0) { return; } defer ctx.debug.loaded_bunfig = true; var config_path: [:0]u8 = undefined; if (config_path_[0] == '/') { @memcpy(config_buf[0..config_path_.len], config_path_); config_buf[config_path_.len] = 0; config_path = config_buf[0..config_path_.len :0]; } else { if (ctx.args.absolute_working_dir == null) { var secondbuf: bun.PathBuffer = undefined; const cwd = bun.getcwd(&secondbuf) catch return; ctx.args.absolute_working_dir = try allocator.dupeZ(u8, cwd); } var parts = [_]string{ ctx.args.absolute_working_dir.?, config_path_ }; config_path_ = resolve_path.joinAbsStringBuf( ctx.args.absolute_working_dir.?, &config_buf, &parts, .auto, ); config_buf[config_path_.len] = 0; config_path = config_buf[0..config_path_.len :0]; } loadConfigPath(allocator, auto_loaded, config_path, ctx, comptime cmd) catch |err| { if (ctx.log.hasAny()) { ctx.log.print(Output.errorWriter()) catch {}; } if (ctx.log.hasAny()) Output.printError("\n", .{}); Output.err(err, "failed to load bunfig", .{}); Global.crash(); }; } pub fn loadConfigWithCmdArgs( comptime cmd: Command.Tag, allocator: std.mem.Allocator, args: clap.Args(clap.Help, cmd.params()), ctx: Command.Context, ) OOM!void { return try loadConfig(allocator, args.option("--config"), ctx, comptime cmd); } pub fn parse(allocator: std.mem.Allocator, ctx: Command.Context, comptime cmd: Command.Tag) !Api.TransformOptions { var diag = clap.Diagnostic{}; const params_to_parse = comptime cmd.params(); var args = clap.parse(clap.Help, params_to_parse, .{ .diagnostic = &diag, .allocator = allocator, .stop_after_positional_at = switch (cmd) { .RunCommand => 2, .AutoCommand, .RunAsNodeCommand => 1, else => 0, }, }) catch |err| { // Report useful error and exit diag.report(Output.errorWriter(), err) catch {}; cmd.printHelp(false); Global.exit(1); }; const print_help = args.flag("--help"); if (print_help) { cmd.printHelp(true); Output.flush(); Global.exit(0); } if (cmd == .AutoCommand) { if (args.flag("--version")) { printVersionAndExit(); } if (args.flag("--revision")) { printRevisionAndExit(); } } if (builtin.have_error_return_tracing) { if (args.flag("--verbose-error-trace")) { bun.crash_handler.verbose_error_trace = true; } } var cwd: [:0]u8 = undefined; if (args.option("--cwd")) |cwd_arg| { cwd = brk: { var outbuf: bun.PathBuffer = undefined; const out = bun.path.joinAbs(try bun.getcwd(&outbuf), .loose, cwd_arg); bun.sys.chdir("", out).unwrap() catch |err| { Output.err(err, "Could not change directory to \"{s}\"\n", .{cwd_arg}); Global.exit(1); }; break :brk try allocator.dupeZ(u8, out); }; } else { cwd = try bun.getcwdAlloc(allocator); } if (cmd == .RunCommand or cmd == .AutoCommand) { ctx.filters = args.options("--filter"); if (args.option("--elide-lines")) |elide_lines| { if (elide_lines.len > 0) { ctx.bundler_options.elide_lines = std.fmt.parseInt(usize, elide_lines, 10) catch { Output.prettyErrorln("error: Invalid elide-lines: \"{s}\"", .{elide_lines}); Global.exit(1); }; } } } if (cmd == .TestCommand) { if (args.option("--timeout")) |timeout_ms| { if (timeout_ms.len > 0) { ctx.test_options.default_timeout_ms = std.fmt.parseInt(u32, timeout_ms, 10) catch { Output.prettyErrorln("error: Invalid timeout: \"{s}\"", .{timeout_ms}); Global.exit(1); }; } } if (!ctx.test_options.coverage.enabled) { ctx.test_options.coverage.enabled = args.flag("--coverage"); } if (args.options("--coverage-reporter").len > 0) { ctx.test_options.coverage.reporters = .{ .text = false, .lcov = false }; for (args.options("--coverage-reporter")) |reporter| { if (bun.strings.eqlComptime(reporter, "text")) { ctx.test_options.coverage.reporters.text = true; } else if (bun.strings.eqlComptime(reporter, "lcov")) { ctx.test_options.coverage.reporters.lcov = true; } else { Output.prettyErrorln("error: --coverage-reporter received invalid reporter: \"{s}\"", .{reporter}); Global.exit(1); } } } if (args.option("--reporter-outfile")) |reporter_outfile| { ctx.test_options.reporter_outfile = reporter_outfile; } if (args.option("--reporter")) |reporter| { if (strings.eqlComptime(reporter, "junit")) { if (ctx.test_options.reporter_outfile == null) { Output.errGeneric("--reporter=junit expects an output file from --reporter-outfile", .{}); Global.crash(); } ctx.test_options.file_reporter = .junit; } else { Output.errGeneric("unrecognized reporter format: '{s}'. Currently, only 'junit' is supported", .{reporter}); Global.crash(); } } if (args.option("--coverage-dir")) |dir| { ctx.test_options.coverage.reports_directory = dir; } if (args.option("--bail")) |bail| { if (bail.len > 0) { ctx.test_options.bail = std.fmt.parseInt(u32, bail, 10) catch |e| { Output.prettyErrorln("error: --bail expects a number: {s}", .{@errorName(e)}); Global.exit(1); }; if (ctx.test_options.bail == 0) { Output.prettyErrorln("error: --bail expects a number greater than 0", .{}); Global.exit(1); } } else { ctx.test_options.bail = 1; } } if (args.option("--rerun-each")) |repeat_count| { if (repeat_count.len > 0) { ctx.test_options.repeat_count = std.fmt.parseInt(u32, repeat_count, 10) catch |e| { Output.prettyErrorln("error: --rerun-each expects a number: {s}", .{@errorName(e)}); Global.exit(1); }; } } if (args.option("--test-name-pattern")) |namePattern| { const regex = RegularExpression.init(bun.String.fromBytes(namePattern), RegularExpression.Flags.none) catch { Output.prettyErrorln( "error: --test-name-pattern expects a valid regular expression but received {}", .{ bun.fmt.QuotedFormatter{ .text = namePattern, }, }, ); Global.exit(1); }; ctx.test_options.test_filter_regex = regex; } ctx.test_options.update_snapshots = args.flag("--update-snapshots"); ctx.test_options.run_todo = args.flag("--todo"); ctx.test_options.only = args.flag("--only"); } ctx.args.absolute_working_dir = cwd; ctx.positionals = args.positionals(); if (comptime Command.Tag.loads_config.get(cmd)) { try loadConfigWithCmdArgs(cmd, allocator, args, ctx); } var opts: Api.TransformOptions = ctx.args; const defines_tuple = try DefineColonList.resolve(allocator, args.options("--define")); if (defines_tuple.keys.len > 0) { opts.define = .{ .keys = defines_tuple.keys, .values = defines_tuple.values, }; } opts.drop = args.options("--drop"); // Node added a `--loader` flag (that's kinda like `--register`). It's // completely different from ours. const loader_tuple = if (cmd != .RunAsNodeCommand) try LoaderColonList.resolve(allocator, args.options("--loader")) else .{ .keys = &[_]u8{}, .values = &[_]Api.Loader{} }; if (loader_tuple.keys.len > 0) { opts.loaders = .{ .extensions = loader_tuple.keys, .loaders = loader_tuple.values, }; } opts.tsconfig_override = if (args.option("--tsconfig-override")) |ts| (Arguments.readFile(allocator, cwd, ts) catch |err| fileReadError(err, Output.errorStream(), ts, "tsconfig.json")) else null; opts.main_fields = args.options("--main-fields"); // we never actually supported inject. // opts.inject = args.options("--inject"); opts.env_files = args.options("--env-file"); opts.extension_order = args.options("--extension-order"); ctx.passthrough = args.remaining(); if (cmd == .AutoCommand or cmd == .RunCommand or cmd == .BuildCommand or cmd == .TestCommand) { if (args.options("--conditions").len > 0) { opts.conditions = args.options("--conditions"); } } // runtime commands if (cmd == .AutoCommand or cmd == .RunCommand or cmd == .TestCommand or cmd == .RunAsNodeCommand) { const preloads = args.options("--preload"); if (args.flag("--hot")) { ctx.debug.hot_reload = .hot; if (args.flag("--no-clear-screen")) { bun.DotEnv.Loader.has_no_clear_screen_cli_flag = true; } } else if (args.flag("--watch")) { ctx.debug.hot_reload = .watch; // Windows applies this to the watcher child process. // The parent process is unable to re-launch itself if (!bun.Environment.isWindows) bun.auto_reload_on_crash = true; if (args.flag("--no-clear-screen")) { bun.DotEnv.Loader.has_no_clear_screen_cli_flag = true; } } if (args.option("--origin")) |origin| { opts.origin = origin; } if (args.option("--port")) |port_str| { if (comptime cmd == .RunAsNodeCommand) { // TODO: prevent `node --port