make get_possible_element_siblings non-recursive

pull/14446/head
Rich Harris 2 years ago
parent 4f0dde5207
commit 6c1a39fff1

@ -932,66 +932,66 @@ function find_previous_sibling(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();
/** @type {Compiler.SvelteNode} */
let prev = node;
while ((prev = find_previous_sibling(prev))) {
if (prev.type === 'RegularElement') {
const has_slot_attribute = prev.attributes.some(
(attr) => attr.type === 'Attribute' && attr.name.toLowerCase() === 'slot'
);
let node = element;
let path = element.metadata.path;
let i = path.length;
while (i--) {
let current = node;
while ((node = find_previous_sibling(node))) {
if (node.type === 'RegularElement') {
const has_slot_attribute = node.attributes.some(
(attr) => attr.type === 'Attribute' && attr.name.toLowerCase() === 'slot'
);
if (!has_slot_attribute) {
result.set(prev, NODE_DEFINITELY_EXISTS);
if (!has_slot_attribute) {
result.set(node, NODE_DEFINITELY_EXISTS);
if (adjacent_only) {
if (adjacent_only) {
return result;
}
}
} else if (is_block(node)) {
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 === 'SlotElement' ||
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
}
} 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
}
}
/** @type {Compiler.SvelteNode | null} */
let parent = node;
let parent = path[i];
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 (parent.type === 'Fragment') {
parent = path[--i];
}
if (!parent || !is_block(parent)) break;
// @ts-expect-error
if (parent.type === 'EachBlock' && !parent.fallback?.nodes.includes(node)) {
if (parent.type === 'EachBlock' && !parent.fallback?.nodes.includes(current)) {
// `{#each ...}<a /><b />{/each}` — `<b>` can be previous sibling of `<a />`
add_to_map(get_possible_last_child(parent, adjacent_only), result);
}
if (adjacent_only && has_definite_elements(possible_siblings)) {
break;
}
node = parent;
}
return result;

Loading…
Cancel
Save