Skip to content

Conversation

@colinhacks
Copy link
Owner

@colinhacks colinhacks commented Dec 31, 2025

const schema = fromJSONSchema({
    type: "string",
    title: "My String",
    deprecated: true,
    examples: ["hello", "world"],
    "x-custom": "custom value",
  });

  const meta = z.globalRegistry.get(schema);
  // => {
  //   title: "My String",
  //   deprecated: true,
  //   examples: ["hello", "world"],
  //   "x-custom": "custom value",
  // }

Closes #5564

Copilot AI review requested due to automatic review settings December 31, 2025 00:27
Copy link
Contributor

@pullfrog pullfrog bot left a 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.

Pullfrog  | Fix all ➔Fix 👍s ➔View workflow runpullfrog.com𝕏

// OpenAPI
"nullable",
"readOnly",
]);
Copy link
Contributor

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",

Copy link
Contributor

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.

Pullfrog  | Triggered by Pullfrog | Using Claude CodeView workflow runpullfrog.com𝕏

@pullfrog
Copy link
Contributor

pullfrog bot commented Dec 31, 2025

Fixed review comment and pushed changes. All tests passing.

Pullfrog  | Triggered by Pullfrog | Using Claude CodeView workflow runpullfrog.com𝕏

Copy link
Contributor

Copilot AI left a 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 registry parameter to fromJSONSchema() to specify where metadata should be stored
  • Implemented logic to identify and capture unrecognized JSON Schema keys as metadata
  • Created a RECOGNIZED_KEYS set 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.

Comment on lines 17 to 20
interface FromJSONSchemaParams {
defaultTarget?: JSONSchemaVersion;
registry?: $ZodRegistry<any>;
}
Copy link

Copilot AI Dec 31, 2025

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

Copilot uses AI. Check for mistakes.
Comment on lines 32 to 84
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",
]);
Copy link

Copilot AI Dec 31, 2025

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.

Copilot uses AI. Check for mistakes.
Comment on lines 571 to 580
// 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);
}
Copy link

Copilot AI Dec 31, 2025

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.

Copilot uses AI. Check for mistakes.
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.
@colinhacks colinhacks merged commit 456af1e into main Dec 31, 2025
8 checks passed
@colinhacks colinhacks deleted the fromjsonschema-metadata branch December 31, 2025 00:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Metadata persistence and Global Registry support in toJSONSchema / fromJSONSchema round-trip

1 participant