]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(transition): warn only when there is more than one rendered child (#903)
authorEduardo San Martin Morote <posva@users.noreply.github.com>
Tue, 31 Mar 2020 22:12:51 +0000 (00:12 +0200)
committerGitHub <noreply@github.com>
Tue, 31 Mar 2020 22:12:51 +0000 (18:12 -0400)
packages/compiler-dom/__tests__/transforms/warnTransitionChildren.spec.ts [new file with mode: 0644]
packages/compiler-dom/src/transforms/warnTransitionChildren.ts

diff --git a/packages/compiler-dom/__tests__/transforms/warnTransitionChildren.spec.ts b/packages/compiler-dom/__tests__/transforms/warnTransitionChildren.spec.ts
new file mode 100644 (file)
index 0000000..8083ce7
--- /dev/null
@@ -0,0 +1,140 @@
+import { compile } from '../../src'
+
+describe('compiler warnings', () => {
+  describe('Transition', () => {
+    function checkWarning(
+      template: string,
+      shouldWarn: boolean,
+      message = `<Transition> expects exactly one child element or component.`
+    ) {
+      const spy = jest.fn()
+      compile(template.trim(), {
+        hoistStatic: true,
+        transformHoist: null,
+        onError: err => {
+          spy(err.message)
+        }
+      })
+
+      if (shouldWarn) expect(spy).toHaveBeenCalledWith(message)
+      else expect(spy).not.toHaveBeenCalled()
+    }
+
+    test('warns if multiple children', () => {
+      checkWarning(
+        `
+      <transition>
+        <div>hey</div>
+        <div>hey</div>
+      </transition>
+      `,
+        true
+      )
+    })
+
+    test('warns with v-for', () => {
+      checkWarning(
+        `
+      <transition>
+        <div v-for="i in items">hey</div>
+      </transition>
+      `,
+        true
+      )
+    })
+
+    test('warns with multiple v-if + v-for', () => {
+      checkWarning(
+        `
+      <transition>
+        <div v-if="a" v-for="i in items">hey</div>
+        <div v-else v-for="i in items">hey</div>
+      </transition>
+      `,
+        true
+      )
+    })
+
+    test('warns with template v-if', () => {
+      checkWarning(
+        `
+      <transition>
+        <template v-if="ok"></template>
+      </transition>
+      `,
+        true
+      )
+    })
+
+    test('warns with multiple templates', () => {
+      checkWarning(
+        `
+      <transition>
+        <template v-if="a"></template>
+        <template v-else></template>
+      </transition>
+      `,
+        true
+      )
+    })
+
+    test('warns if multiple children with v-if', () => {
+      checkWarning(
+        `
+      <transition>
+        <div v-if="one">hey</div>
+        <div v-if="other">hey</div>
+      </transition>
+      `,
+        true
+      )
+    })
+
+    test('does not warn with regular element', () => {
+      checkWarning(
+        `
+      <transition>
+        <div>hey</div>
+      </transition>
+      `,
+        false
+      )
+    })
+
+    test('does not warn with one single v-if', () => {
+      checkWarning(
+        `
+      <transition>
+        <div v-if="a">hey</div>
+      </transition>
+      `,
+        false
+      )
+    })
+
+    test('does not warn with v-if v-else-if v-else', () => {
+      checkWarning(
+        `
+      <transition>
+        <div v-if="a">hey</div>
+        <div v-else-if="b">hey</div>
+        <div v-else>hey</div>
+      </transition>
+      `,
+        false
+      )
+    })
+
+    test('does not warn with v-if v-else', () => {
+      checkWarning(
+        `
+      <transition>
+        <div v-if="a">hey</div>
+        <div v-else>hey</div>
+      </transition>
+      `,
+        false
+      )
+    })
+  })
+})
index 0cd1d6669ac87a780b11ecccae78f18391ba03cb..577b3a8876ffabf11083cf693ad46c59169d9182 100644 (file)
@@ -1,4 +1,10 @@
-import { NodeTransform, NodeTypes, ElementTypes } from '@vue/compiler-core'
+import {
+  NodeTransform,
+  NodeTypes,
+  ElementTypes,
+  ComponentNode,
+  IfBranchNode
+} from '@vue/compiler-core'
 import { TRANSITION } from '../runtimeHelpers'
 import { createDOMCompilerError, DOMErrorCodes } from '../errors'
 
@@ -8,17 +14,30 @@ export const warnTransitionChildren: NodeTransform = (node, context) => {
     node.tagType === ElementTypes.COMPONENT
   ) {
     const component = context.isBuiltInComponent(node.tag)
-    if (
-      component === TRANSITION &&
-      (node.children.length > 1 || node.children[0].type === NodeTypes.FOR)
-    ) {
-      context.onError(
-        createDOMCompilerError(DOMErrorCodes.X_TRANSITION_INVALID_CHILDREN, {
-          start: node.children[0].loc.start,
-          end: node.children[node.children.length - 1].loc.end,
-          source: ''
-        })
-      )
+    if (component === TRANSITION) {
+      return () => {
+        if (node.children.length && hasMultipleChildren(node)) {
+          context.onError(
+            createDOMCompilerError(
+              DOMErrorCodes.X_TRANSITION_INVALID_CHILDREN,
+              {
+                start: node.children[0].loc.start,
+                end: node.children[node.children.length - 1].loc.end,
+                source: ''
+              }
+            )
+          )
+        }
+      }
     }
   }
 }
+
+function hasMultipleChildren(node: ComponentNode | IfBranchNode): boolean {
+  const child = node.children[0]
+  return (
+    node.children.length !== 1 ||
+    child.type === NodeTypes.FOR ||
+    (child.type === NodeTypes.IF && child.branches.some(hasMultipleChildren))
+  )
+}