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 1005x 1005x 1005x 1005x 1005x 1005x 1005x 1x 1x 1x 1004x 1005x 225x 225x 225x 225x 1004x 1004x 1004x 1004x 1004x 1004x 1004x 1004x 1004x 1005x 1001x 994x 994x 994x  
/** @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);
}