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.
Files changed (195) hide show
  1. package/README.md +77 -35
  2. package/dist/browser.cjs +2144 -5355
  3. package/dist/browser.cjs.map +1 -1
  4. package/dist/browser.d.ts +2 -1655
  5. package/dist/browser.dev.cjs +110 -0
  6. package/dist/browser.dev.cjs.map +1 -0
  7. package/dist/browser.dev.d.ts +2 -0
  8. package/dist/browser.dev.esm.js +5 -0
  9. package/dist/browser.dev.esm.js.map +1 -0
  10. package/dist/browser.esm.js +20 -107
  11. package/dist/browser.esm.js.map +1 -1
  12. package/dist/chunks/{async-browser-CA0jPWIi.cjs → async-browser-BU_IfxYD.cjs} +19 -107
  13. package/dist/chunks/async-browser-BU_IfxYD.cjs.map +1 -0
  14. package/dist/chunks/{async-core-UqHzvJ-S.cjs → async-core-CRLKP3l-.cjs} +8 -4
  15. package/dist/chunks/async-core-CRLKP3l-.cjs.map +1 -0
  16. package/dist/chunks/{async-node-BYHuGTni.cjs → async-node-3PrbVAbB.cjs} +7 -12
  17. package/dist/chunks/async-node-3PrbVAbB.cjs.map +1 -0
  18. package/dist/chunks/index-CaaQQlPJ.esm.js +3174 -0
  19. package/dist/chunks/index-CaaQQlPJ.esm.js.map +1 -0
  20. package/dist/chunks/node-nKJBk8iJ.esm.js +96 -0
  21. package/dist/chunks/node-nKJBk8iJ.esm.js.map +1 -0
  22. package/dist/chunks/proxy-Dtg-bJ3T.cjs +3763 -0
  23. package/dist/chunks/proxy-Dtg-bJ3T.cjs.map +1 -0
  24. package/dist/chunks/proxy-r7lARftl.esm.js +3701 -0
  25. package/dist/chunks/proxy-r7lARftl.esm.js.map +1 -0
  26. package/dist/debug.cjs +980 -0
  27. package/dist/debug.cjs.map +1 -0
  28. package/dist/debug.d.ts +208 -0
  29. package/dist/debug.esm.js +950 -0
  30. package/dist/debug.esm.js.map +1 -0
  31. package/dist/devtools/manifest.json +1 -1
  32. package/dist/devtools/panel.html +1 -1
  33. package/dist/devtools/panel.js +107 -94
  34. package/dist/devtools/panel.js.map +1 -1
  35. package/dist/index.d.ts +1447 -13
  36. package/dist/mutts.umd.js +7167 -1
  37. package/dist/mutts.umd.js.map +1 -1
  38. package/dist/mutts.umd.min.js +1 -1
  39. package/dist/mutts.umd.min.js.map +1 -1
  40. package/dist/node.cjs +70 -66
  41. package/dist/node.cjs.map +1 -1
  42. package/dist/node.d.ts +2 -1
  43. package/dist/node.dev.cjs +110 -0
  44. package/dist/node.dev.cjs.map +1 -0
  45. package/dist/node.dev.d.ts +2 -0
  46. package/dist/node.dev.esm.js +6 -0
  47. package/dist/node.dev.esm.js.map +1 -0
  48. package/dist/node.esm.js +4 -103
  49. package/dist/node.esm.js.map +1 -1
  50. package/dist/{reactive/types.d.ts → types-W5vD6m2n.d.ts} +186 -93
  51. package/docs/ai/api-reference.md +12 -19
  52. package/docs/ai/manual.md +521 -17
  53. package/docs/events.md +57 -2
  54. package/docs/flavored.md +210 -0
  55. package/docs/reactive/advanced.md +314 -5
  56. package/docs/reactive/attend.md +142 -0
  57. package/docs/reactive/collections.md +76 -39
  58. package/docs/reactive/core.md +100 -14
  59. package/docs/reactive/debugging.md +123 -18
  60. package/docs/reactive/error-handling.md +121 -0
  61. package/docs/reactive/resource.md +125 -0
  62. package/docs/reactive/scan.md +247 -1
  63. package/docs/reactive.md +4 -1
  64. package/docs/std-decorators.md +102 -51
  65. package/docs/utils.md +70 -0
  66. package/docs/zone.md +3 -7
  67. package/package.json +64 -30
  68. package/dist/async/browser.d.ts +0 -2
  69. package/dist/async/browser.d.ts.map +0 -1
  70. package/dist/async/index.d.ts +0 -18
  71. package/dist/async/index.d.ts.map +0 -1
  72. package/dist/async/node.d.ts +0 -2
  73. package/dist/async/node.d.ts.map +0 -1
  74. package/dist/chunks/async-browser-CA0jPWIi.cjs.map +0 -1
  75. package/dist/chunks/async-core-UqHzvJ-S.cjs.map +0 -1
  76. package/dist/chunks/async-node-BYHuGTni.cjs.map +0 -1
  77. package/dist/chunks/index-DhaOVusv.esm.js +0 -6411
  78. package/dist/chunks/index-DhaOVusv.esm.js.map +0 -1
  79. package/dist/decorator.d.ts +0 -106
  80. package/dist/decorator.d.ts.map +0 -1
  81. package/dist/destroyable.d.ts +0 -87
  82. package/dist/destroyable.d.ts.map +0 -1
  83. package/dist/entry-browser.d.ts +0 -3
  84. package/dist/entry-browser.d.ts.map +0 -1
  85. package/dist/entry-node.d.ts +0 -3
  86. package/dist/entry-node.d.ts.map +0 -1
  87. package/dist/eventful.d.ts +0 -18
  88. package/dist/eventful.d.ts.map +0 -1
  89. package/dist/index.d.ts.map +0 -1
  90. package/dist/indexable.d.ts +0 -243
  91. package/dist/indexable.d.ts.map +0 -1
  92. package/dist/introspection.d.ts +0 -27
  93. package/dist/introspection.d.ts.map +0 -1
  94. package/dist/iterableWeak.d.ts +0 -53
  95. package/dist/iterableWeak.d.ts.map +0 -1
  96. package/dist/mixins.d.ts +0 -25
  97. package/dist/mixins.d.ts.map +0 -1
  98. package/dist/promiseChain.d.ts +0 -20
  99. package/dist/promiseChain.d.ts.map +0 -1
  100. package/dist/reactive/array.d.ts +0 -49
  101. package/dist/reactive/array.d.ts.map +0 -1
  102. package/dist/reactive/buffer.d.ts +0 -44
  103. package/dist/reactive/buffer.d.ts.map +0 -1
  104. package/dist/reactive/change.d.ts +0 -29
  105. package/dist/reactive/change.d.ts.map +0 -1
  106. package/dist/reactive/debug.d.ts +0 -111
  107. package/dist/reactive/debug.d.ts.map +0 -1
  108. package/dist/reactive/deep-touch.d.ts +0 -28
  109. package/dist/reactive/deep-touch.d.ts.map +0 -1
  110. package/dist/reactive/deep-watch-state.d.ts +0 -25
  111. package/dist/reactive/deep-watch-state.d.ts.map +0 -1
  112. package/dist/reactive/deep-watch.d.ts +0 -19
  113. package/dist/reactive/deep-watch.d.ts.map +0 -1
  114. package/dist/reactive/effect-context.d.ts +0 -7
  115. package/dist/reactive/effect-context.d.ts.map +0 -1
  116. package/dist/reactive/effects.d.ts +0 -151
  117. package/dist/reactive/effects.d.ts.map +0 -1
  118. package/dist/reactive/index.d.ts +0 -20
  119. package/dist/reactive/index.d.ts.map +0 -1
  120. package/dist/reactive/interface.d.ts +0 -64
  121. package/dist/reactive/interface.d.ts.map +0 -1
  122. package/dist/reactive/map.d.ts +0 -30
  123. package/dist/reactive/map.d.ts.map +0 -1
  124. package/dist/reactive/memoize.d.ts +0 -5
  125. package/dist/reactive/memoize.d.ts.map +0 -1
  126. package/dist/reactive/non-reactive-state.d.ts +0 -9
  127. package/dist/reactive/non-reactive-state.d.ts.map +0 -1
  128. package/dist/reactive/non-reactive.d.ts +0 -11
  129. package/dist/reactive/non-reactive.d.ts.map +0 -1
  130. package/dist/reactive/project.d.ts +0 -41
  131. package/dist/reactive/project.d.ts.map +0 -1
  132. package/dist/reactive/proxy-state.d.ts +0 -8
  133. package/dist/reactive/proxy-state.d.ts.map +0 -1
  134. package/dist/reactive/proxy.d.ts +0 -23
  135. package/dist/reactive/proxy.d.ts.map +0 -1
  136. package/dist/reactive/record.d.ts +0 -116
  137. package/dist/reactive/record.d.ts.map +0 -1
  138. package/dist/reactive/register.d.ts +0 -64
  139. package/dist/reactive/register.d.ts.map +0 -1
  140. package/dist/reactive/registry.d.ts +0 -20
  141. package/dist/reactive/registry.d.ts.map +0 -1
  142. package/dist/reactive/set.d.ts +0 -28
  143. package/dist/reactive/set.d.ts.map +0 -1
  144. package/dist/reactive/tracking.d.ts +0 -7
  145. package/dist/reactive/tracking.d.ts.map +0 -1
  146. package/dist/reactive/types.d.ts.map +0 -1
  147. package/dist/std-decorators.d.ts +0 -50
  148. package/dist/std-decorators.d.ts.map +0 -1
  149. package/dist/utils.d.ts +0 -49
  150. package/dist/utils.d.ts.map +0 -1
  151. package/dist/zone.d.ts +0 -40
  152. package/dist/zone.d.ts.map +0 -1
  153. package/docs/reactive/project.md +0 -93
  154. package/src/async/browser.ts +0 -319
  155. package/src/async/index.ts +0 -23
  156. package/src/async/node.ts +0 -104
  157. package/src/decorator.ts +0 -272
  158. package/src/destroyable.ts +0 -199
  159. package/src/entry-browser.ts +0 -5
  160. package/src/entry-node.ts +0 -5
  161. package/src/eventful.ts +0 -77
  162. package/src/index.d.ts +0 -12
  163. package/src/index.ts +0 -64
  164. package/src/indexable.ts +0 -526
  165. package/src/introspection.ts +0 -59
  166. package/src/iterableWeak.ts +0 -233
  167. package/src/mixins.ts +0 -123
  168. package/src/promiseChain.ts +0 -110
  169. package/src/reactive/array.ts +0 -507
  170. package/src/reactive/buffer.ts +0 -168
  171. package/src/reactive/change.ts +0 -138
  172. package/src/reactive/debug.ts +0 -517
  173. package/src/reactive/deep-touch.ts +0 -268
  174. package/src/reactive/deep-watch-state.ts +0 -82
  175. package/src/reactive/deep-watch.ts +0 -168
  176. package/src/reactive/effect-context.ts +0 -18
  177. package/src/reactive/effects.ts +0 -1382
  178. package/src/reactive/index.ts +0 -75
  179. package/src/reactive/interface.ts +0 -210
  180. package/src/reactive/map.ts +0 -158
  181. package/src/reactive/memoize.ts +0 -163
  182. package/src/reactive/non-reactive-state.ts +0 -49
  183. package/src/reactive/non-reactive.ts +0 -43
  184. package/src/reactive/project.ts +0 -453
  185. package/src/reactive/proxy-state.ts +0 -27
  186. package/src/reactive/proxy.ts +0 -264
  187. package/src/reactive/record.ts +0 -196
  188. package/src/reactive/register.ts +0 -419
  189. package/src/reactive/registry.ts +0 -59
  190. package/src/reactive/set.ts +0 -130
  191. package/src/reactive/tracking.ts +0 -44
  192. package/src/reactive/types.ts +0 -440
  193. package/src/std-decorators.ts +0 -217
  194. package/src/utils.ts +0 -301
  195. package/src/zone.ts +0 -138
@@ -1,440 +0,0 @@
1
- // biome-ignore-all lint/suspicious/noConfusingVoidType: Type 'void' is not assignable to type 'ScopedCallback | undefined'.
2
- // Argument of type '() => void' is not assignable to parameter of type '(dep: DependencyFunction) => ScopedCallback | undefined'.
3
-
4
- import { FunctionWrapper } from "../zone"
5
-
6
- /**
7
- * Dependency access passed to user callbacks within effects/watch
8
- * Provides functions to track dependencies and information about the effect execution
9
- */
10
- export interface DependencyAccess {
11
- // TODO: remove tracked (async is managed)
12
- // TODO: remove ascend (make a global like `untracked` who withEffect(parentEffect, () => {}))
13
- /**
14
- * Tracks dependencies in the current effect context
15
- * Use this for normal dependency tracking within the effect
16
- * @example
17
- * ```typescript
18
- * effect(({ tracked }) => {
19
- * // In async context, use tracked to restore dependency tracking
20
- * await someAsyncOperation()
21
- * const value = tracked(() => state.count) // Tracks state.count in this effect
22
- * })
23
- * ```
24
- */
25
- tracked: FunctionWrapper
26
- /**
27
- * Tracks dependencies in the parent effect context
28
- * Use this when child effects should track dependencies in the parent,
29
- * allowing parent cleanup to manage child effects while dependencies trigger the parent
30
- * @example
31
- * ```typescript
32
- * effect(({ ascend }) => {
33
- * const length = inputs.length
34
- * if (length > 0) {
35
- * ascend(() => {
36
- * // Dependencies here are tracked in the parent effect
37
- * inputs.forEach(item => console.log(item))
38
- * })
39
- * }
40
- * })
41
- * ```
42
- */
43
- ascend: FunctionWrapper
44
- /**
45
- * Indicates whether the effect is running as a reaction (i.e. not the first call)
46
- * - `false`: First execution when the effect is created
47
- * - `true`: Subsequent executions triggered by dependency changes
48
- * @example
49
- * ```typescript
50
- * effect(({ reaction }) => {
51
- * if (!reaction) {
52
- * console.log('Effect initialized')
53
- * // Setup code that should only run once
54
- * } else {
55
- * console.log('Effect re-ran due to dependency change')
56
- * // Code that runs on every update
57
- * }
58
- * })
59
- * ```
60
- */
61
- reaction: boolean
62
- }
63
- // Zone-based async context preservation is implemented in zone.ts
64
- // It automatically preserves effect context across Promise boundaries (.then, .catch, .finally)
65
-
66
- /**
67
- * Type for effect cleanup functions
68
- */
69
- export type ScopedCallback = () => void
70
-
71
- /**
72
- * Async execution mode for effects
73
- * - `cancel`: Cancel previous async execution when dependencies change (default)
74
- * - `queue`: Queue next execution to run after current completes
75
- * - `ignore`: Ignore new executions while async work is running
76
- */
77
- export type AsyncExecutionMode = 'cancel' | 'queue' | 'ignore'
78
-
79
- /**
80
- * Options for effect creation
81
- */
82
- export interface EffectOptions {
83
- /**
84
- * How to handle async effect executions when dependencies change
85
- * @default 'cancel'
86
- */
87
- asyncMode?: AsyncExecutionMode
88
- /**
89
- * If true, this effect is "opaque" to deep optimizations: it sees the object reference itself
90
- * and must be notified when it changes, regardless of deep content similarity.
91
- * Use this for effects that depend on object identity (like memoize).
92
- */
93
- opaque?: boolean
94
- }
95
-
96
- /**
97
- * Type for property evolution events
98
- */
99
- export type PropEvolution = {
100
- type: 'set' | 'del' | 'add' | 'invalidate'
101
- prop: any
102
- }
103
-
104
- /**
105
- * Type for collection operation evolution events
106
- */
107
- export type BunchEvolution = {
108
- type: 'bunch'
109
- method: string
110
- }
111
- export type Evolution = PropEvolution | BunchEvolution
112
-
113
- type State =
114
- | {
115
- evolution: Evolution
116
- next: State
117
- }
118
- | {}
119
-
120
- // Track native reactivity
121
- const nativeReactive = Symbol('native-reactive')
122
-
123
- /**
124
- * Symbol to mark individual objects as non-reactive
125
- */
126
- export const nonReactiveMark = Symbol('non-reactive')
127
- /**
128
- * Symbol to mark class properties as non-reactive
129
- */
130
- export const unreactiveProperties = Symbol('unreactive-properties')
131
-
132
- /**
133
- * Symbol representing all properties in reactive tracking
134
- */
135
- export const allProps = Symbol('all-props')
136
-
137
- /**
138
- * Symbol for accessing projection information on reactive objects
139
- */
140
- export const projectionInfo = Symbol('projection-info')
141
-
142
- /**
143
- * Symbol to check if an effect is stopped
144
- */
145
- export const stopped = Symbol('stopped')
146
-
147
- /**
148
- * Symbol to access effect cleanup function
149
- */
150
- export const cleanup = Symbol('cleanup')
151
-
152
- /**
153
- * Context for a running projection item effect
154
- */
155
- export interface ProjectionContext {
156
- source: any
157
- key?: any
158
- target: any
159
- depth: number
160
- parent?: ProjectionContext
161
- }
162
-
163
- // Symbol to mark functions with their root function
164
- const rootFunction = Symbol('root-function')
165
-
166
- /**
167
- * Structured error codes for machine-readable diagnosis
168
- */
169
- export enum ReactiveErrorCode {
170
- CycleDetected = 'CYCLE_DETECTED',
171
- MaxDepthExceeded = 'MAX_DEPTH_EXCEEDED',
172
- MaxReactionExceeded = 'MAX_REACTION_EXCEEDED',
173
- WriteInComputed = 'WRITE_IN_COMPUTED',
174
- TrackingError = 'TRACKING_ERROR',
175
- BrokenEffects = 'BROKEN_EFFECTS',
176
- }
177
-
178
- export type CycleDebugInfo = {
179
- code: ReactiveErrorCode.CycleDetected
180
- cycle: string[]
181
- details?: string
182
- }
183
-
184
- export type MaxDepthDebugInfo = {
185
- code: ReactiveErrorCode.MaxDepthExceeded
186
- depth: number
187
- chain: string[]
188
- }
189
-
190
- export type MaxReactionDebugInfo = {
191
- code: ReactiveErrorCode.MaxReactionExceeded
192
- count: number
193
- effect: string
194
- }
195
-
196
- export type BrokenEffectsDebugInfo = {
197
- code: ReactiveErrorCode.BrokenEffects
198
- cause: any
199
- }
200
-
201
- export type GenericDebugInfo = {
202
- code: ReactiveErrorCode
203
- causalChain?: string[]
204
- creationStack?: string
205
- [key: string]: any
206
- }
207
-
208
- export type ReactiveDebugInfo =
209
- | CycleDebugInfo
210
- | MaxDepthDebugInfo
211
- | MaxReactionDebugInfo
212
- | BrokenEffectsDebugInfo
213
- | GenericDebugInfo
214
-
215
- /**
216
- * Error class for reactive system errors
217
- */
218
- export class ReactiveError extends Error {
219
- constructor(
220
- message: string,
221
- public debugInfo?: ReactiveDebugInfo
222
- ) {
223
- super(message)
224
- this.name = 'ReactiveError'
225
- }
226
-
227
- get code(): ReactiveErrorCode | undefined {
228
- return this.debugInfo?.code
229
- }
230
-
231
- get cause(): any {
232
- return (this.debugInfo as any)?.cause
233
- }
234
- }
235
-
236
- // biome-ignore-start lint/correctness/noUnusedFunctionParameters: Interface declaration with empty defaults
237
- /**
238
- * Global options for the reactive system
239
- */
240
- export const options = {
241
- /**
242
- * Debug purpose: called when an effect is entered
243
- * @param effect - The effect that is entered
244
- */
245
- enter: (_effect: Function) => {},
246
- /**
247
- * Debug purpose: called when an effect is left
248
- * @param effect - The effect that is left
249
- */
250
- leave: (_effect: Function) => {},
251
- /**
252
- * Debug purpose: called when an effect is chained
253
- * @param target - The effect that is being triggered
254
- * @param caller - The effect that is calling the target
255
- */
256
- chain: (_targets: Function[], _caller?: Function) => {},
257
- /**
258
- * Debug purpose: called when an effect chain is started
259
- * @param target - The effect that is being triggered
260
- */
261
- beginChain: (_targets: Function[]) => {},
262
- /**
263
- * Debug purpose: called when an effect chain is ended
264
- */
265
- endChain: () => {},
266
- garbageCollected: (_fn: Function) => {},
267
- /**
268
- * Debug purpose: called when an object is touched
269
- * @param obj - The object that is touched
270
- * @param evolution - The type of change
271
- * @param props - The properties that changed
272
- * @param deps - The dependencies that changed
273
- */
274
- touched: (_obj: any, _evolution: Evolution, _props?: any[], _deps?: Set<ScopedCallback>) => {},
275
- /**
276
- * Debug purpose: called when an effect is skipped because it's already running
277
- * @param effect - The effect that is already running
278
- * @param runningChain - The array of effects from the detected one to the currently running one
279
- */
280
- skipRunningEffect: (_effect: ScopedCallback) => {},
281
- /**
282
- * Debug purpose: maximum effect chain (like call stack max depth)
283
- * Used to prevent infinite loops
284
- * @default 100
285
- */
286
- maxEffectChain: 100,
287
- /**
288
- * Maximum number of times an effect can be triggered by the same cause in a single batch
289
- * Used to detect aggressive re-computation or infinite loops
290
- * @default 10
291
- */
292
- maxTriggerPerBatch: 10,
293
- /**
294
- * Debug purpose: maximum effect reaction (like call stack max depth)
295
- * Used to prevent infinite loops
296
- * @default 'throw'
297
- */
298
- maxEffectReaction: 'throw' as 'throw' | 'debug' | 'warn',
299
- /**
300
- * Callback called when a memoization discrepancy is detected (debug only)
301
- * When defined, memoized functions will run a second time (untracked) to verify consistency.
302
- * If the untracked run returns a different value than the cached one, this callback is triggered.
303
- *
304
- * This is the primary tool for detecting missing reactive dependencies in computed values.
305
- *
306
- * @param cached - The value currently in the memoization cache
307
- * @param fresh - The value obtained by re-running the function untracked
308
- * @param fn - The memoized function itself
309
- * @param args - Arguments passed to the function
310
- *
311
- * @example
312
- * ```typescript
313
- * reactiveOptions.onMemoizationDiscrepancy = (cached, fresh, fn, args) => {
314
- * throw new Error(`Memoization discrepancy in ${fn.name}!`);
315
- * };
316
- * ```
317
- */
318
- onMemoizationDiscrepancy: undefined as
319
- | ((
320
- cached: any,
321
- fresh: any,
322
- fn: Function,
323
- args: any[],
324
- cause: 'calculation' | 'comparison'
325
- ) => void)
326
- | undefined,
327
- /**
328
- * How to handle cycles detected in effect batches.
329
- *
330
- * - `'none'` (Default): High-performance mode. Disables dependency graph maintenance and
331
- * Topological Sorting in favor of a simple FIFO queue. Use this for trustworthy, acyclic UI code.
332
- * Cycle detection is heuristic (uses execution counts).
333
- *
334
- * - `'throw'`: Traditional Topological Sorting. Guarantees dependency order and catches
335
- * circular dependencies mathematically before execution.
336
- *
337
- * - `'warn'`: Topological sorting, but logs a warning instead of throwing on cycles.
338
- * - `'break'`: Topological sorting, but silently breaks cycles.
339
- * - `'strict'`: Prevents cycle creation by checking the graph *during* dependency discovery.
340
- *
341
- * @default 'none'
342
- */
343
- cycleHandling: 'none' as 'none' | 'throw' | 'warn' | 'break' | 'strict',
344
- /**
345
- * Internal flag used by memoization discrepancy detector to avoid counting calls in tests
346
- * @warning Do not modify this flag manually, this flag is given by the engine
347
- */
348
- isVerificationRun: false,
349
- /**
350
- * Maximum depth for deep watching traversal
351
- * Used to prevent infinite recursion in circular references
352
- * @default 100
353
- */
354
- maxDeepWatchDepth: 100,
355
- /**
356
- * Only react on instance members modification (not inherited properties)
357
- * For instance, do not track class methods
358
- * @default true
359
- */
360
- instanceMembers: true,
361
- /**
362
- * Ignore accessors (getters and setters) and only track direct properties
363
- * @default true
364
- */
365
- ignoreAccessors: true,
366
- /**
367
- * Enable recursive touching when objects with the same prototype are replaced
368
- * When enabled, replacing an object with another of the same prototype triggers
369
- * recursive diffing instead of notifying parent effects
370
- * @default true
371
- */
372
- recursiveTouching: true,
373
- /**
374
- * Default async execution mode for effects that return Promises
375
- * - 'cancel': Cancel previous async execution when dependencies change (default, enables async zone)
376
- * - 'queue': Queue next execution to run after current completes (enables async zone)
377
- * - 'ignore': Ignore new executions while async work is running (enables async zone)
378
- * - false: Disable async zone and async mode handling (effects run concurrently)
379
- *
380
- * **When truthy:** Enables async zone (Promise.prototype wrapping) for automatic context
381
- * preservation in Promise callbacks. Warning: This modifies Promise.prototype globally.
382
- * Only enable if no other library modifies Promise.prototype.
383
- *
384
- * **When false:** Async zone is disabled. Use `tracked()` manually in Promise callbacks.
385
- *
386
- * Can be overridden per-effect via EffectOptions
387
- * @default 'cancel'
388
- */
389
- asyncMode: 'cancel' as AsyncExecutionMode | false,
390
- // biome-ignore lint/suspicious/noConsole: This is the whole point here
391
- warn: (...args: any[]) => console.warn(...args),
392
-
393
- /**
394
- * Configuration for the introspection system
395
- */
396
- introspection: {
397
- /**
398
- * Whether to keep a history of mutations for debugging
399
- * @default false
400
- */
401
- enableHistory: false,
402
- /**
403
- * Number of mutations to keep in history
404
- * @default 50
405
- */
406
- historySize: 50,
407
- },
408
-
409
- /**
410
- * Configuration for zone hooks - control which async APIs are hooked
411
- * Each option controls whether the corresponding async API is wrapped to preserve effect context
412
- * Only applies when asyncMode is enabled (truthy)
413
- * @deprecated Should take all when we made sure PIXI.create, Game.create, ... are -> .root()
414
- */
415
- zones: {
416
- /**
417
- * Hook setTimeout to preserve effect context
418
- * @default true
419
- */
420
- setTimeout: true,
421
- /**
422
- * Hook setInterval to preserve effect context
423
- * @default true
424
- */
425
- setInterval: true,
426
- /**
427
- * Hook requestAnimationFrame (runs in untracked context when hooked)
428
- * @default true
429
- */
430
- requestAnimationFrame: true,
431
- /**
432
- * Hook queueMicrotask to preserve effect context
433
- * @default true
434
- */
435
- queueMicrotask: true,
436
- },
437
- }
438
- // biome-ignore-end lint/correctness/noUnusedFunctionParameters: Interface declaration with empty defaults
439
-
440
- export { type State, nativeReactive, rootFunction }
@@ -1,217 +0,0 @@
1
- import { decorator, type GenericClassDecorator } from './decorator'
2
-
3
- // In order to avoid async re-entrance, we could use zone.js or something like that.
4
- const syncCalculating: { object: object; prop: PropertyKey }[] = []
5
- /**
6
- * Decorator that caches the result of a getter method and only recomputes when dependencies change
7
- * Prevents circular dependencies and provides automatic cache invalidation
8
- */
9
- export const cached = decorator({
10
- getter(original, _target, propertyKey) {
11
- return function (this: any) {
12
- const alreadyCalculating = syncCalculating.findIndex(
13
- (c) => c.object === this && c.prop === propertyKey
14
- )
15
- if (alreadyCalculating > -1)
16
- throw new Error(
17
- `Circular dependency detected: ${syncCalculating
18
- .slice(alreadyCalculating)
19
- .map((c) => `${c.object.constructor.name}.${String(c.prop)}`)
20
- .join(' -> ')} -> again`
21
- )
22
- syncCalculating.push({ object: this, prop: propertyKey })
23
- try {
24
- const rv = original.call(this)
25
- cache(this, propertyKey, rv)
26
- return rv
27
- } finally {
28
- syncCalculating.pop()
29
- }
30
- }
31
- },
32
- })
33
-
34
- /**
35
- * Checks if a property is cached (has a cached value)
36
- * @param object - The object to check
37
- * @param propertyKey - The property key to check
38
- * @returns True if the property has a cached value
39
- */
40
- export function isCached(object: Object, propertyKey: PropertyKey) {
41
- return !!Object.getOwnPropertyDescriptor(object, propertyKey)
42
- }
43
-
44
- /**
45
- * Caches a value for a property on an object
46
- * @param object - The object to cache the value on
47
- * @param propertyKey - The property key to cache
48
- * @param value - The value to cache
49
- */
50
- export function cache(object: Object, propertyKey: PropertyKey, value: any) {
51
- Object.defineProperty(object, propertyKey, { value })
52
- }
53
-
54
- /**
55
- * Creates a decorator that modifies property descriptors for specified properties
56
- * @param descriptor - The descriptor properties to apply
57
- * @returns A class decorator that applies the descriptor to specified properties
58
- */
59
- export function describe(descriptor: {
60
- enumerable?: boolean
61
- configurable?: boolean // Not modifiable once the property has been defined ?
62
- writable?: boolean
63
- }) {
64
- return <T>(...properties: (keyof T)[]): GenericClassDecorator<T> =>
65
- (Base) => {
66
- return class extends Base {
67
- constructor(...args: any[]) {
68
- super(...args)
69
- for (const key of properties) {
70
- Object.defineProperty(this, key, {
71
- ...Object.getOwnPropertyDescriptor(this, key),
72
- ...descriptor,
73
- })
74
- }
75
- }
76
- }
77
- }
78
- }
79
-
80
- /**
81
- * Decorator that marks methods, properties, or classes as deprecated
82
- * Provides warning messages when deprecated items are used
83
- */
84
- export const deprecated = Object.assign(
85
- decorator({
86
- method(original, _target, propertyKey) {
87
- return function (this: any, ...args: any[]) {
88
- deprecated.warn(this, propertyKey)
89
- return original.apply(this, args)
90
- }
91
- },
92
- getter(original, _target, propertyKey) {
93
- return function (this: any) {
94
- deprecated.warn(this, propertyKey)
95
- return original.call(this)
96
- }
97
- },
98
- setter(original, _target, propertyKey) {
99
- return function (this: any, value: any) {
100
- deprecated.warn(this, propertyKey)
101
- return original.call(this, value)
102
- }
103
- },
104
- class(original) {
105
- return class extends original {
106
- constructor(...args: any[]) {
107
- super(...args)
108
- deprecated.warn(this, 'constructor')
109
- }
110
- }
111
- },
112
- default(message: string) {
113
- return decorator({
114
- method(original, _target, propertyKey) {
115
- return function (this: any, ...args: any[]) {
116
- deprecated.warn(this, propertyKey, message)
117
- return original.apply(this, args)
118
- }
119
- },
120
- getter(original, _target, propertyKey) {
121
- return function (this: any) {
122
- deprecated.warn(this, propertyKey, message)
123
- return original.call(this)
124
- }
125
- },
126
- setter(original, _target, propertyKey) {
127
- return function (this: any, value: any) {
128
- deprecated.warn(this, propertyKey, message)
129
- return original.call(this, value)
130
- }
131
- },
132
- class(original) {
133
- return class extends original {
134
- constructor(...args: any[]) {
135
- super(...args)
136
- deprecated.warn(this, 'constructor', message)
137
- }
138
- }
139
- },
140
- })
141
- },
142
- }),
143
- {
144
- warn: (target: any, propertyKey: PropertyKey, message?: string) => {
145
- // biome-ignore lint/suspicious/noConsole: To be overridden
146
- console.warn(
147
- `${target.constructor.name}.${String(propertyKey)} is deprecated${message ? `: ${message}` : ''}`
148
- )
149
- },
150
- }
151
- )
152
-
153
- /**
154
- * Creates a debounced method decorator that delays execution until after the delay period has passed
155
- * @param delay - The delay in milliseconds
156
- * @returns A method decorator that debounces method calls
157
- */
158
- export function debounce(delay: number) {
159
- return decorator({
160
- method(original, _target, _propertyKey) {
161
- let timeoutId: ReturnType<typeof setTimeout> | null = null
162
-
163
- return function (this: any, ...args: any[]) {
164
- // Clear existing timeout
165
- if (timeoutId) {
166
- clearTimeout(timeoutId)
167
- }
168
-
169
- // Set new timeout
170
- timeoutId = setTimeout(() => {
171
- original.apply(this, args)
172
- timeoutId = null
173
- }, delay)
174
- }
175
- },
176
- })
177
- }
178
-
179
- /**
180
- * Creates a throttled method decorator that limits execution to once per delay period
181
- * @param delay - The delay in milliseconds
182
- * @returns A method decorator that throttles method calls
183
- */
184
- export function throttle(delay: number) {
185
- return decorator({
186
- method(original, _target, _propertyKey) {
187
- let lastCallTime = 0
188
- let timeoutId: ReturnType<typeof setTimeout> | null = null
189
-
190
- return function (this: any, ...args: any[]) {
191
- const now = Date.now()
192
-
193
- // If enough time has passed since last call, execute immediately
194
- if (now - lastCallTime >= delay) {
195
- // Clear any pending timeout since we're executing now
196
- if (timeoutId) {
197
- clearTimeout(timeoutId)
198
- timeoutId = null
199
- }
200
- lastCallTime = now
201
- return original.apply(this, args)
202
- }
203
-
204
- // Otherwise, schedule execution for when the delay period ends
205
- if (!timeoutId) {
206
- const remainingTime = delay - (now - lastCallTime)
207
- const scheduledArgs = [...args] // Capture args at scheduling time
208
- timeoutId = setTimeout(() => {
209
- lastCallTime = Date.now()
210
- original.apply(this, scheduledArgs)
211
- timeoutId = null
212
- }, remainingTime)
213
- }
214
- }
215
- },
216
- })
217
- }