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 | 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 1461x 1461x 1461x 1558x 1558x 1558x 1558x 1558x 325x 1558x 4x 4x 1554x 1554x 1558x 64x 1558x 1x 1x 1553x 1558x 968x 217x 217x 217x 204x 204x 2x 2x 2x 2x 1x 2x 2x 204x 217x 966x 966x 966x 968x 23x 23x 968x 1549x 1558x 245x 245x 1558x 1452x 1452x 1452x 1452x 1452x 1461x 1461x 1461x 1461x 1548x 1548x 1451x 1451x 1451x 1451x 1451x 1451x 1451x 1461x 1888x 7x 7x 7x 1881x 1888x 1888x 1888x 1888x 1888x 1451x 1451x 1451x 1461x 1632x 1632x 1632x 1632x 1632x 1632x 1632x 1632x 1632x 1434x | /** @import { AST } from '#compiler' */
/** @import { Context } from '../../types' */
import * as e from '../../../../errors.js';
import { get_attribute_expression, is_expression_attribute } from '../../../../utils/ast.js';
import { determine_slot } from '../../../../utils/slot.js';
import {
validate_attribute,
validate_attribute_name,
validate_slot_attribute
} from './attribute.js';
import { mark_subtree_dynamic } from './fragment.js';
/**
* @param {AST.Component | AST.SvelteComponent | AST.SvelteSelf} node
* @param {Context} context
*/
export function visit_component(node, context) {
mark_subtree_dynamic(context.path);
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;
}
}
// If the component has a slot attribute — `<Foo slot="whatever" .../>` —
// then `let:` directives apply to other attributes, instead of just the
// top-level contents of the component. Yes, this is very weird.
const default_state = determine_slot(node)
? context.state
: { ...context.state, scope: node.metadata.scopes.default };
for (const attribute of node.attributes) {
context.visit(attribute, attribute.type === 'LetDirective' ? default_state : context.state);
}
/** @type {AST.Comment[]} */
let comments = [];
/** @type {Record<string, AST.Fragment['nodes']>} */
const nodes = { default: [] };
for (const child of node.fragment.nodes) {
if (child.type === 'Comment') {
comments.push(child);
continue;
}
const slot_name = determine_slot(child) ?? 'default';
(nodes[slot_name] ??= []).push(...comments, child);
if (slot_name !== 'default') comments = [];
}
const component_slots = new Set();
for (const slot_name in nodes) {
const state = {
...context.state,
scope: node.metadata.scopes[slot_name],
parent_element: null,
component_slots
};
context.visit({ ...node.fragment, nodes: nodes[slot_name] }, state);
}
}
|