Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ jobs:
secrets: inherit

# The shared pipeline runs the C# suite only, so the TypeScript/Zod side of the cross-platform
# parity guarantee (docs/wiki/Guarantees-and-Limitations.md) would otherwise never run in CI.
# parity guarantee (docs/wiki/quality/Guarantees-and-Limitations.md) would otherwise never run in CI.
# The vitest suite validates the JSON the C# cross-platform tests write, so the C# tests must run
# first, in this same workspace — hence running them here rather than relying on the `build` job.
cross-platform:
Expand Down Expand Up @@ -288,7 +288,7 @@ jobs:
# packages only - a Native AOT console, a Blazor WebAssembly app (trimmed and RunAOTCompilation) and a Native AOT
# minimal API - and leak-scans every bin and publish folder for compiler-host assemblies. It then proves every
# PackValidation ForbiddenContent rule rejects a package, against the packages the consumers used.
# `just smoke-packed-consumers` and `just verify-pack-rules` run the same locally. See docs/wiki/Release-Flow.md.
# `just smoke-packed-consumers` and `just verify-pack-rules` run the same locally. See docs/wiki/development/Release-Flow.md.
packed-consumers:
name: Packed consumers (Native AOT, Blazor WebAssembly, minimal API)
runs-on: ubuntu-latest
Expand Down
13 changes: 12 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,17 @@ Each package ships its own `README.md`, placed in the project's `Sdk/` folder (f

Keep `purview-build.json`'s `PackValidation` requirements in sync with any packaging change.

## Documentation (`docs/wiki`)

`docs/wiki` is the source of the [purview.dev](https://purview.dev) documentation for this project: the site's `github-path` sync reads the folder for both the `live` (latest stable tag) and `prerelease` (`main`) channels.

- **One folder per topic area.** A page is published at `/docs/zodsharp/<folder>/<slug>/`, so the folder is part of its URL, and a link inside a page resolves relative to that page (`../concepts/Core-Concepts.md`). The tree, the seven sections and the conventions are in `docs/wiki/development/Contributing.md`.
- **Three pages stay at the wiki root.** `Getting-Started.md` is the site's landing page (`docs.rootPage`), and `Fluent-Schema-API.md` and `AspNetCore-Integration.md` are deep-linked by the site catalogue (`docsPage`), whose slug must be a single path segment and must exist in both documentation channels.
- **Adding a page is three edits** - the page in its folder, its `_Sidebar.md` entry inside the right section (path relative to the wiki root), and its `Home.md` row.
- **Renaming or moving a page changes a published URL.** Add the old slug to `docs.redirects` in the site repository's `src/src/data/projects/zodsharp.yml`; that is a cross-repository change.

`src/tests/Repository.UnitTests/DocumentationWikiTests.cs` enforces that every page is listed exactly once in the sidebar and is reachable from `Home.md`, that both sets of links resolve to existing files, that every sidebar section has a matching `## ` heading in `Home.md`, that every folder's pages are all in the sidebar, and that every page opens with a single `# ` title.

## Cross-platform fixtures

Schemas and fixtures shared between TypeScript/Zod and C#/Purview.ZodSharp live under `src/ts/`. The fixture generator (`bun run generate-fixtures`) writes JSON fixtures and a `manifest.json` that the C# tests consume. Keep the TS `UserSchema` and the C# `CrossPlatformUserSchema` in sync.
Expand Down Expand Up @@ -159,7 +170,7 @@ Commits must follow [Conventional Commits](https://www.conventionalcommits.org/)
- Packed packages match `purview-build.json` `PackValidation` (including per-package `README.md` and `purview-logo-light.png`, and no `ForbiddenContent`: compiler-host assemblies outside `analyzers/`, generator or code-fix assemblies under `lib/`). After changing `PackValidation`, `just verify-pack-rules` proves every forbidden-content rule still rejects a package.
- No build or publish output carries a compiler-host assembly (`Purview.SourceGeneratorFramework*`, `Microsoft.CodeAnalysis*`, `Purview.ZodSharp.SourceGenerators*`, `Purview.ZodSharp.CodeFixes*`): every publish recipe and CI publish job runs `scripts/assert-no-compiler-host-assemblies.ps1`, and `ReleaseGateTests` fails a workflow job that publishes without it.
- Changes that affect what ships (packaging, `buildTransitive/`, package dependencies, the generator, trimming or AOT) also pass the gates that consume the real `.nupkg`: `just smoke-packed-generator` and `just smoke-packed-consumers` (Native AOT console, Blazor WebAssembly trimmed and AOT, Native AOT minimal API), plus `just wasm-size`, `just verify-trim <rid>` and `just publish-aot-sample`.
- Before a release, run the pre-release checklist in `docs/wiki/Release-Flow.md` ("Release gates"): `just scrub`, `just pipeline-local-release ...`, then every gate above.
- Before a release, run the pre-release checklist in `docs/wiki/development/Release-Flow.md` ("Release gates"): `just scrub`, `just pipeline-local-release ...`, then every gate above.

## Installed skills (`.agents/skills/`)

Expand Down
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,13 +86,13 @@ canonical paths (`Items[0].Name`, `Map[en]`, `Map["0"]`), typed bounds and local

| Package | What it adds |
| --- | --- |
| `Purview.ZodSharp.Extensions.Validation` | The Microsoft.Extensions.Validation bridge (`AddZodSharpValidation()`); WebAssembly-safe. See [Microsoft.Extensions.Validation](docs/wiki/Microsoft-Extensions-Validation.md) |
| `Purview.ZodSharp.AspNetCore.OpenApi` | OpenAPI transformers that describe ZodSharp's constraints and validation problem responses (`options.AddZodSharp()`). See [OpenAPI Integration](docs/wiki/OpenAPI-Integration.md) |
| `Purview.ZodSharp.Blazor` | Blazor Server and WebAssembly form validation. See [Blazor Integration](docs/wiki/Blazor-Integration.md) |
| `Purview.ZodSharp.Extensions.Validation` | The Microsoft.Extensions.Validation bridge (`AddZodSharpValidation()`); WebAssembly-safe. See [Microsoft.Extensions.Validation](docs/wiki/hosting/Microsoft-Extensions-Validation.md) |
| `Purview.ZodSharp.AspNetCore.OpenApi` | OpenAPI transformers that describe ZodSharp's constraints and validation problem responses (`options.AddZodSharp()`). See [OpenAPI Integration](docs/wiki/hosting/OpenAPI-Integration.md) |
| `Purview.ZodSharp.Blazor` | Blazor Server and WebAssembly form validation. See [Blazor Integration](docs/wiki/hosting/Blazor-Integration.md) |

`Purview.ZodSharp.AspNetCore` uses the bridge on `net11.0` to produce full-fidelity ProblemDetails from the built-in
pipeline ([ASP.NET Core Integration](docs/wiki/AspNetCore-Integration.md)), and messages are localized through
`IZodMessageFormatter` ([Localization](docs/wiki/Localization.md)).
`IZodMessageFormatter` ([Localization](docs/wiki/hosting/Localization.md)).

## Usage Examples

Expand Down Expand Up @@ -275,7 +275,7 @@ public readonly struct MinLengthRule : IValidationRule<string>
}
```

Every rule exposes its reported code and message template as public `ErrorCode`/`MessageFormat` constants so tests can assert against the rule instead of duplicating literals (`ZODSGEN042` enforces this convention — see the [Validation Rules Reference](docs/wiki/Validation-Rules-Reference.md) for the catalogue of built-in rules, [Custom Rules](docs/wiki/Custom-Rules.md) for the rule contract and [Value Objects Integration](docs/wiki/Value-Objects-Integration.md) for scalar value objects).
Every rule exposes its reported code and message template as public `ErrorCode`/`MessageFormat` constants so tests can assert against the rule instead of duplicating literals (`ZODSGEN042` enforces this convention — see the [Validation Rules Reference](docs/wiki/schemas/Validation-Rules-Reference.md) for the catalogue of built-in rules, [Custom Rules](docs/wiki/schemas/Custom-Rules.md) for the rule contract and [Value Objects Integration](docs/wiki/schemas/Value-Objects-Integration.md) for scalar value objects).

#### 3. Compiled Validators

Expand Down Expand Up @@ -575,7 +575,7 @@ var either = UserSchema.ApplyOr(user, u => u.Age < 18, "Must be an adult or a mi
- Zero-reflection, zero-allocation validators
- Value-first composition methods (`.ApplyAnd()`, `.ApplyOr()`, `.ApplyRefine()`) plus instance schema-composing composition (`.Refine()`, `.SuperRefine()`, `.Pipe()`, `.Catch()`, `.Prefault()`, `.Default()`)
- Supports classes, structs, and records
- Validates `Purview.ValueObjects` `[Scalar]` types as a unit, adapting a rule written against the underlying value automatically ([Value Objects Integration](docs/wiki/Value-Objects-Integration.md))
- Validates `Purview.ValueObjects` `[Scalar]` types as a unit, adapting a rule written against the underlying value automatically ([Value Objects Integration](docs/wiki/schemas/Value-Objects-Integration.md))

#### Supported DataAnnotations size validators

Expand Down
20 changes: 10 additions & 10 deletions docs/wiki/AspNetCore-Integration.md
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ The contract:

- **Keys.** `errors` keys and `issues[].path` are `ValidationError.FullPath.ToDottedString()`: members joined with
`.`, indexes as `[0]`, and keys as `[en]` or, when ambiguous, quoted (`Map["0"]`, `Map["a.b"]`). The root is `""`.
See [Core Concepts](Core-Concepts.md#paths). By default member names are the C# names, matching
See [Core Concepts](concepts/Core-Concepts.md#paths). By default member names are the C# names, matching
Microsoft.Extensions.Validation and MVC model state. `PathNaming = ZodPathNaming.Json` applies the minimal-API
`JsonOptions` naming policy.
- **`code` and `category`.** `code` is ZodSharp's specific identity (`invalid_range`). `category` is the Zod issue
Expand All @@ -210,11 +210,11 @@ The contract:
issue's `path` already names the member. `displayName` is kept. Set `IncludeDiagnosticParameters = true` to send them.
- **`traceId`.** It is present on every path: `Activity.Current?.Id`, else `HttpContext.TraceIdentifier`.
- **No input values.** Messages and parameters never contain the input unless `ZodErrorOptions.IncludeReceivedValues`
is enabled. See [Core Concepts](Core-Concepts.md#pii).
is enabled. See [Core Concepts](concepts/Core-Concepts.md#pii).
- **Messages.** They come from the registered `IZodMessageFormatter` in `CultureInfo.CurrentUICulture`. See
[Localization](Localization.md).
[Localization](hosting/Localization.md).
- **OpenAPI.** The body is described by the `ZodValidationProblemDetails` and `ZodValidationIssue` component schemas
(see [OpenAPI Integration](OpenAPI-Integration.md)).
(see [OpenAPI Integration](hosting/OpenAPI-Integration.md)).

## Minimal API validation

Expand Down Expand Up @@ -317,17 +317,17 @@ Notes:
- **Localization**: register `AddLocalization()` and an `IZodMessageFormatter`, for example
`new StringLocalizerZodMessageFormatter(factory, sharedResourceType: typeof(ValidationMessages))`. Messages
follow `Accept-Language` (with `UseRequestLocalization`); codes and paths are unchanged. See
[Localization](Localization.md).
[Localization](hosting/Localization.md).
- **The bridge**: resolver placement, `ZodReport` and non-HTTP validation are covered in
[Microsoft.Extensions.Validation](Microsoft-Extensions-Validation.md).
[Microsoft.Extensions.Validation](hosting/Microsoft-Extensions-Validation.md).
- **Unions**: a union parameter is claimed by the runtime parameter resolver, which the application's
`AddValidation()` call adds. The active case is reported under `Value` (`Value.Email`).
- **Double validation**: `WithZodSharpValidation()` on an endpoint the pipeline validates skips the parameters
the bridge covers, logging that once at `Debug` when the endpoint is built. On a `DisableValidation()` endpoint
it validates as usual.
- **OpenAPI**: the `Purview.ZodSharp.AspNetCore.OpenApi` operation transformer adds the validation problem
response for endpoints with a ZodSharp-known parameter. No endpoint metadata is added by the pipeline path. See
[OpenAPI Integration](OpenAPI-Integration.md).
[OpenAPI Integration](hosting/OpenAPI-Integration.md).

| | `WithZodSharpValidation()` filter | Built-in pipeline |
|---|---|---|
Expand Down Expand Up @@ -645,7 +645,7 @@ builder.Services.AddZodSharp(options =>
assembly sources, which auto-discovers source-generated `[assembly: ZodSchemaGenerated(typeof(...))]`
registrations.

Assembly scanning is not trim-safe. In a trimmed or Native AOT host, use the generated `AddZodSharp{Assembly}Schemas()` (see [Source Generator](Source-Generator.md)).
Assembly scanning is not trim-safe. In a trimmed or Native AOT host, use the generated `AddZodSharp{Assembly}Schemas()` (see [Source Generator](generator/Source-Generator.md)).

`ZodSchemaFactoryOptions`:

Expand Down Expand Up @@ -683,8 +683,8 @@ builder.Services.AddZodSharpLoadedAssemblies();
| `AddZodSharpFactory(configure)` | core `Purview.ZodSharp` | singleton `IZodSchemaFactory` | Any .NET host where you want manual control — register validators yourself in the `configure` callback. |
| `AddZodSharp{Assembly}Schemas()` | generated into each assembly with `[ZodSchema]` types | a trim-safe `ZodSchemaRegistration` naming every generated validator | Trimmed or Native AOT hosts, and anywhere assembly scanning is unwanted. |
| `AddZodSharpProblemDetails(...)` | `Purview.ZodSharp.AspNetCore` | `ZodExceptionHandler`, the ProblemDetails writer and services, and the .NET 11 pipeline enrichment — does **not** register the factory | Mapping thrown `ZodException`s to `ProblemDetails`; pair it with `AddZodSharp` when you also need DI validator resolution. |
| `AddZodSharpValidation(...)` | `Purview.ZodSharp.Extensions.Validation` (`net11.0`) | the Microsoft.Extensions.Validation resolver | Validating with the .NET 11 pipeline; see [Microsoft.Extensions.Validation](Microsoft-Extensions-Validation.md). |
| `AddZodSharpValidation(...)` | `Purview.ZodSharp.Extensions.Validation` (`net11.0`) | the Microsoft.Extensions.Validation resolver | Validating with the .NET 11 pipeline; see [Microsoft.Extensions.Validation](hosting/Microsoft-Extensions-Validation.md). |
| `AddZodSchemaOptionsValidator<T>(...)` | core `Purview.ZodSharp` | singleton `IValidateOptions<T>` | Validating options objects; requires a factory registered first via `AddZodSharp` or `AddZodSharpFactory`. Validates every options name; on .NET 11 `ValidateOnStart()` runs its asynchronous rules too. |
| `OptionsBuilder<T>.BindAndValidateWithZod(section)` | `Purview.ZodSharp.AspNetCore` | binds a configuration section and adds the ZodSharp options validator | Options whose failures should name the configuration key (`Smtp:Servers:0:Host`). Uses the reflection-based binder; under Native AOT call `BindConfiguration` and `AddZodSchemaValidator` yourself. |

See [Dependency Injection](Dependency-Injection.md) for the underlying factory and options-validation wiring.
See [Dependency Injection](hosting/Dependency-Injection.md) for the underlying factory and options-validation wiring.
68 changes: 0 additions & 68 deletions docs/wiki/Contributing.md

This file was deleted.

Loading
Loading