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

100% Statements 69/69
100% Branches 17/17
100% Functions 1/1
100% Lines 67/67

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 682x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 230x 230x 230x 230x 230x 230x 230x 230x 230x 230x 230x 230x 230x 230x 230x 230x 230x 230x 169x 4x 169x 164x 164x 164x 79x 79x 164x 83x 60x 83x 23x 23x 83x 165x 1x 1x 169x 230x 230x 230x 230x 230x 230x 230x 230x 230x 230x 230x 230x 230x 230x 230x 230x 230x 230x 230x  
/** @import { BlockStatement, Expression, ExpressionStatement, 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 {Expression} */
	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 = 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 expression = is_default
		? b.call('$.default_slot', b.id('$$props'))
		: b.member(b.member(b.id('$$props'), '$$slots'), name, true, true);
 
	const slot = b.call('$.slot', context.state.node, expression, props_expression, fallback);
	context.state.init.push(b.stmt(slot));
}