-
-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Support metadata in z.fromJSONSchema()
#5586
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good addition. One issue: RECOGNIZED_KEYS is missing several standard JSON Schema keywords, which will cause them to be incorrectly captured as custom metadata.
| // OpenAPI | ||
| "nullable", | ||
| "readOnly", | ||
| ]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
RECOGNIZED_KEYS is missing several standard JSON Schema keywords:
Validation keywords (mentioned in TODOs but not recognized):
uniqueItems- array validation (see line 443)contains,minContains,maxContains- array validation (see line 444)minProperties,maxProperties- object validation
Core keywords (structural, not user metadata):
$id,id- schema identifiers$comment- developer comments$anchor- named anchors$vocabulary- vocabulary declarations$dynamicRef,$dynamicAnchor- dynamic references
Content keywords:
contentEncoding,contentMediaType,contentSchema
Metadata keywords (these are intentionally omitted and correctly captured):
title,deprecated,writeOnly,examples
Without adding the validation and core keywords, schemas using these will have them incorrectly stored as custom metadata. For example, a schema with {"type": "array", "uniqueItems": true} would store uniqueItems as metadata rather than recognizing it as an unsupported validation constraint.
Suggestion: Add these to RECOGNIZED_KEYS:
// Validation (unsupported)
"uniqueItems",
"contains",
"minContains",
"maxContains",
"minProperties",
"maxProperties",
// Core schema keywords
"$id",
"id",
"$comment",
"$anchor",
"$vocabulary",
"$dynamicRef",
"$dynamicAnchor",
// Content
"contentEncoding",
"contentMediaType",
"contentSchema",There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added all suggested keywords to RECOGNIZED_KEYS and implemented metadata capture for core/content keywords.
|
Fixed review comment and pushed changes. All tests passing. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR adds support for capturing JSON Schema metadata (like title, deprecated, examples, and custom extension fields) when converting from JSON Schema to Zod schemas using z.fromJSONSchema(). The metadata is stored in a registry (either the global registry by default, or a custom one provided via parameters) and can be retrieved later.
Key Changes:
- Added a
registryparameter tofromJSONSchema()to specify where metadata should be stored - Implemented logic to identify and capture unrecognized JSON Schema keys as metadata
- Created a
RECOGNIZED_KEYSset to distinguish between standard JSON Schema keywords and metadata/custom fields
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
packages/zod/src/v4/classic/from-json-schema.ts |
Adds registry support to the conversion context, defines RECOGNIZED_KEYS set, and implements metadata collection logic that stores unrecognized keys in the registry |
packages/zod/src/v4/classic/tests/from-json-schema.test.ts |
Adds comprehensive test coverage for metadata extraction including global/custom registries, standard metadata fields, extension keys, nested schemas, and edge cases |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| interface FromJSONSchemaParams { | ||
| defaultTarget?: JSONSchemaVersion; | ||
| registry?: $ZodRegistry<any>; | ||
| } |
Copilot
AI
Dec 31, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The FromJSONSchemaParams interface now includes a registry parameter but lacks documentation explaining its purpose. Consider adding JSDoc comments to document:
- What the registry parameter does (stores unrecognized JSON Schema keywords as metadata)
- When users might want to provide a custom registry vs using the global one
- What type of metadata will be captured
| const RECOGNIZED_KEYS = new Set([ | ||
| // Schema identification | ||
| "$schema", | ||
| "$ref", | ||
| "$defs", | ||
| "definitions", | ||
| // Type | ||
| "type", | ||
| "enum", | ||
| "const", | ||
| // Composition | ||
| "anyOf", | ||
| "oneOf", | ||
| "allOf", | ||
| "not", | ||
| // Object | ||
| "properties", | ||
| "required", | ||
| "additionalProperties", | ||
| "patternProperties", | ||
| "propertyNames", | ||
| // Array | ||
| "items", | ||
| "prefixItems", | ||
| "additionalItems", | ||
| "minItems", | ||
| "maxItems", | ||
| // String | ||
| "minLength", | ||
| "maxLength", | ||
| "pattern", | ||
| "format", | ||
| // Number | ||
| "minimum", | ||
| "maximum", | ||
| "exclusiveMinimum", | ||
| "exclusiveMaximum", | ||
| "multipleOf", | ||
| // Already handled metadata | ||
| "description", | ||
| "default", | ||
| // Unsupported (error-throwing) | ||
| "unevaluatedItems", | ||
| "unevaluatedProperties", | ||
| "if", | ||
| "then", | ||
| "else", | ||
| "dependentSchemas", | ||
| "dependentRequired", | ||
| // OpenAPI | ||
| "nullable", | ||
| "readOnly", | ||
| ]); |
Copilot
AI
Dec 31, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The RECOGNIZED_KEYS set is missing several standard JSON Schema keywords that are defined in the JSONSchema type. This will cause these keywords to be incorrectly captured as metadata even though they are part of the JSON Schema specification. The following keywords should be added to RECOGNIZED_KEYS:
uniqueItems(used in array validation)contains,minContains,maxContains(array contains constraints)minProperties,maxProperties(object property count constraints)$dynamicRef,$dynamicAnchor,$vocabulary(JSON Schema Draft 2020-12 features)contentMediaType,contentEncoding,contentSchema(content description keywords)$id,$anchor,$comment(schema annotation keywords)
While some of these features are not currently supported by the conversion logic (and may throw errors or be ignored), they should still be in RECOGNIZED_KEYS to prevent them from being stored as custom metadata.
| // Collect unrecognized keys as metadata | ||
| const extraMeta: Record<string, unknown> = {}; | ||
| for (const key of Object.keys(schema)) { | ||
| if (!RECOGNIZED_KEYS.has(key)) { | ||
| extraMeta[key] = schema[key]; | ||
| } | ||
| } | ||
| if (Object.keys(extraMeta).length > 0) { | ||
| ctx.registry.add(baseSchema, extraMeta); | ||
| } |
Copilot
AI
Dec 31, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The metadata collection logic iterates through all keys of the schema object and checks if they are in RECOGNIZED_KEYS. However, when a schema contains a $ref, enum, or const, the function returns early from convertBaseSchema before reaching this metadata collection code. This means metadata on schemas with these keywords will not be captured.
For example, a schema like { "$ref": "#/definitions/User", "title": "User Reference" } would not have its title captured as metadata because the function returns at line 154 or 172 before reaching the metadata collection at line 571-580.
Consider collecting metadata earlier in the process, or ensuring that schemas with early returns also have their metadata captured.
Added validation keywords (uniqueItems, contains, minContains, maxContains, minProperties, maxProperties), core schema keywords ($id, id, $comment, $anchor, $vocabulary, $dynamicRef, $dynamicAnchor), and content keywords (contentEncoding, contentMediaType, contentSchema) to RECOGNIZED_KEYS. These keywords are now properly recognized as standard JSON Schema keywords rather than being treated as custom metadata. Core and content keywords are explicitly captured and stored in the metadata registry since Zod doesn't have direct equivalents for them.
Closes #5564