All files / src/internal/client/dom hydration.js

96.29% Statements 104/108
95.23% Branches 20/21
100% Functions 7/7
96.19% Lines 101/105

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 1062x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 4900x 4900x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 16461x 3x 3x 3x 16458x 16458x 16458x 2x 2x 7736x 7736x 2x 2x 2x 7469x 3306x 3306x 7462x 1x 1x 1x 3305x 3305x 3305x 2x 2x 2x 2x 2x 2x 1x 1x 1x 2x 2x 2x 625x 265x 265x 265x 265x 370x 370x 265x 265x 265x 625x 2x 2x 2x 2x 2x 447x 447x 447x 447x 462x 447x 447x 447x 447x         447x 15x 15x 15x 15x 15x 447x  
/** @import { TemplateNode } from '#client' */
 
import {
	HYDRATION_END,
	HYDRATION_ERROR,
	HYDRATION_START,
	HYDRATION_START_ELSE
} from '../../../constants.js';
import * as w from '../warnings.js';
import { get_next_sibling } from './operations.js';
 
/**
 * Use this variable to guard everything related to hydration code so it can be treeshaken out
 * if the user doesn't use the `hydrate` method and these code paths are therefore not needed.
 */
export let hydrating = false;
 
/** @param {boolean} value */
export function set_hydrating(value) {
	hydrating = value;
}
 
/**
 * The node that is currently being hydrated. This starts out as the first node inside the opening
 * <!--[--> comment, and updates each time a component calls `$.child(...)` or `$.sibling(...)`.
 * When entering a block (e.g. `{#if ...}`), `hydrate_node` is the block opening comment; by the
 * time we leave the block it is the closing comment, which serves as the block's anchor.
 * @type {TemplateNode}
 */
export let hydrate_node;
 
/** @param {TemplateNode} node */
export function set_hydrate_node(node) {
	if (node === null) {
		w.hydration_mismatch();
		throw HYDRATION_ERROR;
	}
 
	return (hydrate_node = node);
}
 
export function hydrate_next() {
	return set_hydrate_node(/** @type {TemplateNode} */ (get_next_sibling(hydrate_node)));
}
 
/** @param {TemplateNode} node */
export function reset(node) {
	if (!hydrating) return;
 
	// If the node has remaining siblings, something has gone wrong
	if (get_next_sibling(hydrate_node) !== null) {
		w.hydration_mismatch();
		throw HYDRATION_ERROR;
	}
 
	hydrate_node = node;
}
 
/**
 * @param {HTMLTemplateElement} template
 */
export function hydrate_template(template) {
	if (hydrating) {
		// @ts-expect-error TemplateNode doesn't include DocumentFragment, but it's actually fine
		hydrate_node = template.content;
	}
}
 
export function next(count = 1) {
	if (hydrating) {
		var i = count;
		var node = hydrate_node;
 
		while (i--) {
			node = /** @type {TemplateNode} */ (get_next_sibling(node));
		}
 
		hydrate_node = node;
	}
}
 
/**
 * Removes all nodes starting at `hydrate_node` up until the next hydration end comment
 */
export function remove_nodes() {
	var depth = 0;
	var node = hydrate_node;
 
	while (true) {
		if (node.nodeType === 8) {
			var data = /** @type {Comment} */ (node).data;
 
			if (data === HYDRATION_END) {
				if (depth === 0) return node;
				depth -= 1;
			} else if (data === HYDRATION_START || data === HYDRATION_START_ELSE) {
				depth += 1;
			}
		}
 
		var next = /** @type {TemplateNode} */ (get_next_sibling(node));
		node.remove();
		node = next;
	}
}