@ersbeth/picoflow 1.0.0 → 1.1.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.
Files changed (180) hide show
  1. package/.cursor/plans/unifier-flowresource-avec-flowderivation-c9506e24.plan.md +372 -0
  2. package/README.md +25 -171
  3. package/biome.json +4 -1
  4. package/dist/picoflow.js +1129 -661
  5. package/dist/types/flow/base/flowDisposable.d.ts +67 -0
  6. package/dist/types/flow/base/flowDisposable.d.ts.map +1 -0
  7. package/dist/types/flow/base/flowEffect.d.ts +127 -0
  8. package/dist/types/flow/base/flowEffect.d.ts.map +1 -0
  9. package/dist/types/flow/base/flowGraph.d.ts +97 -0
  10. package/dist/types/flow/base/flowGraph.d.ts.map +1 -0
  11. package/dist/types/flow/base/flowSignal.d.ts +134 -0
  12. package/dist/types/flow/base/flowSignal.d.ts.map +1 -0
  13. package/dist/types/flow/base/flowTracker.d.ts +15 -0
  14. package/dist/types/flow/base/flowTracker.d.ts.map +1 -0
  15. package/dist/types/flow/base/index.d.ts +7 -0
  16. package/dist/types/flow/base/index.d.ts.map +1 -0
  17. package/dist/types/flow/base/utils.d.ts +20 -0
  18. package/dist/types/flow/base/utils.d.ts.map +1 -0
  19. package/dist/types/{advanced/array.d.ts → flow/collections/flowArray.d.ts} +50 -12
  20. package/dist/types/flow/collections/flowArray.d.ts.map +1 -0
  21. package/dist/types/flow/collections/flowMap.d.ts +224 -0
  22. package/dist/types/flow/collections/flowMap.d.ts.map +1 -0
  23. package/dist/types/flow/collections/index.d.ts +3 -0
  24. package/dist/types/flow/collections/index.d.ts.map +1 -0
  25. package/dist/types/flow/index.d.ts +4 -0
  26. package/dist/types/flow/index.d.ts.map +1 -0
  27. package/dist/types/flow/nodes/async/flowConstantAsync.d.ts +137 -0
  28. package/dist/types/flow/nodes/async/flowConstantAsync.d.ts.map +1 -0
  29. package/dist/types/flow/nodes/async/flowDerivationAsync.d.ts +137 -0
  30. package/dist/types/flow/nodes/async/flowDerivationAsync.d.ts.map +1 -0
  31. package/dist/types/flow/nodes/async/flowNodeAsync.d.ts +343 -0
  32. package/dist/types/flow/nodes/async/flowNodeAsync.d.ts.map +1 -0
  33. package/dist/types/flow/nodes/async/flowReadonlyAsync.d.ts +81 -0
  34. package/dist/types/flow/nodes/async/flowReadonlyAsync.d.ts.map +1 -0
  35. package/dist/types/flow/nodes/async/flowStateAsync.d.ts +111 -0
  36. package/dist/types/flow/nodes/async/flowStateAsync.d.ts.map +1 -0
  37. package/dist/types/flow/nodes/async/index.d.ts +6 -0
  38. package/dist/types/flow/nodes/async/index.d.ts.map +1 -0
  39. package/dist/types/flow/nodes/index.d.ts +3 -0
  40. package/dist/types/flow/nodes/index.d.ts.map +1 -0
  41. package/dist/types/flow/nodes/sync/flowConstant.d.ts +108 -0
  42. package/dist/types/flow/nodes/sync/flowConstant.d.ts.map +1 -0
  43. package/dist/types/flow/nodes/sync/flowDerivation.d.ts +100 -0
  44. package/dist/types/flow/nodes/sync/flowDerivation.d.ts.map +1 -0
  45. package/dist/types/flow/nodes/sync/flowNode.d.ts +314 -0
  46. package/dist/types/flow/nodes/sync/flowNode.d.ts.map +1 -0
  47. package/dist/types/flow/nodes/sync/flowReadonly.d.ts +57 -0
  48. package/dist/types/flow/nodes/sync/flowReadonly.d.ts.map +1 -0
  49. package/dist/types/flow/nodes/sync/flowState.d.ts +96 -0
  50. package/dist/types/flow/nodes/sync/flowState.d.ts.map +1 -0
  51. package/dist/types/flow/nodes/sync/index.d.ts +6 -0
  52. package/dist/types/flow/nodes/sync/index.d.ts.map +1 -0
  53. package/dist/types/index.d.ts +1 -4
  54. package/dist/types/index.d.ts.map +1 -1
  55. package/dist/types/solid/converters.d.ts +34 -44
  56. package/dist/types/solid/converters.d.ts.map +1 -1
  57. package/dist/types/solid/primitives.d.ts +1 -0
  58. package/dist/types/solid/primitives.d.ts.map +1 -1
  59. package/docs/.vitepress/config.mts +1 -1
  60. package/docs/api/typedoc-sidebar.json +81 -1
  61. package/package.json +60 -58
  62. package/src/flow/base/flowDisposable.ts +71 -0
  63. package/src/flow/base/flowEffect.ts +171 -0
  64. package/src/flow/base/flowGraph.ts +288 -0
  65. package/src/flow/base/flowSignal.ts +207 -0
  66. package/src/flow/base/flowTracker.ts +17 -0
  67. package/src/flow/base/index.ts +6 -0
  68. package/src/flow/base/utils.ts +19 -0
  69. package/src/flow/collections/flowArray.ts +409 -0
  70. package/src/flow/collections/flowMap.ts +398 -0
  71. package/src/flow/collections/index.ts +2 -0
  72. package/src/flow/index.ts +3 -0
  73. package/src/flow/nodes/async/flowConstantAsync.ts +142 -0
  74. package/src/flow/nodes/async/flowDerivationAsync.ts +143 -0
  75. package/src/flow/nodes/async/flowNodeAsync.ts +474 -0
  76. package/src/flow/nodes/async/flowReadonlyAsync.ts +81 -0
  77. package/src/flow/nodes/async/flowStateAsync.ts +116 -0
  78. package/src/flow/nodes/async/index.ts +5 -0
  79. package/src/flow/nodes/await/advanced/index.ts +5 -0
  80. package/src/{advanced → flow/nodes/await/advanced}/resource.ts +37 -3
  81. package/src/{advanced → flow/nodes/await/advanced}/resourceAsync.ts +35 -3
  82. package/src/{advanced → flow/nodes/await/advanced}/stream.ts +40 -2
  83. package/src/{advanced → flow/nodes/await/advanced}/streamAsync.ts +38 -3
  84. package/src/flow/nodes/await/flowConstantAwait.ts +154 -0
  85. package/src/flow/nodes/await/flowDerivationAwait.ts +154 -0
  86. package/src/flow/nodes/await/flowNodeAwait.ts +508 -0
  87. package/src/flow/nodes/await/flowReadonlyAwait.ts +89 -0
  88. package/src/flow/nodes/await/flowStateAwait.ts +130 -0
  89. package/src/flow/nodes/await/index.ts +5 -0
  90. package/src/flow/nodes/index.ts +3 -0
  91. package/src/flow/nodes/sync/flowConstant.ts +111 -0
  92. package/src/flow/nodes/sync/flowDerivation.ts +105 -0
  93. package/src/flow/nodes/sync/flowNode.ts +439 -0
  94. package/src/flow/nodes/sync/flowReadonly.ts +57 -0
  95. package/src/flow/nodes/sync/flowState.ts +101 -0
  96. package/src/flow/nodes/sync/index.ts +5 -0
  97. package/src/index.ts +1 -47
  98. package/src/solid/converters.ts +59 -198
  99. package/src/solid/primitives.ts +4 -0
  100. package/test/base/flowEffect.test.ts +108 -0
  101. package/test/base/flowGraph.test.ts +485 -0
  102. package/test/base/flowSignal.test.ts +372 -0
  103. package/test/collections/flowArray.asyncStates.test.ts +1553 -0
  104. package/test/collections/flowArray.scalars.test.ts +1129 -0
  105. package/test/collections/flowArray.states.test.ts +1365 -0
  106. package/test/collections/flowMap.asyncStates.test.ts +1105 -0
  107. package/test/collections/flowMap.scalars.test.ts +877 -0
  108. package/test/collections/flowMap.states.test.ts +1097 -0
  109. package/test/nodes/async/flowConstantAsync.test.ts +860 -0
  110. package/test/nodes/async/flowDerivationAsync.test.ts +1517 -0
  111. package/test/nodes/async/flowStateAsync.test.ts +1387 -0
  112. package/test/{resource.test.ts → nodes/await/advanced/resource.test.ts} +21 -19
  113. package/test/{resourceAsync.test.ts → nodes/await/advanced/resourceAsync.test.ts} +3 -1
  114. package/test/{stream.test.ts → nodes/await/advanced/stream.test.ts} +30 -28
  115. package/test/{streamAsync.test.ts → nodes/await/advanced/streamAsync.test.ts} +16 -14
  116. package/test/nodes/await/flowConstantAwait.test.ts +643 -0
  117. package/test/nodes/await/flowDerivationAwait.test.ts +1583 -0
  118. package/test/nodes/await/flowStateAwait.test.ts +999 -0
  119. package/test/nodes/mixed/derivation.test.ts +1527 -0
  120. package/test/nodes/sync/flowConstant.test.ts +620 -0
  121. package/test/nodes/sync/flowDerivation.test.ts +1373 -0
  122. package/test/nodes/sync/flowState.test.ts +945 -0
  123. package/test/solid/converters.test.ts +721 -0
  124. package/test/solid/primitives.test.ts +1031 -0
  125. package/tsconfig.json +2 -1
  126. package/vitest.config.ts +7 -1
  127. package/IMPLEMENTATION_GUIDE.md +0 -1578
  128. package/dist/types/advanced/array.d.ts.map +0 -1
  129. package/dist/types/advanced/index.d.ts +0 -9
  130. package/dist/types/advanced/index.d.ts.map +0 -1
  131. package/dist/types/advanced/map.d.ts +0 -166
  132. package/dist/types/advanced/map.d.ts.map +0 -1
  133. package/dist/types/advanced/resource.d.ts +0 -78
  134. package/dist/types/advanced/resource.d.ts.map +0 -1
  135. package/dist/types/advanced/resourceAsync.d.ts +0 -56
  136. package/dist/types/advanced/resourceAsync.d.ts.map +0 -1
  137. package/dist/types/advanced/stream.d.ts +0 -117
  138. package/dist/types/advanced/stream.d.ts.map +0 -1
  139. package/dist/types/advanced/streamAsync.d.ts +0 -97
  140. package/dist/types/advanced/streamAsync.d.ts.map +0 -1
  141. package/dist/types/basic/constant.d.ts +0 -60
  142. package/dist/types/basic/constant.d.ts.map +0 -1
  143. package/dist/types/basic/derivation.d.ts +0 -89
  144. package/dist/types/basic/derivation.d.ts.map +0 -1
  145. package/dist/types/basic/disposable.d.ts +0 -82
  146. package/dist/types/basic/disposable.d.ts.map +0 -1
  147. package/dist/types/basic/effect.d.ts +0 -67
  148. package/dist/types/basic/effect.d.ts.map +0 -1
  149. package/dist/types/basic/index.d.ts +0 -10
  150. package/dist/types/basic/index.d.ts.map +0 -1
  151. package/dist/types/basic/observable.d.ts +0 -83
  152. package/dist/types/basic/observable.d.ts.map +0 -1
  153. package/dist/types/basic/signal.d.ts +0 -69
  154. package/dist/types/basic/signal.d.ts.map +0 -1
  155. package/dist/types/basic/state.d.ts +0 -47
  156. package/dist/types/basic/state.d.ts.map +0 -1
  157. package/dist/types/basic/trackingContext.d.ts +0 -33
  158. package/dist/types/basic/trackingContext.d.ts.map +0 -1
  159. package/dist/types/creators.d.ts +0 -340
  160. package/dist/types/creators.d.ts.map +0 -1
  161. package/src/advanced/array.ts +0 -222
  162. package/src/advanced/index.ts +0 -12
  163. package/src/advanced/map.ts +0 -193
  164. package/src/basic/constant.ts +0 -97
  165. package/src/basic/derivation.ts +0 -147
  166. package/src/basic/disposable.ts +0 -86
  167. package/src/basic/effect.ts +0 -104
  168. package/src/basic/index.ts +0 -9
  169. package/src/basic/observable.ts +0 -109
  170. package/src/basic/signal.ts +0 -145
  171. package/src/basic/state.ts +0 -60
  172. package/src/basic/trackingContext.ts +0 -45
  173. package/src/creators.ts +0 -395
  174. package/test/array.test.ts +0 -600
  175. package/test/constant.test.ts +0 -44
  176. package/test/derivation.test.ts +0 -539
  177. package/test/effect.test.ts +0 -29
  178. package/test/map.test.ts +0 -240
  179. package/test/signal.test.ts +0 -72
  180. package/test/state.test.ts +0 -212
package/test/map.test.ts DELETED
@@ -1,240 +0,0 @@
1
- import { describe, expect, test, vi } from "vitest";
2
- import { effect, type FlowState, map, state } from "#package";
3
-
4
- describe("map", () => {
5
- test("is initialized", () => {
6
- const $map = map({
7
- key1: 1,
8
- key2: 2,
9
- key3: 3,
10
- });
11
-
12
- expect(Array.from($map.pick().entries())).toEqual([
13
- ["key1", 1],
14
- ["key2", 2],
15
- ["key3", 3],
16
- ]);
17
- });
18
-
19
- test("is updated", () => {
20
- const $map = map();
21
-
22
- expect(Array.from($map.pick().entries())).toEqual([]);
23
-
24
- $map.add("key1", 1);
25
- expect($map.pick().get("key1")).toBe(1);
26
- expect($map.$lastAdded.pick()).toEqual({ key: "key1", value: 1 });
27
-
28
- $map.add("key2", 2);
29
- expect($map.pick().get("key1")).toBe(1);
30
- expect($map.pick().get("key2")).toBe(2);
31
- expect($map.$lastAdded.pick()).toEqual({ key: "key2", value: 2 });
32
-
33
- $map.update("key1", 3);
34
- expect($map.pick().get("key1")).toBe(3);
35
- expect($map.pick().get("key2")).toBe(2);
36
- expect($map.$lastUpdated.pick()).toEqual({ key: "key1", value: 3 });
37
-
38
- $map.delete("key1");
39
- expect($map.pick().get("key1")).toBe(undefined);
40
- expect($map.pick().get("key2")).toBe(2);
41
- expect($map.$lastDeleted.pick()).toEqual({ key: "key1", value: 3 });
42
- });
43
-
44
- test("get throws when disposed", () => {
45
- const $map = map({ key1: 1, key2: 2, key3: 3 });
46
- $map.dispose();
47
- expect(() => $map.pick()).toThrowError("[PicoFlow] Primitive is disposed");
48
- });
49
-
50
- test("add throws when disposed", () => {
51
- const $map = map<string, number>();
52
- $map.dispose();
53
- expect(() => $map.add("key1", 2)).toThrowError(
54
- "[PicoFlow] Primitive is disposed",
55
- );
56
- });
57
-
58
- test("update throws when disposed", () => {
59
- const $map = map<string, number>();
60
- $map.add("key1", 1);
61
- $map.dispose();
62
- expect(() => $map.update("key1", 2)).toThrowError(
63
- "[PicoFlow] Primitive is disposed",
64
- );
65
- });
66
-
67
- test("delete throws when disposed", () => {
68
- const $map = map<string, number>({ key1: 1, key2: 2, key3: 3 });
69
- $map.dispose();
70
- expect(() => $map.delete("key1")).toThrowError(
71
- "[PicoFlow] Primitive is disposed",
72
- );
73
- });
74
-
75
- test("add throws when key already exists", () => {
76
- const $map = map<string, number>();
77
- $map.add("key1", 1);
78
- expect(() => $map.add("key1", 2)).toThrowError(
79
- "[PicoFlow] Key already exists",
80
- );
81
- });
82
-
83
- test("update throws when key does not exist", () => {
84
- const $map = map<string, number>();
85
- expect(() => $map.update("key1", 1)).toThrowError(
86
- "[PicoFlow] Key does not exist",
87
- );
88
- });
89
-
90
- test("dispose disposes map values that are disposable", () => {
91
- const $map = map<string, FlowState<number>>();
92
- const $value1 = state(1);
93
- const $value2 = state(2);
94
- const $value3 = state(3);
95
-
96
- $map.add("key1", $value1);
97
- $map.add("key2", $value2);
98
- $map.add("key3", $value3);
99
-
100
- expect($value1.disposed).toBe(false);
101
- expect($value2.disposed).toBe(false);
102
- expect($value3.disposed).toBe(false);
103
-
104
- $map.dispose();
105
-
106
- expect($value1.disposed).toBe(true);
107
- expect($value2.disposed).toBe(true);
108
- expect($value3.disposed).toBe(true);
109
- });
110
-
111
- test("dispose clears the map after disposing values", () => {
112
- const $map = map<string, FlowState<number>>();
113
- const $value1 = state(1);
114
- const $value2 = state(2);
115
-
116
- $map.add("key1", $value1);
117
- $map.add("key2", $value2);
118
-
119
- expect($map.pick().size).toBe(2);
120
-
121
- $map.dispose();
122
-
123
- // Map is cleared during disposal, but we can't verify after disposal
124
- // since pick() will throw. We verify the values were disposed instead.
125
- expect($value1.disposed).toBe(true);
126
- expect($value2.disposed).toBe(true);
127
- });
128
-
129
- test("dispose handles non-disposable values gracefully", () => {
130
- const $map = map<string, number>();
131
- $map.add("key1", 1);
132
- $map.add("key2", 2);
133
- $map.add("key3", 3);
134
-
135
- expect($map.pick().size).toBe(3);
136
-
137
- // Should not throw even with non-disposable values
138
- expect(() => $map.dispose()).not.toThrow();
139
- });
140
-
141
- test("dispose passes options to value disposal", () => {
142
- const $map = map<string, FlowState<number>>();
143
- const $value1 = state(1);
144
- const $value2 = state(2);
145
-
146
- $map.add("key1", $value1);
147
- $map.add("key2", $value2);
148
-
149
- // Create an effect that depends on value1
150
- const fx = effect((t) => {
151
- $value1.get(t);
152
- });
153
-
154
- expect(fx.disposed).toBe(false);
155
-
156
- // Dispose with self: true - should only dispose the map and values, not dependent effects
157
- $map.dispose({ self: true });
158
-
159
- expect($value1.disposed).toBe(true);
160
- expect($value2.disposed).toBe(true);
161
- // Effect should still be active since we used self: true
162
- expect(fx.disposed).toBe(false);
163
-
164
- fx.dispose();
165
- });
166
- });
167
-
168
- describe("effect", () => {
169
- test("called when map is updated", () => {
170
- const $map = map();
171
- const onSetFn = vi.fn();
172
- const onAddFn = vi.fn();
173
- const onUpdateFn = vi.fn();
174
- const onDeleteFn = vi.fn();
175
-
176
- effect((t) => onSetFn($map.get(t)));
177
- effect((t) => onAddFn($map.$lastAdded.get(t)));
178
- effect((t) => onUpdateFn($map.$lastUpdated.get(t)));
179
- effect((t) => onDeleteFn($map.$lastDeleted.get(t)));
180
-
181
- expect(onSetFn).toHaveBeenCalledTimes(1);
182
- expect(onSetFn).toHaveBeenLastCalledWith(new Map());
183
- expect(onAddFn).toHaveBeenCalledTimes(1);
184
- expect(onAddFn).toHaveBeenLastCalledWith(null);
185
- expect(onUpdateFn).toHaveBeenCalledTimes(1);
186
- expect(onUpdateFn).toHaveBeenLastCalledWith(null);
187
- expect(onDeleteFn).toHaveBeenCalledTimes(1);
188
- expect(onDeleteFn).toHaveBeenLastCalledWith(null);
189
-
190
- $map.add("key1", 1);
191
- expect(onSetFn).toHaveBeenCalledTimes(2);
192
- expect(onSetFn).toHaveBeenLastCalledWith(new Map([["key1", 1]]));
193
- expect(onAddFn).toHaveBeenCalledTimes(2);
194
- expect(onAddFn).toHaveBeenLastCalledWith({ key: "key1", value: 1 });
195
- expect(onUpdateFn).toHaveBeenCalledTimes(1);
196
- expect(onUpdateFn).toHaveBeenLastCalledWith(null);
197
- expect(onDeleteFn).toHaveBeenCalledTimes(1);
198
- expect(onDeleteFn).toHaveBeenLastCalledWith(null);
199
-
200
- $map.add("key2", 2);
201
- expect(onSetFn).toHaveBeenCalledTimes(3);
202
- expect(onSetFn).toHaveBeenLastCalledWith(
203
- new Map([
204
- ["key1", 1],
205
- ["key2", 2],
206
- ]),
207
- );
208
- expect(onAddFn).toHaveBeenCalledTimes(3);
209
- expect(onAddFn).toHaveBeenLastCalledWith({ key: "key2", value: 2 });
210
- expect(onUpdateFn).toHaveBeenCalledTimes(1);
211
- expect(onUpdateFn).toHaveBeenLastCalledWith(null);
212
- expect(onDeleteFn).toHaveBeenCalledTimes(1);
213
- expect(onDeleteFn).toHaveBeenLastCalledWith(null);
214
-
215
- $map.update("key1", 3);
216
- expect(onSetFn).toHaveBeenCalledTimes(4);
217
- expect(onSetFn).toHaveBeenLastCalledWith(
218
- new Map([
219
- ["key1", 3],
220
- ["key2", 2],
221
- ]),
222
- );
223
- expect(onAddFn).toHaveBeenCalledTimes(3);
224
- expect(onAddFn).toHaveBeenLastCalledWith({ key: "key2", value: 2 });
225
- expect(onUpdateFn).toHaveBeenCalledTimes(2);
226
- expect(onUpdateFn).toHaveBeenLastCalledWith({ key: "key1", value: 3 });
227
- expect(onDeleteFn).toHaveBeenCalledTimes(1);
228
- expect(onDeleteFn).toHaveBeenLastCalledWith(null);
229
-
230
- $map.delete("key1");
231
- expect(onSetFn).toHaveBeenCalledTimes(5);
232
- expect(onSetFn).toHaveBeenLastCalledWith(new Map([["key2", 2]]));
233
- expect(onAddFn).toHaveBeenCalledTimes(3);
234
- expect(onAddFn).toHaveBeenLastCalledWith({ key: "key2", value: 2 });
235
- expect(onUpdateFn).toHaveBeenCalledTimes(2);
236
- expect(onUpdateFn).toHaveBeenLastCalledWith({ key: "key1", value: 3 });
237
- expect(onDeleteFn).toHaveBeenCalledTimes(2);
238
- expect(onDeleteFn).toHaveBeenLastCalledWith({ key: "key1", value: 3 });
239
- });
240
- });
@@ -1,72 +0,0 @@
1
- import { describe, expect, test, vi } from "vitest";
2
- import { effect, signal } from "#package";
3
-
4
- describe("signal", () => {
5
- test("disposed is correct", () => {
6
- const $signal = signal();
7
- expect($signal.disposed).toBe(false);
8
- $signal.dispose();
9
- expect($signal.disposed).toBe(true);
10
- });
11
-
12
- test("throws when disposed", () => {
13
- const $signal = signal();
14
- const effectFn = vi.fn();
15
- effect((t) => {
16
- $signal.watch(t);
17
- effectFn();
18
- });
19
-
20
- expect(effectFn).toHaveBeenCalledTimes(1);
21
-
22
- $signal.trigger();
23
- expect(effectFn).toHaveBeenCalledTimes(2);
24
-
25
- $signal.dispose();
26
- expect(() => $signal.trigger()).toThrow("[PicoFlow] Primitive is disposed");
27
- });
28
-
29
- test("throws when disposed twice", () => {
30
- const $signal = signal();
31
- $signal.dispose();
32
- expect(() => $signal.dispose()).toThrow("[PicoFlow] Primitive is disposed");
33
- });
34
- });
35
-
36
- describe("effect", () => {
37
- test("called when signal triggered", () => {
38
- const $signal = signal();
39
- const effectFn = vi.fn();
40
- effect((t) => {
41
- $signal.watch(t);
42
- effectFn();
43
- });
44
-
45
- expect(effectFn).toHaveBeenCalledTimes(1);
46
-
47
- $signal.trigger();
48
- expect(effectFn).toHaveBeenCalledTimes(2);
49
-
50
- $signal.trigger();
51
- expect(effectFn).toHaveBeenCalledTimes(3);
52
- });
53
-
54
- test("NOT called when disposed", () => {
55
- const $signal = signal();
56
- const effectFn = vi.fn();
57
- const $effect = effect((t) => {
58
- $signal.watch(t);
59
- effectFn();
60
- });
61
-
62
- expect(effectFn).toHaveBeenCalledTimes(1);
63
-
64
- $signal.trigger();
65
- expect(effectFn).toHaveBeenCalledTimes(2);
66
-
67
- $effect.dispose();
68
-
69
- $signal.trigger();
70
- expect(effectFn).toHaveBeenCalledTimes(2);
71
- });
72
- });
@@ -1,212 +0,0 @@
1
- import { describe, expect, test, vi } from "vitest";
2
- import { effect, state } from "#package";
3
-
4
- describe("state", () => {
5
- test("is initialized", () => {
6
- const $state = state(1);
7
- expect($state.pick()).toBe(1);
8
- });
9
-
10
- test("is lazy initialized", () => {
11
- const $state = state(() => 1);
12
- expect($state.pick()).toBe(1);
13
- });
14
-
15
- test("is updated", () => {
16
- const $state = state(1);
17
- expect($state.pick()).toBe(1);
18
-
19
- $state.set(2);
20
- expect($state.pick()).toBe(2);
21
- });
22
-
23
- test("is updated from current", () => {
24
- const $state = state(1);
25
- expect($state.pick()).toBe(1);
26
-
27
- $state.set((state) => state + 1);
28
- expect($state.pick()).toBe(2);
29
- });
30
-
31
- test("set throws when disposed", () => {
32
- const $state = state(1);
33
-
34
- expect($state.pick()).toBe(1);
35
-
36
- $state.set(2);
37
- expect($state.pick()).toBe(2);
38
-
39
- $state.dispose();
40
-
41
- expect(() => $state.set(3)).toThrow("[PicoFlow] Primitive is disposed");
42
- });
43
-
44
- test("get throws when disposed", () => {
45
- const $state = state(1);
46
-
47
- expect($state.pick()).toBe(1);
48
-
49
- $state.set(2);
50
- expect($state.pick()).toBe(2);
51
-
52
- $state.dispose();
53
-
54
- expect(() => $state.pick()).toThrow("[PicoFlow] Primitive is disposed");
55
- });
56
- });
57
-
58
- describe("effect", () => {
59
- test("called with init value", () => {
60
- const $state = state(1);
61
- const effectFn = vi.fn();
62
- effect((t) => effectFn($state.get(t)));
63
-
64
- expect(effectFn).toHaveBeenCalledTimes(1);
65
- expect(effectFn).toHaveBeenLastCalledWith(1);
66
- });
67
-
68
- test("called with lazy init value", () => {
69
- const $state = state(() => 1);
70
- const effectFn = vi.fn();
71
- effect((t) => effectFn($state.get(t)));
72
-
73
- expect(effectFn).toHaveBeenCalledTimes(1);
74
- expect(effectFn).toHaveBeenLastCalledWith(1);
75
- });
76
-
77
- test("called when updated", () => {
78
- const $state = state(1);
79
- const effectFn = vi.fn();
80
- effect((t) => effectFn($state.get(t)));
81
-
82
- expect(effectFn).toHaveBeenCalledTimes(1);
83
- expect(effectFn).toHaveBeenLastCalledWith(1);
84
-
85
- $state.set(2);
86
- expect(effectFn).toHaveBeenCalledTimes(2);
87
- expect(effectFn).toHaveBeenLastCalledWith(2);
88
- });
89
-
90
- test("NOT called when updated with the same value", () => {
91
- const $state = state(1);
92
- const effectFn = vi.fn();
93
- effect((t) => effectFn($state.get(t)));
94
-
95
- expect(effectFn).toHaveBeenCalledTimes(1);
96
- expect(effectFn).toHaveBeenLastCalledWith(1);
97
-
98
- $state.set(2);
99
- expect(effectFn).toHaveBeenCalledTimes(2);
100
- expect(effectFn).toHaveBeenLastCalledWith(2);
101
-
102
- $state.set(2);
103
- expect(effectFn).toHaveBeenCalledTimes(2);
104
- expect(effectFn).toHaveBeenLastCalledWith(2);
105
- });
106
-
107
- test("NOT called when disposed", () => {
108
- const $state = state(1);
109
- const effectFn = vi.fn();
110
- const $effect = effect((t) => effectFn($state.get(t)));
111
-
112
- expect(effectFn).toHaveBeenCalledTimes(1);
113
- expect(effectFn).toHaveBeenLastCalledWith(1);
114
-
115
- $state.set(2);
116
- expect(effectFn).toHaveBeenCalledTimes(2);
117
- expect(effectFn).toHaveBeenLastCalledWith(2);
118
-
119
- $effect.dispose();
120
-
121
- $state.set(3);
122
- expect(effectFn).toHaveBeenCalledTimes(2);
123
- expect(effectFn).toHaveBeenLastCalledWith(2);
124
- });
125
-
126
- test("nested states", () => {
127
- const $stateA = state(1);
128
- const $stateB = state(2);
129
- const $stateC = state({
130
- a: $stateA,
131
- b: $stateB,
132
- });
133
-
134
- const effectFn = vi.fn();
135
- effect((t) => {
136
- const a = $stateC.get(t).a.get(t);
137
- effectFn(a);
138
- });
139
-
140
- expect(effectFn).toHaveBeenCalledTimes(1);
141
- expect(effectFn).toHaveBeenLastCalledWith(1);
142
- });
143
- });
144
-
145
- describe("subscribe", () => {
146
- test("called with init value", () => {
147
- const $state = state(1);
148
- const effectFn = vi.fn();
149
- $state.subscribe((value) => effectFn(value));
150
-
151
- expect(effectFn).toHaveBeenCalledTimes(1);
152
- expect(effectFn).toHaveBeenLastCalledWith(1);
153
- });
154
-
155
- test("called with lazy init value", () => {
156
- const $state = state(() => 1);
157
- const effectFn = vi.fn();
158
- $state.subscribe((value) => effectFn(value));
159
-
160
- expect(effectFn).toHaveBeenCalledTimes(1);
161
- expect(effectFn).toHaveBeenLastCalledWith(1);
162
- });
163
-
164
- test("called when updated", () => {
165
- const $state = state(1);
166
- const effectFn = vi.fn();
167
- $state.subscribe((value) => effectFn(value));
168
-
169
- expect(effectFn).toHaveBeenCalledTimes(1);
170
- expect(effectFn).toHaveBeenLastCalledWith(1);
171
-
172
- $state.set(2);
173
- expect(effectFn).toHaveBeenCalledTimes(2);
174
- expect(effectFn).toHaveBeenLastCalledWith(2);
175
- });
176
-
177
- test("NOT called when updated with the same value", () => {
178
- const $state = state(1);
179
- const effectFn = vi.fn();
180
- $state.subscribe((value) => effectFn(value));
181
-
182
- expect(effectFn).toHaveBeenCalledTimes(1);
183
- expect(effectFn).toHaveBeenLastCalledWith(1);
184
-
185
- $state.set(2);
186
- expect(effectFn).toHaveBeenCalledTimes(2);
187
- expect(effectFn).toHaveBeenLastCalledWith(2);
188
-
189
- $state.set(2);
190
- expect(effectFn).toHaveBeenCalledTimes(2);
191
- expect(effectFn).toHaveBeenLastCalledWith(2);
192
- });
193
-
194
- test("NOT called when disposed", () => {
195
- const $state = state(1);
196
- const effectFn = vi.fn();
197
- const unsubscribe = $state.subscribe((value) => effectFn(value));
198
-
199
- expect(effectFn).toHaveBeenCalledTimes(1);
200
- expect(effectFn).toHaveBeenLastCalledWith(1);
201
-
202
- $state.set(2);
203
- expect(effectFn).toHaveBeenCalledTimes(2);
204
- expect(effectFn).toHaveBeenLastCalledWith(2);
205
-
206
- unsubscribe();
207
-
208
- $state.set(3);
209
- expect(effectFn).toHaveBeenCalledTimes(2);
210
- expect(effectFn).toHaveBeenLastCalledWith(2);
211
- });
212
- });