import * as PropTypes from 'prop-types' ; import { Record , tools , AnyType , ChangeHandler } from 'type-r' ; import { ComponentProto } from './common' ; export interface TypeSpecs { [ name ] : object | Function ; } export function compileSpecs ( props ) { const propTypes = { } , modelProto = Record . defaults ( props ) . prototype ; let defaults , watchers , changeHandlers ; modelProto . forEachAttr ( modelProto . _attributes , ( spec , name ) => { if ( name !== 'id' ) { const { value , type , options } = spec ; propTypes [ name ] = translateType ( type , options . isRequired ) ; if ( options . _onChange ) { watchers || ( watchers = { } ) ; watchers [ name ] = toLocalWatcher ( options . _onChange ) ; } if ( options . changeHandlers && options . changeHandlers . length ) { changeHandlers || ( changeHandlers = { } ) ; changeHandlers [ name ] = options . changeHandlers ; } if ( options . changeEvents ) { changeHandlers || ( changeHandlers = { } ) ; const handlers = changeHandlers [ name ] || ( changeHandlers [ name ] = [ ] ) , changeEvents = typeof options . changeEvents === 'string' ? options . changeEvents : null ; handlers . push ( function ( next , prev , component ) { prev && component . stopListening ( prev ) ; next && component . listenTo ( next , changeEvents || next . _changeEventName , component . asyncUpdate ) ; } ) ; } if ( value !== void 0 ) { defaults || ( defaults = { } ) ; defaults [ name ] = spec . convert ( value , void 0 , null , { } ) ; } } } ) ; return { propTypes , defaults , watchers , changeHandlers } ; } type PropWatcher = ( this : ComponentProto , propValue : any , propName : string ) => void ; function toLocalWatcher ( ref ) { return typeof ref === 'function' ? ref : function ( value , name ) { this [ ref ] && this [ ref ] ( value , name ) ; } ; } export class Node { } export class Element { } function translateType ( Type , isRequired ) { const T = _translateType ( Type ) ; return isRequired ? T . isRequired : T ; } declare global { interface NumberConstructor { integer : Function ; } } function _translateType ( Type ) { switch ( Type ) { case Number : case Number . integer : return PropTypes . number ; case String : return PropTypes . string ; case Boolean : return PropTypes . bool ; case Array : return PropTypes . array ; case Function : return PropTypes . func ; case Object : return PropTypes . object ; case Node : return PropTypes . node ; case Element : return PropTypes . element ; case void 0 : case null : return PropTypes . any ; default : return PropTypes . instanceOf ( Type ) ; } }