mutts 1.0.0

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 (82) hide show
  1. package/README.md +150 -0
  2. package/dist/chunks/decorator-BXsign4Z.js +176 -0
  3. package/dist/chunks/decorator-BXsign4Z.js.map +1 -0
  4. package/dist/chunks/decorator-CPbZNnsX.esm.js +168 -0
  5. package/dist/chunks/decorator-CPbZNnsX.esm.js.map +1 -0
  6. package/dist/decorator.d.ts +50 -0
  7. package/dist/decorator.esm.js +2 -0
  8. package/dist/decorator.esm.js.map +1 -0
  9. package/dist/decorator.js +11 -0
  10. package/dist/decorator.js.map +1 -0
  11. package/dist/destroyable.d.ts +48 -0
  12. package/dist/destroyable.esm.js +91 -0
  13. package/dist/destroyable.esm.js.map +1 -0
  14. package/dist/destroyable.js +98 -0
  15. package/dist/destroyable.js.map +1 -0
  16. package/dist/eventful.d.ts +11 -0
  17. package/dist/eventful.esm.js +88 -0
  18. package/dist/eventful.esm.js.map +1 -0
  19. package/dist/eventful.js +90 -0
  20. package/dist/eventful.js.map +1 -0
  21. package/dist/index.d.ts +15 -0
  22. package/dist/index.esm.js +7 -0
  23. package/dist/index.esm.js.map +1 -0
  24. package/dist/index.js +52 -0
  25. package/dist/index.js.map +1 -0
  26. package/dist/indexable.d.ts +31 -0
  27. package/dist/indexable.esm.js +85 -0
  28. package/dist/indexable.esm.js.map +1 -0
  29. package/dist/indexable.js +89 -0
  30. package/dist/indexable.js.map +1 -0
  31. package/dist/mutts.umd.js +2 -0
  32. package/dist/mutts.umd.js.map +1 -0
  33. package/dist/mutts.umd.min.js +2 -0
  34. package/dist/mutts.umd.min.js.map +1 -0
  35. package/dist/promiseChain.d.ts +11 -0
  36. package/dist/promiseChain.esm.js +72 -0
  37. package/dist/promiseChain.esm.js.map +1 -0
  38. package/dist/promiseChain.js +74 -0
  39. package/dist/promiseChain.js.map +1 -0
  40. package/dist/reactive.d.ts +114 -0
  41. package/dist/reactive.esm.js +1455 -0
  42. package/dist/reactive.esm.js.map +1 -0
  43. package/dist/reactive.js +1472 -0
  44. package/dist/reactive.js.map +1 -0
  45. package/dist/std-decorators.d.ts +17 -0
  46. package/dist/std-decorators.esm.js +161 -0
  47. package/dist/std-decorators.esm.js.map +1 -0
  48. package/dist/std-decorators.js +169 -0
  49. package/dist/std-decorators.js.map +1 -0
  50. package/docs/decorator.md +300 -0
  51. package/docs/destroyable.md +294 -0
  52. package/docs/events.md +225 -0
  53. package/docs/indexable.md +561 -0
  54. package/docs/promiseChain.md +218 -0
  55. package/docs/reactive.md +2072 -0
  56. package/docs/std-decorators.md +558 -0
  57. package/package.json +132 -0
  58. package/src/decorator.test.ts +495 -0
  59. package/src/decorator.ts +205 -0
  60. package/src/destroyable.test.ts +155 -0
  61. package/src/destroyable.ts +158 -0
  62. package/src/eventful.test.ts +380 -0
  63. package/src/eventful.ts +69 -0
  64. package/src/index.ts +7 -0
  65. package/src/indexable.test.ts +388 -0
  66. package/src/indexable.ts +124 -0
  67. package/src/promiseChain.test.ts +201 -0
  68. package/src/promiseChain.ts +99 -0
  69. package/src/reactive/array.test.ts +923 -0
  70. package/src/reactive/array.ts +352 -0
  71. package/src/reactive/core.test.ts +1663 -0
  72. package/src/reactive/core.ts +866 -0
  73. package/src/reactive/index.ts +28 -0
  74. package/src/reactive/interface.test.ts +1477 -0
  75. package/src/reactive/interface.ts +231 -0
  76. package/src/reactive/map.test.ts +866 -0
  77. package/src/reactive/map.ts +162 -0
  78. package/src/reactive/set.test.ts +289 -0
  79. package/src/reactive/set.ts +142 -0
  80. package/src/std-decorators.test.ts +679 -0
  81. package/src/std-decorators.ts +182 -0
  82. package/src/utils.ts +52 -0
@@ -0,0 +1,182 @@
1
+ import { decorator, 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
+ export const cached = decorator({
6
+ getter(original, propertyKey) {
7
+ return function (this: any) {
8
+ const alreadyCalculating = syncCalculating.findIndex(
9
+ (c) => c.object === this && c.prop === propertyKey
10
+ )
11
+ if (alreadyCalculating > -1)
12
+ throw new Error(
13
+ `Circular dependency detected: ${syncCalculating
14
+ .slice(alreadyCalculating)
15
+ .map((c) => `${c.object.constructor.name}.${String(c.prop)}`)
16
+ .join(' -> ')} -> again`
17
+ )
18
+ syncCalculating.push({ object: this, prop: propertyKey })
19
+ try {
20
+ const rv = original.call(this)
21
+ cache(this, propertyKey, rv)
22
+ return rv
23
+ } finally {
24
+ syncCalculating.pop()
25
+ }
26
+ }
27
+ },
28
+ })
29
+
30
+ export function isCached(object: Object, propertyKey: PropertyKey) {
31
+ return !!Object.getOwnPropertyDescriptor(object, propertyKey)
32
+ }
33
+
34
+ export function cache(object: Object, propertyKey: PropertyKey, value: any) {
35
+ Object.defineProperty(object, propertyKey, { value })
36
+ }
37
+
38
+ export function describe(descriptor: {
39
+ enumerable?: boolean
40
+ configurable?: boolean // Not modifiable once the property has been defined ?
41
+ writable?: boolean
42
+ }) {
43
+ return <T>(...properties: (keyof T)[]): GenericClassDecorator<T> =>
44
+ (Base) => {
45
+ return class extends Base {
46
+ constructor(...args: any[]) {
47
+ super(...args)
48
+ for (const key of properties) {
49
+ Object.defineProperty(this, key, {
50
+ ...Object.getOwnPropertyDescriptor(this, key),
51
+ ...descriptor,
52
+ })
53
+ }
54
+ }
55
+ }
56
+ }
57
+ }
58
+
59
+ export const deprecated = Object.assign(
60
+ decorator({
61
+ method(original, propertyKey) {
62
+ return function (this: any, ...args: any[]) {
63
+ deprecated.warn(this, propertyKey)
64
+ return original.apply(this, args)
65
+ }
66
+ },
67
+ getter(original, propertyKey) {
68
+ return function (this: any) {
69
+ deprecated.warn(this, propertyKey)
70
+ return original.call(this)
71
+ }
72
+ },
73
+ setter(original, propertyKey) {
74
+ return function (this: any, value: any) {
75
+ deprecated.warn(this, propertyKey)
76
+ return original.call(this, value)
77
+ }
78
+ },
79
+ class(original) {
80
+ return class extends original {
81
+ constructor(...args: any[]) {
82
+ super(...args)
83
+ deprecated.warn(this, 'constructor')
84
+ }
85
+ }
86
+ },
87
+ default(message: string) {
88
+ return decorator({
89
+ method(original, propertyKey) {
90
+ return function (this: any, ...args: any[]) {
91
+ deprecated.warn(this, propertyKey, message)
92
+ return original.apply(this, args)
93
+ }
94
+ },
95
+ getter(original, propertyKey) {
96
+ return function (this: any) {
97
+ deprecated.warn(this, propertyKey, message)
98
+ return original.call(this)
99
+ }
100
+ },
101
+ setter(original, propertyKey) {
102
+ return function (this: any, value: any) {
103
+ deprecated.warn(this, propertyKey, message)
104
+ return original.call(this, value)
105
+ }
106
+ },
107
+ class(original) {
108
+ return class extends original {
109
+ constructor(...args: any[]) {
110
+ super(...args)
111
+ deprecated.warn(this, 'constructor', message)
112
+ }
113
+ }
114
+ },
115
+ })
116
+ },
117
+ }),
118
+ {
119
+ warn: (target: any, propertyKey: PropertyKey, message?: string) => {
120
+ // biome-ignore lint/suspicious/noConsole: To be overridden
121
+ console.warn(
122
+ `${target.constructor.name}.${String(propertyKey)} is deprecated${message ? `: ${message}` : ''}`
123
+ )
124
+ },
125
+ }
126
+ )
127
+
128
+ export function debounce(delay: number) {
129
+ return decorator({
130
+ method(original, _propertyKey) {
131
+ let timeoutId: ReturnType<typeof setTimeout> | null = null
132
+
133
+ return function (this: any, ...args: any[]) {
134
+ // Clear existing timeout
135
+ if (timeoutId) {
136
+ clearTimeout(timeoutId)
137
+ }
138
+
139
+ // Set new timeout
140
+ timeoutId = setTimeout(() => {
141
+ original.apply(this, args)
142
+ timeoutId = null
143
+ }, delay)
144
+ }
145
+ },
146
+ })
147
+ }
148
+
149
+ export function throttle(delay: number) {
150
+ return decorator({
151
+ method(original, _propertyKey) {
152
+ let lastCallTime = 0
153
+ let timeoutId: ReturnType<typeof setTimeout> | null = null
154
+
155
+ return function (this: any, ...args: any[]) {
156
+ const now = Date.now()
157
+
158
+ // If enough time has passed since last call, execute immediately
159
+ if (now - lastCallTime >= delay) {
160
+ // Clear any pending timeout since we're executing now
161
+ if (timeoutId) {
162
+ clearTimeout(timeoutId)
163
+ timeoutId = null
164
+ }
165
+ lastCallTime = now
166
+ return original.apply(this, args)
167
+ }
168
+
169
+ // Otherwise, schedule execution for when the delay period ends
170
+ if (!timeoutId) {
171
+ const remainingTime = delay - (now - lastCallTime)
172
+ const scheduledArgs = [...args] // Capture args at scheduling time
173
+ timeoutId = setTimeout(() => {
174
+ lastCallTime = Date.now()
175
+ original.apply(this, scheduledArgs)
176
+ timeoutId = null
177
+ }, remainingTime)
178
+ }
179
+ }
180
+ },
181
+ })
182
+ }
package/src/utils.ts ADDED
@@ -0,0 +1,52 @@
1
+ type ElementTypes<T extends readonly unknown[]> = {
2
+ [K in keyof T]: T[K] extends readonly (infer U)[] ? U : T[K]
3
+ }
4
+
5
+ export function zip<T extends (readonly unknown[])[]>(...args: T): ElementTypes<T>[] {
6
+ if (!args.length) return []
7
+ const minLength = Math.min(...args.map((arr) => arr.length))
8
+ const result: ElementTypes<T>[] = []
9
+
10
+ for (let i = 0; i < minLength; i++) {
11
+ const tuple = args.map((arr) => arr[i]) as ElementTypes<T>
12
+ result.push(tuple)
13
+ }
14
+
15
+ return result
16
+ }
17
+
18
+ const nativeConstructors = new Set<Function>([
19
+ Object,
20
+ Array,
21
+ Date,
22
+ Function,
23
+ Set,
24
+ Map,
25
+ WeakMap,
26
+ WeakSet,
27
+ Promise,
28
+ Error,
29
+ TypeError,
30
+ ReferenceError,
31
+ SyntaxError,
32
+ RangeError,
33
+ URIError,
34
+ EvalError,
35
+ Reflect,
36
+ Proxy,
37
+ RegExp,
38
+ String,
39
+ Number,
40
+ Boolean,
41
+ ] as Function[])
42
+ export function isConstructor(fn: Function): boolean {
43
+ return fn && (nativeConstructors.has(fn) || fn.toString().startsWith('class '))
44
+ }
45
+
46
+ export function renamed<F extends Function>(fct: F, name: string): F {
47
+ return Object.defineProperties(fct, {
48
+ name: {
49
+ value: name,
50
+ },
51
+ })
52
+ }