@praxisjs/decorators 0.2.0 → 0.4.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.
- package/CHANGELOG.md +34 -0
- package/dist/component/component.d.ts +2 -2
- package/dist/component/component.d.ts.map +1 -1
- package/dist/component/component.js +5 -2
- package/dist/component/component.js.map +1 -1
- package/dist/component/index.d.ts +0 -1
- package/dist/component/index.d.ts.map +1 -1
- package/dist/component/index.js +0 -1
- package/dist/component/index.js.map +1 -1
- package/dist/component/lazy.d.ts +2 -2
- package/dist/component/lazy.d.ts.map +1 -1
- package/dist/component/lazy.js +8 -8
- package/dist/component/lazy.js.map +1 -1
- package/dist/component/virtual.d.ts +2 -2
- package/dist/component/virtual.d.ts.map +1 -1
- package/dist/component/virtual.js +45 -14
- package/dist/component/virtual.js.map +1 -1
- package/dist/events/emit.d.ts +2 -1
- package/dist/events/emit.d.ts.map +1 -1
- package/dist/events/emit.js +11 -16
- package/dist/events/emit.js.map +1 -1
- package/dist/events/helper.d.ts +2 -2
- package/dist/events/helper.d.ts.map +1 -1
- package/dist/events/helper.js.map +1 -1
- package/dist/events/on-command.d.ts +2 -1
- package/dist/events/on-command.d.ts.map +1 -1
- package/dist/events/on-command.js +30 -27
- package/dist/events/on-command.js.map +1 -1
- package/dist/functions/bind.d.ts +2 -1
- package/dist/functions/bind.d.ts.map +1 -1
- package/dist/functions/bind.js +10 -15
- package/dist/functions/bind.js.map +1 -1
- package/dist/functions/debounce.d.ts +2 -1
- package/dist/functions/debounce.d.ts.map +1 -1
- package/dist/functions/debounce.js +20 -24
- package/dist/functions/debounce.js.map +1 -1
- package/dist/functions/log.d.ts +2 -1
- package/dist/functions/log.d.ts.map +1 -1
- package/dist/functions/log.js +5 -6
- package/dist/functions/log.js.map +1 -1
- package/dist/functions/memo.d.ts +2 -1
- package/dist/functions/memo.d.ts.map +1 -1
- package/dist/functions/memo.js +5 -6
- package/dist/functions/memo.js.map +1 -1
- package/dist/functions/once.d.ts +2 -1
- package/dist/functions/once.d.ts.map +1 -1
- package/dist/functions/once.js +3 -5
- package/dist/functions/once.js.map +1 -1
- package/dist/functions/retry.d.ts +2 -1
- package/dist/functions/retry.d.ts.map +1 -1
- package/dist/functions/retry.js +3 -5
- package/dist/functions/retry.js.map +1 -1
- package/dist/functions/throttle.d.ts +2 -1
- package/dist/functions/throttle.d.ts.map +1 -1
- package/dist/functions/throttle.js +18 -22
- package/dist/functions/throttle.js.map +1 -1
- package/dist/functions/watch.d.ts +7 -7
- package/dist/functions/watch.d.ts.map +1 -1
- package/dist/functions/watch.js +31 -35
- package/dist/functions/watch.js.map +1 -1
- package/dist/functions/when.d.ts +2 -1
- package/dist/functions/when.d.ts.map +1 -1
- package/dist/functions/when.js +24 -24
- package/dist/functions/when.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/properties/computed.d.ts +3 -0
- package/dist/properties/computed.d.ts.map +1 -0
- package/dist/properties/computed.js +15 -0
- package/dist/properties/computed.js.map +1 -0
- package/dist/properties/history.d.ts +3 -2
- package/dist/properties/history.d.ts.map +1 -1
- package/dist/properties/history.js +35 -27
- package/dist/properties/history.js.map +1 -1
- package/dist/properties/index.d.ts +1 -0
- package/dist/properties/index.d.ts.map +1 -1
- package/dist/properties/index.js +1 -0
- package/dist/properties/index.js.map +1 -1
- package/dist/properties/persisted.d.ts +3 -2
- package/dist/properties/persisted.d.ts.map +1 -1
- package/dist/properties/persisted.js +20 -23
- package/dist/properties/persisted.js.map +1 -1
- package/dist/properties/prop.d.ts +2 -1
- package/dist/properties/prop.d.ts.map +1 -1
- package/dist/properties/prop.js +24 -13
- package/dist/properties/prop.js.map +1 -1
- package/dist/properties/slot.d.ts +4 -8
- package/dist/properties/slot.d.ts.map +1 -1
- package/dist/properties/slot.js +34 -24
- package/dist/properties/slot.js.map +1 -1
- package/dist/properties/state.d.ts +2 -1
- package/dist/properties/state.d.ts.map +1 -1
- package/dist/properties/state.js +19 -19
- package/dist/properties/state.js.map +1 -1
- package/package.json +3 -4
- package/src/component/component.ts +9 -2
- package/src/component/index.ts +0 -1
- package/src/component/lazy.ts +10 -8
- package/src/component/virtual.tsx +71 -28
- package/src/events/emit.ts +15 -22
- package/src/events/helper.ts +5 -2
- package/src/events/on-command.ts +43 -44
- package/src/functions/bind.ts +14 -18
- package/src/functions/debounce.ts +23 -26
- package/src/functions/log.ts +11 -11
- package/src/functions/memo.ts +8 -9
- package/src/functions/once.ts +7 -10
- package/src/functions/retry.ts +7 -12
- package/src/functions/throttle.ts +21 -24
- package/src/functions/watch.ts +44 -48
- package/src/functions/when.ts +30 -32
- package/src/index.ts +11 -2
- package/src/properties/computed.ts +20 -0
- package/src/properties/history.ts +49 -32
- package/src/properties/index.ts +1 -0
- package/src/properties/persisted.ts +40 -31
- package/src/properties/prop.ts +30 -13
- package/src/properties/slot.ts +46 -50
- package/src/properties/state.ts +24 -18
- package/dist/component/lifecycle.d.ts +0 -3
- package/dist/component/lifecycle.d.ts.map +0 -1
- package/dist/component/lifecycle.js +0 -35
- package/dist/component/lifecycle.js.map +0 -1
- package/dist/component/memoize.d.ts +0 -5
- package/dist/component/memoize.d.ts.map +0 -1
- package/dist/component/memoize.js +0 -23
- package/dist/component/memoize.js.map +0 -1
- package/src/component/lifecycle.ts +0 -47
- package/src/component/memoize.ts +0 -31
|
@@ -1,24 +1,30 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { computed, effect, type RootComponent, signal } from "@praxisjs/core/internal";
|
|
2
|
+
|
|
3
|
+
interface VirtualHost {
|
|
4
|
+
_anchor?: Comment;
|
|
5
|
+
items?: unknown[];
|
|
6
|
+
renderItem(item: unknown, index: number): Node | Node[] | null;
|
|
7
|
+
}
|
|
3
8
|
|
|
4
9
|
export function Virtual(itemHeight: number, buffer = 3) {
|
|
5
10
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
6
|
-
return function <T extends new (...args: any[]) =>
|
|
11
|
+
return function <T extends new (...args: any[]) => RootComponent>(
|
|
7
12
|
constructor: T,
|
|
13
|
+
_context: ClassDecoratorContext,
|
|
8
14
|
): T {
|
|
9
15
|
return class VirtualWrapper extends constructor {
|
|
10
16
|
private readonly _scrollTop = signal(0);
|
|
11
17
|
private readonly _viewHeight = signal(600);
|
|
12
18
|
private _container?: HTMLElement;
|
|
13
19
|
private _scrollHandler?: () => void;
|
|
20
|
+
private _cleanups: Array<() => void> = [];
|
|
14
21
|
|
|
15
22
|
onMount() {
|
|
16
23
|
super.onMount?.();
|
|
17
24
|
|
|
25
|
+
// Use the end anchor set by the runtime to locate the parent element
|
|
18
26
|
this._container =
|
|
19
|
-
|
|
20
|
-
`[data-component="${constructor.name}"]`,
|
|
21
|
-
) ?? undefined;
|
|
27
|
+
(this as unknown as VirtualHost)._anchor?.parentElement ?? undefined;
|
|
22
28
|
|
|
23
29
|
if (!this._container) return;
|
|
24
30
|
|
|
@@ -39,24 +45,25 @@ export function Virtual(itemHeight: number, buffer = 3) {
|
|
|
39
45
|
if (this._container && this._scrollHandler) {
|
|
40
46
|
this._container.removeEventListener("scroll", this._scrollHandler);
|
|
41
47
|
}
|
|
48
|
+
this._cleanups.forEach((c) => { c(); });
|
|
49
|
+
this._cleanups = [];
|
|
42
50
|
}
|
|
43
51
|
|
|
44
52
|
render() {
|
|
45
|
-
const
|
|
46
|
-
const items =
|
|
53
|
+
const host = this as unknown as VirtualHost;
|
|
54
|
+
const items = host.items ?? [];
|
|
47
55
|
const total = items.length;
|
|
48
56
|
const totalH = total * itemHeight;
|
|
49
57
|
|
|
50
|
-
|
|
51
|
-
| ((item: unknown, i: number) => VNode | null)
|
|
52
|
-
| undefined;
|
|
53
|
-
if (!renderItem) {
|
|
58
|
+
if (typeof host.renderItem !== "function") {
|
|
54
59
|
console.warn(
|
|
55
60
|
`[Virtual] ${constructor.name} must implement renderItem(item, index)`,
|
|
56
61
|
);
|
|
57
62
|
return null;
|
|
58
63
|
}
|
|
59
64
|
|
|
65
|
+
const renderItem = host.renderItem.bind(host);
|
|
66
|
+
|
|
60
67
|
const startIdx = computed(() => {
|
|
61
68
|
const start = Math.floor(this._scrollTop() / itemHeight) - buffer;
|
|
62
69
|
return Math.max(0, start);
|
|
@@ -70,7 +77,7 @@ export function Virtual(itemHeight: number, buffer = 3) {
|
|
|
70
77
|
});
|
|
71
78
|
|
|
72
79
|
const visibleItems = computed(() => {
|
|
73
|
-
const result = [];
|
|
80
|
+
const result: Array<{ item: unknown; index: number }> = [];
|
|
74
81
|
for (let i = startIdx(); i <= endIdx(); i++) {
|
|
75
82
|
result.push({ item: items[i], index: i });
|
|
76
83
|
}
|
|
@@ -82,22 +89,58 @@ export function Virtual(itemHeight: number, buffer = 3) {
|
|
|
82
89
|
() => (total - 1 - endIdx()) * itemHeight,
|
|
83
90
|
);
|
|
84
91
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
92
|
+
const outer = document.createElement("div");
|
|
93
|
+
outer.setAttribute(
|
|
94
|
+
"style",
|
|
95
|
+
`height:${String(totalH)}px; position:relative;`,
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
const spacerTop = document.createElement("div");
|
|
99
|
+
this._cleanups.push(
|
|
100
|
+
effect(() => {
|
|
101
|
+
spacerTop.setAttribute("style", `height:${String(offsetTop())}px;`);
|
|
102
|
+
}),
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
const itemsSlot = document.createElement("div");
|
|
106
|
+
this._cleanups.push(
|
|
107
|
+
effect(() => {
|
|
108
|
+
while (itemsSlot.firstChild) {
|
|
109
|
+
itemsSlot.removeChild(itemsSlot.firstChild);
|
|
97
110
|
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
111
|
+
visibleItems().forEach(({ item, index }) => {
|
|
112
|
+
const wrapper = document.createElement("div");
|
|
113
|
+
wrapper.setAttribute(
|
|
114
|
+
"style",
|
|
115
|
+
`height:${String(itemHeight)}px; overflow:hidden;`,
|
|
116
|
+
);
|
|
117
|
+
const rendered = renderItem(item, index);
|
|
118
|
+
if (rendered) {
|
|
119
|
+
const nodes = (
|
|
120
|
+
Array.isArray(rendered) ? rendered.flat() : [rendered]
|
|
121
|
+
);
|
|
122
|
+
nodes.forEach((n) => wrapper.appendChild(n));
|
|
123
|
+
}
|
|
124
|
+
itemsSlot.appendChild(wrapper);
|
|
125
|
+
});
|
|
126
|
+
}),
|
|
127
|
+
);
|
|
128
|
+
|
|
129
|
+
const spacerBottom = document.createElement("div");
|
|
130
|
+
this._cleanups.push(
|
|
131
|
+
effect(() => {
|
|
132
|
+
spacerBottom.setAttribute(
|
|
133
|
+
"style",
|
|
134
|
+
`height:${String(offsetBottom())}px;`,
|
|
135
|
+
);
|
|
136
|
+
}),
|
|
137
|
+
);
|
|
138
|
+
|
|
139
|
+
outer.appendChild(spacerTop);
|
|
140
|
+
outer.appendChild(itemsSlot);
|
|
141
|
+
outer.appendChild(spacerBottom);
|
|
142
|
+
|
|
143
|
+
return outer;
|
|
101
144
|
}
|
|
102
145
|
} as unknown as T;
|
|
103
146
|
};
|
package/src/events/emit.ts
CHANGED
|
@@ -1,20 +1,17 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { StatefulComponent } from "@praxisjs/core";
|
|
2
2
|
|
|
3
3
|
import { readProp } from "./helper";
|
|
4
4
|
|
|
5
5
|
export function Emit(propName: string) {
|
|
6
6
|
return function (
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
): PropertyDescriptor {
|
|
11
|
-
const originalMethod = descriptor.value as (...args: unknown[]) => unknown;
|
|
12
|
-
|
|
7
|
+
value: (this: StatefulComponent, ...args: unknown[]) => unknown,
|
|
8
|
+
context: ClassMethodDecoratorContext<StatefulComponent>,
|
|
9
|
+
): void {
|
|
13
10
|
const wrapped = function (
|
|
14
|
-
this:
|
|
11
|
+
this: StatefulComponent,
|
|
15
12
|
...args: unknown[]
|
|
16
13
|
): unknown {
|
|
17
|
-
const result =
|
|
14
|
+
const result = value.apply(this, args);
|
|
18
15
|
|
|
19
16
|
const callback = readProp(this, propName);
|
|
20
17
|
if (typeof callback !== "function") return result;
|
|
@@ -30,18 +27,14 @@ export function Emit(propName: string) {
|
|
|
30
27
|
return result;
|
|
31
28
|
};
|
|
32
29
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
});
|
|
43
|
-
return bound;
|
|
44
|
-
},
|
|
45
|
-
};
|
|
30
|
+
context.addInitializer(function (this: unknown) {
|
|
31
|
+
const name = context.name as string;
|
|
32
|
+
const bound = wrapped.bind(this as StatefulComponent);
|
|
33
|
+
Object.defineProperty(this as object, name, {
|
|
34
|
+
value: bound,
|
|
35
|
+
configurable: true,
|
|
36
|
+
writable: true,
|
|
37
|
+
});
|
|
38
|
+
});
|
|
46
39
|
};
|
|
47
40
|
}
|
package/src/events/helper.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { StatefulComponent } from "@praxisjs/core";
|
|
2
2
|
|
|
3
|
-
export function readProp(
|
|
3
|
+
export function readProp(
|
|
4
|
+
instance: StatefulComponent,
|
|
5
|
+
propName: string,
|
|
6
|
+
): unknown {
|
|
4
7
|
const fromParent = instance._rawProps[propName];
|
|
5
8
|
if (fromParent !== undefined) return fromParent;
|
|
6
9
|
return instance._defaults[propName];
|
package/src/events/on-command.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { StatefulComponent } from "@praxisjs/core";
|
|
2
2
|
|
|
3
3
|
import { readProp } from "./helper";
|
|
4
4
|
|
|
@@ -6,50 +6,49 @@ import type { Command } from "./command";
|
|
|
6
6
|
|
|
7
7
|
export function OnCommand(propName: string) {
|
|
8
8
|
return function (
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
): PropertyDescriptor {
|
|
13
|
-
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
14
|
-
const originalOnMount = (target as { onMount?(): void }).onMount;
|
|
15
|
-
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
16
|
-
const originalOnUnmount = (target as { onUnmount?(): void }).onUnmount;
|
|
17
|
-
|
|
18
|
-
const method = descriptor.value as (...args: unknown[]) => void;
|
|
9
|
+
value: (this: StatefulComponent, ...args: unknown[]) => void,
|
|
10
|
+
context: ClassMethodDecoratorContext<StatefulComponent>,
|
|
11
|
+
): void {
|
|
19
12
|
const cleanups = new WeakMap<object, () => void>();
|
|
20
13
|
|
|
21
|
-
(
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
);
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
14
|
+
context.addInitializer(function (this: unknown) {
|
|
15
|
+
const instance = this as StatefulComponent;
|
|
16
|
+
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
17
|
+
const originalOnMount = instance.onMount;
|
|
18
|
+
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
19
|
+
const originalOnUnmount = instance.onUnmount;
|
|
20
|
+
|
|
21
|
+
instance.onMount = function (this: StatefulComponent) {
|
|
22
|
+
originalOnMount?.call(this);
|
|
23
|
+
|
|
24
|
+
const command = readProp(this, propName) as Command<unknown> | undefined;
|
|
25
|
+
|
|
26
|
+
if (!command) {
|
|
27
|
+
console.warn(
|
|
28
|
+
`[OnCommand] prop "${propName}" was not provided to ${this.constructor.name}`,
|
|
29
|
+
);
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (typeof command.subscribe !== "function") {
|
|
34
|
+
console.warn(
|
|
35
|
+
`[OnCommand] prop "${propName}" is not a valid Command in ${this.constructor.name}`,
|
|
36
|
+
);
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const bound = value.bind(this);
|
|
41
|
+
const unsub = command.subscribe((...args: unknown[]) => {
|
|
42
|
+
bound(...args);
|
|
43
|
+
});
|
|
44
|
+
cleanups.set(this, unsub);
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
instance.onUnmount = function (this: StatefulComponent) {
|
|
48
|
+
originalOnUnmount?.call(this);
|
|
49
|
+
cleanups.get(this)?.();
|
|
50
|
+
cleanups.delete(this);
|
|
51
|
+
};
|
|
52
|
+
});
|
|
54
53
|
};
|
|
55
54
|
}
|
package/src/functions/bind.ts
CHANGED
|
@@ -1,22 +1,18 @@
|
|
|
1
|
+
import type { StatefulComponent } from "@praxisjs/core";
|
|
2
|
+
|
|
1
3
|
export function Bind() {
|
|
2
4
|
return function (
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
configurable: true,
|
|
16
|
-
writable: true,
|
|
17
|
-
});
|
|
18
|
-
return bound;
|
|
19
|
-
},
|
|
20
|
-
};
|
|
5
|
+
value: (this: object, ...args: unknown[]) => unknown,
|
|
6
|
+
context: ClassMethodDecoratorContext<StatefulComponent>,
|
|
7
|
+
): void {
|
|
8
|
+
context.addInitializer(function (this: unknown) {
|
|
9
|
+
const name = context.name as string;
|
|
10
|
+
const bound = value.bind(this as object);
|
|
11
|
+
Object.defineProperty(this as object, name, {
|
|
12
|
+
value: bound,
|
|
13
|
+
configurable: true,
|
|
14
|
+
writable: true,
|
|
15
|
+
});
|
|
16
|
+
});
|
|
21
17
|
};
|
|
22
18
|
}
|
|
@@ -1,34 +1,31 @@
|
|
|
1
|
+
import type { StatefulComponent } from "@praxisjs/core";
|
|
2
|
+
|
|
1
3
|
export function Debounce(ms: number) {
|
|
2
4
|
const timers = new WeakMap<object, ReturnType<typeof setTimeout>>();
|
|
3
5
|
|
|
4
6
|
return function (
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
const bound = (...args: unknown[]) => {
|
|
15
|
-
const existing = timers.get(this);
|
|
16
|
-
if (existing !== undefined) clearTimeout(existing);
|
|
7
|
+
value: (this: object, ...args: unknown[]) => unknown,
|
|
8
|
+
context: ClassMethodDecoratorContext<StatefulComponent>,
|
|
9
|
+
): void {
|
|
10
|
+
context.addInitializer(function (this: unknown) {
|
|
11
|
+
const instance = this as object;
|
|
12
|
+
const name = context.name as string;
|
|
13
|
+
const bound = (...args: unknown[]) => {
|
|
14
|
+
const existing = timers.get(instance);
|
|
15
|
+
if (existing !== undefined) clearTimeout(existing);
|
|
17
16
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
17
|
+
const timer = setTimeout(() => {
|
|
18
|
+
timers.delete(instance);
|
|
19
|
+
value.apply(instance, args);
|
|
20
|
+
}, ms);
|
|
22
21
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
},
|
|
32
|
-
};
|
|
22
|
+
timers.set(instance, timer);
|
|
23
|
+
};
|
|
24
|
+
Object.defineProperty(instance, name, {
|
|
25
|
+
value: bound,
|
|
26
|
+
configurable: true,
|
|
27
|
+
writable: true,
|
|
28
|
+
});
|
|
29
|
+
});
|
|
33
30
|
};
|
|
34
31
|
}
|
package/src/functions/log.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { StatefulComponent } from "@praxisjs/core";
|
|
2
|
+
|
|
1
3
|
export interface LogOptions {
|
|
2
4
|
level?: "log" | "warn" | "error" | "debug";
|
|
3
5
|
args?: boolean;
|
|
@@ -16,29 +18,29 @@ export function Log(options: LogOptions = {}) {
|
|
|
16
18
|
} = options;
|
|
17
19
|
|
|
18
20
|
return function (
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
const originalMethod = descriptor.value as (...args: unknown[]) => unknown;
|
|
21
|
+
value: (this: object, ...args: unknown[]) => unknown,
|
|
22
|
+
context: ClassMethodDecoratorContext<StatefulComponent>,
|
|
23
|
+
): (this: object, ...args: unknown[]) => unknown {
|
|
24
|
+
const methodKey = context.name as string;
|
|
24
25
|
|
|
25
|
-
|
|
26
|
+
return function (this: object, ...args: unknown[]) {
|
|
26
27
|
if (
|
|
27
28
|
devOnly &&
|
|
28
29
|
typeof process !== "undefined" &&
|
|
29
30
|
process.env.NODE_ENV === "production"
|
|
30
31
|
) {
|
|
31
|
-
return
|
|
32
|
+
return value.apply(this, args);
|
|
32
33
|
}
|
|
33
34
|
|
|
34
|
-
const className =
|
|
35
|
+
const className =
|
|
36
|
+
(this.constructor as { name?: string }).name ?? "Unknown";
|
|
35
37
|
const label = `[${className}.${methodKey}]`;
|
|
36
38
|
const logger = console[level].bind(console);
|
|
37
39
|
|
|
38
40
|
if (logArgs) logger(`${label} args:`, args);
|
|
39
41
|
|
|
40
42
|
const start = time ? performance.now() : 0;
|
|
41
|
-
const output =
|
|
43
|
+
const output = value.apply(this, args);
|
|
42
44
|
|
|
43
45
|
if (output instanceof Promise) {
|
|
44
46
|
return (output as Promise<unknown>)
|
|
@@ -62,7 +64,5 @@ export function Log(options: LogOptions = {}) {
|
|
|
62
64
|
|
|
63
65
|
return output;
|
|
64
66
|
};
|
|
65
|
-
|
|
66
|
-
return descriptor;
|
|
67
67
|
};
|
|
68
68
|
}
|
package/src/functions/memo.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { StatefulComponent } from "@praxisjs/core";
|
|
2
|
+
import { computed } from "@praxisjs/core/internal";
|
|
2
3
|
import type { Computed } from "@praxisjs/shared";
|
|
3
4
|
|
|
4
5
|
const instanceCache = new WeakMap<
|
|
@@ -46,18 +47,16 @@ function serializeArgs(args: unknown[]) {
|
|
|
46
47
|
|
|
47
48
|
export function Memo() {
|
|
48
49
|
return function (
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
descriptor.value = function (this: object, ...args: unknown[]) {
|
|
50
|
+
value: (this: object, ...args: unknown[]) => unknown,
|
|
51
|
+
context: ClassMethodDecoratorContext<StatefulComponent>,
|
|
52
|
+
): (this: object, ...args: unknown[]) => unknown {
|
|
53
|
+
const methodName = context.name as string;
|
|
54
|
+
return function (this: object, ...args: unknown[]) {
|
|
55
55
|
const argKey = serializeArgs(args);
|
|
56
56
|
const memoized = getCache(this, methodName, argKey, () =>
|
|
57
|
-
|
|
57
|
+
value.apply(this, args),
|
|
58
58
|
);
|
|
59
59
|
return memoized();
|
|
60
60
|
};
|
|
61
|
-
return descriptor;
|
|
62
61
|
};
|
|
63
62
|
}
|
package/src/functions/once.ts
CHANGED
|
@@ -1,22 +1,19 @@
|
|
|
1
|
+
import type { StatefulComponent } from "@praxisjs/core";
|
|
2
|
+
|
|
1
3
|
export function Once() {
|
|
2
4
|
const called = new WeakMap<object, boolean>();
|
|
3
5
|
const results = new WeakMap<object, unknown>();
|
|
4
6
|
|
|
5
7
|
return function (
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
const originalMethod = descriptor.value as (...args: unknown[]) => unknown;
|
|
11
|
-
|
|
12
|
-
descriptor.value = function (this: object, ...args: unknown[]) {
|
|
8
|
+
value: (this: object, ...args: unknown[]) => unknown,
|
|
9
|
+
_context: ClassMethodDecoratorContext<StatefulComponent>,
|
|
10
|
+
): (this: object, ...args: unknown[]) => unknown {
|
|
11
|
+
return function (this: object, ...args: unknown[]) {
|
|
13
12
|
if (called.get(this)) return results.get(this);
|
|
14
|
-
const result =
|
|
13
|
+
const result = value.apply(this, args);
|
|
15
14
|
called.set(this, true);
|
|
16
15
|
results.set(this, result);
|
|
17
16
|
return result;
|
|
18
17
|
};
|
|
19
|
-
|
|
20
|
-
return descriptor;
|
|
21
18
|
};
|
|
22
19
|
}
|
package/src/functions/retry.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { StatefulComponent } from "@praxisjs/core";
|
|
2
|
+
|
|
1
3
|
export interface RetryOptions {
|
|
2
4
|
delay?: number;
|
|
3
5
|
backoff?: number;
|
|
@@ -8,21 +10,16 @@ export function Retry(maxAttempts: number, options: RetryOptions = {}) {
|
|
|
8
10
|
const { delay = 0, backoff = 1, onRetry } = options;
|
|
9
11
|
|
|
10
12
|
return function (
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
const originalMethod = descriptor.value as (
|
|
16
|
-
...args: unknown[]
|
|
17
|
-
) => Promise<unknown>;
|
|
18
|
-
|
|
19
|
-
descriptor.value = async function (this: object, ...args: unknown[]) {
|
|
13
|
+
value: (this: object, ...args: unknown[]) => Promise<unknown>,
|
|
14
|
+
_context: ClassMethodDecoratorContext<StatefulComponent>,
|
|
15
|
+
): (this: object, ...args: unknown[]) => Promise<unknown> {
|
|
16
|
+
return async function (this: object, ...args: unknown[]) {
|
|
20
17
|
let lastError: Error = new Error("Unknown error");
|
|
21
18
|
let currentDelay = delay;
|
|
22
19
|
|
|
23
20
|
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
24
21
|
try {
|
|
25
|
-
return await
|
|
22
|
+
return await value.apply(this, args);
|
|
26
23
|
} catch (e: unknown) {
|
|
27
24
|
lastError = e instanceof Error ? e : new Error(String(e));
|
|
28
25
|
if (attempt === maxAttempts) break;
|
|
@@ -37,7 +34,5 @@ export function Retry(maxAttempts: number, options: RetryOptions = {}) {
|
|
|
37
34
|
|
|
38
35
|
throw lastError;
|
|
39
36
|
};
|
|
40
|
-
|
|
41
|
-
return descriptor;
|
|
42
37
|
};
|
|
43
38
|
}
|
|
@@ -1,32 +1,29 @@
|
|
|
1
|
+
import type { StatefulComponent } from "@praxisjs/core";
|
|
2
|
+
|
|
1
3
|
export function Throttle(ms: number) {
|
|
2
4
|
const lastRun = new WeakMap<object, number>();
|
|
3
5
|
|
|
4
6
|
return function (
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
const bound = (...args: unknown[]) => {
|
|
15
|
-
const now = Date.now();
|
|
16
|
-
const last = lastRun.get(this) ?? 0;
|
|
7
|
+
value: (this: object, ...args: unknown[]) => unknown,
|
|
8
|
+
context: ClassMethodDecoratorContext<StatefulComponent>,
|
|
9
|
+
): void {
|
|
10
|
+
context.addInitializer(function (this: unknown) {
|
|
11
|
+
const instance = this as object;
|
|
12
|
+
const name = context.name as string;
|
|
13
|
+
const bound = (...args: unknown[]) => {
|
|
14
|
+
const now = Date.now();
|
|
15
|
+
const last = lastRun.get(instance) ?? 0;
|
|
17
16
|
|
|
18
|
-
|
|
17
|
+
if (now - last < ms) return;
|
|
19
18
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
},
|
|
30
|
-
};
|
|
19
|
+
lastRun.set(instance, now);
|
|
20
|
+
return value.apply(instance, args);
|
|
21
|
+
};
|
|
22
|
+
Object.defineProperty(instance, name, {
|
|
23
|
+
value: bound,
|
|
24
|
+
configurable: true,
|
|
25
|
+
writable: true,
|
|
26
|
+
});
|
|
27
|
+
});
|
|
31
28
|
};
|
|
32
29
|
}
|