From d67c95d8ebb366d14976ce74e9448a23c3d6886a Mon Sep 17 00:00:00 2001 From: Jarred Sumner Date: Fri, 11 Feb 2022 19:01:00 -0800 Subject: [PATCH] [bun install] Implement bunfig.toml config --- bun.lockb | Bin 7340 -> 7340 bytes integration/scripts/bun.lockb | Bin 17219 -> 17219 bytes packages/bun-error/bun.lockb | Bin 11916 -> 11916 bytes src/api/schema.d.ts | 48 ++++++ src/api/schema.js | 271 ++++++++++++++++++++++++++++++++++ src/api/schema.peechy | 33 ++++- src/api/schema.zig | 235 +++++++++++++++++++++++++++++ src/bunfig.zig | 253 +++++++++++++++++++++++++++++-- src/cli.zig | 179 +++++++++++++--------- src/env_loader.zig | 15 ++ src/http/header_builder.zig | 18 +++ src/string_builder.zig | 11 ++ 12 files changed, 977 insertions(+), 86 deletions(-) diff --git a/bun.lockb b/bun.lockb index 0be659f47d520950909a99568f5c802ac7009dcf..88730849d5e30c70da79e3127f96b44ec6cddbec 100755 GIT binary patch delta 766 zcmZ2uxyEwCB2kux%DqgJmx=i4=^#t8S5G7nJ_Rk<}(82J%N~;fuX_AHK`>>#O; z5CW9s0!nT;z2=tIeTGnk=4Xr`&2do8PbRs{U4G5)D_Gu8&j@CCCQzOesDH65ss;>JDQD23fFG*!(g1j-=bd_r8Ielau@H}UZ?SyyhUMFb1T&-mO4Nl=8+ l1n!{H1DP)Zv;vYMC+bJ_s%^EkWMb5s?8qp(IY2sw5dg%o)u8|Y delta 822 zcmZ2uxyEwCB2g9wAeg*N)Q0(V4&&sfqV_D@3=9pEHN<2lACZ(}{>aQYIaN%)UIVBq zCBH;BIk7nP+}HCTwtTfcz{D75tY@HS!oa|<(!$EX;0aU%((LD($3ZXDEtCzD*} zF2CmY6|BHe&xnBmVn8NPo)c)mjwjn@^(*OLLoxuUKizw>hq%?`L*fc55clBr4+GFY zlaGnpByVJ9WXL#CQk;{S1T@=i{@qoJ#CQJynhWxnF$2RUpgaRZClG@ie$J%$#+O@D z-a+Nz?!v2o@=jDtqdQ(sk|;^_LYO8B4rbh@K|%qyw}7q% z+7j!$2kdIx>L9^`+n%dHb6mxgC!Y|vvV+)(TP-AnaQSKS0Wqa|h!WgJK%BD}8pxaY z_?WCKx6~qng^fV4NP<%r&cwsY&;f~VC0U>q;1oPjKdM)4tF0vyqZUXA2!L+b>?)nk F2monD$F?JS#pEbJJWp5;vLv5aFmd_)JdRTTRWyOpk4@%#}2GS$1V=+A_#8{ggOJE-asfGdx%O1$FZA_beEbJJWp65;Ov5aGBUU-dl@;gfz5TD0N4y?+m zj_Doai-Z>;55T0jQy*~G9oECMp}Y-~UhYi#B* z9b%m9V=D*N1fhC>)Cr(oTRWyupk4@%#}2GS$1V=+A_#8{ggOJE-asfGdx%O1Nq5hx-66tT``1hV9Tm8@o&iu8B<(RdLPMcG3dj-$DtdR;v(=>I_F|wSBRz9HLk0$Bu*-6R@_ayf zj)E|$KF{szp@tYUFhDG+2Fi;AH5eFw)H|?iYX?8K8g< zF`T^d+N~2afd&}?<$(d4hubFx;D84k@fS#n0`)tw-K^WlUMke04iX$&g1eT$IKE6L1F)y;#-OO~=N zX0wtuLdZirPzRI;d4TzVN2W(sS^z>G;=q2OJSf!_XR3#Ee_=4Zj8FivU=dJ(7*K)x zxuQ0{&lBp<X)AzFhfS#R&NlR>sMu+P2D!;7BnCssjZY@7H2gKf(O@DC#y()&9-|0NL%^t^fc4 delta 1045 zcmeB)?TOv6NmYdb3<`=;6O&6A7(CCvy*Ocm`vWG%I70(HQ$0fy?gU=e$=6ipFwf0q zoLs6FTmPDs5vWBQh3;_A_71W29UIeJdof4@|dm{HcWRk(gs-w)NjDR@c%zh3b*<7Pz$1fiiCj%ygTdJ zYSM9gG0*@bJ#&Nua)I)EKzWXWFsVMz?dzcy7&9=4fjv+SlotoeZ>ViNZ1ChtB~ad2 z&qB`#C=3RZfFwvhe)6Sh-Ai^eAI+%-!XWR#hnp|PH!02?SU&;wt9Q48V*h7VvH?f`k9uojrtI{8%NC0?*o zfpG)#3U2*iVrv0|nU-=zjz*4XQ=0JHNpnO|`&MN6Wa*q)5#$b6*pghO{7aTvyd9&7tBIHGY z>6L*Y4k#}GlwZ19r7@`3_H8{v0VI9pK@~`rvMpw_k~Tuf^RWY^80vro$Op^^JTg79 z(gG0jY+wuef%2f_SDdLH(*1?uGD2Pp?7&4pc`=~8`?;bvzRwc`>kta~!4^!Op=FiK z0XFLa)ULkM?Y`#IAFM+t1;-!5N1!|?FqCaQmALK9Rv_dd`k9#^o?W=@zAslkS202! isDHAlwyiS69CM&LP@wUCEmrjt%%6{ { + return this; + }, + + 1 => { + this.default_registry = try reader.readValue(NpmRegistry); + }, + 2 => { + this.scoped = try reader.readValue(NpmRegistryMap); + }, + 3 => { + this.lockfile_path = try reader.readValue([]const u8); + }, + 4 => { + this.save_lockfile_path = try reader.readValue([]const u8); + }, + 5 => { + this.cache_directory = try reader.readValue([]const u8); + }, + 6 => { + this.dry_run = try reader.readValue(bool); + }, + 7 => { + this.force = try reader.readValue(bool); + }, + 8 => { + this.save_dev = try reader.readValue(bool); + }, + 9 => { + this.save_optional = try reader.readValue(bool); + }, + 10 => { + this.save_peer = try reader.readValue(bool); + }, + 11 => { + this.save_lockfile = try reader.readValue(bool); + }, + 12 => { + this.production = try reader.readValue(bool); + }, + 13 => { + this.save_yarn_lockfile = try reader.readValue(bool); + }, + 14 => { + this.native_bin_links = try reader.readArray([]const u8); + }, + 15 => { + this.disable_cache = try reader.readValue(bool); + }, + 16 => { + this.disable_manifest_cache = try reader.readValue(bool); + }, + else => { + return error.InvalidMessage; + }, + } + } + unreachable; + } + + pub fn encode(this: *const @This(), writer: anytype) anyerror!void { + if (this.default_registry) |default_registry| { + try writer.writeFieldID(1); + try writer.writeValue(@TypeOf(default_registry), default_registry); + } + if (this.scoped) |scoped| { + try writer.writeFieldID(2); + try writer.writeValue(@TypeOf(scoped), scoped); + } + if (this.lockfile_path) |lockfile_path| { + try writer.writeFieldID(3); + try writer.writeValue(@TypeOf(lockfile_path), lockfile_path); + } + if (this.save_lockfile_path) |save_lockfile_path| { + try writer.writeFieldID(4); + try writer.writeValue(@TypeOf(save_lockfile_path), save_lockfile_path); + } + if (this.cache_directory) |cache_directory| { + try writer.writeFieldID(5); + try writer.writeValue(@TypeOf(cache_directory), cache_directory); + } + if (this.dry_run) |dry_run| { + try writer.writeFieldID(6); + try writer.writeInt(@as(u8, @boolToInt(dry_run))); + } + if (this.force) |force| { + try writer.writeFieldID(7); + try writer.writeInt(@as(u8, @boolToInt(force))); + } + if (this.save_dev) |save_dev| { + try writer.writeFieldID(8); + try writer.writeInt(@as(u8, @boolToInt(save_dev))); + } + if (this.save_optional) |save_optional| { + try writer.writeFieldID(9); + try writer.writeInt(@as(u8, @boolToInt(save_optional))); + } + if (this.save_peer) |save_peer| { + try writer.writeFieldID(10); + try writer.writeInt(@as(u8, @boolToInt(save_peer))); + } + if (this.save_lockfile) |save_lockfile| { + try writer.writeFieldID(11); + try writer.writeInt(@as(u8, @boolToInt(save_lockfile))); + } + if (this.production) |production| { + try writer.writeFieldID(12); + try writer.writeInt(@as(u8, @boolToInt(production))); + } + if (this.save_yarn_lockfile) |save_yarn_lockfile| { + try writer.writeFieldID(13); + try writer.writeInt(@as(u8, @boolToInt(save_yarn_lockfile))); + } + if (this.native_bin_links) |native_bin_links| { + try writer.writeFieldID(14); + try writer.writeArray([]const u8, native_bin_links); + } + if (this.disable_cache) |disable_cache| { + try writer.writeFieldID(15); + try writer.writeInt(@as(u8, @boolToInt(disable_cache))); + } + if (this.disable_manifest_cache) |disable_manifest_cache| { + try writer.writeFieldID(16); + try writer.writeInt(@as(u8, @boolToInt(disable_manifest_cache))); + } + try writer.endMessage(); + } + }; }; diff --git a/src/bunfig.zig b/src/bunfig.zig index 46d14ff0ff..65e2000982 100644 --- a/src/bunfig.zig +++ b/src/bunfig.zig @@ -12,7 +12,6 @@ const URL = @import("./query_string_map.zig").URL; const C = _global.C; const options = @import("./options.zig"); const logger = @import("./logger.zig"); -const cache = @import("./cache.zig"); const js_ast = @import("./js_ast.zig"); const js_lexer = @import("./js_lexer.zig"); const Defines = @import("./defines.zig"); @@ -45,6 +44,68 @@ pub const Bunfig = struct { return error.@"Invalid Bunfig"; } + fn parseRegistry(this: *Parser, expr: js_ast.Expr) !Api.NpmRegistry { + var registry = std.mem.zeroes(Api.NpmRegistry); + + switch (expr.data) { + .e_string => |str| { + const url = URL.parse(str.utf8); + // Token + if (url.username.len == 0 and url.password.len > 0) { + registry.token = url.password; + registry.url = try std.fmt.allocPrint(this.allocator, "{s}://{s}/{s}", .{ url.displayProtocol(), url.displayHostname(), std.mem.trimLeft(u8, url.pathname, "/") }); + } else if (url.username.len > 0 and url.password.len > 0) { + registry.username = url.username; + registry.password = url.password; + registry.url = try std.fmt.allocPrint(this.allocator, "{s}://{s}/{s}", .{ url.displayProtocol(), url.displayHostname(), std.mem.trimLeft(u8, url.pathname, "/") }); + } else { + registry.url = url.href; + } + }, + .e_object => |obj| { + if (obj.get("url")) |url| { + try this.expect(url, .e_string); + registry.url = url.data.e_string.utf8; + } + + if (obj.get("username")) |username| { + try this.expect(username, .e_string); + registry.username = username.data.e_string.utf8; + } + + if (obj.get("password")) |password| { + try this.expect(password, .e_string); + registry.password = password.data.e_string.utf8; + } + + if (obj.get("token")) |token| { + try this.expect(token, .e_string); + registry.token = token.data.e_string.utf8; + } + }, + else => { + try this.addError(expr.loc, "Expected registry to be a URL string or an object"); + }, + } + + return registry; + } + + fn loadLogLevel(this: *Parser, expr: js_ast.Expr) !void { + try this.expect(expr, .e_string); + const Matcher = strings.ExactSizeMatcher(8); + + this.bunfig.log_level = switch (Matcher.match(expr.asString(this.allocator).?)) { + Matcher.case("debug") => Api.MessageLevel.debug, + Matcher.case("error") => Api.MessageLevel.err, + Matcher.case("warn") => Api.MessageLevel.warn, + else => { + try this.addError(expr.loc, "Invalid log level, must be one of debug, error, or warn"); + unreachable; + }, + }; + } + pub fn parse(this: *Parser, comptime cmd: Command.Tag) !void { const json = this.json; var allocator = this.allocator; @@ -53,6 +114,10 @@ pub const Bunfig = struct { try this.addError(json.loc, "bunfig expects an object { } at the root"); } + if (json.get("logLevel")) |expr| { + try this.loadLogLevel(expr); + } + if (json.get("define")) |expr| { try this.expect(expr, .e_object); var valid_count: usize = 0; @@ -89,6 +154,10 @@ pub const Bunfig = struct { this.ctx.debug.fallback_only = disable.asBool() orelse false; } + if (expr.get("logLevel")) |expr2| { + try this.loadLogLevel(expr2); + } + if (expr.get("port")) |port| { try this.expect(port, .e_number); this.bunfig.port = port.data.e_number.toU16(); @@ -99,6 +168,169 @@ pub const Bunfig = struct { } } + if (comptime cmd.isNPMRelated()) { + if (json.get("install")) |bun| { + var install: *Api.BunInstall = this.ctx.install orelse brk: { + var install_ = try this.allocator.create(Api.BunInstall); + install_.* = std.mem.zeroes(Api.BunInstall); + this.ctx.install = install_; + break :brk install_; + }; + + if (bun.get("registry")) |registry| { + install.default_registry = try this.parseRegistry(registry); + } + + if (bun.get("scopes")) |scopes| { + var registry_map = install.scoped orelse std.mem.zeroes(Api.NpmRegistryMap); + try this.expect(scopes, .e_object); + const count = scopes.data.e_object.properties.len + registry_map.registries.len; + var registries = std.ArrayListUnmanaged(Api.NpmRegistry){ + .items = try this.allocator.alloc(Api.NpmRegistry, count), + .capacity = count, + }; + registries.appendSliceAssumeCapacity(registry_map.registries); + + var names = std.ArrayListUnmanaged(string){ + .items = try this.allocator.alloc(string, count), + .capacity = count, + }; + + names.appendSliceAssumeCapacity(registry_map.names); + + for (scopes.data.e_object.properties.slice()) |prop| { + const name_ = prop.key.?.data.e_string.string(this.allocator) orelse continue; + const value = prop.value orelse continue; + if (name_.len == 0) continue; + const name = if (name_[0] == '@') name_[1..] else name_; + var index = names.items.len; + for (names.items) |comparator, i| { + if (strings.eql(name, comparator)) { + index = i; + break; + } + } + + if (index == names.items.len) { + names.items.len += 1; + registries.items.len += 1; + } + names.items[index] = name; + registries.items[index] = try this.parseRegistry(value); + } + + registry_map.registries = registries.items; + registry_map.names = names.items; + install.scoped = registry_map; + } + + if (bun.get("dryRun")) |dry_run| { + if (dry_run.asBool()) |value| { + install.dry_run = value; + } + } + + if (bun.get("production")) |production| { + if (production.asBool()) |value| { + install.production = value; + } + } + + if (bun.get("lockfile")) |lockfile_expr| { + if (lockfile_expr.get("outputFormat")) |lockfile| { + try this.expect(lockfile, .e_string); + if (lockfile.asString(this.allocator)) |value| { + if (!(strings.eqlComptime(value, "bun"))) { + if (!strings.eqlComptime(value, "yarn")) { + try this.addError(lockfile.loc, "Invalid lockfile format, only 'yarn' output is implemented"); + } + + install.save_yarn_lockfile = true; + } + } + } + + if (lockfile_expr.get("save")) |lockfile| { + if (lockfile.asString()) |value| { + install.save_lockfile = value; + } + } + + if (lockfile_expr.get("path")) |lockfile| { + if (lockfile.asString()) |value| { + install.lockfile_path = value; + } + } + + if (lockfile_expr.get("savePath")) |lockfile| { + if (lockfile.asString()) |value| { + install.save_lockfile_path = value; + } + } + } + + if (bun.get("optional")) |optional| { + if (optional.asBool()) |value| { + install.save_optional = value; + } + } + + if (bun.get("peer")) |optional| { + if (optional.asBool()) |value| { + install.save_peer = value; + } + } + + if (bun.get("dev")) |optional| { + if (optional.asBool()) |value| { + install.save_dev = value; + } + } + + if (bun.get("logLevel")) |expr| { + try this.loadLogLevel(expr); + } + + if (bun.get("cache")) |cache| { + load: { + if (cache.asBool()) |value| { + if (!value) { + install.disable_cache = true; + install.disable_manifest_cache = true; + } + + break :load; + } + + if (cache.asString(allocator)) |value| { + install.cache_directory = value; + break :load; + } + + if (cache.data == .e_object) { + if (cache.get("disable")) |disable| { + if (disable.asBool()) |value| { + install.disable_cache = value; + } + } + + if (cache.get("disableManifest")) |disable| { + if (disable.asBool()) |value| { + install.disable_manifest_cache = value; + } + } + + if (cache.get("directory")) |directory| { + if (directory.asString(allocator)) |value| { + install.cache_directory = value; + } + } + } + } + } + } + } + if (json.get("bundle")) |bun| { if (comptime cmd == .DevCommand or cmd == .BuildCommand or cmd == .RunCommand or cmd == .AutoCommand or cmd == .BunCommand) { if (bun.get("saveTo")) |file| { @@ -108,6 +340,10 @@ pub const Bunfig = struct { } if (comptime cmd == .BunCommand) { + if (bun.get("logLevel")) |expr2| { + try this.loadLogLevel(expr2); + } + if (bun.get("entryPoints")) |entryPoints| { try this.expect(entryPoints, .e_array); const items = entryPoints.data.e_array.items.slice(); @@ -224,21 +460,6 @@ pub const Bunfig = struct { }; } - if (json.get("logLevel")) |expr| { - try this.expect(expr, .e_string); - const Matcher = strings.ExactSizeMatcher(8); - - this.bunfig.log_level = switch (Matcher.match(expr.asString(allocator).?)) { - Matcher.case("debug") => Api.MessageLevel.debug, - Matcher.case("error") => Api.MessageLevel.err, - Matcher.case("warn") => Api.MessageLevel.warn, - else => { - try this.addError(expr.loc, "Invalid log level, must be one of debug, error, or warn"); - unreachable; - }, - }; - } - Analytics.Features.bunfig = true; } diff --git a/src/cli.zig b/src/cli.zig index 38128f66e0..ed588a2cd6 100644 --- a/src/cli.zig +++ b/src/cli.zig @@ -205,6 +205,97 @@ pub const Arguments = struct { Global.exit(0); } + 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.openFileAbsoluteZ(config_path, .{ .read = true }) catch |err| { + if (auto_loaded) return; + Output.prettyErrorln("error: {s} opening config \"{s}\"", .{ + @errorName(err), + std.mem.span(config_path), + }); + Output.flush(); + 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("error: {s} reading config \"{s}\"", .{ + @errorName(err), + std.mem.span(config_path), + }); + Output.flush(); + 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(std.mem.span(config_path), contents), ctx, cmd); + } + + fn getHomeConfigPath(cwd: string, buf: *[std.fs.MAX_PATH_BYTES]u8) ?[:0]const u8 { + if (std.os.getenvZ("XDG_CONFIG_HOME")) |data_dir| { + var paths = [_]string{ data_dir, ".bunfig.toml" }; + return resolve_path.joinAbsStringBufZ(cwd, buf, &paths, .auto); + } + + if (std.os.getenvZ("HOME")) |data_dir| { + var paths = [_]string{ data_dir, ".bunfig.toml" }; + return resolve_path.joinAbsStringBufZ(cwd, buf, &paths, .auto); + } + + return null; + } + + pub fn loadConfig(allocator: std.mem.Allocator, args: clap.Args(clap.Help, ¶ms), ctx: *Command.Context, comptime cmd: Command.Tag) !void { + var config_buf: [std.fs.MAX_PATH_BYTES]u8 = undefined; + if (comptime cmd.readGlobalConfig()) { + if (getHomeConfigPath(ctx.args.absolute_working_dir, &config_buf)) |path| { + try loadConfigPath(allocator, true, path, ctx, comptime cmd); + } + } + + var config_path_: []const u8 = ""; + if (args.option("--config")) |config_path__| { + config_path_ = config_path__; + } + var auto_loaded: bool = false; + if (config_path_.len == 0 and (args.option("--config") != null or Command.Tag.always_loads_config.get(cmd))) { + config_path_ = "bunfig.toml"; + auto_loaded = true; + } + + if (config_path_.len == 0) { + return; + } + + 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 { + 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 parse(allocator: std.mem.Allocator, ctx: *Command.Context, comptime cmd: Command.Tag) !Api.TransformOptions { var diag = clap.Diagnostic{}; @@ -229,79 +320,14 @@ pub const Arguments = struct { cwd = try std.process.getCwdAlloc(allocator); } - var opts: Api.TransformOptions = ctx.args; - opts.absolute_working_dir = cwd; + ctx.args.absolute_working_dir = cwd; if (comptime Command.Tag.loads_config.get(cmd)) { - load_config: { - var config_buf: [std.fs.MAX_PATH_BYTES]u8 = undefined; - - var config_path_: []const u8 = ""; - if (args.option("--config")) |config_path__| { - config_path_ = config_path__; - } - var auto_loaded: bool = false; - if (config_path_.len == 0 and (args.option("--config") != null or Command.Tag.always_loads_config.get(cmd))) { - config_path_ = "bunfig.toml"; - auto_loaded = true; - } - - if (config_path_.len == 0) { - break :load_config; - } - - 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 { - var parts = [_]string{ cwd, config_path_ }; - config_path_ = resolve_path.joinAbsStringBuf( - cwd, - &config_buf, - &parts, - .auto, - ); - config_buf[config_path_.len] = 0; - config_path = config_buf[0..config_path_.len :0]; - } - - var config_file = std.fs.openFileAbsoluteZ(config_path, .{ .read = true }) catch |err| { - if (auto_loaded) break :load_config; - Output.prettyErrorln("error: {s} opening config \"{s}\"", .{ - @errorName(err), - std.mem.span(config_path), - }); - Output.flush(); - Global.exit(1); - }; - var contents = config_file.readToEndAlloc(allocator, std.math.maxInt(usize)) catch |err| { - if (auto_loaded) break :load_config; - Output.prettyErrorln("error: {s} reading config \"{s}\"", .{ - @errorName(err), - std.mem.span(config_path), - }); - Output.flush(); - 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(std.mem.span(config_path), contents), ctx, cmd); - opts = ctx.args; - } + try loadConfig(allocator, args, ctx, cmd); } + var opts: Api.TransformOptions = ctx.args; + var defines_tuple = try DefineColonList.resolve(allocator, args.options("--define")); if (defines_tuple.keys.len > 0) { @@ -699,6 +725,7 @@ pub const Command = struct { log: *logger.Log, allocator: std.mem.Allocator, positionals: []const string = &[_]string{}, + install: ?*Api.BunInstall = null, debug: DebugOptions = DebugOptions{}, @@ -1126,6 +1153,20 @@ pub const Command = struct { PackageManagerCommand, TestCommand, + pub fn readGlobalConfig(this: Tag) bool { + return switch (this) { + .PackageManagerCommand, .InstallCommand, .AddCommand, .RemoveCommand => true, + else => false, + }; + } + + pub fn isNPMRelated(this: Tag) bool { + return switch (this) { + .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 = true, diff --git a/src/env_loader.zig b/src/env_loader.zig index a369564248..f680ea371a 100644 --- a/src/env_loader.zig +++ b/src/env_loader.zig @@ -396,6 +396,21 @@ pub const Loader = struct { const empty_string_value: string = "\"\""; + pub fn get(this: *const Loader, key: string) ?string { + var _key = key; + if (_key.len > 0 and _key[0] == '$') { + _key = key[1..]; + } + + if (_key.len == 0) return null; + + return this.map.get(_key); + } + + pub fn getAuto(this: *const Loader, key: string) string { + return this.get(key) orelse key; + } + /// Load values from the environment into Define. /// /// If there is a framework, values from the framework are inserted with a diff --git a/src/http/header_builder.zig b/src/http/header_builder.zig index 0f33b9d4ba..18dcbe1e73 100644 --- a/src/http/header_builder.zig +++ b/src/http/header_builder.zig @@ -36,6 +36,24 @@ pub fn append(this: *HeaderBuilder, name: string, value: string) void { this.entries.appendAssumeCapacity(Headers.Kv{ .name = name_ptr, .value = value_ptr }); } +pub fn appendFmt(this: *HeaderBuilder, name: string, comptime fmt: string, args: anytype) void { + const name_ptr = Api.StringPointer{ + .offset = @truncate(u32, this.content.len), + .length = @truncate(u32, name.len), + }; + + _ = this.content.append(name); + + const value = this.content.fmt(fmt, args); + + const value_ptr = Api.StringPointer{ + .offset = @truncate(u32, this.content.len), + .length = @truncate(u32, value.len), + }; + + this.entries.appendAssumeCapacity(Headers.Kv{ .name = name_ptr, .value = value_ptr }); +} + pub fn apply(this: *HeaderBuilder, client: *HTTPClient) void { client.header_entries = this.entries; client.header_buf = this.content.ptr.?[0..this.content.len]; diff --git a/src/string_builder.zig b/src/string_builder.zig index 577fa15482..610ddd00f6 100644 --- a/src/string_builder.zig +++ b/src/string_builder.zig @@ -30,3 +30,14 @@ pub fn append(this: *StringBuilder, slice: string) string { assert(this.len <= this.cap); return result; } + +const std = @import("std"); +pub fn fmt(this: *StringBuilder, comptime str: string, args: anytype) string { + assert(this.len <= this.cap); // didn't count everything + assert(this.ptr != null); // must call allocate first + + var buf = this.ptr.?[this.len..this.cap]; + const out = std.fmt.bufPrint(buf, str, args) catch unreachable; + this.len += out.len; + return out; +}