feat(json-schema): smart coercion plugin for any standard schema#748
feat(json-schema): smart coercion plugin for any standard schema#748
Conversation
|
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
WalkthroughA new Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant SmartCoercionPlugin
participant SchemaConverter
participant JsonSchemaCoercer
participant Handler
Client->>SmartCoercionPlugin: Send input with schema
SmartCoercionPlugin->>SchemaConverter: Convert schema to JSON Schema
SchemaConverter-->>SmartCoercionPlugin: Return JSON Schema
SmartCoercionPlugin->>JsonSchemaCoercer: Coerce input using JSON Schema
JsonSchemaCoercer-->>SmartCoercionPlugin: Return coerced input
SmartCoercionPlugin->>Handler: Pass coerced input
Handler-->>Client: Return response
Assessment against linked issues
Assessment against linked issues: Out-of-scope changes
Possibly related PRs
Poem
✨ Finishing Touches
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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Summary of Changes
Hello @unnoq, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!
This pull request introduces a powerful new 'smart coercion' feature to oRPC, enabling automatic and safe type conversion of incoming data based on its defined JSON Schema. This significantly improves developer experience by reducing the need for manual data transformation, and is implemented through a new dedicated @orpc/json-schema package, along with necessary updates to existing schema converters.
Highlights
- New Core Package: Introduced a new
@orpc/json-schemapackage, which provides a genericexperimental_JsonSchemaCoercerfor intelligent type conversion based on JSON Schema definitions, and anexperimental_SmartCoercionPluginto integrate this functionality into the oRPC client request pipeline. - Enhanced Schema Generation: Updated the
@orpc/zodpackage's JSON Schema converter to emit customx-native-typemetadata for native JavaScript types (like BigInt, Date, RegExp, URL, Set, and Map). This metadata is crucial for the new smart coercion logic to correctly identify and transform these types. - Plugin Deprecation and Migration: The existing
experimental_ZodSmartCoercionPluginin@orpc/zodhas been deprecated in favor of the new, more versatileexperimental_SmartCoercionPluginfrom@orpc/json-schema. Playgrounds have been updated to reflect this migration. - Comprehensive Documentation and Testing: Added detailed documentation for the new Smart Coercion Plugin, explaining its purpose, usage, and conversion rules. Extensive unit tests have also been included to ensure the robustness and correctness of the coercion logic across various data types and schema structures.
Using Gemini Code Assist
The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.
Invoking Gemini
You can request assistance from Gemini at any point in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands.
| Feature | Command | Description |
|---|---|---|
| Code Review | /gemini review |
Performs a code review for the current pull request in its current state. |
| Pull Request Summary | /gemini summary |
Provides a summary of the current pull request in its current state. |
| Comment | @gemini-code-assist | Responds in comments when explicitly tagged, both in issue comments and review comments. |
| Help | /gemini help |
Displays a list of available commands. |
Customization
To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.
Limitations & Feedback
Gemini Code Assist is currently in preview and may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments to provide feedback.
You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.
Footnotes
-
Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution. ↩
There was a problem hiding this comment.
Code Review
This pull request introduces a new @orpc/json-schema package with a generic smart coercion plugin. The date coercion implementation in coercer.ts has a potential timezone issue, and x-native-type metadata is missing in zod/src/converter.ts for bigint, date, set, and map.
There was a problem hiding this comment.
Actionable comments posted: 4
♻️ Duplicate comments (3)
playgrounds/solid-start/package.json (1)
10-14: Same runtime / dev-only concern as commented in Nuxt playground.
See previous note; ensure@orpc/json-schemais available in production builds.playgrounds/astro/package.json (1)
12-18: Same runtime / dev-only concern as commented in Nuxt playground.
Verify whether@orpc/json-schemashould move fromdevDependenciestodependencies.playgrounds/svelte-kit/package.json (1)
14-18: Same runtime / dev-only concern as commented in Nuxt playground.
Confirm correct placement of@orpc/json-schema.
🧹 Nitpick comments (11)
playgrounds/solid-start/src/routes/api/[...rest].ts (1)
20-24: Plugin configuration follows the correct pattern.The new plugin is properly configured with the
ZodToJsonSchemaConverterto maintain compatibility with existing Zod schemas while leveraging the more flexible JSON Schema coercion system.Consider adding a comment about the experimental nature of the plugin:
+ // Using experimental JSON Schema-based coercion plugin new SmartCoercionPlugin({ schemaConverters: [ new ZodToJsonSchemaConverter(), ], }),packages/json-schema/README.md (2)
49-61: Improve readability by varying sentence beginnings.The package descriptions all start with similar patterns, making them repetitive. Consider varying the sentence structures for better readability.
- [@orpc/contract](https://www.npmjs.com/package/@orpc/contract): Build your API contract. - [@orpc/server](https://www.npmjs.com/package/@orpc/server): Build your API or implement API contract. - [@orpc/client](https://www.npmjs.com/package/@orpc/client): Consume your API on the client with type-safety. - [@orpc/openapi](https://www.npmjs.com/package/@orpc/openapi): Generate OpenAPI specs and handle OpenAPI requests. + [@orpc/contract](https://www.npmjs.com/package/@orpc/contract): Build your API contract. + [@orpc/server](https://www.npmjs.com/package/@orpc/server): Create your API or implement API contract. + [@orpc/client](https://www.npmjs.com/package/@orpc/client): Consume your API on the client with type-safety. + [@orpc/openapi](https://www.npmjs.com/package/@orpc/openapi): Generate OpenAPI specs and handle OpenAPI requests.
70-70: Add alt text for accessibility.The sponsors image is missing alt text, which is important for accessibility.
- <img src='https://cdn.jsdelivr.net/gh/unnoq/unnoq/sponsors.svg'/> + <img src='https://cdn.jsdelivr.net/gh/unnoq/unnoq/sponsors.svg' alt='Sponsors'/>packages/json-schema/src/smart-coercion-plugin.test.ts (1)
5-37: LGTM: Basic functionality tests are correct.The test structure properly simulates the plugin's interceptor behavior and covers fundamental coercion scenarios.
Consider expanding test coverage to include:
- Error handling scenarios (invalid inputs, malformed schemas)
- Complex schema types (nested objects, arrays, unions)
- Native type coercion (Date, BigInt, URL, etc.)
- Edge cases (null, undefined, empty values)
Example additional test:
expect(await coerce(z.object({ date: z.date() }), { date: '2023-01-01' })).toEqual({ date: new Date('2023-01-01') })apps/content/docs/openapi/plugins/smart-coercion.md (1)
82-82: Simplify the wording for better readability.The phrase "with the exception of" can be replaced with a more concise alternative.
Apply this diff to improve readability:
-The built-in [JSON Schema Converters](/docs/openapi/openapi-specification#generating-specifications) handle these cases (with the exception of some experimental converters). +The built-in [JSON Schema Converters](/docs/openapi/openapi-specification#generating-specifications) handle these cases (except for some experimental converters).packages/json-schema/src/coercer.test.ts (4)
7-12: Fix typo in test description.The test description contains a grammatical error.
- it('do no thing with boolean/any schema', () => { + it('does nothing with boolean/any schema', () => {
33-37: Address the TODO comment for multiple types test.There's an unfinished test case for coercing with multiple types including 'null'.
Would you like me to help implement this test case or open an issue to track this?
52-52: Use regex literal instead of RegExp constructor.Static analysis correctly identifies that a regex literal would be cleaner here.
- expect(coercer.coerce({ 'type': 'string', 'x-native-type': 'regexp' } as any, '/abc/i')).toEqual(new RegExp('abc', 'i')) + expect(coercer.coerce({ 'type': 'string', 'x-native-type': 'regexp' } as any, '/abc/i')).toEqual(/abc/i)
258-280: Add type cast for consistency.For consistency with other tests, add the
as anytype cast to the schema.}, required: ['a'], - } + } as anypackages/json-schema/src/coercer.ts (2)
121-123: Remove unnecessary type assertion.The type assertion
as JsonSchema | undefinedis redundant here.const itemSchema: JsonSchema | undefined = Array.isArray(schema.items) ? schema.additionalItems - : schema.items as JsonSchema | undefined + : schema.items
169-170: Consider caching compiled regex patterns for better performance.Creating RegExp objects on every coercion call could impact performance when processing many objects with the same schema.
Consider caching the compiled regex patterns at the schema level or in a WeakMap to avoid repeated compilation of the same patterns.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (37)
apps/content/.vitepress/config.ts(1 hunks)apps/content/docs/openapi/plugins/smart-coercion.md(1 hunks)packages/json-schema/.gitignore(1 hunks)packages/json-schema/README.md(1 hunks)packages/json-schema/package.json(1 hunks)packages/json-schema/src/coercer.test.ts(1 hunks)packages/json-schema/src/coercer.ts(1 hunks)packages/json-schema/src/index.ts(1 hunks)packages/json-schema/src/smart-coercion-plugin.test.ts(1 hunks)packages/json-schema/src/smart-coercion-plugin.ts(1 hunks)packages/json-schema/src/types.ts(1 hunks)packages/json-schema/tsconfig.json(1 hunks)packages/openapi/src/schema-converter.ts(1 hunks)packages/zod/package.json(1 hunks)packages/zod/src/converter.test.ts(9 hunks)packages/zod/src/converter.ts(8 hunks)packages/zod/src/zod4/coercer.ts(1 hunks)packages/zod/src/zod4/converter.native.test.ts(1 hunks)packages/zod/src/zod4/converter.number.test.ts(1 hunks)packages/zod/src/zod4/converter.structure.test.ts(2 hunks)packages/zod/src/zod4/converter.ts(4 hunks)packages/zod/tests/shared.ts(1 hunks)packages/zod/tsconfig.json(1 hunks)playgrounds/astro/package.json(1 hunks)playgrounds/astro/src/pages/api/[...rest].ts(2 hunks)playgrounds/contract-first/package.json(1 hunks)playgrounds/contract-first/src/main.ts(2 hunks)playgrounds/next/package.json(1 hunks)playgrounds/next/src/app/api/[[...rest]]/route.ts(2 hunks)playgrounds/nuxt/package.json(1 hunks)playgrounds/nuxt/server/routes/api/[...].ts(2 hunks)playgrounds/solid-start/package.json(1 hunks)playgrounds/solid-start/src/routes/api/[...rest].ts(2 hunks)playgrounds/svelte-kit/package.json(1 hunks)playgrounds/svelte-kit/src/routes/api/[...rest]/+server.ts(2 hunks)playgrounds/tanstack-start/package.json(1 hunks)playgrounds/tanstack-start/src/routes/api/$.ts(2 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (11)
packages/zod/tests/shared.ts (1)
packages/openapi/src/schema.ts (1)
JSONSchema(6-6)
playgrounds/solid-start/src/routes/api/[...rest].ts (1)
packages/zod/src/converter.ts (1)
ZodToJsonSchemaConverter(77-695)
playgrounds/tanstack-start/src/routes/api/$.ts (1)
packages/zod/src/converter.ts (1)
ZodToJsonSchemaConverter(77-695)
playgrounds/next/src/app/api/[[...rest]]/route.ts (1)
packages/zod/src/converter.ts (1)
ZodToJsonSchemaConverter(77-695)
playgrounds/astro/src/pages/api/[...rest].ts (1)
packages/zod/src/converter.ts (1)
ZodToJsonSchemaConverter(77-695)
playgrounds/svelte-kit/src/routes/api/[...rest]/+server.ts (1)
packages/zod/src/converter.ts (1)
ZodToJsonSchemaConverter(77-695)
playgrounds/nuxt/server/routes/api/[...].ts (1)
packages/zod/src/converter.ts (1)
ZodToJsonSchemaConverter(77-695)
packages/json-schema/src/smart-coercion-plugin.ts (8)
packages/openapi/src/schema-converter.ts (3)
ConditionalSchemaConverter(34-36)SchemaConverter(30-32)CompositeSchemaConverter(38-54)packages/server/src/context.ts (1)
Context(1-1)packages/server/src/adapters/standard/plugin.ts (1)
StandardHandlerPlugin(5-8)packages/contract/src/schema.ts (1)
AnySchema(7-7)packages/json-schema/src/types.ts (1)
JsonSchema(6-9)packages/shared/src/array.ts (1)
toArray(1-3)packages/server/src/adapters/standard/handler.ts (1)
StandardHandlerOptions(27-48)packages/json-schema/src/coercer.ts (11)
schema(15-336)value(338-346)value(348-356)value(358-370)value(372-374)value(376-384)value(386-395)value(397-399)value(401-403)value(405-413)value(415-421)
packages/zod/src/zod4/converter.ts (2)
packages/openapi/src/schema.ts (1)
JSONSchemaFormat(5-5)packages/json-schema/src/coercer.ts (1)
schema(15-336)
packages/zod/src/converter.test.ts (2)
packages/openapi/src/schema.ts (1)
JSONSchema(6-6)packages/zod/src/schemas/url.ts (1)
url(6-20)
packages/json-schema/src/coercer.test.ts (1)
packages/json-schema/src/coercer.ts (1)
schema(15-336)
🪛 LanguageTool
packages/json-schema/README.md
[style] ~51-~51: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ... your API or implement API contract. - [@orpc/client](https://www.npmjs.com/package/@...
(ENGLISH_WORD_REPEAT_BEGINNING_RULE)
[style] ~52-~52: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ... API on the client with type-safety. - [@orpc/openapi](https://www.npmjs.com/package/...
(ENGLISH_WORD_REPEAT_BEGINNING_RULE)
[style] ~53-~53: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...I specs and handle OpenAPI requests. - [@orpc/nest](https://www.npmjs.com/package/@or...
(ENGLISH_WORD_REPEAT_BEGINNING_RULE)
[style] ~54-~54: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ... with NestJS. - [@orpc/react](https://www.npmjs.com/package/@o...
(ENGLISH_WORD_REPEAT_BEGINNING_RULE)
[style] ~55-~55: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...with React and React Server Actions. - [@orpc/tanstack-query](https://www.npmjs.com/p...
(ENGLISH_WORD_REPEAT_BEGINNING_RULE)
[style] ~56-~56: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...stack.com/query/latest) integration. - [@orpc/vue-colada](https://www.npmjs.com/packa...
(ENGLISH_WORD_REPEAT_BEGINNING_RULE)
[style] ~57-~57: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...ada](https://pinia-colada.esm.dev/). - [@orpc/hey-api](https://www.npmjs.com/package/...
(ENGLISH_WORD_REPEAT_BEGINNING_RULE)
[style] ~58-~58: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...I](https://heyapi.dev/) integration. - [@orpc/zod](https://www.npmjs.com/package/@orp...
(ENGLISH_WORD_REPEAT_BEGINNING_RULE)
[style] ~59-~59: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...tps://zod.dev/) doesn't support yet. - [@orpc/valibot](https://www.npmjs.com/package/...
(ENGLISH_WORD_REPEAT_BEGINNING_RULE)
[style] ~60-~60: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...rom Valibot. - [@orpc/arktype](https://www.npmjs.com/package/...
(ENGLISH_WORD_REPEAT_BEGINNING_RULE)
apps/content/docs/openapi/plugins/smart-coercion.md
[style] ~82-~82: ‘with the exception of’ might be wordy. Consider a shorter alternative.
Context: ...ing-specifications) handle these cases (with the exception of some experimental converters). Since th...
(EN_WORDINESS_PREMIUM_WITH_THE_EXCEPTION_OF)
🪛 markdownlint-cli2 (0.17.2)
packages/json-schema/README.md
70-70: Images should have alternate text (alt text)
(MD045, no-alt-text)
🪛 Biome (1.9.4)
packages/json-schema/src/coercer.test.ts
[error] 52-52: Use a regular expression literal instead of the RegExp constructor.
Regular expression literals avoid some escaping required in a string literal, and are easier to analyze statically.
Safe fix: Use a literal notation instead.
(lint/complexity/useRegexLiterals)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (38)
playgrounds/nuxt/package.json (1)
12-17: Verify the correct section (dependenciesvsdevDependencies).
@orpc/json-schemalooks like it is imported at runtime by the playground’s route handlers (e.g. when the coercion plugin is instantiated inside the server-side API route). If that’s the case Nuxt will need the package in production, so it should live under the regulardependencieskey rather thandevDependencies, otherwise the built container/image may miss it at runtime.Please double-check how the package is consumed and move it if necessary.
- "devDependencies": { - "@orpc/client": "next", - "@orpc/json-schema": "next", + "dependencies": { + "@orpc/json-schema": "next" + }, + "devDependencies": { + "@orpc/client": "next",packages/zod/package.json (1)
47-50: No circular dependency detected; please verify@orpc/json-schema’s Zod usage
Running a fulltsortof everypackage.jsondependency edge produced no cycles, so adding@orpc/json-schemaas a hard dependency in@orpc/zoddoes not currently introduce a cycle.Please confirm that
packages/json-schema/package.jsondoes not listzodorzod-to-json-schemain either itsdependenciesorpeerDependencies.
- If you find any Zod‐related entries there, consider moving them to a
peerDependencyor extracting the conversion logic into a separate package to avoid a cycle.- If no such entries exist, the current setup is safe.
playgrounds/contract-first/package.json (1)
14-14: LGTM! Consistent with migration pattern.The addition of
@orpc/json-schemadependency aligns with the broader migration from Zod-specific to JSON Schema-based smart coercion plugin across all playgrounds.Note: The "next" tag indicates a pre-release version, which appears intentional for this migration.
playgrounds/tanstack-start/package.json (1)
14-14: LGTM! Consistent dependency addition.The addition of
@orpc/json-schemadependency follows the same pattern as other playgrounds in this migration.playgrounds/next/package.json (1)
14-14: LGTM! Consistent with migration pattern.The dependency addition matches the pattern used across all playgrounds for this migration.
apps/content/.vitepress/config.ts (1)
211-211: Smart Coercion docs link verifiedThe file
apps/content/docs/openapi/plugins/smart-coercion.mdexists alongsidezod-smart-coercion.md, so the sidebar link is valid. LGTM—approving this addition.packages/zod/src/zod4/converter.number.test.ts (1)
38-38: LGTM! Proper JSON Schema extension for native type annotation.The addition of
'x-native-type': 'bigint'correctly follows JSON Schema extension conventions (using thex-prefix) and provides necessary type information for the smart coercion plugin.packages/zod/tsconfig.json (1)
5-5: LGTM! Clean integration of the new package reference.The addition of the
json-schemapackage reference follows the established pattern and correctly integrates the new@orpc/json-schemapackage into the Zod package's TypeScript project configuration.packages/zod/src/zod4/converter.native.test.ts (1)
23-23: LGTM! Correctly adds native type annotation for date schema.The addition of
'x-native-type': 'date'to the expected JSON Schema output properly reflects the new native type annotation system introduced for enhanced coercion capabilities.packages/json-schema/src/index.ts (1)
1-3: LGTM! Clean barrel export pattern for the new package.The entry point file follows best practices by consolidating exports from core modules (
coercer,smart-coercion-plugin, andtypes) into a single interface, making the API more user-friendly.packages/zod/src/zod4/converter.structure.test.ts (4)
61-61: LGTM! Correctly adds native type annotation for set schema.The addition of
'x-native-type': 'set'to the expected JSON Schema output properly supports the new native type annotation system for Set types.
66-67: LGTM! Consistent native type annotations for optional set schema.The native type annotations are correctly applied to both input and output schemas for the optional set test case, maintaining consistency across the coercion system.
112-112: LGTM! Correctly adds native type annotation for map schema.The addition of
'x-native-type': 'map'to the expected JSON Schema output properly supports the new native type annotation system for Map types.
117-118: LGTM! Consistent native type annotations for optional map schema.The native type annotations are correctly applied to both input and output schemas for the optional map test case, ensuring proper coercion behavior for Map types with optional values.
playgrounds/tanstack-start/src/routes/api/$.ts (2)
4-5: LGTM! Clean migration to the new JSON Schema-based plugin.The import changes correctly replace the deprecated
ZodSmartCoercionPluginwith the newexperimental_SmartCoercionPluginfrom@orpc/json-schema, maintaining the same functionality while adopting the more extensible architecture.
21-25: LGTM! Proper configuration of the new smart coercion plugin.The plugin configuration correctly uses the
schemaConvertersarray withZodToJsonSchemaConverter, providing the same coercion capabilities as the deprecated plugin while enabling future extensibility with additional schema converters.packages/json-schema/tsconfig.json (1)
1-17: LGTM! Well-structured TypeScript configuration.The configuration properly extends the base lib config, establishes correct project references, and uses appropriate include/exclude patterns for a library package.
playgrounds/solid-start/src/routes/api/[...rest].ts (1)
4-5: Migration to JSON Schema-based coercion looks good.The import changes correctly migrate from the deprecated Zod-specific plugin to the new experimental JSON Schema-based approach. The aliasing of
experimental_SmartCoercionPluginasSmartCoercionPluginimproves readability.playgrounds/astro/src/pages/api/[...rest].ts (2)
4-5: Consistent migration pattern across playgrounds.The import changes follow the same pattern as other playgrounds, maintaining consistency in the migration from Zod-specific to JSON Schema-based coercion.
20-24: Plugin configuration is consistent and correct.The configuration matches the pattern used in other playgrounds, ensuring uniform behavior across different environments.
packages/json-schema/.gitignore (1)
1-26: Comprehensive .gitignore configuration.The ignore patterns cover all standard artifacts for a Node.js/TypeScript project including build outputs, dependencies, logs, and temporary files. The configuration is well-organized and follows best practices.
packages/zod/tests/shared.ts (1)
11-12: Good type refinement for improved type safety.The intersection with
Record<string, unknown>ensures that the JSON schema objects have string keys, which aligns with the enhanced native type support being introduced in this PR.playgrounds/svelte-kit/src/routes/api/[...rest]/+server.ts (2)
5-6: Good migration to the new JSON Schema-based plugin.The import changes correctly replace the Zod-specific plugin with the more flexible JSON Schema-based
SmartCoercionPlugin.
20-24: Ensure SmartCoercionPlugin fully replaces ZodSmartCoercionPluginAll application code now imports
experimental_SmartCoercionPlugin as SmartCoercionPluginfrom@orpc/json-schema, and there are no remaining references to the oldZodSmartCoercionPlugin.Please run your coercion test suite (or add new tests) to confirm that the new plugin’s behavior matches the previous implementation.
• Verified in:
– playgrounds/*/src/routes/api/[...rest]
– playgrounds/nuxt/server/routes/api/[...].ts
– playgrounds/next/src/app/api/[[...rest]]/route.ts
– …and other playgrounds underplaygrounds/
• Confirmed noZodSmartCoercionPluginusage outside of package testsplaygrounds/contract-first/src/main.ts (2)
5-6: Consistent migration pattern across playground files.The import changes follow the same pattern as other playground files, replacing the Zod-specific plugin with the flexible JSON Schema-based plugin.
21-25: Plugin configuration matches other playground implementations.The
SmartCoercionPluginconfiguration withZodToJsonSchemaConverteris consistent with the pattern used in other playground files.packages/openapi/src/schema-converter.ts (1)
39-41: Excellent immutability improvement.Making the
convertersarray readonly prevents accidental mutations and ensures the converter composition remains stable after construction. This is particularly important for the newSmartCoercionPluginthat relies on stable converter arrays.playgrounds/next/src/app/api/[[...rest]]/route.ts (2)
4-5: Consistent migration pattern completion.The import changes complete the uniform migration across all playground files, maintaining consistency in the codebase.
19-23: ✅ Migration completeness verified across all playgroundsNo occurrences of
ZodSmartCoercionPluginremain, and every playground now usesSmartCoercionPluginas intended. Approving these changes.packages/json-schema/src/types.ts (2)
6-9: LGTM: Comprehensive JSON Schema type support.The union type covering multiple JSON Schema draft versions provides excellent compatibility and future-proofing.
11-18: LGTM: Well-defined native type enum.The enum effectively captures native JavaScript types that need special handling in JSON Schema contexts. The string literal values are appropriate for use as JSON Schema extension properties.
playgrounds/nuxt/server/routes/api/[...].ts (2)
3-4: LGTM: Correct import migration.The import change from the Zod-specific plugin to the experimental JSON Schema-based plugin is appropriate for the new architecture.
18-22: LGTM: Proper plugin configuration.The plugin instantiation with
schemaConvertersconfiguration correctly bridges Zod schemas to JSON Schema format, maintaining compatibility while using the new plugin architecture.packages/json-schema/package.json (1)
1-46: LGTM: Well-structured package configuration.The package.json follows oRPC conventions with proper ES module configuration, appropriate dependencies, and correct build setup.
packages/zod/src/converter.ts (1)
35-35: Native type annotations are correctly implemented.The addition of
x-native-typeproperties to the JSON Schema output for native JavaScript types (BigInt, Date, Set, Map, RegExp, URL) is implemented correctly and consistently. This metadata will enable proper coercion in the smart coercion plugin.Also applies to: 286-290, 308-312, 470-474, 489-501, 643-643, 660-664, 668-672
packages/json-schema/src/smart-coercion-plugin.ts (1)
26-40: Plugin implementation looks good.The smart coercion plugin is well-implemented with proper caching and async support. The use of WeakMap for caching ensures that schemas can be garbage collected when no longer referenced.
packages/zod/src/zod4/converter.ts (1)
30-30: Native type annotations correctly implemented for Zod v4.The implementation of
x-native-typeannotations for Zod v4 schemas is consistent with the main converter and correctly handles all native JavaScript types.Also applies to: 237-241, 245-249, 407-418, 423-428
packages/zod/src/converter.test.ts (1)
14-15: Test coverage for native type annotations is comprehensive.The test updates correctly verify that
x-native-typeproperties are included in the JSON Schema output for all native JavaScript types. The consistent property quoting and type refinements ensure proper TypeScript type checking.Also applies to: 145-147, 169-171, 346-346, 351-351, 540-544, 554-555, 565-576, 592-595
Codecov ReportAll modified and coverable lines are covered by tests ✅ 📢 Thoughts on this report? Let us know! |
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (3)
packages/json-schema/src/coercer.test.ts (3)
1-1: Consider removing the eslint disable comment.The
prefer-regex-literalsrule is disabled, but it would be better to fix the actual issue (line 53) rather than disabling the rule for the entire file.
34-35: Address or remove the TODO comment.The commented-out test suggests incomplete functionality for multiple type coercion. This should either be implemented and uncommented, or removed if not needed.
Would you like me to help implement the missing multiple type coercion functionality or create an issue to track this task?
53-53: Use regex literal instead of RegExp constructor.The static analysis tool correctly identifies this as an issue - regex literals are more readable and avoid escaping issues.
-expect(coercer.coerce({ 'type': 'string', 'x-native-type': 'regexp' } as any, '/abc/i')).toEqual(new RegExp('abc', 'i')) +expect(coercer.coerce({ 'type': 'string', 'x-native-type': 'regexp' } as any, '/abc/i')).toEqual(/abc/i)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (11)
apps/content/docs/openapi/plugins/smart-coercion.md(1 hunks)packages/json-schema/src/coercer.test.ts(1 hunks)packages/json-schema/src/coercer.ts(1 hunks)packages/zod/package.json(1 hunks)playgrounds/astro/package.json(1 hunks)playgrounds/contract-first/package.json(1 hunks)playgrounds/next/package.json(1 hunks)playgrounds/nuxt/package.json(1 hunks)playgrounds/solid-start/package.json(1 hunks)playgrounds/svelte-kit/package.json(1 hunks)playgrounds/tanstack-start/package.json(1 hunks)
✅ Files skipped from review due to trivial changes (3)
- playgrounds/svelte-kit/package.json
- playgrounds/contract-first/package.json
- playgrounds/next/package.json
🚧 Files skipped from review as they are similar to previous changes (7)
- playgrounds/astro/package.json
- playgrounds/tanstack-start/package.json
- playgrounds/solid-start/package.json
- packages/zod/package.json
- playgrounds/nuxt/package.json
- apps/content/docs/openapi/plugins/smart-coercion.md
- packages/json-schema/src/coercer.ts
🧰 Additional context used
🧬 Code Graph Analysis (1)
packages/json-schema/src/coercer.test.ts (1)
packages/json-schema/src/coercer.ts (1)
schema(15-336)
🪛 Biome (1.9.4)
packages/json-schema/src/coercer.test.ts
[error] 53-53: Use a regular expression literal instead of the RegExp constructor.
Regular expression literals avoid some escaping required in a string literal, and are easier to analyze statically.
Safe fix: Use a literal notation instead.
(lint/complexity/useRegexLiterals)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: publish-commit
- GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (11)
packages/json-schema/src/coercer.test.ts (11)
7-12: Good coverage of boolean and any schema edge cases.The tests correctly verify that boolean schemas and empty schemas pass through values unchanged, including the
not: {}case.
14-31: Comprehensive primitive type coercion tests.The tests cover successful coercion cases (string to number/boolean/integer) and failed coercion cases where the original value is preserved. The edge cases with
undefinedvalues are particularly valuable.
39-76: Excellent coverage of native type coercion.The tests thoroughly validate coercion for Date, BigInt, URL, RegExp, Set, and Map types, including both successful conversions and fallback behavior for invalid inputs. The edge cases for Set and Map coercion are particularly well-tested.
78-89: Solid enum and const value coercion tests.The tests validate string-to-number and string-to-boolean coercion within enum constraints, and properly test fallback behavior for invalid values.
91-121: Thorough array and tuple coercion coverage.The tests cover both JSON Schema draft-07 (
itemswithadditionalItems) and draft-2020-12 (prefixItemswithitems) array schemas, ensuring compatibility across schema versions.
123-156: Comprehensive object coercion tests.The tests validate property coercion, pattern properties, additional properties, required fields, and array-to-object conversion. The combination of different property types demonstrates the recursive nature of the coercion.
158-196: Well-designed union type tests.The tests effectively validate
anyOfschema handling, including preference for exact matches and complex nested union scenarios. The array tuple union test is particularly sophisticated.
198-208: Excellent discriminated union validation.The tests demonstrate proper handling of discriminated unions based on constant values, ensuring the correct branch is chosen and appropriate coercion is applied.
210-222: Good intersection type coverage.The
allOftests validate that all schemas in the intersection are satisfied and that properties from multiple schemas are properly merged and coerced.
224-257: Robust recursive schema testing.The test validates
$refresolution and recursive coercion with proper component resolution. The nested structure demonstrates the coercer's ability to handle complex recursive types.
259-298: Excellent complex structure integration test.This test validates the complete coercion pipeline with nested objects, arrays, native types, and Sets, demonstrating the full capability of the coercer in real-world scenarios.
More templates
@orpc/arktype
@orpc/client
@orpc/contract
@orpc/experimental-durable-event-iterator
@orpc/hey-api
@orpc/json-schema
@orpc/nest
@orpc/openapi
@orpc/openapi-client
@orpc/react
@orpc/react-query
@orpc/server
@orpc/shared
@orpc/solid-query
@orpc/standard-server
@orpc/standard-server-aws-lambda
@orpc/standard-server-fetch
@orpc/standard-server-node
@orpc/standard-server-peer
@orpc/svelte-query
@orpc/tanstack-query
@orpc/trpc
@orpc/valibot
@orpc/vue-colada
@orpc/vue-query
@orpc/zod
commit: |
There was a problem hiding this comment.
Pull Request Overview
Add the experimental Smart Coercion Plugin for deep JSON Schema–based type coercion and wire it into all playgrounds, update the Zod converters to emit x-native-type metadata, and include a new @orpc/json-schema package with implementation, tests, and docs.
- Replace
ZodSmartCoercionPluginwith the new Smart Coercion Plugin and update imports in all playground entry points - Add
@orpc/json-schemaas a dependency in playgrounds and workspace packages - Enhance Zod converters/tests to annotate schemas with
x-native-typeand ship a full coercer implementation
Reviewed Changes
Copilot reviewed 38 out of 39 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| playgrounds/*/src/routes/api/... | Swapped in SmartCoercionPlugin import/usage |
| playgrounds/*/package.json | Added @orpc/json-schema devDependency |
| packages/zod/src/{converter,coercer}.ts | Inject x-native-type in schemas and deprecate old plugin |
| packages/zod/tests | Adjusted JSONSchema types and expected test outputs |
| packages/openapi/src/schema-converter.ts | Made converter list readonly |
| packages/json-schema/{tsconfig,src/types.ts,...} | New package with types, plugin, coercer, tests, README |
| apps/content/docs/openapi/plugins/smart-coercion.md | Added Smart Coercion plugin documentation |
| apps/content/.vitepress/config.ts | Updated sidebar navigation entries |
| apps/content/docs/openapi/integrations/implement-contract-in-nest.md | Removed stray blank line |
Comments suppressed due to low confidence (2)
apps/content/docs/openapi/plugins/smart-coercion.md:53
- The usage example calls
new ZodToJsonSchemaConverter()but doesn’t import it. Addimport { ZodToJsonSchemaConverter } from '@orpc/zod'above the snippet.
schemaConverters: [
apps/content/.vitepress/config.ts:212
- [nitpick] Consider renaming this sidebar label to 'Zod Smart Coercion (legacy)' for clarity that it’s the deprecated implementation.
{ text: 'Zod Smart Coercion (old)', link: '/docs/openapi/plugins/zod-smart-coercion' },
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (5)
packages/json-schema/src/coercer.test.ts (5)
1-1: Remove or justify the eslint disable comment.The
prefer-regex-literalsrule is disabled at the file level, but the static analysis tool still flags this issue on line 55. Either remove the disable comment if it's not needed, or ensure it's properly configured.
7-7: Fix the typo in the test description."do no thing" should be "do nothing".
- it('do no thing with boolean/any schema', () => { + it('do nothing with boolean/any schema', () => {
34-35: Address the TODO comment or remove it.The TODO comment suggests incomplete functionality for multiple types coercion. Consider either implementing the test or removing the comment if it's not needed.
Would you like me to help implement this test case or should this TODO be removed?
41-50: Consider improving type safety for native type tests.The tests use
as anyto bypass TypeScript's type checking for thex-native-typeextension. While this may be necessary for testing extensions, consider creating a proper type definition for these extended schemas.Consider creating a type definition for extended JSON schemas:
interface ExtendedJsonSchema extends JsonSchema { 'x-native-type'?: string; }
55-55: Use regex literal instead of RegExp constructor.As flagged by the static analysis tool, regex literals are preferred over the RegExp constructor for better readability and static analysis.
- expect(coercer.coerce({ 'type': 'string', 'x-native-type': 'regexp' } as any, '/abc/i')).toEqual(new RegExp('abc', 'i')) + expect(coercer.coerce({ 'type': 'string', 'x-native-type': 'regexp' } as any, '/abc/i')).toEqual(/abc/i)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
apps/content/docs/openapi/plugins/smart-coercion.md(1 hunks)packages/json-schema/src/coercer.test.ts(1 hunks)packages/json-schema/src/coercer.ts(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- apps/content/docs/openapi/plugins/smart-coercion.md
- packages/json-schema/src/coercer.ts
🧰 Additional context used
🧬 Code Graph Analysis (1)
packages/json-schema/src/coercer.test.ts (1)
packages/json-schema/src/coercer.ts (1)
schema(17-338)
🪛 Biome (1.9.4)
packages/json-schema/src/coercer.test.ts
[error] 55-55: Use a regular expression literal instead of the RegExp constructor.
Regular expression literals avoid some escaping required in a string literal, and are easier to analyze statically.
Safe fix: Use a literal notation instead.
(lint/complexity/useRegexLiterals)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: publish-commit
- GitHub Check: lint
- GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (8)
packages/json-schema/src/coercer.test.ts (8)
64-78: Excellent test coverage for Set and Map coercion edge cases.The tests properly verify that when coercion fails for Sets and Maps (due to duplicates or invalid array structures), the coercer falls back to returning the original array. This demonstrates good understanding of the coercion logic.
83-86: Verify the enum coercion logic for string-to-number conversion.The test expects
'123'to be coerced to123when the enum contains the number123. This behavior should be documented or verified as intentional, as it represents implicit type coercion that might not be expected by all users.Please confirm that the string-to-number coercion behavior in enums is intentional and documented.
101-123: Comprehensive coverage of array/tuple coercion patterns.The tests cover both JSON Schema draft-07 (
itemsas array +additionalItems) and draft-2020 (prefixItems+items) patterns. The expected behavior where additional items beyond the tuple length are only coerced if they match the additional/items schema is correctly tested.
152-157: Interesting test case for array-to-object coercion.The test demonstrates that arrays can be coerced to objects when the schema expects numeric string keys. This is a useful edge case that shows the coercer's flexibility in handling different input formats.
160-198: Well-designed union type tests with increasing complexity.The tests progressively increase in complexity:
- Simple union with different types
- Union with objects having different required properties
- Union with different tuple schemas
This demonstrates thorough understanding of how the coercer should handle ambiguous cases and prefer the most specific matching schema.
200-210: Excellent discriminated union test case.The test properly verifies that discriminated unions work correctly by using the discriminator field (
t) to determine which schema variant to apply, then coercing the value field (v) according to the selected schema.
226-259: Comprehensive recursive schema test with proper component resolution.The test demonstrates proper handling of
$refresolution using thecomponentsoption, and shows that recursive coercion works correctly with proper fallback behavior when coercion becomes impossible at deeper levels.
261-300: Excellent complex integration test.This test effectively combines multiple coercion features:
- Primitive type coercion (boolean, number)
- Native type coercion (Date, URL, Set)
- Nested object and array structures
- Mixed coercion scenarios
This provides good confidence that the coercer works correctly in real-world scenarios.
Closes: https://github.com/unnoq/orpc/issues/395
Summary by CodeRabbit
New Features
Improvements
Bug Fixes
Chores
@orpc/json-schemapackage with source code, tests, documentation, and build configuration.@orpc/json-schema..gitignoreand README files for the new package.