@@ -48,40 +48,65 @@ function alphabeticalCompare(a, b, ignoreCase) {
48
48
return a . localeCompare ( b ) ;
49
49
}
50
50
51
+ /**
52
+ * Create an array of arrays where each subarray is composed of attributes
53
+ * that are considered sortable.
54
+ * @param {Array<JSXSpreadAttribute|JSXAttribute> } attributes
55
+ * @return {Array<Array<JSXAttribute> }
56
+ */
57
+ function getGroupsOfSortableAttributes ( attributes ) {
58
+ const sortableAttributeGroups = [ ] ;
59
+ let groupCount = 0 ;
60
+ for ( var i = 0 ; i < attributes . length ; i ++ ) {
61
+ const lastAttr = attributes [ i - 1 ] ;
62
+ // If we have no groups or if the last attribute was JSXSpreadAttribute
63
+ // then we start a new group. Append attributes to the group until we
64
+ // come across another JSXSpreadAttribute or exhaust the array.
65
+ if (
66
+ ! lastAttr ||
67
+ ( lastAttr . type === 'JSXSpreadAttribute' &&
68
+ attributes [ i ] . type !== 'JSXSpreadAttribute' )
69
+ ) {
70
+ groupCount ++ ;
71
+ sortableAttributeGroups [ groupCount - 1 ] = [ ] ;
72
+ }
73
+ if ( attributes [ i ] . type !== 'JSXSpreadAttribute' ) {
74
+ sortableAttributeGroups [ groupCount - 1 ] . push ( attributes [ i ] ) ;
75
+ }
76
+ }
77
+ return sortableAttributeGroups ;
78
+ }
79
+
51
80
function generateFixerFunction ( node , context ) {
52
81
var sourceCode = context . getSourceCode ( ) ;
53
82
var attributes = node . attributes . slice ( 0 ) ;
54
83
var configuration = context . options [ 0 ] || { } ;
55
84
var ignoreCase = configuration . ignoreCase || false ;
56
85
57
86
// Sort props according to the context. Only supports ignoreCase.
58
- // Since we cannot safely move JSXSpreadAttributes (due to potential variable overrides),
59
- // we only consider the sortable attributes.
60
- const sortableAttributes = attributes . filter ( function ( attr ) {
61
- return attr . type !== 'JSXSpreadAttribute' ;
62
- } ) ;
63
-
64
- sortableAttributes . sort ( function ( a , b ) {
65
- return alphabeticalCompare ( propName ( a ) , propName ( b ) , ignoreCase ) ;
87
+ // Since we cannot safely move JSXSpreadAttribute (due to potential variable overrides),
88
+ // we only consider groups of sortable attributes.
89
+ const sortableAttributeGroups = getGroupsOfSortableAttributes ( attributes ) ;
90
+ const sortedAttributeGroups = sortableAttributeGroups . slice ( 0 ) . map ( function ( group ) {
91
+ return group . slice ( 0 ) . sort ( function ( a , b ) {
92
+ return alphabeticalCompare ( propName ( a ) , propName ( b ) , ignoreCase ) ;
93
+ } ) ;
66
94
} ) ;
67
95
68
96
return function ( fixer ) {
69
- // Replace each unsorted attribute with the sorted one.
70
97
const fixers = [ ] ;
71
- let skipIndex = 0 ; // skip over spread attributes
72
-
73
- node . attributes . forEach ( function ( attr , index ) {
74
- if ( attr . type === 'JSXSpreadAttribute' ) {
75
- skipIndex ++ ;
76
- return ;
77
- }
78
98
79
- var sortedAttr = sortableAttributes [ index - skipIndex ] ;
80
- var sortedAttrText = sourceCode . getText ( sortedAttr ) ;
81
- fixers . push (
82
- fixer . replaceTextRange ( [ attr . start , attr . end ] , sortedAttrText )
83
- ) ;
99
+ // Replace each unsorted attribute with the sorted one.
100
+ sortableAttributeGroups . forEach ( function ( sortableGroup , ii ) {
101
+ sortableGroup . forEach ( function ( attr , jj ) {
102
+ var sortedAttr = sortedAttributeGroups [ ii ] [ jj ] ;
103
+ var sortedAttrText = sourceCode . getText ( sortedAttr ) ;
104
+ fixers . push (
105
+ fixer . replaceTextRange ( [ attr . start , attr . end ] , sortedAttrText )
106
+ ) ;
107
+ } ) ;
84
108
} ) ;
109
+
85
110
return fixers ;
86
111
} ;
87
112
}
0 commit comments