feat(compiler): transform slot outlets
This commit is contained in:
@@ -13,7 +13,8 @@ import {
|
||||
createObjectProperty,
|
||||
createSimpleExpression,
|
||||
createObjectExpression,
|
||||
Property
|
||||
Property,
|
||||
SourceLocation
|
||||
} from '../ast'
|
||||
import { isArray } from '@vue/shared'
|
||||
import { createCompilerError, ErrorCodes } from '../errors'
|
||||
@@ -26,6 +27,7 @@ import {
|
||||
TO_HANDLERS
|
||||
} from '../runtimeConstants'
|
||||
import { getInnerRange } from '../utils'
|
||||
import { buildSlotOutlet, buildSlots } from './vSlot'
|
||||
|
||||
const toValidId = (str: string): string => str.replace(/[^\w]/g, '')
|
||||
|
||||
@@ -56,7 +58,7 @@ export const transformElement: NodeTransform = (node, context) => {
|
||||
]
|
||||
// props
|
||||
if (hasProps) {
|
||||
const { props, directives } = buildProps(node, context)
|
||||
const { props, directives } = buildProps(node.props, node.loc, context)
|
||||
args.push(props)
|
||||
runtimeDirectives = directives
|
||||
}
|
||||
@@ -94,8 +96,7 @@ export const transformElement: NodeTransform = (node, context) => {
|
||||
node.codegenNode = vnode
|
||||
}
|
||||
} else if (node.tagType === ElementTypes.SLOT) {
|
||||
// <slot [name="xxx"]/>
|
||||
// TODO
|
||||
buildSlotOutlet(node, context)
|
||||
}
|
||||
// node.tagType can also be TEMPLATE, in which case nothing needs to be done
|
||||
}
|
||||
@@ -103,8 +104,9 @@ export const transformElement: NodeTransform = (node, context) => {
|
||||
|
||||
type PropsExpression = ObjectExpression | CallExpression | ExpressionNode
|
||||
|
||||
function buildProps(
|
||||
{ loc: elementLoc, props }: ElementNode,
|
||||
export function buildProps(
|
||||
props: ElementNode['props'],
|
||||
elementLoc: SourceLocation,
|
||||
context: TransformContext
|
||||
): {
|
||||
props: PropsExpression
|
||||
@@ -311,13 +313,3 @@ function createDirectiveArgs(
|
||||
}
|
||||
return createArrayExpression(dirArgs, dir.loc)
|
||||
}
|
||||
|
||||
function buildSlots(
|
||||
{ loc, children }: ElementNode,
|
||||
context: TransformContext
|
||||
): ObjectExpression {
|
||||
const slots = createObjectExpression([], loc)
|
||||
// TODO
|
||||
|
||||
return slots
|
||||
}
|
||||
|
||||
@@ -1 +1,105 @@
|
||||
// TODO
|
||||
import {
|
||||
ElementNode,
|
||||
ObjectExpression,
|
||||
createObjectExpression,
|
||||
NodeTypes,
|
||||
createCompoundExpression,
|
||||
createCallExpression,
|
||||
CompoundExpressionNode,
|
||||
CallExpression
|
||||
} from '../ast'
|
||||
import { TransformContext } from '../transform'
|
||||
import { buildProps } from './transformElement'
|
||||
import { createCompilerError, ErrorCodes } from '../errors'
|
||||
import { isSimpleIdentifier } from '../utils'
|
||||
import { RENDER_SLOT } from '../runtimeConstants'
|
||||
|
||||
export function buildSlots(
|
||||
{ loc, children }: ElementNode,
|
||||
context: TransformContext
|
||||
): ObjectExpression {
|
||||
const slots = createObjectExpression([], loc)
|
||||
// TODO
|
||||
|
||||
return slots
|
||||
}
|
||||
|
||||
export function buildSlotOutlet(node: ElementNode, context: TransformContext) {
|
||||
const { props, children, loc } = node
|
||||
const $slots = context.prefixIdentifiers ? `_ctx.$slots` : `$slots`
|
||||
let slot: string | CompoundExpressionNode = $slots + `.default`
|
||||
|
||||
// check for <slot name="xxx" OR :name="xxx" />
|
||||
let nameIndex: number = -1
|
||||
for (let i = 0; i < props.length; i++) {
|
||||
const prop = props[i]
|
||||
if (prop.type === NodeTypes.ATTRIBUTE) {
|
||||
if (prop.name === `name` && prop.value) {
|
||||
// static name="xxx"
|
||||
const name = prop.value.content
|
||||
const accessor = isSimpleIdentifier(name)
|
||||
? `.${name}`
|
||||
: `[${JSON.stringify(name)}]`
|
||||
slot = `${$slots}${accessor}`
|
||||
nameIndex = i
|
||||
break
|
||||
}
|
||||
} else if (prop.name === `bind`) {
|
||||
const { arg, exp } = prop
|
||||
if (
|
||||
arg &&
|
||||
exp &&
|
||||
arg.type === NodeTypes.SIMPLE_EXPRESSION &&
|
||||
arg.isStatic &&
|
||||
arg.content === `name`
|
||||
) {
|
||||
// dynamic :name="xxx"
|
||||
slot = createCompoundExpression(
|
||||
[
|
||||
$slots + `[`,
|
||||
...(exp.type === NodeTypes.SIMPLE_EXPRESSION
|
||||
? [exp]
|
||||
: exp.children),
|
||||
`]`
|
||||
],
|
||||
loc
|
||||
)
|
||||
nameIndex = i
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const slotArgs: CallExpression['arguments'] = [slot]
|
||||
const propsWithoutName =
|
||||
nameIndex > -1
|
||||
? props.slice(0, nameIndex).concat(props.slice(nameIndex + 1))
|
||||
: props
|
||||
const hasProps = propsWithoutName.length
|
||||
if (hasProps) {
|
||||
const { props: propsExpression, directives } = buildProps(
|
||||
propsWithoutName,
|
||||
loc,
|
||||
context
|
||||
)
|
||||
if (directives.length) {
|
||||
context.onError(
|
||||
createCompilerError(ErrorCodes.X_UNEXPECTED_DIRECTIVE_ON_SLOT_OUTLET)
|
||||
)
|
||||
}
|
||||
slotArgs.push(propsExpression)
|
||||
}
|
||||
|
||||
if (children.length) {
|
||||
if (!hasProps) {
|
||||
slotArgs.push(`{}`)
|
||||
}
|
||||
slotArgs.push(children)
|
||||
}
|
||||
|
||||
node.codegenNode = createCallExpression(
|
||||
context.helper(RENDER_SLOT),
|
||||
slotArgs,
|
||||
loc
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user