@@ -14,18 +14,27 @@ import {
14
14
import { JSONSchema6 as JSONSchema } from 'json-schema' ;
15
15
import { JSON_SCHEMA_KEY } from './keys' ;
16
16
17
+ export interface JsonSchemaOptions {
18
+ visited ?: { [ key : string ] : JSONSchema } ;
19
+ }
20
+
17
21
/**
18
22
* Gets the JSON Schema of a TypeScript model/class by seeing if one exists
19
23
* in a cache. If not, one is generated and then cached.
20
24
* @param ctor Contructor of class to get JSON Schema from
21
25
*/
22
- export function getJsonSchema ( ctor : Function ) : JSONSchema {
23
- // NOTE(shimks) currently impossible to dynamically update
24
- const jsonSchema = MetadataInspector . getClassMetadata ( JSON_SCHEMA_KEY , ctor ) ;
25
- if ( jsonSchema ) {
26
- return jsonSchema ;
26
+ export function getJsonSchema (
27
+ ctor : Function ,
28
+ options ?: JsonSchemaOptions ,
29
+ ) : JSONSchema {
30
+ // In the near future the metadata will be an object with
31
+ // different titles as keys
32
+ const cached = MetadataInspector . getClassMetadata ( JSON_SCHEMA_KEY , ctor ) ;
33
+
34
+ if ( cached ) {
35
+ return cached ;
27
36
} else {
28
- const newSchema = modelToJsonSchema ( ctor ) ;
37
+ const newSchema = modelToJsonSchema ( ctor , options ) ;
29
38
MetadataInspector . defineMetadata ( JSON_SCHEMA_KEY . key , newSchema , ctor ) ;
30
39
return newSchema ;
31
40
}
@@ -142,16 +151,26 @@ export function metaToJsonProperty(meta: PropertyDefinition): JSONSchema {
142
151
* reflection API
143
152
* @param ctor Constructor of class to convert from
144
153
*/
145
- export function modelToJsonSchema ( ctor : Function ) : JSONSchema {
154
+ export function modelToJsonSchema (
155
+ ctor : Function ,
156
+ jsonSchemaOptions : JsonSchemaOptions = { } ,
157
+ ) : JSONSchema {
158
+ const options = { ...jsonSchemaOptions } ;
159
+ options . visited = options . visited || { } ;
160
+
146
161
const meta : ModelDefinition | { } = ModelMetadataHelper . getModelMetadata ( ctor ) ;
147
- const result : JSONSchema = { } ;
148
162
149
163
// returns an empty object if metadata is an empty object
150
164
if ( ! ( meta instanceof ModelDefinition ) ) {
151
165
return { } ;
152
166
}
153
167
154
- result . title = meta . title || ctor . name ;
168
+ const title = meta . title || ctor . name ;
169
+
170
+ if ( options . visited [ title ] ) return options . visited [ title ] ;
171
+
172
+ const result : JSONSchema = { title} ;
173
+ options . visited [ title ] = result ;
155
174
156
175
if ( meta . description ) {
157
176
result . description = meta . description ;
@@ -190,20 +209,24 @@ export function modelToJsonSchema(ctor: Function): JSONSchema {
190
209
continue ;
191
210
}
192
211
193
- const propSchema = getJsonSchema ( referenceType ) ;
212
+ const propSchema = getJsonSchema ( referenceType , options ) ;
213
+
214
+ includeReferencedSchema ( referenceType . name , propSchema ) ;
194
215
195
- if ( propSchema && Object . keys ( propSchema ) . length > 0 ) {
216
+ function includeReferencedSchema ( name : string , schema : JSONSchema ) {
217
+ if ( ! schema || ! Object . keys ( schema ) . length ) return ;
196
218
result . definitions = result . definitions || { } ;
197
219
198
- // delete nested definition
199
- if ( propSchema . definitions ) {
200
- for ( const key in propSchema . definitions ) {
201
- result . definitions [ key ] = propSchema . definitions [ key ] ;
220
+ // promote nested definition to the top level
221
+ if ( schema . definitions ) {
222
+ for ( const key in schema . definitions ) {
223
+ if ( key === title ) continue ;
224
+ result . definitions [ key ] = schema . definitions [ key ] ;
202
225
}
203
- delete propSchema . definitions ;
226
+ delete schema . definitions ;
204
227
}
205
228
206
- result . definitions [ referenceType . name ] = propSchema ;
229
+ result . definitions [ name ] = schema ;
207
230
}
208
231
}
209
232
return result ;
0 commit comments