feat(zod): add generateMeta to attach .meta() to component schemas (zod v4) - #3469
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (13)
✅ Files skipped from review due to trivial changes (3)
🚧 Files skipped from review as they are similar to previous changes (9)
📝 WalkthroughWalkthroughAdds a ChangesZod v4 Metadata Emission
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
Adds optional Zod v4 registry metadata emission for generated component schemas by emitting .meta({ id, description?, deprecated? }), while keeping Zod v3 behavior as .describe(...).
Changes:
- Introduces
generateMeta/emitMetaoption plumbing from config → generators → reusable schema generation. - Updates Zod schema generation to emit top-level
.meta(...)(Zod v4) and adds parsing support for themetafunction in definitions. - Adds tests and documentation for the new configuration flag.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/zod/src/zod.test.ts | Adds unit tests for .meta() emission/parsing behavior across v3/v4 and schema shapes. |
| packages/zod/src/index.ts | Implements .meta() emission (emitMeta) and parsing logic for meta in generated chains. |
| packages/orval/src/write-zod-specs.ts | Plumbs generateMeta from output options into schema generation calls. |
| packages/orval/src/write-zod-specs.test.ts | Adds integration tests ensuring generateMeta behaves correctly for v3 vs v4. |
| packages/orval/src/utils/options.ts | Normalizes the new generateMeta option into normalized output options. |
| packages/orval/src/reusable-schemas.ts | Passes generateMeta into reusable schema set generation (as emitMeta). |
| packages/core/src/types.ts | Adds generateMeta to (normalized) Zod options types. |
| packages/core/src/test-utils/context.ts | Updates test context defaults to include generateMeta: false. |
| docs/content/docs/reference/configuration/output.mdx | Documents generateMeta and its behavior/limitations. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (3)
packages/orval/src/write-zod-specs.test.ts (1)
625-639: ⚡ Quick winConsider more flexible assertions for metadata field order.
The exact string match for
.meta({ id: 'Pet', description: 'A pet', deprecated: true })will break if the field order changes (e.g., if the generator reorders fields alphabetically or changes quote style). Consider breaking this into separate assertions:- expect(result).toContain( - ".meta({ id: 'Pet', description: 'A pet', deprecated: true })", - ); + expect(result).toContain('.meta('); + expect(result).toContain("id: 'Pet'"); + expect(result).toContain("description: 'A pet'"); + expect(result).toContain('deprecated: true');This would make the test more resilient to formatting changes while still verifying all required fields are present.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/orval/src/write-zod-specs.test.ts` around lines 625 - 639, The test currently asserts an exact substring match for the generated .meta object which is brittle to field order/formatting; update the assertion in the test case that uses generateZodSchemasInline(metaBuilder(), output) so it instead checks for the presence of the individual metadata properties (e.g., that the result contains "id: 'Pet'", "description: 'A pet'", and "deprecated: true") or use a regex that tolerates any key order/spacing; locate the test block referencing createOutputOptions(), zodOverride.generateMeta, metaBuilder(), and generateZodSchemasInline and replace the strict expect(result).toContain(".meta({...})") with separate contains assertions or an order-agnostic regex check.packages/zod/src/zod.test.ts (2)
7919-8063: ⚡ Quick winConsider adding tests for partial metadata and edge cases.
The test coverage is solid for the main scenarios, but a few additional test cases would strengthen confidence:
- Partial metadata: Test when only
descriptionis present (nodeprecated), and vice versa- Modifier ordering: Verify
.meta()is placed after modifiers like.optional(),.nullable(),.default()to ensure the correct chain order- Additional schema types: Test top-level
oneOf,allOf,anyOfwith meta to ensure it works beyond objects and multi-type unions- Edge cases: Empty/whitespace-only description strings
The current tests thoroughly cover the primary happy paths and the v3/v4 split, so this is a nice-to-have rather than blocking.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/zod/src/zod.test.ts` around lines 7919 - 8063, Add additional unit tests in packages/zod/src/zod.test.ts that exercise partial metadata and edge cases: create cases where only description exists (no deprecated) and only deprecated exists to assert def.functions contains the expected meta payload via generateZodValidationSchemaDefinition and parseZodValidationSchemaDefinition; add tests that ensure .meta() appears after modifiers by building schemas with optional/nullable/default and asserting parsed.zod shows modifiers before ".meta(...)" (use the same def.functions and parsed.zod checks as existing tests); add top-level oneOf/allOf/anyOf schemas to confirm meta is emitted for those constructs; and add tests for empty or whitespace-only description strings to ensure meta is omitted or contains only id per existing behavior. Use the existing helper functions (generateZodValidationSchemaDefinition, parseZodValidationSchemaDefinition) and the def.functions lookups for 'meta' and 'describe' to validate outputs.
7961-7963: 💤 Low valueExact string matching may be brittle for object literals.
The assertion checks for an exact string match including key order and formatting:
".meta({ id: 'Pet', description: 'A pet', deprecated: true })"While acceptable for unit tests, consider whether key order is guaranteed. If the object serialization changes (e.g., keys reordered, quote style changes), this test would break. For more robust testing, you could:
- Parse the output and compare structure
- Use regex patterns for flexible matching
- Split into multiple
.toContain()checksHowever, exact string matching provides strong guarantees about output format, so the current approach is reasonable if the format is intentional.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/zod/src/zod.test.ts` around lines 7961 - 7963, The assertion using parsed.zod checks for an exact object-literal string which is brittle to key order/formatting; update the test around parsed.zod to perform a more robust check—either replace the exact .toContain(...) string with a regex that matches the .meta(...) call and the required keys/values (e.g., ensure substrings like "id: 'Pet'", "description: 'A pet'", and "deprecated: true" appear) or split into multiple .toContain() assertions verifying each key/value and the ".meta(" wrapper, or parse the generated output and compare the object structure programmatically; target the assertion using the parsed.zod reference when making the change.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/zod/src/index.ts`:
- Around line 223-230: The early-return fast path that returns a plain `$ref`
schema when encountering chainable `$ref` siblings skips adding the top-level
metadata; update the branch that handles reusable `$ref` aliases to check
`rules.emitMeta` (or `emitMeta`) and, when true, call `.meta({ id, description?,
deprecated? })` on the returned Zod schema before returning it so the registry
`id` is present; locate the early-return for chainable `$ref` siblings (the
logic that currently returns the `$ref` directly) and add a conditional wrapping
step that attaches `.meta(...)` using the same `id` generation used elsewhere
(matching how top-level component code adds metadata) so the behavior is
consistent with the non-fast-path.
---
Nitpick comments:
In `@packages/orval/src/write-zod-specs.test.ts`:
- Around line 625-639: The test currently asserts an exact substring match for
the generated .meta object which is brittle to field order/formatting; update
the assertion in the test case that uses generateZodSchemasInline(metaBuilder(),
output) so it instead checks for the presence of the individual metadata
properties (e.g., that the result contains "id: 'Pet'", "description: 'A pet'",
and "deprecated: true") or use a regex that tolerates any key order/spacing;
locate the test block referencing createOutputOptions(),
zodOverride.generateMeta, metaBuilder(), and generateZodSchemasInline and
replace the strict expect(result).toContain(".meta({...})") with separate
contains assertions or an order-agnostic regex check.
In `@packages/zod/src/zod.test.ts`:
- Around line 7919-8063: Add additional unit tests in
packages/zod/src/zod.test.ts that exercise partial metadata and edge cases:
create cases where only description exists (no deprecated) and only deprecated
exists to assert def.functions contains the expected meta payload via
generateZodValidationSchemaDefinition and parseZodValidationSchemaDefinition;
add tests that ensure .meta() appears after modifiers by building schemas with
optional/nullable/default and asserting parsed.zod shows modifiers before
".meta(...)" (use the same def.functions and parsed.zod checks as existing
tests); add top-level oneOf/allOf/anyOf schemas to confirm meta is emitted for
those constructs; and add tests for empty or whitespace-only description strings
to ensure meta is omitted or contains only id per existing behavior. Use the
existing helper functions (generateZodValidationSchemaDefinition,
parseZodValidationSchemaDefinition) and the def.functions lookups for 'meta' and
'describe' to validate outputs.
- Around line 7961-7963: The assertion using parsed.zod checks for an exact
object-literal string which is brittle to key order/formatting; update the test
around parsed.zod to perform a more robust check—either replace the exact
.toContain(...) string with a regex that matches the .meta(...) call and the
required keys/values (e.g., ensure substrings like "id: 'Pet'", "description: 'A
pet'", and "deprecated: true" appear) or split into multiple .toContain()
assertions verifying each key/value and the ".meta(" wrapper, or parse the
generated output and compare the object structure programmatically; target the
assertion using the parsed.zod reference when making the change.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 0cd1688c-a6fd-460c-9107-e8a9a45b36c2
📒 Files selected for processing (9)
docs/content/docs/reference/configuration/output.mdxpackages/core/src/test-utils/context.tspackages/core/src/types.tspackages/orval/src/reusable-schemas.tspackages/orval/src/utils/options.tspackages/orval/src/write-zod-specs.test.tspackages/orval/src/write-zod-specs.tspackages/zod/src/index.tspackages/zod/src/zod.test.ts
|
@z4o4z conflicts |
…od v4)
New opt-in `override.zod.generateMeta` (default false). When enabled on zod v4,
each generated component schema gets registry metadata via `.meta({ id,
description?, deprecated? })`: `id` is the schema name, with `description` /
`deprecated` included when the OpenAPI schema provides them. This makes the
schemas self-describing and lets `z.toJSONSchema()` reference them by `id`.
- Generator: a top-level-only `emitMeta` rule folds the schema's trailing
`.describe(...)` into a single `.meta({...})` on zod v4; nested properties keep
`.describe()`. `.meta()` is emitted last (zod v4 turns `.meta().describe()`
into a `$ref` wrapper, whereas `.describe().meta()` stays flat). Handled at
both generator exits (multi-type union + main).
- Scope: component schemas only (named exports). Operation wrappers are left
untouched so zod's global-registry `id`s stay unique.
- zod v3 has no `.meta()` — the option is a no-op and descriptions still emit via
`.describe()`.
Verified: generated v4 output type-checks under strict and round-trips through
`z.toJSONSchema` (id/description/deprecated surface in the JSON Schema).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…rage
- Restore prior empty-string description semantics: empty `''` (or non-string)
descriptions are treated as absent in `pushDescriptionOrMeta`, so neither
`.describe('')` nor `description: ''` is emitted. Matches the old
`if (schema.description)` falsy check (Copilot review).
- Add `generateMeta: false` to the inline `NormalizedZodOptions` test fixtures
in `@orval/mock`, `@orval/angular` (×2), and `@orval/solid-start` — the
monorepo typecheck was failing there because `generateMeta` is required on
the normalized type.
- Tests: regression for the empty-string fix (v3, v4, and emitMeta-off); pin
the use-site arrangement when a `$ref` has a `description` sibling
(`Pet.describe(...)` chained AFTER Pet's `.meta(...)`), which is the
documented zod v4 pattern that round-trips through `z.toJSONSchema` as
`{ description, $ref: '#/$defs/Pet' }`.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Actionable comments posted: 0 |
Summary
Adds an opt-in
override.zod.generateMeta(defaultfalse). When enabled on zod v4, each generated component schema gets registry metadata via.meta():idis the schema name (always);descriptionanddeprecatedare included only when the OpenAPI schema provides them.z.toJSONSchema()reference them byid(#/$defs/Pet), round-tripping the component structure.Design
emitMetarule folds the schema's trailing.describe(...)into a single.meta({ id, description?, deprecated? })on zod v4; nested property descriptions keep.describe(). Handled at both generator exit points (multi-type union + main)..meta()is emitted last. Verified against zod 4.3.6 that.meta({id}).describe(...)wraps the schema in a$refindirection, whereas.describe(...).meta({id})(and a lone.meta) stay flat.schemas: { type: 'zod' }orclient: 'zod'+generateReusableSchemas). Operation wrapper schemas are intentionally left untouched, so zod's global-registryids never collide..meta()exists — the option is a silent no-op and descriptions still emit via.describe().Test plan
.meta(); id-only when no description/deprecated; nested keeps.describe(); v3 falls back to.describe();emitMetaoff → no.meta(); multi-type (type-array) top-level schema gets meta['meta', {...}]→.meta({ id: 'X', description: '...', deprecated: true })write-zod-specs): config →.meta()on zod v4;.describe()(no.meta) on zod v3strict;z.toJSONSchema()surfacesid/description/deprecated(nested description preserved)lint,typecheck, and full suites pass — core 1933, zod 188, orval 119### generateMetasection underoverride.zod🤖 Generated with Claude Code
Summary by CodeRabbit