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

98.87% Statements 88/89
95.65% Branches 22/23
100% Functions 1/1
98.8% Lines 83/84

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 852x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 793x 793x 793x 793x 793x 793x 793x 793x 793x 793x 793x 793x 793x 793x 793x 793x 1714x 1478x 1478x 1478x 1478x 1714x 366x 366x 366x 1x 1x 1x 1x 1x 1x 366x 1478x 1714x 754x 44x 754x 710x 710x 753x 754x 58x 56x 58x 58x 1714x 724x   724x 194x 194x 724x 724x 330x 268x 330x 330x 724x 1477x 1714x 1x 1x 1x 793x 793x 793x 52x 52x 793x  
import { IS_ELSEIF } from '../../constants.js';
import { hydrate_nodes, hydrating, set_hydrating } from '../hydration.js';
import { remove } from '../reconciler.js';
import { block, branch, pause_effect, resume_effect } from '../../reactivity/effects.js';
import { HYDRATION_END_ELSE } from '../../../../constants.js';
 
/**
 * @param {Comment} anchor
 * @param {() => boolean} get_condition
 * @param {(anchor: Node) => import('#client').Dom} consequent_fn
 * @param {null | ((anchor: Node) => import('#client').Dom)} [alternate_fn]
 * @param {boolean} [elseif] True if this is an `{:else if ...}` block rather than an `{#if ...}`, as that affects which transitions are considered 'local'
 * @returns {void}
 */
export function if_block(
	anchor,
	get_condition,
	consequent_fn,
	alternate_fn = null,
	elseif = false
) {
	/** @type {import('#client').Effect | null} */
	let consequent_effect = null;
 
	/** @type {import('#client').Effect | null} */
	let alternate_effect = null;
 
	/** @type {boolean | null} */
	let condition = null;
 
	const effect = block(() => {
		if (condition === (condition = !!get_condition())) return;
 
		/** Whether or not there was a hydration mismatch. Needs to be a `let` or else it isn't treeshaken out */
		let mismatch = false;
 
		if (hydrating) {
			const is_else = anchor.data === HYDRATION_END_ELSE;
 
			if (condition === is_else) {
				// Hydration mismatch: remove everything inside the anchor and start fresh.
				// This could happen with `{#if browser}...{/if}`, for example
				remove(hydrate_nodes);
				set_hydrating(false);
				mismatch = true;
			}
		}
 
		if (condition) {
			if (consequent_effect) {
				resume_effect(consequent_effect);
			} else {
				consequent_effect = branch(() => consequent_fn(anchor));
			}
 
			if (alternate_effect) {
				pause_effect(alternate_effect, () => {
					alternate_effect = null;
				});
			}
		} else {
			if (alternate_effect) {
				resume_effect(alternate_effect);
			} else if (alternate_fn) {
				alternate_effect = branch(() => alternate_fn(anchor));
			}
 
			if (consequent_effect) {
				pause_effect(consequent_effect, () => {
					consequent_effect = null;
				});
			}
		}
 
		if (mismatch) {
			// continue in hydration mode
			set_hydrating(true);
		}
	});
 
	if (elseif) {
		effect.f |= IS_ELSEIF;
	}
}