import Vue from 'vue' ; import { tools , is } from '../utils' ; import { VueConstructor } from 'vue/types/vue' ; import { CollectionFactory , ContainerFactory , EuvComponentOptions , EuvInstance , PropTagIdentifier } from '../interfaces' ; import { metadata } from '../constants' ; export type Extras = { methods : object ; data : object ; computed : object ; [ key ] : any ; } ; export const DEFAULT_EXTRAS = { methods : { } , data : { } , computed : { } , } ; export class Mutation { private _prototype : any ; private _depDatas : { [ key ] : any ; } = { } ; constructor ( private collection , private instances = [ ] , private container ) { this . _prototype = collection . factory . prototype ; this . updateDependencies ( ) ; } toVueComponent ( ) { const extras = Object . getOwnPropertyNames ( this . _prototype ) . reduce ( ( tree , key ) => { const descriptor = Reflect . getOwnPropertyDescriptor ( this . _prototype , key ) ; const val = this . _prototype [ key ] ; const next = { [ key ] : val } ; if ( is . constructor ( key ) ) return tree ; if ( is . vueHook ( key ) ) return Object . assign ( tree , next ) ; if ( is . vueMethod ( descriptor ) ) return tools . assignChild ( tree , 'methods' , next ) ; return tools . assignChild ( tree , 'data' , next ) ; } , DEFAULT_EXTRAS ) ; const vueDatas = Object . assign ( { } , extras . data , this . _depDatas ) ; const tags = Reflect . getMetadata ( metadata . PROPS_IDENTIFIER , this . collection . factory ) || [ ] ; const props = tags . reduce ( ( tree , next ) => { if ( vueDatas [ next . name ] !== undefined ) { next . value = vueDatas [ next . name ] ; delete vueDatas [ next . name ] ; } return Object . assign ( tree , { [ next . name ] : { type : next . type , default : next . value } , } ) ; } , { } ) ; extras . data = ( ) => vueDatas ; extras . props = props ; return Vue . component ( this . collection . bindingName , Object . assign ( { } , extras , this . makeVueExtra ( ) ) ) ; } private makeVueExtra ( ) { const options = this . collection . vueComponentOptions || { } ; const components = ( options . components || [ ] ) . reduce ( ( coms , next ) => { const component = this . container . findOne ( next ) . vueComponent ; if ( ! component ) return coms ; return Object . assign ( { } , coms , { [ next ] : component } ) ; } , { } ) ; return { template : options . template || '' , name : this . collection . bindingName , components , } ; } private updateDependencies ( ) { const shamFactory = new this . collection . factory ( ... this . instances ) ; this . _depDatas = Object . keys ( shamFactory ) . reduce ( ( pre , key ) => Object . assign ( pre , key && shamFactory [ key ] ? { [ key ] : shamFactory [ key ] } : { } ) , { } ) ; this . _prototype = Object . assign ( this . _prototype , this . _depDatas ) ; } }