Skip to content
This repository was archived by the owner on Nov 11, 2025. It is now read-only.

Commit 5d365c0

Browse files
committed
feat: adds parsing infrastructure for version 3.2
Signed-off-by: Vincent Biret <[email protected]>
1 parent 7f869d0 commit 5d365c0

39 files changed

+2660
-3
lines changed

src/Microsoft.OpenApi.Hidi/OpenApiService.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ public static async Task TransformOpenApiDocumentAsync(HidiOptions options, ILog
6969

7070
// Default to yaml and OpenApiVersion 3_1 during csdl to OpenApi conversion
7171
var openApiFormat = options.OpenApiFormat ?? (!string.IsNullOrEmpty(options.OpenApi) ? GetOpenApiFormat(options.OpenApi, logger) : OpenApiConstants.Yaml);
72-
var openApiVersion = options.Version != null ? TryParseOpenApiSpecVersion(options.Version) : OpenApiSpecVersion.OpenApi3_1;
72+
var openApiVersion = options.Version != null ? TryParseOpenApiSpecVersion(options.Version) : OpenApiSpecVersion.OpenApi3_2;
7373

7474
// If ApiManifest is provided, set the referenced OpenAPI document
7575
var apiDependency = await FindApiDependencyAsync(options.FilterOptions.FilterByApiManifest, logger, cancellationToken).ConfigureAwait(false);

src/Microsoft.OpenApi.Hidi/OpenApiSpecVersionHelper.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,12 @@ public static OpenApiSpecVersion TryParseOpenApiSpecVersion(string value)
3535
{
3636
return OpenApiSpecVersion.OpenApi3_1;
3737
}
38+
else if (majorVersion == 3 && minorVersion == 2)
39+
{
40+
return OpenApiSpecVersion.OpenApi3_2;
41+
}
3842

39-
return OpenApiSpecVersion.OpenApi3_1; // default
43+
return OpenApiSpecVersion.OpenApi3_2; // default
4044
}
4145
}
4246
}

src/Microsoft.OpenApi.Workbench/MainModel.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ public OpenApiSpecVersion Version
155155
OnPropertyChanged(nameof(IsV2_0));
156156
OnPropertyChanged(nameof(IsV3_0));
157157
OnPropertyChanged(nameof(IsV3_1));
158+
OnPropertyChanged(nameof(IsV3_2));
158159
}
159160
}
160161

@@ -188,6 +189,12 @@ public bool IsV3_1
188189
set => Version = value ? OpenApiSpecVersion.OpenApi3_1 : Version;
189190
}
190191

192+
public bool IsV3_2
193+
{
194+
get => Version == OpenApiSpecVersion.OpenApi3_2;
195+
set => Version = value ? OpenApiSpecVersion.OpenApi3_2 : Version;
196+
}
197+
191198
/// <summary>
192199
/// Handling method when the property with given name has changed.
193200
/// </summary>

src/Microsoft.OpenApi/Extensions/OpenApiSerializableExtensions.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,10 @@ public static Task SerializeAsync<T>(this T element, IOpenApiWriter writer, Open
111111

112112
switch (specVersion)
113113
{
114+
case OpenApiSpecVersion.OpenApi3_2:
115+
element.SerializeAsV32(writer);
116+
break;
117+
114118
case OpenApiSpecVersion.OpenApi3_1:
115119
element.SerializeAsV31(writer);
116120
break;

src/Microsoft.OpenApi/Models/OpenApiDocument.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,10 @@ public void SerializeAs(OpenApiSpecVersion version, IOpenApiWriter writer)
162162
SerializeAsV31(writer);
163163
break;
164164

165+
case OpenApiSpecVersion.OpenApi3_2:
166+
SerializeAsV32(writer);
167+
break;
168+
165169
default:
166170
throw new ArgumentOutOfRangeException(nameof(version), version, string.Format(SRResource.OpenApiSpecVersionNotSupported, version));
167171
}

src/Microsoft.OpenApi/Reader/OpenApiVersionExtensionMethods.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,5 +57,21 @@ public static bool is3_1(this string version)
5757

5858
return result;
5959
}
60+
61+
/// <summary>
62+
/// Extension method for Spec version 3.2
63+
/// </summary>
64+
/// <param name="version"></param>
65+
/// <returns></returns>
66+
public static bool is3_2(this string version)
67+
{
68+
bool result = false;
69+
if (version.StartsWith("3.2", StringComparison.OrdinalIgnoreCase))
70+
{
71+
result = true;
72+
}
73+
74+
return result;
75+
}
6076
}
6177
}

src/Microsoft.OpenApi/Reader/ParsingContext.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using Microsoft.OpenApi.Reader.V2;
99
using Microsoft.OpenApi.Reader.V3;
1010
using Microsoft.OpenApi.Reader.V31;
11+
using Microsoft.OpenApi.Reader.V32;
1112

1213
namespace Microsoft.OpenApi.Reader
1314
{
@@ -88,6 +89,12 @@ public OpenApiDocument Parse(JsonNode jsonNode, Uri location)
8889
this.Diagnostic.SpecificationVersion = OpenApiSpecVersion.OpenApi3_1;
8990
ValidateRequiredFields(doc, version);
9091
break;
92+
case string version when version.is3_2():
93+
VersionService = new OpenApiV32VersionService(Diagnostic);
94+
doc = VersionService.LoadDocument(RootNode, location);
95+
this.Diagnostic.SpecificationVersion = OpenApiSpecVersion.OpenApi3_2;
96+
ValidateRequiredFields(doc, version);
97+
break;
9198
default:
9299
throw new OpenApiUnsupportedSpecVersionException(inputVersion);
93100
}
@@ -123,6 +130,10 @@ public OpenApiDocument Parse(JsonNode jsonNode, Uri location)
123130
this.VersionService = new OpenApiV31VersionService(Diagnostic);
124131
element = this.VersionService.LoadElement<T>(node, openApiDocument);
125132
break;
133+
case OpenApiSpecVersion.OpenApi3_2:
134+
this.VersionService = new OpenApiV32VersionService(Diagnostic);
135+
element = this.VersionService.LoadElement<T>(node, openApiDocument);
136+
break;
126137
}
127138

128139
return element;

src/Microsoft.OpenApi/Reader/V31/OpenApiV31VersionService.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ internal class OpenApiV31VersionService : BaseOpenApiVersionService
1515
/// <summary>
1616
/// Create Parsing Context
1717
/// </summary>
18-
/// <param name="diagnostic">Provide instance for diagnotic object for collecting and accessing information about the parsing.</param>
18+
/// <param name="diagnostic">Provide instance for diagnostic object for collecting and accessing information about the parsing.</param>
1919
public OpenApiV31VersionService(OpenApiDiagnostic diagnostic):base(diagnostic)
2020
{
2121
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
using System;
2+
3+
namespace Microsoft.OpenApi.Reader.V32
4+
{
5+
/// <summary>
6+
/// Class containing logic to deserialize Open API V3 document into
7+
/// runtime Open API object model.
8+
/// </summary>
9+
internal static partial class OpenApiV32Deserializer
10+
{
11+
private static readonly FixedFieldMap<OpenApiCallback> _callbackFixedFields =
12+
new();
13+
14+
private static readonly PatternFieldMap<OpenApiCallback> _callbackPatternFields =
15+
new()
16+
{
17+
{s => !s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, t) => o.AddPathItem(RuntimeExpression.Build(p), LoadPathItem(n, t))},
18+
{s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p,n))},
19+
};
20+
21+
public static IOpenApiCallback LoadCallback(ParseNode node, OpenApiDocument hostDocument)
22+
{
23+
var mapNode = node.CheckMapNode("callback");
24+
25+
if (mapNode.GetReferencePointer() is { } pointer)
26+
{
27+
var reference = GetReferenceIdAndExternalResource(pointer);
28+
var callbackReference = new OpenApiCallbackReference(reference.Item1, hostDocument, reference.Item2);
29+
callbackReference.Reference.SetMetadataFromMapNode(mapNode);
30+
return callbackReference;
31+
}
32+
33+
var domainObject = new OpenApiCallback();
34+
35+
ParseMap(mapNode, domainObject, _callbackFixedFields, _callbackPatternFields, hostDocument);
36+
37+
return domainObject;
38+
}
39+
}
40+
}
41+
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT license.
3+
4+
using System;
5+
6+
namespace Microsoft.OpenApi.Reader.V32
7+
{
8+
/// <summary>
9+
/// Class containing logic to deserialize Open API V32 document into
10+
/// runtime Open API object model.
11+
/// </summary>
12+
internal static partial class OpenApiV32Deserializer
13+
{
14+
private static readonly FixedFieldMap<OpenApiComponents> _componentsFixedFields = new()
15+
{
16+
{"schemas", (o, n, t) => o.Schemas = n.CreateMap(LoadSchema, t)},
17+
{"responses", (o, n, t) => o.Responses = n.CreateMap(LoadResponse, t)},
18+
{"parameters", (o, n, t) => o.Parameters = n.CreateMap(LoadParameter, t)},
19+
{"examples", (o, n, t) => o.Examples = n.CreateMap(LoadExample, t)},
20+
{"requestBodies", (o, n, t) => o.RequestBodies = n.CreateMap(LoadRequestBody, t)},
21+
{"headers", (o, n, t) => o.Headers = n.CreateMap(LoadHeader, t)},
22+
{"securitySchemes", (o, n, t) => o.SecuritySchemes = n.CreateMap(LoadSecurityScheme, t)},
23+
{"links", (o, n, t) => o.Links = n.CreateMap(LoadLink, t)},
24+
{"callbacks", (o, n, t) => o.Callbacks = n.CreateMap(LoadCallback, t)},
25+
{"pathItems", (o, n, t) => o.PathItems = n.CreateMap(LoadPathItem, t)}
26+
};
27+
28+
private static readonly PatternFieldMap<OpenApiComponents> _componentsPatternFields =
29+
new()
30+
{
31+
{s => s.StartsWith(OpenApiConstants.ExtensionFieldNamePrefix, StringComparison.OrdinalIgnoreCase), (o, p, n, _) => o.AddExtension(p, LoadExtension(p, n))}
32+
};
33+
34+
public static OpenApiComponents LoadComponents(ParseNode node, OpenApiDocument hostDocument)
35+
{
36+
var mapNode = node.CheckMapNode("components");
37+
var components = new OpenApiComponents();
38+
39+
ParseMap(mapNode, components, _componentsFixedFields, _componentsPatternFields, hostDocument);
40+
41+
return components;
42+
}
43+
}
44+
}
45+

0 commit comments

Comments
 (0)