]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix: make sure v-if and v-for work together
authorEvan You <yyx990803@gmail.com>
Mon, 23 Sep 2019 00:55:18 +0000 (20:55 -0400)
committerEvan You <yyx990803@gmail.com>
Mon, 23 Sep 2019 00:55:18 +0000 (20:55 -0400)
packages/compiler-core/src/transform.ts
packages/compiler-core/src/transforms/vIf.ts

index f9bef475e30cb4eb9ad7b6889af79f823bad8b5e..23eefd0d03a3ea8eed4f578c85c353c685e1b126 100644 (file)
@@ -54,7 +54,7 @@ export interface TransformContext extends Required<TransformOptions> {
 
 export function transform(root: RootNode, options: TransformOptions) {
   const context = createTransformContext(root, options)
-  traverseChildren(root, context, context.ancestors)
+  traverseChildren(root, context)
 }
 
 function createTransformContext(
@@ -103,12 +103,11 @@ function createTransformContext(
   return context
 }
 
-function traverseChildren(
+export function traverseChildren(
   parent: ParentNode,
-  context: TransformContext,
-  ancestors: ParentNode[]
+  context: TransformContext
 ) {
-  ancestors = ancestors.concat(parent)
+  const ancestors = context.ancestors.concat(parent)
   let i = 0
   const nodeRemoved = () => {
     i--
@@ -118,39 +117,35 @@ function traverseChildren(
     context.ancestors = ancestors
     context.childIndex = i
     context.onNodeRemoved = nodeRemoved
-    traverseNode((context.currentNode = parent.children[i]), context, ancestors)
+    traverseNode((context.currentNode = parent.children[i]), context)
   }
 }
 
-function traverseNode(
-  node: ChildNode,
-  context: TransformContext,
-  ancestors: ParentNode[]
-) {
+export function traverseNode(node: ChildNode, context: TransformContext) {
   // apply transform plugins
   const { nodeTransforms } = context
   for (let i = 0; i < nodeTransforms.length; i++) {
     const plugin = nodeTransforms[i]
     plugin(node, context)
-    // node may have been replaced
-    node = context.currentNode || node
-  }
-
-  if (!context.currentNode) {
-    // node was removed
-    return
+    if (!context.currentNode) {
+      // node was removed
+      return
+    } else {
+      // node may have been replaced
+      node = context.currentNode
+    }
   }
 
   // further traverse downwards
   switch (node.type) {
     case NodeTypes.IF:
       for (let i = 0; i < node.branches.length; i++) {
-        traverseChildren(node.branches[i], context, ancestors)
+        traverseChildren(node.branches[i], context)
       }
       break
     case NodeTypes.FOR:
     case NodeTypes.ELEMENT:
-      traverseChildren(node, context, ancestors)
+      traverseChildren(node, context)
       break
   }
 }
@@ -169,11 +164,12 @@ export function createStructuralDirectiveTransform(
       for (let i = 0; i < props.length; i++) {
         const prop = props[i]
         if (prop.type === NodeTypes.DIRECTIVE && matches(prop.name)) {
-          fn(node, prop, context)
-          // structural directives are removed after being processed
-          // to avoid infinite recursion
+          // structural directives are removed to avoid infinite recursion
+          // also we remove them *before* applying so that it can further
+          // traverse itself in case it moves the node around
           props.splice(i, 1)
           i--
+          fn(node, prop, context)
         }
       }
     }
index 494823c9f71f43dbd3a5d33692f5c9e2bd631a39..85f2165d6def61a9ab96a9d43b1e224d6a3036b7 100644 (file)
@@ -1,4 +1,7 @@
-import { createStructuralDirectiveTransform } from '../transform'
+import {
+  createStructuralDirectiveTransform,
+  traverseChildren
+} from '../transform'
 import {
   NodeTypes,
   ElementTypes,
@@ -37,6 +40,9 @@ export const transformIf = createStructuralDirectiveTransform(
             branch.children = [...comments, ...branch.children]
           }
           sibling.branches.push(branch)
+          // since the branch was removed, it will not be traversed.
+          // make sure to traverse here.
+          traverseChildren(branch, context)
         } else {
           context.onError(
             createCompilerError(