|
| 1 | +# CLAUDE.md |
| 2 | + |
| 3 | +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. |
| 4 | + |
| 5 | +## Project Overview |
| 6 | + |
| 7 | +`enum` is a Go code generator that creates type-safe, marshalable enum implementations from simple type definitions. It generates idiomatic Go code with zero runtime dependencies and supports JSON, SQL, MongoDB BSON, and YAML marshaling through optional flags. |
| 8 | + |
| 9 | +## Commands |
| 10 | + |
| 11 | +### Build and Test |
| 12 | +```bash |
| 13 | +# Run all tests (excludes examples) |
| 14 | +go test ./... |
| 15 | + |
| 16 | +# Run tests with race detection and coverage |
| 17 | +go test -race -cover ./... |
| 18 | + |
| 19 | +# Run a specific test |
| 20 | +go test -run TestRuntimeIntegration ./internal/generator |
| 21 | + |
| 22 | +# Run integration tests (includes MongoDB container tests) |
| 23 | +go test ./internal/generator -v -run TestRuntimeIntegration |
| 24 | + |
| 25 | +# Build the enum generator |
| 26 | +go build |
| 27 | + |
| 28 | +# Install globally |
| 29 | +go install github.com/go-pkgz/enum@latest |
| 30 | +``` |
| 31 | + |
| 32 | +### Linting and Formatting |
| 33 | +```bash |
| 34 | +# Run linter (golangci-lint v2.0.2) |
| 35 | +golangci-lint run |
| 36 | + |
| 37 | +# Format code |
| 38 | +gofmt -s -w . |
| 39 | +goimports -w . |
| 40 | +``` |
| 41 | + |
| 42 | +### Generate Enums |
| 43 | +```bash |
| 44 | +# Generate using go:generate directives |
| 45 | +go generate ./... |
| 46 | + |
| 47 | +# Direct invocation examples |
| 48 | +go run github.com/go-pkgz/enum@latest -type status -lower |
| 49 | +go run github.com/go-pkgz/enum@latest -type status -lower -sql -bson -yaml |
| 50 | +``` |
| 51 | + |
| 52 | +## Architecture |
| 53 | + |
| 54 | +### Core Components |
| 55 | + |
| 56 | +1. **main.go** - CLI entry point that parses flags and invokes the generator |
| 57 | +2. **internal/generator/generator.go** - Core generator logic: |
| 58 | + - Parses Go AST to find enum constants |
| 59 | + - Evaluates constant values including iota and binary expressions |
| 60 | + - Generates code from template with conditional blocks for features |
| 61 | +3. **internal/generator/enum.go.tmpl** - Go template for generated code with conditional sections for SQL/BSON/YAML |
| 62 | + |
| 63 | +### Key Design Decisions |
| 64 | + |
| 65 | +1. **Type name must be lowercase (private)** - Enforced to prevent confusion with public types |
| 66 | +2. **Constants must be prefixed with type name** - Ensures clear namespacing (e.g., `statusActive` for type `status`) |
| 67 | +3. **Generated public types are capitalized** - Follows Go conventions (private `status` → public `Status`) |
| 68 | +4. **Zero runtime dependencies** - Generated code uses only stdlib unless optional features are enabled |
| 69 | +5. **Conditional feature generation** - SQL/BSON/YAML code only generated when flags are set to avoid forcing dependencies |
| 70 | + |
| 71 | +### Integration Support |
| 72 | + |
| 73 | +- **JSON**: Via `encoding.TextMarshaler`/`TextUnmarshaler` (always generated) |
| 74 | +- **SQL** (`-sql` flag): Implements `database/sql/driver.Valuer` and `sql.Scanner` |
| 75 | + - Smart NULL handling: uses zero value if available, errors otherwise |
| 76 | +- **BSON** (`-bson` flag): Implements `MarshalBSONValue`/`UnmarshalBSONValue` for MongoDB |
| 77 | + - Stores as string values, not documents |
| 78 | +- **YAML** (`-yaml` flag): Implements `yaml.Marshaler`/`yaml.Unmarshaler` for gopkg.in/yaml.v3 |
| 79 | + |
| 80 | +### Testing Strategy |
| 81 | + |
| 82 | +1. **Unit tests** (`generator_test.go`): Test parsing, generation, edge cases |
| 83 | +2. **Integration tests** (`integration_test.go`): |
| 84 | + - `TestRuntimeIntegration`: Full pipeline test that builds binary, generates code, runs tests with real databases |
| 85 | + - Uses testcontainers for MongoDB integration testing |
| 86 | + - SQLite for SQL testing (in-memory) |
| 87 | +3. **Test data** in `testdata/integration/`: |
| 88 | + - `enum_test.go`: Real database tests run by runtime integration |
| 89 | + - `status.go`, `priority.go`: Sample enums for testing |
| 90 | + |
| 91 | +### Parsing and Generation Flow |
| 92 | + |
| 93 | +1. Parse Go source files to find type definition |
| 94 | +2. Extract constants prefixed with type name |
| 95 | +3. Evaluate constant values: |
| 96 | + - Handle iota increments |
| 97 | + - Evaluate binary expressions (e.g., `iota + 1`, `1 << iota`) |
| 98 | + - Support explicit values |
| 99 | +4. Generate code with: |
| 100 | + - String() method |
| 101 | + - Parse/Must functions |
| 102 | + - Marshal/Unmarshal methods based on flags |
| 103 | + - Iterator for Go 1.23+ range-over-func |
| 104 | + - Optional GetByID function (requires unique values) |
| 105 | + |
| 106 | +## Important Constraints |
| 107 | + |
| 108 | +1. **Enum type must be lowercase** - Generator validates and rejects uppercase type names |
| 109 | +2. **Constants must start with type name** - e.g., for type `status`, constants must be `statusXxx` |
| 110 | +3. **Unique IDs required for -getter flag** - Generator fails if duplicate values exist when getter is requested |
| 111 | +4. **Declaration order preserved** - Enums maintain source order, not alphabetical |
| 112 | +5. **Type fidelity** - Generated code preserves underlying type (uint8, int32, etc.) |
| 113 | + |
| 114 | +## CI/CD |
| 115 | + |
| 116 | +GitHub Actions workflow (`.github/workflows/ci.yml`): |
| 117 | +- Runs on all pushes and PRs |
| 118 | +- Tests with Go 1.24 |
| 119 | +- Runs tests with race detection and coverage |
| 120 | +- Runs golangci-lint |
| 121 | +- Submits coverage to Coveralls |
| 122 | +- Tests examples separately |
| 123 | + |
| 124 | +## Integration Testing Architecture |
| 125 | + |
| 126 | +### Test Structure |
| 127 | +The integration tests use a unique two-stage approach: |
| 128 | + |
| 129 | +1. **`TestRuntimeIntegration`** in `integration_test.go`: |
| 130 | + - Builds the enum binary from source |
| 131 | + - Creates a temporary package with enum definitions |
| 132 | + - Runs the built binary to generate enum code |
| 133 | + - Creates a temporary `go.mod` with test dependencies |
| 134 | + - Copies test file from `testdata/integration/enum_test.go` |
| 135 | + - Runs the generated tests in isolation |
| 136 | + |
| 137 | +2. **Actual database tests** in `testdata/integration/enum_test.go`: |
| 138 | + - `TestGeneratedEnumWithMongoDB`: Uses `github.com/go-pkgz/testutils` to spin up MongoDB 7 container |
| 139 | + - `TestGeneratedEnumWithSQL`: Uses in-memory SQLite for SQL testing |
| 140 | + - Tests real marshal/unmarshal operations, not just code generation |
| 141 | + |
| 142 | +### Key Integration Test Patterns |
| 143 | + |
| 144 | +1. **Test files in testdata are NOT compiled by Go** - They're copied and run in temp directory |
| 145 | +2. **MongoDB container via testutils**: |
| 146 | + ```go |
| 147 | + mongoContainer := containers.NewMongoTestContainer(ctx, t, 7) |
| 148 | + defer mongoContainer.Close(ctx) |
| 149 | + coll := mongoContainer.Collection("test_db") |
| 150 | + ``` |
| 151 | +3. **Verifies storage format** - Confirms enums stored as strings in MongoDB, not empty documents |
| 152 | +4. **Full round-trip testing** - Writes enum to database, reads back, verifies correct unmarshaling |
| 153 | + |
| 154 | +### Running Integration Tests |
| 155 | +```bash |
| 156 | +# Run full integration test (builds binary, generates code, tests with real databases) |
| 157 | +go test ./internal/generator -v -run TestRuntimeIntegration |
| 158 | + |
| 159 | +# Skip integration tests in short mode |
| 160 | +go test -short ./... |
| 161 | + |
| 162 | +# Clean test cache before running to ensure fresh MongoDB container |
| 163 | +go clean -testcache && go test ./internal/generator -v -run TestRuntimeIntegration |
| 164 | +``` |
| 165 | + |
| 166 | +### Test Dependencies |
| 167 | +Integration tests require: |
| 168 | +- Docker for MongoDB containers (via testcontainers) |
| 169 | +- Network access for go mod tidy in temp package |
| 170 | +- Write access to temp directory for generated code |
| 171 | + |
| 172 | +### Important Testing Details |
| 173 | +- `TestMongoDBIntegration` in main `integration_test.go` only verifies code generation, not actual MongoDB |
| 174 | +- Real MongoDB testing happens via `TestRuntimeIntegration` → `TestGeneratedEnumWithMongoDB` |
| 175 | +- Tests verify both success and error paths (NULL handling, invalid values) |
| 176 | +- Uses `require` for critical assertions, `assert` for non-critical ones |
0 commit comments