All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
- Added
ZodSchemaimpls foru8,u16,i8,i16: These small integer types were missing despite the README claiming "built-in support for all common Rust types". They map toz.number(), matching the existing impls fori32,i64,u32,u64,f32,f64. This unblocks the#[derive(ZodSchema)]macro on enums and structs that contain small-integer fields (e.g. byte-level protocols, packed bitfields, layer indices).
- Added core numeric primitive coverage in
zod_gen/src/lib.rs - Added derive integration coverage for small-integer struct and enum fields in
zod_gen_derive/tests/derive_tests.rs
- Serde enum representations: support externally tagged, internally tagged, adjacently tagged, and untagged enums in the derive macro
- Zod helpers: added
z.intersection(...)to model internally tagged newtype flattening - Diagnostics: improved compile-time validation for invalid serde tagging combinations
- Expanded README and crate docs with enum representation behavior and examples
- Updated derive example to showcase internally and adjacently tagged enums
- GitHub Actions CI/CD: Comprehensive automation for testing, releases, and maintenance
ci.yml: Full test suite on multiple Rust versions, formatting, clippy, docs, security audit, coveragerelease.yml: Automated publishing to crates.io when tags are pushedpr.yml: PR validation with breaking change detection, commit message validation, CHANGELOG checksdependencies.yml: Weekly dependency updates and security auditsdocs.yml: Automatic documentation deployment to GitHub Pages
- Automated Testing: Tests run on stable, beta, and nightly Rust
- Code Quality: Automated formatting, clippy lints, and documentation checks
- Security: Weekly security audits with automatic issue creation
- Release Automation: Tag-triggered releases with automatic crates.io publishing
- Documentation: Auto-deployed docs at GitHub Pages
- Update Version: Bump version in
Cargo.tomlworkspace - Update CHANGELOG: Document all changes in this file
- Update README: Update version numbers in installation instructions
- Commit:
git add . && git commit -m "Release vX.Y.Z" - Tag:
git tag vX.Y.Z - Push:
git push origin main --tags - Automated: GitHub Actions will automatically:
- Run full test suite
- Publish to crates.io
- Create GitHub release with changelog
To release a new version manually:
- Update Version: Bump version in
Cargo.tomlworkspace - Update CHANGELOG: Document all changes in this file
- Update README: Update version numbers in installation instructions
- Test: Run
cargo testto ensure all tests pass - Commit:
git add . && git commit -m "Release vX.Y.Z" - Tag:
git tag vX.Y.Z - Push:
git push origin main --tags - Publish:
cargo publish -p zod_gen_derive && cargo publish -p zod_gen
- Major (X.0.0): Breaking API changes
- Minor (X.Y.0): New features, backward compatible
- Patch (X.Y.Z): Bug fixes, backward compatible
- Extended serde rename to struct fields: Previously only enum variants supported
#[serde(rename = "...")], now struct fields do too- Struct fields with
#[serde(rename = "new_name")]generate TypeScript schemas with the renamed field names - Ensures perfect alignment between Rust serialization and TypeScript types for structs
- Example:
#[serde(rename = "userName")]generatesuserName: z.string()instead ofuser_name: z.string() - Thanks to @julienr for this contribution!
- Struct fields with
- Deterministic output for CI workflows: Switched from
HashMaptoBTreeMapfor schema storage- Generated TypeScript files now have stable, alphabetically sorted schema ordering
- Eliminates spurious diffs in version control when schemas are checked in
- Essential for CI workflows that validate generated files match committed versions
- Thanks to @julienr for this contribution!
- Refactored attribute parsing to use idiomatic
&[Attribute]slice parameter - Moved
serdedependency to dev-dependencies (only needed for tests) - Added comprehensive test coverage for struct field renaming
- Enhanced
serde_rename_test.rsto demonstrate struct field renaming - Added test case
test_struct_rename()in derive tests
- Comprehensive Crate Documentation: Added detailed module documentation prominently featuring the derive macro
- TypeScript Output Examples: Show exactly what gets generated from Rust types
- Installation Guide: Clear instructions for using both
zod_genandzod_gen_derivetogether - Usage Examples: Both derive macro (recommended) and manual implementation approaches
- Crates.io Description: Updated to mention
zod_gen_derivefor better discoverability
This release makes it much clearer to new users that zod_gen_derive is the recommended way to use the library, addressing feedback about the crates.io page.
This release focuses on improving the development experience and ensuring consistency between local development and CI environments.
- Native Git Pre-commit Hook: Automatically runs rustfmt, clippy, tests, and example verification before each commit
- Rust Toolchain Pinning: Added
rust-toolchain.tomlto ensure consistent Rust version across environments - CI Consistency Scripts:
scripts/clippy-ci.sh- Run clippy with exact CI flags locallyscripts/debug-clippy.sh- Troubleshoot clippy differences between local and CI
- Development Documentation: Comprehensive
DEVELOPMENT.mdwith setup and troubleshooting guides - Hook Setup Script:
scripts/setup-hooks.shfor verifying pre-commit hook installation
- API Cleanup: Simplified
zod_gen/src/lib.rsby removing unused wrapper methods - Format String Compliance: Updated format strings in
zod_gen_deriveto comply withclippy::uninlined-format-args - Enhanced README: Added development tooling section with links to new documentation
- CI Consistency: Resolved local vs CI clippy differences that could cause unexpected CI failures
- Code Quality: Ensured all code passes strict clippy lints matching CI configuration
This release ensures developers can't accidentally commit code that will fail CI, significantly improving the development workflow.
1.1.0 - 2025-07-30
- Serde Rename Support: Full support for
#[serde(rename = "...")]attributes on enum variants- TypeScript schemas now use the renamed values instead of Rust variant names
- Provides compile-time type safety between Rust serialization and TypeScript
- Example:
#[serde(rename = "active")]generatesz.literal("active")instead ofz.literal("Active")
- Comprehensive Examples: Added
serde_rename_test.rsdemonstrating rename functionality - Better Documentation: Updated README with serde rename examples and use cases
This feature closes the gap between Rust serialization and TypeScript type checking, ensuring developers can't accidentally use incorrect string literals.
1.0.0 - 2025-07-29
This is the first stable release of zod_gen with a clean, simplified API.
- ZodSchema Trait: Simple trait with only
zod_schema()method - Derive Macro:
#[derive(ZodSchema)]for automatic schema generation - ZodGenerator: Single-file TypeScript output with user-controlled naming
- Generic Type Support: Built-in support for
Option<T>,Vec<T>,HashMap<String, T> - Inline Schemas: Self-contained schemas with no external dependencies
- TypeScript Integration: Automatic type inference using
z.infer<typeof Schema>
String,i32,i64,u32,u64,f32,f64,boolserde_json::Value
Option<T>→T.nullable()Vec<T>→z.array(T)HashMap<String, T>→z.record(z.string(), T)
- Structs with named fields →
z.object({ ... }) - Enums with unit variants →
z.union([z.literal('A'), z.literal('B')])
// Manual implementation
impl ZodSchema for MyType {
fn zod_schema() -> String {
// Return Zod schema string
}
}
// Derive macro
#[derive(ZodSchema)]
struct User {
id: u64,
name: String,
}
// Generator
let mut gen = ZodGenerator::new();
gen.add_schema::<User>("User");
let typescript = gen.generate();- Simplicity: Minimal API surface with maximum functionality
- User Control: Users provide TypeScript type names explicitly
- Single Responsibility: Library only generates Zod schemas
- Zero Magic: Predictable behavior with no hidden complexity
- TypeScript First: Designed for seamless Zod integration
1.1.0 - 2025-07-30
- Serde Rename Support: Automatic handling of
#[serde(rename = "...")]attributes on enum variants- Enum variants with serde rename generate TypeScript literal types using the renamed values
- Ensures perfect alignment between Rust serialization and TypeScript types
- Provides compile-time type safety to catch serialization mismatches
- TypeScript now catches typos when using enum values (e.g.,
'Active'vs'active') - Generated schemas use serde-renamed values for runtime validation
- Maintains backward compatibility for enums without serde rename
#[derive(ZodSchema, Serialize, Deserialize)]
enum Status {
#[serde(rename = "active")]
Active,
#[serde(rename = "inactive")]
Inactive,
}Generates:
export const StatusSchema = z.union([z.literal('active'), z.literal('inactive')]);
export type Status = z.infer<typeof StatusSchema>;- Fixed Version Display in Release Workflow: Corrected double
vprefix in logging messages- Changed
v${VERSION}to${VERSION}sincegithub.ref_namealready includesvprefix - Prevents confusion in release logs and ensures proper version tracking
- This fixes the "vv1.1.6" issue seen in release logs
- Changed
- Updated
.github/workflows/release.ymlwait step logging - Removed duplicate
vprefix from version display messages - No API changes, only release process improvement
- Fixed GitHub Actions Release Workflow: Resolved dependency order issue in automated releases
- Updated dry run validation to only check
zod_gensincezod_gen_derivedepends on unpublished version - Replaced fixed 30-second wait with intelligent polling that checks crates.io availability
- Fixed version pattern matching to handle
v1.1.6vs1.1.6format differences - Ensures reliable automated releases for future versions
- Updated dry run validation to only check
- Modified
.github/workflows/release.ymlto handle package dependencies correctly - Added intelligent version availability checking with retry logic
- Improved error handling and logging in release workflow
- This change only affects the release process, not the library API
- Parcel Bundler Compatibility: Fixed import statement generation to use
import * as z from 'zod';instead ofimport { z } from 'zod';- Resolves runtime error
i.z.string is not a functionwhen bundled with Parcel - Ensures Zod validation works correctly in Parcel-based applications
- Maintains full backward compatibility with existing functionality
- Resolves runtime error
- Updated
ZodGenerator::generate()method inzod_gen/src/lib.rs - Updated all documentation examples to use the correct import format
- Updated tests to verify the new import statement
- This change affects generated TypeScript files but maintains API compatibility
- Fixed Version Availability Check: Replaced unreliable
cargo search | grepwithcargo info --versionfor checking package availability- Resolves issue where
cargo searchdoesn't return packages in expected format in GitHub Actions environment - Uses
cargo info zod_gen --version ${VERSION}which returns proper exit codes for version existence - Ensures reliable automated releases by eliminating dependency on output format parsing
- Fixes the "did not become available after 2 minutes" error in release workflow
- Resolves issue where
- Updated
.github/workflows/release.ymlwait step to usecargo infoinstead ofcargo search - More reliable version checking that doesn't depend on parsing output format
- No API changes, only release process improvement
- Fixed Version Availability Check: Updated to use
cargo info zod_gen | grep -q "version: ${VERSION_WITHOUT_V}"for reliable package availability detection- This approach is more reliable than previous attempts as it uses the standard cargo info output format
- Resolves the persistent "did not become available after 2 minutes" error in GitHub Actions
- Ensures automated releases work consistently by checking for the version string in cargo info output
- Final fix for the release workflow that was causing multiple release failures
- Updated
.github/workflows/release.ymlline 85 with the correct cargo info and grep pattern - Uses the standard cargo info output format which includes "version: X.Y.Z" line
- No API changes, only release process improvement
- Fixed Local vs Registry Version Confusion: Updated
cargo infoto use--registry crates-ioflag to force checking published version instead of local version- Previous attempts were failing because
cargo info zod_genwas returning the local project version(from ./zod_gen)instead of the crates.io published version - The
--registry crates-ioflag ensures cargo checks the actual published version on crates.io - This should finally resolve the persistent "did not become available after 2 minutes" error
- Removes debug output line that was added for troubleshooting
- Previous attempts were failing because
- Updated
.github/workflows/release.ymlto usecargo info --registry crates-io zod_gen - Forces cargo to check the registry version instead of finding the local project
- No API changes, only release process improvement
- Fixed Missing Registry Flag: Properly applied
--registry crates-ioflag to both cargo info commands in the release workflow- Previous fix was incomplete - the debug line still used
cargo info zod_genwithout the registry flag - Now both the debug output (removed) and the actual check use
--registry crates-ioto ensure consistent behavior - Removes the debug output line that was showing local version instead of registry version
- This should finally resolve the version availability check issue
- Previous fix was incomplete - the debug line still used
- Updated
.github/workflows/release.ymlto properly apply--registry crates-ioflag - Removed debug output line that was causing confusion
- Ensures all cargo info commands check the registry version, not local version
- No API changes, only release process improvement
- Fixed Version Availability Check: Changed from grep pattern matching to using
cargo info --versionwith exit code checking- Previous approach using
grep -q "version: ${VERSION_WITHOUT_V}"was unreliable in GitHub Actions environment - New approach uses
cargo info --registry crates-io zod_gen --version ${VERSION_WITHOUT_V}which returns proper exit codes - If the specific version exists, the command succeeds (exit code 0); if not, it fails (non-zero exit code)
- This is more reliable than parsing output format and should work consistently across environments
- Previous approach using
- Updated
.github/workflows/release.ymlto usecargo info --versioninstead of grep pattern matching - Uses exit code checking instead of output parsing for version availability
- More robust approach that doesn't depend on output format variations
- No API changes, only release process improvement
- Fixed Version Pattern Matching: Updated grep pattern to use exact line matching with
^version: ${VERSION_WITHOUT_V}$- Previous attempt used non-existent
--versionflag for cargo info command - New approach uses exact line matching to ensure we match the complete version line
- Added
2>/dev/nullto suppress error messages and focus on successful output - Uses
^and$anchors to match the entire line exactly, preventing partial matches
- Previous attempt used non-existent
- Updated
.github/workflows/release.ymlto usegrep -q "^version: ${VERSION_WITHOUT_V}$" - Removed invalid
--versionflag from cargo info command - Added error suppression to clean up output
- Uses exact line matching for more reliable version detection
- No API changes, only release process improvement
- Added Debug Output to Version Check: Enhanced the version availability check with comprehensive debugging information
- Added debug output to show VERSION and VERSION_WITHOUT_V variables
- Added debug output to display the actual cargo info command output
- Added debug output to show the exact grep pattern being searched for
- Added debug output to indicate whether pattern matching succeeded or failed
- This will help identify the exact cause of version availability check failures
- Debug information will be visible in GitHub Actions logs for troubleshooting
- Updated
.github/workflows/release.ymlto include comprehensive debug output - Shows variable values, command output, and pattern matching results
- No API changes, only release process improvement and debugging enhancement
- Fixed Pattern Matching with Status Messages: Added filtering to exclude cargo status messages from version pattern matching
- Debug output revealed that cargo status messages ("Updating crates.io index", "Downloading crates...", "Downloaded zod_gen") were interfering with pattern matching
- The package was actually available and showing
version: 1.1.14but the grep pattern wasn't matching due to mixed output - Added
grep -v "Updating\|Downloading\|Downloaded"to filter out status messages before pattern matching - This should finally allow the version availability check to work correctly
- Updated
.github/workflows/release.ymlto filter cargo status messages before version pattern matching - Uses
grep -vto exclude status lines, thengrep -qto match the version pattern - Debug output helped identify the exact cause of pattern matching failure
- No API changes, only release process improvement
- Added Enhanced Debug Output: Added more comprehensive debugging to identify pattern matching issues
- Shows filtered output after removing status messages
- Shows lines containing 'version:' specifically
- Added whitespace trimming with sed to handle potential leading/trailing spaces
- This will help identify if there are hidden characters or formatting issues preventing pattern matching
- Previous debug showed the version line was present but pattern matching still failed
- Updated
.github/workflows/release.ymlwith enhanced debug output and whitespace handling - Added sed commands to trim leading and trailing whitespace from filtered output
- Shows both filtered output and specific version lines for detailed troubleshooting
- No API changes, only release process improvement and debugging enhancement
- Fixed Version Pattern Matching: Changed from exact line pattern to specific version line matching
- Debug output revealed there are multiple lines containing 'version:' (
version: 1.1.16andrust-version: unknown) - The exact line pattern
^version: ${VERSION_WITHOUT_V}$was failing despite the correct line being present - New approach uses
grep "^version: " | grep -q "${VERSION_WITHOUT_V}"to first isolate the version line, then check for the version number - This should finally resolve the pattern matching issue that was preventing version availability detection
- Debug output revealed there are multiple lines containing 'version:' (
- Updated
.github/workflows/release.ymlto use two-stage grep for version line matching - First grep isolates lines starting with "version: " (excluding "rust-version:")
- Second grep checks if the version number is present in that line
- More robust approach that handles multiple version-related lines in cargo info output
- No API changes, only release process improvement
- Replaced Complex Version Detection with Simple Retry: Eliminated the problematic version availability check in favor of direct publish retry
- Removed all the complex cargo info parsing, pattern matching, and debug output that was consistently failing
- New approach simply retries
cargo publish -p zod_gen_deriveup to 12 times with 10-second intervals - If
zod_genis available, the publish succeeds immediately; if not, it fails and retries - Much simpler, more reliable approach that lets cargo handle the dependency resolution
- Eliminates all the pattern matching issues we've been debugging
- Updated
.github/workflows/release.ymlto use direct publish retry instead of version detection - Removed complex cargo info parsing and grep pattern matching logic
- Uses cargo's built-in dependency resolution to determine when zod_gen is available
- Retries up to 12 times (2 minutes) with clear logging of each attempt
- No API changes, only release process simplification and improvement
- Fixed cargo upgrade command: Removed invalid
--workspaceflag fromcargo upgradein dependencies workflow- The
cargo upgradecommand from cargo-edit doesn't support the--workspaceflag - Updated
.github/workflows/dependencies.ymlto usecargo upgradewithout the flag - This fixes the weekly dependency update automation that was failing due to the invalid flag
- Also cleaned up trailing whitespace in the workflow file
- The
- Added AI Agent Debugging Guide: Added comprehensive documentation about "Let it crash" debugging philosophy
ai-agent-prompt.md: Guide for AI agents on embracing failure as signal rather than avoiding itlet-it-crash-lesson.md: Real-world lesson from 18 failed release attempts and the breakthrough solution- Documents the anti-pattern of complex failure avoidance vs. simple retry mechanisms
- Updated dependencies workflow to use correct cargo-edit syntax
- No API changes, only CI/CD process improvement and documentation additions