@praxisjs/decorators 1.7.0 → 2.0.1
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 +41 -0
- package/dist/component/component.d.ts +1 -1
- package/dist/component/component.d.ts.map +1 -1
- package/dist/component/component.js +8 -15
- package/dist/component/component.js.map +1 -1
- package/dist/component/lazy.d.ts +1 -1
- package/dist/component/lazy.d.ts.map +1 -1
- package/dist/component/lazy.js +44 -36
- package/dist/component/lazy.js.map +1 -1
- package/dist/create-class-decorator.d.ts +27 -5
- package/dist/create-class-decorator.d.ts.map +1 -1
- package/dist/create-class-decorator.js +53 -18
- package/dist/create-class-decorator.js.map +1 -1
- package/dist/create-field-decorator.d.ts +42 -3
- package/dist/create-field-decorator.d.ts.map +1 -1
- package/dist/create-field-decorator.js +63 -27
- package/dist/create-field-decorator.js.map +1 -1
- package/dist/create-getter-decorator.d.ts +81 -16
- package/dist/create-getter-decorator.d.ts.map +1 -1
- package/dist/create-getter-decorator.js +127 -15
- package/dist/create-getter-decorator.js.map +1 -1
- package/dist/create-lifecycle-method-decorator.d.ts +21 -3
- package/dist/create-lifecycle-method-decorator.d.ts.map +1 -1
- package/dist/create-lifecycle-method-decorator.js +25 -18
- package/dist/create-lifecycle-method-decorator.js.map +1 -1
- package/dist/create-method-decorator.d.ts +43 -3
- package/dist/create-method-decorator.d.ts.map +1 -1
- package/dist/create-method-decorator.js +49 -8
- package/dist/create-method-decorator.js.map +1 -1
- package/dist/events/command.d.ts +2 -1
- package/dist/events/command.d.ts.map +1 -1
- package/dist/events/command.js +10 -8
- package/dist/events/command.js.map +1 -1
- package/dist/events/emit.d.ts +2 -2
- package/dist/events/emit.d.ts.map +1 -1
- package/dist/events/emit.js +18 -24
- package/dist/events/emit.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 +12 -14
- package/dist/events/on-command.js.map +1 -1
- package/dist/field.d.ts +51 -0
- package/dist/field.d.ts.map +1 -0
- package/dist/field.js +82 -0
- package/dist/field.js.map +1 -0
- package/dist/functions/bind.d.ts +2 -1
- package/dist/functions/bind.d.ts.map +1 -1
- package/dist/functions/bind.js +4 -4
- package/dist/functions/bind.js.map +1 -1
- package/dist/functions/debounce.d.ts +2 -2
- package/dist/functions/debounce.d.ts.map +1 -1
- package/dist/functions/debounce.js +25 -23
- 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 +38 -40
- 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 +41 -40
- 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 +10 -14
- 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 +21 -23
- 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 +12 -14
- package/dist/functions/throttle.js.map +1 -1
- package/dist/functions/until.d.ts +2 -1
- package/dist/functions/until.d.ts.map +1 -1
- package/dist/functions/until.js +13 -14
- package/dist/functions/until.js.map +1 -1
- package/dist/functions/watch.d.ts +1 -1
- package/dist/functions/watch.d.ts.map +1 -1
- package/dist/functions/watch.js +36 -34
- package/dist/functions/watch.js.map +1 -1
- package/dist/functions/when.d.ts +1 -1
- package/dist/functions/when.d.ts.map +1 -1
- package/dist/functions/when.js +19 -21
- package/dist/functions/when.js.map +1 -1
- package/dist/index.d.ts +5 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/lifecycle.d.ts +24 -0
- package/dist/lifecycle.d.ts.map +1 -0
- package/dist/lifecycle.js +55 -0
- package/dist/lifecycle.js.map +1 -0
- package/dist/properties/compose.d.ts +3 -2
- package/dist/properties/compose.d.ts.map +1 -1
- package/dist/properties/compose.js +33 -19
- package/dist/properties/compose.js.map +1 -1
- package/dist/properties/computed.d.ts +12 -10
- package/dist/properties/computed.d.ts.map +1 -1
- package/dist/properties/computed.js +26 -21
- package/dist/properties/computed.js.map +1 -1
- package/dist/properties/deep-state.d.ts +2 -1
- package/dist/properties/deep-state.d.ts.map +1 -1
- package/dist/properties/deep-state.js +66 -60
- package/dist/properties/deep-state.js.map +1 -1
- package/dist/properties/function-prop.d.ts +2 -1
- package/dist/properties/function-prop.d.ts.map +1 -1
- package/dist/properties/function-prop.js +20 -22
- package/dist/properties/function-prop.js.map +1 -1
- package/dist/properties/history.d.ts +2 -2
- package/dist/properties/history.d.ts.map +1 -1
- package/dist/properties/history.js +34 -33
- 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 +2 -1
- package/dist/properties/persisted.d.ts.map +1 -1
- package/dist/properties/persisted.js +24 -18
- 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 +26 -22
- package/dist/properties/prop.js.map +1 -1
- package/dist/properties/ref.d.ts +2 -1
- package/dist/properties/ref.d.ts.map +1 -1
- package/dist/properties/ref.js +11 -8
- package/dist/properties/ref.js.map +1 -1
- package/dist/properties/resource.d.ts.map +1 -1
- package/dist/properties/resource.js +21 -16
- package/dist/properties/resource.js.map +1 -1
- package/dist/properties/selector.d.ts +12 -0
- package/dist/properties/selector.d.ts.map +1 -0
- package/dist/properties/selector.js +25 -0
- package/dist/properties/selector.js.map +1 -0
- package/dist/properties/slot.d.ts +2 -1
- package/dist/properties/slot.d.ts.map +1 -1
- package/dist/properties/slot.js +22 -20
- package/dist/properties/slot.js.map +1 -1
- package/dist/properties/state.d.ts.map +1 -1
- package/dist/properties/state.js +27 -16
- package/dist/properties/state.js.map +1 -1
- package/dist/properties/synced.d.ts +2 -1
- package/dist/properties/synced.d.ts.map +1 -1
- package/dist/properties/synced.js +27 -19
- package/dist/properties/synced.js.map +1 -1
- package/dist/shared-method.d.ts +14 -0
- package/dist/shared-method.d.ts.map +1 -0
- package/dist/shared-method.js +87 -0
- package/dist/shared-method.js.map +1 -0
- package/package.json +14 -5
- package/src/component/component.ts +8 -27
- package/src/component/lazy.ts +51 -41
- package/src/create-class-decorator.ts +90 -31
- package/src/create-field-decorator.ts +120 -43
- package/src/create-getter-decorator.ts +263 -66
- package/src/create-lifecycle-method-decorator.ts +50 -28
- package/src/create-method-decorator.ts +119 -13
- package/src/events/command.ts +11 -9
- package/src/events/emit.ts +16 -22
- package/src/events/on-command.ts +17 -18
- package/src/field.ts +116 -0
- package/src/functions/bind.ts +4 -4
- package/src/functions/debounce.ts +25 -23
- package/src/functions/log.ts +44 -46
- package/src/functions/memo.ts +39 -37
- package/src/functions/once.ts +10 -13
- package/src/functions/retry.ts +19 -21
- package/src/functions/throttle.ts +12 -13
- package/src/functions/until.ts +14 -14
- package/src/functions/watch.ts +37 -36
- package/src/functions/when.ts +18 -20
- package/src/index.ts +12 -5
- package/src/lifecycle.ts +74 -0
- package/src/properties/compose.ts +33 -20
- package/src/properties/computed.ts +35 -45
- package/src/properties/deep-state.ts +66 -64
- package/src/properties/function-prop.ts +25 -27
- package/src/properties/history.ts +34 -35
- package/src/properties/index.ts +1 -0
- package/src/properties/persisted.ts +30 -20
- package/src/properties/prop.ts +30 -22
- package/src/properties/ref.ts +12 -10
- package/src/properties/resource.ts +22 -17
- package/src/properties/selector.ts +45 -0
- package/src/properties/slot.ts +28 -22
- package/src/properties/state.ts +32 -16
- package/src/properties/synced.ts +31 -19
- package/src/shared-method.ts +101 -0
- package/dist/__tests__/component.test.d.ts +0 -2
- package/dist/__tests__/component.test.d.ts.map +0 -1
- package/dist/__tests__/component.test.js +0 -147
- package/dist/__tests__/component.test.js.map +0 -1
- package/dist/__tests__/compose.test.d.ts +0 -2
- package/dist/__tests__/compose.test.d.ts.map +0 -1
- package/dist/__tests__/compose.test.js +0 -164
- package/dist/__tests__/compose.test.js.map +0 -1
- package/dist/__tests__/deep-state.test.d.ts +0 -2
- package/dist/__tests__/deep-state.test.d.ts.map +0 -1
- package/dist/__tests__/deep-state.test.js +0 -221
- package/dist/__tests__/deep-state.test.js.map +0 -1
- package/dist/__tests__/events.test.d.ts +0 -2
- package/dist/__tests__/events.test.d.ts.map +0 -1
- package/dist/__tests__/events.test.js +0 -295
- package/dist/__tests__/events.test.js.map +0 -1
- package/dist/__tests__/functions.test.d.ts +0 -2
- package/dist/__tests__/functions.test.d.ts.map +0 -1
- package/dist/__tests__/functions.test.js +0 -618
- package/dist/__tests__/functions.test.js.map +0 -1
- package/dist/__tests__/lazy.test.d.ts +0 -2
- package/dist/__tests__/lazy.test.d.ts.map +0 -1
- package/dist/__tests__/lazy.test.js +0 -227
- package/dist/__tests__/lazy.test.js.map +0 -1
- package/dist/__tests__/memo.test.d.ts +0 -2
- package/dist/__tests__/memo.test.d.ts.map +0 -1
- package/dist/__tests__/memo.test.js +0 -249
- package/dist/__tests__/memo.test.js.map +0 -1
- package/dist/__tests__/properties-browser.test.d.ts +0 -2
- package/dist/__tests__/properties-browser.test.d.ts.map +0 -1
- package/dist/__tests__/properties-browser.test.js +0 -227
- package/dist/__tests__/properties-browser.test.js.map +0 -1
- package/dist/__tests__/properties.test.d.ts +0 -2
- package/dist/__tests__/properties.test.d.ts.map +0 -1
- package/dist/__tests__/properties.test.js +0 -1253
- package/dist/__tests__/properties.test.js.map +0 -1
- package/dist/__tests__/ref.test.d.ts +0 -2
- package/dist/__tests__/ref.test.d.ts.map +0 -1
- package/dist/__tests__/ref.test.js +0 -106
- package/dist/__tests__/ref.test.js.map +0 -1
- package/dist/__tests__/resource.test.d.ts +0 -2
- package/dist/__tests__/resource.test.d.ts.map +0 -1
- package/dist/__tests__/resource.test.js +0 -217
- package/dist/__tests__/resource.test.js.map +0 -1
- package/dist/__tests__/slot.test.d.ts +0 -2
- package/dist/__tests__/slot.test.d.ts.map +0 -1
- package/dist/__tests__/slot.test.js +0 -147
- package/dist/__tests__/slot.test.js.map +0 -1
- package/dist/__tests__/synced.test.d.ts +0 -2
- package/dist/__tests__/synced.test.d.ts.map +0 -1
- package/dist/__tests__/synced.test.js +0 -161
- package/dist/__tests__/synced.test.js.map +0 -1
- package/dist/__tests__/until.test.d.ts +0 -2
- package/dist/__tests__/until.test.d.ts.map +0 -1
- package/dist/__tests__/until.test.js +0 -88
- package/dist/__tests__/until.test.js.map +0 -1
- package/dist/create-accessor-decorator.d.ts +0 -14
- package/dist/create-accessor-decorator.d.ts.map +0 -1
- package/dist/create-accessor-decorator.js +0 -27
- package/dist/create-accessor-decorator.js.map +0 -1
- package/src/__tests__/component.test.ts +0 -167
- package/src/__tests__/compose.test.ts +0 -202
- package/src/__tests__/deep-state.test.ts +0 -265
- package/src/__tests__/events.test.ts +0 -366
- package/src/__tests__/functions.test.ts +0 -803
- package/src/__tests__/lazy.test.ts +0 -296
- package/src/__tests__/memo.test.ts +0 -293
- package/src/__tests__/properties-browser.test.ts +0 -288
- package/src/__tests__/properties.test.ts +0 -1556
- package/src/__tests__/ref.test.ts +0 -131
- package/src/__tests__/resource.test.ts +0 -246
- package/src/__tests__/slot.test.ts +0 -179
- package/src/__tests__/synced.test.ts +0 -193
- package/src/__tests__/until.test.ts +0 -113
- package/src/create-accessor-decorator.ts +0 -45
- package/tsconfig.json +0 -9
|
@@ -1,193 +0,0 @@
|
|
|
1
|
-
// @vitest-environment jsdom
|
|
2
|
-
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
3
|
-
|
|
4
|
-
import { StatefulComponent } from "@praxisjs/core";
|
|
5
|
-
import { effect } from "@praxisjs/core/internal";
|
|
6
|
-
|
|
7
|
-
import { Synced } from "../properties/synced";
|
|
8
|
-
|
|
9
|
-
// BroadcastChannel mock (same as core test)
|
|
10
|
-
class MockBroadcastChannel {
|
|
11
|
-
static instances: MockBroadcastChannel[] = [];
|
|
12
|
-
static byChannel: Map<string, MockBroadcastChannel[]> = new Map();
|
|
13
|
-
|
|
14
|
-
onmessage: ((event: MessageEvent) => void) | null = null;
|
|
15
|
-
readonly name: string;
|
|
16
|
-
closed = false;
|
|
17
|
-
|
|
18
|
-
constructor(name: string) {
|
|
19
|
-
this.name = name;
|
|
20
|
-
MockBroadcastChannel.instances.push(this);
|
|
21
|
-
if (!MockBroadcastChannel.byChannel.has(name)) {
|
|
22
|
-
MockBroadcastChannel.byChannel.set(name, []);
|
|
23
|
-
}
|
|
24
|
-
MockBroadcastChannel.byChannel.get(name)!.push(this);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
postMessage(data: unknown) {
|
|
28
|
-
MockBroadcastChannel.byChannel.get(this.name)?.forEach((ch) => {
|
|
29
|
-
if (ch !== this && ch.onmessage) {
|
|
30
|
-
ch.onmessage(new MessageEvent("message", { data }));
|
|
31
|
-
}
|
|
32
|
-
});
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
close() {
|
|
36
|
-
this.closed = true;
|
|
37
|
-
const list = MockBroadcastChannel.byChannel.get(this.name);
|
|
38
|
-
if (list) {
|
|
39
|
-
const idx = list.indexOf(this);
|
|
40
|
-
if (idx !== -1) list.splice(idx, 1);
|
|
41
|
-
}
|
|
42
|
-
MockBroadcastChannel.instances.splice(
|
|
43
|
-
MockBroadcastChannel.instances.indexOf(this),
|
|
44
|
-
1,
|
|
45
|
-
);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
beforeEach(() => {
|
|
50
|
-
MockBroadcastChannel.instances = [];
|
|
51
|
-
MockBroadcastChannel.byChannel = new Map();
|
|
52
|
-
vi.stubGlobal("BroadcastChannel", MockBroadcastChannel);
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
class TestComponent extends StatefulComponent {
|
|
56
|
-
render() { return null; }
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
function fieldCtx(name: string) {
|
|
60
|
-
const initializers: Array<(this: unknown) => void> = [];
|
|
61
|
-
return {
|
|
62
|
-
ctx: {
|
|
63
|
-
name,
|
|
64
|
-
kind: "field" as const,
|
|
65
|
-
addInitializer(fn: (this: unknown) => void) { initializers.push(fn); },
|
|
66
|
-
} as ClassFieldDecoratorContext,
|
|
67
|
-
run(instance: unknown) {
|
|
68
|
-
initializers.forEach((fn) => { fn.call(instance); });
|
|
69
|
-
},
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
describe("@Synced decorator", () => {
|
|
74
|
-
it("reads and writes the field reactively", () => {
|
|
75
|
-
const { ctx, run } = fieldCtx("count");
|
|
76
|
-
Synced()(undefined, ctx);
|
|
77
|
-
const instance = new TestComponent();
|
|
78
|
-
(instance as unknown as Record<string, unknown>).count = 0;
|
|
79
|
-
run(instance);
|
|
80
|
-
|
|
81
|
-
const inst = instance as unknown as { count: number };
|
|
82
|
-
expect(inst.count).toBe(0);
|
|
83
|
-
inst.count = 5;
|
|
84
|
-
expect(inst.count).toBe(5);
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
it("uses field name as channel name by default", () => {
|
|
88
|
-
const { ctx, run } = fieldCtx("cart");
|
|
89
|
-
Synced()(undefined, ctx);
|
|
90
|
-
const instance = new TestComponent();
|
|
91
|
-
(instance as unknown as Record<string, unknown>).cart = [];
|
|
92
|
-
run(instance);
|
|
93
|
-
|
|
94
|
-
expect(MockBroadcastChannel.instances[0].name).toBe("cart");
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
it("uses custom channel name when provided", () => {
|
|
98
|
-
const { ctx, run } = fieldCtx("items");
|
|
99
|
-
Synced("my-channel")(undefined, ctx);
|
|
100
|
-
const instance = new TestComponent();
|
|
101
|
-
(instance as unknown as Record<string, unknown>).items = [];
|
|
102
|
-
run(instance);
|
|
103
|
-
|
|
104
|
-
expect(MockBroadcastChannel.instances[0].name).toBe("my-channel");
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
it("triggers reactive effects on write", () => {
|
|
108
|
-
const { ctx, run } = fieldCtx("value");
|
|
109
|
-
Synced()(undefined, ctx);
|
|
110
|
-
const instance = new TestComponent();
|
|
111
|
-
(instance as unknown as Record<string, unknown>).value = 0;
|
|
112
|
-
run(instance);
|
|
113
|
-
|
|
114
|
-
const inst = instance as unknown as { value: number };
|
|
115
|
-
const log: number[] = [];
|
|
116
|
-
effect(() => { log.push(inst.value); });
|
|
117
|
-
|
|
118
|
-
inst.value = 10;
|
|
119
|
-
expect(log).toEqual([0, 10]);
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
it("updates field when a remote message arrives", () => {
|
|
123
|
-
const { ctx, run } = fieldCtx("score");
|
|
124
|
-
Synced()(undefined, ctx);
|
|
125
|
-
const instance = new TestComponent();
|
|
126
|
-
(instance as unknown as Record<string, unknown>).score = 0;
|
|
127
|
-
run(instance);
|
|
128
|
-
|
|
129
|
-
const inst = instance as unknown as { score: number };
|
|
130
|
-
const channel = MockBroadcastChannel.instances[0];
|
|
131
|
-
channel.onmessage!(new MessageEvent("message", { data: JSON.stringify(42) }));
|
|
132
|
-
|
|
133
|
-
expect(inst.score).toBe(42);
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
it("two @Synced fields on the same instance share the signalMap entry", () => {
|
|
137
|
-
const { ctx: ctx1, run: run1 } = fieldCtx("a");
|
|
138
|
-
const { ctx: ctx2, run: run2 } = fieldCtx("b");
|
|
139
|
-
Synced()(undefined, ctx1);
|
|
140
|
-
Synced()(undefined, ctx2);
|
|
141
|
-
|
|
142
|
-
const instance = new TestComponent();
|
|
143
|
-
(instance as unknown as Record<string, unknown>).a = 1;
|
|
144
|
-
(instance as unknown as Record<string, unknown>).b = 2;
|
|
145
|
-
run1(instance);
|
|
146
|
-
run2(instance);
|
|
147
|
-
|
|
148
|
-
const inst = instance as unknown as { a: number; b: number };
|
|
149
|
-
inst.a = 10;
|
|
150
|
-
inst.b = 20;
|
|
151
|
-
expect(inst.a).toBe(10);
|
|
152
|
-
expect(inst.b).toBe(20);
|
|
153
|
-
|
|
154
|
-
// Both fields have their own BroadcastChannel
|
|
155
|
-
expect(MockBroadcastChannel.instances.length).toBe(2);
|
|
156
|
-
instance.onUnmount?.();
|
|
157
|
-
expect(MockBroadcastChannel.instances.every((ch) => ch.closed)).toBe(true);
|
|
158
|
-
});
|
|
159
|
-
|
|
160
|
-
it("reuses the existing signal when the same channel key is registered again on the same instance", () => {
|
|
161
|
-
// Two fields using an identical explicit channel name bind to the same SyncedSignal.
|
|
162
|
-
const { ctx: ctx1, run: run1 } = fieldCtx("alpha");
|
|
163
|
-
const { ctx: ctx2, run: run2 } = fieldCtx("beta");
|
|
164
|
-
Synced("shared-chan")(undefined, ctx1);
|
|
165
|
-
Synced("shared-chan")(undefined, ctx2);
|
|
166
|
-
|
|
167
|
-
const instance = new TestComponent();
|
|
168
|
-
(instance as unknown as Record<string, unknown>).alpha = "initial";
|
|
169
|
-
(instance as unknown as Record<string, unknown>).beta = "initial";
|
|
170
|
-
run1(instance);
|
|
171
|
-
// second bind for "shared-chan" on the same instance hits the map.has(key) === true branch
|
|
172
|
-
run2(instance);
|
|
173
|
-
|
|
174
|
-
const inst = instance as unknown as { alpha: string; beta: string };
|
|
175
|
-
inst.alpha = "changed";
|
|
176
|
-
// both fields share the same underlying signal
|
|
177
|
-
expect(inst.beta).toBe("changed");
|
|
178
|
-
instance.onUnmount?.();
|
|
179
|
-
});
|
|
180
|
-
|
|
181
|
-
it("onUnmount closes the BroadcastChannel", () => {
|
|
182
|
-
const { ctx, run } = fieldCtx("data");
|
|
183
|
-
Synced()(undefined, ctx);
|
|
184
|
-
const instance = new TestComponent();
|
|
185
|
-
(instance as unknown as Record<string, unknown>).data = null;
|
|
186
|
-
run(instance);
|
|
187
|
-
|
|
188
|
-
const channel = MockBroadcastChannel.instances[0];
|
|
189
|
-
expect(channel.closed).toBe(false);
|
|
190
|
-
instance.onUnmount?.();
|
|
191
|
-
expect(channel.closed).toBe(true);
|
|
192
|
-
});
|
|
193
|
-
});
|
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from "vitest";
|
|
2
|
-
|
|
3
|
-
import { signal, computed } from "@praxisjs/core/internal";
|
|
4
|
-
|
|
5
|
-
import { Until } from "../functions/until";
|
|
6
|
-
|
|
7
|
-
// Simulates TC39 decorator context for a method decorator
|
|
8
|
-
function mockMethodContext(name: string) {
|
|
9
|
-
const initializers: Array<(this: object) => void> = [];
|
|
10
|
-
const ctx = {
|
|
11
|
-
name,
|
|
12
|
-
kind: "method" as const,
|
|
13
|
-
addInitializer(fn: (this: object) => void) {
|
|
14
|
-
initializers.push(fn);
|
|
15
|
-
},
|
|
16
|
-
runInitializers(instance: object) {
|
|
17
|
-
initializers.forEach((fn) => { fn.call(instance); });
|
|
18
|
-
},
|
|
19
|
-
};
|
|
20
|
-
return ctx;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
// ── @Until ────────────────────────────────────────────────────────────────────
|
|
24
|
-
|
|
25
|
-
describe("Until", () => {
|
|
26
|
-
it("resolves immediately when the signal is already truthy", async () => {
|
|
27
|
-
const s = signal(42);
|
|
28
|
-
const obj: Record<string, unknown> = { count: s };
|
|
29
|
-
|
|
30
|
-
const ctx = mockMethodContext("wait");
|
|
31
|
-
Until("count")(() => {}, ctx as unknown as ClassMethodDecoratorContext);
|
|
32
|
-
ctx.runInitializers(obj);
|
|
33
|
-
|
|
34
|
-
const result = await (obj.wait as () => Promise<number>)();
|
|
35
|
-
expect(result).toBe(42);
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
it("resolves when the signal becomes truthy", async () => {
|
|
39
|
-
const s = signal<number>(0);
|
|
40
|
-
const obj: Record<string, unknown> = { count: s };
|
|
41
|
-
|
|
42
|
-
const ctx = mockMethodContext("wait");
|
|
43
|
-
Until("count")(() => {}, ctx as unknown as ClassMethodDecoratorContext);
|
|
44
|
-
ctx.runInitializers(obj);
|
|
45
|
-
|
|
46
|
-
const promise = (obj.wait as () => Promise<number>)();
|
|
47
|
-
s.set(5);
|
|
48
|
-
expect(await promise).toBe(5);
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
it("resolves with a computed signal", async () => {
|
|
52
|
-
const s = signal(0);
|
|
53
|
-
const doubled = computed(() => s() * 2);
|
|
54
|
-
const obj: Record<string, unknown> = { doubled };
|
|
55
|
-
|
|
56
|
-
const ctx = mockMethodContext("waitDoubled");
|
|
57
|
-
Until("doubled")(() => {}, ctx as unknown as ClassMethodDecoratorContext);
|
|
58
|
-
ctx.runInitializers(obj);
|
|
59
|
-
|
|
60
|
-
const promise = (obj.waitDoubled as () => Promise<number>)();
|
|
61
|
-
s.set(3); // doubled becomes 6 (truthy)
|
|
62
|
-
expect(await promise).toBe(6);
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
it("each call returns a new promise", async () => {
|
|
66
|
-
const s = signal<string>("");
|
|
67
|
-
const obj: Record<string, unknown> = { name: s };
|
|
68
|
-
|
|
69
|
-
const ctx = mockMethodContext("waitName");
|
|
70
|
-
Until("name")(() => {}, ctx as unknown as ClassMethodDecoratorContext);
|
|
71
|
-
ctx.runInitializers(obj);
|
|
72
|
-
|
|
73
|
-
const wait = obj.waitName as () => Promise<string>;
|
|
74
|
-
|
|
75
|
-
const p1 = wait();
|
|
76
|
-
const p2 = wait();
|
|
77
|
-
expect(p1).not.toBe(p2);
|
|
78
|
-
|
|
79
|
-
s.set("alice");
|
|
80
|
-
expect(await p1).toBe("alice");
|
|
81
|
-
expect(await p2).toBe("alice");
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
it("does not resolve when signal stays falsy", async () => {
|
|
85
|
-
const s = signal<number>(0);
|
|
86
|
-
const obj: Record<string, unknown> = { count: s };
|
|
87
|
-
|
|
88
|
-
const ctx = mockMethodContext("wait");
|
|
89
|
-
Until("count")(() => {}, ctx as unknown as ClassMethodDecoratorContext);
|
|
90
|
-
ctx.runInitializers(obj);
|
|
91
|
-
|
|
92
|
-
let resolved = false;
|
|
93
|
-
(obj.wait as () => Promise<number>)().then(() => { resolved = true; });
|
|
94
|
-
|
|
95
|
-
await new Promise((res) => { setTimeout(res, 10); });
|
|
96
|
-
expect(resolved).toBe(false);
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
it("ignores the original method body", async () => {
|
|
100
|
-
const s = signal("hello");
|
|
101
|
-
const obj: Record<string, unknown> = { value: s };
|
|
102
|
-
|
|
103
|
-
let bodyCalled = false;
|
|
104
|
-
const original = () => { bodyCalled = true; };
|
|
105
|
-
|
|
106
|
-
const ctx = mockMethodContext("wait");
|
|
107
|
-
Until("value")(original, ctx as unknown as ClassMethodDecoratorContext);
|
|
108
|
-
ctx.runInitializers(obj);
|
|
109
|
-
|
|
110
|
-
await (obj.wait as () => Promise<string>)();
|
|
111
|
-
expect(bodyCalled).toBe(false);
|
|
112
|
-
});
|
|
113
|
-
});
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
export interface AccessorBinding {
|
|
2
|
-
get: () => unknown;
|
|
3
|
-
set?: (value: unknown) => void;
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
export interface AccessorBehavior {
|
|
7
|
-
/**
|
|
8
|
-
* Called once per instance on first access. `initialValue` is the value
|
|
9
|
-
* provided by the `accessor` field initializer (e.g. `accessor count = 0`).
|
|
10
|
-
* Returns the get/set pair used by the accessor.
|
|
11
|
-
*/
|
|
12
|
-
bind(instance: object, name: string | symbol, initialValue: unknown): AccessorBinding;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export function createAccessorDecorator(behavior: AccessorBehavior) {
|
|
16
|
-
return function <This extends object, V>(
|
|
17
|
-
_target: ClassAccessorDecoratorTarget<This, V>,
|
|
18
|
-
context: ClassAccessorDecoratorContext<This, V>,
|
|
19
|
-
): ClassAccessorDecoratorResult<This, V> {
|
|
20
|
-
const bindings = new WeakMap<object, AccessorBinding>();
|
|
21
|
-
const initValues = new WeakMap<object, unknown>();
|
|
22
|
-
|
|
23
|
-
function getBinding(instance: object): AccessorBinding {
|
|
24
|
-
let b = bindings.get(instance);
|
|
25
|
-
if (!b) {
|
|
26
|
-
b = behavior.bind(instance, context.name, initValues.get(instance));
|
|
27
|
-
bindings.set(instance, b);
|
|
28
|
-
}
|
|
29
|
-
return b;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
return {
|
|
33
|
-
init(this: This, value: V): V {
|
|
34
|
-
initValues.set(this as object, value);
|
|
35
|
-
return value;
|
|
36
|
-
},
|
|
37
|
-
get(this: This): V {
|
|
38
|
-
return getBinding(this as object).get() as V;
|
|
39
|
-
},
|
|
40
|
-
set(this: This, value: V): void {
|
|
41
|
-
getBinding(this as object).set?.(value as unknown);
|
|
42
|
-
},
|
|
43
|
-
};
|
|
44
|
-
};
|
|
45
|
-
}
|