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

100% Statements 107/107
100% Branches 15/15
100% Functions 3/3
100% Lines 101/101

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 1022x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 92x 92x 92x 92x 92x 92x 92x 92x 92x 110x 106x 110x 14x 14x 14x 106x 106x 106x 106x 92x 92x 92x 44x 44x 92x 2x 2x 2x 2x 2x 2x 2x 2x 2x 34x 36x 36x 36x 36x 36x 36x 36x 36x 34x 34x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 5x 5x 5x 5x 5x 5x 5x 3x 3x 3x 2x 2x 2x 2x 2x 5x 5x 5x 5x 5x 2x 2x 5x 5x  
/** @import { Snippet } from 'svelte' */
/** @import { Effect, TemplateNode } from '#client' */
/** @import { Getters } from '#shared' */
import { EFFECT_TRANSPARENT } from '../../constants.js';
import { branch, block, destroy_effect, teardown } from '../../reactivity/effects.js';
import {
	dev_current_component_function,
	set_dev_current_component_function
} from '../../runtime.js';
import { hydrate_next, hydrate_node, hydrating } from '../hydration.js';
import { create_fragment_from_html } from '../reconciler.js';
import { assign_nodes } from '../template.js';
 
/**
 * @template {(node: TemplateNode, ...args: any[]) => void} SnippetFn
 * @param {TemplateNode} node
 * @param {() => SnippetFn | null | undefined} get_snippet
 * @param {(() => any)[]} args
 * @returns {void}
 */
export function snippet(node, get_snippet, ...args) {
	var anchor = node;
 
	/** @type {SnippetFn | null | undefined} */
	var snippet;
 
	/** @type {Effect | null} */
	var snippet_effect;
 
	block(() => {
		if (snippet === (snippet = get_snippet())) return;
 
		if (snippet_effect) {
			destroy_effect(snippet_effect);
			snippet_effect = null;
		}
 
		if (snippet) {
			snippet_effect = branch(() => /** @type {SnippetFn} */ (snippet)(anchor, ...args));
		}
	}, EFFECT_TRANSPARENT);
 
	if (hydrating) {
		anchor = hydrate_node;
	}
}
 
/**
 * In development, wrap the snippet function so that it passes validation, and so that the
 * correct component context is set for ownership checks
 * @param {any} component
 * @param {Snippet} fn
 * @returns {Snippet}
 */
export function wrap_snippet(component, fn) {
	return (node, ...args) => {
		var previous_component_function = dev_current_component_function;
		set_dev_current_component_function(component);
 
		try {
			return fn(node, ...args);
		} finally {
			set_dev_current_component_function(previous_component_function);
		}
	};
}
 
/**
 * Create a snippet programmatically
 * @template {unknown[]} Params
 * @param {(...params: Getters<Params>) => {
 *   render: () => string
 *   setup?: (element: Element) => void
 * }} fn
 * @returns {Snippet<Params>}
 */
export function createRawSnippet(fn) {
	return (anchor, ...params) => {
		var snippet = fn(...params);
 
		/** @type {Element} */
		var element;
 
		if (hydrating) {
			element = /** @type {Element} */ (hydrate_node);
			hydrate_next();
		} else {
			var html = snippet.render().trim();
			var fragment = create_fragment_from_html(html);
			element = /** @type {Element} */ (fragment.firstChild);
			/** @type {TemplateNode} */ (/** @type {unknown} */ (anchor)).before(element);
		}
 
		const result = snippet.setup?.(element);
		assign_nodes(element, element);
 
		if (typeof result === 'function') {
			teardown(result);
		}
	};
}