signalium 0.2.7 → 0.3.0
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/.turbo/turbo-build.log +12 -0
- package/CHANGELOG.md +12 -0
- package/dist/cjs/config.d.ts +14 -5
- package/dist/cjs/config.d.ts.map +1 -1
- package/dist/cjs/config.js +23 -14
- package/dist/cjs/config.js.map +1 -1
- package/dist/cjs/debug.d.ts +3 -0
- package/dist/cjs/debug.d.ts.map +1 -0
- package/dist/cjs/debug.js +16 -0
- package/dist/cjs/debug.js.map +1 -0
- package/dist/cjs/hooks.d.ts +45 -0
- package/dist/cjs/hooks.d.ts.map +1 -0
- package/dist/cjs/hooks.js +260 -0
- package/dist/cjs/hooks.js.map +1 -0
- package/dist/cjs/index.d.ts +5 -3
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +21 -8
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/react/context.d.ts +4 -0
- package/dist/cjs/react/context.d.ts.map +1 -0
- package/dist/cjs/react/context.js +10 -0
- package/dist/cjs/react/context.js.map +1 -0
- package/dist/cjs/react/index.d.ts +5 -0
- package/dist/cjs/react/index.d.ts.map +1 -0
- package/dist/cjs/react/index.js +12 -0
- package/dist/cjs/react/index.js.map +1 -0
- package/dist/cjs/react/provider.d.ts +7 -0
- package/dist/cjs/react/provider.d.ts.map +1 -0
- package/dist/cjs/react/provider.js +13 -0
- package/dist/cjs/react/provider.js.map +1 -0
- package/dist/cjs/react/signal-value.d.ts +3 -0
- package/dist/cjs/react/signal-value.d.ts.map +1 -0
- package/dist/cjs/react/signal-value.js +42 -0
- package/dist/cjs/react/signal-value.js.map +1 -0
- package/dist/cjs/react/state.d.ts +3 -0
- package/dist/cjs/react/state.d.ts.map +1 -0
- package/dist/cjs/react/state.js +13 -0
- package/dist/cjs/react/state.js.map +1 -0
- package/dist/cjs/scheduling.d.ts +5 -0
- package/dist/cjs/scheduling.d.ts.map +1 -1
- package/dist/cjs/scheduling.js +59 -5
- package/dist/cjs/scheduling.js.map +1 -1
- package/dist/cjs/signals.d.ts +28 -65
- package/dist/cjs/signals.d.ts.map +1 -1
- package/dist/cjs/signals.js +223 -65
- package/dist/cjs/signals.js.map +1 -1
- package/dist/cjs/trace.d.ts +127 -0
- package/dist/cjs/trace.d.ts.map +1 -0
- package/dist/cjs/trace.js +319 -0
- package/dist/cjs/trace.js.map +1 -0
- package/dist/cjs/types.d.ts +66 -0
- package/dist/cjs/types.d.ts.map +1 -0
- package/dist/cjs/types.js +3 -0
- package/dist/cjs/types.js.map +1 -0
- package/dist/cjs/utils.d.ts +4 -0
- package/dist/cjs/utils.d.ts.map +1 -0
- package/dist/cjs/utils.js +80 -0
- package/dist/cjs/utils.js.map +1 -0
- package/dist/esm/config.d.ts +14 -5
- package/dist/esm/config.d.ts.map +1 -1
- package/dist/esm/config.js +19 -11
- package/dist/esm/config.js.map +1 -1
- package/dist/esm/debug.d.ts +3 -0
- package/dist/esm/debug.d.ts.map +1 -0
- package/dist/esm/debug.js +3 -0
- package/dist/esm/debug.js.map +1 -0
- package/dist/esm/hooks.d.ts +45 -0
- package/dist/esm/hooks.d.ts.map +1 -0
- package/dist/esm/hooks.js +243 -0
- package/dist/esm/hooks.js.map +1 -0
- package/dist/esm/index.d.ts +5 -3
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +4 -2
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/react/context.d.ts +4 -0
- package/dist/esm/react/context.d.ts.map +1 -0
- package/dist/esm/react/context.js +6 -0
- package/dist/esm/react/context.js.map +1 -0
- package/dist/esm/react/index.d.ts +5 -0
- package/dist/esm/react/index.d.ts.map +1 -0
- package/dist/esm/react/index.js +5 -0
- package/dist/esm/react/index.js.map +1 -0
- package/dist/esm/react/provider.d.ts +7 -0
- package/dist/esm/react/provider.d.ts.map +1 -0
- package/dist/esm/react/provider.js +10 -0
- package/dist/esm/react/provider.js.map +1 -0
- package/dist/esm/react/signal-value.d.ts +3 -0
- package/dist/esm/react/signal-value.d.ts.map +1 -0
- package/dist/esm/react/signal-value.js +38 -0
- package/dist/esm/react/signal-value.js.map +1 -0
- package/dist/esm/react/state.d.ts +3 -0
- package/dist/esm/react/state.d.ts.map +1 -0
- package/dist/esm/react/state.js +10 -0
- package/dist/esm/react/state.js.map +1 -0
- package/dist/esm/scheduling.d.ts +5 -0
- package/dist/esm/scheduling.d.ts.map +1 -1
- package/dist/esm/scheduling.js +51 -1
- package/dist/esm/scheduling.js.map +1 -1
- package/dist/esm/signals.d.ts +28 -65
- package/dist/esm/signals.d.ts.map +1 -1
- package/dist/esm/signals.js +215 -61
- package/dist/esm/signals.js.map +1 -1
- package/dist/esm/trace.d.ts +127 -0
- package/dist/esm/trace.d.ts.map +1 -0
- package/dist/esm/trace.js +311 -0
- package/dist/esm/trace.js.map +1 -0
- package/dist/esm/types.d.ts +66 -0
- package/dist/esm/types.d.ts.map +1 -0
- package/dist/esm/types.js +2 -0
- package/dist/esm/types.js.map +1 -0
- package/dist/esm/utils.d.ts +4 -0
- package/dist/esm/utils.d.ts.map +1 -0
- package/dist/esm/utils.js +75 -0
- package/dist/esm/utils.js.map +1 -0
- package/package.json +43 -2
- package/src/__tests__/hooks/async-computed.test.ts +190 -0
- package/src/__tests__/hooks/async-task.test.ts +227 -0
- package/src/__tests__/hooks/computed.test.ts +126 -0
- package/src/__tests__/hooks/context.test.ts +527 -0
- package/src/__tests__/hooks/nesting.test.ts +303 -0
- package/src/__tests__/hooks/params-and-state.test.ts +168 -0
- package/src/__tests__/hooks/subscription.test.ts +97 -0
- package/src/__tests__/signals/async.test.ts +416 -0
- package/src/__tests__/signals/basic.test.ts +399 -0
- package/src/__tests__/signals/subscription.test.ts +632 -0
- package/src/__tests__/signals/watcher.test.ts +253 -0
- package/src/__tests__/utils/async.ts +6 -0
- package/src/__tests__/utils/builders.ts +22 -0
- package/src/__tests__/utils/instrumented-hooks.ts +309 -0
- package/src/__tests__/utils/instrumented-signals.ts +281 -0
- package/src/__tests__/utils/permute.ts +74 -0
- package/src/config.ts +32 -17
- package/src/debug.ts +14 -0
- package/src/hooks.ts +429 -0
- package/src/index.ts +28 -3
- package/src/react/__tests__/react.test.tsx +135 -0
- package/src/react/context.ts +8 -0
- package/src/react/index.ts +4 -0
- package/src/react/provider.tsx +18 -0
- package/src/react/signal-value.ts +56 -0
- package/src/react/state.ts +13 -0
- package/src/scheduling.ts +69 -1
- package/src/signals.ts +331 -157
- package/src/trace.ts +449 -0
- package/src/types.ts +86 -0
- package/src/utils.ts +83 -0
- package/tsconfig.json +2 -1
- package/vitest.workspace.ts +24 -0
- package/src/__tests__/async.test.ts +0 -426
- package/src/__tests__/basic.test.ts +0 -378
- package/src/__tests__/subscription.test.ts +0 -645
- package/src/__tests__/utils/instrumented.ts +0 -326
@@ -1,326 +0,0 @@
|
|
1
|
-
import { expect, beforeEach, afterEach, vi } from 'vitest';
|
2
|
-
import {
|
3
|
-
state as createState,
|
4
|
-
computed as createComputed,
|
5
|
-
asyncComputed as createAsyncComputed,
|
6
|
-
subscription as createSubscription,
|
7
|
-
watcher as createWatcher,
|
8
|
-
SignalOptions,
|
9
|
-
Signal,
|
10
|
-
WriteableSignal,
|
11
|
-
SignalCompute,
|
12
|
-
SignalAsyncCompute,
|
13
|
-
SignalSubscribe,
|
14
|
-
SignalSubscription,
|
15
|
-
SignalOptionsWithInit,
|
16
|
-
Watcher,
|
17
|
-
SignalWatcherEffect,
|
18
|
-
AsyncSignal,
|
19
|
-
} from '../../signals.js';
|
20
|
-
|
21
|
-
class SignalCounts {
|
22
|
-
name: string;
|
23
|
-
|
24
|
-
get = 0;
|
25
|
-
set = 0;
|
26
|
-
compute = 0;
|
27
|
-
|
28
|
-
resolve = 0;
|
29
|
-
|
30
|
-
subscribe = 0;
|
31
|
-
update = 0;
|
32
|
-
unsubscribe = 0;
|
33
|
-
internalGet = 0;
|
34
|
-
internalSet = 0;
|
35
|
-
|
36
|
-
effect = 0;
|
37
|
-
|
38
|
-
constructor(name: string) {
|
39
|
-
this.name = name;
|
40
|
-
}
|
41
|
-
}
|
42
|
-
|
43
|
-
const countsKeys = Object.keys(new SignalCounts('')).filter(k => k !== 'name') as (keyof SignalCounts)[];
|
44
|
-
|
45
|
-
let currentOrder: string[] | undefined = [];
|
46
|
-
const COUNTS = new WeakMap<Signal<any> | Watcher, SignalCounts>();
|
47
|
-
|
48
|
-
interface CustomMatchers<R = unknown> {
|
49
|
-
toHaveValue: (v: any) => R;
|
50
|
-
toHaveCounts: (counts: Partial<SignalCounts>) => R;
|
51
|
-
toHaveValueAndCounts: (v: any, counts: Partial<SignalCounts>) => R;
|
52
|
-
toHaveComputedOrder: (order: string[]) => R;
|
53
|
-
}
|
54
|
-
|
55
|
-
declare module 'vitest' {
|
56
|
-
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
57
|
-
interface Assertion<T = any> extends CustomMatchers<T> {}
|
58
|
-
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
59
|
-
interface AsymmetricMatchersContaining extends CustomMatchers {}
|
60
|
-
}
|
61
|
-
|
62
|
-
function toHaveValue(this: { equals(a: unknown, b: unknown): boolean }, signal: Signal<any>, value: any) {
|
63
|
-
const signalValue = signal.get();
|
64
|
-
|
65
|
-
return {
|
66
|
-
pass: this.equals(signalValue, value),
|
67
|
-
message: () => `Expected signal value to be ${JSON.stringify(value)}, but got ${JSON.stringify(signalValue)}`,
|
68
|
-
};
|
69
|
-
}
|
70
|
-
|
71
|
-
function toHaveCounts(signal: Signal<any>, counts: SignalCounts) {
|
72
|
-
const signalCounts = COUNTS.get(signal);
|
73
|
-
|
74
|
-
if (!signalCounts) {
|
75
|
-
return {
|
76
|
-
pass: false,
|
77
|
-
message: () => 'Signal not found in counts map',
|
78
|
-
};
|
79
|
-
}
|
80
|
-
|
81
|
-
for (const key of countsKeys) {
|
82
|
-
const count = counts[key];
|
83
|
-
|
84
|
-
if (count !== undefined && signalCounts[key] !== count) {
|
85
|
-
return {
|
86
|
-
pass: false,
|
87
|
-
message: () => `Expected ${key} count to be ${count} but got ${signalCounts[key]}`,
|
88
|
-
};
|
89
|
-
}
|
90
|
-
}
|
91
|
-
|
92
|
-
return {
|
93
|
-
pass: true,
|
94
|
-
message: () => 'Counts match',
|
95
|
-
};
|
96
|
-
}
|
97
|
-
|
98
|
-
expect.extend({
|
99
|
-
toHaveValue,
|
100
|
-
toHaveCounts,
|
101
|
-
|
102
|
-
toHaveValueAndCounts(signal, value, counts) {
|
103
|
-
const valueResult = toHaveValue.call(this, signal, value);
|
104
|
-
const countsResult = toHaveCounts.call(this, signal, counts);
|
105
|
-
|
106
|
-
return {
|
107
|
-
pass: valueResult.pass && countsResult.pass,
|
108
|
-
message: () => {
|
109
|
-
const messages = [
|
110
|
-
!valueResult.pass && valueResult.message(),
|
111
|
-
!countsResult.pass && countsResult.message(),
|
112
|
-
].filter(m => m);
|
113
|
-
|
114
|
-
return messages.join('\n');
|
115
|
-
},
|
116
|
-
};
|
117
|
-
},
|
118
|
-
|
119
|
-
toHaveComputedOrder(fn: () => void, expectedOrder: string[]) {
|
120
|
-
const order = (currentOrder = []);
|
121
|
-
|
122
|
-
fn();
|
123
|
-
|
124
|
-
currentOrder = undefined;
|
125
|
-
|
126
|
-
return {
|
127
|
-
pass: this.equals(order, expectedOrder),
|
128
|
-
message: () => `Expected compute count to be ${expectedOrder.toString()} but got ${order.toString()}`,
|
129
|
-
};
|
130
|
-
},
|
131
|
-
});
|
132
|
-
|
133
|
-
export const state = <T>(initialValue: T, opts?: SignalOptions<T> & { name?: string }): WriteableSignal<T> => {
|
134
|
-
const name = opts?.name || 'unlabeled';
|
135
|
-
const s = createState(initialValue, opts);
|
136
|
-
|
137
|
-
const counts = new SignalCounts(name);
|
138
|
-
|
139
|
-
const wrapper = {
|
140
|
-
get() {
|
141
|
-
counts.get++;
|
142
|
-
return s.get();
|
143
|
-
},
|
144
|
-
|
145
|
-
set(value: T) {
|
146
|
-
counts.set++;
|
147
|
-
s.set(value);
|
148
|
-
},
|
149
|
-
};
|
150
|
-
|
151
|
-
COUNTS.set(wrapper, counts);
|
152
|
-
|
153
|
-
return wrapper;
|
154
|
-
};
|
155
|
-
|
156
|
-
export function computed<T>(name: string, compute: SignalCompute<T>, opts?: SignalOptions<T>): Signal<T>;
|
157
|
-
export function computed<T>(compute: SignalCompute<T>, opts?: SignalOptions<T>): Signal<T>;
|
158
|
-
export function computed<T>(
|
159
|
-
nameOrCompute: string | SignalCompute<T>,
|
160
|
-
computeOrOpts?: SignalCompute<T> | SignalOptions<T>,
|
161
|
-
maybeOpts?: SignalOptions<T>,
|
162
|
-
): Signal<T> {
|
163
|
-
const name = typeof nameOrCompute === 'string' ? nameOrCompute : 'unlabeled';
|
164
|
-
const compute = typeof nameOrCompute === 'string' ? (computeOrOpts as SignalCompute<T>) : nameOrCompute;
|
165
|
-
const opts = typeof nameOrCompute === 'string' ? maybeOpts : (computeOrOpts as SignalOptions<T>);
|
166
|
-
const counts = new SignalCounts(name);
|
167
|
-
|
168
|
-
const s = createComputed(v => {
|
169
|
-
counts.compute++;
|
170
|
-
|
171
|
-
if (name) {
|
172
|
-
currentOrder?.push(name);
|
173
|
-
}
|
174
|
-
|
175
|
-
return compute(v);
|
176
|
-
}, opts);
|
177
|
-
|
178
|
-
const wrapper = {
|
179
|
-
get() {
|
180
|
-
counts.get++;
|
181
|
-
return s.get();
|
182
|
-
},
|
183
|
-
};
|
184
|
-
|
185
|
-
COUNTS.set(wrapper, counts);
|
186
|
-
|
187
|
-
return wrapper;
|
188
|
-
}
|
189
|
-
|
190
|
-
export function asyncComputed<T>(name: string, compute: SignalAsyncCompute<T>, opts?: SignalOptions<T>): AsyncSignal<T>;
|
191
|
-
export function asyncComputed<T>(
|
192
|
-
name: string,
|
193
|
-
compute: SignalAsyncCompute<T>,
|
194
|
-
opts: SignalOptionsWithInit<T>,
|
195
|
-
): AsyncSignal<T>;
|
196
|
-
export function asyncComputed<T>(compute: SignalAsyncCompute<T>, opts?: SignalOptions<T>): AsyncSignal<T>;
|
197
|
-
export function asyncComputed<T>(compute: SignalAsyncCompute<T>, opts: SignalOptionsWithInit<T>): AsyncSignal<T>;
|
198
|
-
export function asyncComputed<T>(
|
199
|
-
nameOrCompute: string | SignalAsyncCompute<T>,
|
200
|
-
computeOrOpts?: SignalCompute<T> | Partial<SignalOptionsWithInit<T>>,
|
201
|
-
maybeOpts?: Partial<SignalOptionsWithInit<T>>,
|
202
|
-
): AsyncSignal<T> {
|
203
|
-
const name = typeof nameOrCompute === 'string' ? nameOrCompute : 'unlabeled';
|
204
|
-
const compute = typeof nameOrCompute === 'string' ? (computeOrOpts as SignalCompute<T>) : nameOrCompute;
|
205
|
-
const opts = typeof nameOrCompute === 'string' ? maybeOpts : (computeOrOpts as SignalOptions<T>);
|
206
|
-
const counts = new SignalCounts(name);
|
207
|
-
|
208
|
-
const s = createAsyncComputed(async v => {
|
209
|
-
counts.compute++;
|
210
|
-
|
211
|
-
if (name) {
|
212
|
-
currentOrder?.push(name);
|
213
|
-
}
|
214
|
-
|
215
|
-
const result = await compute(v);
|
216
|
-
|
217
|
-
counts.resolve++;
|
218
|
-
|
219
|
-
return result;
|
220
|
-
}, opts);
|
221
|
-
|
222
|
-
const wrapper = {
|
223
|
-
get() {
|
224
|
-
counts.get++;
|
225
|
-
return s.get();
|
226
|
-
},
|
227
|
-
};
|
228
|
-
|
229
|
-
COUNTS.set(wrapper, counts);
|
230
|
-
|
231
|
-
return wrapper;
|
232
|
-
}
|
233
|
-
|
234
|
-
export function subscription<T>(
|
235
|
-
name: string,
|
236
|
-
subscribe: SignalSubscribe<T>,
|
237
|
-
opts?: SignalOptions<T>,
|
238
|
-
): Signal<T | undefined>;
|
239
|
-
export function subscription<T>(name: string, subscribe: SignalSubscribe<T>, opts: SignalOptionsWithInit<T>): Signal<T>;
|
240
|
-
export function subscription<T>(subscribe: SignalSubscribe<T>, opts?: SignalOptions<T>): Signal<T | undefined>;
|
241
|
-
export function subscription<T>(subscribe: SignalSubscribe<T>, opts: SignalOptionsWithInit<T>): Signal<T>;
|
242
|
-
export function subscription<T>(
|
243
|
-
nameOrSubscribe: string | SignalSubscribe<T>,
|
244
|
-
subscribeOrOpts?: SignalSubscribe<T> | Partial<SignalOptionsWithInit<T>>,
|
245
|
-
maybeOpts?: Partial<SignalOptionsWithInit<T>>,
|
246
|
-
): Signal<T> | Signal<T | undefined> {
|
247
|
-
const name = typeof nameOrSubscribe === 'string' ? nameOrSubscribe : 'unlabeled';
|
248
|
-
const subscribe = typeof nameOrSubscribe === 'string' ? (subscribeOrOpts as SignalSubscribe<T>) : nameOrSubscribe;
|
249
|
-
const opts = typeof nameOrSubscribe === 'string' ? maybeOpts : (subscribeOrOpts as SignalOptions<T>);
|
250
|
-
const counts = new SignalCounts(name);
|
251
|
-
|
252
|
-
const s = createSubscription((get, set) => {
|
253
|
-
counts.subscribe++;
|
254
|
-
|
255
|
-
if (name) {
|
256
|
-
currentOrder?.push(name);
|
257
|
-
}
|
258
|
-
|
259
|
-
const result = subscribe(
|
260
|
-
() => {
|
261
|
-
counts.internalGet++;
|
262
|
-
return get();
|
263
|
-
},
|
264
|
-
v => {
|
265
|
-
counts.internalSet++;
|
266
|
-
set(v);
|
267
|
-
},
|
268
|
-
);
|
269
|
-
|
270
|
-
let subscriptionWrapper: SignalSubscription | undefined;
|
271
|
-
|
272
|
-
if (result) {
|
273
|
-
subscriptionWrapper = {};
|
274
|
-
|
275
|
-
if (result.unsubscribe) {
|
276
|
-
subscriptionWrapper.unsubscribe = () => {
|
277
|
-
counts.unsubscribe++;
|
278
|
-
result.unsubscribe!();
|
279
|
-
};
|
280
|
-
}
|
281
|
-
|
282
|
-
if (result.update) {
|
283
|
-
subscriptionWrapper.update = () => {
|
284
|
-
counts.update++;
|
285
|
-
result.update!();
|
286
|
-
};
|
287
|
-
}
|
288
|
-
}
|
289
|
-
|
290
|
-
return subscriptionWrapper;
|
291
|
-
}, opts);
|
292
|
-
|
293
|
-
const wrapper = {
|
294
|
-
get() {
|
295
|
-
counts.get++;
|
296
|
-
return s.get();
|
297
|
-
},
|
298
|
-
};
|
299
|
-
|
300
|
-
COUNTS.set(wrapper, counts);
|
301
|
-
|
302
|
-
return wrapper;
|
303
|
-
}
|
304
|
-
|
305
|
-
export function watcher<T>(effect: SignalWatcherEffect): Watcher;
|
306
|
-
export function watcher<T>(name: string, effect: SignalWatcherEffect): Watcher;
|
307
|
-
export function watcher<T>(nameOrEffect: string | SignalWatcherEffect, maybeEffect?: SignalWatcherEffect): Watcher {
|
308
|
-
const name = typeof nameOrEffect === 'string' ? nameOrEffect : 'unlabeled';
|
309
|
-
const effect = typeof nameOrEffect === 'string' ? (maybeEffect as SignalWatcherEffect) : nameOrEffect;
|
310
|
-
|
311
|
-
const counts = new SignalCounts(name);
|
312
|
-
|
313
|
-
const w = createWatcher(() => {
|
314
|
-
counts.effect++;
|
315
|
-
|
316
|
-
if (name) {
|
317
|
-
currentOrder?.push(name);
|
318
|
-
}
|
319
|
-
|
320
|
-
effect();
|
321
|
-
});
|
322
|
-
|
323
|
-
COUNTS.set(w, counts);
|
324
|
-
|
325
|
-
return w;
|
326
|
-
}
|