mirror of
https://github.com/oven-sh/bun
synced 2026-02-09 18:38:55 +00:00
* alright now just gotta try running it
* fix a gajillion compiler errors
* even more code
* okay i fixed more errors
* wip
* Update launch.json
* Update string_builder.zig
* `fast_debug_build_mode` makes debug build 2x faster
* Update bundle_v2.zig
* more code!
* It bundles!
* Rename `Bun.Transpiler` to `Bun.Bundler`
* `import()` expressions almost work
* wip attempt to get import() expr to work
* Bundle namespace imports
* Attempt to fix the issue with import() unsuccessfully
* consider current working directory when resolving relative paths (#2313)
* consider current working directory when resolving relative paths
fixes #2298
* comment test
---------
Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
* support `expect().toThrow(/pattern/)` (#2314)
- fix time-zone-dependent test failure
* fix missing `Blob` error messages on Linux (#2315)
* fix & clean up tests (#2318)
- skip flaky tests when running as `root`
- use `expect().toThrow()`
- clean up temporary files after tests
* feat(tty): add some `tty.WriteStream` methods to `process.{stdout, stderr}` (#2320)
* feat(stdio): add some `tty.WriteStream` methods
* chore(builtins): add process builtin gen'd code
* Fix docker install command
* `bun test` on macOS in GitHub Actions (#2322)
* Fixes #2323
* throw invalid parameter errors in `crypto.scryptSync` (#2331)
* throw invalid parameter errors
* remove comptime, add empty buffer function
* remove error_name comptime
* Add reference documentation for bun:test (#2327)
* Reorganize tests (#2332)
* Fix html-rewriter.test.js
* fix the wrong thing being incremented in hmr example (#2334)
* Add more test harness
* Improve Benchmarking page, small fixes (#2339)
* Improve benchmarking page
* WIP
* Add typescript instructions to hot
* Document preload in Plugins. Fix loader in plugin types.
* Fix typo
* Fix links
* run prettier
* Document openInEditor
* improve `Buffer` compatibility with Node.js (#2341)
* improve `Buffer` compatibility with Node.js
* use `memmove()`
allow `encoding` to be `undefined`
* run `bun test` after macOS builds (#2343)
* "binary" is an alias of "latin1"
Fixes https://github.com/oven-sh/bun/issues/2110
* More spec compliant `Blob.prototype.type` (#2340)
* Make `Blob.prototype. type` more spec compliant
* Add a few more checks for isNumber()
* Fix `make headers`
* Safer JSValue.isString()
* More tests for blob.slice
* Make `Blob.prototype.type` more spec compliant
* Add isASCII check
* Fix types
* Fix failing type test
* Update blob.zig
* Update blob.zig
* Fix .eql check on empty values
---------
Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
* Fix bug in test runner
* Support `import()` expressions
* Implement `require()`
* clean up bit_set.zig slightly
* Move some things around
* misc cleanup
* Cleanup some things
* Fix a lot of stuff
* Fix `module.exports.fn = fn;` in ESM entry point
* Fix crash due when printing file
* Fix issue with class names
* Fix issue with `export default identifier`
* Update js_parser.zig
* optimization: inline single-property object acceses and arrays
* Fix undefined memory in renamed symbols list
* Handle call target
* wip
* Inline it
* Fix undefined memory issue when reclaiming blocks in ast
* Halt linking on any parse errors
* alias
* Rename `enable_bundling` to `enable_legacy_bundling`
* Workaround anonymous struct literal zig bug
* Use slower approach (without bitset) because it doesn't break after 8 symbols
* Fix incorrectly-renaming statically defined symbols
* Handle more edgecases in our bit_set fork
* Reduce number of allocations for `define`
* Do not rename unbound symbols
* Clean up dot defines a little more
* Make the generated names prettier
* Workaround runtime symbol missing issue
* Fail the build on errors
* Support export * from
* Support `--outfile`
* partially fix renaming
* fanicer symbol renaming impl
* misc, extremely revertible cleanup
* Fix up some bugs with symbol renaming
* formatting
* Update launch.json
* Parse `__PURE__` comments
* clean up simd code for pure comments
* changes to merge
* workaround runtime issue
* Fix issue with `export * as` not propagating correctly
* Make all top-level declarations `var` when bundling
* Fix missing prefix
* Fix assigning to stack copy
* Fix missing runtime symbol
* Fix bug with namespace exports
* Dramatically reduce allocations
* Update launch.json
* Add missing flags
* Update js_parser.zig
* small cleanup
* Make the export name better
* Fix unnecessary `var foo = foo`
* Implement CommonJS -> ESM conversion
* Implement module redirects
* Port esbuild bundler tests for new bundler (#2380)
* started porting esbuild tests
* clean up test names and api before moving on
* port tests using a program i wrote
* replace todo generated comment
* fix generated tests not including some files
* work on tests
* [github web editor] add define, external, inject, minifySyntax, minifyWhitespace options.
* get most of the todo comments out of the way, but expectBundled does not handle most of the cases
* continue working on esbuild tests
* use test.skip for unsupported tests
* Fixups for test runner
* Hoist imports & exports
* Fix test
* Hoist classes
* bundler test refining, 51/835
* Fix runtime require
* bundler test refining, 81/835
* bundler test refining, 93/835
* Make the test work in any timezone
* feat(expect): update toBeInstanceOf (#2396)
* feat: update instanceof binding
* fix: according to PR comments
* Rename `expectObjectTypeCount` to `expectMaxObjectTypeCount`
* Fix socket tests with connection errors (#2403)
* release pending activity with connection error handler
* unref poll_ref
* remove trailing comma
* Organize Dockerfiles for official status
* Remove test Dockerfile
* Remove old Docker workflow
* Feat(test): add toMatch (#2404)
* Fix various fetch/response/request tests (#2416)
* fix most fetch tests, skip a few
* fastGet, toValueGC, and invalid init
* bigint unreachable, range error, log process as process
* remove extra fetch_headers
* remove js_type parameter, check isObject()
* throw invalid mime type error, use enum literal
* switch back to promise rejection
* RangeError pascal case
* Fix several bugs (#2418)
* utf16 codepoint with replacement character
* Fix test failure with `TextEncoder("ascii')`
* Add missing type
* Fix Response.prototype.bodyUsed and Request.prototype.bodyUsed
* Fix bug with scrypt error not clearing
* Update server.zig
* oopsie
* 💅
* docs: Use correct url in the 'Issues' link in README header (#2420)
* Fix crash when rendering error page and the server or network is slow
* [fetch] Make the default body value `null` when unspecified
This is better aligned with the fetch spec
* Make node-net tests less flaky
* [node:net] Fix issue with `listen` callback firing before it's listening
* Always clear timers in node test harness
* Fix out of bounds access
Repro'd in Buffer tests
* Update UWS
cc @cirospaciari
* Make this test more thorough
* Hanging abort test
* 0 length body is a null stream
* Several bug fixes (#2427)
* Fix test
* Fix segfault when unexpected type is passed in `expect().toThrow`
* Fix issues with request constructor
* Don't bother cloning headers when its empty
* woops
* more tests
* fix incorrect test
* Make the fetch error messages better
* Update response.zig
* Fix test that failed on macOS
* Fix test
* Remove extra hash table lookups
* Support running dummy registry directly
cc @alexlamsl
* Update test
* Update test
* fixup
* Workaround crash in test runner
* Fixup test
* Fixup test
* Update os.test.js
---------
Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
* Remove usages of port numbers in tests
* Set -O2 and -fno-rtti
* Remove -g
* Prevent undefined memory access
* [bun test] Implement `--rerun-each` flag to run each test N times
* Reduce number of module scopes created
* add some extra abort checks into streams (#2430)
* add some checks to avoid UAF
* avoid multiple calls to finalize if endFromJS is called more than once
* fix no-op comment
* mark as requested_end on abort
* remove requested_end from abort
* remove unnecessary check (#2432)
* Fix bug with scoped aliased dependencies in bun install on macOS
* remove `addLog`, remove `--prominent-compile-errors`
* Finish the upgrade
* Optional chaining flag
* Implement same_target_becomes_destructuring optimization
* bundler test refining, 109/835
* Reset bindings
* Support multiple entry points
* Implement `--entry-names` flag
* Use a tempdir with a better name
* prettier
* Log file name
* Update js_parser.zig
* Mark all bun builtins as external
* Make resolve errors actually errors
* Update bundler_default.test.ts
* Fix `await import(foo)`
* WIP react server components
* Do more stuff at runtime
* ✂️
* Support automatic JSX imports
* Use a module cache for now
* Update tsconfig.base.json
* Fix ThisOutsideFunctionNotRenamed
* woopsie
* moar cpu
* clamp it
* fixup
* Add a bunch of assertions
* Bun uses automatic runtime by default
* Parse Import Attributes
* Add a note about Valgrind
* Update developing.md
* Fix up code splitting for React Server Components
* Implement client component manifest
* Fix crash with --react-server-components and no client components
* Backport 4d31e3c917
* Update launch.json
* Fix for latest zig
* Workaround bug with ?[]const string
Occasionally saw alignment errors in this code
Workaround https://github.com/ziglang/zig/issues/15085
related: https://github.com/ziglang/zig/pull/15089
* switch to regular slice
* Avoid initializing named_imports and named_exports as undefined
* Reduce usages of `undefined`
* Add more assertions
* --watch wip
* Update javascript.zig
* Possibly fix the race condition
* Faster `do`
* bump allocator
* Reduce the size of `Symbol` slightly
* Alphabetically sort runtime import symbols, for determinism
* Prepare for code splitting
* handle overlapping stdout
* pure
* clean up some things
* Fix bug with `$$typeof`
* Address CommonJS -> ESM hoisting bug
* Support `"use server"` in manifest
* Implement `"use server"`
* Fix importing bun builtins when bundling
* Make `commonjs_to_esm` a feature flag, fix some splitting bugs
* ✂️
* fixme remove this
* Fix crash in longestCommonPath
* Chunking! Just need to do import paths now.
* Import paths work...now trying to figure out how to make runtime symbols work
* add workaround
* Replace `bun bun` with `bun build`
* Fix crash with dual package hazard
* Fix many CommonJS <> ESM interop bugs
* Support package.json `"sideEffects"`
also skip loading unnecessary package.json data in `bun run`
* add a not good --watch implementation
* bundler test refining, 140/831
* remove accidentally committed file
* do not return status code 1 on successful bundles
* bundler test refining, 159/830
* pass exit code to exitOrWatch
* clean up help menu
-remove two spaces to line up bun build
-moved all <r> tags to the end of the text they are colorizing
-moved other colors to the start of the text they colorize
-removed unneeded <r> tags, keeping only one at the start of the block
* importstar is fully ported
* wip
* you can run code in this branch now
* Disable this transform
* organize and document bundler tests
* Fix double import
* Fix sloppy mode function declarations
* Disable our CommonJS transform for now
* add `assertNotPresent` to make splitting cases easier
* Bump!
* Update bun.d.ts
* use import.meta.require in runtime code
* Disable this again
* Fix dirname
* Fix ESM -> CJS wrapper
* 💅
---------
Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
Co-authored-by: Alex Lam S.L <alexlamsl@gmail.com>
Co-authored-by: Derrick Farris <mr.dcfarris@gmail.com>
Co-authored-by: Ashcon Partovi <ashcon@partovi.net>
Co-authored-by: Dylan Conway <35280289+dylan-conway@users.noreply.github.com>
Co-authored-by: pfg <pfg@pfg.pw>
Co-authored-by: Colin McDonnell <colinmcd94@gmail.com>
Co-authored-by: dave caruso <me@paperdave.net>
Co-authored-by: zhiyuan <32867472+zhiyuang@users.noreply.github.com>
Co-authored-by: Dylan Conway <dylan.conway567@gmail.com>
Co-authored-by: Kamil Ogórek <kamil.ogorek@gmail.com>
Co-authored-by: Ciro Spaciari <ciro.spaciari@gmail.com>
1567 lines
67 KiB
Zig
1567 lines
67 KiB
Zig
const bun = @import("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 constStrToU8 = bun.constStrToU8;
|
|
const FeatureFlags = bun.FeatureFlags;
|
|
const C = bun.C;
|
|
const root = @import("root");
|
|
const std = @import("std");
|
|
const lex = bun.js_lexer;
|
|
const logger = @import("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 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 = @import("bun").clap;
|
|
const BunJS = @import("./bun_js.zig");
|
|
const Install = @import("./install/install.zig");
|
|
const bundler = bun.bundler;
|
|
const DotEnv = @import("./env_loader.zig");
|
|
|
|
const fs = @import("fs.zig");
|
|
const Router = @import("./router.zig");
|
|
|
|
const NodeModuleBundle = @import("./node_module_bundle.zig").NodeModuleBundle;
|
|
|
|
const MacroMap = @import("./resolver/package_json.zig").MacroMap;
|
|
const TestCommand = @import("./cli/test_command.zig").TestCommand;
|
|
const Reporter = @import("./report.zig");
|
|
pub var start_time: i128 = undefined;
|
|
const Bunfig = @import("./bunfig.zig").Bunfig;
|
|
|
|
pub const Cli = struct {
|
|
var wait_group: sync.WaitGroup = undefined;
|
|
var log_: logger.Log = undefined;
|
|
pub fn startTransform(_: std.mem.Allocator, _: Api.TransformOptions, _: *logger.Log) anyerror!void {}
|
|
pub fn start(allocator: std.mem.Allocator, _: anytype, _: anytype, comptime MainPanicHandler: type) void {
|
|
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| {
|
|
switch (err) {
|
|
error.MissingEntryPoint => {
|
|
Output.prettyErrorln("<r><red>MissingEntryPoint<r> what do you want to bundle?\n\n<d>Example:\n\n<r> <b><cyan>bun bun --use next<r>\n\n <b><cyan>bun bun ./src/index.ts ./src/file2.ts<r>\n", .{});
|
|
Global.exit(1);
|
|
},
|
|
else => {
|
|
// Always dump the logs
|
|
if (Output.enable_ansi_colors_stderr) {
|
|
log.printForLogLevelWithEnableAnsiColors(Output.errorWriter(), true) catch {};
|
|
} else {
|
|
log.printForLogLevelWithEnableAnsiColors(Output.errorWriter(), false) catch {};
|
|
}
|
|
|
|
Reporter.globalError(err);
|
|
},
|
|
}
|
|
};
|
|
}
|
|
|
|
pub var cmd: ?Command.Tag = null;
|
|
};
|
|
|
|
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 invalidPlatform(diag: *clap.Diagnostic, _platform: []const u8) noreturn {
|
|
@setCold(true);
|
|
diag.name.long = "--platform";
|
|
diag.arg = _platform;
|
|
diag.report(Output.errorWriter(), error.InvalidPlatform) catch {};
|
|
std.process.exit(1);
|
|
}
|
|
pub const Arguments = struct {
|
|
pub fn loader_resolver(in: string) !Api.Loader {
|
|
const Matcher = strings.ExactSizeMatcher(4);
|
|
switch (Matcher.match(in)) {
|
|
Matcher.case("jsx") => return Api.Loader.jsx,
|
|
Matcher.case("js") => return Api.Loader.js,
|
|
Matcher.case("ts") => return Api.Loader.ts,
|
|
Matcher.case("tsx") => return Api.Loader.tsx,
|
|
Matcher.case("css") => return Api.Loader.css,
|
|
Matcher.case("file") => return Api.Loader.file,
|
|
Matcher.case("json") => return Api.Loader.json,
|
|
else => {
|
|
return error.InvalidLoader;
|
|
},
|
|
}
|
|
}
|
|
|
|
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 std.fs.openFileAbsolute(outpath, std.fs.File.OpenFlags{ .mode = .read_only });
|
|
defer file.close();
|
|
const stats = try file.stat();
|
|
return try file.readToEndAlloc(allocator, stats.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 public_params = [_]ParamType{
|
|
clap.parseParam("--use <STR> Choose a framework, e.g. \"--use next\". It checks first for a package named \"bun-framework-packagename\" and then \"packagename\".") catch unreachable,
|
|
clap.parseParam("-b, --bun Force a script or package to use Bun.js instead of Node.js (via symlinking node)") catch unreachable,
|
|
clap.parseParam("--bunfile <STR> Use a .bun file (default: node_modules.bun)") catch unreachable,
|
|
clap.parseParam("--server-bunfile <STR> Use a .server.bun file (default: node_modules.server.bun)") catch unreachable,
|
|
clap.parseParam("--cwd <STR> Absolute path to resolve files & entry points from. This just changes the process' cwd.") catch unreachable,
|
|
clap.parseParam("-c, --config <PATH>? Config file to load bun from (e.g. -c bunfig.toml") catch unreachable,
|
|
clap.parseParam("--disable-react-fast-refresh Disable React Fast Refresh") catch unreachable,
|
|
clap.parseParam("--disable-hmr Disable Hot Module Reloading (disables fast refresh too) in bun dev") catch unreachable,
|
|
clap.parseParam("--extension-order <STR>... defaults to: .tsx,.ts,.jsx,.js,.json ") catch unreachable,
|
|
clap.parseParam("--jsx-factory <STR> Changes the function called when compiling JSX elements using the classic JSX runtime") catch unreachable,
|
|
clap.parseParam("--jsx-fragment <STR> Changes the function called when compiling JSX fragments") catch unreachable,
|
|
clap.parseParam("--jsx-import-source <STR> Declares the module specifier to be used for importing the jsx and jsxs factory functions. Default: \"react\"") catch unreachable,
|
|
clap.parseParam("--jsx-production Use jsx instead of jsxDEV (default) for the automatic runtime") catch unreachable,
|
|
clap.parseParam("--jsx-runtime <STR> \"automatic\" (default) or \"classic\"") catch unreachable,
|
|
clap.parseParam("-r, --preload <STR>... Import a module before other modules are loaded") catch unreachable,
|
|
clap.parseParam("--main-fields <STR>... Main fields to lookup in package.json. Defaults to --platform dependent") catch unreachable,
|
|
clap.parseParam("--no-summary Don't print a summary (when generating .bun") catch unreachable,
|
|
clap.parseParam("-v, --version Print version and exit") catch unreachable,
|
|
clap.parseParam("--platform <STR> \"bun\" or \"browser\" or \"node\", used when building or bundling") catch unreachable,
|
|
// clap.parseParam("--production [not implemented] generate production code") catch unreachable,
|
|
clap.parseParam("--public-dir <STR> Top-level directory for .html files, fonts or anything external. Defaults to \"<cwd>/public\", to match create-react-app and Next.js") catch unreachable,
|
|
clap.parseParam("--tsconfig-override <STR> Load tsconfig from path instead of cwd/tsconfig.json") catch unreachable,
|
|
clap.parseParam("-d, --define <STR>... Substitute K:V while parsing, e.g. --define process.env.NODE_ENV:\"development\". Values are parsed as JSON.") catch unreachable,
|
|
clap.parseParam("-e, --external <STR>... Exclude module from transpilation (can use * wildcards). ex: -e react") catch unreachable,
|
|
clap.parseParam("-h, --help Display this help and exit. ") catch unreachable,
|
|
clap.parseParam("-l, --loader <STR>... Parse files with .ext:loader, e.g. --loader .js:jsx. Valid loaders: jsx, js, json, tsx, ts, css") catch unreachable,
|
|
clap.parseParam("-u, --origin <STR> Rewrite import URLs to start with --origin. Default: \"\"") catch unreachable,
|
|
clap.parseParam("-p, --port <STR> Port to serve bun's dev server on. Default: \"3000\"") catch unreachable,
|
|
clap.parseParam("--hot Enable auto reload in bun's JavaScript runtime") catch unreachable,
|
|
clap.parseParam("--watch Automatically restart bun's JavaScript runtime on file change") catch unreachable,
|
|
clap.parseParam("--no-install Disable auto install in bun's JavaScript runtime") catch unreachable,
|
|
clap.parseParam("-i Automatically install dependencies and use global cache in bun's runtime, equivalent to --install=fallback") catch unreachable,
|
|
clap.parseParam("--install <STR> Install dependencies automatically when no node_modules are present, default: \"auto\". \"force\" to ignore node_modules, fallback to install any missing") catch unreachable,
|
|
clap.parseParam("--prefer-offline Skip staleness checks for packages in bun's JavaScript runtime and resolve from disk") catch unreachable,
|
|
clap.parseParam("--prefer-latest Use the latest matching versions of packages in bun's JavaScript runtime, always checking npm") catch unreachable,
|
|
clap.parseParam("--silent Don't repeat the command for bun run") catch unreachable,
|
|
clap.parseParam("<POS>... ") catch unreachable,
|
|
};
|
|
|
|
const debug_params = [_]ParamType{
|
|
clap.parseParam("--dump-environment-variables Dump environment variables from .env and process as JSON and quit. Useful for debugging") catch unreachable,
|
|
clap.parseParam("--dump-limits Dump system limits. Useful for debugging") catch unreachable,
|
|
clap.parseParam("--disable-bun.js Disable bun.js from loading in the dev server") catch unreachable,
|
|
};
|
|
|
|
pub const params = public_params ++ debug_params;
|
|
|
|
const build_only_params = [_]ParamType{
|
|
clap.parseParam("--sourcemap <STR>? Build with sourcemaps - 'inline', 'external', or 'none'") catch unreachable,
|
|
clap.parseParam("--outdir <STR> Default to \"dist\" if multiple files") catch unreachable,
|
|
clap.parseParam("--entry-names <STR> Pattern to use for entry point filenames") catch unreachable,
|
|
clap.parseParam("--outfile <STR> Write to a file") catch unreachable,
|
|
clap.parseParam("--server-components Enable React Server Components (experimental)") catch unreachable,
|
|
clap.parseParam("--splitting Split up code!") catch unreachable,
|
|
};
|
|
|
|
// TODO: update test completions
|
|
const test_only_params = [_]ParamType{
|
|
clap.parseParam("--update-snapshots Update snapshot files") catch unreachable,
|
|
clap.parseParam("--rerun-each <NUMBER> Re-run each test file <NUMBER> times, helps catch certain bugs") catch unreachable,
|
|
};
|
|
|
|
const build_params_public = public_params ++ build_only_params;
|
|
pub const build_params = build_params_public ++ debug_params;
|
|
pub const test_params = params ++ test_only_params;
|
|
|
|
fn printVersionAndExit() noreturn {
|
|
@setCold(true);
|
|
Output.writer().writeAll(Global.package_json_version ++ "\n") catch {};
|
|
Global.exit(0);
|
|
}
|
|
|
|
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 = std.fs.File{
|
|
.handle = std.os.openZ(config_path, std.os.O.RDONLY, 0) catch |err| {
|
|
if (auto_loaded) return;
|
|
Output.prettyErrorln("<r><red>error<r>: {s} opening config \"{s}\"", .{
|
|
@errorName(err),
|
|
config_path,
|
|
});
|
|
Global.exit(1);
|
|
},
|
|
};
|
|
defer config_file.close();
|
|
var contents = config_file.readToEndAlloc(allocator, std.math.maxInt(usize)) catch |err| {
|
|
if (auto_loaded) return;
|
|
Output.prettyErrorln("<r><red>error<r>: {s} reading config \"{s}\"", .{
|
|
@errorName(err),
|
|
config_path,
|
|
});
|
|
Global.exit(1);
|
|
};
|
|
|
|
js_ast.Stmt.Data.Store.create(allocator);
|
|
js_ast.Expr.Data.Store.create(allocator);
|
|
defer {
|
|
js_ast.Stmt.Data.Store.reset();
|
|
js_ast.Expr.Data.Store.reset();
|
|
}
|
|
var 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.MAX_PATH_BYTES]u8) ?[:0]const u8 {
|
|
if (bun.getenvZ("XDG_CONFIG_HOME") orelse bun.getenvZ("HOME")) |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) !void {
|
|
var config_buf: [bun.MAX_PATH_BYTES]u8 = undefined;
|
|
if (comptime cmd.readGlobalConfig()) {
|
|
if (!ctx.has_loaded_global_config) {
|
|
ctx.has_loaded_global_config = true;
|
|
|
|
if (getHomeConfigPath(&config_buf)) |path| {
|
|
try loadConfigPath(allocator, true, path, ctx, comptime cmd);
|
|
}
|
|
}
|
|
}
|
|
|
|
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, config_path_.ptr, config_path_.len);
|
|
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.MAX_PATH_BYTES]u8 = undefined;
|
|
var cwd = std.os.getcwd(&secondbuf) catch return;
|
|
ctx.args.absolute_working_dir = try allocator.dupe(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];
|
|
}
|
|
|
|
try loadConfigPath(allocator, auto_loaded, config_path, ctx, comptime cmd);
|
|
}
|
|
|
|
pub fn loadConfigWithCmdArgs(
|
|
comptime cmd: Command.Tag,
|
|
allocator: std.mem.Allocator,
|
|
args: clap.Args(clap.Help, cmd.params()),
|
|
ctx: *Command.Context,
|
|
) !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_use = comptime cmd.params();
|
|
|
|
var args = clap.parse(clap.Help, params_to_use, .{
|
|
.diagnostic = &diag,
|
|
.allocator = allocator,
|
|
.stop_after_positional_at = if (cmd == .RunCommand) 2 else if (cmd == .AutoCommand)
|
|
1
|
|
else
|
|
0,
|
|
}) catch |err| {
|
|
// Report useful error and exit
|
|
clap.help(Output.errorWriter(), params_to_use) catch {};
|
|
Output.errorWriter().writeAll("\n") catch {};
|
|
diag.report(Output.errorWriter(), err) catch {};
|
|
Global.exit(1);
|
|
};
|
|
|
|
if (args.flag("--version")) {
|
|
printVersionAndExit();
|
|
}
|
|
|
|
var cwd: []u8 = undefined;
|
|
if (args.option("--cwd")) |cwd_| {
|
|
cwd = brk: {
|
|
var outbuf: [bun.MAX_PATH_BYTES]u8 = undefined;
|
|
const out = std.os.realpath(cwd_, &outbuf) catch |err| {
|
|
Output.prettyErrorln("error resolving --cwd: {s}", .{@errorName(err)});
|
|
Global.exit(1);
|
|
};
|
|
break :brk try allocator.dupe(u8, out);
|
|
};
|
|
} else {
|
|
cwd = try std.process.getCwdAlloc(allocator);
|
|
}
|
|
|
|
if (cmd == .TestCommand) {
|
|
ctx.test_options.update_snapshots = args.flag("--update-snapshots");
|
|
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("--rerun-each expects a number: {s}", .{@errorName(e)});
|
|
Global.exit(1);
|
|
};
|
|
}
|
|
}
|
|
}
|
|
|
|
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;
|
|
|
|
var 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,
|
|
};
|
|
}
|
|
|
|
var loader_tuple = try LoaderColonList.resolve(allocator, args.options("--loader"));
|
|
|
|
if (loader_tuple.keys.len > 0) {
|
|
opts.loaders = .{
|
|
.extensions = loader_tuple.keys,
|
|
.loaders = loader_tuple.values,
|
|
};
|
|
}
|
|
|
|
if (args.options("--external").len > 0) {
|
|
var externals = try allocator.alloc([]u8, args.options("--external").len);
|
|
for (args.options("--external"), 0..) |external, i| {
|
|
externals[i] = constStrToU8(external);
|
|
}
|
|
opts.external = externals;
|
|
}
|
|
|
|
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;
|
|
|
|
if (args.option("--origin")) |origin| {
|
|
opts.origin = origin;
|
|
}
|
|
|
|
if (args.option("--port")) |port_str| {
|
|
opts.port = std.fmt.parseInt(u16, port_str, 10) catch return error.InvalidPort;
|
|
}
|
|
opts.serve = cmd == .DevCommand;
|
|
opts.main_fields = args.options("--main-fields");
|
|
// we never actually supported inject.
|
|
// opts.inject = args.options("--inject");
|
|
opts.extension_order = args.options("--extension-order");
|
|
if (args.flag("--hot")) {
|
|
ctx.debug.hot_reload = .hot;
|
|
} else if (args.flag("--watch")) {
|
|
ctx.debug.hot_reload = .watch;
|
|
bun.auto_reload_on_crash = true;
|
|
}
|
|
ctx.passthrough = args.remaining();
|
|
|
|
opts.no_summary = args.flag("--no-summary");
|
|
opts.disable_hmr = args.flag("--disable-hmr");
|
|
|
|
if (cmd != .DevCommand) {
|
|
const preloads = args.options("--preload");
|
|
if (ctx.preloads.len > 0 and preloads.len > 0) {
|
|
var all = std.ArrayList(string).initCapacity(ctx.allocator, ctx.preloads.len + preloads.len) catch unreachable;
|
|
all.appendSliceAssumeCapacity(ctx.preloads);
|
|
all.appendSliceAssumeCapacity(preloads);
|
|
ctx.preloads = all.items;
|
|
} else if (preloads.len > 0) {
|
|
ctx.preloads = preloads;
|
|
}
|
|
}
|
|
|
|
ctx.debug.silent = args.flag("--silent");
|
|
if (opts.port != null and opts.origin == null) {
|
|
opts.origin = try std.fmt.allocPrint(allocator, "http://localhost:{d}/", .{opts.port.?});
|
|
}
|
|
|
|
const print_help = args.flag("--help");
|
|
if (print_help) {
|
|
const params_len = if (cmd == .BuildCommand) build_params_public.len else public_params.len;
|
|
clap.help(Output.writer(), params_to_use[0..params_len]) catch {};
|
|
Output.prettyln("\n-------\n\n", .{});
|
|
Output.flush();
|
|
HelpCommand.printWithReason(.explicit);
|
|
Global.exit(0);
|
|
}
|
|
|
|
ctx.debug.dump_environment_variables = args.flag("--dump-environment-variables");
|
|
ctx.debug.fallback_only = ctx.debug.fallback_only or args.flag("--disable-bun.js");
|
|
ctx.debug.dump_limits = args.flag("--dump-limits");
|
|
|
|
ctx.debug.offline_mode_setting = if (args.flag("--prefer-offline"))
|
|
Bunfig.OfflineMode.offline
|
|
else if (args.flag("--prefer-latest"))
|
|
Bunfig.OfflineMode.latest
|
|
else
|
|
Bunfig.OfflineMode.online;
|
|
|
|
if (args.flag("--no-install")) {
|
|
ctx.debug.global_cache = .disable;
|
|
} else if (args.flag("-i")) {
|
|
ctx.debug.global_cache = .fallback;
|
|
} else if (args.option("--install")) |enum_value| {
|
|
// -i=auto --install=force, --install=disable
|
|
if (options.GlobalCache.Map.get(enum_value)) |result| {
|
|
ctx.debug.global_cache = result;
|
|
// -i, --install
|
|
} else if (enum_value.len == 0) {
|
|
ctx.debug.global_cache = options.GlobalCache.force;
|
|
} else {
|
|
Output.prettyErrorln("Invalid value for --install: \"{s}\". Must be either \"auto\", \"fallback\", \"force\", or \"disable\"\n", .{enum_value});
|
|
Global.exit(1);
|
|
}
|
|
}
|
|
|
|
// var output_dir = args.option("--outdir");
|
|
var output_dir: ?string = null;
|
|
const production = false;
|
|
var output_file: ?string = null;
|
|
|
|
if (cmd == .BuildCommand) {
|
|
if (args.option("--outdir")) |outdir| {
|
|
if (outdir.len > 0) {
|
|
ctx.bundler_options.outdir = outdir;
|
|
}
|
|
} else if (args.option("--outfile")) |outfile| {
|
|
if (outfile.len > 0) {
|
|
ctx.bundler_options.outfile = outfile;
|
|
}
|
|
}
|
|
|
|
if (args.flag("--splitting")) {
|
|
ctx.bundler_options.code_splitting = true;
|
|
}
|
|
|
|
if (args.option("--entry-names")) |entry_names| {
|
|
ctx.bundler_options.entry_names = entry_names;
|
|
}
|
|
|
|
if (comptime FeatureFlags.react_server_components) {
|
|
if (args.flag("--server-components")) {
|
|
ctx.bundler_options.react_server_components = true;
|
|
}
|
|
}
|
|
|
|
if (args.option("--sourcemap")) |setting| {
|
|
if (setting.len == 0 or strings.eqlComptime(setting, "inline")) {
|
|
opts.source_map = Api.SourceMapMode.inline_into_file;
|
|
} else if (strings.eqlComptime(setting, "none")) {
|
|
opts.source_map = Api.SourceMapMode._none;
|
|
} else if (strings.eqlComptime(setting, "external")) {
|
|
opts.source_map = Api.SourceMapMode.external;
|
|
} else {
|
|
Output.prettyErrorln("<r><red>error<r>: Invalid sourcemap setting: \"{s}\"", .{setting});
|
|
Global.crash();
|
|
}
|
|
}
|
|
}
|
|
|
|
if (opts.entry_points.len == 0) {
|
|
var entry_points = ctx.positionals;
|
|
|
|
switch (comptime cmd) {
|
|
.BuildCommand => {
|
|
if (entry_points.len > 0 and (strings.eqlComptime(
|
|
entry_points[0],
|
|
"build",
|
|
) or strings.eqlComptime(entry_points[0], "bun"))) {
|
|
entry_points = entry_points[1..];
|
|
}
|
|
},
|
|
.DevCommand => {
|
|
if (entry_points.len > 0 and (strings.eqlComptime(
|
|
entry_points[0],
|
|
"dev",
|
|
) or strings.eqlComptime(
|
|
entry_points[0],
|
|
"d",
|
|
))) {
|
|
entry_points = entry_points[1..];
|
|
}
|
|
},
|
|
.RunCommand => {
|
|
if (entry_points.len > 0 and (strings.eqlComptime(
|
|
entry_points[0],
|
|
"run",
|
|
) or strings.eqlComptime(
|
|
entry_points[0],
|
|
"r",
|
|
))) {
|
|
entry_points = entry_points[1..];
|
|
}
|
|
},
|
|
else => {},
|
|
}
|
|
|
|
opts.entry_points = entry_points;
|
|
}
|
|
|
|
var jsx_factory = args.option("--jsx-factory");
|
|
var jsx_fragment = args.option("--jsx-fragment");
|
|
var jsx_import_source = args.option("--jsx-import-source");
|
|
var jsx_runtime = args.option("--jsx-runtime");
|
|
var jsx_production = args.flag("--jsx-production");
|
|
const react_fast_refresh = switch (comptime cmd) {
|
|
.BuildCommand, .DevCommand => !(args.flag("--disable-react-fast-refresh") or jsx_production),
|
|
else => true,
|
|
};
|
|
|
|
if (comptime Command.Tag.cares_about_bun_file.get(cmd)) {
|
|
opts.node_modules_bundle_path = args.option("--bunfile") orelse opts.node_modules_bundle_path orelse brk: {
|
|
const node_modules_bundle_path_absolute = resolve_path.joinAbs(cwd, .auto, "node_modules.bun");
|
|
|
|
break :brk std.fs.realpathAlloc(allocator, node_modules_bundle_path_absolute) catch null;
|
|
};
|
|
|
|
opts.node_modules_bundle_path_server = args.option("--server-bunfile") orelse opts.node_modules_bundle_path_server orelse brk: {
|
|
const node_modules_bundle_path_absolute = resolve_path.joinAbs(cwd, .auto, "node_modules.server.bun");
|
|
|
|
break :brk std.fs.realpathAlloc(allocator, node_modules_bundle_path_absolute) catch null;
|
|
};
|
|
}
|
|
|
|
switch (comptime cmd) {
|
|
.AutoCommand,
|
|
.DevCommand,
|
|
.BuildCommand,
|
|
=> {
|
|
if (args.option("--public-dir")) |public_dir| {
|
|
if (public_dir.len > 0) {
|
|
opts.router = Api.RouteConfig{ .extensions = &.{}, .dir = &.{}, .static_dir = public_dir };
|
|
}
|
|
}
|
|
},
|
|
else => {},
|
|
}
|
|
|
|
// const ResolveMatcher = strings.ExactSizeMatcher(8);
|
|
|
|
opts.resolve = Api.ResolveMode.lazy;
|
|
|
|
switch (comptime cmd) {
|
|
.BuildCommand => {
|
|
// if (args.option("--resolve")) |_resolve| {
|
|
// switch (ResolveMatcher.match(_resolve)) {
|
|
// ResolveMatcher.case("disable") => {
|
|
// opts.resolve = Api.ResolveMode.disable;
|
|
// },
|
|
// ResolveMatcher.case("bundle") => {
|
|
// opts.resolve = Api.ResolveMode.bundle;
|
|
// },
|
|
// ResolveMatcher.case("dev") => {
|
|
// opts.resolve = Api.ResolveMode.dev;
|
|
// },
|
|
// ResolveMatcher.case("lazy") => {
|
|
// opts.resolve = Api.ResolveMode.lazy;
|
|
// },
|
|
// else => {
|
|
// diag.name.long = "--resolve";
|
|
// diag.arg = _resolve;
|
|
// try diag.report(Output.errorWriter(), error.InvalidResolveOption);
|
|
// std.process.exit(1);
|
|
// },
|
|
// }
|
|
// }
|
|
},
|
|
else => {},
|
|
}
|
|
|
|
const PlatformMatcher = strings.ExactSizeMatcher(8);
|
|
|
|
if (args.option("--platform")) |_platform| {
|
|
opts.platform = opts.platform orelse switch (PlatformMatcher.match(_platform)) {
|
|
PlatformMatcher.case("browser") => Api.Platform.browser,
|
|
PlatformMatcher.case("node") => Api.Platform.node,
|
|
PlatformMatcher.case("macro") => if (cmd == .BuildCommand) Api.Platform.bun_macro else Api.Platform.bun,
|
|
PlatformMatcher.case("bun") => Api.Platform.bun,
|
|
else => invalidPlatform(&diag, _platform),
|
|
};
|
|
|
|
ctx.debug.run_in_bun = opts.platform.? == .bun;
|
|
}
|
|
|
|
ctx.debug.run_in_bun = args.flag("--bun") or ctx.debug.run_in_bun;
|
|
|
|
if (jsx_factory != null or
|
|
jsx_fragment != null or
|
|
jsx_import_source != null or
|
|
jsx_runtime != null or
|
|
jsx_production or !react_fast_refresh)
|
|
{
|
|
var default_factory = "".*;
|
|
var default_fragment = "".*;
|
|
var default_import_source = "".*;
|
|
if (opts.jsx == null) {
|
|
opts.jsx = Api.Jsx{
|
|
.factory = constStrToU8(jsx_factory orelse &default_factory),
|
|
.fragment = constStrToU8(jsx_fragment orelse &default_fragment),
|
|
.import_source = constStrToU8(jsx_import_source orelse &default_import_source),
|
|
.runtime = if (jsx_runtime != null) try resolve_jsx_runtime(jsx_runtime.?) else Api.JsxRuntime.automatic,
|
|
.development = !jsx_production,
|
|
.react_fast_refresh = react_fast_refresh,
|
|
};
|
|
} else {
|
|
opts.jsx = Api.Jsx{
|
|
.factory = constStrToU8(jsx_factory orelse opts.jsx.?.factory),
|
|
.fragment = constStrToU8(jsx_fragment orelse opts.jsx.?.fragment),
|
|
.import_source = constStrToU8(jsx_import_source orelse opts.jsx.?.import_source),
|
|
.runtime = if (jsx_runtime != null) try resolve_jsx_runtime(jsx_runtime.?) else opts.jsx.?.runtime,
|
|
.development = !jsx_production,
|
|
.react_fast_refresh = react_fast_refresh,
|
|
};
|
|
}
|
|
}
|
|
|
|
if (args.option("--use")) |entry| {
|
|
opts.framework = Api.FrameworkConfig{
|
|
.package = entry,
|
|
.development = !production,
|
|
};
|
|
}
|
|
|
|
if (cmd == .BuildCommand) {
|
|
if (opts.entry_points.len == 0 and opts.framework == null and opts.node_modules_bundle_path == null) {
|
|
return error.MissingEntryPoint;
|
|
}
|
|
}
|
|
|
|
if (opts.log_level) |log_level| {
|
|
logger.Log.default_log_level = switch (log_level) {
|
|
.debug => logger.Log.Level.debug,
|
|
.err => logger.Log.Level.err,
|
|
.warn => logger.Log.Level.warn,
|
|
else => logger.Log.Level.err,
|
|
};
|
|
ctx.log.level = logger.Log.default_log_level;
|
|
}
|
|
|
|
opts.output_dir = output_dir;
|
|
if (output_file != null)
|
|
ctx.debug.output_file = output_file.?;
|
|
|
|
return opts;
|
|
}
|
|
};
|
|
|
|
const AutoCommand = struct {
|
|
pub fn exec(allocator: std.mem.Allocator) !void {
|
|
try HelpCommand.execWithReason(allocator, .invalid_command);
|
|
}
|
|
};
|
|
const InitCommand = @import("./cli/init_command.zig").InitCommand;
|
|
|
|
pub const HelpCommand = struct {
|
|
pub fn exec(allocator: std.mem.Allocator) !void {
|
|
@setCold(true);
|
|
execWithReason(allocator, .explicit);
|
|
}
|
|
|
|
pub const Reason = enum {
|
|
explicit,
|
|
invalid_command,
|
|
};
|
|
|
|
// someone will get mad at me for this
|
|
pub const packages_to_remove_filler = [_]string{
|
|
"moment",
|
|
"underscore",
|
|
"jquery",
|
|
"backbone",
|
|
"redux",
|
|
"browserify",
|
|
"webpack",
|
|
"left-pad",
|
|
"is-array",
|
|
"babel-core",
|
|
"@parcel/core",
|
|
};
|
|
|
|
pub const packages_to_add_filler = [_]string{
|
|
"elysia",
|
|
"@shumai/shumai",
|
|
"hono",
|
|
"react",
|
|
"lyra",
|
|
"@remix-run/dev",
|
|
"@evan/duckdb",
|
|
"@zarfjs/zarf",
|
|
};
|
|
|
|
pub fn printWithReason(comptime reason: Reason) void {
|
|
// the spacing between commands here is intentional
|
|
const fmt =
|
|
\\> <r><b><magenta>run<r> <d>./my-script.ts<r> Run JavaScript with bun, a package.json script, or a bin
|
|
\\> <b><magenta>build<r> <d>./a.ts ./b.jsx<r> Bundle TypeScript & JavaScript into a single file
|
|
\\> <b><green>x<r> <d>bun-repl<r> Install and execute a package bin <d>(bunx)<r>
|
|
\\
|
|
\\> <b><cyan>init<r> Start an empty Bun project from a blank template
|
|
\\> <b><cyan>create<r> <d>next ./app<r> Create a new project from a template <d>(bun c)<r>
|
|
\\> <b><green>install<r> Install dependencies for a package.json <d>(bun i)<r>
|
|
\\> <b><blue>add<r> <d>{s:<16}<r> Add a dependency to package.json <d>(bun a)<r>
|
|
\\> <b><blue>link<r> Link an npm package globally
|
|
\\> remove<r> <d>{s:<16}<r> Remove a dependency from package.json <d>(bun rm)<r>
|
|
\\> unlink<r> Globally unlink an npm package
|
|
\\> pm<r> More commands for managing packages
|
|
\\
|
|
\\> <b><green>dev<r> <d>./a.ts ./b.jsx<r> Start a bun (frontend) Dev Server
|
|
\\
|
|
\\> <b><blue>upgrade<r> Get the latest version of bun
|
|
\\> <b><d>completions<r> Install shell completions for tab-completion
|
|
\\> <b><d>discord<r> Open bun's Discord server
|
|
\\> <b><d>help<r> Print this help menu
|
|
\\
|
|
;
|
|
|
|
var rand_state = std.rand.DefaultPrng.init(@intCast(u64, @max(std.time.milliTimestamp(), 0)));
|
|
const rand = rand_state.random();
|
|
const package_add_i = rand.uintAtMost(usize, packages_to_add_filler.len - 1);
|
|
const package_remove_i = rand.uintAtMost(usize, packages_to_remove_filler.len - 1);
|
|
|
|
const args = .{
|
|
packages_to_add_filler[package_add_i],
|
|
packages_to_remove_filler[package_remove_i],
|
|
};
|
|
|
|
switch (reason) {
|
|
.explicit => Output.pretty(
|
|
"<r><b><magenta>bun<r>: a fast bundler, transpiler, JavaScript Runtime and package manager for web software.\n\n" ++ fmt,
|
|
args,
|
|
),
|
|
.invalid_command => Output.prettyError(
|
|
"<r><red>Uh-oh<r> not sure what to do with that command.\n\n" ++ fmt,
|
|
args,
|
|
),
|
|
}
|
|
|
|
Output.flush();
|
|
}
|
|
pub fn execWithReason(_: std.mem.Allocator, comptime reason: Reason) void {
|
|
@setCold(true);
|
|
printWithReason(reason);
|
|
|
|
if (reason == .invalid_command) {
|
|
std.process.exit(1);
|
|
}
|
|
}
|
|
};
|
|
|
|
const AddCompletions = @import("./cli/add_completions.zig");
|
|
|
|
pub const PrintBundleCommand = struct {
|
|
pub fn exec(ctx: Command.Context) !void {
|
|
@setCold(true);
|
|
|
|
const entry_point = ctx.args.entry_points[0];
|
|
var out_buffer: [bun.MAX_PATH_BYTES]u8 = undefined;
|
|
var stdout = std.io.getStdOut();
|
|
|
|
var input = try std.fs.openFileAbsolute(try std.os.realpath(entry_point, &out_buffer), .{ .mode = .read_only });
|
|
const params = comptime [_]Arguments.ParamType{
|
|
clap.parseParam("--summary Peek inside the .bun") catch unreachable,
|
|
};
|
|
|
|
var jsBundleArgs = clap.parse(clap.Help, ¶ms, .{ .allocator = ctx.allocator }) catch {
|
|
try NodeModuleBundle.printBundle(std.fs.File, input, @TypeOf(stdout), stdout);
|
|
return;
|
|
};
|
|
|
|
if (jsBundleArgs.flag("--summary")) {
|
|
NodeModuleBundle.printSummaryFromDisk(std.fs.File, input, @TypeOf(stdout), stdout, ctx.allocator) catch {};
|
|
return;
|
|
}
|
|
|
|
try NodeModuleBundle.printBundle(std.fs.File, input, @TypeOf(stdout), stdout);
|
|
}
|
|
};
|
|
|
|
pub const Command = struct {
|
|
var script_name_buf: [bun.MAX_PATH_BYTES]u8 = undefined;
|
|
|
|
pub const DebugOptions = struct {
|
|
dump_environment_variables: bool = false,
|
|
dump_limits: bool = false,
|
|
fallback_only: bool = false,
|
|
silent: bool = false,
|
|
hot_reload: HotReload = HotReload.none,
|
|
global_cache: options.GlobalCache = .auto,
|
|
offline_mode_setting: ?Bunfig.OfflineMode = null,
|
|
run_in_bun: bool = false,
|
|
loaded_bunfig: bool = false,
|
|
|
|
// technical debt
|
|
macros: ?MacroMap = null,
|
|
editor: string = "",
|
|
package_bundle_map: bun.StringArrayHashMapUnmanaged(options.BundlePackage) = bun.StringArrayHashMapUnmanaged(options.BundlePackage){},
|
|
|
|
test_directory: []const u8 = "",
|
|
output_file: []const u8 = "",
|
|
};
|
|
|
|
pub const HotReload = enum {
|
|
none,
|
|
hot,
|
|
watch,
|
|
};
|
|
|
|
pub const TestOptions = struct {
|
|
update_snapshots: bool = false,
|
|
repeat_count: u32 = 0,
|
|
};
|
|
|
|
pub const Context = struct {
|
|
start_time: i128,
|
|
args: Api.TransformOptions,
|
|
log: *logger.Log,
|
|
allocator: std.mem.Allocator,
|
|
positionals: []const string = &[_]string{},
|
|
passthrough: []const string = &[_]string{},
|
|
install: ?*Api.BunInstall = null,
|
|
|
|
debug: DebugOptions = DebugOptions{},
|
|
test_options: TestOptions = TestOptions{},
|
|
bundler_options: BundlerOptions = BundlerOptions{},
|
|
|
|
preloads: []const string = &[_]string{},
|
|
has_loaded_global_config: bool = false,
|
|
|
|
pub const BundlerOptions = struct {
|
|
outdir: []const u8 = "",
|
|
outfile: []const u8 = "",
|
|
entry_names: []const u8 = "./[name].[ext]",
|
|
react_server_components: bool = false,
|
|
code_splitting: bool = false,
|
|
};
|
|
|
|
const _ctx = Command.Context{
|
|
.args = std.mem.zeroes(Api.TransformOptions),
|
|
.log = undefined,
|
|
.start_time = 0,
|
|
.allocator = undefined,
|
|
};
|
|
|
|
pub fn create(allocator: std.mem.Allocator, log: *logger.Log, comptime command: Command.Tag) anyerror!Context {
|
|
Cli.cmd = command;
|
|
var ctx = _ctx;
|
|
ctx.log = log;
|
|
ctx.start_time = start_time;
|
|
ctx.allocator = allocator;
|
|
|
|
if (comptime Command.Tag.uses_global_options.get(command)) {
|
|
ctx.args = try Arguments.parse(allocator, &ctx, command);
|
|
}
|
|
|
|
return ctx;
|
|
}
|
|
};
|
|
|
|
// std.process.args allocates!
|
|
const ArgsIterator = struct {
|
|
buf: [][*:0]u8 = undefined,
|
|
i: u32 = 0,
|
|
|
|
pub fn next(this: *ArgsIterator) ?[]const u8 {
|
|
if (this.buf.len <= this.i) {
|
|
return null;
|
|
}
|
|
const i = this.i;
|
|
this.i += 1;
|
|
return std.mem.span(this.buf[i]);
|
|
}
|
|
|
|
pub fn skip(this: *ArgsIterator) bool {
|
|
return this.next() != null;
|
|
}
|
|
};
|
|
|
|
pub fn which() Tag {
|
|
var args_iter = ArgsIterator{ .buf = std.os.argv };
|
|
// first one is the executable name
|
|
|
|
const argv0 = args_iter.next() orelse return .HelpCommand;
|
|
|
|
// symlink is argv[0]
|
|
if (strings.endsWithComptime(argv0, "bunx"))
|
|
return .BunxCommand;
|
|
|
|
if (comptime Environment.isDebug) {
|
|
if (strings.endsWithComptime(argv0, "bunx-debug"))
|
|
return .BunxCommand;
|
|
}
|
|
|
|
var next_arg = ((args_iter.next()) orelse return .AutoCommand);
|
|
while (next_arg[0] == '-') {
|
|
next_arg = ((args_iter.next()) orelse return .AutoCommand);
|
|
}
|
|
|
|
const first_arg_name = next_arg;
|
|
const RootCommandMatcher = strings.ExactSizeMatcher(16);
|
|
|
|
return switch (RootCommandMatcher.match(first_arg_name)) {
|
|
RootCommandMatcher.case("init") => .InitCommand,
|
|
RootCommandMatcher.case("build"), RootCommandMatcher.case("bun") => .BuildCommand,
|
|
RootCommandMatcher.case("discord") => .DiscordCommand,
|
|
RootCommandMatcher.case("upgrade") => .UpgradeCommand,
|
|
RootCommandMatcher.case("completions") => .InstallCompletionsCommand,
|
|
RootCommandMatcher.case("getcompletes") => .GetCompletionsCommand,
|
|
RootCommandMatcher.case("link") => .LinkCommand,
|
|
RootCommandMatcher.case("unlink") => .UnlinkCommand,
|
|
RootCommandMatcher.case("x") => .BunxCommand,
|
|
|
|
RootCommandMatcher.case("i"), RootCommandMatcher.case("install") => brk: {
|
|
for (args_iter.buf) |arg| {
|
|
const span = std.mem.span(arg);
|
|
if (span.len > 0 and (strings.eqlComptime(span, "-g") or strings.eqlComptime(span, "--global"))) {
|
|
break :brk Command.Tag.AddCommand;
|
|
}
|
|
}
|
|
|
|
break :brk Command.Tag.InstallCommand;
|
|
},
|
|
RootCommandMatcher.case("c"), RootCommandMatcher.case("create") => .CreateCommand,
|
|
|
|
RootCommandMatcher.case(TestCommand.name), RootCommandMatcher.case(TestCommand.old_name) => .TestCommand,
|
|
|
|
RootCommandMatcher.case("pm") => .PackageManagerCommand,
|
|
|
|
RootCommandMatcher.case("add"), RootCommandMatcher.case("update"), RootCommandMatcher.case("a") => .AddCommand,
|
|
RootCommandMatcher.case("r"), RootCommandMatcher.case("remove"), RootCommandMatcher.case("rm"), RootCommandMatcher.case("uninstall") => .RemoveCommand,
|
|
|
|
RootCommandMatcher.case("run") => .RunCommand,
|
|
RootCommandMatcher.case("d"), RootCommandMatcher.case("dev") => .DevCommand,
|
|
|
|
RootCommandMatcher.case("help") => .HelpCommand,
|
|
else => .AutoCommand,
|
|
};
|
|
}
|
|
|
|
const default_completions_list = [_]string{
|
|
// "build",
|
|
"install",
|
|
"add",
|
|
"run",
|
|
"link",
|
|
"unlink",
|
|
"remove",
|
|
"dev",
|
|
"create",
|
|
"bun",
|
|
"upgrade",
|
|
"discord",
|
|
"pm",
|
|
"x",
|
|
};
|
|
|
|
const reject_list = default_completions_list ++ [_]string{
|
|
"build",
|
|
"completions",
|
|
"help",
|
|
};
|
|
|
|
pub fn start(allocator: std.mem.Allocator, log: *logger.Log) !void {
|
|
const BuildCommand = @import("./cli/build_command.zig").BuildCommand;
|
|
|
|
const AddCommand = @import("./cli/add_command.zig").AddCommand;
|
|
const CreateCommand = @import("./cli/create_command.zig").CreateCommand;
|
|
const CreateListExamplesCommand = @import("./cli/create_command.zig").CreateListExamplesCommand;
|
|
const DevCommand = @import("./cli/dev_command.zig").DevCommand;
|
|
const DiscordCommand = @import("./cli/discord_command.zig").DiscordCommand;
|
|
const InstallCommand = @import("./cli/install_command.zig").InstallCommand;
|
|
const LinkCommand = @import("./cli/link_command.zig").LinkCommand;
|
|
const UnlinkCommand = @import("./cli/unlink_command.zig").UnlinkCommand;
|
|
const InstallCompletionsCommand = @import("./cli/install_completions_command.zig").InstallCompletionsCommand;
|
|
const PackageManagerCommand = @import("./cli/package_manager_command.zig").PackageManagerCommand;
|
|
const RemoveCommand = @import("./cli/remove_command.zig").RemoveCommand;
|
|
const RunCommand = @import("./cli/run_command.zig").RunCommand;
|
|
const ShellCompletions = @import("./cli/shell_completions.zig");
|
|
|
|
const UpgradeCommand = @import("./cli/upgrade_command.zig").UpgradeCommand;
|
|
const BunxCommand = @import("./cli/bunx_command.zig").BunxCommand;
|
|
|
|
if (comptime bun.fast_debug_build_mode) {
|
|
// _ = AddCommand;
|
|
// _ = BuildCommand;
|
|
// _ = CreateCommand;
|
|
_ = CreateListExamplesCommand;
|
|
// _ = DevCommand;
|
|
_ = DiscordCommand;
|
|
// _ = InstallCommand;
|
|
// _ = LinkCommand;
|
|
// _ = UnlinkCommand;
|
|
// _ = InstallCompletionsCommand;
|
|
// _ = PackageManagerCommand;
|
|
// _ = RemoveCommand;
|
|
// _ = RunCommand;
|
|
// _ = ShellCompletions;
|
|
// _ = TestCommand;
|
|
// _ = UpgradeCommand;
|
|
// _ = BunxCommand;
|
|
}
|
|
|
|
const tag = which();
|
|
|
|
switch (tag) {
|
|
// .DiscordCommand => return try DiscordCommand.exec(allocator),
|
|
// .HelpCommand => return try HelpCommand.exec(allocator),
|
|
// .InitCommand => return try InitCommand.exec(allocator, std.os.argv),
|
|
else => {},
|
|
}
|
|
|
|
switch (tag) {
|
|
.BuildCommand => {
|
|
if (comptime bun.fast_debug_build_mode and bun.fast_debug_build_cmd != .BuildCommand) unreachable;
|
|
const ctx = try Command.Context.create(allocator, log, .BuildCommand);
|
|
|
|
try BuildCommand.exec(ctx);
|
|
},
|
|
.DevCommand => {
|
|
if (comptime bun.fast_debug_build_mode and bun.fast_debug_build_cmd != .DevCommand) unreachable;
|
|
const ctx = try Command.Context.create(allocator, log, .DevCommand);
|
|
|
|
try DevCommand.exec(ctx);
|
|
},
|
|
.InstallCompletionsCommand => {
|
|
if (comptime bun.fast_debug_build_mode and bun.fast_debug_build_cmd != .InstallCompletionsCommand) unreachable;
|
|
try InstallCompletionsCommand.exec(allocator);
|
|
return;
|
|
},
|
|
.InstallCommand => {
|
|
if (comptime bun.fast_debug_build_mode and bun.fast_debug_build_cmd != .InstallCommand) unreachable;
|
|
const ctx = try Command.Context.create(allocator, log, .InstallCommand);
|
|
|
|
try InstallCommand.exec(ctx);
|
|
return;
|
|
},
|
|
.AddCommand => {
|
|
if (comptime bun.fast_debug_build_mode and bun.fast_debug_build_cmd != .AddCommand) unreachable;
|
|
const ctx = try Command.Context.create(allocator, log, .AddCommand);
|
|
|
|
try AddCommand.exec(ctx);
|
|
return;
|
|
},
|
|
.BunxCommand => {
|
|
if (comptime bun.fast_debug_build_mode and bun.fast_debug_build_cmd != .BunxCommand) unreachable;
|
|
const ctx = try Command.Context.create(allocator, log, .BunxCommand);
|
|
|
|
try BunxCommand.exec(ctx);
|
|
return;
|
|
},
|
|
.RemoveCommand => {
|
|
if (comptime bun.fast_debug_build_mode and bun.fast_debug_build_cmd != .RemoveCommand) unreachable;
|
|
const ctx = try Command.Context.create(allocator, log, .RemoveCommand);
|
|
|
|
try RemoveCommand.exec(ctx);
|
|
return;
|
|
},
|
|
.LinkCommand => {
|
|
if (comptime bun.fast_debug_build_mode and bun.fast_debug_build_cmd != .LinkCommand) unreachable;
|
|
const ctx = try Command.Context.create(allocator, log, .LinkCommand);
|
|
|
|
try LinkCommand.exec(ctx);
|
|
return;
|
|
},
|
|
.UnlinkCommand => {
|
|
if (comptime bun.fast_debug_build_mode and bun.fast_debug_build_cmd != .UnlinkCommand) unreachable;
|
|
const ctx = try Command.Context.create(allocator, log, .UnlinkCommand);
|
|
|
|
try UnlinkCommand.exec(ctx);
|
|
return;
|
|
},
|
|
.PackageManagerCommand => {
|
|
if (comptime bun.fast_debug_build_mode and bun.fast_debug_build_cmd != .PackageManagerCommand) unreachable;
|
|
const ctx = try Command.Context.create(allocator, log, .PackageManagerCommand);
|
|
|
|
try PackageManagerCommand.exec(ctx);
|
|
return;
|
|
},
|
|
.TestCommand => {
|
|
if (comptime bun.fast_debug_build_mode and bun.fast_debug_build_cmd != .TestCommand) unreachable;
|
|
const ctx = try Command.Context.create(allocator, log, .TestCommand);
|
|
|
|
try TestCommand.exec(ctx);
|
|
return;
|
|
},
|
|
.GetCompletionsCommand => {
|
|
if (comptime bun.fast_debug_build_mode and bun.fast_debug_build_cmd != .GetCompletionsCommand) unreachable;
|
|
const ctx = try Command.Context.create(allocator, log, .GetCompletionsCommand);
|
|
var filter = ctx.positionals;
|
|
|
|
for (filter, 0..) |item, i| {
|
|
if (strings.eqlComptime(item, "getcompletes")) {
|
|
if (i + 1 < filter.len) {
|
|
filter = filter[i + 1 ..];
|
|
} else {
|
|
filter = &[_]string{};
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
var prefilled_completions: [AddCompletions.biggest_list]string = undefined;
|
|
var completions = ShellCompletions{};
|
|
|
|
if (filter.len == 0) {
|
|
completions = try RunCommand.completions(ctx, &default_completions_list, &reject_list, .all);
|
|
} else if (strings.eqlComptime(filter[0], "s")) {
|
|
completions = try RunCommand.completions(ctx, null, &reject_list, .script);
|
|
} else if (strings.eqlComptime(filter[0], "i")) {
|
|
completions = try RunCommand.completions(ctx, &default_completions_list, &reject_list, .script_exclude);
|
|
} else if (strings.eqlComptime(filter[0], "b")) {
|
|
completions = try RunCommand.completions(ctx, null, &reject_list, .bin);
|
|
} else if (strings.eqlComptime(filter[0], "r")) {
|
|
completions = try RunCommand.completions(ctx, null, &reject_list, .all);
|
|
} else if (strings.eqlComptime(filter[0], "g")) {
|
|
completions = try RunCommand.completions(ctx, null, &reject_list, .all_plus_bun_js);
|
|
} else if (strings.eqlComptime(filter[0], "j")) {
|
|
completions = try RunCommand.completions(ctx, null, &reject_list, .bun_js);
|
|
} else if (strings.eqlComptime(filter[0], "z")) {
|
|
completions = try RunCommand.completions(ctx, null, &reject_list, .script_and_descriptions);
|
|
} else if (strings.eqlComptime(filter[0], "a")) {
|
|
const FirstLetter = AddCompletions.FirstLetter;
|
|
const index = AddCompletions.index;
|
|
|
|
outer: {
|
|
if (filter.len > 1) {
|
|
const first_letter: FirstLetter = switch (filter[1][0]) {
|
|
'a' => FirstLetter.a,
|
|
'b' => FirstLetter.b,
|
|
'c' => FirstLetter.c,
|
|
'd' => FirstLetter.d,
|
|
'e' => FirstLetter.e,
|
|
'f' => FirstLetter.f,
|
|
'g' => FirstLetter.g,
|
|
'h' => FirstLetter.h,
|
|
'i' => FirstLetter.i,
|
|
'j' => FirstLetter.j,
|
|
'k' => FirstLetter.k,
|
|
'l' => FirstLetter.l,
|
|
'm' => FirstLetter.m,
|
|
'n' => FirstLetter.n,
|
|
'o' => FirstLetter.o,
|
|
'p' => FirstLetter.p,
|
|
'q' => FirstLetter.q,
|
|
'r' => FirstLetter.r,
|
|
's' => FirstLetter.s,
|
|
't' => FirstLetter.t,
|
|
'u' => FirstLetter.u,
|
|
'v' => FirstLetter.v,
|
|
'w' => FirstLetter.w,
|
|
'x' => FirstLetter.x,
|
|
'y' => FirstLetter.y,
|
|
'z' => FirstLetter.z,
|
|
else => break :outer,
|
|
};
|
|
const results = index.get(first_letter);
|
|
|
|
var prefilled_i: usize = 0;
|
|
for (results) |cur| {
|
|
if (cur.len == 0 or !strings.hasPrefix(cur, filter[1])) continue;
|
|
prefilled_completions[prefilled_i] = cur;
|
|
prefilled_i += 1;
|
|
if (prefilled_i >= prefilled_completions.len) break;
|
|
}
|
|
completions.commands = prefilled_completions[0..prefilled_i];
|
|
}
|
|
}
|
|
}
|
|
completions.print();
|
|
|
|
return;
|
|
},
|
|
.CreateCommand => {
|
|
if (comptime bun.fast_debug_build_mode and bun.fast_debug_build_cmd != .CreateCommand) unreachable;
|
|
const ctx = try Command.Context.create(allocator, log, .CreateCommand);
|
|
var positionals: [2]string = undefined;
|
|
var positional_i: usize = 0;
|
|
|
|
var args = try std.process.argsAlloc(allocator);
|
|
|
|
if (args.len > 2) {
|
|
var remainder = args[2..];
|
|
var remainder_i: usize = 0;
|
|
while (remainder_i < remainder.len and positional_i < positionals.len) : (remainder_i += 1) {
|
|
var slice = std.mem.trim(u8, bun.asByteSlice(remainder[remainder_i]), " \t\n;");
|
|
if (slice.len > 0) {
|
|
positionals[positional_i] = slice;
|
|
positional_i += 1;
|
|
}
|
|
}
|
|
}
|
|
var positionals_ = positionals[0..positional_i];
|
|
|
|
try CreateCommand.exec(ctx, positionals_);
|
|
return;
|
|
},
|
|
.RunCommand => {
|
|
if (comptime bun.fast_debug_build_mode and bun.fast_debug_build_cmd != .RunCommand) unreachable;
|
|
const ctx = try Command.Context.create(allocator, log, .RunCommand);
|
|
if (ctx.positionals.len > 0) {
|
|
if (try RunCommand.exec(ctx, false, true)) {
|
|
return;
|
|
}
|
|
|
|
Global.exit(1);
|
|
}
|
|
},
|
|
.UpgradeCommand => {
|
|
if (comptime bun.fast_debug_build_mode and bun.fast_debug_build_cmd != .UpgradeCommand) unreachable;
|
|
const ctx = try Command.Context.create(allocator, log, .UpgradeCommand);
|
|
try UpgradeCommand.exec(ctx);
|
|
return;
|
|
},
|
|
.AutoCommand => {
|
|
if (comptime bun.fast_debug_build_mode and bun.fast_debug_build_cmd != .AutoCommand) unreachable;
|
|
var ctx = Command.Context.create(allocator, log, .AutoCommand) catch |e| {
|
|
switch (e) {
|
|
error.MissingEntryPoint => {
|
|
HelpCommand.execWithReason(allocator, .explicit);
|
|
return;
|
|
},
|
|
else => {
|
|
return e;
|
|
},
|
|
}
|
|
};
|
|
|
|
const extension: []const u8 = if (ctx.args.entry_points.len > 0)
|
|
std.fs.path.extension(ctx.args.entry_points[0])
|
|
else
|
|
@as([]const u8, "");
|
|
// KEYWORDS: open file argv argv0
|
|
if (ctx.args.entry_points.len == 1) {
|
|
if (strings.eqlComptime(extension, ".bun")) {
|
|
try PrintBundleCommand.exec(ctx);
|
|
return;
|
|
}
|
|
|
|
if (strings.eqlComptime(extension, ".lockb")) {
|
|
for (std.os.argv) |arg| {
|
|
if (strings.eqlComptime(std.mem.span(arg), "--hash")) {
|
|
try PackageManagerCommand.printHash(ctx, ctx.args.entry_points[0]);
|
|
return;
|
|
}
|
|
}
|
|
|
|
try Install.Lockfile.Printer.print(
|
|
ctx.allocator,
|
|
ctx.log,
|
|
ctx.args.entry_points[0],
|
|
.yarn,
|
|
);
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
var was_js_like = false;
|
|
// If we start bun with:
|
|
// 1. `bun foo.js`, assume it's a JavaScript file.
|
|
// 2. `bun /absolute/path/to/bin/foo` assume its a JavaScript file.
|
|
// ^ no file extension
|
|
//
|
|
// #!/usr/bin/env bun
|
|
// will pass us an absolute path to the script.
|
|
// This means a non-standard file extension will not work, but that is better than the current state
|
|
// which is file extension-less doesn't work
|
|
const default_loader = options.defaultLoaders.get(extension) orelse brk: {
|
|
if (extension.len == 0 and ctx.args.entry_points.len > 0 and ctx.args.entry_points[0].len > 0 and std.fs.path.isAbsolute(ctx.args.entry_points[0])) {
|
|
break :brk options.Loader.js;
|
|
}
|
|
|
|
if (extension.len > 0) {
|
|
if (!ctx.debug.loaded_bunfig) {
|
|
try bun.CLI.Arguments.loadConfigPath(ctx.allocator, true, "bunfig.toml", &ctx, .RunCommand);
|
|
}
|
|
|
|
if (ctx.preloads.len > 0)
|
|
break :brk options.Loader.js;
|
|
}
|
|
|
|
break :brk null;
|
|
};
|
|
|
|
const force_using_bun = ctx.debug.run_in_bun;
|
|
var did_check = false;
|
|
if (default_loader) |loader| {
|
|
if (loader.canBeRunByBun()) {
|
|
was_js_like = true;
|
|
if (maybeOpenWithBunJS(&ctx)) {
|
|
return;
|
|
}
|
|
did_check = true;
|
|
}
|
|
}
|
|
|
|
if (force_using_bun and !did_check) {
|
|
if (maybeOpenWithBunJS(&ctx)) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (ctx.positionals.len > 0 and extension.len == 0) {
|
|
if (try RunCommand.exec(ctx, true, false)) {
|
|
return;
|
|
}
|
|
|
|
Output.prettyErrorln("<r><red>error<r><d>:<r> script not found \"<b>{s}<r>\"", .{
|
|
ctx.positionals[0],
|
|
});
|
|
|
|
Global.exit(1);
|
|
}
|
|
|
|
if (was_js_like) {
|
|
Output.prettyErrorln("<r><red>error<r><d>:<r> module not found \"<b>{s}<r>\"", .{
|
|
ctx.positionals[0],
|
|
});
|
|
Global.exit(1);
|
|
} else if (ctx.positionals.len > 0) {
|
|
Output.prettyErrorln("<r><red>error<r><d>:<r> file not found \"<b>{s}<r>\"", .{
|
|
ctx.positionals[0],
|
|
});
|
|
Global.exit(1);
|
|
}
|
|
|
|
try HelpCommand.exec(allocator);
|
|
},
|
|
else => unreachable,
|
|
}
|
|
}
|
|
|
|
fn maybeOpenWithBunJS(ctx: *Command.Context) bool {
|
|
if (ctx.args.entry_points.len == 0)
|
|
return false;
|
|
|
|
const script_name_to_search = ctx.args.entry_points[0];
|
|
|
|
var file_path = script_name_to_search;
|
|
const file_: std.fs.File.OpenError!std.fs.File = brk: {
|
|
if (script_name_to_search[0] == std.fs.path.sep) {
|
|
break :brk std.fs.openFileAbsolute(script_name_to_search, .{ .mode = .read_only });
|
|
} else if (!strings.hasPrefix(script_name_to_search, "..") and script_name_to_search[0] != '~') {
|
|
const file_pathZ = brk2: {
|
|
if (!strings.hasPrefix(file_path, "./")) {
|
|
script_name_buf[0..2].* = "./".*;
|
|
@memcpy(script_name_buf[2..], file_path.ptr, file_path.len);
|
|
script_name_buf[file_path.len + 2] = 0;
|
|
break :brk2 script_name_buf[0 .. file_path.len + 2 :0];
|
|
} else {
|
|
@memcpy(&script_name_buf, file_path.ptr, file_path.len);
|
|
script_name_buf[file_path.len] = 0;
|
|
break :brk2 script_name_buf[0..file_path.len :0];
|
|
}
|
|
};
|
|
|
|
break :brk std.fs.cwd().openFileZ(file_pathZ, .{ .mode = .read_only });
|
|
} else {
|
|
var path_buf: [bun.MAX_PATH_BYTES]u8 = undefined;
|
|
const cwd = std.os.getcwd(&path_buf) catch return false;
|
|
path_buf[cwd.len] = std.fs.path.sep;
|
|
var parts = [_]string{script_name_to_search};
|
|
file_path = resolve_path.joinAbsStringBuf(
|
|
path_buf[0 .. cwd.len + 1],
|
|
&script_name_buf,
|
|
&parts,
|
|
.auto,
|
|
);
|
|
if (file_path.len == 0) return false;
|
|
script_name_buf[file_path.len] = 0;
|
|
var file_pathZ = script_name_buf[0..file_path.len :0];
|
|
break :brk std.fs.openFileAbsoluteZ(file_pathZ, .{ .mode = .read_only });
|
|
}
|
|
};
|
|
|
|
const file = file_ catch return false;
|
|
|
|
Global.configureAllocator(.{ .long_running = true });
|
|
|
|
// the case where this doesn't work is if the script name on disk doesn't end with a known JS-like file extension
|
|
var absolute_script_path = bun.getFdPath(file.handle, &script_name_buf) catch return false;
|
|
|
|
if (!ctx.debug.loaded_bunfig) {
|
|
bun.CLI.Arguments.loadConfigPath(ctx.allocator, true, "bunfig.toml", ctx, .RunCommand) catch {};
|
|
}
|
|
|
|
BunJS.Run.boot(
|
|
ctx.*,
|
|
file,
|
|
absolute_script_path,
|
|
) catch |err| {
|
|
if (Output.enable_ansi_colors) {
|
|
ctx.log.printForLogLevelWithEnableAnsiColors(Output.errorWriter(), true) catch {};
|
|
} else {
|
|
ctx.log.printForLogLevelWithEnableAnsiColors(Output.errorWriter(), false) catch {};
|
|
}
|
|
|
|
Output.prettyErrorln("<r><red>error<r>: Failed to run <b>{s}<r> due to error <b>{s}<r>", .{
|
|
std.fs.path.basename(file_path),
|
|
@errorName(err),
|
|
});
|
|
Global.exit(1);
|
|
};
|
|
return true;
|
|
}
|
|
|
|
pub const Tag = enum {
|
|
AddCommand,
|
|
AutoCommand,
|
|
BuildCommand,
|
|
BunxCommand,
|
|
CreateCommand,
|
|
DevCommand,
|
|
DiscordCommand,
|
|
GetCompletionsCommand,
|
|
HelpCommand,
|
|
InitCommand,
|
|
InstallCommand,
|
|
InstallCompletionsCommand,
|
|
LinkCommand,
|
|
PackageManagerCommand,
|
|
RemoveCommand,
|
|
RunCommand,
|
|
TestCommand,
|
|
UnlinkCommand,
|
|
UpgradeCommand,
|
|
|
|
pub fn params(comptime cmd: Tag) []const Arguments.ParamType {
|
|
return &comptime switch (cmd) {
|
|
Command.Tag.BuildCommand => Arguments.build_params,
|
|
Command.Tag.TestCommand => Arguments.test_params,
|
|
else => Arguments.params,
|
|
};
|
|
}
|
|
|
|
pub fn readGlobalConfig(this: Tag) bool {
|
|
return switch (this) {
|
|
.BunxCommand, .PackageManagerCommand, .InstallCommand, .AddCommand, .RemoveCommand => true,
|
|
else => false,
|
|
};
|
|
}
|
|
|
|
pub fn isNPMRelated(this: Tag) bool {
|
|
return switch (this) {
|
|
.BunxCommand, .LinkCommand, .UnlinkCommand, .PackageManagerCommand, .InstallCommand, .AddCommand, .RemoveCommand => true,
|
|
else => false,
|
|
};
|
|
}
|
|
|
|
pub const cares_about_bun_file: std.EnumArray(Tag, bool) = std.EnumArray(Tag, bool).initDefault(false, .{
|
|
.AutoCommand = true,
|
|
.BuildCommand = false,
|
|
.DevCommand = true,
|
|
.RunCommand = true,
|
|
.TestCommand = true,
|
|
});
|
|
|
|
pub const loads_config = brk: {
|
|
var cares = cares_about_bun_file;
|
|
cares.set(.InstallCommand, true);
|
|
cares.set(.AddCommand, true);
|
|
cares.set(.RemoveCommand, true);
|
|
cares.set(.LinkCommand, true);
|
|
cares.set(.UnlinkCommand, true);
|
|
cares.set(.BunxCommand, true);
|
|
break :brk cares;
|
|
};
|
|
pub const always_loads_config: std.EnumArray(Tag, bool) = std.EnumArray(Tag, bool).initDefault(false, .{
|
|
.BuildCommand = true,
|
|
.DevCommand = true,
|
|
.TestCommand = true,
|
|
.InstallCommand = true,
|
|
.AddCommand = true,
|
|
.RemoveCommand = true,
|
|
.PackageManagerCommand = true,
|
|
.BunxCommand = true,
|
|
});
|
|
|
|
pub const uses_global_options: std.EnumArray(Tag, bool) = std.EnumArray(Tag, bool).initDefault(true, .{
|
|
.CreateCommand = false,
|
|
.InstallCommand = false,
|
|
.AddCommand = false,
|
|
.RemoveCommand = false,
|
|
.PackageManagerCommand = false,
|
|
.LinkCommand = false,
|
|
.UnlinkCommand = false,
|
|
.BunxCommand = false,
|
|
});
|
|
};
|
|
};
|