mutts 1.0.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/dist/chunks/{decorator-BXsign4Z.js → decorator-8qjFb7dw.js} +2 -2
  2. package/dist/chunks/decorator-8qjFb7dw.js.map +1 -0
  3. package/dist/chunks/{decorator-CPbZNnsX.esm.js → decorator-AbRkXM5O.esm.js} +2 -2
  4. package/dist/chunks/decorator-AbRkXM5O.esm.js.map +1 -0
  5. package/dist/decorator.d.ts +1 -1
  6. package/dist/decorator.esm.js +1 -1
  7. package/dist/decorator.js +1 -1
  8. package/dist/destroyable.esm.js +1 -1
  9. package/dist/destroyable.js +1 -1
  10. package/dist/index.d.ts +1 -1
  11. package/dist/index.esm.js +2 -2
  12. package/dist/index.js +2 -1
  13. package/dist/index.js.map +1 -1
  14. package/dist/mutts.umd.js +1 -1
  15. package/dist/mutts.umd.js.map +1 -1
  16. package/dist/mutts.umd.min.js +1 -1
  17. package/dist/mutts.umd.min.js.map +1 -1
  18. package/dist/reactive.d.ts +4 -3
  19. package/dist/reactive.esm.js +61 -57
  20. package/dist/reactive.esm.js.map +1 -1
  21. package/dist/reactive.js +61 -56
  22. package/dist/reactive.js.map +1 -1
  23. package/dist/std-decorators.esm.js +1 -1
  24. package/dist/std-decorators.js +1 -1
  25. package/docs/reactive.md +616 -0
  26. package/package.json +1 -2
  27. package/dist/chunks/decorator-BXsign4Z.js.map +0 -1
  28. package/dist/chunks/decorator-CPbZNnsX.esm.js.map +0 -1
  29. package/src/decorator.test.ts +0 -495
  30. package/src/decorator.ts +0 -205
  31. package/src/destroyable.test.ts +0 -155
  32. package/src/destroyable.ts +0 -158
  33. package/src/eventful.test.ts +0 -380
  34. package/src/eventful.ts +0 -69
  35. package/src/index.ts +0 -7
  36. package/src/indexable.test.ts +0 -388
  37. package/src/indexable.ts +0 -124
  38. package/src/promiseChain.test.ts +0 -201
  39. package/src/promiseChain.ts +0 -99
  40. package/src/reactive/array.test.ts +0 -923
  41. package/src/reactive/array.ts +0 -352
  42. package/src/reactive/core.test.ts +0 -1663
  43. package/src/reactive/core.ts +0 -866
  44. package/src/reactive/index.ts +0 -28
  45. package/src/reactive/interface.test.ts +0 -1477
  46. package/src/reactive/interface.ts +0 -231
  47. package/src/reactive/map.test.ts +0 -866
  48. package/src/reactive/map.ts +0 -162
  49. package/src/reactive/set.test.ts +0 -289
  50. package/src/reactive/set.ts +0 -142
  51. package/src/std-decorators.test.ts +0 -679
  52. package/src/std-decorators.ts +0 -182
  53. package/src/utils.ts +0 -52
@@ -1,162 +0,0 @@
1
- import {
2
- dependant,
3
- makeReactiveEntriesIterator,
4
- makeReactiveIterator,
5
- prototypeForwarding,
6
- reactive,
7
- touched,
8
- touched1,
9
- } from './core'
10
-
11
- const native = Symbol('native')
12
-
13
- // TODO: [prototypeForwarding]
14
-
15
- export class ReactiveWeakMap<K extends object, V> {
16
- declare readonly [native]: WeakMap<K, V>
17
- declare readonly content: symbol
18
- constructor(original: WeakMap<K, V>) {
19
- Object.defineProperties(this, {
20
- [native]: { value: original },
21
- [prototypeForwarding]: { value: original },
22
- content: { value: Symbol('content') },
23
- [Symbol.toStringTag]: { value: 'ReactiveWeakMap' },
24
- })
25
- }
26
-
27
- // Implement WeakMap interface methods with reactivity
28
- delete(key: K): boolean {
29
- const hadKey = this[native].has(key)
30
- const result = this[native].delete(key)
31
-
32
- if (hadKey) touched1(this.content, { type: 'del', prop: key }, key)
33
-
34
- return result
35
- }
36
-
37
- get(key: K): V | undefined {
38
- dependant(this.content, key)
39
- return reactive(this[native].get(key))
40
- }
41
-
42
- has(key: K): boolean {
43
- dependant(this.content, key)
44
- return this[native].has(key)
45
- }
46
-
47
- set(key: K, value: V): this {
48
- // Trigger effects for the specific key
49
- touched1(this.content, { type: this[native].has(key) ? 'set' : 'add', prop: key }, key)
50
- this[native].set(key, value)
51
-
52
- return this
53
- }
54
- }
55
-
56
- export class ReactiveMap<K, V> {
57
- declare readonly [native]: Map<K, V>
58
- declare readonly content: symbol
59
-
60
- constructor(original: Map<K, V>) {
61
- Object.defineProperties(this, {
62
- [native]: { value: original },
63
- [prototypeForwarding]: { value: original },
64
- content: { value: Symbol('content') },
65
- [Symbol.toStringTag]: { value: 'ReactiveMap' },
66
- })
67
- }
68
-
69
- // Implement Map interface methods with reactivity
70
- get size(): number {
71
- dependant(this, 'size') // The ReactiveMap instance still goes through proxy
72
- return this[native].size
73
- }
74
-
75
- clear(): void {
76
- const hadEntries = this[native].size > 0
77
- this[native].clear()
78
-
79
- if (hadEntries) {
80
- const evolution = { type: 'bunch', method: 'clear' } as const
81
- // Clear triggers all effects since all keys are affected
82
- touched1(this, evolution, 'size')
83
- touched(this.content, evolution)
84
- }
85
- }
86
-
87
- entries(): Generator<[K, V]> {
88
- dependant(this.content)
89
- return makeReactiveEntriesIterator(this[native].entries())
90
- }
91
-
92
- forEach(callbackfn: (value: V, key: K, map: Map<K, V>) => void, thisArg?: any): void {
93
- dependant(this.content)
94
- this[native].forEach(callbackfn, thisArg)
95
- }
96
-
97
- keys(): MapIterator<K> {
98
- dependant(this.content)
99
- return this[native].keys()
100
- }
101
-
102
- values(): Generator<V> {
103
- dependant(this.content)
104
- return makeReactiveIterator(this[native].values())
105
- }
106
-
107
- [Symbol.iterator](): Iterator<[K, V]> {
108
- dependant(this.content)
109
- const nativeIterator = this[native][Symbol.iterator]()
110
- return {
111
- next() {
112
- const result = nativeIterator.next()
113
- if (result.done) {
114
- return result
115
- }
116
- return {
117
- value: [result.value[0], reactive(result.value[1])],
118
- done: false,
119
- }
120
- },
121
- }
122
- }
123
-
124
- // Implement Map methods with reactivity
125
- delete(key: K): boolean {
126
- const hadKey = this[native].has(key)
127
- const result = this[native].delete(key)
128
-
129
- if (hadKey) {
130
- const evolution = { type: 'del', prop: key } as const
131
- touched1(this.content, evolution, key)
132
- touched1(this, evolution, 'size')
133
- }
134
-
135
- return result
136
- }
137
-
138
- get(key: K): V | undefined {
139
- dependant(this.content, key)
140
- return reactive(this[native].get(key))
141
- }
142
-
143
- has(key: K): boolean {
144
- dependant(this.content, key)
145
- return this[native].has(key)
146
- }
147
-
148
- set(key: K, value: V): this {
149
- const hadKey = this[native].has(key)
150
- const oldValue = this[native].get(key)
151
- const reactiveValue = reactive(value)
152
- this[native].set(key, reactiveValue)
153
-
154
- if (!hadKey || oldValue !== reactiveValue) {
155
- const evolution = { type: hadKey ? 'set' : 'add', prop: key } as const
156
- touched1(this.content, evolution, key)
157
- touched1(this, evolution, 'size')
158
- }
159
-
160
- return this
161
- }
162
- }
@@ -1,289 +0,0 @@
1
- import { effect, reactive } from './index'
2
-
3
- describe('ReactiveWeakSet', () => {
4
- describe('reactive operations', () => {
5
- it('should track dependencies when checking existence', () => {
6
- const ws = new WeakSet<object>()
7
- const rws = reactive(ws)
8
- const key = { id: 1 }
9
-
10
- let count = 0
11
- effect(() => {
12
- count++
13
- rws.has(key)
14
- })
15
-
16
- expect(count).toBe(1)
17
- rws.add(key)
18
- expect(count).toBe(2)
19
- rws.delete(key)
20
- expect(count).toBe(3)
21
- })
22
-
23
- it('should not trigger when deleting non-existent keys', () => {
24
- const ws = new WeakSet<object>()
25
- const rws = reactive(ws)
26
- const key = { id: 1 }
27
-
28
- let count = 0
29
- effect(() => {
30
- count++
31
- rws.has(key)
32
- })
33
-
34
- expect(count).toBe(1)
35
- rws.delete(key)
36
- expect(count).toBe(1)
37
- })
38
- })
39
-
40
- describe('toStringTag', () => {
41
- it('should have correct toStringTag', () => {
42
- const ws = new WeakSet<object>()
43
- const rws = reactive(ws)
44
- expect(rws[Symbol.toStringTag]).toBe('ReactiveWeakSet')
45
- })
46
- })
47
- })
48
-
49
- describe('ReactiveSet', () => {
50
- describe('reactive operations', () => {
51
- it('should track size dependencies', () => {
52
- const s = new Set<number>()
53
- const rs = reactive(s)
54
-
55
- let count = 0
56
- effect(() => {
57
- count++
58
- rs.size
59
- })
60
-
61
- expect(count).toBe(1)
62
- rs.add(1)
63
- expect(count).toBe(2)
64
- })
65
-
66
- it('should track dependencies when checking existence', () => {
67
- const s = new Set<number>()
68
- const rs = reactive(s)
69
- rs.add(1)
70
-
71
- let count = 0
72
- effect(() => {
73
- count++
74
- rs.has(1)
75
- })
76
-
77
- expect(count).toBe(1)
78
- rs.add(2)
79
- expect(count).toBe(1)
80
- rs.delete(1)
81
- expect(count).toBe(2)
82
- })
83
-
84
- it('should trigger effects when adding new values', () => {
85
- const s = new Set<number>()
86
- const rs = reactive(s)
87
-
88
- let count = 0
89
- effect(() => {
90
- count++
91
- rs.has(1)
92
- })
93
-
94
- expect(count).toBe(1)
95
- rs.add(1)
96
- expect(count).toBe(2)
97
- })
98
-
99
- it('should trigger effects when deleting values', () => {
100
- const s = new Set<number>()
101
- const rs = reactive(s)
102
- rs.add(1)
103
-
104
- let count = 0
105
- effect(() => {
106
- count++
107
- rs.has(1)
108
- })
109
-
110
- expect(count).toBe(1)
111
- rs.delete(1)
112
- expect(count).toBe(2)
113
- })
114
-
115
- it('should not trigger effects when deleting non-existent values', () => {
116
- const s = new Set<number>()
117
- const rs = reactive(s)
118
-
119
- let count = 0
120
- effect(() => {
121
- count++
122
- rs.has(1)
123
- })
124
-
125
- expect(count).toBe(1)
126
- rs.delete(1)
127
- expect(count).toBe(1)
128
- })
129
- })
130
-
131
- describe('allProps reactivity', () => {
132
- it('should trigger allProps effects when adding values', () => {
133
- const s = new Set<number>()
134
- const rs = reactive(s)
135
-
136
- let allPropsCount = 0
137
- effect(() => {
138
- allPropsCount++
139
- // Use iteration to depend on all entries
140
- for (const _v of rs.entries()) {
141
- }
142
- })
143
-
144
- expect(allPropsCount).toBe(1)
145
- rs.add(1)
146
- expect(allPropsCount).toBe(2)
147
- rs.add(2)
148
- expect(allPropsCount).toBe(3)
149
- })
150
-
151
- it('should trigger allProps effects when deleting values', () => {
152
- const s = new Set<number>()
153
- const rs = reactive(s)
154
- rs.add(1)
155
- rs.add(2)
156
-
157
- let allPropsCount = 0
158
- effect(() => {
159
- allPropsCount++
160
- rs.keys()
161
- })
162
-
163
- expect(allPropsCount).toBe(1)
164
- rs.delete(1)
165
- expect(allPropsCount).toBe(2)
166
- rs.delete(2)
167
- expect(allPropsCount).toBe(3)
168
- })
169
-
170
- it('should trigger allProps effects when clearing', () => {
171
- const s = new Set<number>()
172
- const rs = reactive(s)
173
- rs.add(1)
174
- rs.add(2)
175
-
176
- let sizeCount = 0
177
- let allPropsCount = 0
178
- effect(() => {
179
- sizeCount++
180
- rs.size
181
- })
182
- effect(() => {
183
- allPropsCount++
184
- rs.values()
185
- })
186
-
187
- expect(sizeCount).toBe(1)
188
- expect(allPropsCount).toBe(1)
189
- rs.clear()
190
- expect(sizeCount).toBe(2)
191
- expect(allPropsCount).toBe(2)
192
- })
193
- })
194
-
195
- describe('iteration methods', () => {
196
- it('should track allProps for entries()', () => {
197
- const rs = reactive(new Set<number>())
198
-
199
- let count = 0
200
- effect(() => {
201
- count++
202
- rs.entries()
203
- })
204
-
205
- expect(count).toBe(1)
206
- rs.add(1)
207
- expect(count).toBe(2)
208
- })
209
-
210
- it('should track allProps for forEach()', () => {
211
- const rs = reactive(new Set<number>())
212
-
213
- let count = 0
214
- effect(() => {
215
- count++
216
- rs.forEach(() => {})
217
- })
218
-
219
- expect(count).toBe(1)
220
- rs.add(1)
221
- expect(count).toBe(2)
222
- })
223
-
224
- it('should track allProps for keys() and values() and iterator', () => {
225
- const rs = reactive(new Set<number>())
226
-
227
- let countKeys = 0
228
- let countValues = 0
229
- let countIter = 0
230
-
231
- effect(() => {
232
- countKeys++
233
- rs.keys()
234
- })
235
-
236
- effect(() => {
237
- countValues++
238
- rs.values()
239
- })
240
-
241
- effect(() => {
242
- countIter++
243
- for (const _v of rs) {
244
- }
245
- })
246
-
247
- expect(countKeys).toBe(1)
248
- expect(countValues).toBe(1)
249
- expect(countIter).toBe(1)
250
-
251
- rs.add(1)
252
- expect(countKeys).toBe(2)
253
- expect(countValues).toBe(2)
254
- expect(countIter).toBe(2)
255
- })
256
- })
257
-
258
- describe('seamless reactive integration', () => {
259
- it('should automatically create ReactiveSet when using reactive() on native Set', () => {
260
- const nativeSet = new Set([1, 2])
261
- const rs = reactive(nativeSet)
262
- expect(rs.size).toBe(2)
263
- // dependency tracking
264
- let count = 0
265
- effect(() => {
266
- count++
267
- rs.has(1)
268
- })
269
- expect(count).toBe(1)
270
- rs.delete(1)
271
- expect(count).toBe(2)
272
- })
273
-
274
- it('should automatically create ReactiveWeakSet when using reactive() on native WeakSet', () => {
275
- const k = { id: 1 }
276
- const native = new WeakSet([k])
277
- const rws = reactive(native)
278
-
279
- let count = 0
280
- effect(() => {
281
- count++
282
- rws.has(k)
283
- })
284
- expect(count).toBe(1)
285
- rws.delete(k)
286
- expect(count).toBe(2)
287
- })
288
- })
289
- })
@@ -1,142 +0,0 @@
1
- import {
2
- dependant,
3
- makeReactiveEntriesIterator,
4
- makeReactiveIterator,
5
- prototypeForwarding,
6
- reactive,
7
- touched,
8
- touched1,
9
- } from './core'
10
-
11
- const native = Symbol('native')
12
-
13
- // TODO: [prototypeForwarding]
14
-
15
- export class ReactiveWeakSet<T extends object> {
16
- declare readonly [native]: WeakSet<T>
17
- declare readonly content: symbol
18
-
19
- constructor(original: WeakSet<T>) {
20
- Object.defineProperties(this, {
21
- [native]: { value: original },
22
- [prototypeForwarding]: { value: original },
23
- content: { value: Symbol('content') },
24
- [Symbol.toStringTag]: { value: 'ReactiveWeakSet' },
25
- })
26
- }
27
-
28
- add(value: T): this {
29
- const had = this[native].has(value)
30
- this[native].add(value)
31
- if (!had) {
32
- // touch the specific value and the collection view
33
- touched1(this.content, { type: 'add', prop: value }, value)
34
- // no size/allProps for WeakSet
35
- }
36
- return this
37
- }
38
-
39
- delete(value: T): boolean {
40
- const had = this[native].has(value)
41
- const res = this[native].delete(value)
42
- if (had) touched1(this.content, { type: 'del', prop: value }, value)
43
- return res
44
- }
45
-
46
- has(value: T): boolean {
47
- dependant(this.content, value)
48
- return this[native].has(value)
49
- }
50
- }
51
-
52
- export class ReactiveSet<T> {
53
- declare readonly [native]: Set<T>
54
- declare readonly content: symbol
55
- constructor(original: Set<T>) {
56
- Object.defineProperties(this, {
57
- [native]: { value: original },
58
- [prototypeForwarding]: { value: original },
59
- content: { value: Symbol('content') },
60
- [Symbol.toStringTag]: { value: 'ReactiveSet' },
61
- })
62
- }
63
-
64
- get size(): number {
65
- // size depends on the wrapper instance, like Map counterpart
66
- dependant(this, 'size')
67
- return this[native].size
68
- }
69
-
70
- add(value: T): this {
71
- const had = this[native].has(value)
72
- const reactiveValue = reactive(value)
73
- this[native].add(reactiveValue)
74
- if (!had) {
75
- const evolution = { type: 'add', prop: reactiveValue } as const
76
- // touch for value-specific and aggregate dependencies
77
- touched1(this.content, evolution, reactiveValue)
78
- touched1(this, evolution, 'size')
79
- }
80
- return this
81
- }
82
-
83
- clear(): void {
84
- const hadEntries = this[native].size > 0
85
- this[native].clear()
86
- if (hadEntries) {
87
- const evolution = { type: 'bunch', method: 'clear' } as const
88
- touched1(this, evolution, 'size')
89
- touched(this.content, evolution)
90
- }
91
- }
92
-
93
- delete(value: T): boolean {
94
- const had = this[native].has(value)
95
- const res = this[native].delete(value)
96
- if (had) {
97
- const evolution = { type: 'del', prop: value } as const
98
- touched1(this.content, evolution, value)
99
- touched1(this, evolution, 'size')
100
- }
101
- return res
102
- }
103
-
104
- has(value: T): boolean {
105
- dependant(this.content, value)
106
- return this[native].has(value)
107
- }
108
-
109
- entries(): Generator<[T, T]> {
110
- dependant(this.content)
111
- return makeReactiveEntriesIterator(this[native].entries())
112
- }
113
-
114
- forEach(callbackfn: (value: T, value2: T, set: Set<T>) => void, thisArg?: any): void {
115
- dependant(this.content)
116
- this[native].forEach(callbackfn, thisArg)
117
- }
118
-
119
- keys(): Generator<T> {
120
- dependant(this.content)
121
- return makeReactiveIterator(this[native].keys())
122
- }
123
-
124
- values(): Generator<T> {
125
- dependant(this.content)
126
- return makeReactiveIterator(this[native].values())
127
- }
128
-
129
- [Symbol.iterator](): Iterator<T> {
130
- dependant(this.content)
131
- const nativeIterator = this[native][Symbol.iterator]()
132
- return {
133
- next() {
134
- const result = nativeIterator.next()
135
- if (result.done) {
136
- return result
137
- }
138
- return { value: reactive(result.value), done: false }
139
- },
140
- }
141
- }
142
- }