Documentation section: Quality
Cross-Platform Interop
Prerelease. These pages describe 3.0.0-prerelease.2 and can differ from the published release. Read the Live 2.4.2 documentation instead.
Cross-Platform Interop
Section titled “Cross-Platform Interop”Purview.ZodSharp ships a cross-platform fixture pipeline that proves the C# implementation agrees with TypeScript/Zod. The TypeScript side runs on Bun; the C# side runs under the TUnit test suite.
The schema
Section titled “The schema”Both sides define the same user schema — TypeScript UserSchema in src/ts/schema.ts and the C# CrossPlatformUserSchema in src/tests/SystemTextJson.UnitTests/CrossPlatformFixtures.cs (mirrored by NewtonsoftJson.UnitTests):
| Field | Zod (TS) | Purview.ZodSharp (C#) |
|---|---|---|
name |
z.string().min(1) |
min-length 1 |
age |
z.number().int().min(0).max(120) |
0..120 integer |
email |
z.string().email().optional() |
optional email |
tags |
z.array(z.string()).default([]) |
string array, default [] |
Fixture generation
Section titled “Fixture generation”bun run generate-fixtures # runs src/ts/generate-fixtures.tsFor each of the eight fixture cases (three valid, five invalid) the script:
- Writes a JSON file to
src/ts/fixtures/{key}.json. - Runs
UserSchema.safeParse(value)and records the outcome insrc/ts/fixtures/manifest.json— the authoritative{ "valid": true|false }result for every fixture.
The validation loop
Section titled “The validation loop”bun run generate-fixtureswritessrc/ts/fixtures/*.jsonandmanifest.json(Zod is the authority on validity).just test(C# TUnit) reads the fixtures and manifest, asserts outcomes match, and writes validated C# output tosrc/tests/cross-platform/output/{systemtext,newtonsoft}-valid.json.bun run test(vitest) re-checks fixture validity under Zod and parses the C# output JSON — closing the TypeScript ↔ C# loop.
C# cross-platform tests (SystemTextCrossPlatformTests, NewtonsoftCrossPlatformTests) load every fixture and assert the C# outcome matches manifest.json, deserialize-and-validate valid fixtures, round-trip TS fixture → C# → JSON → C#, and serialize a validated CrossPlatformUser into src/tests/cross-platform/output/{systemtext,newtonsoft}-valid.json.
Vitest cross-platform tests (tests/ts/cross-platform.test.ts) re-check fixture validity under Zod, verify canonical serialization, and parse every JSON file in cross-platform/output with Zod to prove C# output is acceptable to TypeScript/Zod.
If the C# output directory is empty, the vitest suite fails rather than passing vacuously: run the C# cross-platform tests first. just test does both, because Repository.UnitTests drives every vitest suite from the .NET test run.
Issue shape
Section titled “Issue shape”Validity is not the only thing that lines up. Every built-in ZodSharp error reports the Zod v4 issue code as its
Category (invalid_type, too_small, too_big, invalid_format, invalid_union, unrecognized_keys, …)
while Code keeps ZodSharp’s more specific identity, and FullPath.ToZodPath() returns the path in Zod’s issue
shape (strings for members and keys, integers for indexes). Messages use Zod’s type names ("Expected number, received string"), never CLR names. A client can therefore handle ZodSharp and Zod issues with the same code;
see Core Concepts.
| Zod issue | ZodSharp error |
|---|---|
code |
Category |
path (["items", 0, "name"]) |
FullPath.ToZodPath() |
origin, minimum, maximum, inclusive |
Origin, Lower/Upper (ErrorBound.Value, ErrorBound.Inclusive) |
expected, keys, format, divisor |
Parameters (ZodIssueParameters.Expected, Keys, Format, Divisor) |
errors of invalid_union |
error.GetUnionErrors() |
JSON Schema bridge
Section titled “JSON Schema bridge”The same interop goal is available without fixtures via JSON Schema:
- Export:
Z.ToJsonSchema(core package) → JSON Schema, orz.toJSONSchemaon the TypeScript side (Zod v4+). - Import:
Z.FromJsonSchema(in the System.Text.Json or Newtonsoft.Json package — namespaceZodSharp.JsonSchema.SystemTextJson/ZodSharp.JsonSchema.NewtonsoftJson).
A generated collection maps to Zod’s array element type: T[] / List<T> ↔ z.array(T), and a nullable element (T?[], List<T?>, or a property that allows nulls via [CollectionBehavior(AllowNulls = true)]) ↔ z.array(T.nullable()). A collection whose elements may be null exports items.anyOf: [ …, { "type": "null" } ], and both z.fromJSONSchema and Z.FromJsonSchema read that shape back. Null elements are rejected by default, so a generated T[] matches z.array(T) exactly — see Collection null items.
A dictionary property (IDictionary<TKey, TValue> / IReadOnlyDictionary<TKey, TValue>) is a map:
Dictionary<string, V> ↔ z.record(z.string(), V). The generated schema exports
{ "type": "object", "additionalProperties": … } (with minProperties/maxProperties for size constraints),
and its failures use the same key-prefixed paths as z.record. Both z.fromJSONSchema and
Z.FromJsonSchema read that shape back as a record — see
JSON Schema Export.
The temporal parity suite (tests/ts/temporal-parity.test.ts) proves the same loop for [NonSentinel] on
DateOnly, TimeOnly, DateTime, and DateTimeOffset under the default preserve-offset contract, including
the offset-equivalent bounds. The C# producer
(JsonSchema_GivenGeneratedTemporalSchemas_WritesZodParityArtifacts) writes to
src/tests/cross-platform/temporal-parity/; the UTC contract has its own generator tests.
See JSON Schema Export and JSON Schema Import.
Directory layout
Section titled “Directory layout”src/ts/ TypeScript (Zod) schemas + fixture generationsrc/ts/fixtures/ generated JSON fixtures + manifest.jsontests/ts/ vitest cross-platform testssrc/tests/cross-platform/ shared output directory for C#-generated JSON