-
Notifications
You must be signed in to change notification settings - Fork 275
fix(library): preserve patternProperties semantics in OpenAPI 2.0 and 3.0 serialization #2746
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 8 commits
1570f61
592d43e
d7a5d72
f4bf56a
ee22d13
6651450
a60794a
581c3d8
1bb349d
deb4104
6c09a0d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,6 +3,8 @@ | |
|
|
||
| using System; | ||
| using System.Collections.Generic; | ||
| using System.Globalization; | ||
| using System.IO; | ||
| using System.Linq; | ||
| using System.Text.Json; | ||
| using System.Text.Json.Nodes; | ||
|
|
@@ -493,6 +495,13 @@ | |
| // properties | ||
| writer.WriteOptionalMap(OpenApiConstants.Properties, Properties, callback); | ||
|
|
||
| var hasPatternPropertiesForV30 = version == OpenApiSpecVersion.OpenApi3_0 && PatternProperties is { Count: > 0 }; | ||
|
|
||
| if (hasPatternPropertiesForV30) | ||
| { | ||
| writer.WriteOptionalMap(OpenApiConstants.PatternPropertiesExtension, PatternProperties, callback); | ||
| } | ||
|
|
||
| // additionalProperties | ||
| if (AdditionalProperties is not null && version >= OpenApiSpecVersion.OpenApi3_0) | ||
| { | ||
|
|
@@ -501,6 +510,20 @@ | |
| AdditionalProperties, | ||
| callback); | ||
| } | ||
| else if (hasPatternPropertiesForV30) | ||
| { | ||
| if (TryGetPatternPropertiesFallbackSchema(out var fallbackSchema) && fallbackSchema is not null) | ||
| { | ||
| writer.WriteOptionalObject( | ||
| OpenApiConstants.AdditionalProperties, | ||
| fallbackSchema, | ||
| callback); | ||
| } | ||
| else | ||
| { | ||
| writer.WriteProperty(OpenApiConstants.AdditionalProperties, true); | ||
| } | ||
| } | ||
| // true is the default, no need to write it out | ||
| else if (!AdditionalPropertiesAllowed) | ||
| { | ||
|
|
@@ -611,6 +634,54 @@ | |
| writer.WriteOptionalMap(OpenApiConstants.DependentRequired, DependentRequired, (w, s) => w.WriteValue(s)); | ||
| } | ||
|
|
||
| private bool TryGetPatternPropertiesFallbackSchema(out IOpenApiSchema? fallbackSchema) | ||
| { | ||
| fallbackSchema = null; | ||
| if (PatternProperties is not { Count: > 0 }) | ||
| { | ||
| return false; | ||
| } | ||
|
|
||
| fallbackSchema = PatternProperties.First().Value; | ||
| if (PatternProperties.Count == 1) | ||
| { | ||
| return fallbackSchema is not null; | ||
| } | ||
|
|
||
| var baselineNode = SerializeSchemaToComparableJsonNode(fallbackSchema); | ||
| if (baselineNode is null) | ||
| { | ||
| fallbackSchema = null; | ||
| return false; | ||
| } | ||
|
|
||
| foreach (var schema in PatternProperties.Skip(1).Select(static x => x.Value)) | ||
| { | ||
| var schemaNode = SerializeSchemaToComparableJsonNode(schema); | ||
| if (schemaNode is null || !JsonNode.DeepEquals(baselineNode, schemaNode)) | ||
| { | ||
| fallbackSchema = null; | ||
| return false; | ||
| } | ||
| } | ||
|
||
|
|
||
| return true; | ||
| } | ||
|
|
||
| private static JsonNode? SerializeSchemaToComparableJsonNode(IOpenApiSchema schema) | ||
| { | ||
| if (schema is not IOpenApiSerializable serializableSchema) | ||
| { | ||
| return null; | ||
| } | ||
|
|
||
| using var stringWriter = new StringWriter(CultureInfo.InvariantCulture); | ||
| var jsonWriter = new OpenApiJsonWriter(stringWriter, new OpenApiJsonWriterSettings { Terse = true }); | ||
| serializableSchema.SerializeAsV31(jsonWriter); | ||
|
|
||
| return JsonNode.Parse(stringWriter.ToString()); | ||
| } | ||
|
Comment on lines
+669
to
+681
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this approach is going to seriously degrade performance when we hit the revealing condition (which the performance tests are not). Plus it's not future proof in the sense that properties will evolve from 3.1 to 3.2, and eventually 3.3, etc... I'd much rather see an IEqualityComparer be implemented, plus that's been a request for this lib for a while, so it'd be a move in the right direction, enable reusability, etc... #414 |
||
|
|
||
| internal void WriteAsItemsProperties(IOpenApiWriter writer) | ||
| { | ||
| // type | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.