@solidjs/signals 0.0.1
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/LICENSE +21 -0
- package/README.md +5 -0
- package/dist/dev.js +1404 -0
- package/dist/node.cjs +1452 -0
- package/dist/prod.js +1403 -0
- package/dist/types/core/constants.d.ts +14 -0
- package/dist/types/core/core.d.ts +157 -0
- package/dist/types/core/effect.d.ts +27 -0
- package/dist/types/core/error.d.ts +11 -0
- package/dist/types/core/flags.d.ts +8 -0
- package/dist/types/core/index.d.ts +7 -0
- package/dist/types/core/owner.d.ts +90 -0
- package/dist/types/core/scheduler.d.ts +26 -0
- package/dist/types/core/suspense.d.ts +11 -0
- package/dist/types/index.d.ts +5 -0
- package/dist/types/map.d.ts +12 -0
- package/dist/types/signals.d.ts +56 -0
- package/dist/types/store/index.d.ts +5 -0
- package/dist/types/store/reconcile.d.ts +1 -0
- package/dist/types/store/store.d.ts +40 -0
- package/dist/types/store/utilities.d.ts +29 -0
- package/dist/types/utils.d.ts +1 -0
- package/package.json +48 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* See https://dev.to/modderme123/super-charging-fine-grained-reactive-performance-47ph
|
|
3
|
+
* State clean corresponds to a node where all the sources are fully up to date
|
|
4
|
+
* State check corresponds to a node where some sources (including grandparents) may have changed
|
|
5
|
+
* State dirty corresponds to a node where the direct parents of a node has changed
|
|
6
|
+
*/
|
|
7
|
+
export declare const STATE_CLEAN = 0;
|
|
8
|
+
export declare const STATE_CHECK = 1;
|
|
9
|
+
export declare const STATE_DIRTY = 2;
|
|
10
|
+
export declare const STATE_DISPOSED = 3;
|
|
11
|
+
export declare const EFFECT_PURE = 0;
|
|
12
|
+
export declare const EFFECT_RENDER = 1;
|
|
13
|
+
export declare const EFFECT_USER = 2;
|
|
14
|
+
export declare const SUPPORTS_PROXY: boolean;
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Nodes for constructing a graph of reactive values and reactive computations.
|
|
3
|
+
*
|
|
4
|
+
* - The graph is acyclic.
|
|
5
|
+
* - The user inputs new values into the graph by calling .write() on one more computation nodes.
|
|
6
|
+
* - The user retrieves computed results from the graph by calling .read() on one or more computation nodes.
|
|
7
|
+
* - The library is responsible for running any necessary computations so that .read() is up to date
|
|
8
|
+
* with all prior .write() calls anywhere in the graph.
|
|
9
|
+
* - We call the input nodes 'roots' and the output nodes 'leaves' of the graph here.
|
|
10
|
+
* - Changes flow from roots to leaves. It would be effective but inefficient to immediately
|
|
11
|
+
* propagate all changes from a root through the graph to descendant leaves. Instead, we defer
|
|
12
|
+
* change most change propagation computation until a leaf is accessed. This allows us to
|
|
13
|
+
* coalesce computations and skip altogether recalculating unused sections of the graph.
|
|
14
|
+
* - Each computation node tracks its sources and its observers (observers are other
|
|
15
|
+
* elements that have this node as a source). Source and observer links are updated automatically
|
|
16
|
+
* as observer computations re-evaluate and call get() on their sources.
|
|
17
|
+
* - Each node stores a cache state (clean/check/dirty) to support the change propagation algorithm:
|
|
18
|
+
*
|
|
19
|
+
* In general, execution proceeds in three passes:
|
|
20
|
+
*
|
|
21
|
+
* 1. write() propagates changes down the graph to the leaves
|
|
22
|
+
* direct children are marked as dirty and their deeper descendants marked as check
|
|
23
|
+
* (no computations are evaluated)
|
|
24
|
+
* 2. read() requests that parent nodes updateIfNecessary(), which proceeds recursively up the tree
|
|
25
|
+
* to decide whether the node is clean (parents unchanged) or dirty (parents changed)
|
|
26
|
+
* 3. updateIfNecessary() evaluates the computation if the node is dirty (the computations are
|
|
27
|
+
* executed in root to leaf order)
|
|
28
|
+
*/
|
|
29
|
+
import { type Flags } from "./flags.js";
|
|
30
|
+
import { Owner } from "./owner.js";
|
|
31
|
+
export interface SignalOptions<T> {
|
|
32
|
+
name?: string;
|
|
33
|
+
equals?: ((prev: T, next: T) => boolean) | false;
|
|
34
|
+
unobserved?: () => void;
|
|
35
|
+
}
|
|
36
|
+
interface SourceType {
|
|
37
|
+
_observers: ObserverType[] | null;
|
|
38
|
+
_unobserved?: () => void;
|
|
39
|
+
_updateIfNecessary: () => void;
|
|
40
|
+
_stateFlags: Flags;
|
|
41
|
+
_time: number;
|
|
42
|
+
}
|
|
43
|
+
interface ObserverType {
|
|
44
|
+
_sources: SourceType[] | null;
|
|
45
|
+
_notify: (state: number) => void;
|
|
46
|
+
_handlerMask: Flags;
|
|
47
|
+
_notifyFlags: (mask: Flags, newFlags: Flags) => void;
|
|
48
|
+
_time: number;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Returns the current observer.
|
|
52
|
+
*/
|
|
53
|
+
export declare function getObserver(): ObserverType | null;
|
|
54
|
+
export declare function incrementClock(): void;
|
|
55
|
+
export declare const UNCHANGED: unique symbol;
|
|
56
|
+
export type UNCHANGED = typeof UNCHANGED;
|
|
57
|
+
export declare class Computation<T = any> extends Owner implements SourceType, ObserverType {
|
|
58
|
+
_sources: SourceType[] | null;
|
|
59
|
+
_observers: ObserverType[] | null;
|
|
60
|
+
_value: T | undefined;
|
|
61
|
+
_compute: null | ((p?: T) => T);
|
|
62
|
+
_name: string | undefined;
|
|
63
|
+
_equals: false | ((a: T, b: T) => boolean);
|
|
64
|
+
_unobserved: (() => void) | undefined;
|
|
65
|
+
/** Whether the computation is an error or has ancestors that are unresolved */
|
|
66
|
+
_stateFlags: number;
|
|
67
|
+
/** Which flags raised by sources are handled, vs. being passed through. */
|
|
68
|
+
_handlerMask: number;
|
|
69
|
+
_error: Computation<boolean> | null;
|
|
70
|
+
_loading: Computation<boolean> | null;
|
|
71
|
+
_time: number;
|
|
72
|
+
constructor(initialValue: T | undefined, compute: null | ((p?: T) => T), options?: SignalOptions<T>);
|
|
73
|
+
_read(): T;
|
|
74
|
+
/**
|
|
75
|
+
* Return the current value of this computation
|
|
76
|
+
* Automatically re-executes the surrounding computation when the value changes
|
|
77
|
+
*/
|
|
78
|
+
read(): T;
|
|
79
|
+
/**
|
|
80
|
+
* Return the current value of this computation
|
|
81
|
+
* Automatically re-executes the surrounding computation when the value changes
|
|
82
|
+
*
|
|
83
|
+
* If the computation has any unresolved ancestors, this function waits for the value to resolve
|
|
84
|
+
* before continuing
|
|
85
|
+
*/
|
|
86
|
+
wait(): T;
|
|
87
|
+
/**
|
|
88
|
+
* Return true if the computation is the value is dependent on an unresolved promise
|
|
89
|
+
* Triggers re-execution of the computation when the loading state changes
|
|
90
|
+
*
|
|
91
|
+
* This is useful especially when effects want to re-execute when a computation's
|
|
92
|
+
* loading state changes
|
|
93
|
+
*/
|
|
94
|
+
loading(): boolean;
|
|
95
|
+
/**
|
|
96
|
+
* Return true if the computation is the computation threw an error
|
|
97
|
+
* Triggers re-execution of the computation when the error state changes
|
|
98
|
+
*/
|
|
99
|
+
error(): boolean;
|
|
100
|
+
/** Update the computation with a new value. */
|
|
101
|
+
write(value: T | ((currentValue: T) => T) | UNCHANGED, flags?: number, raw?: boolean): T;
|
|
102
|
+
/**
|
|
103
|
+
* Set the current node's state, and recursively mark all of this node's observers as STATE_CHECK
|
|
104
|
+
*/
|
|
105
|
+
_notify(state: number): void;
|
|
106
|
+
/**
|
|
107
|
+
* Notify the computation that one of its sources has changed flags.
|
|
108
|
+
*
|
|
109
|
+
* @param mask A bitmask for which flag(s) were changed.
|
|
110
|
+
* @param newFlags The source's new flags, masked to just the changed ones.
|
|
111
|
+
*/
|
|
112
|
+
_notifyFlags(mask: Flags, newFlags: Flags): void;
|
|
113
|
+
_setError(error: unknown): void;
|
|
114
|
+
/**
|
|
115
|
+
* This is the core part of the reactivity system, which makes sure that the values are updated
|
|
116
|
+
* before they are read. We've also adapted it to return the loading state of the computation,
|
|
117
|
+
* so that we can propagate that to the computation's observers.
|
|
118
|
+
*
|
|
119
|
+
* This function will ensure that the value and states we read from the computation are up to date
|
|
120
|
+
*/
|
|
121
|
+
_updateIfNecessary(): void;
|
|
122
|
+
/**
|
|
123
|
+
* Remove ourselves from the owner graph and the computation graph
|
|
124
|
+
*/
|
|
125
|
+
_disposeNode(): void;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Reruns a computation's _compute function, producing a new value and keeping track of dependencies.
|
|
129
|
+
*
|
|
130
|
+
* It handles the updating of sources and observers, disposal of previous executions,
|
|
131
|
+
* and error handling if the _compute function throws. It also sets the node as loading
|
|
132
|
+
* if it reads any parents that are currently loading.
|
|
133
|
+
*/
|
|
134
|
+
export declare function update<T>(node: Computation<T>): void;
|
|
135
|
+
export declare function isEqual<T>(a: T, b: T): boolean;
|
|
136
|
+
/**
|
|
137
|
+
* Returns the current value stored inside the given compute function without triggering any
|
|
138
|
+
* dependencies. Use `untrack` if you want to also disable owner tracking.
|
|
139
|
+
*/
|
|
140
|
+
export declare function untrack<T>(fn: () => T): T;
|
|
141
|
+
/**
|
|
142
|
+
* Returns true if the given functinon contains signals that have been updated since the last time
|
|
143
|
+
* the parent computation was run.
|
|
144
|
+
*/
|
|
145
|
+
export declare function hasUpdated(fn: () => any): boolean;
|
|
146
|
+
/**
|
|
147
|
+
* Returns true if the given function contains async signals that are not ready yet.
|
|
148
|
+
*/
|
|
149
|
+
export declare function isPending(fn: () => any): boolean;
|
|
150
|
+
export declare function latest<T>(fn: () => T): T | undefined;
|
|
151
|
+
/**
|
|
152
|
+
* A convenient wrapper that calls `compute` with the `owner` and `observer` and is guaranteed
|
|
153
|
+
* to reset the global context after the computation is finished even if an error is thrown.
|
|
154
|
+
*/
|
|
155
|
+
export declare function compute<T>(owner: Owner | null, compute: (val: T) => T, observer: Computation<T>): T;
|
|
156
|
+
export declare function compute<T>(owner: Owner | null, compute: (val: undefined) => T, observer: null): T;
|
|
157
|
+
export {};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { EFFECT_RENDER, EFFECT_USER } from "./constants.js";
|
|
2
|
+
import { Computation, type SignalOptions } from "./core.js";
|
|
3
|
+
import { type IQueue } from "./scheduler.js";
|
|
4
|
+
/**
|
|
5
|
+
* Effects are the leaf nodes of our reactive graph. When their sources change, they are
|
|
6
|
+
* automatically added to the queue of effects to re-execute, which will cause them to fetch their
|
|
7
|
+
* sources and recompute
|
|
8
|
+
*/
|
|
9
|
+
export declare class Effect<T = any> extends Computation<T> {
|
|
10
|
+
_effect: (val: T, prev: T | undefined) => void;
|
|
11
|
+
_modified: boolean;
|
|
12
|
+
_prevValue: T | undefined;
|
|
13
|
+
_type: typeof EFFECT_RENDER | typeof EFFECT_USER;
|
|
14
|
+
_queue: IQueue;
|
|
15
|
+
constructor(initialValue: T, compute: () => T, effect: (val: T, prev: T | undefined) => void, options?: SignalOptions<T> & {
|
|
16
|
+
render?: boolean;
|
|
17
|
+
});
|
|
18
|
+
write(value: T, flags?: number): T;
|
|
19
|
+
_notify(state: number): void;
|
|
20
|
+
_setError(error: unknown): void;
|
|
21
|
+
_disposeNode(): void;
|
|
22
|
+
}
|
|
23
|
+
export declare class EagerComputation<T = any> extends Computation<T> {
|
|
24
|
+
_queue: IQueue;
|
|
25
|
+
constructor(initialValue: T, compute: () => T, options?: SignalOptions<T>);
|
|
26
|
+
_notify(state: number): void;
|
|
27
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export declare class NotReadyError extends Error {
|
|
2
|
+
}
|
|
3
|
+
export declare class NoOwnerError extends Error {
|
|
4
|
+
constructor();
|
|
5
|
+
}
|
|
6
|
+
export declare class ContextNotFoundError extends Error {
|
|
7
|
+
constructor();
|
|
8
|
+
}
|
|
9
|
+
export interface ErrorHandler {
|
|
10
|
+
(error: unknown): void;
|
|
11
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export type Flags = number;
|
|
2
|
+
export declare const ERROR_OFFSET = 0;
|
|
3
|
+
export declare const ERROR_BIT: number;
|
|
4
|
+
export declare const ERROR: unique symbol;
|
|
5
|
+
export declare const LOADING_OFFSET = 1;
|
|
6
|
+
export declare const LOADING_BIT: number;
|
|
7
|
+
export declare const LOADING: unique symbol;
|
|
8
|
+
export declare const DEFAULT_FLAGS: number;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { ContextNotFoundError, NoOwnerError, NotReadyError, type ErrorHandler } from "./error.js";
|
|
2
|
+
export { Owner, createContext, getContext, setContext, hasContext, getOwner, onCleanup, type Context, type ContextRecord, type Disposable } from "./owner.js";
|
|
3
|
+
export { Computation, getObserver, isEqual, untrack, hasUpdated, isPending, latest, UNCHANGED, compute, type SignalOptions } from "./core.js";
|
|
4
|
+
export { Effect, EagerComputation } from "./effect.js";
|
|
5
|
+
export { flushSync, createBoundary, type IQueue, Queue } from "./scheduler.js";
|
|
6
|
+
export { createSuspense } from "./suspense.js";
|
|
7
|
+
export * from "./flags.js";
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Owner tracking is used to enable nested tracking scopes with automatic cleanup.
|
|
3
|
+
* We also use owners to also keep track of which error handling context we are in.
|
|
4
|
+
*
|
|
5
|
+
* If you write the following
|
|
6
|
+
*
|
|
7
|
+
* const a = createOwner(() => {
|
|
8
|
+
* const b = createOwner(() => {});
|
|
9
|
+
*
|
|
10
|
+
* const c = createOwner(() => {
|
|
11
|
+
* const d = createOwner(() => {});
|
|
12
|
+
* });
|
|
13
|
+
*
|
|
14
|
+
* const e = createOwner(() => {});
|
|
15
|
+
* });
|
|
16
|
+
*
|
|
17
|
+
* The owner tree will look like this:
|
|
18
|
+
*
|
|
19
|
+
* a
|
|
20
|
+
* /|\
|
|
21
|
+
* b-c-e
|
|
22
|
+
* |
|
|
23
|
+
* d
|
|
24
|
+
*
|
|
25
|
+
* Following the _nextSibling pointers of each owner will first give you its children, and then its siblings (in reverse).
|
|
26
|
+
* a -> e -> c -> d -> b
|
|
27
|
+
*
|
|
28
|
+
* Note that the owner tree is largely orthogonal to the reactivity tree, and is much closer to the component tree.
|
|
29
|
+
*/
|
|
30
|
+
import { type ErrorHandler } from "./error.js";
|
|
31
|
+
import type { IQueue } from "./scheduler.js";
|
|
32
|
+
export type ContextRecord = Record<string | symbol, unknown>;
|
|
33
|
+
export interface Disposable {
|
|
34
|
+
(): void;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Returns the currently executing parent owner.
|
|
38
|
+
*/
|
|
39
|
+
export declare function getOwner(): Owner | null;
|
|
40
|
+
export declare function setOwner(owner: Owner | null): Owner | null;
|
|
41
|
+
export declare class Owner {
|
|
42
|
+
_parent: Owner | null;
|
|
43
|
+
_nextSibling: Owner | null;
|
|
44
|
+
_prevSibling: Owner | null;
|
|
45
|
+
_state: number;
|
|
46
|
+
_disposal: Disposable | Disposable[] | null;
|
|
47
|
+
_context: ContextRecord;
|
|
48
|
+
_handlers: ErrorHandler[] | null;
|
|
49
|
+
_queue: IQueue | null;
|
|
50
|
+
constructor(signal?: boolean);
|
|
51
|
+
append(child: Owner): void;
|
|
52
|
+
dispose(this: Owner, self?: boolean): void;
|
|
53
|
+
_disposeNode(): void;
|
|
54
|
+
emptyDisposal(): void;
|
|
55
|
+
handleError(error: unknown): void;
|
|
56
|
+
}
|
|
57
|
+
export interface Context<T> {
|
|
58
|
+
readonly id: symbol;
|
|
59
|
+
readonly defaultValue: T | undefined;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Context provides a form of dependency injection. It is used to save from needing to pass
|
|
63
|
+
* data as props through intermediate components. This function creates a new context object
|
|
64
|
+
* that can be used with `getContext` and `setContext`.
|
|
65
|
+
*
|
|
66
|
+
* A default value can be provided here which will be used when a specific value is not provided
|
|
67
|
+
* via a `setContext` call.
|
|
68
|
+
*/
|
|
69
|
+
export declare function createContext<T>(defaultValue?: T, description?: string): Context<T>;
|
|
70
|
+
/**
|
|
71
|
+
* Attempts to get a context value for the given key.
|
|
72
|
+
*
|
|
73
|
+
* @throws `NoOwnerError` if there's no owner at the time of call.
|
|
74
|
+
* @throws `ContextNotFoundError` if a context value has not been set yet.
|
|
75
|
+
*/
|
|
76
|
+
export declare function getContext<T>(context: Context<T>, owner?: Owner | null): T;
|
|
77
|
+
/**
|
|
78
|
+
* Attempts to set a context value on the parent scope with the given key.
|
|
79
|
+
*
|
|
80
|
+
* @throws `NoOwnerError` if there's no owner at the time of call.
|
|
81
|
+
*/
|
|
82
|
+
export declare function setContext<T>(context: Context<T>, value?: T, owner?: Owner | null): void;
|
|
83
|
+
/**
|
|
84
|
+
* Whether the given context is currently defined.
|
|
85
|
+
*/
|
|
86
|
+
export declare function hasContext(context: Context<any>, owner?: Owner | null): boolean;
|
|
87
|
+
/**
|
|
88
|
+
* Runs the given function when the parent owner computation is being disposed.
|
|
89
|
+
*/
|
|
90
|
+
export declare function onCleanup(disposable: Disposable): void;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Computation } from "./core.js";
|
|
2
|
+
import type { Effect } from "./effect.js";
|
|
3
|
+
export interface IQueue {
|
|
4
|
+
enqueue<T extends Computation | Effect>(type: number, node: T): void;
|
|
5
|
+
run(type: number): void;
|
|
6
|
+
flush(): void;
|
|
7
|
+
addChild(child: IQueue): void;
|
|
8
|
+
removeChild(child: IQueue): void;
|
|
9
|
+
}
|
|
10
|
+
export declare class Queue implements IQueue {
|
|
11
|
+
_running: boolean;
|
|
12
|
+
_queues: [Computation[], Effect[], Effect[]];
|
|
13
|
+
_children: IQueue[];
|
|
14
|
+
enqueue<T extends Computation | Effect>(type: number, node: T): void;
|
|
15
|
+
run(type: number): void;
|
|
16
|
+
flush(): void;
|
|
17
|
+
addChild(child: IQueue): void;
|
|
18
|
+
removeChild(child: IQueue): void;
|
|
19
|
+
}
|
|
20
|
+
export declare const globalQueue: Queue;
|
|
21
|
+
/**
|
|
22
|
+
* By default, changes are batched on the microtask queue which is an async process. You can flush
|
|
23
|
+
* the queue synchronously to get the latest updates by calling `flushSync()`.
|
|
24
|
+
*/
|
|
25
|
+
export declare function flushSync(): void;
|
|
26
|
+
export declare function createBoundary<T>(fn: () => T, queue: IQueue): T;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Computation } from "./core.js";
|
|
2
|
+
import type { Effect } from "./effect.js";
|
|
3
|
+
import { Queue } from "./scheduler.js";
|
|
4
|
+
export declare class SuspenseQueue extends Queue {
|
|
5
|
+
_nodes: Set<Effect>;
|
|
6
|
+
_fallback: boolean;
|
|
7
|
+
_signal: Computation<boolean>;
|
|
8
|
+
run(type: number): void;
|
|
9
|
+
_update(node: Effect): void;
|
|
10
|
+
}
|
|
11
|
+
export declare function createSuspense(fn: () => any, fallbackFn: () => any): () => any;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { Computation, ContextNotFoundError, NoOwnerError, NotReadyError, Owner, Queue, createContext, flushSync, createBoundary, getContext, setContext, hasContext, getOwner, onCleanup, getObserver, isEqual, untrack, hasUpdated, isPending, latest, createSuspense } from "./core/index.js";
|
|
2
|
+
export type { ErrorHandler, SignalOptions, Context, ContextRecord, Disposable, IQueue } from "./core/index.js";
|
|
3
|
+
export { mapArray, type Maybe } from "./map.js";
|
|
4
|
+
export * from "./signals.js";
|
|
5
|
+
export * from "./store/index.js";
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Accessor } from "./signals.js";
|
|
2
|
+
export type Maybe<T> = T | void | null | undefined | false;
|
|
3
|
+
/**
|
|
4
|
+
* Reactive map helper that caches each list item by reference to reduce unnecessary mapping on
|
|
5
|
+
* updates.
|
|
6
|
+
*
|
|
7
|
+
* @see {@link https://github.com/solidjs/x-reactivity#maparray}
|
|
8
|
+
*/
|
|
9
|
+
export declare function mapArray<Item, MappedItem>(list: Accessor<Maybe<readonly Item[]>>, map: (value: Accessor<Item>, index: Accessor<number>) => MappedItem, options?: {
|
|
10
|
+
keyed?: boolean | ((item: Item) => any);
|
|
11
|
+
name?: string;
|
|
12
|
+
}): Accessor<MappedItem[]>;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { SignalOptions } from "./core/index.js";
|
|
2
|
+
import { Owner } from "./core/index.js";
|
|
3
|
+
export interface Accessor<T> {
|
|
4
|
+
(): T;
|
|
5
|
+
}
|
|
6
|
+
export interface Setter<T> {
|
|
7
|
+
(value: T | SetValue<T>): T;
|
|
8
|
+
}
|
|
9
|
+
export interface SetValue<T> {
|
|
10
|
+
(currentValue: T): T;
|
|
11
|
+
}
|
|
12
|
+
export type Signal<T> = [read: Accessor<T>, write: Setter<T>];
|
|
13
|
+
/**
|
|
14
|
+
* Wraps the given value into a signal. The signal will return the current value when invoked
|
|
15
|
+
* `fn()`, and provide a simple write API via `write()`. The value can now be observed
|
|
16
|
+
* when used inside other computations created with `computed` and `effect`.
|
|
17
|
+
*/
|
|
18
|
+
export declare function createSignal<T>(initialValue: Exclude<T, Function>, options?: SignalOptions<T>): Signal<T>;
|
|
19
|
+
export declare function createSignal<T>(fn: (prev?: T) => T, initialValue?: T, options?: SignalOptions<T>): Signal<T>;
|
|
20
|
+
export declare function createAsync<T>(fn: (prev?: T) => Promise<T> | AsyncIterable<T> | T, initial?: T, options?: SignalOptions<T>): Accessor<T>;
|
|
21
|
+
/**
|
|
22
|
+
* Creates a new computation whose value is computed and returned by the given function. The given
|
|
23
|
+
* compute function is _only_ re-run when one of it's dependencies are updated. Dependencies are
|
|
24
|
+
* are all signals that are read during execution.
|
|
25
|
+
*/
|
|
26
|
+
export declare function createMemo<T>(compute: (prev?: T) => T, initialValue?: T, options?: SignalOptions<T>): Accessor<T>;
|
|
27
|
+
/**
|
|
28
|
+
* Invokes the given function each time any of the signals that are read inside are updated
|
|
29
|
+
* (i.e., their value changes). The effect is immediately invoked on initialization.
|
|
30
|
+
*/
|
|
31
|
+
export declare function createEffect<T>(compute: () => T, effect: (v: T) => (() => void) | void, initialValue?: T, options?: {
|
|
32
|
+
name?: string;
|
|
33
|
+
}): void;
|
|
34
|
+
/**
|
|
35
|
+
* Invokes the given function each time any of the signals that are read inside are updated
|
|
36
|
+
* (i.e., their value changes). The effect is immediately invoked on initialization.
|
|
37
|
+
*/
|
|
38
|
+
export declare function createRenderEffect<T>(compute: () => T, effect: (v: T) => (() => void) | void, initialValue?: T, options?: {
|
|
39
|
+
name?: string;
|
|
40
|
+
}): void;
|
|
41
|
+
/**
|
|
42
|
+
* Creates a computation root which is given a `dispose()` function to dispose of all inner
|
|
43
|
+
* computations.
|
|
44
|
+
*/
|
|
45
|
+
export declare function createRoot<T>(init: ((dispose: () => void) => T) | (() => T)): T;
|
|
46
|
+
/**
|
|
47
|
+
* Runs the given function in the given owner so that error handling and cleanups continue to work.
|
|
48
|
+
*
|
|
49
|
+
* Warning: Usually there are simpler ways of modeling a problem that avoid using this function
|
|
50
|
+
*/
|
|
51
|
+
export declare function runWithOwner<T>(owner: Owner | null, run: () => T): T | undefined;
|
|
52
|
+
/**
|
|
53
|
+
* Runs the given function when an error is thrown in a child owner. If the error is thrown again
|
|
54
|
+
* inside the error handler, it will trigger the next available parent owner handler.
|
|
55
|
+
*/
|
|
56
|
+
export declare function catchError<T>(fn: () => T, handler: (error: unknown) => void): void;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export type { Store, StoreSetter, StoreNode, NotWrappable } from "./store.js";
|
|
2
|
+
export type { Merge, Omit } from "./utilities.js";
|
|
3
|
+
export { unwrap, isWrappable, createStore, createProjection, $RAW, $TRACK, $PROXY, $TARGET } from "./store.js";
|
|
4
|
+
export { reconcile } from "./reconcile.js";
|
|
5
|
+
export { merge, omit } from "./utilities.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function reconcile<T extends U, U>(value: T, key: string | ((item: NonNullable<any>) => any)): (state: U) => void;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { Computation } from "../core/index.js";
|
|
2
|
+
export type Store<T> = Readonly<T>;
|
|
3
|
+
export type StoreSetter<T> = (fn: (state: T) => void) => void;
|
|
4
|
+
type DataNode = Computation<any>;
|
|
5
|
+
type DataNodes = Record<PropertyKey, DataNode>;
|
|
6
|
+
declare const $RAW: unique symbol, $TRACK: unique symbol, $TARGET: unique symbol, $PROXY: unique symbol;
|
|
7
|
+
export declare const STORE_VALUE = "v", STORE_NODE = "n", STORE_HAS = "h";
|
|
8
|
+
export { $PROXY, $TRACK, $RAW, $TARGET };
|
|
9
|
+
export type StoreNode = {
|
|
10
|
+
[STORE_VALUE]: Record<PropertyKey, any>;
|
|
11
|
+
[STORE_NODE]?: DataNodes;
|
|
12
|
+
[STORE_HAS]?: DataNodes;
|
|
13
|
+
};
|
|
14
|
+
export declare namespace SolidStore {
|
|
15
|
+
interface Unwrappable {
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
export type NotWrappable = string | number | bigint | symbol | boolean | Function | null | undefined | SolidStore.Unwrappable[keyof SolidStore.Unwrappable];
|
|
19
|
+
export declare function wrap<T extends Record<PropertyKey, any>>(value: T): T;
|
|
20
|
+
export declare function isWrappable<T>(obj: T | NotWrappable): obj is T;
|
|
21
|
+
/**
|
|
22
|
+
* Returns the underlying data in the store without a proxy.
|
|
23
|
+
* @param item store proxy object
|
|
24
|
+
* @example
|
|
25
|
+
* ```js
|
|
26
|
+
* const initial = {z...};
|
|
27
|
+
* const [state, setState] = createStore(initial);
|
|
28
|
+
* initial === state; // => false
|
|
29
|
+
* initial === unwrap(state); // => true
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export declare function unwrap<T>(item: T, deep?: boolean, set?: Set<unknown>): T;
|
|
33
|
+
export declare function createStore<T extends object = {}>(store: T | Store<T>): [get: Store<T>, set: StoreSetter<T>];
|
|
34
|
+
export declare function createStore<T extends object = {}>(fn: (store: T) => void, store: T | Store<T>): [get: Store<T>, set: StoreSetter<T>];
|
|
35
|
+
/**
|
|
36
|
+
* Creates a mutable derived value
|
|
37
|
+
*
|
|
38
|
+
* @see {@link https://github.com/solidjs/x-reactivity#createprojection}
|
|
39
|
+
*/
|
|
40
|
+
export declare function createProjection<T extends Object>(fn: (draft: T) => void, initialValue?: T): Readonly<T>;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
type DistributeOverride<T, F> = T extends undefined ? F : T;
|
|
2
|
+
type Override<T, U> = T extends any ? U extends any ? {
|
|
3
|
+
[K in keyof T]: K extends keyof U ? DistributeOverride<U[K], T[K]> : T[K];
|
|
4
|
+
} & {
|
|
5
|
+
[K in keyof U]: K extends keyof T ? DistributeOverride<U[K], T[K]> : U[K];
|
|
6
|
+
} : T & U : T & U;
|
|
7
|
+
type OverrideSpread<T, U> = T extends any ? {
|
|
8
|
+
[K in keyof ({
|
|
9
|
+
[K in keyof T]: any;
|
|
10
|
+
} & {
|
|
11
|
+
[K in keyof U]?: any;
|
|
12
|
+
} & {
|
|
13
|
+
[K in U extends any ? keyof U : keyof U]?: any;
|
|
14
|
+
})]: K extends keyof T ? Exclude<U extends any ? U[K & keyof U] : never, undefined> | T[K] : U extends any ? U[K & keyof U] : never;
|
|
15
|
+
} : T & U;
|
|
16
|
+
type Simplify<T> = T extends any ? {
|
|
17
|
+
[K in keyof T]: T[K];
|
|
18
|
+
} : T;
|
|
19
|
+
type _Merge<T extends unknown[], Curr = {}> = T extends [
|
|
20
|
+
infer Next | (() => infer Next),
|
|
21
|
+
...infer Rest
|
|
22
|
+
] ? _Merge<Rest, Override<Curr, Next>> : T extends [...infer Rest, infer Next | (() => infer Next)] ? Override<_Merge<Rest, Curr>, Next> : T extends [] ? Curr : T extends (infer I | (() => infer I))[] ? OverrideSpread<Curr, I> : Curr;
|
|
23
|
+
export type Merge<T extends unknown[]> = Simplify<_Merge<T>>;
|
|
24
|
+
export declare function merge<T extends unknown[]>(...sources: T): Merge<T>;
|
|
25
|
+
export type Omit<T, K extends readonly (keyof T)[]> = {
|
|
26
|
+
[P in keyof T as Exclude<P, K[number]>]: T[P];
|
|
27
|
+
};
|
|
28
|
+
export declare function omit<T extends Record<any, any>, K extends readonly (keyof T)[]>(props: T, ...keys: K): Omit<T, K>;
|
|
29
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function isUndefined(value: any): value is undefined;
|
package/package.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@solidjs/signals",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "",
|
|
5
|
+
"license": "ISC",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "dist/node.cjs",
|
|
8
|
+
"module": "dist/prod.js",
|
|
9
|
+
"types": "dist/types/index.d.ts",
|
|
10
|
+
"publishConfig": {
|
|
11
|
+
"access": "public"
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"dist"
|
|
15
|
+
],
|
|
16
|
+
"devDependencies": {
|
|
17
|
+
"@ianvs/prettier-plugin-sort-imports": "^4.1.1",
|
|
18
|
+
"@types/node": "^20.5.1",
|
|
19
|
+
"rimraf": "^5.0.1",
|
|
20
|
+
"tsup": "^7.2.0",
|
|
21
|
+
"typescript": "5.1.6",
|
|
22
|
+
"vite": "^5.4.10",
|
|
23
|
+
"vitest": "^2.0.0"
|
|
24
|
+
},
|
|
25
|
+
"exports": {
|
|
26
|
+
".": {
|
|
27
|
+
"types": "./dist/types/index.d.ts",
|
|
28
|
+
"import": {
|
|
29
|
+
"test": "./dist/dev.js",
|
|
30
|
+
"development": "./dist/dev.js",
|
|
31
|
+
"default": "./dist/prod.js"
|
|
32
|
+
},
|
|
33
|
+
"require": "./dist/node.cjs"
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
"scripts": {
|
|
37
|
+
"build": "rimraf dist && tsup && pnpm types",
|
|
38
|
+
"types": "tsc -p tsconfig.build.json",
|
|
39
|
+
"format": "prettier src tests --write --log-level warn",
|
|
40
|
+
"sandbox": "node ./.sandbox/launch.js",
|
|
41
|
+
"test": "vitest run",
|
|
42
|
+
"test:watch": "vitest watch tests",
|
|
43
|
+
"test:gc": "node --expose-gc ./vitest.js",
|
|
44
|
+
"test:gc:watch": "node --expose-gc ./vitest.js --watch",
|
|
45
|
+
"test:coverage": "vitest run --coverage",
|
|
46
|
+
"bench": "vitest bench --run"
|
|
47
|
+
}
|
|
48
|
+
}
|