feat(compiler): v-for codegen w/ correct blocks optimization + key flags
This commit is contained in:
parent
07955e6c96
commit
a477594d65
@ -15,11 +15,11 @@ return function render() {
|
|||||||
(_openBlock(), ok
|
(_openBlock(), ok
|
||||||
? _createBlock(\\"div\\", { key: 0 }, \\"yes\\")
|
? _createBlock(\\"div\\", { key: 0 }, \\"yes\\")
|
||||||
: _createBlock(_Fragment, { key: 1 }, \\"no\\")),
|
: _createBlock(_Fragment, { key: 1 }, \\"no\\")),
|
||||||
(_openBlock(), _createBlock(_Fragment, null, _renderList(list, (value, index) => {
|
_createVNode(_Fragment, null, _renderList(list, (value, index) => {
|
||||||
return _createVNode(\\"div\\", null, [
|
return (_openBlock(), _createBlock(\\"div\\", null, [
|
||||||
_createVNode(\\"span\\", null, _toString(value + index))
|
_createVNode(\\"span\\", null, _toString(value + index))
|
||||||
])
|
]))
|
||||||
})))
|
}), 128 /* UNKEYED_FRAGMENT */)
|
||||||
], 2 /* CLASS */)
|
], 2 /* CLASS */)
|
||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
@ -38,11 +38,11 @@ return function render() {
|
|||||||
(openBlock(), (_ctx.ok)
|
(openBlock(), (_ctx.ok)
|
||||||
? createBlock(\\"div\\", { key: 0 }, \\"yes\\")
|
? createBlock(\\"div\\", { key: 0 }, \\"yes\\")
|
||||||
: createBlock(Fragment, { key: 1 }, \\"no\\")),
|
: createBlock(Fragment, { key: 1 }, \\"no\\")),
|
||||||
(openBlock(), createBlock(Fragment, null, renderList(_ctx.list, (value, index) => {
|
createVNode(Fragment, null, renderList(_ctx.list, (value, index) => {
|
||||||
return createVNode(\\"div\\", null, [
|
return (openBlock(), createBlock(\\"div\\", null, [
|
||||||
createVNode(\\"span\\", null, toString(value + index))
|
createVNode(\\"span\\", null, toString(value + index))
|
||||||
])
|
]))
|
||||||
})))
|
}), 128 /* UNKEYED_FRAGMENT */)
|
||||||
], 2 /* CLASS */)
|
], 2 /* CLASS */)
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
@ -60,11 +60,11 @@ export default function render() {
|
|||||||
(openBlock(), (_ctx.ok)
|
(openBlock(), (_ctx.ok)
|
||||||
? createBlock(\\"div\\", { key: 0 }, \\"yes\\")
|
? createBlock(\\"div\\", { key: 0 }, \\"yes\\")
|
||||||
: createBlock(Fragment, { key: 1 }, \\"no\\")),
|
: createBlock(Fragment, { key: 1 }, \\"no\\")),
|
||||||
(openBlock(), createBlock(Fragment, null, renderList(_ctx.list, (value, index) => {
|
createVNode(Fragment, null, renderList(_ctx.list, (value, index) => {
|
||||||
return createVNode(\\"div\\", null, [
|
return (openBlock(), createBlock(\\"div\\", null, [
|
||||||
createVNode(\\"span\\", null, _toString(value + index))
|
createVNode(\\"span\\", null, _toString(value + index))
|
||||||
])
|
]))
|
||||||
})))
|
}), 128 /* UNKEYED_FRAGMENT */)
|
||||||
], 2 /* CLASS */)
|
], 2 /* CLASS */)
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
@ -5,11 +5,42 @@ exports[`compiler: v-for codegen basic v-for 1`] = `
|
|||||||
|
|
||||||
return function render() {
|
return function render() {
|
||||||
with (this) {
|
with (this) {
|
||||||
const { openBlock: _openBlock, createVNode: _createVNode, createBlock: _createBlock, Fragment: _Fragment, renderList: _renderList } = _Vue
|
const { renderList: _renderList, createVNode: _createVNode, Fragment: _Fragment, createBlock: _createBlock, openBlock: _openBlock } = _Vue
|
||||||
|
|
||||||
return (_openBlock(), _createBlock(_Fragment, null, _renderList(items, (item) => {
|
return _createVNode(_Fragment, null, _renderList(items, (item) => {
|
||||||
return _createVNode(\\"span\\")
|
return (_openBlock(), _createBlock(\\"span\\"))
|
||||||
})))
|
}), 128 /* UNKEYED_FRAGMENT */)
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`compiler: v-for codegen keyed template v-for 1`] = `
|
||||||
|
"const _Vue = Vue
|
||||||
|
|
||||||
|
return function render() {
|
||||||
|
with (this) {
|
||||||
|
const { renderList: _renderList, createVNode: _createVNode, Fragment: _Fragment, openBlock: _openBlock, createBlock: _createBlock } = _Vue
|
||||||
|
|
||||||
|
return _createVNode(_Fragment, null, _renderList(items, (item) => {
|
||||||
|
return (_openBlock(), _createBlock(_Fragment, { key: item }, [
|
||||||
|
\\"hello\\",
|
||||||
|
_createVNode(\\"span\\")
|
||||||
|
]))
|
||||||
|
}), 64 /* KEYED_FRAGMENT */)
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`compiler: v-for codegen keyed v-for 1`] = `
|
||||||
|
"const _Vue = Vue
|
||||||
|
|
||||||
|
return function render() {
|
||||||
|
with (this) {
|
||||||
|
const { renderList: _renderList, createVNode: _createVNode, Fragment: _Fragment, createBlock: _createBlock, openBlock: _openBlock } = _Vue
|
||||||
|
|
||||||
|
return _createVNode(_Fragment, null, _renderList(items, (item) => {
|
||||||
|
return (_openBlock(), _createBlock(\\"span\\", { key: item }))
|
||||||
|
}), 64 /* KEYED_FRAGMENT */)
|
||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
@ -19,11 +50,11 @@ exports[`compiler: v-for codegen skipped key 1`] = `
|
|||||||
|
|
||||||
return function render() {
|
return function render() {
|
||||||
with (this) {
|
with (this) {
|
||||||
const { openBlock: _openBlock, createVNode: _createVNode, createBlock: _createBlock, Fragment: _Fragment, renderList: _renderList } = _Vue
|
const { renderList: _renderList, createVNode: _createVNode, Fragment: _Fragment, createBlock: _createBlock, openBlock: _openBlock } = _Vue
|
||||||
|
|
||||||
return (_openBlock(), _createBlock(_Fragment, null, _renderList(items, (value, __, index) => {
|
return _createVNode(_Fragment, null, _renderList(items, (item, __, index) => {
|
||||||
return _createVNode(\\"span\\")
|
return (_openBlock(), _createBlock(\\"span\\"))
|
||||||
})))
|
}), 128 /* UNKEYED_FRAGMENT */)
|
||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
@ -33,11 +64,11 @@ exports[`compiler: v-for codegen skipped value & key 1`] = `
|
|||||||
|
|
||||||
return function render() {
|
return function render() {
|
||||||
with (this) {
|
with (this) {
|
||||||
const { openBlock: _openBlock, createVNode: _createVNode, createBlock: _createBlock, Fragment: _Fragment, renderList: _renderList } = _Vue
|
const { renderList: _renderList, createVNode: _createVNode, Fragment: _Fragment, createBlock: _createBlock, openBlock: _openBlock } = _Vue
|
||||||
|
|
||||||
return (_openBlock(), _createBlock(_Fragment, null, _renderList(items, (_, __, index) => {
|
return _createVNode(_Fragment, null, _renderList(items, (_, __, index) => {
|
||||||
return _createVNode(\\"span\\")
|
return (_openBlock(), _createBlock(\\"span\\"))
|
||||||
})))
|
}), 128 /* UNKEYED_FRAGMENT */)
|
||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
@ -47,11 +78,11 @@ exports[`compiler: v-for codegen skipped value 1`] = `
|
|||||||
|
|
||||||
return function render() {
|
return function render() {
|
||||||
with (this) {
|
with (this) {
|
||||||
const { openBlock: _openBlock, createVNode: _createVNode, createBlock: _createBlock, Fragment: _Fragment, renderList: _renderList } = _Vue
|
const { renderList: _renderList, createVNode: _createVNode, Fragment: _Fragment, createBlock: _createBlock, openBlock: _openBlock } = _Vue
|
||||||
|
|
||||||
return (_openBlock(), _createBlock(_Fragment, null, _renderList(items, (_, key, index) => {
|
return _createVNode(_Fragment, null, _renderList(items, (_, key, index) => {
|
||||||
return _createVNode(\\"span\\")
|
return (_openBlock(), _createBlock(\\"span\\"))
|
||||||
})))
|
}), 128 /* UNKEYED_FRAGMENT */)
|
||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
@ -61,14 +92,14 @@ exports[`compiler: v-for codegen template v-for 1`] = `
|
|||||||
|
|
||||||
return function render() {
|
return function render() {
|
||||||
with (this) {
|
with (this) {
|
||||||
const { openBlock: _openBlock, createVNode: _createVNode, createBlock: _createBlock, Fragment: _Fragment, renderList: _renderList } = _Vue
|
const { renderList: _renderList, createVNode: _createVNode, Fragment: _Fragment, openBlock: _openBlock, createBlock: _createBlock } = _Vue
|
||||||
|
|
||||||
return (_openBlock(), _createBlock(_Fragment, null, _renderList(items, (item) => {
|
return _createVNode(_Fragment, null, _renderList(items, (item) => {
|
||||||
return [
|
return (_openBlock(), _createBlock(_Fragment, null, [
|
||||||
\\"hello\\",
|
\\"hello\\",
|
||||||
_createVNode(\\"span\\")
|
_createVNode(\\"span\\")
|
||||||
]
|
]))
|
||||||
})))
|
}), 128 /* UNKEYED_FRAGMENT */)
|
||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
@ -78,12 +109,12 @@ exports[`compiler: v-for codegen v-if + v-for 1`] = `
|
|||||||
|
|
||||||
return function render() {
|
return function render() {
|
||||||
with (this) {
|
with (this) {
|
||||||
const { openBlock: _openBlock, createVNode: _createVNode, createBlock: _createBlock, Fragment: _Fragment, renderList: _renderList, Empty: _Empty } = _Vue
|
const { openBlock: _openBlock, renderList: _renderList, createVNode: _createVNode, Fragment: _Fragment, createBlock: _createBlock, Empty: _Empty } = _Vue
|
||||||
|
|
||||||
return (_openBlock(), ok
|
return (_openBlock(), ok
|
||||||
? _createBlock(_Fragment, { key: 0 }, _renderList(list, (i) => {
|
? _createBlock(_Fragment, { key: 0 }, _renderList(list, (i) => {
|
||||||
return _createVNode(\\"div\\")
|
return (_openBlock(), _createBlock(\\"div\\"))
|
||||||
}))
|
}), 128 /* UNKEYED_FRAGMENT */)
|
||||||
: _createBlock(_Empty))
|
: _createBlock(_Empty))
|
||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
@ -94,11 +125,11 @@ exports[`compiler: v-for codegen value + key + index 1`] = `
|
|||||||
|
|
||||||
return function render() {
|
return function render() {
|
||||||
with (this) {
|
with (this) {
|
||||||
const { openBlock: _openBlock, createVNode: _createVNode, createBlock: _createBlock, Fragment: _Fragment, renderList: _renderList } = _Vue
|
const { renderList: _renderList, createVNode: _createVNode, Fragment: _Fragment, createBlock: _createBlock, openBlock: _openBlock } = _Vue
|
||||||
|
|
||||||
return (_openBlock(), _createBlock(_Fragment, null, _renderList(items, (item, key, index) => {
|
return _createVNode(_Fragment, null, _renderList(items, (item, key, index) => {
|
||||||
return _createVNode(\\"span\\")
|
return (_openBlock(), _createBlock(\\"span\\"))
|
||||||
})))
|
}), 128 /* UNKEYED_FRAGMENT */)
|
||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
@ -19,7 +19,7 @@ exports[`compiler: v-if codegen template v-if 1`] = `
|
|||||||
|
|
||||||
return function render() {
|
return function render() {
|
||||||
with (this) {
|
with (this) {
|
||||||
const { openBlock: _openBlock, createVNode: _createVNode, createBlock: _createBlock, Fragment: _Fragment, Empty: _Empty } = _Vue
|
const { openBlock: _openBlock, createVNode: _createVNode, Fragment: _Fragment, createBlock: _createBlock, Empty: _Empty } = _Vue
|
||||||
|
|
||||||
return (_openBlock(), ok
|
return (_openBlock(), ok
|
||||||
? _createBlock(_Fragment, { key: 0 }, [
|
? _createBlock(_Fragment, { key: 0 }, [
|
||||||
|
@ -2,25 +2,29 @@ import { parse } from '../../src/parse'
|
|||||||
import { transform } from '../../src/transform'
|
import { transform } from '../../src/transform'
|
||||||
import { transformIf } from '../../src/transforms/vIf'
|
import { transformIf } from '../../src/transforms/vIf'
|
||||||
import { transformFor } from '../../src/transforms/vFor'
|
import { transformFor } from '../../src/transforms/vFor'
|
||||||
|
import { transformBind } from '../../src/transforms/vBind'
|
||||||
import { transformElement } from '../../src/transforms/transformElement'
|
import { transformElement } from '../../src/transforms/transformElement'
|
||||||
|
import { transformExpression } from '../../src/transforms/transformExpression'
|
||||||
import {
|
import {
|
||||||
ForNode,
|
ForNode,
|
||||||
NodeTypes,
|
NodeTypes,
|
||||||
SimpleExpressionNode,
|
SimpleExpressionNode,
|
||||||
ElementNode,
|
ElementNode,
|
||||||
InterpolationNode,
|
InterpolationNode,
|
||||||
SequenceExpression,
|
|
||||||
CallExpression
|
CallExpression
|
||||||
} from '../../src/ast'
|
} from '../../src/ast'
|
||||||
import { ErrorCodes } from '../../src/errors'
|
import { ErrorCodes } from '../../src/errors'
|
||||||
import { CompilerOptions, generate } from '../../src'
|
import { CompilerOptions, generate } from '../../src'
|
||||||
import { transformExpression } from '../../src/transforms/transformExpression'
|
|
||||||
import {
|
import {
|
||||||
OPEN_BLOCK,
|
OPEN_BLOCK,
|
||||||
CREATE_BLOCK,
|
CREATE_BLOCK,
|
||||||
FRAGMENT,
|
FRAGMENT,
|
||||||
RENDER_LIST
|
RENDER_LIST,
|
||||||
|
CREATE_VNODE
|
||||||
} from '../../src/runtimeConstants'
|
} from '../../src/runtimeConstants'
|
||||||
|
import { PatchFlags } from '@vue/runtime-dom'
|
||||||
|
import { PatchFlagNames } from '@vue/shared'
|
||||||
|
import { createObjectMatcher } from '../testUtils'
|
||||||
|
|
||||||
function parseWithForTransform(
|
function parseWithForTransform(
|
||||||
template: string,
|
template: string,
|
||||||
@ -34,6 +38,9 @@ function parseWithForTransform(
|
|||||||
...(options.prefixIdentifiers ? [transformExpression] : []),
|
...(options.prefixIdentifiers ? [transformExpression] : []),
|
||||||
transformElement
|
transformElement
|
||||||
],
|
],
|
||||||
|
directiveTransforms: {
|
||||||
|
bind: transformBind
|
||||||
|
},
|
||||||
...options
|
...options
|
||||||
})
|
})
|
||||||
return {
|
return {
|
||||||
@ -555,31 +562,51 @@ describe('compiler: v-for', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
describe('codegen', () => {
|
describe('codegen', () => {
|
||||||
function assertSharedCodegen(node: SequenceExpression) {
|
function assertSharedCodegen(node: CallExpression, keyed: boolean = false) {
|
||||||
expect(node).toMatchObject({
|
expect(node).toMatchObject({
|
||||||
type: NodeTypes.JS_SEQUENCE_EXPRESSION,
|
type: NodeTypes.JS_CALL_EXPRESSION,
|
||||||
expressions: [
|
callee: `_${CREATE_VNODE}`,
|
||||||
|
arguments: [
|
||||||
|
`_${FRAGMENT}`,
|
||||||
|
`null`,
|
||||||
{
|
{
|
||||||
type: NodeTypes.JS_CALL_EXPRESSION,
|
type: NodeTypes.JS_CALL_EXPRESSION,
|
||||||
callee: `_${OPEN_BLOCK}`,
|
callee: `_${RENDER_LIST}`,
|
||||||
arguments: []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: NodeTypes.JS_CALL_EXPRESSION,
|
|
||||||
callee: `_${CREATE_BLOCK}`,
|
|
||||||
arguments: [
|
arguments: [
|
||||||
`_${FRAGMENT}`,
|
{}, // to be asserted by each test
|
||||||
`null`,
|
|
||||||
{
|
{
|
||||||
type: NodeTypes.JS_CALL_EXPRESSION,
|
type: NodeTypes.JS_FUNCTION_EXPRESSION,
|
||||||
callee: `_${RENDER_LIST}`
|
returns: {
|
||||||
|
type: NodeTypes.JS_SEQUENCE_EXPRESSION,
|
||||||
|
expressions: [
|
||||||
|
{
|
||||||
|
type: NodeTypes.JS_CALL_EXPRESSION,
|
||||||
|
callee: `_${OPEN_BLOCK}`
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: NodeTypes.JS_CALL_EXPRESSION,
|
||||||
|
callee: `_${CREATE_BLOCK}`
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
},
|
||||||
|
keyed
|
||||||
|
? `${PatchFlags.KEYED_FRAGMENT} /* ${
|
||||||
|
PatchFlagNames[PatchFlags.KEYED_FRAGMENT]
|
||||||
|
} */`
|
||||||
|
: `${PatchFlags.UNKEYED_FRAGMENT} /* ${
|
||||||
|
PatchFlagNames[PatchFlags.UNKEYED_FRAGMENT]
|
||||||
|
} */`
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
return (node.expressions[1] as CallExpression)
|
const renderListArgs = (node.arguments[2] as CallExpression).arguments
|
||||||
.arguments[2] as CallExpression
|
return {
|
||||||
|
source: renderListArgs[0] as SimpleExpressionNode,
|
||||||
|
params: (renderListArgs[1] as any).params,
|
||||||
|
blockArgs: (renderListArgs[1] as any).returns.expressions[1].arguments
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
test('basic v-for', () => {
|
test('basic v-for', () => {
|
||||||
@ -587,17 +614,11 @@ describe('compiler: v-for', () => {
|
|||||||
root,
|
root,
|
||||||
node: { codegenNode }
|
node: { codegenNode }
|
||||||
} = parseWithForTransform('<span v-for="(item) in items" />')
|
} = parseWithForTransform('<span v-for="(item) in items" />')
|
||||||
expect(assertSharedCodegen(codegenNode).arguments).toMatchObject([
|
expect(assertSharedCodegen(codegenNode)).toMatchObject({
|
||||||
{ content: `items` },
|
source: { content: `items` },
|
||||||
{
|
params: [{ content: `item` }],
|
||||||
type: NodeTypes.JS_FUNCTION_EXPRESSION,
|
blockArgs: [`"span"`]
|
||||||
params: [{ content: `item` }],
|
})
|
||||||
returns: {
|
|
||||||
type: NodeTypes.ELEMENT,
|
|
||||||
tag: `span`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
])
|
|
||||||
expect(generate(root).code).toMatchSnapshot()
|
expect(generate(root).code).toMatchSnapshot()
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -606,17 +627,10 @@ describe('compiler: v-for', () => {
|
|||||||
root,
|
root,
|
||||||
node: { codegenNode }
|
node: { codegenNode }
|
||||||
} = parseWithForTransform('<span v-for="(item, key, index) in items" />')
|
} = parseWithForTransform('<span v-for="(item, key, index) in items" />')
|
||||||
expect(assertSharedCodegen(codegenNode).arguments).toMatchObject([
|
expect(assertSharedCodegen(codegenNode)).toMatchObject({
|
||||||
{ content: `items` },
|
source: { content: `items` },
|
||||||
{
|
params: [{ content: `item` }, { content: `key` }, { content: `index` }]
|
||||||
type: NodeTypes.JS_FUNCTION_EXPRESSION,
|
})
|
||||||
params: [
|
|
||||||
{ content: `item` },
|
|
||||||
{ content: `key` },
|
|
||||||
{ content: `index` }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
])
|
|
||||||
expect(generate(root).code).toMatchSnapshot()
|
expect(generate(root).code).toMatchSnapshot()
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -624,14 +638,11 @@ describe('compiler: v-for', () => {
|
|||||||
const {
|
const {
|
||||||
root,
|
root,
|
||||||
node: { codegenNode }
|
node: { codegenNode }
|
||||||
} = parseWithForTransform('<span v-for="(,key,index) in items" />')
|
} = parseWithForTransform('<span v-for="(, key, index) in items" />')
|
||||||
expect(assertSharedCodegen(codegenNode).arguments).toMatchObject([
|
expect(assertSharedCodegen(codegenNode)).toMatchObject({
|
||||||
{ content: `items` },
|
source: { content: `items` },
|
||||||
{
|
params: [{ content: `_` }, { content: `key` }, { content: `index` }]
|
||||||
type: NodeTypes.JS_FUNCTION_EXPRESSION,
|
})
|
||||||
params: [{ content: `_` }, { content: `key` }, { content: `index` }]
|
|
||||||
}
|
|
||||||
])
|
|
||||||
expect(generate(root).code).toMatchSnapshot()
|
expect(generate(root).code).toMatchSnapshot()
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -639,18 +650,11 @@ describe('compiler: v-for', () => {
|
|||||||
const {
|
const {
|
||||||
root,
|
root,
|
||||||
node: { codegenNode }
|
node: { codegenNode }
|
||||||
} = parseWithForTransform('<span v-for="(value,,index) in items" />')
|
} = parseWithForTransform('<span v-for="(item,,index) in items" />')
|
||||||
expect(assertSharedCodegen(codegenNode).arguments).toMatchObject([
|
expect(assertSharedCodegen(codegenNode)).toMatchObject({
|
||||||
{ content: `items` },
|
source: { content: `items` },
|
||||||
{
|
params: [{ content: `item` }, { content: `__` }, { content: `index` }]
|
||||||
type: NodeTypes.JS_FUNCTION_EXPRESSION,
|
})
|
||||||
params: [
|
|
||||||
{ content: `value` },
|
|
||||||
{ content: `__` },
|
|
||||||
{ content: `index` }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
])
|
|
||||||
expect(generate(root).code).toMatchSnapshot()
|
expect(generate(root).code).toMatchSnapshot()
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -659,13 +663,10 @@ describe('compiler: v-for', () => {
|
|||||||
root,
|
root,
|
||||||
node: { codegenNode }
|
node: { codegenNode }
|
||||||
} = parseWithForTransform('<span v-for="(,,index) in items" />')
|
} = parseWithForTransform('<span v-for="(,,index) in items" />')
|
||||||
expect(assertSharedCodegen(codegenNode).arguments).toMatchObject([
|
expect(assertSharedCodegen(codegenNode)).toMatchObject({
|
||||||
{ content: `items` },
|
source: { content: `items` },
|
||||||
{
|
params: [{ content: `_` }, { content: `__` }, { content: `index` }]
|
||||||
type: NodeTypes.JS_FUNCTION_EXPRESSION,
|
})
|
||||||
params: [{ content: `_` }, { content: `__` }, { content: `index` }]
|
|
||||||
}
|
|
||||||
])
|
|
||||||
expect(generate(root).code).toMatchSnapshot()
|
expect(generate(root).code).toMatchSnapshot()
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -676,17 +677,60 @@ describe('compiler: v-for', () => {
|
|||||||
} = parseWithForTransform(
|
} = parseWithForTransform(
|
||||||
'<template v-for="item in items">hello<span/></template>'
|
'<template v-for="item in items">hello<span/></template>'
|
||||||
)
|
)
|
||||||
expect(assertSharedCodegen(codegenNode).arguments).toMatchObject([
|
expect(assertSharedCodegen(codegenNode)).toMatchObject({
|
||||||
{ content: `items` },
|
source: { content: `items` },
|
||||||
{
|
params: [{ content: `item` }],
|
||||||
type: NodeTypes.JS_FUNCTION_EXPRESSION,
|
blockArgs: [
|
||||||
params: [{ content: `item` }],
|
`_${FRAGMENT}`,
|
||||||
returns: [
|
`null`,
|
||||||
|
[
|
||||||
{ type: NodeTypes.TEXT, content: `hello` },
|
{ type: NodeTypes.TEXT, content: `hello` },
|
||||||
{ type: NodeTypes.ELEMENT, tag: `span` }
|
{ type: NodeTypes.ELEMENT, tag: `span` }
|
||||||
]
|
]
|
||||||
}
|
]
|
||||||
])
|
})
|
||||||
|
expect(generate(root).code).toMatchSnapshot()
|
||||||
|
})
|
||||||
|
|
||||||
|
test('keyed v-for', () => {
|
||||||
|
const {
|
||||||
|
root,
|
||||||
|
node: { codegenNode }
|
||||||
|
} = parseWithForTransform('<span v-for="(item) in items" :key="item" />')
|
||||||
|
expect(assertSharedCodegen(codegenNode, true)).toMatchObject({
|
||||||
|
source: { content: `items` },
|
||||||
|
params: [{ content: `item` }],
|
||||||
|
blockArgs: [
|
||||||
|
`"span"`,
|
||||||
|
createObjectMatcher({
|
||||||
|
key: `[item]`
|
||||||
|
})
|
||||||
|
]
|
||||||
|
})
|
||||||
|
expect(generate(root).code).toMatchSnapshot()
|
||||||
|
})
|
||||||
|
|
||||||
|
test('keyed template v-for', () => {
|
||||||
|
const {
|
||||||
|
root,
|
||||||
|
node: { codegenNode }
|
||||||
|
} = parseWithForTransform(
|
||||||
|
'<template v-for="item in items" :key="item">hello<span/></template>'
|
||||||
|
)
|
||||||
|
expect(assertSharedCodegen(codegenNode, true)).toMatchObject({
|
||||||
|
source: { content: `items` },
|
||||||
|
params: [{ content: `item` }],
|
||||||
|
blockArgs: [
|
||||||
|
`_${FRAGMENT}`,
|
||||||
|
createObjectMatcher({
|
||||||
|
key: `[item]`
|
||||||
|
}),
|
||||||
|
[
|
||||||
|
{ type: NodeTypes.TEXT, content: `hello` },
|
||||||
|
{ type: NodeTypes.ELEMENT, tag: `span` }
|
||||||
|
]
|
||||||
|
]
|
||||||
|
})
|
||||||
expect(generate(root).code).toMatchSnapshot()
|
expect(generate(root).code).toMatchSnapshot()
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -722,12 +766,25 @@ describe('compiler: v-for', () => {
|
|||||||
type: NodeTypes.JS_FUNCTION_EXPRESSION,
|
type: NodeTypes.JS_FUNCTION_EXPRESSION,
|
||||||
params: [{ content: `i` }],
|
params: [{ content: `i` }],
|
||||||
returns: {
|
returns: {
|
||||||
type: NodeTypes.ELEMENT,
|
type: NodeTypes.JS_SEQUENCE_EXPRESSION,
|
||||||
tag: `div`
|
expressions: [
|
||||||
|
{
|
||||||
|
type: NodeTypes.JS_CALL_EXPRESSION,
|
||||||
|
callee: `_${OPEN_BLOCK}`
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: NodeTypes.JS_CALL_EXPRESSION,
|
||||||
|
callee: `_${CREATE_BLOCK}`,
|
||||||
|
arguments: [`"div"`]
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
},
|
||||||
|
`${PatchFlags.UNKEYED_FRAGMENT} /* ${
|
||||||
|
PatchFlagNames[PatchFlags.UNKEYED_FRAGMENT]
|
||||||
|
} */`
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -158,7 +158,7 @@ export interface ForNode extends Node {
|
|||||||
keyAlias: ExpressionNode | undefined
|
keyAlias: ExpressionNode | undefined
|
||||||
objectIndexAlias: ExpressionNode | undefined
|
objectIndexAlias: ExpressionNode | undefined
|
||||||
children: TemplateChildNode[]
|
children: TemplateChildNode[]
|
||||||
codegenNode: SequenceExpression
|
codegenNode: CallExpression
|
||||||
}
|
}
|
||||||
|
|
||||||
// We also include a number of JavaScript AST nodes for code generation.
|
// We also include a number of JavaScript AST nodes for code generation.
|
||||||
@ -198,7 +198,7 @@ export interface ArrayExpression extends Node {
|
|||||||
export interface FunctionExpression extends Node {
|
export interface FunctionExpression extends Node {
|
||||||
type: NodeTypes.JS_FUNCTION_EXPRESSION
|
type: NodeTypes.JS_FUNCTION_EXPRESSION
|
||||||
params: ExpressionNode | ExpressionNode[] | undefined
|
params: ExpressionNode | ExpressionNode[] | undefined
|
||||||
returns: TemplateChildNode | TemplateChildNode[]
|
returns: TemplateChildNode | TemplateChildNode[] | JSChildNode
|
||||||
newline: boolean
|
newline: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -261,7 +261,6 @@ function genHoists(hoists: JSChildNode[], context: CodegenContext) {
|
|||||||
// - The target position explicitly allows a single node (root, if, for)
|
// - The target position explicitly allows a single node (root, if, for)
|
||||||
// - The list has length === 1, AND The only child is a:
|
// - The list has length === 1, AND The only child is a:
|
||||||
// - text
|
// - text
|
||||||
// - expression
|
|
||||||
// - <slot> outlet, which always produces an array
|
// - <slot> outlet, which always produces an array
|
||||||
function genChildren(
|
function genChildren(
|
||||||
children: TemplateChildNode[],
|
children: TemplateChildNode[],
|
||||||
|
@ -163,7 +163,7 @@ export function buildProps(
|
|||||||
// patchFlag analysis
|
// patchFlag analysis
|
||||||
let patchFlag = 0
|
let patchFlag = 0
|
||||||
const dynamicPropNames: string[] = []
|
const dynamicPropNames: string[] = []
|
||||||
let hasDynammicKeys = false
|
let hasDynamicKeys = false
|
||||||
let hasClassBinding = false
|
let hasClassBinding = false
|
||||||
let hasStyleBinding = false
|
let hasStyleBinding = false
|
||||||
let hasRef = false
|
let hasRef = false
|
||||||
@ -207,7 +207,7 @@ export function buildProps(
|
|||||||
// special case for v-bind and v-on with no argument
|
// special case for v-bind and v-on with no argument
|
||||||
const isBind = name === 'bind'
|
const isBind = name === 'bind'
|
||||||
if (!arg && (isBind || name === 'on')) {
|
if (!arg && (isBind || name === 'on')) {
|
||||||
hasDynammicKeys = true
|
hasDynamicKeys = true
|
||||||
if (exp) {
|
if (exp) {
|
||||||
if (properties.length) {
|
if (properties.length) {
|
||||||
mergeArgs.push(
|
mergeArgs.push(
|
||||||
@ -249,11 +249,11 @@ export function buildProps(
|
|||||||
hasClassBinding = true
|
hasClassBinding = true
|
||||||
} else if (name === 'style') {
|
} else if (name === 'style') {
|
||||||
hasStyleBinding = true
|
hasStyleBinding = true
|
||||||
} else {
|
} else if (name !== 'key') {
|
||||||
dynamicPropNames.push(name)
|
dynamicPropNames.push(name)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
hasDynammicKeys = true
|
hasDynamicKeys = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -303,7 +303,7 @@ export function buildProps(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// determine the flags to add
|
// determine the flags to add
|
||||||
if (hasDynammicKeys) {
|
if (hasDynamicKeys) {
|
||||||
patchFlag |= PatchFlags.FULL_PROPS
|
patchFlag |= PatchFlags.FULL_PROPS
|
||||||
} else {
|
} else {
|
||||||
if (hasClassBinding) {
|
if (hasClassBinding) {
|
||||||
|
@ -11,17 +11,22 @@ import {
|
|||||||
createSequenceExpression,
|
createSequenceExpression,
|
||||||
createCallExpression,
|
createCallExpression,
|
||||||
createFunctionExpression,
|
createFunctionExpression,
|
||||||
ElementTypes
|
ElementTypes,
|
||||||
|
ObjectExpression,
|
||||||
|
createObjectExpression,
|
||||||
|
createObjectProperty
|
||||||
} from '../ast'
|
} from '../ast'
|
||||||
import { createCompilerError, ErrorCodes } from '../errors'
|
import { createCompilerError, ErrorCodes } from '../errors'
|
||||||
import { getInnerRange } from '../utils'
|
import { getInnerRange, findProp } from '../utils'
|
||||||
import {
|
import {
|
||||||
RENDER_LIST,
|
RENDER_LIST,
|
||||||
OPEN_BLOCK,
|
OPEN_BLOCK,
|
||||||
CREATE_BLOCK,
|
CREATE_BLOCK,
|
||||||
FRAGMENT
|
FRAGMENT,
|
||||||
|
CREATE_VNODE
|
||||||
} from '../runtimeConstants'
|
} from '../runtimeConstants'
|
||||||
import { processExpression } from './transformExpression'
|
import { processExpression } from './transformExpression'
|
||||||
|
import { PatchFlags, PatchFlagNames } from '@vue/shared'
|
||||||
|
|
||||||
export const transformFor = createStructuralDirectiveTransform(
|
export const transformFor = createStructuralDirectiveTransform(
|
||||||
'for',
|
'for',
|
||||||
@ -38,9 +43,19 @@ export const transformFor = createStructuralDirectiveTransform(
|
|||||||
const { helper, addIdentifiers, removeIdentifiers } = context
|
const { helper, addIdentifiers, removeIdentifiers } = context
|
||||||
const { source, value, key, index } = parseResult
|
const { source, value, key, index } = parseResult
|
||||||
|
|
||||||
const codegenNode = createSequenceExpression([
|
// create the loop render function expression now, and add the
|
||||||
createCallExpression(helper(OPEN_BLOCK))
|
// iterator on exit after all children have been traversed
|
||||||
// to be filled in on exit after children traverse
|
const renderExp = createCallExpression(helper(RENDER_LIST), [source])
|
||||||
|
const keyProp = findProp(node.props, `key`)
|
||||||
|
const fragmentFlag = keyProp
|
||||||
|
? PatchFlags.KEYED_FRAGMENT
|
||||||
|
: PatchFlags.UNKEYED_FRAGMENT
|
||||||
|
const codegenNode = createCallExpression(helper(CREATE_VNODE), [
|
||||||
|
helper(FRAGMENT),
|
||||||
|
`null`,
|
||||||
|
renderExp,
|
||||||
|
fragmentFlag +
|
||||||
|
(__DEV__ ? ` /* ${PatchFlagNames[fragmentFlag]} */` : ``)
|
||||||
])
|
])
|
||||||
|
|
||||||
context.replaceNode({
|
context.replaceNode({
|
||||||
@ -63,6 +78,13 @@ export const transformFor = createStructuralDirectiveTransform(
|
|||||||
}
|
}
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
|
if (!__BROWSER__ && context.prefixIdentifiers) {
|
||||||
|
value && removeIdentifiers(value)
|
||||||
|
key && removeIdentifiers(key)
|
||||||
|
index && removeIdentifiers(index)
|
||||||
|
}
|
||||||
|
|
||||||
|
// finish the codegen now that all children have been traversed
|
||||||
const params: ExpressionNode[] = []
|
const params: ExpressionNode[] = []
|
||||||
if (value) {
|
if (value) {
|
||||||
params.push(value)
|
params.push(value)
|
||||||
@ -83,26 +105,46 @@ export const transformFor = createStructuralDirectiveTransform(
|
|||||||
params.push(index)
|
params.push(index)
|
||||||
}
|
}
|
||||||
|
|
||||||
codegenNode.expressions.push(
|
let childBlock
|
||||||
createCallExpression(helper(CREATE_BLOCK), [
|
if (node.tagType === ElementTypes.TEMPLATE) {
|
||||||
helper(FRAGMENT),
|
// <template v-for="...">
|
||||||
`null`,
|
// should genereate a fragment block for each loop
|
||||||
createCallExpression(helper(RENDER_LIST), [
|
let childBlockProps: string | ObjectExpression = `null`
|
||||||
source,
|
if (keyProp) {
|
||||||
createFunctionExpression(
|
childBlockProps = createObjectExpression([
|
||||||
params,
|
createObjectProperty(
|
||||||
node.tagType === ElementTypes.TEMPLATE ? node.children : node,
|
createSimpleExpression(`key`, true),
|
||||||
true /* force newline to make it more readable */
|
keyProp.type === NodeTypes.ATTRIBUTE
|
||||||
|
? createSimpleExpression(keyProp.value!.content, true)
|
||||||
|
: keyProp.exp!
|
||||||
)
|
)
|
||||||
])
|
])
|
||||||
|
}
|
||||||
|
childBlock = createSequenceExpression([
|
||||||
|
createCallExpression(helper(OPEN_BLOCK)),
|
||||||
|
createCallExpression(helper(CREATE_BLOCK), [
|
||||||
|
helper(FRAGMENT),
|
||||||
|
childBlockProps,
|
||||||
|
node.children
|
||||||
|
])
|
||||||
|
])
|
||||||
|
} else {
|
||||||
|
// Normal element v-for. Directly use the child's codegenNode,
|
||||||
|
// but replace createVNode() with createBlock()
|
||||||
|
node.codegenNode!.callee = helper(CREATE_BLOCK)
|
||||||
|
childBlock = createSequenceExpression([
|
||||||
|
createCallExpression(helper(OPEN_BLOCK)),
|
||||||
|
node.codegenNode!
|
||||||
])
|
])
|
||||||
)
|
|
||||||
|
|
||||||
if (!__BROWSER__ && context.prefixIdentifiers) {
|
|
||||||
value && removeIdentifiers(value)
|
|
||||||
key && removeIdentifiers(key)
|
|
||||||
index && removeIdentifiers(index)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
renderExp.arguments.push(
|
||||||
|
createFunctionExpression(
|
||||||
|
params,
|
||||||
|
childBlock,
|
||||||
|
true /* force newline */
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
context.onError(
|
context.onError(
|
||||||
|
@ -20,9 +20,7 @@ import {
|
|||||||
ObjectExpression,
|
ObjectExpression,
|
||||||
createObjectProperty,
|
createObjectProperty,
|
||||||
Property,
|
Property,
|
||||||
ExpressionNode,
|
ExpressionNode
|
||||||
TemplateChildNode,
|
|
||||||
FunctionExpression
|
|
||||||
} from '../ast'
|
} from '../ast'
|
||||||
import { createCompilerError, ErrorCodes } from '../errors'
|
import { createCompilerError, ErrorCodes } from '../errors'
|
||||||
import { processExpression } from './transformExpression'
|
import { processExpression } from './transformExpression'
|
||||||
@ -168,17 +166,19 @@ function createChildrenCodegenNode(
|
|||||||
const needFragmentWrapper =
|
const needFragmentWrapper =
|
||||||
children.length > 1 || child.type !== NodeTypes.ELEMENT
|
children.length > 1 || child.type !== NodeTypes.ELEMENT
|
||||||
if (needFragmentWrapper) {
|
if (needFragmentWrapper) {
|
||||||
let fragmentChildren: TemplateChildNode[] | FunctionExpression = children
|
const blockArgs: CallExpression['arguments'] = [
|
||||||
// optimize away nested fragments when child is a ForNode
|
|
||||||
if (children.length === 1 && child.type === NodeTypes.FOR) {
|
|
||||||
fragmentChildren = (child.codegenNode.expressions[1] as CallExpression)
|
|
||||||
.arguments[2] as FunctionExpression
|
|
||||||
}
|
|
||||||
return createCallExpression(helper(CREATE_BLOCK), [
|
|
||||||
helper(FRAGMENT),
|
helper(FRAGMENT),
|
||||||
keyExp,
|
keyExp,
|
||||||
fragmentChildren
|
children
|
||||||
])
|
]
|
||||||
|
// optimize away nested fragments when child is a ForNode
|
||||||
|
if (children.length === 1 && child.type === NodeTypes.FOR) {
|
||||||
|
const forBlockExp = child.codegenNode
|
||||||
|
// directly use the for block's children and patchFlag
|
||||||
|
blockArgs[2] = forBlockExp.arguments[2]
|
||||||
|
blockArgs[3] = forBlockExp.arguments[3]
|
||||||
|
}
|
||||||
|
return createCallExpression(helper(CREATE_BLOCK), blockArgs)
|
||||||
} else {
|
} else {
|
||||||
const childCodegen = (child as ElementNode).codegenNode!
|
const childCodegen = (child as ElementNode).codegenNode!
|
||||||
let vnodeCall = childCodegen
|
let vnodeCall = childCodegen
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { SourceLocation, Position } from './ast'
|
import { SourceLocation, Position, ElementNode, NodeTypes } from './ast'
|
||||||
import { parseScript } from 'meriyah'
|
import { parseScript } from 'meriyah'
|
||||||
import { walk } from 'estree-walker'
|
import { walk } from 'estree-walker'
|
||||||
|
|
||||||
@ -94,3 +94,25 @@ export function assert(condition: boolean, msg?: string) {
|
|||||||
throw new Error(msg || `unexpected compiler condition`)
|
throw new Error(msg || `unexpected compiler condition`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function findProp(
|
||||||
|
props: ElementNode['props'],
|
||||||
|
name: string
|
||||||
|
): ElementNode['props'][0] | undefined {
|
||||||
|
for (let i = 0; i < props.length; i++) {
|
||||||
|
const p = props[i]
|
||||||
|
if (p.type === NodeTypes.ATTRIBUTE) {
|
||||||
|
if (p.name === name && p.value && !p.value.isEmpty) {
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
} else if (
|
||||||
|
p.arg &&
|
||||||
|
p.arg.type === NodeTypes.SIMPLE_EXPRESSION &&
|
||||||
|
p.arg.isStatic &&
|
||||||
|
p.arg.content === name &&
|
||||||
|
p.exp
|
||||||
|
) {
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1230,7 +1230,7 @@ export function createRenderer<
|
|||||||
// fast path
|
// fast path
|
||||||
const { patchFlag, shapeFlag } = n2
|
const { patchFlag, shapeFlag } = n2
|
||||||
if (patchFlag) {
|
if (patchFlag) {
|
||||||
if (patchFlag & PatchFlags.KEYED_V_FOR) {
|
if (patchFlag & PatchFlags.KEYED_FRAGMENT) {
|
||||||
// this could be either fully-keyed or mixed (some keyed some not)
|
// this could be either fully-keyed or mixed (some keyed some not)
|
||||||
// presence of patchFlag means children are guaranteed to be arrays
|
// presence of patchFlag means children are guaranteed to be arrays
|
||||||
patchKeyedChildren(
|
patchKeyedChildren(
|
||||||
@ -1244,7 +1244,7 @@ export function createRenderer<
|
|||||||
optimized
|
optimized
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
} else if (patchFlag & PatchFlags.UNKEYED_V_FOR) {
|
} else if (patchFlag & PatchFlags.UNKEYED_FRAGMENT) {
|
||||||
// unkeyed
|
// unkeyed
|
||||||
patchUnkeyedChildren(
|
patchUnkeyedChildren(
|
||||||
c1 as HostVNode[],
|
c1 as HostVNode[],
|
||||||
|
@ -47,11 +47,11 @@ export const enum PatchFlags {
|
|||||||
// value.
|
// value.
|
||||||
NEED_PATCH = 1 << 5,
|
NEED_PATCH = 1 << 5,
|
||||||
|
|
||||||
// Indicates a v-for fragment with keyed or partially keyed children
|
// Indicates a fragment with keyed or partially keyed children
|
||||||
KEYED_V_FOR = 1 << 6,
|
KEYED_FRAGMENT = 1 << 6,
|
||||||
|
|
||||||
// Indicates a v-for fragment with unkeyed children.
|
// Indicates a fragment with unkeyed children.
|
||||||
UNKEYED_V_FOR = 1 << 7,
|
UNKEYED_FRAGMENT = 1 << 7,
|
||||||
|
|
||||||
// Indicates a component with dynamic slots (e.g. slot that references a v-for
|
// Indicates a component with dynamic slots (e.g. slot that references a v-for
|
||||||
// iterated value, or dynamic slot names).
|
// iterated value, or dynamic slot names).
|
||||||
@ -67,8 +67,8 @@ export const PublicPatchFlags = {
|
|||||||
PROPS: PatchFlags.PROPS,
|
PROPS: PatchFlags.PROPS,
|
||||||
NEED_PATCH: PatchFlags.NEED_PATCH,
|
NEED_PATCH: PatchFlags.NEED_PATCH,
|
||||||
FULL_PROPS: PatchFlags.FULL_PROPS,
|
FULL_PROPS: PatchFlags.FULL_PROPS,
|
||||||
KEYED_V_FOR: PatchFlags.KEYED_V_FOR,
|
KEYED_FRAGMENT: PatchFlags.KEYED_FRAGMENT,
|
||||||
UNKEYED_V_FOR: PatchFlags.UNKEYED_V_FOR,
|
UNKEYED_FRAGMENT: PatchFlags.UNKEYED_FRAGMENT,
|
||||||
DYNAMIC_SLOTS: PatchFlags.DYNAMIC_SLOTS
|
DYNAMIC_SLOTS: PatchFlags.DYNAMIC_SLOTS
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,7 +80,7 @@ export const PatchFlagNames = {
|
|||||||
[PatchFlags.PROPS]: `PROPS`,
|
[PatchFlags.PROPS]: `PROPS`,
|
||||||
[PatchFlags.NEED_PATCH]: `NEED_PATCH`,
|
[PatchFlags.NEED_PATCH]: `NEED_PATCH`,
|
||||||
[PatchFlags.FULL_PROPS]: `FULL_PROPS`,
|
[PatchFlags.FULL_PROPS]: `FULL_PROPS`,
|
||||||
[PatchFlags.KEYED_V_FOR]: `KEYED_V_FOR`,
|
[PatchFlags.KEYED_FRAGMENT]: `KEYED_FRAGMENT`,
|
||||||
[PatchFlags.UNKEYED_V_FOR]: `UNKEYED_V_FOR`,
|
[PatchFlags.UNKEYED_FRAGMENT]: `UNKEYED_FRAGMENT`,
|
||||||
[PatchFlags.DYNAMIC_SLOTS]: `DYNAMIC_SLOTS`
|
[PatchFlags.DYNAMIC_SLOTS]: `DYNAMIC_SLOTS`
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user