]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
test: split test files (#38)
authorRizumu Ayaka <rizumu@ayaka.moe>
Fri, 8 Dec 2023 19:29:38 +0000 (03:29 +0800)
committerGitHub <noreply@github.com>
Fri, 8 Dec 2023 19:29:38 +0000 (03:29 +0800)
15 files changed:
packages/compiler-vapor/__tests__/__snapshots__/compile.spec.ts.snap [moved from packages/compiler-vapor/__tests__/__snapshots__/compile.test.ts.snap with 50% similarity]
packages/compiler-vapor/__tests__/compile.spec.ts [new file with mode: 0644]
packages/compiler-vapor/__tests__/compile.test.ts [deleted file]
packages/compiler-vapor/__tests__/transforms/__snapshots__/vBind.spec.ts.snap [new file with mode: 0644]
packages/compiler-vapor/__tests__/transforms/__snapshots__/vHtml.spec.ts.snap [new file with mode: 0644]
packages/compiler-vapor/__tests__/transforms/__snapshots__/vOn.spec.ts.snap [new file with mode: 0644]
packages/compiler-vapor/__tests__/transforms/__snapshots__/vOnce.spec.ts.snap [new file with mode: 0644]
packages/compiler-vapor/__tests__/transforms/__snapshots__/vText.spec.ts.snap [new file with mode: 0644]
packages/compiler-vapor/__tests__/transforms/transformElement.spec.ts [new file with mode: 0644]
packages/compiler-vapor/__tests__/transforms/transformInterpolation.spec.ts [new file with mode: 0644]
packages/compiler-vapor/__tests__/transforms/vBind.spec.ts [new file with mode: 0644]
packages/compiler-vapor/__tests__/transforms/vHtml.spec.ts [new file with mode: 0644]
packages/compiler-vapor/__tests__/transforms/vOn.spec.ts [new file with mode: 0644]
packages/compiler-vapor/__tests__/transforms/vOnce.spec.ts [new file with mode: 0644]
packages/compiler-vapor/__tests__/transforms/vText.spec.ts [new file with mode: 0644]

similarity index 50%
rename from packages/compiler-vapor/__tests__/__snapshots__/compile.test.ts.snap
rename to packages/compiler-vapor/__tests__/__snapshots__/compile.spec.ts.snap
index 5e3b020fa497c0e0bf1733719149405b42a75023..02c09554ee1b381943a692cd01eca81871acd24e 100644 (file)
@@ -100,86 +100,6 @@ export function render(_ctx) {
 }"
 `;
 
-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';
 
@@ -190,118 +110,6 @@ export function render(_ctx) {
 }"
 `;
 
-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';
 
@@ -350,32 +158,6 @@ export function render(_ctx) {
 }"
 `;
 
-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';
 
diff --git a/packages/compiler-vapor/__tests__/compile.spec.ts b/packages/compiler-vapor/__tests__/compile.spec.ts
new file mode 100644 (file)
index 0000000..3c7cf95
--- /dev/null
@@ -0,0 +1,210 @@
+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)
+  })
+})
diff --git a/packages/compiler-vapor/__tests__/compile.test.ts b/packages/compiler-vapor/__tests__/compile.test.ts
deleted file mode 100644 (file)
index 95f7471..0000000
+++ /dev/null
@@ -1,434 +0,0 @@
-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)
-  })
-})
diff --git a/packages/compiler-vapor/__tests__/transforms/__snapshots__/vBind.spec.ts.snap b/packages/compiler-vapor/__tests__/transforms/__snapshots__/vBind.spec.ts.snap
new file mode 100644 (file)
index 0000000..379d8c2
--- /dev/null
@@ -0,0 +1,81 @@
+// 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
+}"
+`;
diff --git a/packages/compiler-vapor/__tests__/transforms/__snapshots__/vHtml.spec.ts.snap b/packages/compiler-vapor/__tests__/transforms/__snapshots__/vHtml.spec.ts.snap
new file mode 100644 (file)
index 0000000..459741e
--- /dev/null
@@ -0,0 +1,41 @@
+// 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
+}"
+`;
diff --git a/packages/compiler-vapor/__tests__/transforms/__snapshots__/vOn.spec.ts.snap b/packages/compiler-vapor/__tests__/transforms/__snapshots__/vOn.spec.ts.snap
new file mode 100644 (file)
index 0000000..df47f15
--- /dev/null
@@ -0,0 +1,46 @@
+// 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
+}"
+`;
diff --git a/packages/compiler-vapor/__tests__/transforms/__snapshots__/vOnce.spec.ts.snap b/packages/compiler-vapor/__tests__/transforms/__snapshots__/vOnce.spec.ts.snap
new file mode 100644 (file)
index 0000000..b255f5d
--- /dev/null
@@ -0,0 +1,28 @@
+// 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
+}"
+`;
diff --git a/packages/compiler-vapor/__tests__/transforms/__snapshots__/vText.spec.ts.snap b/packages/compiler-vapor/__tests__/transforms/__snapshots__/vText.spec.ts.snap
new file mode 100644 (file)
index 0000000..f2b62b2
--- /dev/null
@@ -0,0 +1,27 @@
+// 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
+}"
+`;
diff --git a/packages/compiler-vapor/__tests__/transforms/transformElement.spec.ts b/packages/compiler-vapor/__tests__/transforms/transformElement.spec.ts
new file mode 100644 (file)
index 0000000..42c304f
--- /dev/null
@@ -0,0 +1,2 @@
+// TODO: add tests for this transform
+test('baisc', () => {})
diff --git a/packages/compiler-vapor/__tests__/transforms/transformInterpolation.spec.ts b/packages/compiler-vapor/__tests__/transforms/transformInterpolation.spec.ts
new file mode 100644 (file)
index 0000000..42c304f
--- /dev/null
@@ -0,0 +1,2 @@
+// TODO: add tests for this transform
+test('baisc', () => {})
diff --git a/packages/compiler-vapor/__tests__/transforms/vBind.spec.ts b/packages/compiler-vapor/__tests__/transforms/vBind.spec.ts
new file mode 100644 (file)
index 0000000..6a990c7
--- /dev/null
@@ -0,0 +1,88 @@
+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')
+  })
+})
diff --git a/packages/compiler-vapor/__tests__/transforms/vHtml.spec.ts b/packages/compiler-vapor/__tests__/transforms/vHtml.spec.ts
new file mode 100644 (file)
index 0000000..6d0492f
--- /dev/null
@@ -0,0 +1,44 @@
+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 }],
+    ])
+  })
+})
diff --git a/packages/compiler-vapor/__tests__/transforms/vOn.spec.ts b/packages/compiler-vapor/__tests__/transforms/vOn.spec.ts
new file mode 100644 (file)
index 0000000..353396b
--- /dev/null
@@ -0,0 +1,73 @@
+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()
+  })
+})
diff --git a/packages/compiler-vapor/__tests__/transforms/vOnce.spec.ts b/packages/compiler-vapor/__tests__/transforms/vOnce.spec.ts
new file mode 100644 (file)
index 0000000..8c87f3b
--- /dev/null
@@ -0,0 +1,35 @@
+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')
+  })
+})
diff --git a/packages/compiler-vapor/__tests__/transforms/vText.spec.ts b/packages/compiler-vapor/__tests__/transforms/vText.spec.ts
new file mode 100644 (file)
index 0000000..0989ef1
--- /dev/null
@@ -0,0 +1,31 @@
+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 }],
+    ])
+  })
+})