`;
exports[`compile > directives > v-pre > should not affect siblings after it 1`] = `
-"import { resolveComponent as _resolveComponent, child as _child, setInsertionState as _setInsertionState, createComponentWithFallback as _createComponentWithFallback, toDisplayString as _toDisplayString, setText as _setText, setProp as _setProp, renderEffect as _renderEffect, template as _template } from 'vue';
+"import { resolveComponent as _resolveComponent, setInsertionState as _setInsertionState, createComponentWithFallback as _createComponentWithFallback, child as _child, toDisplayString as _toDisplayString, setText as _setText, setProp as _setProp, renderEffect as _renderEffect, template as _template } from 'vue';
const t0 = _template("<div :id=\\"foo\\"><Comp></Comp>{{ bar }}</div>")
const t1 = _template("<div> </div>")
const _component_Comp = _resolveComponent("Comp")
const n0 = t0()
const n3 = t1()
- const n2 = _child(n3)
_setInsertionState(n3, 0)
const n1 = _createComponentWithFallback(_component_Comp)
+ const n2 = _child(n3)
_renderEffect(() => {
_setText(n2, _toDisplayString(_ctx.bar))
_setProp(n3, "id", _ctx.foo)
export function render(_ctx) {
const n3 = t0()
const p0 = _next(_child(n3))
- const n0 = _child(p0)
const p1 = _next(p0)
- const n1 = _child(p1)
const p2 = _next(p1)
+ const n0 = _child(p0)
+ const n1 = _child(p1)
const n2 = _child(p2)
const x0 = _child(n0)
const x1 = _child(n1)
const t0 = _template("123")
export function render(_ctx, $props, $emit, $attrs, $slots) {
- const n1 = t0()
const n0 = _createComponent(_ctx.Comp)
+ const n1 = t0()
return [n0, n1]
}"
`;
export function render(_ctx) {
const n1 = t1()
- const n0 = t0()
const n3 = t2()
+ const n0 = t0()
const n2 = t2()
_insert(n0, n1)
_insert(n2, n3)
const t5 = _template("<div> </div>")
export function render(_ctx) {
- const n13 = t5()
const n0 = _createIf(() => (_ctx.ok), () => {
const n2 = t0()
return n2
const n11 = t4()
return [n10, n11]
}))
+ const n13 = t5()
const x13 = _child(n13)
_renderEffect(() => _setText(x13, _toDisplayString(_ctx.text)))
return [n0, n13]
const _component_Comp = _resolveComponent("Comp")
const n5 = _createComponentWithFallback(_component_Comp, null, {
"default": (_slotProps0) => {
- const n3 = t0()
const n1 = _createComponentWithFallback(_component_Inner, null, {
"default": (_slotProps1) => {
const n0 = t0()
return n0
}
})
+ const n3 = t0()
_renderEffect(() => _setText(n3, " " + _toDisplayString(_slotProps0["foo"] + _ctx.bar + _ctx.baz)))
return [n1, n3]
}
expect(code).toMatchSnapshot()
expect(helpers).contains.all.keys('resolveComponent')
expect(helpers).contains.all.keys('createComponentWithFallback')
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.CREATE_COMPONENT_NODE,
- id: 0,
- tag: 'Foo',
- asset: true,
- root: true,
- props: [[]],
- },
- ])
+ expect(ir.block.dynamic.children[0].operation).toMatchObject({
+ type: IRNodeTypes.CREATE_COMPONENT_NODE,
+ id: 0,
+ tag: 'Foo',
+ asset: true,
+ root: true,
+ props: [[]],
+ })
})
test.todo('resolve implicitly self-referencing component', () => {
})
expect(code).toMatchSnapshot()
expect(helpers).not.toContain('resolveComponent')
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.CREATE_COMPONENT_NODE,
- tag: 'Example',
- asset: false,
- },
- ])
+ expect(ir.block.dynamic.children[0].operation).toMatchObject({
+ type: IRNodeTypes.CREATE_COMPONENT_NODE,
+ tag: 'Example',
+ asset: false,
+ })
})
test('resolve component from setup bindings (inline)', () => {
})
expect(code).toMatchSnapshot()
expect(helpers).toContain('resolveComponent')
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.CREATE_COMPONENT_NODE,
- id: 0,
- tag: 'Example',
- asset: true,
- },
- ])
+ expect(ir.block.dynamic.children[0].operation).toMatchObject({
+ type: IRNodeTypes.CREATE_COMPONENT_NODE,
+ id: 0,
+ tag: 'Example',
+ asset: true,
+ })
})
test('generate single root component', () => {
class: () => ("bar")
}`)
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.CREATE_COMPONENT_NODE,
- tag: 'Foo',
- asset: true,
- root: true,
- props: [
- [
- {
- key: {
+ expect(ir.block.dynamic.children[0].operation).toMatchObject({
+ type: IRNodeTypes.CREATE_COMPONENT_NODE,
+ tag: 'Foo',
+ asset: true,
+ root: true,
+ props: [
+ [
+ {
+ key: {
+ type: NodeTypes.SIMPLE_EXPRESSION,
+ content: 'id',
+ isStatic: true,
+ },
+ values: [
+ {
type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'id',
+ content: 'foo',
isStatic: true,
},
- values: [
- {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'foo',
- isStatic: true,
- },
- ],
+ ],
+ },
+ {
+ key: {
+ type: NodeTypes.SIMPLE_EXPRESSION,
+ content: 'class',
+ isStatic: true,
},
- {
- key: {
+ values: [
+ {
type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'class',
+ content: 'bar',
isStatic: true,
},
- values: [
- {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'bar',
- isStatic: true,
- },
- ],
- },
- ],
+ ],
+ },
],
- },
- ])
+ ],
+ })
})
test('v-bind="obj"', () => {
expect(code).contains(`[
() => (_ctx.obj)
]`)
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.CREATE_COMPONENT_NODE,
- tag: 'Foo',
- props: [
- {
- kind: IRDynamicPropsKind.EXPRESSION,
- value: { content: 'obj', isStatic: false },
- },
- ],
- },
- ])
+ expect(ir.block.dynamic.children[0].operation).toMatchObject({
+ type: IRNodeTypes.CREATE_COMPONENT_NODE,
+ tag: 'Foo',
+ props: [
+ {
+ kind: IRDynamicPropsKind.EXPRESSION,
+ value: { content: 'obj', isStatic: false },
+ },
+ ],
+ })
})
test('v-bind="obj" after static prop', () => {
() => (_ctx.obj)
]
}`)
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.CREATE_COMPONENT_NODE,
- tag: 'Foo',
- props: [
- [{ key: { content: 'id' }, values: [{ content: 'foo' }] }],
- {
- kind: IRDynamicPropsKind.EXPRESSION,
- value: { content: 'obj' },
- },
- ],
- },
- ])
+ expect(ir.block.dynamic.children[0].operation).toMatchObject({
+ type: IRNodeTypes.CREATE_COMPONENT_NODE,
+ tag: 'Foo',
+ props: [
+ [{ key: { content: 'id' }, values: [{ content: 'foo' }] }],
+ {
+ kind: IRDynamicPropsKind.EXPRESSION,
+ value: { content: 'obj' },
+ },
+ ],
+ })
})
test('v-bind="obj" before static prop', () => {
() => (_ctx.obj),
{ id: () => ("foo") }
]`)
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.CREATE_COMPONENT_NODE,
- tag: 'Foo',
- props: [
- {
- kind: IRDynamicPropsKind.EXPRESSION,
- value: { content: 'obj' },
- },
- [{ key: { content: 'id' }, values: [{ content: 'foo' }] }],
- ],
- },
- ])
+ expect(ir.block.dynamic.children[0].operation).toMatchObject({
+ type: IRNodeTypes.CREATE_COMPONENT_NODE,
+ tag: 'Foo',
+ props: [
+ {
+ kind: IRDynamicPropsKind.EXPRESSION,
+ value: { content: 'obj' },
+ },
+ [{ key: { content: 'id' }, values: [{ content: 'foo' }] }],
+ ],
+ })
})
test('v-bind="obj" between static props', () => {
{ class: () => ("bar") }
]
}`)
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.CREATE_COMPONENT_NODE,
- tag: 'Foo',
- props: [
- [{ key: { content: 'id' }, values: [{ content: 'foo' }] }],
- {
- kind: IRDynamicPropsKind.EXPRESSION,
- value: { content: 'obj' },
- },
- [{ key: { content: 'class' }, values: [{ content: 'bar' }] }],
- ],
- },
- ])
+ expect(ir.block.dynamic.children[0].operation).toMatchObject({
+ type: IRNodeTypes.CREATE_COMPONENT_NODE,
+ tag: 'Foo',
+ props: [
+ [{ key: { content: 'id' }, values: [{ content: 'foo' }] }],
+ {
+ kind: IRDynamicPropsKind.EXPRESSION,
+ value: { content: 'obj' },
+ },
+ [{ key: { content: 'class' }, values: [{ content: 'bar' }] }],
+ ],
+ })
})
test.todo('props merging: event handlers', () => {
expect(code).contains(`[
() => (_toHandlers(_ctx.obj))
]`)
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.CREATE_COMPONENT_NODE,
- tag: 'Foo',
- props: [
- {
- kind: IRDynamicPropsKind.EXPRESSION,
- value: { content: 'obj' },
- handler: true,
- },
- ],
- },
- ])
+ expect(ir.block.dynamic.children[0].operation).toMatchObject({
+ type: IRNodeTypes.CREATE_COMPONENT_NODE,
+ tag: 'Foo',
+ props: [
+ {
+ kind: IRDynamicPropsKind.EXPRESSION,
+ value: { content: 'obj' },
+ handler: true,
+ },
+ ],
+ })
})
test('v-on expression is inline statement', () => {
expect(code).toMatchSnapshot()
expect(code).contains(`onBar: () => _on_bar`)
expect(code).contains(`const _on_bar = () => _ctx.handler`)
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.CREATE_COMPONENT_NODE,
- tag: 'Foo',
- props: [
- [
- {
- key: { content: 'bar' },
- handler: true,
- values: [{ content: '_on_bar' }],
- },
- ],
+ expect(ir.block.dynamic.children[0].operation).toMatchObject({
+ type: IRNodeTypes.CREATE_COMPONENT_NODE,
+ tag: 'Foo',
+ props: [
+ [
+ {
+ key: { content: 'bar' },
+ handler: true,
+ values: [{ content: '_on_bar' }],
+ },
],
- },
- ])
+ ],
+ })
})
test('v-on expression is a function call', () => {
expect(code).contains(
`const _on_bar = $event => (_ctx.handleBar($event))`,
)
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.CREATE_COMPONENT_NODE,
- tag: 'Foo',
- props: [
- [
- {
- key: { content: 'bar' },
- handler: true,
- values: [{ content: '_on_bar' }],
- },
- ],
+ expect(ir.block.dynamic.children[0].operation).toMatchObject({
+ type: IRNodeTypes.CREATE_COMPONENT_NODE,
+ tag: 'Foo',
+ props: [
+ [
+ {
+ key: { content: 'bar' },
+ handler: true,
+ values: [{ content: '_on_bar' }],
+ },
],
- },
- ])
+ ],
+ })
})
test('cache v-on expression with unique handler name', () => {
)
expect(code).contains(`onBar: () => _on_bar1`)
expect(code).contains(`const _on_bar1 = () => _ctx.handler`)
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.CREATE_COMPONENT_NODE,
- tag: 'Foo',
- props: [
- [
- {
- key: { content: 'bar' },
- handler: true,
- values: [{ content: '_on_bar' }],
- },
- ],
+ expect(ir.block.dynamic.children[0].operation).toMatchObject({
+ type: IRNodeTypes.CREATE_COMPONENT_NODE,
+ tag: 'Foo',
+ props: [
+ [
+ {
+ key: { content: 'bar' },
+ handler: true,
+ values: [{ content: '_on_bar' }],
+ },
],
- },
- {
- type: IRNodeTypes.CREATE_COMPONENT_NODE,
- tag: 'Bar',
- props: [
- [
- {
- key: { content: 'bar' },
- handler: true,
- values: [{ content: '_on_bar1' }],
- },
- ],
+ ],
+ })
+
+ expect(ir.block.dynamic.children[1].operation).toMatchObject({
+ type: IRNodeTypes.CREATE_COMPONENT_NODE,
+ tag: 'Bar',
+ props: [
+ [
+ {
+ key: { content: 'bar' },
+ handler: true,
+ values: [{ content: '_on_bar1' }],
+ },
],
- },
- ])
+ ],
+ })
})
})
)
expect(code).toMatchSnapshot()
expect(helpers).toContain('resolveDynamicComponent')
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.CREATE_COMPONENT_NODE,
- tag: 'component',
- asset: true,
- root: true,
- props: [[]],
- dynamic: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'foo',
- isStatic: true,
- },
+ expect(ir.block.dynamic.children[0].operation).toMatchObject({
+ type: IRNodeTypes.CREATE_COMPONENT_NODE,
+ tag: 'component',
+ asset: true,
+ root: true,
+ props: [[]],
+ dynamic: {
+ type: NodeTypes.SIMPLE_EXPRESSION,
+ content: 'foo',
+ isStatic: true,
},
- ])
+ })
})
test('capitalized version w/ static binding', () => {
)
expect(code).toMatchSnapshot()
expect(helpers).toContain('resolveDynamicComponent')
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.CREATE_COMPONENT_NODE,
- tag: 'Component',
- asset: true,
- root: true,
- props: [[]],
- dynamic: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'foo',
- isStatic: true,
- },
+ expect(ir.block.dynamic.children[0].operation).toMatchObject({
+ type: IRNodeTypes.CREATE_COMPONENT_NODE,
+ tag: 'Component',
+ asset: true,
+ root: true,
+ props: [[]],
+ dynamic: {
+ type: NodeTypes.SIMPLE_EXPRESSION,
+ content: 'foo',
+ isStatic: true,
},
- ])
+ })
})
test('dynamic binding', () => {
)
expect(code).toMatchSnapshot()
expect(helpers).toContain('createDynamicComponent')
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.CREATE_COMPONENT_NODE,
- tag: 'component',
- asset: true,
- root: true,
- props: [[]],
- dynamic: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'foo',
- isStatic: false,
- },
+ expect(ir.block.dynamic.children[0].operation).toMatchObject({
+ type: IRNodeTypes.CREATE_COMPONENT_NODE,
+ tag: 'component',
+ asset: true,
+ root: true,
+ props: [[]],
+ dynamic: {
+ type: NodeTypes.SIMPLE_EXPRESSION,
+ content: 'foo',
+ isStatic: false,
},
- ])
+ })
})
test('dynamic binding shorthand', () => {
compileWithElementTransform(`<component :is />`)
expect(code).toMatchSnapshot()
expect(helpers).toContain('createDynamicComponent')
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.CREATE_COMPONENT_NODE,
- tag: 'component',
- asset: true,
- root: true,
- props: [[]],
- dynamic: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'is',
- isStatic: false,
- },
+ expect(ir.block.dynamic.children[0].operation).toMatchObject({
+ type: IRNodeTypes.CREATE_COMPONENT_NODE,
+ tag: 'component',
+ asset: true,
+ root: true,
+ props: [[]],
+ dynamic: {
+ type: NodeTypes.SIMPLE_EXPRESSION,
+ content: 'is',
+ isStatic: false,
},
- ])
+ })
})
// #3934
expect(code).toMatchSnapshot()
expect(helpers).toContain('resolveComponent')
expect(helpers).not.toContain('resolveDynamicComponent')
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.CREATE_COMPONENT_NODE,
- tag: 'custom-input',
- asset: true,
- root: true,
- props: [[{ key: { content: 'is' }, values: [{ content: 'foo' }] }]],
- },
- ])
+ expect(ir.block.dynamic.children[0].operation).toMatchObject({
+ type: IRNodeTypes.CREATE_COMPONENT_NODE,
+ tag: 'custom-input',
+ asset: true,
+ root: true,
+ props: [[{ key: { content: 'is' }, values: [{ content: 'foo' }] }]],
+ })
})
})
`<Foo :[foo-bar]="bar" :[baz]="qux" />`,
)
expect(code).toMatchSnapshot()
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.CREATE_COMPONENT_NODE,
- tag: 'Foo',
- props: [
- {
- kind: IRDynamicPropsKind.ATTRIBUTE,
- key: { content: 'foo-bar' },
- values: [{ content: 'bar' }],
- },
- {
- kind: IRDynamicPropsKind.ATTRIBUTE,
- key: { content: 'baz' },
- values: [{ content: 'qux' }],
- },
- ],
- },
- ])
+ expect(ir.block.dynamic.children[0].operation).toMatchObject({
+ type: IRNodeTypes.CREATE_COMPONENT_NODE,
+ tag: 'Foo',
+ props: [
+ {
+ kind: IRDynamicPropsKind.ATTRIBUTE,
+ key: { content: 'foo-bar' },
+ values: [{ content: 'bar' }],
+ },
+ {
+ kind: IRDynamicPropsKind.ATTRIBUTE,
+ key: { content: 'baz' },
+ values: [{ content: 'qux' }],
+ },
+ ],
+ })
})
test('component with dynamic event arguments', () => {
`<Foo @[foo-bar]="bar" @[baz]="qux" />`,
)
expect(code).toMatchSnapshot()
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.CREATE_COMPONENT_NODE,
- tag: 'Foo',
- props: [
- {
- kind: IRDynamicPropsKind.ATTRIBUTE,
- key: { content: 'foo-bar' },
- values: [{ content: 'bar' }],
- handler: true,
- },
- {
- kind: IRDynamicPropsKind.ATTRIBUTE,
- key: { content: 'baz' },
- values: [{ content: 'qux' }],
- handler: true,
- },
- ],
- },
- ])
+ expect(ir.block.dynamic.children[0].operation).toMatchObject({
+ type: IRNodeTypes.CREATE_COMPONENT_NODE,
+ tag: 'Foo',
+ props: [
+ {
+ kind: IRDynamicPropsKind.ATTRIBUTE,
+ key: { content: 'foo-bar' },
+ values: [{ content: 'bar' }],
+ handler: true,
+ },
+ {
+ kind: IRDynamicPropsKind.ATTRIBUTE,
+ key: { content: 'baz' },
+ values: [{ content: 'qux' }],
+ handler: true,
+ },
+ ],
+ })
})
test('component event with once modifier', () => {
expect(code).toMatchSnapshot()
expect(helpers).toContain('createSlot')
expect(ir.block.effect).toEqual([])
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.SLOT_OUTLET_NODE,
- id: 0,
- name: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'default',
- isStatic: true,
- },
- props: [],
- fallback: undefined,
+ expect(ir.block.dynamic.children[0].operation).toMatchObject({
+ type: IRNodeTypes.SLOT_OUTLET_NODE,
+ id: 0,
+ name: {
+ type: NodeTypes.SIMPLE_EXPRESSION,
+ content: 'default',
+ isStatic: true,
},
- ])
+ props: [],
+ fallback: undefined,
+ })
})
test('statically named slot outlet', () => {
const { ir, code } = compileWithSlotsOutlet(`<slot name="foo" />`)
expect(code).toMatchSnapshot()
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.SLOT_OUTLET_NODE,
- id: 0,
- name: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'foo',
- isStatic: true,
- },
+ expect(ir.block.dynamic.children[0].operation).toMatchObject({
+ type: IRNodeTypes.SLOT_OUTLET_NODE,
+ id: 0,
+ name: {
+ type: NodeTypes.SIMPLE_EXPRESSION,
+ content: 'foo',
+ isStatic: true,
},
- ])
+ })
})
test('dynamically named slot outlet', () => {
const { ir, code } = compileWithSlotsOutlet(`<slot :name="foo + bar" />`)
expect(code).toMatchSnapshot()
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.SLOT_OUTLET_NODE,
- id: 0,
- name: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'foo + bar',
- isStatic: false,
- },
+ expect(ir.block.dynamic.children[0].operation).toMatchObject({
+ type: IRNodeTypes.SLOT_OUTLET_NODE,
+ id: 0,
+ name: {
+ type: NodeTypes.SIMPLE_EXPRESSION,
+ content: 'foo + bar',
+ isStatic: false,
},
- ])
+ })
})
test('dynamically named slot outlet with v-bind shorthand', () => {
const { ir, code } = compileWithSlotsOutlet(`<slot :name />`)
expect(code).toMatchSnapshot()
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.SLOT_OUTLET_NODE,
- id: 0,
- name: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'name',
- isStatic: false,
- },
+ expect(ir.block.dynamic.children[0].operation).toMatchObject({
+ type: IRNodeTypes.SLOT_OUTLET_NODE,
+ id: 0,
+ name: {
+ type: NodeTypes.SIMPLE_EXPRESSION,
+ content: 'name',
+ isStatic: false,
},
- ])
+ })
})
test('default slot outlet with props', () => {
`<slot foo="bar" :baz="qux" :foo-bar="foo-bar" />`,
)
expect(code).toMatchSnapshot()
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.SLOT_OUTLET_NODE,
- name: { content: 'default' },
- props: [
- [
- { key: { content: 'foo' }, values: [{ content: 'bar' }] },
- { key: { content: 'baz' }, values: [{ content: 'qux' }] },
- { key: { content: 'fooBar' }, values: [{ content: 'foo-bar' }] },
- ],
+ expect(ir.block.dynamic.children[0].operation).toMatchObject({
+ type: IRNodeTypes.SLOT_OUTLET_NODE,
+ name: { content: 'default' },
+ props: [
+ [
+ { key: { content: 'foo' }, values: [{ content: 'bar' }] },
+ { key: { content: 'baz' }, values: [{ content: 'qux' }] },
+ { key: { content: 'fooBar' }, values: [{ content: 'foo-bar' }] },
],
- },
- ])
+ ],
+ })
})
test('statically named slot outlet with props', () => {
`<slot name="foo" foo="bar" :baz="qux" />`,
)
expect(code).toMatchSnapshot()
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.SLOT_OUTLET_NODE,
- name: { content: 'foo' },
- props: [
- [
- { key: { content: 'foo' }, values: [{ content: 'bar' }] },
- { key: { content: 'baz' }, values: [{ content: 'qux' }] },
- ],
+ expect(ir.block.dynamic.children[0].operation).toMatchObject({
+ type: IRNodeTypes.SLOT_OUTLET_NODE,
+ name: { content: 'foo' },
+ props: [
+ [
+ { key: { content: 'foo' }, values: [{ content: 'bar' }] },
+ { key: { content: 'baz' }, values: [{ content: 'qux' }] },
],
- },
- ])
+ ],
+ })
})
test('statically named slot outlet with v-bind="obj"', () => {
`<slot name="foo" foo="bar" v-bind="obj" :baz="qux" />`,
)
expect(code).toMatchSnapshot()
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.SLOT_OUTLET_NODE,
- name: { content: 'foo' },
- props: [
- [{ key: { content: 'foo' }, values: [{ content: 'bar' }] }],
- { value: { content: 'obj', isStatic: false } },
- [{ key: { content: 'baz' }, values: [{ content: 'qux' }] }],
- ],
- },
- ])
+ expect(ir.block.dynamic.children[0].operation).toMatchObject({
+ type: IRNodeTypes.SLOT_OUTLET_NODE,
+ name: { content: 'foo' },
+ props: [
+ [{ key: { content: 'foo' }, values: [{ content: 'bar' }] }],
+ { value: { content: 'obj', isStatic: false } },
+ [{ key: { content: 'baz' }, values: [{ content: 'qux' }] }],
+ ],
+ })
})
test('statically named slot outlet with v-on', () => {
`<slot @click="foo" v-on="bar" :baz="qux" />`,
)
expect(code).toMatchSnapshot()
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.SLOT_OUTLET_NODE,
- props: [
- [{ key: { content: 'click' }, values: [{ content: 'foo' }] }],
- { value: { content: 'bar' }, handler: true },
- [{ key: { content: 'baz' }, values: [{ content: 'qux' }] }],
- ],
- },
- ])
+ expect(ir.block.dynamic.children[0].operation).toMatchObject({
+ type: IRNodeTypes.SLOT_OUTLET_NODE,
+ props: [
+ [{ key: { content: 'click' }, values: [{ content: 'foo' }] }],
+ { value: { content: 'bar' }, handler: true },
+ [{ key: { content: 'baz' }, values: [{ content: 'qux' }] }],
+ ],
+ })
})
test('default slot outlet with fallback', () => {
const { ir, code } = compileWithSlotsOutlet(`<slot><div/></slot>`)
expect(code).toMatchSnapshot()
expect(ir.template[0]).toBe('<div></div>')
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.SLOT_OUTLET_NODE,
- id: 0,
- name: { content: 'default' },
- fallback: {
- type: IRNodeTypes.BLOCK,
- dynamic: {
- children: [{ template: 0, id: 2 }],
- },
- returns: [2],
+ expect(ir.block.dynamic.children[0].operation).toMatchObject({
+ type: IRNodeTypes.SLOT_OUTLET_NODE,
+ id: 0,
+ name: { content: 'default' },
+ fallback: {
+ type: IRNodeTypes.BLOCK,
+ dynamic: {
+ children: [{ template: 0, id: 2 }],
},
+ returns: [2],
},
- ])
+ })
})
test('named slot outlet with fallback', () => {
)
expect(code).toMatchSnapshot()
expect(ir.template[0]).toBe('<div></div>')
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.SLOT_OUTLET_NODE,
- id: 0,
- name: { content: 'foo' },
- fallback: {
- type: IRNodeTypes.BLOCK,
- dynamic: {
- children: [{ template: 0, id: 2 }],
- },
- returns: [2],
+ expect(ir.block.dynamic.children[0].operation).toMatchObject({
+ type: IRNodeTypes.SLOT_OUTLET_NODE,
+ id: 0,
+ name: { content: 'foo' },
+ fallback: {
+ type: IRNodeTypes.BLOCK,
+ dynamic: {
+ children: [{ template: 0, id: 2 }],
},
+ returns: [2],
},
- ])
+ })
})
test('default slot outlet with props & fallback', () => {
)
expect(code).toMatchSnapshot()
expect(ir.template[0]).toBe('<div></div>')
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.SLOT_OUTLET_NODE,
- id: 0,
- name: { content: 'default' },
- props: [[{ key: { content: 'foo' }, values: [{ content: 'bar' }] }]],
- fallback: {
- type: IRNodeTypes.BLOCK,
- dynamic: {
- children: [{ template: 0, id: 2 }],
- },
- returns: [2],
+ expect(ir.block.dynamic.children[0].operation).toMatchObject({
+ type: IRNodeTypes.SLOT_OUTLET_NODE,
+ id: 0,
+ name: { content: 'default' },
+ props: [[{ key: { content: 'foo' }, values: [{ content: 'bar' }] }]],
+ fallback: {
+ type: IRNodeTypes.BLOCK,
+ dynamic: {
+ children: [{ template: 0, id: 2 }],
},
+ returns: [2],
},
- ])
+ })
})
test('named slot outlet with props & fallback', () => {
)
expect(code).toMatchSnapshot()
expect(ir.template[0]).toBe('<div></div>')
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.SLOT_OUTLET_NODE,
- id: 0,
- name: { content: 'foo' },
- props: [[{ key: { content: 'foo' }, values: [{ content: 'bar' }] }]],
- fallback: {
- type: IRNodeTypes.BLOCK,
- dynamic: {
- children: [{ template: 0, id: 2 }],
- },
- returns: [2],
+ expect(ir.block.dynamic.children[0].operation).toMatchObject({
+ type: IRNodeTypes.SLOT_OUTLET_NODE,
+ id: 0,
+ name: { content: 'foo' },
+ props: [[{ key: { content: 'foo' }, values: [{ content: 'bar' }] }]],
+ fallback: {
+ type: IRNodeTypes.BLOCK,
+ dynamic: {
+ children: [{ template: 0, id: 2 }],
},
+ returns: [2],
},
- ])
+ })
})
test('error on unexpected custom directive on <slot>', () => {
`<div ref="foo" v-if="true" />`,
)
- expect(ir.block.operation).lengthOf(1)
- expect(ir.block.operation[0].type).toBe(IRNodeTypes.IF)
+ const op = ir.block.dynamic.children[0].operation as IfIRNode
+ expect(op.type).toBe(IRNodeTypes.IF)
- const { positive } = ir.block.operation[0] as IfIRNode
+ const { positive } = op
expect(positive.operation).toMatchObject([
{
type: IRNodeTypes.SET_TEMPLATE_REF,
`<div ref="foo" v-for="item in [1,2,3]" />`,
)
- const { render } = ir.block.operation[0] as ForIRNode
+ const { render } = ir.block.dynamic.children[0].operation as ForIRNode
expect(render.operation).toMatchObject([
{
type: IRNodeTypes.SET_TEMPLATE_REF,
expect(code).matchSnapshot()
expect(helpers).contains('createFor')
expect(ir.template).toEqual(['<div> </div>'])
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.FOR,
- id: 0,
- source: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'items',
- },
- value: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'item',
- },
- key: undefined,
- index: undefined,
- render: {
- type: IRNodeTypes.BLOCK,
- dynamic: {
- children: [{ template: 0 }],
- },
- },
- keyProp: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'item.id',
+ expect(ir.block.dynamic.children[0].operation).toMatchObject({
+ type: IRNodeTypes.FOR,
+ id: 0,
+ source: {
+ type: NodeTypes.SIMPLE_EXPRESSION,
+ content: 'items',
+ },
+ value: {
+ type: NodeTypes.SIMPLE_EXPRESSION,
+ content: 'item',
+ },
+ key: undefined,
+ index: undefined,
+ render: {
+ type: IRNodeTypes.BLOCK,
+ dynamic: {
+ children: [{ template: 0 }],
},
},
- ])
+ keyProp: {
+ type: NodeTypes.SIMPLE_EXPRESSION,
+ content: 'item.id',
+ },
+ })
expect(ir.block.returns).toEqual([0])
expect(ir.block.dynamic).toMatchObject({
children: [{ id: 0 }],
})
expect(ir.block.effect).toEqual([])
- expect((ir.block.operation[0] as ForIRNode).render.effect).lengthOf(1)
+ expect(
+ (ir.block.dynamic.children[0].operation as ForIRNode).render.effect,
+ ).lengthOf(1)
})
test('multi effect', () => {
)
expect(code).contains(`_for_item1.value+_for_item0.value`)
expect(ir.template).toEqual(['<span> </span>', '<div></div>'])
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.FOR,
- id: 0,
- source: { content: 'list' },
- value: { content: 'i' },
- render: {
- type: IRNodeTypes.BLOCK,
- dynamic: {
- children: [{ template: 1 }],
- },
+ const parentOp = ir.block.dynamic.children[0].operation
+ expect(parentOp).toMatchObject({
+ type: IRNodeTypes.FOR,
+ id: 0,
+ source: { content: 'list' },
+ value: { content: 'i' },
+ render: {
+ type: IRNodeTypes.BLOCK,
+ dynamic: {
+ children: [{ template: 1 }],
},
},
- ])
- expect((ir.block.operation[0] as any).render.operation[0]).toMatchObject({
+ })
+ expect(
+ (parentOp as any).render.dynamic.children[0].children[0].operation,
+ ).toMatchObject({
type: IRNodeTypes.FOR,
id: 2,
source: { content: 'i' },
'<span v-for="({ id, value }) in items" :key="id">{{ id }}{{ value }}</span>',
)
expect(code).matchSnapshot()
- expect(ir.block.operation[0]).toMatchObject({
+ expect(ir.block.dynamic.children[0].operation).toMatchObject({
type: IRNodeTypes.FOR,
source: {
type: NodeTypes.SIMPLE_EXPRESSION,
)
expect(code).matchSnapshot()
expect(code).toContain('_getRestElement(_for_item0.value, ["id"])')
- expect(ir.block.operation[0]).toMatchObject({
+ expect(ir.block.dynamic.children[0].operation).toMatchObject({
type: IRNodeTypes.FOR,
source: {
type: NodeTypes.SIMPLE_EXPRESSION,
`<div v-for="([id, other], index) in list" :key="id">{{ id + other + index }}</div>`,
)
expect(code).matchSnapshot()
- expect(ir.block.operation[0]).toMatchObject({
+ expect(ir.block.dynamic.children[0].operation).toMatchObject({
type: IRNodeTypes.FOR,
source: {
type: NodeTypes.SIMPLE_EXPRESSION,
)
expect(code).matchSnapshot()
expect(code).toContain('_for_item0.value.slice(1)')
- expect(ir.block.operation[0]).toMatchObject({
+ expect(ir.block.dynamic.children[0].operation).toMatchObject({
type: IRNodeTypes.FOR,
source: {
type: NodeTypes.SIMPLE_EXPRESSION,
expect(code).toContain(
`_getDefaultValue(_for_item0.value.baz[0], _ctx.quux)`,
)
- expect(ir.block.operation[0]).toMatchObject({
+ expect(ir.block.dynamic.children[0].operation).toMatchObject({
type: IRNodeTypes.FOR,
source: {
type: NodeTypes.SIMPLE_EXPRESSION,
expect(helpers).contains('createIf')
expect(ir.template).toEqual(['<div> </div>'])
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.IF,
- id: 0,
- condition: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'ok',
- isStatic: false,
- },
- positive: {
- type: IRNodeTypes.BLOCK,
- dynamic: {
- children: [{ template: 0 }],
- },
+
+ const op = ir.block.dynamic.children[0].operation
+ expect(op).toMatchObject({
+ type: IRNodeTypes.IF,
+ id: 0,
+ condition: {
+ type: NodeTypes.SIMPLE_EXPRESSION,
+ content: 'ok',
+ isStatic: false,
+ },
+ positive: {
+ type: IRNodeTypes.BLOCK,
+ dynamic: {
+ children: [{ template: 0 }],
},
},
- ])
+ })
expect(ir.block.returns).toEqual([0])
expect(ir.block.dynamic).toMatchObject({
})
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(ir.template).toEqual(['<div></div>', 'hello', '<p> </p>'])
expect(ir.block.effect).toEqual([])
- expect((ir.block.operation[0] as IfIRNode).positive.effect).toMatchObject([
+ const op = ir.block.dynamic.children[0].operation as IfIRNode
+ expect(op.positive.effect).toMatchObject([
{
operations: [
{
],
},
])
- expect((ir.block.operation[0] as IfIRNode).positive.dynamic).toMatchObject({
+ expect(op.positive.dynamic).toMatchObject({
id: 1,
children: {
2: {
expect(helpers).contains('createIf')
expect(ir.block.effect).lengthOf(0)
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.IF,
- id: 0,
- condition: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'ok',
- isStatic: false,
- },
- positive: {
- type: IRNodeTypes.BLOCK,
- dynamic: {
- children: [{ template: 0 }],
- },
+ expect(ir.block.dynamic.children[0].operation).toMatchObject({
+ type: IRNodeTypes.IF,
+ id: 0,
+ condition: {
+ type: NodeTypes.SIMPLE_EXPRESSION,
+ content: 'ok',
+ isStatic: false,
+ },
+ positive: {
+ type: IRNodeTypes.BLOCK,
+ dynamic: {
+ children: [{ template: 0 }],
},
- negative: {
- type: IRNodeTypes.BLOCK,
- dynamic: {
- children: [{ template: 1 }],
- },
+ },
+ negative: {
+ type: IRNodeTypes.BLOCK,
+ dynamic: {
+ children: [{ template: 1 }],
},
},
- ])
+ })
expect(ir.block.returns).toEqual([0])
})
expect(code).matchSnapshot()
expect(ir.template).toEqual(['<div></div>', '<p></p>'])
- expect(ir.block.operation).toMatchObject([
- {
+ expect(ir.block.dynamic.children[0].operation).toMatchObject({
+ type: IRNodeTypes.IF,
+ id: 0,
+ condition: {
+ type: NodeTypes.SIMPLE_EXPRESSION,
+ content: 'ok',
+ isStatic: false,
+ },
+ positive: {
+ type: IRNodeTypes.BLOCK,
+ dynamic: {
+ children: [{ template: 0 }],
+ },
+ },
+ negative: {
type: IRNodeTypes.IF,
- id: 0,
condition: {
type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'ok',
+ content: 'orNot',
isStatic: false,
},
positive: {
type: IRNodeTypes.BLOCK,
dynamic: {
- children: [{ template: 0 }],
- },
- },
- negative: {
- type: IRNodeTypes.IF,
- condition: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'orNot',
- isStatic: false,
- },
- positive: {
- type: IRNodeTypes.BLOCK,
- dynamic: {
- children: [{ template: 1 }],
- },
+ children: [{ template: 1 }],
},
},
},
- ])
+ })
expect(ir.block.returns).toEqual([0])
})
expect(ir.template).toEqual(['<div></div>', '<p></p>', 'fine'])
expect(ir.block.returns).toEqual([0])
- expect(ir.block.operation).toMatchObject([
- {
+ expect(ir.block.dynamic.children[0].operation).toMatchObject({
+ type: IRNodeTypes.IF,
+ id: 0,
+ positive: {
+ type: IRNodeTypes.BLOCK,
+ dynamic: {
+ children: [{ template: 0 }],
+ },
+ },
+ negative: {
type: IRNodeTypes.IF,
- id: 0,
positive: {
type: IRNodeTypes.BLOCK,
dynamic: {
- children: [{ template: 0 }],
+ children: [{ template: 1 }],
},
},
negative: {
- type: IRNodeTypes.IF,
- positive: {
- type: IRNodeTypes.BLOCK,
- dynamic: {
- children: [{ template: 1 }],
- },
- },
- negative: {
- type: IRNodeTypes.BLOCK,
- dynamic: {
- children: [{ template: 2 }],
- },
+ type: IRNodeTypes.BLOCK,
+ dynamic: {
+ children: [{ template: 2 }],
},
},
},
- ])
+ })
})
test('comment between branches', () => {
expect(code).contains(
`"onUpdate:modelValue": () => _value => (_ctx.foo = _value)`,
)
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.CREATE_COMPONENT_NODE,
- tag: 'Comp',
- props: [
- [
- {
- key: { content: 'modelValue', isStatic: true },
- model: true,
- modelModifiers: [],
- values: [{ content: 'foo', isStatic: false }],
- },
- ],
+ expect(ir.block.dynamic.children[0].operation).toMatchObject({
+ type: IRNodeTypes.CREATE_COMPONENT_NODE,
+ tag: 'Comp',
+ props: [
+ [
+ {
+ key: { content: 'modelValue', isStatic: true },
+ model: true,
+ modelModifiers: [],
+ values: [{ content: 'foo', isStatic: false }],
+ },
],
- },
- ])
+ ],
+ })
})
test('v-model with arguments for component should work', () => {
expect(code).contains(
`"onUpdate:bar": () => _value => (_ctx.foo = _value)`,
)
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.CREATE_COMPONENT_NODE,
- tag: 'Comp',
- props: [
- [
- {
- key: { content: 'bar', isStatic: true },
- model: true,
- modelModifiers: [],
- values: [{ content: 'foo', isStatic: false }],
- },
- ],
+ expect(ir.block.dynamic.children[0].operation).toMatchObject({
+ type: IRNodeTypes.CREATE_COMPONENT_NODE,
+ tag: 'Comp',
+ props: [
+ [
+ {
+ key: { content: 'bar', isStatic: true },
+ model: true,
+ modelModifiers: [],
+ values: [{ content: 'foo', isStatic: false }],
+ },
],
- },
- ])
+ ],
+ })
})
test('v-model with dynamic arguments for component should work', () => {
`[_ctx.arg]: _ctx.foo,
["onUpdate:" + _ctx.arg]: () => _value => (_ctx.foo = _value)`,
)
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.CREATE_COMPONENT_NODE,
- tag: 'Comp',
- props: [
- {
- key: { content: 'arg', isStatic: false },
- values: [{ content: 'foo', isStatic: false }],
- model: true,
- modelModifiers: [],
- },
- ],
- },
- ])
+ expect(ir.block.dynamic.children[0].operation).toMatchObject({
+ type: IRNodeTypes.CREATE_COMPONENT_NODE,
+ tag: 'Comp',
+ props: [
+ {
+ key: { content: 'arg', isStatic: false },
+ values: [{ content: 'foo', isStatic: false }],
+ model: true,
+ modelModifiers: [],
+ },
+ ],
+ })
})
test('v-model for component should generate modelModifiers', () => {
expect(code).contain(
`modelModifiers: () => ({ trim: true, "bar-baz": true })`,
)
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.CREATE_COMPONENT_NODE,
- tag: 'Comp',
- props: [
- [
- {
- key: { content: 'modelValue', isStatic: true },
- values: [{ content: 'foo', isStatic: false }],
- model: true,
- modelModifiers: ['trim', 'bar-baz'],
- },
- ],
+ expect(ir.block.dynamic.children[0].operation).toMatchObject({
+ type: IRNodeTypes.CREATE_COMPONENT_NODE,
+ tag: 'Comp',
+ props: [
+ [
+ {
+ key: { content: 'modelValue', isStatic: true },
+ values: [{ content: 'foo', isStatic: false }],
+ model: true,
+ modelModifiers: ['trim', 'bar-baz'],
+ },
],
- },
- ])
+ ],
+ })
})
test('v-model with arguments for component should generate modelModifiers', () => {
expect(code).toMatchSnapshot()
expect(code).contain(`fooModifiers: () => ({ trim: true })`)
expect(code).contain(`barModifiers: () => ({ number: true })`)
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.CREATE_COMPONENT_NODE,
- tag: 'Comp',
- props: [
- [
- {
- key: { content: 'foo', isStatic: true },
- values: [{ content: 'foo', isStatic: false }],
- model: true,
- modelModifiers: ['trim'],
- },
- {
- key: { content: 'bar', isStatic: true },
- values: [{ content: 'bar', isStatic: false }],
- model: true,
- modelModifiers: ['number'],
- },
- ],
- ],
- },
- ])
- })
-
- test('v-model with dynamic arguments for component should generate modelModifiers ', () => {
- const { code, ir } = compileWithVModel(
- '<Comp v-model:[foo].trim="foo" v-model:[bar].number="bar" />',
- )
- expect(code).toMatchSnapshot()
- expect(code).contain(`[_ctx.foo + "Modifiers"]: () => ({ trim: true })`)
- expect(code).contain(`[_ctx.bar + "Modifiers"]: () => ({ number: true })`)
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.CREATE_COMPONENT_NODE,
- tag: 'Comp',
- props: [
+ expect(ir.block.dynamic.children[0].operation).toMatchObject({
+ type: IRNodeTypes.CREATE_COMPONENT_NODE,
+ tag: 'Comp',
+ props: [
+ [
{
- key: { content: 'foo', isStatic: false },
+ key: { content: 'foo', isStatic: true },
values: [{ content: 'foo', isStatic: false }],
model: true,
modelModifiers: ['trim'],
},
{
- key: { content: 'bar', isStatic: false },
+ key: { content: 'bar', isStatic: true },
values: [{ content: 'bar', isStatic: false }],
model: true,
modelModifiers: ['number'],
},
],
- },
- ])
+ ],
+ })
+ })
+
+ test('v-model with dynamic arguments for component should generate modelModifiers ', () => {
+ const { code, ir } = compileWithVModel(
+ '<Comp v-model:[foo].trim="foo" v-model:[bar].number="bar" />',
+ )
+ expect(code).toMatchSnapshot()
+ expect(code).contain(`[_ctx.foo + "Modifiers"]: () => ({ trim: true })`)
+ expect(code).contain(`[_ctx.bar + "Modifiers"]: () => ({ number: true })`)
+ expect(ir.block.dynamic.children[0].operation).toMatchObject({
+ type: IRNodeTypes.CREATE_COMPONENT_NODE,
+ tag: 'Comp',
+ props: [
+ {
+ key: { content: 'foo', isStatic: false },
+ values: [{ content: 'foo', isStatic: false }],
+ model: true,
+ modelModifiers: ['trim'],
+ },
+ {
+ key: { content: 'bar', isStatic: false },
+ values: [{ content: 'bar', isStatic: false }],
+ model: true,
+ modelModifiers: ['number'],
+ },
+ ],
+ })
})
})
})
const { ir, code } = compileWithOnce(`<div><Comp :id="foo" v-once /></div>`)
expect(code).toMatchSnapshot()
expect(ir.block.effect).lengthOf(0)
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.CREATE_COMPONENT_NODE,
- id: 0,
- tag: 'Comp',
- once: true,
- parent: 1,
- },
- ])
+ expect(ir.block.dynamic.children[0].children[0].operation).toMatchObject({
+ type: IRNodeTypes.CREATE_COMPONENT_NODE,
+ id: 0,
+ tag: 'Comp',
+ once: true,
+ parent: 1,
+ })
})
test.todo('on slot outlet')
expect(code).toMatchSnapshot()
expect(ir.block.effect).lengthOf(0)
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.IF,
- id: 0,
- once: true,
- condition: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'expr',
- isStatic: false,
- },
- positive: {
- type: IRNodeTypes.BLOCK,
- dynamic: {
- children: [{ template: 0 }],
- },
+ expect(ir.block.dynamic.children[0].operation).toMatchObject({
+ type: IRNodeTypes.IF,
+ id: 0,
+ once: true,
+ condition: {
+ type: NodeTypes.SIMPLE_EXPRESSION,
+ content: 'expr',
+ isStatic: false,
+ },
+ positive: {
+ type: IRNodeTypes.BLOCK,
+ dynamic: {
+ children: [{ template: 0 }],
},
},
- ])
+ })
})
test('with v-if/else', () => {
expect(code).toMatchSnapshot()
expect(ir.block.effect).lengthOf(0)
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.IF,
- id: 0,
- once: true,
- condition: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'expr',
- isStatic: false,
- },
- positive: {
- type: IRNodeTypes.BLOCK,
- dynamic: {
- children: [{ template: 0 }],
- },
+ expect(ir.block.dynamic.children[0].operation).toMatchObject({
+ type: IRNodeTypes.IF,
+ id: 0,
+ once: true,
+ condition: {
+ type: NodeTypes.SIMPLE_EXPRESSION,
+ content: 'expr',
+ isStatic: false,
+ },
+ positive: {
+ type: IRNodeTypes.BLOCK,
+ dynamic: {
+ children: [{ template: 0 }],
},
- negative: {
- type: IRNodeTypes.BLOCK,
- dynamic: {
- children: [{ template: 1 }],
- },
+ },
+ negative: {
+ type: IRNodeTypes.BLOCK,
+ dynamic: {
+ children: [{ template: 1 }],
},
},
- ])
+ })
})
test('with v-for', () => {
const { ir, code } = compileWithOnce(`<div v-for="i in list" v-once />`)
expect(code).toMatchSnapshot()
expect(ir.block.effect).lengthOf(0)
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.FOR,
- id: 0,
- once: true,
- },
- ])
+ expect(ir.block.dynamic.children[0].operation).toMatchObject({
+ type: IRNodeTypes.FOR,
+ id: 0,
+ once: true,
+ })
})
})
expect(code).toMatchSnapshot()
expect(ir.template).toEqual(['<div></div>'])
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.CREATE_COMPONENT_NODE,
- id: 1,
- tag: 'Comp',
- props: [[]],
- slots: [
- {
- slotType: IRSlotType.STATIC,
- slots: {
- default: {
- type: IRNodeTypes.BLOCK,
- dynamic: {
- children: [{ template: 0 }],
- },
+ expect(ir.block.dynamic.children[0].operation).toMatchObject({
+ type: IRNodeTypes.CREATE_COMPONENT_NODE,
+ id: 1,
+ tag: 'Comp',
+ props: [[]],
+ slots: [
+ {
+ slotType: IRSlotType.STATIC,
+ slots: {
+ default: {
+ type: IRNodeTypes.BLOCK,
+ dynamic: {
+ children: [{ template: 0 }],
},
},
},
- ],
- },
- ])
+ },
+ ],
+ })
expect(ir.block.returns).toEqual([1])
expect(ir.block.dynamic).toMatchObject({
children: [{ id: 1 }],
expect(code).contains(`"default": (_slotProps0) =>`)
expect(code).contains(`_slotProps0["foo"] + _ctx.bar`)
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.CREATE_COMPONENT_NODE,
- tag: 'Comp',
- props: [[]],
- slots: [
- {
- slotType: IRSlotType.STATIC,
- slots: {
- default: {
- type: IRNodeTypes.BLOCK,
- props: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: '{ foo }',
- ast: {
- type: 'ArrowFunctionExpression',
- params: [{ type: 'ObjectPattern' }],
- },
+ expect(ir.block.dynamic.children[0].operation).toMatchObject({
+ type: IRNodeTypes.CREATE_COMPONENT_NODE,
+ tag: 'Comp',
+ props: [[]],
+ slots: [
+ {
+ slotType: IRSlotType.STATIC,
+ slots: {
+ default: {
+ type: IRNodeTypes.BLOCK,
+ props: {
+ type: NodeTypes.SIMPLE_EXPRESSION,
+ content: '{ foo }',
+ ast: {
+ type: 'ArrowFunctionExpression',
+ params: [{ type: 'ObjectPattern' }],
},
},
},
},
- ],
- },
- ])
+ },
+ ],
+ })
})
test('on component named slot', () => {
expect(code).contains(`"named": (_slotProps0) =>`)
expect(code).contains(`_slotProps0["foo"] + _ctx.bar`)
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.CREATE_COMPONENT_NODE,
- tag: 'Comp',
- slots: [
- {
- slotType: IRSlotType.STATIC,
- slots: {
- named: {
- type: IRNodeTypes.BLOCK,
- props: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: '{ foo }',
- },
+ expect(ir.block.dynamic.children[0].operation).toMatchObject({
+ type: IRNodeTypes.CREATE_COMPONENT_NODE,
+ tag: 'Comp',
+ slots: [
+ {
+ slotType: IRSlotType.STATIC,
+ slots: {
+ named: {
+ type: IRNodeTypes.BLOCK,
+ props: {
+ type: NodeTypes.SIMPLE_EXPRESSION,
+ content: '{ foo }',
},
},
},
- ],
- },
- ])
+ },
+ ],
+ })
})
test('on component dynamically named slot', () => {
expect(code).contains(`fn: (_slotProps0) =>`)
expect(code).contains(`_slotProps0["foo"] + _ctx.bar`)
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.CREATE_COMPONENT_NODE,
- tag: 'Comp',
- slots: [
- {
- name: {
+ expect(ir.block.dynamic.children[0].operation).toMatchObject({
+ type: IRNodeTypes.CREATE_COMPONENT_NODE,
+ tag: 'Comp',
+ slots: [
+ {
+ name: {
+ type: NodeTypes.SIMPLE_EXPRESSION,
+ content: 'named',
+ isStatic: false,
+ },
+ fn: {
+ type: IRNodeTypes.BLOCK,
+ props: {
type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'named',
- isStatic: false,
- },
- fn: {
- type: IRNodeTypes.BLOCK,
- props: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: '{ foo }',
- },
+ content: '{ foo }',
},
},
- ],
- },
- ])
+ },
+ ],
+ })
})
test('named slots w/ implicit default slot', () => {
expect(code).toMatchSnapshot()
expect(ir.template).toEqual(['foo', 'bar', '<span></span>'])
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.CREATE_COMPONENT_NODE,
- id: 4,
- tag: 'Comp',
- props: [[]],
- slots: [
- {
- slotType: IRSlotType.STATIC,
- slots: {
- one: {
- type: IRNodeTypes.BLOCK,
- dynamic: {
- children: [{ template: 0 }],
- },
+ expect(ir.block.dynamic.children[0].operation).toMatchObject({
+ type: IRNodeTypes.CREATE_COMPONENT_NODE,
+ id: 4,
+ tag: 'Comp',
+ props: [[]],
+ slots: [
+ {
+ slotType: IRSlotType.STATIC,
+ slots: {
+ one: {
+ type: IRNodeTypes.BLOCK,
+ dynamic: {
+ children: [{ template: 0 }],
},
- default: {
- type: IRNodeTypes.BLOCK,
- dynamic: {
- children: [{}, { template: 1 }, { template: 2 }],
- },
+ },
+ default: {
+ type: IRNodeTypes.BLOCK,
+ dynamic: {
+ children: [{}, { template: 1 }, { template: 2 }],
},
},
},
- ],
- },
- ])
+ },
+ ],
+ })
})
test('nested slots scoping', () => {
expect(code).contains(`_slotProps0["foo"] + _slotProps1["bar"] + _ctx.baz`)
expect(code).contains(`_slotProps0["foo"] + _ctx.bar + _ctx.baz`)
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.CREATE_COMPONENT_NODE,
- tag: 'Comp',
- props: [[]],
- slots: [
- {
- slotType: IRSlotType.STATIC,
- slots: {
- default: {
- type: IRNodeTypes.BLOCK,
- props: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: '{ foo }',
- },
+ const outerOp = ir.block.dynamic.children[0].operation
+ expect(outerOp).toMatchObject({
+ type: IRNodeTypes.CREATE_COMPONENT_NODE,
+ tag: 'Comp',
+ props: [[]],
+ slots: [
+ {
+ slotType: IRSlotType.STATIC,
+ slots: {
+ default: {
+ type: IRNodeTypes.BLOCK,
+ props: {
+ type: NodeTypes.SIMPLE_EXPRESSION,
+ content: '{ foo }',
},
},
},
- ],
- },
- ])
+ },
+ ],
+ })
expect(
- (ir.block.operation[0] as any).slots[0].slots.default.operation[0],
+ (outerOp as any).slots[0].slots.default.dynamic.children[0].operation,
).toMatchObject({
type: IRNodeTypes.CREATE_COMPONENT_NODE,
tag: 'Inner',
</Comp>`,
)
expect(code).toMatchSnapshot()
- expect(ir.block.operation[0].type).toBe(IRNodeTypes.CREATE_COMPONENT_NODE)
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.CREATE_COMPONENT_NODE,
- tag: 'Comp',
- slots: [
- {
- name: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'name',
- isStatic: false,
- },
- fn: { type: IRNodeTypes.BLOCK },
+ expect(ir.block.dynamic.children[0].operation).toMatchObject({
+ type: IRNodeTypes.CREATE_COMPONENT_NODE,
+ tag: 'Comp',
+ slots: [
+ {
+ name: {
+ type: NodeTypes.SIMPLE_EXPRESSION,
+ content: 'name',
+ isStatic: false,
},
- ],
- },
- ])
+ fn: { type: IRNodeTypes.BLOCK },
+ },
+ ],
+ })
})
test('dynamic slots name w/ v-for', () => {
expect(code).contains(`fn: (_slotProps0) =>`)
expect(code).contains(`_setText(n0, _toDisplayString(_slotProps0["bar"]))`)
- expect(ir.block.operation[0].type).toBe(IRNodeTypes.CREATE_COMPONENT_NODE)
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.CREATE_COMPONENT_NODE,
- tag: 'Comp',
- slots: [
- {
- name: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'item',
- isStatic: false,
- },
- fn: { type: IRNodeTypes.BLOCK },
- loop: {
- source: { content: 'list' },
- value: { content: 'item' },
- index: undefined,
- },
+ expect(ir.block.dynamic.children[0].operation).toMatchObject({
+ type: IRNodeTypes.CREATE_COMPONENT_NODE,
+ tag: 'Comp',
+ slots: [
+ {
+ name: {
+ type: NodeTypes.SIMPLE_EXPRESSION,
+ content: 'item',
+ isStatic: false,
},
- ],
- },
- ])
+ fn: { type: IRNodeTypes.BLOCK },
+ loop: {
+ source: { content: 'list' },
+ value: { content: 'item' },
+ index: undefined,
+ },
+ },
+ ],
+ })
})
test('dynamic slots name w/ v-for and provide absent key', () => {
</Comp>`,
)
expect(code).toMatchSnapshot()
- expect(ir.block.operation[0].type).toBe(IRNodeTypes.CREATE_COMPONENT_NODE)
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.CREATE_COMPONENT_NODE,
- tag: 'Comp',
- slots: [
- {
- name: {
+ expect(ir.block.dynamic.children[0].operation).toMatchObject({
+ type: IRNodeTypes.CREATE_COMPONENT_NODE,
+ tag: 'Comp',
+ slots: [
+ {
+ name: {
+ type: NodeTypes.SIMPLE_EXPRESSION,
+ content: 'index',
+ isStatic: false,
+ },
+ fn: { type: IRNodeTypes.BLOCK },
+ loop: {
+ source: { content: 'list' },
+ value: undefined,
+ index: {
type: NodeTypes.SIMPLE_EXPRESSION,
- content: 'index',
- isStatic: false,
- },
- fn: { type: IRNodeTypes.BLOCK },
- loop: {
- source: { content: 'list' },
- value: undefined,
- index: {
- type: NodeTypes.SIMPLE_EXPRESSION,
- },
},
},
- ],
- },
- ])
+ },
+ ],
+ })
})
test('dynamic slots name w/ v-if / v-else[-if]', () => {
expect(code).contains(`fn: (_slotProps0) =>`)
- expect(ir.block.operation[0].type).toBe(IRNodeTypes.CREATE_COMPONENT_NODE)
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.CREATE_COMPONENT_NODE,
- tag: 'Comp',
- slots: [
- {
+ expect(ir.block.dynamic.children[0].operation).toMatchObject({
+ type: IRNodeTypes.CREATE_COMPONENT_NODE,
+ tag: 'Comp',
+ slots: [
+ {
+ slotType: IRSlotType.CONDITIONAL,
+ condition: { content: 'condition' },
+ positive: {
+ slotType: IRSlotType.DYNAMIC,
+ },
+ negative: {
slotType: IRSlotType.CONDITIONAL,
- condition: { content: 'condition' },
+ condition: { content: 'anotherCondition' },
positive: {
slotType: IRSlotType.DYNAMIC,
},
- negative: {
- slotType: IRSlotType.CONDITIONAL,
- condition: { content: 'anotherCondition' },
- positive: {
- slotType: IRSlotType.DYNAMIC,
- },
- negative: { slotType: IRSlotType.DYNAMIC },
- },
+ negative: { slotType: IRSlotType.DYNAMIC },
},
- ],
- },
- ])
+ },
+ ],
+ })
})
test('quote slot name', () => {
test('nested component slot', () => {
const { ir, code } = compileWithSlots(`<A><B/></A>`)
expect(code).toMatchSnapshot()
- expect(ir.block.operation).toMatchObject([
- {
- type: IRNodeTypes.CREATE_COMPONENT_NODE,
- tag: 'A',
- slots: [
- {
- slotType: IRSlotType.STATIC,
- slots: {
- default: {
- type: IRNodeTypes.BLOCK,
- operation: [
+ expect(ir.block.dynamic.children[0].operation).toMatchObject({
+ type: IRNodeTypes.CREATE_COMPONENT_NODE,
+ tag: 'A',
+ slots: [
+ {
+ slotType: IRSlotType.STATIC,
+ slots: {
+ default: {
+ type: IRNodeTypes.BLOCK,
+ dynamic: {
+ children: [
{
- type: IRNodeTypes.CREATE_COMPONENT_NODE,
- tag: 'B',
- slots: [],
+ operation: {
+ type: IRNodeTypes.CREATE_COMPONENT_NODE,
+ tag: 'B',
+ slots: [],
+ },
},
],
},
},
},
- ],
- },
- ])
+ },
+ ],
+ })
})
describe('errors', () => {
} from './utils'
import type { CodegenContext } from '../generate'
import { genEffects, genOperations } from './operation'
-import { genChildren } from './template'
+import { genChildren, genSelf } from './template'
import { toValidAssetId } from '@vue/compiler-dom'
export function genBlock(
genResolveAssets('directive', 'resolveDirective')
}
+ for (const child of dynamic.children) {
+ push(...genSelf(child, context))
+ }
for (const child of dynamic.children) {
push(...genChildren(child, context, `n${child.id!}`))
}
IRNodeTypes,
type InsertionStateTypes,
type OperationNode,
- isTypeThatNeedsInsertionState,
+ isBlockOperation,
} from '../ir'
import type { CodegenContext } from '../generate'
import { genInsertNode, genPrependNode } from './dom'
): CodeFragment[] {
const [frag, push] = buildCodeFragment()
for (const operation of opers) {
- if (isTypeThatNeedsInsertionState(operation) && operation.parent) {
- push(...genInsertionstate(operation, context))
- }
- push(...genOperation(operation, context))
+ push(...genOperationWithInsertionState(operation, context))
+ }
+ return frag
+}
+
+export function genOperationWithInsertionState(
+ oper: OperationNode,
+ context: CodegenContext,
+): CodeFragment[] {
+ const [frag, push] = buildCodeFragment()
+ if (isBlockOperation(oper) && oper.parent) {
+ push(...genInsertionstate(oper, context))
}
+ push(...genOperation(oper, context))
return frag
}
import type { CodegenContext } from '../generate'
import { DynamicFlag, type IRDynamicInfo } from '../ir'
import { genDirectivesForElement } from './directive'
+import { genOperationWithInsertionState } from './operation'
import { type CodeFragment, NEWLINE, buildCodeFragment, genCall } from './utils'
export function genTemplates(
.join('')
}
-export function genChildren(
+export function genSelf(
dynamic: IRDynamicInfo,
context: CodegenContext,
- from: string,
- path: number[] = [],
- knownPaths: [id: string, path: number[]][] = [],
): CodeFragment[] {
- const { helper } = context
const [frag, push] = buildCodeFragment()
- let offset = 0
- const { children, id, template } = dynamic
+ const { id, template, operation } = dynamic
if (id !== undefined && template !== undefined) {
push(NEWLINE, `const n${id} = t${template}()`)
push(...genDirectivesForElement(id, context))
}
+ if (operation) {
+ push(...genOperationWithInsertionState(operation, context))
+ }
+
+ return frag
+}
+
+export function genChildren(
+ dynamic: IRDynamicInfo,
+ context: CodegenContext,
+ from: string = `n${dynamic.id}`,
+): CodeFragment[] {
+ const { helper } = context
+ const [frag, push] = buildCodeFragment()
+ const { children } = dynamic
+
+ let offset = 0
let prev: [variable: string, elementIndex: number] | undefined
+ const childrenToGen: [IRDynamicInfo, string][] = []
+
for (const [index, child] of children.entries()) {
if (child.flags & DynamicFlag.NON_TEMPLATE) {
offset--
: undefined
if (id === undefined && !child.hasDynamicChild) {
- const { id, template } = child
- if (id !== undefined && template !== undefined) {
- push(NEWLINE, `const n${id} = t${template}()`)
- push(...genDirectivesForElement(id, context))
- }
+ push(...genSelf(child, context))
continue
}
const elementIndex = Number(index) + offset
- const newPath = [...path, elementIndex]
-
// p for "placeholder" variables that are meant for possible reuse by
// other access paths
const variable = id === undefined ? `p${context.block.tempId++}` : `n${id}`
push(...genCall(helper('nthChild'), from, String(elementIndex)))
}
} else {
- if (newPath.length === 1 && newPath[0] === 0) {
+ if (elementIndex === 0) {
push(...genCall(helper('child'), from))
} else {
// check if there's a node that we can reuse from
- let resolvedFrom = from
- let resolvedPath = newPath
- let skipFirstChild = false
- outer: for (const [from, path] of knownPaths) {
- const l = path.length
- const tail = newPath.slice(l)
- for (let i = 0; i < l; i++) {
- const parentSeg = path[i]
- const thisSeg = newPath[i]
- if (parentSeg !== thisSeg) {
- if (i === l - 1) {
- // last bit is reusable
- resolvedFrom = from
- resolvedPath = [thisSeg - parentSeg, ...tail]
- skipFirstChild = true
- break outer
- }
- break
- } else if (i === l - 1) {
- // full overlap
- resolvedFrom = from
- resolvedPath = tail
- break outer
- }
- }
- }
- let init
- 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))
- }
+ let init = genCall(helper('child'), from)
+ if (elementIndex === 1) {
+ init = genCall(helper('next'), init)
+ } else if (elementIndex > 1) {
+ init = genCall(helper('nthChild'), from, String(elementIndex))
}
- push(...init!)
+ push(...init)
}
}
if (id !== undefined) {
push(...genDirectivesForElement(id, context))
}
- knownPaths.unshift([variable, newPath])
prev = [variable, elementIndex]
- push(...genChildren(child, context, variable))
+ childrenToGen.push([child, variable])
+ }
+
+ for (const [child, from] of childrenToGen) {
+ push(...genChildren(child, context, from))
}
return frag
children: IRDynamicInfo[]
template?: number
hasDynamicChild?: boolean
+ operation?: OperationNode
}
export interface IREffect {
| SlotOutletIRNode
| CreateComponentIRNode
-export function isTypeThatNeedsInsertionState(
- op: OperationNode,
-): op is InsertionStateTypes {
+export function isBlockOperation(op: OperationNode): op is InsertionStateTypes {
const type = op.type
return (
type === IRNodeTypes.CREATE_COMPONENT_NODE ||
DynamicFlag,
type IRDynamicInfo,
IRNodeTypes,
- isTypeThatNeedsInsertionState as isBlockOperation,
+ isBlockOperation,
} from '../ir'
export const transformChildren: NodeTransform = (node, context) => {
parent: context.reference(),
anchor,
})
- } else {
+ } else if (child.operation && isBlockOperation(child.operation)) {
// block types
- for (const op of context.block.operation) {
- if (isBlockOperation(op) && op.id === child.id) {
- op.parent = context.reference()
- op.anchor = anchor
- }
- }
+ child.operation.parent = context.reference()
+ child.operation.anchor = anchor
}
}
}
}
context.dynamic.flags |= DynamicFlag.NON_TEMPLATE | DynamicFlag.INSERT
- context.registerOperation({
+ context.dynamic.operation = {
type: IRNodeTypes.CREATE_COMPONENT_NODE,
id: context.reference(),
tag,
slots: [...context.slots],
once: context.inVOnce,
dynamic: dynamicComponent,
- })
+ }
context.slots = []
}
return () => {
exitBlock && exitBlock()
- context.registerOperation({
+ context.dynamic.operation = {
type: IRNodeTypes.SLOT_OUTLET_NODE,
id,
name: slotName,
props: irProps,
fallback,
- })
+ }
}
}
parent.block.node !== parent.node &&
parent.node.children.length === 1
- context.registerOperation({
+ context.dynamic.operation = {
type: IRNodeTypes.FOR,
id,
source: source as SimpleExpressionNode,
),
component: isComponent,
onlyChild: !!isOnlyChild,
- })
+ }
}
}
return () => {
onExit()
- context.registerOperation({
+ context.dynamic.operation = {
type: IRNodeTypes.IF,
id,
condition: dir.exp!,
once:
context.inVOnce ||
isStaticExpression(dir.exp!, context.options.bindingMetadata),
- })
+ }
}
} else {
// check the adjacent v-if
const siblingIf = getSiblingIf(context, true)
- const { operation } = context.block
- let lastIfNode = operation[operation.length - 1]
+ const siblings = context.parent && context.parent.dynamic.children
+ let lastIfNode
+ if (siblings) {
+ let i = siblings.length
+ while (i--) {
+ if (siblings[i].operation) lastIfNode = siblings[i].operation
+ }
+ }
if (
// check if v-if is the sibling node
)
})
+ test('nested fragment components', async () => {
+ const t0 = template('<div> </div>')
+ const t1 = template(' ')
+ const msg = ref('foo')
+ const Comp = {
+ setup() {
+ const n0 = t0() as Element
+ const n1 = t1() as Text
+ const x0 = child(n0) as Text
+ renderEffect(() => {
+ const _msg = msg.value
+
+ setText(x0, toDisplayString(_msg))
+ setText(n1, toDisplayString(_msg))
+ })
+ return [n0, n1]
+ },
+ }
+
+ const t2 = template('<div></div>')
+ const Parent = {
+ setup() {
+ const n0 = t2()
+ const n1 = createComponent(Comp)
+ const n2 = t2()
+ return [n0, n1, n2]
+ },
+ }
+
+ const t3 = template('<div><span></span></div>', true)
+ const { container } = mountWithHydration(
+ '<div><!--[-->' +
+ '<div></div><!--[--><div>foo</div>foo<!--]--><div></div>' +
+ '<!--]--><span></span></div>',
+ () => {
+ const n1 = t3() as Element
+ setInsertionState(n1, 0)
+ createComponent(Parent)
+ return n1
+ },
+ )
+
+ expect(container.innerHTML).toBe(
+ '<div><!--[-->' +
+ '<div></div><!--[--><div>foo</div>foo<!--]--><div></div>' +
+ '<!--]--><span></span></div>',
+ )
+
+ msg.value = 'bar'
+ await nextTick()
+ expect(container.innerHTML).toBe(
+ '<div><!--[-->' +
+ '<div></div><!--[--><div>bar</div>bar<!--]--><div></div>' +
+ '<!--]--><span></span></div>',
+ )
+ })
+
// test('element with ref', () => {
// const el = ref()
// const { vnode, container } = mountWithHydration('<div></div>', () =>
} from './componentSlots'
import { hmrReload, hmrRerender } from './hmr'
import { isHydrating, locateHydrationNode } from './dom/hydration'
-import {
- insertionAnchor,
- insertionParent,
- resetInsertionState,
-} from './insertionState'
+import { insertionAnchor, insertionParent } from './insertionState'
export { currentInstance } from '@vue/runtime-dom'
currentInstance.appContext) ||
emptyContext,
): VaporComponentInstance {
+ const _insertionParent = insertionParent
+ const _insertionAnchor = insertionAnchor
if (isHydrating) {
locateHydrationNode()
}
onScopeDispose(() => unmountComponent(instance), true)
- if (!isHydrating && insertionParent) {
- insert(instance.block, insertionParent, insertionAnchor)
- resetInsertionState()
+ if (!isHydrating && _insertionParent) {
+ insert(instance.block, _insertionParent, _insertionAnchor)
}
return instance
setInsertionState(container, 0)
const res = fn()
resetInsertionState()
+ currentHydrationNode = null
isHydrating = false
return res
}
}
function locateHydrationNodeImpl() {
- if (__DEV__ && !insertionParent) {
- warn('Hydration error: missing insertion state.')
- }
-
let node: Node | null
// prepend / firstChild
} else {
node = insertionAnchor
? insertionAnchor.previousSibling
- : insertionParent!.lastChild
+ : insertionParent
+ ? insertionParent.lastChild
+ : currentHydrationNode
if (node && isComment(node, ']')) {
// fragment backward search
}
}
- currentHydrationNode = node
-
- if (__DEV__ && !currentHydrationNode) {
+ if (__DEV__ && !node) {
// TODO more info
warn('Hydration mismatch in ', insertionParent)
}
+
+ resetInsertionState()
+ currentHydrationNode = node
}
-import { setCurrentHydrationNode } from './dom/hydration'
-
export let insertionParent: ParentNode | undefined
export let insertionAnchor: Node | 0 | undefined
export function resetInsertionState(): void {
insertionParent = insertionAnchor = undefined
- setCurrentHydrationNode(null)
}