wip(vapor): adjust children and block generation order for hydration
This commit is contained in:
parent
e3a33e6092
commit
9722574744
|
@ -149,7 +149,7 @@ export function render(_ctx, $props, $emit, $attrs, $slots) {
|
|||
`;
|
||||
|
||||
exports[`compile > directives > v-pre > should not affect siblings after it 1`] = `
|
||||
"import { resolveComponent as _resolveComponent, child as _child, setInsertionState as _setInsertionState, createComponentWithFallback as _createComponentWithFallback, toDisplayString as _toDisplayString, setText as _setText, setProp as _setProp, renderEffect as _renderEffect, template as _template } from 'vue';
|
||||
"import { resolveComponent as _resolveComponent, setInsertionState as _setInsertionState, createComponentWithFallback as _createComponentWithFallback, child as _child, toDisplayString as _toDisplayString, setText as _setText, setProp as _setProp, renderEffect as _renderEffect, template as _template } from 'vue';
|
||||
const t0 = _template("<div :id=\\"foo\\"><Comp></Comp>{{ bar }}</div>")
|
||||
const t1 = _template("<div> </div>")
|
||||
|
||||
|
@ -157,9 +157,9 @@ export function render(_ctx, $props, $emit, $attrs, $slots) {
|
|||
const _component_Comp = _resolveComponent("Comp")
|
||||
const n0 = t0()
|
||||
const n3 = t1()
|
||||
const n2 = _child(n3)
|
||||
_setInsertionState(n3, 0)
|
||||
const n1 = _createComponentWithFallback(_component_Comp)
|
||||
const n2 = _child(n3)
|
||||
_renderEffect(() => {
|
||||
_setText(n2, _toDisplayString(_ctx.bar))
|
||||
_setProp(n3, "id", _ctx.foo)
|
||||
|
|
|
@ -40,10 +40,10 @@ const t0 = _template("<div><div>x</div><div><span> </span></div><div><span> </sp
|
|||
export function render(_ctx) {
|
||||
const n3 = t0()
|
||||
const p0 = _next(_child(n3))
|
||||
const n0 = _child(p0)
|
||||
const p1 = _next(p0)
|
||||
const n1 = _child(p1)
|
||||
const p2 = _next(p1)
|
||||
const n0 = _child(p0)
|
||||
const n1 = _child(p1)
|
||||
const n2 = _child(p2)
|
||||
const x0 = _child(n0)
|
||||
const x1 = _child(n1)
|
||||
|
|
|
@ -29,8 +29,8 @@ exports[`compiler: element transform > component > generate multi root component
|
|||
const t0 = _template("123")
|
||||
|
||||
export function render(_ctx, $props, $emit, $attrs, $slots) {
|
||||
const n1 = t0()
|
||||
const n0 = _createComponent(_ctx.Comp)
|
||||
const n1 = t0()
|
||||
return [n0, n1]
|
||||
}"
|
||||
`;
|
||||
|
@ -321,8 +321,8 @@ const t2 = _template("<form></form>")
|
|||
|
||||
export function render(_ctx) {
|
||||
const n1 = t1()
|
||||
const n0 = t0()
|
||||
const n3 = t2()
|
||||
const n0 = t0()
|
||||
const n2 = t2()
|
||||
_insert(n0, n1)
|
||||
_insert(n2, n3)
|
||||
|
|
|
@ -25,7 +25,6 @@ const t4 = _template("fine")
|
|||
const t5 = _template("<div> </div>")
|
||||
|
||||
export function render(_ctx) {
|
||||
const n13 = t5()
|
||||
const n0 = _createIf(() => (_ctx.ok), () => {
|
||||
const n2 = t0()
|
||||
return n2
|
||||
|
@ -38,6 +37,7 @@ export function render(_ctx) {
|
|||
const n11 = t4()
|
||||
return [n10, n11]
|
||||
}))
|
||||
const n13 = t5()
|
||||
const x13 = _child(n13)
|
||||
_renderEffect(() => _setText(x13, _toDisplayString(_ctx.text)))
|
||||
return [n0, n13]
|
||||
|
|
|
@ -167,7 +167,6 @@ export function render(_ctx) {
|
|||
const _component_Comp = _resolveComponent("Comp")
|
||||
const n5 = _createComponentWithFallback(_component_Comp, null, {
|
||||
"default": (_slotProps0) => {
|
||||
const n3 = t0()
|
||||
const n1 = _createComponentWithFallback(_component_Inner, null, {
|
||||
"default": (_slotProps1) => {
|
||||
const n0 = t0()
|
||||
|
@ -175,6 +174,7 @@ export function render(_ctx) {
|
|||
return n0
|
||||
}
|
||||
})
|
||||
const n3 = t0()
|
||||
_renderEffect(() => _setText(n3, " " + _toDisplayString(_slotProps0["foo"] + _ctx.bar + _ctx.baz)))
|
||||
return [n1, n3]
|
||||
}
|
||||
|
|
|
@ -29,16 +29,14 @@ describe('compiler: element transform', () => {
|
|||
expect(code).toMatchSnapshot()
|
||||
expect(helpers).contains.all.keys('resolveComponent')
|
||||
expect(helpers).contains.all.keys('createComponentWithFallback')
|
||||
expect(ir.block.operation).toMatchObject([
|
||||
{
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
id: 0,
|
||||
tag: 'Foo',
|
||||
asset: true,
|
||||
root: true,
|
||||
props: [[]],
|
||||
},
|
||||
])
|
||||
expect(ir.block.dynamic.children[0].operation).toMatchObject({
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
id: 0,
|
||||
tag: 'Foo',
|
||||
asset: true,
|
||||
root: true,
|
||||
props: [[]],
|
||||
})
|
||||
})
|
||||
|
||||
test.todo('resolve implicitly self-referencing component', () => {
|
||||
|
@ -57,13 +55,11 @@ describe('compiler: element transform', () => {
|
|||
})
|
||||
expect(code).toMatchSnapshot()
|
||||
expect(helpers).not.toContain('resolveComponent')
|
||||
expect(ir.block.operation).toMatchObject([
|
||||
{
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
tag: 'Example',
|
||||
asset: false,
|
||||
},
|
||||
])
|
||||
expect(ir.block.dynamic.children[0].operation).toMatchObject({
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
tag: 'Example',
|
||||
asset: false,
|
||||
})
|
||||
})
|
||||
|
||||
test('resolve component from setup bindings (inline)', () => {
|
||||
|
@ -149,14 +145,12 @@ describe('compiler: element transform', () => {
|
|||
})
|
||||
expect(code).toMatchSnapshot()
|
||||
expect(helpers).toContain('resolveComponent')
|
||||
expect(ir.block.operation).toMatchObject([
|
||||
{
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
id: 0,
|
||||
tag: 'Example',
|
||||
asset: true,
|
||||
},
|
||||
])
|
||||
expect(ir.block.dynamic.children[0].operation).toMatchObject({
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
id: 0,
|
||||
tag: 'Example',
|
||||
asset: true,
|
||||
})
|
||||
})
|
||||
|
||||
test('generate single root component', () => {
|
||||
|
@ -186,46 +180,44 @@ describe('compiler: element transform', () => {
|
|||
class: () => ("bar")
|
||||
}`)
|
||||
|
||||
expect(ir.block.operation).toMatchObject([
|
||||
{
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
tag: 'Foo',
|
||||
asset: true,
|
||||
root: true,
|
||||
props: [
|
||||
[
|
||||
{
|
||||
key: {
|
||||
expect(ir.block.dynamic.children[0].operation).toMatchObject({
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
tag: 'Foo',
|
||||
asset: true,
|
||||
root: true,
|
||||
props: [
|
||||
[
|
||||
{
|
||||
key: {
|
||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||
content: 'id',
|
||||
isStatic: true,
|
||||
},
|
||||
values: [
|
||||
{
|
||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||
content: 'id',
|
||||
content: 'foo',
|
||||
isStatic: true,
|
||||
},
|
||||
values: [
|
||||
{
|
||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||
content: 'foo',
|
||||
isStatic: true,
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
{
|
||||
key: {
|
||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||
content: 'class',
|
||||
isStatic: true,
|
||||
},
|
||||
{
|
||||
key: {
|
||||
values: [
|
||||
{
|
||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||
content: 'class',
|
||||
content: 'bar',
|
||||
isStatic: true,
|
||||
},
|
||||
values: [
|
||||
{
|
||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||
content: 'bar',
|
||||
isStatic: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
])
|
||||
],
|
||||
})
|
||||
})
|
||||
|
||||
test('v-bind="obj"', () => {
|
||||
|
@ -234,18 +226,16 @@ describe('compiler: element transform', () => {
|
|||
expect(code).contains(`[
|
||||
() => (_ctx.obj)
|
||||
]`)
|
||||
expect(ir.block.operation).toMatchObject([
|
||||
{
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
tag: 'Foo',
|
||||
props: [
|
||||
{
|
||||
kind: IRDynamicPropsKind.EXPRESSION,
|
||||
value: { content: 'obj', isStatic: false },
|
||||
},
|
||||
],
|
||||
},
|
||||
])
|
||||
expect(ir.block.dynamic.children[0].operation).toMatchObject({
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
tag: 'Foo',
|
||||
props: [
|
||||
{
|
||||
kind: IRDynamicPropsKind.EXPRESSION,
|
||||
value: { content: 'obj', isStatic: false },
|
||||
},
|
||||
],
|
||||
})
|
||||
})
|
||||
|
||||
test('v-bind="obj" after static prop', () => {
|
||||
|
@ -259,19 +249,17 @@ describe('compiler: element transform', () => {
|
|||
() => (_ctx.obj)
|
||||
]
|
||||
}`)
|
||||
expect(ir.block.operation).toMatchObject([
|
||||
{
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
tag: 'Foo',
|
||||
props: [
|
||||
[{ key: { content: 'id' }, values: [{ content: 'foo' }] }],
|
||||
{
|
||||
kind: IRDynamicPropsKind.EXPRESSION,
|
||||
value: { content: 'obj' },
|
||||
},
|
||||
],
|
||||
},
|
||||
])
|
||||
expect(ir.block.dynamic.children[0].operation).toMatchObject({
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
tag: 'Foo',
|
||||
props: [
|
||||
[{ key: { content: 'id' }, values: [{ content: 'foo' }] }],
|
||||
{
|
||||
kind: IRDynamicPropsKind.EXPRESSION,
|
||||
value: { content: 'obj' },
|
||||
},
|
||||
],
|
||||
})
|
||||
})
|
||||
|
||||
test('v-bind="obj" before static prop', () => {
|
||||
|
@ -283,19 +271,17 @@ describe('compiler: element transform', () => {
|
|||
() => (_ctx.obj),
|
||||
{ id: () => ("foo") }
|
||||
]`)
|
||||
expect(ir.block.operation).toMatchObject([
|
||||
{
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
tag: 'Foo',
|
||||
props: [
|
||||
{
|
||||
kind: IRDynamicPropsKind.EXPRESSION,
|
||||
value: { content: 'obj' },
|
||||
},
|
||||
[{ key: { content: 'id' }, values: [{ content: 'foo' }] }],
|
||||
],
|
||||
},
|
||||
])
|
||||
expect(ir.block.dynamic.children[0].operation).toMatchObject({
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
tag: 'Foo',
|
||||
props: [
|
||||
{
|
||||
kind: IRDynamicPropsKind.EXPRESSION,
|
||||
value: { content: 'obj' },
|
||||
},
|
||||
[{ key: { content: 'id' }, values: [{ content: 'foo' }] }],
|
||||
],
|
||||
})
|
||||
})
|
||||
|
||||
test('v-bind="obj" between static props', () => {
|
||||
|
@ -310,20 +296,18 @@ describe('compiler: element transform', () => {
|
|||
{ class: () => ("bar") }
|
||||
]
|
||||
}`)
|
||||
expect(ir.block.operation).toMatchObject([
|
||||
{
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
tag: 'Foo',
|
||||
props: [
|
||||
[{ key: { content: 'id' }, values: [{ content: 'foo' }] }],
|
||||
{
|
||||
kind: IRDynamicPropsKind.EXPRESSION,
|
||||
value: { content: 'obj' },
|
||||
},
|
||||
[{ key: { content: 'class' }, values: [{ content: 'bar' }] }],
|
||||
],
|
||||
},
|
||||
])
|
||||
expect(ir.block.dynamic.children[0].operation).toMatchObject({
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
tag: 'Foo',
|
||||
props: [
|
||||
[{ key: { content: 'id' }, values: [{ content: 'foo' }] }],
|
||||
{
|
||||
kind: IRDynamicPropsKind.EXPRESSION,
|
||||
value: { content: 'obj' },
|
||||
},
|
||||
[{ key: { content: 'class' }, values: [{ content: 'bar' }] }],
|
||||
],
|
||||
})
|
||||
})
|
||||
|
||||
test.todo('props merging: event handlers', () => {
|
||||
|
@ -368,19 +352,17 @@ describe('compiler: element transform', () => {
|
|||
expect(code).contains(`[
|
||||
() => (_toHandlers(_ctx.obj))
|
||||
]`)
|
||||
expect(ir.block.operation).toMatchObject([
|
||||
{
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
tag: 'Foo',
|
||||
props: [
|
||||
{
|
||||
kind: IRDynamicPropsKind.EXPRESSION,
|
||||
value: { content: 'obj' },
|
||||
handler: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
])
|
||||
expect(ir.block.dynamic.children[0].operation).toMatchObject({
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
tag: 'Foo',
|
||||
props: [
|
||||
{
|
||||
kind: IRDynamicPropsKind.EXPRESSION,
|
||||
value: { content: 'obj' },
|
||||
handler: true,
|
||||
},
|
||||
],
|
||||
})
|
||||
})
|
||||
|
||||
test('v-on expression is inline statement', () => {
|
||||
|
@ -390,21 +372,19 @@ describe('compiler: element transform', () => {
|
|||
expect(code).toMatchSnapshot()
|
||||
expect(code).contains(`onBar: () => _on_bar`)
|
||||
expect(code).contains(`const _on_bar = () => _ctx.handler`)
|
||||
expect(ir.block.operation).toMatchObject([
|
||||
{
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
tag: 'Foo',
|
||||
props: [
|
||||
[
|
||||
{
|
||||
key: { content: 'bar' },
|
||||
handler: true,
|
||||
values: [{ content: '_on_bar' }],
|
||||
},
|
||||
],
|
||||
expect(ir.block.dynamic.children[0].operation).toMatchObject({
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
tag: 'Foo',
|
||||
props: [
|
||||
[
|
||||
{
|
||||
key: { content: 'bar' },
|
||||
handler: true,
|
||||
values: [{ content: '_on_bar' }],
|
||||
},
|
||||
],
|
||||
},
|
||||
])
|
||||
],
|
||||
})
|
||||
})
|
||||
|
||||
test('v-on expression is a function call', () => {
|
||||
|
@ -416,21 +396,19 @@ describe('compiler: element transform', () => {
|
|||
expect(code).contains(
|
||||
`const _on_bar = $event => (_ctx.handleBar($event))`,
|
||||
)
|
||||
expect(ir.block.operation).toMatchObject([
|
||||
{
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
tag: 'Foo',
|
||||
props: [
|
||||
[
|
||||
{
|
||||
key: { content: 'bar' },
|
||||
handler: true,
|
||||
values: [{ content: '_on_bar' }],
|
||||
},
|
||||
],
|
||||
expect(ir.block.dynamic.children[0].operation).toMatchObject({
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
tag: 'Foo',
|
||||
props: [
|
||||
[
|
||||
{
|
||||
key: { content: 'bar' },
|
||||
handler: true,
|
||||
values: [{ content: '_on_bar' }],
|
||||
},
|
||||
],
|
||||
},
|
||||
])
|
||||
],
|
||||
})
|
||||
})
|
||||
|
||||
test('cache v-on expression with unique handler name', () => {
|
||||
|
@ -444,34 +422,33 @@ describe('compiler: element transform', () => {
|
|||
)
|
||||
expect(code).contains(`onBar: () => _on_bar1`)
|
||||
expect(code).contains(`const _on_bar1 = () => _ctx.handler`)
|
||||
expect(ir.block.operation).toMatchObject([
|
||||
{
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
tag: 'Foo',
|
||||
props: [
|
||||
[
|
||||
{
|
||||
key: { content: 'bar' },
|
||||
handler: true,
|
||||
values: [{ content: '_on_bar' }],
|
||||
},
|
||||
],
|
||||
expect(ir.block.dynamic.children[0].operation).toMatchObject({
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
tag: 'Foo',
|
||||
props: [
|
||||
[
|
||||
{
|
||||
key: { content: 'bar' },
|
||||
handler: true,
|
||||
values: [{ content: '_on_bar' }],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
tag: 'Bar',
|
||||
props: [
|
||||
[
|
||||
{
|
||||
key: { content: 'bar' },
|
||||
handler: true,
|
||||
values: [{ content: '_on_bar1' }],
|
||||
},
|
||||
],
|
||||
],
|
||||
})
|
||||
|
||||
expect(ir.block.dynamic.children[1].operation).toMatchObject({
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
tag: 'Bar',
|
||||
props: [
|
||||
[
|
||||
{
|
||||
key: { content: 'bar' },
|
||||
handler: true,
|
||||
values: [{ content: '_on_bar1' }],
|
||||
},
|
||||
],
|
||||
},
|
||||
])
|
||||
],
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
|
@ -482,20 +459,18 @@ describe('compiler: element transform', () => {
|
|||
)
|
||||
expect(code).toMatchSnapshot()
|
||||
expect(helpers).toContain('resolveDynamicComponent')
|
||||
expect(ir.block.operation).toMatchObject([
|
||||
{
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
tag: 'component',
|
||||
asset: true,
|
||||
root: true,
|
||||
props: [[]],
|
||||
dynamic: {
|
||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||
content: 'foo',
|
||||
isStatic: true,
|
||||
},
|
||||
expect(ir.block.dynamic.children[0].operation).toMatchObject({
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
tag: 'component',
|
||||
asset: true,
|
||||
root: true,
|
||||
props: [[]],
|
||||
dynamic: {
|
||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||
content: 'foo',
|
||||
isStatic: true,
|
||||
},
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
test('capitalized version w/ static binding', () => {
|
||||
|
@ -504,20 +479,18 @@ describe('compiler: element transform', () => {
|
|||
)
|
||||
expect(code).toMatchSnapshot()
|
||||
expect(helpers).toContain('resolveDynamicComponent')
|
||||
expect(ir.block.operation).toMatchObject([
|
||||
{
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
tag: 'Component',
|
||||
asset: true,
|
||||
root: true,
|
||||
props: [[]],
|
||||
dynamic: {
|
||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||
content: 'foo',
|
||||
isStatic: true,
|
||||
},
|
||||
expect(ir.block.dynamic.children[0].operation).toMatchObject({
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
tag: 'Component',
|
||||
asset: true,
|
||||
root: true,
|
||||
props: [[]],
|
||||
dynamic: {
|
||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||
content: 'foo',
|
||||
isStatic: true,
|
||||
},
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
test('dynamic binding', () => {
|
||||
|
@ -526,20 +499,18 @@ describe('compiler: element transform', () => {
|
|||
)
|
||||
expect(code).toMatchSnapshot()
|
||||
expect(helpers).toContain('createDynamicComponent')
|
||||
expect(ir.block.operation).toMatchObject([
|
||||
{
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
tag: 'component',
|
||||
asset: true,
|
||||
root: true,
|
||||
props: [[]],
|
||||
dynamic: {
|
||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||
content: 'foo',
|
||||
isStatic: false,
|
||||
},
|
||||
expect(ir.block.dynamic.children[0].operation).toMatchObject({
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
tag: 'component',
|
||||
asset: true,
|
||||
root: true,
|
||||
props: [[]],
|
||||
dynamic: {
|
||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||
content: 'foo',
|
||||
isStatic: false,
|
||||
},
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
test('dynamic binding shorthand', () => {
|
||||
|
@ -547,20 +518,18 @@ describe('compiler: element transform', () => {
|
|||
compileWithElementTransform(`<component :is />`)
|
||||
expect(code).toMatchSnapshot()
|
||||
expect(helpers).toContain('createDynamicComponent')
|
||||
expect(ir.block.operation).toMatchObject([
|
||||
{
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
tag: 'component',
|
||||
asset: true,
|
||||
root: true,
|
||||
props: [[]],
|
||||
dynamic: {
|
||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||
content: 'is',
|
||||
isStatic: false,
|
||||
},
|
||||
expect(ir.block.dynamic.children[0].operation).toMatchObject({
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
tag: 'component',
|
||||
asset: true,
|
||||
root: true,
|
||||
props: [[]],
|
||||
dynamic: {
|
||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||
content: 'is',
|
||||
isStatic: false,
|
||||
},
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
// #3934
|
||||
|
@ -574,15 +543,13 @@ describe('compiler: element transform', () => {
|
|||
expect(code).toMatchSnapshot()
|
||||
expect(helpers).toContain('resolveComponent')
|
||||
expect(helpers).not.toContain('resolveDynamicComponent')
|
||||
expect(ir.block.operation).toMatchObject([
|
||||
{
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
tag: 'custom-input',
|
||||
asset: true,
|
||||
root: true,
|
||||
props: [[{ key: { content: 'is' }, values: [{ content: 'foo' }] }]],
|
||||
},
|
||||
])
|
||||
expect(ir.block.dynamic.children[0].operation).toMatchObject({
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
tag: 'custom-input',
|
||||
asset: true,
|
||||
root: true,
|
||||
props: [[{ key: { content: 'is' }, values: [{ content: 'foo' }] }]],
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
|
@ -893,24 +860,22 @@ describe('compiler: element transform', () => {
|
|||
`<Foo :[foo-bar]="bar" :[baz]="qux" />`,
|
||||
)
|
||||
expect(code).toMatchSnapshot()
|
||||
expect(ir.block.operation).toMatchObject([
|
||||
{
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
tag: 'Foo',
|
||||
props: [
|
||||
{
|
||||
kind: IRDynamicPropsKind.ATTRIBUTE,
|
||||
key: { content: 'foo-bar' },
|
||||
values: [{ content: 'bar' }],
|
||||
},
|
||||
{
|
||||
kind: IRDynamicPropsKind.ATTRIBUTE,
|
||||
key: { content: 'baz' },
|
||||
values: [{ content: 'qux' }],
|
||||
},
|
||||
],
|
||||
},
|
||||
])
|
||||
expect(ir.block.dynamic.children[0].operation).toMatchObject({
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
tag: 'Foo',
|
||||
props: [
|
||||
{
|
||||
kind: IRDynamicPropsKind.ATTRIBUTE,
|
||||
key: { content: 'foo-bar' },
|
||||
values: [{ content: 'bar' }],
|
||||
},
|
||||
{
|
||||
kind: IRDynamicPropsKind.ATTRIBUTE,
|
||||
key: { content: 'baz' },
|
||||
values: [{ content: 'qux' }],
|
||||
},
|
||||
],
|
||||
})
|
||||
})
|
||||
|
||||
test('component with dynamic event arguments', () => {
|
||||
|
@ -918,26 +883,24 @@ describe('compiler: element transform', () => {
|
|||
`<Foo @[foo-bar]="bar" @[baz]="qux" />`,
|
||||
)
|
||||
expect(code).toMatchSnapshot()
|
||||
expect(ir.block.operation).toMatchObject([
|
||||
{
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
tag: 'Foo',
|
||||
props: [
|
||||
{
|
||||
kind: IRDynamicPropsKind.ATTRIBUTE,
|
||||
key: { content: 'foo-bar' },
|
||||
values: [{ content: 'bar' }],
|
||||
handler: true,
|
||||
},
|
||||
{
|
||||
kind: IRDynamicPropsKind.ATTRIBUTE,
|
||||
key: { content: 'baz' },
|
||||
values: [{ content: 'qux' }],
|
||||
handler: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
])
|
||||
expect(ir.block.dynamic.children[0].operation).toMatchObject({
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
tag: 'Foo',
|
||||
props: [
|
||||
{
|
||||
kind: IRDynamicPropsKind.ATTRIBUTE,
|
||||
key: { content: 'foo-bar' },
|
||||
values: [{ content: 'bar' }],
|
||||
handler: true,
|
||||
},
|
||||
{
|
||||
kind: IRDynamicPropsKind.ATTRIBUTE,
|
||||
key: { content: 'baz' },
|
||||
values: [{ content: 'qux' }],
|
||||
handler: true,
|
||||
},
|
||||
],
|
||||
})
|
||||
})
|
||||
|
||||
test('component event with once modifier', () => {
|
||||
|
|
|
@ -31,67 +31,59 @@ describe('compiler: transform <slot> outlets', () => {
|
|||
expect(code).toMatchSnapshot()
|
||||
expect(helpers).toContain('createSlot')
|
||||
expect(ir.block.effect).toEqual([])
|
||||
expect(ir.block.operation).toMatchObject([
|
||||
{
|
||||
type: IRNodeTypes.SLOT_OUTLET_NODE,
|
||||
id: 0,
|
||||
name: {
|
||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||
content: 'default',
|
||||
isStatic: true,
|
||||
},
|
||||
props: [],
|
||||
fallback: undefined,
|
||||
expect(ir.block.dynamic.children[0].operation).toMatchObject({
|
||||
type: IRNodeTypes.SLOT_OUTLET_NODE,
|
||||
id: 0,
|
||||
name: {
|
||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||
content: 'default',
|
||||
isStatic: true,
|
||||
},
|
||||
])
|
||||
props: [],
|
||||
fallback: undefined,
|
||||
})
|
||||
})
|
||||
|
||||
test('statically named slot outlet', () => {
|
||||
const { ir, code } = compileWithSlotsOutlet(`<slot name="foo" />`)
|
||||
expect(code).toMatchSnapshot()
|
||||
expect(ir.block.operation).toMatchObject([
|
||||
{
|
||||
type: IRNodeTypes.SLOT_OUTLET_NODE,
|
||||
id: 0,
|
||||
name: {
|
||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||
content: 'foo',
|
||||
isStatic: true,
|
||||
},
|
||||
expect(ir.block.dynamic.children[0].operation).toMatchObject({
|
||||
type: IRNodeTypes.SLOT_OUTLET_NODE,
|
||||
id: 0,
|
||||
name: {
|
||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||
content: 'foo',
|
||||
isStatic: true,
|
||||
},
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
test('dynamically named slot outlet', () => {
|
||||
const { ir, code } = compileWithSlotsOutlet(`<slot :name="foo + bar" />`)
|
||||
expect(code).toMatchSnapshot()
|
||||
expect(ir.block.operation).toMatchObject([
|
||||
{
|
||||
type: IRNodeTypes.SLOT_OUTLET_NODE,
|
||||
id: 0,
|
||||
name: {
|
||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||
content: 'foo + bar',
|
||||
isStatic: false,
|
||||
},
|
||||
expect(ir.block.dynamic.children[0].operation).toMatchObject({
|
||||
type: IRNodeTypes.SLOT_OUTLET_NODE,
|
||||
id: 0,
|
||||
name: {
|
||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||
content: 'foo + bar',
|
||||
isStatic: false,
|
||||
},
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
test('dynamically named slot outlet with v-bind shorthand', () => {
|
||||
const { ir, code } = compileWithSlotsOutlet(`<slot :name />`)
|
||||
expect(code).toMatchSnapshot()
|
||||
expect(ir.block.operation).toMatchObject([
|
||||
{
|
||||
type: IRNodeTypes.SLOT_OUTLET_NODE,
|
||||
id: 0,
|
||||
name: {
|
||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||
content: 'name',
|
||||
isStatic: false,
|
||||
},
|
||||
expect(ir.block.dynamic.children[0].operation).toMatchObject({
|
||||
type: IRNodeTypes.SLOT_OUTLET_NODE,
|
||||
id: 0,
|
||||
name: {
|
||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||
content: 'name',
|
||||
isStatic: false,
|
||||
},
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
test('default slot outlet with props', () => {
|
||||
|
@ -99,19 +91,17 @@ describe('compiler: transform <slot> outlets', () => {
|
|||
`<slot foo="bar" :baz="qux" :foo-bar="foo-bar" />`,
|
||||
)
|
||||
expect(code).toMatchSnapshot()
|
||||
expect(ir.block.operation).toMatchObject([
|
||||
{
|
||||
type: IRNodeTypes.SLOT_OUTLET_NODE,
|
||||
name: { content: 'default' },
|
||||
props: [
|
||||
[
|
||||
{ key: { content: 'foo' }, values: [{ content: 'bar' }] },
|
||||
{ key: { content: 'baz' }, values: [{ content: 'qux' }] },
|
||||
{ key: { content: 'fooBar' }, values: [{ content: 'foo-bar' }] },
|
||||
],
|
||||
expect(ir.block.dynamic.children[0].operation).toMatchObject({
|
||||
type: IRNodeTypes.SLOT_OUTLET_NODE,
|
||||
name: { content: 'default' },
|
||||
props: [
|
||||
[
|
||||
{ key: { content: 'foo' }, values: [{ content: 'bar' }] },
|
||||
{ key: { content: 'baz' }, values: [{ content: 'qux' }] },
|
||||
{ key: { content: 'fooBar' }, values: [{ content: 'foo-bar' }] },
|
||||
],
|
||||
},
|
||||
])
|
||||
],
|
||||
})
|
||||
})
|
||||
|
||||
test('statically named slot outlet with props', () => {
|
||||
|
@ -119,18 +109,16 @@ describe('compiler: transform <slot> outlets', () => {
|
|||
`<slot name="foo" foo="bar" :baz="qux" />`,
|
||||
)
|
||||
expect(code).toMatchSnapshot()
|
||||
expect(ir.block.operation).toMatchObject([
|
||||
{
|
||||
type: IRNodeTypes.SLOT_OUTLET_NODE,
|
||||
name: { content: 'foo' },
|
||||
props: [
|
||||
[
|
||||
{ key: { content: 'foo' }, values: [{ content: 'bar' }] },
|
||||
{ key: { content: 'baz' }, values: [{ content: 'qux' }] },
|
||||
],
|
||||
expect(ir.block.dynamic.children[0].operation).toMatchObject({
|
||||
type: IRNodeTypes.SLOT_OUTLET_NODE,
|
||||
name: { content: 'foo' },
|
||||
props: [
|
||||
[
|
||||
{ key: { content: 'foo' }, values: [{ content: 'bar' }] },
|
||||
{ key: { content: 'baz' }, values: [{ content: 'qux' }] },
|
||||
],
|
||||
},
|
||||
])
|
||||
],
|
||||
})
|
||||
})
|
||||
|
||||
test('statically named slot outlet with v-bind="obj"', () => {
|
||||
|
@ -138,17 +126,15 @@ describe('compiler: transform <slot> outlets', () => {
|
|||
`<slot name="foo" foo="bar" v-bind="obj" :baz="qux" />`,
|
||||
)
|
||||
expect(code).toMatchSnapshot()
|
||||
expect(ir.block.operation).toMatchObject([
|
||||
{
|
||||
type: IRNodeTypes.SLOT_OUTLET_NODE,
|
||||
name: { content: 'foo' },
|
||||
props: [
|
||||
[{ key: { content: 'foo' }, values: [{ content: 'bar' }] }],
|
||||
{ value: { content: 'obj', isStatic: false } },
|
||||
[{ key: { content: 'baz' }, values: [{ content: 'qux' }] }],
|
||||
],
|
||||
},
|
||||
])
|
||||
expect(ir.block.dynamic.children[0].operation).toMatchObject({
|
||||
type: IRNodeTypes.SLOT_OUTLET_NODE,
|
||||
name: { content: 'foo' },
|
||||
props: [
|
||||
[{ key: { content: 'foo' }, values: [{ content: 'bar' }] }],
|
||||
{ value: { content: 'obj', isStatic: false } },
|
||||
[{ key: { content: 'baz' }, values: [{ content: 'qux' }] }],
|
||||
],
|
||||
})
|
||||
})
|
||||
|
||||
test('statically named slot outlet with v-on', () => {
|
||||
|
@ -156,36 +142,32 @@ describe('compiler: transform <slot> outlets', () => {
|
|||
`<slot @click="foo" v-on="bar" :baz="qux" />`,
|
||||
)
|
||||
expect(code).toMatchSnapshot()
|
||||
expect(ir.block.operation).toMatchObject([
|
||||
{
|
||||
type: IRNodeTypes.SLOT_OUTLET_NODE,
|
||||
props: [
|
||||
[{ key: { content: 'click' }, values: [{ content: 'foo' }] }],
|
||||
{ value: { content: 'bar' }, handler: true },
|
||||
[{ key: { content: 'baz' }, values: [{ content: 'qux' }] }],
|
||||
],
|
||||
},
|
||||
])
|
||||
expect(ir.block.dynamic.children[0].operation).toMatchObject({
|
||||
type: IRNodeTypes.SLOT_OUTLET_NODE,
|
||||
props: [
|
||||
[{ key: { content: 'click' }, values: [{ content: 'foo' }] }],
|
||||
{ value: { content: 'bar' }, handler: true },
|
||||
[{ key: { content: 'baz' }, values: [{ content: 'qux' }] }],
|
||||
],
|
||||
})
|
||||
})
|
||||
|
||||
test('default slot outlet with fallback', () => {
|
||||
const { ir, code } = compileWithSlotsOutlet(`<slot><div/></slot>`)
|
||||
expect(code).toMatchSnapshot()
|
||||
expect(ir.template[0]).toBe('<div></div>')
|
||||
expect(ir.block.operation).toMatchObject([
|
||||
{
|
||||
type: IRNodeTypes.SLOT_OUTLET_NODE,
|
||||
id: 0,
|
||||
name: { content: 'default' },
|
||||
fallback: {
|
||||
type: IRNodeTypes.BLOCK,
|
||||
dynamic: {
|
||||
children: [{ template: 0, id: 2 }],
|
||||
},
|
||||
returns: [2],
|
||||
expect(ir.block.dynamic.children[0].operation).toMatchObject({
|
||||
type: IRNodeTypes.SLOT_OUTLET_NODE,
|
||||
id: 0,
|
||||
name: { content: 'default' },
|
||||
fallback: {
|
||||
type: IRNodeTypes.BLOCK,
|
||||
dynamic: {
|
||||
children: [{ template: 0, id: 2 }],
|
||||
},
|
||||
returns: [2],
|
||||
},
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
test('named slot outlet with fallback', () => {
|
||||
|
@ -194,20 +176,18 @@ describe('compiler: transform <slot> outlets', () => {
|
|||
)
|
||||
expect(code).toMatchSnapshot()
|
||||
expect(ir.template[0]).toBe('<div></div>')
|
||||
expect(ir.block.operation).toMatchObject([
|
||||
{
|
||||
type: IRNodeTypes.SLOT_OUTLET_NODE,
|
||||
id: 0,
|
||||
name: { content: 'foo' },
|
||||
fallback: {
|
||||
type: IRNodeTypes.BLOCK,
|
||||
dynamic: {
|
||||
children: [{ template: 0, id: 2 }],
|
||||
},
|
||||
returns: [2],
|
||||
expect(ir.block.dynamic.children[0].operation).toMatchObject({
|
||||
type: IRNodeTypes.SLOT_OUTLET_NODE,
|
||||
id: 0,
|
||||
name: { content: 'foo' },
|
||||
fallback: {
|
||||
type: IRNodeTypes.BLOCK,
|
||||
dynamic: {
|
||||
children: [{ template: 0, id: 2 }],
|
||||
},
|
||||
returns: [2],
|
||||
},
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
test('default slot outlet with props & fallback', () => {
|
||||
|
@ -216,21 +196,19 @@ describe('compiler: transform <slot> outlets', () => {
|
|||
)
|
||||
expect(code).toMatchSnapshot()
|
||||
expect(ir.template[0]).toBe('<div></div>')
|
||||
expect(ir.block.operation).toMatchObject([
|
||||
{
|
||||
type: IRNodeTypes.SLOT_OUTLET_NODE,
|
||||
id: 0,
|
||||
name: { content: 'default' },
|
||||
props: [[{ key: { content: 'foo' }, values: [{ content: 'bar' }] }]],
|
||||
fallback: {
|
||||
type: IRNodeTypes.BLOCK,
|
||||
dynamic: {
|
||||
children: [{ template: 0, id: 2 }],
|
||||
},
|
||||
returns: [2],
|
||||
expect(ir.block.dynamic.children[0].operation).toMatchObject({
|
||||
type: IRNodeTypes.SLOT_OUTLET_NODE,
|
||||
id: 0,
|
||||
name: { content: 'default' },
|
||||
props: [[{ key: { content: 'foo' }, values: [{ content: 'bar' }] }]],
|
||||
fallback: {
|
||||
type: IRNodeTypes.BLOCK,
|
||||
dynamic: {
|
||||
children: [{ template: 0, id: 2 }],
|
||||
},
|
||||
returns: [2],
|
||||
},
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
test('named slot outlet with props & fallback', () => {
|
||||
|
@ -239,21 +217,19 @@ describe('compiler: transform <slot> outlets', () => {
|
|||
)
|
||||
expect(code).toMatchSnapshot()
|
||||
expect(ir.template[0]).toBe('<div></div>')
|
||||
expect(ir.block.operation).toMatchObject([
|
||||
{
|
||||
type: IRNodeTypes.SLOT_OUTLET_NODE,
|
||||
id: 0,
|
||||
name: { content: 'foo' },
|
||||
props: [[{ key: { content: 'foo' }, values: [{ content: 'bar' }] }]],
|
||||
fallback: {
|
||||
type: IRNodeTypes.BLOCK,
|
||||
dynamic: {
|
||||
children: [{ template: 0, id: 2 }],
|
||||
},
|
||||
returns: [2],
|
||||
expect(ir.block.dynamic.children[0].operation).toMatchObject({
|
||||
type: IRNodeTypes.SLOT_OUTLET_NODE,
|
||||
id: 0,
|
||||
name: { content: 'foo' },
|
||||
props: [[{ key: { content: 'foo' }, values: [{ content: 'bar' }] }]],
|
||||
fallback: {
|
||||
type: IRNodeTypes.BLOCK,
|
||||
dynamic: {
|
||||
children: [{ template: 0, id: 2 }],
|
||||
},
|
||||
returns: [2],
|
||||
},
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
test('error on unexpected custom directive on <slot>', () => {
|
||||
|
|
|
@ -86,10 +86,10 @@ describe('compiler: template ref transform', () => {
|
|||
`<div ref="foo" v-if="true" />`,
|
||||
)
|
||||
|
||||
expect(ir.block.operation).lengthOf(1)
|
||||
expect(ir.block.operation[0].type).toBe(IRNodeTypes.IF)
|
||||
const op = ir.block.dynamic.children[0].operation as IfIRNode
|
||||
expect(op.type).toBe(IRNodeTypes.IF)
|
||||
|
||||
const { positive } = ir.block.operation[0] as IfIRNode
|
||||
const { positive } = op
|
||||
expect(positive.operation).toMatchObject([
|
||||
{
|
||||
type: IRNodeTypes.SET_TEMPLATE_REF,
|
||||
|
@ -111,7 +111,7 @@ describe('compiler: template ref transform', () => {
|
|||
`<div ref="foo" v-for="item in [1,2,3]" />`,
|
||||
)
|
||||
|
||||
const { render } = ir.block.operation[0] as ForIRNode
|
||||
const { render } = ir.block.dynamic.children[0].operation as ForIRNode
|
||||
expect(render.operation).toMatchObject([
|
||||
{
|
||||
type: IRNodeTypes.SET_TEMPLATE_REF,
|
||||
|
|
|
@ -33,38 +33,38 @@ describe('compiler: v-for', () => {
|
|||
expect(code).matchSnapshot()
|
||||
expect(helpers).contains('createFor')
|
||||
expect(ir.template).toEqual(['<div> </div>'])
|
||||
expect(ir.block.operation).toMatchObject([
|
||||
{
|
||||
type: IRNodeTypes.FOR,
|
||||
id: 0,
|
||||
source: {
|
||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||
content: 'items',
|
||||
},
|
||||
value: {
|
||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||
content: 'item',
|
||||
},
|
||||
key: undefined,
|
||||
index: undefined,
|
||||
render: {
|
||||
type: IRNodeTypes.BLOCK,
|
||||
dynamic: {
|
||||
children: [{ template: 0 }],
|
||||
},
|
||||
},
|
||||
keyProp: {
|
||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||
content: 'item.id',
|
||||
expect(ir.block.dynamic.children[0].operation).toMatchObject({
|
||||
type: IRNodeTypes.FOR,
|
||||
id: 0,
|
||||
source: {
|
||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||
content: 'items',
|
||||
},
|
||||
value: {
|
||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||
content: 'item',
|
||||
},
|
||||
key: undefined,
|
||||
index: undefined,
|
||||
render: {
|
||||
type: IRNodeTypes.BLOCK,
|
||||
dynamic: {
|
||||
children: [{ template: 0 }],
|
||||
},
|
||||
},
|
||||
])
|
||||
keyProp: {
|
||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||
content: 'item.id',
|
||||
},
|
||||
})
|
||||
expect(ir.block.returns).toEqual([0])
|
||||
expect(ir.block.dynamic).toMatchObject({
|
||||
children: [{ id: 0 }],
|
||||
})
|
||||
expect(ir.block.effect).toEqual([])
|
||||
expect((ir.block.operation[0] as ForIRNode).render.effect).lengthOf(1)
|
||||
expect(
|
||||
(ir.block.dynamic.children[0].operation as ForIRNode).render.effect,
|
||||
).lengthOf(1)
|
||||
})
|
||||
|
||||
test('multi effect', () => {
|
||||
|
@ -90,21 +90,22 @@ describe('compiler: v-for', () => {
|
|||
)
|
||||
expect(code).contains(`_for_item1.value+_for_item0.value`)
|
||||
expect(ir.template).toEqual(['<span> </span>', '<div></div>'])
|
||||
expect(ir.block.operation).toMatchObject([
|
||||
{
|
||||
type: IRNodeTypes.FOR,
|
||||
id: 0,
|
||||
source: { content: 'list' },
|
||||
value: { content: 'i' },
|
||||
render: {
|
||||
type: IRNodeTypes.BLOCK,
|
||||
dynamic: {
|
||||
children: [{ template: 1 }],
|
||||
},
|
||||
const parentOp = ir.block.dynamic.children[0].operation
|
||||
expect(parentOp).toMatchObject({
|
||||
type: IRNodeTypes.FOR,
|
||||
id: 0,
|
||||
source: { content: 'list' },
|
||||
value: { content: 'i' },
|
||||
render: {
|
||||
type: IRNodeTypes.BLOCK,
|
||||
dynamic: {
|
||||
children: [{ template: 1 }],
|
||||
},
|
||||
},
|
||||
])
|
||||
expect((ir.block.operation[0] as any).render.operation[0]).toMatchObject({
|
||||
})
|
||||
expect(
|
||||
(parentOp as any).render.dynamic.children[0].children[0].operation,
|
||||
).toMatchObject({
|
||||
type: IRNodeTypes.FOR,
|
||||
id: 2,
|
||||
source: { content: 'i' },
|
||||
|
@ -123,7 +124,7 @@ describe('compiler: v-for', () => {
|
|||
'<span v-for="({ id, value }) in items" :key="id">{{ id }}{{ value }}</span>',
|
||||
)
|
||||
expect(code).matchSnapshot()
|
||||
expect(ir.block.operation[0]).toMatchObject({
|
||||
expect(ir.block.dynamic.children[0].operation).toMatchObject({
|
||||
type: IRNodeTypes.FOR,
|
||||
source: {
|
||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||
|
@ -152,7 +153,7 @@ describe('compiler: v-for', () => {
|
|||
)
|
||||
expect(code).matchSnapshot()
|
||||
expect(code).toContain('_getRestElement(_for_item0.value, ["id"])')
|
||||
expect(ir.block.operation[0]).toMatchObject({
|
||||
expect(ir.block.dynamic.children[0].operation).toMatchObject({
|
||||
type: IRNodeTypes.FOR,
|
||||
source: {
|
||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||
|
@ -183,7 +184,7 @@ describe('compiler: v-for', () => {
|
|||
`<div v-for="([id, other], index) in list" :key="id">{{ id + other + index }}</div>`,
|
||||
)
|
||||
expect(code).matchSnapshot()
|
||||
expect(ir.block.operation[0]).toMatchObject({
|
||||
expect(ir.block.dynamic.children[0].operation).toMatchObject({
|
||||
type: IRNodeTypes.FOR,
|
||||
source: {
|
||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||
|
@ -215,7 +216,7 @@ describe('compiler: v-for', () => {
|
|||
)
|
||||
expect(code).matchSnapshot()
|
||||
expect(code).toContain('_for_item0.value.slice(1)')
|
||||
expect(ir.block.operation[0]).toMatchObject({
|
||||
expect(ir.block.dynamic.children[0].operation).toMatchObject({
|
||||
type: IRNodeTypes.FOR,
|
||||
source: {
|
||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||
|
@ -252,7 +253,7 @@ describe('compiler: v-for', () => {
|
|||
expect(code).toContain(
|
||||
`_getDefaultValue(_for_item0.value.baz[0], _ctx.quux)`,
|
||||
)
|
||||
expect(ir.block.operation[0]).toMatchObject({
|
||||
expect(ir.block.dynamic.children[0].operation).toMatchObject({
|
||||
type: IRNodeTypes.FOR,
|
||||
source: {
|
||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||
|
|
|
@ -33,23 +33,23 @@ describe('compiler: v-if', () => {
|
|||
expect(helpers).contains('createIf')
|
||||
|
||||
expect(ir.template).toEqual(['<div> </div>'])
|
||||
expect(ir.block.operation).toMatchObject([
|
||||
{
|
||||
type: IRNodeTypes.IF,
|
||||
id: 0,
|
||||
condition: {
|
||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||
content: 'ok',
|
||||
isStatic: false,
|
||||
},
|
||||
positive: {
|
||||
type: IRNodeTypes.BLOCK,
|
||||
dynamic: {
|
||||
children: [{ template: 0 }],
|
||||
},
|
||||
|
||||
const op = ir.block.dynamic.children[0].operation
|
||||
expect(op).toMatchObject({
|
||||
type: IRNodeTypes.IF,
|
||||
id: 0,
|
||||
condition: {
|
||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||
content: 'ok',
|
||||
isStatic: false,
|
||||
},
|
||||
positive: {
|
||||
type: IRNodeTypes.BLOCK,
|
||||
dynamic: {
|
||||
children: [{ template: 0 }],
|
||||
},
|
||||
},
|
||||
])
|
||||
})
|
||||
expect(ir.block.returns).toEqual([0])
|
||||
|
||||
expect(ir.block.dynamic).toMatchObject({
|
||||
|
@ -57,7 +57,7 @@ describe('compiler: v-if', () => {
|
|||
})
|
||||
|
||||
expect(ir.block.effect).toEqual([])
|
||||
expect((ir.block.operation[0] as IfIRNode).positive.effect).lengthOf(1)
|
||||
expect((op as IfIRNode).positive.effect).lengthOf(1)
|
||||
|
||||
expect(code).matchSnapshot()
|
||||
})
|
||||
|
@ -70,7 +70,8 @@ describe('compiler: v-if', () => {
|
|||
|
||||
expect(ir.template).toEqual(['<div></div>', 'hello', '<p> </p>'])
|
||||
expect(ir.block.effect).toEqual([])
|
||||
expect((ir.block.operation[0] as IfIRNode).positive.effect).toMatchObject([
|
||||
const op = ir.block.dynamic.children[0].operation as IfIRNode
|
||||
expect(op.positive.effect).toMatchObject([
|
||||
{
|
||||
operations: [
|
||||
{
|
||||
|
@ -87,7 +88,7 @@ describe('compiler: v-if', () => {
|
|||
],
|
||||
},
|
||||
])
|
||||
expect((ir.block.operation[0] as IfIRNode).positive.dynamic).toMatchObject({
|
||||
expect(op.positive.dynamic).toMatchObject({
|
||||
id: 1,
|
||||
children: {
|
||||
2: {
|
||||
|
@ -116,29 +117,27 @@ describe('compiler: v-if', () => {
|
|||
|
||||
expect(helpers).contains('createIf')
|
||||
expect(ir.block.effect).lengthOf(0)
|
||||
expect(ir.block.operation).toMatchObject([
|
||||
{
|
||||
type: IRNodeTypes.IF,
|
||||
id: 0,
|
||||
condition: {
|
||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||
content: 'ok',
|
||||
isStatic: false,
|
||||
},
|
||||
positive: {
|
||||
type: IRNodeTypes.BLOCK,
|
||||
dynamic: {
|
||||
children: [{ template: 0 }],
|
||||
},
|
||||
},
|
||||
negative: {
|
||||
type: IRNodeTypes.BLOCK,
|
||||
dynamic: {
|
||||
children: [{ template: 1 }],
|
||||
},
|
||||
expect(ir.block.dynamic.children[0].operation).toMatchObject({
|
||||
type: IRNodeTypes.IF,
|
||||
id: 0,
|
||||
condition: {
|
||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||
content: 'ok',
|
||||
isStatic: false,
|
||||
},
|
||||
positive: {
|
||||
type: IRNodeTypes.BLOCK,
|
||||
dynamic: {
|
||||
children: [{ template: 0 }],
|
||||
},
|
||||
},
|
||||
])
|
||||
negative: {
|
||||
type: IRNodeTypes.BLOCK,
|
||||
dynamic: {
|
||||
children: [{ template: 1 }],
|
||||
},
|
||||
},
|
||||
})
|
||||
expect(ir.block.returns).toEqual([0])
|
||||
})
|
||||
|
||||
|
@ -149,37 +148,35 @@ describe('compiler: v-if', () => {
|
|||
expect(code).matchSnapshot()
|
||||
expect(ir.template).toEqual(['<div></div>', '<p></p>'])
|
||||
|
||||
expect(ir.block.operation).toMatchObject([
|
||||
{
|
||||
expect(ir.block.dynamic.children[0].operation).toMatchObject({
|
||||
type: IRNodeTypes.IF,
|
||||
id: 0,
|
||||
condition: {
|
||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||
content: 'ok',
|
||||
isStatic: false,
|
||||
},
|
||||
positive: {
|
||||
type: IRNodeTypes.BLOCK,
|
||||
dynamic: {
|
||||
children: [{ template: 0 }],
|
||||
},
|
||||
},
|
||||
negative: {
|
||||
type: IRNodeTypes.IF,
|
||||
id: 0,
|
||||
condition: {
|
||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||
content: 'ok',
|
||||
content: 'orNot',
|
||||
isStatic: false,
|
||||
},
|
||||
positive: {
|
||||
type: IRNodeTypes.BLOCK,
|
||||
dynamic: {
|
||||
children: [{ template: 0 }],
|
||||
},
|
||||
},
|
||||
negative: {
|
||||
type: IRNodeTypes.IF,
|
||||
condition: {
|
||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||
content: 'orNot',
|
||||
isStatic: false,
|
||||
},
|
||||
positive: {
|
||||
type: IRNodeTypes.BLOCK,
|
||||
dynamic: {
|
||||
children: [{ template: 1 }],
|
||||
},
|
||||
children: [{ template: 1 }],
|
||||
},
|
||||
},
|
||||
},
|
||||
])
|
||||
})
|
||||
expect(ir.block.returns).toEqual([0])
|
||||
})
|
||||
|
||||
|
@ -191,33 +188,31 @@ describe('compiler: v-if', () => {
|
|||
expect(ir.template).toEqual(['<div></div>', '<p></p>', 'fine'])
|
||||
|
||||
expect(ir.block.returns).toEqual([0])
|
||||
expect(ir.block.operation).toMatchObject([
|
||||
{
|
||||
expect(ir.block.dynamic.children[0].operation).toMatchObject({
|
||||
type: IRNodeTypes.IF,
|
||||
id: 0,
|
||||
positive: {
|
||||
type: IRNodeTypes.BLOCK,
|
||||
dynamic: {
|
||||
children: [{ template: 0 }],
|
||||
},
|
||||
},
|
||||
negative: {
|
||||
type: IRNodeTypes.IF,
|
||||
id: 0,
|
||||
positive: {
|
||||
type: IRNodeTypes.BLOCK,
|
||||
dynamic: {
|
||||
children: [{ template: 0 }],
|
||||
children: [{ template: 1 }],
|
||||
},
|
||||
},
|
||||
negative: {
|
||||
type: IRNodeTypes.IF,
|
||||
positive: {
|
||||
type: IRNodeTypes.BLOCK,
|
||||
dynamic: {
|
||||
children: [{ template: 1 }],
|
||||
},
|
||||
},
|
||||
negative: {
|
||||
type: IRNodeTypes.BLOCK,
|
||||
dynamic: {
|
||||
children: [{ template: 2 }],
|
||||
},
|
||||
type: IRNodeTypes.BLOCK,
|
||||
dynamic: {
|
||||
children: [{ template: 2 }],
|
||||
},
|
||||
},
|
||||
},
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
test('comment between branches', () => {
|
||||
|
|
|
@ -206,22 +206,20 @@ describe('compiler: vModel transform', () => {
|
|||
expect(code).contains(
|
||||
`"onUpdate:modelValue": () => _value => (_ctx.foo = _value)`,
|
||||
)
|
||||
expect(ir.block.operation).toMatchObject([
|
||||
{
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
tag: 'Comp',
|
||||
props: [
|
||||
[
|
||||
{
|
||||
key: { content: 'modelValue', isStatic: true },
|
||||
model: true,
|
||||
modelModifiers: [],
|
||||
values: [{ content: 'foo', isStatic: false }],
|
||||
},
|
||||
],
|
||||
expect(ir.block.dynamic.children[0].operation).toMatchObject({
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
tag: 'Comp',
|
||||
props: [
|
||||
[
|
||||
{
|
||||
key: { content: 'modelValue', isStatic: true },
|
||||
model: true,
|
||||
modelModifiers: [],
|
||||
values: [{ content: 'foo', isStatic: false }],
|
||||
},
|
||||
],
|
||||
},
|
||||
])
|
||||
],
|
||||
})
|
||||
})
|
||||
|
||||
test('v-model with arguments for component should work', () => {
|
||||
|
@ -231,22 +229,20 @@ describe('compiler: vModel transform', () => {
|
|||
expect(code).contains(
|
||||
`"onUpdate:bar": () => _value => (_ctx.foo = _value)`,
|
||||
)
|
||||
expect(ir.block.operation).toMatchObject([
|
||||
{
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
tag: 'Comp',
|
||||
props: [
|
||||
[
|
||||
{
|
||||
key: { content: 'bar', isStatic: true },
|
||||
model: true,
|
||||
modelModifiers: [],
|
||||
values: [{ content: 'foo', isStatic: false }],
|
||||
},
|
||||
],
|
||||
expect(ir.block.dynamic.children[0].operation).toMatchObject({
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
tag: 'Comp',
|
||||
props: [
|
||||
[
|
||||
{
|
||||
key: { content: 'bar', isStatic: true },
|
||||
model: true,
|
||||
modelModifiers: [],
|
||||
values: [{ content: 'foo', isStatic: false }],
|
||||
},
|
||||
],
|
||||
},
|
||||
])
|
||||
],
|
||||
})
|
||||
})
|
||||
|
||||
test('v-model with dynamic arguments for component should work', () => {
|
||||
|
@ -256,20 +252,18 @@ describe('compiler: vModel transform', () => {
|
|||
`[_ctx.arg]: _ctx.foo,
|
||||
["onUpdate:" + _ctx.arg]: () => _value => (_ctx.foo = _value)`,
|
||||
)
|
||||
expect(ir.block.operation).toMatchObject([
|
||||
{
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
tag: 'Comp',
|
||||
props: [
|
||||
{
|
||||
key: { content: 'arg', isStatic: false },
|
||||
values: [{ content: 'foo', isStatic: false }],
|
||||
model: true,
|
||||
modelModifiers: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
])
|
||||
expect(ir.block.dynamic.children[0].operation).toMatchObject({
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
tag: 'Comp',
|
||||
props: [
|
||||
{
|
||||
key: { content: 'arg', isStatic: false },
|
||||
values: [{ content: 'foo', isStatic: false }],
|
||||
model: true,
|
||||
modelModifiers: [],
|
||||
},
|
||||
],
|
||||
})
|
||||
})
|
||||
|
||||
test('v-model for component should generate modelModifiers', () => {
|
||||
|
@ -280,22 +274,20 @@ describe('compiler: vModel transform', () => {
|
|||
expect(code).contain(
|
||||
`modelModifiers: () => ({ trim: true, "bar-baz": true })`,
|
||||
)
|
||||
expect(ir.block.operation).toMatchObject([
|
||||
{
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
tag: 'Comp',
|
||||
props: [
|
||||
[
|
||||
{
|
||||
key: { content: 'modelValue', isStatic: true },
|
||||
values: [{ content: 'foo', isStatic: false }],
|
||||
model: true,
|
||||
modelModifiers: ['trim', 'bar-baz'],
|
||||
},
|
||||
],
|
||||
expect(ir.block.dynamic.children[0].operation).toMatchObject({
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
tag: 'Comp',
|
||||
props: [
|
||||
[
|
||||
{
|
||||
key: { content: 'modelValue', isStatic: true },
|
||||
values: [{ content: 'foo', isStatic: false }],
|
||||
model: true,
|
||||
modelModifiers: ['trim', 'bar-baz'],
|
||||
},
|
||||
],
|
||||
},
|
||||
])
|
||||
],
|
||||
})
|
||||
})
|
||||
|
||||
test('v-model with arguments for component should generate modelModifiers', () => {
|
||||
|
@ -305,28 +297,26 @@ describe('compiler: vModel transform', () => {
|
|||
expect(code).toMatchSnapshot()
|
||||
expect(code).contain(`fooModifiers: () => ({ trim: true })`)
|
||||
expect(code).contain(`barModifiers: () => ({ number: true })`)
|
||||
expect(ir.block.operation).toMatchObject([
|
||||
{
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
tag: 'Comp',
|
||||
props: [
|
||||
[
|
||||
{
|
||||
key: { content: 'foo', isStatic: true },
|
||||
values: [{ content: 'foo', isStatic: false }],
|
||||
model: true,
|
||||
modelModifiers: ['trim'],
|
||||
},
|
||||
{
|
||||
key: { content: 'bar', isStatic: true },
|
||||
values: [{ content: 'bar', isStatic: false }],
|
||||
model: true,
|
||||
modelModifiers: ['number'],
|
||||
},
|
||||
],
|
||||
expect(ir.block.dynamic.children[0].operation).toMatchObject({
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
tag: 'Comp',
|
||||
props: [
|
||||
[
|
||||
{
|
||||
key: { content: 'foo', isStatic: true },
|
||||
values: [{ content: 'foo', isStatic: false }],
|
||||
model: true,
|
||||
modelModifiers: ['trim'],
|
||||
},
|
||||
{
|
||||
key: { content: 'bar', isStatic: true },
|
||||
values: [{ content: 'bar', isStatic: false }],
|
||||
model: true,
|
||||
modelModifiers: ['number'],
|
||||
},
|
||||
],
|
||||
},
|
||||
])
|
||||
],
|
||||
})
|
||||
})
|
||||
|
||||
test('v-model with dynamic arguments for component should generate modelModifiers ', () => {
|
||||
|
@ -336,26 +326,24 @@ describe('compiler: vModel transform', () => {
|
|||
expect(code).toMatchSnapshot()
|
||||
expect(code).contain(`[_ctx.foo + "Modifiers"]: () => ({ trim: true })`)
|
||||
expect(code).contain(`[_ctx.bar + "Modifiers"]: () => ({ number: true })`)
|
||||
expect(ir.block.operation).toMatchObject([
|
||||
{
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
tag: 'Comp',
|
||||
props: [
|
||||
{
|
||||
key: { content: 'foo', isStatic: false },
|
||||
values: [{ content: 'foo', isStatic: false }],
|
||||
model: true,
|
||||
modelModifiers: ['trim'],
|
||||
},
|
||||
{
|
||||
key: { content: 'bar', isStatic: false },
|
||||
values: [{ content: 'bar', isStatic: false }],
|
||||
model: true,
|
||||
modelModifiers: ['number'],
|
||||
},
|
||||
],
|
||||
},
|
||||
])
|
||||
expect(ir.block.dynamic.children[0].operation).toMatchObject({
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
tag: 'Comp',
|
||||
props: [
|
||||
{
|
||||
key: { content: 'foo', isStatic: false },
|
||||
values: [{ content: 'foo', isStatic: false }],
|
||||
model: true,
|
||||
modelModifiers: ['trim'],
|
||||
},
|
||||
{
|
||||
key: { content: 'bar', isStatic: false },
|
||||
values: [{ content: 'bar', isStatic: false }],
|
||||
model: true,
|
||||
modelModifiers: ['number'],
|
||||
},
|
||||
],
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
@ -126,15 +126,13 @@ describe('compiler: v-once', () => {
|
|||
const { ir, code } = compileWithOnce(`<div><Comp :id="foo" v-once /></div>`)
|
||||
expect(code).toMatchSnapshot()
|
||||
expect(ir.block.effect).lengthOf(0)
|
||||
expect(ir.block.operation).toMatchObject([
|
||||
{
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
id: 0,
|
||||
tag: 'Comp',
|
||||
once: true,
|
||||
parent: 1,
|
||||
},
|
||||
])
|
||||
expect(ir.block.dynamic.children[0].children[0].operation).toMatchObject({
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
id: 0,
|
||||
tag: 'Comp',
|
||||
once: true,
|
||||
parent: 1,
|
||||
})
|
||||
})
|
||||
|
||||
test.todo('on slot outlet')
|
||||
|
@ -155,24 +153,22 @@ describe('compiler: v-once', () => {
|
|||
expect(code).toMatchSnapshot()
|
||||
|
||||
expect(ir.block.effect).lengthOf(0)
|
||||
expect(ir.block.operation).toMatchObject([
|
||||
{
|
||||
type: IRNodeTypes.IF,
|
||||
id: 0,
|
||||
once: true,
|
||||
condition: {
|
||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||
content: 'expr',
|
||||
isStatic: false,
|
||||
},
|
||||
positive: {
|
||||
type: IRNodeTypes.BLOCK,
|
||||
dynamic: {
|
||||
children: [{ template: 0 }],
|
||||
},
|
||||
expect(ir.block.dynamic.children[0].operation).toMatchObject({
|
||||
type: IRNodeTypes.IF,
|
||||
id: 0,
|
||||
once: true,
|
||||
condition: {
|
||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||
content: 'expr',
|
||||
isStatic: false,
|
||||
},
|
||||
positive: {
|
||||
type: IRNodeTypes.BLOCK,
|
||||
dynamic: {
|
||||
children: [{ template: 0 }],
|
||||
},
|
||||
},
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
test('with v-if/else', () => {
|
||||
|
@ -182,42 +178,38 @@ describe('compiler: v-once', () => {
|
|||
expect(code).toMatchSnapshot()
|
||||
|
||||
expect(ir.block.effect).lengthOf(0)
|
||||
expect(ir.block.operation).toMatchObject([
|
||||
{
|
||||
type: IRNodeTypes.IF,
|
||||
id: 0,
|
||||
once: true,
|
||||
condition: {
|
||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||
content: 'expr',
|
||||
isStatic: false,
|
||||
},
|
||||
positive: {
|
||||
type: IRNodeTypes.BLOCK,
|
||||
dynamic: {
|
||||
children: [{ template: 0 }],
|
||||
},
|
||||
},
|
||||
negative: {
|
||||
type: IRNodeTypes.BLOCK,
|
||||
dynamic: {
|
||||
children: [{ template: 1 }],
|
||||
},
|
||||
expect(ir.block.dynamic.children[0].operation).toMatchObject({
|
||||
type: IRNodeTypes.IF,
|
||||
id: 0,
|
||||
once: true,
|
||||
condition: {
|
||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||
content: 'expr',
|
||||
isStatic: false,
|
||||
},
|
||||
positive: {
|
||||
type: IRNodeTypes.BLOCK,
|
||||
dynamic: {
|
||||
children: [{ template: 0 }],
|
||||
},
|
||||
},
|
||||
])
|
||||
negative: {
|
||||
type: IRNodeTypes.BLOCK,
|
||||
dynamic: {
|
||||
children: [{ template: 1 }],
|
||||
},
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
test('with v-for', () => {
|
||||
const { ir, code } = compileWithOnce(`<div v-for="i in list" v-once />`)
|
||||
expect(code).toMatchSnapshot()
|
||||
expect(ir.block.effect).lengthOf(0)
|
||||
expect(ir.block.operation).toMatchObject([
|
||||
{
|
||||
type: IRNodeTypes.FOR,
|
||||
id: 0,
|
||||
once: true,
|
||||
},
|
||||
])
|
||||
expect(ir.block.dynamic.children[0].operation).toMatchObject({
|
||||
type: IRNodeTypes.FOR,
|
||||
id: 0,
|
||||
once: true,
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
@ -36,27 +36,25 @@ describe('compiler: transform slot', () => {
|
|||
expect(code).toMatchSnapshot()
|
||||
|
||||
expect(ir.template).toEqual(['<div></div>'])
|
||||
expect(ir.block.operation).toMatchObject([
|
||||
{
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
id: 1,
|
||||
tag: 'Comp',
|
||||
props: [[]],
|
||||
slots: [
|
||||
{
|
||||
slotType: IRSlotType.STATIC,
|
||||
slots: {
|
||||
default: {
|
||||
type: IRNodeTypes.BLOCK,
|
||||
dynamic: {
|
||||
children: [{ template: 0 }],
|
||||
},
|
||||
expect(ir.block.dynamic.children[0].operation).toMatchObject({
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
id: 1,
|
||||
tag: 'Comp',
|
||||
props: [[]],
|
||||
slots: [
|
||||
{
|
||||
slotType: IRSlotType.STATIC,
|
||||
slots: {
|
||||
default: {
|
||||
type: IRNodeTypes.BLOCK,
|
||||
dynamic: {
|
||||
children: [{ template: 0 }],
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
])
|
||||
},
|
||||
],
|
||||
})
|
||||
expect(ir.block.returns).toEqual([1])
|
||||
expect(ir.block.dynamic).toMatchObject({
|
||||
children: [{ id: 1 }],
|
||||
|
@ -72,31 +70,29 @@ describe('compiler: transform slot', () => {
|
|||
expect(code).contains(`"default": (_slotProps0) =>`)
|
||||
expect(code).contains(`_slotProps0["foo"] + _ctx.bar`)
|
||||
|
||||
expect(ir.block.operation).toMatchObject([
|
||||
{
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
tag: 'Comp',
|
||||
props: [[]],
|
||||
slots: [
|
||||
{
|
||||
slotType: IRSlotType.STATIC,
|
||||
slots: {
|
||||
default: {
|
||||
type: IRNodeTypes.BLOCK,
|
||||
props: {
|
||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||
content: '{ foo }',
|
||||
ast: {
|
||||
type: 'ArrowFunctionExpression',
|
||||
params: [{ type: 'ObjectPattern' }],
|
||||
},
|
||||
expect(ir.block.dynamic.children[0].operation).toMatchObject({
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
tag: 'Comp',
|
||||
props: [[]],
|
||||
slots: [
|
||||
{
|
||||
slotType: IRSlotType.STATIC,
|
||||
slots: {
|
||||
default: {
|
||||
type: IRNodeTypes.BLOCK,
|
||||
props: {
|
||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||
content: '{ foo }',
|
||||
ast: {
|
||||
type: 'ArrowFunctionExpression',
|
||||
params: [{ type: 'ObjectPattern' }],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
])
|
||||
},
|
||||
],
|
||||
})
|
||||
})
|
||||
|
||||
test('on component named slot', () => {
|
||||
|
@ -108,26 +104,24 @@ describe('compiler: transform slot', () => {
|
|||
expect(code).contains(`"named": (_slotProps0) =>`)
|
||||
expect(code).contains(`_slotProps0["foo"] + _ctx.bar`)
|
||||
|
||||
expect(ir.block.operation).toMatchObject([
|
||||
{
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
tag: 'Comp',
|
||||
slots: [
|
||||
{
|
||||
slotType: IRSlotType.STATIC,
|
||||
slots: {
|
||||
named: {
|
||||
type: IRNodeTypes.BLOCK,
|
||||
props: {
|
||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||
content: '{ foo }',
|
||||
},
|
||||
expect(ir.block.dynamic.children[0].operation).toMatchObject({
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
tag: 'Comp',
|
||||
slots: [
|
||||
{
|
||||
slotType: IRSlotType.STATIC,
|
||||
slots: {
|
||||
named: {
|
||||
type: IRNodeTypes.BLOCK,
|
||||
props: {
|
||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||
content: '{ foo }',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
])
|
||||
},
|
||||
],
|
||||
})
|
||||
})
|
||||
|
||||
test('on component dynamically named slot', () => {
|
||||
|
@ -139,28 +133,26 @@ describe('compiler: transform slot', () => {
|
|||
expect(code).contains(`fn: (_slotProps0) =>`)
|
||||
expect(code).contains(`_slotProps0["foo"] + _ctx.bar`)
|
||||
|
||||
expect(ir.block.operation).toMatchObject([
|
||||
{
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
tag: 'Comp',
|
||||
slots: [
|
||||
{
|
||||
name: {
|
||||
expect(ir.block.dynamic.children[0].operation).toMatchObject({
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
tag: 'Comp',
|
||||
slots: [
|
||||
{
|
||||
name: {
|
||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||
content: 'named',
|
||||
isStatic: false,
|
||||
},
|
||||
fn: {
|
||||
type: IRNodeTypes.BLOCK,
|
||||
props: {
|
||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||
content: 'named',
|
||||
isStatic: false,
|
||||
},
|
||||
fn: {
|
||||
type: IRNodeTypes.BLOCK,
|
||||
props: {
|
||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||
content: '{ foo }',
|
||||
},
|
||||
content: '{ foo }',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
])
|
||||
},
|
||||
],
|
||||
})
|
||||
})
|
||||
|
||||
test('named slots w/ implicit default slot', () => {
|
||||
|
@ -172,33 +164,31 @@ describe('compiler: transform slot', () => {
|
|||
expect(code).toMatchSnapshot()
|
||||
|
||||
expect(ir.template).toEqual(['foo', 'bar', '<span></span>'])
|
||||
expect(ir.block.operation).toMatchObject([
|
||||
{
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
id: 4,
|
||||
tag: 'Comp',
|
||||
props: [[]],
|
||||
slots: [
|
||||
{
|
||||
slotType: IRSlotType.STATIC,
|
||||
slots: {
|
||||
one: {
|
||||
type: IRNodeTypes.BLOCK,
|
||||
dynamic: {
|
||||
children: [{ template: 0 }],
|
||||
},
|
||||
expect(ir.block.dynamic.children[0].operation).toMatchObject({
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
id: 4,
|
||||
tag: 'Comp',
|
||||
props: [[]],
|
||||
slots: [
|
||||
{
|
||||
slotType: IRSlotType.STATIC,
|
||||
slots: {
|
||||
one: {
|
||||
type: IRNodeTypes.BLOCK,
|
||||
dynamic: {
|
||||
children: [{ template: 0 }],
|
||||
},
|
||||
default: {
|
||||
type: IRNodeTypes.BLOCK,
|
||||
dynamic: {
|
||||
children: [{}, { template: 1 }, { template: 2 }],
|
||||
},
|
||||
},
|
||||
default: {
|
||||
type: IRNodeTypes.BLOCK,
|
||||
dynamic: {
|
||||
children: [{}, { template: 1 }, { template: 2 }],
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
])
|
||||
},
|
||||
],
|
||||
})
|
||||
})
|
||||
|
||||
test('nested slots scoping', () => {
|
||||
|
@ -219,29 +209,28 @@ describe('compiler: transform slot', () => {
|
|||
expect(code).contains(`_slotProps0["foo"] + _slotProps1["bar"] + _ctx.baz`)
|
||||
expect(code).contains(`_slotProps0["foo"] + _ctx.bar + _ctx.baz`)
|
||||
|
||||
expect(ir.block.operation).toMatchObject([
|
||||
{
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
tag: 'Comp',
|
||||
props: [[]],
|
||||
slots: [
|
||||
{
|
||||
slotType: IRSlotType.STATIC,
|
||||
slots: {
|
||||
default: {
|
||||
type: IRNodeTypes.BLOCK,
|
||||
props: {
|
||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||
content: '{ foo }',
|
||||
},
|
||||
const outerOp = ir.block.dynamic.children[0].operation
|
||||
expect(outerOp).toMatchObject({
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
tag: 'Comp',
|
||||
props: [[]],
|
||||
slots: [
|
||||
{
|
||||
slotType: IRSlotType.STATIC,
|
||||
slots: {
|
||||
default: {
|
||||
type: IRNodeTypes.BLOCK,
|
||||
props: {
|
||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||
content: '{ foo }',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
])
|
||||
},
|
||||
],
|
||||
})
|
||||
expect(
|
||||
(ir.block.operation[0] as any).slots[0].slots.default.operation[0],
|
||||
(outerOp as any).slots[0].slots.default.dynamic.children[0].operation,
|
||||
).toMatchObject({
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
tag: 'Inner',
|
||||
|
@ -269,23 +258,20 @@ describe('compiler: transform slot', () => {
|
|||
</Comp>`,
|
||||
)
|
||||
expect(code).toMatchSnapshot()
|
||||
expect(ir.block.operation[0].type).toBe(IRNodeTypes.CREATE_COMPONENT_NODE)
|
||||
expect(ir.block.operation).toMatchObject([
|
||||
{
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
tag: 'Comp',
|
||||
slots: [
|
||||
{
|
||||
name: {
|
||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||
content: 'name',
|
||||
isStatic: false,
|
||||
},
|
||||
fn: { type: IRNodeTypes.BLOCK },
|
||||
expect(ir.block.dynamic.children[0].operation).toMatchObject({
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
tag: 'Comp',
|
||||
slots: [
|
||||
{
|
||||
name: {
|
||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||
content: 'name',
|
||||
isStatic: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
])
|
||||
fn: { type: IRNodeTypes.BLOCK },
|
||||
},
|
||||
],
|
||||
})
|
||||
})
|
||||
|
||||
test('dynamic slots name w/ v-for', () => {
|
||||
|
@ -299,28 +285,25 @@ describe('compiler: transform slot', () => {
|
|||
expect(code).contains(`fn: (_slotProps0) =>`)
|
||||
expect(code).contains(`_setText(n0, _toDisplayString(_slotProps0["bar"]))`)
|
||||
|
||||
expect(ir.block.operation[0].type).toBe(IRNodeTypes.CREATE_COMPONENT_NODE)
|
||||
expect(ir.block.operation).toMatchObject([
|
||||
{
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
tag: 'Comp',
|
||||
slots: [
|
||||
{
|
||||
name: {
|
||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||
content: 'item',
|
||||
isStatic: false,
|
||||
},
|
||||
fn: { type: IRNodeTypes.BLOCK },
|
||||
loop: {
|
||||
source: { content: 'list' },
|
||||
value: { content: 'item' },
|
||||
index: undefined,
|
||||
},
|
||||
expect(ir.block.dynamic.children[0].operation).toMatchObject({
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
tag: 'Comp',
|
||||
slots: [
|
||||
{
|
||||
name: {
|
||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||
content: 'item',
|
||||
isStatic: false,
|
||||
},
|
||||
],
|
||||
},
|
||||
])
|
||||
fn: { type: IRNodeTypes.BLOCK },
|
||||
loop: {
|
||||
source: { content: 'list' },
|
||||
value: { content: 'item' },
|
||||
index: undefined,
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
})
|
||||
|
||||
test('dynamic slots name w/ v-for and provide absent key', () => {
|
||||
|
@ -330,30 +313,27 @@ describe('compiler: transform slot', () => {
|
|||
</Comp>`,
|
||||
)
|
||||
expect(code).toMatchSnapshot()
|
||||
expect(ir.block.operation[0].type).toBe(IRNodeTypes.CREATE_COMPONENT_NODE)
|
||||
expect(ir.block.operation).toMatchObject([
|
||||
{
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
tag: 'Comp',
|
||||
slots: [
|
||||
{
|
||||
name: {
|
||||
expect(ir.block.dynamic.children[0].operation).toMatchObject({
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
tag: 'Comp',
|
||||
slots: [
|
||||
{
|
||||
name: {
|
||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||
content: 'index',
|
||||
isStatic: false,
|
||||
},
|
||||
fn: { type: IRNodeTypes.BLOCK },
|
||||
loop: {
|
||||
source: { content: 'list' },
|
||||
value: undefined,
|
||||
index: {
|
||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||
content: 'index',
|
||||
isStatic: false,
|
||||
},
|
||||
fn: { type: IRNodeTypes.BLOCK },
|
||||
loop: {
|
||||
source: { content: 'list' },
|
||||
value: undefined,
|
||||
index: {
|
||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
])
|
||||
},
|
||||
],
|
||||
})
|
||||
})
|
||||
|
||||
test('dynamic slots name w/ v-if / v-else[-if]', () => {
|
||||
|
@ -368,30 +348,27 @@ describe('compiler: transform slot', () => {
|
|||
|
||||
expect(code).contains(`fn: (_slotProps0) =>`)
|
||||
|
||||
expect(ir.block.operation[0].type).toBe(IRNodeTypes.CREATE_COMPONENT_NODE)
|
||||
expect(ir.block.operation).toMatchObject([
|
||||
{
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
tag: 'Comp',
|
||||
slots: [
|
||||
{
|
||||
expect(ir.block.dynamic.children[0].operation).toMatchObject({
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
tag: 'Comp',
|
||||
slots: [
|
||||
{
|
||||
slotType: IRSlotType.CONDITIONAL,
|
||||
condition: { content: 'condition' },
|
||||
positive: {
|
||||
slotType: IRSlotType.DYNAMIC,
|
||||
},
|
||||
negative: {
|
||||
slotType: IRSlotType.CONDITIONAL,
|
||||
condition: { content: 'condition' },
|
||||
condition: { content: 'anotherCondition' },
|
||||
positive: {
|
||||
slotType: IRSlotType.DYNAMIC,
|
||||
},
|
||||
negative: {
|
||||
slotType: IRSlotType.CONDITIONAL,
|
||||
condition: { content: 'anotherCondition' },
|
||||
positive: {
|
||||
slotType: IRSlotType.DYNAMIC,
|
||||
},
|
||||
negative: { slotType: IRSlotType.DYNAMIC },
|
||||
},
|
||||
negative: { slotType: IRSlotType.DYNAMIC },
|
||||
},
|
||||
],
|
||||
},
|
||||
])
|
||||
},
|
||||
],
|
||||
})
|
||||
})
|
||||
|
||||
test('quote slot name', () => {
|
||||
|
@ -405,29 +382,31 @@ describe('compiler: transform slot', () => {
|
|||
test('nested component slot', () => {
|
||||
const { ir, code } = compileWithSlots(`<A><B/></A>`)
|
||||
expect(code).toMatchSnapshot()
|
||||
expect(ir.block.operation).toMatchObject([
|
||||
{
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
tag: 'A',
|
||||
slots: [
|
||||
{
|
||||
slotType: IRSlotType.STATIC,
|
||||
slots: {
|
||||
default: {
|
||||
type: IRNodeTypes.BLOCK,
|
||||
operation: [
|
||||
expect(ir.block.dynamic.children[0].operation).toMatchObject({
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
tag: 'A',
|
||||
slots: [
|
||||
{
|
||||
slotType: IRSlotType.STATIC,
|
||||
slots: {
|
||||
default: {
|
||||
type: IRNodeTypes.BLOCK,
|
||||
dynamic: {
|
||||
children: [
|
||||
{
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
tag: 'B',
|
||||
slots: [],
|
||||
operation: {
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
tag: 'B',
|
||||
slots: [],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
])
|
||||
},
|
||||
],
|
||||
})
|
||||
})
|
||||
|
||||
describe('errors', () => {
|
||||
|
|
|
@ -11,7 +11,7 @@ import {
|
|||
} from './utils'
|
||||
import type { CodegenContext } from '../generate'
|
||||
import { genEffects, genOperations } from './operation'
|
||||
import { genChildren } from './template'
|
||||
import { genChildren, genSelf } from './template'
|
||||
import { toValidAssetId } from '@vue/compiler-dom'
|
||||
|
||||
export function genBlock(
|
||||
|
@ -48,6 +48,9 @@ export function genBlockContent(
|
|||
genResolveAssets('directive', 'resolveDirective')
|
||||
}
|
||||
|
||||
for (const child of dynamic.children) {
|
||||
push(...genSelf(child, context))
|
||||
}
|
||||
for (const child of dynamic.children) {
|
||||
push(...genChildren(child, context, `n${child.id!}`))
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ import {
|
|||
IRNodeTypes,
|
||||
type InsertionStateTypes,
|
||||
type OperationNode,
|
||||
isTypeThatNeedsInsertionState,
|
||||
isBlockOperation,
|
||||
} from '../ir'
|
||||
import type { CodegenContext } from '../generate'
|
||||
import { genInsertNode, genPrependNode } from './dom'
|
||||
|
@ -33,14 +33,23 @@ export function genOperations(
|
|||
): CodeFragment[] {
|
||||
const [frag, push] = buildCodeFragment()
|
||||
for (const operation of opers) {
|
||||
if (isTypeThatNeedsInsertionState(operation) && operation.parent) {
|
||||
push(...genInsertionstate(operation, context))
|
||||
}
|
||||
push(...genOperation(operation, context))
|
||||
push(...genOperationWithInsertionState(operation, context))
|
||||
}
|
||||
return frag
|
||||
}
|
||||
|
||||
export function genOperationWithInsertionState(
|
||||
oper: OperationNode,
|
||||
context: CodegenContext,
|
||||
): CodeFragment[] {
|
||||
const [frag, push] = buildCodeFragment()
|
||||
if (isBlockOperation(oper) && oper.parent) {
|
||||
push(...genInsertionstate(oper, context))
|
||||
}
|
||||
push(...genOperation(oper, context))
|
||||
return frag
|
||||
}
|
||||
|
||||
export function genOperation(
|
||||
oper: OperationNode,
|
||||
context: CodegenContext,
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import type { CodegenContext } from '../generate'
|
||||
import { DynamicFlag, type IRDynamicInfo } from '../ir'
|
||||
import { genDirectivesForElement } from './directive'
|
||||
import { genOperationWithInsertionState } from './operation'
|
||||
import { type CodeFragment, NEWLINE, buildCodeFragment, genCall } from './utils'
|
||||
|
||||
export function genTemplates(
|
||||
|
@ -18,24 +19,38 @@ export function genTemplates(
|
|||
.join('')
|
||||
}
|
||||
|
||||
export function genChildren(
|
||||
export function genSelf(
|
||||
dynamic: IRDynamicInfo,
|
||||
context: CodegenContext,
|
||||
from: string,
|
||||
path: number[] = [],
|
||||
knownPaths: [id: string, path: number[]][] = [],
|
||||
): CodeFragment[] {
|
||||
const { helper } = context
|
||||
const [frag, push] = buildCodeFragment()
|
||||
let offset = 0
|
||||
const { children, id, template } = dynamic
|
||||
const { id, template, operation } = dynamic
|
||||
|
||||
if (id !== undefined && template !== undefined) {
|
||||
push(NEWLINE, `const n${id} = t${template}()`)
|
||||
push(...genDirectivesForElement(id, context))
|
||||
}
|
||||
|
||||
if (operation) {
|
||||
push(...genOperationWithInsertionState(operation, context))
|
||||
}
|
||||
|
||||
return frag
|
||||
}
|
||||
|
||||
export function genChildren(
|
||||
dynamic: IRDynamicInfo,
|
||||
context: CodegenContext,
|
||||
from: string = `n${dynamic.id}`,
|
||||
): CodeFragment[] {
|
||||
const { helper } = context
|
||||
const [frag, push] = buildCodeFragment()
|
||||
const { children } = dynamic
|
||||
|
||||
let offset = 0
|
||||
let prev: [variable: string, elementIndex: number] | undefined
|
||||
const childrenToGen: [IRDynamicInfo, string][] = []
|
||||
|
||||
for (const [index, child] of children.entries()) {
|
||||
if (child.flags & DynamicFlag.NON_TEMPLATE) {
|
||||
offset--
|
||||
|
@ -49,17 +64,11 @@ export function genChildren(
|
|||
: undefined
|
||||
|
||||
if (id === undefined && !child.hasDynamicChild) {
|
||||
const { id, template } = child
|
||||
if (id !== undefined && template !== undefined) {
|
||||
push(NEWLINE, `const n${id} = t${template}()`)
|
||||
push(...genDirectivesForElement(id, context))
|
||||
}
|
||||
push(...genSelf(child, context))
|
||||
continue
|
||||
}
|
||||
|
||||
const elementIndex = Number(index) + offset
|
||||
const newPath = [...path, elementIndex]
|
||||
|
||||
// p for "placeholder" variables that are meant for possible reuse by
|
||||
// other access paths
|
||||
const variable = id === undefined ? `p${context.block.tempId++}` : `n${id}`
|
||||
|
@ -72,58 +81,28 @@ export function genChildren(
|
|||
push(...genCall(helper('nthChild'), from, String(elementIndex)))
|
||||
}
|
||||
} else {
|
||||
if (newPath.length === 1 && newPath[0] === 0) {
|
||||
if (elementIndex === 0) {
|
||||
push(...genCall(helper('child'), from))
|
||||
} else {
|
||||
// check if there's a node that we can reuse from
|
||||
let resolvedFrom = from
|
||||
let resolvedPath = newPath
|
||||
let skipFirstChild = false
|
||||
outer: for (const [from, path] of knownPaths) {
|
||||
const l = path.length
|
||||
const tail = newPath.slice(l)
|
||||
for (let i = 0; i < l; i++) {
|
||||
const parentSeg = path[i]
|
||||
const thisSeg = newPath[i]
|
||||
if (parentSeg !== thisSeg) {
|
||||
if (i === l - 1) {
|
||||
// last bit is reusable
|
||||
resolvedFrom = from
|
||||
resolvedPath = [thisSeg - parentSeg, ...tail]
|
||||
skipFirstChild = true
|
||||
break outer
|
||||
}
|
||||
break
|
||||
} else if (i === l - 1) {
|
||||
// full overlap
|
||||
resolvedFrom = from
|
||||
resolvedPath = tail
|
||||
break outer
|
||||
}
|
||||
}
|
||||
let init = genCall(helper('child'), from)
|
||||
if (elementIndex === 1) {
|
||||
init = genCall(helper('next'), init)
|
||||
} else if (elementIndex > 1) {
|
||||
init = genCall(helper('nthChild'), from, String(elementIndex))
|
||||
}
|
||||
let init
|
||||
for (const i of resolvedPath) {
|
||||
init = init
|
||||
? genCall(helper('child'), init)
|
||||
: skipFirstChild
|
||||
? resolvedFrom
|
||||
: genCall(helper('child'), resolvedFrom)
|
||||
if (i === 1) {
|
||||
init = genCall(helper('next'), init)
|
||||
} else if (i > 1) {
|
||||
init = genCall(helper('nthChild'), resolvedFrom, String(i))
|
||||
}
|
||||
}
|
||||
push(...init!)
|
||||
push(...init)
|
||||
}
|
||||
}
|
||||
if (id !== undefined) {
|
||||
push(...genDirectivesForElement(id, context))
|
||||
}
|
||||
knownPaths.unshift([variable, newPath])
|
||||
prev = [variable, elementIndex]
|
||||
push(...genChildren(child, context, variable))
|
||||
childrenToGen.push([child, variable])
|
||||
}
|
||||
|
||||
for (const [child, from] of childrenToGen) {
|
||||
push(...genChildren(child, context, from))
|
||||
}
|
||||
|
||||
return frag
|
||||
|
|
|
@ -270,6 +270,7 @@ export interface IRDynamicInfo {
|
|||
children: IRDynamicInfo[]
|
||||
template?: number
|
||||
hasDynamicChild?: boolean
|
||||
operation?: OperationNode
|
||||
}
|
||||
|
||||
export interface IREffect {
|
||||
|
@ -304,9 +305,7 @@ export type InsertionStateTypes =
|
|||
| SlotOutletIRNode
|
||||
| CreateComponentIRNode
|
||||
|
||||
export function isTypeThatNeedsInsertionState(
|
||||
op: OperationNode,
|
||||
): op is InsertionStateTypes {
|
||||
export function isBlockOperation(op: OperationNode): op is InsertionStateTypes {
|
||||
const type = op.type
|
||||
return (
|
||||
type === IRNodeTypes.CREATE_COMPONENT_NODE ||
|
||||
|
|
|
@ -8,7 +8,7 @@ import {
|
|||
DynamicFlag,
|
||||
type IRDynamicInfo,
|
||||
IRNodeTypes,
|
||||
isTypeThatNeedsInsertionState as isBlockOperation,
|
||||
isBlockOperation,
|
||||
} from '../ir'
|
||||
|
||||
export const transformChildren: NodeTransform = (node, context) => {
|
||||
|
@ -102,14 +102,10 @@ function registerInsertion(
|
|||
parent: context.reference(),
|
||||
anchor,
|
||||
})
|
||||
} else {
|
||||
} else if (child.operation && isBlockOperation(child.operation)) {
|
||||
// block types
|
||||
for (const op of context.block.operation) {
|
||||
if (isBlockOperation(op) && op.id === child.id) {
|
||||
op.parent = context.reference()
|
||||
op.anchor = anchor
|
||||
}
|
||||
}
|
||||
child.operation.parent = context.reference()
|
||||
child.operation.anchor = anchor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -124,7 +124,7 @@ function transformComponentElement(
|
|||
}
|
||||
|
||||
context.dynamic.flags |= DynamicFlag.NON_TEMPLATE | DynamicFlag.INSERT
|
||||
context.registerOperation({
|
||||
context.dynamic.operation = {
|
||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||
id: context.reference(),
|
||||
tag,
|
||||
|
@ -134,7 +134,7 @@ function transformComponentElement(
|
|||
slots: [...context.slots],
|
||||
once: context.inVOnce,
|
||||
dynamic: dynamicComponent,
|
||||
})
|
||||
}
|
||||
context.slots = []
|
||||
}
|
||||
|
||||
|
|
|
@ -100,13 +100,13 @@ export const transformSlotOutlet: NodeTransform = (node, context) => {
|
|||
|
||||
return () => {
|
||||
exitBlock && exitBlock()
|
||||
context.registerOperation({
|
||||
context.dynamic.operation = {
|
||||
type: IRNodeTypes.SLOT_OUTLET_NODE,
|
||||
id,
|
||||
name: slotName,
|
||||
props: irProps,
|
||||
fallback,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -67,7 +67,7 @@ export function processFor(
|
|||
parent.block.node !== parent.node &&
|
||||
parent.node.children.length === 1
|
||||
|
||||
context.registerOperation({
|
||||
context.dynamic.operation = {
|
||||
type: IRNodeTypes.FOR,
|
||||
id,
|
||||
source: source as SimpleExpressionNode,
|
||||
|
@ -84,6 +84,6 @@ export function processFor(
|
|||
),
|
||||
component: isComponent,
|
||||
onlyChild: !!isOnlyChild,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,7 +46,7 @@ export function processIf(
|
|||
|
||||
return () => {
|
||||
onExit()
|
||||
context.registerOperation({
|
||||
context.dynamic.operation = {
|
||||
type: IRNodeTypes.IF,
|
||||
id,
|
||||
condition: dir.exp!,
|
||||
|
@ -54,14 +54,20 @@ export function processIf(
|
|||
once:
|
||||
context.inVOnce ||
|
||||
isStaticExpression(dir.exp!, context.options.bindingMetadata),
|
||||
})
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// check the adjacent v-if
|
||||
const siblingIf = getSiblingIf(context, true)
|
||||
|
||||
const { operation } = context.block
|
||||
let lastIfNode = operation[operation.length - 1]
|
||||
const siblings = context.parent && context.parent.dynamic.children
|
||||
let lastIfNode
|
||||
if (siblings) {
|
||||
let i = siblings.length
|
||||
while (i--) {
|
||||
if (siblings[i].operation) lastIfNode = siblings[i].operation
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
// check if v-if is the sibling node
|
||||
|
|
|
@ -257,6 +257,63 @@ describe('SSR hydration', () => {
|
|||
)
|
||||
})
|
||||
|
||||
test('nested fragment components', async () => {
|
||||
const t0 = template('<div> </div>')
|
||||
const t1 = template(' ')
|
||||
const msg = ref('foo')
|
||||
const Comp = {
|
||||
setup() {
|
||||
const n0 = t0() as Element
|
||||
const n1 = t1() as Text
|
||||
const x0 = child(n0) as Text
|
||||
renderEffect(() => {
|
||||
const _msg = msg.value
|
||||
|
||||
setText(x0, toDisplayString(_msg))
|
||||
setText(n1, toDisplayString(_msg))
|
||||
})
|
||||
return [n0, n1]
|
||||
},
|
||||
}
|
||||
|
||||
const t2 = template('<div></div>')
|
||||
const Parent = {
|
||||
setup() {
|
||||
const n0 = t2()
|
||||
const n1 = createComponent(Comp)
|
||||
const n2 = t2()
|
||||
return [n0, n1, n2]
|
||||
},
|
||||
}
|
||||
|
||||
const t3 = template('<div><span></span></div>', true)
|
||||
const { container } = mountWithHydration(
|
||||
'<div><!--[-->' +
|
||||
'<div></div><!--[--><div>foo</div>foo<!--]--><div></div>' +
|
||||
'<!--]--><span></span></div>',
|
||||
() => {
|
||||
const n1 = t3() as Element
|
||||
setInsertionState(n1, 0)
|
||||
createComponent(Parent)
|
||||
return n1
|
||||
},
|
||||
)
|
||||
|
||||
expect(container.innerHTML).toBe(
|
||||
'<div><!--[-->' +
|
||||
'<div></div><!--[--><div>foo</div>foo<!--]--><div></div>' +
|
||||
'<!--]--><span></span></div>',
|
||||
)
|
||||
|
||||
msg.value = 'bar'
|
||||
await nextTick()
|
||||
expect(container.innerHTML).toBe(
|
||||
'<div><!--[-->' +
|
||||
'<div></div><!--[--><div>bar</div>bar<!--]--><div></div>' +
|
||||
'<!--]--><span></span></div>',
|
||||
)
|
||||
})
|
||||
|
||||
// test('element with ref', () => {
|
||||
// const el = ref()
|
||||
// const { vnode, container } = mountWithHydration('<div></div>', () =>
|
||||
|
|
|
@ -59,11 +59,7 @@ import {
|
|||
} from './componentSlots'
|
||||
import { hmrReload, hmrRerender } from './hmr'
|
||||
import { isHydrating, locateHydrationNode } from './dom/hydration'
|
||||
import {
|
||||
insertionAnchor,
|
||||
insertionParent,
|
||||
resetInsertionState,
|
||||
} from './insertionState'
|
||||
import { insertionAnchor, insertionParent } from './insertionState'
|
||||
|
||||
export { currentInstance } from '@vue/runtime-dom'
|
||||
|
||||
|
@ -142,6 +138,8 @@ export function createComponent(
|
|||
currentInstance.appContext) ||
|
||||
emptyContext,
|
||||
): VaporComponentInstance {
|
||||
const _insertionParent = insertionParent
|
||||
const _insertionAnchor = insertionAnchor
|
||||
if (isHydrating) {
|
||||
locateHydrationNode()
|
||||
}
|
||||
|
@ -263,9 +261,8 @@ export function createComponent(
|
|||
|
||||
onScopeDispose(() => unmountComponent(instance), true)
|
||||
|
||||
if (!isHydrating && insertionParent) {
|
||||
insert(instance.block, insertionParent, insertionAnchor)
|
||||
resetInsertionState()
|
||||
if (!isHydrating && _insertionParent) {
|
||||
insert(instance.block, _insertionParent, _insertionAnchor)
|
||||
}
|
||||
|
||||
return instance
|
||||
|
|
|
@ -28,6 +28,7 @@ export function withHydration(container: ParentNode, fn: () => void): void {
|
|||
setInsertionState(container, 0)
|
||||
const res = fn()
|
||||
resetInsertionState()
|
||||
currentHydrationNode = null
|
||||
isHydrating = false
|
||||
return res
|
||||
}
|
||||
|
@ -75,10 +76,6 @@ function adoptTemplateImpl(node: Node, template: string): Node | null {
|
|||
}
|
||||
|
||||
function locateHydrationNodeImpl() {
|
||||
if (__DEV__ && !insertionParent) {
|
||||
warn('Hydration error: missing insertion state.')
|
||||
}
|
||||
|
||||
let node: Node | null
|
||||
|
||||
// prepend / firstChild
|
||||
|
@ -87,7 +84,9 @@ function locateHydrationNodeImpl() {
|
|||
} else {
|
||||
node = insertionAnchor
|
||||
? insertionAnchor.previousSibling
|
||||
: insertionParent!.lastChild
|
||||
: insertionParent
|
||||
? insertionParent.lastChild
|
||||
: currentHydrationNode
|
||||
|
||||
if (node && isComment(node, ']')) {
|
||||
// fragment backward search
|
||||
|
@ -120,10 +119,11 @@ function locateHydrationNodeImpl() {
|
|||
}
|
||||
}
|
||||
|
||||
currentHydrationNode = node
|
||||
|
||||
if (__DEV__ && !currentHydrationNode) {
|
||||
if (__DEV__ && !node) {
|
||||
// TODO more info
|
||||
warn('Hydration mismatch in ', insertionParent)
|
||||
}
|
||||
|
||||
resetInsertionState()
|
||||
currentHydrationNode = node
|
||||
}
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
import { setCurrentHydrationNode } from './dom/hydration'
|
||||
|
||||
export let insertionParent: ParentNode | undefined
|
||||
export let insertionAnchor: Node | 0 | undefined
|
||||
|
||||
|
@ -15,5 +13,4 @@ export function setInsertionState(parent: ParentNode, anchor?: Node | 0): void {
|
|||
|
||||
export function resetInsertionState(): void {
|
||||
insertionParent = insertionAnchor = undefined
|
||||
setCurrentHydrationNode(null)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue