|
| 1 | +# ValidGen - GitHub Copilot Instructions |
| 2 | + |
| 3 | +## Project Overview |
| 4 | + |
| 5 | +ValidGen is a **code generation tool** for Go that creates high-performance validators as an alternative to reflection-based validation libraries. It generates validation code at build time by parsing Go structs with `validate` tags and creating corresponding validator functions. |
| 6 | + |
| 7 | +### Core Purpose |
| 8 | +- **Performance**: Generate compile-time validation code instead of runtime reflection |
| 9 | +- **Compatibility**: Compatible with `github.com/go-playground/validator` tag syntax |
| 10 | +- **Code Generation**: Creates `*_validator.go` files with validation functions |
| 11 | + |
| 12 | +## Project Structure & Architecture |
| 13 | + |
| 14 | +``` |
| 15 | +validgen/ |
| 16 | +├── main.go # CLI entry point - takes path argument |
| 17 | +├── validgen/ # Core code generation package |
| 18 | +│ ├── find_files.go # File discovery and processing |
| 19 | +│ ├── parse_file.go # AST parsing of Go files |
| 20 | +│ ├── struct.go # Struct representation and template generation |
| 21 | +│ ├── code_generator.go # Main code generation orchestration |
| 22 | +│ ├── if_code.go # Validation code building |
| 23 | +│ ├── parser_validation.go # Validation tag parsing |
| 24 | +│ └── test_elements.go # Test condition building |
| 25 | +├── types/ # Common types and error handling |
| 26 | +├── _examples/ # Example usage and test cases |
| 27 | +└── tests/ # Integration, unit, and benchmark tests |
| 28 | +``` |
| 29 | + |
| 30 | +## Code Style & Conventions |
| 31 | + |
| 32 | +### Go Code Standards |
| 33 | +- **Package naming**: Use lowercase, single-word package names |
| 34 | +- **Function naming**: PascalCase for exported functions, camelCase for internal |
| 35 | +- **Error handling**: Always return errors explicitly, use `log.Fatal()` in main package only |
| 36 | +- **Struct fields**: PascalCase with appropriate struct tags |
| 37 | + |
| 38 | +### Validation Tag Format |
| 39 | +```go |
| 40 | +type User struct { |
| 41 | + Name string `validate:"required,min=2,max=50"` |
| 42 | + Email string `validate:"required,email"` |
| 43 | + Age int `validate:"gte=0,lte=120"` |
| 44 | +} |
| 45 | +``` |
| 46 | + |
| 47 | +### Generated Code Patterns |
| 48 | +- **File naming**: `{structname}_validator.go` (lowercase) |
| 49 | +- **Function naming**: `{StructName}Validate(obj *{StructName}) []error` |
| 50 | +- **Header comment**: `// Code generated by ValidGen. DO NOT EDIT.` |
| 51 | +- **Package**: Same as source struct package |
| 52 | +- **Import**: Always import `github.com/opencodeco/validgen/types` for errors |
| 53 | + |
| 54 | +### Template Structure |
| 55 | +```go |
| 56 | +// Generated validator functions follow this pattern: |
| 57 | +func UserValidate(obj *User) []error { |
| 58 | + var errs []error |
| 59 | + |
| 60 | + // Validation conditions with error accumulation |
| 61 | + if !(condition) { |
| 62 | + errs = append(errs, types.NewValidationError("message")) |
| 63 | + } |
| 64 | + |
| 65 | + return errs |
| 66 | +} |
| 67 | +``` |
| 68 | + |
| 69 | +## Supported Validation Rules |
| 70 | + |
| 71 | +### String Validations |
| 72 | +- `required` - Field cannot be empty string |
| 73 | +- `eq=value` - Must equal specific value |
| 74 | +- `eq_ignore_case=value` - Must equal value (case insensitive) |
| 75 | +- `neq=value` - Must not equal specific value |
| 76 | +- `neq_ignore_case=value` - Must not equal value (case insensitive) |
| 77 | +- `min=N` - Minimum length N characters |
| 78 | +- `max=N` - Maximum length N characters |
| 79 | +- `len=N` - Exact length N characters |
| 80 | +- `in=val1 val2 val3` - Must be one of specified values |
| 81 | + |
| 82 | +### Numeric Validations |
| 83 | +- `required` - Field cannot be zero value |
| 84 | +- `gt=N` - Greater than N |
| 85 | +- `gte=N` - Greater than or equal to N |
| 86 | +- `lt=N` - Less than N |
| 87 | +- `lte=N` - Less than or equal to N |
| 88 | + |
| 89 | +## Development Guidelines |
| 90 | + |
| 91 | +### Adding New Validations |
| 92 | +1. **Update parser**: Add validation to `expectedValuesCount` map in `parser_validation.go` |
| 93 | +2. **Add test elements**: Implement condition building in `test_elements.go` |
| 94 | +3. **Add tests**: Create test cases in `tests/endtoend/` directory |
| 95 | +4. **Update documentation**: Add to README.md validation list |
| 96 | + |
| 97 | +### Testing Strategy |
| 98 | +- **Unit tests**: Test individual validation parsing and code generation |
| 99 | +- **Integration tests**: Test complete struct validation generation |
| 100 | +- **End-to-end tests**: Test full CLI workflow with real Go files |
| 101 | +- **Benchmark tests**: Performance comparison with reflection-based validators |
| 102 | + |
| 103 | +### File Processing Workflow |
| 104 | +1. `FindFiles()` - Recursively discover `.go` files |
| 105 | +2. `parseFile()` - Parse AST to extract structs with validate tags |
| 106 | +3. `generateCode()` - Generate validator functions for valid structs |
| 107 | +4. Write `*_validator.go` files in same directories as source |
| 108 | + |
| 109 | +### Error Handling Patterns |
| 110 | +- **Validation errors**: Use `types.NewValidationError()` for user-facing errors |
| 111 | +- **Internal errors**: Return standard Go errors for development issues |
| 112 | +- **Fatal errors**: Use `log.Fatal()` only in main package for CLI errors |
| 113 | + |
| 114 | +## Best Practices for Contributors |
| 115 | + |
| 116 | +### Code Generation |
| 117 | +- **Template driven**: Use Go templates for consistent code generation |
| 118 | +- **Type awareness**: Handle different Go types (string, numeric, custom types) |
| 119 | +- **Package preservation**: Generated code must be in same package as source |
| 120 | +- **Import management**: Only import necessary packages in generated code |
| 121 | + |
| 122 | +### Performance Considerations |
| 123 | +- **No reflection**: Generated code should never use reflection |
| 124 | +- **Minimal allocations**: Efficient error collection and string operations |
| 125 | +- **Compile-time validation**: All validation logic determined at generation time |
| 126 | + |
| 127 | +### Testing Requirements |
| 128 | +- **Generated code tests**: Verify generated validators work correctly |
| 129 | +- **Cross-package support**: Test structs in different packages |
| 130 | +- **Edge cases**: Empty structs, no validation tags, invalid tags |
| 131 | +- **Performance benchmarks**: Compare against reflection-based alternatives |
| 132 | + |
| 133 | +### Documentation Standards |
| 134 | +- **Generated code comments**: Include generation warning in all generated files |
| 135 | +- **Function documentation**: Document validation functions if exported |
| 136 | +- **Example usage**: Provide clear examples in `_examples/` directory |
| 137 | + |
| 138 | +## CLI Usage Patterns |
| 139 | + |
| 140 | +```bash |
| 141 | +# Generate validators for all Go files in directory |
| 142 | +./bin/validgen /path/to/project |
| 143 | + |
| 144 | +# Typical development workflow |
| 145 | +make build # Build the binary |
| 146 | +make endtoendtests # Run full test suite |
| 147 | +make benchtests # Run performance benchmarks |
| 148 | +``` |
| 149 | + |
| 150 | +## When Working on ValidGen |
| 151 | + |
| 152 | +1. **Always regenerate test validators** after code changes using `make endtoendtests` |
| 153 | +2. **Run benchmarks** to ensure performance improvements with `make benchtests` |
| 154 | +3. **Test multiple packages** - structs in different packages should work correctly |
| 155 | +4. **Validate generated code** - ensure it compiles and passes tests |
| 156 | +5. **Maintain compatibility** - keep validator tag syntax compatible where possible |
| 157 | + |
| 158 | +## Important Notes |
| 159 | + |
| 160 | +- **Early stage project**: Not suitable for production use yet |
| 161 | +- **Go version**: Requires Go 1.24 or higher |
| 162 | +- **Template-based**: Core generation logic uses Go text templates |
| 163 | +- **Error accumulation**: Validators return slice of errors, not single error |
| 164 | +- **Zero values**: Different types have different "required" validation logic |
0 commit comments