}"
`;
-exports[`compile > directives > v-bind > .camel modifier 1`] = `
-"import { template as _template, children as _children, effect as _effect, setAttr as _setAttr } from 'vue/vapor';
-
-export function render(_ctx) {
- const t0 = _template("<div></div>")
- const n0 = t0()
- const { 0: [n1],} = _children(n0)
- _effect(() => {
- _setAttr(n1, "foo-bar", undefined, _ctx.id)
- })
- return n0
-}"
-`;
-
-exports[`compile > directives > v-bind > dynamic arg 1`] = `
-"import { template as _template, children as _children, effect as _effect, setAttr as _setAttr } from 'vue/vapor';
-
-export function render(_ctx) {
- const t0 = _template("<div></div>")
- const n0 = t0()
- const { 0: [n1],} = _children(n0)
- _effect(() => {
- _setAttr(n1, _ctx.id, undefined, _ctx.id)
- })
- return n0
-}"
-`;
-
-exports[`compile > directives > v-bind > no expression (shorthand) 1`] = `
-"import { template as _template, children as _children, effect as _effect, setAttr as _setAttr } from 'vue/vapor';
-
-export function render(_ctx) {
- const t0 = _template("<div></div>")
- const n0 = t0()
- const { 0: [n1],} = _children(n0)
- _effect(() => {
- _setAttr(n1, "camel-case", undefined, _ctx.camelCase)
- })
- return n0
-}"
-`;
-
-exports[`compile > directives > v-bind > no expression 1`] = `
-"import { template as _template, children as _children, effect as _effect, setAttr as _setAttr } from 'vue/vapor';
-
-export function render(_ctx) {
- const t0 = _template("<div></div>")
- const n0 = t0()
- const { 0: [n1],} = _children(n0)
- _effect(() => {
- _setAttr(n1, "id", undefined, _ctx.id)
- })
- return n0
-}"
-`;
-
-exports[`compile > directives > v-bind > should error if no expression 1`] = `
-"import { template as _template } from 'vue/vapor';
-
-export function render(_ctx) {
- const t0 = _template("<div arg=\\"\\"></div>")
- const n0 = t0()
- return n0
-}"
-`;
-
-exports[`compile > directives > v-bind > simple expression 1`] = `
-"import { template as _template, children as _children, effect as _effect, setAttr as _setAttr } from 'vue/vapor';
-
-export function render(_ctx) {
- const t0 = _template("<div></div>")
- const n0 = t0()
- const { 0: [n1],} = _children(n0)
- _effect(() => {
- _setAttr(n1, "id", undefined, _ctx.id)
- })
- return n0
-}"
-`;
-
exports[`compile > directives > v-cloak > basic 1`] = `
"import { template as _template } from 'vue/vapor';
}"
`;
-exports[`compile > directives > v-html > should raise error and ignore children when v-html is present 1`] = `
-"import { template as _template, children as _children, effect as _effect, setHtml as _setHtml } from 'vue/vapor';
-
-export function render(_ctx) {
- const t0 = _template("<div></div>")
- const n0 = t0()
- const { 0: [n1],} = _children(n0)
- _effect(() => {
- _setHtml(n1, undefined, _ctx.test)
- })
- return n0
-}"
-`;
-
-exports[`compile > directives > v-html > should raise error if has no expression 1`] = `
-"import { template as _template, children as _children, setHtml as _setHtml } from 'vue/vapor';
-
-export function render(_ctx) {
- const t0 = _template("<div></div>")
- const n0 = t0()
- const { 0: [n1],} = _children(n0)
- _setHtml(n1, undefined, "")
- return n0
-}"
-`;
-
-exports[`compile > directives > v-html > simple expression 1`] = `
-"import { template as _template, children as _children, effect as _effect, setHtml as _setHtml } from 'vue/vapor';
-
-export function render(_ctx) {
- const t0 = _template("<div></div>")
- const n0 = t0()
- const { 0: [n1],} = _children(n0)
- _effect(() => {
- _setHtml(n1, undefined, _ctx.code)
- })
- return n0
-}"
-`;
-
-exports[`compile > directives > v-on > event modifier 1`] = `
-"import { template as _template, children as _children, on as _on, withModifiers as _withModifiers, withKeys as _withKeys } from 'vue/vapor';
-
-export function render(_ctx) {
- const t0 = _template("<a></a><form></form><a></a><div></div><div></div><a></a><div></div><input><input><input><input><input><input><input><input><input><input><input><input><input><input><input>")
- const n0 = t0()
- const { 0: [n1], 1: [n2], 2: [n3], 3: [n4], 4: [n5], 5: [n6], 6: [n7], 7: [n8], 8: [n9], 9: [n10], 10: [n11], 11: [n12], 12: [n13], 13: [n14], 14: [n15], 15: [n16], 16: [n17], 17: [n18], 18: [n19], 19: [n20], 20: [n21], 21: [n22],} = _children(n0)
- _on(n1, "click", _withModifiers((...args) => (_ctx.handleEvent && _ctx.handleEvent(...args)), ["stop"]))
- _on(n2, "submit", _withModifiers((...args) => (_ctx.handleEvent && _ctx.handleEvent(...args)), ["prevent"]))
- _on(n3, "click", _withModifiers((...args) => (_ctx.handleEvent && _ctx.handleEvent(...args)), ["stop", "prevent"]))
- _on(n4, "click", _withModifiers((...args) => (_ctx.handleEvent && _ctx.handleEvent(...args)), ["self"]))
- _on(n5, "click", (...args) => (_ctx.handleEvent && _ctx.handleEvent(...args)), { capture: true })
- _on(n6, "click", (...args) => (_ctx.handleEvent && _ctx.handleEvent(...args)), { once: true })
- _on(n7, "scroll", (...args) => (_ctx.handleEvent && _ctx.handleEvent(...args)), { passive: true })
- _on(n8, "contextmenu", _withModifiers((...args) => (_ctx.handleEvent && _ctx.handleEvent(...args)), ["right"]))
- _on(n9, "click", _withModifiers((...args) => (_ctx.handleEvent && _ctx.handleEvent(...args)), ["left"]))
- _on(n10, "mouseup", _withModifiers((...args) => (_ctx.handleEvent && _ctx.handleEvent(...args)), ["middle"]))
- _on(n11, "contextmenu", _withModifiers((...args) => (_ctx.handleEvent && _ctx.handleEvent(...args)), ["right"]))
- _on(n12, "keyup", _withKeys((...args) => (_ctx.handleEvent && _ctx.handleEvent(...args)), ["enter"]))
- _on(n13, "keyup", _withKeys((...args) => (_ctx.handleEvent && _ctx.handleEvent(...args)), ["tab"]))
- _on(n14, "keyup", _withKeys((...args) => (_ctx.handleEvent && _ctx.handleEvent(...args)), ["delete"]))
- _on(n15, "keyup", _withKeys((...args) => (_ctx.handleEvent && _ctx.handleEvent(...args)), ["esc"]))
- _on(n16, "keyup", _withKeys((...args) => (_ctx.handleEvent && _ctx.handleEvent(...args)), ["space"]))
- _on(n17, "keyup", _withKeys((...args) => (_ctx.handleEvent && _ctx.handleEvent(...args)), ["up"]))
- _on(n18, "keyup", _withKeys((...args) => (_ctx.handleEvent && _ctx.handleEvent(...args)), ["down"]))
- _on(n19, "keyup", _withKeys((...args) => (_ctx.handleEvent && _ctx.handleEvent(...args)), ["left"]))
- _on(n20, "keyup", _withModifiers((...args) => (_ctx.submit && _ctx.submit(...args)), ["middle"]))
- _on(n21, "keyup", _withModifiers((...args) => (_ctx.submit && _ctx.submit(...args)), ["middle", "self"]))
- _on(n22, "keyup", _withKeys(_withModifiers((...args) => (_ctx.handleEvent && _ctx.handleEvent(...args)), ["self"]), ["enter"]))
- return n0
-}"
-`;
-
-exports[`compile > directives > v-on > simple expression 1`] = `
-"import { template as _template, children as _children, on as _on } from 'vue/vapor';
-
-export function render(_ctx) {
- const t0 = _template("<div></div>")
- const n0 = t0()
- const { 0: [n1],} = _children(n0)
- _on(n1, "click", (...args) => (_ctx.handleClick && _ctx.handleClick(...args)))
- return n0
-}"
-`;
-
-exports[`compile > directives > v-once > as root node 1`] = `
-"import { template as _template, children as _children, setAttr as _setAttr } from 'vue/vapor';
-
-export function render(_ctx) {
- const t0 = _template("<div></div>")
- const n0 = t0()
- const { 0: [n1],} = _children(n0)
- _setAttr(n1, "id", undefined, _ctx.foo)
- return n0
-}"
-`;
-
-exports[`compile > directives > v-once > basic 1`] = `
-"import { template as _template, children as _children, createTextNode as _createTextNode, setText as _setText, setAttr as _setAttr, prepend as _prepend } from 'vue/vapor';
-
-export function render(_ctx) {
- const t0 = _template("<div> <span></span></div>")
- const n0 = t0()
- const { 0: [n3, { 1: [n2],}],} = _children(n0)
- const n1 = _createTextNode(_ctx.msg)
- _setText(n1, undefined, _ctx.msg)
- _setAttr(n2, "class", undefined, _ctx.clz)
- _prepend(n3, n1)
- return n0
-}"
-`;
-
exports[`compile > directives > v-pre > basic 1`] = `
"import { template as _template } from 'vue/vapor';
}"
`;
-exports[`compile > directives > v-text > no expression 1`] = `
-"import { template as _template, children as _children, setText as _setText } from 'vue/vapor';
-
-export function render(_ctx) {
- const t0 = _template("<div></div>")
- const n0 = t0()
- const { 0: [n1],} = _children(n0)
- _setText(n1, undefined, "")
- return n0
-}"
-`;
-
-exports[`compile > directives > v-text > simple expression 1`] = `
-"import { template as _template, children as _children, effect as _effect, setText as _setText } from 'vue/vapor';
-
-export function render(_ctx) {
- const t0 = _template("<div></div>")
- const n0 = t0()
- const { 0: [n1],} = _children(n0)
- _effect(() => {
- _setText(n1, undefined, _ctx.str)
- })
- return n0
-}"
-`;
-
exports[`compile > dynamic root 1`] = `
"import { fragment as _fragment, createTextNode as _createTextNode, append as _append, effect as _effect, setText as _setText } from 'vue/vapor';
--- /dev/null
+import { type RootNode, BindingTypes } from '@vue/compiler-dom'
+import { type CompilerOptions, compile as _compile } from '../src'
+
+function compile(template: string | RootNode, options: CompilerOptions = {}) {
+ let { code } = _compile(template, {
+ ...options,
+ mode: 'module',
+ prefixIdentifiers: true,
+ })
+ return code
+}
+
+describe('compile', () => {
+ test('static template', () => {
+ const code = compile(
+ `<div>
+ <p>hello</p>
+ <input />
+ <span />
+ </div>`,
+ )
+ expect(code).matchSnapshot()
+ })
+
+ test('dynamic root', () => {
+ const code = compile(`{{ 1 }}{{ 2 }}`)
+ expect(code).matchSnapshot()
+ })
+
+ test('dynamic root nodes and interpolation', () => {
+ const code = compile(
+ `<button @click="handleClick" :id="count">{{count}}foo{{count}}foo{{count}} </button>`,
+ )
+ expect(code).matchSnapshot()
+ })
+
+ test('static + dynamic root', () => {
+ const code = compile(
+ `{{ 1 }}{{ 2 }}3{{ 4 }}{{ 5 }}6{{ 7 }}{{ 8 }}9{{ 'A' }}{{ 'B' }}`,
+ )
+ expect(code).matchSnapshot()
+ })
+
+ test('fragment', () => {
+ const code = compile(`<p/><span/><div/>`)
+ expect(code).matchSnapshot()
+ })
+
+ test('bindings', () => {
+ const code = compile(`<div>count is {{ count }}.</div>`, {
+ bindingMetadata: {
+ count: BindingTypes.SETUP_REF,
+ },
+ })
+ expect(code).matchSnapshot()
+ })
+
+ describe('directives', () => {
+ describe('v-pre', () => {
+ test('basic', () => {
+ const code = compile(`<div v-pre :id="foo"><Comp/>{{ bar }}</div>\n`, {
+ bindingMetadata: {
+ foo: BindingTypes.SETUP_REF,
+ bar: BindingTypes.SETUP_REF,
+ },
+ })
+
+ expect(code).toMatchSnapshot()
+ expect(code).contains(
+ JSON.stringify('<div :id="foo"><Comp></Comp>{{ bar }}</div>'),
+ )
+ expect(code).not.contains('effect')
+ })
+
+ // TODO: support multiple root nodes and components
+ test('should not affect siblings after it', () => {
+ const code = compile(
+ `<div v-pre :id="foo"><Comp/>{{ bar }}</div>\n` +
+ `<div :id="foo"><Comp/>{{ bar }}</div>`,
+ {
+ bindingMetadata: {
+ foo: BindingTypes.SETUP_REF,
+ bar: BindingTypes.SETUP_REF,
+ },
+ },
+ )
+
+ expect(code).toMatchSnapshot()
+ // Waiting for TODO, There should be more here.
+ })
+
+ // TODO: support multiple root nodes and components
+ test('self-closing v-pre', () => {
+ const code = compile(
+ `<div v-pre/>\n<div :id="foo"><Comp/>{{ bar }}</div>`,
+ )
+
+ expect(code).toMatchSnapshot()
+ expect(code).contains('<div></div><div><Comp></Comp></div>')
+ // Waiting for TODO, There should be more here.
+ })
+ })
+
+ describe('v-cloak', () => {
+ test('basic', () => {
+ const code = compile(`<div v-cloak>test</div>`)
+ expect(code).toMatchSnapshot()
+ expect(code).not.contains('v-cloak')
+ })
+ })
+
+ describe('custom directive', () => {
+ test('basic', () => {
+ const code = compile(`<div v-example></div>`, {
+ bindingMetadata: {
+ vExample: BindingTypes.SETUP_CONST,
+ },
+ })
+ expect(code).matchSnapshot()
+ })
+
+ test('binding value', () => {
+ const code = compile(`<div v-example="msg"></div>`, {
+ bindingMetadata: {
+ msg: BindingTypes.SETUP_REF,
+ vExample: BindingTypes.SETUP_CONST,
+ },
+ })
+ expect(code).matchSnapshot()
+ })
+
+ test('static parameters', () => {
+ const code = compile(`<div v-example:foo="msg"></div>`, {
+ bindingMetadata: {
+ msg: BindingTypes.SETUP_REF,
+ vExample: BindingTypes.SETUP_CONST,
+ },
+ })
+ expect(code).matchSnapshot()
+ })
+
+ test('modifiers', () => {
+ const code = compile(`<div v-example.bar="msg"></div>`, {
+ bindingMetadata: {
+ msg: BindingTypes.SETUP_REF,
+ vExample: BindingTypes.SETUP_CONST,
+ },
+ })
+ expect(code).matchSnapshot()
+ })
+
+ test('modifiers w/o binding', () => {
+ const code = compile(`<div v-example.foo-bar></div>`, {
+ bindingMetadata: {
+ vExample: BindingTypes.SETUP_CONST,
+ },
+ })
+ expect(code).matchSnapshot()
+ })
+
+ test('static parameters and modifiers', () => {
+ const code = compile(`<div v-example:foo.bar="msg"></div>`, {
+ bindingMetadata: {
+ msg: BindingTypes.SETUP_REF,
+ vExample: BindingTypes.SETUP_CONST,
+ },
+ })
+ expect(code).matchSnapshot()
+ })
+
+ test('dynamic parameters', () => {
+ const code = compile(`<div v-example:[foo]="msg"></div>`, {
+ bindingMetadata: {
+ foo: BindingTypes.SETUP_REF,
+ vExample: BindingTypes.SETUP_CONST,
+ },
+ })
+ expect(code).matchSnapshot()
+ })
+ })
+ })
+
+ describe('expression parsing', () => {
+ test('interpolation', () => {
+ const code = compile(`{{ a + b }}`, {
+ inline: true,
+ bindingMetadata: {
+ b: BindingTypes.SETUP_REF,
+ },
+ })
+ expect(code).matchSnapshot()
+ expect(code).contains('a + b.value')
+ })
+
+ test('v-bind', () => {
+ const code = compile(`<div :[key+1]="foo[key+1]()" />`, {
+ inline: true,
+ bindingMetadata: {
+ key: BindingTypes.SETUP_REF,
+ foo: BindingTypes.SETUP_MAYBE_REF,
+ },
+ })
+ expect(code).matchSnapshot()
+ expect(code).contains('key.value+1')
+ expect(code).contains('_unref(foo)[key.value+1]()')
+ })
+
+ // TODO: add more test for expression parsing (v-on, v-slot, v-for)
+ })
+})
+++ /dev/null
-import {
- type RootNode,
- BindingTypes,
- ErrorCodes,
- DOMErrorCodes,
-} from '@vue/compiler-dom'
-import { type CompilerOptions, compile as _compile } from '../src'
-
-function compile(template: string | RootNode, options: CompilerOptions = {}) {
- let { code } = _compile(template, {
- ...options,
- mode: 'module',
- prefixIdentifiers: true,
- })
- return code
-}
-
-describe('compile', () => {
- test('static template', async () => {
- const code = await compile(
- `<div>
- <p>hello</p>
- <input />
- <span />
- </div>`,
- )
- expect(code).matchSnapshot()
- })
-
- test('dynamic root', async () => {
- const code = await compile(`{{ 1 }}{{ 2 }}`)
- expect(code).matchSnapshot()
- })
-
- test('dynamic root nodes and interpolation', async () => {
- const code = await compile(
- `<button @click="handleClick" :id="count">{{count}}foo{{count}}foo{{count}} </button>`,
- )
- expect(code).matchSnapshot()
- })
-
- test('static + dynamic root', async () => {
- const code = await compile(
- `{{ 1 }}{{ 2 }}3{{ 4 }}{{ 5 }}6{{ 7 }}{{ 8 }}9{{ 'A' }}{{ 'B' }}`,
- )
- expect(code).matchSnapshot()
- })
-
- test('fragment', async () => {
- const code = await compile(`<p/><span/><div/>`)
- expect(code).matchSnapshot()
- })
-
- test('bindings', async () => {
- const code = await compile(`<div>count is {{ count }}.</div>`, {
- bindingMetadata: {
- count: BindingTypes.SETUP_REF,
- },
- })
- expect(code).matchSnapshot()
- })
-
- describe('directives', () => {
- describe('v-bind', () => {
- test('simple expression', async () => {
- const code = await compile(`<div :id="id"></div>`, {
- bindingMetadata: {
- id: BindingTypes.SETUP_REF,
- },
- })
- expect(code).matchSnapshot()
- })
-
- test('should error if no expression', async () => {
- const onError = vi.fn()
- const code = await compile(`<div v-bind:arg="" />`, { onError })
-
- expect(onError.mock.calls[0][0]).toMatchObject({
- code: ErrorCodes.X_V_BIND_NO_EXPRESSION,
- loc: {
- start: {
- line: 1,
- column: 6,
- },
- end: {
- line: 1,
- column: 19,
- },
- },
- })
-
- expect(code).matchSnapshot()
- // the arg is static
- expect(code).contains(JSON.stringify('<div arg=""></div>'))
- })
-
- test('no expression', async () => {
- const code = await compile('<div v-bind:id />', {
- bindingMetadata: {
- id: BindingTypes.SETUP_REF,
- },
- })
-
- expect(code).matchSnapshot()
- expect(code).contains('_setAttr(n1, "id", undefined, _ctx.id)')
- })
-
- test('no expression (shorthand)', async () => {
- const code = await compile('<div :camel-case />', {
- bindingMetadata: {
- camelCase: BindingTypes.SETUP_REF,
- },
- })
-
- expect(code).matchSnapshot()
- expect(code).contains(
- '_setAttr(n1, "camel-case", undefined, _ctx.camelCase)',
- )
- })
-
- test('dynamic arg', async () => {
- const code = await compile('<div v-bind:[id]="id"/>', {
- bindingMetadata: {
- id: BindingTypes.SETUP_REF,
- },
- })
-
- expect(code).matchSnapshot()
- expect(code).contains('_setAttr(n1, _ctx.id, undefined, _ctx.id)')
- })
-
- // TODO: camel modifier for v-bind
- test.fails('.camel modifier', async () => {
- const code = await compile(`<div v-bind:foo-bar.camel="id"/>`)
-
- expect(code).matchSnapshot()
- expect(code).contains('fooBar')
- })
- })
-
- describe('v-on', () => {
- test('simple expression', async () => {
- const code = await compile(`<div @click="handleClick"></div>`, {
- bindingMetadata: {
- handleClick: BindingTypes.SETUP_CONST,
- },
- })
- expect(code).matchSnapshot()
- })
-
- test('should error if no expression AND no modifier', async () => {
- const onError = vi.fn()
- await compile(`<div v-on:click />`, { onError })
- expect(onError.mock.calls[0][0]).toMatchObject({
- code: ErrorCodes.X_V_ON_NO_EXPRESSION,
- loc: {
- start: {
- line: 1,
- column: 6,
- },
- end: {
- line: 1,
- column: 16,
- },
- },
- })
- })
-
- test('event modifier', async () => {
- const code = await compile(
- `<a @click.stop="handleEvent"></a>
- <form @submit.prevent="handleEvent"></form>
- <a @click.stop.prevent="handleEvent"></a>
- <div @click.self="handleEvent"></div>
- <div @click.capture="handleEvent"></div>
- <a @click.once="handleEvent"></a>
- <div @scroll.passive="handleEvent"></div>
- <input @click.right="handleEvent" />
- <input @click.left="handleEvent" />
- <input @click.middle="handleEvent" />
- <input @click.enter.right="handleEvent" />
- <input @keyup.enter="handleEvent" />
- <input @keyup.tab="handleEvent" />
- <input @keyup.delete="handleEvent" />
- <input @keyup.esc="handleEvent" />
- <input @keyup.space="handleEvent" />
- <input @keyup.up="handleEvent" />
- <input @keyup.down="handleEvent" />
- <input @keyup.left="handleEvent" />
- <input @keyup.middle="submit" />
- <input @keyup.middle.self="submit" />
- <input @keyup.self.enter="handleEvent" />`,
- {
- bindingMetadata: {
- handleEvent: BindingTypes.SETUP_CONST,
- },
- },
- )
- expect(code).matchSnapshot()
- })
- })
-
- describe('v-html', () => {
- test('simple expression', async () => {
- const code = await compile(`<div v-html="code"></div>`, {
- bindingMetadata: {
- code: BindingTypes.SETUP_REF,
- },
- })
- expect(code).matchSnapshot()
- })
-
- test('should raise error and ignore children when v-html is present', async () => {
- const onError = vi.fn()
- const code = await compile(`<div v-html="test">hello</div>`, {
- onError,
- })
- expect(code).matchSnapshot()
- expect(onError.mock.calls).toMatchObject([
- [{ code: DOMErrorCodes.X_V_HTML_WITH_CHILDREN }],
- ])
- })
-
- test('should raise error if has no expression', async () => {
- const onError = vi.fn()
- const code = await compile(`<div v-html></div>`, {
- onError,
- })
- expect(code).matchSnapshot()
- expect(onError.mock.calls).toMatchObject([
- [{ code: DOMErrorCodes.X_V_HTML_NO_EXPRESSION }],
- ])
- })
- })
-
- describe('v-text', () => {
- test('simple expression', async () => {
- const code = await compile(`<div v-text="str"></div>`, {
- bindingMetadata: {
- str: BindingTypes.SETUP_REF,
- },
- })
- expect(code).matchSnapshot()
- })
-
- test('no expression', async () => {
- const onError = vi.fn()
- const code = await compile(`<div v-text></div>`, { onError })
- expect(code).matchSnapshot()
- expect(onError.mock.calls).toMatchObject([
- [{ code: DOMErrorCodes.X_V_TEXT_NO_EXPRESSION }],
- ])
- })
- })
-
- describe('v-once', () => {
- test('basic', async () => {
- const code = await compile(
- `<div v-once>
- {{ msg }}
- <span :class="clz" />
- </div>`,
- {
- bindingMetadata: {
- msg: BindingTypes.SETUP_REF,
- clz: BindingTypes.SETUP_REF,
- },
- },
- )
- expect(code).matchSnapshot()
- })
-
- test('as root node', async () => {
- const code = await compile(`<div :id="foo" v-once />`)
- expect(code).toMatchSnapshot()
- expect(code).not.contains('effect')
- })
- })
-
- describe('v-pre', () => {
- test('basic', async () => {
- const code = await compile(
- `<div v-pre :id="foo"><Comp/>{{ bar }}</div>\n`,
- {
- bindingMetadata: {
- foo: BindingTypes.SETUP_REF,
- bar: BindingTypes.SETUP_REF,
- },
- },
- )
-
- expect(code).toMatchSnapshot()
- expect(code).contains(
- JSON.stringify('<div :id="foo"><Comp></Comp>{{ bar }}</div>'),
- )
- expect(code).not.contains('effect')
- })
-
- // TODO: support multiple root nodes and components
- test('should not affect siblings after it', async () => {
- const code = await compile(
- `<div v-pre :id="foo"><Comp/>{{ bar }}</div>\n` +
- `<div :id="foo"><Comp/>{{ bar }}</div>`,
- {
- bindingMetadata: {
- foo: BindingTypes.SETUP_REF,
- bar: BindingTypes.SETUP_REF,
- },
- },
- )
-
- expect(code).toMatchSnapshot()
- // Waiting for TODO, There should be more here.
- })
-
- // TODO: support multiple root nodes and components
- test('self-closing v-pre', async () => {
- const code = await compile(
- `<div v-pre/>\n<div :id="foo"><Comp/>{{ bar }}</div>`,
- )
-
- expect(code).toMatchSnapshot()
- expect(code).contains('<div></div><div><Comp></Comp></div>')
- // Waiting for TODO, There should be more here.
- })
- })
-
- describe('v-cloak', () => {
- test('basic', async () => {
- const code = await compile(`<div v-cloak>test</div>`)
- expect(code).toMatchSnapshot()
- expect(code).not.contains('v-cloak')
- })
- })
-
- describe('custom directive', () => {
- test('basic', async () => {
- const code = await compile(`<div v-example></div>`, {
- bindingMetadata: {
- vExample: BindingTypes.SETUP_CONST,
- },
- })
- expect(code).matchSnapshot()
- })
-
- test('binding value', async () => {
- const code = await compile(`<div v-example="msg"></div>`, {
- bindingMetadata: {
- msg: BindingTypes.SETUP_REF,
- vExample: BindingTypes.SETUP_CONST,
- },
- })
- expect(code).matchSnapshot()
- })
-
- test('static parameters', async () => {
- const code = await compile(`<div v-example:foo="msg"></div>`, {
- bindingMetadata: {
- msg: BindingTypes.SETUP_REF,
- vExample: BindingTypes.SETUP_CONST,
- },
- })
- expect(code).matchSnapshot()
- })
-
- test('modifiers', async () => {
- const code = await compile(`<div v-example.bar="msg"></div>`, {
- bindingMetadata: {
- msg: BindingTypes.SETUP_REF,
- vExample: BindingTypes.SETUP_CONST,
- },
- })
- expect(code).matchSnapshot()
- })
-
- test('modifiers w/o binding', async () => {
- const code = await compile(`<div v-example.foo-bar></div>`, {
- bindingMetadata: {
- vExample: BindingTypes.SETUP_CONST,
- },
- })
- expect(code).matchSnapshot()
- })
-
- test('static parameters and modifiers', async () => {
- const code = await compile(`<div v-example:foo.bar="msg"></div>`, {
- bindingMetadata: {
- msg: BindingTypes.SETUP_REF,
- vExample: BindingTypes.SETUP_CONST,
- },
- })
- expect(code).matchSnapshot()
- })
-
- test('dynamic parameters', async () => {
- const code = await compile(`<div v-example:[foo]="msg"></div>`, {
- bindingMetadata: {
- foo: BindingTypes.SETUP_REF,
- vExample: BindingTypes.SETUP_CONST,
- },
- })
- expect(code).matchSnapshot()
- })
- })
- })
-
- describe('expression parsing', () => {
- test('interpolation', async () => {
- const code = await compile(`{{ a + b }}`, {
- inline: true,
- bindingMetadata: {
- b: BindingTypes.SETUP_REF,
- },
- })
- expect(code).matchSnapshot()
- expect(code).contains('a + b.value')
- })
-
- test('v-bind', async () => {
- const code = compile(`<div :[key+1]="foo[key+1]()" />`, {
- inline: true,
- bindingMetadata: {
- key: BindingTypes.SETUP_REF,
- foo: BindingTypes.SETUP_MAYBE_REF,
- },
- })
- expect(code).matchSnapshot()
- expect(code).contains('key.value+1')
- expect(code).contains('_unref(foo)[key.value+1]()')
- })
-
- // TODO: add more test for expression parsing (v-on, v-slot, v-for)
- })
-})
--- /dev/null
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
+
+exports[`v-bind > .camel modifier 1`] = `
+"import { template as _template, children as _children, effect as _effect, setAttr as _setAttr } from 'vue/vapor';
+
+export function render(_ctx) {
+ const t0 = _template("<div></div>")
+ const n0 = t0()
+ const { 0: [n1],} = _children(n0)
+ _effect(() => {
+ _setAttr(n1, "foo-bar", undefined, _ctx.id)
+ })
+ return n0
+}"
+`;
+
+exports[`v-bind > dynamic arg 1`] = `
+"import { template as _template, children as _children, effect as _effect, setAttr as _setAttr } from 'vue/vapor';
+
+export function render(_ctx) {
+ const t0 = _template("<div></div>")
+ const n0 = t0()
+ const { 0: [n1],} = _children(n0)
+ _effect(() => {
+ _setAttr(n1, _ctx.id, undefined, _ctx.id)
+ })
+ return n0
+}"
+`;
+
+exports[`v-bind > no expression (shorthand) 1`] = `
+"import { template as _template, children as _children, effect as _effect, setAttr as _setAttr } from 'vue/vapor';
+
+export function render(_ctx) {
+ const t0 = _template("<div></div>")
+ const n0 = t0()
+ const { 0: [n1],} = _children(n0)
+ _effect(() => {
+ _setAttr(n1, "camel-case", undefined, _ctx.camelCase)
+ })
+ return n0
+}"
+`;
+
+exports[`v-bind > no expression 1`] = `
+"import { template as _template, children as _children, effect as _effect, setAttr as _setAttr } from 'vue/vapor';
+
+export function render(_ctx) {
+ const t0 = _template("<div></div>")
+ const n0 = t0()
+ const { 0: [n1],} = _children(n0)
+ _effect(() => {
+ _setAttr(n1, "id", undefined, _ctx.id)
+ })
+ return n0
+}"
+`;
+
+exports[`v-bind > should error if no expression 1`] = `
+"import { template as _template } from 'vue/vapor';
+
+export function render(_ctx) {
+ const t0 = _template("<div arg=\\"\\"></div>")
+ const n0 = t0()
+ return n0
+}"
+`;
+
+exports[`v-bind > simple expression 1`] = `
+"import { template as _template, children as _children, effect as _effect, setAttr as _setAttr } from 'vue/vapor';
+
+export function render(_ctx) {
+ const t0 = _template("<div></div>")
+ const n0 = t0()
+ const { 0: [n1],} = _children(n0)
+ _effect(() => {
+ _setAttr(n1, "id", undefined, _ctx.id)
+ })
+ return n0
+}"
+`;
--- /dev/null
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
+
+exports[`v-html > should raise error and ignore children when v-html is present 1`] = `
+"import { template as _template, children as _children, effect as _effect, setHtml as _setHtml } from 'vue/vapor';
+
+export function render(_ctx) {
+ const t0 = _template("<div></div>")
+ const n0 = t0()
+ const { 0: [n1],} = _children(n0)
+ _effect(() => {
+ _setHtml(n1, undefined, _ctx.test)
+ })
+ return n0
+}"
+`;
+
+exports[`v-html > should raise error if has no expression 1`] = `
+"import { template as _template, children as _children, setHtml as _setHtml } from 'vue/vapor';
+
+export function render(_ctx) {
+ const t0 = _template("<div></div>")
+ const n0 = t0()
+ const { 0: [n1],} = _children(n0)
+ _setHtml(n1, undefined, "")
+ return n0
+}"
+`;
+
+exports[`v-html > simple expression 1`] = `
+"import { template as _template, children as _children, effect as _effect, setHtml as _setHtml } from 'vue/vapor';
+
+export function render(_ctx) {
+ const t0 = _template("<div></div>")
+ const n0 = t0()
+ const { 0: [n1],} = _children(n0)
+ _effect(() => {
+ _setHtml(n1, undefined, _ctx.code)
+ })
+ return n0
+}"
+`;
--- /dev/null
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
+
+exports[`v-on > event modifier 1`] = `
+"import { template as _template, children as _children, on as _on, withModifiers as _withModifiers, withKeys as _withKeys } from 'vue/vapor';
+
+export function render(_ctx) {
+ const t0 = _template("<a></a><form></form><a></a><div></div><div></div><a></a><div></div><input><input><input><input><input><input><input><input><input><input><input><input><input><input><input>")
+ const n0 = t0()
+ const { 0: [n1], 1: [n2], 2: [n3], 3: [n4], 4: [n5], 5: [n6], 6: [n7], 7: [n8], 8: [n9], 9: [n10], 10: [n11], 11: [n12], 12: [n13], 13: [n14], 14: [n15], 15: [n16], 16: [n17], 17: [n18], 18: [n19], 19: [n20], 20: [n21], 21: [n22],} = _children(n0)
+ _on(n1, "click", _withModifiers((...args) => (_ctx.handleEvent && _ctx.handleEvent(...args)), ["stop"]))
+ _on(n2, "submit", _withModifiers((...args) => (_ctx.handleEvent && _ctx.handleEvent(...args)), ["prevent"]))
+ _on(n3, "click", _withModifiers((...args) => (_ctx.handleEvent && _ctx.handleEvent(...args)), ["stop", "prevent"]))
+ _on(n4, "click", _withModifiers((...args) => (_ctx.handleEvent && _ctx.handleEvent(...args)), ["self"]))
+ _on(n5, "click", (...args) => (_ctx.handleEvent && _ctx.handleEvent(...args)), { capture: true })
+ _on(n6, "click", (...args) => (_ctx.handleEvent && _ctx.handleEvent(...args)), { once: true })
+ _on(n7, "scroll", (...args) => (_ctx.handleEvent && _ctx.handleEvent(...args)), { passive: true })
+ _on(n8, "contextmenu", _withModifiers((...args) => (_ctx.handleEvent && _ctx.handleEvent(...args)), ["right"]))
+ _on(n9, "click", _withModifiers((...args) => (_ctx.handleEvent && _ctx.handleEvent(...args)), ["left"]))
+ _on(n10, "mouseup", _withModifiers((...args) => (_ctx.handleEvent && _ctx.handleEvent(...args)), ["middle"]))
+ _on(n11, "contextmenu", _withModifiers((...args) => (_ctx.handleEvent && _ctx.handleEvent(...args)), ["right"]))
+ _on(n12, "keyup", _withKeys((...args) => (_ctx.handleEvent && _ctx.handleEvent(...args)), ["enter"]))
+ _on(n13, "keyup", _withKeys((...args) => (_ctx.handleEvent && _ctx.handleEvent(...args)), ["tab"]))
+ _on(n14, "keyup", _withKeys((...args) => (_ctx.handleEvent && _ctx.handleEvent(...args)), ["delete"]))
+ _on(n15, "keyup", _withKeys((...args) => (_ctx.handleEvent && _ctx.handleEvent(...args)), ["esc"]))
+ _on(n16, "keyup", _withKeys((...args) => (_ctx.handleEvent && _ctx.handleEvent(...args)), ["space"]))
+ _on(n17, "keyup", _withKeys((...args) => (_ctx.handleEvent && _ctx.handleEvent(...args)), ["up"]))
+ _on(n18, "keyup", _withKeys((...args) => (_ctx.handleEvent && _ctx.handleEvent(...args)), ["down"]))
+ _on(n19, "keyup", _withKeys((...args) => (_ctx.handleEvent && _ctx.handleEvent(...args)), ["left"]))
+ _on(n20, "keyup", _withModifiers((...args) => (_ctx.submit && _ctx.submit(...args)), ["middle"]))
+ _on(n21, "keyup", _withModifiers((...args) => (_ctx.submit && _ctx.submit(...args)), ["middle", "self"]))
+ _on(n22, "keyup", _withKeys(_withModifiers((...args) => (_ctx.handleEvent && _ctx.handleEvent(...args)), ["self"]), ["enter"]))
+ return n0
+}"
+`;
+
+exports[`v-on > simple expression 1`] = `
+"import { template as _template, children as _children, on as _on } from 'vue/vapor';
+
+export function render(_ctx) {
+ const t0 = _template("<div></div>")
+ const n0 = t0()
+ const { 0: [n1],} = _children(n0)
+ _on(n1, "click", (...args) => (_ctx.handleClick && _ctx.handleClick(...args)))
+ return n0
+}"
+`;
--- /dev/null
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
+
+exports[`v-once > as root node 1`] = `
+"import { template as _template, children as _children, setAttr as _setAttr } from 'vue/vapor';
+
+export function render(_ctx) {
+ const t0 = _template("<div></div>")
+ const n0 = t0()
+ const { 0: [n1],} = _children(n0)
+ _setAttr(n1, "id", undefined, _ctx.foo)
+ return n0
+}"
+`;
+
+exports[`v-once > basic 1`] = `
+"import { template as _template, children as _children, createTextNode as _createTextNode, setText as _setText, setAttr as _setAttr, prepend as _prepend } from 'vue/vapor';
+
+export function render(_ctx) {
+ const t0 = _template("<div> <span></span></div>")
+ const n0 = t0()
+ const { 0: [n3, { 1: [n2],}],} = _children(n0)
+ const n1 = _createTextNode(_ctx.msg)
+ _setText(n1, undefined, _ctx.msg)
+ _setAttr(n2, "class", undefined, _ctx.clz)
+ _prepend(n3, n1)
+ return n0
+}"
+`;
--- /dev/null
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
+
+exports[`v-text > no expression 1`] = `
+"import { template as _template, children as _children, setText as _setText } from 'vue/vapor';
+
+export function render(_ctx) {
+ const t0 = _template("<div></div>")
+ const n0 = t0()
+ const { 0: [n1],} = _children(n0)
+ _setText(n1, undefined, "")
+ return n0
+}"
+`;
+
+exports[`v-text > simple expression 1`] = `
+"import { template as _template, children as _children, effect as _effect, setText as _setText } from 'vue/vapor';
+
+export function render(_ctx) {
+ const t0 = _template("<div></div>")
+ const n0 = t0()
+ const { 0: [n1],} = _children(n0)
+ _effect(() => {
+ _setText(n1, undefined, _ctx.str)
+ })
+ return n0
+}"
+`;
--- /dev/null
+// TODO: add tests for this transform
+test('baisc', () => {})
--- /dev/null
+// TODO: add tests for this transform
+test('baisc', () => {})
--- /dev/null
+import { type RootNode, BindingTypes, ErrorCodes } from '@vue/compiler-dom'
+import { type CompilerOptions, compile as _compile } from '../../src'
+
+function compile(template: string | RootNode, options: CompilerOptions = {}) {
+ let { code } = _compile(template, {
+ ...options,
+ mode: 'module',
+ prefixIdentifiers: true,
+ })
+ return code
+}
+
+describe('v-bind', () => {
+ test('simple expression', () => {
+ const code = compile(`<div :id="id"></div>`, {
+ bindingMetadata: {
+ id: BindingTypes.SETUP_REF,
+ },
+ })
+ expect(code).matchSnapshot()
+ })
+
+ test('should error if no expression', () => {
+ const onError = vi.fn()
+ const code = compile(`<div v-bind:arg="" />`, { onError })
+
+ expect(onError.mock.calls[0][0]).toMatchObject({
+ code: ErrorCodes.X_V_BIND_NO_EXPRESSION,
+ loc: {
+ start: {
+ line: 1,
+ column: 6,
+ },
+ end: {
+ line: 1,
+ column: 19,
+ },
+ },
+ })
+
+ expect(code).matchSnapshot()
+ // the arg is static
+ expect(code).contains(JSON.stringify('<div arg=""></div>'))
+ })
+
+ test('no expression', () => {
+ const code = compile('<div v-bind:id />', {
+ bindingMetadata: {
+ id: BindingTypes.SETUP_REF,
+ },
+ })
+
+ expect(code).matchSnapshot()
+ expect(code).contains('_setAttr(n1, "id", undefined, _ctx.id)')
+ })
+
+ test('no expression (shorthand)', () => {
+ const code = compile('<div :camel-case />', {
+ bindingMetadata: {
+ camelCase: BindingTypes.SETUP_REF,
+ },
+ })
+
+ expect(code).matchSnapshot()
+ expect(code).contains(
+ '_setAttr(n1, "camel-case", undefined, _ctx.camelCase)',
+ )
+ })
+
+ test('dynamic arg', () => {
+ const code = compile('<div v-bind:[id]="id"/>', {
+ bindingMetadata: {
+ id: BindingTypes.SETUP_REF,
+ },
+ })
+
+ expect(code).matchSnapshot()
+ expect(code).contains('_setAttr(n1, _ctx.id, undefined, _ctx.id)')
+ })
+
+ // TODO: camel modifier for v-bind
+ test.fails('.camel modifier', () => {
+ const code = compile(`<div v-bind:foo-bar.camel="id"/>`)
+
+ expect(code).matchSnapshot()
+ expect(code).contains('fooBar')
+ })
+})
--- /dev/null
+import { type RootNode, BindingTypes, DOMErrorCodes } from '@vue/compiler-dom'
+import { type CompilerOptions, compile as _compile } from '../../src'
+
+function compile(template: string | RootNode, options: CompilerOptions = {}) {
+ let { code } = _compile(template, {
+ ...options,
+ mode: 'module',
+ prefixIdentifiers: true,
+ })
+ return code
+}
+
+describe('v-html', () => {
+ test('simple expression', () => {
+ const code = compile(`<div v-html="code"></div>`, {
+ bindingMetadata: {
+ code: BindingTypes.SETUP_REF,
+ },
+ })
+ expect(code).matchSnapshot()
+ })
+
+ test('should raise error and ignore children when v-html is present', () => {
+ const onError = vi.fn()
+ const code = compile(`<div v-html="test">hello</div>`, {
+ onError,
+ })
+ expect(code).matchSnapshot()
+ expect(onError.mock.calls).toMatchObject([
+ [{ code: DOMErrorCodes.X_V_HTML_WITH_CHILDREN }],
+ ])
+ })
+
+ test('should raise error if has no expression', () => {
+ const onError = vi.fn()
+ const code = compile(`<div v-html></div>`, {
+ onError,
+ })
+ expect(code).matchSnapshot()
+ expect(onError.mock.calls).toMatchObject([
+ [{ code: DOMErrorCodes.X_V_HTML_NO_EXPRESSION }],
+ ])
+ })
+})
--- /dev/null
+import { type RootNode, BindingTypes, ErrorCodes } from '@vue/compiler-dom'
+import { type CompilerOptions, compile as _compile } from '../../src'
+
+function compile(template: string | RootNode, options: CompilerOptions = {}) {
+ let { code } = _compile(template, {
+ ...options,
+ mode: 'module',
+ prefixIdentifiers: true,
+ })
+ return code
+}
+
+describe('v-on', () => {
+ test('simple expression', () => {
+ const code = compile(`<div @click="handleClick"></div>`, {
+ bindingMetadata: {
+ handleClick: BindingTypes.SETUP_CONST,
+ },
+ })
+ expect(code).matchSnapshot()
+ })
+
+ test('should error if no expression AND no modifier', () => {
+ const onError = vi.fn()
+ compile(`<div v-on:click />`, { onError })
+ expect(onError.mock.calls[0][0]).toMatchObject({
+ code: ErrorCodes.X_V_ON_NO_EXPRESSION,
+ loc: {
+ start: {
+ line: 1,
+ column: 6,
+ },
+ end: {
+ line: 1,
+ column: 16,
+ },
+ },
+ })
+ })
+
+ test('event modifier', () => {
+ const code = compile(
+ `<a @click.stop="handleEvent"></a>
+ <form @submit.prevent="handleEvent"></form>
+ <a @click.stop.prevent="handleEvent"></a>
+ <div @click.self="handleEvent"></div>
+ <div @click.capture="handleEvent"></div>
+ <a @click.once="handleEvent"></a>
+ <div @scroll.passive="handleEvent"></div>
+ <input @click.right="handleEvent" />
+ <input @click.left="handleEvent" />
+ <input @click.middle="handleEvent" />
+ <input @click.enter.right="handleEvent" />
+ <input @keyup.enter="handleEvent" />
+ <input @keyup.tab="handleEvent" />
+ <input @keyup.delete="handleEvent" />
+ <input @keyup.esc="handleEvent" />
+ <input @keyup.space="handleEvent" />
+ <input @keyup.up="handleEvent" />
+ <input @keyup.down="handleEvent" />
+ <input @keyup.left="handleEvent" />
+ <input @keyup.middle="submit" />
+ <input @keyup.middle.self="submit" />
+ <input @keyup.self.enter="handleEvent" />`,
+ {
+ bindingMetadata: {
+ handleEvent: BindingTypes.SETUP_CONST,
+ },
+ },
+ )
+ expect(code).matchSnapshot()
+ })
+})
--- /dev/null
+import { type RootNode, BindingTypes } from '@vue/compiler-dom'
+import { type CompilerOptions, compile as _compile } from '../../src'
+
+function compile(template: string | RootNode, options: CompilerOptions = {}) {
+ let { code } = _compile(template, {
+ ...options,
+ mode: 'module',
+ prefixIdentifiers: true,
+ })
+ return code
+}
+
+describe('v-once', () => {
+ test('basic', () => {
+ const code = compile(
+ `<div v-once>
+ {{ msg }}
+ <span :class="clz" />
+ </div>`,
+ {
+ bindingMetadata: {
+ msg: BindingTypes.SETUP_REF,
+ clz: BindingTypes.SETUP_REF,
+ },
+ },
+ )
+ expect(code).matchSnapshot()
+ })
+
+ test('as root node', () => {
+ const code = compile(`<div :id="foo" v-once />`)
+ expect(code).toMatchSnapshot()
+ expect(code).not.contains('effect')
+ })
+})
--- /dev/null
+import { type RootNode, BindingTypes, DOMErrorCodes } from '@vue/compiler-dom'
+import { type CompilerOptions, compile as _compile } from '../../src'
+
+function compile(template: string | RootNode, options: CompilerOptions = {}) {
+ let { code } = _compile(template, {
+ ...options,
+ mode: 'module',
+ prefixIdentifiers: true,
+ })
+ return code
+}
+
+describe('v-text', () => {
+ test('simple expression', () => {
+ const code = compile(`<div v-text="str"></div>`, {
+ bindingMetadata: {
+ str: BindingTypes.SETUP_REF,
+ },
+ })
+ expect(code).matchSnapshot()
+ })
+
+ test('no expression', () => {
+ const onError = vi.fn()
+ const code = compile(`<div v-text></div>`, { onError })
+ expect(code).matchSnapshot()
+ expect(onError.mock.calls).toMatchObject([
+ [{ code: DOMErrorCodes.X_V_TEXT_NO_EXPRESSION }],
+ ])
+ })
+})