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

100% Statements 72/72
100% Branches 16/16
100% Functions 1/1
100% Lines 70/70

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 712x 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 175x 4x 175x 170x 170x 170x 81x 81x 170x 87x 62x 85x 25x 25x 87x 171x 1x 1x 175x 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;
 
	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));
}