]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
test: test transformElements
authorEvan You <yyx990803@gmail.com>
Tue, 24 Sep 2019 00:45:40 +0000 (20:45 -0400)
committerEvan You <yyx990803@gmail.com>
Tue, 24 Sep 2019 00:45:40 +0000 (20:45 -0400)
13 files changed:
packages/compiler-core/__tests__/transforms/element.spec.ts [deleted file]
packages/compiler-core/__tests__/transforms/expression.spec.ts [deleted file]
packages/compiler-core/__tests__/transforms/transformElement.spec.ts [new file with mode: 0644]
packages/compiler-core/__tests__/transforms/transformExpressions.spec.ts [new file with mode: 0644]
packages/compiler-core/__tests__/transforms/vFor.spec.ts
packages/compiler-core/__tests__/transforms/vIf.spec.ts
packages/compiler-core/src/codegen.ts
packages/compiler-core/src/index.ts
packages/compiler-core/src/runtimeConstants.ts
packages/compiler-core/src/transforms/transformElement.ts [moved from packages/compiler-core/src/transforms/element.ts with 93% similarity]
packages/compiler-core/src/transforms/transformExpression.ts [moved from packages/compiler-core/src/transforms/expression.ts with 98% similarity]
packages/compiler-core/src/transforms/vFor.ts
packages/compiler-core/src/transforms/vIf.ts

diff --git a/packages/compiler-core/__tests__/transforms/element.spec.ts b/packages/compiler-core/__tests__/transforms/element.spec.ts
deleted file mode 100644 (file)
index 4107656..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-describe('compiler: element transform', () => {
-  test.todo('should work')
-})
diff --git a/packages/compiler-core/__tests__/transforms/expression.spec.ts b/packages/compiler-core/__tests__/transforms/expression.spec.ts
deleted file mode 100644 (file)
index 9fe4e49..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-import { SourceMapConsumer } from 'source-map'
-import { compile } from '../../src'
-
-test(`should work`, async () => {
-  const { code, map } = compile(`<div>{{ foo }} bar</div>`, {
-    prefixIdentifiers: true
-  })
-  console.log(code)
-  const consumer = await new SourceMapConsumer(map!)
-  const pos = consumer.originalPositionFor({
-    line: 4,
-    column: 31
-  })
-  console.log(pos)
-})
diff --git a/packages/compiler-core/__tests__/transforms/transformElement.spec.ts b/packages/compiler-core/__tests__/transforms/transformElement.spec.ts
new file mode 100644 (file)
index 0000000..95a5522
--- /dev/null
@@ -0,0 +1,359 @@
+import {
+  ElementNode,
+  CompilerOptions,
+  parse,
+  transform,
+  ErrorCodes
+} from '../../src'
+import { transformElement } from '../../src/transforms/transformElement'
+import {
+  RESOLVE_COMPONENT,
+  CREATE_VNODE,
+  MERGE_PROPS,
+  RESOLVE_DIRECTIVE,
+  APPLY_DIRECTIVES
+} from '../../src/runtimeConstants'
+import {
+  CallExpression,
+  NodeTypes,
+  createObjectProperty,
+  DirectiveNode,
+  RootNode
+} from '../../src/ast'
+
+function parseWithElementTransform(
+  template: string,
+  options: CompilerOptions = {}
+): {
+  root: RootNode
+  node: CallExpression
+} {
+  const ast = parse(template, options)
+  transform(ast, {
+    nodeTransforms: [transformElement],
+    ...options
+  })
+  const codegenNode = (ast.children[0] as ElementNode)
+    .codegenNode as CallExpression
+  expect(codegenNode.type).toBe(NodeTypes.JS_CALL_EXPRESSION)
+  return {
+    root: ast,
+    node: codegenNode
+  }
+}
+
+function createStaticObjectMatcher(obj: any) {
+  return {
+    type: NodeTypes.JS_OBJECT_EXPRESSION,
+    properties: Object.keys(obj).map(key => ({
+      type: NodeTypes.JS_PROPERTY,
+      key: {
+        type: NodeTypes.EXPRESSION,
+        content: key,
+        isStatic: true
+      },
+      value: {
+        type: NodeTypes.EXPRESSION,
+        content: obj[key],
+        isStatic: true
+      }
+    }))
+  }
+}
+
+describe('compiler: element transform', () => {
+  test('import + resovle component', () => {
+    const { root } = parseWithElementTransform(`<Foo/>`)
+    expect(root.imports).toContain(RESOLVE_COMPONENT)
+    expect(root.statements[0]).toMatch(`${RESOLVE_COMPONENT}("Foo")`)
+  })
+
+  test('static props', () => {
+    const { node } = parseWithElementTransform(`<div id="foo" class="bar" />`)
+    expect(node.callee).toBe(CREATE_VNODE)
+    expect(node.arguments).toMatchObject([
+      `"div"`,
+      createStaticObjectMatcher({
+        id: 'foo',
+        class: 'bar'
+      })
+    ])
+  })
+
+  test('v-bind="obj"', () => {
+    const { root, node } = parseWithElementTransform(`<div v-bind="obj" />`)
+    // single v-bind doesn't need mergeProps
+    expect(root.imports).not.toContain(MERGE_PROPS)
+    expect(node.callee).toBe(CREATE_VNODE)
+    // should directly use `obj` in props position
+    expect(node.arguments[1]).toMatchObject({
+      type: NodeTypes.EXPRESSION,
+      content: `obj`
+    })
+  })
+
+  test('v-bind="obj" after static prop', () => {
+    const { root, node } = parseWithElementTransform(
+      `<div id="foo" v-bind="obj" />`
+    )
+    expect(root.imports).toContain(MERGE_PROPS)
+    expect(node.callee).toBe(CREATE_VNODE)
+    expect(node.arguments[1]).toMatchObject({
+      type: NodeTypes.JS_CALL_EXPRESSION,
+      callee: MERGE_PROPS,
+      arguments: [
+        createStaticObjectMatcher({
+          id: 'foo'
+        }),
+        {
+          type: NodeTypes.EXPRESSION,
+          content: `obj`
+        }
+      ]
+    })
+  })
+
+  test('v-bind="obj" before static prop', () => {
+    const { root, node } = parseWithElementTransform(
+      `<div v-bind="obj" id="foo" />`
+    )
+    expect(root.imports).toContain(MERGE_PROPS)
+    expect(node.callee).toBe(CREATE_VNODE)
+    expect(node.arguments[1]).toMatchObject({
+      type: NodeTypes.JS_CALL_EXPRESSION,
+      callee: MERGE_PROPS,
+      arguments: [
+        {
+          type: NodeTypes.EXPRESSION,
+          content: `obj`
+        },
+        createStaticObjectMatcher({
+          id: 'foo'
+        })
+      ]
+    })
+  })
+
+  test('v-bind="obj" between static props', () => {
+    const { root, node } = parseWithElementTransform(
+      `<div id="foo" v-bind="obj" class="bar" />`
+    )
+    expect(root.imports).toContain(MERGE_PROPS)
+    expect(node.callee).toBe(CREATE_VNODE)
+    expect(node.arguments[1]).toMatchObject({
+      type: NodeTypes.JS_CALL_EXPRESSION,
+      callee: MERGE_PROPS,
+      arguments: [
+        createStaticObjectMatcher({
+          id: 'foo'
+        }),
+        {
+          type: NodeTypes.EXPRESSION,
+          content: `obj`
+        },
+        createStaticObjectMatcher({
+          class: 'bar'
+        })
+      ]
+    })
+  })
+
+  test('error on v-bind with no argument', () => {
+    const onError = jest.fn()
+    parseWithElementTransform(`<div v-bind/>`, { onError })
+    expect(onError.mock.calls[0]).toMatchObject([
+      {
+        code: ErrorCodes.X_V_BIND_NO_EXPRESSION
+      }
+    ])
+  })
+
+  test('directiveTransforms', () => {
+    let _dir: DirectiveNode
+    const { node } = parseWithElementTransform(`<div v-foo:bar="hello" />`, {
+      directiveTransforms: {
+        foo(dir) {
+          _dir = dir
+          return {
+            props: createObjectProperty(dir.arg!, dir.exp!, dir.loc),
+            needRuntime: false
+          }
+        }
+      }
+    })
+    expect(node.callee).toBe(CREATE_VNODE)
+    expect(node.arguments[1]).toMatchObject({
+      type: NodeTypes.JS_OBJECT_EXPRESSION,
+      properties: [
+        {
+          type: NodeTypes.JS_PROPERTY,
+          key: _dir!.arg,
+          value: _dir!.exp
+        }
+      ]
+    })
+  })
+
+  test('directiveTransform with needRuntime: true', () => {
+    let _dir: DirectiveNode
+    const { root, node } = parseWithElementTransform(
+      `<div v-foo:bar="hello" />`,
+      {
+        directiveTransforms: {
+          foo(dir) {
+            _dir = dir
+            return {
+              props: [
+                createObjectProperty(dir.arg!, dir.exp!, dir.loc),
+                createObjectProperty(dir.arg!, dir.exp!, dir.loc)
+              ],
+              needRuntime: true
+            }
+          }
+        }
+      }
+    )
+    expect(root.imports).toContain(RESOLVE_DIRECTIVE)
+    expect(root.statements[0]).toMatch(`${RESOLVE_DIRECTIVE}("foo")`)
+
+    expect(node.callee).toBe(APPLY_DIRECTIVES)
+    expect(node.arguments).toMatchObject([
+      {
+        type: NodeTypes.JS_CALL_EXPRESSION,
+        callee: CREATE_VNODE,
+        arguments: [
+          `"div"`,
+          {
+            type: NodeTypes.JS_OBJECT_EXPRESSION,
+            properties: [
+              {
+                type: NodeTypes.JS_PROPERTY,
+                key: _dir!.arg,
+                value: _dir!.exp
+              },
+              {
+                type: NodeTypes.JS_PROPERTY,
+                key: _dir!.arg,
+                value: _dir!.exp
+              }
+            ]
+          }
+        ]
+      },
+      {
+        type: NodeTypes.JS_ARRAY_EXPRESSION,
+        elements: [
+          {
+            type: NodeTypes.JS_ARRAY_EXPRESSION,
+            elements: [
+              `_directive_foo`,
+              // exp
+              {
+                type: NodeTypes.EXPRESSION,
+                content: `hello`,
+                isStatic: false,
+                isInterpolation: false
+              },
+              // arg
+              {
+                type: NodeTypes.EXPRESSION,
+                content: `bar`,
+                isStatic: true
+              }
+            ]
+          }
+        ]
+      }
+    ])
+  })
+
+  test('runtime directives', () => {
+    const { root, node } = parseWithElementTransform(
+      `<div v-foo v-bar="x" v-baz:[arg].mod.mad="y" />`
+    )
+    expect(root.imports).toContain(RESOLVE_DIRECTIVE)
+    expect(root.statements[0]).toMatch(`${RESOLVE_DIRECTIVE}("foo")`)
+    expect(root.statements[1]).toMatch(`${RESOLVE_DIRECTIVE}("bar")`)
+    expect(root.statements[2]).toMatch(`${RESOLVE_DIRECTIVE}("baz")`)
+
+    expect(node.callee).toBe(APPLY_DIRECTIVES)
+    expect(node.arguments).toMatchObject([
+      {
+        type: NodeTypes.JS_CALL_EXPRESSION
+      },
+      {
+        type: NodeTypes.JS_ARRAY_EXPRESSION,
+        elements: [
+          {
+            type: NodeTypes.JS_ARRAY_EXPRESSION,
+            elements: [`_directive_foo`]
+          },
+          {
+            type: NodeTypes.JS_ARRAY_EXPRESSION,
+            elements: [
+              `_directive_bar`,
+              // exp
+              {
+                type: NodeTypes.EXPRESSION,
+                content: `x`
+              }
+            ]
+          },
+          {
+            type: NodeTypes.JS_ARRAY_EXPRESSION,
+            elements: [
+              `_directive_baz`,
+              // exp
+              {
+                type: NodeTypes.EXPRESSION,
+                content: `y`,
+                isStatic: false,
+                isInterpolation: false
+              },
+              // arg
+              {
+                type: NodeTypes.EXPRESSION,
+                content: `arg`,
+                isStatic: false
+              },
+              // modifiers
+              {
+                type: NodeTypes.JS_OBJECT_EXPRESSION,
+                properties: [
+                  {
+                    type: NodeTypes.JS_PROPERTY,
+                    key: {
+                      type: NodeTypes.EXPRESSION,
+                      content: `mod`,
+                      isStatic: true
+                    },
+                    value: {
+                      type: NodeTypes.EXPRESSION,
+                      content: `true`,
+                      isStatic: false
+                    }
+                  },
+                  {
+                    type: NodeTypes.JS_PROPERTY,
+                    key: {
+                      type: NodeTypes.EXPRESSION,
+                      content: `mad`,
+                      isStatic: true
+                    },
+                    value: {
+                      type: NodeTypes.EXPRESSION,
+                      content: `true`,
+                      isStatic: false
+                    }
+                  }
+                ]
+              }
+            ]
+          }
+        ]
+      }
+    ])
+  })
+
+  test.todo('slot outlets')
+})
diff --git a/packages/compiler-core/__tests__/transforms/transformExpressions.spec.ts b/packages/compiler-core/__tests__/transforms/transformExpressions.spec.ts
new file mode 100644 (file)
index 0000000..0b68b42
--- /dev/null
@@ -0,0 +1,8 @@
+import { compile } from '../../src'
+
+test(`should work`, () => {
+  const { code } = compile(`<div>{{ foo }} bar</div>`, {
+    prefixIdentifiers: true
+  })
+  expect(code).toContain(`foo`)
+})
index 92664e75a4fd5c1cee4bea791e48f23304d46827..76100fbeb880d1c8f6172c14a6e887b88f220bae 100644 (file)
@@ -5,7 +5,7 @@ import { ForNode, NodeTypes } from '../../src/ast'
 import { ErrorCodes } from '../../src/errors'
 import { CompilerOptions } from '../../src'
 
-function transformWithFor(
+function parseWithForTransform(
   template: string,
   options: CompilerOptions = {}
 ): ForNode {
@@ -20,7 +20,7 @@ function transformWithFor(
 
 describe('compiler: transform v-for', () => {
   test('number expression', () => {
-    const forNode = transformWithFor('<span v-for="index in 5" />')
+    const forNode = parseWithForTransform('<span v-for="index in 5" />')
     expect(forNode.keyAlias).toBeUndefined()
     expect(forNode.objectIndexAlias).toBeUndefined()
     expect(forNode.valueAlias!.content).toBe('index')
@@ -28,7 +28,7 @@ describe('compiler: transform v-for', () => {
   })
 
   test('value', () => {
-    const forNode = transformWithFor('<span v-for="(item) in items" />')
+    const forNode = parseWithForTransform('<span v-for="(item) in items" />')
     expect(forNode.keyAlias).toBeUndefined()
     expect(forNode.objectIndexAlias).toBeUndefined()
     expect(forNode.valueAlias!.content).toBe('item')
@@ -36,7 +36,7 @@ describe('compiler: transform v-for', () => {
   })
 
   test('object de-structured value', () => {
-    const forNode = transformWithFor(
+    const forNode = parseWithForTransform(
       '<span v-for="({ id, value }) in items" />'
     )
     expect(forNode.keyAlias).toBeUndefined()
@@ -46,7 +46,7 @@ describe('compiler: transform v-for', () => {
   })
 
   test('array de-structured value', () => {
-    const forNode = transformWithFor(
+    const forNode = parseWithForTransform(
       '<span v-for="([ id, value ]) in items" />'
     )
     expect(forNode.keyAlias).toBeUndefined()
@@ -56,7 +56,9 @@ describe('compiler: transform v-for', () => {
   })
 
   test('value and key', () => {
-    const forNode = transformWithFor('<span v-for="(item, key) in items" />')
+    const forNode = parseWithForTransform(
+      '<span v-for="(item, key) in items" />'
+    )
     expect(forNode.keyAlias).not.toBeUndefined()
     expect(forNode.keyAlias!.content).toBe('key')
     expect(forNode.objectIndexAlias).toBeUndefined()
@@ -65,7 +67,7 @@ describe('compiler: transform v-for', () => {
   })
 
   test('value, key and index', () => {
-    const forNode = transformWithFor(
+    const forNode = parseWithForTransform(
       '<span v-for="(value, key, index) in items" />'
     )
     expect(forNode.keyAlias).not.toBeUndefined()
@@ -77,7 +79,9 @@ describe('compiler: transform v-for', () => {
   })
 
   test('skipped key', () => {
-    const forNode = transformWithFor('<span v-for="(value,,index) in items" />')
+    const forNode = parseWithForTransform(
+      '<span v-for="(value,,index) in items" />'
+    )
     expect(forNode.keyAlias).toBeUndefined()
     expect(forNode.objectIndexAlias).not.toBeUndefined()
     expect(forNode.objectIndexAlias!.content).toBe('index')
@@ -86,7 +90,7 @@ describe('compiler: transform v-for', () => {
   })
 
   test('skipped value and key', () => {
-    const forNode = transformWithFor('<span v-for="(,,index) in items" />')
+    const forNode = parseWithForTransform('<span v-for="(,,index) in items" />')
     expect(forNode.keyAlias).toBeUndefined()
     expect(forNode.objectIndexAlias).not.toBeUndefined()
     expect(forNode.objectIndexAlias!.content).toBe('index')
@@ -95,7 +99,7 @@ describe('compiler: transform v-for', () => {
   })
 
   test('unbracketed value', () => {
-    const forNode = transformWithFor('<span v-for="item in items" />')
+    const forNode = parseWithForTransform('<span v-for="item in items" />')
     expect(forNode.keyAlias).toBeUndefined()
     expect(forNode.objectIndexAlias).toBeUndefined()
     expect(forNode.valueAlias!.content).toBe('item')
@@ -103,7 +107,7 @@ describe('compiler: transform v-for', () => {
   })
 
   test('unbracketed value and key', () => {
-    const forNode = transformWithFor('<span v-for="item, key in items" />')
+    const forNode = parseWithForTransform('<span v-for="item, key in items" />')
     expect(forNode.keyAlias).not.toBeUndefined()
     expect(forNode.keyAlias!.content).toBe('key')
     expect(forNode.objectIndexAlias).toBeUndefined()
@@ -112,7 +116,7 @@ describe('compiler: transform v-for', () => {
   })
 
   test('unbracketed value, key and index', () => {
-    const forNode = transformWithFor(
+    const forNode = parseWithForTransform(
       '<span v-for="value, key, index in items" />'
     )
     expect(forNode.keyAlias).not.toBeUndefined()
@@ -124,7 +128,9 @@ describe('compiler: transform v-for', () => {
   })
 
   test('unbracketed skipped key', () => {
-    const forNode = transformWithFor('<span v-for="value, , index in items" />')
+    const forNode = parseWithForTransform(
+      '<span v-for="value, , index in items" />'
+    )
     expect(forNode.keyAlias).toBeUndefined()
     expect(forNode.objectIndexAlias).not.toBeUndefined()
     expect(forNode.objectIndexAlias!.content).toBe('index')
@@ -133,7 +139,7 @@ describe('compiler: transform v-for', () => {
   })
 
   test('unbracketed skipped value and key', () => {
-    const forNode = transformWithFor('<span v-for=", , index in items" />')
+    const forNode = parseWithForTransform('<span v-for=", , index in items" />')
     expect(forNode.keyAlias).toBeUndefined()
     expect(forNode.objectIndexAlias).not.toBeUndefined()
     expect(forNode.objectIndexAlias!.content).toBe('index')
@@ -143,7 +149,7 @@ describe('compiler: transform v-for', () => {
 
   test('missing expression', () => {
     const onError = jest.fn()
-    transformWithFor('<span v-for />', { onError })
+    parseWithForTransform('<span v-for />', { onError })
 
     expect(onError).toHaveBeenCalledTimes(1)
     expect(onError).toHaveBeenCalledWith(
@@ -155,7 +161,7 @@ describe('compiler: transform v-for', () => {
 
   test('empty expression', () => {
     const onError = jest.fn()
-    transformWithFor('<span v-for="" />', { onError })
+    parseWithForTransform('<span v-for="" />', { onError })
 
     expect(onError).toHaveBeenCalledTimes(1)
     expect(onError).toHaveBeenCalledWith(
@@ -167,7 +173,7 @@ describe('compiler: transform v-for', () => {
 
   test('invalid expression', () => {
     const onError = jest.fn()
-    transformWithFor('<span v-for="items" />', { onError })
+    parseWithForTransform('<span v-for="items" />', { onError })
 
     expect(onError).toHaveBeenCalledTimes(1)
     expect(onError).toHaveBeenCalledWith(
@@ -179,7 +185,7 @@ describe('compiler: transform v-for', () => {
 
   test('missing source', () => {
     const onError = jest.fn()
-    transformWithFor('<span v-for="item in" />', { onError })
+    parseWithForTransform('<span v-for="item in" />', { onError })
 
     expect(onError).toHaveBeenCalledTimes(1)
     expect(onError).toHaveBeenCalledWith(
@@ -191,7 +197,7 @@ describe('compiler: transform v-for', () => {
 
   test('missing value', () => {
     const onError = jest.fn()
-    transformWithFor('<span v-for="in items" />', { onError })
+    parseWithForTransform('<span v-for="in items" />', { onError })
 
     expect(onError).toHaveBeenCalledTimes(1)
     expect(onError).toHaveBeenCalledWith(
@@ -204,7 +210,7 @@ describe('compiler: transform v-for', () => {
   describe('source location', () => {
     test('value & source', () => {
       const source = '<span v-for="item in items" />'
-      const forNode = transformWithFor(source)
+      const forNode = parseWithForTransform(source)
 
       expect(forNode.valueAlias!.content).toBe('item')
       expect(forNode.valueAlias!.loc.start.offset).toBe(
@@ -227,7 +233,7 @@ describe('compiler: transform v-for', () => {
 
     test('bracketed value', () => {
       const source = '<span v-for="( item ) in items" />'
-      const forNode = transformWithFor(source)
+      const forNode = parseWithForTransform(source)
 
       expect(forNode.valueAlias!.content).toBe('item')
       expect(forNode.valueAlias!.loc.start.offset).toBe(
@@ -250,7 +256,7 @@ describe('compiler: transform v-for', () => {
 
     test('de-structured value', () => {
       const source = '<span v-for="(  { id, key })in items" />'
-      const forNode = transformWithFor(source)
+      const forNode = parseWithForTransform(source)
 
       expect(forNode.valueAlias!.content).toBe('{ id, key }')
       expect(forNode.valueAlias!.loc.start.offset).toBe(
@@ -275,7 +281,7 @@ describe('compiler: transform v-for', () => {
 
     test('bracketed value, key, index', () => {
       const source = '<span v-for="( item, key, index ) in items" />'
-      const forNode = transformWithFor(source)
+      const forNode = parseWithForTransform(source)
 
       expect(forNode.valueAlias!.content).toBe('item')
       expect(forNode.valueAlias!.loc.start.offset).toBe(
@@ -318,7 +324,7 @@ describe('compiler: transform v-for', () => {
 
     test('skipped key', () => {
       const source = '<span v-for="( item,, index ) in items" />'
-      const forNode = transformWithFor(source)
+      const forNode = parseWithForTransform(source)
 
       expect(forNode.valueAlias!.content).toBe('item')
       expect(forNode.valueAlias!.loc.start.offset).toBe(
index aa56d175a82f48f874833a6d15fed5a0305204fe..a9da468896da29d07766f401b57fcb0739db49fe 100644 (file)
@@ -11,7 +11,7 @@ import {
 import { ErrorCodes } from '../../src/errors'
 import { CompilerOptions } from '../../src'
 
-function transformWithIf(
+function parseWithIfTransform(
   template: string,
   options: CompilerOptions = {},
   returnIndex: number = 0
@@ -27,7 +27,7 @@ function transformWithIf(
 
 describe('compiler: transform v-if', () => {
   test('basic v-if', () => {
-    const node = transformWithIf(`<div v-if="ok"/>`)
+    const node = parseWithIfTransform(`<div v-if="ok"/>`)
     expect(node.type).toBe(NodeTypes.IF)
     expect(node.branches.length).toBe(1)
     expect(node.branches[0].condition!.content).toBe(`ok`)
@@ -37,7 +37,7 @@ describe('compiler: transform v-if', () => {
   })
 
   test('template v-if', () => {
-    const node = transformWithIf(
+    const node = parseWithIfTransform(
       `<template v-if="ok"><div/>hello<p/></template>`
     )
     expect(node.type).toBe(NodeTypes.IF)
@@ -53,7 +53,7 @@ describe('compiler: transform v-if', () => {
   })
 
   test('v-if + v-else', () => {
-    const node = transformWithIf(`<div v-if="ok"/><p v-else/>`)
+    const node = parseWithIfTransform(`<div v-if="ok"/><p v-else/>`)
     expect(node.type).toBe(NodeTypes.IF)
     expect(node.branches.length).toBe(2)
 
@@ -71,7 +71,7 @@ describe('compiler: transform v-if', () => {
   })
 
   test('v-if + v-else-if', () => {
-    const node = transformWithIf(`<div v-if="ok"/><p v-else-if="orNot"/>`)
+    const node = parseWithIfTransform(`<div v-if="ok"/><p v-else-if="orNot"/>`)
     expect(node.type).toBe(NodeTypes.IF)
     expect(node.branches.length).toBe(2)
 
@@ -89,7 +89,7 @@ describe('compiler: transform v-if', () => {
   })
 
   test('v-if + v-else-if + v-else', () => {
-    const node = transformWithIf(
+    const node = parseWithIfTransform(
       `<div v-if="ok"/><p v-else-if="orNot"/><template v-else>fine</template>`
     )
     expect(node.type).toBe(NodeTypes.IF)
@@ -115,7 +115,7 @@ describe('compiler: transform v-if', () => {
   })
 
   test('comment between branches', () => {
-    const node = transformWithIf(`
+    const node = parseWithIfTransform(`
       <div v-if="ok"/>
       <!--foo-->
       <p v-else-if="orNot"/>
@@ -151,7 +151,7 @@ describe('compiler: transform v-if', () => {
   test('error on v-else missing adjacent v-if', () => {
     const onError = jest.fn()
 
-    const node1 = transformWithIf(`<div v-else/>`, { onError })
+    const node1 = parseWithIfTransform(`<div v-else/>`, { onError })
     expect(onError.mock.calls[0]).toMatchObject([
       {
         code: ErrorCodes.X_ELSE_NO_ADJACENT_IF,
@@ -159,7 +159,7 @@ describe('compiler: transform v-if', () => {
       }
     ])
 
-    const node2 = transformWithIf(`<div/><div v-else/>`, { onError }, 1)
+    const node2 = parseWithIfTransform(`<div/><div v-else/>`, { onError }, 1)
     expect(onError.mock.calls[1]).toMatchObject([
       {
         code: ErrorCodes.X_ELSE_NO_ADJACENT_IF,
@@ -167,7 +167,7 @@ describe('compiler: transform v-if', () => {
       }
     ])
 
-    const node3 = transformWithIf(`<div/>foo<div v-else/>`, { onError }, 2)
+    const node3 = parseWithIfTransform(`<div/>foo<div v-else/>`, { onError }, 2)
     expect(onError.mock.calls[2]).toMatchObject([
       {
         code: ErrorCodes.X_ELSE_NO_ADJACENT_IF,
@@ -179,7 +179,7 @@ describe('compiler: transform v-if', () => {
   test('error on v-else-if missing adjacent v-if', () => {
     const onError = jest.fn()
 
-    const node1 = transformWithIf(`<div v-else-if="foo"/>`, { onError })
+    const node1 = parseWithIfTransform(`<div v-else-if="foo"/>`, { onError })
     expect(onError.mock.calls[0]).toMatchObject([
       {
         code: ErrorCodes.X_ELSE_IF_NO_ADJACENT_IF,
@@ -187,7 +187,7 @@ describe('compiler: transform v-if', () => {
       }
     ])
 
-    const node2 = transformWithIf(
+    const node2 = parseWithIfTransform(
       `<div/><div v-else-if="foo"/>`,
       { onError },
       1
@@ -199,7 +199,7 @@ describe('compiler: transform v-if', () => {
       }
     ])
 
-    const node3 = transformWithIf(
+    const node3 = parseWithIfTransform(
       `<div/>foo<div v-else-if="foo"/>`,
       { onError },
       2
index 3b3e54786911014924751451afc2d4716cfd61df..0259c3bbf4a176426aa670906f9d974596bac0bd 100644 (file)
@@ -147,6 +147,9 @@ export function generate(
   if (!prefixIdentifiers) {
     push(`with (this) {`)
     indent()
+  } else {
+    push(`const _ctx = this`)
+    newline()
   }
   push(`return `)
   genChildren(ast.children, context, true /* asRoot */)
index 7b0a95decb916f6e328a014b729e3fe1d4f349fb..127b29c251926513e742d70cf392edee71de0e2e 100644 (file)
@@ -5,10 +5,10 @@ import { RootNode } from './ast'
 import { isString } from '@vue/shared'
 import { transformIf } from './transforms/vIf'
 import { transformFor } from './transforms/vFor'
-import { prepareElementForCodegen } from './transforms/element'
+import { transformElement } from './transforms/transformElement'
 import { transformOn } from './transforms/vOn'
 import { transformBind } from './transforms/vBind'
-import { expressionTransform } from './transforms/expression'
+import { transformExpression } from './transforms/transformExpression'
 import { defaultOnError, createCompilerError, ErrorCodes } from './errors'
 
 export type CompilerOptions = ParserOptions & TransformOptions & CodegenOptions
@@ -32,8 +32,8 @@ export function compile(
     nodeTransforms: [
       transformIf,
       transformFor,
-      ...(prefixIdentifiers ? [expressionTransform] : []),
-      prepareElementForCodegen,
+      ...(prefixIdentifiers ? [transformExpression] : []),
+      transformElement,
       ...(options.nodeTransforms || []) // user transforms
     ],
     directiveTransforms: {
@@ -65,4 +65,6 @@ export { ErrorCodes, CompilerError, createCompilerError } from './errors'
 export * from './ast'
 
 // debug
-export { prepareElementForCodegen } from './transforms/element'
+export {
+  transformElement as prepareElementForCodegen
+} from './transforms/transformElement'
index c7a393be52527f2db44bc47aebeb486b14255ffa..bc5859956800785be908d7bc01fbff2a23ff7da2 100644 (file)
@@ -7,3 +7,4 @@ export const APPLY_DIRECTIVES = `applyDirectives`
 export const RENDER_LIST = `renderList`
 export const CAPITALIZE = `capitalize`
 export const TO_STRING = `toString`
+export const MERGE_PROPS = `mergeProps`
similarity index 93%
rename from packages/compiler-core/src/transforms/element.ts
rename to packages/compiler-core/src/transforms/transformElement.ts
index 2c6ff252e664f1b4dc1089a04172064094a670e2..fe381dedca0b9a0bc03e7f8b47a544ff0b003677 100644 (file)
@@ -20,13 +20,14 @@ import {
   CREATE_VNODE,
   APPLY_DIRECTIVES,
   RESOLVE_DIRECTIVE,
-  RESOLVE_COMPONENT
+  RESOLVE_COMPONENT,
+  MERGE_PROPS
 } from '../runtimeConstants'
 
 const toValidId = (str: string): string => str.replace(/[^\w]/g, '')
 
 // generate a JavaScript AST for this element's codegen
-export const prepareElementForCodegen: NodeTransform = (node, context) => {
+export const transformElement: NodeTransform = (node, context) => {
   if (node.type === NodeTypes.ELEMENT) {
     if (
       node.tagType === ElementTypes.ELEMENT ||
@@ -91,9 +92,8 @@ export const prepareElementForCodegen: NodeTransform = (node, context) => {
     } else if (node.tagType === ElementTypes.SLOT) {
       // <slot [name="xxx"]/>
       // TODO
-    } else if (node.tagType === ElementTypes.TEMPLATE) {
-      // do nothing
     }
+    // node.tagType can also be TEMPLATE, in which case nothing needs to be done
   }
 }
 
@@ -101,7 +101,7 @@ function buildProps(
   { loc, props }: ElementNode,
   context: TransformContext
 ): {
-  props: ObjectExpression | CallExpression
+  props: ObjectExpression | CallExpression | ExpressionNode
   directives: DirectiveNode[]
 } {
   let properties: ObjectExpression['properties'] = []
@@ -160,7 +160,7 @@ function buildProps(
     }
   }
 
-  let ret: ObjectExpression | CallExpression
+  let ret: ObjectExpression | CallExpression | ExpressionNode
 
   // has v-bind="object", wrap with mergeProps
   if (mergeArgs.length) {
@@ -168,10 +168,11 @@ function buildProps(
       mergeArgs.push(createObjectExpression(properties, loc))
     }
     if (mergeArgs.length > 1) {
-      ret = createCallExpression(`mergeProps`, mergeArgs, loc)
+      context.imports.add(MERGE_PROPS)
+      ret = createCallExpression(MERGE_PROPS, mergeArgs, loc)
     } else {
       // single v-bind with nothing else - no need for a mergeProps call
-      ret = createObjectExpression(properties, loc)
+      ret = mergeArgs[0]
     }
   } else {
     ret = createObjectExpression(properties, loc)
similarity index 98%
rename from packages/compiler-core/src/transforms/expression.ts
rename to packages/compiler-core/src/transforms/transformExpression.ts
index 08e83b690e38be70e1e6735bff2e8c5189f87634..adc9ee1cb35ee5b5496bd7d6d476ca893d14bfc1 100644 (file)
@@ -15,7 +15,7 @@ import { NodeTypes, createExpression, ExpressionNode } from '../ast'
 import { Node, Function, Identifier } from 'estree'
 import { advancePositionWithClone } from '../utils'
 
-export const expressionTransform: NodeTransform = (node, context) => {
+export const transformExpression: NodeTransform = (node, context) => {
   if (node.type === NodeTypes.EXPRESSION && !node.isStatic) {
     processExpression(node, context)
   } else if (node.type === NodeTypes.ELEMENT) {
index fdb9d7a2cd34dc8f29c70803ec57935df13423ff..b1cf727aacb8cf8ae9faa2535af025bd8c212239 100644 (file)
@@ -11,7 +11,7 @@ import {
 import { createCompilerError, ErrorCodes } from '../errors'
 import { getInnerRange } from '../utils'
 import { RENDER_LIST } from '../runtimeConstants'
-import { processExpression } from './expression'
+import { processExpression } from './transformExpression'
 
 const forAliasRE = /([\s\S]*?)(?:(?<=\))|\s+)(?:in|of)\s+([\s\S]*)/
 const forIteratorRE = /,([^,\}\]]*)(?:,([^,\}\]]*))?$/
index f0f5830c610b77938c320550ed215c3063a7d7b0..1d8fe08aaf6db6aa08c9a42f9f27b45a754aab9a 100644 (file)
@@ -10,7 +10,7 @@ import {
   IfBranchNode
 } from '../ast'
 import { createCompilerError, ErrorCodes } from '../errors'
-import { processExpression } from './expression'
+import { processExpression } from './transformExpression'
 
 export const transformIf = createStructuralDirectiveTransform(
   /^(if|else|else-if)$/,