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

95.34% Statements 123/129
85.1% Branches 40/47
100% Functions 2/2
94.95% Lines 113/119

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 1202x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 46x 46x 2x 2x 2x 2x 46x 46x   11x     2x 2x 46x 46x 46x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 95x 95x 95x 95x 95x 95x 95x 95x 1631x 130x 1631x 35x 35x 35x 95x 1631x 95x 95x 95x 49x 49x 49x 49x 49x 49x 49x 49x 100x 49x 53x 53x 53x 47x 49x       47x 49x 46x 46x 47x 47x 47x 47x 47x 46x 46x 83x 40x 46x 46x 46x 46x 46x 46x 95x 7x 7x 46x 46x 46x 46x 46x 46x 95x 7x 11x 11x 83x 39x 39x 95x 95x 95x  
/** @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 | null} */
	var effect;
 
	block(() => {
		if (value === (value = get_value())) return;
 
		if (effect) {
			destroy_effect(effect);
			effect = null;
		}
 
		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);
			}
		});
	});
}