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

Commit b54a163

Browse files
authored
Merge pull request #56 from BinkyLabs/chore/upstream-sync
Chore/upstream sync
2 parents c981f10 + 8564a5b commit b54a163

File tree

7 files changed

+134
-14
lines changed

7 files changed

+134
-14
lines changed

.github/workflows/release-please-gha.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ on:
1717
- support/v1
1818
- support/v2
1919

20+
permissions:
21+
contents: read
22+
2023
jobs:
2124
release:
2225
runs-on: ubuntu-latest

.release-please-manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
{
2-
".": "2.3.7"
2+
".": "2.3.8"
33
}

CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,16 @@
11
# Changelog
22

3+
## [2.3.8](https://github.com/microsoft/OpenAPI.NET/compare/v2.3.7...v2.3.8) (2025-10-27)
4+
5+
6+
### Bug Fixes
7+
8+
* an issue where numeric property names would be missing quotes in yaml conversion ([da43c98](https://github.com/microsoft/OpenAPI.NET/commit/da43c98cfd7938a2354bfe57f431aa4bd0407b66))
9+
* an issue where numeric property names would be missing quotes in yaml conversion ([234504c](https://github.com/microsoft/OpenAPI.NET/commit/234504c6a1a53be8630b1f2eda8640f04a92327d))
10+
* quote property names in yaml that match boolean values ([39a9f41](https://github.com/microsoft/OpenAPI.NET/commit/39a9f4112a123b9207504d4a840a9be553703555))
11+
* yaml blocks and line returns ([b053848](https://github.com/microsoft/OpenAPI.NET/commit/b05384872e9364aedf8d8fc24b36bab9824594c5))
12+
* yaml multi-line literals maintain their lines ([558a1ce](https://github.com/microsoft/OpenAPI.NET/commit/558a1ceafc22e6075470a8799582575c8c1e125d))
13+
314
## [2.3.7](https://github.com/microsoft/OpenAPI.NET/compare/v2.3.6...v2.3.7) (2025-10-24)
415

516

Directory.Build.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
<PackageProjectUrl>https://github.com/Microsoft/OpenAPI.NET</PackageProjectUrl>
1313
<Copyright>© Microsoft Corporation. All rights reserved.</Copyright>
1414
<PackageTags>OpenAPI .NET</PackageTags>
15-
<Version>2.3.7</Version>
15+
<Version>2.3.8</Version>
1616
</PropertyGroup>
1717
<!-- https://github.com/clairernovotny/DeterministicBuilds#deterministic-builds -->
1818
<PropertyGroup Condition="'$(TF_BUILD)' == 'true'">

src/Microsoft.OpenApi.YamlReader/Microsoft.OpenApi.YamlReader.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
<PrivateAssets>all</PrivateAssets>
3434
</PackageReference>
3535

36-
<PackageReference Include="SharpYaml" Version="2.1.3" />
36+
<PackageReference Include="SharpYaml" Version="2.1.4" />
3737
<PackageReference Include="System.Text.Json" Version="[8.0.5,)" />
3838
<NuGetAuditSuppress Include="https://github.com/advisories/GHSA-hh2w-p6rv-4g7w" />
3939
<NuGetAuditSuppress Include="https://github.com/advisories/GHSA-8g4q-xg66-9fp4" />

src/Microsoft.OpenApi.YamlReader/YamlConverter.cs

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,10 @@ public static JsonObject ToJsonObject(this YamlMappingNode yaml)
8787

8888
private static YamlMappingNode ToYamlMapping(this JsonObject obj)
8989
{
90-
return new YamlMappingNode(obj.ToDictionary(x => (YamlNode)new YamlScalarNode(x.Key), x => x.Value!.ToYamlNode()));
90+
return new YamlMappingNode(obj.ToDictionary(x => (YamlNode)new YamlScalarNode(x.Key)
91+
{
92+
Style = NeedsQuoting(x.Key) ? ScalarStyle.DoubleQuoted : ScalarStyle.Plain
93+
}, x => x.Value!.ToYamlNode()));
9194
}
9295

9396
/// <summary>
@@ -132,6 +135,11 @@ ScalarStyle.Plain when YamlNullRepresentations.Contains(yaml.Value) => (JsonValu
132135
};
133136
}
134137

138+
private static bool NeedsQuoting(string value) =>
139+
decimal.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out _) ||
140+
bool.TryParse(value, out _) ||
141+
YamlNullRepresentations.Contains(value);
142+
135143
private static YamlScalarNode ToYamlScalar(this JsonValue val)
136144
{
137145
// Try to get the underlying value based on its actual type
@@ -142,13 +150,20 @@ private static YamlScalarNode ToYamlScalar(this JsonValue val)
142150
// For string values, we need to determine if they should be quoted in YAML
143151
// Strings that look like numbers, booleans, or null need to be quoted
144152
// to preserve their string type when round-tripping
145-
var needsQuoting = decimal.TryParse(stringValue, NumberStyles.Float, CultureInfo.InvariantCulture, out _) ||
146-
bool.TryParse(stringValue, out _) ||
147-
YamlNullRepresentations.Contains(stringValue);
153+
var needsQuoting = NeedsQuoting(stringValue);
154+
155+
var containsNewLine = stringValue.Contains('\n');
156+
157+
var style = (needsQuoting, containsNewLine) switch
158+
{
159+
(true, _) => ScalarStyle.DoubleQuoted,
160+
(false, true) => ScalarStyle.Literal,
161+
(false, false) => ScalarStyle.Plain
162+
};
148163

149164
return new YamlScalarNode(stringValue)
150165
{
151-
Style = needsQuoting ? ScalarStyle.DoubleQuoted : ScalarStyle.Plain
166+
Style = style
152167
};
153168
}
154169

test/Microsoft.OpenApi.Readers.Tests/YamlConverterTests.cs

Lines changed: 97 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using Microsoft.OpenApi.YamlReader;
1+
using Microsoft.OpenApi.Tests;
2+
using Microsoft.OpenApi.YamlReader;
23
using SharpYaml;
34
using SharpYaml.Serialization;
45
using System.IO;
@@ -208,10 +209,7 @@ public void ToYamlNode_StringWithLineBreaks_PreservesLineBreaks()
208209
var yamlOutput = ConvertYamlNodeToString(yamlNode);
209210

210211
// Convert back to JSON to verify round-tripping
211-
var yamlStream = new YamlStream();
212-
using var sr = new StringReader(yamlOutput);
213-
yamlStream.Load(sr);
214-
var jsonBack = yamlStream.Documents[0].ToJsonNode();
212+
var jsonBack = ConvertYamlStringToJsonNode(yamlOutput);
215213

216214
// Assert - line breaks should be preserved during round-trip
217215
var originalMultiline = json["multiline"]?.GetValue<string>();
@@ -225,12 +223,105 @@ public void ToYamlNode_StringWithLineBreaks_PreservesLineBreaks()
225223
Assert.Contains("\n", roundTripDescription);
226224
}
227225

226+
[Fact]
227+
public void NumericPropertyNamesShouldRemainStringsFromJson()
228+
{
229+
// Given
230+
var yamlInput =
231+
"""
232+
"123": value1
233+
"456": value2
234+
""";
235+
236+
// Given
237+
var jsonNode = Assert.IsType<JsonObject>(JsonNode.Parse(@"{
238+
""123"": ""value1"",
239+
""456"": ""value2""
240+
}"));
241+
242+
// When
243+
var convertedBack = jsonNode.ToYamlNode();
244+
var convertedBackOutput = ConvertYamlNodeToString(convertedBack);
245+
246+
// Then
247+
Assert.Equal(yamlInput.MakeLineBreaksEnvironmentNeutral(), convertedBackOutput.MakeLineBreaksEnvironmentNeutral());
248+
}
249+
250+
[Fact]
251+
public void NumericPropertyNamesShouldRemainStringsFromYaml()
252+
{
253+
// Given
254+
var yamlInput =
255+
"""
256+
"123": value1
257+
"456": value2
258+
""";
259+
260+
var jsonNode = ConvertYamlStringToJsonNode(yamlInput);
261+
262+
var convertedBack = jsonNode.ToYamlNode();
263+
var convertedBackOutput = ConvertYamlNodeToString(convertedBack);
264+
// Then
265+
Assert.Equal(yamlInput.MakeLineBreaksEnvironmentNeutral(), convertedBackOutput.MakeLineBreaksEnvironmentNeutral());
266+
}
267+
268+
[Fact]
269+
public void BooleanPropertyNamesShouldRemainStringsFromYaml()
270+
{
271+
// Given
272+
var yamlInput =
273+
"""
274+
"true": value1
275+
"false": value2
276+
""";
277+
278+
var jsonNode = ConvertYamlStringToJsonNode(yamlInput);
279+
280+
var convertedBack = jsonNode.ToYamlNode();
281+
var convertedBackOutput = ConvertYamlNodeToString(convertedBack);
282+
// Then
283+
Assert.Equal(yamlInput.MakeLineBreaksEnvironmentNeutral(), convertedBackOutput.MakeLineBreaksEnvironmentNeutral());
284+
}
285+
286+
[Fact]
287+
public void LineBreaksShouldRoundTrip()
288+
{
289+
var yamlInput =
290+
"""
291+
python: |-
292+
from openai import OpenAI
293+
294+
client = OpenAI(
295+
api_key="My API Key",
296+
)
297+
page = client.beta.assistants.list()
298+
page = page.data[0]
299+
print(page.id)
300+
""";
301+
// When
302+
var jsonNode = ConvertYamlStringToJsonNode(yamlInput);
303+
var convertedBack = jsonNode.ToYamlNode();
304+
var convertedBackOutput = ConvertYamlNodeToString(convertedBack);
305+
306+
// Then
307+
Assert.Equal(yamlInput.MakeLineBreaksEnvironmentNeutral(), convertedBackOutput.MakeLineBreaksEnvironmentNeutral());
308+
}
309+
310+
private static JsonNode ConvertYamlStringToJsonNode(string yamlInput)
311+
{
312+
var yamlDocument = new YamlStream();
313+
using var sr = new StringReader(yamlInput);
314+
yamlDocument.Load(sr);
315+
var yamlRoot = yamlDocument.Documents[0].RootNode;
316+
return yamlRoot.ToJsonNode();
317+
}
318+
228319
private static string ConvertYamlNodeToString(YamlNode yamlNode)
229320
{
230321
using var ms = new MemoryStream();
231322
var yamlStream = new YamlStream(new YamlDocument(yamlNode));
232323
var writer = new StreamWriter(ms);
233-
yamlStream.Save(writer);
324+
yamlStream.Save(writer, isLastDocumentEndImplicit: true);
234325
writer.Flush();
235326
ms.Seek(0, SeekOrigin.Begin);
236327
var reader = new StreamReader(ms);

0 commit comments

Comments
 (0)