]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix: fix source map by fixing advancePositionWithMutation
authorEvan You <yyx990803@gmail.com>
Wed, 25 Sep 2019 23:17:45 +0000 (19:17 -0400)
committerEvan You <yyx990803@gmail.com>
Wed, 25 Sep 2019 23:17:45 +0000 (19:17 -0400)
20 files changed:
packages/compiler-core/__tests__/__snapshots__/codegen.spec.ts.snap
packages/compiler-core/__tests__/__snapshots__/compile.spec.ts.snap [new file with mode: 0644]
packages/compiler-core/__tests__/__snapshots__/parse.spec.ts.snap
packages/compiler-core/__tests__/codegen.spec.ts
packages/compiler-core/__tests__/compile.spec.ts
packages/compiler-core/__tests__/parse.spec.ts
packages/compiler-core/__tests__/transforms/transformElement.spec.ts
packages/compiler-core/__tests__/transforms/vBind.spec.ts
packages/compiler-core/__tests__/transforms/vFor.spec.ts
packages/compiler-core/__tests__/transforms/vIf.spec.ts
packages/compiler-core/__tests__/transforms/vOn.spec.ts
packages/compiler-core/__tests__/utils.spec.ts
packages/compiler-core/src/ast.ts
packages/compiler-core/src/codegen.ts
packages/compiler-core/src/parse.ts
packages/compiler-core/src/transform.ts
packages/compiler-core/src/transforms/transformElement.ts
packages/compiler-core/src/transforms/vFor.ts
packages/compiler-core/src/transforms/vIf.ts
packages/compiler-core/src/utils.ts

index d5e65e6a763478553050472da9d7ed4d57e413e8..dd8d8311b07b6e9ebb9fbef6a7837bb053eb5be8 100644 (file)
@@ -20,7 +20,7 @@ exports[`compiler: codegen comment 1`] = `
 "
 return function render() {
   with (this) {
-    return createVNode(Comment, 0, \\"foo\\")
+    return _createVNode(_Comment, 0, \\"foo\\")
   }
 }"
 `;
@@ -29,7 +29,7 @@ exports[`compiler: codegen compound expression 1`] = `
 "
 return function render() {
   with (this) {
-    return toString(_ctx.foo)
+    return _toString(_ctx.foo)
   }
 }"
 `;
@@ -38,16 +38,30 @@ exports[`compiler: codegen forNode 1`] = `
 "
 return function render() {
   with (this) {
-    return renderList(list, (v, k, i) => toString(v))
+    return _renderList(list, (v, k, i) => {
+      return _toString(v)
+    })
   }
 }"
 `;
 
+exports[`compiler: codegen forNode w/ prefixIdentifiers: true 1`] = `
+"
+return function render() {
+  const _ctx = this
+  return renderList(list, (v, k, i) => {
+    return toString(v)
+  })
+}"
+`;
+
 exports[`compiler: codegen forNode w/ skipped key alias 1`] = `
 "
 return function render() {
   with (this) {
-    return renderList(list, (v, __key, i) => toString(v))
+    return _renderList(list, (v, __key, i) => {
+      return _toString(v)
+    })
   }
 }"
 `;
@@ -56,7 +70,9 @@ exports[`compiler: codegen forNode w/ skipped value alias 1`] = `
 "
 return function render() {
   with (this) {
-    return renderList(list, (__value, k, i) => toString(v))
+    return _renderList(list, (__value, k, i) => {
+      return _toString(v)
+    })
   }
 }"
 `;
@@ -65,7 +81,9 @@ exports[`compiler: codegen forNode w/ skipped value and key aliases 1`] = `
 "
 return function render() {
   with (this) {
-    return renderList(list, (__value, __key, i) => toString(v))
+    return _renderList(list, (__value, __key, i) => {
+      return _toString(v)
+    })
   }
 }"
 `;
@@ -74,12 +92,21 @@ exports[`compiler: codegen function mode preamble 1`] = `
 "const _Vue = Vue
 return function render() {
   with (this) {
-    const { helperOnehelperTwo } = _Vue
+    const { helperOne: _helperOne, helperTwo: _helperTwo } = _Vue
     return null
   }
 }"
 `;
 
+exports[`compiler: codegen function mode preamble w/ prefixIdentifiers: true 1`] = `
+"const { helperOne, helperTwo } = Vue
+
+return function render() {
+  const _ctx = this
+  return null
+}"
+`;
+
 exports[`compiler: codegen hoists 1`] = `
 "const _hoisted_1 = hello
 const _hoisted_2 = { id: \\"foo\\" }
@@ -98,8 +125,8 @@ return function render() {
     return foo
       ? \\"foo\\"
       : (a + b)
-        ? toString(bye)
-        : createVNode(Comment, 0, \\"foo\\")
+        ? _toString(bye)
+        : _createVNode(_Comment, 0, \\"foo\\")
   }
 }"
 `;
@@ -111,7 +138,7 @@ return function render() {
     return foo
       ? \\"foo\\"
       : (a + b)
-        ? toString(bye)
+        ? _toString(bye)
         : null
   }
 }"
@@ -121,7 +148,7 @@ exports[`compiler: codegen interpolation 1`] = `
 "
 return function render() {
   with (this) {
-    return toString(hello)
+    return _toString(hello)
   }
 }"
 `;
@@ -171,9 +198,21 @@ return function render() {
   with (this) {
     return [
       \\"foo\\",
-      toString(hello),
-      createVNode(Comment, 0, \\"foo\\")
+      _toString(hello),
+      _createVNode(_Comment, 0, \\"foo\\")
     ]
   }
 }"
 `;
+
+exports[`compiler: codegen text + comment + interpolation w/ prefixIdentifiers: true 1`] = `
+"
+return function render() {
+  const _ctx = this
+  return [
+    \\"foo\\",
+    toString(hello),
+    createVNode(Comment, 0, \\"foo\\")
+  ]
+}"
+`;
diff --git a/packages/compiler-core/__tests__/__snapshots__/compile.spec.ts.snap b/packages/compiler-core/__tests__/__snapshots__/compile.spec.ts.snap
new file mode 100644 (file)
index 0000000..f750822
--- /dev/null
@@ -0,0 +1,22 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`function mode 1`] = `
+"const _Vue = Vue
+return function render() {
+  with (this) {
+    const { createVNode: _createVNode, toString: _toString, renderList: _renderList } = _Vue
+    return _createVNode(\\"div\\", {
+      id: \\"foo\\",
+      class: bar
+    }, [
+      _toString(world),
+      ok
+        ? _createVNode(\\"div\\", 0, \\"yes\\")
+        : \\"no\\",
+      _renderList(list, (i, j) => {
+        return _createVNode(\\"div\\", 0, [_createVNode(\\"span\\", 0, _toString(i + j))])
+      })
+    ])
+  }
+}"
+`;
index 250b91ae099181bcb15f0066db3f7cc4e5364674..694b37348d2dec796aa1723afee6f9172ed78b7e 100644 (file)
@@ -7481,15 +7481,15 @@ Object {
             "isStatic": false,
             "loc": Object {
               "end": Object {
-                "column": 34,
+                "column": 33,
                 "line": 1,
-                "offset": 33,
+                "offset": 32,
               },
               "source": "\\"{ some: condition }\\"",
               "start": Object {
-                "column": 13,
+                "column": 14,
                 "line": 1,
-                "offset": 12,
+                "offset": 13,
               },
             },
             "type": 4,
@@ -7561,15 +7561,15 @@ Object {
             "isStatic": false,
             "loc": Object {
               "end": Object {
-                "column": 35,
+                "column": 34,
                 "line": 2,
-                "offset": 71,
+                "offset": 70,
               },
               "source": "\\"{ color: 'red' }\\"",
               "start": Object {
-                "column": 17,
+                "column": 18,
                 "line": 2,
-                "offset": 53,
+                "offset": 54,
               },
             },
             "type": 4,
@@ -7629,13 +7629,13 @@ Object {
           "isSelfClosing": true,
           "loc": Object {
             "end": Object {
-              "column": 38,
+              "column": 39,
               "line": 2,
               "offset": 73,
             },
             "source": "<p v-bind:style=\\"{ color: 'red' }\\"/>",
             "start": Object {
-              "column": 2,
+              "column": 3,
               "line": 2,
               "offset": 37,
             },
@@ -7649,13 +7649,13 @@ Object {
                 "isStatic": true,
                 "loc": Object {
                   "end": Object {
-                    "column": 17,
+                    "column": 18,
                     "line": 2,
                     "offset": 52,
                   },
                   "source": "style",
                   "start": Object {
-                    "column": 12,
+                    "column": 13,
                     "line": 2,
                     "offset": 47,
                   },
@@ -7670,26 +7670,26 @@ Object {
                   "end": Object {
                     "column": 36,
                     "line": 2,
-                    "offset": 71,
+                    "offset": 70,
                   },
                   "source": "\\"{ color: 'red' }\\"",
                   "start": Object {
-                    "column": 18,
+                    "column": 20,
                     "line": 2,
-                    "offset": 53,
+                    "offset": 54,
                   },
                 },
                 "type": 4,
               },
               "loc": Object {
                 "end": Object {
-                  "column": 36,
+                  "column": 37,
                   "line": 2,
                   "offset": 71,
                 },
                 "source": "v-bind:style=\\"{ color: 'red' }\\"",
                 "start": Object {
-                  "column": 5,
+                  "column": 6,
                   "line": 2,
                   "offset": 40,
                 },
@@ -7707,13 +7707,13 @@ Object {
           "content": " a comment with <html> inside it ",
           "loc": Object {
             "end": Object {
-              "column": 42,
+              "column": 43,
               "line": 3,
               "offset": 116,
             },
             "source": "<!-- a comment with <html> inside it -->",
             "start": Object {
-              "column": 2,
+              "column": 3,
               "line": 3,
               "offset": 76,
             },
@@ -7767,15 +7767,15 @@ Object {
             "isStatic": false,
             "loc": Object {
               "end": Object {
-                "column": 34,
+                "column": 33,
                 "line": 1,
-                "offset": 33,
+                "offset": 32,
               },
               "source": "\\"{ some: condition }\\"",
               "start": Object {
-                "column": 13,
+                "column": 14,
                 "line": 1,
-                "offset": 12,
+                "offset": 13,
               },
             },
             "type": 4,
index 5e76e6258005797100b702f0d93f1d22086ee79f..88416f067b991c1bb5637dc5c862c63e27952447 100644 (file)
@@ -12,7 +12,12 @@ import {
   createArrayExpression,
   ElementNode
 } from '../src'
-import { CREATE_VNODE, COMMENT, TO_STRING } from '../src/runtimeConstants'
+import {
+  CREATE_VNODE,
+  COMMENT,
+  TO_STRING,
+  RENDER_LIST
+} from '../src/runtimeConstants'
 
 const mockLoc: SourceLocation = {
   source: ``,
@@ -56,7 +61,22 @@ describe('compiler: codegen', () => {
     })
     const { code } = generate(root, { mode: 'function' })
     expect(code).toMatch(`const _Vue = Vue`)
-    expect(code).toMatch(`const { helperOne, helperTwo } = _Vue`)
+    expect(code).toMatch(
+      `const { helperOne: _helperOne, helperTwo: _helperTwo } = _Vue`
+    )
+    expect(code).toMatchSnapshot()
+  })
+
+  test('function mode preamble w/ prefixIdentifiers: true', () => {
+    const root = createRoot({
+      imports: [`helperOne`, `helperTwo`]
+    })
+    const { code } = generate(root, {
+      mode: 'function',
+      prefixIdentifiers: true
+    })
+    expect(code).not.toMatch(`const _Vue = Vue`)
+    expect(code).toMatch(`const { helperOne, helperTwo } = Vue`)
     expect(code).toMatchSnapshot()
   })
 
@@ -121,7 +141,7 @@ describe('compiler: codegen', () => {
         children: [createExpression(`hello`, false, mockLoc, true)]
       })
     )
-    expect(code).toMatch(`return toString(hello)`)
+    expect(code).toMatch(`return _${TO_STRING}(hello)`)
     expect(code).toMatchSnapshot()
   })
 
@@ -137,7 +157,7 @@ describe('compiler: codegen', () => {
         ]
       })
     )
-    expect(code).toMatch(`return ${CREATE_VNODE}(${COMMENT}, 0, "foo")`)
+    expect(code).toMatch(`return _${CREATE_VNODE}(_${COMMENT}, 0, "foo")`)
     expect(code).toMatchSnapshot()
   })
 
@@ -163,12 +183,43 @@ describe('compiler: codegen', () => {
     expect(code).toMatch(`
     return [
       "foo",
-      toString(hello),
-      ${CREATE_VNODE}(${COMMENT}, 0, "foo")
+      _${TO_STRING}(hello),
+      _${CREATE_VNODE}(_${COMMENT}, 0, "foo")
     ]`)
     expect(code).toMatchSnapshot()
   })
 
+  test('text + comment + interpolation w/ prefixIdentifiers: true', () => {
+    const { code } = generate(
+      createRoot({
+        children: [
+          {
+            type: NodeTypes.TEXT,
+            content: 'foo',
+            isEmpty: false,
+            loc: mockLoc
+          },
+          createExpression(`hello`, false, mockLoc, true),
+          {
+            type: NodeTypes.COMMENT,
+            content: 'foo',
+            loc: mockLoc
+          }
+        ]
+      }),
+      {
+        prefixIdentifiers: true
+      }
+    )
+    expect(code).toMatch(`
+  return [
+    "foo",
+    ${TO_STRING}(hello),
+    ${CREATE_VNODE}(${COMMENT}, 0, "foo")
+  ]`)
+    expect(code).toMatchSnapshot()
+  })
+
   test('compound expression', () => {
     const { code } = generate(
       createRoot({
@@ -184,7 +235,7 @@ describe('compiler: codegen', () => {
         ]
       })
     )
-    expect(code).toMatch(`return toString(_ctx.foo)`)
+    expect(code).toMatch(`return _${TO_STRING}(_ctx.foo)`)
     expect(code).toMatchSnapshot()
   })
 
@@ -195,13 +246,11 @@ describe('compiler: codegen', () => {
           {
             type: NodeTypes.IF,
             loc: mockLoc,
-            isRoot: true,
             branches: [
               {
                 type: NodeTypes.IF_BRANCH,
                 condition: createExpression('foo', false, mockLoc),
                 loc: mockLoc,
-                isRoot: true,
                 children: [
                   {
                     type: NodeTypes.TEXT,
@@ -215,14 +264,12 @@ describe('compiler: codegen', () => {
                 type: NodeTypes.IF_BRANCH,
                 condition: createExpression('a + b', false, mockLoc),
                 loc: mockLoc,
-                isRoot: true,
                 children: [createExpression(`bye`, false, mockLoc, true)]
               },
               {
                 type: NodeTypes.IF_BRANCH,
                 condition: undefined,
                 loc: mockLoc,
-                isRoot: true,
                 children: [
                   {
                     type: NodeTypes.COMMENT,
@@ -240,8 +287,8 @@ describe('compiler: codegen', () => {
     return foo
       ? "foo"
       : (a + b)
-        ? ${TO_STRING}(bye)
-        : ${CREATE_VNODE}(${COMMENT}, 0, "foo")`)
+        ? _${TO_STRING}(bye)
+        : _${CREATE_VNODE}(_${COMMENT}, 0, "foo")`)
     expect(code).toMatchSnapshot()
   })
 
@@ -252,13 +299,11 @@ describe('compiler: codegen', () => {
           {
             type: NodeTypes.IF,
             loc: mockLoc,
-            isRoot: true,
             branches: [
               {
                 type: NodeTypes.IF_BRANCH,
                 condition: createExpression('foo', false, mockLoc),
                 loc: mockLoc,
-                isRoot: true,
                 children: [
                   {
                     type: NodeTypes.TEXT,
@@ -272,7 +317,6 @@ describe('compiler: codegen', () => {
                 type: NodeTypes.IF_BRANCH,
                 condition: createExpression('a + b', false, mockLoc),
                 loc: mockLoc,
-                isRoot: true,
                 children: [createExpression(`bye`, false, mockLoc, true)]
               }
             ]
@@ -284,7 +328,7 @@ describe('compiler: codegen', () => {
     return foo
       ? "foo"
       : (a + b)
-        ? ${TO_STRING}(bye)
+        ? _${TO_STRING}(bye)
         : null`)
     expect(code).toMatchSnapshot()
   })
@@ -305,7 +349,38 @@ describe('compiler: codegen', () => {
         ]
       })
     )
-    expect(code).toMatch(`renderList(list, (v, k, i) => toString(v))`)
+    expect(code).toMatch(
+      `return _${RENDER_LIST}(list, (v, k, i) => {
+      return _${TO_STRING}(v)
+    })`
+    )
+    expect(code).toMatchSnapshot()
+  })
+
+  test('forNode w/ prefixIdentifiers: true', () => {
+    const { code } = generate(
+      createRoot({
+        children: [
+          {
+            type: NodeTypes.FOR,
+            loc: mockLoc,
+            source: createExpression(`list`, false, mockLoc),
+            valueAlias: createExpression(`v`, false, mockLoc),
+            keyAlias: createExpression(`k`, false, mockLoc),
+            objectIndexAlias: createExpression(`i`, false, mockLoc),
+            children: [createExpression(`v`, false, mockLoc, true)]
+          }
+        ]
+      }),
+      {
+        prefixIdentifiers: true
+      }
+    )
+    expect(code).toMatch(
+      `return ${RENDER_LIST}(list, (v, k, i) => {
+    return ${TO_STRING}(v)
+  })`
+    )
     expect(code).toMatchSnapshot()
   })
 
@@ -325,7 +400,11 @@ describe('compiler: codegen', () => {
         ]
       })
     )
-    expect(code).toMatch(`renderList(list, (__value, k, i) => toString(v))`)
+    expect(code).toMatch(
+      `return _${RENDER_LIST}(list, (__value, k, i) => {
+      return _${TO_STRING}(v)
+    })`
+    )
     expect(code).toMatchSnapshot()
   })
 
@@ -345,7 +424,11 @@ describe('compiler: codegen', () => {
         ]
       })
     )
-    expect(code).toMatch(`renderList(list, (v, __key, i) => toString(v))`)
+    expect(code).toMatch(
+      `return _${RENDER_LIST}(list, (v, __key, i) => {
+      return _${TO_STRING}(v)
+    })`
+    )
     expect(code).toMatchSnapshot()
   })
 
@@ -365,7 +448,11 @@ describe('compiler: codegen', () => {
         ]
       })
     )
-    expect(code).toMatch(`renderList(list, (__value, __key, i) => toString(v))`)
+    expect(code).toMatch(
+      `return _${RENDER_LIST}(list, (__value, __key, i) => {
+      return _${TO_STRING}(v)
+    })`
+    )
     expect(code).toMatchSnapshot()
   })
 
index d961d0693857adedf4b7f315547f116e4425daf0..ceb69aeae289a45e52eb608634b855259b5b0210 100644 (file)
@@ -2,35 +2,138 @@ import { compile } from '../src'
 import { SourceMapConsumer, RawSourceMap } from 'source-map'
 
 // Integration tests for parser + transform + codegen
-test('basic source map support', async () => {
-  const source = `hello {{ world }}`
+test('function mode', async () => {
+  const source = `
+<div id="foo" :class="bar">
+  {{ world }}
+  <div v-if="ok">yes</div>
+  <template v-else>no</template>
+  <div v-for="(i, j) in list"><span>{{ i + j }}</span></div>
+</div>
+`.trim()
   const { code, map } = compile(source, {
     sourceMap: true,
     filename: `foo.vue`
   })
-  expect(code).toMatch(
-    `const _Vue = Vue
-return function render() {
-  with (this) {
-    const { toString } = _Vue
-    return [
-      "hello ",
-      toString(world)
-    ]
-  }
-}`
-  )
 
+  expect(code).toMatchSnapshot()
   expect(map!.sources).toEqual([`foo.vue`])
   expect(map!.sourcesContent).toEqual([source])
 
   const consumer = await new SourceMapConsumer(map as RawSourceMap)
-  const pos = consumer.originalPositionFor({
-    line: 7,
-    column: 16
+
+  // id=
+  expect(
+    consumer.originalPositionFor({
+      line: 6,
+      column: 6
+    })
+  ).toMatchObject({
+    line: 1,
+    column: 5
+  })
+
+  // "foo"
+  expect(
+    consumer.originalPositionFor({
+      line: 6,
+      column: 10
+    })
+  ).toMatchObject({
+    line: 1,
+    column: 8
+  })
+
+  // :class=
+  expect(
+    consumer.originalPositionFor({
+      line: 7,
+      column: 6
+    })
+  ).toMatchObject({
+    line: 1,
+    column: 15
   })
-  expect(pos).toMatchObject({
+  // bar
+  expect(
+    consumer.originalPositionFor({
+      line: 7,
+      column: 13
+    })
+  ).toMatchObject({
     line: 1,
-    column: 6
+    column: 22
+  })
+
+  // {{ world }}
+  expect(
+    consumer.originalPositionFor({
+      line: 9,
+      column: 16
+    })
+  ).toMatchObject({
+    line: 2,
+    column: 2
+  })
+
+  // ok
+  expect(
+    consumer.originalPositionFor({
+      line: 10,
+      column: 6
+    })
+  ).toMatchObject({
+    line: 3,
+    column: 13
+  })
+
+  // i
+  expect(
+    consumer.originalPositionFor({
+      line: 13,
+      column: 25
+    })
+  ).toMatchObject({
+    line: 5,
+    column: 15
+  })
+
+  // j
+  expect(
+    consumer.originalPositionFor({
+      line: 13,
+      column: 28
+    })
+  ).toMatchObject({
+    line: 5,
+    column: 18
+  })
+
+  // list
+  expect(
+    consumer.originalPositionFor({
+      line: 13,
+      column: 18
+    })
+  ).toMatchObject({
+    line: 5,
+    column: 24
+  })
+
+  // i + j
+  expect(
+    consumer.originalPositionFor({
+      line: 14,
+      column: 81
+    })
+  ).toMatchObject({
+    line: 5,
+    column: 36
   })
 })
+
+test.todo('function mode w/ prefixIdentifiers: true')
+
+test.todo('module mode')
+
+test.todo('module mode w/ prefixIdentifiers: true')
index 692f89bd8f77071e12c233f8a284f8718624e058..d948f9ef90a66c531d76242c4985c7df79e63bd5 100644 (file)
@@ -894,8 +894,8 @@ describe('compiler: parse', () => {
           isStatic: false,
           isInterpolation: false,
           loc: {
-            start: { offset: 10, line: 1, column: 11 },
-            end: { offset: 13, line: 1, column: 14 },
+            start: { offset: 11, line: 1, column: 12 },
+            end: { offset: 12, line: 1, column: 13 },
             source: '"a"'
           }
         },
@@ -1303,25 +1303,27 @@ describe('compiler: parse', () => {
 
   test('parse with correct location info', () => {
     const [foo, bar, but, baz] = parse(
-      'foo \n is {{ bar }} but {{ baz }}'
+      `
+foo
+ is {{ bar }} but {{ baz }}`.trim()
     ).children
 
     let offset = 0
     expect(foo.loc.start).toEqual({ line: 1, column: 1, offset })
     offset += foo.loc.source.length
-    expect(foo.loc.end).toEqual({ line: 2, column: 4, offset })
+    expect(foo.loc.end).toEqual({ line: 2, column: 5, offset })
 
-    expect(bar.loc.start).toEqual({ line: 2, column: 4, offset })
+    expect(bar.loc.start).toEqual({ line: 2, column: 5, offset })
     offset += bar.loc.source.length
-    expect(bar.loc.end).toEqual({ line: 2, column: 13, offset })
+    expect(bar.loc.end).toEqual({ line: 2, column: 14, offset })
 
-    expect(but.loc.start).toEqual({ line: 2, column: 13, offset })
+    expect(but.loc.start).toEqual({ line: 2, column: 14, offset })
     offset += but.loc.source.length
-    expect(but.loc.end).toEqual({ line: 2, column: 18, offset })
+    expect(but.loc.end).toEqual({ line: 2, column: 19, offset })
 
-    expect(baz.loc.start).toEqual({ line: 2, column: 18, offset })
+    expect(baz.loc.start).toEqual({ line: 2, column: 19, offset })
     offset += baz.loc.source.length
-    expect(baz.loc.end).toEqual({ line: 2, column: 27, offset })
+    expect(baz.loc.end).toEqual({ line: 2, column: 28, offset })
   })
 
   describe('namedCharacterReferences option', () => {
index 1723d0f624ef2c5b45406dd63492049703041d30..eb11cda61faf317f52e00a4f07fdffc2da30215d 100644 (file)
@@ -3,8 +3,7 @@ import {
   CompilerOptions,
   parse,
   transform,
-  ErrorCodes,
-  compile
+  ErrorCodes
 } from '../../src'
 import { transformElement } from '../../src/transforms/transformElement'
 import {
@@ -74,7 +73,7 @@ describe('compiler: element transform', () => {
     const { root, node } = parseWithElementTransform(
       `<div id="foo" class="bar" />`
     )
-    expect(node.callee).toBe(CREATE_VNODE)
+    expect(node.callee).toBe(`_${CREATE_VNODE}`)
     // should hoist the static object
     expect(root.hoists).toMatchObject([
       createStaticObjectMatcher({
@@ -95,7 +94,7 @@ describe('compiler: element transform', () => {
     const { root, node } = parseWithElementTransform(
       `<div id="foo"><span/></div>`
     )
-    expect(node.callee).toBe(CREATE_VNODE)
+    expect(node.callee).toBe(`_${CREATE_VNODE}`)
     expect(root.hoists).toMatchObject([
       createStaticObjectMatcher({
         id: 'foo'
@@ -112,7 +111,7 @@ describe('compiler: element transform', () => {
           type: NodeTypes.ELEMENT,
           tag: 'span',
           codegenNode: {
-            callee: CREATE_VNODE,
+            callee: `_${CREATE_VNODE}`,
             arguments: [`"span"`]
           }
         }
@@ -122,7 +121,7 @@ describe('compiler: element transform', () => {
 
   test('0 placeholder for children with no props', () => {
     const { node } = parseWithElementTransform(`<div><span/></div>`)
-    expect(node.callee).toBe(CREATE_VNODE)
+    expect(node.callee).toBe(`_${CREATE_VNODE}`)
     expect(node.arguments).toMatchObject([
       `"div"`,
       `0`,
@@ -131,7 +130,7 @@ describe('compiler: element transform', () => {
           type: NodeTypes.ELEMENT,
           tag: 'span',
           codegenNode: {
-            callee: CREATE_VNODE,
+            callee: `_${CREATE_VNODE}`,
             arguments: [`"span"`]
           }
         }
@@ -143,7 +142,7 @@ describe('compiler: element transform', () => {
     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)
+    expect(node.callee).toBe(`_${CREATE_VNODE}`)
     // should directly use `obj` in props position
     expect(node.arguments[1]).toMatchObject({
       type: NodeTypes.EXPRESSION,
@@ -156,10 +155,10 @@ describe('compiler: element transform', () => {
       `<div id="foo" v-bind="obj" />`
     )
     expect(root.imports).toContain(MERGE_PROPS)
-    expect(node.callee).toBe(CREATE_VNODE)
+    expect(node.callee).toBe(`_${CREATE_VNODE}`)
     expect(node.arguments[1]).toMatchObject({
       type: NodeTypes.JS_CALL_EXPRESSION,
-      callee: MERGE_PROPS,
+      callee: `_${MERGE_PROPS}`,
       arguments: [
         createStaticObjectMatcher({
           id: 'foo'
@@ -177,10 +176,10 @@ describe('compiler: element transform', () => {
       `<div v-bind="obj" id="foo" />`
     )
     expect(root.imports).toContain(MERGE_PROPS)
-    expect(node.callee).toBe(CREATE_VNODE)
+    expect(node.callee).toBe(`_${CREATE_VNODE}`)
     expect(node.arguments[1]).toMatchObject({
       type: NodeTypes.JS_CALL_EXPRESSION,
-      callee: MERGE_PROPS,
+      callee: `_${MERGE_PROPS}`,
       arguments: [
         {
           type: NodeTypes.EXPRESSION,
@@ -198,10 +197,10 @@ describe('compiler: element transform', () => {
       `<div id="foo" v-bind="obj" class="bar" />`
     )
     expect(root.imports).toContain(MERGE_PROPS)
-    expect(node.callee).toBe(CREATE_VNODE)
+    expect(node.callee).toBe(`_${CREATE_VNODE}`)
     expect(node.arguments[1]).toMatchObject({
       type: NodeTypes.JS_CALL_EXPRESSION,
-      callee: MERGE_PROPS,
+      callee: `_${MERGE_PROPS}`,
       arguments: [
         createStaticObjectMatcher({
           id: 'foo'
@@ -222,17 +221,17 @@ describe('compiler: element transform', () => {
       `<div id="foo" v-on="obj" class="bar" />`
     )
     expect(root.imports).toContain(MERGE_PROPS)
-    expect(node.callee).toBe(CREATE_VNODE)
+    expect(node.callee).toBe(`_${CREATE_VNODE}`)
     expect(node.arguments[1]).toMatchObject({
       type: NodeTypes.JS_CALL_EXPRESSION,
-      callee: MERGE_PROPS,
+      callee: `_${MERGE_PROPS}`,
       arguments: [
         createStaticObjectMatcher({
           id: 'foo'
         }),
         {
           type: NodeTypes.JS_CALL_EXPRESSION,
-          callee: TO_HANDLERS,
+          callee: `_${TO_HANDLERS}`,
           arguments: [
             {
               type: NodeTypes.EXPRESSION,
@@ -252,17 +251,17 @@ describe('compiler: element transform', () => {
       `<div id="foo" v-on="handlers" v-bind="obj" />`
     )
     expect(root.imports).toContain(MERGE_PROPS)
-    expect(node.callee).toBe(CREATE_VNODE)
+    expect(node.callee).toBe(`_${CREATE_VNODE}`)
     expect(node.arguments[1]).toMatchObject({
       type: NodeTypes.JS_CALL_EXPRESSION,
-      callee: MERGE_PROPS,
+      callee: `_${MERGE_PROPS}`,
       arguments: [
         createStaticObjectMatcher({
           id: 'foo'
         }),
         {
           type: NodeTypes.JS_CALL_EXPRESSION,
-          callee: TO_HANDLERS,
+          callee: `_${TO_HANDLERS}`,
           arguments: [
             {
               type: NodeTypes.EXPRESSION,
@@ -301,7 +300,7 @@ describe('compiler: element transform', () => {
         }
       }
     })
-    expect(node.callee).toBe(CREATE_VNODE)
+    expect(node.callee).toBe(`_${CREATE_VNODE}`)
     expect(node.arguments[1]).toMatchObject({
       type: NodeTypes.JS_OBJECT_EXPRESSION,
       properties: [
@@ -333,11 +332,11 @@ describe('compiler: element transform', () => {
     expect(root.imports).toContain(RESOLVE_DIRECTIVE)
     expect(root.statements[0]).toMatch(`${RESOLVE_DIRECTIVE}("foo")`)
 
-    expect(node.callee).toBe(APPLY_DIRECTIVES)
+    expect(node.callee).toBe(`_${APPLY_DIRECTIVES}`)
     expect(node.arguments).toMatchObject([
       {
         type: NodeTypes.JS_CALL_EXPRESSION,
-        callee: CREATE_VNODE,
+        callee: `_${CREATE_VNODE}`,
         arguments: [
           `"div"`,
           {
@@ -388,7 +387,7 @@ describe('compiler: element transform', () => {
     expect(root.statements[1]).toMatch(`${RESOLVE_DIRECTIVE}("bar")`)
     expect(root.statements[2]).toMatch(`${RESOLVE_DIRECTIVE}("baz")`)
 
-    expect(node.callee).toBe(APPLY_DIRECTIVES)
+    expect(node.callee).toBe(`_${APPLY_DIRECTIVES}`)
     expect(node.arguments).toMatchObject([
       {
         type: NodeTypes.JS_CALL_EXPRESSION
@@ -467,13 +466,7 @@ describe('compiler: element transform', () => {
     ])
   })
 
-  test('props dedupe', () => {
-    const { code } = compile(
-      `<div class="a" :class="b" @click.foo="a" @click.bar="b" style="color: red" />
-      <div id="foo"/>`
-    )
-    console.log(code)
-  })
+  test.todo(`props dedupe`)
 
   test.todo('slot outlets')
 })
index 016efeedd8a8dae9a59bfdb491fd4e04b18a67c1..fb12b20a5270068816a92c0e02212999a37698fb 100644 (file)
@@ -49,11 +49,11 @@ describe('compiler: transform v-bind', () => {
         loc: {
           start: {
             line: 1,
-            column: 16
+            column: 17
           },
           end: {
             line: 1,
-            column: 20
+            column: 19
           }
         }
       },
index 76100fbeb880d1c8f6172c14a6e887b88f220bae..30f54dce4a912412352e8dd0348792f638d374fa 100644 (file)
@@ -212,150 +212,155 @@ describe('compiler: transform v-for', () => {
       const source = '<span v-for="item in items" />'
       const forNode = parseWithForTransform(source)
 
+      const itemOffset = source.indexOf('item')
       expect(forNode.valueAlias!.content).toBe('item')
-      expect(forNode.valueAlias!.loc.start.offset).toBe(
-        source.indexOf('item') - 1
-      )
+      expect(forNode.valueAlias!.loc.start.offset).toBe(itemOffset)
       expect(forNode.valueAlias!.loc.start.line).toBe(1)
-      expect(forNode.valueAlias!.loc.start.column).toBe(source.indexOf('item'))
+      expect(forNode.valueAlias!.loc.start.column).toBe(itemOffset + 1)
       expect(forNode.valueAlias!.loc.end.line).toBe(1)
       expect(forNode.valueAlias!.loc.end.column).toBe(
-        source.indexOf('item') + 4
+        itemOffset + 1 + `item`.length
       )
 
+      const itemsOffset = source.indexOf('items')
       expect(forNode.source.content).toBe('items')
-      expect(forNode.source.loc.start.offset).toBe(source.indexOf('items') - 1)
+      expect(forNode.source.loc.start.offset).toBe(itemsOffset)
       expect(forNode.source.loc.start.line).toBe(1)
-      expect(forNode.source.loc.start.column).toBe(source.indexOf('items'))
+      expect(forNode.source.loc.start.column).toBe(itemsOffset + 1)
       expect(forNode.source.loc.end.line).toBe(1)
-      expect(forNode.source.loc.end.column).toBe(source.indexOf('items') + 5)
+      expect(forNode.source.loc.end.column).toBe(
+        itemsOffset + 1 + `items`.length
+      )
     })
 
     test('bracketed value', () => {
       const source = '<span v-for="( item ) in items" />'
       const forNode = parseWithForTransform(source)
 
+      const itemOffset = source.indexOf('item')
       expect(forNode.valueAlias!.content).toBe('item')
-      expect(forNode.valueAlias!.loc.start.offset).toBe(
-        source.indexOf('item') - 1
-      )
+      expect(forNode.valueAlias!.loc.start.offset).toBe(itemOffset)
       expect(forNode.valueAlias!.loc.start.line).toBe(1)
-      expect(forNode.valueAlias!.loc.start.column).toBe(source.indexOf('item'))
+      expect(forNode.valueAlias!.loc.start.column).toBe(itemOffset + 1)
       expect(forNode.valueAlias!.loc.end.line).toBe(1)
       expect(forNode.valueAlias!.loc.end.column).toBe(
-        source.indexOf('item') + 4
+        itemOffset + 1 + `item`.length
       )
 
+      const itemsOffset = source.indexOf('items')
       expect(forNode.source.content).toBe('items')
-      expect(forNode.source.loc.start.offset).toBe(source.indexOf('items') - 1)
+      expect(forNode.source.loc.start.offset).toBe(itemsOffset)
       expect(forNode.source.loc.start.line).toBe(1)
-      expect(forNode.source.loc.start.column).toBe(source.indexOf('items'))
+      expect(forNode.source.loc.start.column).toBe(itemsOffset + 1)
       expect(forNode.source.loc.end.line).toBe(1)
-      expect(forNode.source.loc.end.column).toBe(source.indexOf('items') + 5)
+      expect(forNode.source.loc.end.column).toBe(
+        itemsOffset + 1 + `items`.length
+      )
     })
 
     test('de-structured value', () => {
       const source = '<span v-for="(  { id, key })in items" />'
       const forNode = parseWithForTransform(source)
 
+      const valueIndex = source.indexOf('{ id, key }')
       expect(forNode.valueAlias!.content).toBe('{ id, key }')
-      expect(forNode.valueAlias!.loc.start.offset).toBe(
-        source.indexOf('{ id, key }') - 1
-      )
+      expect(forNode.valueAlias!.loc.start.offset).toBe(valueIndex)
       expect(forNode.valueAlias!.loc.start.line).toBe(1)
-      expect(forNode.valueAlias!.loc.start.column).toBe(
-        source.indexOf('{ id, key }')
-      )
+      expect(forNode.valueAlias!.loc.start.column).toBe(valueIndex + 1)
       expect(forNode.valueAlias!.loc.end.line).toBe(1)
       expect(forNode.valueAlias!.loc.end.column).toBe(
-        source.indexOf('{ id, key }') + '{ id, key }'.length
+        valueIndex + 1 + '{ id, key }'.length
       )
 
+      const itemsOffset = source.indexOf('items')
       expect(forNode.source.content).toBe('items')
-      expect(forNode.source.loc.start.offset).toBe(source.indexOf('items') - 1)
+      expect(forNode.source.loc.start.offset).toBe(itemsOffset)
       expect(forNode.source.loc.start.line).toBe(1)
-      expect(forNode.source.loc.start.column).toBe(source.indexOf('items'))
+      expect(forNode.source.loc.start.column).toBe(itemsOffset + 1)
       expect(forNode.source.loc.end.line).toBe(1)
-      expect(forNode.source.loc.end.column).toBe(source.indexOf('items') + 5)
+      expect(forNode.source.loc.end.column).toBe(
+        itemsOffset + 1 + `items`.length
+      )
     })
 
     test('bracketed value, key, index', () => {
       const source = '<span v-for="( item, key, index ) in items" />'
       const forNode = parseWithForTransform(source)
 
+      const itemOffset = source.indexOf('item')
       expect(forNode.valueAlias!.content).toBe('item')
-      expect(forNode.valueAlias!.loc.start.offset).toBe(
-        source.indexOf('item') - 1
-      )
+      expect(forNode.valueAlias!.loc.start.offset).toBe(itemOffset)
       expect(forNode.valueAlias!.loc.start.line).toBe(1)
-      expect(forNode.valueAlias!.loc.start.column).toBe(source.indexOf('item'))
+      expect(forNode.valueAlias!.loc.start.column).toBe(itemOffset + 1)
       expect(forNode.valueAlias!.loc.end.line).toBe(1)
       expect(forNode.valueAlias!.loc.end.column).toBe(
-        source.indexOf('item') + 4
+        itemOffset + 1 + `item`.length
       )
 
+      const keyOffset = source.indexOf('key')
       expect(forNode.keyAlias!.content).toBe('key')
-      expect(forNode.keyAlias!.loc.start.offset).toBe(source.indexOf('key') - 1)
+      expect(forNode.keyAlias!.loc.start.offset).toBe(keyOffset)
       expect(forNode.keyAlias!.loc.start.line).toBe(1)
-      expect(forNode.keyAlias!.loc.start.column).toBe(source.indexOf('key'))
+      expect(forNode.keyAlias!.loc.start.column).toBe(keyOffset + 1)
       expect(forNode.keyAlias!.loc.end.line).toBe(1)
-      expect(forNode.keyAlias!.loc.end.column).toBe(source.indexOf('key') + 3)
+      expect(forNode.keyAlias!.loc.end.column).toBe(
+        keyOffset + 1 + `key`.length
+      )
 
+      const indexOffset = source.indexOf('index')
       expect(forNode.objectIndexAlias!.content).toBe('index')
-      expect(forNode.objectIndexAlias!.loc.start.offset).toBe(
-        source.indexOf('index') - 1
-      )
+      expect(forNode.objectIndexAlias!.loc.start.offset).toBe(indexOffset)
       expect(forNode.objectIndexAlias!.loc.start.line).toBe(1)
-      expect(forNode.objectIndexAlias!.loc.start.column).toBe(
-        source.indexOf('index')
-      )
+      expect(forNode.objectIndexAlias!.loc.start.column).toBe(indexOffset + 1)
       expect(forNode.objectIndexAlias!.loc.end.line).toBe(1)
       expect(forNode.objectIndexAlias!.loc.end.column).toBe(
-        source.indexOf('index') + 5
+        indexOffset + 1 + `index`.length
       )
 
+      const itemsOffset = source.indexOf('items')
       expect(forNode.source.content).toBe('items')
-      expect(forNode.source.loc.start.offset).toBe(source.indexOf('items') - 1)
+      expect(forNode.source.loc.start.offset).toBe(itemsOffset)
       expect(forNode.source.loc.start.line).toBe(1)
-      expect(forNode.source.loc.start.column).toBe(source.indexOf('items'))
+      expect(forNode.source.loc.start.column).toBe(itemsOffset + 1)
       expect(forNode.source.loc.end.line).toBe(1)
-      expect(forNode.source.loc.end.column).toBe(source.indexOf('items') + 5)
+      expect(forNode.source.loc.end.column).toBe(
+        itemsOffset + 1 + `items`.length
+      )
     })
 
     test('skipped key', () => {
       const source = '<span v-for="( item,, index ) in items" />'
       const forNode = parseWithForTransform(source)
 
+      const itemOffset = source.indexOf('item')
       expect(forNode.valueAlias!.content).toBe('item')
-      expect(forNode.valueAlias!.loc.start.offset).toBe(
-        source.indexOf('item') - 1
-      )
+      expect(forNode.valueAlias!.loc.start.offset).toBe(itemOffset)
       expect(forNode.valueAlias!.loc.start.line).toBe(1)
-      expect(forNode.valueAlias!.loc.start.column).toBe(source.indexOf('item'))
+      expect(forNode.valueAlias!.loc.start.column).toBe(itemOffset + 1)
       expect(forNode.valueAlias!.loc.end.line).toBe(1)
       expect(forNode.valueAlias!.loc.end.column).toBe(
-        source.indexOf('item') + 4
+        itemOffset + 1 + `item`.length
       )
 
+      const indexOffset = source.indexOf('index')
       expect(forNode.objectIndexAlias!.content).toBe('index')
-      expect(forNode.objectIndexAlias!.loc.start.offset).toBe(
-        source.indexOf('index') - 1
-      )
+      expect(forNode.objectIndexAlias!.loc.start.offset).toBe(indexOffset)
       expect(forNode.objectIndexAlias!.loc.start.line).toBe(1)
-      expect(forNode.objectIndexAlias!.loc.start.column).toBe(
-        source.indexOf('index')
-      )
+      expect(forNode.objectIndexAlias!.loc.start.column).toBe(indexOffset + 1)
       expect(forNode.objectIndexAlias!.loc.end.line).toBe(1)
       expect(forNode.objectIndexAlias!.loc.end.column).toBe(
-        source.indexOf('index') + 5
+        indexOffset + 1 + `index`.length
       )
 
+      const itemsOffset = source.indexOf('items')
       expect(forNode.source.content).toBe('items')
-      expect(forNode.source.loc.start.offset).toBe(source.indexOf('items') - 1)
+      expect(forNode.source.loc.start.offset).toBe(itemsOffset)
       expect(forNode.source.loc.start.line).toBe(1)
-      expect(forNode.source.loc.start.column).toBe(source.indexOf('items'))
+      expect(forNode.source.loc.start.column).toBe(itemsOffset + 1)
       expect(forNode.source.loc.end.line).toBe(1)
-      expect(forNode.source.loc.end.column).toBe(source.indexOf('items') + 5)
+      expect(forNode.source.loc.end.column).toBe(
+        itemsOffset + 1 + `items`.length
+      )
     })
   })
 })
index 2c6ddc46324aa9c2b95be229013f5e1f13061000..a9da468896da29d07766f401b57fcb0739db49fe 100644 (file)
@@ -29,9 +29,7 @@ describe('compiler: transform v-if', () => {
   test('basic v-if', () => {
     const node = parseWithIfTransform(`<div v-if="ok"/>`)
     expect(node.type).toBe(NodeTypes.IF)
-    expect(node.isRoot).toBe(true)
     expect(node.branches.length).toBe(1)
-    expect(node.branches[0].isRoot).toBe(true)
     expect(node.branches[0].condition!.content).toBe(`ok`)
     expect(node.branches[0].children.length).toBe(1)
     expect(node.branches[0].children[0].type).toBe(NodeTypes.ELEMENT)
index 713b34be59b55d903d687e0d3f1cd8d88fa7bd7a..2f2f131e6b4f48d262384145f3b8b171ec37b4f5 100644 (file)
@@ -50,11 +50,11 @@ describe('compiler: transform v-bind', () => {
         loc: {
           start: {
             line: 1,
-            column: 17
+            column: 18
           },
           end: {
             line: 1,
-            column: 26
+            column: 25
           }
         }
       },
index c83ce2261f86083c153f8a153180186971385640..b5d1bea04c95f2b894ea1b0768579e295337d86a 100644 (file)
@@ -28,7 +28,7 @@ describe('advancePositionWithClone', () => {
     const pos = p(1, 1, 0)
     const newPos = advancePositionWithClone(pos, 'foo\nbar\nbaz', 10)
 
-    expect(newPos.column).toBe(2)
+    expect(newPos.column).toBe(3)
     expect(newPos.line).toBe(3)
     expect(newPos.offset).toBe(10)
   })
@@ -62,7 +62,7 @@ describe('getInnerRange', () => {
     expect(loc2.start.column).toBe(1)
     expect(loc2.start.line).toBe(2)
     expect(loc2.start.offset).toBe(4)
-    expect(loc2.end.column).toBe(3)
+    expect(loc2.end.column).toBe(4)
     expect(loc2.end.line).toBe(2)
     expect(loc2.end.offset).toBe(7)
   })
index 786cdfd4dd04be32a84a9333349802567e099c3e..d9b3cbc4c455fd90a47e19710d1b2d591acc2ec6 100644 (file)
@@ -118,14 +118,12 @@ export interface ExpressionNode extends Node {
 export interface IfNode extends Node {
   type: NodeTypes.IF
   branches: IfBranchNode[]
-  isRoot: boolean
 }
 
 export interface IfBranchNode extends Node {
   type: NodeTypes.IF_BRANCH
   condition: ExpressionNode | undefined // else
   children: ChildNode[]
-  isRoot: boolean
 }
 
 export interface ForNode extends Node {
index 84e5a5d74a93c3d877052ec5afa65e3d3c85dfdc..c851d9567880a6d21b210ff3b639b5f5490247fc 100644 (file)
@@ -65,6 +65,7 @@ export interface CodegenContext extends Required<CodegenOptions> {
   offset: number
   indentLevel: number
   map?: SourceMapGenerator
+  helper(name: string): string
   push(code: string, node?: CodegenNode): void
   indent(): void
   deindent(withoutNewLine?: boolean): void
@@ -98,11 +99,14 @@ function createCodegenContext(
         ? undefined
         : new (require('source-map')).SourceMapGenerator(),
 
+    helper(name) {
+      return prefixIdentifiers ? name : `_${name}`
+    },
     push(code, node?: CodegenNode) {
       context.code += code
       if (context.map) {
         if (node) {
-          context.map.addMapping({
+          const mapping = {
             source: context.filename,
             original: {
               line: node.loc.start.line,
@@ -112,9 +116,10 @@ function createCodegenContext(
               line: context.line,
               column: context.column - 1
             }
-          })
+          }
+          context.map.addMapping(mapping)
         }
-        advancePositionWithMutation(context, code, code.length)
+        advancePositionWithMutation(context, code)
       }
     },
     indent() {
@@ -144,7 +149,7 @@ export function generate(
 ): CodegenResult {
   const context = createCodegenContext(ast, options)
   const { mode, push, prefixIdentifiers, indent, deindent, newline } = context
-  const imports = ast.imports.join(', ')
+  const hasImports = ast.imports.length
 
   // preambles
   if (mode === 'function') {
@@ -152,9 +157,9 @@ export function generate(
     // In prefix mode, we place the const declaration at top so it's done
     // only once; But if we not prefixing, we place the decalration inside the
     // with block so it doesn't incur the `in` check cost for every helper access.
-    if (imports) {
+    if (hasImports) {
       if (prefixIdentifiers) {
-        push(`const { ${imports} } = Vue\n`)
+        push(`const { ${ast.imports.join(', ')} } = Vue\n`)
       } else {
         // save Vue in a separate variable to avoid collision
         push(`const _Vue = Vue`)
@@ -164,8 +169,8 @@ export function generate(
     push(`return `)
   } else {
     // generate import statements for helpers
-    if (imports) {
-      push(`import { ${imports} } from 'vue'\n`)
+    if (hasImports) {
+      push(`import { ${ast.imports.join(', ')} } from 'vue'\n`)
     }
     genHoists(ast.hoists, context)
     push(`export default `)
@@ -179,8 +184,9 @@ export function generate(
     push(`with (this) {`)
     indent()
     // function mode const declarations should be inside with block
-    if (mode === 'function' && imports) {
-      push(`const { ${imports} } = _Vue`)
+    // also they should be renamed to avoid collision with user properties
+    if (mode === 'function' && hasImports) {
+      push(`const { ${ast.imports.map(n => `${n}: _${n}`).join(', ')} } = _Vue`)
       newline()
     }
   } else {
@@ -199,7 +205,7 @@ export function generate(
 
   // generate the VNode tree expression
   push(`return `)
-  genChildren(ast.children, context, true /* asRoot */)
+  genChildren(ast.children, context, true)
   if (!prefixIdentifiers) {
     deindent()
     push(`}`)
@@ -223,13 +229,12 @@ function genHoists(hoists: JSChildNode[], context: CodegenContext) {
 }
 
 // This will generate a single vnode call if:
-// - The list has length === 1, AND:
-// - This is a root node, OR:
-// - The only child is a text or expression.
+// - The target position explicitly allows a single node (root, if, for)
+// - The list has length === 1, AND The only child is a text or expression.
 function genChildren(
   children: ChildNode[],
   context: CodegenContext,
-  asRoot: boolean = false
+  allowSingle: boolean = false
 ) {
   if (!children.length) {
     return context.push(`null`)
@@ -237,7 +242,7 @@ function genChildren(
   const child = children[0]
   if (
     children.length === 1 &&
-    (asRoot ||
+    (allowSingle ||
       child.type === NodeTypes.TEXT ||
       child.type == NodeTypes.EXPRESSION)
   ) {
@@ -336,10 +341,10 @@ function genText(node: TextNode | ExpressionNode, context: CodegenContext) {
 }
 
 function genExpression(node: ExpressionNode, context: CodegenContext) {
-  const { push } = context
+  const { push, helper } = context
   const { content, children, isStatic, isInterpolation } = node
   if (isInterpolation) {
-    push(`${TO_STRING}(`)
+    push(`${helper(TO_STRING)}(`)
   }
   if (children) {
     genCompoundExpression(node, context)
@@ -383,8 +388,11 @@ function genCompoundExpression(node: ExpressionNode, context: CodegenContext) {
 
 function genComment(node: CommentNode, context: CodegenContext) {
   if (__DEV__) {
-    context.push(
-      `${CREATE_VNODE}(${COMMENT}, 0, ${JSON.stringify(node.content)})`,
+    const { push, helper } = context
+    push(
+      `${helper(CREATE_VNODE)}(${helper(COMMENT)}, 0, ${JSON.stringify(
+        node.content
+      )})`,
       node
     )
   }
@@ -396,7 +404,7 @@ function genIf(node: IfNode, context: CodegenContext) {
 }
 
 function genIfBranch(
-  { condition, children, isRoot }: IfBranchNode,
+  { condition, children }: IfBranchNode,
   branches: IfBranchNode[],
   nextIndex: number,
   context: CodegenContext
@@ -411,7 +419,7 @@ function genIfBranch(
     indent()
     context.indentLevel++
     push(`? `)
-    genChildren(children, context, isRoot)
+    genChildren(children, context, true)
     context.indentLevel--
     newline()
     push(`: `)
@@ -424,14 +432,14 @@ function genIfBranch(
   } else {
     // v-else
     __DEV__ && assert(nextIndex === branches.length)
-    genChildren(children, context, isRoot)
+    genChildren(children, context, true)
   }
 }
 
 function genFor(node: ForNode, context: CodegenContext) {
-  const { push } = context
+  const { push, helper, indent, deindent } = context
   const { source, keyAlias, valueAlias, objectIndexAlias, children } = node
-  push(`${RENDER_LIST}(`, node)
+  push(`${helper(RENDER_LIST)}(`, node)
   genExpression(source, context)
   push(`, (`)
   if (valueAlias) {
@@ -455,9 +463,12 @@ function genFor(node: ForNode, context: CodegenContext) {
     push(`, `)
     genExpression(objectIndexAlias, context)
   }
-  push(`) => `)
-  genChildren(children, context)
-  push(`)`)
+  push(`) => {`)
+  indent()
+  push(`return `)
+  genChildren(children, context, true)
+  deindent()
+  push(`})`)
 }
 
 // JavaScript
index e80480fba8fa223ddc9fe51668b5fd2bd197325b..b153bab0f0cd4dbe18a0024ea2d89fbbb9ff99d8 100644 (file)
@@ -479,7 +479,14 @@ function parseAttribute(
   advanceBy(context, name.length)
 
   // Value
-  let value: { content: string; loc: SourceLocation } | undefined = undefined
+  let value:
+    | {
+        content: string
+        isQuoted: boolean
+        loc: SourceLocation
+      }
+    | undefined = undefined
+
   if (/^[\t\r\n\f ]*=/.test(context.source)) {
     advanceSpaces(context)
     advanceBy(context, 1)
@@ -530,6 +537,13 @@ function parseAttribute(
       }
     }
 
+    if (value && value.isQuoted) {
+      const valueLoc = value.loc
+      valueLoc.start.offset++
+      valueLoc.start.column++
+      valueLoc.end = advancePositionWithClone(valueLoc.start, value.content)
+    }
+
     return {
       type: NodeTypes.DIRECTIVE,
       name:
@@ -567,13 +581,20 @@ function parseAttribute(
 
 function parseAttributeValue(
   context: ParserContext
-): { content: string; loc: SourceLocation } | undefined {
+):
+  | {
+      content: string
+      isQuoted: boolean
+      loc: SourceLocation
+    }
+  | undefined {
   const start = getCursor(context)
   let content: string
 
-  if (/^["']/.test(context.source)) {
+  const quote = context.source[0]
+  const isQuoted = quote === `"` || quote === `'`
+  if (isQuoted) {
     // Quoted value.
-    const quote = context.source[0]
     advanceBy(context, 1)
 
     const endIndex = context.source.indexOf(quote)
@@ -605,7 +626,7 @@ function parseAttributeValue(
     content = parseTextData(context, match[0].length, TextModes.ATTRIBUTE_VALUE)
   }
 
-  return { content, loc: getSelection(context, start) }
+  return { content, isQuoted, loc: getSelection(context, start) }
 }
 
 function parseInterpolation(
index ad62b402b6abbdf175fcd17185ab32c4317d3982..a7714b5c31fe35c8096a7be7d32630faefc3e0b8 100644 (file)
@@ -59,6 +59,7 @@ export interface TransformContext extends Required<TransformOptions> {
   parent: ParentNode
   childIndex: number
   currentNode: ChildNode | null
+  helper(name: string): string
   replaceNode(node: ChildNode): void
   removeNode(node?: ChildNode): void
   onNodeRemoved: () => void
@@ -89,6 +90,10 @@ function createTransformContext(
     parent: root,
     childIndex: 0,
     currentNode: null,
+    helper(name) {
+      context.imports.add(name)
+      return prefixIdentifiers ? name : `_${name}`
+    },
     replaceNode(node) {
       /* istanbul ignore if */
       if (__DEV__ && !context.currentNode) {
@@ -195,15 +200,15 @@ export function traverseNode(node: ChildNode, context: TransformContext) {
 
   switch (node.type) {
     case NodeTypes.COMMENT:
-      context.imports.add(CREATE_VNODE)
+      context.helper(CREATE_VNODE)
       // inject import for the Comment symbol, which is needed for creating
       // comment nodes with `createVNode`
-      context.imports.add(COMMENT)
+      context.helper(COMMENT)
       break
     case NodeTypes.EXPRESSION:
       // no need to traverse, but we need to inject toString helper
       if (node.isInterpolation) {
-        context.imports.add(TO_STRING)
+        context.helper(TO_STRING)
       }
       break
 
index a28a9e1eafa00a53380530159477e6b0231387ea..e346afbd1ebe4f365ccab99571a1a31de6f226a6 100644 (file)
@@ -42,12 +42,11 @@ export const transformElement: NodeTransform = (node, context) => {
       let componentIdentifier: string | undefined
 
       if (isComponent) {
-        context.imports.add(RESOLVE_COMPONENT)
         componentIdentifier = `_component_${toValidId(node.tag)}`
         context.statements.push(
-          `const ${componentIdentifier} = ${RESOLVE_COMPONENT}(${JSON.stringify(
-            node.tag
-          )})`
+          `const ${componentIdentifier} = ${context.helper(
+            RESOLVE_COMPONENT
+          )}(${JSON.stringify(node.tag)})`
         )
       }
 
@@ -70,13 +69,15 @@ export const transformElement: NodeTransform = (node, context) => {
       }
 
       const { loc } = node
-      context.imports.add(CREATE_VNODE)
-      const vnode = createCallExpression(CREATE_VNODE, args, loc)
+      const vnode = createCallExpression(
+        context.helper(CREATE_VNODE),
+        args,
+        loc
+      )
 
       if (runtimeDirectives && runtimeDirectives.length) {
-        context.imports.add(APPLY_DIRECTIVES)
         node.codegenNode = createCallExpression(
-          APPLY_DIRECTIVES,
+          context.helper(APPLY_DIRECTIVES),
           [
             vnode,
             createArrayExpression(
@@ -147,11 +148,10 @@ function buildProps(
             mergeArgs.push(exp)
           } else {
             // v-on="obj" -> toHandlers(obj)
-            context.imports.add(TO_HANDLERS)
             mergeArgs.push({
               type: NodeTypes.JS_CALL_EXPRESSION,
               loc,
-              callee: TO_HANDLERS,
+              callee: context.helper(TO_HANDLERS),
               arguments: [exp]
             })
           }
@@ -197,8 +197,11 @@ function buildProps(
       )
     }
     if (mergeArgs.length > 1) {
-      context.imports.add(MERGE_PROPS)
-      propsExpression = createCallExpression(MERGE_PROPS, mergeArgs, elementLoc)
+      propsExpression = createCallExpression(
+        context.helper(MERGE_PROPS),
+        mergeArgs,
+        elementLoc
+      )
     } else {
       // single v-bind with nothing else - no need for a mergeProps call
       propsExpression = mergeArgs[0]
@@ -285,12 +288,12 @@ function createDirectiveArgs(
   dir: DirectiveNode,
   context: TransformContext
 ): ArrayExpression {
-  // inject import for `resolveDirective`
-  context.imports.add(RESOLVE_DIRECTIVE)
   // inject statement for resolving directive
   const dirIdentifier = `_directive_${toValidId(dir.name)}`
   context.statements.push(
-    `const ${dirIdentifier} = ${RESOLVE_DIRECTIVE}(${JSON.stringify(dir.name)})`
+    `const ${dirIdentifier} = ${context.helper(
+      RESOLVE_DIRECTIVE
+    )}(${JSON.stringify(dir.name)})`
   )
   const dirArgs: ArrayExpression['elements'] = [dirIdentifier]
   const { loc } = dir
index b1cf727aacb8cf8ae9faa2535af025bd8c212239..04c6bf34dd3e553cfd7d62197cfde9f0fc35a480 100644 (file)
@@ -24,7 +24,7 @@ export const transformFor = createStructuralDirectiveTransform(
       const parseResult = parseForExpression(dir.exp, context)
 
       if (parseResult) {
-        context.imports.add(RENDER_LIST)
+        context.helper(RENDER_LIST)
         const { source, value, key, index } = parseResult
 
         context.replaceNode({
index 70120d5f1dab9f99fa7dee401090e49d234dfe34..1d8fe08aaf6db6aa08c9a42f9f27b45a754aab9a 100644 (file)
@@ -19,14 +19,10 @@ export const transformIf = createStructuralDirectiveTransform(
       processExpression(dir.exp, context)
     }
     if (dir.name === 'if') {
-      // check if this v-if is root - so that in codegen we can avoid generating
-      // arrays for each branch
-      const isRoot = context.parent === context.root
       context.replaceNode({
         type: NodeTypes.IF,
         loc: node.loc,
-        branches: [createIfBranch(node, dir, isRoot)],
-        isRoot
+        branches: [createIfBranch(node, dir)]
       })
     } else {
       // locate the adjacent v-if
@@ -43,7 +39,7 @@ export const transformIf = createStructuralDirectiveTransform(
         if (sibling && sibling.type === NodeTypes.IF) {
           // move the node to the if node's branches
           context.removeNode()
-          const branch = createIfBranch(node, dir, sibling.isRoot)
+          const branch = createIfBranch(node, dir)
           if (__DEV__ && comments.length) {
             branch.children = [...comments, ...branch.children]
           }
@@ -67,16 +63,11 @@ export const transformIf = createStructuralDirectiveTransform(
   }
 )
 
-function createIfBranch(
-  node: ElementNode,
-  dir: DirectiveNode,
-  isRoot: boolean
-): IfBranchNode {
+function createIfBranch(node: ElementNode, dir: DirectiveNode): IfBranchNode {
   return {
     type: NodeTypes.IF_BRANCH,
     loc: node.loc,
     condition: dir.name === 'else' ? undefined : dir.exp,
-    children: node.tagType === ElementTypes.TEMPLATE ? node.children : [node],
-    isRoot
+    children: node.tagType === ElementTypes.TEMPLATE ? node.children : [node]
   }
 }
index f857f629edd48e13e2cb2b21cb4de56a434bb931..2745b041ca181f0db8c7dab25d0e61e86a59a860 100644 (file)
@@ -31,7 +31,7 @@ export function getInnerRange(
 export function advancePositionWithClone(
   pos: Position,
   source: string,
-  numberOfCharacters: number
+  numberOfCharacters: number = source.length
 ): Position {
   return advancePositionWithMutation({ ...pos }, source, numberOfCharacters)
 }
@@ -41,7 +41,7 @@ export function advancePositionWithClone(
 export function advancePositionWithMutation(
   pos: Position,
   source: string,
-  numberOfCharacters: number
+  numberOfCharacters: number = source.length
 ): Position {
   let linesCount = 0
   let lastNewLinePos = -1
@@ -57,7 +57,7 @@ export function advancePositionWithMutation(
   pos.column =
     lastNewLinePos === -1
       ? pos.column + numberOfCharacters
-      : Math.max(1, numberOfCharacters - lastNewLinePos - 1)
+      : Math.max(1, numberOfCharacters - lastNewLinePos)
 
   return pos
 }