refactor(compiler): refine codegen node types
This commit is contained in:
parent
bfecf2cdce
commit
82bd9eb1db
@ -1,5 +1,17 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`compiler: codegen ArrayExpression 1`] = `
|
||||
"
|
||||
return function render() {
|
||||
with (this) {
|
||||
return [
|
||||
foo,
|
||||
bar(baz)
|
||||
]
|
||||
}
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`compiler: codegen ConditionalExpression 1`] = `
|
||||
"
|
||||
return function render() {
|
||||
@ -13,7 +25,7 @@ return function render() {
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`compiler: codegen Element (callExpression + objectExpression + arrayExpression) 1`] = `
|
||||
exports[`compiler: codegen Element (callExpression + objectExpression + TemplateChildNode[]) 1`] = `
|
||||
"
|
||||
return function render() {
|
||||
with (this) {
|
||||
@ -23,10 +35,7 @@ return function render() {
|
||||
[foo + bar]: bar
|
||||
}, [
|
||||
_createVNode(\\"p\\", { \\"some-key\\": \\"foo\\" })
|
||||
], [
|
||||
foo,
|
||||
_createVNode(\\"p\\")
|
||||
])
|
||||
], 16)
|
||||
}
|
||||
}"
|
||||
`;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -11,7 +11,9 @@ import {
|
||||
createInterpolation,
|
||||
createSequenceExpression,
|
||||
createCallExpression,
|
||||
createConditionalExpression
|
||||
createConditionalExpression,
|
||||
IfCodegenNode,
|
||||
ForCodegenNode
|
||||
} from '../src'
|
||||
import {
|
||||
CREATE_VNODE,
|
||||
@ -22,6 +24,7 @@ import {
|
||||
RESOLVE_COMPONENT
|
||||
} from '../src/runtimeHelpers'
|
||||
import { createElementWithCodegen } from './testUtils'
|
||||
import { PatchFlags } from 'vue'
|
||||
|
||||
function createRoot(options: Partial<RootNode> = {}): RootNode {
|
||||
return {
|
||||
@ -205,7 +208,7 @@ describe('compiler: codegen', () => {
|
||||
codegenNode: createSequenceExpression([
|
||||
createSimpleExpression('foo', false),
|
||||
createSimpleExpression('bar', false)
|
||||
])
|
||||
]) as IfCodegenNode
|
||||
}
|
||||
})
|
||||
)
|
||||
@ -227,7 +230,7 @@ describe('compiler: codegen', () => {
|
||||
codegenNode: createSequenceExpression([
|
||||
createSimpleExpression('foo', false),
|
||||
createSimpleExpression('bar', false)
|
||||
])
|
||||
]) as ForCodegenNode
|
||||
}
|
||||
})
|
||||
)
|
||||
@ -235,7 +238,7 @@ describe('compiler: codegen', () => {
|
||||
expect(code).toMatchSnapshot()
|
||||
})
|
||||
|
||||
test('Element (callExpression + objectExpression + arrayExpression)', () => {
|
||||
test('Element (callExpression + objectExpression + TemplateChildNode[])', () => {
|
||||
const { code } = generate(
|
||||
createRoot({
|
||||
codegenNode: createElementWithCodegen([
|
||||
@ -283,19 +286,8 @@ describe('compiler: codegen', () => {
|
||||
)
|
||||
])
|
||||
],
|
||||
// ArrayExpression
|
||||
createArrayExpression(
|
||||
[
|
||||
'foo',
|
||||
{
|
||||
type: NodeTypes.JS_CALL_EXPRESSION,
|
||||
loc: locStub,
|
||||
callee: CREATE_VNODE,
|
||||
arguments: [`"p"`]
|
||||
}
|
||||
],
|
||||
locStub
|
||||
)
|
||||
// flag
|
||||
PatchFlags.FULL_PROPS + ''
|
||||
])
|
||||
})
|
||||
)
|
||||
@ -306,10 +298,23 @@ describe('compiler: codegen', () => {
|
||||
[foo + bar]: bar
|
||||
}, [
|
||||
_${helperNameMap[CREATE_VNODE]}("p", { "some-key": "foo" })
|
||||
], [
|
||||
], ${PatchFlags.FULL_PROPS})`)
|
||||
expect(code).toMatchSnapshot()
|
||||
})
|
||||
|
||||
test('ArrayExpression', () => {
|
||||
const { code } = generate(
|
||||
createRoot({
|
||||
codegenNode: createArrayExpression([
|
||||
createSimpleExpression(`foo`, false),
|
||||
createCallExpression(`bar`, [`baz`])
|
||||
])
|
||||
})
|
||||
)
|
||||
expect(code).toMatch(`return [
|
||||
foo,
|
||||
_${helperNameMap[CREATE_VNODE]}("p")
|
||||
])`)
|
||||
bar(baz)
|
||||
]`)
|
||||
expect(code).toMatchSnapshot()
|
||||
})
|
||||
|
||||
|
@ -1,10 +1,10 @@
|
||||
import {
|
||||
NodeTypes,
|
||||
CallExpression,
|
||||
ElementNode,
|
||||
locStub,
|
||||
Namespaces,
|
||||
ElementTypes
|
||||
ElementTypes,
|
||||
ElementCodegenNode
|
||||
} from '../src'
|
||||
import { CREATE_VNODE } from '../src/runtimeHelpers'
|
||||
import { isString } from '@vue/shared'
|
||||
@ -39,7 +39,7 @@ export function createObjectMatcher(obj: any) {
|
||||
}
|
||||
|
||||
export function createElementWithCodegen(
|
||||
args: CallExpression['arguments']
|
||||
args: ElementCodegenNode['arguments']
|
||||
): ElementNode {
|
||||
return {
|
||||
type: NodeTypes.ELEMENT,
|
||||
|
@ -1,6 +1,17 @@
|
||||
import { isString } from '@vue/shared'
|
||||
import { ForParseResult } from './transforms/vFor'
|
||||
import { CREATE_VNODE, RuntimeHelper } from './runtimeHelpers'
|
||||
import {
|
||||
CREATE_VNODE,
|
||||
RuntimeHelper,
|
||||
APPLY_DIRECTIVES,
|
||||
RENDER_SLOT,
|
||||
CREATE_SLOTS,
|
||||
RENDER_LIST,
|
||||
OPEN_BLOCK,
|
||||
CREATE_BLOCK,
|
||||
FRAGMENT
|
||||
} from './runtimeHelpers'
|
||||
import { PropsExpression } from './transforms/transformElement'
|
||||
|
||||
// Vue template is a platform-agnostic superset of HTML (syntax only).
|
||||
// More namespaces like SVG and MathML are declared by platform specific
|
||||
@ -84,7 +95,13 @@ export interface RootNode extends Node {
|
||||
codegenNode: TemplateChildNode | JSChildNode | undefined
|
||||
}
|
||||
|
||||
export interface ElementNode extends Node {
|
||||
export type ElementNode =
|
||||
| PlainElementNode
|
||||
| ComponentNode
|
||||
| SlotOutletNode
|
||||
| TemplateNode
|
||||
|
||||
export interface BaseElementNode extends Node {
|
||||
type: NodeTypes.ELEMENT
|
||||
ns: Namespace
|
||||
tag: string
|
||||
@ -95,29 +112,32 @@ export interface ElementNode extends Node {
|
||||
codegenNode: CallExpression | SimpleExpressionNode | undefined
|
||||
}
|
||||
|
||||
export interface PlainElementNode extends ElementNode {
|
||||
export interface PlainElementNode extends BaseElementNode {
|
||||
tagType: ElementTypes.ELEMENT
|
||||
codegenNode: VNodeCodegenNode | VNodeWithDirectiveCodegenNode
|
||||
codegenNode:
|
||||
| ElementCodegenNode
|
||||
| CodegenNodeWithDirective<ElementCodegenNode>
|
||||
| undefined
|
||||
// | SimpleExpressionNode (only when hoisted)
|
||||
}
|
||||
|
||||
export interface ComponentNode extends ElementNode {
|
||||
export interface ComponentNode extends BaseElementNode {
|
||||
tagType: ElementTypes.COMPONENT
|
||||
codegenNode: VNodeCodegenNode | VNodeWithDirectiveCodegenNode
|
||||
codegenNode:
|
||||
| ComponentCodegenNode
|
||||
| CodegenNodeWithDirective<ComponentCodegenNode>
|
||||
| undefined
|
||||
}
|
||||
|
||||
export interface SlotOutletNode extends ElementNode {
|
||||
export interface SlotOutletNode extends BaseElementNode {
|
||||
tagType: ElementTypes.SLOT
|
||||
codegenNode: SlotOutletCodegenNode
|
||||
codegenNode: SlotOutletCodegenNode | undefined
|
||||
}
|
||||
|
||||
export interface VNodeCodegenNode extends CallExpression {
|
||||
callee: typeof CREATE_VNODE
|
||||
export interface TemplateNode extends BaseElementNode {
|
||||
tagType: ElementTypes.TEMPLATE
|
||||
}
|
||||
|
||||
export interface VNodeWithDirectiveCodegenNode extends CallExpression {}
|
||||
|
||||
export interface SlotOutletCodegenNode extends CallExpression {}
|
||||
|
||||
export interface TextNode extends Node {
|
||||
type: NodeTypes.TEXT
|
||||
content: string
|
||||
@ -179,8 +199,6 @@ export interface IfNode extends Node {
|
||||
codegenNode: IfCodegenNode
|
||||
}
|
||||
|
||||
export interface IfCodegenNode extends SequenceExpression {}
|
||||
|
||||
export interface IfBranchNode extends Node {
|
||||
type: NodeTypes.IF_BRANCH
|
||||
condition: ExpressionNode | undefined // else
|
||||
@ -197,8 +215,6 @@ export interface ForNode extends Node {
|
||||
codegenNode: ForCodegenNode
|
||||
}
|
||||
|
||||
export interface ForCodegenNode extends SequenceExpression {}
|
||||
|
||||
// We also include a number of JavaScript AST nodes for code generation.
|
||||
// The AST is an intentionally minimal subset just to meet the exact needs of
|
||||
// Vue render function generation.
|
||||
@ -257,6 +273,204 @@ export interface ConditionalExpression extends Node {
|
||||
alternate: JSChildNode
|
||||
}
|
||||
|
||||
// Codegen Node Types ----------------------------------------------------------
|
||||
|
||||
// createVNode(...)
|
||||
export interface ElementCodegenNode extends CallExpression {
|
||||
callee: typeof CREATE_VNODE
|
||||
arguments: // tag, props, children, patchFlag, dynamicProps
|
||||
|
||||
| [string | RuntimeHelper]
|
||||
| [string | RuntimeHelper, PropsExpression]
|
||||
| [string | RuntimeHelper, 'null' | PropsExpression, TemplateChildNode[]]
|
||||
| [
|
||||
string | RuntimeHelper,
|
||||
'null' | PropsExpression,
|
||||
'null' | TemplateChildNode[],
|
||||
string
|
||||
]
|
||||
| [
|
||||
string | RuntimeHelper,
|
||||
'null' | PropsExpression,
|
||||
'null' | TemplateChildNode[],
|
||||
string,
|
||||
string
|
||||
]
|
||||
}
|
||||
|
||||
export type ElementCodegenNodeWithDirective = CodegenNodeWithDirective<
|
||||
ElementCodegenNode
|
||||
>
|
||||
|
||||
// createVNode(...)
|
||||
export interface ComponentCodegenNode extends CallExpression {
|
||||
callee: typeof CREATE_VNODE
|
||||
arguments: // Comp, props, slots, patchFlag, dynamicProps
|
||||
|
||||
| [string | RuntimeHelper]
|
||||
| [string | RuntimeHelper, PropsExpression]
|
||||
| [string | RuntimeHelper, 'null' | PropsExpression, SlotsExpression]
|
||||
| [
|
||||
string | RuntimeHelper,
|
||||
'null' | PropsExpression,
|
||||
'null' | SlotsExpression,
|
||||
string
|
||||
]
|
||||
| [
|
||||
string | RuntimeHelper,
|
||||
'null' | PropsExpression,
|
||||
'null' | SlotsExpression,
|
||||
string,
|
||||
string
|
||||
]
|
||||
}
|
||||
|
||||
export type CompoenntCodegenNodeWithDirective = CodegenNodeWithDirective<
|
||||
ComponentCodegenNode
|
||||
>
|
||||
|
||||
export type SlotsExpression = SlotsObjectExpression | DynamicSlotsExpression
|
||||
|
||||
// { foo: () => [...] }
|
||||
export interface SlotsObjectExpression extends ObjectExpression {
|
||||
properties: SlotsObjectProperty[]
|
||||
}
|
||||
|
||||
export interface SlotsObjectProperty extends Property {
|
||||
value: SlotFunctionExpression
|
||||
}
|
||||
|
||||
export interface SlotFunctionExpression extends FunctionExpression {
|
||||
returns: TemplateChildNode[]
|
||||
}
|
||||
|
||||
// createSlots({ ... }, [
|
||||
// foo ? () => [] : undefined,
|
||||
// renderList(list, i => () => [i])
|
||||
// ])
|
||||
export interface DynamicSlotsExpression extends CallExpression {
|
||||
callee: typeof CREATE_SLOTS
|
||||
arguments: [SlotsObjectExpression, DynamicSlotEntries]
|
||||
}
|
||||
|
||||
export interface DynamicSlotEntries extends ArrayExpression {
|
||||
elements: (ConditionalDynamicSlotNode | ListDyanmicSlotNode)[]
|
||||
}
|
||||
|
||||
export interface ConditionalDynamicSlotNode extends ConditionalExpression {
|
||||
consequent: DynamicSlotNode
|
||||
alternate: DynamicSlotNode | SimpleExpressionNode
|
||||
}
|
||||
|
||||
export interface ListDyanmicSlotNode extends CallExpression {
|
||||
callee: typeof RENDER_LIST
|
||||
arguments: [ExpressionNode, ListDyanmicSlotIterator]
|
||||
}
|
||||
|
||||
export interface ListDyanmicSlotIterator extends FunctionExpression {
|
||||
returns: DynamicSlotNode
|
||||
}
|
||||
|
||||
export interface DynamicSlotNode extends ObjectExpression {
|
||||
properties: [Property, DynamicSlotFnProperty]
|
||||
}
|
||||
|
||||
export interface DynamicSlotFnProperty extends Property {
|
||||
value: SlotFunctionExpression
|
||||
}
|
||||
|
||||
// applyDirectives(createVNode(...), [
|
||||
// [_directive_foo, someValue],
|
||||
// [_directive_bar, someValue, "arg", { mod: true }]
|
||||
// ])
|
||||
export interface CodegenNodeWithDirective<T extends CallExpression>
|
||||
extends CallExpression {
|
||||
callee: typeof APPLY_DIRECTIVES
|
||||
arguments: [T, DirectiveArguments]
|
||||
}
|
||||
|
||||
export interface DirectiveArguments extends ArrayExpression {
|
||||
elements: DirectiveArgumentNode[]
|
||||
}
|
||||
|
||||
export interface DirectiveArgumentNode extends ArrayExpression {
|
||||
elements: // dir, exp, arg, modifiers
|
||||
|
||||
| [string]
|
||||
| [string, ExpressionNode]
|
||||
| [string, ExpressionNode, ExpressionNode]
|
||||
| [string, ExpressionNode, ExpressionNode, ObjectExpression]
|
||||
}
|
||||
|
||||
// renderSlot(...)
|
||||
export interface SlotOutletCodegenNode extends CallExpression {
|
||||
callee: typeof RENDER_SLOT
|
||||
arguments: // $slots, name, props, fallback
|
||||
|
||||
| [string, string | ExpressionNode]
|
||||
| [string, string | ExpressionNode, PropsExpression]
|
||||
| [
|
||||
string,
|
||||
string | ExpressionNode,
|
||||
PropsExpression | '{}',
|
||||
TemplateChildNode[]
|
||||
]
|
||||
}
|
||||
|
||||
export interface IfCodegenNode extends SequenceExpression {
|
||||
expressions: [OpenBlockExpression, IfConditionalExpression]
|
||||
}
|
||||
|
||||
export interface IfConditionalExpression extends ConditionalExpression {
|
||||
consequent: BlockCodegenNode
|
||||
alternate: BlockCodegenNode | IfConditionalExpression
|
||||
}
|
||||
|
||||
export interface ForCodegenNode extends SequenceExpression {
|
||||
expressions: [OpenBlockExpression, ForBlockCodegenNode]
|
||||
}
|
||||
|
||||
export interface ForBlockCodegenNode extends CallExpression {
|
||||
callee: typeof CREATE_BLOCK
|
||||
arguments: [typeof FRAGMENT, 'null', ForRenderListExpression, string]
|
||||
}
|
||||
|
||||
export interface ForRenderListExpression extends CallExpression {
|
||||
callee: typeof RENDER_LIST
|
||||
arguments: [ExpressionNode, ForIteratorExpression]
|
||||
}
|
||||
|
||||
export interface ForIteratorExpression extends FunctionExpression {
|
||||
returns: BlockCodegenNode
|
||||
}
|
||||
|
||||
export interface OpenBlockExpression extends CallExpression {
|
||||
callee: typeof OPEN_BLOCK
|
||||
arguments: []
|
||||
}
|
||||
|
||||
export type BlockCodegenNode =
|
||||
| BlockElementCodegenNode
|
||||
| BlockComponentCodegenNode
|
||||
| BlockElementCodegenNodeWithDirective
|
||||
| BlockComponentCodegenNodeWithDirective
|
||||
|
||||
export type BlockElementCodegenNode = ElementCodegenNode & {
|
||||
callee: typeof CREATE_BLOCK
|
||||
}
|
||||
|
||||
export type BlockComponentCodegenNode = ComponentCodegenNode & {
|
||||
callee: typeof CREATE_BLOCK
|
||||
}
|
||||
|
||||
export type BlockElementCodegenNodeWithDirective = CodegenNodeWithDirective<
|
||||
BlockElementCodegenNode
|
||||
>
|
||||
|
||||
export type BlockComponentCodegenNodeWithDirective = CodegenNodeWithDirective<
|
||||
BlockComponentCodegenNode
|
||||
>
|
||||
|
||||
// AST Utilities ---------------------------------------------------------------
|
||||
|
||||
// Some expressions, e.g. sequence and conditional expressions, are never
|
||||
@ -338,17 +552,25 @@ export function createCompoundExpression(
|
||||
}
|
||||
}
|
||||
|
||||
export function createCallExpression(
|
||||
callee: CallExpression['callee'],
|
||||
type InferCodegenNodeType<T> = T extends typeof CREATE_VNODE
|
||||
? ElementCodegenNode | ComponentCodegenNode
|
||||
: T extends typeof CREATE_BLOCK
|
||||
? BlockElementCodegenNode | BlockComponentCodegenNode
|
||||
: T extends typeof APPLY_DIRECTIVES
|
||||
? CodegenNodeWithDirective<ElementCodegenNode | ComponentCodegenNode>
|
||||
: T extends typeof RENDER_SLOT ? SlotOutletCodegenNode : CallExpression
|
||||
|
||||
export function createCallExpression<T extends CallExpression['callee']>(
|
||||
callee: T,
|
||||
args: CallExpression['arguments'] = [],
|
||||
loc: SourceLocation = locStub
|
||||
): CallExpression {
|
||||
): InferCodegenNodeType<T> {
|
||||
return {
|
||||
type: NodeTypes.JS_CALL_EXPRESSION,
|
||||
loc,
|
||||
callee,
|
||||
arguments: args
|
||||
}
|
||||
} as any
|
||||
}
|
||||
|
||||
export function createFunctionExpression(
|
||||
|
@ -83,8 +83,9 @@ export function parse(content: string, options: ParserOptions = {}): RootNode {
|
||||
return {
|
||||
type: NodeTypes.ROOT,
|
||||
children: parseChildren(context, TextModes.DATA, []),
|
||||
imports: [],
|
||||
statements: [],
|
||||
helpers: [],
|
||||
components: [],
|
||||
directives: [],
|
||||
hoists: [],
|
||||
codegenNode: undefined,
|
||||
loc: getSelection(context, start)
|
||||
|
@ -2,13 +2,13 @@ import {
|
||||
RootNode,
|
||||
NodeTypes,
|
||||
TemplateChildNode,
|
||||
CallExpression,
|
||||
ElementNode,
|
||||
ElementTypes
|
||||
ElementTypes,
|
||||
ElementCodegenNode,
|
||||
ElementCodegenNodeWithDirective
|
||||
} from '../ast'
|
||||
import { TransformContext } from '../transform'
|
||||
import { APPLY_DIRECTIVES } from '../runtimeHelpers'
|
||||
import { PropsExpression } from './transformElement'
|
||||
import { PatchFlags } from '@vue/shared'
|
||||
|
||||
export function hoistStatic(root: RootNode, context: TransformContext) {
|
||||
@ -29,7 +29,7 @@ function walk(
|
||||
) {
|
||||
if (isStaticNode(child, resultCache)) {
|
||||
// whole tree is static
|
||||
child.codegenNode = context.hoist(child.codegenNode!)
|
||||
;(child as any).codegenNode = context.hoist(child.codegenNode!)
|
||||
continue
|
||||
} else {
|
||||
// node may contain dynamic children, but its props may be eligible for
|
||||
@ -40,18 +40,13 @@ function walk(
|
||||
flag === PatchFlags.NEED_PATCH ||
|
||||
flag === PatchFlags.TEXT
|
||||
) {
|
||||
let codegenNode = child.codegenNode as CallExpression
|
||||
let codegenNode = child.codegenNode!
|
||||
if (codegenNode.callee === APPLY_DIRECTIVES) {
|
||||
codegenNode = codegenNode.arguments[0] as CallExpression
|
||||
codegenNode = codegenNode.arguments[0]
|
||||
}
|
||||
const props = codegenNode.arguments[1] as
|
||||
| PropsExpression
|
||||
| `null`
|
||||
| undefined
|
||||
const props = codegenNode.arguments[1]
|
||||
if (props && props !== `null`) {
|
||||
;(child.codegenNode as CallExpression).arguments[1] = context.hoist(
|
||||
props
|
||||
)
|
||||
codegenNode.arguments[1] = context.hoist(props)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -67,9 +62,11 @@ function walk(
|
||||
}
|
||||
|
||||
function getPatchFlag(node: ElementNode): number | undefined {
|
||||
let codegenNode = node.codegenNode as CallExpression
|
||||
let codegenNode = node.codegenNode as
|
||||
| ElementCodegenNode
|
||||
| ElementCodegenNodeWithDirective
|
||||
if (codegenNode.callee === APPLY_DIRECTIVES) {
|
||||
codegenNode = codegenNode.arguments[0] as CallExpression
|
||||
codegenNode = codegenNode.arguments[0]
|
||||
}
|
||||
const flag = codegenNode.arguments[3]
|
||||
return flag ? parseInt(flag as string, 10) : undefined
|
||||
|
@ -14,7 +14,8 @@ import {
|
||||
ElementTypes,
|
||||
createObjectExpression,
|
||||
createObjectProperty,
|
||||
CallExpression
|
||||
ForCodegenNode,
|
||||
PlainElementNode
|
||||
} from '../ast'
|
||||
import { createCompilerError, ErrorCodes } from '../errors'
|
||||
import {
|
||||
@ -66,7 +67,7 @@ export const transformFor = createStructuralDirectiveTransform(
|
||||
fragmentFlag +
|
||||
(__DEV__ ? ` /* ${PatchFlagNames[fragmentFlag]} */` : ``)
|
||||
])
|
||||
])
|
||||
]) as ForCodegenNode
|
||||
|
||||
context.replaceNode({
|
||||
type: NodeTypes.FOR,
|
||||
@ -118,7 +119,7 @@ export const transformFor = createStructuralDirectiveTransform(
|
||||
: null
|
||||
if (slotOutlet) {
|
||||
// <slot v-for="..."> or <template v-for="..."><slot/></template>
|
||||
childBlock = slotOutlet.codegenNode as CallExpression
|
||||
childBlock = slotOutlet.codegenNode!
|
||||
if (isTemplate && keyProperty) {
|
||||
// <template v-for="..." :key="..."><slot/></template>
|
||||
// we need to inject the key to the renderSlot() call.
|
||||
@ -148,7 +149,7 @@ export const transformFor = createStructuralDirectiveTransform(
|
||||
// Normal element v-for. Directly use the child's codegenNode
|
||||
// arguments, but replace createVNode() with createBlock()
|
||||
childBlock = createBlockExpression(
|
||||
(node.codegenNode as CallExpression).arguments,
|
||||
(node as PlainElementNode).codegenNode!.arguments,
|
||||
context
|
||||
)
|
||||
}
|
||||
|
@ -17,7 +17,15 @@ import {
|
||||
CallExpression,
|
||||
createSimpleExpression,
|
||||
createObjectProperty,
|
||||
createObjectExpression
|
||||
createObjectExpression,
|
||||
IfCodegenNode,
|
||||
IfConditionalExpression,
|
||||
BlockCodegenNode,
|
||||
SlotOutletCodegenNode,
|
||||
ElementCodegenNode,
|
||||
ComponentCodegenNode,
|
||||
ElementCodegenNodeWithDirective,
|
||||
CompoenntCodegenNodeWithDirective
|
||||
} from '../ast'
|
||||
import { createCompilerError, ErrorCodes } from '../errors'
|
||||
import { processExpression } from './transformExpression'
|
||||
@ -31,7 +39,6 @@ import {
|
||||
RENDER_SLOT
|
||||
} from '../runtimeHelpers'
|
||||
import { injectProp } from '../utils'
|
||||
import { PropsExpression } from './transformElement'
|
||||
|
||||
export const transformIf = createStructuralDirectiveTransform(
|
||||
/^(if|else|else-if)$/,
|
||||
@ -57,7 +64,8 @@ export const transformIf = createStructuralDirectiveTransform(
|
||||
const branch = createIfBranch(node, dir)
|
||||
const codegenNode = createSequenceExpression([
|
||||
createCallExpression(context.helper(OPEN_BLOCK))
|
||||
])
|
||||
]) as IfCodegenNode
|
||||
|
||||
context.replaceNode({
|
||||
type: NodeTypes.IF,
|
||||
loc: node.loc,
|
||||
@ -68,9 +76,11 @@ export const transformIf = createStructuralDirectiveTransform(
|
||||
// Exit callback. Complete the codegenNode when all children have been
|
||||
// transformed.
|
||||
return () => {
|
||||
codegenNode.expressions.push(
|
||||
createCodegenNodeForBranch(branch, 0, context)
|
||||
)
|
||||
codegenNode.expressions.push(createCodegenNodeForBranch(
|
||||
branch,
|
||||
0,
|
||||
context
|
||||
) as IfConditionalExpression)
|
||||
}
|
||||
} else {
|
||||
// locate the adjacent v-if
|
||||
@ -137,7 +147,7 @@ function createCodegenNodeForBranch(
|
||||
branch: IfBranchNode,
|
||||
index: number,
|
||||
context: TransformContext
|
||||
): ConditionalExpression | CallExpression {
|
||||
): IfConditionalExpression | BlockCodegenNode {
|
||||
if (branch.condition) {
|
||||
return createConditionalExpression(
|
||||
branch.condition,
|
||||
@ -145,9 +155,9 @@ function createCodegenNodeForBranch(
|
||||
createCallExpression(context.helper(CREATE_BLOCK), [
|
||||
context.helper(EMPTY)
|
||||
])
|
||||
)
|
||||
) as IfConditionalExpression
|
||||
} else {
|
||||
return createChildrenCodegenNode(branch, index, context)
|
||||
return createChildrenCodegenNode(branch, index, context) as BlockCodegenNode
|
||||
}
|
||||
}
|
||||
|
||||
@ -173,23 +183,27 @@ function createChildrenCodegenNode(
|
||||
]
|
||||
if (children.length === 1 && child.type === NodeTypes.FOR) {
|
||||
// optimize away nested fragments when child is a ForNode
|
||||
const forBlockArgs = (child.codegenNode.expressions[1] as CallExpression)
|
||||
.arguments
|
||||
const forBlockArgs = child.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 CallExpression
|
||||
const childCodegen = (child as ElementNode).codegenNode as
|
||||
| ElementCodegenNode
|
||||
| ComponentCodegenNode
|
||||
| ElementCodegenNodeWithDirective
|
||||
| CompoenntCodegenNodeWithDirective
|
||||
| SlotOutletCodegenNode
|
||||
let vnodeCall = childCodegen
|
||||
// Element with custom directives. Locate the actual createVNode() call.
|
||||
if (vnodeCall.callee === APPLY_DIRECTIVES) {
|
||||
vnodeCall = vnodeCall.arguments[0] as CallExpression
|
||||
vnodeCall = vnodeCall.arguments[0]
|
||||
}
|
||||
// Change createVNode to createBlock.
|
||||
if (vnodeCall.callee === CREATE_VNODE) {
|
||||
vnodeCall.callee = helper(CREATE_BLOCK)
|
||||
;(vnodeCall as any).callee = helper(CREATE_BLOCK)
|
||||
}
|
||||
// It's possible to have renderSlot() here as well - which already produces
|
||||
// a block, so no need to change the callee. However it accepts props at
|
||||
@ -197,10 +211,9 @@ function createChildrenCodegenNode(
|
||||
// logic below works for it too.
|
||||
const propsIndex = vnodeCall.callee === RENDER_SLOT ? 2 : 1
|
||||
// inject branch key
|
||||
const existingProps = vnodeCall.arguments[propsIndex] as
|
||||
| PropsExpression
|
||||
| undefined
|
||||
| 'null'
|
||||
const existingProps = vnodeCall.arguments[
|
||||
propsIndex
|
||||
] as ElementCodegenNode['arguments'][1]
|
||||
vnodeCall.arguments[propsIndex] = injectProp(
|
||||
existingProps,
|
||||
keyProperty,
|
||||
|
@ -14,7 +14,9 @@ import {
|
||||
ObjectExpression,
|
||||
Property,
|
||||
JSChildNode,
|
||||
createObjectExpression
|
||||
createObjectExpression,
|
||||
SlotOutletNode,
|
||||
TemplateNode
|
||||
} from './ast'
|
||||
import { parse } from 'acorn'
|
||||
import { walk } from 'estree-walker'
|
||||
@ -180,12 +182,12 @@ export const isVSlot = (p: ElementNode['props'][0]): p is DirectiveNode =>
|
||||
|
||||
export const isTemplateNode = (
|
||||
node: RootNode | TemplateChildNode
|
||||
): node is ElementNode & { tagType: ElementTypes.TEMPLATE } =>
|
||||
): node is TemplateNode =>
|
||||
node.type === NodeTypes.ELEMENT && node.tagType === ElementTypes.TEMPLATE
|
||||
|
||||
export const isSlotOutlet = (
|
||||
node: RootNode | TemplateChildNode
|
||||
): node is ElementNode & { tagType: ElementTypes.ELEMENT } =>
|
||||
): node is SlotOutletNode =>
|
||||
node.type === NodeTypes.ELEMENT && node.tagType === ElementTypes.SLOT
|
||||
|
||||
export function injectProp(
|
||||
|
Loading…
Reference in New Issue
Block a user