@@ -7,13 +7,15 @@ import { is_keyframes_node } from '../../css.js';
7
7
import { is_global , is_unscoped_pseudo_class } from './utils.js' ;
8
8
9
9
/**
10
- * @typedef {Visitors<
11
- * AST.CSS.Node,
12
- * {
13
- * keyframes: string[];
14
- * rule: AST.CSS.Rule | null;
15
- * }
16
- * >} CssVisitors
10
+ * @typedef {{
11
+ * keyframes: string[];
12
+ * rule: AST.CSS.Rule | null;
13
+ * analysis: ComponentAnalysis;
14
+ * }} CssState
15
+ */
16
+
17
+ /**
18
+ * @typedef {Visitors<AST.CSS.Node, CssState> } CssVisitors
17
19
*/
18
20
19
21
/**
@@ -28,6 +30,15 @@ function is_global_block_selector(simple_selector) {
28
30
) ;
29
31
}
30
32
33
+ /**
34
+ * @param {AST.SvelteNode[] } path
35
+ */
36
+ function is_unscoped ( path ) {
37
+ return path
38
+ . filter ( ( node ) => node . type === 'Rule' )
39
+ . every ( ( node ) => node . metadata . has_global_selectors ) ;
40
+ }
41
+
31
42
/**
32
43
*
33
44
* @param {Array<AST.CSS.Node> } path
@@ -42,6 +53,9 @@ const css_visitors = {
42
53
if ( is_keyframes_node ( node ) ) {
43
54
if ( ! node . prelude . startsWith ( '-global-' ) && ! is_in_global_block ( context . path ) ) {
44
55
context . state . keyframes . push ( node . prelude ) ;
56
+ } else if ( node . prelude . startsWith ( '-global-' ) ) {
57
+ // we don't check if the block.children.length because the keyframe is still added even if empty
58
+ context . state . analysis . css . has_global ||= is_unscoped ( context . path ) ;
45
59
}
46
60
}
47
61
@@ -99,10 +113,12 @@ const css_visitors = {
99
113
100
114
node . metadata . rule = context . state . rule ;
101
115
102
- node . metadata . used || = node . children . every (
116
+ node . metadata . is_global = node . children . every (
103
117
( { metadata } ) => metadata . is_global || metadata . is_global_like
104
118
) ;
105
119
120
+ node . metadata . used ||= node . metadata . is_global ;
121
+
106
122
if (
107
123
node . metadata . rule ?. metadata . parent_rule &&
108
124
node . children [ 0 ] ?. selectors [ 0 ] ?. type === 'NestingSelector'
@@ -190,6 +206,7 @@ const css_visitors = {
190
206
191
207
if ( idx !== - 1 ) {
192
208
is_global_block = true ;
209
+
193
210
for ( let i = idx + 1 ; i < child . selectors . length ; i ++ ) {
194
211
walk ( /** @type {AST.CSS.Node } */ ( child . selectors [ i ] ) , null , {
195
212
ComplexSelector ( node ) {
@@ -242,16 +259,26 @@ const css_visitors = {
242
259
}
243
260
}
244
261
245
- context . next ( {
246
- ...context . state ,
247
- rule : node
248
- } ) ;
262
+ const state = { ...context . state , rule : node } ;
249
263
250
- node . metadata . has_local_selectors = node . prelude . children . some ( ( selector ) => {
251
- return selector . children . some (
252
- ( { metadata } ) => ! metadata . is_global && ! metadata . is_global_like
253
- ) ;
254
- } ) ;
264
+ // visit selector list first, to populate child selector metadata
265
+ context . visit ( node . prelude , state ) ;
266
+
267
+ for ( const selector of node . prelude . children ) {
268
+ node . metadata . has_global_selectors ||= selector . metadata . is_global ;
269
+ node . metadata . has_local_selectors ||= ! selector . metadata . is_global ;
270
+ }
271
+
272
+ // if this rule has a ComplexSelector whose RelativeSelector children are all
273
+ // `:global(...)`, and the rule contains declarations (rather than just
274
+ // nested rules) then the component as a whole includes global CSS
275
+ context . state . analysis . css . has_global ||=
276
+ node . metadata . has_global_selectors &&
277
+ node . block . children . filter ( ( child ) => child . type === 'Declaration' ) . length > 0 &&
278
+ is_unscoped ( context . path ) ;
279
+
280
+ // visit block list, so parent rule metadata is populated
281
+ context . visit ( node . block , state ) ;
255
282
} ,
256
283
NestingSelector ( node , context ) {
257
284
const rule = /** @type {AST.CSS.Rule } */ ( context . state . rule ) ;
@@ -289,5 +316,12 @@ const css_visitors = {
289
316
* @param {ComponentAnalysis } analysis
290
317
*/
291
318
export function analyze_css ( stylesheet , analysis ) {
292
- walk ( stylesheet , { keyframes : analysis . css . keyframes , rule : null } , css_visitors ) ;
319
+ /** @type {CssState } */
320
+ const css_state = {
321
+ keyframes : analysis . css . keyframes ,
322
+ rule : null ,
323
+ analysis
324
+ } ;
325
+
326
+ walk ( stylesheet , css_state , css_visitors ) ;
293
327
}
0 commit comments