All files / src/compiler/phases/2-analyze/visitors/shared component.js

100% Statements 71/71
100% Branches 23/23
100% Functions 1/1
100% Lines 68/68

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 692x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 1407x 1498x 1498x 1498x 1498x 1498x 302x 1498x 4x 4x 1494x 1494x 1498x 60x 1498x 1x 1x 1493x 1498x 937x 194x 194x 194x 187x 187x 2x 2x 2x 2x 1x 2x 2x 187x 194x 935x 935x 935x 937x 23x 23x 937x 1489x 1498x 224x 224x 1498x 1398x 1398x 1398x 1398x 1398x 1398x 1398x  
/** @import { Component, SvelteComponent, SvelteSelf } from '#compiler' */
/** @import { Context } from '../../types' */
import * as e from '../../../../errors.js';
import { get_attribute_expression, is_expression_attribute } from '../../../../utils/ast.js';
import {
	validate_attribute,
	validate_attribute_name,
	validate_slot_attribute
} from './attribute.js';
 
/**
 * @param {Component | SvelteComponent | SvelteSelf} node
 * @param {Context} context
 */
export function visit_component(node, context) {
	for (const attribute of node.attributes) {
		if (
			attribute.type !== 'Attribute' &&
			attribute.type !== 'SpreadAttribute' &&
			attribute.type !== 'LetDirective' &&
			attribute.type !== 'OnDirective' &&
			attribute.type !== 'BindDirective'
		) {
			e.component_invalid_directive(attribute);
		}
 
		if (
			attribute.type === 'OnDirective' &&
			(attribute.modifiers.length > 1 || attribute.modifiers.some((m) => m !== 'once'))
		) {
			e.event_handler_invalid_component_modifier(attribute);
		}
 
		if (attribute.type === 'Attribute') {
			if (context.state.analysis.runes) {
				validate_attribute(attribute, node);
 
				if (is_expression_attribute(attribute)) {
					const expression = get_attribute_expression(attribute);
					if (expression.type === 'SequenceExpression') {
						let i = /** @type {number} */ (expression.start);
						while (--i > 0) {
							const char = context.state.analysis.source[i];
							if (char === '(') break; // parenthesized sequence expressions are ok
							if (char === '{') e.attribute_invalid_sequence_expression(expression);
						}
					}
				}
			}
 
			validate_attribute_name(attribute);
 
			if (attribute.name === 'slot') {
				validate_slot_attribute(context, attribute, true);
			}
		}
 
		if (attribute.type === 'BindDirective' && attribute.name !== 'this') {
			context.state.analysis.uses_component_bindings = true;
		}
	}
 
	context.next({
		...context.state,
		parent_element: null,
		component_slots: new Set()
	});
}