`;
exports[`comile > directives > v-once > basic 1`] = `
-"import { template, children, createTextNode, setText, setAttr, insert } from 'vue/vapor';
+"import { template, children, createTextNode, setText, setAttr, prepend } from 'vue/vapor';
const t0 = template('<div> <span></span></div>');
export function render() {
const n0 = t0();
0: [
n3,
{
- 2: [n2],
+ 1: [n2],
},
],
} = children(n0);
const n1 = createTextNode(msg.value);
setText(n1, undefined, msg.value);
setAttr(n2, 'class', undefined, clz.value);
- insert(n1, n3, 0 /* InsertPosition.FIRST */);
+ prepend(n3, n1);
return n0;
}
"
exports[`comile > static + dynamic root 1`] = `
"import { watchEffect } from 'vue';
-import { template, createTextNode, insert, setText } from 'vue/vapor';
-const t0 = template('2');
+import { template, children, createTextNode, prepend, insert, append, setText } from 'vue/vapor';
+const t0 = template('3<!>6<!>9');
export function render() {
const n0 = t0();
+ const {
+ 1: [n9],
+ 3: [n10],
+ } = children(n0);
const n1 = createTextNode(1);
- const n2 = createTextNode(3);
- insert(n1, n0, 0 /* InsertPosition.FIRST */);
- insert(n2, n0);
+ const n2 = createTextNode(2);
+ const n3 = createTextNode(4);
+ const n4 = createTextNode(5);
+ const n5 = createTextNode(7);
+ const n6 = createTextNode(8);
+ const n7 = createTextNode('A');
+ const n8 = createTextNode('B');
+ prepend(n0, n1, n2);
+ insert([n3, n4], n0, n9);
+ insert([n5, n6], n0, n10);
+ append(n0, n7, n8);
watchEffect(() => {
setText(n1, undefined, 1);
});
watchEffect(() => {
- setText(n2, undefined, 3);
+ setText(n2, undefined, 2);
+ });
+ watchEffect(() => {
+ setText(n3, undefined, 4);
+ });
+ watchEffect(() => {
+ setText(n4, undefined, 5);
+ });
+ watchEffect(() => {
+ setText(n5, undefined, 7);
+ });
+ watchEffect(() => {
+ setText(n6, undefined, 8);
+ });
+ watchEffect(() => {
+ setText(n7, undefined, 'A');
+ });
+ watchEffect(() => {
+ setText(n8, undefined, 'B');
});
return n0;
}
exports[`fixtures 1`] = `
"import { defineComponent as _defineComponent } from 'vue'
import { watchEffect } from 'vue'
-import { template, children, createTextNode, insert, setText, on, setHtml } from 'vue/vapor'
+import { template, children, createTextNode, append, setText, on, setHtml } from 'vue/vapor'
const t0 = template(\\"<h1 id=\\\\\\"title\\\\\\">Counter</h1><p>Count: </p><p>Double: </p><button>Increment</button><div></div><input type=\\\\\\"text\\\\\\"><p>once: </p><p>{{ count }}</p>\\")
import { ref, computed } from 'vue'
const n0 = t0()
const { 1: [n2], 2: [n4], 3: [n5], 4: [n6], 6: [n8],} = children(n0)
const n1 = createTextNode(count.value)
-insert(n1, n2)
+append(n2, n1)
const n3 = createTextNode(double.value)
-insert(n3, n4)
+append(n4, n3)
const n7 = createTextNode(count.value)
setText(n7, undefined, count.value)
-insert(n7, n8)
+append(n8, n7)
watchEffect(() => {
setText(n1, undefined, count.value)
})
})
test('static + dynamic root', async () => {
- const code = await compile(`{{ 1 }}2{{ 3 }}`)
+ const code = await compile(
+ `{{ 1 }}{{ 2 }}3{{ 4 }}{{ 5 }}6{{ 7 }}{{ 8 }}9{{ 'A' }}{{ 'B' }}`,
+ )
expect(code).matchSnapshot()
})
}
case IRNodeTypes.INSERT_NODE: {
- let anchor = ''
- if (typeof oper.anchor === 'number') {
- anchor = `, n${oper.anchor}`
- } else if (oper.anchor === 'first') {
- anchor = `, 0 /* InsertPosition.FIRST */`
- }
- code = `insert(n${oper.element}, n${oper.parent}${anchor})\n`
+ const elements = ([] as number[]).concat(oper.element)
+ let element = elements.map((el) => `n${el}`).join(', ')
+ if (elements.length > 1) element = `[${element}]`
+ code = `insert(${element}, n${oper.parent}${`, n${oper.anchor}`})\n`
vaporHelpers.add('insert')
break
}
+ case IRNodeTypes.PREPEND_NODE: {
+ code = `prepend(n${oper.parent}, ${oper.elements
+ .map((el) => `n${el}`)
+ .join(', ')})\n`
+ vaporHelpers.add('prepend')
+ break
+ }
case IRNodeTypes.APPEND_NODE: {
code = `append(n${oper.parent}, ${oper.elements
.map((el) => `n${el}`)
let code = ''
// TODO
let offset = 0
-
for (const [index, child] of Object.entries(children)) {
const childrenLength = Object.keys(child.children).length
- if (child.ghost && child.placeholder === null && childrenLength === 0)
+ if (child.ghost && child.placeholder === null && childrenLength === 0) {
+ offset--
continue
+ }
code += ` ${Number(index) + offset}: [`
SET_HTML,
INSERT_NODE,
+ PREPEND_NODE,
APPEND_NODE,
CREATE_TEXT_NODE,
}
value: string
}
-export type InsertAnchor = number | 'first' | 'last'
export interface InsertNodeIRNode extends IRNode {
type: IRNodeTypes.INSERT_NODE
- element: number
+ element: number | number[]
+ parent: number
+ anchor: number
+}
+
+export interface PrependNodeIRNode extends IRNode {
+ type: IRNodeTypes.PREPEND_NODE
+ elements: number[]
parent: number
- anchor: InsertAnchor
}
export interface AppendNodeIRNode extends IRNode {
| SetHtmlIRNode
| CreateTextNodeIRNode
| InsertNodeIRNode
+ | PrependNodeIRNode
| AppendNodeIRNode
export interface DynamicInfo {
type RootIRNode,
IRNodeTypes,
DynamicInfo,
- InsertAnchor,
} from './ir'
import { isVoidTag } from '@vue/shared'
const childrenTemplate: string[] = []
children.forEach((child, i) => walkNode(child, i))
- const dynamicChildren = Object.values(ctx.dynamic.children)
- const dynamicCount = dynamicChildren.reduce(
- (prev, child) => prev + (child.ghost ? 1 : 0),
- 0,
- )
- if (dynamicCount === children.length) {
- // all dynamic node
- ctx.registerOpration({
- type: IRNodeTypes.APPEND_NODE,
- loc: ctx.node.loc,
- elements: dynamicChildren.map((child) => child.id!),
- parent: ctx.reference(),
- })
- } else if (dynamicCount > 0 && dynamicCount < children.length) {
- // mixed
- for (const [indexString, child] of Object.entries(ctx.dynamic.children)) {
- if (!child.ghost) continue
-
- const index = Number(indexString)
- let anchor: InsertAnchor
- if (index === 0) {
- anchor = 'first'
- } else if (index === children.length - 1) {
- anchor = 'last'
- } else {
- childrenTemplate[index] = `<!>`
- anchor = child.placeholder = ctx.incraseId()
- }
+ let prevChildren: DynamicInfo[] = []
+ let hasStatic = false
+
+ for (let index = 0; index < children.length; index++) {
+ const child = ctx.dynamic.children[index]
+
+ if (!child || !child.ghost) {
+ if (prevChildren.length)
+ if (hasStatic) {
+ childrenTemplate[index - prevChildren.length] = `<!>`
+ const anchor = (prevChildren[0].placeholder = ctx.incraseId())
+
+ ctx.registerOpration({
+ type: IRNodeTypes.INSERT_NODE,
+ loc: ctx.node.loc,
+ element: prevChildren.map((child) => child.id!),
+ parent: ctx.reference(),
+ anchor,
+ })
+ } else {
+ ctx.registerOpration({
+ type: IRNodeTypes.PREPEND_NODE,
+ loc: ctx.node.loc,
+ elements: prevChildren.map((child) => child.id!),
+ parent: ctx.reference(),
+ })
+ }
+ hasStatic = true
+ prevChildren = []
+ continue
+ }
+
+ prevChildren.push(child)
+ if (index === children.length - 1) {
ctx.registerOpration({
- type: IRNodeTypes.INSERT_NODE,
+ type: IRNodeTypes.APPEND_NODE,
loc: ctx.node.loc,
- element: child.id!,
+ elements: prevChildren.map((child) => child.id!),
parent: ctx.reference(),
- anchor,
})
}
}
// }
}
+export function prepend(parent: ParentBlock, ...nodes: Node[]) {
+ if (parent instanceof Node) {
+ parent.prepend(...nodes)
+ } else if (isArray(parent)) {
+ parent.unshift(...nodes)
+ }
+}
+
export function append(parent: ParentBlock, ...nodes: Node[]) {
if (parent instanceof Node) {
parent.append(...nodes)
--- /dev/null
+<template>
+ {{ 1 }}{{ 2 }}3{{ 4 }}{{ 5 }}6{{ 7 }}{{ 8 }}9{{ 'A' }}{{ 'B' }}
+</template>