|
|
@ -13,7 +13,7 @@ import {
|
|
|
|
import { dev } from '../../../../state.js';
|
|
|
|
import { dev } from '../../../../state.js';
|
|
|
|
import { extract_paths, object } from '../../../../utils/ast.js';
|
|
|
|
import { extract_paths, object } from '../../../../utils/ast.js';
|
|
|
|
import * as b from '../../../../utils/builders.js';
|
|
|
|
import * as b from '../../../../utils/builders.js';
|
|
|
|
import { build_getter, with_loc } from '../utils.js';
|
|
|
|
import { build_getter } from '../utils.js';
|
|
|
|
import { get_value } from './shared/declarations.js';
|
|
|
|
import { get_value } from './shared/declarations.js';
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
@ -48,18 +48,26 @@ export function EachBlock(node, context) {
|
|
|
|
if (node.index) {
|
|
|
|
if (node.index) {
|
|
|
|
flags |= EACH_INDEX_REACTIVE;
|
|
|
|
flags |= EACH_INDEX_REACTIVE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// In runes mode, if key === item, we don't need to wrap the item in a source
|
|
|
|
const key_is_item =
|
|
|
|
const key_is_item =
|
|
|
|
node.key?.type === 'Identifier' &&
|
|
|
|
/** @type {Expression} */ (node.key).type === 'Identifier' &&
|
|
|
|
node.context.type === 'Identifier' &&
|
|
|
|
node.context.type === 'Identifier' &&
|
|
|
|
node.context.name === node.key.name;
|
|
|
|
node.context.name === node.key.name;
|
|
|
|
|
|
|
|
|
|
|
|
for (const binding of node.metadata.expression.dependencies) {
|
|
|
|
|
|
|
|
// if the expression doesn't reference any external state, we don't need to
|
|
|
|
|
|
|
|
// create a source for the item. TODO cover more cases (e.g. `x.filter(y)`
|
|
|
|
|
|
|
|
// should also qualify if `y` doesn't reference state, and non-state
|
|
|
|
|
|
|
|
// bindings should also be fine
|
|
|
|
|
|
|
|
if (binding.scope.function_depth >= context.state.scope.function_depth) {
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!context.state.analysis.runes || !key_is_item) {
|
|
|
|
if (!context.state.analysis.runes || !key_is_item || binding.kind === 'store_sub') {
|
|
|
|
flags |= EACH_ITEM_REACTIVE;
|
|
|
|
flags |= EACH_ITEM_REACTIVE;
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
|
|
|
|
flags |= EACH_ITEM_REACTIVE;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Since `animate:` can only appear on elements that are the sole child of a keyed each block,
|
|
|
|
// Since `animate:` can only appear on elements that are the sole child of a keyed each block,
|
|
|
@ -134,21 +142,13 @@ export function EachBlock(node, context) {
|
|
|
|
const index =
|
|
|
|
const index =
|
|
|
|
each_node_meta.contains_group_binding || !node.index ? each_node_meta.index : b.id(node.index);
|
|
|
|
each_node_meta.contains_group_binding || !node.index ? each_node_meta.index : b.id(node.index);
|
|
|
|
const item = each_node_meta.item;
|
|
|
|
const item = each_node_meta.item;
|
|
|
|
const binding = /** @type {Binding} */ (context.state.scope.get(item.name));
|
|
|
|
|
|
|
|
const getter = (/** @type {Identifier} */ id) => {
|
|
|
|
|
|
|
|
const item_with_loc = with_loc(item, id);
|
|
|
|
|
|
|
|
return b.call('$.unwrap', item_with_loc);
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (node.index) {
|
|
|
|
if (node.index) {
|
|
|
|
child_state.transform[node.index] = {
|
|
|
|
if ((flags & EACH_INDEX_REACTIVE) !== 0) {
|
|
|
|
read: (id) => {
|
|
|
|
child_state.transform[node.index] = { read: get_value };
|
|
|
|
const index_with_loc = with_loc(index, id);
|
|
|
|
} else {
|
|
|
|
return (flags & EACH_INDEX_REACTIVE) === 0
|
|
|
|
delete child_state.transform[node.index];
|
|
|
|
? index_with_loc
|
|
|
|
}
|
|
|
|
: b.call('$.get', index_with_loc);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
delete key_state.transform[node.index];
|
|
|
|
delete key_state.transform[node.index];
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -172,7 +172,7 @@ export function EachBlock(node, context) {
|
|
|
|
|
|
|
|
|
|
|
|
if (node.context.type === 'Identifier') {
|
|
|
|
if (node.context.type === 'Identifier') {
|
|
|
|
child_state.transform[node.context.name] = {
|
|
|
|
child_state.transform[node.context.name] = {
|
|
|
|
read: getter,
|
|
|
|
read: (flags & EACH_ITEM_REACTIVE) !== 0 ? get_value : (node) => node,
|
|
|
|
assign: (_, value) => {
|
|
|
|
assign: (_, value) => {
|
|
|
|
const left = b.member(
|
|
|
|
const left = b.member(
|
|
|
|
each_node_meta.array_name ? b.call(each_node_meta.array_name) : collection,
|
|
|
|
each_node_meta.array_name ? b.call(each_node_meta.array_name) : collection,
|
|
|
@ -187,12 +187,12 @@ export function EachBlock(node, context) {
|
|
|
|
|
|
|
|
|
|
|
|
delete key_state.transform[node.context.name];
|
|
|
|
delete key_state.transform[node.context.name];
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
const unwrapped = getter(binding.node);
|
|
|
|
const unwrapped = (flags & EACH_ITEM_REACTIVE) !== 0 ? b.call('$.get', item) : item;
|
|
|
|
const paths = extract_paths(node.context);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (const path of paths) {
|
|
|
|
for (const path of extract_paths(node.context)) {
|
|
|
|
const name = /** @type {Identifier} */ (path.node).name;
|
|
|
|
const name = /** @type {Identifier} */ (path.node).name;
|
|
|
|
const needs_derived = path.has_default_value; // to ensure that default value is only called once
|
|
|
|
const needs_derived = path.has_default_value; // to ensure that default value is only called once
|
|
|
|
|
|
|
|
|
|
|
|
const fn = b.thunk(
|
|
|
|
const fn = b.thunk(
|
|
|
|
/** @type {Expression} */ (context.visit(path.expression?.(unwrapped), child_state))
|
|
|
|
/** @type {Expression} */ (context.visit(path.expression?.(unwrapped), child_state))
|
|
|
|
);
|
|
|
|
);
|
|
|
@ -203,11 +203,11 @@ export function EachBlock(node, context) {
|
|
|
|
|
|
|
|
|
|
|
|
child_state.transform[name] = {
|
|
|
|
child_state.transform[name] = {
|
|
|
|
read,
|
|
|
|
read,
|
|
|
|
assign: (node, value) => {
|
|
|
|
assign: (_, value) => {
|
|
|
|
const left = /** @type {Pattern} */ (path.update_expression(unwrapped));
|
|
|
|
const left = /** @type {Pattern} */ (path.update_expression(unwrapped));
|
|
|
|
return b.sequence([b.assignment('=', left, value), ...sequence]);
|
|
|
|
return b.sequence([b.assignment('=', left, value), ...sequence]);
|
|
|
|
},
|
|
|
|
},
|
|
|
|
mutate: (node, mutation) => {
|
|
|
|
mutate: (_, mutation) => {
|
|
|
|
return b.sequence([mutation, ...sequence]);
|
|
|
|
return b.sequence([mutation, ...sequence]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
};
|
|
|
|