diff --git a/packages/svelte/src/internal/client/constants.js b/packages/svelte/src/internal/client/constants.js index 032b6c3e2b..190a947af8 100644 --- a/packages/svelte/src/internal/client/constants.js +++ b/packages/svelte/src/internal/client/constants.js @@ -69,7 +69,6 @@ export const STALE_REACTION = new (class StaleReactionError extends Error { message = 'The reaction that called `getAbortSignal()` was re-run or destroyed'; })(); -// TODO: DOM access export const IS_XHTML = // We gotta write it like this because after downleveling the pure comment may end up in the wrong location !!globalThis.document?.contentType && diff --git a/packages/svelte/src/internal/client/dev/css.js b/packages/svelte/src/internal/client/dev/css.js index 96f67f7d10..cc868e92fa 100644 --- a/packages/svelte/src/internal/client/dev/css.js +++ b/packages/svelte/src/internal/client/dev/css.js @@ -1,3 +1,5 @@ +import { remove_node } from '../dom/operations'; + /** @type {Map>} */ var all_styles = new Map(); @@ -24,7 +26,7 @@ export function cleanup_styles(hash) { if (!styles) return; for (const style of styles) { - style.remove(); + remove_node(style); } all_styles.delete(hash); diff --git a/packages/svelte/src/internal/client/dev/elements.js b/packages/svelte/src/internal/client/dev/elements.js index df765607a0..c0a2c14a85 100644 --- a/packages/svelte/src/internal/client/dev/elements.js +++ b/packages/svelte/src/internal/client/dev/elements.js @@ -3,6 +3,7 @@ import { COMMENT_NODE, DOCUMENT_FRAGMENT_NODE, ELEMENT_NODE } from '#client/cons import { HYDRATION_END, HYDRATION_START } from '../../../constants.js'; import { hydrating } from '../dom/hydration.js'; import { dev_stack } from '../context.js'; +import { get_first_child, get_next_sibling, get_node_value, node_type } from '../dom/operations.js'; /** * @param {any} fn @@ -14,7 +15,12 @@ export function add_locations(fn, filename, locations) { return (/** @type {any[]} */ ...args) => { const dom = fn(...args); - var node = hydrating ? dom : dom.nodeType === DOCUMENT_FRAGMENT_NODE ? dom.firstChild : dom; + // check here + var node = hydrating + ? dom + : node_type(dom) === DOCUMENT_FRAGMENT_NODE + ? get_first_child(dom) + : dom; assign_locations(node, filename, locations); return dom; @@ -28,13 +34,14 @@ export function add_locations(fn, filename, locations) { */ function assign_location(element, filename, location) { // @ts-expect-error + // TODO RENDERER: what if the element is not an object? element.__svelte_meta = { parent: dev_stack, loc: { file: filename, line: location[0], column: location[1] } }; if (location[2]) { - assign_locations(element.firstChild, filename, location[2]); + assign_locations(get_first_child(element), filename, location[2]); } } @@ -48,16 +55,17 @@ function assign_locations(node, filename, locations) { var depth = 0; while (node && i < locations.length) { - if (hydrating && node.nodeType === COMMENT_NODE) { + if (hydrating && node_type(node) === COMMENT_NODE) { var comment = /** @type {Comment} */ (node); - if (comment.data[0] === HYDRATION_START) depth += 1; - else if (comment.data[0] === HYDRATION_END) depth -= 1; + const data = get_node_value(comment) ?? ''; + if (data[0] === HYDRATION_START) depth += 1; + else if (data[0] === HYDRATION_END) depth -= 1; } - if (depth === 0 && node.nodeType === ELEMENT_NODE) { + if (depth === 0 && node_type(node) === ELEMENT_NODE) { assign_location(/** @type {Element} */ (node), filename, locations[i++]); } - node = node.nextSibling; + node = get_next_sibling(node); } } diff --git a/packages/svelte/src/internal/client/dev/validation.js b/packages/svelte/src/internal/client/dev/validation.js index 60d140c718..1fc4f3540e 100644 --- a/packages/svelte/src/internal/client/dev/validation.js +++ b/packages/svelte/src/internal/client/dev/validation.js @@ -4,6 +4,7 @@ import * as e from '../errors.js'; * @param {...(()=>any)[]} args */ export function validate_snippet_args(anchor, ...args) { + // TODO RENDERER: don't emit validate args for custom renderers if (typeof anchor !== 'object' || !(anchor instanceof Node)) { e.invalid_snippet_arguments(); } diff --git a/packages/svelte/src/internal/client/dom/blocks/await.js b/packages/svelte/src/internal/client/dom/blocks/await.js index d6430547b5..4b70e38a0e 100644 --- a/packages/svelte/src/internal/client/dom/blocks/await.js +++ b/packages/svelte/src/internal/client/dom/blocks/await.js @@ -15,6 +15,7 @@ import { is_runes } from '../../context.js'; import { Batch, current_batch, flushSync, is_flushing_sync } from '../../reactivity/batch.js'; import { BranchManager } from './branches.js'; import { capture, unset_context } from '../../reactivity/async.js'; +import { get_node_value } from '../operations.js'; const PENDING = 0; const THEN = 1; @@ -57,7 +58,8 @@ export function await_block(node, get_input, pending_fn, then_fn, catch_fn) { /** Whether or not there was a hydration mismatch. Needs to be a `let` or else it isn't treeshaken out */ // @ts-ignore coercing `node` to a `Comment` causes TypeScript and Prettier to fight - let mismatch = hydrating && is_promise(input) === (node.data === HYDRATION_START_ELSE); + let mismatch = + hydrating && is_promise(input) === (get_node_value(node) === HYDRATION_START_ELSE); if (mismatch) { // Hydration mismatch: remove everything inside the anchor and start fresh diff --git a/packages/svelte/src/internal/client/dom/blocks/css-props.js b/packages/svelte/src/internal/client/dom/blocks/css-props.js index 084a5561be..ea8b268ff6 100644 --- a/packages/svelte/src/internal/client/dom/blocks/css-props.js +++ b/packages/svelte/src/internal/client/dom/blocks/css-props.js @@ -1,6 +1,6 @@ import { render_effect } from '../../reactivity/effects.js'; import { hydrating, set_hydrate_node } from '../hydration.js'; -import { get_first_child } from '../operations.js'; +import { get_first_child, style_set_property, style_remove_property } from '../operations.js'; /** * @param {HTMLDivElement | SVGGElement} element @@ -19,9 +19,9 @@ export function css_props(element, get_styles) { var value = styles[key]; if (value) { - element.style.setProperty(key, value); + style_set_property(/** @type {HTMLElement} */ (element), key, value); } else { - element.style.removeProperty(key); + style_remove_property(/** @type {HTMLElement} */ (element), key); } } }); diff --git a/packages/svelte/src/internal/client/dom/blocks/html.js b/packages/svelte/src/internal/client/dom/blocks/html.js index ffe947eb16..cda857c9bc 100644 --- a/packages/svelte/src/internal/client/dom/blocks/html.js +++ b/packages/svelte/src/internal/client/dom/blocks/html.js @@ -14,7 +14,17 @@ import * as w from '../../warnings.js'; import { hash, sanitize_location } from '../../../../utils.js'; import { DEV } from 'esm-env'; import { dev_current_component_function } from '../../context.js'; -import { create_element, get_first_child, get_next_sibling } from '../operations.js'; +import { + create_element, + get_first_child, + get_next_sibling, + get_last_child, + set_inner_html, + insert_before, + get_parent_node, + node_type, + get_node_value +} from '../operations.js'; import { active_effect } from '../../runtime.js'; import { COMMENT_NODE } from '#client/constants'; @@ -81,12 +91,12 @@ export function html( // When @html is the only child, use innerHTML directly. // This also handles contenteditable, where the user may delete the anchor comment. effect.nodes = null; - parent_node.innerHTML = /** @type {string} */ (value); + set_inner_html(parent_node, /** @type {string} */ (value)); if (value !== '') { assign_nodes( /** @type {TemplateNode} */ (get_first_child(parent_node)), - /** @type {TemplateNode} */ (parent_node.lastChild) + /** @type {TemplateNode} */ (get_last_child(parent_node)) ); } @@ -103,16 +113,13 @@ export function html( if (hydrating) { // We're deliberately not trying to repair mismatches between server and client, // as it's costly and error-prone (and it's an edge case to have a mismatch anyway) - var hash = /** @type {Comment} */ (hydrate_node).data; + var hash = get_node_value(hydrate_node); /** @type {TemplateNode | null} */ var next = hydrate_next(); var last = next; - while ( - next !== null && - (next.nodeType !== COMMENT_NODE || /** @type {Comment} */ (next).data !== '') - ) { + while (next !== null && (node_type(next) !== COMMENT_NODE || get_node_value(next) !== '')) { last = next; next = get_next_sibling(next); } @@ -123,7 +130,7 @@ export function html( } if (DEV && !skip_warning) { - check_hash(/** @type {Element} */ (next.parentNode), hash, value); + check_hash(/** @type {Element} */ (get_parent_node(next)), hash, value); } assign_nodes(hydrate_node, last); @@ -139,22 +146,22 @@ export function html( var wrapper = /** @type {HTMLTemplateElement | SVGElement | MathMLElement} */ ( create_element(svg ? 'svg' : mathml ? 'math' : 'template', ns) ); - wrapper.innerHTML = /** @type {any} */ (value); + set_inner_html(wrapper, /** @type {any} */ (value)); /** @type {DocumentFragment | Element} */ var node = svg || mathml ? wrapper : /** @type {HTMLTemplateElement} */ (wrapper).content; assign_nodes( /** @type {TemplateNode} */ (get_first_child(node)), - /** @type {TemplateNode} */ (node.lastChild) + /** @type {TemplateNode} */ (get_last_child(node)) ); if (svg || mathml) { while (get_first_child(node)) { - anchor.before(/** @type {TemplateNode} */ (get_first_child(node))); + insert_before(anchor, /** @type {TemplateNode} */ (get_first_child(node))); } } else { - anchor.before(node); + insert_before(anchor, node); } }); } diff --git a/packages/svelte/src/internal/client/dom/blocks/snippet.js b/packages/svelte/src/internal/client/dom/blocks/snippet.js index 0c4948aca0..343d510e72 100644 --- a/packages/svelte/src/internal/client/dom/blocks/snippet.js +++ b/packages/svelte/src/internal/client/dom/blocks/snippet.js @@ -13,7 +13,7 @@ import { assign_nodes } from '../template.js'; import * as w from '../../warnings.js'; import * as e from '../../errors.js'; import { DEV } from 'esm-env'; -import { get_first_child, get_next_sibling } from '../operations.js'; +import { get_first_child, get_next_sibling, insert_before, node_type } from '../operations.js'; import { prevent_snippet_stringification } from '../../../shared/validate.js'; import { BranchManager } from './branches.js'; @@ -71,6 +71,7 @@ export function wrap_snippet(component, fn) { * @returns {Snippet} */ export function createRawSnippet(fn) { + // TODO RENDERER: throw an error for createRawSnippet in a non-browser environment, as it relies on DOM APIs // @ts-expect-error the types are a lie return (/** @type {TemplateNode} */ anchor, /** @type {Getters} */ ...params) => { var snippet = fn(...params); @@ -86,11 +87,11 @@ export function createRawSnippet(fn) { var fragment = create_fragment_from_html(html); element = /** @type {Element} */ (get_first_child(fragment)); - if (DEV && (get_next_sibling(element) !== null || element.nodeType !== ELEMENT_NODE)) { + if (DEV && (get_next_sibling(element) !== null || node_type(element) !== ELEMENT_NODE)) { w.invalid_raw_snippet_render(); } - anchor.before(element); + insert_before(anchor, element); } const result = snippet.setup?.(element); diff --git a/packages/svelte/src/internal/client/dom/blocks/svelte-element.js b/packages/svelte/src/internal/client/dom/blocks/svelte-element.js index 6df020d2d7..d11af3dfa4 100644 --- a/packages/svelte/src/internal/client/dom/blocks/svelte-element.js +++ b/packages/svelte/src/internal/client/dom/blocks/svelte-element.js @@ -7,7 +7,15 @@ import { set_hydrate_node, set_hydrating } from '../hydration.js'; -import { create_element, create_text, get_first_child } from '../operations.js'; +import { + create_element, + create_text, + get_first_child, + append_child, + create_comment, + insert_before, + node_type +} from '../operations.js'; import { block, teardown } from '../../reactivity/effects.js'; import { set_should_intro } from '../../render.js'; import { active_effect } from '../../runtime.js'; @@ -40,7 +48,7 @@ export function element(node, get_tag, is_svg, render_fn, get_namespace, locatio /** @type {null | Element} */ var element = null; - if (hydrating && hydrate_node.nodeType === ELEMENT_NODE) { + if (hydrating && node_type(hydrate_node) === ELEMENT_NODE) { element = /** @type {Element} */ (hydrate_node); hydrate_next(); } @@ -90,14 +98,14 @@ export function element(node, get_tag, is_svg, render_fn, get_namespace, locatio if (render_fn) { if (hydrating && is_raw_text_element(next_tag)) { // prevent hydration glitches - element.append(document.createComment('')); + append_child(element, create_comment('')); } // If hydrating, use the existing ssr comment as the anchor so that the // inner open and close methods can pick up the existing nodes correctly var child_anchor = hydrating ? get_first_child(element) - : element.appendChild(create_text()); + : /** @type {Text} */ (append_child(element, create_text())); if (hydrating) { if (child_anchor === null) { @@ -121,7 +129,7 @@ export function element(node, get_tag, is_svg, render_fn, get_namespace, locatio // we do this after calling `render_fn` so that child effects don't override `nodes.end` /** @type {Effect & { nodes: EffectNodes }} */ (active_effect).nodes.end = element; - anchor.before(element); + insert_before(anchor, element); } if (hydrating) { diff --git a/packages/svelte/src/internal/client/dom/blocks/svelte-head.js b/packages/svelte/src/internal/client/dom/blocks/svelte-head.js index 7cab6c3385..11c949f083 100644 --- a/packages/svelte/src/internal/client/dom/blocks/svelte-head.js +++ b/packages/svelte/src/internal/client/dom/blocks/svelte-head.js @@ -1,6 +1,14 @@ /** @import { TemplateNode } from '#client' */ import { hydrate_node, hydrating, set_hydrate_node, set_hydrating } from '../hydration.js'; -import { create_text, get_first_child, get_next_sibling } from '../operations.js'; +import { + create_text, + get_first_child, + get_next_sibling, + remove_node, + append_child, + node_type, + get_node_value +} from '../operations.js'; import { block } from '../../reactivity/effects.js'; import { COMMENT_NODE, EFFECT_PRESERVED, HEAD_EFFECT } from '#client/constants'; @@ -10,6 +18,7 @@ import { COMMENT_NODE, EFFECT_PRESERVED, HEAD_EFFECT } from '#client/constants'; * @returns {void} */ export function head(hash, render_fn) { + // TODO RENDERER: throw in case we are using custom renderers as this rely on the head element // The head function may be called after the first hydration pass and ssr comment nodes may still be present, // therefore we need to skip that when we detect that we're not in hydration mode. let previous_hydrate_node = null; @@ -27,7 +36,7 @@ export function head(hash, render_fn) { // rendered in an arbitrary order — find one corresponding to this component while ( head_anchor !== null && - (head_anchor.nodeType !== COMMENT_NODE || /** @type {Comment} */ (head_anchor).data !== hash) + (node_type(head_anchor) !== COMMENT_NODE || get_node_value(head_anchor) !== hash) ) { head_anchor = get_next_sibling(head_anchor); } @@ -38,14 +47,14 @@ export function head(hash, render_fn) { set_hydrating(false); } else { var start = /** @type {TemplateNode} */ (get_next_sibling(head_anchor)); - head_anchor.remove(); // in case this component is repeated + remove_node(/** @type {ChildNode} */ (head_anchor)); // in case this component is repeated set_hydrate_node(start); } } if (!hydrating) { - anchor = document.head.appendChild(create_text()); + anchor = /** @type {Comment | Text} */ (append_child(document.head, create_text())); } try { diff --git a/packages/svelte/src/internal/client/dom/css.js b/packages/svelte/src/internal/client/dom/css.js index 74bf2d49f9..81256f504d 100644 --- a/packages/svelte/src/internal/client/dom/css.js +++ b/packages/svelte/src/internal/client/dom/css.js @@ -1,29 +1,39 @@ import { DEV } from 'esm-env'; import { register_style } from '../dev/css.js'; import { effect } from '../reactivity/effects.js'; -import { create_element } from './operations.js'; +import { + create_element, + get_root_node, + query_selector, + append_child, + set_text_content +} from './operations.js'; /** * @param {Node} anchor * @param {{ hash: string, code: string }} css */ export function append_styles(anchor, css) { + // TODO RENDERER: disallow css inject with custom renderer? // Use `queue_micro_task` to ensure `anchor` is in the DOM, otherwise getRootNode() will yield wrong results effect(() => { - var root = anchor.getRootNode(); + var root = get_root_node(anchor); + // TODO: DOM access var target = /** @type {ShadowRoot} */ (root).host ? /** @type {ShadowRoot} */ (root) - : /** @type {Document} */ (root).head ?? /** @type {Document} */ (root.ownerDocument).head; + : // TODO: DOM access + /** @type {Document} */ (root).head ?? /** @type {Document} */ (root.ownerDocument).head; // Always querying the DOM is roughly the same perf as additionally checking for presence in a map first assuming // that you'll get cache hits half of the time, so we just always query the dom for simplicity and code savings. - if (!target.querySelector('#' + css.hash)) { + if (!query_selector(/** @type {Element} */ (target), '#' + css.hash)) { const style = create_element('style'); + // TODO: DOM access style.id = css.hash; - style.textContent = css.code; + set_text_content(style, css.code); - target.appendChild(style); + append_child(target, style); if (DEV) { register_style(css.hash, style); diff --git a/packages/svelte/src/internal/client/dom/elements/misc.js b/packages/svelte/src/internal/client/dom/elements/misc.js index f350d1df8c..eec86f0fa0 100644 --- a/packages/svelte/src/internal/client/dom/elements/misc.js +++ b/packages/svelte/src/internal/client/dom/elements/misc.js @@ -1,5 +1,5 @@ import { hydrating } from '../hydration.js'; -import { clear_text_content, get_first_child } from '../operations.js'; +import { clear_text_content, get_first_child, focus, add_event_listener } from '../operations.js'; import { queue_micro_task } from '../task.js'; /** @@ -14,7 +14,7 @@ export function autofocus(dom, value) { queue_micro_task(() => { if (document.activeElement === body) { - dom.focus(); + focus(dom); } }); } @@ -27,6 +27,7 @@ export function autofocus(dom, value) { * @returns {void} */ export function remove_textarea_child(dom) { + // TODO RENDERER: never output in custom render mode if (hydrating && get_first_child(dom) !== null) { clear_text_content(dom); } @@ -35,15 +36,19 @@ export function remove_textarea_child(dom) { let listening_to_form_reset = false; export function add_form_reset_listener() { + // TODO RENDERER: never output in custom render mode if (!listening_to_form_reset) { listening_to_form_reset = true; - document.addEventListener( + // TODO: DOM access + add_event_listener( + document, 'reset', (evt) => { // Needs to happen one tick later or else the dom properties of the form // elements have not updated to their reset values yet Promise.resolve().then(() => { if (!evt.defaultPrevented) { + // TODO: DOM access for (const e of /**@type {HTMLFormElement} */ (evt.target).elements) { // @ts-expect-error e.__on_r?.(); diff --git a/packages/svelte/src/internal/client/dom/hydration.js b/packages/svelte/src/internal/client/dom/hydration.js index 83833f493d..63dea7da5b 100644 --- a/packages/svelte/src/internal/client/dom/hydration.js +++ b/packages/svelte/src/internal/client/dom/hydration.js @@ -8,7 +8,7 @@ import { HYDRATION_START_ELSE } from '../../../constants.js'; import * as w from '../warnings.js'; -import { get_next_sibling } from './operations.js'; +import { get_next_sibling, get_node_value, node_type, remove_node } from './operations.js'; /** * Use this variable to guard everything related to hydration code so it can be treeshaken out @@ -89,8 +89,8 @@ export function skip_nodes(remove = true) { var node = hydrate_node; while (true) { - if (node.nodeType === COMMENT_NODE) { - var data = /** @type {Comment} */ (node).data; + if (node_type(node) === COMMENT_NODE) { + var data = get_node_value(node) ?? ''; if (data === HYDRATION_END) { if (depth === 0) return node; @@ -106,7 +106,7 @@ export function skip_nodes(remove = true) { } var next = /** @type {TemplateNode} */ (get_next_sibling(node)); - if (remove) node.remove(); + if (remove) remove_node(node); node = next; } } @@ -116,10 +116,10 @@ export function skip_nodes(remove = true) { * @param {TemplateNode} node */ export function read_hydration_instruction(node) { - if (!node || node.nodeType !== COMMENT_NODE) { + if (!node || node_type(node) !== COMMENT_NODE) { w.hydration_mismatch(); throw HYDRATION_ERROR; } - return /** @type {Comment} */ (node).data; + return get_node_value(node) ?? ''; } diff --git a/packages/svelte/src/internal/client/dom/reconciler.js b/packages/svelte/src/internal/client/dom/reconciler.js index 294cd9c35d..d0001e1ed2 100644 --- a/packages/svelte/src/internal/client/dom/reconciler.js +++ b/packages/svelte/src/internal/client/dom/reconciler.js @@ -1,4 +1,4 @@ -import { create_element } from './operations.js'; +import { create_element, set_inner_html } from './operations.js'; const policy = // We gotta write it like this because after downleveling the pure comment may end up in the wrong location @@ -20,6 +20,6 @@ export function create_trusted_html(html) { */ export function create_fragment_from_html(html) { var elem = create_element('template'); - elem.innerHTML = create_trusted_html(html.replaceAll('', '')); // XHTML compliance + set_inner_html(elem, create_trusted_html(html.replaceAll('', ''))); // XHTML compliance return elem.content; } diff --git a/packages/svelte/src/internal/client/dom/template.js b/packages/svelte/src/internal/client/dom/template.js index d7c57765a4..3fa5612a30 100644 --- a/packages/svelte/src/internal/client/dom/template.js +++ b/packages/svelte/src/internal/client/dom/template.js @@ -208,7 +208,7 @@ function fragment_from_tree(structure, ns) { if (children.length > 0) { var target = node_name(element) === TEMPLATE_TAG - ? // TODO: DOM access + ? // this is safe for custom renderers because the name will never be `template` due to how `node_name` works /** @type {HTMLTemplateElement} */ (element).content : element; @@ -283,6 +283,7 @@ export function from_tree(structure, flags) { * @param {() => Element | DocumentFragment} fn */ export function with_script(fn) { + // TODO RENDERER: never emit this for custom renderers return () => run_scripts(fn()); } @@ -293,6 +294,7 @@ export function with_script(fn) { * @returns {Node | Node[]} */ function run_scripts(node) { + // this should be custom renderer safe since we never emit `with_script` in that case // scripts were SSR'd, in which case they will run if (hydrating) return node; @@ -307,12 +309,11 @@ function run_scripts(node) { for (const script of scripts) { const clone = create_element('script'); - // TODO: DOM access + for (var attribute of script.attributes) { set_attribute(clone, attribute.name, attribute.value); } - // TODO: DOM access set_text_content(clone, script.textContent ?? ''); // The script has changed - if it's at the edges, the effect now points at dead nodes diff --git a/packages/svelte/src/internal/client/render.js b/packages/svelte/src/internal/client/render.js index cb152ed9c1..37d6c401fb 100644 --- a/packages/svelte/src/internal/client/render.js +++ b/packages/svelte/src/internal/client/render.js @@ -6,7 +6,15 @@ import { create_text, get_first_child, get_next_sibling, - init_operations + init_operations, + append_child, + add_event_listener, + remove_event_listener, + get_parent_node, + remove_child, + set_node_value, + get_node_value, + node_type } from './dom/operations.js'; import { HYDRATION_END, HYDRATION_ERROR, HYDRATION_START } from '../../constants.js'; import { active_effect } from './runtime.js'; @@ -47,10 +55,10 @@ export function set_text(text, value) { // For objects, we apply string coercion (which might make things like $state array references in the template reactive) before diffing var str = value == null ? '' : typeof value === 'object' ? `${value}` : value; // @ts-expect-error - if (str !== (text.__t ??= text.nodeValue)) { + if (str !== (text.__t ??= get_node_value(text))) { // @ts-expect-error text.__t = str; - text.nodeValue = `${str}`; + set_node_value(text, `${str}`); } } @@ -105,7 +113,7 @@ export function hydrate(component, options) { while ( anchor && - (anchor.nodeType !== COMMENT_NODE || /** @type {Comment} */ (anchor).data !== HYDRATION_START) + (node_type(anchor) !== COMMENT_NODE || get_node_value(anchor) !== HYDRATION_START) ) { anchor = get_next_sibling(anchor); } @@ -171,7 +179,7 @@ function _mount( var component = undefined; var unmount = component_root(() => { - var anchor_node = anchor ?? target.appendChild(create_text()); + var anchor_node = anchor ?? /** @type {Text} */ (append_child(target, create_text())); boundary( /** @type {TemplateNode} */ (anchor_node), @@ -202,8 +210,8 @@ function _mount( if ( hydrate_node === null || - hydrate_node.nodeType !== COMMENT_NODE || - /** @type {Comment} */ (hydrate_node).data !== HYDRATION_END + node_type(hydrate_node) !== COMMENT_NODE || + get_node_value(hydrate_node) !== HYDRATION_END ) { w.hydration_mismatch(); throw HYDRATION_ERROR; @@ -246,7 +254,7 @@ function _mount( var count = counts.get(event_name); if (count === undefined) { - node.addEventListener(event_name, handle_event_propagation, { passive }); + add_event_listener(node, event_name, handle_event_propagation, { passive }); counts.set(event_name, 1); } else { counts.set(event_name, count + 1); @@ -265,7 +273,7 @@ function _mount( var count = /** @type {number} */ (counts.get(event_name)); if (--count == 0) { - node.removeEventListener(event_name, handle_event_propagation); + remove_event_listener(node, event_name, handle_event_propagation); counts.delete(event_name); if (counts.size === 0) { @@ -280,7 +288,8 @@ function _mount( root_event_handles.delete(event_handle); if (anchor_node !== anchor) { - anchor_node.parentNode?.removeChild(anchor_node); + var parent = get_parent_node(anchor_node); + if (parent) remove_child(parent, /** @type {ChildNode} */ (anchor_node)); } }; });