pull/12780/head
Rich Harris 2 years ago
parent 7192ece1de
commit e8ec10d98d

@ -28,7 +28,7 @@ export interface ClientTransformState extends TransformState {
* A map of `[name, node]` pairs, where `Identifier` nodes matching `name`
* will be replaced with `node` (e.g. `x` -> `$.get(x)`)
*/
readonly getters: Record<string, Expression | ((id: Identifier) => Expression)>;
readonly getters: Record<string, (id: Identifier) => Expression>;
/**
* Counterpart to `getters`
*/

@ -464,7 +464,7 @@ function get_hoisted_params(node, context) {
binding = /** @type {Binding} */ (scope.get(binding.node.name.slice(1)));
}
const expression = context.state.getters[reference];
let expression = context.state.getters[reference]?.(b.id(binding.node.name));
if (
// If it's a destructured derived binding, then we can extract the derived signal reference and use that.

@ -5,6 +5,7 @@ import { dev } from '../../../../state.js';
import { extract_identifiers } from '../../../../utils/ast.js';
import * as b from '../../../../utils/builders.js';
import { create_derived } from '../utils.js';
import { get_value } from './shared/declarations.js';
/**
* @param {ConstTag} node
@ -24,7 +25,7 @@ export function ConstTag(node, context) {
)
);
context.state.getters[declaration.id.name] = b.call('$.get', declaration.id);
context.state.getters[declaration.id.name] = get_value;
// we need to eagerly evaluate the expression in order to hit any
// 'Cannot access x before initialization' errors
@ -40,7 +41,7 @@ export function ConstTag(node, context) {
// Make all identifiers that are declared within the following computed regular
// variables, as they are not signals in that context yet
for (const node of identifiers) {
getters[node.name] = node;
delete getters[node.name];
}
const child_state = { ...context.state, getters };
@ -67,7 +68,7 @@ export function ConstTag(node, context) {
}
for (const node of identifiers) {
context.state.getters[node.name] = b.member(b.call('$.get', tmp), node);
context.state.getters[node.name] = (node) => b.member(b.call('$.get', tmp), node);
}
}
}

@ -14,6 +14,7 @@ import { dev } from '../../../../state.js';
import { extract_paths, object } from '../../../../utils/ast.js';
import * as b from '../../../../utils/builders.js';
import { get_assignment_value, build_getter, build_setter, with_loc } from '../utils.js';
import { get_value } from './shared/declarations.js';
/**
* @param {EachBlock} node
@ -187,7 +188,7 @@ export function EachBlock(node, context) {
return (flags & EACH_INDEX_REACTIVE) === 0 ? index_with_loc : b.call('$.get', index_with_loc);
};
key_state.getters[node.index] = b.id(node.index);
delete key_state.getters[node.index];
}
/** @type {Statement[]} */
@ -202,7 +203,7 @@ export function EachBlock(node, context) {
)
);
key_state.getters[node.context.name] = node.context;
delete key_state.getters[node.context.name];
} else {
const unwrapped = getter(binding.node);
const paths = extract_paths(node.context);
@ -217,7 +218,7 @@ export function EachBlock(node, context) {
declarations.push(b.let(path.node, needs_derived ? b.call('$.derived_safe_equal', fn) : fn));
const getter = needs_derived ? b.call('$.get', b.id(name)) : b.call(name);
const getter = needs_derived ? get_value : b.call;
child_state.getters[name] = getter;
child_state.setters[name] = create_mutation(
/** @type {Pattern} */ (path.update_expression(unwrapped))
@ -226,10 +227,10 @@ export function EachBlock(node, context) {
// we need to eagerly evaluate the expression in order to hit any
// 'Cannot access x before initialization' errors
if (dev) {
declarations.push(b.stmt(getter));
declarations.push(b.stmt(getter(b.id(name))));
}
key_state.getters[name] = path.node;
key_state.getters[name] = () => path.node;
}
}

@ -16,10 +16,8 @@ export function LetDirective(node, context) {
const bindings = context.state.scope.get_bindings(node);
for (const binding of bindings) {
context.state.getters[binding.node.name] = b.member(
b.call('$.get', b.id(name)),
b.id(binding.node.name)
);
context.state.getters[binding.node.name] = (node) =>
b.member(b.call('$.get', b.id(name)), node);
}
return b.const(

@ -4,6 +4,7 @@
import { dev } from '../../../../state.js';
import { extract_paths } from '../../../../utils/ast.js';
import * as b from '../../../../utils/builders.js';
import { get_value } from './shared/declarations.js';
/**
* @param {SnippetBlock} node
@ -35,7 +36,7 @@ export function SnippetBlock(node, context) {
right: b.id('$.noop')
});
getters[argument.name] = b.call(argument);
getters[argument.name] = b.call;
continue;
}
@ -53,12 +54,12 @@ export function SnippetBlock(node, context) {
declarations.push(b.let(path.node, needs_derived ? b.call('$.derived_safe_equal', fn) : fn));
getters[name] = needs_derived ? b.call('$.get', b.id(name)) : b.call(name);
getters[name] = needs_derived ? get_value : b.call;
// we need to eagerly evaluate the expression in order to hit any
// 'Cannot access x before initialization' errors
if (dev) {
declarations.push(b.stmt(getters[name]));
declarations.push(b.stmt(getters[name](b.id(name))));
}
}
}

@ -4,6 +4,7 @@ import { is_state_source } from '../../utils.js';
import * as b from '../../../../../utils/builders.js';
/**
* Turns `foo` into `$.get(foo)`
* @param {Identifier} node
*/
export function get_value(node) {

@ -145,8 +145,10 @@ export function build_bind_this(expression, value, { state, visit }) {
/** @type {Expression[]} */
const values = [];
/** @type {typeof state.getters} */
const getters = {};
/** @type {string[]} */
const seen = [];
const getters = { ...state.getters };
// Pass in each context variables to the get/set functions, so that we can null out old values on teardown.
// Note that we only do this for each context variables, the consequence is that the value might be stale in
@ -154,7 +156,8 @@ export function build_bind_this(expression, value, { state, visit }) {
// variables, but that was the same case in Svelte 4, too. Once legacy mode is gone completely, we can revisit this.
walk(expression, null, {
Identifier(node, { path }) {
if (Object.hasOwn(getters, node.name)) return;
if (seen.includes(node.name)) return;
seen.push(node.name);
const parent = /** @type {Expression} */ (path.at(-1));
if (!is_reference(node, parent)) return;
@ -166,14 +169,14 @@ export function build_bind_this(expression, value, { state, visit }) {
if (owner.type === 'EachBlock' && scope === binding.scope) {
ids.push(node);
values.push(/** @type {Expression} */ (visit(node)));
getters[node.name] = node;
delete getters[node.name];
break;
}
}
}
});
const child_state = { ...state, getters: { ...state.getters, ...getters } };
const child_state = { ...state, getters };
const get = /** @type {Expression} */ (visit(expression, child_state));
const set = /** @type {Expression} */ (

Loading…
Cancel
Save