text: /* @flow */
  
  // https://github.com/Hanks10100/weex-native-directive/tree/master/component
  
  import { mergeOptions, isPlainObject, noop } from 'core/util/index'
  import Watcher from 'core/observer/watcher'
  import { initProxy } from 'core/instance/proxy'
  import { initState, getData } from 'core/instance/state'
  import { initRender } from 'core/instance/render'
  import { initEvents } from 'core/instance/events'
  import { initProvide, initInjections } from 'core/instance/inject'
  import { initLifecycle, callHook } from 'core/instance/lifecycle'
  import { initInternalComponent, resolveConstructorOptions } from 'core/instance/init'
  import { registerComponentHook, updateComponentData } from '../../util/index'
  
  let uid = 0
  
  // override Vue.prototype._init
  function initVirtualComponent(options: Object = {}) {
    const vm: Component = this
    const componentId = options.componentId
  
    // virtual component uid
    vm._uid = `virtual-component-${uid++}`
  
    // a flag to avoid this being observed
    vm._isVue = true
    // merge options
    if (options && options._isComponent) {
      // optimize internal component instantiation
      // since dynamic options merging is pretty slow, and none of the
      // internal component options needs special treatment.
      initInternalComponent(vm, options)
    } else {
      vm.$options = mergeOptions(resolveConstructorOptions(vm.constructor), options || {}, vm)
    }
  
    /* istanbul ignore else */
    if (process.env.NODE_ENV !== 'production') {
      initProxy(vm)
    } else {
      vm._renderProxy = vm
    }
  
    vm._self = vm
    initLifecycle(vm)
    initEvents(vm)
    initRender(vm)
    callHook(vm, 'beforeCreate')
    initInjections(vm) // resolve injections before data/props
    initState(vm)
    initProvide(vm) // resolve provide after data/props
    callHook(vm, 'created')
  
    // send initial data to native
    const data = vm.$options.data
    const params = typeof data === 'function' ? getData(data, vm) : data || {}
    if (isPlainObject(params)) {
      updateComponentData(componentId, params)
    }
  
    registerComponentHook(componentId, 'lifecycle', 'attach', () => {
      callHook(vm, 'beforeMount')
  
      const updateComponent = () => {
        vm._update(vm._vnode, false)
      }
      new Watcher(vm, updateComponent, noop, null, true)
  
      vm._isMounted = true
      callHook(vm, 'mounted')
    })
  
    registerComponentHook(componentId, 'lifecycle', 'detach', () => {
      vm.$destroy()
    })
  }
  
  // override Vue.prototype._update
  function updateVirtualComponent(vnode?: VNode) {
    const vm: Component = this
    const componentId = vm.$options.componentId
    if (vm._isMounted) {
      callHook(vm, 'beforeUpdate')
    }
    vm._vnode = vnode
    if (vm._isMounted && componentId) {
      // TODO: data should be filtered and without bindings
      const data = Object.assign({}, vm._data)
      updateComponentData(componentId, data, () => {
        callHook(vm, 'updated')
      })
    }
  }
  
  // listening on native callback
  export function resolveVirtualComponent(vnode: MountedComponentVNode): VNode {
    const BaseCtor = vnode.componentOptions.Ctor
    const VirtualComponent = BaseCtor.extend({})
    const cid = VirtualComponent.cid
    VirtualComponent.prototype._init = initVirtualComponent
    VirtualComponent.prototype._update = updateVirtualComponent
  
    vnode.componentOptions.Ctor = BaseCtor.extend({
      beforeCreate() {
        // const vm: Component = this
  
        // TODO: listen on all events and dispatch them to the
        // corresponding virtual components according to the componentId.
        // vm._virtualComponents = {}
        const createVirtualComponent = (componentId, propsData) => {
          // create virtual component
          // const subVm =
          new VirtualComponent({
            componentId,
            propsData,
          })
          // if (vm._virtualComponents) {
          //   vm._virtualComponents[componentId] = subVm
          // }
        }
  
        registerComponentHook(cid, 'lifecycle', 'create', createVirtualComponent)
      },
      beforeDestroy() {
        delete this._virtualComponents
      },
    })
  }
  