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 1557x 1557x 1557x 1608x 1608x 1608x 1608x 1608x 323x 1608x 4x 4x 1604x 1604x 1608x 76x 1608x 1x 1x 1603x 1608x 996x 227x 227x 227x 206x 206x 2x 2x 2x 2x 1x 2x 2x 206x 227x 994x 994x 994x 996x 23x 23x 996x 1599x 1608x 243x 243x 1608x 1548x 1548x 1548x 1548x 1548x 1557x 1557x 1557x 1557x 1598x 1598x 1547x 1547x 1547x 1547x 1547x 1547x 1547x 1557x 2017x 7x 7x 7x 2010x 2017x 2017x 2017x 2017x 2017x 1547x 1547x 1547x 1557x 1749x 1749x 1749x 1749x 1749x 1749x 1749x 1749x 1749x 1530x | /** @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);
}
}
|