export type Arguments = { [ name ] : any ; } ; export class Validate { private entry ? : Function ; public static get required ( ) : Validate { return new Validate ( true ) ; } public static get optional ( ) : Validate { return new Validate ( false ) ; } constructor ( private required ) { } public argument ( args ) { this . entry = this . argument ; this . each ( args , ( ) => { } ) ; } public booleanProperty ( object , path ) { this . entry = this . booleanProperty ; this . property ( object , path , ( name , value ) => { if ( typeof value !== 'boolean' ) { throw this . typeError ( `Property '${ name }' must be a boolean` ) ; } } ) ; } public string ( args ) { this . entry = this . string ; this . each ( args , ( name , value ) => { if ( typeof value !== 'string' ) { throw this . typeError ( `'Argument '${ name }' must be a string` ) ; } } ) ; } public nonEmptyString ( args ) { this . entry = this . nonEmptyString ; this . each ( args , ( name , value ) => { if ( typeof value !== 'string' || value . length === 0 ) { throw this . typeError ( `'Argument '${ name }' must be a non-empty string` ) ; } } ) ; } public stringProperty ( object , path ) { this . entry = this . stringProperty ; this . property ( object , path , ( name , value ) => { if ( typeof value !== 'string' ) { throw this . typeError ( `Property '${ name }' must be a string` ) ; } } ) ; } public numberProperty ( object , path ) { this . entry = this . numberProperty ; this . property ( object , path , ( name , value ) => { if ( typeof value !== 'number' || isNaN ( value ) ) { throw this . typeError ( `Property '${ name }' must be a number` ) ; } } ) ; } public functionProperty ( object , path ) { this . entry = this . functionProperty ; this . property ( object , path , ( name , value ) => { if ( typeof value !== 'function' ) { throw this . typeError ( `Property '${ name }' must be a function` ) ; } } ) ; } public object ( args ) { this . entry = this . object ; this . each ( args , ( name , value ) => { if ( typeof value !== 'object' || value === null ) { throw this . typeError ( `Argument '${ name }' must be an object` ) ; } } ) ; } public nonEmptyArray ( args ) { this . entry = this . nonEmptyArray ; this . each ( args , ( name , value ) => { if ( ! ( value instanceof Array ) || value . length === 0 ) { throw this . typeError ( `Argument '${ name }' must be a non-empty array` ) ; } } ) ; } public arrayProperty ( object , path ) { this . entry = this . arrayProperty ; this . property ( object , path , ( name , value ) => { if ( ! ( value instanceof Array ) ) { throw this . typeError ( `Property '${ name }' must be an array` ) ; } } ) ; } public regexProperty ( object , path ) { this . entry = this . regexProperty ; this . property ( object , path , ( name , value ) => { if ( ! ( value instanceof RegExp ) ) { throw this . typeError ( `Property '${ name }' must be a regular expression` ) ; } } ) ; } private each ( args , callback ) { for ( let name of Object . keys ( args ) ) { let value = args [ name ] ; if ( value !== undefined ) { callback ( name , value ) ; } else if ( this . required ) { throw this . error ( `Missing argument '${ name }'` ) ; } } } private property ( object , path , callback ) { let properties = path . split ( '.' ) ; let value = object ; let name = properties . shift ( ) ! ; if ( ! value && ! this . required ) { return ; } this . object ( { [ name ] : value } ) ; let property ; while ( property = properties . shift ( ) ) { name += `.${ property }` ; value = value [ property ] ; if ( properties . length ) { if ( typeof value !== 'object' || value === null ) { if ( value !== undefined || this . required ) { throw this . typeError ( `Property '${ name }' must be an object` ) ; } else { break ; } } } else { if ( value !== undefined ) { callback ( name , value ) ; } else if ( this . required ) { throw this . error ( `Property '${ name }' is missing` ) ; } } } } private typeError ( message ) { let error = new TypeError ( message ) ; Error . captureStackTrace ( error , this . entry ) ; return error ; } private error ( message ) { let error = new Error ( message ) ; Error . captureStackTrace ( error , this . entry ) ; return error ; } }