44import { walk } from 'zimmerframe' ;
55import * as e from '../../../errors.js' ;
66import { is_keyframes_node } from '../../css.js' ;
7- import { merge } from '../../visitors.js' ;
87
98/**
109 * @typedef {Visitors<
@@ -50,17 +49,66 @@ function is_global_block_selector(simple_selector) {
5049}
5150
5251/** @type {CssVisitors } */
53- const analysis_visitors = {
52+ const css_visitors = {
5453 Atrule ( node , context ) {
5554 if ( is_keyframes_node ( node ) ) {
5655 if ( ! node . prelude . startsWith ( '-global-' ) ) {
5756 context . state . keyframes . push ( node . prelude ) ;
5857 }
5958 }
59+
60+ context . next ( ) ;
6061 } ,
6162 ComplexSelector ( node , context ) {
6263 context . next ( ) ; // analyse relevant selectors first
6364
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+
64112 node . metadata . rule = context . state . rule ;
65113
66114 node . metadata . used ||= node . children . every (
@@ -119,22 +167,6 @@ const analysis_visitors = {
119167 return is_global_block ;
120168 } ) ;
121169
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 ) {
138170 if ( node . metadata . is_global_block ) {
139171 if ( node . prelude . children . length > 1 ) {
140172 e . css_global_block_invalid_list ( node . prelude ) ;
@@ -174,59 +206,21 @@ const validation_visitors = {
174206 }
175207 }
176208
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+ } ) ;
213213
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+ } ) ;
226219 } ,
227220 NestingSelector ( node , context ) {
228221 const rule = /** @type {Css.Rule } */ ( context . state . rule ) ;
229222 const parent_rule = rule . metadata . parent_rule ;
223+
230224 if ( ! parent_rule ) {
231225 e . css_nesting_selector_invalid_placement ( node ) ;
232226 } else if (
@@ -238,11 +232,11 @@ const validation_visitors = {
238232 ) {
239233 e . css_global_block_invalid_modifier_start ( node ) ;
240234 }
235+
236+ context . next ( ) ;
241237 }
242238} ;
243239
244- const css_visitors = merge ( analysis_visitors , validation_visitors ) ;
245-
246240/**
247241 * @param {Css.StyleSheet } stylesheet
248242 * @param {ComponentAnalysis } analysis
0 commit comments