mirror of https://github.com/vuejs/core.git
feat(compiler-vapor): `v-else` / `v-else-if` (#98)
Co-authored-by: 三咲智子 Kevin Deng <sxzz@sxzz.moe>
This commit is contained in:
parent
63aacf6194
commit
63a127b612
|
@ -20,6 +20,30 @@ export function render(_ctx) {
|
|||
}"
|
||||
`;
|
||||
|
||||
exports[`compiler: v-if > comment between branches 1`] = `
|
||||
"import { template as _template, fragment as _fragment, createIf as _createIf, prepend as _prepend } from 'vue/vapor';
|
||||
|
||||
export function render(_ctx) {
|
||||
const t0 = _template("<div></div>")
|
||||
const t1 = _template("<!--foo--><p></p>")
|
||||
const t2 = _template("<!--bar-->fine")
|
||||
const t3 = _fragment()
|
||||
const n0 = t3()
|
||||
const n1 = _createIf(() => (_ctx.ok), () => {
|
||||
const n2 = t0()
|
||||
return n2
|
||||
}, () => _createIf(() => (_ctx.orNot), () => {
|
||||
const n3 = t1()
|
||||
return n3
|
||||
}, () => {
|
||||
const n4 = t2()
|
||||
return n4
|
||||
}))
|
||||
_prepend(n0, n1)
|
||||
return n0
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`compiler: v-if > dedupe same template 1`] = `
|
||||
"import { template as _template, fragment as _fragment, createIf as _createIf, append as _append } from 'vue/vapor';
|
||||
|
||||
|
@ -59,3 +83,67 @@ export function render(_ctx) {
|
|||
return n0
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`compiler: v-if > v-if + v-else 1`] = `
|
||||
"import { template as _template, fragment as _fragment, createIf as _createIf, prepend as _prepend } from 'vue/vapor';
|
||||
|
||||
export function render(_ctx) {
|
||||
const t0 = _template("<div></div>")
|
||||
const t1 = _template("<p></p>")
|
||||
const t2 = _fragment()
|
||||
const n0 = t2()
|
||||
const n1 = _createIf(() => (_ctx.ok), () => {
|
||||
const n2 = t0()
|
||||
return n2
|
||||
}, () => {
|
||||
const n3 = t1()
|
||||
return n3
|
||||
})
|
||||
_prepend(n0, n1)
|
||||
return n0
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`compiler: v-if > v-if + v-else-if + v-else 1`] = `
|
||||
"import { template as _template, fragment as _fragment, createIf as _createIf, prepend as _prepend } from 'vue/vapor';
|
||||
|
||||
export function render(_ctx) {
|
||||
const t0 = _template("<div></div>")
|
||||
const t1 = _template("<p></p>")
|
||||
const t2 = _template("fine")
|
||||
const t3 = _fragment()
|
||||
const n0 = t3()
|
||||
const n1 = _createIf(() => (_ctx.ok), () => {
|
||||
const n2 = t0()
|
||||
return n2
|
||||
}, () => _createIf(() => (_ctx.orNot), () => {
|
||||
const n3 = t1()
|
||||
return n3
|
||||
}, () => {
|
||||
const n4 = t2()
|
||||
return n4
|
||||
}))
|
||||
_prepend(n0, n1)
|
||||
return n0
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`compiler: v-if > v-if + v-else-if 1`] = `
|
||||
"import { template as _template, fragment as _fragment, createIf as _createIf, prepend as _prepend } from 'vue/vapor';
|
||||
|
||||
export function render(_ctx) {
|
||||
const t0 = _template("<div></div>")
|
||||
const t1 = _template("<p></p>")
|
||||
const t2 = _fragment()
|
||||
const n0 = t2()
|
||||
const n1 = _createIf(() => (_ctx.ok), () => {
|
||||
const n2 = t0()
|
||||
return n2
|
||||
}, () => _createIf(() => (_ctx.orNot), () => {
|
||||
const n3 = t1()
|
||||
return n3
|
||||
}))
|
||||
_prepend(n0, n1)
|
||||
return n0
|
||||
}"
|
||||
`;
|
||||
|
|
|
@ -1,11 +1,14 @@
|
|||
import { makeCompile } from './_utils'
|
||||
import {
|
||||
IRNodeTypes,
|
||||
type IfIRNode,
|
||||
transformElement,
|
||||
transformInterpolation,
|
||||
transformOnce,
|
||||
transformVIf,
|
||||
transformVText,
|
||||
} from '../../src'
|
||||
import { NodeTypes } from '@vue/compiler-core'
|
||||
|
||||
const compileWithVIf = makeCompile({
|
||||
nodeTransforms: [
|
||||
|
@ -21,15 +24,87 @@ const compileWithVIf = makeCompile({
|
|||
|
||||
describe('compiler: v-if', () => {
|
||||
test('basic v-if', () => {
|
||||
const { code } = compileWithVIf(`<div v-if="ok">{{msg}}</div>`)
|
||||
const { code, vaporHelpers, ir, helpers } = compileWithVIf(
|
||||
`<div v-if="ok">{{msg}}</div>`,
|
||||
)
|
||||
|
||||
expect(vaporHelpers).contains('createIf')
|
||||
expect(helpers.size).toBe(0)
|
||||
|
||||
expect(ir.template).lengthOf(2)
|
||||
expect(ir.template).toMatchObject([
|
||||
{
|
||||
template: '<div></div>',
|
||||
type: IRNodeTypes.TEMPLATE_FACTORY,
|
||||
},
|
||||
{
|
||||
type: IRNodeTypes.FRAGMENT_FACTORY,
|
||||
},
|
||||
])
|
||||
expect(ir.operation).toMatchObject([
|
||||
{
|
||||
type: IRNodeTypes.IF,
|
||||
id: 1,
|
||||
condition: {
|
||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||
content: 'ok',
|
||||
isStatic: false,
|
||||
},
|
||||
positive: {
|
||||
type: IRNodeTypes.BLOCK_FUNCTION,
|
||||
templateIndex: 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
type: IRNodeTypes.APPEND_NODE,
|
||||
elements: [1],
|
||||
parent: 0,
|
||||
},
|
||||
])
|
||||
|
||||
expect(ir.dynamic).toMatchObject({
|
||||
id: 0,
|
||||
children: { 0: { id: 1 } },
|
||||
})
|
||||
|
||||
expect(ir.effect).toEqual([])
|
||||
expect((ir.operation[0] as IfIRNode).positive.effect).lengthOf(1)
|
||||
|
||||
expect(code).matchSnapshot()
|
||||
})
|
||||
|
||||
test('template v-if', () => {
|
||||
const { code } = compileWithVIf(
|
||||
const { code, ir } = compileWithVIf(
|
||||
`<template v-if="ok"><div/>hello<p v-text="msg"/></template>`,
|
||||
)
|
||||
expect(code).matchSnapshot()
|
||||
|
||||
expect(ir.template).lengthOf(2)
|
||||
expect(ir.template[0]).toMatchObject({
|
||||
template: '<div></div>hello<p></p>',
|
||||
type: IRNodeTypes.TEMPLATE_FACTORY,
|
||||
})
|
||||
|
||||
expect(ir.effect).toEqual([])
|
||||
expect((ir.operation[0] as IfIRNode).positive.effect).toMatchObject([
|
||||
{
|
||||
operations: [
|
||||
{
|
||||
type: IRNodeTypes.SET_TEXT,
|
||||
element: 3,
|
||||
value: {
|
||||
content: 'msg',
|
||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||
isStatic: false,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
])
|
||||
expect((ir.operation[0] as IfIRNode).positive.dynamic).toMatchObject({
|
||||
id: 2,
|
||||
children: { 2: { id: 3 } },
|
||||
})
|
||||
})
|
||||
|
||||
test('dedupe same template', () => {
|
||||
|
@ -42,10 +117,185 @@ describe('compiler: v-if', () => {
|
|||
|
||||
test.todo('v-if with v-once')
|
||||
test.todo('component v-if')
|
||||
test.todo('v-if + v-else')
|
||||
test.todo('v-if + v-else-if')
|
||||
test.todo('v-if + v-else-if + v-else')
|
||||
test.todo('comment between branches')
|
||||
|
||||
test('v-if + v-else', () => {
|
||||
const { code, ir, vaporHelpers, helpers } = compileWithVIf(
|
||||
`<div v-if="ok"/><p v-else/>`,
|
||||
)
|
||||
expect(code).matchSnapshot()
|
||||
expect(ir.template).lengthOf(3)
|
||||
expect(ir.template).toMatchObject([
|
||||
{
|
||||
template: '<div></div>',
|
||||
type: IRNodeTypes.TEMPLATE_FACTORY,
|
||||
},
|
||||
{
|
||||
template: '<p></p>',
|
||||
type: IRNodeTypes.TEMPLATE_FACTORY,
|
||||
},
|
||||
{
|
||||
type: IRNodeTypes.FRAGMENT_FACTORY,
|
||||
},
|
||||
])
|
||||
|
||||
expect(vaporHelpers).contains('createIf')
|
||||
expect(ir.effect).lengthOf(0)
|
||||
expect(helpers).lengthOf(0)
|
||||
expect(ir.operation).toMatchObject([
|
||||
{
|
||||
type: IRNodeTypes.IF,
|
||||
id: 1,
|
||||
condition: {
|
||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||
content: 'ok',
|
||||
isStatic: false,
|
||||
},
|
||||
positive: {
|
||||
type: IRNodeTypes.BLOCK_FUNCTION,
|
||||
templateIndex: 0,
|
||||
},
|
||||
negative: {
|
||||
type: IRNodeTypes.BLOCK_FUNCTION,
|
||||
templateIndex: 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
type: IRNodeTypes.PREPEND_NODE,
|
||||
elements: [1],
|
||||
parent: 0,
|
||||
},
|
||||
])
|
||||
})
|
||||
|
||||
test('v-if + v-else-if', () => {
|
||||
const { code, ir } = compileWithVIf(
|
||||
`<div v-if="ok"/><p v-else-if="orNot"/>`,
|
||||
)
|
||||
expect(code).matchSnapshot()
|
||||
expect(ir.template).lengthOf(3)
|
||||
expect(ir.template).toMatchObject([
|
||||
{
|
||||
template: '<div></div>',
|
||||
type: IRNodeTypes.TEMPLATE_FACTORY,
|
||||
},
|
||||
{
|
||||
template: '<p></p>',
|
||||
type: IRNodeTypes.TEMPLATE_FACTORY,
|
||||
},
|
||||
{ type: IRNodeTypes.FRAGMENT_FACTORY },
|
||||
])
|
||||
|
||||
expect(ir.operation).toMatchObject([
|
||||
{
|
||||
type: IRNodeTypes.IF,
|
||||
id: 1,
|
||||
condition: {
|
||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||
content: 'ok',
|
||||
isStatic: false,
|
||||
},
|
||||
positive: {
|
||||
type: IRNodeTypes.BLOCK_FUNCTION,
|
||||
templateIndex: 0,
|
||||
},
|
||||
negative: {
|
||||
type: IRNodeTypes.IF,
|
||||
condition: {
|
||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||
content: 'orNot',
|
||||
isStatic: false,
|
||||
},
|
||||
positive: {
|
||||
type: IRNodeTypes.BLOCK_FUNCTION,
|
||||
templateIndex: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
type: IRNodeTypes.PREPEND_NODE,
|
||||
elements: [1],
|
||||
parent: 0,
|
||||
},
|
||||
])
|
||||
})
|
||||
|
||||
test('v-if + v-else-if + v-else', () => {
|
||||
const { code, ir } = compileWithVIf(
|
||||
`<div v-if="ok"/><p v-else-if="orNot"/><template v-else>fine</template>`,
|
||||
)
|
||||
expect(code).matchSnapshot()
|
||||
expect(ir.template).lengthOf(4)
|
||||
expect(ir.template).toMatchObject([
|
||||
{
|
||||
template: '<div></div>',
|
||||
type: IRNodeTypes.TEMPLATE_FACTORY,
|
||||
},
|
||||
{
|
||||
template: '<p></p>',
|
||||
type: IRNodeTypes.TEMPLATE_FACTORY,
|
||||
},
|
||||
{
|
||||
template: 'fine',
|
||||
type: IRNodeTypes.TEMPLATE_FACTORY,
|
||||
},
|
||||
{ type: IRNodeTypes.FRAGMENT_FACTORY },
|
||||
])
|
||||
|
||||
expect(ir.operation).toMatchObject([
|
||||
{
|
||||
type: IRNodeTypes.IF,
|
||||
id: 1,
|
||||
positive: {
|
||||
type: IRNodeTypes.BLOCK_FUNCTION,
|
||||
templateIndex: 0,
|
||||
},
|
||||
negative: {
|
||||
type: IRNodeTypes.IF,
|
||||
positive: {
|
||||
type: IRNodeTypes.BLOCK_FUNCTION,
|
||||
templateIndex: 1,
|
||||
},
|
||||
negative: {
|
||||
type: IRNodeTypes.BLOCK_FUNCTION,
|
||||
templateIndex: 2,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
type: IRNodeTypes.PREPEND_NODE,
|
||||
elements: [1],
|
||||
parent: 0,
|
||||
},
|
||||
])
|
||||
})
|
||||
|
||||
test('comment between branches', () => {
|
||||
const { code, ir } = compileWithVIf(`
|
||||
<div v-if="ok"/>
|
||||
<!--foo-->
|
||||
<p v-else-if="orNot"/>
|
||||
<!--bar-->
|
||||
<template v-else>fine</template>
|
||||
`)
|
||||
expect(code).matchSnapshot()
|
||||
expect(ir.template).lengthOf(4)
|
||||
expect(ir.template).toMatchObject([
|
||||
{
|
||||
template: '<div></div>',
|
||||
type: IRNodeTypes.TEMPLATE_FACTORY,
|
||||
},
|
||||
{
|
||||
template: '<!--foo--><p></p>',
|
||||
type: IRNodeTypes.TEMPLATE_FACTORY,
|
||||
},
|
||||
{
|
||||
template: '<!--bar-->fine',
|
||||
type: IRNodeTypes.TEMPLATE_FACTORY,
|
||||
},
|
||||
{ type: IRNodeTypes.FRAGMENT_FACTORY },
|
||||
])
|
||||
})
|
||||
|
||||
describe.todo('errors')
|
||||
describe.todo('codegen')
|
||||
test.todo('v-on with v-if')
|
||||
|
|
|
@ -1,12 +1,30 @@
|
|||
import { type CodegenContext, genBlockFunctionContent } from '../generate'
|
||||
import type { BlockFunctionIRNode, IfIRNode } from '../ir'
|
||||
import { type BlockFunctionIRNode, IRNodeTypes, type IfIRNode } from '../ir'
|
||||
import { genExpression } from './expression'
|
||||
|
||||
export function genIf(oper: IfIRNode, context: CodegenContext) {
|
||||
const { pushFnCall, vaporHelper, pushNewline, push, withIndent } = context
|
||||
export function genIf(
|
||||
oper: IfIRNode,
|
||||
context: CodegenContext,
|
||||
isNested = false,
|
||||
) {
|
||||
const { pushFnCall, vaporHelper, pushNewline, push } = context
|
||||
const { condition, positive, negative } = oper
|
||||
|
||||
pushNewline(`const n${oper.id} = `)
|
||||
let positiveArg = () => genBlockFunction(positive, context)
|
||||
let negativeArg: false | (() => void) = false
|
||||
|
||||
if (negative) {
|
||||
if (negative.type === IRNodeTypes.BLOCK_FUNCTION) {
|
||||
negativeArg = () => genBlockFunction(negative, context)
|
||||
} else {
|
||||
negativeArg = () => {
|
||||
push('() => ')
|
||||
genIf(negative!, context, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!isNested) pushNewline(`const n${oper.id} = `)
|
||||
pushFnCall(
|
||||
vaporHelper('createIf'),
|
||||
() => {
|
||||
|
@ -14,15 +32,17 @@ export function genIf(oper: IfIRNode, context: CodegenContext) {
|
|||
genExpression(condition, context)
|
||||
push(')')
|
||||
},
|
||||
() => genBlockFunction(positive),
|
||||
!!negative && (() => genBlockFunction(negative!)),
|
||||
positiveArg,
|
||||
negativeArg,
|
||||
)
|
||||
}
|
||||
|
||||
function genBlockFunction(oper: BlockFunctionIRNode, context: CodegenContext) {
|
||||
const { pushNewline, push, withIndent } = context
|
||||
|
||||
function genBlockFunction(oper: BlockFunctionIRNode) {
|
||||
push('() => {')
|
||||
withIndent(() => {
|
||||
genBlockFunctionContent(oper, context)
|
||||
})
|
||||
pushNewline('}')
|
||||
}
|
||||
}
|
||||
|
|
|
@ -62,7 +62,7 @@ export interface IfIRNode extends BaseIRNode {
|
|||
id: number
|
||||
condition: IRExpression
|
||||
positive: BlockFunctionIRNode
|
||||
negative?: BlockFunctionIRNode
|
||||
negative?: BlockFunctionIRNode | IfIRNode
|
||||
}
|
||||
|
||||
export interface TemplateFactoryIRNode extends BaseIRNode {
|
||||
|
|
|
@ -42,9 +42,9 @@ export type DirectiveTransform = (
|
|||
// A structural directive transform is technically also a NodeTransform;
|
||||
// Only v-if and v-for fall into this category.
|
||||
export type StructuralDirectiveTransform = (
|
||||
node: RootNode | TemplateChildNode,
|
||||
node: ElementNode,
|
||||
dir: VaporDirectiveNode,
|
||||
context: TransformContext<RootNode | TemplateChildNode>,
|
||||
context: TransformContext<ElementNode>,
|
||||
) => void | (() => void)
|
||||
|
||||
export type TransformOptions = HackOptions<BaseTransformOptions>
|
||||
|
@ -60,7 +60,7 @@ export interface TransformContext<T extends AllNode = AllNode> {
|
|||
>
|
||||
|
||||
template: string
|
||||
childrenTemplate: string[]
|
||||
childrenTemplate: (string | null)[]
|
||||
dynamic: IRDynamicInfo
|
||||
|
||||
inVOnce: boolean
|
||||
|
@ -311,15 +311,12 @@ function transformNode(
|
|||
}
|
||||
|
||||
if (context.node.type === NodeTypes.ROOT)
|
||||
context.template += context.childrenTemplate.join('')
|
||||
context.template += context.childrenTemplate.filter(Boolean).join('')
|
||||
}
|
||||
|
||||
function transformChildren(ctx: TransformContext<RootNode | ElementNode>) {
|
||||
const { children } = ctx.node
|
||||
let i = 0
|
||||
// const nodeRemoved = () => {
|
||||
// i--
|
||||
// }
|
||||
for (; i < children.length; i++) {
|
||||
const child = children[i]
|
||||
const childContext = createContext(child, ctx, i)
|
||||
|
@ -405,7 +402,11 @@ export function createStructuralDirectiveTransform(
|
|||
const exitFns = []
|
||||
for (const prop of props) {
|
||||
if (prop.type === NodeTypes.DIRECTIVE && matches(prop.name)) {
|
||||
const onExit = fn(node, prop as VaporDirectiveNode, context)
|
||||
const onExit = fn(
|
||||
node,
|
||||
prop as VaporDirectiveNode,
|
||||
context as TransformContext<ElementNode>,
|
||||
)
|
||||
if (onExit) exitFns.push(onExit)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import {
|
||||
type ElementNode,
|
||||
ElementTypes,
|
||||
ErrorCodes,
|
||||
NodeTypes,
|
||||
|
@ -15,6 +16,7 @@ import {
|
|||
import {
|
||||
type BlockFunctionIRNode,
|
||||
IRNodeTypes,
|
||||
type OperationNode,
|
||||
type VaporDirectiveNode,
|
||||
} from '../ir'
|
||||
import { extend } from '@vue/shared'
|
||||
|
@ -25,7 +27,7 @@ export const transformVIf = createStructuralDirectiveTransform(
|
|||
)
|
||||
|
||||
export function processIf(
|
||||
node: RootNode | TemplateChildNode,
|
||||
node: ElementNode,
|
||||
dir: VaporDirectiveNode,
|
||||
context: TransformContext<RootNode | TemplateChildNode>,
|
||||
) {
|
||||
|
@ -40,7 +42,7 @@ export function processIf(
|
|||
if (dir.name === 'if') {
|
||||
const id = context.reference()
|
||||
context.dynamic.ghost = true
|
||||
const [branch, onExit] = createIfBranch(node, dir, context)
|
||||
const [branch, onExit] = createIfBranch(node, context)
|
||||
|
||||
return () => {
|
||||
onExit()
|
||||
|
@ -52,37 +54,100 @@ export function processIf(
|
|||
positive: branch,
|
||||
})
|
||||
}
|
||||
} else {
|
||||
// check the adjacent v-if
|
||||
const parent = context.parent!
|
||||
const siblings = parent.node.children
|
||||
const templates = parent.childrenTemplate
|
||||
|
||||
const comments = []
|
||||
let sibling: TemplateChildNode | undefined
|
||||
let i = siblings.indexOf(node)
|
||||
while (i-- >= -1) {
|
||||
sibling = siblings[i]
|
||||
|
||||
if (sibling) {
|
||||
if (sibling.type === NodeTypes.COMMENT) {
|
||||
__DEV__ && comments.unshift(sibling)
|
||||
templates[i] = null
|
||||
continue
|
||||
} else if (
|
||||
sibling.type === NodeTypes.TEXT &&
|
||||
!sibling.content.trim().length
|
||||
) {
|
||||
templates[i] = null
|
||||
continue
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
const { operation } = context.block
|
||||
let lastIfNode: OperationNode
|
||||
if (
|
||||
// check if v-if is the sibling node
|
||||
!sibling ||
|
||||
sibling.type !== NodeTypes.ELEMENT ||
|
||||
!sibling.props.some(
|
||||
({ type, name }) =>
|
||||
type === NodeTypes.DIRECTIVE && ['if', 'else-if'].includes(name),
|
||||
) ||
|
||||
// check if IFNode is the last operation and get the root IFNode
|
||||
!(lastIfNode = operation[operation.length - 1]) ||
|
||||
lastIfNode.type !== IRNodeTypes.IF
|
||||
) {
|
||||
context.options.onError(
|
||||
createCompilerError(ErrorCodes.X_V_ELSE_NO_ADJACENT_IF, node.loc),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
while (lastIfNode.negative && lastIfNode.negative.type === IRNodeTypes.IF) {
|
||||
lastIfNode = lastIfNode.negative
|
||||
}
|
||||
|
||||
// Check if v-else was followed by v-else-if
|
||||
if (dir.name === 'else-if' && lastIfNode.negative) {
|
||||
context.options.onError(
|
||||
createCompilerError(ErrorCodes.X_V_ELSE_NO_ADJACENT_IF, node.loc),
|
||||
)
|
||||
}
|
||||
|
||||
// TODO ignore comments if the v-if is direct child of <transition> (PR #3622)
|
||||
if (__DEV__ && comments.length) {
|
||||
node = wrapTemplate(node)
|
||||
context.node = node = extend({}, node, {
|
||||
children: [...comments, ...node.children],
|
||||
})
|
||||
}
|
||||
|
||||
const [branch, onExit] = createIfBranch(node, context)
|
||||
|
||||
if (dir.name === 'else') {
|
||||
lastIfNode.negative = branch
|
||||
} else {
|
||||
lastIfNode.negative = {
|
||||
type: IRNodeTypes.IF,
|
||||
id: -1,
|
||||
loc: dir.loc,
|
||||
condition: dir.exp!,
|
||||
positive: branch,
|
||||
}
|
||||
}
|
||||
|
||||
return () => onExit()
|
||||
}
|
||||
}
|
||||
|
||||
export function createIfBranch(
|
||||
node: RootNode | TemplateChildNode,
|
||||
dir: VaporDirectiveNode,
|
||||
node: ElementNode,
|
||||
context: TransformContext<RootNode | TemplateChildNode>,
|
||||
): [BlockFunctionIRNode, () => void] {
|
||||
if (
|
||||
node.type === NodeTypes.ELEMENT &&
|
||||
node.tagType !== ElementTypes.TEMPLATE
|
||||
) {
|
||||
node = extend({}, node, {
|
||||
type: NodeTypes.ELEMENT,
|
||||
tag: 'template',
|
||||
props: [],
|
||||
tagType: ElementTypes.TEMPLATE,
|
||||
children: [
|
||||
extend({}, node, {
|
||||
props: node.props.filter(
|
||||
p => p.type !== NodeTypes.DIRECTIVE && p.name !== 'if',
|
||||
),
|
||||
} as TemplateChildNode),
|
||||
],
|
||||
} as Partial<TemplateNode>)
|
||||
context.node = node
|
||||
}
|
||||
context.node = node = wrapTemplate(node)
|
||||
|
||||
const branch: BlockFunctionIRNode = {
|
||||
type: IRNodeTypes.BLOCK_FUNCTION,
|
||||
loc: dir.loc,
|
||||
loc: node.loc,
|
||||
node,
|
||||
templateIndex: -1,
|
||||
dynamic: {
|
||||
|
@ -105,3 +170,22 @@ export function createIfBranch(
|
|||
}
|
||||
return [branch, onExit]
|
||||
}
|
||||
|
||||
function wrapTemplate(node: ElementNode): TemplateNode {
|
||||
if (node.tagType === ElementTypes.TEMPLATE) {
|
||||
return node
|
||||
}
|
||||
return extend({}, node, {
|
||||
type: NodeTypes.ELEMENT,
|
||||
tag: 'template',
|
||||
props: [],
|
||||
tagType: ElementTypes.TEMPLATE,
|
||||
children: [
|
||||
extend({}, node, {
|
||||
props: node.props.filter(
|
||||
p => p.type !== NodeTypes.DIRECTIVE && p.name !== 'if',
|
||||
),
|
||||
} as TemplateChildNode),
|
||||
],
|
||||
} as Partial<TemplateNode>)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue