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