4
4
import { walk } from 'zimmerframe' ;
5
5
import * as e from '../../../errors.js' ;
6
6
import { is_keyframes_node } from '../../css.js' ;
7
- import { merge } from '../../visitors.js' ;
8
7
9
8
/**
10
9
* @typedef {Visitors<
@@ -50,17 +49,66 @@ function is_global_block_selector(simple_selector) {
50
49
}
51
50
52
51
/** @type {CssVisitors } */
53
- const analysis_visitors = {
52
+ const css_visitors = {
54
53
Atrule ( node , context ) {
55
54
if ( is_keyframes_node ( node ) ) {
56
55
if ( ! node . prelude . startsWith ( '-global-' ) ) {
57
56
context . state . keyframes . push ( node . prelude ) ;
58
57
}
59
58
}
59
+
60
+ context . next ( ) ;
60
61
} ,
61
62
ComplexSelector ( node , context ) {
62
63
context . next ( ) ; // analyse relevant selectors first
63
64
65
+ {
66
+ const global = node . children . find ( is_global ) ;
67
+
68
+ if ( global ) {
69
+ const idx = node . children . indexOf ( global ) ;
70
+
71
+ if ( global . selectors [ 0 ] . args !== null && idx !== 0 && idx !== node . children . length - 1 ) {
72
+ // ensure `:global(...)` is not used in the middle of a selector (but multiple `global(...)` in sequence are ok)
73
+ for ( let i = idx + 1 ; i < node . children . length ; i ++ ) {
74
+ if ( ! is_global ( node . children [ i ] ) ) {
75
+ e . css_global_invalid_placement ( global . selectors [ 0 ] ) ;
76
+ }
77
+ }
78
+ }
79
+ }
80
+ }
81
+
82
+ // ensure `:global(...)` do not lead to invalid css after `:global()` is removed
83
+ for ( const relative_selector of node . children ) {
84
+ for ( let i = 0 ; i < relative_selector . selectors . length ; i ++ ) {
85
+ const selector = relative_selector . selectors [ i ] ;
86
+
87
+ if ( selector . type === 'PseudoClassSelector' && selector . name === 'global' ) {
88
+ const child = selector . args ?. children [ 0 ] . children [ 0 ] ;
89
+ // ensure `:global(element)` to be at the first position in a compound selector
90
+ if ( child ?. selectors [ 0 ] . type === 'TypeSelector' && i !== 0 ) {
91
+ e . css_global_invalid_selector_list ( selector ) ;
92
+ }
93
+
94
+ // ensure `:global(.class)` is not followed by a type selector, eg: `:global(.class)element`
95
+ if ( relative_selector . selectors [ i + 1 ] ?. type === 'TypeSelector' ) {
96
+ e . css_type_selector_invalid_placement ( relative_selector . selectors [ i + 1 ] ) ;
97
+ }
98
+
99
+ // ensure `:global(...)`contains a single selector
100
+ // (standalone :global() with multiple selectors is OK)
101
+ if (
102
+ selector . args !== null &&
103
+ selector . args . children . length > 1 &&
104
+ ( node . children . length > 1 || relative_selector . selectors . length > 1 )
105
+ ) {
106
+ e . css_global_invalid_selector ( selector ) ;
107
+ }
108
+ }
109
+ }
110
+ }
111
+
64
112
node . metadata . rule = context . state . rule ;
65
113
66
114
node . metadata . used ||= node . children . every (
@@ -119,22 +167,6 @@ const analysis_visitors = {
119
167
return is_global_block ;
120
168
} ) ;
121
169
122
- context . next ( {
123
- ...context . state ,
124
- rule : node
125
- } ) ;
126
-
127
- node . metadata . has_local_selectors = node . prelude . children . some ( ( selector ) => {
128
- return selector . children . some (
129
- ( { metadata } ) => ! metadata . is_global && ! metadata . is_global_like
130
- ) ;
131
- } ) ;
132
- }
133
- } ;
134
-
135
- /** @type {CssVisitors } */
136
- const validation_visitors = {
137
- Rule ( node , context ) {
138
170
if ( node . metadata . is_global_block ) {
139
171
if ( node . prelude . children . length > 1 ) {
140
172
e . css_global_block_invalid_list ( node . prelude ) ;
@@ -174,59 +206,21 @@ const validation_visitors = {
174
206
}
175
207
}
176
208
177
- context . next ( ) ;
178
- } ,
179
- ComplexSelector ( node ) {
180
- {
181
- const global = node . children . find ( is_global ) ;
182
-
183
- if ( global ) {
184
- const idx = node . children . indexOf ( global ) ;
185
-
186
- if ( global . selectors [ 0 ] . args !== null && idx !== 0 && idx !== node . children . length - 1 ) {
187
- // ensure `:global(...)` is not used in the middle of a selector (but multiple `global(...)` in sequence are ok)
188
- for ( let i = idx + 1 ; i < node . children . length ; i ++ ) {
189
- if ( ! is_global ( node . children [ i ] ) ) {
190
- e . css_global_invalid_placement ( global . selectors [ 0 ] ) ;
191
- }
192
- }
193
- }
194
- }
195
- }
196
-
197
- // ensure `:global(...)` do not lead to invalid css after `:global()` is removed
198
- for ( const relative_selector of node . children ) {
199
- for ( let i = 0 ; i < relative_selector . selectors . length ; i ++ ) {
200
- const selector = relative_selector . selectors [ i ] ;
201
-
202
- if ( selector . type === 'PseudoClassSelector' && selector . name === 'global' ) {
203
- const child = selector . args ?. children [ 0 ] . children [ 0 ] ;
204
- // ensure `:global(element)` to be at the first position in a compound selector
205
- if ( child ?. selectors [ 0 ] . type === 'TypeSelector' && i !== 0 ) {
206
- e . css_global_invalid_selector_list ( selector ) ;
207
- }
208
-
209
- // ensure `:global(.class)` is not followed by a type selector, eg: `:global(.class)element`
210
- if ( relative_selector . selectors [ i + 1 ] ?. type === 'TypeSelector' ) {
211
- e . css_type_selector_invalid_placement ( relative_selector . selectors [ i + 1 ] ) ;
212
- }
209
+ context . next ( {
210
+ ...context . state ,
211
+ rule : node
212
+ } ) ;
213
213
214
- // ensure `:global(...)`contains a single selector
215
- // (standalone :global() with multiple selectors is OK)
216
- if (
217
- selector . args !== null &&
218
- selector . args . children . length > 1 &&
219
- ( node . children . length > 1 || relative_selector . selectors . length > 1 )
220
- ) {
221
- e . css_global_invalid_selector ( selector ) ;
222
- }
223
- }
224
- }
225
- }
214
+ node . metadata . has_local_selectors = node . prelude . children . some ( ( selector ) => {
215
+ return selector . children . some (
216
+ ( { metadata } ) => ! metadata . is_global && ! metadata . is_global_like
217
+ ) ;
218
+ } ) ;
226
219
} ,
227
220
NestingSelector ( node , context ) {
228
221
const rule = /** @type {Css.Rule } */ ( context . state . rule ) ;
229
222
const parent_rule = rule . metadata . parent_rule ;
223
+
230
224
if ( ! parent_rule ) {
231
225
e . css_nesting_selector_invalid_placement ( node ) ;
232
226
} else if (
@@ -238,11 +232,11 @@ const validation_visitors = {
238
232
) {
239
233
e . css_global_block_invalid_modifier_start ( node ) ;
240
234
}
235
+
236
+ context . next ( ) ;
241
237
}
242
238
} ;
243
239
244
- const css_visitors = merge ( analysis_visitors , validation_visitors ) ;
245
-
246
240
/**
247
241
* @param {Css.StyleSheet } stylesheet
248
242
* @param {ComponentAnalysis } analysis
0 commit comments