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
16 changes: 16 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ on:
branches:
- master
- main
- v15
tags:
- 'v*.*.*'
paths:
Expand All @@ -45,6 +46,11 @@ jobs:
dotnet-version: |
10.0
- uses: actions/checkout@v6
- name: 'Clone NJsonSchema (v12) as sibling for project references'
run: git clone --depth 1 --branch v12 https://github.com/RicoSuter/NJsonSchema.git ../NJsonSchema
- name: 'Pre-build NJsonSchema (v12) in Release so project-ref artifacts exist'
run: dotnet build src/NJsonSchema.sln -c Release -v minimal
working-directory: ../NJsonSchema
- name: 'Run: Compile, Test, Pack, Publish'
run: ./build.cmd Compile Test Pack Publish
env:
Expand Down Expand Up @@ -81,6 +87,11 @@ jobs:
dotnet-version: |
10.0
- uses: actions/checkout@v6
- name: 'Clone NJsonSchema (v12) as sibling for project references'
run: git clone --depth 1 --branch v12 https://github.com/RicoSuter/NJsonSchema.git ../NJsonSchema
- name: 'Pre-build NJsonSchema (v12) in Release so project-ref artifacts exist'
run: dotnet build src/NJsonSchema.sln -c Release -v minimal
working-directory: ../NJsonSchema
- name: 'Run: Compile, Test, Pack, Publish'
run: ./build.cmd Compile Test Pack Publish
env:
Expand All @@ -97,6 +108,11 @@ jobs:
dotnet-version: |
10.0
- uses: actions/checkout@v6
- name: 'Clone NJsonSchema (v12) as sibling for project references'
run: git clone --depth 1 --branch v12 https://github.com/RicoSuter/NJsonSchema.git ../NJsonSchema
- name: 'Pre-build NJsonSchema (v12) in Release so project-ref artifacts exist'
run: dotnet build src/NJsonSchema.sln -c Release -v minimal
working-directory: ../NJsonSchema
- name: 'Run: Compile, Test, Pack, Publish'
run: ./build.cmd Compile Test Pack Publish
env:
Expand Down
16 changes: 16 additions & 0 deletions .github/workflows/pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ on:
branches:
- master
- main
- v15
paths:
- '**/*.*'
- '!**/*.md'
Expand All @@ -47,6 +48,11 @@ jobs:
dotnet-version: |
10.0
- uses: actions/checkout@v6
- name: 'Clone NJsonSchema (v12) as sibling for project references'
run: git clone --depth 1 --branch v12 https://github.com/RicoSuter/NJsonSchema.git ../NJsonSchema
- name: 'Pre-build NJsonSchema (v12) in Release so project-ref artifacts exist'
run: dotnet build src/NJsonSchema.sln -c Release -v minimal
working-directory: ../NJsonSchema
- name: 'Run: Compile, Test, Pack'
run: ./build.cmd Compile Test Pack
- name: 'Publish: NSwag.zip'
Expand Down Expand Up @@ -78,6 +84,11 @@ jobs:
dotnet-version: |
10.0
- uses: actions/checkout@v6
- name: 'Clone NJsonSchema (v12) as sibling for project references'
run: git clone --depth 1 --branch v12 https://github.com/RicoSuter/NJsonSchema.git ../NJsonSchema
- name: 'Pre-build NJsonSchema (v12) in Release so project-ref artifacts exist'
run: dotnet build src/NJsonSchema.sln -c Release -v minimal
working-directory: ../NJsonSchema
- name: 'Run: Compile, Test, Pack'
run: ./build.cmd Compile Test Pack
macos-latest:
Expand All @@ -89,5 +100,10 @@ jobs:
dotnet-version: |
10.0
- uses: actions/checkout@v6
- name: 'Clone NJsonSchema (v12) as sibling for project references'
run: git clone --depth 1 --branch v12 https://github.com/RicoSuter/NJsonSchema.git ../NJsonSchema
- name: 'Pre-build NJsonSchema (v12) in Release so project-ref artifacts exist'
run: dotnet build src/NJsonSchema.sln -c Release -v minimal
working-directory: ../NJsonSchema
- name: 'Run: Compile, Test, Pack'
run: ./build.cmd Compile Test Pack
109 changes: 109 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project Overview

NSwag is an OpenAPI/Swagger toolchain for .NET and TypeScript: it generates OpenAPI documents from ASP.NET / Web API controllers, generates C# and TypeScript client/controller code from OpenAPI documents, serves Swagger UI / ReDoc at runtime, and ships a Windows GUI (NSwagStudio), an MSBuild target, a CLI (including an npm wrapper), and a Chocolatey-distributed installer. It's built on top of [NJsonSchema](https://github.com/RicoSuter/NJsonSchema) (sibling repo), which provides the JSON Schema object model and code generation primitives.

## Cross-check with NJsonSchema

NSwag consumes NJsonSchema for the JSON Schema object model, `$ref` resolution, reflection-based schema generation, and C#/TypeScript type generation. A sibling clone of NJsonSchema is expected at `../NJsonSchema`.

**Direction of change.** Most NSwag work stays within NSwag. When an NSwag task reveals an NJsonSchema limitation or needs a new capability, don't paper over it — open an NJsonSchema PR first. The reverse direction (NJsonSchema changes affecting NSwag) is governed by NJsonSchema's CLAUDE.md → "Cross-check with NSwag" section.

**When an NSwag change does need NJsonSchema awareness:**

1. **Extending NJsonSchema types.** NSwag subclasses `JsonSchema` (e.g. `OpenApiParameter : JsonSchema` overrides `ActualSchema`), relies on virtual members via overrides, and uses `InternalsVisibleTo` grants in a few places. Read `../NJsonSchema/docs/references.md` for reference-resolution mechanics before adding new overrides or relying on specific `ActualSchema` / `ActualTypeSchema` behavior.
2. **Hitting an NJsonSchema API limitation.** Open an issue or PR on NJsonSchema. Don't patch NSwag to work around missing or broken NJsonSchema behavior — the workaround becomes load-bearing and blocks the eventual fix.
3. **Spec keyword parity.** If NSwag starts emitting or reading an OpenAPI keyword that has a JSON Schema counterpart, verify NJsonSchema supports the same keyword across the same draft versions. Mismatches here are usually platform-level issues worth fixing on NJsonSchema.
4. **Bumping the NJsonSchema dependency.** While v15 builds against sibling project refs (`UseLocalNJsonSchemaProjects=true`), no version bump is needed day-to-day; just commit on both sides. When v15 switches to NuGet for release, update the version in `Directory.Packages.props`.

### Supported spec targets

NSwag supports, both reading and writing:

- **Swagger 2.0** (OpenAPI 2.0) — JSON Schema Draft 4 subset.
- **OpenAPI 3.0.x** — Draft 5 subset; nullability expressed via `nullable: true`.
- **OpenAPI 3.1** — aligned with JSON Schema 2020-12 (native `const`, arbitrary `$ref` siblings, type-array nullability). Full 3.1 support depends on NJsonSchema v12 and lands on the `v15` branch.

`master` / v14.x is primarily 3.0-oriented; `v15` completes 3.1 support. Code that reads or emits an OpenAPI document should behave sensibly across all three formats — the `OpenApiDocument` abstraction paves over most differences, but spec-specific keywords (e.g. `nullable`, `const`) still need branches on `SchemaType`.

## Build and test

The build is driven by [NUKE](https://nuke.build/) via `build.cmd` / `build.sh` / `build.ps1` (all three bootstrap the same `build/_build.csproj`). The SDK version in `global.json` (currently `10.0.100`, `rollForward: latestMinor`) is required — the bootstrapper will download a local copy if the system SDK is missing.

Common targets (run from repo root):

```
./build.cmd Compile # Restore + build the solution
./build.cmd Test # Compile + run all *.Tests projects
./build.cmd Pack # Build NuGet packages, MSI, NSwag.zip / NSwag.Npm.zip (Windows only)
./build.cmd Publish # Push packages (CI only — needs *_API_KEY env vars)
```

Working directly with `dotnet` is fine for day-to-day iteration:

```
dotnet build src/NSwag.sln # Windows full solution (includes WiX installer)
dotnet build src/NSwag.NoInstaller.slnf # Linux/macOS filtered solution (no WiX)
dotnet test src/NSwag.CodeGeneration.CSharp.Tests/NSwag.CodeGeneration.CSharp.Tests.csproj
dotnet test src/NSwag.CodeGeneration.CSharp.Tests/... --filter "FullyQualifiedName~ClientGenerationTests"
```

The NUKE `Compile` target also publishes `NSwag.Console{,.x86}` (net462) and `NSwag.ConsoleCore` (net8.0/9.0/10.0) and copies the binaries into `src/NSwag.Npm/bin/binaries` and (on Windows) the NSwagStudio output. Skipping NUKE and running `dotnet build` alone will not lay out those binaries — use the NUKE target when testing the CLI/NPM/Studio distributions.

## High-level architecture

NSwag is a layered toolchain for OpenAPI/Swagger → .NET & TypeScript. Projects under `src/` are organized by layer:

- **Specification** — `NSwag.Core`, `NSwag.Core.Yaml`, `NSwag.Annotations`: the `OpenApiDocument` object model, (de)serialization, attributes used to decorate controllers.
- **Generation (spec from code)** — `NSwag.Generation`, `NSwag.Generation.WebApi`, `NSwag.Generation.AspNetCore`: walk ASP.NET (Core) / Web API controllers to produce an `OpenApiDocument`.
- **CodeGeneration (code from spec)** — `NSwag.CodeGeneration` (shared base), `NSwag.CodeGeneration.CSharp`, `NSwag.CodeGeneration.TypeScript`: read `OpenApiDocument`, emit C# clients/controllers or TypeScript clients. Templates are `*.liquid` files embedded as resources under each project's `Templates/` folder.
- **Hosting middleware** — `NSwag.AspNetCore`, `NSwag.AspNet.Owin`, `NSwag.AspNet.WebApi`: serve the generated spec + Swagger UI / ReDoc at runtime.
- **Frontends** — `NSwag.Commands` (command object model), `NSwag.ConsoleCore` / `NSwag.Console{,.x86}` (CLIs), `NSwag.MSBuild` (MSBuild target), `NSwag.ApiDescription.Client` (`ServiceProjectReference` SDK), `NSwag.AssemblyLoader` (isolated-AppDomain loader for the CLI), `NSwag.Npm` (npm package wrapping the CLI), `NSwagStudio*` (WPF GUI + Chocolatey + WiX installer).

NSwag depends heavily on **NJsonSchema** (sibling repo [`RicoSuter/NJsonSchema`](https://github.com/RicoSuter/NJsonSchema)) for the JSON Schema object model and for C#/TypeScript type generation. Most code gen works by composing an NJsonSchema `*TypeResolver` + `*Generator` with NSwag's client/controller templates on top.

Multi-targeting: specification/generation projects typically target `netstandard2.0;net462;net8.0` (plus net9/net10 where relevant); hosting packages target `net462` or `netstandard` plus the modern `net8.0`/`net9.0`/`net10.0` ASP.NET Core targets — see `Directory.Packages.props` for the per-TFM package version table (central package management is enabled).

Tests use **xUnit v3** + **Verify.XunitV3** for snapshot assertions — expected output lives under `Snapshots/*.verified.txt` next to each test project. When generator output intentionally changes, a `.received.txt` file will appear; review, rename to `.verified.txt`, and commit. `NSwag.CodeGeneration.CSharp.Tests` also shells out to a C# compiler (`CSharpCompiler.cs`) to confirm generated code actually builds.

## Project docs

| File | Read when |
|------|-----------|
| `docs/plan_v15.md` | Working on the `v15` branch — scope, branch model, pre-release cleanup checklist |
| `docs/changelog_v15.md` | Landing any user-visible change on `v15` — **must be updated** (Breaking / New / Fixes + Migration guide entry if the change breaks v14 consumers) |
| `../NJsonSchema/docs/references.md` | Touching `$ref` resolution, `ActualSchema` / `ActualTypeSchema`, overrides like `OpenApiParameter.ActualSchema`, or spec-keyword parity issues |
| `../NJsonSchema/docs/plan_v12.md` | Coordinating NSwag v15 work with upstream NJsonSchema v12 changes |
| `../NJsonSchema/docs/changelog_v12.md` | Understanding which NJsonSchema breaking changes cascade into v15 — link from `changelog_v15.md` entries that absorb upstream changes |

Keep this index up to date — if a new persistent doc lands under `docs/`, add a row with a concrete "read when" trigger.

## v15 branch conventions

- **NJsonSchema is consumed via local project references**, not NuGet, while v15 is in development. This is controlled by `<UseLocalNJsonSchemaProjects>true</UseLocalNJsonSchemaProjects>` in `Directory.Build.props`. Every `*.csproj` that uses NJsonSchema has paired `ItemGroup Condition=...` blocks — leave both arms in sync when adding a new NJsonSchema reference.
- **Expected local layout**: `../NJsonSchema` (on the `v12` branch) as a sibling to this checkout. CI clones it explicitly; locally you must check it out yourself.
- **Feature PRs target `v15`**, not `master`. `master` is the v14.x stable line. See `docs/plan_v15.md` for the full branch model, release plan, and pre-release cleanup checklist.
- **User-visible changes must update `docs/changelog_v15.md`** (add under `Unreleased` → Breaking / New / Fixes, plus a Migration guide section if it breaks v14 consumers).
- **CI workflow YAMLs are auto-generated by NUKE** (`build/Build.CI.GitHubActions.cs`). The sibling-NJsonSchema `git clone` step in `.github/workflows/{build,pr}.yml` is a **hand edit** on the v15 branch — regenerating via `nuke --generate-configuration ...` will delete it. Don't regenerate without re-adding the clone step (or wait until v15 flips to NuGet-based NJsonSchema).

## Repo-wide settings worth knowing

- **`TreatWarningsAsErrors=true`** for all projects (`Directory.Build.props`). NuGet audit warnings `NU1901-NU1904` are exempt. New warnings from analyzers (`AnalysisLevel=latest-Recommended`, `EnforceCodeStyleInBuild=true`) will break the build — fix them rather than suppressing locally.
- **Assemblies are strong-named** with `NSwag.snk`. `InternalsVisibleTo` entries in `.csproj` files include the full public key — copy an existing entry when adding a new internals-visible consumer.
- **`<UseArtifactsOutput>true</UseArtifactsOutput>`** — all build outputs land under the repo-root `artifacts/` directory (not per-project `bin/`), which is what the NUKE build and the packaging logic assume.
- **`<ImplicitUsings>enable</ImplicitUsings>`** and `<LangVersion>latest</LangVersion>` everywhere.

## Code style

- C# latest language version (`LangVersion=latest`) with implicit usings enabled.
- **Warnings as errors** with analyzer level `latest-Recommended` and `EnforceCodeStyleInBuild=true`. New analyzer warnings will break the build — fix them rather than adding local suppressions (the `NoWarn` lists in `Directory.Build.props` are the established exceptions).
- **No abbreviations in variable / field / parameter names** (e.g. `attribute` not `attr`, `property` not `prop`, `parameter` not `param`).
- **4-space indentation, CRLF line endings** (except `.verified.txt` snapshot files, which are LF).
- Tests follow the **AAA pattern** (`// Arrange`, `// Act`, `// Assert` comments) matching existing test style.

## Git Rules

- Never include "Claude", "Co-Authored-By", or AI attribution in commit messages, PR descriptions, or GitHub comments.
4 changes: 4 additions & 0 deletions Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@

<UseArtifactsOutput>true</UseArtifactsOutput>

<!-- v15 development: build against the sibling NJsonSchema v12 checkout via project references.
Flip to false (or remove) when v15 switches to stable NJsonSchema v12 NuGet packages before release. -->
<UseLocalNJsonSchemaProjects>true</UseLocalNJsonSchemaProjects>

</PropertyGroup>

<ItemGroup>
Expand Down
4 changes: 2 additions & 2 deletions build/Build.CI.GitHubActions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
GitHubActionsImage.WindowsLatest,
GitHubActionsImage.UbuntuLatest,
GitHubActionsImage.MacOsLatest,
OnPullRequestBranches = ["master", "main"],
OnPullRequestBranches = ["master", "main", "v15"],
OnPullRequestIncludePaths = ["**/*.*"],
OnPullRequestExcludePaths = ["**/*.md"],
PublishArtifacts = true,
Expand All @@ -23,7 +23,7 @@
GitHubActionsImage.WindowsLatest,
GitHubActionsImage.UbuntuLatest,
GitHubActionsImage.MacOsLatest,
OnPushBranches = ["master", "main"],
OnPushBranches = ["master", "main", "v15"],
OnPushTags = ["v*.*.*"],
OnPushIncludePaths = ["**/*.*"],
OnPushExcludePaths = ["**/*.md"],
Expand Down
64 changes: 64 additions & 0 deletions docs/changelog_v15.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# NSwag v15 Changelog

Running record of changes on the `v15` branch and migration guidance for users upgrading from v14.

See [`plan_v15.md`](./plan_v15.md) for the v15 scope, branch model, and release plan.

---

## Unreleased

### Breaking changes

- **Set up v15 integration branch, project-ref mechanism, CI triggers, and sibling NJsonSchema v12 checkout** (this PR) — no user-facing impact; infrastructure only.
- Adds `UseLocalNJsonSchemaProjects` property (`Directory.Build.props`, default `true` on v15).
- Converts 8 NSwag csprojs that reference NJsonSchema packages to conditional `ItemGroup` blocks: `NSwag.Core`, `NSwag.Core.Yaml`, `NSwag.CodeGeneration`, `NSwag.CodeGeneration.CSharp`, `NSwag.CodeGeneration.TypeScript`, `NSwag.Generation`, `NSwag.AspNet.WebApi`, `NSwag.CodeGeneration.Tests`.

Planned (not yet merged — track via linked PRs):

- **STJ core migration** — PR [#5355](https://github.com/RicoSuter/NSwag/pull/5355). Mirrors NJsonSchema v12's STJ migration.
- **Absorb NJsonSchema v12 breaking API changes** — `ValidationError.Token` type change, `SchemaType` enum expansion (OpenAPI 3.0 vs 3.1), reference-resolution semantics, etc. Items added as upstream changes land.

### New features

*(to be filled as PRs merge)*

### Fixes

*(to be filled as PRs merge)*

---

## Migration guide (v14 → v15)

Intended as a running "how do I upgrade" companion. Each section is added as breaking changes land on the `v15` branch.

### System.Text.Json migration

*(placeholder — to be filled when PR #5355 merges)*

- What changes for NSwag consumers
- Before/after code snippets
- Newtonsoft.Json escape hatch if you need to keep the old behavior

### NJsonSchema v12 dependency

*(placeholder — to be filled closer to release)*

- NSwag v15 requires NJsonSchema v12.0.0 or later.
- Breaking changes that cascade from NJsonSchema v12 — link to [NJsonSchema's migration guide](https://github.com/RicoSuter/NJsonSchema/blob/v12/docs/changelog_v12.md#migration-guide-v11--v12).

### `SchemaType` enum expansion (OpenAPI 3.0 vs 3.1)

*(placeholder — to be filled when the upstream NJsonSchema enum change lands and NSwag absorbs it)*

---

## Contributing

When merging a v15 PR that includes a user-visible change:

1. Add an entry under `Unreleased → Breaking changes` / `New features` / `Fixes`.
2. If it breaks v14 consumers, also add a section under **Migration guide** with a before/after example.
3. If the change cascades from an NJsonSchema v12 change, link to the corresponding entry in NJsonSchema's `changelog_v12.md` migration guide.
4. Keep entries concise; link to the merged PR for full detail.
Loading
Loading