Browse Source

test: add transform test

三咲智子 Kevin Deng 2 years ago
parent
commit
5f769745fa

+ 6 - 6
packages/compiler-vapor/__tests__/transforms/__snapshots__/vBind.spec.ts.snap

@@ -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) {

+ 214 - 3
packages/compiler-vapor/__tests__/transforms/vBind.spec.ts

@@ -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: {

+ 2 - 2
packages/compiler-vapor/src/generate.ts

@@ -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

+ 8 - 0
packages/compiler-vapor/src/index.ts

@@ -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'

+ 2 - 2
packages/compiler-vapor/src/ir.ts

@@ -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

+ 1 - 1
packages/compiler-vapor/src/transforms/vBind.ts

@@ -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,
       },
     ],

+ 1 - 1
packages/compiler-vapor/src/transforms/vOn.ts

@@ -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,