text: /* @flow */
  
  import { def } from 'core/util/lang'
  import { normalizeChildren } from 'core/vdom/helpers/normalize-children'
  import { emptyObject } from 'shared/util'
  
  export function normalizeScopedSlots (
    slots: { [key: string]: Function } | void,
    normalSlots: { [key: string]: Array<VNode> },
    prevSlots?: { [key: string]: Function } | void
  ): any {
    let res
    if (!slots) {
      res = {}
    } else if (slots._normalized) {
      // fast path 1: child component re-render only, parent did not change
      return slots._normalized
    } else if (slots.$stable && prevSlots && prevSlots !== emptyObject) {
      // fast path 2: stable scoped slots, only need to normalize once
      return prevSlots
    } else {
      res = {}
      for (const key in slots) {
        if (slots[key] && key[0] !== '$') {
          res[key] = normalizeScopedSlot(normalSlots, key, slots[key])
        }
      }
    }
    // expose normal slots on scopedSlots
    for (const key in normalSlots) {
      if (!(key in res)) {
        res[key] = proxyNormalSlot(normalSlots, key)
      }
    }
    // avoriaz seems to mock a non-extensible $scopedSlots object
    // and when that is passed down this would cause an error
    if (slots && Object.isExtensible(slots)) {
      (slots: any)._normalized = res
    }
    def(res, '$stable', slots ? !!slots.$stable : true)
    return res
  }
  
  function normalizeScopedSlot(normalSlots, key, fn) {
    const normalized = scope => {
      let res = fn(scope || {})
      res = res && typeof res === 'object' && !Array.isArray(res)
        ? [res] // single vnode
        : normalizeChildren(res)
      return res && res.length === 0
        ? undefined
        : res
    }
    // this is a slot using the new v-slot syntax without scope. although it is
    // compiled as a scoped slot, render fn users would expect it to be present
    // on this.$slots because the usage is semantically a normal slot.
    if (fn.proxy) {
      Object.defineProperty(normalSlots, key, {
        get: normalized,
        enumerable: true,
        configurable: true
      })
    }
    return normalized
  }
  
  function proxyNormalSlot(slots, key) {
    return () => slots[key]
  }
  