@@ -138,8 +138,9 @@ function apply_selector(stylesheet: Stylesheet, blocks: Block[], node: Node, sta
138
138
139
139
while ( i -- ) {
140
140
const selector = block . selectors [ i ] ;
141
+ const name = typeof selector . name === 'string' && selector . name . replace ( / \\ ( .) / g, '$1' ) ;
141
142
142
- if ( selector . type === 'PseudoClassSelector' && selector . name === 'global' ) {
143
+ if ( selector . type === 'PseudoClassSelector' && name === 'global' ) {
143
144
// TODO shouldn't see this here... maybe we should enforce that :global(...)
144
145
// cannot be sandwiched between non-global selectors?
145
146
return false ;
@@ -150,20 +151,19 @@ function apply_selector(stylesheet: Stylesheet, blocks: Block[], node: Node, sta
150
151
}
151
152
152
153
if ( selector . type === 'ClassSelector' ) {
153
- if ( ! attribute_matches ( node , 'class' , selector . name , '~=' , false ) && ! class_matches ( node , selector . name ) ) return false ;
154
+ if ( ! attribute_matches ( node , 'class' , name , '~=' , false ) && ! node . classes . some ( c => c . name === name ) ) return false ;
154
155
}
155
156
156
157
else if ( selector . type === 'IdSelector' ) {
157
- if ( ! attribute_matches ( node , 'id' , selector . name , '=' , false ) ) return false ;
158
+ if ( ! attribute_matches ( node , 'id' , name , '=' , false ) ) return false ;
158
159
}
159
160
160
161
else if ( selector . type === 'AttributeSelector' ) {
161
162
if ( ! attribute_matches ( node , selector . name . name , selector . value && unquote ( selector . value ) , selector . matcher , selector . flags ) ) return false ;
162
163
}
163
164
164
165
else if ( selector . type === 'TypeSelector' ) {
165
- // remove toLowerCase() in v2, when uppercase elements will be forbidden
166
- if ( node . name . toLowerCase ( ) !== selector . name . toLowerCase ( ) && selector . name !== '*' ) return false ;
166
+ if ( node . name . toLowerCase ( ) !== name . toLowerCase ( ) && name !== '*' ) return false ;
167
167
}
168
168
169
169
else {
@@ -206,14 +206,21 @@ function apply_selector(stylesheet: Stylesheet, blocks: Block[], node: Node, sta
206
206
return true ;
207
207
}
208
208
209
- const operators = {
210
- '=' : ( value : string , flags : string ) => new RegExp ( `^${ value } $` , flags ) ,
211
- '~=' : ( value : string , flags : string ) => new RegExp ( `\\b${ value } \\b` , flags ) ,
212
- '|=' : ( value : string , flags : string ) => new RegExp ( `^${ value } (-.+)?$` , flags ) ,
213
- '^=' : ( value : string , flags : string ) => new RegExp ( `^${ value } ` , flags ) ,
214
- '$=' : ( value : string , flags : string ) => new RegExp ( `${ value } $` , flags ) ,
215
- '*=' : ( value : string , flags : string ) => new RegExp ( value , flags )
216
- } ;
209
+ function test_attribute ( operator , expected_value , case_insensitive , value ) {
210
+ if ( case_insensitive ) {
211
+ expected_value = expected_value . toLowerCase ( ) ;
212
+ value = value . toLowerCase ( ) ;
213
+ }
214
+ switch ( operator ) {
215
+ case '=' : return value === expected_value ;
216
+ case '~=' : return ` ${ value } ` . includes ( ` ${ expected_value } ` ) ;
217
+ case '|=' : return `${ value } -` . startsWith ( `${ expected_value } -` ) ;
218
+ case '^=' : return value . startsWith ( expected_value ) ;
219
+ case '$=' : return value . endsWith ( expected_value ) ;
220
+ case '*=' : return value . includes ( expected_value ) ;
221
+ default : throw new Error ( `this shouldn't happen` ) ;
222
+ }
223
+ }
217
224
218
225
function attribute_matches ( node : Node , name : string , expected_value : string , operator : string , case_insensitive : boolean ) {
219
226
const spread = node . attributes . find ( attr => attr . type === 'Spread' ) ;
@@ -227,29 +234,22 @@ function attribute_matches(node: Node, name: string, expected_value: string, ope
227
234
if ( attr . chunks . length > 1 ) return true ;
228
235
if ( ! expected_value ) return true ;
229
236
230
- const pattern = operators [ operator ] ( expected_value , case_insensitive ? 'i' : '' ) ;
231
237
const value = attr . chunks [ 0 ] ;
232
238
233
239
if ( ! value ) return false ;
234
- if ( value . type === 'Text' ) return pattern . test ( value . data ) ;
240
+ if ( value . type === 'Text' ) return test_attribute ( operator , expected_value , case_insensitive , value . data ) ;
235
241
236
242
const possible_values = new Set ( ) ;
237
243
gather_possible_values ( value . node , possible_values ) ;
238
244
if ( possible_values . has ( UNKNOWN ) ) return true ;
239
245
240
- for ( const x of Array . from ( possible_values ) ) { // TypeScript for-of is slightly unlike JS
241
- if ( pattern . test ( x ) ) return true ;
246
+ for ( const value of possible_values ) {
247
+ if ( test_attribute ( operator , expected_value , case_insensitive , value ) ) return true ;
242
248
}
243
249
244
250
return false ;
245
251
}
246
252
247
- function class_matches ( node , name : string ) {
248
- return node . classes . some ( ( class_directive ) => {
249
- return new RegExp ( `\\b${ name } \\b` ) . test ( class_directive . name ) ;
250
- } ) ;
251
- }
252
-
253
253
function unquote ( value : Node ) {
254
254
if ( value . type === 'Identifier' ) return value . name ;
255
255
const str = value . value ;
0 commit comments