Skip to content

Commit

Permalink
chore: tweak each block code (#15094)
Browse files Browse the repository at this point in the history
  • Loading branch information
Rich-Harris authored Jan 24, 2025
1 parent 3d828b4 commit e9cc7dc
Show file tree
Hide file tree
Showing 4 changed files with 26 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,6 @@ export function EachBlock(node, context) {
context.state.template.push('<!>');
}

if (each_node_meta.array_name !== null) {
context.state.init.push(b.const(each_node_meta.array_name, b.thunk(collection)));
}

let flags = 0;

if (node.metadata.keyed && node.index) {
Expand Down Expand Up @@ -120,8 +116,21 @@ export function EachBlock(node, context) {
return [array, ...transitive_dependencies];
});

if (each_node_meta.array_name) {
indirect_dependencies.push(b.call(each_node_meta.array_name));
/** @type {Identifier | null} */
let collection_id = null;

// Check if inner scope shadows something from outer scope.
// This is necessary because we need access to the array expression of the each block
// in the inner scope if bindings are used, in order to invalidate the array.
for (const [name] of context.state.scope.declarations) {
if (context.state.scope.parent?.get(name) != null) {
collection_id = context.state.scope.root.unique('$$array');
break;
}
}

if (collection_id) {
indirect_dependencies.push(b.call(collection_id));
} else {
indirect_dependencies.push(collection);

Expand Down Expand Up @@ -195,7 +204,7 @@ export function EachBlock(node, context) {
// TODO 6.0 this only applies in legacy mode, reassignments are
// forbidden in runes mode
return b.member(
each_node_meta.array_name ? b.call(each_node_meta.array_name) : collection,
collection_id ? b.call(collection_id) : collection,
(flags & EACH_INDEX_REACTIVE) !== 0 ? get_value(index) : index,
true
);
Expand All @@ -207,7 +216,7 @@ export function EachBlock(node, context) {
uses_index = true;

const left = b.member(
each_node_meta.array_name ? b.call(each_node_meta.array_name) : collection,
collection_id ? b.call(collection_id) : collection,
(flags & EACH_INDEX_REACTIVE) !== 0 ? get_value(index) : index,
true
);
Expand Down Expand Up @@ -283,16 +292,17 @@ export function EachBlock(node, context) {
);
}

const render_args = [b.id('$$anchor'), item];
if (uses_index || collection_id) render_args.push(index);
if (collection_id) render_args.push(collection_id);

/** @type {Expression[]} */
const args = [
context.state.node,
b.literal(flags),
each_node_meta.array_name ? each_node_meta.array_name : b.thunk(collection),
b.thunk(collection),
key_function,
b.arrow(
uses_index ? [b.id('$$anchor'), item, index] : [b.id('$$anchor'), item],
b.block(declarations.concat(block.body))
)
b.arrow(render_args, b.block(declarations.concat(block.body)))
];

if (node.fallback) {
Expand Down
11 changes: 0 additions & 11 deletions packages/svelte/src/compiler/phases/scope.js
Original file line number Diff line number Diff line change
Expand Up @@ -575,21 +575,10 @@ export function create_scopes(ast, root, allow_reactive_declarations, parent) {
}
if (node.fallback) visit(node.fallback, { scope });

// Check if inner scope shadows something from outer scope.
// This is necessary because we need access to the array expression of the each block
// in the inner scope if bindings are used, in order to invalidate the array.
let needs_array_deduplication = false;
for (const [name] of scope.declarations) {
if (state.scope.get(name) !== null) {
needs_array_deduplication = true;
}
}

node.metadata = {
expression: create_expression_metadata(),
keyed: false,
contains_group_binding: false,
array_name: needs_array_deduplication ? state.scope.root.unique('$$array') : null,
index: scope.root.unique('$$index'),
declarations: scope.declarations,
is_controlled: false
Expand Down
2 changes: 0 additions & 2 deletions packages/svelte/src/compiler/types/template.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -414,8 +414,6 @@ export namespace AST {
expression: ExpressionMetadata;
keyed: boolean;
contains_group_binding: boolean;
/** Set if something in the array expression is shadowed within the each block */
array_name: Identifier | null;
index: Identifier;
declarations: Map<string, Binding>;
/**
Expand Down
6 changes: 3 additions & 3 deletions packages/svelte/src/internal/client/dom/blocks/each.js
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ export function each(node, flags, get_collection, get_key, render_fn, fallback_f
* @param {Array<V>} array
* @param {EachState} state
* @param {Element | Comment | Text} anchor
* @param {(anchor: Node, item: MaybeSource<V>, index: number | Source<number>) => void} render_fn
* @param {(anchor: Node, item: MaybeSource<V>, index: number | Source<number>, collection: () => V[]) => void} render_fn
* @param {number} flags
* @param {boolean} is_inert
* @param {(value: V, index: number) => any} get_key
Expand Down Expand Up @@ -510,7 +510,7 @@ function update_item(item, value, index, type) {
* @param {V} value
* @param {unknown} key
* @param {number} index
* @param {(anchor: Node, item: V | Source<V>, index: number | Value<number>) => void} render_fn
* @param {(anchor: Node, item: V | Source<V>, index: number | Value<number>, collection: () => V[]) => void} render_fn
* @param {number} flags
* @param {() => V[]} get_collection
* @returns {EachItem}
Expand Down Expand Up @@ -559,7 +559,7 @@ function create_item(
current_each_item = item;

try {
item.e = branch(() => render_fn(anchor, v, i), hydrating);
item.e = branch(() => render_fn(anchor, v, i, get_collection), hydrating);

item.e.prev = prev && prev.e;
item.e.next = next && next.e;
Expand Down

0 comments on commit e9cc7dc

Please sign in to comment.