diff --git a/cmake/sources/ZigSources.txt b/cmake/sources/ZigSources.txt index 96b823856e..1696f9b333 100644 --- a/cmake/sources/ZigSources.txt +++ b/cmake/sources/ZigSources.txt @@ -298,6 +298,7 @@ src/ci_info.zig src/cli.zig src/cli/add_command.zig src/cli/add_completions.zig +src/cli/Arguments.zig src/cli/audit_command.zig src/cli/build_command.zig src/cli/bunx_command.zig diff --git a/docs/cli/info.md b/docs/cli/info.md new file mode 100644 index 0000000000..d1fb1801f8 --- /dev/null +++ b/docs/cli/info.md @@ -0,0 +1,65 @@ +`bun info` displays package metadata from the npm registry. + +## Usage + +```bash +$ bun info react +``` + +This will display information about the `react` package, including its latest version, description, homepage, dependencies, and more. + +## Viewing specific versions + +To view information about a specific version: + +```bash +$ bun info react@18.0.0 +``` + +## Viewing specific properties + +You can also query specific properties from the package metadata: + +```bash +$ bun info react version +$ bun info react dependencies +$ bun info react repository.url +``` + +## JSON output + +To get the output in JSON format, use the `--json` flag: + +```bash +$ bun info react --json +``` + +## Alias + +`bun pm view` is an alias for `bun info`: + +```bash +$ bun pm view react # equivalent to: bun info react +``` + +## Examples + +```bash +# View basic package information +$ bun info is-number + +# View a specific version +$ bun info is-number@7.0.0 + +# View all available versions +$ bun info is-number versions + +# View package dependencies +$ bun info express dependencies + +# View package homepage +$ bun info lodash homepage + +# Get JSON output +$ bun info react --json +``` diff --git a/src/cli.zig b/src/cli.zig index 25f16fb3ea..f95921e6e8 100644 --- a/src/cli.zig +++ b/src/cli.zig @@ -5,26 +5,20 @@ const Global = bun.Global; const Environment = bun.Environment; const strings = bun.strings; const default_allocator = bun.default_allocator; -const FeatureFlags = bun.FeatureFlags; const std = @import("std"); const logger = bun.logger; const options = @import("options.zig"); -const js_ast = bun.JSAst; 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 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 FilterRun = @import("./cli/filter_run.zig"); @@ -34,11 +28,6 @@ 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; @@ -68,8 +57,8 @@ pub const Cli = struct { }; pub const debug_flags = if (Environment.show_crash_trace) struct { - var resolve_breakpoints: []const []const u8 = &.{}; - var print_breakpoints: []const []const u8 = &.{}; + pub var resolve_breakpoints: []const []const u8 = &.{}; + pub var print_breakpoints: []const []const u8 = &.{}; pub fn hasResolveBreakpoint(str: []const u8) bool { for (resolve_breakpoints) |bp| { @@ -96,7 +85,7 @@ pub const debug_flags = if (Environment.show_crash_trace) struct { 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 { +pub fn invalidTarget(diag: *clap.Diagnostic, _target: []const u8) noreturn { @branchHint(.cold); diag.name.long = "target"; diag.arg = _target; @@ -130,1170 +119,10 @@ pub const PackCommand = @import("./cli/pack_command.zig").PackCommand; pub const AuditCommand = @import("./cli/audit_command.zig").AuditCommand; 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(); - } +const PackageManager = Install.PackageManager; +const PmViewCommand = @import("./cli/pm_view_command.zig"); - 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.show_crash_trace) 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("--preserve-symlinks Preserve symlinks when resolving files") catch unreachable, - clap.parseParam("--preserve-symlinks-main Preserve symlinks when resolving the main entry point") 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("--require ... Alias of --preload, for Node.js compatibility") 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, - clap.parseParam("--redis-preconnect Preconnect to $REDIS_URL at startup") catch unreachable, - clap.parseParam("--no-addons Throw an error if process.dlopen is called, and disable export condition \"node-addons\"") catch unreachable, - clap.parseParam("--unhandled-rejections One of \"strict\", \"throw\", \"warn\", \"none\", or \"warn-with-error-code\"") 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.stdFile(), - .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"); - - if (args.flag("--preserve-symlinks")) { - opts.preserve_symlinks = true; - } - if (args.flag("--preserve-symlinks-main")) { - ctx.runtime_options.preserve_symlinks_main = true; - } - - 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) { - var preloads = args.options("--preload"); - if (preloads.len == 0) { - if (bun.getenvZ("BUN_INSPECT_PRELOAD")) |preload| { - preloads = bun.default_allocator.dupe([]const u8, &.{preload}) catch unreachable; - } - } - const preloads2 = args.options("--require"); - - 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.flag("--redis-preconnect")) { - ctx.runtime_options.redis_preconnect = true; - } - - if (args.flag("--no-addons")) { - // used for disabling process.dlopen and - // for disabling export condition "node-addons" - opts.allow_addons = false; - } - - if (args.option("--unhandled-rejections")) |unhandled_rejections| { - const resolved = Api.UnhandledRejections.map.get(unhandled_rejections) orelse { - Output.errGeneric("Invalid value for --unhandled-rejections: \"{s}\". Must be one of \"strict\", \"throw\", \"warn\", \"none\", \"warn-with-error-code\"\n", .{unhandled_rejections}); - Global.exit(1); - }; - opts.unhandled_rejections = resolved; - } - - if (args.option("--port")) |port_str| { - if (comptime cmd == .RunAsNodeCommand) { - // TODO: prevent `node --port