--- /dev/null
+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
+ )
+ })
+ })
+})
-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'
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))
+ )
+}