@@ -37,6 +37,37 @@ function concat(a, b, selectorP) {
37
37
) || a + b
38
38
}
39
39
40
+ // "Tokenizes" the selectors into parts relevant for the next function.
41
+ // Strings and comments are matched, but ignored afterwards.
42
+ var selectorTokenizer = / [ ( ) , ] | " (?: \\ .| [ ^ " \n ] ) * " | ' (?: \\ .| [ ^ ' \n ] ) * ' | \/ \* [ \s \S ] * ?\* \/ / g
43
+
44
+ /**
45
+ * This will split a coma-separated selector list into individual selectors,
46
+ * ignoring comas in strings and in :pseudo-selectors(parameter, lists).
47
+ * regexp generated by scripts/regexps.js then trimmed by hand
48
+ * @param {string } selector
49
+ * @return {string[] }
50
+ */
51
+
52
+ function splitSelector ( selector ) {
53
+ var indices = [ ] , res = [ ] , inParen = 0 , match , i
54
+ /*eslint-disable no-cond-assign*/
55
+ while ( match = selectorTokenizer . exec ( selector ) ) {
56
+ /*eslint-enable no-cond-assign*/
57
+ switch ( match [ 0 ] ) {
58
+ case '(' : inParen ++ ; break
59
+ case ')' : inParen -- ; break
60
+ case ',' : if ( inParen ) break ; indices . push ( match . index )
61
+ }
62
+ }
63
+ for ( i = indices . length ; i -- ; ) {
64
+ res . unshift ( selector . slice ( indices [ i ] + 1 ) )
65
+ selector = selector . slice ( 0 , indices [ i ] )
66
+ }
67
+ res . unshift ( selector )
68
+ return res
69
+ }
70
+
40
71
function decamelize ( match ) {
41
72
return '-' + match . toLowerCase ( )
42
73
}
@@ -136,7 +167,7 @@ var findClass = /()(?::global\(\s*(\.[-\w]+)\s*\)|(\.)([-\w]+))/g
136
167
*/
137
168
138
169
function at ( k , v , buf , prefix , rawPrefix , vendors , local , ns ) {
139
- var kk
170
+ var kk , i
140
171
if ( / ^ @ (?: n a m e s p a c e | i m p o r t | c h a r s e t ) $ / . test ( k ) ) {
141
172
if ( type . call ( v ) == ARRAY ) {
142
173
for ( kk = 0 ; kk < v . length ; kk ++ ) {
@@ -162,27 +193,32 @@ function at(k, v, buf, prefix, rawPrefix, vendors, local, ns){
162
193
buf . c ( '}\n' )
163
194
164
195
} else if ( / ^ @ e x t e n d s ? $ / . test ( k ) ) {
165
-
166
- /*eslint-disable no-cond-assign*/
167
- // pick the last class to be extended
168
- while ( kk = findClass . exec ( rawPrefix ) ) k = kk [ 4 ]
169
- /*eslint-enable no-cond-assign*/
170
- if ( k == null || ! local ) {
171
- // we're in a @global{} block
172
- buf . a ( '@-error-cannot-extend-in-global-context ' , JSON . stringify ( rawPrefix ) , ';\n' )
173
- return
174
- } else if ( / ^ @ e x t e n d s ? $ / . test ( k ) ) {
175
- // no class in the selector
176
- buf . a ( '@-error-no-class-to-extend-in ' , JSON . stringify ( rawPrefix ) , ';\n' )
196
+ if ( ! local ) {
197
+ buf . c ( '@-error-cannot-extend-in-global-context ' , JSON . stringify ( rawPrefix ) , ';\n' )
177
198
return
178
199
}
179
- ns . e (
180
- type . call ( v ) == ARRAY ? v . map ( function ( parent ) {
181
- return parent . replace ( / ( ) (?: : g l o b a l \( \s * ( \. [ - \w ] + ) \s * \) | ( ) \. ( [ - \w ] + ) ) / , ns . l )
182
- } ) . join ( ' ' ) : v . replace ( / ( ) (?: : g l o b a l \( \s * ( \. [ - \w ] + ) \s * \) | ( ) \. ( [ - \w ] + ) ) / , ns . l ) ,
183
- k
184
- )
185
-
200
+ rawPrefix = splitSelector ( rawPrefix )
201
+ for ( i = 0 ; i < rawPrefix . length ; i ++ ) {
202
+ /*eslint-disable no-cond-assign*/
203
+ // pick the last class to be extended
204
+ while ( kk = findClass . exec ( rawPrefix [ i ] ) ) k = kk [ 4 ]
205
+ /*eslint-enable no-cond-assign*/
206
+ if ( k == null ) {
207
+ // the last class is a :global(.one)
208
+ buf . c ( '@-error-cannot-extend-in-global-context ' , JSON . stringify ( rawPrefix [ i ] ) , ';\n' )
209
+ continue
210
+ } else if ( / ^ @ e x t e n d s ? $ / . test ( k ) ) {
211
+ // no class in the selector, therefore `k` hasn't been overwritten.
212
+ buf . c ( '@-error-no-class-to-extend-in ' , JSON . stringify ( rawPrefix [ i ] ) , ';\n' )
213
+ continue
214
+ }
215
+ ns . e (
216
+ type . call ( v ) == ARRAY ? v . map ( function ( parent ) {
217
+ return parent . replace ( / ( ) (?: : g l o b a l \( \s * ( \. [ - \w ] + ) \s * \) | ( ) \. ( [ - \w ] + ) ) / , ns . l )
218
+ } ) . join ( ' ' ) : v . replace ( / ( ) (?: : g l o b a l \( \s * ( \. [ - \w ] + ) \s * \) | ( ) \. ( [ - \w ] + ) ) / , ns . l ) ,
219
+ k
220
+ )
221
+ }
186
222
} else if ( / ^ @ (?: f o n t - f a c e $ | v i e w p o r t $ | p a g e ) / . test ( k ) ) {
187
223
if ( type . call ( v ) === ARRAY ) {
188
224
for ( kk = 0 ; kk < v . length ; kk ++ ) {
@@ -212,28 +248,6 @@ function at(k, v, buf, prefix, rawPrefix, vendors, local, ns){
212
248
}
213
249
}
214
250
215
- // This will split a coma-separated selector list into individual selectors,
216
- // ignoring comas in strings and in :pseudo-selectors(parameter, lists).
217
- // regexp generated by scripts/regexps.js then trimmed by hand
218
- var selectorTokenizer = / [ ( ) , ] | " (?: \\ .| [ ^ " \n ] ) * " | ' (?: \\ .| [ ^ ' \n ] ) * ' | \/ \* [ \s \S ] * ?\* \/ / g
219
-
220
- function splitSelector ( selector ) {
221
- var indices = [ ] , res = [ ] , inParen = 0 , match , i
222
- while ( match = selectorTokenizer . exec ( selector ) ) {
223
- switch ( match [ 0 ] ) {
224
- case '(' : inParen ++ ; break
225
- case ')' : inParen -- ; break
226
- case ',' : if ( inParen ) break ; indices . push ( match . index )
227
- }
228
- }
229
- for ( i = indices . length ; i -- ; ) {
230
- res . unshift ( selector . slice ( indices [ i ] + 1 ) )
231
- selector = selector . slice ( 0 , indices [ i ] )
232
- }
233
- res . unshift ( selector )
234
- return res
235
- }
236
-
237
251
/**
238
252
* Add rulesets and other CSS statements to the sheet.
239
253
*
0 commit comments