signalium 0.3.8 → 1.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.
Files changed (287) hide show
  1. package/.turbo/turbo-build.log +3 -3
  2. package/CHANGELOG.md +21 -0
  3. package/build/react.js +19 -0
  4. package/build/transform.js +19 -0
  5. package/dist/cjs/config.d.ts +8 -3
  6. package/dist/cjs/config.d.ts.map +1 -1
  7. package/dist/cjs/config.js +14 -8
  8. package/dist/cjs/config.js.map +1 -1
  9. package/dist/cjs/debug.d.ts +2 -2
  10. package/dist/cjs/debug.d.ts.map +1 -1
  11. package/dist/cjs/debug.js +3 -3
  12. package/dist/cjs/debug.js.map +1 -1
  13. package/dist/cjs/hooks.d.ts +14 -42
  14. package/dist/cjs/hooks.d.ts.map +1 -1
  15. package/dist/cjs/hooks.js +19 -240
  16. package/dist/cjs/hooks.js.map +1 -1
  17. package/dist/cjs/index.d.ts +5 -3
  18. package/dist/cjs/index.d.ts.map +1 -1
  19. package/dist/cjs/index.js +18 -18
  20. package/dist/cjs/index.js.map +1 -1
  21. package/dist/cjs/internals/async.d.ts +52 -0
  22. package/dist/cjs/internals/async.d.ts.map +1 -0
  23. package/dist/cjs/internals/async.js +394 -0
  24. package/dist/cjs/internals/async.js.map +1 -0
  25. package/dist/cjs/internals/connect.d.ts +4 -0
  26. package/dist/cjs/internals/connect.d.ts.map +1 -0
  27. package/dist/cjs/internals/connect.js +37 -0
  28. package/dist/cjs/internals/connect.js.map +1 -0
  29. package/dist/cjs/internals/consumer.d.ts +6 -0
  30. package/dist/cjs/internals/consumer.d.ts.map +1 -0
  31. package/dist/cjs/internals/consumer.js +13 -0
  32. package/dist/cjs/internals/consumer.js.map +1 -0
  33. package/dist/cjs/internals/contexts.d.ts +33 -0
  34. package/dist/cjs/internals/contexts.d.ts.map +1 -0
  35. package/dist/cjs/internals/contexts.js +103 -0
  36. package/dist/cjs/internals/contexts.js.map +1 -0
  37. package/dist/cjs/internals/derived.d.ts +66 -0
  38. package/dist/cjs/internals/derived.d.ts.map +1 -0
  39. package/dist/cjs/internals/derived.js +128 -0
  40. package/dist/cjs/internals/derived.js.map +1 -0
  41. package/dist/cjs/internals/dirty.d.ts +5 -0
  42. package/dist/cjs/internals/dirty.d.ts.map +1 -0
  43. package/dist/cjs/internals/dirty.js +79 -0
  44. package/dist/cjs/internals/dirty.js.map +1 -0
  45. package/dist/cjs/internals/edge.d.ts +32 -0
  46. package/dist/cjs/internals/edge.d.ts.map +1 -0
  47. package/dist/cjs/internals/edge.js +59 -0
  48. package/dist/cjs/internals/edge.js.map +1 -0
  49. package/dist/cjs/internals/get.d.ts +10 -0
  50. package/dist/cjs/internals/get.d.ts.map +1 -0
  51. package/dist/cjs/internals/get.js +255 -0
  52. package/dist/cjs/internals/get.js.map +1 -0
  53. package/dist/cjs/internals/scheduling.d.ts +12 -0
  54. package/dist/cjs/internals/scheduling.d.ts.map +1 -0
  55. package/dist/cjs/internals/scheduling.js +117 -0
  56. package/dist/cjs/internals/scheduling.js.map +1 -0
  57. package/dist/cjs/internals/state.d.ts +18 -0
  58. package/dist/cjs/internals/state.d.ts.map +1 -0
  59. package/dist/cjs/internals/state.js +88 -0
  60. package/dist/cjs/internals/state.js.map +1 -0
  61. package/dist/cjs/internals/utils/debug-name.d.ts +2 -0
  62. package/dist/cjs/internals/utils/debug-name.d.ts.map +1 -0
  63. package/dist/cjs/internals/utils/debug-name.js +14 -0
  64. package/dist/cjs/internals/utils/debug-name.js.map +1 -0
  65. package/dist/cjs/internals/utils/equals.d.ts +3 -0
  66. package/dist/cjs/internals/utils/equals.d.ts.map +1 -0
  67. package/dist/cjs/internals/utils/equals.js +13 -0
  68. package/dist/cjs/internals/utils/equals.js.map +1 -0
  69. package/dist/cjs/internals/utils/hash.d.ts +7 -0
  70. package/dist/cjs/internals/utils/hash.d.ts.map +1 -0
  71. package/dist/cjs/internals/utils/hash.js +181 -0
  72. package/dist/cjs/internals/utils/hash.js.map +1 -0
  73. package/dist/cjs/internals/utils/stringify.d.ts +3 -0
  74. package/dist/cjs/internals/utils/stringify.d.ts.map +1 -0
  75. package/dist/cjs/{utils.js → internals/utils/stringify.js} +5 -27
  76. package/dist/cjs/internals/utils/stringify.js.map +1 -0
  77. package/dist/cjs/internals/utils/type-utils.d.ts +6 -0
  78. package/dist/cjs/internals/utils/type-utils.d.ts.map +1 -0
  79. package/dist/cjs/internals/utils/type-utils.js +22 -0
  80. package/dist/cjs/internals/utils/type-utils.js.map +1 -0
  81. package/dist/cjs/react/context.d.ts +1 -1
  82. package/dist/cjs/react/context.d.ts.map +1 -1
  83. package/dist/cjs/react/provider.d.ts +4 -3
  84. package/dist/cjs/react/provider.d.ts.map +1 -1
  85. package/dist/cjs/react/provider.js +7 -3
  86. package/dist/cjs/react/provider.js.map +1 -1
  87. package/dist/cjs/react/setup.d.ts.map +1 -1
  88. package/dist/cjs/react/setup.js +2 -1
  89. package/dist/cjs/react/setup.js.map +1 -1
  90. package/dist/cjs/react/signal-value.d.ts +5 -1
  91. package/dist/cjs/react/signal-value.d.ts.map +1 -1
  92. package/dist/cjs/react/signal-value.js +35 -45
  93. package/dist/cjs/react/signal-value.js.map +1 -1
  94. package/dist/cjs/trace.d.ts +32 -28
  95. package/dist/cjs/trace.d.ts.map +1 -1
  96. package/dist/cjs/trace.js +14 -16
  97. package/dist/cjs/trace.js.map +1 -1
  98. package/dist/cjs/transform.d.ts +6 -0
  99. package/dist/cjs/transform.d.ts.map +1 -0
  100. package/dist/cjs/transform.js +92 -0
  101. package/dist/cjs/transform.js.map +1 -0
  102. package/dist/cjs/types.d.ts +32 -40
  103. package/dist/cjs/types.d.ts.map +1 -1
  104. package/dist/esm/config.d.ts +8 -3
  105. package/dist/esm/config.d.ts.map +1 -1
  106. package/dist/esm/config.js +12 -7
  107. package/dist/esm/config.js.map +1 -1
  108. package/dist/esm/debug.d.ts +2 -2
  109. package/dist/esm/debug.d.ts.map +1 -1
  110. package/dist/esm/debug.js +2 -2
  111. package/dist/esm/debug.js.map +1 -1
  112. package/dist/esm/hooks.d.ts +14 -42
  113. package/dist/esm/hooks.d.ts.map +1 -1
  114. package/dist/esm/hooks.js +17 -226
  115. package/dist/esm/hooks.js.map +1 -1
  116. package/dist/esm/index.d.ts +5 -3
  117. package/dist/esm/index.d.ts.map +1 -1
  118. package/dist/esm/index.js +5 -3
  119. package/dist/esm/index.js.map +1 -1
  120. package/dist/esm/internals/async.d.ts +52 -0
  121. package/dist/esm/internals/async.d.ts.map +1 -0
  122. package/dist/esm/internals/async.js +387 -0
  123. package/dist/esm/internals/async.js.map +1 -0
  124. package/dist/esm/internals/connect.d.ts +4 -0
  125. package/dist/esm/internals/connect.d.ts.map +1 -0
  126. package/dist/esm/internals/connect.js +33 -0
  127. package/dist/esm/internals/connect.js.map +1 -0
  128. package/dist/esm/internals/consumer.d.ts +6 -0
  129. package/dist/esm/internals/consumer.d.ts.map +1 -0
  130. package/dist/esm/internals/consumer.js +9 -0
  131. package/dist/esm/internals/consumer.js.map +1 -0
  132. package/dist/esm/internals/contexts.d.ts +33 -0
  133. package/dist/esm/internals/contexts.d.ts.map +1 -0
  134. package/dist/esm/internals/contexts.js +92 -0
  135. package/dist/esm/internals/contexts.js.map +1 -0
  136. package/dist/esm/internals/derived.d.ts +66 -0
  137. package/dist/esm/internals/derived.d.ts.map +1 -0
  138. package/dist/esm/internals/derived.js +118 -0
  139. package/dist/esm/internals/derived.js.map +1 -0
  140. package/dist/esm/internals/dirty.d.ts +5 -0
  141. package/dist/esm/internals/dirty.d.ts.map +1 -0
  142. package/dist/esm/internals/dirty.js +75 -0
  143. package/dist/esm/internals/dirty.js.map +1 -0
  144. package/dist/esm/internals/edge.d.ts +32 -0
  145. package/dist/esm/internals/edge.d.ts.map +1 -0
  146. package/dist/esm/internals/edge.js +54 -0
  147. package/dist/esm/internals/edge.js.map +1 -0
  148. package/dist/esm/internals/get.d.ts +10 -0
  149. package/dist/esm/internals/get.d.ts.map +1 -0
  150. package/dist/esm/internals/get.js +247 -0
  151. package/dist/esm/internals/get.js.map +1 -0
  152. package/dist/esm/internals/scheduling.d.ts +12 -0
  153. package/dist/esm/internals/scheduling.d.ts.map +1 -0
  154. package/dist/esm/internals/scheduling.js +106 -0
  155. package/dist/esm/internals/scheduling.js.map +1 -0
  156. package/dist/esm/internals/state.d.ts +18 -0
  157. package/dist/esm/internals/state.d.ts.map +1 -0
  158. package/dist/esm/internals/state.js +82 -0
  159. package/dist/esm/internals/state.js.map +1 -0
  160. package/dist/esm/internals/utils/debug-name.d.ts +2 -0
  161. package/dist/esm/internals/utils/debug-name.d.ts.map +1 -0
  162. package/dist/esm/internals/utils/debug-name.js +11 -0
  163. package/dist/esm/internals/utils/debug-name.js.map +1 -0
  164. package/dist/esm/internals/utils/equals.d.ts +3 -0
  165. package/dist/esm/internals/utils/equals.d.ts.map +1 -0
  166. package/dist/esm/internals/utils/equals.js +9 -0
  167. package/dist/esm/internals/utils/equals.js.map +1 -0
  168. package/dist/esm/internals/utils/hash.d.ts +7 -0
  169. package/dist/esm/internals/utils/hash.d.ts.map +1 -0
  170. package/dist/esm/internals/utils/hash.js +174 -0
  171. package/dist/esm/internals/utils/hash.js.map +1 -0
  172. package/dist/esm/internals/utils/stringify.d.ts +3 -0
  173. package/dist/esm/internals/utils/stringify.d.ts.map +1 -0
  174. package/dist/esm/{utils.js → internals/utils/stringify.js} +4 -25
  175. package/dist/esm/internals/utils/stringify.js.map +1 -0
  176. package/dist/esm/internals/utils/type-utils.d.ts +6 -0
  177. package/dist/esm/internals/utils/type-utils.d.ts.map +1 -0
  178. package/dist/esm/internals/utils/type-utils.js +15 -0
  179. package/dist/esm/internals/utils/type-utils.js.map +1 -0
  180. package/dist/esm/react/context.d.ts +1 -1
  181. package/dist/esm/react/context.d.ts.map +1 -1
  182. package/dist/esm/react/provider.d.ts +4 -3
  183. package/dist/esm/react/provider.d.ts.map +1 -1
  184. package/dist/esm/react/provider.js +6 -2
  185. package/dist/esm/react/provider.js.map +1 -1
  186. package/dist/esm/react/setup.d.ts.map +1 -1
  187. package/dist/esm/react/setup.js +3 -2
  188. package/dist/esm/react/setup.js.map +1 -1
  189. package/dist/esm/react/signal-value.d.ts +5 -1
  190. package/dist/esm/react/signal-value.d.ts.map +1 -1
  191. package/dist/esm/react/signal-value.js +34 -45
  192. package/dist/esm/react/signal-value.js.map +1 -1
  193. package/dist/esm/trace.d.ts +32 -28
  194. package/dist/esm/trace.d.ts.map +1 -1
  195. package/dist/esm/trace.js +13 -15
  196. package/dist/esm/trace.js.map +1 -1
  197. package/dist/esm/transform.d.ts +6 -0
  198. package/dist/esm/transform.d.ts.map +1 -0
  199. package/dist/esm/transform.js +89 -0
  200. package/dist/esm/transform.js.map +1 -0
  201. package/dist/esm/types.d.ts +32 -40
  202. package/dist/esm/types.d.ts.map +1 -1
  203. package/package.json +23 -4
  204. package/src/__tests__/__snapshots__/context.test.ts.snap +2101 -0
  205. package/src/__tests__/__snapshots__/nesting.test.ts.snap +16201 -0
  206. package/src/__tests__/__snapshots__/params-and-state.test.ts.snap +1879 -0
  207. package/src/__tests__/async-task.test.ts +327 -0
  208. package/src/__tests__/context.test.ts +517 -0
  209. package/src/__tests__/nesting.test.ts +298 -0
  210. package/src/__tests__/params-and-state.test.ts +230 -0
  211. package/src/__tests__/reactive-async.test.ts +548 -0
  212. package/src/__tests__/reactive-sync.test.ts +130 -0
  213. package/src/__tests__/subscription.test.ts +510 -0
  214. package/src/__tests__/utils/async.ts +1 -1
  215. package/src/__tests__/utils/instrumented-hooks.ts +229 -124
  216. package/src/__tests__/utils/permute.ts +25 -14
  217. package/src/config.ts +19 -9
  218. package/src/debug.ts +2 -2
  219. package/src/hooks.ts +46 -380
  220. package/src/index.ts +7 -24
  221. package/src/internals/async.ts +558 -0
  222. package/src/internals/connect.ts +41 -0
  223. package/src/internals/consumer.ts +13 -0
  224. package/src/internals/contexts.ts +133 -0
  225. package/src/internals/derived.ts +208 -0
  226. package/src/internals/dirty.ts +91 -0
  227. package/src/internals/edge.ts +109 -0
  228. package/src/internals/get.ts +298 -0
  229. package/src/internals/scheduling.ts +140 -0
  230. package/src/internals/state.ts +111 -0
  231. package/src/internals/utils/debug-name.ts +14 -0
  232. package/src/internals/utils/equals.ts +12 -0
  233. package/src/internals/utils/hash.ts +221 -0
  234. package/src/{utils.ts → internals/utils/stringify.ts} +3 -29
  235. package/src/internals/utils/type-utils.ts +19 -0
  236. package/src/react/__tests__/async.test.tsx +704 -0
  237. package/src/react/__tests__/basic.test.tsx +95 -0
  238. package/src/react/__tests__/contexts.test.tsx +99 -0
  239. package/src/react/__tests__/subscriptions.test.tsx +49 -0
  240. package/src/react/__tests__/utils.tsx +40 -0
  241. package/src/react/context.ts +1 -1
  242. package/src/react/provider.tsx +12 -4
  243. package/src/react/setup.ts +3 -2
  244. package/src/react/signal-value.ts +47 -67
  245. package/src/trace.ts +43 -38
  246. package/src/transform.ts +113 -0
  247. package/src/types.ts +56 -46
  248. package/transform.js +19 -0
  249. package/vitest.workspace.ts +38 -2
  250. package/dist/cjs/scheduling.d.ts +0 -11
  251. package/dist/cjs/scheduling.d.ts.map +0 -1
  252. package/dist/cjs/scheduling.js +0 -108
  253. package/dist/cjs/scheduling.js.map +0 -1
  254. package/dist/cjs/signals.d.ts +0 -73
  255. package/dist/cjs/signals.d.ts.map +0 -1
  256. package/dist/cjs/signals.js +0 -632
  257. package/dist/cjs/signals.js.map +0 -1
  258. package/dist/cjs/utils.d.ts +0 -4
  259. package/dist/cjs/utils.d.ts.map +0 -1
  260. package/dist/cjs/utils.js.map +0 -1
  261. package/dist/esm/scheduling.d.ts +0 -11
  262. package/dist/esm/scheduling.d.ts.map +0 -1
  263. package/dist/esm/scheduling.js +0 -97
  264. package/dist/esm/scheduling.js.map +0 -1
  265. package/dist/esm/signals.d.ts +0 -73
  266. package/dist/esm/signals.d.ts.map +0 -1
  267. package/dist/esm/signals.js +0 -614
  268. package/dist/esm/signals.js.map +0 -1
  269. package/dist/esm/utils.d.ts +0 -4
  270. package/dist/esm/utils.d.ts.map +0 -1
  271. package/dist/esm/utils.js.map +0 -1
  272. package/src/__tests__/hooks/async-computed.test.ts +0 -190
  273. package/src/__tests__/hooks/async-task.test.ts +0 -334
  274. package/src/__tests__/hooks/computed.test.ts +0 -126
  275. package/src/__tests__/hooks/context.test.ts +0 -527
  276. package/src/__tests__/hooks/nesting.test.ts +0 -303
  277. package/src/__tests__/hooks/params-and-state.test.ts +0 -168
  278. package/src/__tests__/hooks/subscription.test.ts +0 -97
  279. package/src/__tests__/signals/async.test.ts +0 -416
  280. package/src/__tests__/signals/basic.test.ts +0 -399
  281. package/src/__tests__/signals/subscription.test.ts +0 -632
  282. package/src/__tests__/signals/watcher.test.ts +0 -253
  283. package/src/__tests__/utils/builders.ts +0 -22
  284. package/src/__tests__/utils/instrumented-signals.ts +0 -291
  285. package/src/react/__tests__/react.test.tsx +0 -227
  286. package/src/scheduling.ts +0 -130
  287. package/src/signals.ts +0 -824
@@ -1,253 +0,0 @@
1
- import { describe, expect, test } from 'vitest';
2
- import {
3
- createStateSignal,
4
- createComputedSignal,
5
- createAsyncComputedSignal,
6
- createSubscriptionSignal,
7
- createWatcherSignal,
8
- } from '../utils/instrumented-signals.js';
9
- import { result } from '../utils/builders.js';
10
- import { nextTick, sleep } from '../utils/async.js';
11
-
12
- describe('Watcher functionality', () => {
13
- describe('with computeds', () => {
14
- test('watches computed values', async () => {
15
- const a = createStateSignal(1);
16
- const b = createStateSignal(2);
17
-
18
- const c = createComputedSignal(() => {
19
- return a.get() + b.get();
20
- });
21
-
22
- let value;
23
- const w = createWatcherSignal(() => {
24
- value = c.get();
25
- });
26
-
27
- w.addListener(() => {
28
- // do something
29
- });
30
-
31
- expect(value).toBe(undefined);
32
- expect(w).toHaveSignalCounts({ compute: 0, effect: 0 });
33
-
34
- await nextTick();
35
-
36
- expect(value).toBe(3);
37
- expect(w).toHaveSignalCounts({ compute: 1, effect: 1 });
38
-
39
- a.set(2);
40
-
41
- await nextTick();
42
-
43
- expect(value).toBe(4);
44
- expect(w).toHaveSignalCounts({ compute: 2, effect: 2 });
45
- });
46
-
47
- test('immediate option works', async () => {
48
- const a = createStateSignal(1);
49
- const b = createStateSignal(2);
50
-
51
- const c = createComputedSignal(() => {
52
- return a.get() + b.get();
53
- });
54
-
55
- let value;
56
- const w = createWatcherSignal(() => {
57
- value = c.get();
58
- });
59
-
60
- w.addListener(
61
- () => {
62
- // do something
63
- },
64
- { immediate: true },
65
- );
66
-
67
- expect(value).toBe(3);
68
- expect(w).toHaveSignalCounts({ compute: 1, effect: 1 });
69
-
70
- a.set(2);
71
-
72
- await nextTick();
73
-
74
- expect(value).toBe(4);
75
- expect(w).toHaveSignalCounts({ compute: 2, effect: 2 });
76
- });
77
- });
78
-
79
- describe('with async computeds', () => {
80
- test('watches async computed values', async () => {
81
- const a = createStateSignal(1);
82
- const b = createStateSignal(2);
83
-
84
- const c = createAsyncComputedSignal(async () => {
85
- return a.get() + b.get();
86
- });
87
-
88
- let value;
89
- const w = createWatcherSignal(() => {
90
- return c.get();
91
- });
92
-
93
- const unsub = w.addListener(v => {
94
- value = { ...v };
95
- // do something
96
- });
97
-
98
- expect(value).toEqual(undefined);
99
- expect(w).toHaveSignalCounts({ compute: 0, effect: 0 });
100
-
101
- await sleep(); // First tick to start async computation
102
-
103
- expect(value).toEqual(result(undefined, 'pending', 'initial'));
104
- expect(w).toHaveSignalCounts({ compute: 1, effect: 1 });
105
-
106
- await nextTick(); // Extra tick for async resolution
107
-
108
- expect(value).toEqual(result(3, 'success', 'resolved'));
109
- expect(w).toHaveSignalCounts({ compute: 2, effect: 2 });
110
-
111
- a.set(2);
112
-
113
- await sleep(); // First tick to start async computation
114
-
115
- expect(value).toEqual(result(3, 'pending', 'resolved'));
116
- expect(w).toHaveSignalCounts({ compute: 3, effect: 3 });
117
-
118
- await nextTick(); // Extra tick for async resolution
119
-
120
- expect(value).toEqual(result(4, 'success', 'resolved'));
121
- expect(w).toHaveSignalCounts({ compute: 4, effect: 4 });
122
-
123
- unsub();
124
- });
125
-
126
- test('immediate option works', async () => {
127
- const a = createStateSignal(1);
128
- const b = createStateSignal(2);
129
-
130
- const c = createAsyncComputedSignal(async () => {
131
- return a.get() + b.get();
132
- });
133
-
134
- const w = createWatcherSignal(() => {
135
- return c.get();
136
- });
137
-
138
- let value;
139
- w.addListener(
140
- v => {
141
- value = { ...v };
142
- // do something
143
- },
144
- {
145
- immediate: true,
146
- },
147
- );
148
-
149
- expect(value).toEqual(result(undefined, 'pending', 'initial'));
150
- expect(w).toHaveSignalCounts({ compute: 1, effect: 1 });
151
-
152
- await nextTick(); // Extra tick for async resolution
153
-
154
- expect(value).toEqual(result(3, 'success', 'resolved'));
155
- expect(w).toHaveSignalCounts({ compute: 2, effect: 2 });
156
-
157
- a.set(2);
158
-
159
- await sleep(); // First tick to start async computation
160
-
161
- expect(value).toEqual(result(3, 'pending', 'resolved'));
162
- expect(w).toHaveSignalCounts({ compute: 3, effect: 3 });
163
-
164
- await nextTick(); // Extra tick for async resolution
165
-
166
- expect(value).toEqual(result(4, 'success', 'resolved'));
167
- expect(w).toHaveSignalCounts({ compute: 4, effect: 4 });
168
- });
169
- });
170
-
171
- describe('with subscriptions', () => {
172
- test('watches subscription values', async () => {
173
- let value = createStateSignal(1);
174
-
175
- const s = createSubscriptionSignal(({ get, set }) => {
176
- set(value.get());
177
-
178
- return {
179
- update() {
180
- set(value.get());
181
- },
182
- };
183
- });
184
-
185
- let watchedValue;
186
- const w = createWatcherSignal(() => {
187
- watchedValue = s.get();
188
- });
189
-
190
- w.addListener(() => {
191
- // do something
192
- });
193
-
194
- expect(watchedValue).toBe(undefined);
195
- expect(w).toHaveSignalCounts({ compute: 0, effect: 0 });
196
- expect(s).toHaveSignalValueAndCounts(undefined, { subscribe: 0 });
197
-
198
- await nextTick();
199
-
200
- expect(watchedValue).toBe(1);
201
- expect(w).toHaveSignalCounts({ compute: 1, effect: 1 });
202
- expect(s).toHaveSignalValueAndCounts(1, { subscribe: 1 });
203
-
204
- value.set(2);
205
- s.get();
206
-
207
- await nextTick();
208
-
209
- expect(watchedValue).toBe(2);
210
- expect(w).toHaveSignalCounts({ compute: 2, effect: 2 });
211
- expect(s).toHaveSignalValueAndCounts(2, { subscribe: 1 });
212
- });
213
-
214
- test('immediate option works', async () => {
215
- let value = createStateSignal(1);
216
-
217
- const s = createSubscriptionSignal(({ get, set }) => {
218
- set(value.get());
219
-
220
- return {
221
- update() {
222
- set(value.get());
223
- },
224
- };
225
- });
226
-
227
- let watchedValue;
228
- const w = createWatcherSignal(() => {
229
- watchedValue = s.get();
230
- });
231
-
232
- w.addListener(
233
- () => {
234
- // do something
235
- },
236
- { immediate: true },
237
- );
238
-
239
- expect(watchedValue).toBe(1);
240
- expect(w).toHaveSignalCounts({ compute: 1, effect: 1 });
241
- expect(s).toHaveSignalValueAndCounts(1, { subscribe: 1 });
242
-
243
- value.set(2);
244
- s.get();
245
-
246
- await nextTick();
247
-
248
- expect(watchedValue).toBe(2);
249
- expect(w).toHaveSignalCounts({ compute: 2, effect: 2 });
250
- expect(s).toHaveSignalValueAndCounts(2, { subscribe: 1 });
251
- });
252
- });
253
- });
@@ -1,22 +0,0 @@
1
- import { expect } from 'vitest';
2
- import { AsyncResult } from '../../types.js';
3
-
4
- export const result = <T>(
5
- value: T | undefined,
6
- promiseState: 'pending' | 'error' | 'success',
7
- readyState: 'initial' | 'ready' | 'resolved',
8
- error?: any,
9
- ): AsyncResult<T> =>
10
- ({
11
- result: value,
12
- error,
13
- isPending: promiseState === 'pending',
14
- isError: promiseState === 'error',
15
- isSuccess: promiseState === 'success',
16
-
17
- isReady: readyState === 'ready' || readyState === 'resolved',
18
- didResolve: readyState === 'resolved',
19
-
20
- await: expect.any(Function),
21
- invalidate: expect.any(Function),
22
- }) as AsyncResult<T>;
@@ -1,291 +0,0 @@
1
- import { expect, beforeEach, afterEach, vi } from 'vitest';
2
- import {
3
- createStateSignal as _createStateSignal,
4
- createComputedSignal as _createComputedSignal,
5
- createAsyncComputedSignal as _createAsyncComputedSignal,
6
- createSubscriptionSignal as _createSubscriptionSignal,
7
- createWatcherSignal as _createWatcherSignal,
8
- SignalOptions,
9
- Signal,
10
- WriteableSignal,
11
- SignalSubscription,
12
- Watcher,
13
- } from '../../index.js';
14
-
15
- class SignalCounts {
16
- name: string;
17
-
18
- get = 0;
19
- set = 0;
20
- compute = 0;
21
-
22
- resolve = 0;
23
-
24
- subscribe = 0;
25
- update = 0;
26
- unsubscribe = 0;
27
- internalGet = 0;
28
- internalSet = 0;
29
-
30
- effect = 0;
31
-
32
- constructor(name: string) {
33
- this.name = name;
34
- }
35
- }
36
-
37
- const countsKeys = Object.keys(new SignalCounts('')).filter(k => k !== 'name') as (keyof SignalCounts)[];
38
-
39
- let currentOrder: string[] | undefined = [];
40
- const COUNTS = new WeakMap<Signal<any> | Watcher<any>, SignalCounts>();
41
-
42
- interface CustomMatchers<R = unknown> {
43
- toHaveSignalValue: (v: any) => R;
44
- toHaveSignalCounts: (counts: Partial<SignalCounts>) => R;
45
- toHaveSignalValueAndCounts: (v: any, counts: Partial<SignalCounts>) => R;
46
- toHaveComputedOrder: (order: string[]) => R;
47
- }
48
-
49
- declare module 'vitest' {
50
- // eslint-disable-next-line @typescript-eslint/no-empty-object-type
51
- interface Assertion<T = any> extends CustomMatchers<T> {}
52
- // eslint-disable-next-line @typescript-eslint/no-empty-object-type
53
- interface AsymmetricMatchersContaining extends CustomMatchers {}
54
- }
55
-
56
- function toHaveSignalValue(this: { equals(a: unknown, b: unknown): boolean }, signal: Signal<any>, value: any) {
57
- const signalValue = signal.get();
58
-
59
- return {
60
- pass: this.equals(signalValue, value),
61
- message: () => `Expected signal value to be ${JSON.stringify(value)}, but got ${JSON.stringify(signalValue)}`,
62
- };
63
- }
64
-
65
- function toHaveSignalCounts(signal: Signal<any>, counts: SignalCounts) {
66
- const signalCounts = COUNTS.get(signal);
67
-
68
- if (!signalCounts) {
69
- return {
70
- pass: false,
71
- message: () => 'Signal not found in counts map',
72
- };
73
- }
74
-
75
- for (const key of countsKeys) {
76
- const count = counts[key];
77
-
78
- if (count !== undefined && signalCounts[key] !== count) {
79
- return {
80
- pass: false,
81
- message: () => `Expected ${key} count to be ${count} but got ${signalCounts[key]}`,
82
- };
83
- }
84
- }
85
-
86
- return {
87
- pass: true,
88
- message: () => 'Counts match',
89
- };
90
- }
91
-
92
- expect.extend({
93
- toHaveSignalValue,
94
- toHaveSignalCounts,
95
-
96
- toHaveSignalValueAndCounts(signal, value, counts) {
97
- const valueResult = toHaveSignalValue.call(this, signal, value);
98
- const countsResult = toHaveSignalCounts.call(this, signal, counts);
99
-
100
- return {
101
- pass: valueResult.pass && countsResult.pass,
102
- message: () => {
103
- const messages = [
104
- !valueResult.pass && valueResult.message(),
105
- !countsResult.pass && countsResult.message(),
106
- ].filter(m => m);
107
-
108
- return messages.join('\n');
109
- },
110
- };
111
- },
112
-
113
- toHaveComputedOrder(fn: () => void, expectedOrder: string[]) {
114
- const order = (currentOrder = []);
115
-
116
- fn();
117
-
118
- currentOrder = undefined;
119
-
120
- return {
121
- pass: this.equals(order, expectedOrder),
122
- message: () => `Expected compute count to be ${expectedOrder.toString()} but got ${order.toString()}`,
123
- };
124
- },
125
- });
126
-
127
- export const createStateSignal = <T>(initialValue: T, opts?: SignalOptions<T, []>): WriteableSignal<T> => {
128
- const desc = opts?.desc || 'unlabeled';
129
- const s = _createStateSignal(initialValue, opts);
130
-
131
- const counts = new SignalCounts(desc);
132
-
133
- const wrapper = {
134
- get() {
135
- counts.get++;
136
- return s.get();
137
- },
138
-
139
- set(value: T) {
140
- counts.set++;
141
- s.set(value);
142
- },
143
- };
144
-
145
- COUNTS.set(wrapper, counts);
146
-
147
- return wrapper;
148
- };
149
-
150
- export const createComputedSignal: typeof _createComputedSignal = (compute, opts) => {
151
- const desc = opts?.desc || 'unlabeled';
152
- const counts = new SignalCounts(desc);
153
-
154
- const s = _createComputedSignal(v => {
155
- counts.compute++;
156
-
157
- if (desc) {
158
- currentOrder?.push(desc);
159
- }
160
-
161
- return compute(v);
162
- }, opts);
163
-
164
- const wrapper = {
165
- get() {
166
- counts.get++;
167
-
168
- // Get twice to ensure idempotency
169
- s.get();
170
-
171
- return s.get();
172
- },
173
- };
174
-
175
- COUNTS.set(wrapper, counts);
176
-
177
- return wrapper;
178
- };
179
-
180
- export const createAsyncComputedSignal: typeof _createAsyncComputedSignal = (compute, opts) => {
181
- const desc = opts?.desc || 'unlabeled';
182
- const counts = new SignalCounts(desc);
183
-
184
- const s = _createAsyncComputedSignal(async v => {
185
- counts.compute++;
186
-
187
- if (desc) {
188
- currentOrder?.push(desc);
189
- }
190
-
191
- const result = await compute(v);
192
-
193
- counts.resolve++;
194
-
195
- return result;
196
- }, opts);
197
-
198
- const wrapper = {
199
- get() {
200
- counts.get++;
201
- return s.get();
202
- },
203
- };
204
-
205
- COUNTS.set(wrapper, counts);
206
-
207
- return wrapper;
208
- };
209
-
210
- export const createSubscriptionSignal: typeof _createSubscriptionSignal = (subscribe, opts) => {
211
- const desc = opts?.desc || 'unlabeled';
212
- const counts = new SignalCounts(desc);
213
-
214
- const s = _createSubscriptionSignal(({ get, set }) => {
215
- counts.subscribe++;
216
-
217
- if (desc) {
218
- currentOrder?.push(desc);
219
- }
220
-
221
- const result = subscribe({
222
- get: () => {
223
- counts.internalGet++;
224
- return get();
225
- },
226
- set: v => {
227
- counts.internalSet++;
228
- set(v);
229
- },
230
- });
231
-
232
- let subscriptionWrapper: SignalSubscription | (() => unknown) | undefined;
233
-
234
- if (typeof result === 'function') {
235
- subscriptionWrapper = () => {
236
- counts.unsubscribe++;
237
- result();
238
- };
239
- } else {
240
- subscriptionWrapper = {};
241
-
242
- subscriptionWrapper.unsubscribe = () => {
243
- counts.unsubscribe++;
244
- result?.unsubscribe?.();
245
- };
246
-
247
- subscriptionWrapper.update = () => {
248
- counts.compute++;
249
- counts.update++;
250
- result?.update?.();
251
- };
252
- }
253
-
254
- return subscriptionWrapper;
255
- }, opts);
256
-
257
- const wrapper = {
258
- get() {
259
- counts.get++;
260
- return s.get();
261
- },
262
- };
263
-
264
- COUNTS.set(wrapper, counts);
265
-
266
- return wrapper;
267
- };
268
-
269
- export function createWatcherSignal<T>(fn: () => T, opts?: SignalOptions<T, []>): Watcher<T> {
270
- const desc = opts?.desc || 'unlabeled';
271
- const counts = new SignalCounts(desc);
272
-
273
- const w = _createWatcherSignal<T>(() => {
274
- counts.compute++;
275
- return fn();
276
- }, opts);
277
-
278
- const wrapper: Watcher<T> = {
279
- addListener: (fn, opts) => {
280
- counts.subscribe++;
281
- return w.addListener(v => {
282
- counts.effect++;
283
- return fn(v);
284
- }, opts);
285
- },
286
- };
287
-
288
- COUNTS.set(wrapper, counts);
289
-
290
- return wrapper;
291
- }