Skip to content

Commit 37b1dc8

Browse files
authored
fix(transition): warn only when there is more than one rendered child (#903)
1 parent 449ab03 commit 37b1dc8

File tree

2 files changed

+171
-12
lines changed

2 files changed

+171
-12
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
import { compile } from '../../src'
2+
3+
describe('compiler warnings', () => {
4+
describe('Transition', () => {
5+
function checkWarning(
6+
template: string,
7+
shouldWarn: boolean,
8+
message = `<Transition> expects exactly one child element or component.`
9+
) {
10+
const spy = jest.fn()
11+
compile(template.trim(), {
12+
hoistStatic: true,
13+
transformHoist: null,
14+
onError: err => {
15+
spy(err.message)
16+
}
17+
})
18+
19+
if (shouldWarn) expect(spy).toHaveBeenCalledWith(message)
20+
else expect(spy).not.toHaveBeenCalled()
21+
}
22+
23+
test('warns if multiple children', () => {
24+
checkWarning(
25+
`
26+
<transition>
27+
<div>hey</div>
28+
<div>hey</div>
29+
</transition>
30+
`,
31+
true
32+
)
33+
})
34+
35+
test('warns with v-for', () => {
36+
checkWarning(
37+
`
38+
<transition>
39+
<div v-for="i in items">hey</div>
40+
</transition>
41+
`,
42+
true
43+
)
44+
})
45+
46+
test('warns with multiple v-if + v-for', () => {
47+
checkWarning(
48+
`
49+
<transition>
50+
<div v-if="a" v-for="i in items">hey</div>
51+
<div v-else v-for="i in items">hey</div>
52+
</transition>
53+
`,
54+
true
55+
)
56+
})
57+
58+
test('warns with template v-if', () => {
59+
checkWarning(
60+
`
61+
<transition>
62+
<template v-if="ok"></template>
63+
</transition>
64+
`,
65+
true
66+
)
67+
})
68+
69+
test('warns with multiple templates', () => {
70+
checkWarning(
71+
`
72+
<transition>
73+
<template v-if="a"></template>
74+
<template v-else></template>
75+
</transition>
76+
`,
77+
true
78+
)
79+
})
80+
81+
test('warns if multiple children with v-if', () => {
82+
checkWarning(
83+
`
84+
<transition>
85+
<div v-if="one">hey</div>
86+
<div v-if="other">hey</div>
87+
</transition>
88+
`,
89+
true
90+
)
91+
})
92+
93+
test('does not warn with regular element', () => {
94+
checkWarning(
95+
`
96+
<transition>
97+
<div>hey</div>
98+
</transition>
99+
`,
100+
false
101+
)
102+
})
103+
104+
test('does not warn with one single v-if', () => {
105+
checkWarning(
106+
`
107+
<transition>
108+
<div v-if="a">hey</div>
109+
</transition>
110+
`,
111+
false
112+
)
113+
})
114+
115+
test('does not warn with v-if v-else-if v-else', () => {
116+
checkWarning(
117+
`
118+
<transition>
119+
<div v-if="a">hey</div>
120+
<div v-else-if="b">hey</div>
121+
<div v-else>hey</div>
122+
</transition>
123+
`,
124+
false
125+
)
126+
})
127+
128+
test('does not warn with v-if v-else', () => {
129+
checkWarning(
130+
`
131+
<transition>
132+
<div v-if="a">hey</div>
133+
<div v-else>hey</div>
134+
</transition>
135+
`,
136+
false
137+
)
138+
})
139+
})
140+
})
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
1-
import { NodeTransform, NodeTypes, ElementTypes } from '@vue/compiler-core'
1+
import {
2+
NodeTransform,
3+
NodeTypes,
4+
ElementTypes,
5+
ComponentNode,
6+
IfBranchNode
7+
} from '@vue/compiler-core'
28
import { TRANSITION } from '../runtimeHelpers'
39
import { createDOMCompilerError, DOMErrorCodes } from '../errors'
410

@@ -8,17 +14,30 @@ export const warnTransitionChildren: NodeTransform = (node, context) => {
814
node.tagType === ElementTypes.COMPONENT
915
) {
1016
const component = context.isBuiltInComponent(node.tag)
11-
if (
12-
component === TRANSITION &&
13-
(node.children.length > 1 || node.children[0].type === NodeTypes.FOR)
14-
) {
15-
context.onError(
16-
createDOMCompilerError(DOMErrorCodes.X_TRANSITION_INVALID_CHILDREN, {
17-
start: node.children[0].loc.start,
18-
end: node.children[node.children.length - 1].loc.end,
19-
source: ''
20-
})
21-
)
17+
if (component === TRANSITION) {
18+
return () => {
19+
if (node.children.length && hasMultipleChildren(node)) {
20+
context.onError(
21+
createDOMCompilerError(
22+
DOMErrorCodes.X_TRANSITION_INVALID_CHILDREN,
23+
{
24+
start: node.children[0].loc.start,
25+
end: node.children[node.children.length - 1].loc.end,
26+
source: ''
27+
}
28+
)
29+
)
30+
}
31+
}
2232
}
2333
}
2434
}
35+
36+
function hasMultipleChildren(node: ComponentNode | IfBranchNode): boolean {
37+
const child = node.children[0]
38+
return (
39+
node.children.length !== 1 ||
40+
child.type === NodeTypes.FOR ||
41+
(child.type === NodeTypes.IF && child.branches.some(hasMultipleChildren))
42+
)
43+
}

0 commit comments

Comments
 (0)