All files / src/compiler/phases/3-transform/client/visitors SlotElement.js

100% Statements 73/73
100% Branches 15/15
100% Functions 1/1
100% Lines 71/71

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 722x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 240x 240x 240x 240x 240x 240x 240x 240x 240x 240x 240x 240x 240x 240x 240x 240x 240x 240x 174x 4x 174x 169x 169x 169x 81x 81x 169x 86x 62x 86x 24x 24x 86x 170x 1x 1x 174x 240x 240x 240x 240x 240x 240x 240x 240x 240x 240x 240x 240x 240x 240x 240x 240x 240x 240x 240x 240x 240x 240x 240x  
/** @import { BlockStatement, Expression, ExpressionStatement, Literal, Property } from 'estree' */
/** @import { AST } from '#compiler' */
/** @import { ComponentContext } from '../types' */
import * as b from '../../../../utils/builders.js';
import { build_attribute_value } from './shared/element.js';
 
/**
 * @param {AST.SlotElement} node
 * @param {ComponentContext} context
 */
export function SlotElement(node, context) {
	// <slot {a}>fallback</slot>  -->   $.slot($$slots.default, { get a() { .. } }, () => ...fallback);
	context.state.template.push('<!>');
 
	/** @type {Property[]} */
	const props = [];
 
	/** @type {Expression[]} */
	const spreads = [];
 
	/** @type {ExpressionStatement[]} */
	const lets = [];
 
	let is_default = true;
 
	/** @type {Literal} */
	let name = b.literal('default');
 
	for (const attribute of node.attributes) {
		if (attribute.type === 'SpreadAttribute') {
			spreads.push(b.thunk(/** @type {Expression} */ (context.visit(attribute))));
		} else if (attribute.type === 'Attribute') {
			const { value } = build_attribute_value(attribute.value, context);
 
			if (attribute.name === 'name') {
				name = /** @type {Literal} */ (value);
				is_default = false;
			} else if (attribute.name !== 'slot') {
				if (attribute.metadata.expression.has_state) {
					props.push(b.get(attribute.name, [b.return(value)]));
				} else {
					props.push(b.init(attribute.name, value));
				}
			}
		} else if (attribute.type === 'LetDirective') {
			lets.push(/** @type {ExpressionStatement} */ (context.visit(attribute)));
		}
	}
 
	// Let bindings first, they can be used on attributes
	context.state.init.push(...lets);
 
	const props_expression =
		spreads.length === 0 ? b.object(props) : b.call('$.spread_props', b.object(props), ...spreads);
 
	const fallback =
		node.fragment.nodes.length === 0
			? b.literal(null)
			: b.arrow([b.id('$$anchor')], /** @type {BlockStatement} */ (context.visit(node.fragment)));
 
	const slot = b.call(
		'$.slot',
		context.state.node,
		b.id('$$props'),
		name,
		props_expression,
		fallback
	);
 
	context.state.init.push(b.stmt(slot));
}