blockless
Rich Harris 10 months ago
parent 1d892605f5
commit 8f4dc6b86b

@ -15,7 +15,7 @@ import {
} from '../../hydration.js';
import { empty, map_get, map_set } from '../../operations.js';
import { insert, remove } from '../../reconciler.js';
import { set_signal_value } from '../../runtime.js';
import { set } from '../../runtime.js';
import {
destroy_effect,
pause_effect,
@ -551,7 +551,7 @@ export function get_first_element(block) {
function update_each_item_block(block, item, index, type) {
const block_v = block.v;
if ((type & EACH_ITEM_REACTIVE) !== 0) {
set_signal_value(block_v, item);
set(block_v, item);
}
// const transitions = block.s;
const transitions = null;
@ -563,7 +563,7 @@ function update_each_item_block(block, item, index, type) {
// each_animation(block, transitions);
}
if (index_is_reactive) {
set_signal_value(/** @type {import('#client').Source<number>} */ (block.i), index);
set(/** @type {import('#client').Source<number>} */ (block.i), index);
} else {
block.i = index;
}

@ -5,8 +5,7 @@ import {
updating_derived,
batch_inspect,
current_component_context,
untrack,
set_signal_value
untrack
} from './runtime.js';
import { effect_active } from './reactivity/effects.js';
import {
@ -150,12 +149,12 @@ export function unstate(value) {
}
/**
* @param {import('./types.js').ValueSignal<number>} signal
* @param {import('./types.js').Source<number>} signal
* @param {1 | -1} [d]
*/
function update_version(signal, d = 1) {
const value = untrack(() => get(signal));
set_signal_value(signal, value + d);
set(signal, value + d);
}
/** @type {ProxyHandler<import('./types.js').ProxyStateObject<any>>} */

@ -225,15 +225,7 @@ function execute_signal_fn(signal) {
current_untracking = false;
try {
let res;
if (is_render_effect) {
res = /** @type {(block: null, signal: import('#client').Signal) => V} */ (init)(
null,
/** @type {import('#client').Signal} */ (signal)
);
} else {
res = /** @type {() => V} */ (init)();
}
const res = /** @type {() => V} */ (init)();
let dependencies = /** @type {import('#client').ValueSignal<unknown>[]} **/ (signal.d);
if (current_dependencies !== null) {
let i;
@ -269,7 +261,7 @@ function execute_signal_fn(signal) {
dependencies[current_dependencies_index + i] = current_dependencies[i];
}
} else {
signal.d = /** @type {import('#client').Signal<V>[]} **/ (
signal.d = /** @type {import('#client').ValueSignal<V>[]} **/ (
dependencies = current_dependencies
);
}
@ -747,18 +739,81 @@ export function get(signal) {
/**
* @template V
* @param {import('#client').Signal<V>} signal
* @param {import('#client').Source<V>} signal
* @param {V} value
* @returns {V}
*/
export function set(signal, value) {
set_signal_value(signal, value);
if (
!current_untracking &&
!ignore_mutation_validation &&
current_consumer !== null &&
is_runes(null) &&
(current_consumer.f & DERIVED) !== 0
) {
throw new Error(
'ERR_SVELTE_UNSAFE_MUTATION' +
(DEV
? ": Unsafe mutations during Svelte's render or derived phase are not permitted in runes mode. " +
'This can lead to unexpected errors and possibly cause infinite loops.\n\nIf this mutation is not meant ' +
'to be reactive do not use the "$state" rune for that declaration.'
: '')
);
}
if (
(signal.f & SOURCE) !== 0 &&
!(/** @type {import('#client').EqualsFunctions} */ (signal.e)(value, signal.v))
) {
signal.v = value;
// Increment write version so that unowned signals can properly track dirtyness
signal.w++;
// If the current signal is running for the first time, it won't have any
// consumers as we only allocate and assign the consumers after the signal
// has fully executed. So in the case of ensuring it registers the consumer
// properly for itself, we need to ensure the current effect actually gets
// scheduled. i.e:
//
// $effect(() => x++)
//
// We additionally want to skip this logic for when ignore_mutation_validation is
// true, as stores write to source signal on initialization.
if (
is_runes(null) &&
!ignore_mutation_validation &&
current_effect !== null &&
current_effect.c === null &&
(current_effect.f & CLEAN) !== 0 &&
(current_effect.f & MANAGED) === 0
) {
if (current_dependencies !== null && current_dependencies.includes(signal)) {
set_signal_status(current_effect, DIRTY);
schedule_effect(current_effect, false);
} else {
if (current_untracked_writes === null) {
current_untracked_writes = [signal];
} else {
current_untracked_writes.push(signal);
}
}
}
mark_signal_consumers(signal, DIRTY, true);
// @ts-expect-error
if (DEV && signal.inspect) {
if (is_batching_effect) {
last_inspected_signal = /** @type {import('#client').SourceDebug} */ (signal);
} else {
for (const fn of /** @type {import('#client').SourceDebug} */ (signal).inspect) fn();
}
}
}
return value;
}
/**
* @template V
* @param {import('#client').Signal<V>} signal
* @param {import('#client').Source<V>} signal
* @param {V} value
* @returns {void}
*/
@ -796,11 +851,11 @@ export function invalidate_inner_signals(fn) {
/**
* @template V
* @param {import('#client').Signal<V>} source
* @param {import('#client').Source<V>} source
* @param {V} value
*/
export function mutate(source, value) {
set_signal_value(
set(
source,
untrack(() => get(source))
);
@ -847,79 +902,6 @@ function mark_signal_consumers(signal, to_status, force_schedule) {
}
/**
* @template V
* @param {import('#client').Signal<V>} signal
* @param {V} value
* @returns {void}
*/
export function set_signal_value(signal, value) {
if (
!current_untracking &&
!ignore_mutation_validation &&
current_consumer !== null &&
is_runes(null) &&
(current_consumer.f & DERIVED) !== 0
) {
throw new Error(
'ERR_SVELTE_UNSAFE_MUTATION' +
(DEV
? ": Unsafe mutations during Svelte's render or derived phase are not permitted in runes mode. " +
'This can lead to unexpected errors and possibly cause infinite loops.\n\nIf this mutation is not meant ' +
'to be reactive do not use the "$state" rune for that declaration.'
: '')
);
}
if (
(signal.f & SOURCE) !== 0 &&
!(/** @type {import('#client').EqualsFunctions} */ (signal.e)(value, signal.v))
) {
signal.v = value;
// Increment write version so that unowned signals can properly track dirtyness
signal.w++;
// If the current signal is running for the first time, it won't have any
// consumers as we only allocate and assign the consumers after the signal
// has fully executed. So in the case of ensuring it registers the consumer
// properly for itself, we need to ensure the current effect actually gets
// scheduled. i.e:
//
// $effect(() => x++)
//
// We additionally want to skip this logic for when ignore_mutation_validation is
// true, as stores write to source signal on initialization.
if (
is_runes(null) &&
!ignore_mutation_validation &&
current_effect !== null &&
current_effect.c === null &&
(current_effect.f & CLEAN) !== 0 &&
(current_effect.f & MANAGED) === 0
) {
if (current_dependencies !== null && current_dependencies.includes(signal)) {
set_signal_status(current_effect, DIRTY);
schedule_effect(current_effect, false);
} else {
if (current_untracked_writes === null) {
current_untracked_writes = [signal];
} else {
current_untracked_writes.push(signal);
}
}
}
mark_signal_consumers(signal, DIRTY, true);
// @ts-expect-error
if (DEV && signal.inspect) {
if (is_batching_effect) {
last_inspected_signal = /** @type {import('#client').SourceDebug} */ (signal);
} else {
for (const fn of /** @type {import('#client').SourceDebug} */ (signal).inspect) fn();
}
}
}
}
/**
* @template V
* @param {import('#client').Reaction} signal
* @returns {void}
*/
@ -1021,7 +1003,7 @@ function get_parent_context(component_context) {
*/
export function update(signal, d = 1) {
const value = get(signal);
set_signal_value(signal, value + d);
set(signal, value + d);
return value;
}
@ -1043,7 +1025,7 @@ export function update_prop(fn, d = 1) {
*/
export function update_pre(signal, d = 1) {
const value = get(signal) + d;
set_signal_value(signal, value);
set(signal, value);
return value;
}

Loading…
Cancel
Save