From 4bc135aaa5ceae83f765f460dd1f3263088b83a1 Mon Sep 17 00:00:00 2001 From: paoloricciuti Date: Mon, 8 Jun 2026 08:54:18 +0200 Subject: [PATCH] fix: update test renderer to output actual dom nodes when interleaving --- .../svelte/tests/custom-renderers/renderer.ts | 68 ++++++++++++++++--- 1 file changed, 57 insertions(+), 11 deletions(-) diff --git a/packages/svelte/tests/custom-renderers/renderer.ts b/packages/svelte/tests/custom-renderers/renderer.ts index 674ac510e6..2ba9f8346d 100644 --- a/packages/svelte/tests/custom-renderers/renderer.ts +++ b/packages/svelte/tests/custom-renderers/renderer.ts @@ -13,6 +13,7 @@ type ObjElement = { name: string; attributes: Record; children: ObjNode[]; + elements_children: Array; listeners: Record>; parent: ObjNode | null; }; @@ -21,9 +22,13 @@ type ObjComment = { type: 'comment'; value: string; parent: ObjNode | null; - before: (node: any) => void; }; -type ObjFragment = { type: 'fragment'; children: ObjNode[]; parent: ObjNode | null }; +export type ObjFragment = { + type: 'fragment'; + children: ObjNode[]; + parent: ObjNode | null; + elements_children: Array; +}; type ObjNode = ObjElement | ObjText | ObjComment | ObjFragment; function insert_node( @@ -32,6 +37,10 @@ function insert_node( anchor: ObjNode | null ) { if (node.type === 'fragment') { + if (parent.type === 'element' || parent.type === 'fragment') { + parent.elements_children = node.elements_children; + } + const children = [...(node.children ?? [])]; for (const child of children) { insert_node(parent, child, anchor); @@ -69,19 +78,31 @@ function remove_from_parent(node: ObjNode) { children.splice(idx, 1); } -export const dom_elements: Array = []; +const mounted_in_dom_elements = new Map(); + +const mounted = new Map< + HTMLElement | DocumentFragment | Text | Comment, + ObjElement | ObjFragment +>(); const renderer = createRenderer<{ fragment: ObjFragment; element: ObjElement; text: ObjText; comment: ObjComment; + foreign: { + comment: Comment; + element: HTMLElement; + text: Text; + fragment: DocumentFragment; + }; }>({ createFragment() { return { type: 'fragment', children: [], - parent: null + parent: null, + elements_children: [] }; }, @@ -92,7 +113,8 @@ const renderer = createRenderer<{ attributes: {}, children: [], listeners: {}, - parent: null + parent: null, + elements_children: [] }; }, @@ -108,12 +130,7 @@ const renderer = createRenderer<{ return { type: 'comment', value: data, - parent: null, - // adding this allows for this renderer to interleave with a DOM-based renderer - // the argument will be the DOM node that represent a DOM Component being mounted - before(node) { - dom_elements.push(node); - } + parent: null }; }, @@ -189,6 +206,35 @@ const renderer = createRenderer<{ target.listeners[type] = target.listeners[type].filter( (/** @type {any} */ l) => l.handler !== handler ); + }, + + foreign: { + insertForeign(parent, element, anchor) { + parent.elements_children.push(element); + mounted.set(element, parent); + }, + removeForeign(node) { + const parent = mounted.get(node); + if (!parent) return; + const idx = parent.elements_children.indexOf(node); + if (idx !== -1) parent.elements_children.splice(idx, 1); + mounted.delete(node); + }, + insertIntoForeign(parent, element, anchor) { + const custom_rendered = document.createElement('custom-rendered'); + custom_rendered.textContent = JSON.stringify(element, (key, value) => { + if (key === 'parent') return undefined; + return value; + }); + parent.insertBefore(custom_rendered, anchor); + mounted_in_dom_elements.set(element, custom_rendered); + }, + removeFromForeign(node) { + const custom_rendered_node = mounted_in_dom_elements.get(node); + if (!custom_rendered_node) return; + custom_rendered_node.parentNode?.removeChild(custom_rendered_node); + mounted_in_dom_elements.delete(node); + } } });