@@ -20,6 +20,7 @@ const ATTRS = {
2020 RENDER_MODIFIERS : 'RENDER_MODIFIERS' ,
2121 GLOBAL : 'GLOBAL' ,
2222 UNIQUE : 'UNIQUE' ,
23+ SLOT : 'SLOT' ,
2324 TWO_WAY_BINDING : 'TWO_WAY_BINDING' ,
2425 OTHER_DIRECTIVES : 'OTHER_DIRECTIVES' ,
2526 OTHER_ATTR : 'OTHER_ATTR' ,
@@ -121,7 +122,7 @@ function getAttributeType(attribute) {
121122 } else if ( name === 'html' || name === 'text' ) {
122123 return ATTRS . CONTENT
123124 } else if ( name === 'slot' ) {
124- return ATTRS . UNIQUE
125+ return ATTRS . SLOT
125126 } else if ( name === 'is' ) {
126127 return ATTRS . DEFINITION
127128 } else {
@@ -139,13 +140,10 @@ function getAttributeType(attribute) {
139140 return ATTRS . DEFINITION
140141 } else if ( propName === 'id' ) {
141142 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' ) {
148144 return ATTRS . UNIQUE
145+ } else if ( propName === 'slot' || propName === 'slot-scope' ) {
146+ return ATTRS . SLOT
149147 } else {
150148 return ATTRS . OTHER_ATTR
151149 }
@@ -154,12 +152,13 @@ function getAttributeType(attribute) {
154152/**
155153 * @param {VAttribute | VDirective } attribute
156154 * @param { { [key: string]: number } } attributePosition
155+ * @returns {number | null } If the value is null, the order is omitted. Do not force the order.
157156 */
158157function getPosition ( attribute , attributePosition ) {
159158 const attributeType = getAttributeType ( attribute )
160159 return attributePosition [ attributeType ] != null
161160 ? attributePosition [ attributeType ]
162- : - 1
161+ : null
163162}
164163
165164/**
@@ -190,7 +189,7 @@ function create(context) {
190189 ATTRS . CONDITIONALS ,
191190 ATTRS . RENDER_MODIFIERS ,
192191 ATTRS . GLOBAL ,
193- ATTRS . UNIQUE ,
192+ [ ATTRS . UNIQUE , ATTRS . SLOT ] ,
194193 ATTRS . TWO_WAY_BINDING ,
195194 ATTRS . OTHER_DIRECTIVES ,
196195 ATTRS . OTHER_ATTR ,
@@ -267,74 +266,96 @@ function create(context) {
267266
268267 return utils . defineTemplateBodyVisitor ( context , {
269268 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 ) {
283271 return
284272 }
285273
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 ]
291280
292281 let valid = previousPosition <= position
293282 if ( valid && alphabetical && previousPosition === position ) {
294- valid = isAlphabetical ( previousNode , node , sourceCode )
283+ valid = isAlphabetical ( previousNode , attr , sourceCode )
295284 }
296285 if ( valid ) {
297- previousNode = node
286+ previousNode = attr
298287 previousPosition = position
299288 } else {
300- reportIssue ( node , previousNode )
289+ reportIssue ( attr , previousNode )
301290 }
302291 }
292+ }
293+ } )
303294
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+ } )
312312
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
315334
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.
319337
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 )
324345 }
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 ]
327349
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 )
332353 }
333354 }
334- return getPosition ( node , attributePosition )
335355 }
356+ return getPosition ( node , attributePosition )
336357 }
337- } )
358+ }
338359}
339360
340361module . exports = {
0 commit comments