muya 1.1.0 → 2.0.0-beta.2

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 (92) hide show
  1. package/README.md +202 -139
  2. package/cjs/index.js +1 -1
  3. package/esm/__tests__/create-async.test.js +1 -0
  4. package/esm/__tests__/test-utils.js +1 -0
  5. package/esm/create.js +1 -1
  6. package/esm/debug/development-tools.js +1 -0
  7. package/esm/index.js +1 -1
  8. package/esm/subscriber.js +1 -0
  9. package/esm/types.js +1 -1
  10. package/esm/use.js +1 -0
  11. package/esm/utils/__tests__/context.test.js +1 -0
  12. package/esm/utils/__tests__/is.test.js +1 -0
  13. package/esm/utils/__tests__/shallow.test.js +1 -0
  14. package/esm/utils/__tests__/sub-memo.test.js +1 -0
  15. package/esm/utils/common.js +1 -0
  16. package/esm/utils/create-context.js +1 -0
  17. package/esm/utils/create-emitter.js +1 -0
  18. package/esm/utils/global-scheduler.js +1 -0
  19. package/esm/utils/is.js +1 -0
  20. package/esm/utils/scheduler.js +1 -0
  21. package/esm/utils/shallow.js +1 -0
  22. package/esm/utils/sub-memo.js +1 -0
  23. package/package.json +1 -1
  24. package/packages/core/__tests__/bench.test.tsx +266 -0
  25. package/packages/core/__tests__/create-async.test.ts +88 -0
  26. package/packages/core/__tests__/create.test.tsx +107 -0
  27. package/packages/core/__tests__/subscriber.test.tsx +89 -0
  28. package/packages/core/__tests__/test-utils.ts +40 -0
  29. package/packages/core/__tests__/use-async.test.tsx +45 -0
  30. package/packages/core/__tests__/use.test.tsx +125 -0
  31. package/packages/core/create.ts +98 -0
  32. package/packages/core/debug/development-tools.ts +37 -0
  33. package/packages/core/index.ts +4 -0
  34. package/packages/core/subscriber.ts +165 -0
  35. package/packages/core/types.ts +15 -0
  36. package/packages/core/use.ts +57 -0
  37. package/packages/core/utils/__tests__/context.test.ts +198 -0
  38. package/packages/core/utils/__tests__/is.test.ts +74 -0
  39. package/packages/core/utils/__tests__/shallow.test.ts +418 -0
  40. package/packages/core/utils/__tests__/sub-memo.test.ts +13 -0
  41. package/packages/core/utils/common.ts +48 -0
  42. package/packages/core/utils/create-context.ts +60 -0
  43. package/packages/core/utils/create-emitter.ts +55 -0
  44. package/packages/core/utils/global-scheduler.ts +75 -0
  45. package/packages/core/utils/is.ts +50 -0
  46. package/packages/core/utils/scheduler.ts +59 -0
  47. package/{src → packages/core/utils}/shallow.ts +3 -6
  48. package/packages/core/utils/sub-memo.ts +49 -0
  49. package/types/__tests__/test-utils.d.ts +20 -0
  50. package/types/create.d.ts +21 -21
  51. package/types/debug/development-tools.d.ts +10 -0
  52. package/types/index.d.ts +2 -4
  53. package/types/subscriber.d.ts +25 -0
  54. package/types/types.d.ts +9 -65
  55. package/types/use.d.ts +2 -0
  56. package/types/utils/common.d.ts +15 -0
  57. package/types/utils/create-context.d.ts +5 -0
  58. package/types/utils/create-emitter.d.ts +20 -0
  59. package/types/utils/global-scheduler.d.ts +5 -0
  60. package/types/utils/is.d.ts +13 -0
  61. package/types/utils/scheduler.d.ts +8 -0
  62. package/types/utils/sub-memo.d.ts +7 -0
  63. package/esm/common.js +0 -1
  64. package/esm/create-base-state.js +0 -1
  65. package/esm/create-emitter.js +0 -1
  66. package/esm/create-getter-state.js +0 -1
  67. package/esm/is.js +0 -1
  68. package/esm/merge.js +0 -1
  69. package/esm/select.js +0 -1
  70. package/esm/shallow.js +0 -1
  71. package/esm/use-state-value.js +0 -1
  72. package/src/common.ts +0 -28
  73. package/src/create-base-state.ts +0 -35
  74. package/src/create-emitter.ts +0 -24
  75. package/src/create-getter-state.ts +0 -19
  76. package/src/create.ts +0 -102
  77. package/src/index.ts +0 -6
  78. package/src/is.ts +0 -36
  79. package/src/merge.ts +0 -41
  80. package/src/select.ts +0 -33
  81. package/src/state.test.tsx +0 -647
  82. package/src/types.ts +0 -94
  83. package/src/use-state-value.ts +0 -29
  84. package/types/common.d.ts +0 -7
  85. package/types/create-base-state.d.ts +0 -10
  86. package/types/create-emitter.d.ts +0 -7
  87. package/types/create-getter-state.d.ts +0 -6
  88. package/types/is.d.ts +0 -10
  89. package/types/merge.d.ts +0 -2
  90. package/types/select.d.ts +0 -2
  91. package/types/use-state-value.d.ts +0 -10
  92. /package/types/{shallow.d.ts → utils/shallow.d.ts} +0 -0
@@ -0,0 +1,74 @@
1
+ import { Abort } from '../common'
2
+ import { isPromise, isFunction, isSetValueFunction, isMap, isSet, isArray, isEqualBase, isAbortError } from '../is'
3
+
4
+ describe('isPromise', () => {
5
+ it('should return true for a Promise', () => {
6
+ expect(isPromise(Promise.resolve())).toBe(true)
7
+ })
8
+ it('should return false for a non-Promise', () => {
9
+ expect(isPromise(123)).toBe(false)
10
+ })
11
+ })
12
+
13
+ describe('isFunction', () => {
14
+ it('should return true for a function', () => {
15
+ expect(isFunction(() => {})).toBe(true)
16
+ })
17
+ it('should return false for a non-function', () => {
18
+ expect(isFunction(123)).toBe(false)
19
+ })
20
+ })
21
+
22
+ describe('isSetValueFunction', () => {
23
+ it('should return true for a function', () => {
24
+ expect(isSetValueFunction(() => {})).toBe(true)
25
+ })
26
+ it('should return false for a non-function', () => {
27
+ expect(isSetValueFunction(123)).toBe(false)
28
+ })
29
+ })
30
+
31
+ describe('isMap', () => {
32
+ it('should return true for a Map', () => {
33
+ expect(isMap(new Map())).toBe(true)
34
+ })
35
+ it('should return false for a non-Map', () => {
36
+ expect(isMap(123)).toBe(false)
37
+ })
38
+ })
39
+
40
+ describe('isSet', () => {
41
+ it('should return true for a Set', () => {
42
+ expect(isSet(new Set())).toBe(true)
43
+ })
44
+ it('should return false for a non-Set', () => {
45
+ expect(isSet(123)).toBe(false)
46
+ })
47
+ })
48
+
49
+ describe('isArray', () => {
50
+ it('should return true for an array', () => {
51
+ expect(isArray([])).toBe(true)
52
+ })
53
+ it('should return false for a non-array', () => {
54
+ expect(isArray(123)).toBe(false)
55
+ })
56
+ })
57
+
58
+ describe('isEqualBase', () => {
59
+ it('should return true for equal values', () => {
60
+ expect(isEqualBase(1, 1)).toBe(true)
61
+ })
62
+ it('should return false for non-equal values', () => {
63
+ expect(isEqualBase(1, 2)).toBe(false)
64
+ })
65
+ })
66
+
67
+ describe('isAbortError', () => {
68
+ it('should return true for an AbortError', () => {
69
+ expect(isAbortError(new DOMException('', Abort.Error))).toBe(true)
70
+ })
71
+ it('should return false for a non-AbortError', () => {
72
+ expect(isAbortError(new DOMException('', 'Error'))).toBe(false)
73
+ })
74
+ })
@@ -0,0 +1,418 @@
1
+ import { shallow } from '../shallow'
2
+
3
+ describe('shallow', () => {
4
+ it('should return true for identical primitive values', () => {
5
+ expect(shallow(1, 1)).toBe(true)
6
+ expect(shallow('a', 'a')).toBe(true)
7
+ expect(shallow(true, true)).toBe(true)
8
+ })
9
+
10
+ it('should return false for different primitive values', () => {
11
+ expect(shallow(1, 2)).toBe(false)
12
+ expect(shallow('a', 'b')).toBe(false)
13
+ expect(shallow(true, false)).toBe(false)
14
+ })
15
+
16
+ it('should return true for identical objects', () => {
17
+ const object = { a: 1 }
18
+ expect(shallow(object, object)).toBe(true)
19
+ })
20
+
21
+ it('should return false for different objects with diff properties', () => {
22
+ expect(shallow({ a: 1 }, { a: 2 })).toBe(false)
23
+ })
24
+
25
+ it('should return true for identical arrays', () => {
26
+ const array = [1, 2, 3]
27
+ expect(shallow(array, array)).toBe(true)
28
+ })
29
+
30
+ it('should return true for different arrays with same elements', () => {
31
+ expect(shallow([1, 2, 3], [1, 2, 3])).toBe(true)
32
+ })
33
+
34
+ it('should return true for identical Maps', () => {
35
+ const map = new Map([['a', 1]])
36
+ expect(shallow(map, map)).toBe(true)
37
+ })
38
+
39
+ it('should return true for different Maps with same entries', () => {
40
+ expect(shallow(new Map([['a', 1]]), new Map([['a', 1]]))).toBe(true)
41
+ })
42
+
43
+ it('should return true for identical Sets', () => {
44
+ const set = new Set([1, 2, 3])
45
+ expect(shallow(set, set)).toBe(true)
46
+ })
47
+
48
+ it('should return true for different Sets with same elements', () => {
49
+ expect(shallow(new Set([1, 2, 3]), new Set([1, 2, 3]))).toBe(true)
50
+ })
51
+
52
+ it('should return true for objects with same reference', () => {
53
+ const object = { a: 1 }
54
+ expect(shallow(object, object)).toBe(true)
55
+ })
56
+
57
+ it('should return true for objects with different references', () => {
58
+ expect(shallow({ a: 1 }, { a: 1 })).toBe(true)
59
+ })
60
+
61
+ it('should return true for arrays with same reference', () => {
62
+ const array = [1, 2, 3]
63
+ expect(shallow(array, array)).toBe(true)
64
+ })
65
+
66
+ it('should return true for arrays with different references', () => {
67
+ expect(shallow([1, 2, 3], [1, 2, 3])).toBe(true)
68
+ })
69
+
70
+ it('should return true for Maps with same reference', () => {
71
+ const map = new Map([['a', 1]])
72
+ expect(shallow(map, map)).toBe(true)
73
+ })
74
+
75
+ it('should return true for Maps with different references', () => {
76
+ expect(shallow(new Map([['a', 1]]), new Map([['a', 1]]))).toBe(true)
77
+ })
78
+
79
+ it('should return true for Sets with same reference', () => {
80
+ const set = new Set([1, 2, 3])
81
+ expect(shallow(set, set)).toBe(true)
82
+ })
83
+
84
+ it('should return true for Sets with different references', () => {
85
+ expect(shallow(new Set([1, 2, 3]), new Set([1, 2, 3]))).toBe(true)
86
+ })
87
+
88
+ it('should return true for objects with same keys and values', () => {
89
+ const objectA = { a: 1, b: 2 }
90
+ const objectB = { a: 1, b: 2 }
91
+ expect(shallow(objectA, objectB)).toBe(true)
92
+ })
93
+
94
+ it('should return false for objects with different keys or values', () => {
95
+ const objectA = { a: 1, b: 2 }
96
+ const objectB = { a: 1, b: 3 }
97
+ expect(shallow(objectA, objectB)).toBe(false)
98
+ })
99
+
100
+ it('should return true for arrays with same elements', () => {
101
+ const arrayA = [1, 2, 3]
102
+ const arrayB = [1, 2, 3]
103
+ expect(shallow(arrayA, arrayB)).toBe(true)
104
+ })
105
+
106
+ it('should return false for arrays with different elements', () => {
107
+ const arrayA = [1, 2, 3]
108
+ const arrayB = [1, 2, 4]
109
+ expect(shallow(arrayA, arrayB)).toBe(false)
110
+ })
111
+
112
+ it('should return true for Maps with same entries', () => {
113
+ const mapA = new Map([
114
+ ['a', 1],
115
+ ['b', 2],
116
+ ])
117
+ const mapB = new Map([
118
+ ['a', 1],
119
+ ['b', 2],
120
+ ])
121
+ expect(shallow(mapA, mapB)).toBe(true)
122
+ })
123
+
124
+ it('should return false for Maps with different entries', () => {
125
+ const mapA = new Map([
126
+ ['a', 1],
127
+ ['b', 2],
128
+ ])
129
+ const mapB = new Map([
130
+ ['a', 1],
131
+ ['b', 3],
132
+ ])
133
+ expect(shallow(mapA, mapB)).toBe(false)
134
+ })
135
+
136
+ it('should return true for Sets with same elements', () => {
137
+ const setA = new Set([1, 2, 3])
138
+ const setB = new Set([1, 2, 3])
139
+ expect(shallow(setA, setB)).toBe(true)
140
+ })
141
+
142
+ it('should return false for Sets with different elements', () => {
143
+ const setA = new Set([1, 2, 3])
144
+ const setB = new Set([1, 2, 4])
145
+ expect(shallow(setA, setB)).toBe(false)
146
+ })
147
+
148
+ it('should return false for different objects with same properties', () => {
149
+ expect(shallow({ a: 1 }, { a: 2 })).toBe(false)
150
+ })
151
+
152
+ it('should return false for different arrays with same elements', () => {
153
+ expect(shallow([1, 2, 3], [1, 2, 4])).toBe(false)
154
+ })
155
+
156
+ it('should return false for different Maps with same entries', () => {
157
+ expect(shallow(new Map([['a', 1]]), new Map([['a', 2]]))).toBe(false)
158
+ })
159
+
160
+ it('should return false for different Sets with same elements', () => {
161
+ expect(shallow(new Set([1, 2, 3]), new Set([1, 2, 4]))).toBe(false)
162
+ })
163
+
164
+ it('should return false for objects with different reference', () => {
165
+ expect(shallow({ a: 1 }, { a: 2 })).toBe(false)
166
+ })
167
+
168
+ it('should return false for arrays with different reference', () => {
169
+ expect(shallow([1, 2, 3], [1, 2, 4])).toBe(false)
170
+ })
171
+
172
+ it('should return false for Maps with different reference', () => {
173
+ expect(shallow(new Map([['a', 1]]), new Map([['a', 2]]))).toBe(false)
174
+ })
175
+
176
+ it('should return false for Sets with different reference', () => {
177
+ expect(shallow(new Set([1, 2, 3]), new Set([1, 2, 4]))).toBe(false)
178
+ })
179
+
180
+ it('should return false for objects with different keys or values in', () => {
181
+ const objectA = { a: 1, b: 2 }
182
+ const objectB = { a: 1, b: 3 }
183
+ expect(shallow(objectA, objectB)).toBe(false)
184
+ })
185
+
186
+ it('should return false for arrays with different elements', () => {
187
+ const arrayA = [1, 2, 3]
188
+ const arrayB = [1, 2, 4]
189
+ expect(shallow(arrayA, arrayB)).toBe(false)
190
+ })
191
+
192
+ it('should return false for Maps with different entries', () => {
193
+ const mapA = new Map([
194
+ ['a', 1],
195
+ ['b', 2],
196
+ ])
197
+ const mapB = new Map([
198
+ ['a', 1],
199
+ ['b', 3],
200
+ ])
201
+ expect(shallow(mapA, mapB)).toBe(false)
202
+ })
203
+
204
+ it('should return false for Sets with different elements', () => {
205
+ const setA = new Set([1, 2, 3])
206
+ const setB = new Set([1, 2, 4])
207
+ expect(shallow(setA, setB)).toBe(false)
208
+ })
209
+
210
+ it('should return false for objects with different keys or values', () => {
211
+ const objectA = { a: 1, b: 2 }
212
+ const objectB = { a: 1, b: 3 }
213
+ expect(shallow(objectA, objectB)).toBe(false)
214
+ })
215
+
216
+ it('should return false for arrays with different elements', () => {
217
+ const arrayA = [1, 2, 3]
218
+ const arrayB = [1, 2, 4]
219
+ expect(shallow(arrayA, arrayB)).toBe(false)
220
+ })
221
+
222
+ it('should return false for Maps with different entries', () => {
223
+ const mapA = new Map([
224
+ ['a', 1],
225
+ ['b', 2],
226
+ ])
227
+ const mapB = new Map([
228
+ ['a', 1],
229
+ ['b', 3],
230
+ ])
231
+ expect(shallow(mapA, mapB)).toBe(false)
232
+ })
233
+
234
+ it('should return false for Sets with different elements', () => {
235
+ const setA = new Set([1, 2, 3])
236
+ const setB = new Set([1, 2, 4])
237
+ expect(shallow(setA, setB)).toBe(false)
238
+ })
239
+
240
+ it('should return false for objects with different keys or values', () => {
241
+ const objectA = { a: 1, b: 2 }
242
+ const objectB = { a: 1, b: 3 }
243
+ expect(shallow(objectA, objectB)).toBe(false)
244
+ })
245
+
246
+ it('should return false for arrays with different elements', () => {
247
+ const arrayA = [1, 2, 3]
248
+ const arrayB = [1, 2, 4]
249
+ expect(shallow(arrayA, arrayB)).toBe(false)
250
+ })
251
+
252
+ it('should return false for Maps with different entries', () => {
253
+ const mapA = new Map([
254
+ ['a', 1],
255
+ ['b', 2],
256
+ ])
257
+ const mapB = new Map([
258
+ ['a', 1],
259
+ ['b', 3],
260
+ ])
261
+ expect(shallow(mapA, mapB)).toBe(false)
262
+ })
263
+
264
+ it('should return false for Sets with different elements', () => {
265
+ const setA = new Set([1, 2, 3])
266
+ const setB = new Set([1, 2, 4])
267
+ expect(shallow(setA, setB)).toBe(false)
268
+ })
269
+
270
+ it('should return false for objects with different keys or values', () => {
271
+ const objectA = { a: 1, b: 2 }
272
+ const objectB = { a: 1, b: 3 }
273
+ expect(shallow(objectA, objectB)).toBe(false)
274
+ })
275
+
276
+ it('should return false for arrays with different elements', () => {
277
+ const arrayA = [1, 2, 3]
278
+ const arrayB = [1, 2, 4]
279
+ expect(shallow(arrayA, arrayB)).toBe(false)
280
+ })
281
+
282
+ it('should return false for Maps with different entries', () => {
283
+ const mapA = new Map([
284
+ ['a', 1],
285
+ ['b', 2],
286
+ ])
287
+ const mapB = new Map([
288
+ ['a', 1],
289
+ ['b', 3],
290
+ ])
291
+ expect(shallow(mapA, mapB)).toBe(false)
292
+ })
293
+
294
+ it('should return false for Sets with different elements', () => {
295
+ const setA = new Set([1, 2, 3])
296
+ const setB = new Set([1, 2, 4])
297
+ expect(shallow(setA, setB)).toBe(false)
298
+ })
299
+
300
+ it('should return false for objects with different keys or values', () => {
301
+ const objectA = { a: 1, b: 2 }
302
+ const objectB = { a: 1, b: 3 }
303
+ expect(shallow(objectA, objectB)).toBe(false)
304
+ })
305
+
306
+ it('should return false for arrays with different elements', () => {
307
+ const arrayA = [1, 2, 3]
308
+ const arrayB = [1, 2, 4]
309
+ expect(shallow(arrayA, arrayB)).toBe(false)
310
+ })
311
+
312
+ it('should return false for Maps with different entries', () => {
313
+ const mapA = new Map([
314
+ ['a', 1],
315
+ ['b', 2],
316
+ ])
317
+ const mapB = new Map([
318
+ ['a', 1],
319
+ ['b', 3],
320
+ ])
321
+ expect(shallow(mapA, mapB)).toBe(false)
322
+ })
323
+
324
+ it('should return false for Sets with different elements', () => {
325
+ const setA = new Set([1, 2, 3])
326
+ const setB = new Set([1, 2, 4])
327
+ expect(shallow(setA, setB)).toBe(false)
328
+ })
329
+
330
+ it('should return false for objects with different keys or values', () => {
331
+ const objectA = { a: 1, b: 2 }
332
+ const objectB = { a: 1, b: 3 }
333
+ expect(shallow(objectA, objectB)).toBe(false)
334
+ })
335
+
336
+ it('should return false for arrays with different elements', () => {
337
+ const arrayA = [1, 2, 3]
338
+ const arrayB = [1, 2, 4]
339
+ expect(shallow(arrayA, arrayB)).toBe(false)
340
+ })
341
+
342
+ it('should return false for Maps with different entries', () => {
343
+ const mapA = new Map([
344
+ ['a', 1],
345
+ ['b', 2],
346
+ ])
347
+ const mapB = new Map([
348
+ ['a', 1],
349
+ ['b', 3],
350
+ ])
351
+ expect(shallow(mapA, mapB)).toBe(false)
352
+ })
353
+
354
+ it('should return false for Sets with different elements', () => {
355
+ const setA = new Set([1, 2, 3])
356
+ const setB = new Set([1, 2, 4])
357
+ expect(shallow(setA, setB)).toBe(false)
358
+ })
359
+
360
+ it('should return false for null and non-null values', () => {
361
+ expect(shallow(null, {})).toBe(false)
362
+ expect(shallow({}, null)).toBe(false)
363
+ })
364
+
365
+ it('should return false for objects with different number of keys', () => {
366
+ expect(shallow({ a: 1 }, { a: 1, b: 2 })).toBe(false)
367
+ })
368
+
369
+ it('should return false for objects with different keys', () => {
370
+ expect(shallow({ a: 1 }, { b: 1 })).toBe(false)
371
+ })
372
+
373
+ it('should return false for objects with different values', () => {
374
+ expect(shallow({ a: 1 }, { a: 2 })).toBe(false)
375
+ })
376
+
377
+ it('should return false for arrays with different lengths', () => {
378
+ expect(shallow([1, 2], [1, 2, 3])).toBe(false)
379
+ })
380
+
381
+ it('should return false for arrays with different elements', () => {
382
+ expect(shallow([1, 2, 3], [1, 2, 4])).toBe(false)
383
+ })
384
+
385
+ it('should return false for Maps with different sizes', () => {
386
+ expect(
387
+ shallow(
388
+ new Map([['a', 1]]),
389
+ new Map([
390
+ ['a', 1],
391
+ ['b', 2],
392
+ ]),
393
+ ),
394
+ ).toBe(false)
395
+ })
396
+
397
+ it('should return false for Maps with different keys', () => {
398
+ expect(shallow(new Map([['a', 1]]), new Map([['b', 1]]))).toBe(false)
399
+ })
400
+
401
+ it('should return false for Maps with different values', () => {
402
+ expect(shallow(new Map([['a', 1]]), new Map([['a', 2]]))).toBe(false)
403
+ })
404
+
405
+ it('should return false for Sets with different sizes', () => {
406
+ expect(shallow(new Set([1, 2]), new Set([1, 2, 3]))).toBe(false)
407
+ })
408
+
409
+ it('should return false for Sets with different elements', () => {
410
+ expect(shallow(new Set([1, 2, 3]), new Set([1, 2, 4]))).toBe(false)
411
+ })
412
+
413
+ it('should return true compare simple values', () => {
414
+ expect(shallow(1, 1)).toBe(true)
415
+ expect(shallow('a', 'a')).toBe(true)
416
+ expect(shallow(true, true)).toBe(true)
417
+ })
418
+ })
@@ -0,0 +1,13 @@
1
+ /* eslint-disable unicorn/consistent-function-scoping */
2
+ import { subMemo } from '../sub-memo'
3
+
4
+ describe('memo-fn', () => {
5
+ it('should create memo fn', () => {
6
+ function toBeMemoized(): boolean {
7
+ return true
8
+ }
9
+
10
+ const memoized = subMemo(toBeMemoized)
11
+ expect(memoized.call().emitter).toBeDefined()
12
+ })
13
+ })
@@ -0,0 +1,48 @@
1
+ import type { Cache, IsEqual } from '../types'
2
+ import { isUndefined } from './is'
3
+
4
+ // eslint-disable-next-line no-shadow
5
+ export enum Abort {
6
+ Error = 'StateAbortError',
7
+ }
8
+
9
+ export interface CancelablePromise<T> {
10
+ promise?: Promise<T>
11
+ controller?: AbortController
12
+ resolveInitialPromise?: (value: T) => void
13
+ }
14
+ /**
15
+ * Cancelable promise function, return promise and controller
16
+ */
17
+ export function cancelablePromise<T>(promise: Promise<T>, previousController?: AbortController): CancelablePromise<T> {
18
+ if (previousController) {
19
+ previousController.abort()
20
+ }
21
+ const controller = new AbortController()
22
+ const { signal } = controller
23
+
24
+ const cancelable = new Promise<T>((resolve, reject) => {
25
+ // Listen for the abort event
26
+ signal.addEventListener('abort', () => {
27
+ reject(new DOMException('Promise was aborted', Abort.Error))
28
+ })
29
+ // When the original promise settles, resolve or reject accordingly
30
+ promise.then(resolve).catch(reject)
31
+ })
32
+ return { promise: cancelable, controller }
33
+ }
34
+
35
+ let id = 0
36
+ export function generateId() {
37
+ return id++
38
+ }
39
+
40
+ export function canUpdate<T>(cache: Cache<T>, isEqual: IsEqual<T> = (previous, next) => previous === next): boolean {
41
+ if (!isUndefined(cache.current)) {
42
+ if (!isUndefined(cache.previous) && isEqual(cache.current, cache.previous)) {
43
+ return false
44
+ }
45
+ cache.previous = cache.current
46
+ }
47
+ return true
48
+ }
@@ -0,0 +1,60 @@
1
+ import { isPromise } from './is'
2
+
3
+ const EMPTY_CONTEXT = Symbol('_')
4
+
5
+ export function createContext<T>(defaultContextValue: T) {
6
+ const contextStack: Array<T | typeof EMPTY_CONTEXT> = []
7
+
8
+ function use(): T | undefined {
9
+ if (contextStack.length === 0) {
10
+ return defaultContextValue
11
+ }
12
+ const currentContext = contextStack.at(-1)
13
+ return currentContext === EMPTY_CONTEXT ? defaultContextValue : currentContext
14
+ }
15
+
16
+ function run<R>(ctxValue: T, cb: () => R | Promise<R>): R {
17
+ contextStack.push(ctxValue)
18
+ const result = cb()
19
+ const isResultPromise = isPromise(result)
20
+ if (isResultPromise) {
21
+ return (async () => {
22
+ try {
23
+ return await result
24
+ } finally {
25
+ contextStack.pop()
26
+ }
27
+ })() as R
28
+ } else {
29
+ contextStack.pop()
30
+ return result
31
+ }
32
+ }
33
+
34
+ function wrap<X>(cb: () => X | Promise<X>): () => X | Promise<X> {
35
+ const capturedContext = use()
36
+ return () => {
37
+ contextStack.push(capturedContext!)
38
+ const result = cb()
39
+ const isResultPromise = isPromise(result)
40
+ if (isResultPromise) {
41
+ return (async () => {
42
+ try {
43
+ return await result
44
+ } finally {
45
+ contextStack.pop()
46
+ }
47
+ })()
48
+ } else {
49
+ contextStack.pop()
50
+ return result
51
+ }
52
+ }
53
+ }
54
+
55
+ return {
56
+ run,
57
+ use,
58
+ wrap,
59
+ }
60
+ }
@@ -0,0 +1,55 @@
1
+ export type EmitterSubscribe<P = undefined> = (listener: (...params: P[]) => void) => () => void
2
+ export interface Emitter<T, P = undefined> {
3
+ subscribe: EmitterSubscribe<P>
4
+ subscribeToOtherEmitter: (emitter: Emitter<unknown>) => void
5
+ getSnapshot: () => T
6
+ getInitialSnapshot?: () => T
7
+ emit: (...params: P[]) => void
8
+ getSize: () => number
9
+ clear: () => void
10
+ contains: (listener: (...params: P[]) => void) => boolean
11
+ }
12
+
13
+ /**
14
+ * Generics parameters are:
15
+ * T: Type of the state
16
+ * R: Type of the snapshot
17
+ * P: Type of the parameters
18
+ * @param getSnapshot
19
+ * @returns
20
+ */
21
+ export function createEmitter<T, P = undefined>(getSnapshot: () => T, getInitialSnapshot?: () => T): Emitter<T, P> {
22
+ const listeners = new Set<(...params: P[]) => void>()
23
+ // const listeners = new WeakSet<(...params: P[]) => void>()
24
+ const otherCleaners: Array<() => void> = []
25
+ return {
26
+ clear: () => {
27
+ for (const cleaner of otherCleaners) {
28
+ cleaner()
29
+ }
30
+
31
+ listeners.clear()
32
+ },
33
+ subscribe: (listener) => {
34
+ listeners.add(listener)
35
+ return () => {
36
+ listeners.delete(listener)
37
+ }
38
+ },
39
+ emit: (...params) => {
40
+ for (const listener of listeners) {
41
+ listener(...params)
42
+ }
43
+ },
44
+ contains: (listener) => listeners.has(listener),
45
+ getSnapshot,
46
+ getInitialSnapshot,
47
+ getSize: () => listeners.size,
48
+ subscribeToOtherEmitter(emitter) {
49
+ const clean = emitter.subscribe(() => {
50
+ this.emit()
51
+ })
52
+ otherCleaners.push(clean)
53
+ },
54
+ }
55
+ }