All files / src/internal/server dev.js

97.84% Statements 91/93
88.88% Branches 16/18
100% Functions 4/4
97.84% Lines 91/93

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 941x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 10x 10x 10x 10x 1x 1x 1x 1x 1x 1x 5x 5x 5x 5x 5x 5x 3x 3x 3x 3x 3x 3x 1x 1x 1x 1x 1x 1x 1x 1x 121x 121x 121x 121x     121x 121x 64x 64x 11x 3x 3x 3x 8x 8x 64x 121x 121x 38x 38x 14x 2x 2x 2x 12x 12x 38x 121x 121x 121x 1x 1x 119x 119x  
import {
	disallowed_paragraph_contents,
	interactive_elements,
	is_tag_valid_with_parent
} from '../../constants.js';
import { current_component } from './context.js';
 
/**
 * @typedef {{
 * 	tag: string;
 * 	parent: null | Element;
 *  filename: null | string;
 *  line: number;
 *  column: number;
 * }} Element
 */
 
/**
 * @type {Element | null}
 */
let parent = null;
 
/** @type {Set<string>} */
let seen;
 
/**
 * @param {Element} element
 */
function stringify(element) {
	if (element.filename === null) return `\`<${element.tag}>\``;
	return `\`<${element.tag}>\` (${element.filename}:${element.line}:${element.column})`;
}
 
/**
 * @param {import('#server').Payload} payload
 * @param {Element} parent
 * @param {Element} child
 */
function print_error(payload, parent, child) {
	var message =
		`${stringify(child)} cannot contain ${stringify(parent)}\n\n` +
		'This can cause content to shift around as the browser repairs the HTML, and will likely result in a `hydration_mismatch` warning.';
 
	if ((seen ??= new Set()).has(message)) return;
	seen.add(message);
 
	// eslint-disable-next-line no-console
	console.error(message);
	payload.head.out += `<script>console.error(${JSON.stringify(message)})</script>`;
}
 
/**
 * @param {import('#server').Payload} payload
 * @param {string} tag
 * @param {number} line
 * @param {number} column
 */
export function push_element(payload, tag, line, column) {
	var filename = /** @type {import('#server').Component} */ (current_component).function.filename;
	var child = { tag, parent, filename, line, column };
 
	if (parent !== null && !is_tag_valid_with_parent(tag, parent.tag)) {
		print_error(payload, parent, child);
	}
 
	if (interactive_elements.has(tag)) {
		let element = parent;
		while (element !== null) {
			if (interactive_elements.has(element.tag)) {
				print_error(payload, element, child);
				break;
			}
			element = element.parent;
		}
	}
 
	if (disallowed_paragraph_contents.includes(tag)) {
		let element = parent;
		while (element !== null) {
			if (element.tag === 'p') {
				print_error(payload, element, child);
				break;
			}
			element = element.parent;
		}
	}
 
	parent = child;
}
 
export function pop_element() {
	parent = /** @type {Element} */ (parent).parent;
}