You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: .github/ISSUE_TEMPLATE/generator-tracking.md
+4Lines changed: 4 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -19,15 +19,19 @@ assignees: ""
19
19
- Generation:
20
20
- Typecheck:
21
21
-`$dynamicRef` fidelity:
22
+
- Recursive fixtures: dynamic scope resolves to the active recursive type
23
+
- Generic fixtures: generators emit reusable parameterized types when the target language supports generics (concrete materialization is PARTIAL — correct content, lost reuse)
Copy file name to clipboardExpand all lines: README.md
+6-2Lines changed: 6 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -6,7 +6,7 @@ This repository is a public compatibility lab for OpenAPI `$dynamicRef` / `$dyna
6
6
7
7
## Current Headline
8
8
9
-
OpenAPI 3.1.x allows JSON Schema 2020-12 schema objects, and OpenAPI 3.2 explicitly recommends dynamic references for generic/template data structures. In the current matrix, tools still either fail to parse `$dynamicAnchor`, generate syntactically valid but semantically degraded TypeScript, or lose concrete dynamic types such as `User[]`, `LocalizedCategory[]`, or `WorkspaceFolder[]`.
9
+
OpenAPI 3.1.x allows JSON Schema 2020-12 schema objects, and OpenAPI 3.2 explicitly recommends dynamic references for generic/template data structures. In the current matrix, tools still either fail to parse `$dynamicAnchor`, generate syntactically valid but semantically degraded output (e.g., `unknown`, `any`, or `Object`), lose dynamic scope resolution for recursive types, or materialize generic/template patterns as duplicate concrete types instead of reusable parameterized types.
10
10
11
11
Generator and typecheck failures in this repo are **report-only** because those failures are the compatibility data. Fixture validity and generated spec freshness are the CI gates.
|`baseline-duplicated-pagination.yaml`| Control case with duplicated concrete paginated wrappers |
57
57
|`generic-schema-binding.yaml`| Generic pagination with named concrete schemas |
58
58
|`paginated-response.yaml`| Generic pagination with inline response-level binding |
59
+
|`api-envelope.yaml`| Generic response envelope with inline route-level binding |
59
60
|`recursive-category-tree.yaml`| Recursive dynamic override using `$dynamicAnchor: category`|
60
-
|`nested-workspace-resources.yaml`| Nested resource graph with multiple dynamic anchors |
61
+
|`nested-workspace-resources.yaml`| Multi-parameter generic template for nested folder/resource graphs |
62
+
|`non-identifier-schema-key.yaml`| Recursive dynamic override with schema keys that need generated identifier normalization |
63
+
64
+
A combined showcase fixture, [`petstore-dynamicref-showcase.yaml`](petstore-dynamicref-showcase.yaml), exercises all `$dynamicRef` patterns together (generic pagination, response envelopes, nested generics, recursive trees, multi-parameter generic templates, non-identifier keys, typed request/response bodies) and is intended for SDK samples and maintainer demos.
61
65
62
66
Focused semantics fixtures live under `fixtures/spec-semantics/`. They cover JSON Schema behaviors that are important for parser/validator correctness but are intentionally kept out of the SDK matrix.
Copy file name to clipboardExpand all lines: RUNBOOK.md
+6-3Lines changed: 6 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -41,7 +41,7 @@ CI also checks `git diff --exit-code -- specs/` after Stage 1. Fixture validity
41
41
npm run matrix
42
42
```
43
43
44
-
Runs all 9 generators × 5 scenarios × 4 OAS versions in parallel (default: 8 workers). Generators that aren't installed are skipped with a clear message.
44
+
Runs all 9 generators × 7 scenarios × 4 OAS versions in parallel (default: 8 workers). Generators that aren't installed are skipped with a clear message.
For dynamicRef fixtures, the desired result is concrete types (e.g., `items: User[]`, `children: Category[]`). Current generator output degrades to `unknown[]`, `Array<any>`, or `any`.
123
+
For dynamicRef fixtures, the desired result depends on fixture category:
124
+
-**Recursive/nested fixtures:** dynamic refs must resolve to the correct active type through dynamic scope (e.g., `children: LocalizedCategory[]`, not `children: unknown[]`).
125
+
-**Generic/template fixtures:** generators must emit reusable parameterized types when the target language supports generics (e.g., `PaginatedTemplate<T>` with `PaginatedUserResponse = PaginatedTemplate<User>`). Concrete duplicate wrappers do not pass validation for these fixtures — the point of `$dynamicRef` for generics is type reuse. Current generator output degrades to `unknown[]`, `Array<any>`, `any`, or materializes duplicates instead of parameterized types.
Copy file name to clipboardExpand all lines: fixtures/README.md
+24-4Lines changed: 24 additions & 4 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -13,10 +13,20 @@ npm run validate:fixtures
13
13
| Fixture | Purpose | What It Tests |
14
14
|---|---|---|
15
15
|`baseline-duplicated-pagination.yaml`| Control case with explicit `PaginatedUserResponse` and `PaginatedGroupResponse` schemas | Confirms a generator can handle ordinary duplicated wrappers before testing `$dynamicRef`|
16
-
|`generic-schema-binding.yaml`| Reusable paginated wrapper with named concrete schemas (`PaginatedUserResponse`, `PaginatedGroupResponse`) | Tests JSON Schema generic-type pattern using `$dynamicRef` / `$dynamicAnchor`with named type instantiations|
16
+
|`generic-schema-binding.yaml`| Reusable paginated wrapper with named concrete schemas (`PaginatedUserResponse`, `PaginatedGroupResponse`) | Tests JSON Schema generic-type pattern using `$dynamicRef` / `$dynamicAnchor`— generators must emit reusable parameterized types when the target language supports generics, not duplicate concrete wrappers|
17
17
|`paginated-response.yaml`| Reusable paginated wrapper with type binding at the route response level | Tests the same generic pattern but with `$dynamicAnchor` overrides inline in the path operation response — no separate named wrapper schemas |
18
+
|`api-envelope.yaml`| Generic response envelope (`ApiEnvelopeTemplate<T>`) with inline `$defs` binding at the route level — one route binds a single resource, another binds a paginated wrapper | Tests two-level `$dynamicRef` nesting: `ApiEnvelopeTemplate<T>` where `T` is bound inline per route. Generators must emit `ApiEnvelopeTemplate<T>` as a reusable parameterized type. The paginated-list route additionally chains `PaginatedTemplate<User>` as the bound type |
18
19
|`recursive-category-tree.yaml`| Canonical dynamic recursive override | Tests dynamic scope for recursive schemas (`children` should use the active category type) |
19
-
|`nested-workspace-resources.yaml`| Multiple anchors and nested dynamic refs | Tests more than one `$dynamicAnchor` / `$dynamicRef` pair in a nested resource graph |
20
+
|`nested-workspace-resources.yaml`| Multi-parameter generic template for nested folder/resource graphs | Tests a `$dynamicRef` template with two generic slots (`folderType`, `resourceType`) that are bound together in the concrete schema, producing a self-referential folder/resource graph |
21
+
|`non-identifier-schema-key.yaml`| Recursive dynamic override with non-identifier schema keys (`base-category`, `localized-category`) | Tests that generators preserve `$dynamicRef` semantics while normalizing schema keys into valid generated identifiers |
22
+
23
+
A combined showcase fixture at [`petstore-dynamicref-showcase.yaml`](../petstore-dynamicref-showcase.yaml) exercises all `$dynamicRef` patterns together (generic pagination, response envelopes, nested generics, recursive trees, multi-parameter generic templates, non-identifier keys, typed request/response bodies) and is intended for SDK samples, maintainer demos, and "what good output looks like" examples. It is not a replacement for the focused minimal fixtures above.
24
+
25
+
## Generator Edge Fixtures
26
+
27
+
Generator edge fixtures are top-level SDK matrix scenarios when the behavior is portable across generators. `non-identifier-schema-key.yaml` is one of these: it tests schema-key normalization plus dynamic reference fidelity, not any one tool's internal implementation.
28
+
29
+
Tool-specific switches, such as Orval's `enableUnstableDynamicRefSupport`, are not modeled as schema fixtures. Track those in the relevant GitHub issue and tool docs instead.
20
30
21
31
## Spec Semantics Fixtures
22
32
@@ -25,6 +35,8 @@ npm run validate:fixtures
25
35
| Fixture | What It Tests |
26
36
|---|---|
27
37
|`spec-semantics/dynamicref-core-semantics.yaml`| Same-resource dynamic anchors, `$dynamicRef` to `$anchor`, `$ref` to `$dynamicAnchor`, fallback to ordinary anchor behavior, non-fragment URI dynamic refs, multi-parameter generic binding, and allOf sibling order |
38
+
|`spec-semantics/external-dynamic-ref.yaml`|`$dynamicRef` to an external JSON Schema resource (`external-dynamic-target.json`) for parser/bundler research |
39
+
|`spec-semantics/ambiguous-sibling-anchors.yaml`| Multiple sibling schemas with the same `$dynamicAnchor` name, documenting where static sibling scans are only an approximation of dynamic scope |
28
40
29
41
## Why Keep The Baseline?
30
42
@@ -63,9 +75,13 @@ Run via `scripts/validate-openapi.sh` as part of the Stage 1 pipeline. This incl
|`api-envelope.yaml`| Valid wrapped-user page fails; invalid item cases fail | Not tested | Not tested | Expected same gap as pagination fixtures; AJV PR #2615 should fix this |
|`nested-workspace-resources.yaml`| Valid nested workspace passes; nested folder missing permissions fails | Fails: "resolves to more than one schema" for multiple same-name `$dynamicAnchor`| Not tested | Separate AJV gap: multiple schemas with same `$dynamicAnchor` name |
99
+
|`nested-workspace-resources.yaml`| Valid nested workspace passes; AJV accepts invalid nested folder data (missing `permissions` field) | Fails: "resolves to more than one schema" for multiple same-name `$dynamicAnchor` in the same document (`FolderTemplate.$defs.folderType` and `WorkspaceFolder.$defs.folderType` share an anchor name) — this is an AJV limitation, not a fixture bug | Not tested | AJV does not correctly resolve the multi-parameter generic template pattern; the fixture is semantically sound |
|`spec-semantics/ambiguous-sibling-anchors.yaml`| Not tested | Not tested | Not tested | OpenAPI-valid research fixture for static-scan limitations |
83
102
|`spec-semantics/dynamicref-core-semantics.yaml`|`$ref` to `$dynamicAnchor` passes; several `$dynamicRef` core cases are known gaps, including non-fragment URI refs | Not tested | Core cases, non-fragment URI refs, allOf order, and multi-parameter generic cases pass | Semantics fixture tier; AJV gaps are documented by case output |
103
+
|`spec-semantics/external-dynamic-ref.yaml`| Not tested | Not tested | Valid external node passes; invalid external node fails | External resource semantics fixture for parser/bundler research |
84
104
85
-
AJV PR [#2615](https://github.com/ajv-validator/ajv/pull/2615) fixes the generic pagination dynamic binding pattern. The nested workspace fixture exposes a separate AJV limitation: multiple schemas declaring the same `$dynamicAnchor` name in a single document causes an ambiguous reference error.
105
+
AJV PR [#2615](https://github.com/ajv-validator/ajv/pull/2615) fixes the generic pagination dynamic binding pattern. The nested workspace fixture exposes a separate AJV limitation: multiple schemas declaring the same `$dynamicAnchor` name in a single document causes an ambiguous reference error. This is a limitation of AJV PR #2615, not a bug in the fixture — `nested-workspace-resources.yaml` is semantically correct (both anchor declarations are scoped to different schemas in the `allOf` chain).
0 commit comments