@@ -20,6 +20,7 @@ const ATTRS = {
20
20
RENDER_MODIFIERS : 'RENDER_MODIFIERS' ,
21
21
GLOBAL : 'GLOBAL' ,
22
22
UNIQUE : 'UNIQUE' ,
23
+ SLOT : 'SLOT' ,
23
24
TWO_WAY_BINDING : 'TWO_WAY_BINDING' ,
24
25
OTHER_DIRECTIVES : 'OTHER_DIRECTIVES' ,
25
26
OTHER_ATTR : 'OTHER_ATTR' ,
@@ -121,7 +122,7 @@ function getAttributeType(attribute) {
121
122
} else if ( name === 'html' || name === 'text' ) {
122
123
return ATTRS . CONTENT
123
124
} else if ( name === 'slot' ) {
124
- return ATTRS . UNIQUE
125
+ return ATTRS . SLOT
125
126
} else if ( name === 'is' ) {
126
127
return ATTRS . DEFINITION
127
128
} else {
@@ -139,13 +140,10 @@ function getAttributeType(attribute) {
139
140
return ATTRS . DEFINITION
140
141
} else if ( propName === 'id' ) {
141
142
return ATTRS . GLOBAL
142
- } else if (
143
- propName === 'ref' ||
144
- propName === 'key' ||
145
- propName === 'slot' ||
146
- propName === 'slot-scope'
147
- ) {
143
+ } else if ( propName === 'ref' || propName === 'key' ) {
148
144
return ATTRS . UNIQUE
145
+ } else if ( propName === 'slot' || propName === 'slot-scope' ) {
146
+ return ATTRS . SLOT
149
147
} else {
150
148
return ATTRS . OTHER_ATTR
151
149
}
@@ -154,12 +152,13 @@ function getAttributeType(attribute) {
154
152
/**
155
153
* @param {VAttribute | VDirective } attribute
156
154
* @param { { [key: string]: number } } attributePosition
155
+ * @returns {number | null } If the value is null, the order is omitted. Do not force the order.
157
156
*/
158
157
function getPosition ( attribute , attributePosition ) {
159
158
const attributeType = getAttributeType ( attribute )
160
159
return attributePosition [ attributeType ] != null
161
160
? attributePosition [ attributeType ]
162
- : - 1
161
+ : null
163
162
}
164
163
165
164
/**
@@ -190,7 +189,7 @@ function create(context) {
190
189
ATTRS . CONDITIONALS ,
191
190
ATTRS . RENDER_MODIFIERS ,
192
191
ATTRS . GLOBAL ,
193
- ATTRS . UNIQUE ,
192
+ [ ATTRS . UNIQUE , ATTRS . SLOT ] ,
194
193
ATTRS . TWO_WAY_BINDING ,
195
194
ATTRS . OTHER_DIRECTIVES ,
196
195
ATTRS . OTHER_ATTR ,
@@ -267,74 +266,96 @@ function create(context) {
267
266
268
267
return utils . defineTemplateBodyVisitor ( context , {
269
268
VStartTag ( node ) {
270
- const attributes = node . attributes . filter ( ( node , index , attributes ) => {
271
- if (
272
- isVBindObject ( node ) &&
273
- ( isVAttributeOrVBind ( attributes [ index - 1 ] ) ||
274
- isVAttributeOrVBind ( attributes [ index + 1 ] ) )
275
- ) {
276
- // In Vue 3, ignore the `v-bind:foo=" ... "` and `v-bind ="object"` syntax
277
- // as they behave differently if you change the order.
278
- return false
279
- }
280
- return true
281
- } )
282
- if ( attributes . length <= 1 ) {
269
+ const attributeAndPositions = getAttributeAndPositionList ( node )
270
+ if ( attributeAndPositions . length <= 1 ) {
283
271
return
284
272
}
285
273
286
- let previousNode = attributes [ 0 ]
287
- let previousPosition = getPositionFromAttrIndex ( 0 )
288
- for ( let index = 1 ; index < attributes . length ; index ++ ) {
289
- const node = attributes [ index ]
290
- const position = getPositionFromAttrIndex ( index )
274
+ let {
275
+ attr : previousNode ,
276
+ position : previousPosition
277
+ } = attributeAndPositions [ 0 ]
278
+ for ( let index = 1 ; index < attributeAndPositions . length ; index ++ ) {
279
+ const { attr, position } = attributeAndPositions [ index ]
291
280
292
281
let valid = previousPosition <= position
293
282
if ( valid && alphabetical && previousPosition === position ) {
294
- valid = isAlphabetical ( previousNode , node , sourceCode )
283
+ valid = isAlphabetical ( previousNode , attr , sourceCode )
295
284
}
296
285
if ( valid ) {
297
- previousNode = node
286
+ previousNode = attr
298
287
previousPosition = position
299
288
} else {
300
- reportIssue ( node , previousNode )
289
+ reportIssue ( attr , previousNode )
301
290
}
302
291
}
292
+ }
293
+ } )
303
294
304
- /**
305
- * @param {number } index
306
- * @returns {number }
307
- */
308
- function getPositionFromAttrIndex ( index ) {
309
- const node = attributes [ index ]
310
- if ( isVBindObject ( node ) ) {
311
- // node is `v-bind ="object"` syntax
295
+ /**
296
+ * @param {VStartTag } node
297
+ * @returns { { attr: ( VAttribute | VDirective ), position: number }[] }
298
+ */
299
+ function getAttributeAndPositionList ( node ) {
300
+ const attributes = node . attributes . filter ( ( node , index , attributes ) => {
301
+ if (
302
+ isVBindObject ( node ) &&
303
+ ( isVAttributeOrVBind ( attributes [ index - 1 ] ) ||
304
+ isVAttributeOrVBind ( attributes [ index + 1 ] ) )
305
+ ) {
306
+ // In Vue 3, ignore the `v-bind:foo=" ... "` and `v-bind ="object"` syntax
307
+ // as they behave differently if you change the order.
308
+ return false
309
+ }
310
+ return true
311
+ } )
312
312
313
- // In Vue 3, if change the order of `v-bind:foo=" ... "` and `v-bind ="object"`,
314
- // the behavior will be different, so adjust so that there is no change in behavior.
313
+ const results = [ ]
314
+ for ( let index = 0 ; index < attributes . length ; index ++ ) {
315
+ const attr = attributes [ index ]
316
+ const position = getPositionFromAttrIndex ( index )
317
+ if ( position == null ) {
318
+ // The omitted order is skipped.
319
+ continue
320
+ }
321
+ results . push ( { attr, position } )
322
+ }
323
+
324
+ return results
325
+
326
+ /**
327
+ * @param {number } index
328
+ * @returns {number | null }
329
+ */
330
+ function getPositionFromAttrIndex ( index ) {
331
+ const node = attributes [ index ]
332
+ if ( isVBindObject ( node ) ) {
333
+ // node is `v-bind ="object"` syntax
315
334
316
- const len = attributes . length
317
- for ( let nextIndex = index + 1 ; nextIndex < len ; nextIndex ++ ) {
318
- const next = attributes [ nextIndex ]
335
+ // In Vue 3, if change the order of `v-bind:foo=" ... "` and `v-bind ="object"`,
336
+ // the behavior will be different, so adjust so that there is no change in behavior.
319
337
320
- if ( isVAttributeOrVBind ( next ) && ! isVBindObject ( next ) ) {
321
- // It is considered to be in the same order as the next bind prop node.
322
- return getPositionFromAttrIndex ( nextIndex )
323
- }
338
+ const len = attributes . length
339
+ for ( let nextIndex = index + 1 ; nextIndex < len ; nextIndex ++ ) {
340
+ const next = attributes [ nextIndex ]
341
+
342
+ if ( isVAttributeOrVBind ( next ) && ! isVBindObject ( next ) ) {
343
+ // It is considered to be in the same order as the next bind prop node.
344
+ return getPositionFromAttrIndex ( nextIndex )
324
345
}
325
- for ( let prevIndex = index - 1 ; prevIndex >= 0 ; prevIndex -- ) {
326
- const prev = attributes [ prevIndex ]
346
+ }
347
+ for ( let prevIndex = index - 1 ; prevIndex >= 0 ; prevIndex -- ) {
348
+ const prev = attributes [ prevIndex ]
327
349
328
- if ( isVAttributeOrVBind ( prev ) && ! isVBindObject ( prev ) ) {
329
- // It is considered to be in the same order as the prev bind prop node.
330
- return getPositionFromAttrIndex ( prevIndex )
331
- }
350
+ if ( isVAttributeOrVBind ( prev ) && ! isVBindObject ( prev ) ) {
351
+ // It is considered to be in the same order as the prev bind prop node.
352
+ return getPositionFromAttrIndex ( prevIndex )
332
353
}
333
354
}
334
- return getPosition ( node , attributePosition )
335
355
}
356
+ return getPosition ( node , attributePosition )
336
357
}
337
- } )
358
+ }
338
359
}
339
360
340
361
module . exports = {
0 commit comments