diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 0242d0da7..7b79990f5 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -21,6 +21,7 @@ on:
branches:
- master
- main
+ - v15
tags:
- 'v*.*.*'
paths:
@@ -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:
@@ -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:
@@ -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:
diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml
index fbd310904..a8c9f0e43 100644
--- a/.github/workflows/pr.yml
+++ b/.github/workflows/pr.yml
@@ -21,6 +21,7 @@ on:
branches:
- master
- main
+ - v15
paths:
- '**/*.*'
- '!**/*.md'
@@ -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'
@@ -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:
@@ -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
diff --git a/CLAUDE.md b/CLAUDE.md
new file mode 100644
index 000000000..c9f24f25b
--- /dev/null
+++ b/CLAUDE.md
@@ -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 `true` 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.
+- **`true`** — 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.
+- **`enable`** and `latest` 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.
diff --git a/Directory.Build.props b/Directory.Build.props
index 8adba07b7..0ec889979 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -36,6 +36,10 @@
true
+
+ true
+
diff --git a/build/Build.CI.GitHubActions.cs b/build/Build.CI.GitHubActions.cs
index 7c270aa6e..18a152a44 100644
--- a/build/Build.CI.GitHubActions.cs
+++ b/build/Build.CI.GitHubActions.cs
@@ -10,7 +10,7 @@
GitHubActionsImage.WindowsLatest,
GitHubActionsImage.UbuntuLatest,
GitHubActionsImage.MacOsLatest,
- OnPullRequestBranches = ["master", "main"],
+ OnPullRequestBranches = ["master", "main", "v15"],
OnPullRequestIncludePaths = ["**/*.*"],
OnPullRequestExcludePaths = ["**/*.md"],
PublishArtifacts = true,
@@ -23,7 +23,7 @@
GitHubActionsImage.WindowsLatest,
GitHubActionsImage.UbuntuLatest,
GitHubActionsImage.MacOsLatest,
- OnPushBranches = ["master", "main"],
+ OnPushBranches = ["master", "main", "v15"],
OnPushTags = ["v*.*.*"],
OnPushIncludePaths = ["**/*.*"],
OnPushExcludePaths = ["**/*.md"],
diff --git a/docs/changelog_v15.md b/docs/changelog_v15.md
new file mode 100644
index 000000000..9e02d44b6
--- /dev/null
+++ b/docs/changelog_v15.md
@@ -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.
diff --git a/docs/plan_v15.md b/docs/plan_v15.md
new file mode 100644
index 000000000..94a62bdef
--- /dev/null
+++ b/docs/plan_v15.md
@@ -0,0 +1,106 @@
+# NSwag v15
+
+Scope, branch model, release plan, and running changelog for the v15 major release.
+
+## Scope
+
+v15 is gated on NJsonSchema v12 and bundles the companion set of breaking improvements:
+
+- **STJ core migration** (PR [#5355](https://github.com/RicoSuter/NSwag/pull/5355)) — mirrors NJsonSchema v12's STJ migration. Newtonsoft.Json usage in `NSwag.Core` and siblings moves to Newtonsoft-specific packages where possible.
+- **Absorb NJsonSchema v12 breaking API changes** — `ValidationError.Token` type change, `SchemaType` enum expansion (3.0 vs 3.1), reference-resolution fixes, etc.
+- **Other v15 cleanups** as identified during development (rename-risk members, deprecated API removal).
+
+## Dependency on NJsonSchema v12
+
+NSwag v15 depends on NJsonSchema v12. During Phase 1 development, this is wired via **project references** using the `UseLocalNJsonSchemaProjects` MSBuild property, defined in `Directory.Build.props` and defaulting to `true` on the `v15` branch. Each NSwag csproj that depends on NJsonSchema has a pair of conditional `ItemGroup` blocks:
+
+```xml
+
+
+
+
+
+
+```
+
+Practical implications:
+
+- Both repos are checked out as siblings locally: `../NJsonSchema` on the `v12` branch, `../NSwag` on the `v15` branch.
+- Changes to NJsonSchema v12 flow into the local NSwag v15 build immediately.
+- A breaking change on NJsonSchema v12 that NSwag v15 relies on surfaces as a compile error on the very next build — the "cross-check with NSwag" rule from [`CLAUDE.md`](../CLAUDE.md) is mechanically enforced.
+
+When NJsonSchema v12 is feature-complete (Phase 2), NSwag v15 flips to `UseLocalNJsonSchemaProjects=false` and consumes NJsonSchema v12 preview NuGet packages for external integration validation before either library releases.
+
+## CI setup (temporary)
+
+While v15 uses `UseLocalNJsonSchemaProjects=true`, the `v15` branch's CI workflows check out `RicoSuter/NJsonSchema` at the `v12` branch as a sibling directory:
+
+```yaml
+- 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
+```
+
+Layout on the runner: `$GITHUB_WORKSPACE/../NJsonSchema` (sibling to the NSwag checkout), which matches the relative project-reference paths (`../../../NJsonSchema/src/…`).
+
+**Why the pre-build step:** even though NSwag's solution build would nominally build NJsonSchema transitively via project references, MSBuild's `Configuration=Release` property doesn't reliably propagate across repo boundaries when both sides use `UseArtifactsOutput=true`. Without the pre-build, NJsonSchema compiles to `artifacts/bin/*/debug_*` while NSwag expects `release_*` for the final `dotnet publish --no-build` step on `NSwag.ConsoleCore`, and the publish fails with `MSB3030: Could not copy the file .../release_net8.0/NJsonSchema.dll`. Pre-building NJsonSchema in Release produces the expected artifacts at the expected paths.
+
+**Note:** The NSwag workflow YAMLs are normally auto-generated by NUKE (`build/Build.CI.GitHubActions.cs`). The sibling-clone step is a hand edit on the `v15` branch only; NUKE regeneration would remove it. This is intentional — see the cleanup checklist below.
+
+## Branch model
+
+Mirrors NJsonSchema v12. The `v15` branch is the integration branch.
+
+```
+master (v14.x stable) ────o────o────o────o────o────o──── v14.x patches
+ \ \
+ \ periodic merges \
+ ↓ ↓
+v15 (integration) ─────o────o────O────O────O────O────── release v15.0.0 → merge to master
+ ↑
+ feature PRs target v15
+```
+
+Rules:
+
+- `master` remains the v14.x stable line.
+- All v15 feature PRs target `v15`.
+- `master` is merged into `v15` periodically to keep v15 fresh.
+- When v15 is ready, it is merged into `master` via a final PR (`--no-ff`), tagged `v15.0.0`, and published.
+
+## Release plan
+
+Ordered by the NJsonSchema → NSwag dependency:
+
+1. **NJsonSchema v12** stabilizes, tagged `v12.0.0`, published to NuGet.
+2. **NSwag v15** bumps its dependency to `NJsonSchema 12.0.0`, switches `UseLocalNJsonSchemaProjects=false`, stabilizes, is tagged `v15.0.0`, and published.
+
+v14.x patches continue to ship from `master` until superseded.
+
+## Pre-release cleanup checklist
+
+Before the final `v15` → `master` merge, revert the temporary shims that only make sense while v15 is a live branch:
+
+- **`build/Build.CI.GitHubActions.cs`**: remove `"v15"` from `OnPullRequestBranches` and `OnPushBranches`.
+- **`.github/workflows/build.yml`, `.github/workflows/pr.yml`**: regenerate from NUKE (`nuke --generate-configuration GitHubActions_build --host GitHubActions` and the `pr` equivalent). This will:
+ - Remove the `v15` branch filter entry.
+ - **Remove the hand-added sibling NJsonSchema checkout steps** — they're the temporary glue for `UseLocalNJsonSchemaProjects=true` in CI and won't make sense once v15 references stable NJsonSchema v12 NuGet packages.
+- **`Directory.Build.props`**: flip `UseLocalNJsonSchemaProjects` default back to `false`, or remove the property entirely and drop the conditional `ItemGroup` blocks from each csproj. NSwag `master` historically uses plain `PackageReference` only; decide before the final merge whether to keep the conditional pattern (allows future major-version dev to reuse it) or revert to the simpler form.
+- **Bump NJsonSchema package references** in `Directory.Packages.props` to the released stable `12.0.0` (or later).
+- **`docs/plan_v15.md` and `docs/changelog_v15.md`**: move or archive after release — either delete once v15 is GA, or relocate to `docs/releases/` as historical context.
+- **Any `[Obsolete]` shims** added specifically to ease the v14→v15 migration: remove or mark for removal in v16.
+
+Add items to this checklist as new temporary shims are introduced during v15 development so nothing leaks into the final release.
+
+## Contributing to v15
+
+- Open PRs against `v15`, not `master`.
+- If the change requires an NJsonSchema change, open the NJsonSchema PR first (against NJsonSchema's `v12` branch) and reference it from your NSwag PR so reviewers see the full picture.
+- Non-breaking bug fixes unrelated to v15 scope should target `master` (v14.x) — they will be brought into `v15` via periodic master→v15 merges.
+
+## Changelog and migration guide
+
+See [`changelog_v15.md`](./changelog_v15.md) for the running list of landed changes and the v14 → v15 migration guide. Every PR merged to `v15` that has user-visible impact should update that file (see its `Contributing` section).
diff --git a/src/NSwag.AspNet.WebApi/NSwag.AspNet.WebApi.csproj b/src/NSwag.AspNet.WebApi/NSwag.AspNet.WebApi.csproj
index a19373901..d115c9a41 100644
--- a/src/NSwag.AspNet.WebApi/NSwag.AspNet.WebApi.csproj
+++ b/src/NSwag.AspNet.WebApi/NSwag.AspNet.WebApi.csproj
@@ -7,6 +7,12 @@
+
+
+
+
+
+
diff --git a/src/NSwag.CodeGeneration.CSharp/NSwag.CodeGeneration.CSharp.csproj b/src/NSwag.CodeGeneration.CSharp/NSwag.CodeGeneration.CSharp.csproj
index 9959284aa..48fc660c0 100644
--- a/src/NSwag.CodeGeneration.CSharp/NSwag.CodeGeneration.CSharp.csproj
+++ b/src/NSwag.CodeGeneration.CSharp/NSwag.CodeGeneration.CSharp.csproj
@@ -12,7 +12,10 @@
-
+
+
+
+
diff --git a/src/NSwag.CodeGeneration.Tests/NSwag.CodeGeneration.Tests.csproj b/src/NSwag.CodeGeneration.Tests/NSwag.CodeGeneration.Tests.csproj
index e827c0105..bc874f939 100644
--- a/src/NSwag.CodeGeneration.Tests/NSwag.CodeGeneration.Tests.csproj
+++ b/src/NSwag.CodeGeneration.Tests/NSwag.CodeGeneration.Tests.csproj
@@ -8,7 +8,6 @@
-
@@ -17,6 +16,13 @@
+
+
+
+
+
+
+
diff --git a/src/NSwag.CodeGeneration.TypeScript/NSwag.CodeGeneration.TypeScript.csproj b/src/NSwag.CodeGeneration.TypeScript/NSwag.CodeGeneration.TypeScript.csproj
index 0caf9128d..781babd9e 100644
--- a/src/NSwag.CodeGeneration.TypeScript/NSwag.CodeGeneration.TypeScript.csproj
+++ b/src/NSwag.CodeGeneration.TypeScript/NSwag.CodeGeneration.TypeScript.csproj
@@ -12,7 +12,10 @@
-
+
+
+
+
\ No newline at end of file
diff --git a/src/NSwag.CodeGeneration/NSwag.CodeGeneration.csproj b/src/NSwag.CodeGeneration/NSwag.CodeGeneration.csproj
index 4bb62721b..7ad9d27e5 100644
--- a/src/NSwag.CodeGeneration/NSwag.CodeGeneration.csproj
+++ b/src/NSwag.CodeGeneration/NSwag.CodeGeneration.csproj
@@ -4,7 +4,10 @@
true
-
+
+
+
+
diff --git a/src/NSwag.Core.Yaml/NSwag.Core.Yaml.csproj b/src/NSwag.Core.Yaml/NSwag.Core.Yaml.csproj
index 94c45c36a..c91533994 100644
--- a/src/NSwag.Core.Yaml/NSwag.Core.Yaml.csproj
+++ b/src/NSwag.Core.Yaml/NSwag.Core.Yaml.csproj
@@ -4,7 +4,10 @@
NSwag
-
+
+
+
+
diff --git a/src/NSwag.Core/NSwag.Core.csproj b/src/NSwag.Core/NSwag.Core.csproj
index 685b4cea4..63affeb27 100644
--- a/src/NSwag.Core/NSwag.Core.csproj
+++ b/src/NSwag.Core/NSwag.Core.csproj
@@ -6,7 +6,10 @@
true
-
+
+
+
+
diff --git a/src/NSwag.Generation/NSwag.Generation.csproj b/src/NSwag.Generation/NSwag.Generation.csproj
index fc12ea958..1c83f7960 100644
--- a/src/NSwag.Generation/NSwag.Generation.csproj
+++ b/src/NSwag.Generation/NSwag.Generation.csproj
@@ -6,7 +6,10 @@
$(NoWarn),618
-
+
+
+
+