import { JsonSchema4 } from '../models' ; const ADDITIONAL_PROPERTIES = 'additionalProperties' ; const REQUIRED_PROPERTIES = 'required' ; type Properties = { [ property ] : JsonSchema4 ; } ; const distinct = ( properties , discriminator ) : JsonSchema4 [ ] => { const known = { } ; return properties . filter ( item => { const discriminatorValue = discriminator ( item ) ; if ( known . hasOwnProperty ( discriminatorValue ) ) { return false ; } else { known [ discriminatorValue ] = true ; return true ; } } ) ; } ; class Gen { constructor ( private findOption ) { } schemaObject = ( data ) : JsonSchema4 => { const props = this . properties ( data ) ; const schema = { type : 'object' , properties : props , additionalProperties : this . findOption ( props ) ( ADDITIONAL_PROPERTIES ) } ; const required = this . findOption ( props ) ( REQUIRED_PROPERTIES ) ; if ( required . length > 0 ) { schema . required = required ; } return schema ; } ; properties = ( data ) : Properties => { const emptyProps = { } ; return Object . keys ( data ) . reduce ( ( acc , propName ) => { acc [ propName ] = this . property ( data [ propName ] ) ; return acc ; } , emptyProps ) ; } ; property = ( data ) : JsonSchema4 => { switch ( typeof data ) { case 'string' : return { type : 'string' } ; case 'boolean' : return { type : 'boolean' } ; case 'number' : if ( Number . isInteger ( data ) ) { return { type : 'integer' } ; } return { type : 'number' } ; case 'object' : if ( data == null ) { return { type : 'null' } ; } return this . schemaObjectOrArray ( data ) ; default : return { } ; } } ; schemaObjectOrArray = ( data ) : JsonSchema4 => { if ( data instanceof Array ) { return this . schemaArray ( data as any [ ] ) ; } else { return this . schemaObject ( data ) ; } } ; schemaArray = ( data ) : JsonSchema4 => { if ( data . length > 0 ) { const allProperties = data . map ( this . property ) ; const uniqueProperties = distinct ( allProperties , prop => JSON . stringify ( prop ) ) ; if ( uniqueProperties . length === 1 ) { return { type : 'array' , items : uniqueProperties [ 0 ] } ; } else { return { type : 'array' , items : { oneOf : uniqueProperties } } ; } } else { return { type : 'array' , items : { } } ; } } ; } param { Object } instance param { any } options returns { JsonSchema } export const generateJsonSchema = ( instance , options = { } ) : JsonSchema4 => { const findOption = ( props ) => ( optionName ) : boolean | string [ ] => { switch ( optionName ) { case ADDITIONAL_PROPERTIES : if ( options . hasOwnProperty ( ADDITIONAL_PROPERTIES ) ) { return options [ ADDITIONAL_PROPERTIES ] ; } return true ; case REQUIRED_PROPERTIES : if ( options . hasOwnProperty ( REQUIRED_PROPERTIES ) ) { return options [ REQUIRED_PROPERTIES ] ( props ) ; } return Object . keys ( props ) ; default : return ; } } ; const gen = new Gen ( findOption ) ; return gen . schemaObject ( instance ) ; } ;