import { action , extendObservable } from 'mobx' ; const pick = require ( 'lodash/pick' ) ; const pickBy = require ( 'lodash/pickBy' ) ; /**
 * Any object hash.
 */ export interface IObjectHash { [ key ] : any ; } /**
 * Various options used by the model.
 */ export interface IModelOptions { /**
     * Calls `parse` on the model before settings attributes.
     */ parse ? : boolean ; /**
     * Remove all undefined values before assigning to model?
     */ stripUndefined ? : boolean ; } /**
 * Model interface.
 */ export interface IModel { /**
     * Sets attributes on the model, optionally calling `parse`.
     */ set ( attributes , options ? ) : this ; /**
     * Called at various points, giving the model a chance to parse attributes
     * before setting them.
     */ parse ( attributes , options ? ) : IObjectHash ; /**
     * Picks the specified properties from the model.
     */ pick < K extends keyof this > ( properties ) : Pick < this , K > ; } /**
 * A map of actions.
 */ export interface IActionsMap < T > { [ key ] : ( this : T , ... args : any [ ] ) => any ; } /**
 * Fluid model, used only with the model factory.
 */ export type IFluidModel < T > = T & IModel & { /**
     * Calls `Object.assign` with the model as the target.
     */ assign < S > ( source ) : IFluidModel < T & S > ; assign < S1 , S2 > ( source1 , source2 ) : IFluidModel < T & S1 & S2 > ; assign < S1 , S2 , S3 > ( source1 , source2 , source3 ) : IFluidModel < T & S1 & S2 & S3 > ; assign ( ... sources ) : IFluidModel < T > ; /**
     * Calls `extendObservable` on itself.
     */ extendObservable < O > ( properties ) : IFluidModel < T & O > ; /**
     * Adds the specified actions to the model.
     */ withActions < A > ( actions ) : IFluidModel < T & A > ; /**
     * Invokes the specified function with the model as the first parameter,
     * it should modify the model in-place. Return value is for TypeScript
     * type inference only, the passed-in model is actually returned.
     */ decorate < D > ( fn ) : IFluidModel < T & D > ; } ; /**
 * The Model class in all its' glory.
 */ export class Model implements IModel { /**
     * If attributes are specified, `set` is called along with the model options.
     */ constructor ( attributes ? , options ? ) { this . set = action ( 'set' , this . set . bind ( this ) ) ; if ( options && ( options as any ) . rootStore ) { ; ( this as any ) . rootStore = ( options as any ) . rootStore ; } if ( attributes ) { this . set ( attributes , options ) ; } } /**
     * Sets the attributes on the model, optionally calling `parse` first.
     */ set ( attributes , options ? ) { if ( options ) { if ( options . parse && this . parse ) { attributes = this . parse ( attributes , options ) ; } if ( options . stripUndefined ) { attributes = pickBy ( attributes , ( prop ) => prop !== undefined ) ; } } Object . assign ( this , attributes ) ; return this ; } /**
     * Used to convert a raw object to something more meaningful.
     */ parse ( attributes , options ? ) { return attributes ; } /**
     * Picks properties and returns them as an object.
     */ pick < K extends keyof this > ( properties ) { return pick ( this , properties ) ; } } param target export function model < T > ( target ? ) { target = target || ( { } as any ) ; target = Object . assign ( target , { set : action ( 'set' , Model . prototype . set . bind ( target ) ) , pick : Model . prototype . pick . bind ( target ) , parse : ( target as any ) . parse || Model . prototype . parse . bind ( target ) , assign : Object . assign . bind ( null , target ) , extendObservable : extendObservable . bind ( null , target ! ) , withActions : withActions . bind ( target as IFluidModel < T > ) , decorate : decorate . bind ( target as IFluidModel < T > ) } ) as any ; return target as T & IFluidModel < T > ; } param this param actions function withActions < T , A extends { [ key ] : Function ; } > ( this , actions ) { for ( const key in actions ) { if ( Object . prototype . hasOwnProperty . call ( actions , key ) ) { const prop = actions [ key ] ; if ( typeof prop !== 'function' ) { throw new Error ( 'The object passed to withActions should only contain ' + `functions, but found ${ key }: ${ typeof prop }` ) ; } ; ( this as any ) [ key ] = action ( key , prop . bind ( this ) ) ; } } return this as IFluidModel < T > & A ; } param fn function decorate < T , D > ( this , fn ) { fn ( this ) ; return this as IFluidModel < T & D > ; }