]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(compiler-core): fix prefixing for `<template v-for>` key expressions
authorEvan You <yyx990803@gmail.com>
Mon, 14 Sep 2020 21:04:27 +0000 (17:04 -0400)
committerEvan You <yyx990803@gmail.com>
Mon, 14 Sep 2020 21:04:27 +0000 (17:04 -0400)
fix #2085

packages/compiler-core/__tests__/transforms/vFor.spec.ts
packages/compiler-core/src/transforms/vFor.ts

index 1fc19c90246cceea79a637b5c8088e9d912c1f6b..411aba2c4610a70de3ef1a749389409d60b12a15 100644 (file)
@@ -582,6 +582,61 @@ describe('compiler: v-for', () => {
         ]
       })
     })
+
+    test('element v-for key expression prefixing', () => {
+      const {
+        node: { codegenNode }
+      } = parseWithForTransform(
+        '<div v-for="item in items" :key="itemKey(item)">test</div>',
+        { prefixIdentifiers: true }
+      )
+      const innerBlock = codegenNode.children.arguments[1].returns
+      expect(innerBlock).toMatchObject({
+        type: NodeTypes.VNODE_CALL,
+        tag: `"div"`,
+        props: createObjectMatcher({
+          key: {
+            type: NodeTypes.COMPOUND_EXPRESSION,
+            children: [
+              // should prefix outer scope references
+              { content: `_ctx.itemKey` },
+              `(`,
+              // should NOT prefix in scope variables
+              { content: `item` },
+              `)`
+            ]
+          }
+        })
+      })
+    })
+
+    // #2085
+    test('template v-for key expression prefixing', () => {
+      const {
+        node: { codegenNode }
+      } = parseWithForTransform(
+        '<template v-for="item in items" :key="itemKey(item)">test</template>',
+        { prefixIdentifiers: true }
+      )
+      const innerBlock = codegenNode.children.arguments[1].returns
+      expect(innerBlock).toMatchObject({
+        type: NodeTypes.VNODE_CALL,
+        tag: FRAGMENT,
+        props: createObjectMatcher({
+          key: {
+            type: NodeTypes.COMPOUND_EXPRESSION,
+            children: [
+              // should prefix outer scope references
+              { content: `_ctx.itemKey` },
+              `(`,
+              // should NOT prefix in scope variables
+              { content: `item` },
+              `)`
+            ]
+          }
+        })
+      })
+    })
   })
 
   describe('codegen', () => {
index 99ab91044631ba63e4f87ed78103d22f32a68797..63c4458c1a99966bca512db2b18da74413fe190f 100644 (file)
@@ -54,6 +54,27 @@ export const transformFor = createStructuralDirectiveTransform(
         forNode.source
       ]) as ForRenderListExpression
       const keyProp = findProp(node, `key`)
+      const keyProperty = keyProp
+        ? createObjectProperty(
+            `key`,
+            keyProp.type === NodeTypes.ATTRIBUTE
+              ? createSimpleExpression(keyProp.value!.content, true)
+              : keyProp.exp!
+          )
+        : null
+
+      if (!__BROWSER__ && context.prefixIdentifiers && keyProperty) {
+        // #2085 process :key expression needs to be processed in order for it
+        // to behave consistently for <template v-for> and <div v-for>.
+        // In the case of `<template v-for>`, the node is discarded and never
+        // traversed so its key expression won't be processed by the normal
+        // transforms.
+        keyProperty.value = processExpression(
+          keyProperty.value as SimpleExpressionNode,
+          context
+        )
+      }
+
       const isStableFragment =
         forNode.source.type === NodeTypes.SIMPLE_EXPRESSION &&
         forNode.source.isConstant
@@ -108,14 +129,7 @@ export const transformFor = createStructuralDirectiveTransform(
             isSlotOutlet(node.children[0])
             ? (node.children[0] as SlotOutletNode) // api-extractor somehow fails to infer this
             : null
-        const keyProperty = keyProp
-          ? createObjectProperty(
-              `key`,
-              keyProp.type === NodeTypes.ATTRIBUTE
-                ? createSimpleExpression(keyProp.value!.content, true)
-                : keyProp.exp!
-            )
-          : null
+
         if (slotOutlet) {
           // <slot v-for="..."> or <template v-for="..."><slot/></template>
           childBlock = slotOutlet.codegenNode as RenderSlotCall