feat(schema): resolve bare $dynamicRef via $dynamicAnchor index#2913
Open
aqeelat wants to merge 1 commit into
Open
feat(schema): resolve bare $dynamicRef via $dynamicAnchor index#2913aqeelat wants to merge 1 commit into
aqeelat wants to merge 1 commit into
Conversation
e4c3bd2 to
96e2bcc
Compare
…chemaReference Implements document-scoped $dynamicRef resolution per JSON Schema 2020-12 §8.2.3.2. Bare $dynamicRef schemas (no $ref) now deserialize as OpenApiSchemaReference whose Target resolves via per-document $dynamicAnchor and $anchor registries in OpenApiWorkspace. Resolution order in Target: 1. $dynamicAnchor index (single candidate → resolved automatically) 2. $anchor fallback when zero $dynamicAnchor candidates exist (per §8.2.3.2) 3. null when ambiguous (multiple candidates need dynamic-scope tracking) Anchor registries are populated by recursively walking the entire document tree: component schemas, reusable component definitions (parameters, responses, request bodies, headers, callbacks, path items, media types), inline schemas (paths, operations, webhooks), and all nested subschema locations ($defs, properties, items, allOf, if/then/else, etc.). Public APIs for consumers tracking dynamic scope: - GetDynamicAnchorCandidates(doc, anchorName): returns all candidate schemas - ResolveDynamicAnchorInContext(contextSchema, anchorName): resolves against a specific schema's $defs for context-dependent resolution Other changes: - Deserializer (V31/V32): detect bare $dynamicRef, create OpenApiSchemaReference with IsDynamicRefOnly, parse siblings via ApplySchemaMetadata - JsonSchemaReference: add IsDynamicRefOnly flag, implement IOpenApiSchemaMissingProperties, override SerializeAsV31/V32 for dynamic-only refs - JsonNodeHelper: GetDynamicReferencePointer, ExtractDynamicAnchorName, IsFragmentOnlyDynamicRef - Siblings preserved via ApplySchemaMetadata and surfaced through existing Reference-first property getters Fixes microsoft#2911.
96e2bcc to
573f8bf
Compare
Contributor
Author
|
@baywet sorry for the mega PR. Most of the changes are tests and mechanical changes. However, if you want, I can split it into multiple PRs if that will make it easier for you to review. |
Member
|
Thanks for the contribution! No worries, I'll take the time to review during the week. Looking back at the reference mechanisms that are implemented throughout the library, I realized we had a specification/documentation page that never got published on release. Took the time to clean it up a little and it's now available here. https://learn.microsoft.com/en-us/openapi/openapi.net/references-openapi Let us know what you think! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Pull Request
Description
Implements document-scoped
$dynamicRefresolution per JSON Schema 2020-12 §8.2.3.2. Bare$dynamicRefschemas (no$ref) now deserialize asOpenApiSchemaReferencewhoseTargetresolves via per-document$dynamicAnchorand$anchorregistries inOpenApiWorkspace.Resolution order in
Target$dynamicAnchorindex — single candidate resolves automatically$anchorfallback — when zero$dynamicAnchorcandidates exist (per §8.2.3.2)null— when ambiguous (multiple candidates need dynamic-scope tracking)Type of Change
Public APIs for consumers tracking dynamic scope
GetDynamicAnchorCandidates(doc, anchorName)— returns all candidate schemasResolveDynamicAnchorInContext(contextSchema, anchorName)— resolves against a specific schemas$defsBehavior change:
$refsiblings now take precedenceThe
$refdeserializer path now usesApplySchemaMetadata(which populatesJsonSchemaReferenceproperties) instead ofSetMetadataFromJsonObject. Structural siblings on$refschemas (type,maxProperties,pattern,allOf, etc.) are now captured and take precedence over target values via the existingReference.X ?? Target?.Xproperty getters. Previously these siblings were stored but not surfaced. This affects all$refschemas with siblings in 3.1+ documents, not just$dynamicRef.Anchor index coverage
Registries are populated by recursively walking the entire document tree: component schemas, reusable component definitions (parameters, responses, request bodies, headers, callbacks, path items, media types), inline schemas (paths, operations, webhooks), and all nested subschema locations (
$defs,properties,items,allOf,if/then/else, etc.).Open question
When multiple schemas declare the same
$dynamicAnchor,Targetreturnsnull(ambiguous). The spec requires the outermost candidate in the dynamic evaluation scope. Automatic resolution would require threading evaluation context throughTarget(e.g.,AsyncLocal<Stack>). Currently consumers handle this viaGetDynamicAnchorCandidates+ResolveDynamicAnchorInContext. Feedback welcome on whether the library should handle this automatically or leave it to consumers.Testing
Serialize_DoesNotMutateDomfailures on clean main)46 dynamic-ref tests across V31 and V32 covering: bare
$dynamicRefdeserialization, resolution to anchors in all schema locations, ambiguity handling,$anchorfallback,$dynamicAnchorprecedence, round-trip serialization, sibling preservation, context-aware resolution, and$refregression.Microsoft.OpenApi.Tests: 1149 passed.Microsoft.OpenApi.Readers.Tests: 535 passed, 7 pre-existing failures.Checklist
Versions applicability
Related
$refschemas)