]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(compiler): improve auto prefixing cases
authorEvan You <yyx990803@gmail.com>
Sat, 28 Sep 2019 03:20:26 +0000 (23:20 -0400)
committerEvan You <yyx990803@gmail.com>
Sat, 28 Sep 2019 03:20:26 +0000 (23:20 -0400)
packages/compiler-core/__tests__/transforms/transformExpressions.spec.ts
packages/compiler-core/src/transforms/transformExpression.ts

index 2c9809a2b02ddd3f7cddd5d28e963b465d331977..6e80abed36c78ceb6a5058a22a9e822921f1c924 100644 (file)
@@ -308,6 +308,59 @@ describe('compiler: expression transform', () => {
     })
   })
 
+  test('should prefix default value of a function expression param', () => {
+    const node = parseWithExpressionTransform(
+      `{{ (foo = baz) => foo + bar }}`
+    ) as InterpolationNode
+    expect(node.content).toMatchObject({
+      type: NodeTypes.COMPOUND_EXPRESSION,
+      children: [
+        `(`,
+        { content: `foo` },
+        ` = `,
+        { content: `_ctx.baz` },
+        `) => `,
+        { content: `foo` },
+        ` + `,
+        { content: `_ctx.bar` }
+      ]
+    })
+  })
+
+  test('should not prefix function param destructuring', () => {
+    const node = parseWithExpressionTransform(
+      `{{ ({ foo }) => foo + bar }}`
+    ) as InterpolationNode
+    expect(node.content).toMatchObject({
+      type: NodeTypes.COMPOUND_EXPRESSION,
+      children: [
+        `({ foo }) => `,
+        { content: `foo` },
+        ` + `,
+        { content: `_ctx.bar` }
+      ]
+    })
+  })
+
+  test('should prefix default value of function param destructuring', () => {
+    const node = parseWithExpressionTransform(
+      `{{ ({ foo = bar }) => foo + bar }}`
+    ) as InterpolationNode
+    expect(node.content).toMatchObject({
+      type: NodeTypes.COMPOUND_EXPRESSION,
+      children: [
+        `({ `,
+        { content: `foo` },
+        ` = `,
+        { content: `_ctx.bar` },
+        ` }) => `,
+        { content: `foo` },
+        ` + `,
+        { content: `_ctx.bar` }
+      ]
+    })
+  })
+
   test('should not prefix an object property key', () => {
     const node = parseWithExpressionTransform(
       `{{ { foo: bar } }}`
index 7555807050c0002a5ce2ab433654d0c27adfb671..35a076cb42c60bd38196fd51cef82a5a0a3351ae 100644 (file)
@@ -20,7 +20,7 @@ import {
   createCompoundExpression
 } from '../ast'
 import { Node, Function, Identifier, Property } from 'estree'
-import { advancePositionWithClone } from '../utils'
+import { advancePositionWithClone, isSimpleIdentifier } from '../utils'
 
 export const transformExpression: NodeTransform = (node, context) => {
   if (node.type === NodeTypes.INTERPOLATION) {
@@ -31,19 +31,19 @@ export const transformExpression: NodeTransform = (node, context) => {
   } else if (node.type === NodeTypes.ELEMENT) {
     // handle directives on element
     for (let i = 0; i < node.props.length; i++) {
-      const prop = node.props[i]
-      if (prop.type === NodeTypes.DIRECTIVE) {
-        const exp = prop.exp as SimpleExpressionNode | undefined
-        const arg = prop.arg as SimpleExpressionNode | undefined
+      const dir = node.props[i]
+      if (dir.type === NodeTypes.DIRECTIVE) {
+        const exp = dir.exp as SimpleExpressionNode | undefined
+        const arg = dir.arg as SimpleExpressionNode | undefined
         if (exp) {
-          prop.exp = processExpression(exp, context)
+          dir.exp = processExpression(exp, context, dir.name === 'slot')
         }
         if (arg && !arg.isStatic) {
-          if (prop.name === 'class') {
+          if (dir.name === 'class') {
             // TODO special expression optimization for classes
-            prop.arg = processExpression(arg, context)
+            dir.arg = processExpression(arg, context)
           } else {
-            prop.arg = processExpression(arg, context)
+            dir.arg = processExpression(arg, context)
           }
         }
       }
@@ -51,14 +51,6 @@ export const transformExpression: NodeTransform = (node, context) => {
   }
 }
 
-const simpleIdRE = /^[a-zA-Z$_][\w$]*$/
-
-const isFunction = (node: Node): node is Function =>
-  /Function(Expression|Declaration)$/.test(node.type)
-
-const isPropertyKey = (node: Node, parent: Node) =>
-  parent.type === 'Property' && parent.key === node && !parent.computed
-
 // cache node requires
 let _parseScript: typeof parseScript
 let _walk: typeof walk
@@ -74,14 +66,15 @@ interface PrefixMeta {
 // tree-shaken from the browser build.
 export function processExpression(
   node: SimpleExpressionNode,
-  context: TransformContext
+  context: TransformContext,
+  asParams: boolean = false
 ): ExpressionNode {
   if (!context.prefixIdentifiers) {
     return node
   }
 
   // fast path if expression is a simple identifier.
-  if (simpleIdRE.test(node.content)) {
+  if (isSimpleIdentifier(node.content)) {
     if (!context.identifiers[node.content]) {
       node.content = `_ctx.${node.content}`
     }
@@ -95,8 +88,11 @@ export function processExpression(
   const walk = _walk || (_walk = require('estree-walker').walk)
 
   let ast
+  // if the expression is supposed to be used in a function params position
+  // we need to parse it differently.
+  const source = `(${node.content})${asParams ? `=>{}` : ``}`
   try {
-    ast = parseScript(`(${node.content})`, { ranges: true }) as any
+    ast = parseScript(source, { ranges: true }) as any
   } catch (e) {
     context.onError(e)
     return node
@@ -132,8 +128,17 @@ export function processExpression(
         // so that we don't prefix them
         node.params.forEach(p =>
           walk(p, {
-            enter(child) {
-              if (child.type === 'Identifier') {
+            enter(child, parent) {
+              if (
+                child.type === 'Identifier' &&
+                !// do not keep as scope variable if this is a default value
+                // assignment of a param
+                (
+                  parent &&
+                  parent.type === 'AssignmentPattern' &&
+                  parent.right === child
+                )
+              ) {
                 knownIds[child.name] = true
                 ;(
                   (node as any)._scopeIds ||
@@ -187,6 +192,12 @@ export function processExpression(
   }
 }
 
+const isFunction = (node: Node): node is Function =>
+  /Function(Expression|Declaration)$/.test(node.type)
+
+const isPropertyKey = (node: Node, parent: Node) =>
+  parent.type === 'Property' && parent.key === node && !parent.computed
+
 const globals = new Set(
   (
     'Infinity,undefined,NaN,isFinite,isNaN,' +