|
|
@@ -23,7 +23,8 @@ import {
|
|
|
BlockCodegenNode,
|
|
|
SlotOutletCodegenNode,
|
|
|
ElementCodegenNode,
|
|
|
- ComponentCodegenNode
|
|
|
+ ComponentCodegenNode,
|
|
|
+ IfNode
|
|
|
} from '../ast'
|
|
|
import { createCompilerError, ErrorCodes } from '../errors'
|
|
|
import { processExpression } from './transformExpression'
|
|
|
@@ -40,73 +41,18 @@ import { injectProp } from '../utils'
|
|
|
export const transformIf = createStructuralDirectiveTransform(
|
|
|
/^(if|else|else-if)$/,
|
|
|
(node, dir, context) => {
|
|
|
- if (
|
|
|
- dir.name !== 'else' &&
|
|
|
- (!dir.exp || !(dir.exp as SimpleExpressionNode).content.trim())
|
|
|
- ) {
|
|
|
- const loc = dir.exp ? dir.exp.loc : node.loc
|
|
|
- context.onError(
|
|
|
- createCompilerError(ErrorCodes.X_V_IF_NO_EXPRESSION, dir.loc)
|
|
|
- )
|
|
|
- dir.exp = createSimpleExpression(`true`, false, loc)
|
|
|
- }
|
|
|
-
|
|
|
- if (!__BROWSER__ && context.prefixIdentifiers && dir.exp) {
|
|
|
- // dir.exp can only be simple expression because vIf transform is applied
|
|
|
- // before expression transform.
|
|
|
- dir.exp = processExpression(dir.exp as SimpleExpressionNode, context)
|
|
|
- }
|
|
|
-
|
|
|
- if (dir.name === 'if') {
|
|
|
- const branch = createIfBranch(node, dir)
|
|
|
- const codegenNode = createSequenceExpression([
|
|
|
- createCallExpression(context.helper(OPEN_BLOCK))
|
|
|
- ]) as IfCodegenNode
|
|
|
-
|
|
|
- context.replaceNode({
|
|
|
- type: NodeTypes.IF,
|
|
|
- loc: node.loc,
|
|
|
- branches: [branch],
|
|
|
- codegenNode
|
|
|
- })
|
|
|
-
|
|
|
+ return processIfBranches(node, dir, context, (ifNode, branch, isRoot) => {
|
|
|
// Exit callback. Complete the codegenNode when all children have been
|
|
|
// transformed.
|
|
|
return () => {
|
|
|
- codegenNode.expressions.push(createCodegenNodeForBranch(
|
|
|
- branch,
|
|
|
- 0,
|
|
|
- context
|
|
|
- ) as IfConditionalExpression)
|
|
|
- }
|
|
|
- } else {
|
|
|
- // locate the adjacent v-if
|
|
|
- const siblings = context.parent!.children
|
|
|
- const comments = []
|
|
|
- let i = siblings.indexOf(node)
|
|
|
- while (i-- >= -1) {
|
|
|
- const sibling = siblings[i]
|
|
|
- if (__DEV__ && sibling && sibling.type === NodeTypes.COMMENT) {
|
|
|
- context.removeNode(sibling)
|
|
|
- comments.unshift(sibling)
|
|
|
- continue
|
|
|
- }
|
|
|
- if (sibling && sibling.type === NodeTypes.IF) {
|
|
|
- // move the node to the if node's branches
|
|
|
- context.removeNode()
|
|
|
- const branch = createIfBranch(node, dir)
|
|
|
- if (__DEV__ && comments.length) {
|
|
|
- branch.children = [...comments, ...branch.children]
|
|
|
- }
|
|
|
- sibling.branches.push(branch)
|
|
|
- // since the branch was removed, it will not be traversed.
|
|
|
- // make sure to traverse here.
|
|
|
- traverseChildren(branch, context)
|
|
|
- // make sure to reset currentNode after traversal to indicate this
|
|
|
- // node has been removed.
|
|
|
- context.currentNode = null
|
|
|
+ if (isRoot) {
|
|
|
+ ifNode.codegenNode = createSequenceExpression([
|
|
|
+ createCallExpression(context.helper(OPEN_BLOCK)),
|
|
|
+ createCodegenNodeForBranch(branch, 0, context)
|
|
|
+ ]) as IfCodegenNode
|
|
|
+ } else {
|
|
|
// attach this branch's codegen node to the v-if root.
|
|
|
- let parentCondition = sibling.codegenNode
|
|
|
+ let parentCondition = ifNode.codegenNode!
|
|
|
.expressions[1] as ConditionalExpression
|
|
|
while (
|
|
|
parentCondition.alternate.type ===
|
|
|
@@ -116,20 +62,92 @@ export const transformIf = createStructuralDirectiveTransform(
|
|
|
}
|
|
|
parentCondition.alternate = createCodegenNodeForBranch(
|
|
|
branch,
|
|
|
- sibling.branches.length - 1,
|
|
|
+ ifNode.branches.length - 1,
|
|
|
context
|
|
|
)
|
|
|
- } else {
|
|
|
- context.onError(
|
|
|
- createCompilerError(ErrorCodes.X_V_ELSE_NO_ADJACENT_IF, node.loc)
|
|
|
- )
|
|
|
}
|
|
|
- break
|
|
|
}
|
|
|
- }
|
|
|
+ })
|
|
|
}
|
|
|
)
|
|
|
|
|
|
+export const processIfBranches = (
|
|
|
+ node: ElementNode,
|
|
|
+ dir: DirectiveNode,
|
|
|
+ context: TransformContext,
|
|
|
+ processCodegen?: (
|
|
|
+ node: IfNode,
|
|
|
+ branch: IfBranchNode,
|
|
|
+ isRoot: boolean
|
|
|
+ ) => (() => void) | void
|
|
|
+) => {
|
|
|
+ if (
|
|
|
+ dir.name !== 'else' &&
|
|
|
+ (!dir.exp || !(dir.exp as SimpleExpressionNode).content.trim())
|
|
|
+ ) {
|
|
|
+ const loc = dir.exp ? dir.exp.loc : node.loc
|
|
|
+ context.onError(
|
|
|
+ createCompilerError(ErrorCodes.X_V_IF_NO_EXPRESSION, dir.loc)
|
|
|
+ )
|
|
|
+ dir.exp = createSimpleExpression(`true`, false, loc)
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!__BROWSER__ && context.prefixIdentifiers && dir.exp) {
|
|
|
+ // dir.exp can only be simple expression because vIf transform is applied
|
|
|
+ // before expression transform.
|
|
|
+ dir.exp = processExpression(dir.exp as SimpleExpressionNode, context)
|
|
|
+ }
|
|
|
+
|
|
|
+ if (dir.name === 'if') {
|
|
|
+ const branch = createIfBranch(node, dir)
|
|
|
+ const ifNode: IfNode = {
|
|
|
+ type: NodeTypes.IF,
|
|
|
+ loc: node.loc,
|
|
|
+ branches: [branch]
|
|
|
+ }
|
|
|
+ context.replaceNode(ifNode)
|
|
|
+ if (processCodegen) {
|
|
|
+ return processCodegen(ifNode, branch, true)
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // locate the adjacent v-if
|
|
|
+ const siblings = context.parent!.children
|
|
|
+ const comments = []
|
|
|
+ let i = siblings.indexOf(node)
|
|
|
+ while (i-- >= -1) {
|
|
|
+ const sibling = siblings[i]
|
|
|
+ if (__DEV__ && sibling && sibling.type === NodeTypes.COMMENT) {
|
|
|
+ context.removeNode(sibling)
|
|
|
+ comments.unshift(sibling)
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ if (sibling && sibling.type === NodeTypes.IF) {
|
|
|
+ // move the node to the if node's branches
|
|
|
+ context.removeNode()
|
|
|
+ const branch = createIfBranch(node, dir)
|
|
|
+ if (__DEV__ && comments.length) {
|
|
|
+ branch.children = [...comments, ...branch.children]
|
|
|
+ }
|
|
|
+ sibling.branches.push(branch)
|
|
|
+ const onExit = processCodegen && processCodegen(sibling, branch, false)
|
|
|
+ // since the branch was removed, it will not be traversed.
|
|
|
+ // make sure to traverse here.
|
|
|
+ traverseChildren(branch, context)
|
|
|
+ // call on exit
|
|
|
+ if (onExit) onExit()
|
|
|
+ // make sure to reset currentNode after traversal to indicate this
|
|
|
+ // node has been removed.
|
|
|
+ context.currentNode = null
|
|
|
+ } else {
|
|
|
+ context.onError(
|
|
|
+ createCompilerError(ErrorCodes.X_V_ELSE_NO_ADJACENT_IF, node.loc)
|
|
|
+ )
|
|
|
+ }
|
|
|
+ break
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
function createIfBranch(node: ElementNode, dir: DirectiveNode): IfBranchNode {
|
|
|
return {
|
|
|
type: NodeTypes.IF_BRANCH,
|
|
|
@@ -171,25 +189,25 @@ function createChildrenCodegenNode(
|
|
|
createSimpleExpression(index + '', false)
|
|
|
)
|
|
|
const { children } = branch
|
|
|
- const child = children[0]
|
|
|
+ const firstChild = children[0]
|
|
|
const needFragmentWrapper =
|
|
|
- children.length !== 1 || child.type !== NodeTypes.ELEMENT
|
|
|
+ children.length !== 1 || firstChild.type !== NodeTypes.ELEMENT
|
|
|
if (needFragmentWrapper) {
|
|
|
const blockArgs: CallExpression['arguments'] = [
|
|
|
helper(FRAGMENT),
|
|
|
createObjectExpression([keyProperty]),
|
|
|
children
|
|
|
]
|
|
|
- if (children.length === 1 && child.type === NodeTypes.FOR) {
|
|
|
+ if (children.length === 1 && firstChild.type === NodeTypes.FOR) {
|
|
|
// optimize away nested fragments when child is a ForNode
|
|
|
- const forBlockArgs = child.codegenNode.expressions[1].arguments
|
|
|
+ const forBlockArgs = firstChild.codegenNode!.expressions[1].arguments
|
|
|
// directly use the for block's children and patchFlag
|
|
|
blockArgs[2] = forBlockArgs[2]
|
|
|
blockArgs[3] = forBlockArgs[3]
|
|
|
}
|
|
|
return createCallExpression(helper(CREATE_BLOCK), blockArgs)
|
|
|
} else {
|
|
|
- const childCodegen = (child as ElementNode).codegenNode as
|
|
|
+ const childCodegen = (firstChild as ElementNode).codegenNode as
|
|
|
| ElementCodegenNode
|
|
|
| ComponentCodegenNode
|
|
|
| SlotOutletCodegenNode
|