pull/16140/merge
Matei Trandafir 3 months ago committed by GitHub
commit d84dcf66b3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -54,8 +54,7 @@ export function SlotElement(node, context) {
// Let bindings first, they can be used on attributes // Let bindings first, they can be used on attributes
context.state.init.push(...lets); context.state.init.push(...lets);
const props_expression = const props_expression = b.call('$.props', b.object(props), ...spreads);
spreads.length === 0 ? b.object(props) : b.call('$.spread_props', b.object(props), ...spreads);
const fallback = const fallback =
node.fragment.nodes.length === 0 node.fragment.nodes.length === 0

@ -4,8 +4,8 @@
import { dev, is_ignored } from '../../../../../state.js'; import { dev, is_ignored } from '../../../../../state.js';
import { get_attribute_chunks, object } from '../../../../../utils/ast.js'; import { get_attribute_chunks, object } from '../../../../../utils/ast.js';
import * as b from '#compiler/builders'; import * as b from '#compiler/builders';
import { build_bind_this, memoize_expression, validate_binding } from '../shared/utils.js'; import { build_bind_this, memoize_expression, validate_binding } from './utils.js';
import { build_attribute_value } from '../shared/element.js'; import { build_attribute_value } from './element.js';
import { build_event_handler } from './events.js'; import { build_event_handler } from './events.js';
import { determine_slot } from '../../../../../utils/slot.js'; import { determine_slot } from '../../../../../utils/slot.js';
@ -408,14 +408,10 @@ export function build_component(node, component_name, context) {
push_prop(b.init('$$legacy', b.true)); push_prop(b.init('$$legacy', b.true));
} }
const props_expression = const props_expression = b.call(
props_and_spreads.length === 0 || '$.props',
(props_and_spreads.length === 1 && Array.isArray(props_and_spreads[0])) ...props_and_spreads.map((p) => (Array.isArray(p) ? b.object(p) : p))
? b.object(/** @type {Property[]} */ (props_and_spreads[0]) || []) );
: b.call(
'$.spread_props',
...props_and_spreads.map((p) => (Array.isArray(p) ? b.object(p) : p))
);
/** @param {Expression} node_id */ /** @param {Expression} node_id */
let fn = (node_id) => { let fn = (node_id) => {

@ -101,16 +101,15 @@ export function getAllContexts() {
* @returns {void} * @returns {void}
*/ */
export function push(props, runes = false, fn) { export function push(props, runes = false, fn) {
var ctx = (component_context = { component_context = {
p: component_context, p: component_context,
c: null, c: null,
d: false,
e: null, e: null,
m: false, m: false,
s: props, s: props,
x: null, x: null,
l: null l: null
}); };
if (legacy_mode_flag && !runes) { if (legacy_mode_flag && !runes) {
component_context.l = { component_context.l = {
@ -121,10 +120,6 @@ export function push(props, runes = false, fn) {
}; };
} }
teardown(() => {
/** @type {ComponentContext} */ (ctx).d = true;
});
if (DEV) { if (DEV) {
// component function // component function
component_context.function = fn; component_context.function = fn;

@ -114,7 +114,7 @@ export {
prop, prop,
rest_props, rest_props,
legacy_rest_props, legacy_rest_props,
spread_props, props,
update_pre_prop, update_pre_prop,
update_prop update_prop
} from './reactivity/props.js'; } from './reactivity/props.js';

@ -117,7 +117,7 @@ let stack = [];
* @param {Derived} derived * @param {Derived} derived
* @returns {Effect | null} * @returns {Effect | null}
*/ */
function get_derived_parent_effect(derived) { export function get_derived_parent_effect(derived) {
var parent = derived.parent; var parent = derived.parent;
while (parent !== null) { while (parent !== null) {
if ((parent.f & DERIVED) === 0) { if ((parent.f & DERIVED) === 0) {

@ -9,11 +9,17 @@ import {
} from '../../../constants.js'; } from '../../../constants.js';
import { get_descriptor, is_function } from '../../shared/utils.js'; import { get_descriptor, is_function } from '../../shared/utils.js';
import { mutable_source, set, source, update } from './sources.js'; import { mutable_source, set, source, update } from './sources.js';
import { derived, derived_safe_equal } from './deriveds.js'; import { derived, derived_safe_equal, get_derived_parent_effect } from './deriveds.js';
import { get, captured_signals, untrack } from '../runtime.js'; import { active_effect, captured_signals, get, untrack } from '../runtime.js';
import { safe_equals } from './equality.js'; import { safe_equals } from './equality.js';
import * as e from '../errors.js'; import * as e from '../errors.js';
import { LEGACY_DERIVED_PROP, LEGACY_PROPS, STATE_SYMBOL } from '#client/constants'; import {
DESTROYED,
INERT,
LEGACY_DERIVED_PROP,
LEGACY_PROPS,
STATE_SYMBOL
} from '#client/constants';
import { proxy } from '../proxy.js'; import { proxy } from '../proxy.js';
import { capture_store_binding } from './store.js'; import { capture_store_binding } from './store.js';
import { legacy_mode_flag } from '../../flags/index.js'; import { legacy_mode_flag } from '../../flags/index.js';
@ -159,16 +165,17 @@ export function legacy_rest_props(props, exclude) {
* The proxy handler for spread props. Handles the incoming array of props * The proxy handler for spread props. Handles the incoming array of props
* that looks like `() => { dynamic: props }, { static: prop }, ..` and wraps * that looks like `() => { dynamic: props }, { static: prop }, ..` and wraps
* them so that the whole thing is passed to the component as the `$$props` argument. * them so that the whole thing is passed to the component as the `$$props` argument.
* @template {Record<string | symbol, unknown>} T * @typedef {Record<string | symbol, unknown>} AnyProps
* @type {ProxyHandler<{ props: Array<T | (() => T)> }>}} * @type {ProxyHandler<{ props: Array<AnyProps | (() => AnyProps)>, old_props: AnyProps, destroyed: boolean }>}}
*/ */
const spread_props_handler = { const spread_props_handler = {
get(target, key) { get(target, key) {
if (target.destroyed && key in target.old_props) return target.old_props[key];
let i = target.props.length; let i = target.props.length;
while (i--) { while (i--) {
let p = target.props[i]; let p = target.props[i];
if (is_function(p)) p = p(); if (is_function(p)) p = p();
if (typeof p === 'object' && p !== null && key in p) return p[key]; if (typeof p === 'object' && p !== null && key in p) return (target.old_props[key] = p[key]);
} }
}, },
set(target, key, value) { set(target, key, value) {
@ -178,7 +185,7 @@ const spread_props_handler = {
if (is_function(p)) p = p(); if (is_function(p)) p = p();
const desc = get_descriptor(p, key); const desc = get_descriptor(p, key);
if (desc && desc.set) { if (desc && desc.set) {
desc.set(value); desc.set((target.old_props[key] = value));
return true; return true;
} }
} }
@ -237,16 +244,34 @@ const spread_props_handler = {
* @param {Array<Record<string, unknown> | (() => Record<string, unknown>)>} props * @param {Array<Record<string, unknown> | (() => Record<string, unknown>)>} props
* @returns {any} * @returns {any}
*/ */
export function spread_props(...props) { export function props(...props) {
return new Proxy({ props }, spread_props_handler); const effect = active_effect;
return new Proxy(
{
props,
old_props: untrack(() => {
const old_props = {};
for (let p of props) {
if (typeof p === 'function') p = p();
Object.assign(old_props, p);
}
return old_props;
}),
get destroyed() {
return effect ? (effect.f & (DESTROYED | INERT)) !== 0 : false;
}
},
spread_props_handler
);
} }
/** /**
* @param {Derived} current_value * @param {Derived} derived
* @returns {boolean}
*/ */
function has_destroyed_component_ctx(current_value) { function is_paused_or_destroyed(derived) {
return current_value.ctx?.d ?? false; const parent = get_derived_parent_effect(derived);
if (!parent) return false;
return (parent.f & (DESTROYED | INERT)) !== 0;
} }
/** /**
@ -414,7 +439,7 @@ export function prop(props, key, flags, fallback) {
fallback_value = new_value; fallback_value = new_value;
} }
if (has_destroyed_component_ctx(current_value)) { if (is_paused_or_destroyed(current_value)) {
return value; return value;
} }
@ -424,7 +449,7 @@ export function prop(props, key, flags, fallback) {
return value; return value;
} }
if (has_destroyed_component_ctx(current_value)) { if (is_paused_or_destroyed(current_value)) {
return current_value.v; return current_value.v;
} }

@ -14,7 +14,6 @@ import {
reaction_sources, reaction_sources,
check_dirtiness, check_dirtiness,
untracking, untracking,
is_destroying_effect,
push_reaction_value push_reaction_value
} from '../runtime.js'; } from '../runtime.js';
import { equals, safe_equals } from './equality.js'; import { equals, safe_equals } from './equality.js';
@ -38,9 +37,6 @@ import { execute_derived } from './deriveds.js';
export let inspect_effects = new Set(); export let inspect_effects = new Set();
/** @type {Map<Source, any>} */
export const old_values = new Map();
/** /**
* @param {Set<any>} v * @param {Set<any>} v
*/ */
@ -162,14 +158,6 @@ export function set(source, value, should_proxy = false) {
*/ */
export function internal_set(source, value) { export function internal_set(source, value) {
if (!source.equals(value)) { if (!source.equals(value)) {
var old_value = source.v;
if (is_destroying_effect) {
old_values.set(source, value);
} else {
old_values.set(source, old_value);
}
source.v = value; source.v = value;
if (DEV && tracing_mode_flag) { if (DEV && tracing_mode_flag) {

@ -26,7 +26,7 @@ import {
STALE_REACTION STALE_REACTION
} from './constants.js'; } from './constants.js';
import { flush_tasks } from './dom/task.js'; import { flush_tasks } from './dom/task.js';
import { internal_set, old_values } from './reactivity/sources.js'; import { internal_set } from './reactivity/sources.js';
import { destroy_derived_effects, update_derived } from './reactivity/deriveds.js'; import { destroy_derived_effects, update_derived } from './reactivity/deriveds.js';
import * as e from './errors.js'; import * as e from './errors.js';
@ -546,7 +546,6 @@ function flush_queued_root_effects() {
var collected_effects = process_effects(root_effects[i]); var collected_effects = process_effects(root_effects[i]);
flush_queued_effects(collected_effects); flush_queued_effects(collected_effects);
} }
old_values.clear();
} }
} finally { } finally {
is_flushing = false; is_flushing = false;
@ -811,10 +810,6 @@ export function get(signal) {
} }
} }
if (is_destroying_effect && old_values.has(signal)) {
return old_values.get(signal);
}
return signal.v; return signal.v;
} }

@ -14,8 +14,6 @@ export type ComponentContext = {
p: null | ComponentContext; p: null | ComponentContext;
/** context */ /** context */
c: null | Map<unknown, unknown>; c: null | Map<unknown, unknown>;
/** destroyed */
d: boolean;
/** deferred effects */ /** deferred effects */
e: null | Array<{ e: null | Array<{
fn: () => void | (() => void); fn: () => void | (() => void);

@ -14,7 +14,8 @@ export default test({
'up', 'up',
{ foo: false, bar: false }, { foo: false, bar: false },
'down', 'down',
{ foo: false, bar: false }, // TODO the test should be deleted as there's no more concept of "teardown stale value"
{ foo: true, bar: true },
'up', 'up',
{ foo: true, bar: true } { foo: true, bar: true }
]); ]);

@ -10,6 +10,14 @@ export default test({
}); });
await Promise.resolve(); await Promise.resolve();
assert.deepEqual(logs, ['top level', 'inner', 0, 'destroy inner', 0, 'destroy outer', 0]); assert.deepEqual(logs, [
'top level',
'inner',
0,
'destroy inner',
undefined,
'destroy outer',
undefined
]);
} }
}); });

@ -18,7 +18,7 @@ export default function Bind_component_snippet($$anchor) {
var fragment = root(); var fragment = root();
var node = $.first_child(fragment); var node = $.first_child(fragment);
TextInput(node, { TextInput(node, $.props({
get value() { get value() {
return $.get(value); return $.get(value);
}, },
@ -26,10 +26,10 @@ export default function Bind_component_snippet($$anchor) {
set value($$value) { set value($$value) {
$.set(value, $$value, true); $.set(value, $$value, true);
} }
}); }));
var text_1 = $.sibling(node); var text_1 = $.sibling(node);
$.template_effect(() => $.set_text(text_1, ` value: ${$.get(value) ?? ''}`)); $.template_effect(() => $.set_text(text_1, ` value: ${$.get(value) ?? ''}`));
$.append($$anchor, fragment); $.append($$anchor, fragment);
} }

@ -3,5 +3,5 @@ import 'svelte/internal/flags/legacy';
import * as $ from 'svelte/internal/client'; import * as $ from 'svelte/internal/client';
export default function Bind_this($$anchor) { export default function Bind_this($$anchor) {
$.bind_this(Foo($$anchor, { $$legacy: true }), ($$value) => foo = $$value, () => foo); $.bind_this(Foo($$anchor, $.props({ $$legacy: true })), ($$value) => foo = $$value, () => foo);
} }

@ -10,7 +10,7 @@ export default function Function_prop_no_getter($$anchor) {
const plusOne = (num) => num + 1; const plusOne = (num) => num + 1;
Button($$anchor, { Button($$anchor, $.props({
onmousedown: () => $.set(count, $.get(count) + 1), onmousedown: () => $.set(count, $.get(count) + 1),
onmouseup, onmouseup,
onmouseenter: () => $.set(count, plusOne($.get(count)), true), onmouseenter: () => $.set(count, plusOne($.get(count)), true),
@ -25,5 +25,5 @@ export default function Function_prop_no_getter($$anchor) {
}, },
$$slots: { default: true } $$slots: { default: true }
}); }));
} }

@ -16,6 +16,6 @@ export default function Purity($$anchor) {
var node = $.sibling(p_1, 2); var node = $.sibling(p_1, 2);
Child(node, { prop: encodeURIComponent('hello') }); Child(node, $.props({ prop: encodeURIComponent('hello') }));
$.append($$anchor, fragment); $.append($$anchor, fragment);
} }

Loading…
Cancel
Save