import { ElementNode, ObjectExpression, createObjectExpression, NodeTypes, createObjectProperty, createSimpleExpression, createFunctionExpression, DirectiveNode, ElementTypes, ExpressionNode, Property, TemplateChildNode, SourceLocation, createConditionalExpression, ConditionalExpression, JSChildNode, SimpleExpressionNode, FunctionExpression, CallExpression, createCallExpression, createArrayExpression } from '../ast' import { TransformContext, NodeTransform } from '../transform' import { createCompilerError, ErrorCodes } from '../errors' import { findDir, isTemplateNode, assert, isVSlot } from '../utils' import { CREATE_SLOTS, RENDER_LIST } from '../runtimeConstants' import { parseForExpression, createForLoopParams } from './vFor' const isStaticExp = (p: JSChildNode): p is SimpleExpressionNode => p.type === NodeTypes.SIMPLE_EXPRESSION && p.isStatic const defaultFallback = createSimpleExpression(`undefined`, false) // A NodeTransform that tracks scope identifiers for scoped slots so that they // don't get prefixed by transformExpression. This transform is only applied // in non-browser builds with { prefixIdentifiers: true } export const trackSlotScopes: NodeTransform = (node, context) => { if ( node.type === NodeTypes.ELEMENT && (node.tagType === ElementTypes.COMPONENT || node.tagType === ElementTypes.TEMPLATE) ) { const vSlot = findDir(node, 'slot') if (vSlot) { const { addIdentifiers, removeIdentifiers } = context const slotProps = vSlot.exp slotProps && addIdentifiers(slotProps) return () => { slotProps && removeIdentifiers(slotProps) } } } } // A NodeTransform that tracks scope identifiers for scoped slots with v-for. // This transform is only applied in non-browser builds with { prefixIdentifiers: true } export const trackVForSlotScopes: NodeTransform = (node, context) => { let vFor if ( isTemplateNode(node) && node.props.some(isVSlot) && (vFor = findDir(node, 'for')) ) { const result = (vFor.parseResult = parseForExpression( vFor.exp as SimpleExpressionNode, context )) if (result) { const { value, key, index } = result const { addIdentifiers, removeIdentifiers } = context value && addIdentifiers(value) key && addIdentifiers(key) index && addIdentifiers(index) return () => { value && removeIdentifiers(value) key && removeIdentifiers(key) index && removeIdentifiers(index) } } } } // Instead of being a DirectiveTransform, v-slot processing is called during // transformElement to build the slots object for a component. export function buildSlots( node: ElementNode, context: TransformContext ): { slots: ObjectExpression | CallExpression hasDynamicSlots: boolean } { const { children, loc } = node const slotsProperties: Property[] = [] const dynamicSlots: (ConditionalExpression | CallExpression)[] = [] let hasDynamicSlots = false // 1. Check for default slot with slotProps on component itself. // const explicitDefaultSlot = findDir(node, 'slot', true) if (explicitDefaultSlot) { const { arg, exp, loc } = explicitDefaultSlot if (arg) { context.onError( createCompilerError(ErrorCodes.X_NAMED_SLOT_ON_COMPONENT, loc) ) } slotsProperties.push(buildDefaultSlot(exp, children, loc)) } // 2. Iterate through children and check for template slots //