All files / src/compiler/phases/3-transform/server/visitors RegularElement.js

100% Statements 112/112
100% Branches 21/21
100% Functions 1/1
100% Lines 106/106

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 102 103 104 105 106 1072x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 3883x 3883x 3883x 3883x 3883x 3883x 3883x 3883x 3883x 3874x 3883x 3883x 3883x 3883x 3883x 3883x 3883x 6x 6x 6x 6x 6x 6x 6x 3877x 3877x 3877x 3877x 3877x 3877x 3877x 3877x 3877x 3877x 3877x 3877x 3877x 3877x 3883x 10x 10x 3877x 3883x 91x 91x 91x 91x 91x 91x 91x 91x 91x 91x 91x 91x 91x 3877x 3882x 3858x 3883x 19x 19x 19x 13x 13x 13x 19x 19x 19x 19x 19x 19x 19x 19x 19x 19x 19x 19x 19x 19x 19x 3877x 3883x 3557x 3557x 3877x 3883x 91x 91x 3883x  
/** @import { Location } from 'locate-character' */
/** @import { RegularElement, Text } from '#compiler' */
/** @import { ComponentContext, ComponentServerTransformState } from '../types.js' */
/** @import { Scope } from '../../../scope.js' */
import { locator } from '../../../../state.js';
import * as b from '../../../../utils/builders.js';
import { VoidElements } from '../../../constants.js';
import { clean_nodes, determine_namespace_for_children } from '../../utils.js';
import { serialize_element_attributes } from './shared/element.js';
import { process_children, serialize_template } from './shared/utils.js';
 
/**
 * @param {RegularElement} node
 * @param {ComponentContext} context
 */
export function RegularElement(node, context) {
	const namespace = determine_namespace_for_children(node, context.state.namespace);
 
	/** @type {ComponentServerTransformState} */
	const state = {
		...context.state,
		getters: { ...context.state.getters },
		namespace,
		preserve_whitespace:
			context.state.preserve_whitespace ||
			((node.name === 'pre' || node.name === 'textarea') && namespace !== 'foreign')
	};
 
	context.state.template.push(b.literal(`<${node.name}`));
	const body = serialize_element_attributes(node, { ...context, state });
	context.state.template.push(b.literal('>'));
 
	if ((node.name === 'script' || node.name === 'style') && node.fragment.nodes.length === 1) {
		context.state.template.push(
			b.literal(/** @type {Text} */ (node.fragment.nodes[0]).data),
			b.literal(`</${node.name}>`)
		);
 
		return;
	}
 
	const { hoisted, trimmed } = clean_nodes(
		node,
		node.fragment.nodes,
		context.path,
		namespace,
		{
			...state,
			scope: /** @type {Scope} */ (state.scopes.get(node.fragment))
		},
		state.preserve_whitespace,
		state.options.preserveComments
	);
 
	for (const node of hoisted) {
		context.visit(node, state);
	}
 
	if (state.options.dev) {
		const location = /** @type {Location} */ (locator(node.start));
		state.template.push(
			b.stmt(
				b.call(
					'$.push_element',
					b.id('$$payload'),
					b.literal(node.name),
					b.literal(location.line),
					b.literal(location.column)
				)
			)
		);
	}
 
	if (body === null) {
		process_children(trimmed, { ...context, state });
	} else {
		let id = body;
 
		if (body.type !== 'Identifier') {
			id = b.id(state.scope.generate('$$body'));
			state.template.push(b.const(id, body));
		}
 
		// if this is a `<textarea>` value or a contenteditable binding, we only add
		// the body if the attribute/binding is falsy
		const inner_state = { ...state, template: [], init: [] };
		process_children(trimmed, { ...context, state: inner_state });
 
		// Use the body expression as the body if it's truthy, otherwise use the inner template
		state.template.push(
			b.if(
				id,
				b.block(serialize_template([id])),
				b.block([...inner_state.init, ...serialize_template(inner_state.template)])
			)
		);
	}
 
	if (!VoidElements.includes(node.name) && namespace !== 'foreign') {
		state.template.push(b.literal(`</${node.name}>`));
	}
 
	if (state.options.dev) {
		state.template.push(b.stmt(b.call('$.pop_element')));
	}
}