@xaendar/signals 0.3.31 → 0.3.34

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xaendar/signals",
3
- "version": "0.3.31",
3
+ "version": "0.3.34",
4
4
  "description": "A library for managing signals in web applications",
5
5
  "sideEffects": false,
6
6
  "type": "module",
@@ -16,7 +16,7 @@
16
16
  }
17
17
  },
18
18
  "dependencies": {
19
- "@xaendar/common": "0.3.31",
20
- "@xaendar/types": "0.3.31"
19
+ "@xaendar/common": "0.3.34",
20
+ "@xaendar/types": "0.3.34"
21
21
  }
22
22
  }
@@ -194,6 +194,74 @@ export { };
194
194
 
195
195
  import { NoArgsVoidFunction } from '@xaendar/types';
196
196
 
197
+ /**
198
+ * A read-only Signal whose value is derived lazily from other Signals.
199
+ *
200
+ * The value is recomputed only when explicitly read and only if one or more
201
+ * of its (recursive) dependencies have changed since the last evaluation.
202
+ * The result is cached and reused until the Signal becomes stale again.
203
+ *
204
+ * @template T The type of the computed value.
205
+ *
206
+ * @see Signal algorithms — "The Signal.Computed class"
207
+ */
208
+ declare class Computed<T = any> {
209
+ #private;
210
+ /* Excluded from this release type: getSources */
211
+ /* Excluded from this release type: getSinks */
212
+ /**
213
+ * Creates a new `Computed` signal.
214
+ *
215
+ * The Signal starts in the `~dirty~` state with an uninitialised value, so
216
+ * `#callback` will be invoked on the first `get()`.
217
+ *
218
+ * @param cb - Pure function evaluated lazily to produce the value.
219
+ * Receives the `Computed` instance as `this`.
220
+ * @param options - Optional configuration:
221
+ * - `equals` — custom equality function; defaults to `Object.is`.
222
+ *
223
+ * @see Signal algorithms — "Signal.Computed Constructor"
224
+ */
225
+ constructor(cb: (this: Computed<T>) => T, options?: SignalOptions<T>);
226
+ /**
227
+ * Returns the current value of this Signal, re-evaluating `#callback` if
228
+ * the cached value may be stale.
229
+ *
230
+ * Registers this Signal as a source of any outer `Computed` currently
231
+ * being evaluated (automatic dependency tracking).
232
+ *
233
+ * If the state is `~dirty~` or `~checked~`, walks the source graph
234
+ * depth-first to find and recalculate the deepest stale `Computed` first,
235
+ * then re-checks upward until this Signal is `~clean~`.
236
+ *
237
+ * @returns The current computed value, or a boxed error object if the last
238
+ * evaluation threw.
239
+ * @throws If `frozen` is `true`.
240
+ * @throws If the Signal is in the `~computing~` state (cyclic dependency).
241
+ *
242
+ * @see Signal algorithms — "Method: Signal.Computed.prototype.get"
243
+ */
244
+ get(): T | {
245
+ isError: true;
246
+ value: Error;
247
+ };
248
+ /* Excluded from this release type: addSource */
249
+ /* Excluded from this release type: getState */
250
+ /* Excluded from this release type: setState */
251
+ /* Excluded from this release type: addSink */
252
+ /* Excluded from this release type: removeSink */
253
+ }
254
+
255
+ /**
256
+ * Rapresents the state of a computed signal.
257
+ * The state can be one of the following:
258
+ * - `dirty`: the computed signal is dirty and needs to be recomputed.
259
+ * - `checked`: the computed signal is checked and needs to be recomputed.
260
+ * - `computing`: the computed signal is currently being computed.
261
+ * - `clean`: the computed signal is clean and does not need to be recomputed.
262
+ */
263
+ declare type ComputedState = 'dirty' | 'checked' | 'computing' | 'clean';
264
+
197
265
  /**
198
266
  * Runs a side-effectful function and automatically re-runs it whenever any
199
267
  * Signal read during its execution changes.
@@ -251,4 +319,176 @@ export declare function loadSignals(options?: {
251
319
  devMode?: boolean;
252
320
  }): void;
253
321
 
322
+ /**
323
+ * A function that compares two values of type `T` and returns `true` if they are considered equal, or `false` otherwise.
324
+ * This function is used to determine if a signal's value has changed and if dependent computations need to be re-evaluated.
325
+ */
326
+ export declare type SignalEqual<T> = (this: State<T> | Computed<T>, t: any, t2: any) => boolean;
327
+
328
+ export declare type SignalOptions<T> = {
329
+ /**
330
+ * Custom comparison function between old and new value. Default: Object.is.
331
+ * The signal is passed in as the this value for context.
332
+ */
333
+ equals?: SignalEqual<T>;
334
+ /**
335
+ * Callback called when isWatched becomes true, if it was previously false
336
+ */
337
+ watched?: (this: State<T> | Computed<T>) => void;
338
+ /**
339
+ * Callback called whenever isWatched becomes false, if it was previously true
340
+ */
341
+ unwatched?: (this: State<T> | Computed<T>) => void;
342
+ };
343
+
344
+ declare class State<T = any> {
345
+ #private;
346
+ /* Excluded from this release type: getSinks */
347
+ /**
348
+ * Creates a new `State` signal.
349
+ *
350
+ * @param initialValue - The initial value of the signal.
351
+ * @param options - Optional configuration:
352
+ * - `equals` — custom equality function; defaults to `Object.is`.
353
+ * - `watched` — called when the signal gains its first sink.
354
+ * - `unwatched` — called when the signal loses its last sink.
355
+ *
356
+ * @see Signal algorithms — 'Constructor: Signal.State(initialValue, options)'
357
+ */
358
+ constructor(initialValue: T, options?: SignalOptions<T>);
359
+ /**
360
+ * Returns the current value of the signal, registering this Signal as a
361
+ * source of the innermost `Computed` currently being evaluated (if any).
362
+ *
363
+ * @throws If `frozen` is `true` — reads are forbidden while a protected
364
+ * callback (`notify`, `watched`, `unwatched`) is executing.
365
+ *
366
+ * @see Signal algorithms — 'Method: Signal.State.prototype.get()'
367
+ */
368
+ get(): T;
369
+ /**
370
+ * Updates the signal's value and propagates changes to all dependent
371
+ * sinks.
372
+ *
373
+ * If `equals(currentValue, newValue)` returns `true` the call is a no-op
374
+ * and no propagation occurs. Otherwise `#value` is updated, all direct
375
+ * `Computed` sinks are marked `~dirty~`, indirect ones `~checked~`, and
376
+ * each reachable `Watcher` has its `notify` callback invoked synchronously
377
+ * (with `frozen = true`).
378
+ *
379
+ * @param newValue - The new value to set.
380
+ * @throws If `frozen` is `true` — writes are forbidden while a protected
381
+ * callback is executing.
382
+ *
383
+ * @see Signal algorithms — 'Method: Signal.State.prototype.set(newValue)'
384
+ * @see Algorithm — 'Set Signal value'
385
+ */
386
+ set(newValue: T): void;
387
+ /* Excluded from this release type: addSink */
388
+ /* Excluded from this release type: removeSink */
389
+ }
390
+
391
+ /**
392
+ * A `Watcher` observes a set of Signals and fires a `notify` callback
393
+ * synchronously when any of their (recursive) dependencies change.
394
+ *
395
+ * It is the low-level primitive on top of which frameworks implement
396
+ * effects and scheduling. It does not hold a value and has no generic
397
+ * type parameter.
398
+ *
399
+ * @see Signal algorithms — 'The `Signal.subtle.Watcher` class'
400
+ */
401
+ declare class Watcher {
402
+ #private;
403
+ /* Excluded from this release type: getSources */
404
+ /**
405
+ * Creates a new Watcher.
406
+ *
407
+ * The Watcher starts in the `~waiting~` state with an empty signals set.
408
+ *
409
+ * @param notifyCallback - Called synchronously (with `frozen = true`) the
410
+ * first time a watched dependency changes after each `watch` call. No
411
+ * Signals may be read or written inside this callback.
412
+ *
413
+ * @see Signal algorithms — 'Constructor: new Signal.subtle.Watcher(callback)'
414
+ */
415
+ constructor(notifyCallback: NoArgsVoidFunction);
416
+ /**
417
+ * Returns the subset of watched Signals that are `Computed` instances
418
+ * currently in a `~dirty~` or `~checked~` state, meaning they may have a
419
+ * stale value that has not yet been re-evaluated.
420
+ *
421
+ * Typically called inside the microtask scheduled by the `notify` callback
422
+ * to know which Signals need to be pulled.
423
+ *
424
+ * @returns An array of `Computed` signals that are dirty or checked.
425
+ *
426
+ * @see Signal algorithms — 'Method: Signal.subtle.Watcher.prototype.getPending()'
427
+ */
428
+ getPending(): Computed<unknown>[];
429
+ /**
430
+ * Adds the given Signals to the watched set and transitions the Watcher to
431
+ * the `~watching~` state.
432
+ *
433
+ * For each newly-watched Signal, the Watcher is registered as a sink and —
434
+ * if it is the first sink — the sink registration is propagated recursively
435
+ * up through the Signal's sources, building the live dependency chain.
436
+ *
437
+ * The `watched` callback of each Signal (if any) is called with
438
+ * `frozen = true`.
439
+ *
440
+ * @param signals - One or more `State` signals to start watching.
441
+ * @throws If `frozen` is `true` at the time of the call.
442
+ *
443
+ * @see Signal algorithms — 'Method: Signal.subtle.Watcher.prototype.watch(...signals)'
444
+ */
445
+ watch(...signals: (State | Computed)[]): void;
446
+ /**
447
+ * Removes the given Signals from the watched set.
448
+ *
449
+ * For each removed Signal, the Watcher is unregistered as a sink. If the
450
+ * Signal's sink set becomes empty as a result, the removal is propagated
451
+ * recursively up through its sources, tearing down the live dependency
452
+ * chain and allowing garbage collection of unwatched nodes.
453
+ *
454
+ * The `unwatched` callback of each Signal (if any) is called with
455
+ * `frozen = true`.
456
+ *
457
+ * If no Signals remain in the watched set, the Watcher transitions back to
458
+ * the `~waiting~` state.
459
+ *
460
+ * @param signals - One or more `State` signals to stop watching.
461
+ * @throws If `frozen` is `true` at the time of the call.
462
+ * @throws If any of the given Signals is not currently being watched.
463
+ *
464
+ * @see Signal algorithms — 'Method: Signal.subtle.Watcher.prototype.unwatch(...signals)'
465
+ */
466
+ unwatch(...signals: (State | Computed)[]): void;
467
+ /**
468
+ * Get the current state of the Watcher.
469
+ * @param symbol - The private symbol for prevent external calls.
470
+ */
471
+ getState(symbol: symbol): WatcherState;
472
+ /**
473
+ * Set the current state of the Watcher.
474
+ * @param newState - The new state to set.
475
+ * @param symbol - The private symbol for prevent external calls.
476
+ * @throws If the transition from `pending` to `watching` is attempted.
477
+ */
478
+ setState(newState: WatcherState, symbol: symbol): void;
479
+ /**
480
+ * Invoce the notify callback when a watched dependency changes
481
+ * @param symbol - The private symbol for prevent external calls.
482
+ */
483
+ notify(symbol: symbol): void;
484
+ }
485
+
486
+ /**
487
+ * Type of the state of a watcher.
488
+ * - `waiting`: The watcher is waiting for its dependencies to change.
489
+ * - `watching`: The watcher is currently watching its dependencies for changes.
490
+ * - `pending`: The watcher has been notified of a change and is pending re-evaluation.
491
+ */
492
+ declare type WatcherState = 'waiting' | 'watching' | 'pending';
493
+
254
494
  export { }