import { ComponentInstance, currentInstance } from './component' import { VNode, NormalizedChildren, normalizeVNode, VNodeChild } from './vnode' import { isArray, isFunction } from '@vue/shared' import { ShapeFlags } from './shapeFlags' import { warn } from './warning' export type Slot = (...args: any[]) => VNode[] export type Slots = Readonly<{ [name: string]: Slot }> export type RawSlots = { [name: string]: unknown } const normalizeSlotValue = (value: unknown): VNode[] => isArray(value) ? value.map(normalizeVNode) : [normalizeVNode(value as VNodeChild)] const normalizeSlot = (key: string, rawSlot: Function): Slot => ( props: any ) => { if (__DEV__ && currentInstance != null) { warn( `Slot "${key}" invoked outside of the render function: ` + `this will not track dependencies used in the slot. ` + `Invoke the slot function inside the render function instead.` ) } return normalizeSlotValue(rawSlot(props)) } export function resolveSlots( instance: ComponentInstance, children: NormalizedChildren ) { let slots: Slots | void if (instance.vnode.shapeFlag & ShapeFlags.SLOTS_CHILDREN) { if ((children as any)._normalized) { // pre-normalized slots object generated by compiler slots = children as Slots } else { slots = {} for (const key in children as RawSlots) { let value = (children as RawSlots)[key] if (isFunction(value)) { ;(slots as any)[key] = normalizeSlot(key, value) } else { if (__DEV__) { warn( `Non-function value encountered for slot "${key}". ` + `Prefer function slots for better performance.` ) } value = normalizeSlotValue(value) ;(slots as any)[key] = () => value } } } } else if (children !== null) { // non slot object children (direct value) passed to a component if (__DEV__) { warn( `Non-function value encountered for default slot. ` + `Prefer function slots for better performance.` ) } const normalized = normalizeSlotValue(children) slots = { default: () => normalized } } if (slots !== void 0) { instance.slots = slots } }