@@ -18,7 +18,8 @@ import {
18
18
IfConditionalExpression ,
19
19
BlockCodegenNode ,
20
20
IfNode ,
21
- createVNodeCall
21
+ createVNodeCall ,
22
+ AttributeNode
22
23
} from '../ast'
23
24
import { createCompilerError , ErrorCodes } from '../errors'
24
25
import { processExpression } from './transformExpression'
@@ -111,11 +112,6 @@ export function processIf(
111
112
validateBrowserExpression ( dir . exp as SimpleExpressionNode , context )
112
113
}
113
114
114
- const userKey = /*#__PURE__*/ findProp ( node , 'key' )
115
- if ( userKey ) {
116
- context . onError ( createCompilerError ( ErrorCodes . X_V_IF_KEY , userKey . loc ) )
117
- }
118
-
119
115
if ( dir . name === 'if' ) {
120
116
const branch = createIfBranch ( node , dir )
121
117
const ifNode : IfNode = {
@@ -146,6 +142,24 @@ export function processIf(
146
142
if ( __DEV__ && comments . length ) {
147
143
branch . children = [ ...comments , ...branch . children ]
148
144
}
145
+
146
+ // check if user is forcing same key on different branches
147
+ if ( __DEV__ || ! __BROWSER__ ) {
148
+ const key = branch . userKey
149
+ if ( key ) {
150
+ sibling . branches . forEach ( ( { userKey } ) => {
151
+ if ( isSameKey ( userKey , key ) ) {
152
+ context . onError (
153
+ createCompilerError (
154
+ ErrorCodes . X_V_IF_SAME_KEY ,
155
+ branch . userKey ! . loc
156
+ )
157
+ )
158
+ }
159
+ } )
160
+ }
161
+ }
162
+
149
163
sibling . branches . push ( branch )
150
164
const onExit = processCodegen && processCodegen ( sibling , branch , false )
151
165
// since the branch was removed, it will not be traversed.
@@ -174,7 +188,8 @@ function createIfBranch(node: ElementNode, dir: DirectiveNode): IfBranchNode {
174
188
children :
175
189
node . tagType === ElementTypes . TEMPLATE && ! findDir ( node , 'for' )
176
190
? node . children
177
- : [ node ]
191
+ : [ node ] ,
192
+ userKey : findProp ( node , `key` )
178
193
}
179
194
}
180
195
@@ -256,3 +271,32 @@ function createChildrenCodegenNode(
256
271
return vnodeCall
257
272
}
258
273
}
274
+
275
+ function isSameKey (
276
+ a : AttributeNode | DirectiveNode | undefined ,
277
+ b : AttributeNode | DirectiveNode
278
+ ) : boolean {
279
+ if ( ! a || a . type !== b . type ) {
280
+ return false
281
+ }
282
+ if ( a . type === NodeTypes . ATTRIBUTE ) {
283
+ if ( a . value ! . content !== ( b as AttributeNode ) . value ! . content ) {
284
+ return false
285
+ }
286
+ } else {
287
+ // directive
288
+ const exp = a . exp !
289
+ const branchExp = ( b as DirectiveNode ) . exp !
290
+ if ( exp . type !== branchExp . type ) {
291
+ return false
292
+ }
293
+ if (
294
+ exp . type !== NodeTypes . SIMPLE_EXPRESSION ||
295
+ ( exp . isStatic !== ( branchExp as SimpleExpressionNode ) . isStatic ||
296
+ exp . content !== ( branchExp as SimpleExpressionNode ) . content )
297
+ ) {
298
+ return false
299
+ }
300
+ }
301
+ return true
302
+ }
0 commit comments