muya 1.1.0 → 2.0.0-beta.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.
- package/README.md +201 -138
- package/cjs/index.js +1 -1
- package/esm/__tests__/create-async.test.js +1 -0
- package/esm/__tests__/test-utils.js +1 -0
- package/esm/create.js +1 -1
- package/esm/index.js +1 -1
- package/esm/subscriber.js +1 -0
- package/esm/types.js +1 -1
- package/esm/use.js +1 -0
- package/esm/utils/__tests__/context.test.js +1 -0
- package/esm/utils/__tests__/is.test.js +1 -0
- package/esm/utils/__tests__/shallow.test.js +1 -0
- package/esm/utils/__tests__/sub-memo.test.js +1 -0
- package/esm/utils/common.js +1 -0
- package/esm/utils/create-context.js +1 -0
- package/esm/utils/create-emitter.js +1 -0
- package/esm/utils/is.js +1 -0
- package/esm/utils/scheduler.js +1 -0
- package/esm/utils/shallow.js +1 -0
- package/esm/utils/sub-memo.js +1 -0
- package/package.json +1 -1
- package/packages/core/__tests__/bench.test.tsx +261 -0
- package/packages/core/__tests__/create-async.test.ts +88 -0
- package/packages/core/__tests__/create.test.tsx +107 -0
- package/packages/core/__tests__/test-utils.ts +40 -0
- package/packages/core/__tests__/use-async.test.tsx +44 -0
- package/packages/core/__tests__/use.test.tsx +76 -0
- package/packages/core/create.ts +67 -0
- package/packages/core/index.ts +4 -0
- package/packages/core/subscriber.ts +121 -0
- package/packages/core/types.ts +15 -0
- package/packages/core/use.ts +59 -0
- package/packages/core/utils/__tests__/context.test.ts +198 -0
- package/packages/core/utils/__tests__/is.test.ts +74 -0
- package/packages/core/utils/__tests__/shallow.test.ts +418 -0
- package/packages/core/utils/__tests__/sub-memo.test.ts +13 -0
- package/packages/core/utils/common.ts +48 -0
- package/packages/core/utils/create-context.ts +60 -0
- package/packages/core/utils/create-emitter.ts +53 -0
- package/packages/core/utils/is.ts +43 -0
- package/packages/core/utils/scheduler.ts +59 -0
- package/{src → packages/core/utils}/shallow.ts +3 -6
- package/packages/core/utils/sub-memo.ts +37 -0
- package/types/__tests__/test-utils.d.ts +20 -0
- package/types/create.d.ts +14 -21
- package/types/index.d.ts +2 -4
- package/types/subscriber.d.ts +25 -0
- package/types/types.d.ts +9 -65
- package/types/use.d.ts +2 -0
- package/types/utils/common.d.ts +15 -0
- package/types/utils/create-context.d.ts +5 -0
- package/types/utils/create-emitter.d.ts +20 -0
- package/types/utils/is.d.ts +11 -0
- package/types/utils/scheduler.d.ts +6 -0
- package/types/utils/sub-memo.d.ts +6 -0
- package/esm/common.js +0 -1
- package/esm/create-base-state.js +0 -1
- package/esm/create-emitter.js +0 -1
- package/esm/create-getter-state.js +0 -1
- package/esm/is.js +0 -1
- package/esm/merge.js +0 -1
- package/esm/select.js +0 -1
- package/esm/shallow.js +0 -1
- package/esm/use-state-value.js +0 -1
- package/src/common.ts +0 -28
- package/src/create-base-state.ts +0 -35
- package/src/create-emitter.ts +0 -24
- package/src/create-getter-state.ts +0 -19
- package/src/create.ts +0 -102
- package/src/index.ts +0 -6
- package/src/is.ts +0 -36
- package/src/merge.ts +0 -41
- package/src/select.ts +0 -33
- package/src/state.test.tsx +0 -647
- package/src/types.ts +0 -94
- package/src/use-state-value.ts +0 -29
- package/types/common.d.ts +0 -7
- package/types/create-base-state.d.ts +0 -10
- package/types/create-emitter.d.ts +0 -7
- package/types/create-getter-state.d.ts +0 -6
- package/types/is.d.ts +0 -10
- package/types/merge.d.ts +0 -2
- package/types/select.d.ts +0 -2
- package/types/use-state-value.d.ts +0 -10
- /package/types/{shallow.d.ts → utils/shallow.d.ts} +0 -0
|
@@ -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,53 @@
|
|
|
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 otherCleaners: Array<() => void> = []
|
|
24
|
+
return {
|
|
25
|
+
clear: () => {
|
|
26
|
+
for (const cleaner of otherCleaners) {
|
|
27
|
+
cleaner()
|
|
28
|
+
}
|
|
29
|
+
listeners.clear()
|
|
30
|
+
},
|
|
31
|
+
subscribe: (listener) => {
|
|
32
|
+
listeners.add(listener)
|
|
33
|
+
return () => {
|
|
34
|
+
listeners.delete(listener)
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
emit: (...params) => {
|
|
38
|
+
for (const listener of listeners) {
|
|
39
|
+
listener(...params)
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
contains: (listener) => listeners.has(listener),
|
|
43
|
+
getSnapshot,
|
|
44
|
+
getInitialSnapshot,
|
|
45
|
+
getSize: () => listeners.size,
|
|
46
|
+
subscribeToOtherEmitter(emitter) {
|
|
47
|
+
const clean = emitter.subscribe(() => {
|
|
48
|
+
this.emit()
|
|
49
|
+
})
|
|
50
|
+
otherCleaners.push(clean)
|
|
51
|
+
},
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { Abort } from './common'
|
|
2
|
+
import type { SetStateCb, SetValue } from '../types'
|
|
3
|
+
|
|
4
|
+
export function isPromise<T>(value: unknown): value is Promise<T> {
|
|
5
|
+
return value instanceof Promise
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function isFunction<T extends (...args: unknown[]) => unknown>(value: unknown): value is T {
|
|
9
|
+
return typeof value === 'function'
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function isMap(value: unknown): value is Map<unknown, unknown> {
|
|
13
|
+
return value instanceof Map
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function isSet(value: unknown): value is Set<unknown> {
|
|
17
|
+
return value instanceof Set
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function isArray(value: unknown): value is Array<unknown> {
|
|
21
|
+
return Array.isArray(value)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function isEqualBase<T>(valueA: T, valueB: T): boolean {
|
|
25
|
+
if (valueA === valueB) {
|
|
26
|
+
return true
|
|
27
|
+
}
|
|
28
|
+
return !!Object.is(valueA, valueB)
|
|
29
|
+
}
|
|
30
|
+
export function isSetValueFunction<T>(value: SetValue<T>): value is SetStateCb<T> {
|
|
31
|
+
return typeof value === 'function'
|
|
32
|
+
}
|
|
33
|
+
export function isAbortError(value: unknown): value is DOMException {
|
|
34
|
+
return value instanceof DOMException && value.name === Abort.Error
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function isAnyOtherError(value: unknown): value is Error {
|
|
38
|
+
return value instanceof Error && value.name !== Abort.Error
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function isUndefined(value: unknown): value is undefined {
|
|
42
|
+
return value === undefined
|
|
43
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
const THRESHOLD = 0.2
|
|
2
|
+
const THRESHOLD_ITEMS = 10
|
|
3
|
+
const RESCHEDULE_COUNT = 0
|
|
4
|
+
|
|
5
|
+
interface Options<T> {
|
|
6
|
+
readonly onResolveItem?: (item: T) => void
|
|
7
|
+
readonly onFinish: () => void
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function createScheduler<T>(options: Options<T>) {
|
|
11
|
+
const batches = new Set<T>()
|
|
12
|
+
const { onResolveItem, onFinish } = options
|
|
13
|
+
let frame = performance.now()
|
|
14
|
+
let scheduled = false
|
|
15
|
+
|
|
16
|
+
function schedule() {
|
|
17
|
+
const startFrame = performance.now()
|
|
18
|
+
const frameSizeDiffIn = startFrame - frame
|
|
19
|
+
const { size } = batches
|
|
20
|
+
if (frameSizeDiffIn < THRESHOLD && size > 0 && size < THRESHOLD_ITEMS) {
|
|
21
|
+
frame = startFrame
|
|
22
|
+
flush()
|
|
23
|
+
return
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (!scheduled) {
|
|
27
|
+
scheduled = true
|
|
28
|
+
Promise.resolve().then(() => {
|
|
29
|
+
scheduled = false
|
|
30
|
+
frame = performance.now()
|
|
31
|
+
flush()
|
|
32
|
+
})
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function flush() {
|
|
37
|
+
if (batches.size === 0) {
|
|
38
|
+
return
|
|
39
|
+
}
|
|
40
|
+
for (const value of batches) {
|
|
41
|
+
if (onResolveItem) {
|
|
42
|
+
onResolveItem(value)
|
|
43
|
+
}
|
|
44
|
+
batches.delete(value)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (batches.size > RESCHEDULE_COUNT) {
|
|
48
|
+
schedule()
|
|
49
|
+
return
|
|
50
|
+
}
|
|
51
|
+
onFinish()
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function addValue(value: T) {
|
|
55
|
+
batches.add(value)
|
|
56
|
+
schedule()
|
|
57
|
+
}
|
|
58
|
+
return addValue
|
|
59
|
+
}
|