]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
test: add transform test
author三咲智子 Kevin Deng <sxzz@sxzz.moe>
Fri, 8 Dec 2023 20:06:46 +0000 (04:06 +0800)
committer三咲智子 Kevin Deng <sxzz@sxzz.moe>
Fri, 8 Dec 2023 20:11:02 +0000 (04:11 +0800)
packages/compiler-vapor/__tests__/transforms/__snapshots__/vBind.spec.ts.snap
packages/compiler-vapor/__tests__/transforms/vBind.spec.ts
packages/compiler-vapor/src/generate.ts
packages/compiler-vapor/src/index.ts
packages/compiler-vapor/src/ir.ts
packages/compiler-vapor/src/transforms/vBind.ts
packages/compiler-vapor/src/transforms/vOn.ts

index 379d8c21dcd4e1051ee06dd6ca6ac7f85be237eb..3352803132f521f87e079b1dacada0c0fc9f7c17 100644 (file)
@@ -1,6 +1,6 @@
 // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
-exports[`v-bind > .camel modifier 1`] = `
+exports[`compiler: codegen 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) {
@@ -14,7 +14,7 @@ export function render(_ctx) {
 }"
 `;
 
-exports[`v-bind > dynamic arg 1`] = `
+exports[`compiler: codegen 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) {
@@ -28,7 +28,7 @@ export function render(_ctx) {
 }"
 `;
 
-exports[`v-bind > no expression (shorthand) 1`] = `
+exports[`compiler: codegen 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) {
@@ -42,7 +42,7 @@ export function render(_ctx) {
 }"
 `;
 
-exports[`v-bind > no expression 1`] = `
+exports[`compiler: codegen 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) {
@@ -56,7 +56,7 @@ export function render(_ctx) {
 }"
 `;
 
-exports[`v-bind > should error if no expression 1`] = `
+exports[`compiler: codegen v-bind > should error if no expression 1`] = `
 "import { template as _template } from 'vue/vapor';
 
 export function render(_ctx) {
@@ -66,7 +66,7 @@ export function render(_ctx) {
 }"
 `;
 
-exports[`v-bind > simple expression 1`] = `
+exports[`compiler: codegen 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) {
index 6a990c786e7aac89e799435dacda05e47e75ad5b..fbaf2b0891d791e28ffb898a97d3505a290e4d79 100644 (file)
@@ -1,5 +1,34 @@
-import { type RootNode, BindingTypes, ErrorCodes } from '@vue/compiler-dom'
-import { type CompilerOptions, compile as _compile } from '../../src'
+import {
+  type RootNode,
+  ErrorCodes,
+  NodeTypes,
+  BindingTypes,
+} from '@vue/compiler-dom'
+import {
+  type RootIRNode,
+  type CompilerOptions,
+  parse,
+  transform,
+  transformVBind,
+  transformElement,
+  IRNodeTypes,
+  compile as _compile,
+} from '../../src'
+
+function parseWithVBind(
+  template: string,
+  options: CompilerOptions = {},
+): RootIRNode {
+  const ast = parse(template)
+  const ir = transform(ast, {
+    nodeTransforms: [transformElement],
+    directiveTransforms: {
+      bind: transformVBind,
+    },
+    ...options,
+  })
+  return ir
+}
 
 function compile(template: string | RootNode, options: CompilerOptions = {}) {
   let { code } = _compile(template, {
@@ -10,7 +39,189 @@ function compile(template: string | RootNode, options: CompilerOptions = {}) {
   return code
 }
 
-describe('v-bind', () => {
+describe('compiler: transform v-bind', () => {
+  test('basic', () => {
+    const node = parseWithVBind(`<div v-bind:id="id"/>`)
+
+    expect(node.dynamic.children[0]).toMatchObject({
+      id: 1,
+      referenced: true,
+    })
+    expect(node.template[0]).toMatchObject({
+      type: IRNodeTypes.TEMPLATE_FACTORY,
+      template: '<div></div>',
+    })
+    expect(node.effect).lengthOf(1)
+    expect(node.effect[0].expressions).lengthOf(1)
+    expect(node.effect[0].operations).lengthOf(1)
+    expect(node.effect[0]).toMatchObject({
+      expressions: [
+        {
+          type: NodeTypes.SIMPLE_EXPRESSION,
+          content: 'id',
+          isStatic: false,
+        },
+      ],
+      operations: [
+        {
+          type: IRNodeTypes.SET_PROP,
+          element: 1,
+          key: {
+            type: NodeTypes.SIMPLE_EXPRESSION,
+            content: 'id',
+            isStatic: true,
+            loc: {
+              start: { line: 1, column: 13, offset: 12 },
+              end: { line: 1, column: 15, offset: 14 },
+              source: 'id',
+            },
+          },
+          value: {
+            type: NodeTypes.SIMPLE_EXPRESSION,
+            content: 'id',
+            isStatic: false,
+            loc: {
+              source: 'id',
+              start: { line: 1, column: 17, offset: 16 },
+              end: { line: 1, column: 19, offset: 18 },
+            },
+          },
+        },
+      ],
+    })
+  })
+
+  test('no expression', () => {
+    const node = parseWithVBind(`<div v-bind:id />`)
+
+    expect(node.effect[0].operations[0]).toMatchObject({
+      type: IRNodeTypes.SET_PROP,
+      key: {
+        content: `id`,
+        isStatic: true,
+        loc: {
+          start: { line: 1, column: 13, offset: 12 },
+          end: { line: 1, column: 15, offset: 14 },
+        },
+      },
+      value: {
+        content: `id`,
+        isStatic: false,
+        loc: {
+          start: { line: 1, column: 13, offset: 12 },
+          end: { line: 1, column: 15, offset: 14 },
+        },
+      },
+    })
+  })
+
+  test('no expression (shorthand)', () => {
+    const node = parseWithVBind(`<div :id />`)
+
+    expect(node.effect[0].operations[0]).toMatchObject({
+      type: IRNodeTypes.SET_PROP,
+      key: {
+        content: `id`,
+        isStatic: true,
+      },
+      value: {
+        content: `id`,
+        isStatic: false,
+      },
+    })
+  })
+
+  test('dynamic arg', () => {
+    const node = parseWithVBind(`<div v-bind:[id]="id"/>`)
+    expect(node.effect[0].operations[0]).toMatchObject({
+      type: IRNodeTypes.SET_PROP,
+      element: 1,
+      key: {
+        type: NodeTypes.SIMPLE_EXPRESSION,
+        content: 'id',
+        isStatic: false,
+      },
+      value: {
+        type: NodeTypes.SIMPLE_EXPRESSION,
+        content: 'id',
+        isStatic: false,
+      },
+    })
+  })
+
+  test('should error if empty expression', () => {
+    const onError = vi.fn()
+    const node = parseWithVBind(`<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(node.template[0]).toMatchObject({
+      type: IRNodeTypes.TEMPLATE_FACTORY,
+      template: '<div arg=""></div>',
+    })
+  })
+
+  test.fails('.camel modifier', () => {
+    const node = parseWithVBind(`<div v-bind:foo-bar.camel="id"/>`)
+    expect(node.effect[0].operations[0]).toMatchObject({
+      key: {
+        content: `fooBar`,
+        isStatic: true,
+      },
+      value: {
+        content: `id`,
+        isStatic: false,
+      },
+    })
+  })
+
+  test.fails('.camel modifier w/ no expression', () => {
+    const node = parseWithVBind(`<div v-bind:foo-bar.camel />`)
+    expect(node.effect[0].operations[0]).toMatchObject({
+      key: {
+        content: `fooBar`,
+        isStatic: true,
+      },
+      value: {
+        content: `fooBar`,
+        isStatic: false,
+      },
+    })
+  })
+
+  test.fails('.camel modifier w/ dynamic arg', () => {
+    const node = parseWithVBind(`<div v-bind:[foo].camel="id"/>`)
+    expect(node.effect[0].operations[0]).toMatchObject({
+      key: {
+        content: `foo`,
+        isStatic: false,
+        somethingShouldBeTrue: true,
+      },
+      value: {
+        content: `id`,
+        isStatic: false,
+      },
+    })
+  })
+
+  test.todo('.camel modifier w/ dynamic arg + prefixIdentifiers')
+
+  test.todo('.prop modifier')
+  test.todo('.prop modifier w/ no expression')
+  test.todo('.prop modifier w/ dynamic arg')
+  test.todo('.prop modifier w/ dynamic arg + prefixIdentifiers')
+  test.todo('.prop modifier (shorthand)')
+  test.todo('.prop modifier (shortband) w/ no expression')
+  test.todo('.attr modifier')
+  test.todo('.attr modifier w/ no expression')
+})
+
+// TODO: combine with above
+describe('compiler: codegen v-bind', () => {
   test('simple expression', () => {
     const code = compile(`<div :id="id"></div>`, {
       bindingMetadata: {
index bdb4f882098d17f5635f639f6baca3e5943cf313..d92def7fe2f2500df46e6e42a61205a72ab2c675 100644 (file)
@@ -372,7 +372,7 @@ function genOperation(oper: OperationNode, context: CodegenContext) {
 function genSetProp(oper: SetPropIRNode, context: CodegenContext) {
   const { push, pushWithNewline, vaporHelper } = context
   pushWithNewline(`${vaporHelper('setAttr')}(n${oper.element}, `)
-  genExpression(oper.name, context)
+  genExpression(oper.key, context)
   push(`, undefined, `)
   genExpression(oper.value, context)
   push(')')
@@ -437,7 +437,7 @@ function genSetEvent(oper: SetEventIRNode, context: CodegenContext) {
 
   pushWithNewline(`${vaporHelper('on')}(n${oper.element}, `)
   // second arg: event name
-  genExpression(oper.name, context)
+  genExpression(oper.key, context)
   push(', ')
 
   const { keys, nonKeys, options } = oper.modifiers
index 1e7b4bd9fcda8baee0fa5a44587f3000cbf2be25..3b1c3d429872d7a56e92774bccc474d8e0dac962 100644 (file)
@@ -4,3 +4,11 @@ export { generate } from './generate'
 export { compile, type CompilerOptions } from './compile'
 export * from './ir'
 export * from './errors'
+export { transformElement } from './transforms/transformElement'
+export { transformInterpolation } from './transforms/transformInterpolation'
+export { transformVBind } from './transforms/vBind'
+export { transformVHtml } from './transforms/vHtml'
+export { transformVOn } from './transforms/vOn'
+export { transformOnce } from './transforms/vOnce'
+export { transformVShow } from './transforms/vShow'
+export { transformVText } from './transforms/vText'
index a8c46ce164cfecf375dcea33874af5d600484d2b..172f32fd7e8f1ae89b7b09f20037568587628dc3 100644 (file)
@@ -58,7 +58,7 @@ export interface FragmentFactoryIRNode extends BaseIRNode {
 export interface SetPropIRNode extends BaseIRNode {
   type: IRNodeTypes.SET_PROP
   element: number
-  name: IRExpression
+  key: IRExpression
   value: IRExpression
 }
 
@@ -71,7 +71,7 @@ export interface SetTextIRNode extends BaseIRNode {
 export interface SetEventIRNode extends BaseIRNode {
   type: IRNodeTypes.SET_EVENT
   element: number
-  name: IRExpression
+  key: IRExpression
   value: IRExpression
   modifiers: {
     // modifiers for addEventListener() options, e.g. .passive & .capture
index 1502a298327a1a21ce71cc0b62920aa2e5fbb514..6bd4cc939a2a29b9a656b6f7d9b2751626fd1c09 100644 (file)
@@ -36,7 +36,7 @@ export const transformVBind: DirectiveTransform = (dir, node, context) => {
         type: IRNodeTypes.SET_PROP,
         loc: dir.loc,
         element: context.reference(),
-        name: arg,
+        key: arg,
         value: exp,
       },
     ],
index 0183138ef1b5468fa60813df42c8d68541ba182c..f1764ffb0fdc03ad4e67a0cb853baec23d1f7647 100644 (file)
@@ -45,7 +45,7 @@ export const transformVOn: DirectiveTransform = (dir, node, context) => {
     type: IRNodeTypes.SET_EVENT,
     loc,
     element: context.reference(),
-    name: createSimpleExpression(name, true, arg.loc),
+    key: createSimpleExpression(name, true, arg.loc),
     value: exp,
     modifiers: {
       keys: keyModifiers,