Skip to content

Commit 3226425

Browse files
committed
Fixed issue with recursive $extend parsing
Nested $extend keys weren't being parsed. Wrote some additional tests and added some complexity to the coldbox json files to account for deep nesting.
1 parent 1ce6d39 commit 3226425

File tree

12 files changed

+173
-38
lines changed

12 files changed

+173
-38
lines changed

models/OpenAPI/Parser.cfc

Lines changed: 23 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -153,8 +153,7 @@ component name="OpenAPIParser" accessors="true" {
153153
}
154154

155155
if (
156-
isStruct( DocItem[ key ] )
157-
&&
156+
isStruct( DocItem[ key ] ) &&
158157
structKeyExists( DocItem[ key ], "$ref" )
159158
) {
160159

@@ -181,40 +180,33 @@ component name="OpenAPIParser" accessors="true" {
181180
* @param [XPath] The XPath to zoom the parsed document to during recursion
182181
**/
183182
public function parseDocumentInheritance( required any DocItem ){
184-
183+
184+
// If `DocItem` is an instance of Parser, we need to flattin it to a CFML struct
185+
if (
186+
isStruct( DocItem ) &&
187+
findNoCase( "Parser", getMetaData( DocItem ).name )
188+
) {
189+
DocItem = DocItem.getNormalizedDocument();
190+
}
191+
185192
if( isArray( DocItem ) ) {
186193
for( var i = 1; i <= arrayLen( DocItem ); i++){
187194
DocItem[ i ] = parseDocumentInheritance( DocItem[ i ] );
188195
}
189-
} else if( isStruct( DocItem ) ) {
190-
191-
// $extend is a special key which enables merging json structs
192-
var compositionKeys = [ "$extend" ];
193-
194-
for( var composition in compositionKeys ){
196+
} else if( isStruct( DocItem ) ) {
195197

196-
// handle top-level extension
197-
if(
198-
structKeyExists( DocItem, composition ) &&
199-
isArray( DocItem[ composition ] )
200-
) {
201-
return extendObject( DocItem[ composition ] );
202-
}
203-
204-
for( var key in DocItem){
198+
// handle top-level extension
199+
if( structKeyExists( DocItem, "$extend" ) ) {
200+
return extendObject( parseDocumentInheritance( DocItem[ "$extend" ] ) );
201+
}
205202

206-
if (
207-
isStruct( DocItem[ key ] ) &&
208-
structKeyExists( DocItem[ key ], composition ) &&
209-
isArray( DocItem[ key ][ composition ] )
210-
) {
211-
DocItem[ key ] = extendObject( DocItem[ key ][ composition ] );
212-
} else if( isStruct( DocItem[ key ] ) || isArray( DocItem[ key ] ) ){
213-
DocItem[ key ] = parseDocumentInheritance( DocItem[ key ] );
214-
}
203+
for( var key in DocItem ){
204+
205+
if( isStruct( DocItem[ key ] ) || isArray( DocItem[ key ] ) ){
206+
DocItem[ key ] = parseDocumentInheritance( DocItem[ key ] );
207+
}
215208

216-
}
217-
}
209+
}
218210

219211
}
220212

@@ -230,17 +222,12 @@ component name="OpenAPIParser" accessors="true" {
230222
* @objects
231223
*/
232224
function extendObject( array objects ) {
225+
233226
var output = {};
234227
objects.each( function( item, index ) {
235228
if ( isStruct( item ) ) {
236-
237-
// If `item` is an instance of Parser, we need to flattin it to a CFML struct
238-
if ( findNoCase( "Parser", getMetaData( item ).name ) ) {
239-
item = item.getNormalizedDocument();
240-
}
241-
242229
item.each( function( key, value ) {
243-
230+
244231
if (
245232
output.keyExists( key ) &&
246233
isStruct( output[ key ] )

test-harness/tests/resources/coldboxRest/coldboxRest.json

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,13 @@
5555
"PostBody": { "$ref": "paths/posts/_schemas/postBody.json" },
5656
"Media": { "$ref": "paths/media/_schemas/media.json" },
5757
"BookMedia": { "$ref": "paths/media/_schemas/bookMedia.json" },
58-
"MusicMedia": { "$ref": "paths/media/_schemas/musicMedia.json" }
58+
"MusicMedia": { "$ref": "paths/media/_schemas/musicMedia.json" },
59+
"BookMediaBody": { "$ref": "paths/media/_schemas/bookMediaBody.json" },
60+
"MusicMediaBody": { "$ref": "paths/media/_schemas/musicMediaBody.json" }
5961
},
6062
"requestBodies": {
61-
"PostBody": { "$ref": "paths/posts/_bodies/postBody.json" }
63+
"PostBody": { "$ref": "paths/posts/_bodies/postBody.json" },
64+
"MediaBody": { "$ref": "paths/media/_bodies/mediaBody.json" }
6265
}
6366
},
6467
"paths": {
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"description": "Media to Create",
3+
"required": true,
4+
"content": {
5+
"application/json": {
6+
"schema": {
7+
"anyOf": [
8+
{ "$ref": "##/components/schemas/MusicMediaBody" },
9+
{ "$ref": "##/components/schemas/BookMediaBody" }
10+
]
11+
},
12+
"examples": {
13+
"MusicMediaBody": { "$ref": "../_examples/musicMediaBody.json" },
14+
"BookMediaBody": { "$ref": "../_examples/bookMediaBody.json" }
15+
}
16+
}
17+
}
18+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"summary": "BookMediaBody",
3+
"description": "An example book media",
4+
"value": {
5+
"title": "Book Title",
6+
"type": "book",
7+
"isbn": "12345678"
8+
}
9+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"summary": "MusicMediaBody",
3+
"description": "An example music media",
4+
"value": {
5+
"title": "Music Title",
6+
"type": "music",
7+
"artist": "Music Artist"
8+
}
9+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"$extend": [
3+
{
4+
"$ref": "../../../_schemas/response.json"
5+
},
6+
{
7+
"properties": {
8+
"data": {
9+
"oneOf": [
10+
{ "$ref": "##/components/schemas/BookMedia" },
11+
{ "$ref": "##/components/schemas/MusicMedia" }
12+
],
13+
"discriminator": {
14+
"propertyName": "type"
15+
}
16+
}
17+
}
18+
}
19+
20+
]
21+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"type": "object",
3+
"properties": {
4+
"id": {
5+
"type": "string"
6+
},
7+
"title": {
8+
"type": "string"
9+
},
10+
"type": {
11+
"type": "string"
12+
},
13+
"isbn": {
14+
"type": "string"
15+
}
16+
}
17+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"type": "object",
3+
"properties": {
4+
"id": {
5+
"type": "string"
6+
},
7+
"title": {
8+
"type": "string"
9+
},
10+
"type": {
11+
"type": "string"
12+
},
13+
"artist": {
14+
"type": "string"
15+
}
16+
}
17+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"data": {
3+
"id": "1",
4+
"title": "The Great Gatsby",
5+
"type": "book",
6+
"isbn": "1234567"
7+
},
8+
"messages": [],
9+
"error": false
10+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"description": "Media to Create",
3+
"required": true,
4+
"content": {
5+
"application/json": {
6+
"schema": {
7+
"anyOf": [
8+
{ "$ref": "##/components/schemas/BookMediaBody" },
9+
{ "$ref": "##/components/schemas/MusicMediaBody" }
10+
]
11+
},
12+
"examples": {
13+
"BookMediaBody": { "$ref": "../_examples/bookMediaBody.json" },
14+
"MusicMediaBody": { "$ref": "../_examples/musicMediaBody.json" }
15+
}
16+
}
17+
}
18+
}

0 commit comments

Comments
 (0)