Skip to content

Commit 10aacfa

Browse files
authored
chore: remove exposable (#9783)
* use flags for prop_source, this will be useful later * remove exposable/expose stuff --------- Co-authored-by: Rich Harris <[email protected]>
1 parent 25abca7 commit 10aacfa

File tree

7 files changed

+57
-126
lines changed

7 files changed

+57
-126
lines changed

packages/svelte/src/compiler/phases/3-transform/client/utils.js

+31-16
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import * as b from '../../../utils/builders.js';
22
import { extract_paths, is_simple_expression } from '../../../utils/ast.js';
33
import { error } from '../../../errors.js';
4+
import { PROPS_CALL_DEFAULT_VALUE, PROPS_IS_IMMUTABLE } from '../../../../constants.js';
45

56
/**
67
* @template {import('./types').ClientTransformState} State
@@ -359,29 +360,43 @@ export function get_props_method(binding, state, name, default_value) {
359360
(state.analysis.immutable ? binding.reassigned : binding.mutated);
360361

361362
if (needs_source) {
362-
args.push(b.literal(state.analysis.immutable));
363-
}
363+
let flags = 0;
364364

365-
if (default_value) {
366-
// To avoid eagerly evaluating the right-hand-side, we wrap it in a thunk if necessary
367-
if (is_simple_expression(default_value)) {
368-
args.push(default_value);
369-
} else {
370-
if (
371-
default_value.type === 'CallExpression' &&
372-
default_value.callee.type === 'Identifier' &&
373-
default_value.arguments.length === 0
374-
) {
375-
args.push(default_value.callee);
365+
/** @type {import('estree').Expression | undefined} */
366+
let arg;
367+
368+
if (state.analysis.immutable) {
369+
flags |= PROPS_IS_IMMUTABLE;
370+
}
371+
372+
if (default_value) {
373+
// To avoid eagerly evaluating the right-hand-side, we wrap it in a thunk if necessary
374+
if (is_simple_expression(default_value)) {
375+
arg = default_value;
376376
} else {
377-
args.push(b.thunk(default_value));
377+
if (
378+
default_value.type === 'CallExpression' &&
379+
default_value.callee.type === 'Identifier' &&
380+
default_value.arguments.length === 0
381+
) {
382+
arg = default_value.callee;
383+
} else {
384+
arg = b.thunk(default_value);
385+
}
386+
387+
flags |= PROPS_CALL_DEFAULT_VALUE;
378388
}
389+
}
379390

380-
args.push(b.true);
391+
if (flags || arg) {
392+
args.push(b.literal(flags));
393+
if (arg) args.push(arg);
381394
}
395+
396+
return b.call('$.prop_source', ...args);
382397
}
383398

384-
return b.call(needs_source ? '$.prop_source' : '$.prop', ...args);
399+
return b.call('$.prop', ...args);
385400
}
386401

387402
/**

packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js

+8-23
Original file line numberDiff line numberDiff line change
@@ -795,32 +795,17 @@ function serialize_inline_component(node, component_name, context) {
795795
push_prop(
796796
b.get(attribute.name, [
797797
b.return(
798-
b.call(
799-
'$.exposable',
800-
b.thunk(
801-
/** @type {import('estree').Expression} */ (context.visit(attribute.expression))
802-
)
803-
)
798+
/** @type {import('estree').Expression} */ (context.visit(attribute.expression))
804799
)
805800
])
806801
);
807-
// If the binding is just a reference to a top level state variable
808-
// we don't need a setter as the inner component can write to the signal directly
809-
const binding =
810-
attribute.expression.type !== 'Identifier'
811-
? null
812-
: context.state.scope.get(attribute.expression.name);
813-
if (
814-
binding === null ||
815-
(binding.kind !== 'state' && binding.kind !== 'prop' && binding.kind !== 'rest_prop')
816-
) {
817-
const assignment = b.assignment('=', attribute.expression, b.id('$$value'));
818-
push_prop(
819-
b.set(attribute.name, [
820-
b.stmt(serialize_set_binding(assignment, context, () => context.visit(assignment)))
821-
])
822-
);
823-
}
802+
803+
const assignment = b.assignment('=', attribute.expression, b.id('$$value'));
804+
push_prop(
805+
b.set(attribute.name, [
806+
b.stmt(serialize_set_binding(assignment, context, () => context.visit(assignment)))
807+
])
808+
);
824809
}
825810
}
826811
}

packages/svelte/src/constants.js

+3
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ export const EACH_IS_CONTROLLED = 1 << 3;
55
export const EACH_IS_ANIMATED = 1 << 4;
66
export const EACH_IS_IMMUTABLE = 1 << 6;
77

8+
export const PROPS_IS_IMMUTABLE = 1;
9+
export const PROPS_CALL_DEFAULT_VALUE = 1 << 1;
10+
811
/** List of Element events that will be delegated */
912
export const DelegatedEvents = [
1013
'beforeinput',

packages/svelte/src/internal/client/render.js

+1-5
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ import {
3434
untrack,
3535
effect,
3636
flushSync,
37-
expose,
3837
safe_not_equal,
3938
current_block,
4039
source,
@@ -1193,10 +1192,7 @@ export function bind_prop(props, prop, value) {
11931192
/** @param {V | null} value */
11941193
const update = (value) => {
11951194
const current_props = unwrap(props);
1196-
const signal = expose(() => current_props[prop]);
1197-
if (is_signal(signal)) {
1198-
set(signal, value);
1199-
} else if (Object.getOwnPropertyDescriptor(current_props, prop)?.set !== undefined) {
1195+
if (get_descriptor(current_props, prop)?.set !== undefined) {
12001196
current_props[prop] = value;
12011197
}
12021198
};

packages/svelte/src/internal/client/runtime.js

+13-79
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import { DEV } from 'esm-env';
22
import { subscribe_to_store } from '../../store/utils.js';
33
import { EMPTY_FUNC, run_all } from '../common.js';
4-
import { get_descriptors, is_array } from './utils.js';
4+
import { get_descriptor, get_descriptors, is_array } from './utils.js';
5+
import { PROPS_CALL_DEFAULT_VALUE, PROPS_IS_IMMUTABLE } from '../../constants.js';
56

67
export const SOURCE = 1;
78
export const DERIVED = 1 << 1;
@@ -30,8 +31,7 @@ let current_scheduler_mode = FLUSH_MICROTASK;
3031
// Used for handling scheduling
3132
let is_micro_task_queued = false;
3233
let is_task_queued = false;
33-
// Used for exposing signals
34-
let is_signal_exposed = false;
34+
3535
// Handle effect queues
3636

3737
/** @type {import('./types.js').EffectSignal[]} */
@@ -63,8 +63,6 @@ export let current_untracking = false;
6363
/** Exists to opt out of the mutation validation for stores which may be set for the first time during a derivation */
6464
let ignore_mutation_validation = false;
6565

66-
/** @type {null | import('./types.js').Signal} */
67-
let current_captured_signal = null;
6866
// If we are working with a get() chain that has no active container,
6967
// to prevent memory leaks, we skip adding the consumer.
7068
let current_skip_consumer = false;
@@ -800,23 +798,6 @@ export function unsubscribe_on_destroy(stores) {
800798
});
801799
}
802800

803-
/**
804-
* Wraps a function and marks execution context so that the last signal read from can be captured
805-
* using the `expose` function.
806-
* @template V
807-
* @param {() => V} fn
808-
* @returns {V}
809-
*/
810-
export function exposable(fn) {
811-
const previous_is_signal_exposed = is_signal_exposed;
812-
try {
813-
is_signal_exposed = true;
814-
return fn();
815-
} finally {
816-
is_signal_exposed = previous_is_signal_exposed;
817-
}
818-
}
819-
820801
/**
821802
* @template V
822803
* @param {import('./types.js').Signal<V>} signal
@@ -836,10 +817,6 @@ export function get(signal) {
836817
return signal.v;
837818
}
838819

839-
if (is_signal_exposed && current_should_capture_signal) {
840-
current_captured_signal = signal;
841-
}
842-
843820
if (is_signals_recorded) {
844821
captured_signals.add(signal);
845822
}
@@ -906,31 +883,6 @@ export function set_sync(signal, value) {
906883
flushSync(() => set(signal, value));
907884
}
908885

909-
/**
910-
* Invokes a function and captures the last signal that is read during the invocation
911-
* if that signal is read within the `exposable` function context.
912-
* If a signal is captured, it returns the signal instead of the read value.
913-
* @template V
914-
* @param {() => V} possible_signal_fn
915-
* @returns {any}
916-
*/
917-
export function expose(possible_signal_fn) {
918-
const previous_captured_signal = current_captured_signal;
919-
const previous_should_capture_signal = current_should_capture_signal;
920-
current_captured_signal = null;
921-
current_should_capture_signal = true;
922-
try {
923-
const value = possible_signal_fn();
924-
if (current_captured_signal === null) {
925-
return value;
926-
}
927-
return current_captured_signal;
928-
} finally {
929-
current_captured_signal = previous_captured_signal;
930-
current_should_capture_signal = previous_should_capture_signal;
931-
}
932-
}
933-
934886
/**
935887
* Invokes a function and captures all signals that are read during the invocation,
936888
* then invalidates them.
@@ -1463,35 +1415,19 @@ export function is_store(val) {
14631415
* @template V
14641416
* @param {import('./types.js').MaybeSignal<Record<string, unknown>>} props_obj
14651417
* @param {string} key
1466-
* @param {boolean} immutable
1418+
* @param {number} flags
14671419
* @param {V | (() => V)} [default_value]
1468-
* @param {boolean} [call_default_value]
14691420
* @returns {import('./types.js').Signal<V> | (() => V)}
14701421
*/
1471-
export function prop_source(props_obj, key, immutable, default_value, call_default_value) {
1422+
export function prop_source(props_obj, key, flags, default_value) {
1423+
const call_default_value = (flags & PROPS_CALL_DEFAULT_VALUE) !== 0;
1424+
const immutable = (flags & PROPS_IS_IMMUTABLE) !== 0;
1425+
14721426
const props = is_signal(props_obj) ? get(props_obj) : props_obj;
1473-
const possible_signal = /** @type {import('./types.js').MaybeSignal<V>} */ (
1474-
expose(() => props[key])
1475-
);
1476-
const update_bound_prop = Object.getOwnPropertyDescriptor(props, key)?.set;
1427+
const update_bound_prop = get_descriptor(props, key)?.set;
14771428
let value = props[key];
14781429
const should_set_default_value = value === undefined && default_value !== undefined;
14791430

1480-
if (
1481-
is_signal(possible_signal) &&
1482-
possible_signal.v === value &&
1483-
update_bound_prop === undefined
1484-
) {
1485-
if (should_set_default_value) {
1486-
set(
1487-
possible_signal,
1488-
// @ts-expect-error would need a cumbersome method overload to type this
1489-
call_default_value ? default_value() : default_value
1490-
);
1491-
}
1492-
return possible_signal;
1493-
}
1494-
14951431
if (should_set_default_value) {
14961432
value =
14971433
// @ts-expect-error would need a cumbersome method overload to type this
@@ -1534,7 +1470,7 @@ export function prop_source(props_obj, key, immutable, default_value, call_defau
15341470
}
15351471
});
15361472

1537-
if (is_signal(possible_signal) && update_bound_prop !== undefined) {
1473+
if (update_bound_prop !== undefined) {
15381474
let ignore_first = !should_set_default_value;
15391475
sync_effect(() => {
15401476
// Before if to ensure signal dependency is registered
@@ -1548,11 +1484,9 @@ export function prop_source(props_obj, key, immutable, default_value, call_defau
15481484
return;
15491485
}
15501486

1551-
if (not_equal(immutable, propagating_value, possible_signal.v)) {
1552-
ignore_next1 = true;
1553-
did_update_to_defined = true;
1554-
untrack(() => update_bound_prop(propagating_value));
1555-
}
1487+
ignore_next1 = true;
1488+
did_update_to_defined = true;
1489+
untrack(() => update_bound_prop(propagating_value));
15561490
});
15571491
}
15581492

packages/svelte/src/internal/index.js

-2
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@ export {
44
set,
55
set_sync,
66
invalidate_inner_signals,
7-
expose,
8-
exposable,
97
source,
108
mutable_source,
119
derived,

packages/svelte/tests/snapshot/samples/svelte-element/_expected/client/index.svelte.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import * as $ from "svelte/internal";
66
export default function Svelte_element($$anchor, $$props) {
77
$.push($$props, true);
88

9-
let tag = $.prop_source($$props, "tag", true, 'hr');
9+
let tag = $.prop_source($$props, "tag", 1, 'hr');
1010
/* Init */
1111
var fragment = $.comment($$anchor);
1212
var node = $.child_frag(fragment);

0 commit comments

Comments
 (0)