correctly inspect derived values (#9731)

Co-authored-by: Rich Harris <rich.harris@vercel.com>
pull/9736/head
Rich Harris 1 year ago committed by GitHub
parent 1108587f1b
commit 765d01d76c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: improve `$inspect` type definition

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: correctly inspect derived values

@ -191,9 +191,36 @@ function create_source_signal(flags, value) {
* @param {import('./types.js').SignalFlags} flags * @param {import('./types.js').SignalFlags} flags
* @param {V} value * @param {V} value
* @param {import('./types.js').Block | null} block * @param {import('./types.js').Block | null} block
* @returns {import('./types.js').ComputationSignal<V>} * @returns {import('./types.js').ComputationSignal<V> | import('./types.js').ComputationSignal<V> & import('./types.js').SourceSignalDebug}
*/ */
function create_computation_signal(flags, value, block) { function create_computation_signal(flags, value, block) {
if (DEV) {
return {
// block
b: block,
// consumers
c: null,
// destroy
d: null,
// equals
e: null,
// flags
f: flags,
// init
i: null,
// references
r: null,
// value
v: value,
// context: We can remove this if we get rid of beforeUpdate/afterUpdate
x: null,
// destroy
y: null,
// this is for DEV only
inspect: new Set()
};
}
return { return {
// block // block
b: block, b: block,
@ -671,6 +698,12 @@ function update_derived(signal, force_schedule) {
if (!equals(value, signal.v)) { if (!equals(value, signal.v)) {
signal.v = value; signal.v = value;
mark_signal_consumers(signal, DIRTY, force_schedule); mark_signal_consumers(signal, DIRTY, force_schedule);
// @ts-expect-error
if (DEV && signal.inspect && force_schedule) {
// @ts-expect-error
for (const fn of signal.inspect) fn();
}
} }
} }
@ -836,7 +869,15 @@ export function get(signal) {
} }
if ((flags & DERIVED) !== 0 && is_signal_dirty(signal)) { if ((flags & DERIVED) !== 0 && is_signal_dirty(signal)) {
update_derived(/** @type {import('./types.js').ComputationSignal<V>} **/ (signal), false); if (DEV) {
// we want to avoid tracking indirect dependencies
const previous_inspect_fn = inspect_fn;
inspect_fn = null;
update_derived(/** @type {import('./types.js').ComputationSignal<V>} **/ (signal), false);
inspect_fn = previous_inspect_fn;
} else {
update_derived(/** @type {import('./types.js').ComputationSignal<V>} **/ (signal), false);
}
} }
return signal.v; return signal.v;
} }

@ -132,12 +132,23 @@ declare namespace $effect {
declare function $props<T>(): T; declare function $props<T>(): T;
/** /**
* Logs the arguments whenever they, or the properties they contain, change. Example: * Inspects a value whenever it, or the properties it contains, change. Example:
* *
* ```ts * ```ts
* $inspect(someValue, someOtherValue) * $inspect({ someValue, someOtherValue })
* ```
*
* If a second argument is provided, it will be called with the value and the event type
* (`'init'` or `'update'`), otherwise the value will be logged to the console.
*
* ```ts
* $inspect(x, console.trace);
* $inspect(y, (y) => { debugger; });
* ``` * ```
* *
* https://svelte-5-preview.vercel.app/docs/runes#$inspect * https://svelte-5-preview.vercel.app/docs/runes#$inspect
*/ */
declare function $inspect(): void; declare function $inspect<T>(
value: T,
callback?: (value: T, type: 'init' | 'update') => void
): void;

@ -0,0 +1,31 @@
import { test } from '../../test';
/**
* @type {any[]}
*/
let log;
export default test({
compileOptions: {
dev: true
},
get props() {
log = [];
return {
push: (/** @type {any} */ ...v) => log.push(...v)
};
},
async test({ assert, target }) {
const button = target.querySelector('button');
button?.click();
await Promise.resolve();
button?.click();
await Promise.resolve();
assert.deepEqual(log, ['X', 'init', 'XX', 'update', 'XXX', 'update']);
}
});

@ -0,0 +1,11 @@
<script>
/** @type {{ push: (v: any) => void }} */
let { push } = $props();
let x = $state('x');
let y = $derived(x.toUpperCase());
$inspect(y, push);
</script>
<button on:click={() => x += 'x'}>{x}</button>
Loading…
Cancel
Save