Skip to content

Commit b5de238

Browse files
[0.12.3] Fix crash in logging when property named "$ref" (#410)
Co-authored-by: Mike Harder <mharder@microsoft.com>
1 parent 928c743 commit b5de238

File tree

7 files changed

+134
-5
lines changed

7 files changed

+134
-5
lines changed

CHANGELOG.md

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

3+
# 0.12.3 2025-10-13
4+
5+
- Fix crash in logging when property named "$ref"
6+
37
## 0.12.2 2025-09-22
48

59
- bump dependency `js-yaml` from `^3.13.0` to `^4.1.0`

openapi-diff/src/core/OpenApiDiff.Core/Logging/ObjectPath.cs

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,23 @@ private static JToken FromObject(JObject o, string name)
7676
{
7777
return null;
7878
}
79+
7980
var @ref = o["$ref"];
80-
var unrefed = @ref != null ? ParseRef(@ref.Value<string>()).CompletePath(o.Root).Last().token : o;
81-
return unrefed[name];
81+
82+
// Handle $ref resolution based on its type
83+
if (@ref != null && @ref.Type == JTokenType.String)
84+
{
85+
// Case 1: $ref is a string reference (e.g., "#/definitions/FieldType")
86+
// Resolve the reference by parsing the path and following it to the target
87+
var unrefed = ParseRef(@ref.Value<string>()).CompletePath(o.Root).Last().token;
88+
return unrefed[name];
89+
}
90+
else
91+
{
92+
// Case 2: $ref is not a string (e.g., a JSON object defining a schema)
93+
// or $ref doesn't exist - use the current object directly
94+
return o[name];
95+
}
8296
}
8397

8498
private static IEnumerable<(JToken token, string name)> CompletePath(IEnumerable<Func<JToken, string>> path, JToken token)
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
{
2+
"swagger": 2.0,
3+
"info": {
4+
"title": "type_changed",
5+
"version": "1.0"
6+
},
7+
"host": "localhost:8000",
8+
"schemes": [ "http", "https" ],
9+
"consumes": [ "text/plain", "text/json" ],
10+
"produces": [ "text/plain" ],
11+
"paths": {
12+
"/api/Parameters": {
13+
"put": {
14+
"tag": [ "Parameters" ],
15+
"operationId": "Parameters_Put",
16+
"produces": [
17+
"text/plain"
18+
],
19+
"parameters": [
20+
{
21+
"name": "database",
22+
"in": "body",
23+
"required": true,
24+
"type": "object",
25+
"schema": { "$ref": "#/definitions/Database" }
26+
}
27+
]
28+
}
29+
}
30+
},
31+
"definitions": {
32+
"Database": {
33+
"properties": {
34+
"$ref": {
35+
"type": "integer",
36+
"readOnly": true,
37+
"description": "Property named '$ref'. Unusual but valid."
38+
},
39+
"b": {
40+
"type": "integer",
41+
"readOnly": true,
42+
"default": 0,
43+
"description": "This property shows the number of databases returned."
44+
}
45+
}
46+
}
47+
}
48+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
{
2+
"swagger": 2.0,
3+
"info": {
4+
"title": "type_changed",
5+
"version": "1.0"
6+
},
7+
"host": "localhost:8000",
8+
"schemes": [ "http", "https" ],
9+
"consumes": [ "text/plain", "text/json" ],
10+
"produces": [ "text/plain" ],
11+
"paths": {
12+
"/api/Parameters": {
13+
"put": {
14+
"tag": [ "Parameters" ],
15+
"operationId": "Parameters_Put",
16+
"produces": [
17+
"text/plain"
18+
],
19+
"parameters": [
20+
{
21+
"name": "database",
22+
"in": "body",
23+
"required": true,
24+
"type": "object",
25+
"schema": { "$ref": "#/definitions/Database" }
26+
}
27+
]
28+
}
29+
}
30+
},
31+
"definitions": {
32+
"Database": {
33+
"properties": {
34+
"$ref": {
35+
"type": "string",
36+
"readOnly": true,
37+
"description": "Property named '$ref'. Unusual but valid."
38+
},
39+
"b": {
40+
"type": "integer",
41+
"readOnly": true,
42+
"default": 0,
43+
"description": "This property shows the number of databases returned."
44+
}
45+
}
46+
}
47+
}
48+
}

openapi-diff/src/modeler/AutoRest.Swagger.Tests/SwaggerModelerCompareTests.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,21 @@ public void TypeObjectChanged()
165165
Assert.Equal("new/type_changed_01.json#/definitions/Database/properties/a", error.NewJsonRef);
166166
}
167167

168+
/// <summary>
169+
/// Verifies that if you change the type of a schema property named "$ref" (unusual but valid), it's caught.
170+
/// </summary>
171+
[Fact]
172+
public void PropertyNamedRefTypeChanged()
173+
{
174+
var messages = CompareSwagger("type_changed_02.json").ToArray();
175+
var missing = messages.Where(m => m.Id == ComparisonMessages.TypeChanged.Id);
176+
Assert.NotEmpty(missing);
177+
var error = missing.Where(err => err.NewJsonRef.StartsWith("new/type_changed_02.json#/definitions/")).FirstOrDefault();
178+
Assert.NotNull(error);
179+
Assert.Equal(Category.Error, error.Severity);
180+
Assert.Equal("new/type_changed_02.json#/definitions/Database/properties/$ref", error.NewJsonRef);
181+
}
182+
168183
/// <summary>
169184
/// Verifies that if you change the default value of a schema, it's caught.
170185
/// </summary>

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@azure/oad",
3-
"version": "0.12.2",
3+
"version": "0.12.3",
44
"author": {
55
"name": "Microsoft Corporation",
66
"email": "azsdkteam@microsoft.com",

0 commit comments

Comments
 (0)