Skip to content

chore(release): prepare the first stable release (2.0.0) - #49

Merged
kieronlanning merged 6 commits into
mainfrom
release/2.0.0
Sep 29, 2026
Merged

kieronlanning merged 6 commits into
mainfrom
release/2.0.0

Conversation

@kieronlanning

@kieronlanning kieronlanning commented Sep 29, 2026 •

Copy link
Copy Markdown
Collaborator

Prepare ZodSharp for the first stable release (2.0.0)

Summary

Drops the prerelease tag for the first stable release, finalises the analyzer release tracking, resolves the
three public-surface decisions from the task, and syncs docs, READMEs, samples and tests.

This PR does not publish, tag or release anything. Merging to main triggers release.yml
(purview-release.yml, release-mode: NuGet), which tags v2.0.0 from package.json and publishes the four
packages. purview-build.json is unchanged (Release.Mode still None, no validation rule weakened).

Work item checklist

# Item Status
1 Move all unshipped analyzer rules to shipped Done - ## Release 2.0.0 in AnalyzerReleases.Shipped.md carries ZODSGEN020, 021, 027-036, ZODSASP001/002/003/100/101; AnalyzerReleases.Unshipped.md keeps the standard Roslyn header and an empty new-rules table. All 35 IDs defined in DiagnosticLibrary.cs are tracked in exactly one file (ZODSGEN002, ZODSGEN022-026 remain intentional gaps). The tracking analyzer is live - a probe rule reported RS2000 as an error - so the clean build means zero RS2000/RS2001/RS2002/RS2007.
2 Bump the version to stable Done - package.json is 2.0.0, just version prints 2.0.0, docs/wiki/Release-Flow.md describes the stable line. No stale 2.0.0-prerelease.* references remain.
3a Empty FromJsonSchemaOptions public type Done - type and options parameters removed from both packages.
3b Duplicate public type names across the JSON packages Done - import types moved into package-specific namespaces; coexistence test project added.
3c External $ref in JSON Schema import Done - limitation kept, message now names the unsupported reference; behaviour tested and documented.
4 Documentation in sync Done - Guarantees-and-Limitations, JsonSchema-Import, JsonSchema-Export, SystemTextJson-Integration, NewtonsoftJson-Integration, AspNetCore-Integration (new ZODSASP diagnostics table), Source-Generator-Diagnostics (severity note + unused-ID gaps), Getting-Started, Cross-Platform-Interop, README.md and both package READMEs.
5 Samples and tests Done - Examples.CLI and all samples/benchmarks build; new tests below; bun run test fixtures unchanged and green.
6 Validation Done - see results below.

Section 3 decisions

Item Decision One-line rationale
3a Remove the dead surface (FromJsonSchemaOptions + both options parameters) Never ship an empty options type into a stable API; there is no near-term need for it.
3b Eliminate the collision via package namespaces ZodSharp.JsonSchema.SystemTextJson / ZodSharp.JsonSchema.NewtonsoftJson (parser, serializer options, Z.FromJsonSchema host class) The four identical full names disappear, so both packages can be referenced from one project without extern alias; the JSON integrations stay mutually exclusive by usage (import one package namespace per file).
3c Keep the limitation, made actionable: NotSupportedException names the offending reference and explains how to resolve it External $ref resolution needs IO/base-URI plumbing that does not belong in this release; the failure is now diagnosable and covered by tests in both packages.

Corrected keyword handling found while implementing 3c (86262af, revised in f0b3aee)

The $ref/$defs support that 3c builds on was effectively broken:

  • There was no JSON property-name mapping for the keyword properties, so "$ref"/"$defs" in an authored
    JSON string were silently ignored (local $ref only ever worked for in-memory definitions, and
    ToJsonSchema wrote non-conformant ref/defs/schema/id names).
  • The Newtonsoft reader consumed $ref as JSON metadata and deserialized such schemas to null, which
    made FromJsonSchemaParser.ConvertSchema throw NullReferenceException.

The final design keeps the shared POCO serializer-agnostic and gives each integration package ownership of
the JSON Schema keyword names:

  • Purview.ZodSharp.SystemTextJson: a JsonSchemaNamingPolicy ($schema/$id/$ref/$defs, camelCase for
    everything else) used by both JsonSchemaSerializerOptions.Default and .Reading.
  • Purview.ZodSharp.NewtonsoftJson: an equivalent naming strategy on the contract resolver, plus
    MetadataPropertyHandling.Ignore so $ref is no longer swallowed as metadata.
  • JsonSchemaDefinition itself carries no serializer annotations, and a null sub-schema now fails with an
    actionable ArgumentException instead of a NullReferenceException.

Behaviour change to serialized JSON Schema output (it now matches the JSON Schema specification and this
repo's own documentation); the core POCO is unchanged apart from that guard, and purview-build.json
RequiredContent/ForbiddenContent are unaffected.

Tests added

  • src/tests/JsonInterop.UnitTests/ - new project referencing both JSON packages: proves they compile
    together without extern alias, that the import types have distinct full names, and that each package's
    namespace binds Z.FromJsonSchema and its own serializer options type.
  • SystemTextJson.UnitTests/Json/Schema/FromJsonSchemaParserTests.cs and the Newtonsoft equivalent - local
    $ref resolution, external $ref exception (type + message naming the reference), null-definition guard,
    JSON Schema keyword naming vs camelCase naming, and the new null-sub-schema failure.
  • SourceGenerators.UnitTests/AnalyzerReleaseTrackingTests.cs - guards the shipped/unshipped files, the
    ## Release 2.0.0 section, the empty unshipped table and "one tracking entry per rule".
  • ZodSharp.UnitTests/Core/MultiTargetingTests.cs - asserts the core assembly declares one of the supported
    target frameworks (net8.0/net9.0/net10.0) on every run.

Validation

Command Result
just version Current Version: 2.0.0
just lint-check Checked 294 files - no formatting changes
just build Build succeeded, 0 warnings / 0 errors (no RS2000/RS2001/RS2002/RS2007)
just test 1851 passed, 0 failed, 0 skipped across net8.0/net9.0/net10.0
just pipeline-pr Pipeline Completed Successfully - 7 passed / 3 skipped (publish + GitHub release disabled); [PackValidation] Valid packages: 8/8; [Version] Package version: 2.0.0
just pipeline-pack-validate Pipeline Completed Successfully (re-run after f0b3aee) - Valid packages: 8/8, Invalid packages: 0/8
bun run test vitest cross-platform fixtures: 12 passed (1 file)

Pack inspection (artifacts/, all at 2.0.0):

  • Purview.ZodSharp.2.0.0.nupkg: analyzers/dotnet/cs/Purview.ZodSharp.SourceGenerators.dll,
    buildTransitive/Purview.ZodSharp.props, lib/{net8.0,net9.0,net10.0}/Purview.ZodSharp.{dll,xml},
    purview-logo-light.png, README.md - exactly RequiredContent, and no
    analyzers/**/Purview.SourceGeneratorFramework.dll (ForbiddenContent).
  • .snupkg symbol packages exist for all four packages (RequireSymbolPackage) and contain the per-TFM
    .pdb files (RequireSymbolFiles).

Notes / review points

  1. 3b scope: the four colliding type names are separated, but the deserialize/serialize extension methods
    (DeserializeAndValidate, ValidateAndSerialize) intentionally remain in the ZodSharp namespace in both
    packages, matching the "mutually exclusive integrations" decision - importing both namespaces in one file
    still makes those calls ambiguous. Documented as a guarantee in Guarantees-and-Limitations.md.
  2. Keyword naming ownership: after review feedback the keyword mapping lives in each integration package
    rather than as attributes on the shared POCO. Consumers who serialize JsonSchemaDefinition with their own
    serializer options get PascalCase names (as before), so use the package's JsonSchemaSerializerOptions for
    keyword-compliant output. f0b3aee carries the revision.
  3. New JsonInterop.UnitTests project: added to src/ZodSharp.slnx; picked up by pipeline test discovery
    (*Tests.csproj under src/tests) with no purview-build.json change.
  4. Commit hygiene: commitlint in this environment rejects the ! breaking-change shorthand (reports an
    empty type/subject), so 86262af marks the break with a canonical BREAKING CHANGE: footer instead.
    No hooks were bypassed.
  5. Cross-platform fixtures were not regenerated because no Zod schema output changed.

package.json now reports the first stable version, 2.0.0, and the release-flow docs
describe the stable line instead of the 2.0.0-prerelease.* line.
Fold every rule that was pending in AnalyzerReleases.Unshipped.md into the new 2.0.0
section of AnalyzerReleases.Shipped.md, preserving each rule id, category, severity
and notes. The unshipped file keeps the standard Roslyn header and an empty
new-rules table.
Move FromJsonSchemaParser, JsonSchemaSerializerOptions and ZExtensions into the
ZodSharp.JsonSchema.SystemTextJson and ZodSharp.JsonSchema.NewtonsoftJson namespaces
so both JSON packages can be referenced from one project without extern alias.

Remove the empty FromJsonSchemaOptions type and the options parameter from
Z.FromJsonSchema and FromJsonSchemaParser.Parse in both packages.

Bind the JSON Schema keyword names ($schema, $id, $ref, $defs) when reading and
writing JsonSchemaDefinition, and ignore JSON metadata handling in the Newtonsoft
reader, which previously consumed $ref as metadata and produced null property
schemas.

BREAKING CHANGE: Z.FromJsonSchema no longer accepts FromJsonSchemaOptions and now
requires the JSON integration package namespace import.
Add a JsonInterop.UnitTests project that references both JSON integration packages to
prove they can be used together without extern alias, parser tests for local and
external $ref plus JSON Schema keyword naming, a release-tracking guard test, and a
multi-targeting test.
Update the wiki, README and package READMEs for the stable 2.0.0 release: the package
specific JSON Schema namespaces, the removed options type, the external $ref message,
the JSON Schema keyword names, the ZODSASP diagnostics table and the shipped ZODSGEN
rules.
…kages

Keep JsonSchemaDefinition free of serializer annotations: the shared POCO stays
serializer-agnostic and each integration package maps the JSON Schema keyword names
($schema, $id, $ref, $defs) in its own options - a naming policy for System.Text.Json
and a naming strategy for Newtonsoft.Json (which keeps MetadataPropertyHandling.Ignore
so the reader does not treat $ref as JSON metadata).

Fail with an actionable ArgumentException instead of a NullReferenceException when a
converted schema graph contains a null sub-schema, and cover both behaviours with tests.
@kieronlanning
kieronlanning enabled auto-merge (squash) September 29, 2026 14:15
@kieronlanning
kieronlanning merged commit f710f19 into main Sep 29, 2026
1 check passed
@kieronlanning
kieronlanning deleted the release/2.0.0 branch September 29, 2026 14:17
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.

1 participant