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

100% Statements 45/45
100% Branches 14/14
100% Functions 1/1
100% Lines 42/42

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 432x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 992x 992x 992x 992x 992x 992x 992x 1x 1x 1x 991x 992x 223x 223x 223x 223x 991x 991x 991x 991x 991x 991x 991x 991x 991x 992x 988x 981x 981x 981x  
/** @import { AST } from '#compiler' */
/** @import { Context } from '../types' */
/** @import { Scope } from '../../scope' */
import * as e from '../../../errors.js';
import { mark_subtree_dynamic } from './shared/fragment.js';
import { validate_block_not_empty, validate_opening_tag } from './shared/utils.js';
 
/**
 * @param {AST.EachBlock} node
 * @param {Context} context
 */
export function EachBlock(node, context) {
	validate_opening_tag(node, context.state, '#');
 
	validate_block_not_empty(node.body, context);
	validate_block_not_empty(node.fallback, context);
 
	const id = node.context;
	if (id.type === 'Identifier' && (id.name === '$state' || id.name === '$derived')) {
		// TODO weird that this is necessary
		e.state_invalid_placement(node, id.name);
	}
 
	if (node.key) {
		// treat `{#each items as item, i (i)}` as a normal indexed block, everything else as keyed
		node.metadata.keyed =
			node.key.type !== 'Identifier' || !node.index || node.key.name !== node.index;
	}
 
	// evaluate expression in parent scope
	context.visit(node.expression, {
		...context.state,
		expression: node.metadata.expression,
		scope: /** @type {Scope} */ (context.state.scope.parent)
	});
 
	context.visit(node.body);
	if (node.key) context.visit(node.key);
	if (node.fallback) context.visit(node.fallback);
 
	mark_subtree_dynamic(context.path);
}