feat(compiler): v-for codegen w/ correct blocks optimization + key flags
This commit is contained in:
@@ -15,11 +15,11 @@ return function render() {
|
||||
(_openBlock(), ok
|
||||
? _createBlock(\\"div\\", { key: 0 }, \\"yes\\")
|
||||
: _createBlock(_Fragment, { key: 1 }, \\"no\\")),
|
||||
(_openBlock(), _createBlock(_Fragment, null, _renderList(list, (value, index) => {
|
||||
return _createVNode(\\"div\\", null, [
|
||||
_createVNode(_Fragment, null, _renderList(list, (value, index) => {
|
||||
return (_openBlock(), _createBlock(\\"div\\", null, [
|
||||
_createVNode(\\"span\\", null, _toString(value + index))
|
||||
])
|
||||
})))
|
||||
]))
|
||||
}), 128 /* UNKEYED_FRAGMENT */)
|
||||
], 2 /* CLASS */)
|
||||
}
|
||||
}"
|
||||
@@ -38,11 +38,11 @@ return function render() {
|
||||
(openBlock(), (_ctx.ok)
|
||||
? createBlock(\\"div\\", { key: 0 }, \\"yes\\")
|
||||
: createBlock(Fragment, { key: 1 }, \\"no\\")),
|
||||
(openBlock(), createBlock(Fragment, null, renderList(_ctx.list, (value, index) => {
|
||||
return createVNode(\\"div\\", null, [
|
||||
createVNode(Fragment, null, renderList(_ctx.list, (value, index) => {
|
||||
return (openBlock(), createBlock(\\"div\\", null, [
|
||||
createVNode(\\"span\\", null, toString(value + index))
|
||||
])
|
||||
})))
|
||||
]))
|
||||
}), 128 /* UNKEYED_FRAGMENT */)
|
||||
], 2 /* CLASS */)
|
||||
}"
|
||||
`;
|
||||
@@ -60,11 +60,11 @@ export default function render() {
|
||||
(openBlock(), (_ctx.ok)
|
||||
? createBlock(\\"div\\", { key: 0 }, \\"yes\\")
|
||||
: createBlock(Fragment, { key: 1 }, \\"no\\")),
|
||||
(openBlock(), createBlock(Fragment, null, renderList(_ctx.list, (value, index) => {
|
||||
return createVNode(\\"div\\", null, [
|
||||
createVNode(Fragment, null, renderList(_ctx.list, (value, index) => {
|
||||
return (openBlock(), createBlock(\\"div\\", null, [
|
||||
createVNode(\\"span\\", null, _toString(value + index))
|
||||
])
|
||||
})))
|
||||
]))
|
||||
}), 128 /* UNKEYED_FRAGMENT */)
|
||||
], 2 /* CLASS */)
|
||||
}"
|
||||
`;
|
||||
|
||||
@@ -5,11 +5,42 @@ exports[`compiler: v-for codegen basic v-for 1`] = `
|
||||
|
||||
return function render() {
|
||||
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(\\"span\\")
|
||||
})))
|
||||
return _createVNode(_Fragment, null, _renderList(items, (item) => {
|
||||
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() {
|
||||
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(\\"span\\")
|
||||
})))
|
||||
return _createVNode(_Fragment, null, _renderList(items, (item, __, index) => {
|
||||
return (_openBlock(), _createBlock(\\"span\\"))
|
||||
}), 128 /* UNKEYED_FRAGMENT */)
|
||||
}
|
||||
}"
|
||||
`;
|
||||
@@ -33,11 +64,11 @@ exports[`compiler: v-for codegen skipped value & key 1`] = `
|
||||
|
||||
return function render() {
|
||||
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(\\"span\\")
|
||||
})))
|
||||
return _createVNode(_Fragment, null, _renderList(items, (_, __, index) => {
|
||||
return (_openBlock(), _createBlock(\\"span\\"))
|
||||
}), 128 /* UNKEYED_FRAGMENT */)
|
||||
}
|
||||
}"
|
||||
`;
|
||||
@@ -47,11 +78,11 @@ exports[`compiler: v-for codegen skipped value 1`] = `
|
||||
|
||||
return function render() {
|
||||
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(\\"span\\")
|
||||
})))
|
||||
return _createVNode(_Fragment, null, _renderList(items, (_, key, index) => {
|
||||
return (_openBlock(), _createBlock(\\"span\\"))
|
||||
}), 128 /* UNKEYED_FRAGMENT */)
|
||||
}
|
||||
}"
|
||||
`;
|
||||
@@ -61,14 +92,14 @@ exports[`compiler: v-for codegen template v-for 1`] = `
|
||||
|
||||
return function render() {
|
||||
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 [
|
||||
return _createVNode(_Fragment, null, _renderList(items, (item) => {
|
||||
return (_openBlock(), _createBlock(_Fragment, null, [
|
||||
\\"hello\\",
|
||||
_createVNode(\\"span\\")
|
||||
]
|
||||
})))
|
||||
]))
|
||||
}), 128 /* UNKEYED_FRAGMENT */)
|
||||
}
|
||||
}"
|
||||
`;
|
||||
@@ -78,12 +109,12 @@ exports[`compiler: v-for codegen v-if + v-for 1`] = `
|
||||
|
||||
return function render() {
|
||||
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
|
||||
? _createBlock(_Fragment, { key: 0 }, _renderList(list, (i) => {
|
||||
return _createVNode(\\"div\\")
|
||||
}))
|
||||
return (_openBlock(), _createBlock(\\"div\\"))
|
||||
}), 128 /* UNKEYED_FRAGMENT */)
|
||||
: _createBlock(_Empty))
|
||||
}
|
||||
}"
|
||||
@@ -94,11 +125,11 @@ exports[`compiler: v-for codegen value + key + index 1`] = `
|
||||
|
||||
return function render() {
|
||||
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(\\"span\\")
|
||||
})))
|
||||
return _createVNode(_Fragment, null, _renderList(items, (item, key, index) => {
|
||||
return (_openBlock(), _createBlock(\\"span\\"))
|
||||
}), 128 /* UNKEYED_FRAGMENT */)
|
||||
}
|
||||
}"
|
||||
`;
|
||||
|
||||
@@ -19,7 +19,7 @@ exports[`compiler: v-if codegen template v-if 1`] = `
|
||||
|
||||
return function render() {
|
||||
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
|
||||
? _createBlock(_Fragment, { key: 0 }, [
|
||||
|
||||
@@ -2,25 +2,29 @@ import { parse } from '../../src/parse'
|
||||
import { transform } from '../../src/transform'
|
||||
import { transformIf } from '../../src/transforms/vIf'
|
||||
import { transformFor } from '../../src/transforms/vFor'
|
||||
import { transformBind } from '../../src/transforms/vBind'
|
||||
import { transformElement } from '../../src/transforms/transformElement'
|
||||
import { transformExpression } from '../../src/transforms/transformExpression'
|
||||
import {
|
||||
ForNode,
|
||||
NodeTypes,
|
||||
SimpleExpressionNode,
|
||||
ElementNode,
|
||||
InterpolationNode,
|
||||
SequenceExpression,
|
||||
CallExpression
|
||||
} from '../../src/ast'
|
||||
import { ErrorCodes } from '../../src/errors'
|
||||
import { CompilerOptions, generate } from '../../src'
|
||||
import { transformExpression } from '../../src/transforms/transformExpression'
|
||||
import {
|
||||
OPEN_BLOCK,
|
||||
CREATE_BLOCK,
|
||||
FRAGMENT,
|
||||
RENDER_LIST
|
||||
RENDER_LIST,
|
||||
CREATE_VNODE
|
||||
} from '../../src/runtimeConstants'
|
||||
import { PatchFlags } from '@vue/runtime-dom'
|
||||
import { PatchFlagNames } from '@vue/shared'
|
||||
import { createObjectMatcher } from '../testUtils'
|
||||
|
||||
function parseWithForTransform(
|
||||
template: string,
|
||||
@@ -34,6 +38,9 @@ function parseWithForTransform(
|
||||
...(options.prefixIdentifiers ? [transformExpression] : []),
|
||||
transformElement
|
||||
],
|
||||
directiveTransforms: {
|
||||
bind: transformBind
|
||||
},
|
||||
...options
|
||||
})
|
||||
return {
|
||||
@@ -555,31 +562,51 @@ describe('compiler: v-for', () => {
|
||||
})
|
||||
|
||||
describe('codegen', () => {
|
||||
function assertSharedCodegen(node: SequenceExpression) {
|
||||
function assertSharedCodegen(node: CallExpression, keyed: boolean = false) {
|
||||
expect(node).toMatchObject({
|
||||
type: NodeTypes.JS_SEQUENCE_EXPRESSION,
|
||||
expressions: [
|
||||
type: NodeTypes.JS_CALL_EXPRESSION,
|
||||
callee: `_${CREATE_VNODE}`,
|
||||
arguments: [
|
||||
`_${FRAGMENT}`,
|
||||
`null`,
|
||||
{
|
||||
type: NodeTypes.JS_CALL_EXPRESSION,
|
||||
callee: `_${OPEN_BLOCK}`,
|
||||
arguments: []
|
||||
},
|
||||
{
|
||||
type: NodeTypes.JS_CALL_EXPRESSION,
|
||||
callee: `_${CREATE_BLOCK}`,
|
||||
callee: `_${RENDER_LIST}`,
|
||||
arguments: [
|
||||
`_${FRAGMENT}`,
|
||||
`null`,
|
||||
{}, // to be asserted by each test
|
||||
{
|
||||
type: NodeTypes.JS_CALL_EXPRESSION,
|
||||
callee: `_${RENDER_LIST}`
|
||||
type: NodeTypes.JS_FUNCTION_EXPRESSION,
|
||||
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)
|
||||
.arguments[2] as CallExpression
|
||||
const renderListArgs = (node.arguments[2] as CallExpression).arguments
|
||||
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', () => {
|
||||
@@ -587,17 +614,11 @@ describe('compiler: v-for', () => {
|
||||
root,
|
||||
node: { codegenNode }
|
||||
} = parseWithForTransform('<span v-for="(item) in items" />')
|
||||
expect(assertSharedCodegen(codegenNode).arguments).toMatchObject([
|
||||
{ content: `items` },
|
||||
{
|
||||
type: NodeTypes.JS_FUNCTION_EXPRESSION,
|
||||
params: [{ content: `item` }],
|
||||
returns: {
|
||||
type: NodeTypes.ELEMENT,
|
||||
tag: `span`
|
||||
}
|
||||
}
|
||||
])
|
||||
expect(assertSharedCodegen(codegenNode)).toMatchObject({
|
||||
source: { content: `items` },
|
||||
params: [{ content: `item` }],
|
||||
blockArgs: [`"span"`]
|
||||
})
|
||||
expect(generate(root).code).toMatchSnapshot()
|
||||
})
|
||||
|
||||
@@ -606,17 +627,10 @@ describe('compiler: v-for', () => {
|
||||
root,
|
||||
node: { codegenNode }
|
||||
} = parseWithForTransform('<span v-for="(item, key, index) in items" />')
|
||||
expect(assertSharedCodegen(codegenNode).arguments).toMatchObject([
|
||||
{ content: `items` },
|
||||
{
|
||||
type: NodeTypes.JS_FUNCTION_EXPRESSION,
|
||||
params: [
|
||||
{ content: `item` },
|
||||
{ content: `key` },
|
||||
{ content: `index` }
|
||||
]
|
||||
}
|
||||
])
|
||||
expect(assertSharedCodegen(codegenNode)).toMatchObject({
|
||||
source: { content: `items` },
|
||||
params: [{ content: `item` }, { content: `key` }, { content: `index` }]
|
||||
})
|
||||
expect(generate(root).code).toMatchSnapshot()
|
||||
})
|
||||
|
||||
@@ -624,14 +638,11 @@ describe('compiler: v-for', () => {
|
||||
const {
|
||||
root,
|
||||
node: { codegenNode }
|
||||
} = parseWithForTransform('<span v-for="(,key,index) in items" />')
|
||||
expect(assertSharedCodegen(codegenNode).arguments).toMatchObject([
|
||||
{ content: `items` },
|
||||
{
|
||||
type: NodeTypes.JS_FUNCTION_EXPRESSION,
|
||||
params: [{ content: `_` }, { content: `key` }, { content: `index` }]
|
||||
}
|
||||
])
|
||||
} = parseWithForTransform('<span v-for="(, key, index) in items" />')
|
||||
expect(assertSharedCodegen(codegenNode)).toMatchObject({
|
||||
source: { content: `items` },
|
||||
params: [{ content: `_` }, { content: `key` }, { content: `index` }]
|
||||
})
|
||||
expect(generate(root).code).toMatchSnapshot()
|
||||
})
|
||||
|
||||
@@ -639,18 +650,11 @@ describe('compiler: v-for', () => {
|
||||
const {
|
||||
root,
|
||||
node: { codegenNode }
|
||||
} = parseWithForTransform('<span v-for="(value,,index) in items" />')
|
||||
expect(assertSharedCodegen(codegenNode).arguments).toMatchObject([
|
||||
{ content: `items` },
|
||||
{
|
||||
type: NodeTypes.JS_FUNCTION_EXPRESSION,
|
||||
params: [
|
||||
{ content: `value` },
|
||||
{ content: `__` },
|
||||
{ content: `index` }
|
||||
]
|
||||
}
|
||||
])
|
||||
} = parseWithForTransform('<span v-for="(item,,index) in items" />')
|
||||
expect(assertSharedCodegen(codegenNode)).toMatchObject({
|
||||
source: { content: `items` },
|
||||
params: [{ content: `item` }, { content: `__` }, { content: `index` }]
|
||||
})
|
||||
expect(generate(root).code).toMatchSnapshot()
|
||||
})
|
||||
|
||||
@@ -659,13 +663,10 @@ describe('compiler: v-for', () => {
|
||||
root,
|
||||
node: { codegenNode }
|
||||
} = parseWithForTransform('<span v-for="(,,index) in items" />')
|
||||
expect(assertSharedCodegen(codegenNode).arguments).toMatchObject([
|
||||
{ content: `items` },
|
||||
{
|
||||
type: NodeTypes.JS_FUNCTION_EXPRESSION,
|
||||
params: [{ content: `_` }, { content: `__` }, { content: `index` }]
|
||||
}
|
||||
])
|
||||
expect(assertSharedCodegen(codegenNode)).toMatchObject({
|
||||
source: { content: `items` },
|
||||
params: [{ content: `_` }, { content: `__` }, { content: `index` }]
|
||||
})
|
||||
expect(generate(root).code).toMatchSnapshot()
|
||||
})
|
||||
|
||||
@@ -676,17 +677,60 @@ describe('compiler: v-for', () => {
|
||||
} = parseWithForTransform(
|
||||
'<template v-for="item in items">hello<span/></template>'
|
||||
)
|
||||
expect(assertSharedCodegen(codegenNode).arguments).toMatchObject([
|
||||
{ content: `items` },
|
||||
{
|
||||
type: NodeTypes.JS_FUNCTION_EXPRESSION,
|
||||
params: [{ content: `item` }],
|
||||
returns: [
|
||||
expect(assertSharedCodegen(codegenNode)).toMatchObject({
|
||||
source: { content: `items` },
|
||||
params: [{ content: `item` }],
|
||||
blockArgs: [
|
||||
`_${FRAGMENT}`,
|
||||
`null`,
|
||||
[
|
||||
{ type: NodeTypes.TEXT, content: `hello` },
|
||||
{ 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()
|
||||
})
|
||||
|
||||
@@ -722,12 +766,25 @@ describe('compiler: v-for', () => {
|
||||
type: NodeTypes.JS_FUNCTION_EXPRESSION,
|
||||
params: [{ content: `i` }],
|
||||
returns: {
|
||||
type: NodeTypes.ELEMENT,
|
||||
tag: `div`
|
||||
type: NodeTypes.JS_SEQUENCE_EXPRESSION,
|
||||
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]
|
||||
} */`
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user