fix: move logic to proxy inside `set`

pull/15073/head
paoloricciuti 8 months ago
parent 82d45a203e
commit e42c7cd567

@ -30,7 +30,7 @@ export interface ClientTransformState extends TransformState {
/** turn `foo` into e.g. `$.get(foo)` */
read: (id: Identifier) => Expression;
/** turn `foo = bar` into e.g. `$.set(foo, bar)` */
assign?: (node: Identifier, value: Expression) => Expression;
assign?: (node: Identifier, value: Expression, proxy?: boolean) => Expression;
/** turn `foo.bar = baz` into e.g. `$.mutate(foo, $.get(foo).bar = baz);` */
mutate?: (node: Identifier, mutation: AssignmentExpression | UpdateExpression) => Expression;
/** turn `foo++` into e.g. `$.update(foo)` */

@ -65,21 +65,22 @@ function build_assignment(operator, left, right, context) {
context.visit(build_assignment_value(operator, left, right))
);
if (
const needs_proxy =
private_state.kind === 'state' &&
is_non_coercive_operator(operator) &&
should_proxy(value, context.state.scope)
) {
value = build_proxy_reassignment(value, b.member(b.this, private_state.id));
}
should_proxy(value, context.state.scope);
if (context.state.in_constructor) {
// inside the constructor, we can assign to `this.#foo.v` rather than using `$.set`,
// since nothing is tracking the signal at this point
return b.assignment(operator, /** @type {Pattern} */ (context.visit(left)), value);
return b.assignment(
operator,
/** @type {Pattern} */ (context.visit(left)),
needs_proxy ? build_proxy_reassignment(value, b.member(b.this, private_state.id)) : value
);
}
return b.call('$.set', left, value);
return b.call('$.set', left, value, needs_proxy && b.true, dev && needs_proxy && b.true);
}
}
@ -113,19 +114,17 @@ function build_assignment(operator, left, right, context) {
context.visit(build_assignment_value(operator, left, right))
);
if (
return transform.assign(
object,
value,
!is_primitive &&
binding.kind !== 'prop' &&
binding.kind !== 'bindable_prop' &&
binding.kind !== 'raw_state' &&
context.state.analysis.runes &&
should_proxy(right, context.state.scope) &&
is_non_coercive_operator(operator)
) {
value = build_proxy_reassignment(value, object);
}
return transform.assign(object, value);
binding.kind !== 'prop' &&
binding.kind !== 'bindable_prop' &&
binding.kind !== 'raw_state' &&
context.state.analysis.runes &&
should_proxy(right, context.state.scope) &&
is_non_coercive_operator(operator)
);
}
// mutation

@ -5,7 +5,7 @@ import { dev, is_ignored } from '../../../../state.js';
import * as b from '../../../../utils/builders.js';
import { regex_invalid_identifier_chars } from '../../../patterns.js';
import { get_rune } from '../../../scope.js';
import { build_proxy_reassignment, should_proxy } from '../utils.js';
import { should_proxy } from '../utils.js';
/**
* @param {ClassBody} node
@ -160,7 +160,7 @@ export function ClassBody(node, context) {
'set',
definition.key,
[value],
[b.stmt(b.call('$.set', member, build_proxy_reassignment(value, prev)))]
[b.stmt(b.call('$.set', member, value, b.true, dev && b.true))]
)
);
}

@ -1,7 +1,8 @@
/** @import { Identifier } from 'estree' */
/** @import { ComponentContext, Context } from '../../types' */
import { is_state_source } from '../../utils.js';
import { is_state_source, should_proxy } from '../../utils.js';
import * as b from '../../../../../utils/builders.js';
import { dev } from '../../../../../state.js';
/**
* Turns `foo` into `$.get(foo)`
@ -24,8 +25,8 @@ export function add_state_transformers(context) {
) {
context.state.transform[name] = {
read: binding.declaration_kind === 'var' ? (node) => b.call('$.safe_get', node) : get_value,
assign: (node, value) => {
let call = b.call('$.set', node, value);
assign: (node, value, proxy = false) => {
let call = b.call('$.set', node, value, proxy && b.true, dev && proxy && b.true);
if (context.state.scope.get(`$${node.name}`)?.kind === 'store_sub') {
call = b.call('$.store_unsub', call, b.literal(`$${node.name}`), b.id('$$stores'));

@ -34,6 +34,7 @@ import {
import * as e from '../errors.js';
import { legacy_mode_flag, tracing_mode_flag } from '../../flags/index.js';
import { get_stack } from '../dev/tracing.js';
import { proxy } from '../proxy.js';
export let inspect_effects = new Set();
@ -154,9 +155,11 @@ export function mutate(source, value) {
* @template V
* @param {Source<V>} source
* @param {V} value
* @param {boolean} [should_proxy]
* @param {boolean} [needs_previous]
* @returns {V}
*/
export function set(source, value) {
export function set(source, value, should_proxy = false, needs_previous = false) {
if (
active_reaction !== null &&
is_runes() &&
@ -168,7 +171,13 @@ export function set(source, value) {
e.state_unsafe_mutation();
}
return internal_set(source, value);
let new_value = should_proxy
? needs_previous
? proxy(value, source.o, null, source)
: proxy(value, source.o)
: value;
return internal_set(source, new_value);
}
/**

@ -23,7 +23,7 @@ export default function Bind_component_snippet($$anchor) {
return $.get(value);
},
set value($$value) {
$.set(value, $.proxy($$value, $.get_options(value)));
$.set(value, $$value, true);
}
});

@ -12,7 +12,7 @@ export default function Class_state_field_constructor_assignment($$anchor, $$pro
}
set a(value) {
$.set(this.#a, $.proxy(value, $.get_options(this.#a)));
$.set(this.#a, value, true);
}
#b = $.state();

@ -8,8 +8,8 @@ let d = 4;
export function update(array) {
(
$.set(a, $.proxy(array[0], $.get_options(a))),
$.set(b, $.proxy(array[1], $.get_options(b)))
$.set(a, array[0], true),
$.set(b, array[1], true)
);
[c, d] = array;

@ -13,7 +13,7 @@ export default function Function_prop_no_getter($$anchor) {
Button($$anchor, {
onmousedown: () => $.set(count, $.get(count) + 1),
onmouseup,
onmouseenter: () => $.set(count, $.proxy(plusOne($.get(count)), $.get_options(count))),
onmouseenter: () => $.set(count, plusOne($.get(count)), true),
children: ($$anchor, $$slotProps) => {
$.next();

Loading…
Cancel
Save