function process_children(nodes, { visit, state }) {
	/** @type {Array<AST.Text | AST.Comment | AST.ExpressionTag>} */
	let sequence = [];

	function flush() {
		let quasi = b.quasi('', false);
		const quasis = [quasi];

		/** @type {Expression[]} */
		const expressions = [];

		for (let i = 0; i < sequence.length; i++) {
			const node = sequence[i];

			if (node.type === 'Text' || node.type === 'Comment') {
				quasi.value.cooked +=
					node.type === 'Comment' ? `<!--${node.data}-->` : escape_html(node.data);
			} else {
				const evaluated = state.scope.evaluate(node.expression);

				if (evaluated.is_known) {
					quasi.value.cooked += escape_html((evaluated.value ?? '') + '');
				} else {
					expressions.push(b.call('$.escape', /** @type {Expression} */ (visit(node.expression))));

					quasi = b.quasi('', i + 1 === sequence.length);
					quasis.push(quasi);
				}
			}
		}

		for (const quasi of quasis) {
			quasi.value.raw = sanitize_template_string(/** @type {string} */ (quasi.value.cooked));
		}

		state.template.push(b.template(quasis, expressions));
	}

	for (let i = 0; i < nodes.length; i += 1) {
		const node = nodes[i];

		if (node.type === 'Text' || node.type === 'Comment' || node.type === 'ExpressionTag') {
			sequence.push(node);
		} else {
			if (sequence.length > 0) {
				flush();
				sequence = [];
			}

			visit(node, { ...state });
		}
	}

	if (sequence.length > 0) {
		flush();
	}
}
Processes an array of template nodes, joining sibling text/expression nodes and
recursing into child nodes.
@param {Array<AST.SvelteNode>} nodes
@param {ComponentContext} context