mutts 1.0.6 → 1.0.8

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 (196) hide show
  1. package/README.md +61 -23
  2. package/dist/async/browser.d.ts +2 -0
  3. package/dist/async/browser.d.ts.map +1 -0
  4. package/dist/async/index.d.ts +18 -0
  5. package/dist/async/index.d.ts.map +1 -0
  6. package/dist/async/node.d.ts +2 -0
  7. package/dist/async/node.d.ts.map +1 -0
  8. package/dist/{chunks/index-CDCOjzTy.js → browser.cjs} +5913 -4382
  9. package/dist/browser.cjs.map +1 -0
  10. package/dist/browser.d.ts +1655 -0
  11. package/dist/browser.esm.js +305 -0
  12. package/dist/browser.esm.js.map +1 -0
  13. package/dist/chunks/async-browser-CA0jPWIi.cjs +304 -0
  14. package/dist/chunks/async-browser-CA0jPWIi.cjs.map +1 -0
  15. package/dist/chunks/async-core-UqHzvJ-S.cjs +25 -0
  16. package/dist/chunks/async-core-UqHzvJ-S.cjs.map +1 -0
  17. package/dist/chunks/async-node-BYHuGTni.cjs +103 -0
  18. package/dist/chunks/async-node-BYHuGTni.cjs.map +1 -0
  19. package/dist/chunks/{index-DiP0RXoZ.esm.js → index-DhaOVusv.esm.js} +5851 -4345
  20. package/dist/chunks/index-DhaOVusv.esm.js.map +1 -0
  21. package/dist/decorator.d.ts +17 -18
  22. package/dist/decorator.d.ts.map +1 -0
  23. package/dist/destroyable.d.ts +12 -15
  24. package/dist/destroyable.d.ts.map +1 -0
  25. package/dist/devtools/devtool/devtools.d.ts +1 -0
  26. package/dist/devtools/devtool/devtools.d.ts.map +1 -0
  27. package/dist/devtools/devtool/panel.d.ts +2 -0
  28. package/dist/devtools/devtool/panel.d.ts.map +1 -0
  29. package/dist/devtools/panel.js.map +1 -1
  30. package/dist/entry-browser.d.ts +3 -0
  31. package/dist/entry-browser.d.ts.map +1 -0
  32. package/dist/entry-node.d.ts +3 -0
  33. package/dist/entry-node.d.ts.map +1 -0
  34. package/dist/eventful.d.ts +3 -5
  35. package/dist/eventful.d.ts.map +1 -0
  36. package/dist/index.d.ts +13 -19
  37. package/dist/index.d.ts.map +1 -0
  38. package/dist/indexable.d.ts +10 -10
  39. package/dist/indexable.d.ts.map +1 -0
  40. package/dist/introspection.d.ts +27 -0
  41. package/dist/introspection.d.ts.map +1 -0
  42. package/dist/iterableWeak.d.ts +53 -0
  43. package/dist/iterableWeak.d.ts.map +1 -0
  44. package/dist/mixins.d.ts +25 -0
  45. package/dist/mixins.d.ts.map +1 -0
  46. package/dist/mutts.umd.js +1 -1
  47. package/dist/mutts.umd.js.map +1 -1
  48. package/dist/mutts.umd.min.js +1 -1
  49. package/dist/mutts.umd.min.js.map +1 -1
  50. package/dist/node.cjs +105 -0
  51. package/dist/node.cjs.map +1 -0
  52. package/dist/node.d.ts +1 -0
  53. package/dist/node.esm.js +104 -0
  54. package/dist/node.esm.js.map +1 -0
  55. package/dist/promiseChain.d.ts +4 -5
  56. package/dist/promiseChain.d.ts.map +1 -0
  57. package/dist/reactive/array.d.ts +49 -0
  58. package/dist/reactive/array.d.ts.map +1 -0
  59. package/dist/reactive/buffer.d.ts +44 -0
  60. package/dist/reactive/buffer.d.ts.map +1 -0
  61. package/dist/reactive/change.d.ts +29 -0
  62. package/dist/reactive/change.d.ts.map +1 -0
  63. package/dist/reactive/debug.d.ts +111 -0
  64. package/dist/reactive/debug.d.ts.map +1 -0
  65. package/dist/reactive/deep-touch.d.ts +28 -0
  66. package/dist/reactive/deep-touch.d.ts.map +1 -0
  67. package/dist/reactive/deep-watch-state.d.ts +25 -0
  68. package/dist/reactive/deep-watch-state.d.ts.map +1 -0
  69. package/dist/reactive/deep-watch.d.ts +19 -0
  70. package/dist/reactive/deep-watch.d.ts.map +1 -0
  71. package/dist/reactive/effect-context.d.ts +7 -0
  72. package/dist/reactive/effect-context.d.ts.map +1 -0
  73. package/dist/reactive/effects.d.ts +151 -0
  74. package/dist/reactive/effects.d.ts.map +1 -0
  75. package/dist/reactive/index.d.ts +20 -0
  76. package/dist/reactive/index.d.ts.map +1 -0
  77. package/dist/reactive/interface.d.ts +64 -0
  78. package/dist/reactive/interface.d.ts.map +1 -0
  79. package/dist/reactive/map.d.ts +30 -0
  80. package/dist/reactive/map.d.ts.map +1 -0
  81. package/dist/reactive/memoize.d.ts +5 -0
  82. package/dist/reactive/memoize.d.ts.map +1 -0
  83. package/dist/reactive/non-reactive-state.d.ts +9 -0
  84. package/dist/reactive/non-reactive-state.d.ts.map +1 -0
  85. package/dist/reactive/non-reactive.d.ts +11 -0
  86. package/dist/reactive/non-reactive.d.ts.map +1 -0
  87. package/dist/reactive/project.d.ts +41 -0
  88. package/dist/reactive/project.d.ts.map +1 -0
  89. package/dist/reactive/proxy-state.d.ts +8 -0
  90. package/dist/reactive/proxy-state.d.ts.map +1 -0
  91. package/dist/reactive/proxy.d.ts +23 -0
  92. package/dist/reactive/proxy.d.ts.map +1 -0
  93. package/dist/reactive/record.d.ts +116 -0
  94. package/dist/reactive/record.d.ts.map +1 -0
  95. package/dist/reactive/register.d.ts +64 -0
  96. package/dist/reactive/register.d.ts.map +1 -0
  97. package/dist/reactive/registry.d.ts +20 -0
  98. package/dist/reactive/registry.d.ts.map +1 -0
  99. package/dist/reactive/set.d.ts +28 -0
  100. package/dist/reactive/set.d.ts.map +1 -0
  101. package/dist/reactive/tracking.d.ts +7 -0
  102. package/dist/reactive/tracking.d.ts.map +1 -0
  103. package/dist/reactive/types.d.ts +376 -0
  104. package/dist/reactive/types.d.ts.map +1 -0
  105. package/dist/std-decorators.d.ts +9 -11
  106. package/dist/std-decorators.d.ts.map +1 -0
  107. package/dist/utils.d.ts +49 -0
  108. package/dist/utils.d.ts.map +1 -0
  109. package/dist/zone.d.ts +40 -0
  110. package/dist/zone.d.ts.map +1 -0
  111. package/docs/ai/api-reference.md +0 -2
  112. package/docs/reactive/advanced.md +2 -5
  113. package/docs/reactive/collections.md +0 -125
  114. package/docs/reactive/core.md +27 -24
  115. package/docs/reactive/debugging.md +12 -2
  116. package/docs/reactive/project.md +1 -1
  117. package/docs/reactive/scan.md +78 -0
  118. package/docs/reactive.md +2 -1
  119. package/docs/std-decorators.md +69 -0
  120. package/docs/zone.md +95 -0
  121. package/package.json +67 -23
  122. package/src/async/browser.ts +319 -0
  123. package/src/async/index.ts +23 -0
  124. package/src/async/node.ts +104 -0
  125. package/src/decorator.ts +5 -1
  126. package/src/destroyable.ts +1 -1
  127. package/src/entry-browser.ts +5 -0
  128. package/src/entry-node.ts +5 -0
  129. package/src/index.d.ts +12 -9
  130. package/src/index.ts +23 -14
  131. package/src/indexable.ts +42 -0
  132. package/src/mixins.ts +2 -2
  133. package/src/reactive/array.ts +274 -179
  134. package/src/reactive/buffer.ts +168 -0
  135. package/src/reactive/change.ts +2 -2
  136. package/src/reactive/effect-context.ts +15 -91
  137. package/src/reactive/effects.ts +119 -179
  138. package/src/reactive/index.ts +11 -13
  139. package/src/reactive/interface.ts +19 -33
  140. package/src/reactive/map.ts +49 -62
  141. package/src/reactive/memoize.ts +19 -9
  142. package/src/reactive/project.ts +43 -22
  143. package/src/reactive/proxy.ts +16 -41
  144. package/src/reactive/record.ts +3 -3
  145. package/src/reactive/register.ts +5 -7
  146. package/src/reactive/registry.ts +9 -17
  147. package/src/reactive/set.ts +43 -57
  148. package/src/reactive/tracking.ts +1 -29
  149. package/src/reactive/types.ts +46 -23
  150. package/src/utils.ts +80 -37
  151. package/src/zone.ts +138 -0
  152. package/dist/chunks/_tslib-BgjropY9.js +0 -81
  153. package/dist/chunks/_tslib-BgjropY9.js.map +0 -1
  154. package/dist/chunks/_tslib-MCKDzsSq.esm.js +0 -75
  155. package/dist/chunks/_tslib-MCKDzsSq.esm.js.map +0 -1
  156. package/dist/chunks/decorator-BGILvPtN.esm.js +0 -627
  157. package/dist/chunks/decorator-BGILvPtN.esm.js.map +0 -1
  158. package/dist/chunks/decorator-BQ2eBTCj.js +0 -651
  159. package/dist/chunks/decorator-BQ2eBTCj.js.map +0 -1
  160. package/dist/chunks/index-CDCOjzTy.js.map +0 -1
  161. package/dist/chunks/index-DiP0RXoZ.esm.js.map +0 -1
  162. package/dist/decorator.esm.js +0 -2
  163. package/dist/decorator.esm.js.map +0 -1
  164. package/dist/decorator.js +0 -11
  165. package/dist/decorator.js.map +0 -1
  166. package/dist/destroyable.esm.js +0 -109
  167. package/dist/destroyable.esm.js.map +0 -1
  168. package/dist/destroyable.js +0 -116
  169. package/dist/destroyable.js.map +0 -1
  170. package/dist/eventful.esm.js +0 -66
  171. package/dist/eventful.esm.js.map +0 -1
  172. package/dist/eventful.js +0 -68
  173. package/dist/eventful.js.map +0 -1
  174. package/dist/index.esm.js +0 -53
  175. package/dist/index.esm.js.map +0 -1
  176. package/dist/index.js +0 -139
  177. package/dist/index.js.map +0 -1
  178. package/dist/indexable.esm.js +0 -285
  179. package/dist/indexable.esm.js.map +0 -1
  180. package/dist/indexable.js +0 -291
  181. package/dist/indexable.js.map +0 -1
  182. package/dist/promiseChain.esm.js +0 -78
  183. package/dist/promiseChain.esm.js.map +0 -1
  184. package/dist/promiseChain.js +0 -80
  185. package/dist/promiseChain.js.map +0 -1
  186. package/dist/reactive.d.ts +0 -910
  187. package/dist/reactive.esm.js +0 -5
  188. package/dist/reactive.esm.js.map +0 -1
  189. package/dist/reactive.js +0 -59
  190. package/dist/reactive.js.map +0 -1
  191. package/dist/std-decorators.esm.js +0 -196
  192. package/dist/std-decorators.esm.js.map +0 -1
  193. package/dist/std-decorators.js +0 -204
  194. package/dist/std-decorators.js.map +0 -1
  195. package/src/reactive/mapped.ts +0 -129
  196. package/src/reactive/zone.ts +0 -208
@@ -1,56 +1,47 @@
1
+ import { contentRef } from '../utils'
1
2
  import { touched, touched1 } from './change'
2
3
  import { notifyPropertyChange } from './deep-touch'
3
4
  import { makeReactiveEntriesIterator, makeReactiveIterator } from './non-reactive'
4
5
  import { reactive } from './proxy'
5
6
  import { dependant } from './tracking'
6
- import { prototypeForwarding } from './types'
7
-
8
- const native = Symbol('native')
9
7
 
10
8
  /**
11
9
  * Reactive wrapper around JavaScript's WeakMap class
12
10
  * Only tracks individual key operations, no size tracking (WeakMap limitation)
13
11
  */
14
- export class ReactiveWeakMap<K extends object, V> {
15
- readonly [native]!: WeakMap<K, V>
16
- readonly content!: symbol
17
- constructor(original: WeakMap<K, V>) {
18
- Object.defineProperties(this, {
19
- [native]: { value: original },
20
- [prototypeForwarding]: { value: original },
21
- content: { value: Symbol('WeakMapContent') },
22
- [Symbol.toStringTag]: { value: 'ReactiveWeakMap' },
23
- })
12
+ export abstract class ReactiveWeakMap<K extends object, V> extends WeakMap<K, V> {
13
+ get [Symbol.toStringTag]() {
14
+ return 'ReactiveWeakMap'
24
15
  }
25
16
 
26
17
  // Implement WeakMap interface methods with reactivity
27
18
  delete(key: K): boolean {
28
- const hadKey = this[native].has(key)
29
- const result = this[native].delete(key)
19
+ const hadKey = this.has(key)
20
+ const result = this.delete(key)
30
21
 
31
- if (hadKey) touched1(this.content, { type: 'del', prop: key }, key)
22
+ if (hadKey) touched1(contentRef(this), { type: 'del', prop: key }, key)
32
23
 
33
24
  return result
34
25
  }
35
26
 
36
27
  get(key: K): V | undefined {
37
- dependant(this.content, key)
38
- return reactive(this[native].get(key))
28
+ dependant(contentRef(this), key)
29
+ return reactive(this.get(key))
39
30
  }
40
31
 
41
32
  has(key: K): boolean {
42
- dependant(this.content, key)
43
- return this[native].has(key)
33
+ dependant(contentRef(this), key)
34
+ return this.has(key)
44
35
  }
45
36
 
46
37
  set(key: K, value: V): this {
47
- const hadKey = this[native].has(key)
48
- const oldValue = this[native].get(key)
38
+ const hadKey = this.has(key)
39
+ const oldValue = this.get(key)
49
40
  const reactiveValue = reactive(value)
50
- this[native].set(key, reactiveValue)
41
+ this.set(key, reactiveValue)
51
42
 
52
43
  if (!hadKey || oldValue !== reactiveValue) {
53
- notifyPropertyChange(this.content, key, oldValue, reactiveValue, hadKey)
44
+ notifyPropertyChange(contentRef(this), key, oldValue, reactiveValue, hadKey)
54
45
  }
55
46
 
56
47
  return this
@@ -61,60 +52,52 @@ export class ReactiveWeakMap<K extends object, V> {
61
52
  * Reactive wrapper around JavaScript's Map class
62
53
  * Tracks size changes, individual key operations, and collection-wide operations
63
54
  */
64
- export class ReactiveMap<K, V> {
65
- readonly [native]!: Map<K, V>
66
- readonly content!: symbol
67
-
68
- constructor(original: Map<K, V>) {
69
- Object.defineProperties(this, {
70
- [native]: { value: original },
71
- [prototypeForwarding]: { value: original },
72
- content: { value: Symbol('MapContent') },
73
- [Symbol.toStringTag]: { value: 'ReactiveMap' },
74
- })
55
+ export abstract class ReactiveMap<K, V> extends Map<K, V> {
56
+ get [Symbol.toStringTag]() {
57
+ return 'ReactiveMap'
75
58
  }
76
59
 
77
60
  // Implement Map interface methods with reactivity
78
61
  get size(): number {
79
62
  dependant(this, 'size') // The ReactiveMap instance still goes through proxy
80
- return this[native].size
63
+ return this.size
81
64
  }
82
65
 
83
66
  clear(): void {
84
- const hadEntries = this[native].size > 0
85
- this[native].clear()
67
+ const hadEntries = this.size > 0
68
+ this.clear()
86
69
 
87
70
  if (hadEntries) {
88
71
  const evolution = { type: 'bunch', method: 'clear' } as const
89
72
  // Clear triggers all effects since all keys are affected
90
73
  touched1(this, evolution, 'size')
91
- touched(this.content, evolution)
74
+ touched(contentRef(this), evolution)
92
75
  }
93
76
  }
94
77
 
95
78
  entries(): Generator<[K, V]> {
96
- dependant(this.content)
97
- return makeReactiveEntriesIterator(this[native].entries())
79
+ dependant(contentRef(this))
80
+ return makeReactiveEntriesIterator(this.entries())
98
81
  }
99
82
 
100
83
  forEach(callbackfn: (value: V, key: K, map: Map<K, V>) => void, thisArg?: any): void {
101
- dependant(this.content)
102
- this[native].forEach(callbackfn, thisArg)
84
+ dependant(contentRef(this))
85
+ this.forEach(callbackfn, thisArg)
103
86
  }
104
87
 
105
88
  keys(): MapIterator<K> {
106
- dependant(this.content)
107
- return this[native].keys()
89
+ dependant(contentRef(this))
90
+ return this.keys()
108
91
  }
109
92
 
110
93
  values(): Generator<V> {
111
- dependant(this.content)
112
- return makeReactiveIterator(this[native].values())
94
+ dependant(contentRef(this))
95
+ return makeReactiveIterator(this.values())
113
96
  }
114
97
 
115
- [Symbol.iterator](): Iterator<[K, V]> {
116
- dependant(this.content)
117
- const nativeIterator = this[native][Symbol.iterator]()
98
+ [Symbol.iterator](): MapIterator<[K, V]> {
99
+ dependant(contentRef(this))
100
+ const nativeIterator = this[Symbol.iterator]()
118
101
  return {
119
102
  next() {
120
103
  const result = nativeIterator.next()
@@ -126,17 +109,21 @@ export class ReactiveMap<K, V> {
126
109
  done: false,
127
110
  }
128
111
  },
129
- }
112
+ [Symbol.iterator]() {
113
+ return this
114
+ },
115
+ [Symbol.dispose]() {},
116
+ } as any // TODO: real iterator? (If easy)
130
117
  }
131
118
 
132
119
  // Implement Map methods with reactivity
133
120
  delete(key: K): boolean {
134
- const hadKey = this[native].has(key)
135
- const result = this[native].delete(key)
121
+ const hadKey = this.has(key)
122
+ const result = this.delete(key)
136
123
 
137
124
  if (hadKey) {
138
125
  const evolution = { type: 'del', prop: key } as const
139
- touched1(this.content, evolution, key)
126
+ touched1(contentRef(this), evolution, key)
140
127
  touched1(this, evolution, 'size')
141
128
  }
142
129
 
@@ -144,23 +131,23 @@ export class ReactiveMap<K, V> {
144
131
  }
145
132
 
146
133
  get(key: K): V | undefined {
147
- dependant(this.content, key)
148
- return reactive(this[native].get(key))
134
+ dependant(contentRef(this), key)
135
+ return reactive(this.get(key))
149
136
  }
150
137
 
151
138
  has(key: K): boolean {
152
- dependant(this.content, key)
153
- return this[native].has(key)
139
+ dependant(contentRef(this), key)
140
+ return this.has(key)
154
141
  }
155
142
 
156
143
  set(key: K, value: V): this {
157
- const hadKey = this[native].has(key)
158
- const oldValue = this[native].get(key)
144
+ const hadKey = this.has(key)
145
+ const oldValue = this.get(key)
159
146
  const reactiveValue = reactive(value)
160
- this[native].set(key, reactiveValue)
147
+ this.set(key, reactiveValue)
161
148
 
162
149
  if (!hadKey || oldValue !== reactiveValue) {
163
- notifyPropertyChange(this.content, key, oldValue, reactiveValue, hadKey)
150
+ notifyPropertyChange(contentRef(this), key, oldValue, reactiveValue, hadKey)
164
151
  // Also notify size change for Map (WeakMap doesn't track size)
165
152
  const evolution = { type: hadKey ? 'set' : 'add', prop: key } as const
166
153
  touched1(this, evolution, 'size')
@@ -2,8 +2,8 @@ import { decorator } from '../decorator'
2
2
  import { deepCompare, renamed } from '../utils'
3
3
  import { touched1 } from './change'
4
4
  import { effect, root, untracked } from './effects'
5
- import { dependant } from './tracking'
6
5
  import { getRoot, markWithRoot } from './registry'
6
+ import { dependant } from './tracking'
7
7
  import { options, rootFunction } from './types'
8
8
 
9
9
  export type Memoizable = object | any[] | symbol | ((...args: any[]) => any)
@@ -114,13 +114,18 @@ export const memoize = decorator({
114
114
  let wrapper = wrapperRegistry.get(original)
115
115
  if (!wrapper) {
116
116
  wrapper = markWithRoot(
117
- renamed((that: object) => {
118
- return original.call(that)
119
- }, `${String(target?.constructor?.name ?? target?.name ?? 'Object')}.${String(propertyKey)}`),
117
+ renamed(
118
+ (that: object) => {
119
+ return original.call(that)
120
+ },
121
+ `${String(target?.constructor?.name ?? target?.name ?? 'Object')}.${String(propertyKey)}`
122
+ ),
120
123
  {
121
124
  method: original,
122
125
  propertyKey,
123
- ...((original as any)[rootFunction] ? { [rootFunction]: (original as any)[rootFunction] } : {}),
126
+ ...((original as any)[rootFunction]
127
+ ? { [rootFunction]: (original as any)[rootFunction] }
128
+ : {}),
124
129
  }
125
130
  )
126
131
  wrapperRegistry.set(original, wrapper)
@@ -134,13 +139,18 @@ export const memoize = decorator({
134
139
  let wrapper = wrapperRegistry.get(original)
135
140
  if (!wrapper) {
136
141
  wrapper = markWithRoot(
137
- renamed((that: object, ...args: object[]) => {
138
- return original.call(that, ...args)
139
- }, `${String(target?.constructor?.name ?? target?.name ?? 'Object')}.${String(name)}`),
142
+ renamed(
143
+ (that: object, ...args: object[]) => {
144
+ return original.call(that, ...args)
145
+ },
146
+ `${String(target?.constructor?.name ?? target?.name ?? 'Object')}.${String(name)}`
147
+ ),
140
148
  {
141
149
  method: original,
142
150
  propertyKey: name,
143
- ...((original as any)[rootFunction] ? { [rootFunction]: (original as any)[rootFunction] } : {}),
151
+ ...((original as any)[rootFunction]
152
+ ? { [rootFunction]: (original as any)[rootFunction] }
153
+ : {}),
144
154
  }
145
155
  )
146
156
  wrapperRegistry.set(original, wrapper)
@@ -1,4 +1,4 @@
1
- import { ReflectGet, ReflectSet } from '../utils'
1
+ import { FoolProof } from '../utils'
2
2
  import { setEffectName } from './debug'
3
3
  import { getActiveEffect } from './effect-context'
4
4
  import { effect, untracked } from './effects'
@@ -42,17 +42,10 @@ export type ProjectAccess<SourceValue, Key, SourceType, Target> = {
42
42
  value: SourceValue
43
43
  }
44
44
 
45
- type BivariantProjectCallback<Args extends any[], Return> = {
46
- bivarianceHack(...args: Args): Return
47
- }['bivarianceHack']
48
-
49
- export type ProjectCallback<
50
- SourceValue,
51
- Key,
52
- Target extends object,
53
- SourceType,
54
- Result,
55
- > = BivariantProjectCallback<[ProjectAccess<SourceValue, Key, SourceType, Target>, Target], Result>
45
+ export type ProjectCallback<SourceValue, Key, Target extends object, SourceType, Result> = (
46
+ access: ProjectAccess<SourceValue, Key, SourceType, Target>,
47
+ target: Target
48
+ ) => Result
56
49
 
57
50
  export type ProjectResult<Target extends object> = Target & { [cleanup]: ScopedCallback }
58
51
 
@@ -92,12 +85,12 @@ function projectArray<SourceValue, ResultValue>(
92
85
  source: readonly SourceValue[],
93
86
  apply: ProjectCallback<SourceValue, number, ResultValue[], readonly SourceValue[], ResultValue>
94
87
  ): ProjectResult<ResultValue[]> {
95
- const observedSource = reactive(source) as readonly SourceValue[]
88
+ source = reactive(source)
96
89
  const target = reactive([] as ResultValue[])
97
90
  const indexEffects = new Map<number, ScopedCallback>()
98
91
 
99
92
  function normalizeTargetLength(length: number) {
100
- ReflectSet(target as unknown as object, 'length', length, target)
93
+ FoolProof.set(target as unknown as object, 'length', length, target)
101
94
  }
102
95
 
103
96
  function disposeIndex(index: number) {
@@ -113,7 +106,7 @@ function projectArray<SourceValue, ResultValue>(
113
106
  const depth = parent ? parent.depth + 1 : 0
114
107
 
115
108
  const cleanupLength = effect(function projectArrayLengthEffect({ ascend }) {
116
- const length = observedSource.length
109
+ const length = source.length
117
110
  normalizeTargetLength(length)
118
111
  const existing = Array.from(indexEffects.keys())
119
112
  for (let i = 0; i < length; i++) {
@@ -124,10 +117,10 @@ function projectArray<SourceValue, ResultValue>(
124
117
  const previous = untracked(() => target[index])
125
118
  const accessBase = {
126
119
  key: index,
127
- source: observedSource,
128
- get: () => ReflectGet(observedSource as any, index, observedSource),
120
+ source,
121
+ get: () => FoolProof.get(source as any, index, source),
129
122
  set: (value: SourceValue) =>
130
- ReflectSet(observedSource as any, index, value, observedSource),
123
+ FoolProof.set(source as any, index, value, source),
131
124
  old: previous,
132
125
  } as ProjectAccess<SourceValue, number, readonly SourceValue[], ResultValue[]>
133
126
  defineAccessValue(accessBase)
@@ -136,7 +129,7 @@ function projectArray<SourceValue, ResultValue>(
136
129
  })
137
130
  setEffectName(stop, `project[${depth}]:${index}`)
138
131
  effectProjectionMetadata.set(stop, {
139
- source: observedSource,
132
+ source,
140
133
  key: index,
141
134
  target,
142
135
  depth,
@@ -149,7 +142,7 @@ function projectArray<SourceValue, ResultValue>(
149
142
  })
150
143
 
151
144
  return makeCleanup(target, indexEffects, () => cleanupLength(), {
152
- source: observedSource,
145
+ source,
153
146
  target,
154
147
  apply,
155
148
  depth,
@@ -274,9 +267,9 @@ function projectRecord<Source extends Record<PropertyKey, any>, ResultValue>(
274
267
  const accessBase = {
275
268
  key: sourceKey,
276
269
  source: observedSource,
277
- get: () => ReflectGet(observedSource, sourceKey, observedSource),
270
+ get: () => FoolProof.get(observedSource, sourceKey, observedSource),
278
271
  set: (value: Source[typeof sourceKey]) =>
279
- ReflectSet(observedSource, sourceKey, value, observedSource),
272
+ FoolProof.set(observedSource, sourceKey, value, observedSource),
280
273
  old: previous,
281
274
  } as ProjectAccess<
282
275
  Source[typeof sourceKey],
@@ -415,6 +408,34 @@ type ProjectOverload = {
415
408
  map: typeof projectMap
416
409
  }
417
410
 
411
+ function projectCore<SourceValue, ResultValue>(
412
+ source: readonly SourceValue[],
413
+ apply: ProjectCallback<SourceValue, number, ResultValue[], readonly SourceValue[], ResultValue>
414
+ ): ProjectResult<ResultValue[]>
415
+ function projectCore<Key extends PropertyKey, SourceValue, ResultValue>(
416
+ source: Register<SourceValue, Key>,
417
+ apply: ProjectCallback<
418
+ SourceValue,
419
+ Key,
420
+ Map<Key, ResultValue>,
421
+ Register<SourceValue, Key>,
422
+ ResultValue
423
+ >
424
+ ): ProjectResult<Map<Key, ResultValue>>
425
+ function projectCore<Source extends Record<PropertyKey, any>, ResultValue>(
426
+ source: Source,
427
+ apply: ProjectCallback<
428
+ Source[keyof Source],
429
+ keyof Source,
430
+ Record<keyof Source, ResultValue>,
431
+ Source,
432
+ ResultValue
433
+ >
434
+ ): ProjectResult<Record<keyof Source, ResultValue>>
435
+ function projectCore<Key, Value, ResultValue>(
436
+ source: Map<Key, Value>,
437
+ apply: ProjectCallback<Value, Key, Map<Key, ResultValue>, Map<Key, Value>, ResultValue>
438
+ ): ProjectResult<Map<Key, ResultValue>>
418
439
  function projectCore(source: any, apply: any): ProjectResult<any> {
419
440
  if (Array.isArray(source)) return projectArray(source, apply)
420
441
  if (source instanceof Map) return projectMap(source, apply)
@@ -1,6 +1,6 @@
1
1
  import { decorator } from '../decorator'
2
2
  import { mixin } from '../mixins'
3
- import { isOwnAccessor, ReflectGet, ReflectSet } from '../utils'
3
+ import { FoolProof, isOwnAccessor } from '../utils'
4
4
  import { touched1 } from './change'
5
5
  import { notifyPropertyChange } from './deep-touch'
6
6
  import {
@@ -10,7 +10,7 @@ import {
10
10
  objectsWithDeepWatchers,
11
11
  removeBackReference,
12
12
  } from './deep-watch-state'
13
- import { withEffect } from './effect-context'
13
+ import { untracked } from './effects'
14
14
  import { absent, isNonReactive } from './non-reactive-state'
15
15
  import {
16
16
  getExistingProxy,
@@ -25,34 +25,29 @@ import {
25
25
  nativeReactive,
26
26
  nonReactiveMark,
27
27
  options,
28
- prototypeForwarding,
29
28
  ReactiveError,
30
29
  ReactiveErrorCode,
31
30
  unreactiveProperties,
32
31
  } from './types'
32
+ export const metaProtos = new WeakMap()
33
33
 
34
34
  const hasReentry: any[] = []
35
35
  const reactiveHandlers = {
36
36
  [Symbol.toStringTag]: 'MutTs Reactive',
37
37
  get(obj: any, prop: PropertyKey, receiver: any) {
38
+ if (obj && typeof obj === 'object' && !Object.hasOwn(obj, prop)) {
39
+ const metaProto = metaProtos.get(obj.constructor)
40
+ if (metaProto && prop in metaProto) {
41
+ const desc = Object.getOwnPropertyDescriptor(metaProto, prop)!
42
+ return desc.get ? desc.get.call(obj) : (...args) => desc.value.apply(obj, args)
43
+ }
44
+ }
38
45
  if (prop === nonReactiveMark) return false
39
46
  const unwrappedObj = unwrap(obj)
40
47
  // Check if this property is marked as unreactive
41
48
  if (unwrappedObj[unreactiveProperties]?.has(prop) || typeof prop === 'symbol')
42
- return ReflectGet(obj, prop, receiver)
49
+ return FoolProof.get(obj, prop, receiver)
43
50
 
44
- // Special-case: array wrappers use prototype forwarding + numeric accessors.
45
- // With options.instanceMembers=true, inherited reads are normally not tracked, which breaks
46
- // reactivity for array indices/length (they appear inherited on the proxy).
47
- const isArrayCase =
48
- prototypeForwarding in obj &&
49
- // biome-ignore lint/suspicious/useIsArray: This is the whole point here
50
- obj[prototypeForwarding] instanceof Array &&
51
- typeof prop === 'string' &&
52
- (prop === 'length' || !Number.isNaN(Number(prop)))
53
- if (isArrayCase) {
54
- dependant(obj, prop === 'length' ? 'length' : Number(prop))
55
- }
56
51
  // Check if property exists and if it's an own property (cached for later use)
57
52
  const hasProp = Reflect.has(receiver, prop)
58
53
  const isOwnProp = hasProp && Object.hasOwn(receiver, prop)
@@ -86,7 +81,7 @@ const reactiveHandlers = {
86
81
  current = next
87
82
  }
88
83
  }
89
- const value = ReflectGet(obj, prop, receiver)
84
+ const value = FoolProof.get(obj, prop, receiver)
90
85
  if (typeof value === 'object' && value !== null) {
91
86
  const reactiveValue = reactiveObject(value)
92
87
 
@@ -106,19 +101,8 @@ const reactiveHandlers = {
106
101
 
107
102
  // Check if this property is marked as unreactive
108
103
  if (unwrappedObj[unreactiveProperties]?.has(prop) || unwrappedObj !== unwrappedReceiver)
109
- return ReflectSet(obj, prop, value, receiver)
110
- // Really specific case for when Array is forwarder, in order to let it manage the reactivity
111
- const isArrayCase =
112
- prototypeForwarding in obj &&
113
- // biome-ignore lint/suspicious/useIsArray: This is the whole point here
114
- obj[prototypeForwarding] instanceof Array &&
115
- (!Number.isNaN(Number(prop)) || prop === 'length')
104
+ return FoolProof.set(obj, prop, value, receiver)
116
105
  const newValue = unwrap(value)
117
-
118
- if (isArrayCase) {
119
- ;(obj as any)[prop] = newValue
120
- return true
121
- }
122
106
  // Read old value, using withEffect(undefined, ...) for getter-only accessors to avoid
123
107
  // breaking memoization dependency tracking during SET operations
124
108
  let oldVal = absent
@@ -130,9 +114,9 @@ const reactiveHandlers = {
130
114
  // We *need* to use `receiver` and not `unwrappedObj` here, otherwise we break
131
115
  // the dependency tracking for memoized getters
132
116
  if (desc?.get && !desc?.set) {
133
- oldVal = withEffect(undefined, () => Reflect.get(unwrappedObj, prop, receiver))
117
+ oldVal = untracked(() => Reflect.get(unwrappedObj, prop, receiver))
134
118
  } else {
135
- oldVal = withEffect(undefined, () => Reflect.get(unwrappedObj, prop, receiver))
119
+ oldVal = untracked(() => Reflect.get(unwrappedObj, prop, receiver))
136
120
  }
137
121
  }
138
122
  if (objectsWithDeepWatchers.has(obj)) {
@@ -148,7 +132,7 @@ const reactiveHandlers = {
148
132
  if (oldVal !== newValue) {
149
133
  // For getter-only accessors, Reflect.set() may fail, but we still return true
150
134
  // to avoid throwing errors. Only proceed with change notifications if set succeeded.
151
- if (ReflectSet(obj, prop, newValue, receiver)) {
135
+ if (FoolProof.set(obj, prop, newValue, receiver)) {
152
136
  notifyPropertyChange(obj, prop, oldVal, newValue, oldVal !== absent)
153
137
  }
154
138
  }
@@ -189,15 +173,6 @@ const reactiveHandlers = {
189
173
 
190
174
  return true
191
175
  },
192
- getPrototypeOf(obj: any): object | null {
193
- if (prototypeForwarding in obj) return obj[prototypeForwarding]
194
- return Object.getPrototypeOf(obj)
195
- },
196
- setPrototypeOf(obj: any, proto: object | null): boolean {
197
- if (prototypeForwarding in obj) return false
198
- Object.setPrototypeOf(obj, proto)
199
- return true
200
- },
201
176
  ownKeys(obj: any): (string | symbol)[] {
202
177
  dependant(obj, allProps)
203
178
  return Reflect.ownKeys(obj)
@@ -1,4 +1,4 @@
1
- import { ReflectGet, ReflectSet } from '../utils'
1
+ import { FoolProof } from '../utils'
2
2
  import { touched1 } from './change'
3
3
  import { effect } from './effects'
4
4
  import { cleanedBy, cleanup } from './interface'
@@ -147,9 +147,9 @@ export function organized<
147
147
  const sourceKey = key as keyof Source
148
148
  const accessBase = {
149
149
  key: sourceKey,
150
- get: () => ReflectGet(observedSource, sourceKey, observedSource),
150
+ get: () => FoolProof.get(observedSource, sourceKey, observedSource),
151
151
  set: (value: Source[typeof sourceKey]) =>
152
- ReflectSet(observedSource, sourceKey, value, observedSource),
152
+ FoolProof.set(observedSource, sourceKey, value, observedSource),
153
153
  }
154
154
  Object.defineProperty(accessBase, 'value', {
155
155
  get: accessBase.get,
@@ -1,8 +1,9 @@
1
+ import { FunctionWrapper } from '../zone'
1
2
  import { ArrayReadForward, forwardArray, getAt, Indexable, setAt } from '../indexable'
2
3
  import { effect } from './effects'
3
4
  import { unreactive } from './interface'
4
5
  import { reactive } from './proxy'
5
- import { type DependencyFunction, prototypeForwarding, type ScopedCallback } from './types'
6
+ import { type ScopedCallback } from './types'
6
7
 
7
8
  // TODO: use register in a real-world crud situation, have "events" for add, delete, update
8
9
 
@@ -36,7 +37,7 @@ function getRegisterBase<T>() {
36
37
  interface RegisterInstance<T> extends ArrayReadForward<T> {
37
38
  [index: number]: T
38
39
  }
39
-
40
+ // TODO: What to do with prototype forwarding ?
40
41
  @unreactive
41
42
  class RegisterClass<T, K extends PropertyKey = PropertyKey>
42
43
  extends getRegisterBase<any>()
@@ -51,12 +52,12 @@ class RegisterClass<T, K extends PropertyKey = PropertyKey>
51
52
  readonly #usage = new Map<K, number>()
52
53
  readonly #valueInfo = new Map<T, { key: K; stop?: ScopedCallback }>()
53
54
  readonly #keyEffects = new Set<ScopedCallback>()
54
- readonly #ascend: DependencyFunction
55
+ readonly #ascend: FunctionWrapper
55
56
 
56
57
  constructor(keyFn: KeyFunction<T, K>, initial?: Iterable<T>) {
57
58
  super()
58
59
  /* Moved below initialization */
59
- let ascendGet: DependencyFunction | undefined
60
+ let ascendGet: FunctionWrapper | undefined
60
61
  effect(({ ascend }) => {
61
62
  ascendGet = ascend
62
63
  })
@@ -65,9 +66,6 @@ class RegisterClass<T, K extends PropertyKey = PropertyKey>
65
66
  this.#keyFn = keyFn
66
67
  this.#keys = reactive([] as K[])
67
68
  this.#values = reactive(new Map<K, T>())
68
- Object.defineProperties(this, {
69
- [prototypeForwarding]: { value: this.#keys },
70
- })
71
69
  if (initial) this.push(...initial)
72
70
  }
73
71
 
@@ -22,21 +22,21 @@ const reverseRoots = new WeakMap<any, WeakRef<Function>>()
22
22
  * @param root - The root function
23
23
  * @returns The marked function
24
24
  */
25
- export function markWithRoot<T extends Function>(fn: T, root: any): T {
25
+ export function markWithRoot<T extends Function>(fn: T, root: any): T {
26
26
  // Check for collision
27
27
  const existingRef = reverseRoots.get(root)
28
28
  const existing = existingRef?.deref()
29
-
29
+
30
30
  if (existing && existing !== fn) {
31
31
  const rootName = root.name || 'anonymous'
32
32
  const existingName = existing.name || 'anonymous'
33
33
  const fnName = fn.name || 'anonymous'
34
34
  throw new Error(
35
35
  `[reactive] Abusive Shared Root detected: Root '${rootName}' is already identifying function '${existingName}'. ` +
36
- `Cannot reuse it for '${fnName}'. Shared roots cause lost updates and broken identity logic.`
36
+ `Cannot reuse it for '${fnName}'. Shared roots cause lost updates and broken identity logic.`
37
37
  )
38
38
  }
39
-
39
+
40
40
  // Always update the map so subsequent checks find this one
41
41
  // (Last writer wins for the check)
42
42
  reverseRoots.set(root, new WeakRef(fn))
@@ -44,9 +44,9 @@ export function markWithRoot<T extends Function>(fn: T, root: any): T {
44
44
  // Mark fn with the new root
45
45
  return Object.defineProperty(fn, rootFunction, {
46
46
  value: getRoot(root),
47
- writable: false,
48
- })
49
- }
47
+ writable: false,
48
+ })
49
+ }
50
50
 
51
51
  /**
52
52
  * Gets the root function of a function for effect tracking
@@ -54,14 +54,6 @@ export function markWithRoot<T extends Function>(fn: T, root: any): T {
54
54
  * @returns The root function
55
55
  */
56
56
  export function getRoot<T extends Function | undefined>(fn: T): T {
57
- while(fn && rootFunction in fn) fn = fn[rootFunction] as T
57
+ while (fn && rootFunction in fn) fn = fn[rootFunction] as T
58
58
  return fn
59
- }
60
-
61
- // Flag to disable dependency tracking for the current active effect (not globally)
62
- export const trackingDisabledEffects = new WeakSet<ScopedCallback>()
63
- export let globalTrackingDisabled = false
64
-
65
- export function setGlobalTrackingDisabled(value: boolean): void {
66
- globalTrackingDisabled = value
67
- }
59
+ }