@ -10,6 +10,7 @@ import { get_attribute_chunks, is_text_attribute } from '../../../utils/ast.js';
* stylesheet : Compiler . Css . StyleSheet ;
* element : Compiler . AST . RegularElement | Compiler . AST . SvelteElement ;
* from _render _tag : boolean ;
* inside _not : boolean ;
* } } State
* /
/** @typedef {NODE_PROBABLY_EXISTS | NODE_DEFINITELY_EXISTS} NodeExistsValue */
@ -61,9 +62,13 @@ export function prune(stylesheet, element) {
const parent = get _element _parent ( element ) ;
if ( ! parent ) return ;
walk ( stylesheet , { stylesheet , element : parent , from _render _tag : true } , visitors ) ;
walk (
stylesheet ,
{ stylesheet , element : parent , from _render _tag : true , inside _not : false } ,
visitors
) ;
} else {
walk ( stylesheet , { stylesheet , element , from _render _tag : false } , visitors ) ;
walk ( stylesheet , { stylesheet , element , from _render _tag : false , inside _not : false } , visitors ) ;
}
}
@ -127,7 +132,7 @@ const visitors = {
selectors _to _check ,
/** @type {Compiler.Css.Rule} */ ( node . metadata . rule ) ,
element ,
context . state . stylesheet
context . state
)
) {
mark ( inner , element ) ;
@ -143,7 +148,7 @@ const visitors = {
selectors ,
/** @type {Compiler.Css.Rule} */ ( node . metadata . rule ) ,
context . state . element ,
context . state . stylesheet
context . state
)
) {
mark ( inner , context . state . element ) ;
@ -188,10 +193,10 @@ function truncate(node) {
* @ param { Compiler . Css . RelativeSelector [ ] } relative _selectors
* @ param { Compiler . Css . Rule } rule
* @ param { Compiler . AST . RegularElement | Compiler . AST . SvelteElement } element
* @ param { Compiler. Css . StyleSheet } stylesheet
* @ param { State} state
* @ returns { boolean }
* /
function apply _selector ( relative _selectors , rule , element , st ylesheet ) {
function apply _selector ( relative _selectors , rule , element , st ate ) {
const parent _selectors = relative _selectors . slice ( ) ;
const relative _selector = parent _selectors . pop ( ) ;
@ -201,7 +206,7 @@ function apply_selector(relative_selectors, rule, element, stylesheet) {
relative _selector ,
rule ,
element ,
st ylesheet
st ate
) ;
if ( ! possible _match ) {
@ -215,14 +220,14 @@ function apply_selector(relative_selectors, rule, element, stylesheet) {
parent _selectors ,
rule ,
element ,
st ylesheet
st ate
) ;
}
// if this is the left-most non-global selector, mark it — we want
// `x y z {...}` to become `x.blah y z.blah {...}`
const parent = parent _selectors [ parent _selectors . length - 1 ] ;
if ( ! parent || is _global ( parent , rule ) ) {
if ( ! state. inside _not && ( ! parent || is _global ( parent , rule ) ) ) {
mark ( relative _selector , element ) ;
}
@ -235,17 +240,10 @@ function apply_selector(relative_selectors, rule, element, stylesheet) {
* @ param { Compiler . Css . RelativeSelector [ ] } parent _selectors
* @ param { Compiler . Css . Rule } rule
* @ param { Compiler . AST . RegularElement | Compiler . AST . SvelteElement } element
* @ param { Compiler. Css . StyleSheet } stylesheet
* @ param { State} state
* @ returns { boolean }
* /
function apply _combinator (
combinator ,
relative _selector ,
parent _selectors ,
rule ,
element ,
stylesheet
) {
function apply _combinator ( combinator , relative _selector , parent _selectors , rule , element , state ) {
const name = combinator . name ;
switch ( name ) {
@ -269,9 +267,9 @@ function apply_combinator(
}
if ( parent . type === 'RegularElement' || parent . type === 'SvelteElement' ) {
if ( apply _selector ( parent _selectors , rule , parent , st ylesheet ) ) {
if ( apply _selector ( parent _selectors , rule , parent , st ate ) ) {
// TODO the `name === ' '` causes false positives, but removing it causes false negatives...
if ( name === ' ' || crossed _component _boundary ) {
if ( ! state . inside _not && ( name === ' ' || crossed _component _boundary ) ) {
mark ( parent _selectors [ parent _selectors . length - 1 ] , parent ) ;
}
@ -297,11 +295,15 @@ function apply_combinator(
if ( possible _sibling . type === 'RenderTag' || possible _sibling . type === 'SlotElement' ) {
// `{@render foo()}<p>foo</p>` with `:global(.x) + p` is a match
if ( parent _selectors . length === 1 && parent _selectors [ 0 ] . metadata . is _global ) {
mark ( relative _selector , element ) ;
if ( ! state . inside _not ) {
mark ( relative _selector , element ) ;
}
sibling _matched = true ;
}
} else if ( apply _selector ( parent _selectors , rule , possible _sibling , stylesheet ) ) {
mark ( relative _selector , element ) ;
} else if ( apply _selector ( parent _selectors , rule , possible _sibling , state ) ) {
if ( ! state . inside _not ) {
mark ( relative _selector , element ) ;
}
sibling _matched = true ;
}
}
@ -381,10 +383,10 @@ const regex_backslash_and_following_character = /\\(.)/g;
* @ param { Compiler . Css . RelativeSelector } relative _selector
* @ param { Compiler . Css . Rule } rule
* @ param { Compiler . AST . RegularElement | Compiler . AST . SvelteElement } element
* @ param { Compiler. Css . StyleSheet } stylesheet
* @ param { State} state
* @ returns { boolean }
* /
function relative _selector _might _apply _to _node ( relative _selector , rule , element , st ylesheet ) {
function relative _selector _might _apply _to _node ( relative _selector , rule , element , st ate ) {
// Sort :has(...) selectors in one bucket and everything else into another
const has _selectors = [ ] ;
const other _selectors = [ ] ;
@ -458,7 +460,7 @@ function relative_selector_might_apply_to_node(relative_selector, rule, element,
if (
selectors . length === 0 /* is :global(...) */ ||
( element . metadata . scoped && selector _matched ) ||
apply _selector ( selectors , rule , element , st ylesheet )
apply _selector ( selectors , rule , element , st ate )
) {
complex _selector . metadata . used = true ;
selector _matched = matched = true ;
@ -504,7 +506,7 @@ function relative_selector_might_apply_to_node(relative_selector, rule, element,
) {
const args = selector . args ;
const complex _selector = args . children [ 0 ] ;
return apply _selector ( complex _selector . children , rule , element , st ylesheet ) ;
return apply _selector ( complex _selector . children , rule , element , st ate ) ;
}
// We came across a :global, everything beyond it is global and therefore a potential match
@ -515,12 +517,37 @@ function relative_selector_might_apply_to_node(relative_selector, rule, element,
for ( const complex _selector of selector . args . children ) {
const relative = truncate ( complex _selector ) ;
if (
relative . length === 0 /* is :global(...) */ ||
apply _selector ( relative , rule , element , stylesheet )
const is _global = relative . length === 0 ;
if ( is _global ) {
complex _selector . metadata . used = true ;
matched = true ;
} else if ( name !== 'not' && apply _selector ( relative , rule , element , state ) ) {
complex _selector . metadata . used = true ;
matched = true ;
} else if (
name === 'not' &&
! apply _selector ( relative , rule , element , { ... state , inside _not : true } )
) {
// For `:not(...)` we gotta do the inverse: If it did not match, mark the element and possibly
// everything above (if the selector is written is a such) as scoped (because they matched by not matching).
element . metadata . scoped = true ;
complex _selector . metadata . used = true ;
matched = true ;
for ( const r of relative ) {
r . metadata . scoped = true ;
}
// bar:not(foo bar) means that foo is an ancestor of bar
if ( complex _selector . children . length > 1 ) {
/** @type {Compiler.AST.RegularElement | Compiler.AST.SvelteElement | null} */
let el = get _element _parent ( element ) ;
while ( el ) {
el . metadata . scoped = true ;
el = get _element _parent ( el ) ;
}
}
} else if ( complex _selector . children . length > 1 && ( name == 'is' || name == 'where' ) ) {
// foo :is(bar baz) can also mean that bar is an ancestor of foo, and baz a descendant.
// We can't fully check if that actually matches with our current algorithm, so we just assume it does.
@ -618,7 +645,7 @@ function relative_selector_might_apply_to_node(relative_selector, rule, element,
const parent = /** @type {Compiler.Css.Rule} */ ( rule . metadata . parent _rule ) ;
for ( const complex _selector of parent . prelude . children ) {
if ( apply _selector ( truncate ( complex _selector ) , parent , element , st ylesheet ) ) {
if ( apply _selector ( truncate ( complex _selector ) , parent , element , st ate ) ) {
complex _selector . metadata . used = true ;
matched = true ;
}