@ersbeth/picoflow 0.0.1 → 0.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 (143) hide show
  1. package/api/doc/index.md +1 -1
  2. package/api/doc/picoflow.constant.md +55 -0
  3. package/api/doc/picoflow.derivation.md +1 -1
  4. package/api/doc/picoflow.effect.md +1 -1
  5. package/api/doc/picoflow.flowconstant._constructor_.md +49 -0
  6. package/api/doc/picoflow.flowconstant.get.md +25 -0
  7. package/api/doc/picoflow.flowconstant.md +88 -0
  8. package/api/doc/picoflow.flowderivation._constructor_.md +2 -2
  9. package/api/doc/picoflow.flowderivation.get.md +2 -2
  10. package/api/doc/picoflow.flowderivation.md +2 -2
  11. package/api/doc/picoflow.floweffect._constructor_.md +7 -2
  12. package/api/doc/picoflow.floweffect.dispose.md +3 -3
  13. package/api/doc/picoflow.floweffect.disposed.md +1 -1
  14. package/api/doc/picoflow.floweffect.md +4 -4
  15. package/api/doc/picoflow.flowgetter.md +2 -2
  16. package/api/doc/picoflow.flowmap._lastdeleted.md +1 -1
  17. package/api/doc/picoflow.flowmap._lastset.md +1 -1
  18. package/api/doc/picoflow.flowmap.delete.md +6 -2
  19. package/api/doc/picoflow.flowmap.md +5 -7
  20. package/api/doc/picoflow.flowmap.setat.md +6 -2
  21. package/api/doc/picoflow.flowobservable.get.md +3 -3
  22. package/api/doc/picoflow.flowobservable.md +18 -4
  23. package/api/doc/picoflow.flowobservable.subscribe.md +55 -0
  24. package/api/doc/picoflow.flowresource._constructor_.md +2 -18
  25. package/api/doc/picoflow.flowresource.fetch.md +1 -1
  26. package/api/doc/picoflow.flowresource.get.md +4 -4
  27. package/api/doc/picoflow.flowresource.md +4 -4
  28. package/api/doc/picoflow.flowresourceasync._constructor_.md +49 -0
  29. package/api/doc/picoflow.flowresourceasync.fetch.md +27 -0
  30. package/api/doc/picoflow.flowresourceasync.get.md +23 -0
  31. package/api/doc/picoflow.flowresourceasync.md +100 -0
  32. package/api/doc/picoflow.flowsignal.dispose.md +3 -7
  33. package/api/doc/picoflow.flowsignal.disposed.md +2 -2
  34. package/api/doc/picoflow.flowsignal.md +5 -5
  35. package/api/doc/picoflow.flowsignal.trigger.md +3 -7
  36. package/api/doc/picoflow.flowstate.md +4 -52
  37. package/api/doc/picoflow.flowstate.set.md +5 -5
  38. package/api/doc/picoflow.flowstream._constructor_.md +3 -19
  39. package/api/doc/picoflow.flowstream.dispose.md +1 -1
  40. package/api/doc/picoflow.flowstream.get.md +4 -4
  41. package/api/doc/picoflow.flowstream.md +5 -5
  42. package/api/doc/picoflow.flowstreamasync._constructor_.md +54 -0
  43. package/api/doc/picoflow.flowstreamasync.dispose.md +21 -0
  44. package/api/doc/picoflow.flowstreamasync.get.md +23 -0
  45. package/api/doc/picoflow.flowstreamasync.md +100 -0
  46. package/api/doc/picoflow.flowstreamdisposer.md +13 -0
  47. package/api/doc/picoflow.flowstreamsetter.md +13 -0
  48. package/api/doc/picoflow.flowstreamupdater.md +19 -0
  49. package/api/doc/picoflow.flowwatcher.md +1 -1
  50. package/api/doc/picoflow.map.md +1 -1
  51. package/api/doc/picoflow.md +80 -14
  52. package/api/doc/picoflow.resource.md +2 -18
  53. package/api/doc/picoflow.resourceasync.md +55 -0
  54. package/api/doc/picoflow.signal.md +1 -1
  55. package/api/doc/picoflow.state.md +3 -3
  56. package/api/doc/picoflow.stream.md +2 -18
  57. package/api/doc/picoflow.streamasync.md +55 -0
  58. package/api/picoflow.public.api.md +131 -0
  59. package/api-extractor.json +2 -1
  60. package/dist/picoflow.js +326 -302
  61. package/dist/types/advanced/index.d.ts +7 -0
  62. package/dist/types/advanced/index.d.ts.map +1 -0
  63. package/dist/types/{map.d.ts → advanced/map.d.ts} +12 -12
  64. package/dist/types/advanced/map.d.ts.map +1 -0
  65. package/dist/types/advanced/resource.d.ts +39 -0
  66. package/dist/types/advanced/resource.d.ts.map +1 -0
  67. package/dist/types/{resource.d.ts → advanced/resourceAsync.d.ts} +6 -11
  68. package/dist/types/advanced/resourceAsync.d.ts.map +1 -0
  69. package/dist/types/advanced/stream.d.ts +59 -0
  70. package/dist/types/advanced/stream.d.ts.map +1 -0
  71. package/dist/types/advanced/streamAsync.d.ts +43 -0
  72. package/dist/types/advanced/streamAsync.d.ts.map +1 -0
  73. package/dist/types/basic/constant.d.ts +32 -0
  74. package/dist/types/basic/constant.d.ts.map +1 -0
  75. package/dist/types/basic/derivation.d.ts +40 -0
  76. package/dist/types/basic/derivation.d.ts.map +1 -0
  77. package/dist/types/basic/effect.d.ts +56 -0
  78. package/dist/types/basic/effect.d.ts.map +1 -0
  79. package/dist/types/basic/index.d.ts +9 -0
  80. package/dist/types/basic/index.d.ts.map +1 -0
  81. package/dist/types/basic/observable.d.ts +34 -0
  82. package/dist/types/basic/observable.d.ts.map +1 -0
  83. package/dist/types/basic/signal.d.ts +37 -0
  84. package/dist/types/basic/signal.d.ts.map +1 -0
  85. package/dist/types/basic/state.d.ts +26 -0
  86. package/dist/types/basic/state.d.ts.map +1 -0
  87. package/dist/types/creators.d.ts +29 -13
  88. package/dist/types/creators.d.ts.map +1 -1
  89. package/dist/types/index.d.ts +3 -9
  90. package/dist/types/index.d.ts.map +1 -1
  91. package/package.json +1 -1
  92. package/src/advanced/index.ts +10 -0
  93. package/src/{map.ts → advanced/map.ts} +14 -14
  94. package/src/advanced/resource.ts +56 -0
  95. package/src/{resource.ts → advanced/resourceAsync.ts} +9 -16
  96. package/src/advanced/stream.ts +87 -0
  97. package/src/advanced/streamAsync.ts +82 -0
  98. package/src/basic/constant.ts +64 -0
  99. package/src/basic/derivation.ts +86 -0
  100. package/src/basic/effect.ts +96 -0
  101. package/src/basic/index.ts +8 -0
  102. package/src/basic/observable.ts +51 -0
  103. package/src/basic/signal.ts +105 -0
  104. package/src/basic/state.ts +39 -0
  105. package/src/creators.ts +54 -15
  106. package/src/index.ts +21 -11
  107. package/test/constant.test.ts +46 -0
  108. package/test/derivation.test.ts +30 -6
  109. package/test/effect.test.ts +29 -0
  110. package/test/map.test.ts +38 -0
  111. package/test/resource.test.ts +18 -16
  112. package/test/resourceAsync.test.ts +108 -0
  113. package/test/signal.test.ts +18 -1
  114. package/test/state.test.ts +107 -2
  115. package/test/stream.test.ts +38 -13
  116. package/test/streamAsync.test.ts +194 -0
  117. package/tsconfig.json +3 -1
  118. package/api/doc/picoflow.flowdisposer.md +0 -13
  119. package/api/doc/picoflow.flowsetter.md +0 -13
  120. package/api/doc/picoflow.flowstate._constructor_.md +0 -49
  121. package/api/doc/picoflow.flowstate.get.md +0 -23
  122. package/api/doc/picoflow.flowupdater.md +0 -19
  123. package/api/picoflow.api.md +0 -145
  124. package/dist/types/derivation.d.ts +0 -58
  125. package/dist/types/derivation.d.ts.map +0 -1
  126. package/dist/types/effect.d.ts +0 -108
  127. package/dist/types/effect.d.ts.map +0 -1
  128. package/dist/types/map.d.ts.map +0 -1
  129. package/dist/types/observable.d.ts +0 -40
  130. package/dist/types/observable.d.ts.map +0 -1
  131. package/dist/types/resource.d.ts.map +0 -1
  132. package/dist/types/signal.d.ts +0 -111
  133. package/dist/types/signal.d.ts.map +0 -1
  134. package/dist/types/state.d.ts +0 -39
  135. package/dist/types/state.d.ts.map +0 -1
  136. package/dist/types/stream.d.ts +0 -71
  137. package/dist/types/stream.d.ts.map +0 -1
  138. package/src/derivation.ts +0 -96
  139. package/src/effect.ts +0 -152
  140. package/src/observable.ts +0 -50
  141. package/src/signal.ts +0 -166
  142. package/src/state.ts +0 -52
  143. package/src/stream.ts +0 -99
@@ -0,0 +1,108 @@
1
+ import { describe, expect, test, vi } from "vitest";
2
+ import { effect, resourceAsync } from "#package";
3
+
4
+ describe("resourceAsync", () => {
5
+ test("is updated", async () => {
6
+ let resourceCounter = 0;
7
+ const fetchResource = async () => {
8
+ resourceCounter++;
9
+ return resourceCounter;
10
+ };
11
+
12
+ const $resource = resourceAsync(fetchResource);
13
+ expect(await $resource.get()).toBe(1);
14
+
15
+ $resource.fetch();
16
+ expect(await $resource.get()).toBe(2);
17
+
18
+ $resource.fetch();
19
+ expect(await $resource.get()).toBe(3);
20
+ });
21
+
22
+ test("fetch throws when disposed", async () => {
23
+ let resourceCounter = 0;
24
+ const fetchResource = async () => {
25
+ resourceCounter++;
26
+ return resourceCounter;
27
+ };
28
+
29
+ const $resource = resourceAsync(fetchResource);
30
+ expect(await $resource.get()).toBe(1);
31
+
32
+ $resource.fetch();
33
+ expect(await $resource.get()).toBe(2);
34
+
35
+ $resource.dispose();
36
+ await expect(() => $resource.fetch()).rejects.toThrow(
37
+ "[PicoFlow] Primitive is disposed",
38
+ );
39
+ });
40
+
41
+ test("get throws when disposed", async () => {
42
+ let resourceCounter = 0;
43
+ const fetchResource = async () => {
44
+ resourceCounter++;
45
+ return resourceCounter;
46
+ };
47
+
48
+ const $resource = resourceAsync(fetchResource);
49
+ expect(await $resource.get()).toBe(1);
50
+
51
+ $resource.fetch();
52
+ expect(await $resource.get()).toBe(2);
53
+
54
+ $resource.dispose();
55
+ expect(() => $resource.get()).toThrow(
56
+ "[PicoFlow] Primitive is disposed",
57
+ );
58
+ });
59
+ });
60
+
61
+ describe("effect", () => {
62
+ test("called when resource updated", async () => {
63
+ let resourceCounter = 0;
64
+ const fetchResource = async () => {
65
+ resourceCounter++;
66
+ return resourceCounter;
67
+ };
68
+
69
+ const $resource = resourceAsync(fetchResource);
70
+ const effectFn = vi.fn();
71
+ effect((get) => effectFn(get($resource)));
72
+
73
+ expect(effectFn).toHaveBeenCalledTimes(1);
74
+ expect(await effectFn.mock.calls[0][0]).toBe(1);
75
+
76
+ $resource.fetch();
77
+ expect(effectFn).toHaveBeenCalledTimes(2);
78
+ expect(await effectFn.mock.calls[1][0]).toBe(2);
79
+
80
+ await $resource.fetch();
81
+ expect(effectFn).toHaveBeenCalledTimes(3);
82
+ expect(await effectFn.mock.calls[2][0]).toBe(3);
83
+ });
84
+
85
+ test("NOT called when disposed", async () => {
86
+ let resourceCounter = 0;
87
+ const fetchResource = async () => {
88
+ resourceCounter++;
89
+ return resourceCounter;
90
+ };
91
+
92
+ const $resource = resourceAsync(fetchResource);
93
+ const effectFn = vi.fn();
94
+ const $effect = effect((get) => effectFn(get($resource)));
95
+
96
+ expect(effectFn).toHaveBeenCalledTimes(1);
97
+ expect(await effectFn.mock.calls[0][0]).toBe(1);
98
+
99
+ await $resource.fetch();
100
+ expect(effectFn).toHaveBeenCalledTimes(2);
101
+ expect(await effectFn.mock.calls[1][0]).toBe(2);
102
+
103
+ $effect.dispose();
104
+ await $resource.fetch();
105
+ expect(effectFn).toHaveBeenCalledTimes(2);
106
+ expect(await effectFn.mock.calls[1][0]).toBe(2);
107
+ });
108
+ });
@@ -2,6 +2,13 @@ import { describe, expect, test, vi } from "vitest";
2
2
  import { effect, signal } from "#package";
3
3
 
4
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
+
5
12
  test("throws when disposed", () => {
6
13
  const $signal = signal();
7
14
  const effectFn = vi.fn();
@@ -16,7 +23,17 @@ describe("signal", () => {
16
23
  expect(effectFn).toHaveBeenCalledTimes(2);
17
24
 
18
25
  $signal.dispose();
19
- expect(() => $signal.trigger()).toThrow("Signal is disposed");
26
+ expect(() => $signal.trigger()).toThrow(
27
+ "[PicoFlow] Primitive is disposed",
28
+ );
29
+ });
30
+
31
+ test("throws when disposed twice", () => {
32
+ const $signal = signal();
33
+ $signal.dispose();
34
+ expect(() => $signal.dispose()).toThrow(
35
+ "[PicoFlow] Primitive is disposed",
36
+ );
20
37
  });
21
38
  });
22
39
 
@@ -2,6 +2,16 @@ import { describe, expect, test, vi } from "vitest";
2
2
  import { effect, state } from "#package";
3
3
 
4
4
  describe("state", () => {
5
+ test("is initialized", () => {
6
+ const $state = state(1);
7
+ expect($state.get()).toBe(1);
8
+ });
9
+
10
+ test("is lazy initialized", () => {
11
+ const $state = state(() => 1);
12
+ expect($state.get()).toBe(1);
13
+ });
14
+
5
15
  test("is updated", () => {
6
16
  const $state = state(1);
7
17
  expect($state.get()).toBe(1);
@@ -10,6 +20,14 @@ describe("state", () => {
10
20
  expect($state.get()).toBe(2);
11
21
  });
12
22
 
23
+ test("is updated from current", () => {
24
+ const $state = state(1);
25
+ expect($state.get()).toBe(1);
26
+
27
+ $state.set((state) => state + 1);
28
+ expect($state.get()).toBe(2);
29
+ });
30
+
13
31
  test("set throws when disposed", () => {
14
32
  const $state = state(1);
15
33
 
@@ -20,7 +38,7 @@ describe("state", () => {
20
38
 
21
39
  $state.dispose();
22
40
 
23
- expect(() => $state.set(3)).toThrow("State is disposed");
41
+ expect(() => $state.set(3)).toThrow("[PicoFlow] Primitive is disposed");
24
42
  });
25
43
 
26
44
  test("get throws when disposed", () => {
@@ -33,11 +51,29 @@ describe("state", () => {
33
51
 
34
52
  $state.dispose();
35
53
 
36
- expect(() => $state.get()).toThrow("State is disposed");
54
+ expect(() => $state.get()).toThrow("[PicoFlow] Primitive is disposed");
37
55
  });
38
56
  });
39
57
 
40
58
  describe("effect", () => {
59
+ test("called with init value", () => {
60
+ const $state = state(1);
61
+ const effectFn = vi.fn();
62
+ effect((get) => effectFn(get($state)));
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((get) => effectFn(get($state)));
72
+
73
+ expect(effectFn).toHaveBeenCalledTimes(1);
74
+ expect(effectFn).toHaveBeenLastCalledWith(1);
75
+ });
76
+
41
77
  test("called when updated", () => {
42
78
  const $state = state(1);
43
79
  const effectFn = vi.fn();
@@ -87,3 +123,72 @@ describe("effect", () => {
87
123
  expect(effectFn).toHaveBeenLastCalledWith(2);
88
124
  });
89
125
  });
126
+
127
+ describe("subscribe", () => {
128
+ test("called with init value", () => {
129
+ const $state = state(1);
130
+ const effectFn = vi.fn();
131
+ $state.subscribe((value) => effectFn(value));
132
+
133
+ expect(effectFn).toHaveBeenCalledTimes(1);
134
+ expect(effectFn).toHaveBeenLastCalledWith(1);
135
+ });
136
+
137
+ test("called with lazy init value", () => {
138
+ const $state = state(() => 1);
139
+ const effectFn = vi.fn();
140
+ $state.subscribe((value) => effectFn(value));
141
+
142
+ expect(effectFn).toHaveBeenCalledTimes(1);
143
+ expect(effectFn).toHaveBeenLastCalledWith(1);
144
+ });
145
+
146
+ test("called when updated", () => {
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
+ $state.set(2);
155
+ expect(effectFn).toHaveBeenCalledTimes(2);
156
+ expect(effectFn).toHaveBeenLastCalledWith(2);
157
+ });
158
+
159
+ test("NOT called when updated with the same value", () => {
160
+ const $state = state(1);
161
+ const effectFn = vi.fn();
162
+ $state.subscribe((value) => effectFn(value));
163
+
164
+ expect(effectFn).toHaveBeenCalledTimes(1);
165
+ expect(effectFn).toHaveBeenLastCalledWith(1);
166
+
167
+ $state.set(2);
168
+ expect(effectFn).toHaveBeenCalledTimes(2);
169
+ expect(effectFn).toHaveBeenLastCalledWith(2);
170
+
171
+ $state.set(2);
172
+ expect(effectFn).toHaveBeenCalledTimes(2);
173
+ expect(effectFn).toHaveBeenLastCalledWith(2);
174
+ });
175
+
176
+ test("NOT called when disposed", () => {
177
+ const $state = state(1);
178
+ const effectFn = vi.fn();
179
+ const unsubscribe = $state.subscribe((value) => effectFn(value));
180
+
181
+ expect(effectFn).toHaveBeenCalledTimes(1);
182
+ expect(effectFn).toHaveBeenLastCalledWith(1);
183
+
184
+ $state.set(2);
185
+ expect(effectFn).toHaveBeenCalledTimes(2);
186
+ expect(effectFn).toHaveBeenLastCalledWith(2);
187
+
188
+ unsubscribe();
189
+
190
+ $state.set(3);
191
+ expect(effectFn).toHaveBeenCalledTimes(2);
192
+ expect(effectFn).toHaveBeenLastCalledWith(2);
193
+ });
194
+ });
@@ -19,9 +19,9 @@ describe("stream", () => {
19
19
  return () => {
20
20
  counter.callback = undefined;
21
21
  };
22
- }, counter.count);
22
+ });
23
23
 
24
- expect($stream.get()).toBe(0);
24
+ expect($stream.get()).toBe(undefined);
25
25
 
26
26
  counter.increment();
27
27
  expect($stream.get()).toBe(1);
@@ -40,9 +40,9 @@ describe("stream", () => {
40
40
  set(counter);
41
41
  }, 1000);
42
42
  return () => clearInterval(interval);
43
- }, 0);
43
+ });
44
44
 
45
- expect($stream.get()).toBe(0);
45
+ expect($stream.get()).toBe(undefined);
46
46
 
47
47
  vi.advanceTimersToNextTimer();
48
48
  expect($stream.get()).toBe(1);
@@ -61,9 +61,9 @@ describe("stream", () => {
61
61
  set(counter);
62
62
  }, 1000);
63
63
  return () => clearInterval(interval);
64
- }, 0);
64
+ });
65
65
 
66
- expect($stream.get()).toBe(0);
66
+ expect($stream.get()).toBe(undefined);
67
67
 
68
68
  vi.advanceTimersToNextTimer();
69
69
  expect($stream.get()).toBe(1);
@@ -73,7 +73,7 @@ describe("stream", () => {
73
73
 
74
74
  $stream.dispose();
75
75
  vi.advanceTimersToNextTimer();
76
- expect(() => $stream.get()).toThrow("Stream is disposed");
76
+ expect(() => $stream.get()).toThrow("[PicoFlow] Primitive is disposed");
77
77
  });
78
78
  });
79
79
 
@@ -88,13 +88,13 @@ describe("effect", () => {
88
88
  set(counter);
89
89
  }, 1000);
90
90
  return () => clearInterval(interval);
91
- }, 0);
91
+ });
92
92
 
93
93
  const effectFn = vi.fn();
94
94
  effect((get) => effectFn(get($stream)));
95
95
 
96
96
  expect(effectFn).toHaveBeenCalledTimes(1);
97
- expect(effectFn).toHaveBeenLastCalledWith(0);
97
+ expect(effectFn).toHaveBeenLastCalledWith(undefined);
98
98
 
99
99
  vi.advanceTimersToNextTimer();
100
100
  expect(effectFn).toHaveBeenCalledTimes(2);
@@ -105,6 +105,31 @@ describe("effect", () => {
105
105
  expect(effectFn).toHaveBeenLastCalledWith(2);
106
106
  });
107
107
 
108
+ test("NOT called when stream is updated with same value", async () => {
109
+ vi.useFakeTimers();
110
+
111
+ const $stream = stream((set) => {
112
+ const interval = setInterval(() => {
113
+ set(5);
114
+ }, 1000);
115
+ return () => clearInterval(interval);
116
+ });
117
+
118
+ const effectFn = vi.fn();
119
+ effect((get) => effectFn(get($stream)));
120
+
121
+ expect(effectFn).toHaveBeenCalledTimes(1);
122
+ expect(effectFn).toHaveBeenLastCalledWith(undefined);
123
+
124
+ vi.advanceTimersToNextTimer();
125
+ expect(effectFn).toHaveBeenCalledTimes(2);
126
+ expect(effectFn).toHaveBeenLastCalledWith(5);
127
+
128
+ vi.advanceTimersToNextTimer();
129
+ expect(effectFn).toHaveBeenCalledTimes(2);
130
+ expect(effectFn).toHaveBeenLastCalledWith(5);
131
+ });
132
+
108
133
  test("NOT called when disposed", async () => {
109
134
  vi.useFakeTimers();
110
135
 
@@ -115,13 +140,13 @@ describe("effect", () => {
115
140
  set(counter);
116
141
  }, 1000);
117
142
  return () => clearInterval(interval);
118
- }, 0);
143
+ });
119
144
 
120
145
  const effectFn = vi.fn();
121
146
  const $effect = effect((get) => effectFn(get($stream)));
122
147
 
123
148
  expect(effectFn).toHaveBeenCalledTimes(1);
124
- expect(effectFn).toHaveBeenLastCalledWith(0);
149
+ expect(effectFn).toHaveBeenLastCalledWith(undefined);
125
150
 
126
151
  vi.advanceTimersToNextTimer();
127
152
  expect(effectFn).toHaveBeenCalledTimes(2);
@@ -147,13 +172,13 @@ describe("effect", () => {
147
172
  set(counter);
148
173
  }, 1000);
149
174
  return () => clearInterval(interval);
150
- }, 0);
175
+ });
151
176
 
152
177
  const effectFn = vi.fn();
153
178
  effect((get) => effectFn(get($stream)));
154
179
 
155
180
  expect(effectFn).toHaveBeenCalledTimes(1);
156
- expect(effectFn).toHaveBeenLastCalledWith(0);
181
+ expect(effectFn).toHaveBeenLastCalledWith(undefined);
157
182
 
158
183
  vi.advanceTimersToNextTimer();
159
184
  expect(effectFn).toHaveBeenCalledTimes(2);
@@ -0,0 +1,194 @@
1
+ import { describe, expect, test, vi } from "vitest";
2
+ import { effect, streamAsync } from "#package";
3
+
4
+ describe("streamAsync", () => {
5
+ test("is updated (callback)", async () => {
6
+ const counter = {
7
+ count: 0,
8
+ callback: undefined as ((value: number) => void) | undefined,
9
+ increment() {
10
+ this.count++;
11
+ if (this.callback) {
12
+ this.callback(this.count);
13
+ }
14
+ },
15
+ };
16
+
17
+ const $stream = streamAsync((set) => {
18
+ counter.callback = set;
19
+ return () => {
20
+ counter.callback = undefined;
21
+ };
22
+ });
23
+
24
+ const promise = $stream.get();
25
+
26
+ counter.increment();
27
+ expect(await promise).toBe(1);
28
+ expect(await $stream.get()).toBe(1);
29
+
30
+ counter.increment();
31
+ expect(await $stream.get()).toBe(2);
32
+ });
33
+
34
+ test("stream is updated (interval)", async () => {
35
+ vi.useFakeTimers();
36
+
37
+ const $stream = streamAsync<number>((set) => {
38
+ let counter = 0;
39
+ const interval = setInterval(() => {
40
+ counter++;
41
+ set(counter);
42
+ }, 1000);
43
+ return () => clearInterval(interval);
44
+ });
45
+
46
+ const promise = $stream.get();
47
+
48
+ vi.advanceTimersToNextTimer();
49
+ expect(await promise).toBe(1);
50
+ expect(await $stream.get()).toBe(1);
51
+
52
+ vi.advanceTimersToNextTimer();
53
+ expect(await $stream.get()).toBe(2);
54
+ });
55
+
56
+ test("get throws when stream is disposed", async () => {
57
+ vi.useFakeTimers();
58
+
59
+ const $stream = streamAsync((set) => {
60
+ let counter = 0;
61
+ const interval = setInterval(() => {
62
+ counter++;
63
+ set(counter);
64
+ }, 1000);
65
+ return () => clearInterval(interval);
66
+ });
67
+
68
+ vi.advanceTimersToNextTimer();
69
+ expect(await $stream.get()).toBe(1);
70
+
71
+ vi.advanceTimersToNextTimer();
72
+ expect(await $stream.get()).toBe(2);
73
+
74
+ $stream.dispose();
75
+ vi.advanceTimersToNextTimer();
76
+ expect(() => $stream.get()).toThrow("[PicoFlow] Primitive is disposed");
77
+ });
78
+ });
79
+
80
+ describe("effect", () => {
81
+ test("called when stream is updated", async () => {
82
+ vi.useFakeTimers();
83
+
84
+ const $stream = streamAsync((set) => {
85
+ let counter = 0;
86
+ const interval = setInterval(() => {
87
+ counter++;
88
+ set(counter);
89
+ }, 1000);
90
+ return () => clearInterval(interval);
91
+ });
92
+
93
+ const effectFn = vi.fn();
94
+ effect((get) => effectFn(get($stream)));
95
+
96
+ expect(effectFn).toHaveBeenCalledTimes(1);
97
+ expect(effectFn).toHaveBeenLastCalledWith(new Promise(() => {}));
98
+
99
+ vi.advanceTimersToNextTimer();
100
+ expect(effectFn).toHaveBeenCalledTimes(2);
101
+ expect(await effectFn.mock.calls[1][0]).toEqual(1);
102
+
103
+ vi.advanceTimersToNextTimer();
104
+ expect(effectFn).toHaveBeenCalledTimes(3);
105
+ expect(await effectFn.mock.calls[2][0]).toEqual(2);
106
+
107
+ vi.advanceTimersToNextTimer();
108
+ expect(effectFn).toHaveBeenCalledTimes(4);
109
+ expect(await effectFn.mock.calls[3][0]).toEqual(3);
110
+ });
111
+
112
+ test("NOT called when stream is updated with same value", async () => {
113
+ vi.useFakeTimers();
114
+
115
+ const $stream = streamAsync((set) => {
116
+ const interval = setInterval(() => {
117
+ set(5);
118
+ }, 1000);
119
+ return () => clearInterval(interval);
120
+ });
121
+
122
+ const effectFn = vi.fn();
123
+ effect((get) => effectFn(get($stream)));
124
+
125
+ expect(effectFn).toHaveBeenCalledTimes(1);
126
+ expect(effectFn).toHaveBeenLastCalledWith(new Promise(() => {}));
127
+
128
+ vi.advanceTimersToNextTimer();
129
+ expect(effectFn).toHaveBeenCalledTimes(2);
130
+ expect(await effectFn.mock.calls[1][0]).toEqual(5);
131
+
132
+ vi.advanceTimersToNextTimer();
133
+ expect(effectFn).toHaveBeenCalledTimes(2);
134
+ expect(await effectFn.mock.calls[1][0]).toEqual(5);
135
+ });
136
+
137
+ test("NOT called when disposed", async () => {
138
+ vi.useFakeTimers();
139
+
140
+ const $stream = streamAsync((set) => {
141
+ let counter = 0;
142
+ const interval = setInterval(() => {
143
+ counter++;
144
+ set(counter);
145
+ }, 1000);
146
+ return () => clearInterval(interval);
147
+ });
148
+
149
+ const effectFn = vi.fn();
150
+ const $effect = effect((get) => effectFn(get($stream)));
151
+
152
+ vi.advanceTimersToNextTimer();
153
+ expect(effectFn).toHaveBeenCalledTimes(2);
154
+ expect(await effectFn.mock.calls[1][0]).toEqual(1);
155
+
156
+ vi.advanceTimersToNextTimer();
157
+ expect(effectFn).toHaveBeenCalledTimes(3);
158
+ expect(await effectFn.mock.calls[2][0]).toEqual(2);
159
+
160
+ $effect.dispose();
161
+ vi.advanceTimersToNextTimer();
162
+ expect(effectFn).toHaveBeenCalledTimes(3);
163
+ expect(await effectFn.mock.calls[2][0]).toEqual(2);
164
+ });
165
+
166
+ test("NOT called when stream is disposed", async () => {
167
+ vi.useFakeTimers();
168
+
169
+ const $stream = streamAsync((set) => {
170
+ let counter = 0;
171
+ const interval = setInterval(() => {
172
+ counter++;
173
+ set(counter);
174
+ }, 1000);
175
+ return () => clearInterval(interval);
176
+ });
177
+
178
+ const effectFn = vi.fn();
179
+ effect((get) => effectFn(get($stream)));
180
+
181
+ vi.advanceTimersToNextTimer();
182
+ expect(effectFn).toHaveBeenCalledTimes(2);
183
+ expect(await effectFn.mock.calls[1][0]).toEqual(1);
184
+
185
+ vi.advanceTimersToNextTimer();
186
+ expect(effectFn).toHaveBeenCalledTimes(3);
187
+ expect(await effectFn.mock.calls[2][0]).toEqual(2);
188
+
189
+ $stream.dispose();
190
+ vi.advanceTimersToNextTimer();
191
+ expect(effectFn).toHaveBeenCalledTimes(3);
192
+ expect(await effectFn.mock.calls[2][0]).toEqual(2);
193
+ });
194
+ });
package/tsconfig.json CHANGED
@@ -16,7 +16,9 @@
16
16
  "noUnusedParameters": true,
17
17
  "noFallthroughCasesInSwitch": true,
18
18
  "noImplicitOverride": true,
19
- "noImplicitReturns": true
19
+ "noImplicitReturns": true,
20
+
21
+ "stripInternal": true
20
22
  },
21
23
  "include": ["./src/**/*", "./test/**/*"]
22
24
  }
@@ -1,13 +0,0 @@
1
- <!-- Do not edit this file. It is automatically generated by API Documenter. -->
2
-
3
- [Home](./index.md) &gt; [picoflow](./picoflow.md) &gt; [FlowDisposer](./picoflow.flowdisposer.md)
4
-
5
- ## FlowDisposer type
6
-
7
- A function that disposes of a resource.
8
-
9
- **Signature:**
10
-
11
- ```typescript
12
- export type FlowDisposer = () => void;
13
- ```
@@ -1,13 +0,0 @@
1
- <!-- Do not edit this file. It is automatically generated by API Documenter. -->
2
-
3
- [Home](./index.md) &gt; [picoflow](./picoflow.md) &gt; [FlowSetter](./picoflow.flowsetter.md)
4
-
5
- ## FlowSetter type
6
-
7
- A function that sets a new value.
8
-
9
- **Signature:**
10
-
11
- ```typescript
12
- export type FlowSetter<T> = (value: T) => void;
13
- ```
@@ -1,49 +0,0 @@
1
- <!-- Do not edit this file. It is automatically generated by API Documenter. -->
2
-
3
- [Home](./index.md) &gt; [picoflow](./picoflow.md) &gt; [FlowState](./picoflow.flowstate.md) &gt; [(constructor)](./picoflow.flowstate._constructor_.md)
4
-
5
- ## FlowState.(constructor)
6
-
7
- Creates a new FlowState with the given initial value.
8
-
9
- **Signature:**
10
-
11
- ```typescript
12
- constructor(value: T);
13
- ```
14
-
15
- ## Parameters
16
-
17
- <table><thead><tr><th>
18
-
19
- Parameter
20
-
21
-
22
- </th><th>
23
-
24
- Type
25
-
26
-
27
- </th><th>
28
-
29
- Description
30
-
31
-
32
- </th></tr></thead>
33
- <tbody><tr><td>
34
-
35
- value
36
-
37
-
38
- </td><td>
39
-
40
- T
41
-
42
-
43
- </td><td>
44
-
45
- The initial value for the state.
46
-
47
-
48
- </td></tr>
49
- </tbody></table>