mutts 1.0.8 → 1.0.10
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 +77 -35
- package/dist/browser.cjs +2144 -5355
- package/dist/browser.cjs.map +1 -1
- package/dist/browser.d.ts +2 -1655
- package/dist/browser.dev.cjs +110 -0
- package/dist/browser.dev.cjs.map +1 -0
- package/dist/browser.dev.d.ts +2 -0
- package/dist/browser.dev.esm.js +5 -0
- package/dist/browser.dev.esm.js.map +1 -0
- package/dist/browser.esm.js +20 -107
- package/dist/browser.esm.js.map +1 -1
- package/dist/chunks/{async-browser-CA0jPWIi.cjs → async-browser-BU_IfxYD.cjs} +19 -107
- package/dist/chunks/async-browser-BU_IfxYD.cjs.map +1 -0
- package/dist/chunks/{async-core-UqHzvJ-S.cjs → async-core-CRLKP3l-.cjs} +8 -4
- package/dist/chunks/async-core-CRLKP3l-.cjs.map +1 -0
- package/dist/chunks/{async-node-BYHuGTni.cjs → async-node-3PrbVAbB.cjs} +7 -12
- package/dist/chunks/async-node-3PrbVAbB.cjs.map +1 -0
- package/dist/chunks/index-CaaQQlPJ.esm.js +3174 -0
- package/dist/chunks/index-CaaQQlPJ.esm.js.map +1 -0
- package/dist/chunks/node-nKJBk8iJ.esm.js +96 -0
- package/dist/chunks/node-nKJBk8iJ.esm.js.map +1 -0
- package/dist/chunks/proxy-Dtg-bJ3T.cjs +3763 -0
- package/dist/chunks/proxy-Dtg-bJ3T.cjs.map +1 -0
- package/dist/chunks/proxy-r7lARftl.esm.js +3701 -0
- package/dist/chunks/proxy-r7lARftl.esm.js.map +1 -0
- package/dist/debug.cjs +980 -0
- package/dist/debug.cjs.map +1 -0
- package/dist/debug.d.ts +208 -0
- package/dist/debug.esm.js +950 -0
- package/dist/debug.esm.js.map +1 -0
- package/dist/devtools/manifest.json +1 -1
- package/dist/devtools/panel.html +1 -1
- package/dist/devtools/panel.js +107 -94
- package/dist/devtools/panel.js.map +1 -1
- package/dist/index.d.ts +1447 -13
- package/dist/mutts.umd.js +7167 -1
- package/dist/mutts.umd.js.map +1 -1
- package/dist/mutts.umd.min.js +1 -1
- package/dist/mutts.umd.min.js.map +1 -1
- package/dist/node.cjs +70 -66
- package/dist/node.cjs.map +1 -1
- package/dist/node.d.ts +2 -1
- package/dist/node.dev.cjs +110 -0
- package/dist/node.dev.cjs.map +1 -0
- package/dist/node.dev.d.ts +2 -0
- package/dist/node.dev.esm.js +6 -0
- package/dist/node.dev.esm.js.map +1 -0
- package/dist/node.esm.js +4 -103
- package/dist/node.esm.js.map +1 -1
- package/dist/{reactive/types.d.ts → types-W5vD6m2n.d.ts} +186 -93
- package/docs/ai/api-reference.md +12 -19
- package/docs/ai/manual.md +521 -17
- package/docs/events.md +57 -2
- package/docs/flavored.md +210 -0
- package/docs/reactive/advanced.md +314 -5
- package/docs/reactive/attend.md +142 -0
- package/docs/reactive/collections.md +76 -39
- package/docs/reactive/core.md +100 -14
- package/docs/reactive/debugging.md +123 -18
- package/docs/reactive/error-handling.md +121 -0
- package/docs/reactive/resource.md +125 -0
- package/docs/reactive/scan.md +247 -1
- package/docs/reactive.md +4 -1
- package/docs/std-decorators.md +102 -51
- package/docs/utils.md +70 -0
- package/docs/zone.md +3 -7
- package/package.json +64 -30
- package/dist/async/browser.d.ts +0 -2
- package/dist/async/browser.d.ts.map +0 -1
- package/dist/async/index.d.ts +0 -18
- package/dist/async/index.d.ts.map +0 -1
- package/dist/async/node.d.ts +0 -2
- package/dist/async/node.d.ts.map +0 -1
- package/dist/chunks/async-browser-CA0jPWIi.cjs.map +0 -1
- package/dist/chunks/async-core-UqHzvJ-S.cjs.map +0 -1
- package/dist/chunks/async-node-BYHuGTni.cjs.map +0 -1
- package/dist/chunks/index-DhaOVusv.esm.js +0 -6411
- package/dist/chunks/index-DhaOVusv.esm.js.map +0 -1
- package/dist/decorator.d.ts +0 -106
- package/dist/decorator.d.ts.map +0 -1
- package/dist/destroyable.d.ts +0 -87
- package/dist/destroyable.d.ts.map +0 -1
- package/dist/entry-browser.d.ts +0 -3
- package/dist/entry-browser.d.ts.map +0 -1
- package/dist/entry-node.d.ts +0 -3
- package/dist/entry-node.d.ts.map +0 -1
- package/dist/eventful.d.ts +0 -18
- package/dist/eventful.d.ts.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/indexable.d.ts +0 -243
- package/dist/indexable.d.ts.map +0 -1
- package/dist/introspection.d.ts +0 -27
- package/dist/introspection.d.ts.map +0 -1
- package/dist/iterableWeak.d.ts +0 -53
- package/dist/iterableWeak.d.ts.map +0 -1
- package/dist/mixins.d.ts +0 -25
- package/dist/mixins.d.ts.map +0 -1
- package/dist/promiseChain.d.ts +0 -20
- package/dist/promiseChain.d.ts.map +0 -1
- package/dist/reactive/array.d.ts +0 -49
- package/dist/reactive/array.d.ts.map +0 -1
- package/dist/reactive/buffer.d.ts +0 -44
- package/dist/reactive/buffer.d.ts.map +0 -1
- package/dist/reactive/change.d.ts +0 -29
- package/dist/reactive/change.d.ts.map +0 -1
- package/dist/reactive/debug.d.ts +0 -111
- package/dist/reactive/debug.d.ts.map +0 -1
- package/dist/reactive/deep-touch.d.ts +0 -28
- package/dist/reactive/deep-touch.d.ts.map +0 -1
- package/dist/reactive/deep-watch-state.d.ts +0 -25
- package/dist/reactive/deep-watch-state.d.ts.map +0 -1
- package/dist/reactive/deep-watch.d.ts +0 -19
- package/dist/reactive/deep-watch.d.ts.map +0 -1
- package/dist/reactive/effect-context.d.ts +0 -7
- package/dist/reactive/effect-context.d.ts.map +0 -1
- package/dist/reactive/effects.d.ts +0 -151
- package/dist/reactive/effects.d.ts.map +0 -1
- package/dist/reactive/index.d.ts +0 -20
- package/dist/reactive/index.d.ts.map +0 -1
- package/dist/reactive/interface.d.ts +0 -64
- package/dist/reactive/interface.d.ts.map +0 -1
- package/dist/reactive/map.d.ts +0 -30
- package/dist/reactive/map.d.ts.map +0 -1
- package/dist/reactive/memoize.d.ts +0 -5
- package/dist/reactive/memoize.d.ts.map +0 -1
- package/dist/reactive/non-reactive-state.d.ts +0 -9
- package/dist/reactive/non-reactive-state.d.ts.map +0 -1
- package/dist/reactive/non-reactive.d.ts +0 -11
- package/dist/reactive/non-reactive.d.ts.map +0 -1
- package/dist/reactive/project.d.ts +0 -41
- package/dist/reactive/project.d.ts.map +0 -1
- package/dist/reactive/proxy-state.d.ts +0 -8
- package/dist/reactive/proxy-state.d.ts.map +0 -1
- package/dist/reactive/proxy.d.ts +0 -23
- package/dist/reactive/proxy.d.ts.map +0 -1
- package/dist/reactive/record.d.ts +0 -116
- package/dist/reactive/record.d.ts.map +0 -1
- package/dist/reactive/register.d.ts +0 -64
- package/dist/reactive/register.d.ts.map +0 -1
- package/dist/reactive/registry.d.ts +0 -20
- package/dist/reactive/registry.d.ts.map +0 -1
- package/dist/reactive/set.d.ts +0 -28
- package/dist/reactive/set.d.ts.map +0 -1
- package/dist/reactive/tracking.d.ts +0 -7
- package/dist/reactive/tracking.d.ts.map +0 -1
- package/dist/reactive/types.d.ts.map +0 -1
- package/dist/std-decorators.d.ts +0 -50
- package/dist/std-decorators.d.ts.map +0 -1
- package/dist/utils.d.ts +0 -49
- package/dist/utils.d.ts.map +0 -1
- package/dist/zone.d.ts +0 -40
- package/dist/zone.d.ts.map +0 -1
- package/docs/reactive/project.md +0 -93
- package/src/async/browser.ts +0 -319
- package/src/async/index.ts +0 -23
- package/src/async/node.ts +0 -104
- package/src/decorator.ts +0 -272
- package/src/destroyable.ts +0 -199
- package/src/entry-browser.ts +0 -5
- package/src/entry-node.ts +0 -5
- package/src/eventful.ts +0 -77
- package/src/index.d.ts +0 -12
- package/src/index.ts +0 -64
- package/src/indexable.ts +0 -526
- package/src/introspection.ts +0 -59
- package/src/iterableWeak.ts +0 -233
- package/src/mixins.ts +0 -123
- package/src/promiseChain.ts +0 -110
- package/src/reactive/array.ts +0 -507
- package/src/reactive/buffer.ts +0 -168
- package/src/reactive/change.ts +0 -138
- package/src/reactive/debug.ts +0 -517
- package/src/reactive/deep-touch.ts +0 -268
- package/src/reactive/deep-watch-state.ts +0 -82
- package/src/reactive/deep-watch.ts +0 -168
- package/src/reactive/effect-context.ts +0 -18
- package/src/reactive/effects.ts +0 -1382
- package/src/reactive/index.ts +0 -75
- package/src/reactive/interface.ts +0 -210
- package/src/reactive/map.ts +0 -158
- package/src/reactive/memoize.ts +0 -163
- package/src/reactive/non-reactive-state.ts +0 -49
- package/src/reactive/non-reactive.ts +0 -43
- package/src/reactive/project.ts +0 -453
- package/src/reactive/proxy-state.ts +0 -27
- package/src/reactive/proxy.ts +0 -264
- package/src/reactive/record.ts +0 -196
- package/src/reactive/register.ts +0 -419
- package/src/reactive/registry.ts +0 -59
- package/src/reactive/set.ts +0 -130
- package/src/reactive/tracking.ts +0 -44
- package/src/reactive/types.ts +0 -440
- package/src/std-decorators.ts +0 -217
- package/src/utils.ts +0 -301
- package/src/zone.ts +0 -138
package/src/reactive/array.ts
DELETED
|
@@ -1,507 +0,0 @@
|
|
|
1
|
-
import { FoolProof } from '../utils'
|
|
2
|
-
import { touched } from './change'
|
|
3
|
-
import { makeReactiveEntriesIterator, makeReactiveIterator } from './non-reactive'
|
|
4
|
-
import { reactive } from './proxy'
|
|
5
|
-
import { unwrap } from './proxy-state'
|
|
6
|
-
import { dependant } from './tracking'
|
|
7
|
-
|
|
8
|
-
function* index(i: number, { length = true } = {}): IterableIterator<number | 'length'> {
|
|
9
|
-
if (length) yield 'length'
|
|
10
|
-
yield i
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
function* range(
|
|
14
|
-
a: number,
|
|
15
|
-
b: number,
|
|
16
|
-
{ length = false } = {}
|
|
17
|
-
): IterableIterator<number | 'length'> {
|
|
18
|
-
const start = Math.min(a, b)
|
|
19
|
-
const end = Math.max(a, b)
|
|
20
|
-
if (length) yield 'length'
|
|
21
|
-
for (let i = start; i <= end; i++) yield i
|
|
22
|
-
}
|
|
23
|
-
export abstract class Indexer extends Array {
|
|
24
|
-
get(i: number): any {
|
|
25
|
-
dependant(this, i)
|
|
26
|
-
return reactive(this[i])
|
|
27
|
-
}
|
|
28
|
-
set(i: number, value: any) {
|
|
29
|
-
const added = i >= this.length
|
|
30
|
-
this[i] = value
|
|
31
|
-
touched(this, { type: 'set', prop: i }, index(i, { length: added }))
|
|
32
|
-
}
|
|
33
|
-
getLength() {
|
|
34
|
-
dependant(this, 'length')
|
|
35
|
-
return this.length
|
|
36
|
-
}
|
|
37
|
-
setLength(value: number) {
|
|
38
|
-
const oldLength = this.length
|
|
39
|
-
try {
|
|
40
|
-
this.length = value
|
|
41
|
-
} finally {
|
|
42
|
-
touched(this, { type: 'set', prop: 'length' }, range(oldLength, value, { length: true }))
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
const indexLess = { get: FoolProof.get, set: FoolProof.set }
|
|
47
|
-
Object.assign(FoolProof, {
|
|
48
|
-
get(obj: any, prop: any, receiver: any) {
|
|
49
|
-
if (obj instanceof Array && typeof prop === 'string') {
|
|
50
|
-
if (prop === 'length') return Indexer.prototype.getLength.call(obj)
|
|
51
|
-
const index = parseInt(prop)
|
|
52
|
-
if (!Number.isNaN(index)) return Indexer.prototype.get.call(obj, index)
|
|
53
|
-
}
|
|
54
|
-
return indexLess.get(obj, prop, receiver)
|
|
55
|
-
},
|
|
56
|
-
set(obj: any, prop: any, value: any, receiver: any) {
|
|
57
|
-
if (obj instanceof Array && typeof prop === 'string') {
|
|
58
|
-
if (prop === 'length') return Indexer.prototype.setLength.call(obj, value)
|
|
59
|
-
const index = parseInt(prop)
|
|
60
|
-
if (!Number.isNaN(index)) return Indexer.prototype.set.call(obj, index, value)
|
|
61
|
-
}
|
|
62
|
-
return indexLess.set(obj, prop, value, receiver)
|
|
63
|
-
},
|
|
64
|
-
})
|
|
65
|
-
|
|
66
|
-
export abstract class ReactiveArray extends Array {
|
|
67
|
-
toJSON() {
|
|
68
|
-
return this
|
|
69
|
-
}
|
|
70
|
-
get [Symbol.toStringTag]() {
|
|
71
|
-
return 'ReactiveArray'
|
|
72
|
-
}
|
|
73
|
-
// Safe array access with negative indices
|
|
74
|
-
at(index: number): any {
|
|
75
|
-
const actualIndex = index < 0 ? this.length + index : index
|
|
76
|
-
dependant(this, actualIndex)
|
|
77
|
-
if (index < 0) dependant(this, 'length')
|
|
78
|
-
if (actualIndex < 0 || actualIndex >= this.length) return undefined
|
|
79
|
-
return reactive(this[actualIndex])
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// Immutable versions of mutator methods
|
|
83
|
-
toReversed(): any[] {
|
|
84
|
-
dependant(this)
|
|
85
|
-
return reactive(this.toReversed())
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
toSorted(compareFn?: (a: any, b: any) => number): any[] {
|
|
89
|
-
dependant(this)
|
|
90
|
-
return reactive(this.toSorted(compareFn))
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
toSpliced(start: number, deleteCount?: number, ...items: any[]): any[] {
|
|
94
|
-
dependant(this)
|
|
95
|
-
return deleteCount === undefined
|
|
96
|
-
? this.toSpliced(start)
|
|
97
|
-
: this.toSpliced(start, deleteCount, ...items)
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
with(index: number, value: any): any[] {
|
|
101
|
-
dependant(this)
|
|
102
|
-
return reactive(this.with(index, value))
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
// Iterator methods with reactivity tracking
|
|
106
|
-
entries() {
|
|
107
|
-
dependant(this)
|
|
108
|
-
return makeReactiveEntriesIterator(this.entries())
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
keys() {
|
|
112
|
-
dependant(this, 'length')
|
|
113
|
-
return this.keys()
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
values() {
|
|
117
|
-
dependant(this)
|
|
118
|
-
return makeReactiveIterator(this.values())
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
[Symbol.iterator](): ArrayIterator<any> {
|
|
122
|
-
dependant(this)
|
|
123
|
-
const nativeIterator = this[Symbol.iterator]()
|
|
124
|
-
return {
|
|
125
|
-
next() {
|
|
126
|
-
const result = nativeIterator.next()
|
|
127
|
-
if (result.done) {
|
|
128
|
-
return result
|
|
129
|
-
}
|
|
130
|
-
return { value: reactive(result.value), done: false }
|
|
131
|
-
},
|
|
132
|
-
[Symbol.iterator]() {
|
|
133
|
-
return this
|
|
134
|
-
},
|
|
135
|
-
[Symbol.dispose]() {},
|
|
136
|
-
} as any
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
indexOf(searchElement: any, fromIndex?: number): number {
|
|
140
|
-
const length = this.length
|
|
141
|
-
let i = fromIndex === undefined ? 0 : fromIndex
|
|
142
|
-
if (i < 0) i = Math.max(length + i, 0)
|
|
143
|
-
|
|
144
|
-
const unwrappedSearch = unwrap(searchElement)
|
|
145
|
-
|
|
146
|
-
for (; i < length; i++) {
|
|
147
|
-
dependant(this, i)
|
|
148
|
-
const item = this[i]
|
|
149
|
-
if (item === searchElement || item === unwrappedSearch || unwrap(item) === unwrappedSearch) {
|
|
150
|
-
return i
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
dependant(this, 'length')
|
|
155
|
-
return -1
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
lastIndexOf(searchElement: any, fromIndex?: number): number {
|
|
159
|
-
const length = this.length
|
|
160
|
-
let i = fromIndex === undefined ? length - 1 : fromIndex
|
|
161
|
-
if (i >= length) i = length - 1
|
|
162
|
-
if (i < 0) i = Math.max(length + i, -1) // -1 ensures loop condition i >= 0 works correctly
|
|
163
|
-
|
|
164
|
-
const unwrappedSearch = unwrap(searchElement)
|
|
165
|
-
|
|
166
|
-
for (; i >= 0; i--) {
|
|
167
|
-
dependant(this, i)
|
|
168
|
-
const item = this[i]
|
|
169
|
-
if (item === searchElement || item === unwrappedSearch || unwrap(item) === unwrappedSearch) {
|
|
170
|
-
return i
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
// If we scanned the whole relevant part and didn't find it, we depend on length
|
|
175
|
-
// (because adding elements might shift indices or add the element)
|
|
176
|
-
// Actually for lastIndexOf, if we start from end, length dependency is implicit in the start index calculation?
|
|
177
|
-
// But if we return -1, it means we didn't find it.
|
|
178
|
-
// If we push an element, should lastIndexOf update?
|
|
179
|
-
// Yes, if the new element is the one we are looking for.
|
|
180
|
-
dependant(this, 'length')
|
|
181
|
-
return -1
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
includes(searchElement: any, fromIndex?: number): boolean {
|
|
185
|
-
return this.indexOf(searchElement, fromIndex) !== -1
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
find(predicate: (this: any, value: any, index: number, obj: any[]) => boolean, thisArg?: any): any
|
|
189
|
-
find(searchElement: any, fromIndex?: number): any
|
|
190
|
-
find(predicateOrElement: any, thisArg?: any): any {
|
|
191
|
-
if (typeof predicateOrElement === 'function') {
|
|
192
|
-
const predicate = predicateOrElement as (
|
|
193
|
-
this: any,
|
|
194
|
-
value: any,
|
|
195
|
-
index: number,
|
|
196
|
-
obj: any[]
|
|
197
|
-
) => boolean
|
|
198
|
-
const length = this.length
|
|
199
|
-
|
|
200
|
-
for (let i = 0; i < length; i++) {
|
|
201
|
-
dependant(this, i)
|
|
202
|
-
const val = reactive(this[i])
|
|
203
|
-
if (predicate.call(thisArg, val, i, this)) {
|
|
204
|
-
return val
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
dependant(this, 'length')
|
|
209
|
-
return undefined
|
|
210
|
-
}
|
|
211
|
-
const fromIndex = typeof thisArg === 'number' ? thisArg : undefined
|
|
212
|
-
const index = this.indexOf(predicateOrElement, fromIndex)
|
|
213
|
-
if (index === -1) return undefined
|
|
214
|
-
return reactive(this[index])
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
findIndex(
|
|
218
|
-
predicate: (this: any, value: any, index: number, obj: any[]) => boolean,
|
|
219
|
-
thisArg?: any
|
|
220
|
-
): number
|
|
221
|
-
findIndex(searchElement: any, fromIndex?: number): number
|
|
222
|
-
findIndex(predicateOrElement: any, thisArg?: any): number {
|
|
223
|
-
if (typeof predicateOrElement === 'function') {
|
|
224
|
-
const predicate = predicateOrElement as (
|
|
225
|
-
this: any,
|
|
226
|
-
value: any,
|
|
227
|
-
index: number,
|
|
228
|
-
obj: any[]
|
|
229
|
-
) => boolean
|
|
230
|
-
const length = this.length
|
|
231
|
-
|
|
232
|
-
for (let i = 0; i < length; i++) {
|
|
233
|
-
dependant(this, i)
|
|
234
|
-
const val = reactive(this[i])
|
|
235
|
-
if (predicate.call(thisArg, val, i, this)) {
|
|
236
|
-
return i
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
dependant(this, 'length')
|
|
241
|
-
return -1
|
|
242
|
-
}
|
|
243
|
-
const fromIndex = typeof thisArg === 'number' ? thisArg : undefined
|
|
244
|
-
return this.indexOf(predicateOrElement, fromIndex)
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
flat(depth?: number): any[] {
|
|
248
|
-
dependant(this)
|
|
249
|
-
return reactive(depth === undefined ? this.flat() : this.flat(depth))
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
flatMap(
|
|
253
|
-
callbackfn: (this: any, value: any, index: number, array: any[]) => any[],
|
|
254
|
-
thisArg?: any
|
|
255
|
-
): any[] {
|
|
256
|
-
dependant(this)
|
|
257
|
-
return reactive(
|
|
258
|
-
this.flatMap(
|
|
259
|
-
(item, index, array) => callbackfn.call(thisArg, reactive(item), index, array),
|
|
260
|
-
thisArg
|
|
261
|
-
)
|
|
262
|
-
)
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
filter(callbackfn: (value: any, index: number, array: any[]) => boolean, thisArg?: any): any[] {
|
|
266
|
-
dependant(this)
|
|
267
|
-
return reactive(
|
|
268
|
-
this.filter((item, index, array) => callbackfn(reactive(item), index, array), thisArg)
|
|
269
|
-
)
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
map(callbackfn: (value: any, index: number, array: any[]) => any, thisArg?: any): any[] {
|
|
273
|
-
dependant(this)
|
|
274
|
-
return reactive(
|
|
275
|
-
this.map((item, index, array) => callbackfn(reactive(item), index, array), thisArg)
|
|
276
|
-
)
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
reduce(
|
|
280
|
-
callbackfn: (previousValue: any, currentValue: any, currentIndex: number, array: any[]) => any,
|
|
281
|
-
initialValue?: any
|
|
282
|
-
): any {
|
|
283
|
-
dependant(this)
|
|
284
|
-
const result =
|
|
285
|
-
initialValue === undefined
|
|
286
|
-
? this.reduce(callbackfn as any)
|
|
287
|
-
: this.reduce(callbackfn as any, initialValue)
|
|
288
|
-
return reactive(result)
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
reduceRight(
|
|
292
|
-
callbackfn: (previousValue: any, currentValue: any, currentIndex: number, array: any[]) => any,
|
|
293
|
-
initialValue?: any
|
|
294
|
-
): any {
|
|
295
|
-
dependant(this)
|
|
296
|
-
const result =
|
|
297
|
-
initialValue !== undefined
|
|
298
|
-
? this.reduceRight(callbackfn as any, initialValue)
|
|
299
|
-
: (this as any).reduceRight(callbackfn as any)
|
|
300
|
-
return reactive(result)
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
slice(start?: number, end?: number): any[] {
|
|
304
|
-
for (const i of range(start || 0, end || this.length - 1)) dependant(this, i)
|
|
305
|
-
return start === undefined
|
|
306
|
-
? this.slice()
|
|
307
|
-
: end === undefined
|
|
308
|
-
? this.slice(start)
|
|
309
|
-
: this.slice(start, end)
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
concat(...items: any[]): any[] {
|
|
313
|
-
dependant(this)
|
|
314
|
-
return reactive(this.concat(...items))
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
join(separator?: string): string {
|
|
318
|
-
dependant(this)
|
|
319
|
-
return this.join(separator as any)
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
forEach(callbackfn: (value: any, index: number, array: any[]) => void, thisArg?: any): void {
|
|
323
|
-
dependant(this)
|
|
324
|
-
this.forEach((value, index, array) => {
|
|
325
|
-
callbackfn.call(thisArg, reactive(value), index, array)
|
|
326
|
-
})
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
// no need to make it dependant on indexes after the found one
|
|
330
|
-
every<S>(
|
|
331
|
-
predicate: (value: any, index: number, array: any[]) => value is S,
|
|
332
|
-
thisArg?: any
|
|
333
|
-
): this is S[]
|
|
334
|
-
every(callbackfn: (value: any, index: number, array: any[]) => boolean, thisArg?: any): boolean
|
|
335
|
-
every(callbackfn: (value: any, index: number, array: any[]) => boolean, thisArg?: any): boolean {
|
|
336
|
-
const length = this.length
|
|
337
|
-
|
|
338
|
-
for (let i = 0; i < length; i++) {
|
|
339
|
-
dependant(this, i)
|
|
340
|
-
if (!callbackfn.call(thisArg, reactive(this[i]), i, this)) {
|
|
341
|
-
return false
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
dependant(this, 'length')
|
|
346
|
-
return true
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
some(callbackfn: (value: any, index: number, array: any[]) => boolean, thisArg?: any): boolean {
|
|
350
|
-
const length = this.length
|
|
351
|
-
|
|
352
|
-
for (let i = 0; i < length; i++) {
|
|
353
|
-
dependant(this, i)
|
|
354
|
-
if (callbackfn.call(thisArg, reactive(this[i]), i, this)) {
|
|
355
|
-
return true
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
dependant(this, 'length')
|
|
360
|
-
return false
|
|
361
|
-
}
|
|
362
|
-
// Side-effectful
|
|
363
|
-
push(...items: any[]) {
|
|
364
|
-
const oldLength = this.length
|
|
365
|
-
try {
|
|
366
|
-
return this.push(...items)
|
|
367
|
-
} finally {
|
|
368
|
-
touched(
|
|
369
|
-
this,
|
|
370
|
-
{ type: 'bunch', method: 'push' },
|
|
371
|
-
range(oldLength, oldLength + items.length - 1, { length: true })
|
|
372
|
-
)
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
pop() {
|
|
377
|
-
if (this.length === 0) return undefined
|
|
378
|
-
try {
|
|
379
|
-
return reactive(this.pop())
|
|
380
|
-
} finally {
|
|
381
|
-
touched(this, { type: 'bunch', method: 'pop' }, index(this.length))
|
|
382
|
-
}
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
shift() {
|
|
386
|
-
if (this.length === 0) return undefined
|
|
387
|
-
try {
|
|
388
|
-
return reactive(this.shift())
|
|
389
|
-
} finally {
|
|
390
|
-
touched(this, { type: 'bunch', method: 'shift' }, range(0, this.length + 1, { length: true }))
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
unshift(...items: any[]) {
|
|
395
|
-
try {
|
|
396
|
-
return this.unshift(...items)
|
|
397
|
-
} finally {
|
|
398
|
-
touched(
|
|
399
|
-
this,
|
|
400
|
-
{ type: 'bunch', method: 'unshift' },
|
|
401
|
-
range(0, this.length - items.length, { length: true })
|
|
402
|
-
)
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
splice(start: number, deleteCount?: number, ...items: any[]) {
|
|
407
|
-
const oldLength = this.length
|
|
408
|
-
|
|
409
|
-
// Normalize start index
|
|
410
|
-
let actualStart = start
|
|
411
|
-
if (actualStart < 0) actualStart = Math.max(oldLength + actualStart, 0)
|
|
412
|
-
else actualStart = Math.min(actualStart, oldLength)
|
|
413
|
-
|
|
414
|
-
// Normalize deleteCount
|
|
415
|
-
let actualDeleteCount = deleteCount
|
|
416
|
-
if (actualDeleteCount === undefined) {
|
|
417
|
-
actualDeleteCount = oldLength - actualStart
|
|
418
|
-
} else {
|
|
419
|
-
actualDeleteCount = Math.max(0, Math.min(actualDeleteCount, oldLength - actualStart))
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
try {
|
|
423
|
-
if (deleteCount === undefined) return reactive(this.splice(start))
|
|
424
|
-
return reactive(this.splice(start, deleteCount, ...items))
|
|
425
|
-
} finally {
|
|
426
|
-
touched(
|
|
427
|
-
this,
|
|
428
|
-
{ type: 'bunch', method: 'splice' },
|
|
429
|
-
actualDeleteCount === items.length
|
|
430
|
-
? range(actualStart, actualStart + actualDeleteCount - 1)
|
|
431
|
-
: range(actualStart, oldLength + Math.max(items.length - actualDeleteCount, 0), {
|
|
432
|
-
length: true,
|
|
433
|
-
})
|
|
434
|
-
)
|
|
435
|
-
}
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
reverse() {
|
|
439
|
-
try {
|
|
440
|
-
return this.reverse()
|
|
441
|
-
} finally {
|
|
442
|
-
touched(this, { type: 'bunch', method: 'reverse' }, range(0, this.length - 1))
|
|
443
|
-
}
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
sort(compareFn?: (a: any, b: any) => number) {
|
|
447
|
-
compareFn = compareFn || ((a, b) => a.toString().localeCompare(b.toString()))
|
|
448
|
-
try {
|
|
449
|
-
return this.sort((a, b) => compareFn(reactive(a), reactive(b))) as any
|
|
450
|
-
} finally {
|
|
451
|
-
touched(this, { type: 'bunch', method: 'sort' }, range(0, this.length - 1))
|
|
452
|
-
}
|
|
453
|
-
}
|
|
454
|
-
|
|
455
|
-
fill(value: any, start?: number, end?: number) {
|
|
456
|
-
const len = this.length
|
|
457
|
-
let k = start === undefined ? 0 : start
|
|
458
|
-
if (k < 0) k = Math.max(len + k, 0)
|
|
459
|
-
else k = Math.min(k, len)
|
|
460
|
-
|
|
461
|
-
let final = end === undefined ? len : end
|
|
462
|
-
if (final < 0) final = Math.max(len + final, 0)
|
|
463
|
-
else final = Math.min(final, len)
|
|
464
|
-
|
|
465
|
-
try {
|
|
466
|
-
if (start === undefined) return this.fill(value) as any
|
|
467
|
-
if (end === undefined) return this.fill(value, start) as any
|
|
468
|
-
return this.fill(value, start, end) as any
|
|
469
|
-
} finally {
|
|
470
|
-
if (final > k) {
|
|
471
|
-
touched(this, { type: 'bunch', method: 'fill' }, range(k, final - 1))
|
|
472
|
-
}
|
|
473
|
-
}
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
copyWithin(target: number, start: number, end?: number) {
|
|
477
|
-
try {
|
|
478
|
-
if (end === undefined) return this.copyWithin(target, start) as any
|
|
479
|
-
return this.copyWithin(target, start, end) as any
|
|
480
|
-
} finally {
|
|
481
|
-
const len = this.length
|
|
482
|
-
|
|
483
|
-
let to = target
|
|
484
|
-
if (to < 0) to = Math.max(len + to, 0)
|
|
485
|
-
else if (to >= len) to = len
|
|
486
|
-
|
|
487
|
-
let from = start
|
|
488
|
-
if (from < 0) from = Math.max(len + from, 0)
|
|
489
|
-
else if (from >= len) from = len
|
|
490
|
-
|
|
491
|
-
let final = end === undefined ? len : end
|
|
492
|
-
if (final < 0) final = Math.max(len + final, 0)
|
|
493
|
-
else if (final >= len) final = len
|
|
494
|
-
|
|
495
|
-
const count = Math.min(final - from, len - to)
|
|
496
|
-
|
|
497
|
-
if (count > 0) {
|
|
498
|
-
touched(
|
|
499
|
-
this,
|
|
500
|
-
{ type: 'bunch', method: 'copyWithin' },
|
|
501
|
-
range(to, to + count - 1)
|
|
502
|
-
)
|
|
503
|
-
}
|
|
504
|
-
|
|
505
|
-
}
|
|
506
|
-
}
|
|
507
|
-
}
|
package/src/reactive/buffer.ts
DELETED
|
@@ -1,168 +0,0 @@
|
|
|
1
|
-
import { FoolProof } from '../utils'
|
|
2
|
-
import { effect, untracked } from './effects'
|
|
3
|
-
import { cleanedBy, cleanup } from './interface'
|
|
4
|
-
import { memoize } from './memoize'
|
|
5
|
-
import { reactive } from './proxy'
|
|
6
|
-
import type { ScopedCallback } from './types'
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Result of a reactive scan, which is a reactive array of accumulated values
|
|
10
|
-
* with an attached cleanup function.
|
|
11
|
-
*/
|
|
12
|
-
export type ScanResult<Output> = readonly Output[] & { [cleanup]: ScopedCallback }
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Perform a reactive scan over an array of items.
|
|
16
|
-
*
|
|
17
|
-
* This implementation is highly optimized for performance and fine-grained reactivity:
|
|
18
|
-
* - **Incremental Updates**: Changes to an item only trigger re-computation from that
|
|
19
|
-
* point onwards in the result chain.
|
|
20
|
-
* - **Move Optimization**: If items are moved within the array, their accumulated
|
|
21
|
-
* values are reused as long as their predecessor remains the same.
|
|
22
|
-
* - **Duplicate Support**: Correctly handles multiple occurrences of the same object
|
|
23
|
-
* instance using an internal occurrence tracking mechanism.
|
|
24
|
-
* - **Memory Efficient**: Uses `WeakMap` for caching intermediates, which are
|
|
25
|
-
* automatically cleared when source items are garbage collected.
|
|
26
|
-
*
|
|
27
|
-
* @example
|
|
28
|
-
* ```typescript
|
|
29
|
-
* const source = reactive([{ val: 1 }, { val: 2 }, { val: 3 }])
|
|
30
|
-
* const sum = scan(source, (acc, item) => acc + item.val, 0)
|
|
31
|
-
*
|
|
32
|
-
* expect([...sum]).toEqual([1, 3, 6])
|
|
33
|
-
*
|
|
34
|
-
* // Modifying an item only re-computes subsequent sums
|
|
35
|
-
* source[1].val = 10
|
|
36
|
-
* expect([...sum]).toEqual([1, 11, 14])
|
|
37
|
-
* ```
|
|
38
|
-
*
|
|
39
|
-
* @param source The source array of objects (will be made reactive)
|
|
40
|
-
* @param callback The accumulator function called with (accumulator, currentItem)
|
|
41
|
-
* @param initialValue The starting value for the accumulation
|
|
42
|
-
* @returns A reactive array of accumulated values, with a [cleanup] property to stop the tracking
|
|
43
|
-
*/
|
|
44
|
-
export function scan<Input extends object, Output>(
|
|
45
|
-
source: readonly Input[],
|
|
46
|
-
callback: (acc: Output, val: Input) => Output,
|
|
47
|
-
initialValue: Output
|
|
48
|
-
): ScanResult<Output> {
|
|
49
|
-
const observedSource = reactive(source)
|
|
50
|
-
const result = reactive([] as Output[])
|
|
51
|
-
|
|
52
|
-
// Track effects for each index to dispose them when the array shrinks
|
|
53
|
-
const indexEffects = new Map<number, ScopedCallback>()
|
|
54
|
-
// Mapping from index to its current intermediate object
|
|
55
|
-
const indexToIntermediate = reactive([] as Intermediate[])
|
|
56
|
-
const intermediaries = new WeakMap<Input, Intermediate[]>()
|
|
57
|
-
|
|
58
|
-
class Intermediate {
|
|
59
|
-
public prev: Intermediate | undefined
|
|
60
|
-
constructor(public val: Input, prev: Intermediate | undefined) {
|
|
61
|
-
this.prev = prev
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
@memoize
|
|
65
|
-
get acc(): Output {
|
|
66
|
-
const prevAcc = this.prev ? this.prev.acc : initialValue
|
|
67
|
-
return callback(prevAcc, this.val)
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
function disposeIndex(index: number) {
|
|
72
|
-
const stop = indexEffects.get(index)
|
|
73
|
-
if (stop) {
|
|
74
|
-
stop()
|
|
75
|
-
indexEffects.delete(index)
|
|
76
|
-
untracked(() => {
|
|
77
|
-
Reflect.deleteProperty(indexToIntermediate as any, index)
|
|
78
|
-
Reflect.deleteProperty(result as any, index)
|
|
79
|
-
})
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
const mainEffect = effect(function scanMainEffect({ ascend }) {
|
|
84
|
-
const length = observedSource.length
|
|
85
|
-
const occurrenceCount = new Map<Input, number>()
|
|
86
|
-
let prev: Intermediate | undefined = undefined
|
|
87
|
-
|
|
88
|
-
for (let i = 0; i < length; i++) {
|
|
89
|
-
const val = FoolProof.get(observedSource as any, i, observedSource) as Input
|
|
90
|
-
|
|
91
|
-
if (!(val && (typeof val === 'object' || typeof val === 'function' || typeof val === 'symbol'))) {
|
|
92
|
-
throw new Error('scan: items must be objects (WeakKey) for intermediate caching')
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
const count = occurrenceCount.get(val) ?? 0
|
|
96
|
-
occurrenceCount.set(val, count + 1)
|
|
97
|
-
|
|
98
|
-
let list = intermediaries.get(val)
|
|
99
|
-
if (!list) {
|
|
100
|
-
list = []
|
|
101
|
-
intermediaries.set(val, list)
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
let intermediate = list[count]
|
|
105
|
-
if (!intermediate) {
|
|
106
|
-
intermediate = reactive(new Intermediate(val, prev))
|
|
107
|
-
list[count] = intermediate
|
|
108
|
-
} else {
|
|
109
|
-
// Update the link.
|
|
110
|
-
if (untracked(() => intermediate.prev) !== prev) {
|
|
111
|
-
intermediate.prev = prev
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
// Update the reactive mapping for this index
|
|
116
|
-
if (indexToIntermediate[i] !== intermediate) {
|
|
117
|
-
indexToIntermediate[i] = intermediate
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
// If we don't have an effect for this index yet, create one
|
|
121
|
-
if (!indexEffects.has(i)) {
|
|
122
|
-
ascend(() => {
|
|
123
|
-
const index = i
|
|
124
|
-
const stop = effect(function scanIndexSyncEffect() {
|
|
125
|
-
const inter = indexToIntermediate[index]
|
|
126
|
-
if (inter) {
|
|
127
|
-
const accValue = inter.acc
|
|
128
|
-
untracked(() => {
|
|
129
|
-
result[index] = accValue
|
|
130
|
-
})
|
|
131
|
-
}
|
|
132
|
-
})
|
|
133
|
-
indexEffects.set(index, stop)
|
|
134
|
-
})
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
prev = intermediate
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
// Cleanup trailing indices
|
|
141
|
-
for (const index of Array.from(indexEffects.keys())) {
|
|
142
|
-
if (index >= length) disposeIndex(index)
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
// Ensure result length matches source length
|
|
146
|
-
untracked(() => {
|
|
147
|
-
if (result.length !== length) {
|
|
148
|
-
FoolProof.set(result as any, 'length', length, result)
|
|
149
|
-
}
|
|
150
|
-
})
|
|
151
|
-
})
|
|
152
|
-
|
|
153
|
-
return cleanedBy(result, () => {
|
|
154
|
-
mainEffect()
|
|
155
|
-
for (const stop of indexEffects.values()) stop()
|
|
156
|
-
indexEffects.clear()
|
|
157
|
-
}) as ScanResult<Output>
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
export function resolve<Output>(cb: () => Output[]): Output[] & { [cleanup]: ScopedCallback } {
|
|
161
|
-
const result = reactive([] as Output[])
|
|
162
|
-
return cleanedBy(result, effect(() => {
|
|
163
|
-
const source = cb()
|
|
164
|
-
if (result.length !== source.length) result.length = source.length
|
|
165
|
-
for (let i = 0; i < source.length; i++)
|
|
166
|
-
if (result[i] !== source[i]) result[i] = source[i]
|
|
167
|
-
}))
|
|
168
|
-
}
|