From c7895db46102bbdc840a57900b2630fe1d8c5c81 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Tue, 20 Feb 2024 18:10:59 -0500 Subject: [PATCH] move source code --- .../src/internal/client/dom/blocks/each.js | 5 +- .../src/internal/client/dom/blocks/key.js | 4 +- packages/svelte/src/internal/client/proxy.js | 3 +- .../internal/client/reactivity/equality.js | 30 ++++++ .../src/internal/client/reactivity/sources.js | 75 ++++++++++++++ .../svelte/src/internal/client/runtime.js | 99 +------------------ .../svelte/src/internal/client/validate.js | 3 +- packages/svelte/src/internal/index.js | 5 +- packages/svelte/tests/signals/test.ts | 27 ++--- 9 files changed, 129 insertions(+), 122 deletions(-) create mode 100644 packages/svelte/src/internal/client/reactivity/equality.js create mode 100644 packages/svelte/src/internal/client/reactivity/sources.js diff --git a/packages/svelte/src/internal/client/dom/blocks/each.js b/packages/svelte/src/internal/client/dom/blocks/each.js index b068869c59..ef3c9c9ed8 100644 --- a/packages/svelte/src/internal/client/dom/blocks/each.js +++ b/packages/svelte/src/internal/client/dom/blocks/each.js @@ -21,12 +21,11 @@ import { current_block, destroy_signal, execute_effect, - mutable_source, push_destroy_fn, - set_signal_value, - source + set_signal_value } from '../../runtime.js'; import { render_effect } from '../../reactivity/effects.js'; +import { source, mutable_source } from '../../reactivity/sources.js'; import { trigger_transitions } from '../../transitions.js'; import { is_array } from '../../utils.js'; diff --git a/packages/svelte/src/internal/client/dom/blocks/key.js b/packages/svelte/src/internal/client/dom/blocks/key.js index ed1541d327..fbe716a9a2 100644 --- a/packages/svelte/src/internal/client/dom/blocks/key.js +++ b/packages/svelte/src/internal/client/dom/blocks/key.js @@ -6,11 +6,11 @@ import { current_block, destroy_signal, execute_effect, - push_destroy_fn, - safe_not_equal + push_destroy_fn } from '../../runtime.js'; import { render_effect } from '../../reactivity/effects.js'; import { trigger_transitions } from '../../transitions.js'; +import { safe_not_equal } from '../../reactivity/equality.js'; /** @returns {import('../../types.js').KeyBlock} */ function create_key_block() { diff --git a/packages/svelte/src/internal/client/proxy.js b/packages/svelte/src/internal/client/proxy.js index 9a8cf2cb63..60b4165d75 100644 --- a/packages/svelte/src/internal/client/proxy.js +++ b/packages/svelte/src/internal/client/proxy.js @@ -3,10 +3,8 @@ import { get, set, update, - source, updating_derived, UNINITIALIZED, - mutable_source, batch_inspect, current_component_context } from './runtime.js'; @@ -22,6 +20,7 @@ import { object_prototype } from './utils.js'; import { add_owner, check_ownership, strip_owner } from './dev/ownership.js'; +import { mutable_source, source } from './reactivity/sources.js'; export const STATE_SYMBOL = Symbol('$state'); diff --git a/packages/svelte/src/internal/client/reactivity/equality.js b/packages/svelte/src/internal/client/reactivity/equality.js new file mode 100644 index 0000000000..34673b2dda --- /dev/null +++ b/packages/svelte/src/internal/client/reactivity/equality.js @@ -0,0 +1,30 @@ +/** + * @param {unknown} a + * @param {unknown} b + * @returns {boolean} + */ +export function default_equals(a, b) { + return a === b; +} + +/** + * @param {unknown} a + * @param {unknown} b + * @returns {boolean} + */ +export function safe_not_equal(a, b) { + // eslint-disable-next-line eqeqeq + return a != a + ? // eslint-disable-next-line eqeqeq + b == b + : a !== b || (a !== null && typeof a === 'object') || typeof a === 'function'; +} + +/** + * @param {unknown} a + * @param {unknown} b + * @returns {boolean} + */ +export function safe_equal(a, b) { + return !safe_not_equal(a, b); +} diff --git a/packages/svelte/src/internal/client/reactivity/sources.js b/packages/svelte/src/internal/client/reactivity/sources.js new file mode 100644 index 0000000000..a889e9c31e --- /dev/null +++ b/packages/svelte/src/internal/client/reactivity/sources.js @@ -0,0 +1,75 @@ +/** + * @template V + * @param {V} initial_value + * @returns {import('../types.js').SourceSignal} + */ + +import { DEV } from 'esm-env'; +import { CLEAN, SOURCE, current_component_context } from '../runtime.js'; +import { default_equals, safe_equal } from './equality.js'; + +/** + * @template V + * @param {V} initial_value + * @returns {import('../types.js').SourceSignal} + */ +/*#__NO_SIDE_EFFECTS__*/ +export function source(initial_value) { + return create_source_signal(SOURCE | CLEAN, initial_value); +} + +/** + * @template V + * @param {V} initial_value + * @returns {import('../types.js').SourceSignal} + */ +/*#__NO_SIDE_EFFECTS__*/ +export function mutable_source(initial_value) { + const s = source(initial_value); + s.e = safe_equal; + + // bind the signal to the component context, in case we need to + // track updates to trigger beforeUpdate/afterUpdate callbacks + if (current_component_context) { + (current_component_context.d ??= []).push(s); + } + + return s; +} + +/** + * @template V + * @param {import('../types.js').SignalFlags} flags + * @param {V} value + * @returns {import('../types.js').SourceSignal | import('../types.js').SourceSignal & import('../types.js').SourceSignalDebug} + */ +function create_source_signal(flags, value) { + if (DEV) { + return { + // consumers + c: null, + // equals + e: default_equals, + // flags + f: flags, + // value + v: value, + // write version + w: 0, + // this is for DEV only + inspect: new Set() + }; + } + return { + // consumers + c: null, + // equals + e: default_equals, + // flags + f: flags, + // value + v: value, + // write version + w: 0 + }; +} diff --git a/packages/svelte/src/internal/client/runtime.js b/packages/svelte/src/internal/client/runtime.js index 87bc7f4291..960b25abce 100644 --- a/packages/svelte/src/internal/client/runtime.js +++ b/packages/svelte/src/internal/client/runtime.js @@ -20,6 +20,8 @@ import { import { STATE_SYMBOL, unstate } from './proxy.js'; import { EACH_BLOCK, IF_BLOCK } from './block.js'; import { pre_effect, user_effect } from './reactivity/effects.js'; +import { mutable_source, source } from './reactivity/sources.js'; +import { default_equals, safe_equal, safe_not_equal } from './reactivity/equality.js'; export const SOURCE = 1; export const DERIVED = 1 << 1; @@ -145,52 +147,6 @@ export function batch_inspect(target, prop, receiver) { }; } -/** - * @param {unknown} a - * @param {unknown} b - * @returns {boolean} - */ -export function default_equals(a, b) { - return a === b; -} - -/** - * @template V - * @param {import('./types.js').SignalFlags} flags - * @param {V} value - * @returns {import('./types.js').SourceSignal | import('./types.js').SourceSignal & import('./types.js').SourceSignalDebug} - */ -function create_source_signal(flags, value) { - if (DEV) { - return { - // consumers - c: null, - // equals - e: default_equals, - // flags - f: flags, - // value - v: value, - // write version - w: 0, - // this is for DEV only - inspect: new Set() - }; - } - return { - // consumers - c: null, - // equals - e: default_equals, - // flags - f: flags, - // value - v: value, - // write version - w: 0 - }; -} - /** * @template V * @param {import('./types.js').SignalFlags} flags @@ -1328,35 +1284,6 @@ export function derived_safe_equal(init) { return signal; } -/** - * @template V - * @param {V} initial_value - * @returns {import('./types.js').SourceSignal} - */ -/*#__NO_SIDE_EFFECTS__*/ -export function source(initial_value) { - return create_source_signal(SOURCE | CLEAN, initial_value); -} - -/** - * @template V - * @param {V} initial_value - * @returns {import('./types.js').SourceSignal} - */ -/*#__NO_SIDE_EFFECTS__*/ -export function mutable_source(initial_value) { - const s = source(initial_value); - s.e = safe_equal; - - // bind the signal to the component context, in case we need to - // track updates to trigger beforeUpdate/afterUpdate callbacks - if (current_component_context) { - (current_component_context.d ??= []).push(s); - } - - return s; -} - /** * Use `untrack` to prevent something from being treated as an `$effect`/`$derived` dependency. * @@ -1542,28 +1469,6 @@ export function prop(props, key, flags, initial) { }; } -/** - * @param {unknown} a - * @param {unknown} b - * @returns {boolean} - */ -export function safe_not_equal(a, b) { - // eslint-disable-next-line eqeqeq - return a != a - ? // eslint-disable-next-line eqeqeq - b == b - : a !== b || (a !== null && typeof a === 'object') || typeof a === 'function'; -} - -/** - * @param {unknown} a - * @param {unknown} b - * @returns {boolean} - */ -export function safe_equal(a, b) { - return !safe_not_equal(a, b); -} - /** @returns {Map} */ export function get_or_init_context_map() { const component_context = current_component_context; diff --git a/packages/svelte/src/internal/client/validate.js b/packages/svelte/src/internal/client/validate.js index c6f590a420..83124697a8 100644 --- a/packages/svelte/src/internal/client/validate.js +++ b/packages/svelte/src/internal/client/validate.js @@ -1,5 +1,4 @@ -import { EACH_INDEX_REACTIVE } from '../../constants.js'; -import { source, untrack } from './runtime.js'; +import { untrack } from './runtime.js'; import { is_array } from './utils.js'; /** regex of all html void element names */ diff --git a/packages/svelte/src/internal/index.js b/packages/svelte/src/internal/index.js index aa38e22d35..c8262e2cdd 100644 --- a/packages/svelte/src/internal/index.js +++ b/packages/svelte/src/internal/index.js @@ -4,14 +4,11 @@ export { set, set_sync, invalidate_inner_signals, - source, - mutable_source, derived, derived_safe_equal, prop, flushSync, bubble_event, - safe_equal, tick, untrack, update, @@ -41,6 +38,8 @@ export { if_block as if } from './client/dom/blocks/if.js'; export { key_block as key } from './client/dom/blocks/key.js'; export * from './client/dom/blocks/each.js'; export * from './client/reactivity/effects.js'; +export * from './client/reactivity/sources.js'; +export * from './client/reactivity/equality.js'; export * from './client/render.js'; export * from './client/validate.js'; export { raf } from './client/timing.js'; diff --git a/packages/svelte/tests/signals/test.ts b/packages/svelte/tests/signals/test.ts index 2713ae9ba1..2628a67fa6 100644 --- a/packages/svelte/tests/signals/test.ts +++ b/packages/svelte/tests/signals/test.ts @@ -1,6 +1,7 @@ import { describe, assert, it } from 'vitest'; import * as $ from '../../src/internal/client/runtime'; import { effect, render_effect, user_effect } from '../../src/internal/client/reactivity/effects'; +import { source } from '../../src/internal/client/reactivity/sources'; import type { ComputationSignal } from '../../src/internal/client/types'; /** @@ -37,7 +38,7 @@ describe('signals', () => { test('effect with state and derived in it', () => { const log: string[] = []; - let count = $.source(0); + let count = source(0); let double = $.derived(() => $.get(count) * 2); effect(() => { log.push(`${$.get(count)}:${$.get(double)}`); @@ -54,7 +55,7 @@ describe('signals', () => { test('multiple effects with state and derived in it#1', () => { const log: string[] = []; - let count = $.source(0); + let count = source(0); let double = $.derived(() => $.get(count) * 2); effect(() => { @@ -75,7 +76,7 @@ describe('signals', () => { test('multiple effects with state and derived in it#2', () => { const log: string[] = []; - let count = $.source(0); + let count = source(0); let double = $.derived(() => $.get(count) * 2); effect(() => { @@ -96,7 +97,7 @@ describe('signals', () => { test('derived from state', () => { const log: number[] = []; - let count = $.source(0); + let count = source(0); let double = $.derived(() => $.get(count) * 2); effect(() => { @@ -114,7 +115,7 @@ describe('signals', () => { test('derived from derived', () => { const log: number[] = []; - let count = $.source(0); + let count = source(0); let double = $.derived(() => $.get(count) * 2); let quadruple = $.derived(() => $.get(double) * 2); @@ -137,8 +138,8 @@ describe('signals', () => { const fib = (n: number): number => (n < 2 ? 1 : fib(n - 1) + fib(n - 2)); const hard = (n: number, l: string) => n + fib(16); - const A = $.source(0); - const B = $.source(0); + const A = source(0); + const B = source(0); const C = $.derived(() => ($.get(A) % 2) + ($.get(B) % 2)); const D = $.derived(() => numbers.map((i) => i + ($.get(A) % 2) - ($.get(B) % 2))); const E = $.derived(() => hard($.get(C) + $.get(A) + $.get(D)[0]!, 'E')); @@ -177,7 +178,7 @@ describe('signals', () => { test('effects correctly handle unowned derived values that do not change', () => { const log: number[] = []; - let count = $.source(0); + let count = source(0); const read = () => { const x = $.derived(() => ({ count: $.get(count) })); return $.get(x); @@ -205,8 +206,8 @@ describe('signals', () => { return () => { const nested: ComputationSignal[] = []; - const a = $.source(0); - const b = $.source(0); + const a = source(0); + const b = source(0); const c = $.derived(() => { const a_2 = $.derived(() => $.get(a) + '!'); const b_2 = $.derived(() => $.get(b) + '?'); @@ -234,7 +235,7 @@ describe('signals', () => { }); // outside of test function so that they are unowned signals - let count = $.source(0); + let count = source(0); let calc = $.derived(() => { if ($.get(count) >= 2) { return 'limit'; @@ -285,7 +286,7 @@ describe('signals', () => { }; }); - let some_state = $.source({}); + let some_state = source({}); let some_deps = $.derived(() => { return [$.get(some_state)]; }); @@ -310,7 +311,7 @@ describe('signals', () => { test('schedules rerun when writing to signal before reading it', (runes) => { if (!runes) return () => {}; - const value = $.source({ count: 0 }); + const value = source({ count: 0 }); user_effect(() => { $.set(value, { count: 0 }); $.get(value);