Skip to content

Commit b6c4272

Browse files
committed
Make env variable name default to field name if key is missing when
using custom parsers - Bump version to 0.8.0
1 parent 5bfe982 commit b6c4272

File tree

3 files changed

+37
-3
lines changed

3 files changed

+37
-3
lines changed

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ const Config = struct {
149149
150150
const env = .{
151151
.port = .{
152-
.key = "PORT",
152+
.key = "PORT", // .key can be omitted to use field name automatically
153153
.parser = env_struct.validator(u32, validatePort),
154154
},
155155
};
@@ -190,6 +190,8 @@ const Config = struct {
190190
```
191191

192192
**Key Points:**
193+
- `.key` is the environment variable name, can be omitted to use the field name
194+
- `.parser` is the custom parser function, can be a validator or a full custom parser
193195
- Use `validator()` when you want default parsing + validation
194196
- Use custom parsers for complex parsing that doesn't follow default rules
195197
- All custom parsers use the signature: `fn(raw: []const u8, allocator: Allocator) !T`

build.zig.zon

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
// This is a [Semantic Version](https://semver.org/).
1212
// In a future version of Zig it will be used for package deduplication.
13-
.version = "0.7.0",
13+
.version = "0.8.0",
1414

1515
// Together with name, this represents a globally unique package
1616
// identifier. This field is generated by the Zig toolchain when the

src/env_struct.zig

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ fn getEnvKey(comptime field_name: []const u8, comptime T: type) ?[]const u8 {
9393
return if (std.mem.eql(u8, env_config.key, "-")) null else env_config.key;
9494
}
9595

96-
@compileError("Invalid env config for field '" ++ field_name ++ "'");
96+
return field_name;
9797
}
9898

9999
fn hasCustomParser(comptime field_name: []const u8, comptime T: type) bool {
@@ -445,6 +445,8 @@ test "custom parsers and validators" {
445445
log_level: LogLevel,
446446
validated_port: u32,
447447
tags: [][]const u8,
448+
auto_port: u32,
449+
auto_log_level: LogLevel,
448450

449451
const env = .{
450452
.port = .{
@@ -463,15 +465,24 @@ test "custom parsers and validators" {
463465
.key = "TAGS",
464466
.parser = parseStringArray,
465467
},
468+
.auto_port = .{
469+
.parser = validator(u32, validatePort),
470+
},
471+
.auto_log_level = .{
472+
.parser = parseEnum(LogLevel),
473+
},
466474
};
467475
};
468476

469477
const allocator = std.testing.allocator;
478+
470479
var env_map = try createTestEnvMap(allocator, &.{
471480
.{ .key = "PORT", .value = "8080" },
472481
.{ .key = "LOG_LEVEL", .value = "info" },
473482
.{ .key = "VALIDATED_PORT", .value = "3000" },
474483
.{ .key = "TAGS", .value = "api, web, production" },
484+
.{ .key = "auto_port", .value = "9000" },
485+
.{ .key = "auto_log_level", .value = "debug" },
475486
});
476487
defer env_map.deinit();
477488

@@ -490,12 +501,33 @@ test "custom parsers and validators" {
490501
try std.testing.expectEqualStrings("api", config.tags[0]);
491502
try std.testing.expectEqualStrings("web", config.tags[1]);
492503
try std.testing.expectEqualStrings("production", config.tags[2]);
504+
try std.testing.expectEqual(@as(u32, 9000), config.auto_port);
505+
try std.testing.expectEqual(LogLevel.debug, config.auto_log_level);
493506

494507
// Test parseValue utility with various types
495508
try std.testing.expectEqual(@as(u32, 42), try parseValue(u32, "42", allocator));
496509
try std.testing.expectEqual(@as(f32, 3.14), try parseValue(f32, "3.14", allocator));
497510
try std.testing.expect(try parseValue(bool, "true", allocator));
498511
try std.testing.expectEqualStrings("hello", try parseValue([]const u8, "hello", allocator));
512+
513+
// Test validation works with automatic key inference (using simple config to avoid memory issues)
514+
{
515+
const SimpleConfig = struct {
516+
port: u32,
517+
518+
const env = .{
519+
.port = .{
520+
.parser = validator(u32, validatePort),
521+
},
522+
};
523+
};
524+
525+
var validation_env_map = try createTestEnvMap(allocator, &.{
526+
.{ .key = "port", .value = "70000" }, // Invalid port > 65535
527+
});
528+
defer validation_env_map.deinit();
529+
try std.testing.expectError(error.InvalidPort, loadMap(SimpleConfig, validation_env_map, allocator));
530+
}
499531
}
500532

501533
test "error cases" {

0 commit comments

Comments
 (0)