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

98.27% Statements 114/116
95.65% Branches 22/23
100% Functions 1/1
98.18% Lines 108/110

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 107 108 109 110 1112x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 3079x 3079x 3079x 3079x 3079x 3079x 3079x 3079x 3079x 3070x 3079x 3079x 3079x 3079x 3079x 3079x 3079x 4x 4x 4x 4x 4x 4x 4x 3075x 3079x     3075x 3075x 3075x 3075x 3075x 3075x 3075x 3075x 3075x 3075x 3075x 3075x 3075x 3075x 3079x 7x 7x 3075x 3079x 28x 28x 28x 28x 28x 28x 28x 28x 28x 28x 28x 28x 28x 3075x 3078x 3059x 3079x 16x 16x 16x 11x 11x 11x 16x 16x 16x 16x 16x 16x 16x 16x 16x 16x 16x 16x 16x 16x 16x 3075x 3079x 2816x 2816x 3075x 3079x 28x 28x 3079x  
/** @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;
	}
 
	if (node.metadata.auto_opens !== null) {
		context.state.template.push(b.literal(node.metadata.auto_opens));
	}
 
	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')));
	}
}