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

100% Statements 94/94
100% Branches 16/16
100% Functions 4/4
100% Lines 90/90

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 912x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 80x 80x 80x 80x 80x 80x 80x 98x 94x 98x 14x 14x 14x 94x 94x 94x 94x 80x 80x 2x 2x 2x 2x 2x 2x 2x 2x 31x 31x 31x 31x 30x 30x 30x 30x 30x 30x 30x 30x 30x 31x 31x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 60x 50x 50x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 50x 58x 58x 58x  
import { add_snippet_symbol } from '../../../shared/validate.js';
import { EFFECT_TRANSPARENT } from '../../constants.js';
import { branch, block, destroy_effect } from '../../reactivity/effects.js';
import {
	current_component_context,
	dev_current_component_function,
	set_dev_current_component_function
} from '../../runtime.js';
 
/**
 * @template {(node: import('#client').TemplateNode, ...args: any[]) => import('#client').Dom} SnippetFn
 * @param {() => SnippetFn | null | undefined} get_snippet
 * @param {import('#client').TemplateNode} node
 * @param {(() => any)[]} args
 * @returns {void}
 */
export function snippet(get_snippet, node, ...args) {
	/** @type {SnippetFn | null | undefined} */
	var snippet;
 
	/** @type {import('#client').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)(node, ...args));
		}
	}, EFFECT_TRANSPARENT);
}
 
/**
 * In development, wrap the snippet function so that it passes validation, and so that the
 * correct component context is set for ownership checks
 * @param {(node: import('#client').TemplateNode, ...args: any[]) => import('#client').Dom} fn
 * @returns
 */
export function wrap_snippet(fn) {
	let component = /** @type {import('#client').ComponentContext} */ (current_component_context);
 
	return add_snippet_symbol(
		(/** @type {import('#client').TemplateNode} */ node, /** @type {any[]} */ ...args) => {
			var previous_component_function = dev_current_component_function;
			set_dev_current_component_function(component.function);
 
			try {
				return fn(node, ...args);
			} finally {
				set_dev_current_component_function(previous_component_function);
			}
		}
	);
}
 
/**
 * Remove this once slots are gone
 * @param {any} snippet_fn
 * @param {Record<string, any>} $$props
 * @param {string} name
 * @param {Element} node
 * @param {any} slot_props
 */
export function render_snippet_or_slot(snippet_fn, $$props, name, node, slot_props) {
	if ($$props.$$slots) {
		const slot = $$props.$$slots[name === 'children' ? 'default' : name];
		if (typeof slot === 'function') {
			let props = undefined;
			if (slot_props) {
				props = new Proxy(
					{},
					{
						get(_, key) {
							return slot_props()?.[key];
						}
					}
				);
			}
			slot(node, props);
			return;
		}
	}
 
	snippet(snippet_fn, node, slot_props);
}