All files / src/internal/client/dom/blocks html.js

95.52% Statements 128/134
82.22% Branches 37/45
100% Functions 2/2
95.16% Lines 118/124

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 1252x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 40x 40x 2x 2x 2x 2x 40x 40x   11x     2x 2x 40x 40x 40x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 81x 81x 81x 81x 81x 81x 81x 81x 141x 3x 2x 2x 3x 3x 138x 141x 56x 56x 56x 138x 141x 136x 136x 136x 41x 41x 41x 41x 41x 41x 41x 41x 86x 41x 46x 46x 46x 40x 41x       40x 41x 40x 40x 40x 40x 40x 40x 40x 95x 95x 136x 82x 95x 95x 95x 95x 95x 95x 136x 13x 13x 95x 95x 95x 95x 95x 95x 136x 13x 17x 17x 136x 82x 82x 136x 81x 81x  
/** @import { Effect, TemplateNode } from '#client' */
import { FILENAME, HYDRATION_ERROR } from '../../../../constants.js';
import { block, branch, destroy_effect } from '../../reactivity/effects.js';
import { hydrate_next, hydrate_node, hydrating, set_hydrate_node } from '../hydration.js';
import { create_fragment_from_html } from '../reconciler.js';
import { assign_nodes } from '../template.js';
import * as w from '../../warnings.js';
import { hash } from '../../../../utils.js';
import { DEV } from 'esm-env';
import { dev_current_component_function } from '../../runtime.js';
import { get_first_child, get_next_sibling } from '../operations.js';
 
/**
 * @param {Element} element
 * @param {string | null} server_hash
 * @param {string} value
 */
function check_hash(element, server_hash, value) {
	if (!server_hash || server_hash === hash(String(value ?? ''))) return;
 
	let location;
 
	// @ts-expect-error
	const loc = element.__svelte_meta?.loc;
	if (loc) {
		location = `near ${loc.file}:${loc.line}:${loc.column}`;
	} else if (dev_current_component_function?.[FILENAME]) {
		location = `in ${dev_current_component_function[FILENAME]}`;
	}
 
	w.hydration_html_changed(
		location?.replace(/\//g, '/\u200b') // prevent devtools trying to make it a clickable link by inserting a zero-width space
	);
}
 
/**
 * @param {Element | Text | Comment} node
 * @param {() => string} get_value
 * @param {boolean} svg
 * @param {boolean} mathml
 * @param {boolean} [skip_warning]
 * @returns {void}
 */
export function html(node, get_value, svg, mathml, skip_warning) {
	var anchor = node;
 
	var value = '';
 
	/** @type {Effect | undefined} */
	var effect;
 
	block(() => {
		if (value === (value = get_value() ?? '')) {
			if (hydrating) {
				hydrate_next();
			}
			return;
		}
 
		if (effect !== undefined) {
			destroy_effect(effect);
			effect = undefined;
		}
 
		if (value === '') return;
 
		effect = branch(() => {
			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 next = hydrate_next();
				var last = next;
 
				while (
					next !== null &&
					(next.nodeType !== 8 || /** @type {Comment} */ (next).data !== '')
				) {
					last = next;
					next = /** @type {TemplateNode} */ (get_next_sibling(next));
				}
 
				if (next === null) {
					w.hydration_mismatch();
					throw HYDRATION_ERROR;
				}
 
				if (DEV && !skip_warning) {
					check_hash(/** @type {Element} */ (next.parentNode), hash, value);
				}
 
				assign_nodes(hydrate_node, last);
				anchor = set_hydrate_node(next);
				return;
			}
 
			var html = value + '';
			if (svg) html = `<svg>${html}</svg>`;
			else if (mathml) html = `<math>${html}</math>`;
 
			// Don't use create_fragment_with_script_from_html here because that would mean script tags are executed.
			// @html is basically `.innerHTML = ...` and that doesn't execute scripts either due to security reasons.
			/** @type {DocumentFragment | Element} */
			var node = create_fragment_from_html(html);
 
			if (svg || mathml) {
				node = /** @type {Element} */ (get_first_child(node));
			}
 
			assign_nodes(
				/** @type {TemplateNode} */ (get_first_child(node)),
				/** @type {TemplateNode} */ (node.lastChild)
			);
 
			if (svg || mathml) {
				while (get_first_child(node)) {
					anchor.before(/** @type {Node} */ (get_first_child(node)));
				}
			} else {
				anchor.before(node);
			}
		});
	});
}