@ -7,7 +7,6 @@ import { get_attribute_chunks, is_text_attribute } from '../../../utils/ast.js';
/ * *
* @ typedef { {
* stylesheet : Compiler . Css . StyleSheet ;
* element : Compiler . AST . RegularElement | Compiler . AST . SvelteElement ;
* from _render _tag : boolean ;
* } } State
@ -61,9 +60,9 @@ 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 , { element: parent , from _render _tag : true } , visitors ) ;
} else {
walk ( stylesheet , { stylesheet, element, from _render _tag : false } , visitors ) ;
walk ( stylesheet , { element, from _render _tag : false } , visitors ) ;
}
}
@ -882,117 +881,63 @@ function get_element_parent(node) {
}
/ * *
* Finds the given node ' s previous sibling in the DOM
*
* The Svelte ` <slot> ` is just a placeholder and is not actually real . Any children nodes
* in ` <slot> ` are 'flattened' and considered as the same level as the ` <slot> ` ' s siblings
*
* e . g .
* ` ` ` html
* < h1 > Heading 1 < / h 1 >
* < slot >
* < h2 > Heading 2 < / h 2 >
* < / s l o t >
* ` ` `
*
* is considered to look like :
* ` ` ` html
* < h1 > Heading 1 < / h 1 >
* < h2 > Heading 2 < / h 2 >
* ` ` `
* @ param { Compiler . SvelteNode } node
* @ returns { Compiler . SvelteNode }
* /
function find _previous _sibling ( node ) {
/** @type {Compiler.SvelteNode} */
let current _node = node ;
while (
// @ts-expect-error TODO
! current _node . prev &&
// @ts-expect-error TODO
current _node . parent ? . type === 'SlotElement'
) {
// @ts-expect-error TODO
current _node = current _node . parent ;
}
// @ts-expect-error
current _node = current _node . prev ;
while ( current _node ? . type === 'SlotElement' ) {
const slot _children = current _node . fragment . nodes ;
if ( slot _children . length > 0 ) {
current _node = slot _children [ slot _children . length - 1 ] ;
} else {
break ;
}
}
return current _node ;
}
/ * *
* @ param { Compiler . SvelteNode } node
* @ param { Compiler . AST . RegularElement | Compiler . AST . SvelteElement } element
* @ param { boolean } adjacent _only
* @ returns { Map < Compiler . AST . RegularElement | Compiler . AST . SvelteElement | Compiler . AST . SlotElement | Compiler . AST . RenderTag , NodeExistsValue > }
* /
function get _possible _element _siblings ( node , adjacent _only ) {
function get _possible _element _siblings ( element , adjacent _only ) {
/** @type {Map<Compiler.AST.RegularElement | Compiler.AST.SvelteElement | Compiler.AST.SlotElement | Compiler.AST.RenderTag, NodeExistsValue>} */
const result = new Map ( ) ;
const path = element . metadata . path ;
/** @type {Compiler.SvelteNode} */
let prev = node ;
while ( ( prev = find _previous _sibling ( prev ) ) ) {
if ( prev . type === 'RegularElement' ) {
if (
! prev . attributes . find (
let current = element ;
let i = path . length ;
while ( i -- ) {
const fragment = /** @type {Compiler.AST.Fragment} */ ( path [ i -- ] ) ;
let j = fragment . nodes . indexOf ( current ) ;
while ( j -- ) {
const node = fragment . nodes [ j ] ;
if ( node . type === 'RegularElement' ) {
const has _slot _attribute = node . attributes . some (
( attr ) => attr . type === 'Attribute' && attr . name . toLowerCase ( ) === 'slot'
)
) {
result . set ( prev , NODE _DEFINITELY _EXISTS ) ;
}
if ( adjacent _only ) {
break ;
}
} else if ( is _block ( prev ) ) {
const possible _last _child = get _possible _last _child ( prev , adjacent _only ) ;
add _to _map ( possible _last _child , result ) ;
if ( adjacent _only && has _definite _elements ( possible _last _child ) ) {
return result ;
}
} else if (
prev . type === 'SlotElement' ||
prev . type === 'RenderTag' ||
prev . type === 'SvelteElement'
) {
result . set ( prev , NODE _PROBABLY _EXISTS ) ;
// Special case: slots, render tags and svelte:element tags could resolve to no siblings,
// so we want to continue until we find a definite sibling even with the adjacent-only combinator
}
}
) ;
if ( ! prev || ! adjacent _only ) {
/** @type {Compiler.SvelteNode | null} */
let parent = node ;
if ( ! has _slot _attribute ) {
result . set ( node , NODE _DEFINITELY _EXISTS ) ;
while (
// @ts-expect-error TODO
( parent = parent ? . parent ) &&
is _block ( parent )
) {
const possible _siblings = get _possible _element _siblings ( parent , adjacent _only ) ;
add _to _map ( possible _siblings , result ) ;
if ( adjacent _only ) {
return result ;
}
}
} else if ( is _block ( node ) ) {
if ( node . type === 'SlotElement' ) {
result . set ( node , NODE _PROBABLY _EXISTS ) ;
}
// @ts-expect-error
if ( parent . type === 'EachBlock' && ! parent . fallback ? . nodes . includes ( node ) ) {
// `{#each ...}<a /><b />{/each}` — `<b>` can be previous sibling of `<a />`
add _to _map ( get _possible _last _child ( parent , adjacent _only ) , result ) ;
const possible _last _child = get _possible _last _child ( node , adjacent _only ) ;
add _to _map ( possible _last _child , result ) ;
if ( adjacent _only && has _definite _elements ( possible _last _child ) ) {
return result ;
}
} else if ( node . type === 'RenderTag' || node . type === 'SvelteElement' ) {
result . set ( node , NODE _PROBABLY _EXISTS ) ;
// Special case: slots, render tags and svelte:element tags could resolve to no siblings,
// so we want to continue until we find a definite sibling even with the adjacent-only combinator
}
}
if ( adjacent _only && has _definite _elements ( possible _siblings ) ) {
break ;
}
current = path [ i ] ;
if ( ! current || ! is _block ( current ) ) break ;
if ( current . type === 'EachBlock' && fragment === current . body ) {
// `{#each ...}<a /><b />{/each}` — `<b>` can be previous sibling of `<a />`
add _to _map ( get _possible _last _child ( current , adjacent _only ) , result ) ;
}
}
@ -1000,7 +945,7 @@ function get_possible_element_siblings(node, adjacent_only) {
}
/ * *
* @ param { Compiler . AST . EachBlock | Compiler . AST . IfBlock | Compiler . AST . AwaitBlock | Compiler . AST . KeyBlock } node
* @ param { Compiler . AST . EachBlock | Compiler . AST . IfBlock | Compiler . AST . AwaitBlock | Compiler . AST . KeyBlock | Compiler . AST . SlotElement } node
* @ param { boolean } adjacent _only
* @ returns { Map < Compiler . AST . RegularElement , NodeExistsValue > }
* /
@ -1024,6 +969,7 @@ function get_possible_last_child(node, adjacent_only) {
break ;
case 'KeyBlock' :
case 'SlotElement' :
fragments . push ( node . fragment ) ;
break ;
}
@ -1031,7 +977,7 @@ function get_possible_last_child(node, adjacent_only) {
/** @type {NodeMap} */
const result = new Map ( ) ;
let exhaustive = true ;
let exhaustive = node . type !== 'SlotElement' ;
for ( const fragment of fragments ) {
if ( fragment == null ) {
@ -1123,13 +1069,14 @@ function loop_child(children, adjacent_only) {
/ * *
* @ param { Compiler . SvelteNode } node
* @ returns { node is Compiler . AST . IfBlock | Compiler . AST . EachBlock | Compiler . AST . AwaitBlock | Compiler . AST . KeyBlock }
* @ returns { node is Compiler . AST . IfBlock | Compiler . AST . EachBlock | Compiler . AST . AwaitBlock | Compiler . AST . KeyBlock | Compiler . AST . SlotElement }
* /
function is _block ( node ) {
return (
node . type === 'IfBlock' ||
node . type === 'EachBlock' ||
node . type === 'AwaitBlock' ||
node . type === 'KeyBlock'
node . type === 'KeyBlock' ||
node . type === 'SlotElement'
) ;
}