@@ -2,7 +2,7 @@ var postcss = require('postcss');
2
2
var path = require ( 'path' ) ;
3
3
var fs = require ( 'fs' ) ;
4
4
5
- function getSortOrder ( options ) {
5
+ function getSortOrderFromOptions ( options ) {
6
6
// If no options use default config
7
7
if ( options === null || typeof options !== 'object' || ! options [ 'sort-order' ] ) {
8
8
options = { 'sort-order' : 'default' } ;
@@ -29,27 +29,34 @@ function getSortOrder(options) {
29
29
// Add sorting indexes to order
30
30
var order = { } ;
31
31
32
- if ( typeof sortOrder [ 0 ] === 'string' ) {
33
- sortOrder . forEach ( function ( prop , propIndex ) {
34
- order [ prop ] = {
35
- group : 0 ,
36
- prop : propIndex
37
- } ;
38
- } ) ;
39
- } else {
40
- sortOrder . forEach ( function ( group , groupIndex ) {
32
+ ( typeof sortOrder [ 0 ] === 'string' ? [ sortOrder ] : sortOrder )
33
+ . forEach ( function ( group , groupIndex ) {
41
34
group . forEach ( function ( prop , propIndex ) {
42
35
order [ prop ] = {
43
36
group : groupIndex ,
44
37
prop : propIndex
45
38
} ;
46
39
} ) ;
47
40
} ) ;
48
- }
49
41
50
42
return order ;
51
43
}
52
44
45
+ function getLinesBetweenChildrenFromOptions ( opts ) {
46
+ var options = opts || { } ;
47
+ var lines = options [ 'empty-lines-between-children-rules' ] ;
48
+
49
+ if ( lines === undefined || lines === null ) {
50
+ return 0 ;
51
+ }
52
+
53
+ if ( typeof lines !== 'number' || isNaN ( lines ) || ! isFinite ( lines ) || lines < 0 || Math . floor ( lines ) !== lines ) {
54
+ throw new Error ( 'Type of "empty-lines-between-children-rules" option must be integer with positive value.' ) ;
55
+ }
56
+
57
+ return lines ;
58
+ }
59
+
53
60
// Replace multiple line breaks with one
54
61
function cleanLineBreaks ( node ) {
55
62
if ( node . raws . before ) {
@@ -63,26 +70,100 @@ function createLineBreaks(lineBreaksCount) {
63
70
return new Array ( lineBreaksCount + 1 ) . join ( '\n' ) ;
64
71
}
65
72
66
- function getLinesBetweenChildrenFromOptions ( opts ) {
67
- var options = opts || { } ;
68
- var lines = options [ 'empty-lines-between-children-rules' ] ;
73
+ function getAtruleSortName ( node , order ) {
74
+ var atruleName = '@' + node . name ;
69
75
70
- if ( lines === undefined || lines === null ) {
71
- return 0 ;
76
+ // If atRule has a parameter like @mixin name or @include name, sort by this parameter
77
+ var atruleParameter = / ^ [ \w - ] + / . exec ( node . params ) ;
78
+
79
+ if ( atruleParameter && atruleParameter . length ) {
80
+ var sortNameExtended = atruleName + ' ' + atruleParameter [ 0 ] ;
81
+
82
+ if ( order [ sortNameExtended ] ) {
83
+ return sortNameExtended ;
84
+ }
72
85
}
73
86
74
- if ( typeof lines !== 'number' || isNaN ( lines ) || ! isFinite ( lines ) || lines < 0 || Math . floor ( lines ) !== lines ) {
75
- throw new Error ( 'Type of "empty-lines-between-children-rules" option must be integer with positive value.' ) ;
87
+ // If atrule with name is in order use the name
88
+ if ( order [ atruleName ] ) {
89
+ return atruleName ;
76
90
}
77
91
78
- return lines ;
92
+ return '@atrule' ;
93
+ }
94
+
95
+ function getSortName ( node , order ) {
96
+ switch ( node . type ) {
97
+ case 'decl' :
98
+ return / ^ \$ [ \w - ] + / . test ( node . prop ) ? '$variable' : node . prop ;
99
+
100
+ case 'atrule' :
101
+ return getAtruleSortName ( node , order ) ;
102
+
103
+ case 'rule' :
104
+ return '>child' ;
105
+
106
+ default :
107
+ return null ;
108
+ }
109
+ }
110
+
111
+ function getOrderProperty ( node , order ) {
112
+ var sortName = getSortName ( node , order ) ;
113
+
114
+ // Trying to get property indexes from order's list
115
+ var orderProperty = order [ sortName ] ;
116
+
117
+ // If no property in the list and this property is prefixed then trying to get parameters for unprefixed property
118
+ if ( ! orderProperty && postcss . vendor . prefix ( sortName ) ) {
119
+ sortName = postcss . vendor . unprefixed ( sortName ) ;
120
+ orderProperty = order [ sortName ] ;
121
+ }
122
+
123
+ return orderProperty ;
79
124
}
80
125
126
+ function fetchAllCommentsBeforeNode ( comments , previousNode , node ) {
127
+ if ( ! previousNode || previousNode . type !== 'comment' ) {
128
+ return comments ;
129
+ }
130
+
131
+ if ( ! previousNode . raws . before || previousNode . raws . before . indexOf ( '\n' ) === - 1 ) {
132
+ return comments ;
133
+ }
134
+
135
+ previousNode . groupIndex = node . groupIndex ;
136
+ previousNode . propertyIndex = node . propertyIndex ;
137
+ previousNode . initialIndex = node . initialIndex - 1 ;
138
+
139
+ var previousNodeClone = cleanLineBreaks ( previousNode ) ;
140
+ var newComments = [ previousNodeClone ] . concat ( comments ) ;
141
+
142
+ return fetchAllCommentsBeforeNode ( newComments , previousNode . prev ( ) , node ) ;
143
+ }
144
+
145
+ function fetchAllCommentsAfterNode ( comments , nextNode , node ) {
146
+ if ( ! nextNode || nextNode . type !== 'comment' ) {
147
+ return comments ;
148
+ }
149
+
150
+ if ( ! nextNode . raws . before || nextNode . raws . before . indexOf ( '\n' ) >= 0 ) {
151
+ return comments ;
152
+ }
153
+
154
+ nextNode . groupIndex = node . groupIndex ;
155
+ nextNode . propertyIndex = node . propertyIndex ;
156
+ nextNode . initialIndex = node . initialIndex + 1 ;
157
+
158
+ return fetchAllCommentsAfterNode ( comments . concat ( nextNode ) , nextNode . next ( ) , node ) ;
159
+ }
160
+
161
+
81
162
module . exports = postcss . plugin ( 'postcss-sorting' , function ( opts ) {
82
163
var linesBetweenChildrenRules = getLinesBetweenChildrenFromOptions ( opts ) ;
83
164
84
165
return function ( css ) {
85
- var order = getSortOrder ( opts ) ;
166
+ var order = getSortOrderFromOptions ( opts ) ;
86
167
87
168
// Index to place the nodes that shouldn't be sorted
88
169
var lastGroupIndex = order [ '...' ] ? order [ '...' ] . group : Infinity ;
@@ -96,49 +177,11 @@ module.exports = postcss.plugin('postcss-sorting', function (opts) {
96
177
var processed = [ ] ;
97
178
98
179
rule . each ( function ( node , index ) {
99
- var sortName = null ;
100
-
101
180
if ( node . type === 'comment' ) {
102
181
return ;
103
- } else if ( node . type === 'decl' ) {
104
- sortName = node . prop ;
105
-
106
- // If property start with $ and letters it's a variable
107
- if ( / ^ \$ [ \w - ] + / . test ( node . prop ) ) {
108
- sortName = '$variable' ;
109
- }
110
- } else if ( node . type === 'atrule' ) {
111
- sortName = '@atrule' ;
112
-
113
- // If atrule with name is in order use the name
114
- var atruleName = '@' + node . name ;
115
-
116
- if ( order [ atruleName ] ) {
117
- sortName = atruleName ;
118
- }
119
-
120
- // Ff atRule has a parameter like @mixin name or @include name, sort by this parameter
121
- var atruleParameter = / ^ [ \w - ] + / . exec ( node . params ) ;
122
-
123
- if ( atruleParameter && atruleParameter . length ) {
124
- var sortNameExtended = atruleName + ' ' + atruleParameter [ 0 ] ;
125
-
126
- if ( order [ sortNameExtended ] ) {
127
- sortName = sortNameExtended ;
128
- }
129
- }
130
- } else if ( node . type === 'rule' ) {
131
- sortName = '>child' ;
132
182
}
133
183
134
- // Trying to get property indexes from order's list
135
- var orderProperty = order [ sortName ] ;
136
-
137
- // If no property in the list and this property is prefixed then trying to get parameters for unprefixed property
138
- if ( ! orderProperty && postcss . vendor . prefix ( sortName ) ) {
139
- sortName = postcss . vendor . unprefixed ( sortName ) ;
140
- orderProperty = order [ sortName ] ;
141
- }
184
+ var orderProperty = getOrderProperty ( node , order ) ;
142
185
143
186
// If the declaration's property is in order's list, save its
144
187
// group and property indexes. Otherwise set them to 10000, so
@@ -148,47 +191,12 @@ module.exports = postcss.plugin('postcss-sorting', function (opts) {
148
191
node . initialIndex = index ;
149
192
150
193
// If comment on separate line before node, use node's indexes for comment
151
- var commentsBefore = [ ] ;
152
- var previousNode = node . prev ( ) ;
153
-
154
- while ( previousNode && previousNode . type === 'comment' ) {
155
- if ( previousNode . raws . before && previousNode . raws . before . indexOf ( '\n' ) > - 1 ) {
156
- previousNode . groupIndex = node . groupIndex ;
157
- previousNode . propertyIndex = node . propertyIndex ;
158
- previousNode . initialIndex = index - 1 ;
159
-
160
- var previousNodeClone = cleanLineBreaks ( previousNode ) ;
161
-
162
- commentsBefore . unshift ( previousNodeClone ) ;
163
-
164
- previousNode = previousNode . prev ( ) ;
165
- } else {
166
- break ;
167
- }
168
- }
169
-
170
- if ( commentsBefore . length ) {
171
- processed = processed . concat ( commentsBefore ) ;
172
- }
173
-
174
- // Add node itself
175
- processed . push ( node ) ;
194
+ var commentsBefore = fetchAllCommentsBeforeNode ( [ ] , node . prev ( ) , node ) ;
176
195
177
196
// If comment on same line with the node and node, use node's indexes for comment
178
- var nextNode = node . next ( ) ;
179
-
180
- while ( nextNode && nextNode . type === 'comment' ) {
181
- if ( nextNode . raws . before && nextNode . raws . before . indexOf ( '\n' ) < 0 ) {
182
- nextNode . groupIndex = node . groupIndex ;
183
- nextNode . propertyIndex = node . propertyIndex ;
184
- nextNode . initialIndex = index + 1 ;
185
-
186
- processed . push ( nextNode ) ;
187
- nextNode = nextNode . next ( ) ;
188
- } else {
189
- break ;
190
- }
191
- }
197
+ var commentsAfter = fetchAllCommentsAfterNode ( [ ] , node . next ( ) , node ) ;
198
+
199
+ processed = processed . concat ( commentsBefore , node , commentsAfter ) ;
192
200
} ) ;
193
201
194
202
// Sort declarations saved for sorting:
@@ -228,7 +236,6 @@ module.exports = postcss.plugin('postcss-sorting', function (opts) {
228
236
}
229
237
}
230
238
} ) ;
231
-
232
239
}
233
240
} ) ;
234
241
} ;
0 commit comments