mutts 1.0.9 → 1.0.11
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 +60 -35
- package/dist/browser.cjs +1333 -1760
- package/dist/browser.cjs.map +1 -1
- package/dist/browser.d.ts +2 -1392
- package/dist/browser.dev.cjs +114 -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 +18 -97
- package/dist/browser.esm.js.map +1 -1
- package/dist/chunks/{async-browser-lvzLOCgk.cjs → async-browser-Dgr5CreQ.cjs} +16 -95
- package/dist/chunks/async-browser-Dgr5CreQ.cjs.map +1 -0
- package/dist/chunks/{async-node-C3DeIb0y.cjs → async-node-3PrbVAbB.cjs} +3 -1
- package/dist/chunks/async-node-3PrbVAbB.cjs.map +1 -0
- package/dist/chunks/index-Sf74wXTV.esm.js +2577 -0
- package/dist/chunks/index-Sf74wXTV.esm.js.map +1 -0
- package/dist/chunks/node-Bo7WU5S2.esm.js +96 -0
- package/dist/chunks/node-Bo7WU5S2.esm.js.map +1 -0
- package/dist/chunks/{index-VTO-b2vR.cjs → proxy-Cc79Lrzj.cjs} +2593 -3216
- package/dist/chunks/proxy-Cc79Lrzj.cjs.map +1 -0
- package/dist/chunks/{index-CtA2AWl3.esm.js → proxy-D2C49sXH.esm.js} +2570 -3174
- package/dist/chunks/proxy-D2C49sXH.esm.js.map +1 -0
- package/dist/debug.cjs +987 -28
- package/dist/debug.cjs.map +1 -1
- package/dist/debug.d.ts +37 -38
- package/dist/debug.esm.js +963 -1
- package/dist/debug.esm.js.map +1 -1
- 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 +1322 -1
- package/dist/mutts.umd.js +6647 -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 +69 -63
- package/dist/node.cjs.map +1 -1
- package/dist/node.d.ts +2 -2
- package/dist/node.dev.cjs +114 -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 -97
- package/dist/node.esm.js.map +1 -1
- package/dist/{types-DaHFfhlN.d.ts → types-Bx2PhORg.d.ts} +134 -88
- package/docs/ai/api-reference.md +11 -32
- package/docs/ai/manual.md +297 -239
- package/docs/reactive/advanced.md +318 -9
- package/docs/reactive/attend.md +2 -4
- package/docs/reactive/collections.md +22 -187
- package/docs/reactive/core.md +223 -131
- package/docs/reactive/debugging.md +119 -12
- package/docs/reactive/error-handling.md +10 -10
- package/docs/reactive/resource.md +125 -0
- package/docs/reactive.md +3 -4
- package/docs/utils.md +70 -0
- package/docs/zone.md +1 -1
- package/package.json +76 -38
- package/dist/chunks/async-browser-lvzLOCgk.cjs.map +0 -1
- package/dist/chunks/async-node-C3DeIb0y.cjs.map +0 -1
- package/dist/chunks/index-2vea86wD.esm.js +0 -3011
- package/dist/chunks/index-2vea86wD.esm.js.map +0 -1
- package/dist/chunks/index-CtA2AWl3.esm.js.map +0 -1
- package/dist/chunks/index-VTO-b2vR.cjs.map +0 -1
- package/dist/debug/debug.d.ts +0 -122
- package/dist/debug/debug.d.ts.map +0 -1
- package/dist/debug/index.d.ts +0 -4
- package/dist/debug/index.d.ts.map +0 -1
- package/dist/debug/lineage-panel.d.ts +0 -5
- package/dist/debug/lineage-panel.d.ts.map +0 -1
- package/dist/debug/lineage.d.ts +0 -79
- package/dist/debug/lineage.d.ts.map +0 -1
- package/dist/src/async/browser.d.ts +0 -2
- package/dist/src/async/browser.d.ts.map +0 -1
- package/dist/src/async/index.d.ts +0 -19
- package/dist/src/async/index.d.ts.map +0 -1
- package/dist/src/async/node.d.ts +0 -2
- package/dist/src/async/node.d.ts.map +0 -1
- package/dist/src/decorator.d.ts +0 -106
- package/dist/src/decorator.d.ts.map +0 -1
- package/dist/src/destroyable.d.ts +0 -87
- package/dist/src/destroyable.d.ts.map +0 -1
- package/dist/src/entry-browser.d.ts +0 -3
- package/dist/src/entry-browser.d.ts.map +0 -1
- package/dist/src/entry-node.d.ts +0 -3
- package/dist/src/entry-node.d.ts.map +0 -1
- package/dist/src/eventful.d.ts +0 -20
- package/dist/src/eventful.d.ts.map +0 -1
- package/dist/src/flavored.d.ts +0 -33
- package/dist/src/flavored.d.ts.map +0 -1
- package/dist/src/index.d.ts +0 -14
- package/dist/src/index.d.ts.map +0 -1
- package/dist/src/indexable.d.ts +0 -243
- package/dist/src/indexable.d.ts.map +0 -1
- package/dist/src/introspection.d.ts +0 -27
- package/dist/src/introspection.d.ts.map +0 -1
- package/dist/src/iterableWeak.d.ts +0 -53
- package/dist/src/iterableWeak.d.ts.map +0 -1
- package/dist/src/mixins.d.ts +0 -25
- package/dist/src/mixins.d.ts.map +0 -1
- package/dist/src/promiseChain.d.ts +0 -20
- package/dist/src/promiseChain.d.ts.map +0 -1
- package/dist/src/reactive/array.d.ts +0 -48
- package/dist/src/reactive/array.d.ts.map +0 -1
- package/dist/src/reactive/buffer.d.ts +0 -120
- package/dist/src/reactive/buffer.d.ts.map +0 -1
- package/dist/src/reactive/change.d.ts +0 -29
- package/dist/src/reactive/change.d.ts.map +0 -1
- package/dist/src/reactive/deep-touch.d.ts +0 -28
- package/dist/src/reactive/deep-touch.d.ts.map +0 -1
- package/dist/src/reactive/deep-watch-state.d.ts +0 -25
- package/dist/src/reactive/deep-watch-state.d.ts.map +0 -1
- package/dist/src/reactive/deep-watch.d.ts +0 -20
- package/dist/src/reactive/deep-watch.d.ts.map +0 -1
- package/dist/src/reactive/describe.d.ts +0 -12
- package/dist/src/reactive/describe.d.ts.map +0 -1
- package/dist/src/reactive/effect-context.d.ts +0 -34
- package/dist/src/reactive/effect-context.d.ts.map +0 -1
- package/dist/src/reactive/effects.d.ts +0 -164
- package/dist/src/reactive/effects.d.ts.map +0 -1
- package/dist/src/reactive/index.d.ts +0 -19
- package/dist/src/reactive/index.d.ts.map +0 -1
- package/dist/src/reactive/map.d.ts +0 -28
- package/dist/src/reactive/map.d.ts.map +0 -1
- package/dist/src/reactive/memoize.d.ts +0 -28
- package/dist/src/reactive/memoize.d.ts.map +0 -1
- package/dist/src/reactive/non-reactive-state.d.ts +0 -9
- package/dist/src/reactive/non-reactive-state.d.ts.map +0 -1
- package/dist/src/reactive/non-reactive.d.ts +0 -11
- package/dist/src/reactive/non-reactive.d.ts.map +0 -1
- package/dist/src/reactive/project.d.ts +0 -40
- package/dist/src/reactive/project.d.ts.map +0 -1
- package/dist/src/reactive/proxy-state.d.ts +0 -8
- package/dist/src/reactive/proxy-state.d.ts.map +0 -1
- package/dist/src/reactive/proxy.d.ts +0 -23
- package/dist/src/reactive/proxy.d.ts.map +0 -1
- package/dist/src/reactive/record.d.ts +0 -115
- package/dist/src/reactive/record.d.ts.map +0 -1
- package/dist/src/reactive/register.d.ts +0 -125
- package/dist/src/reactive/register.d.ts.map +0 -1
- package/dist/src/reactive/registry.d.ts +0 -21
- package/dist/src/reactive/registry.d.ts.map +0 -1
- package/dist/src/reactive/set.d.ts +0 -26
- package/dist/src/reactive/set.d.ts.map +0 -1
- package/dist/src/reactive/tracking.d.ts +0 -7
- package/dist/src/reactive/tracking.d.ts.map +0 -1
- package/dist/src/reactive/types.d.ts +0 -424
- package/dist/src/reactive/types.d.ts.map +0 -1
- package/dist/src/reactive/watch.d.ts +0 -48
- package/dist/src/reactive/watch.d.ts.map +0 -1
- package/dist/src/std-decorators.d.ts +0 -45
- package/dist/src/std-decorators.d.ts.map +0 -1
- package/dist/src/utils.d.ts +0 -49
- package/dist/src/utils.d.ts.map +0 -1
- package/dist/src/zone.d.ts +0 -40
- package/dist/src/zone.d.ts.map +0 -1
- package/docs/reactive/describe.md +0 -85
- package/docs/reactive/project.md +0 -93
- package/docs/reactive/scan.md +0 -293
- package/src/async/browser.ts +0 -323
- package/src/async/index.ts +0 -27
- package/src/async/node.ts +0 -92
- 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 -110
- package/src/flavored.ts +0 -106
- 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 -500
- package/src/reactive/buffer.ts +0 -328
- package/src/reactive/change.ts +0 -131
- package/src/reactive/deep-touch.ts +0 -273
- package/src/reactive/deep-watch-state.ts +0 -82
- package/src/reactive/deep-watch.ts +0 -171
- package/src/reactive/describe.ts +0 -39
- package/src/reactive/effect-context.ts +0 -83
- package/src/reactive/effects.ts +0 -1434
- package/src/reactive/index.ts +0 -72
- package/src/reactive/map.ts +0 -142
- package/src/reactive/memoize.ts +0 -186
- package/src/reactive/non-reactive-state.ts +0 -49
- package/src/reactive/non-reactive.ts +0 -43
- package/src/reactive/project.md +0 -107
- package/src/reactive/project.ts +0 -430
- package/src/reactive/proxy-state.ts +0 -27
- package/src/reactive/proxy.ts +0 -282
- package/src/reactive/record.ts +0 -181
- package/src/reactive/register.ts +0 -538
- package/src/reactive/registry.ts +0 -72
- package/src/reactive/set.ts +0 -117
- package/src/reactive/tracking.ts +0 -41
- package/src/reactive/types.ts +0 -520
- package/src/reactive/watch.ts +0 -180
- package/src/std-decorators.ts +0 -256
- package/src/utils.ts +0 -300
- package/src/zone.ts +0 -142
package/src/reactive/watch.ts
DELETED
|
@@ -1,180 +0,0 @@
|
|
|
1
|
-
import { decorator, type GenericClassDecorator } from '../decorator'
|
|
2
|
-
import { deepWatch } from './deep-watch'
|
|
3
|
-
import { effect } from './effects'
|
|
4
|
-
import { isNonReactive, nonReactiveClass, nonReactiveObjects } from './non-reactive-state'
|
|
5
|
-
import { unwrap } from './proxy-state'
|
|
6
|
-
import { markWithRoot } from './registry'
|
|
7
|
-
import { dependant } from './tracking'
|
|
8
|
-
import {
|
|
9
|
-
type EffectAccess,
|
|
10
|
-
type EffectCleanup,
|
|
11
|
-
nonReactiveMark,
|
|
12
|
-
stopped,
|
|
13
|
-
unreactiveProperties,
|
|
14
|
-
} from './types'
|
|
15
|
-
|
|
16
|
-
//#region watch
|
|
17
|
-
|
|
18
|
-
const unsetYet = Symbol('unset-yet')
|
|
19
|
-
/**
|
|
20
|
-
* Options for the watch function
|
|
21
|
-
*/
|
|
22
|
-
export interface WatchOptions {
|
|
23
|
-
/** Whether to call the callback immediately */
|
|
24
|
-
immediate?: boolean
|
|
25
|
-
/** Whether to watch nested properties */
|
|
26
|
-
deep?: boolean
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Watches a reactive value and calls a callback when it changes
|
|
31
|
-
* @param value - Function that returns the value to watch
|
|
32
|
-
* @param changed - Callback to call when the value changes
|
|
33
|
-
* @param options - Watch options
|
|
34
|
-
* @returns Cleanup function to stop watching
|
|
35
|
-
*/
|
|
36
|
-
export function watch<T>(
|
|
37
|
-
value: (dep: EffectAccess) => T,
|
|
38
|
-
changed: (value: T, oldValue?: T) => void,
|
|
39
|
-
options?: Omit<WatchOptions, 'deep'> & { deep?: false }
|
|
40
|
-
): EffectCleanup
|
|
41
|
-
/**
|
|
42
|
-
* Watches a reactive value with deep watching enabled
|
|
43
|
-
* @param value - Function that returns the value to watch
|
|
44
|
-
* @param changed - Callback to call when the value changes
|
|
45
|
-
* @param options - Watch options with deep watching enabled
|
|
46
|
-
* @returns Cleanup function to stop watching
|
|
47
|
-
*/
|
|
48
|
-
export function watch<T extends object | any[]>(
|
|
49
|
-
value: (dep: EffectAccess) => T,
|
|
50
|
-
changed: (value: T, oldValue?: T) => void,
|
|
51
|
-
options?: Omit<WatchOptions, 'deep'> & { deep: true }
|
|
52
|
-
): EffectCleanup
|
|
53
|
-
/**
|
|
54
|
-
* Watches a reactive object directly
|
|
55
|
-
* @param value - The reactive object to watch
|
|
56
|
-
* @param changed - Callback to call when the object changes
|
|
57
|
-
* @param options - Watch options
|
|
58
|
-
* @returns Cleanup function to stop watching
|
|
59
|
-
*/
|
|
60
|
-
export function watch<T extends object | any[]>(
|
|
61
|
-
value: T,
|
|
62
|
-
changed: (value: T) => void,
|
|
63
|
-
options?: WatchOptions
|
|
64
|
-
): EffectCleanup
|
|
65
|
-
|
|
66
|
-
export function watch(
|
|
67
|
-
value: any, //object | ((dep: DependencyAccess) => object),
|
|
68
|
-
changed: (value?: object, oldValue?: object) => void,
|
|
69
|
-
options: any = {}
|
|
70
|
-
) {
|
|
71
|
-
return typeof value === 'function'
|
|
72
|
-
? watchCallBack(value, changed, options)
|
|
73
|
-
: typeof value === 'object' && value !== null
|
|
74
|
-
? watchObject(value, changed, options)
|
|
75
|
-
: (() => {
|
|
76
|
-
throw new Error('watch: value must be a function or an object')
|
|
77
|
-
})()
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
function watchObject(
|
|
81
|
-
value: object,
|
|
82
|
-
changed: (value: object) => void,
|
|
83
|
-
{ immediate = false, deep = false } = {}
|
|
84
|
-
): EffectCleanup {
|
|
85
|
-
if (deep) return deepWatch(value, changed, { immediate })!
|
|
86
|
-
return effect(function watchObjectEffect() {
|
|
87
|
-
dependant(value)
|
|
88
|
-
if (immediate) changed(value)
|
|
89
|
-
immediate = true
|
|
90
|
-
})
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
function watchCallBack<T>(
|
|
94
|
-
value: (dep: EffectAccess) => T,
|
|
95
|
-
changed: (value: T, oldValue?: T) => void,
|
|
96
|
-
{ immediate = false, deep = false } = {}
|
|
97
|
-
): EffectCleanup {
|
|
98
|
-
let oldValue: T | typeof unsetYet = unsetYet
|
|
99
|
-
let deepCleanup: EffectCleanup | undefined
|
|
100
|
-
const cbCleanup = effect(
|
|
101
|
-
markWithRoot(function watchCallBackEffect(access) {
|
|
102
|
-
const newValue = value(access)
|
|
103
|
-
if (oldValue !== newValue)
|
|
104
|
-
if (oldValue === unsetYet) {
|
|
105
|
-
if (immediate) changed(newValue)
|
|
106
|
-
} else changed(newValue, oldValue)
|
|
107
|
-
oldValue = newValue
|
|
108
|
-
if (deep) {
|
|
109
|
-
if (deepCleanup) deepCleanup()
|
|
110
|
-
deepCleanup = deepWatch(newValue as object, (value) => changed(value as T, value as T))
|
|
111
|
-
}
|
|
112
|
-
}, value)
|
|
113
|
-
)
|
|
114
|
-
return Object.defineProperties(
|
|
115
|
-
() => {
|
|
116
|
-
cbCleanup()
|
|
117
|
-
if (deepCleanup) deepCleanup()
|
|
118
|
-
},
|
|
119
|
-
{
|
|
120
|
-
[stopped]: { get: () => cbCleanup[stopped] },
|
|
121
|
-
}
|
|
122
|
-
) as EffectCleanup
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
//#endregion
|
|
126
|
-
|
|
127
|
-
//#region nonReactive
|
|
128
|
-
|
|
129
|
-
/**
|
|
130
|
-
* Mark an object as non-reactive. This object and all its properties will never be made reactive.
|
|
131
|
-
* @param obj - The object to mark as non-reactive
|
|
132
|
-
*/
|
|
133
|
-
function shallowNonReactive<T>(obj: T): T {
|
|
134
|
-
obj = unwrap(obj)
|
|
135
|
-
if (isNonReactive(obj)) return obj
|
|
136
|
-
try {
|
|
137
|
-
Object.defineProperty(obj as object, nonReactiveMark, {
|
|
138
|
-
value: true,
|
|
139
|
-
writable: false,
|
|
140
|
-
enumerable: false,
|
|
141
|
-
configurable: true,
|
|
142
|
-
})
|
|
143
|
-
} catch {}
|
|
144
|
-
if (!(nonReactiveMark in (obj as object))) nonReactiveObjects.add(obj as object)
|
|
145
|
-
// Finally, not deep
|
|
146
|
-
//for (const key in obj) deepNonReactive(obj[key])
|
|
147
|
-
return obj
|
|
148
|
-
}
|
|
149
|
-
function unreactiveApplication<T extends object>(...args: (keyof T)[]): GenericClassDecorator<T>
|
|
150
|
-
function unreactiveApplication<T extends object>(obj: T): T
|
|
151
|
-
function unreactiveApplication<T extends object>(
|
|
152
|
-
arg1: T | keyof T,
|
|
153
|
-
...args: (keyof T)[]
|
|
154
|
-
): GenericClassDecorator<T> | T {
|
|
155
|
-
return typeof arg1 === 'object'
|
|
156
|
-
? shallowNonReactive(arg1)
|
|
157
|
-
: (((original) => {
|
|
158
|
-
// Copy the parent's unreactive properties if they exist
|
|
159
|
-
original.prototype[unreactiveProperties] = new Set<PropertyKey>(
|
|
160
|
-
original.prototype[unreactiveProperties] || []
|
|
161
|
-
)
|
|
162
|
-
// Add all arguments (including the first one)
|
|
163
|
-
original.prototype[unreactiveProperties].add(arg1)
|
|
164
|
-
for (const arg of args) original.prototype[unreactiveProperties].add(arg)
|
|
165
|
-
return original // Return the class
|
|
166
|
-
}) as GenericClassDecorator<T>)
|
|
167
|
-
}
|
|
168
|
-
/**
|
|
169
|
-
* Decorator that marks classes or properties as non-reactive
|
|
170
|
-
* Prevents objects from being made reactive
|
|
171
|
-
*/
|
|
172
|
-
export const unreactive = decorator({
|
|
173
|
-
class(original) {
|
|
174
|
-
// Called without arguments, mark entire class as non-reactive
|
|
175
|
-
nonReactiveClass(original)
|
|
176
|
-
},
|
|
177
|
-
default: unreactiveApplication,
|
|
178
|
-
})
|
|
179
|
-
|
|
180
|
-
//#endregion
|
package/src/std-decorators.ts
DELETED
|
@@ -1,256 +0,0 @@
|
|
|
1
|
-
import { decorator, type GenericClassDecorator } from './decorator'
|
|
2
|
-
import { flavored } from './flavored'
|
|
3
|
-
|
|
4
|
-
// In order to avoid async re-entrance, we could use zone.js or something like that.
|
|
5
|
-
const syncCalculating: { object: object; prop: PropertyKey }[] = []
|
|
6
|
-
/**
|
|
7
|
-
* Decorator that caches the result of a getter method and only recomputes when dependencies change
|
|
8
|
-
* Prevents circular dependencies and provides automatic cache invalidation
|
|
9
|
-
*/
|
|
10
|
-
export const cached = decorator({
|
|
11
|
-
getter(original, _target, propertyKey) {
|
|
12
|
-
return function (this: any) {
|
|
13
|
-
const alreadyCalculating = syncCalculating.findIndex(
|
|
14
|
-
(c) => c.object === this && c.prop === propertyKey
|
|
15
|
-
)
|
|
16
|
-
if (alreadyCalculating > -1)
|
|
17
|
-
throw new Error(
|
|
18
|
-
`Circular dependency detected: ${syncCalculating
|
|
19
|
-
.slice(alreadyCalculating)
|
|
20
|
-
.map((c) => `${c.object.constructor.name}.${String(c.prop)}`)
|
|
21
|
-
.join(' -> ')} -> again`
|
|
22
|
-
)
|
|
23
|
-
syncCalculating.push({ object: this, prop: propertyKey })
|
|
24
|
-
try {
|
|
25
|
-
const rv = original.call(this)
|
|
26
|
-
cache(this, propertyKey, rv)
|
|
27
|
-
return rv
|
|
28
|
-
} finally {
|
|
29
|
-
syncCalculating.pop()
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
},
|
|
33
|
-
})
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Checks if a property is cached (has a cached value)
|
|
37
|
-
* @param object - The object to check
|
|
38
|
-
* @param propertyKey - The property key to check
|
|
39
|
-
* @returns True if the property has a cached value
|
|
40
|
-
*/
|
|
41
|
-
export function isCached(object: Object, propertyKey: PropertyKey) {
|
|
42
|
-
return !!Object.getOwnPropertyDescriptor(object, propertyKey)
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Caches a value for a property on an object
|
|
47
|
-
* @param object - The object to cache the value on
|
|
48
|
-
* @param propertyKey - The property key to cache
|
|
49
|
-
* @param value - The value to cache
|
|
50
|
-
*/
|
|
51
|
-
export function cache(object: Object, propertyKey: PropertyKey, value: any) {
|
|
52
|
-
Object.defineProperty(object, propertyKey, { value })
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Creates a decorator that modifies property descriptors for specified properties
|
|
57
|
-
* @param descriptor - The descriptor properties to apply
|
|
58
|
-
* @returns A class decorator that applies the descriptor to specified properties
|
|
59
|
-
*/
|
|
60
|
-
export const descriptor = flavored(
|
|
61
|
-
function descriptor(descriptor: {
|
|
62
|
-
enumerable?: boolean
|
|
63
|
-
configurable?: boolean // Not modifiable once the property has been defined
|
|
64
|
-
writable?: boolean
|
|
65
|
-
}) {
|
|
66
|
-
return <T>(...properties: (keyof T)[]): GenericClassDecorator<T> =>
|
|
67
|
-
(Base) => {
|
|
68
|
-
return class extends Base {
|
|
69
|
-
constructor(...args: any[]) {
|
|
70
|
-
super(...args)
|
|
71
|
-
for (const key of properties) {
|
|
72
|
-
const existing = Object.getOwnPropertyDescriptor(this, key)
|
|
73
|
-
Object.defineProperty(this, key, Object.assign(existing || {}, descriptor))
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
},
|
|
79
|
-
{
|
|
80
|
-
/**
|
|
81
|
-
* enumerable: true
|
|
82
|
-
*/
|
|
83
|
-
get enumerable() {
|
|
84
|
-
return descriptor({ enumerable: true })
|
|
85
|
-
},
|
|
86
|
-
/**
|
|
87
|
-
* enumerable: false
|
|
88
|
-
*/
|
|
89
|
-
get hidden() {
|
|
90
|
-
return descriptor({ enumerable: false })
|
|
91
|
-
},
|
|
92
|
-
/**
|
|
93
|
-
* configurable: true
|
|
94
|
-
*/
|
|
95
|
-
get configurable() {
|
|
96
|
-
return descriptor({ configurable: true })
|
|
97
|
-
},
|
|
98
|
-
/**
|
|
99
|
-
* configurable: false
|
|
100
|
-
*/
|
|
101
|
-
get frozen() {
|
|
102
|
-
return descriptor({ configurable: false })
|
|
103
|
-
},
|
|
104
|
-
/**
|
|
105
|
-
* writable: true
|
|
106
|
-
*/
|
|
107
|
-
get writable() {
|
|
108
|
-
return descriptor({ writable: true })
|
|
109
|
-
},
|
|
110
|
-
/**
|
|
111
|
-
* writable: false
|
|
112
|
-
*/
|
|
113
|
-
get readonly() {
|
|
114
|
-
return descriptor({ writable: false })
|
|
115
|
-
},
|
|
116
|
-
}
|
|
117
|
-
)
|
|
118
|
-
|
|
119
|
-
/**
|
|
120
|
-
* Decorator that marks methods, properties, or classes as deprecated
|
|
121
|
-
* Provides warning messages when deprecated items are used
|
|
122
|
-
*/
|
|
123
|
-
export const deprecated = Object.assign(
|
|
124
|
-
decorator({
|
|
125
|
-
method(original, _target, propertyKey) {
|
|
126
|
-
return function (this: any, ...args: any[]) {
|
|
127
|
-
deprecated.warn(this, propertyKey)
|
|
128
|
-
return original.apply(this, args)
|
|
129
|
-
}
|
|
130
|
-
},
|
|
131
|
-
getter(original, _target, propertyKey) {
|
|
132
|
-
return function (this: any) {
|
|
133
|
-
deprecated.warn(this, propertyKey)
|
|
134
|
-
return original.call(this)
|
|
135
|
-
}
|
|
136
|
-
},
|
|
137
|
-
setter(original, _target, propertyKey) {
|
|
138
|
-
return function (this: any, value: any) {
|
|
139
|
-
deprecated.warn(this, propertyKey)
|
|
140
|
-
return original.call(this, value)
|
|
141
|
-
}
|
|
142
|
-
},
|
|
143
|
-
class(original) {
|
|
144
|
-
return class extends original {
|
|
145
|
-
constructor(...args: any[]) {
|
|
146
|
-
super(...args)
|
|
147
|
-
deprecated.warn(this, 'constructor')
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
},
|
|
151
|
-
default(message: string) {
|
|
152
|
-
return decorator({
|
|
153
|
-
method(original, _target, propertyKey) {
|
|
154
|
-
return function (this: any, ...args: any[]) {
|
|
155
|
-
deprecated.warn(this, propertyKey, message)
|
|
156
|
-
return original.apply(this, args)
|
|
157
|
-
}
|
|
158
|
-
},
|
|
159
|
-
getter(original, _target, propertyKey) {
|
|
160
|
-
return function (this: any) {
|
|
161
|
-
deprecated.warn(this, propertyKey, message)
|
|
162
|
-
return original.call(this)
|
|
163
|
-
}
|
|
164
|
-
},
|
|
165
|
-
setter(original, _target, propertyKey) {
|
|
166
|
-
return function (this: any, value: any) {
|
|
167
|
-
deprecated.warn(this, propertyKey, message)
|
|
168
|
-
return original.call(this, value)
|
|
169
|
-
}
|
|
170
|
-
},
|
|
171
|
-
class(original) {
|
|
172
|
-
return class extends original {
|
|
173
|
-
constructor(...args: any[]) {
|
|
174
|
-
super(...args)
|
|
175
|
-
deprecated.warn(this, 'constructor', message)
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
},
|
|
179
|
-
})
|
|
180
|
-
},
|
|
181
|
-
}),
|
|
182
|
-
{
|
|
183
|
-
warn: (target: any, propertyKey: PropertyKey, message?: string) => {
|
|
184
|
-
// biome-ignore lint/suspicious/noConsole: To be overridden
|
|
185
|
-
console.warn(
|
|
186
|
-
`${target.constructor.name}.${String(propertyKey)} is deprecated${message ? `: ${message}` : ''}`
|
|
187
|
-
)
|
|
188
|
-
},
|
|
189
|
-
}
|
|
190
|
-
)
|
|
191
|
-
|
|
192
|
-
/**
|
|
193
|
-
* Creates a debounced method decorator that delays execution until after the delay period has passed
|
|
194
|
-
* @param delay - The delay in milliseconds
|
|
195
|
-
* @returns A method decorator that debounces method calls
|
|
196
|
-
*/
|
|
197
|
-
export function debounce(delay: number) {
|
|
198
|
-
return decorator({
|
|
199
|
-
method(original, _target, _propertyKey) {
|
|
200
|
-
let timeoutId: ReturnType<typeof setTimeout> | null = null
|
|
201
|
-
|
|
202
|
-
return function (this: any, ...args: any[]) {
|
|
203
|
-
// Clear existing timeout
|
|
204
|
-
if (timeoutId) {
|
|
205
|
-
clearTimeout(timeoutId)
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
// Set new timeout
|
|
209
|
-
timeoutId = setTimeout(() => {
|
|
210
|
-
original.apply(this, args)
|
|
211
|
-
timeoutId = null
|
|
212
|
-
}, delay)
|
|
213
|
-
}
|
|
214
|
-
},
|
|
215
|
-
})
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
/**
|
|
219
|
-
* Creates a throttled method decorator that limits execution to once per delay period
|
|
220
|
-
* @param delay - The delay in milliseconds
|
|
221
|
-
* @returns A method decorator that throttles method calls
|
|
222
|
-
*/
|
|
223
|
-
export function throttle(delay: number) {
|
|
224
|
-
return decorator({
|
|
225
|
-
method(original, _target, _propertyKey) {
|
|
226
|
-
let lastCallTime = 0
|
|
227
|
-
let timeoutId: ReturnType<typeof setTimeout> | null = null
|
|
228
|
-
|
|
229
|
-
return function (this: any, ...args: any[]) {
|
|
230
|
-
const now = Date.now()
|
|
231
|
-
|
|
232
|
-
// If enough time has passed since last call, execute immediately
|
|
233
|
-
if (now - lastCallTime >= delay) {
|
|
234
|
-
// Clear any pending timeout since we're executing now
|
|
235
|
-
if (timeoutId) {
|
|
236
|
-
clearTimeout(timeoutId)
|
|
237
|
-
timeoutId = null
|
|
238
|
-
}
|
|
239
|
-
lastCallTime = now
|
|
240
|
-
return original.apply(this, args)
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
// Otherwise, schedule execution for when the delay period ends
|
|
244
|
-
if (!timeoutId) {
|
|
245
|
-
const remainingTime = delay - (now - lastCallTime)
|
|
246
|
-
const scheduledArgs = [...args] // Capture args at scheduling time
|
|
247
|
-
timeoutId = setTimeout(() => {
|
|
248
|
-
lastCallTime = Date.now()
|
|
249
|
-
original.apply(this, scheduledArgs)
|
|
250
|
-
timeoutId = null
|
|
251
|
-
}, remainingTime)
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
},
|
|
255
|
-
})
|
|
256
|
-
}
|