@@ -54,8 +54,13 @@ angular
5454 */
5555 function resolveAllOf ( openApiSpec , schema ) {
5656 if ( schema . allOf ) {
57+ schema = angular . copy ( schema ) ;
5758 angular . forEach ( schema . allOf , function ( def ) {
58- angular . merge ( schema , resolveReference ( openApiSpec , def ) ) ;
59+ var ref = resolveReference ( openApiSpec , def ) ;
60+ if ( ! ref . discriminator ) {
61+ // do not handle inhertited properties here
62+ angular . merge ( schema , ref ) ;
63+ }
5964 } ) ;
6065 delete schema . allOf ;
6166 }
@@ -69,6 +74,12 @@ angular
6974 var sample , def , name , prop ;
7075 currentGenerated = currentGenerated || { } ; // used to handle circular references
7176 schema = resolveAllOf ( openApiSpec , schema ) ;
77+ if ( schema . parentModelsRef ) {
78+ angular . forEach ( schema . parentModelsRef , function ( ref ) {
79+ var def = resolveReference ( openApiSpec , ref ) ;
80+ angular . merge ( schema , def ) ;
81+ } ) ;
82+ }
7283 if ( schema . default || schema . example ) {
7384 sample = schema . default || schema . example ;
7485 } else if ( schema . properties ) {
@@ -200,30 +211,58 @@ angular
200211 return name ;
201212 }
202213
214+ /**
215+ * identify models using inheritance
216+ */
217+ this . resolveInheritance = function ( openApiSpec ) {
218+ angular . forEach ( openApiSpec . definitions , function ( schema , modelName ) {
219+ if ( schema . discriminator ) {
220+ schema . subModelsRef = [ ] ;
221+ angular . forEach ( openApiSpec . definitions , function ( subSchema , subModelName ) {
222+ if ( schema !== subSchema && subSchema . allOf ) {
223+ angular . forEach ( subSchema . allOf , function ( parent ) {
224+ if ( parent . $ref && modelName === getClassName ( parent ) ) {
225+ subSchema . parentModelsRef = subSchema . parentModelsRef || [ ] ;
226+ subSchema . parentModelsRef . push ( {
227+ '$ref' : '#/definitions/' + modelName
228+ } ) ;
229+ schema . subModelsRef . push ( {
230+ '$ref' : '#/definitions/' + subModelName
231+ } ) ;
232+ }
233+ } ) ;
234+ }
235+ } ) ;
236+ }
237+ } ) ;
238+ } ;
239+
203240 /**
204241 * generate a model and its submodels from schema
205242 */
206243 this . generateModel = function ( openApiSpec , schema , operationId ) {
207244 var model = [ ] ,
208245 subModelIds = { } ,
209- subModels = { } ;
246+ subModels = { } ,
247+ def ;
210248
211249 try {
212250 schema = resolveAllOf ( openApiSpec , schema ) ;
251+ // find models to generate
213252 if ( schema . properties ) {
214253 // if inline model
215254 subModels [ getInlineModelName ( ) ] = schema ;
216255 subModels = angular . merge ( subModels , findAllModels ( openApiSpec , schema , subModelIds ) ) ;
217256 } else {
218257 subModels = findAllModels ( openApiSpec , schema , subModelIds ) ;
219258 }
220-
221- if ( ! schema . $ref && ! schema . properties ) {
222- // if array or map/dictionary or simple type
223- model . push ( '<strong>' , getModelProperty ( schema , subModels , subModelIds , operationId ) , '</strong><br><br>' ) ;
259+ def = resolveReference ( openApiSpec , schema ) ;
260+ if ( ! def . properties ) {
261+ // if not complex type
262+ model . push ( '<strong>' , getModelProperty ( def , subModels , subModelIds , operationId ) , '</strong><br><br>' ) ;
224263 }
225- angular . forEach ( subModels , function ( schema , modelName ) {
226- model . push ( getModel ( openApiSpec , schema , modelName , subModels , subModelIds , operationId ) ) ;
264+ angular . forEach ( subModels , function ( subSchema , subModelName ) {
265+ model . push ( getModel ( openApiSpec , subSchema , subModelName , subModels , subModelIds , operationId ) ) ;
227266 } ) ;
228267 } catch ( ex ) {
229268 console . error ( 'AngularSwaggerUI: failed to generate model' , schema , ex ) ;
@@ -255,38 +294,54 @@ angular
255294 def = resolveReference ( openApiSpec , subSchema ) ,
256295 subPropertyModelName = getClassName ( subSchema ) ;
257296
258- if ( def && ( def . type === 'object' || def . type === 'array' ) ) {
297+ if ( def && ( ! def . type || def . type === 'object' || def . type === 'array' ) ) {
298+ def = resolveAllOf ( openApiSpec , def ) ;
259299 models [ subPropertyModelName ] = def ;
260300 subModelIds [ subPropertyModelName ] = countModel ++ ;
261301 angular . merge ( models , findAllModels ( openApiSpec , def , subModelIds , subPropertyModelName , onGoing ) ) ;
262- } else if ( def ) {
263- schema = angular . merge ( schema , def ) ;
264- delete schema . $ref ;
265302 }
266303 } else if ( schema . type === 'array' ) {
267304 inspectSubModel ( openApiSpec , schema . items , models , subModelIds , onGoing ) ;
268305 } else if ( schema . additionalProperties ) {
269306 // this is a map/dictionary
270307 inspectSubModel ( openApiSpec , schema . additionalProperties , models , subModelIds , onGoing ) ;
271308 }
272- if ( schema . discriminator ) {
273- // find subclasses
274- angular . forEach ( openApiSpec . definitions , function ( subSchema , subModelName ) {
275- if ( subSchema . allOf ) {
276- angular . forEach ( subSchema . allOf , function ( parent ) {
277- if ( parent . $ref && modelName === getClassName ( parent ) ) {
278- subSchema . parentModel = modelName ;
279- models [ subModelName ] = subSchema ;
280- subModelIds [ subModelName ] = countModel ++ ;
281- angular . merge ( models , findAllModels ( openApiSpec , subSchema , subModelIds , subModelName , onGoing ) ) ;
282- }
283- } ) ;
309+ if ( schema . subModelsRef ) {
310+ // check if subclass not already built
311+ var subClasses = schema . subModelsRef . map ( getClassName ) ,
312+ found = false ,
313+ keys = Object . keys ( subModelIds ) ,
314+ i = 0 ;
315+
316+ for ( ; i < subClasses . length ; i ++ ) {
317+ if ( keys . indexOf ( subClasses [ i ] ) > - 1 ) {
318+ found = true ;
319+ break ;
284320 }
285- } ) ;
321+ }
322+ if ( ! found ) {
323+ // add sub classes
324+ addInheritanceModels ( openApiSpec , schema . subModelsRef , models , subModelIds , onGoing ) ;
325+ }
326+ }
327+ if ( schema . parentModelsRef ) {
328+ // find super classes
329+ addInheritanceModels ( openApiSpec , schema . parentModelsRef , models , subModelIds , onGoing ) ;
286330 }
287331 return models ;
288332 }
289333
334+ function addInheritanceModels ( openApiSpec , inheritanceModels , models , subModelIds , onGoing ) {
335+ angular . forEach ( inheritanceModels , function ( ref ) {
336+ var def = resolveReference ( openApiSpec , ref ) ,
337+ subModelName = getClassName ( ref ) ;
338+
339+ models [ subModelName ] = def ;
340+ subModelIds [ subModelName ] = countModel ++ ;
341+ angular . merge ( models , findAllModels ( openApiSpec , def , subModelIds , subModelName , onGoing ) ) ;
342+ } ) ;
343+ }
344+
290345 /**
291346 * look for submodels
292347 */
@@ -312,7 +367,7 @@ angular
312367 /**
313368 * generates an HTML link to a submodel
314369 */
315- function getSubModelLink ( operationId , modelId , name ) {
370+ function getSubModelLink ( operationId , name ) {
316371 var linkModelId = operationId + '-model-' + name ;
317372 return [ '<a class="model-link type" onclick="swaggerlink(\'' , linkModelId , '\')">' , name , '</a>' ] . join ( '' ) ;
318373 }
@@ -330,13 +385,24 @@ angular
330385 schema = resolveAllOf ( openApiSpec , schema ) ;
331386 if ( schema . properties ) {
332387 buffer . push ( '<div><strong>' , modelName ) ;
333- if ( schema . parentModel ) {
334- buffer . push ( '</strong> extends <strong>' , schema . parentModel ) ;
388+ if ( schema . parentModelsRef ) {
389+ buffer . push ( '</strong> extends <strong>' ) ;
390+ angular . forEach ( schema . parentModelsRef , function ( ref ) {
391+ buffer . push ( getSubModelLink ( operationId , getClassName ( ref ) ) , ' ' ) ;
392+ } ) ;
393+ buffer . pop ( ) ;
335394 }
336395 buffer . push ( ' {</strong></div>' ) ;
337396 var hasProperties = false ;
338397 angular . forEach ( schema . properties , function ( property , propertyName ) {
339398 hasProperties = true ;
399+ if ( ! property . type && property . $ref ) {
400+ var ref = resolveReference ( openApiSpec , property ) ;
401+ if ( ref . type !== 'object' && ref . type !== 'array' ) {
402+ // this is a simple type
403+ property = ref ;
404+ }
405+ }
340406 buffer . push ( '<div class="pad"><strong>' , propertyName , '</strong> (<span class="type">' ) ;
341407 buffer . push ( getModelProperty ( property , subModels , subModelIds , operationId ) ) ;
342408 buffer . push ( '</span>' ) ;
@@ -374,16 +440,16 @@ angular
374440 function getModelProperty ( property , subModels , subModelIds , operationId ) {
375441 var modelName , buffer = [ ] ;
376442 if ( property . modelName ) {
377- buffer . push ( getSubModelLink ( operationId , subModelIds [ property . modelName ] , property . modelName ) ) ;
443+ buffer . push ( getSubModelLink ( operationId , property . modelName ) ) ;
378444 } else if ( property . schema || property . $ref ) {
379445 modelName = getClassName ( property . schema || property ) ;
380- buffer . push ( getSubModelLink ( operationId , subModelIds [ modelName ] , modelName ) ) ;
446+ buffer . push ( getSubModelLink ( operationId , modelName ) ) ;
381447 } else if ( property . type === 'array' ) {
382448 buffer . push ( 'Array[' ) ;
383449 buffer . push ( getModelProperty ( property . items , subModels , subModelIds , operationId ) ) ;
384450 buffer . push ( ']' ) ;
385451 } else if ( property . properties ) {
386- buffer . push ( getSubModelLink ( operationId , subModelIds [ property . modelName ] , modelName ) ) ;
452+ buffer . push ( getSubModelLink ( operationId , modelName ) ) ;
387453 } else if ( property . additionalProperties ) {
388454 // this is a map/dictionary
389455 buffer . push ( 'Map<string, ' ) ;
0 commit comments