1
- import { get_possible_values } from './gather_possible_values .js' ;
2
- import { regex_starts_with_whitespace , regex_ends_with_whitespace } from '../.. /patterns.js' ;
3
- import { error } from '../../../ errors.js' ;
1
+ import { get_possible_values } from './utils .js' ;
2
+ import { regex_starts_with_whitespace , regex_ends_with_whitespace } from '../phases /patterns.js' ;
3
+ import { error } from '../errors.js' ;
4
4
import { Stylesheet , Rule } from './Stylesheet.js' ;
5
5
6
6
const NO_MATCH = 'NO_MATCH' ;
@@ -14,8 +14,6 @@ const NodeExist = /** @type {const} */ ({
14
14
15
15
/**
16
16
* @typedef {typeof NodeExist[keyof typeof NodeExist] } NodeExistsValue
17
- * @typedef {Array<RelativeSelector> } ComplexSelector
18
- * @typedef {Array<ComplexSelector> } SelectorList
19
17
* @typedef {import("#compiler").Css.SimpleSelector & { use_wrapper: { used: boolean }, visible: boolean } } SimpleSelectorWithData
20
18
* */
21
19
@@ -24,23 +22,23 @@ const whitelist_attribute_selector = new Map([
24
22
[ 'dialog' , new Set ( [ 'open' ] ) ]
25
23
] ) ;
26
24
27
- export default class Selector {
28
- /** @type {import('#compiler').Css.Selector } */
25
+ export class ComplexSelector {
26
+ /** @type {import('#compiler').Css.ComplexSelector } */
29
27
node ;
30
28
31
29
/** @type {Stylesheet } */
32
30
stylesheet ;
33
31
34
- /** @type {SelectorList } */
32
+ /** @type {RelativeSelector[][] } */
35
33
selector_list ;
36
34
37
- /** @type {SelectorList } */
35
+ /** @type {RelativeSelector[][] } */
38
36
local_selector_list ;
39
37
40
38
used = false ;
41
39
42
40
/**
43
- * @param {import('#compiler').Css.Selector } node
41
+ * @param {import('#compiler').Css.ComplexSelector } node
44
42
* @param {Stylesheet } stylesheet
45
43
* @param {Rule } rule
46
44
*/
@@ -150,7 +148,7 @@ export default class Selector {
150
148
}
151
149
}
152
150
153
- /** @param {import('../.. /types.js').ComponentAnalysis } analysis */
151
+ /** @param {import('../phases /types.js').ComponentAnalysis } analysis */
154
152
validate ( analysis ) {
155
153
this . validate_global_placement ( ) ;
156
154
this . validate_global_with_multiple_selectors ( ) ;
@@ -197,7 +195,7 @@ export default class Selector {
197
195
}
198
196
}
199
197
200
- /** @param {import('../.. /types.js').ComponentAnalysis } analysis */
198
+ /** @param {import('../phases /types.js').ComponentAnalysis } analysis */
201
199
validate_invalid_combinator_without_selector ( analysis ) {
202
200
for ( const complex_selector of this . selector_list ) {
203
201
for ( const relative_selector of complex_selector ) {
@@ -238,20 +236,22 @@ export default class Selector {
238
236
}
239
237
240
238
/**
241
- * @param {RelativeSelector[] } blocks
239
+ * @param {RelativeSelector[] } relative_selectors
242
240
* @param {import('#compiler').RegularElement | import('#compiler').SvelteElement | null } node
243
241
* @param {Stylesheet } stylesheet
244
242
* @returns {boolean }
245
243
*/
246
- function apply_selector ( blocks , node , stylesheet ) {
247
- const block = blocks . pop ( ) ;
248
- if ( ! block ) return false ;
244
+ function apply_selector ( relative_selectors , node , stylesheet ) {
245
+ const relative_selector = relative_selectors . pop ( ) ;
246
+ if ( ! relative_selector ) return false ;
249
247
if ( ! node ) {
250
248
return (
251
- ( block . global && blocks . every ( ( block ) => block . global ) ) || ( block . host && blocks . length === 0 )
249
+ ( relative_selector . global &&
250
+ relative_selectors . every ( ( relative_selector ) => relative_selector . global ) ) ||
251
+ ( relative_selector . host && relative_selectors . length === 0 )
252
252
) ;
253
253
}
254
- const applies = block_might_apply_to_node ( block , node ) ;
254
+ const applies = block_might_apply_to_node ( relative_selector , node ) ;
255
255
256
256
if ( applies === NO_MATCH ) {
257
257
return false ;
@@ -260,28 +260,31 @@ function apply_selector(blocks, node, stylesheet) {
260
260
/**
261
261
* Mark both the compound selector and the node it selects as encapsulated,
262
262
* for transformation in a later step
263
- * @param {RelativeSelector } block
263
+ * @param {RelativeSelector } relative_selector
264
264
* @param {import('#compiler').RegularElement | import('#compiler').SvelteElement } node
265
265
*/
266
- function mark ( block , node ) {
267
- block . should_encapsulate = true ;
266
+ function mark ( relative_selector , node ) {
267
+ relative_selector . should_encapsulate = true ;
268
268
stylesheet . nodes_with_css_class . add ( node ) ;
269
269
return true ;
270
270
}
271
271
272
272
if ( applies === UNKNOWN_SELECTOR ) {
273
- return mark ( block , node ) ;
273
+ return mark ( relative_selector , node ) ;
274
274
}
275
275
276
- if ( block . combinator ) {
277
- if ( block . combinator . type === 'Combinator' && block . combinator . name === ' ' ) {
278
- for ( const ancestor_block of blocks ) {
276
+ if ( relative_selector . combinator ) {
277
+ if (
278
+ relative_selector . combinator . type === 'Combinator' &&
279
+ relative_selector . combinator . name === ' '
280
+ ) {
281
+ for ( const ancestor_block of relative_selectors ) {
279
282
if ( ancestor_block . global ) {
280
283
continue ;
281
284
}
282
285
283
286
if ( ancestor_block . host ) {
284
- return mark ( block , node ) ;
287
+ return mark ( relative_selector , node ) ;
285
288
}
286
289
287
290
/** @type {import('#compiler').RegularElement | import('#compiler').SvelteElement | null } */
@@ -294,40 +297,51 @@ function apply_selector(blocks, node, stylesheet) {
294
297
}
295
298
}
296
299
if ( matched ) {
297
- return mark ( block , node ) ;
300
+ return mark ( relative_selector , node ) ;
298
301
}
299
302
}
300
303
301
- if ( blocks . every ( ( block ) => block . global ) ) {
302
- return mark ( block , node ) ;
304
+ if ( relative_selectors . every ( ( relative_selector ) => relative_selector . global ) ) {
305
+ return mark ( relative_selector , node ) ;
303
306
}
304
307
305
308
return false ;
306
- } else if ( block . combinator . name === '>' ) {
307
- const has_global_parent = blocks . every ( ( block ) => block . global ) ;
308
- if ( has_global_parent || apply_selector ( blocks , get_element_parent ( node ) , stylesheet ) ) {
309
- return mark ( block , node ) ;
309
+ } else if ( relative_selector . combinator . name === '>' ) {
310
+ const has_global_parent = relative_selectors . every (
311
+ ( relative_selector ) => relative_selector . global
312
+ ) ;
313
+ if (
314
+ has_global_parent ||
315
+ apply_selector ( relative_selectors , get_element_parent ( node ) , stylesheet )
316
+ ) {
317
+ return mark ( relative_selector , node ) ;
310
318
}
311
319
312
320
return false ;
313
- } else if ( block . combinator . name === '+' || block . combinator . name === '~' ) {
314
- const siblings = get_possible_element_siblings ( node , block . combinator . name === '+' ) ;
321
+ } else if (
322
+ relative_selector . combinator . name === '+' ||
323
+ relative_selector . combinator . name === '~'
324
+ ) {
325
+ const siblings = get_possible_element_siblings (
326
+ node ,
327
+ relative_selector . combinator . name === '+'
328
+ ) ;
315
329
let has_match = false ;
316
330
317
331
// NOTE: if we have :global(), we couldn't figure out what is selected within `:global` due to the
318
332
// css-tree limitation that does not parse the inner selector of :global
319
333
// so unless we are sure there will be no sibling to match, we will consider it as matched
320
- const has_global = blocks . some ( ( block ) => block . global ) ;
334
+ const has_global = relative_selectors . some ( ( relative_selector ) => relative_selector . global ) ;
321
335
if ( has_global ) {
322
336
if ( siblings . size === 0 && get_element_parent ( node ) !== null ) {
323
337
return false ;
324
338
}
325
- return mark ( block , node ) ;
339
+ return mark ( relative_selector , node ) ;
326
340
}
327
341
328
342
for ( const possible_sibling of siblings . keys ( ) ) {
329
- if ( apply_selector ( blocks . slice ( ) , possible_sibling , stylesheet ) ) {
330
- mark ( block , node ) ;
343
+ if ( apply_selector ( relative_selectors . slice ( ) , possible_sibling , stylesheet ) ) {
344
+ mark ( relative_selector , node ) ;
331
345
has_match = true ;
332
346
}
333
347
}
@@ -336,25 +350,25 @@ function apply_selector(blocks, node, stylesheet) {
336
350
}
337
351
338
352
// TODO other combinators
339
- return mark ( block , node ) ;
353
+ return mark ( relative_selector , node ) ;
340
354
}
341
355
342
- return mark ( block , node ) ;
356
+ return mark ( relative_selector , node ) ;
343
357
}
344
358
345
359
const regex_backslash_and_following_character = / \\ ( .) / g;
346
360
347
361
/**
348
- * @param {RelativeSelector } block
362
+ * @param {RelativeSelector } relative_selector
349
363
* @param {import('#compiler').RegularElement | import('#compiler').SvelteElement } node
350
364
* @returns {NO_MATCH | POSSIBLE_MATCH | UNKNOWN_SELECTOR }
351
365
*/
352
- function block_might_apply_to_node ( block , node ) {
353
- if ( block . host || block . root ) return NO_MATCH ;
366
+ function block_might_apply_to_node ( relative_selector , node ) {
367
+ if ( relative_selector . host || relative_selector . root ) return NO_MATCH ;
354
368
355
- let i = block . compound . selectors . length ;
369
+ let i = relative_selector . compound . selectors . length ;
356
370
while ( i -- ) {
357
- const selector = block . compound . selectors [ i ] ;
371
+ const selector = relative_selector . compound . selectors [ i ] ;
358
372
359
373
if ( selector . type === 'Percentage' || selector . type === 'Nth' ) continue ;
360
374
@@ -364,7 +378,7 @@ function block_might_apply_to_node(block, node) {
364
378
return NO_MATCH ;
365
379
}
366
380
if (
367
- block . compound . selectors . length === 1 &&
381
+ relative_selector . compound . selectors . length === 1 &&
368
382
selector . type === 'PseudoClassSelector' &&
369
383
name === 'global'
370
384
) {
@@ -683,22 +697,22 @@ function get_possible_element_siblings(node, adjacent_only) {
683
697
}
684
698
685
699
/**
686
- * @param {import('#compiler').EachBlock | import('#compiler').IfBlock | import('#compiler').AwaitBlock } block
700
+ * @param {import('#compiler').EachBlock | import('#compiler').IfBlock | import('#compiler').AwaitBlock } relative_selector
687
701
* @param {boolean } adjacent_only
688
702
* @returns {Map<import('#compiler').RegularElement, NodeExistsValue> }
689
703
*/
690
- function get_possible_last_child ( block , adjacent_only ) {
704
+ function get_possible_last_child ( relative_selector , adjacent_only ) {
691
705
/** @typedef {Map<import('#compiler').RegularElement, NodeExistsValue> } NodeMap */
692
706
693
707
/** @type {NodeMap } */
694
708
const result = new Map ( ) ;
695
- if ( block . type === 'EachBlock' ) {
709
+ if ( relative_selector . type === 'EachBlock' ) {
696
710
/** @type {NodeMap } */
697
- const each_result = loop_child ( block . body . nodes , adjacent_only ) ;
711
+ const each_result = loop_child ( relative_selector . body . nodes , adjacent_only ) ;
698
712
699
713
/** @type {NodeMap } */
700
- const else_result = block . fallback
701
- ? loop_child ( block . fallback . nodes , adjacent_only )
714
+ const else_result = relative_selector . fallback
715
+ ? loop_child ( relative_selector . fallback . nodes , adjacent_only )
702
716
: new Map ( ) ;
703
717
const not_exhaustive = ! has_definite_elements ( else_result ) ;
704
718
if ( not_exhaustive ) {
@@ -707,13 +721,13 @@ function get_possible_last_child(block, adjacent_only) {
707
721
}
708
722
add_to_map ( each_result , result ) ;
709
723
add_to_map ( else_result , result ) ;
710
- } else if ( block . type === 'IfBlock' ) {
724
+ } else if ( relative_selector . type === 'IfBlock' ) {
711
725
/** @type {NodeMap } */
712
- const if_result = loop_child ( block . consequent . nodes , adjacent_only ) ;
726
+ const if_result = loop_child ( relative_selector . consequent . nodes , adjacent_only ) ;
713
727
714
728
/** @type {NodeMap } */
715
- const else_result = block . alternate
716
- ? loop_child ( block . alternate . nodes , adjacent_only )
729
+ const else_result = relative_selector . alternate
730
+ ? loop_child ( relative_selector . alternate . nodes , adjacent_only )
717
731
: new Map ( ) ;
718
732
const not_exhaustive = ! has_definite_elements ( if_result ) || ! has_definite_elements ( else_result ) ;
719
733
if ( not_exhaustive ) {
@@ -722,17 +736,21 @@ function get_possible_last_child(block, adjacent_only) {
722
736
}
723
737
add_to_map ( if_result , result ) ;
724
738
add_to_map ( else_result , result ) ;
725
- } else if ( block . type === 'AwaitBlock' ) {
739
+ } else if ( relative_selector . type === 'AwaitBlock' ) {
726
740
/** @type {NodeMap } */
727
- const pending_result = block . pending
728
- ? loop_child ( block . pending . nodes , adjacent_only )
741
+ const pending_result = relative_selector . pending
742
+ ? loop_child ( relative_selector . pending . nodes , adjacent_only )
729
743
: new Map ( ) ;
730
744
731
745
/** @type {NodeMap } */
732
- const then_result = block . then ? loop_child ( block . then . nodes , adjacent_only ) : new Map ( ) ;
746
+ const then_result = relative_selector . then
747
+ ? loop_child ( relative_selector . then . nodes , adjacent_only )
748
+ : new Map ( ) ;
733
749
734
750
/** @type {NodeMap } */
735
- const catch_result = block . catch ? loop_child ( block . catch . nodes , adjacent_only ) : new Map ( ) ;
751
+ const catch_result = relative_selector . catch
752
+ ? loop_child ( relative_selector . catch . nodes , adjacent_only )
753
+ : new Map ( ) ;
736
754
const not_exhaustive =
737
755
! has_definite_elements ( pending_result ) ||
738
756
! has_definite_elements ( then_result ) ||
@@ -933,9 +951,9 @@ class CompoundSelector {
933
951
/**
934
952
* Groups selectors and inserts parent blocks into nested rules.
935
953
*
936
- * @param {import('#compiler').Css.Selector } selector - The selector to group and analyze.
954
+ * @param {import('#compiler').Css.ComplexSelector } selector - The selector to group and analyze.
937
955
* @param {Rule } rule
938
- * @returns {SelectorList } - The grouped selectors with parent's blocks inserted if nested.
956
+ * @returns {RelativeSelector[][] } - The grouped selectors with parent's blocks inserted if nested.
939
957
*/
940
958
function group_selectors ( selector , rule ) {
941
959
// TODO this logic isn't quite right, as it doesn't properly account for atrules
@@ -945,21 +963,19 @@ function group_selectors(selector, rule) {
945
963
. flat ( ) ;
946
964
947
965
return parent_selector_list . map ( ( parent_complex_selector ) => {
948
- const block_group = selector_to_blocks (
966
+ return selector_to_blocks (
949
967
[ ...selector . children ] ,
950
968
[ ...parent_complex_selector ] // Clone the parent's blocks to avoid modifying the original array
951
969
) ;
952
-
953
- return block_group ;
954
970
} ) ;
955
971
}
956
972
957
973
return [ selector_to_blocks ( [ ...selector . children ] , null ) ] ;
958
974
}
959
975
960
976
/**
961
- * @param {import('#compiler').Css.Selector ["children"] } children
962
- * @param {ComplexSelector | null } parent_complex_selector - The parent rule's selectors to insert/swap into the nesting selector positions.
977
+ * @param {import('#compiler').Css.ComplexSelector ["children"] } children
978
+ * @param {RelativeSelector[] | null } parent_complex_selector - The parent rule's selectors to insert/swap into the nesting selector positions.
963
979
*/
964
980
function selector_to_blocks ( children , parent_complex_selector ) {
965
981
let block = new RelativeSelector ( null , new CompoundSelector ( ) ) ;
@@ -997,8 +1013,8 @@ function selector_to_blocks(children, parent_complex_selector) {
997
1013
}
998
1014
999
1015
/**
1000
- * @param {ComplexSelector } parent_complex_selector - The parent blocks to insert into the nesting selector positions.
1001
- * @returns {import('#compiler').Css.Selector ["children"] } - The parent selectors to insert into the nesting selector positions.
1016
+ * @param {RelativeSelector[] } parent_complex_selector - The parent blocks to insert into the nesting selector positions.
1017
+ * @returns {import('#compiler').Css.ComplexSelector ["children"] } - The parent selectors to insert into the nesting selector positions.
1002
1018
*/
1003
1019
function get_parent_selectors ( parent_complex_selector ) {
1004
1020
const parent_selectors = [ ] ;
@@ -1027,8 +1043,8 @@ function get_parent_selectors(parent_complex_selector) {
1027
1043
* b { c & { color: red }} -> so we need to insert ' ' after c so children needs to look like [c, " ",b]
1028
1044
* .x { & { color: red }} -> no combinator, so children needs to look like .x.x
1029
1045
*
1030
- * @param {import('#compiler').Css.Selector ["children"] } children
1031
- * @param {ComplexSelector } parent_complex_selector - The parent blocks to insert into the nesting selector positions.
1046
+ * @param {import('#compiler').Css.ComplexSelector ["children"] } children
1047
+ * @param {RelativeSelector[] } parent_complex_selector - The parent blocks to insert into the nesting selector positions.
1032
1048
*/
1033
1049
function nest_fake_parents ( children , parent_complex_selector ) {
1034
1050
const nested_selector_indexes = children . reduce ( ( indexes , child , index ) => {
0 commit comments