import { template, children, insert, setText } from 'vue/vapor';
const t0 = template(\`<div>count is <!>.</div>\`);
export function render() {
- const root = t0();
+ const n0 = t0();
const {
0: [
n1,
watchEffect(() => {
setText(n2, undefined, count.value);
});
- return root;
+ return n0;
}
"
`;
import { template, children, setAttr } from 'vue/vapor';
const t0 = template(\`<div></div>\`);
export function render() {
- const root = t0();
+ const n0 = t0();
const {
0: [n1],
} = children(root);
watchEffect(() => {
setAttr(n1, 'id', undefined, id.value);
});
- return root;
+ return n0;
}
"
`;
import { template, children, setHtml } from 'vue/vapor';
const t0 = template(\`<div></div>\`);
export function render() {
- const root = t0();
+ const n0 = t0();
const {
0: [n1],
} = children(root);
watchEffect(() => {
setHtml(n1, undefined, '');
});
- return root;
+ return n0;
}
"
`;
import { template, children, setHtml } from 'vue/vapor';
const t0 = template(\`<div></div>\`);
export function render() {
- const root = t0();
+ const n0 = t0();
const {
0: [n1],
} = children(root);
watchEffect(() => {
setHtml(n1, undefined, code.value);
});
- return root;
+ return n0;
}
"
`;
import { template, children, on } from 'vue/vapor';
const t0 = template(\`<div></div>\`);
export function render() {
- const root = t0();
+ const n0 = t0();
const {
0: [n1],
} = children(root);
watchEffect(() => {
on(n1, 'click', handleClick);
});
- return root;
+ return n0;
}
"
`;
import { template, children, setAttr } from 'vue/vapor';
const t0 = template(\`<div></div>\`);
export function render() {
- const root = t0();
+ const n0 = t0();
const {
0: [n1],
} = children(root);
watchEffect(() => {
setAttr(n1, 'id', undefined, foo);
});
- return root;
+ return n0;
}
"
`;
"import { template, children, insert, setText, setAttr } from 'vue/vapor';
const t0 = template(\`<div> <span></span></div>\`);
export function render() {
- const root = t0();
+ const n0 = t0();
const {
0: [
n1,
insert(n2, n1, 0 /* InsertPosition.FIRST */);
setText(n2, undefined, msg.value);
setAttr(n3, 'class', undefined, clz.value);
- return root;
+ return n0;
}
"
`;
import { template, children, setText } from 'vue/vapor';
const t0 = template(\`<div></div>\`);
export function render() {
- const root = t0();
+ const n0 = t0();
const {
0: [n1],
} = children(root);
watchEffect(() => {
setText(n1, undefined, '');
});
- return root;
+ return n0;
}
"
`;
import { template, children, setText } from 'vue/vapor';
const t0 = template(\`<div></div>\`);
export function render() {
- const root = t0();
+ const n0 = t0();
const {
0: [n1],
} = children(root);
watchEffect(() => {
setText(n1, undefined, str.value);
});
- return root;
+ return n0;
}
"
`;
exports[`comile > fragment 1`] = `
-"import { template, children } from 'vue/vapor';
+"import { template } from 'vue/vapor';
const t0 = template(\`<p></p><span></span><div></div>\`);
export function render() {
- const root = t0();
- const {
- 0: [n1],
- 1: [n2],
- 2: [n3],
- } = children(root);
- return root;
+ const n0 = t0();
+ return n0;
+}
+"
+`;
+
+exports[`comile > static + dynamic root 1`] = `
+"import { watchEffect } from 'vue';
+import { template, insert, setText } from 'vue/vapor';
+const t0 = template(\`2\`);
+export function render() {
+ const n0 = t0();
+ const n1 = document.createTextNode(1);
+ insert(n1, n0, 0 /* InsertPosition.FIRST */);
+ const n2 = document.createTextNode(3);
+ insert(n2, n0);
+ watchEffect(() => {
+ setText(n1, undefined, 1);
+ });
+ watchEffect(() => {
+ setText(n2, undefined, 3);
+ });
+ return n0;
}
"
`;
exports[`comile > static template 1`] = `
-"import { template, children } from 'vue/vapor';
+"import { template } from 'vue/vapor';
const t0 = template(\`<div><p>hello</p><input><span></span></div>\`);
export function render() {
- const root = t0();
- const {
- 0: [n1],
- } = children(root);
- return root;
+ const n0 = t0();
+ return n0;
}
"
`;
return (() => {
-const root = t0()
-const { 0: [n1], 1: [n2], 2: [n4], 3: [n6], 4: [n7], 5: [n8], 6: [n9], 7: [n11],} = children(root)
-const n3 = document.createTextNode(count.value)
-insert(n3, n2)
-const n5 = document.createTextNode(double.value)
-insert(n5, n4)
-const n10 = document.createTextNode(count.value)
-insert(n10, n9)
-setText(n10, undefined, count.value)
+const n0 = t0()
+const { 1: [n1], 2: [n3], 3: [n5], 4: [n6], 6: [n7],} = children(root)
+const n2 = document.createTextNode(count.value)
+insert(n2, n1)
+const n4 = document.createTextNode(double.value)
+insert(n4, n3)
+const n8 = document.createTextNode(count.value)
+insert(n8, n7)
+setText(n8, undefined, count.value)
watchEffect(() => {
-setText(n3, undefined, count.value)
+setText(n2, undefined, count.value)
})
watchEffect(() => {
-setText(n5, undefined, double.value)
+setText(n4, undefined, double.value)
})
watchEffect(() => {
-on(n6, \\"click\\", increment)
+on(n5, \\"click\\", increment)
})
watchEffect(() => {
-setHtml(n7, undefined, html)
+setHtml(n6, undefined, html)
})
-return root
+return n0
})();
}
expect(code).matchSnapshot()
})
+ test('static + dynamic root', async () => {
+ const code = await compile(`{{ 1 }}2{{ 3 }}`)
+ expect(code).matchSnapshot()
+ })
+
test('fragment', async () => {
const code = await compile(`<p/><span/><div/>`)
expect(code).matchSnapshot()
}
{
- code += `const root = t0()\n`
- code += `const {${genChildren(ir.children.children)}} = children(root)\n`
- vaporHelpers.add('children')
+ code += `const n${ir.children.id} = t0()\n`
+ if (Object.keys(ir.children.children).length) {
+ code += `const {${genChildren(ir.children.children)}} = children(root)\n`
+ vaporHelpers.add('children')
+ }
for (const operation of ir.operation) {
code += genOperation(operation)
code += scope
}
// TODO multiple-template
- code += `return root\n`
+ code += `return n${ir.children.id}\n`
}
if (vaporHelpers.size)
export interface DynamicChild {
id: number | null
store: boolean
+ ghost: boolean
children: DynamicChildren
}
export type DynamicChildren = Record<number, DynamicChild>
store: boolean
ghost: boolean
once: boolean
+ id: number | null
- getElementId(): number
+ getId(): number
+ incraseId(): number
registerTemplate(): number
registerEffect(expr: string, operation: OperationNode): void
registerOpration(...oprations: OperationNode[]): void
node: RootNode,
options: TransformOptions,
): TransformContext<RootNode> {
- let i = 0
+ let globalId = 0
const { effect, operation: operation, helpers, vaporHelpers } = ir
const ctx: TransformContext<RootNode> = {
ghost: false,
once: false,
- getElementId: () => i++,
+ id: null,
+ incraseId: () => globalId++,
+ getId() {
+ if (this.id !== null) return this.id
+ return (this.id = this.incraseId())
+ },
registerEffect(expr, operation) {
if (!effect[expr]) effect[expr] = []
effect[expr].push(operation)
parent: TransformContext,
index: number,
): TransformContext<T> {
- let id: number | undefined
- const getElementId = () => {
- if (id !== undefined) return id
- return (id = parent.root.getElementId())
- }
const children = {}
const ctx: TransformContext<T> = {
...parent,
+ id: null,
node,
parent,
index,
set template(t) {
parent.template = t
},
- getElementId,
-
children,
store: false,
registerEffect(expr, operation) {
vaporHelpers: new Set([]),
}
const ctx = createRootContext(ir, root, options)
- const rootId = ctx.getElementId()
+ const rootId = ctx.getId()
// TODO: transform presets, see packages/compiler-core/src/transforms
transformChildren(ctx, true)
ir.children = {
- store: true,
id: rootId,
+ store: true,
+ ghost: false,
children: ctx.children,
}
const isFirst = i === 0
const isLast = i === children.length - 1
- // TODO: multiple root elements
- if (root) {
- child.store = true
- // generate id for root element early
- child.getElementId()
- }
-
switch (node.type) {
case 1 satisfies NodeTypes.ELEMENT: {
transformElement(child as TransformContext<ElementNode>)
if (Object.keys(child.children).length > 0 || child.store)
ctx.children[index] = {
- id: child.store ? child.getElementId() : null,
+ id: child.store ? child.getId() : null,
store: child.store,
children: child.children,
+ ghost: child.ghost,
}
if (!child.ghost) index++
const expr = processExpression(ctx, node.content)!
const parent = ctx.parent!
- const parentId = parent.getElementId()
+ const parentId = parent.getId()
parent.store = true
if (isFirst && isLast) {
let anchor: number | 'first' | 'last'
if (!isFirst && !isLast) {
- id = ctx.root.getElementId()
- anchor = ctx.getElementId()
+ id = ctx.incraseId()
+ anchor = ctx.getId()
ctx.template += '<!>'
ctx.store = true
} else {
- id = ctx.getElementId()
+ id = ctx.getId()
ctx.ghost = true
anchor = isFirst ? 'first' : 'last'
}
ctx.registerEffect(expr, {
type: IRNodeTypes.SET_PROP,
loc: node.loc,
- element: ctx.getElementId(),
+ element: ctx.getId(),
name: node.arg.content,
value: expr,
})
ctx.registerEffect(expr, {
type: IRNodeTypes.SET_EVENT,
loc: node.loc,
- element: ctx.getElementId(),
+ element: ctx.getId(),
name: node.arg.content,
value: expr,
})
ctx.registerEffect(value, {
type: IRNodeTypes.SET_HTML,
loc: node.loc,
- element: ctx.getElementId(),
+ element: ctx.getId(),
value,
})
break
ctx.registerEffect(value, {
type: IRNodeTypes.SET_TEXT,
loc: node.loc,
- element: ctx.getElementId(),
+ element: ctx.getId(),
value,
})
break
--- /dev/null
+<template>{{ '1' }}2{{ '3' }}</template>