Просмотр исходного кода

test: tests for v-bind transform

Evan You 6 лет назад
Родитель
Сommit
597ada36ed

+ 120 - 1
packages/compiler-core/__tests__/transforms/vBind.spec.ts

@@ -1 +1,120 @@
-test.todo('v-bind')
+import {
+  parse,
+  transform,
+  ElementNode,
+  ObjectExpression,
+  CompilerOptions,
+  ErrorCodes
+} from '../../src'
+import { transformBind } from '../../src/transforms/vBind'
+import { transformElement } from '../../src/transforms/transformElement'
+
+function parseWithVBind(
+  template: string,
+  options: CompilerOptions = {}
+): ElementNode {
+  const ast = parse(template)
+  transform(ast, {
+    nodeTransforms: [transformElement],
+    directiveTransforms: {
+      bind: transformBind
+    },
+    ...options
+  })
+  return ast.children[0] as ElementNode
+}
+
+describe('compiler: transform v-bind', () => {
+  test('basic', () => {
+    const node = parseWithVBind(`<div v-bind:id="id"/>`)
+    const props = node.codegenNode!.arguments[1] as ObjectExpression
+    expect(props.properties[0]).toMatchObject({
+      key: {
+        content: `id`,
+        isStatic: true,
+        loc: {
+          start: {
+            line: 1,
+            column: 13
+          },
+          end: {
+            line: 1,
+            column: 15
+          }
+        }
+      },
+      value: {
+        content: `id`,
+        isStatic: false,
+        loc: {
+          start: {
+            line: 1,
+            column: 16
+          },
+          end: {
+            line: 1,
+            column: 20
+          }
+        }
+      },
+      loc: {
+        start: {
+          line: 1,
+          column: 6
+        },
+        end: {
+          line: 1,
+          column: 20
+        }
+      }
+    })
+  })
+
+  test('dynamic arg', () => {
+    const node = parseWithVBind(`<div v-bind:[id]="id"/>`)
+    const props = node.codegenNode!.arguments[1] as ObjectExpression
+    expect(props.properties[0]).toMatchObject({
+      key: {
+        content: `id`,
+        isStatic: false
+      },
+      value: {
+        content: `id`,
+        isStatic: false
+      }
+    })
+  })
+
+  test('should error if no expression', () => {
+    const onError = jest.fn()
+    parseWithVBind(`<div v-bind />`, { 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: 12
+        }
+      }
+    })
+  })
+
+  test('.camel modifier', () => {
+    const node = parseWithVBind(`<div v-bind:foo-bar.camel="id"/>`)
+    const props = node.codegenNode!.arguments[1] as ObjectExpression
+    expect(props.properties[0]).toMatchObject({
+      key: {
+        content: `fooBar`,
+        isStatic: true
+      },
+      value: {
+        content: `id`,
+        isStatic: false
+      }
+    })
+  })
+})

+ 0 - 1
packages/compiler-core/src/runtimeConstants.ts

@@ -10,7 +10,6 @@ export const RESOLVE_COMPONENT = `resolveComponent`
 export const RESOLVE_DIRECTIVE = `resolveDirective`
 export const APPLY_DIRECTIVES = `applyDirectives`
 export const RENDER_LIST = `renderList`
-export const CAPITALIZE = `capitalize`
 export const TO_STRING = `toString`
 export const MERGE_PROPS = `mergeProps`
 export const TO_HANDLERS = `toHandlers`

+ 2 - 2
packages/compiler-core/src/transforms/transformExpression.ts

@@ -86,7 +86,7 @@ export function processExpression(
     enter(node: Node & PrefixMeta, parent) {
       if (node.type === 'Identifier') {
         if (
-          ids.indexOf(node) === -1 &&
+          !ids.includes(node) &&
           !knownIds[node.name] &&
           shouldPrefix(node, parent)
         ) {
@@ -177,7 +177,7 @@ function shouldPrefix(identifier: Identifier, parent: Node) {
       // not id of a FunctionDeclaration
       ((parent as any).id === identifier ||
         // not a params of a function
-        parent.params.indexOf(identifier) > -1)
+        parent.params.includes(identifier))
     ) &&
     // not a key of Property
     !(

+ 15 - 10
packages/compiler-core/src/transforms/vBind.ts

@@ -1,23 +1,28 @@
 import { DirectiveTransform } from '../transform'
 import { createObjectProperty, createExpression } from '../ast'
 import { createCompilerError, ErrorCodes } from '../errors'
+import { camelize } from '@vue/shared'
 
 // v-bind without arg is handled directly in ./element.ts due to it affecting
 // codegen for the entire props object. This transform here is only for v-bind
 // *with* args.
-export const transformBind: DirectiveTransform = (dir, context) => {
-  if (!dir.exp) {
-    context.onError(
-      createCompilerError(ErrorCodes.X_V_BIND_NO_EXPRESSION, dir.loc)
-    )
+export const transformBind: DirectiveTransform = (
+  { exp, arg, modifiers, loc },
+  context
+) => {
+  if (!exp) {
+    context.onError(createCompilerError(ErrorCodes.X_V_BIND_NO_EXPRESSION, loc))
+  }
+  // .prop is no longer necessary due to new patch behavior
+  // .sync is replced by v-model:arg
+  if (modifiers.includes('camel')) {
+    arg!.content = camelize(arg!.content)
   }
-  // TODO handle .prop modifier
-  // TODO handle .camel modifier
   return {
     props: createObjectProperty(
-      dir.arg!,
-      dir.exp || createExpression('', true, dir.loc),
-      dir.loc
+      arg!,
+      exp || createExpression('', true, loc),
+      loc
     ),
     needRuntime: false
   }

+ 6 - 8
packages/compiler-core/src/transforms/vOn.ts

@@ -1,23 +1,21 @@
 import { DirectiveTransform } from '../transform'
 import { createObjectProperty, createExpression } from '../ast'
 import { capitalize } from '@vue/shared'
-import { CAPITALIZE } from '../runtimeConstants'
 
 // v-on without arg is handled directly in ./element.ts due to it affecting
 // codegen for the entire props object. This transform here is only for v-on
 // *with* args.
-export const transformOn: DirectiveTransform = (dir, context) => {
-  const arg = dir.arg!
-  const eventName = arg.isStatic
-    ? createExpression(`on${capitalize(arg.content)}`, true, arg.loc)
-    : createExpression(`'on' + ${CAPITALIZE}(${arg.content})`, false, arg.loc)
+export const transformOn: DirectiveTransform = ({ arg, exp, loc }) => {
+  const eventName = arg!.isStatic
+    ? createExpression(`on${capitalize(arg!.content)}`, true, arg!.loc)
+    : createExpression(`'on' + (${arg!.content})`, false, arg!.loc)
   // TODO .once modifier handling since it is platform agnostic
   // other modifiers are handled in compiler-dom
   return {
     props: createObjectProperty(
       eventName,
-      dir.exp || createExpression(`() => {}`, false, dir.loc),
-      dir.loc
+      exp || createExpression(`() => {}`, false, loc),
+      loc
     ),
     needRuntime: false
   }

+ 0 - 1
packages/runtime-core/src/index.ts

@@ -42,7 +42,6 @@ export { resolveComponent, resolveDirective } from './helpers/resolveAssets'
 export { renderList } from './helpers/renderList'
 export { toString } from './helpers/toString'
 export { toHandlers } from './helpers/toHandlers'
-export { capitalize } from '@vue/shared'
 
 // Internal, for integration with runtime compiler
 export { registerRuntimeCompiler } from './component'