import { ElementNode, ObjectExpression, createObjectExpression, NodeTypes, createObjectProperty, createSimpleExpression, createFunctionExpression, DirectiveNode, ElementTypes, ExpressionNode, Property, TemplateChildNode, SourceLocation } from '../ast' import { TransformContext, NodeTransform } from '../transform' import { createCompilerError, ErrorCodes } from '../errors' import { isString } from '@vue/shared' export const isVSlot = (p: ElementNode['props'][0]): p is DirectiveNode => p.type === NodeTypes.DIRECTIVE && p.name === 'slot' // 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 = node.props.find(isVSlot) if (vSlot && vSlot.exp) { context.addIdentifiers(vSlot.exp) return () => { context.removeIdentifiers(vSlot.exp!) } } } } // Instead of being a DirectiveTransform, v-slot processing is called during // transformElement to build the slots object for a component. export function buildSlots( { props, children, loc }: ElementNode, context: TransformContext ): { slots: ObjectExpression hasDynamicSlotName: boolean } { const slots: Property[] = [] let hasDynamicSlotName = false // 1. Check for default slot with slotProps on component itself. // const explicitDefaultSlot = props.find(isVSlot) if (explicitDefaultSlot) { const { arg, exp, loc } = explicitDefaultSlot if (arg) { context.onError( createCompilerError(ErrorCodes.X_NAMED_SLOT_ON_COMPONENT, loc) ) } slots.push(buildSlot(`default`, exp, children, loc)) } // 2. Iterate through children and check for template slots //