effectable 0.1.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/LICENSE +21 -0
- package/README.md +157 -0
- package/build/LICENSE +21 -0
- package/build/bootstrap/bootstrap.d.ts +32 -0
- package/build/bootstrap/bootstrap.d.ts.map +1 -0
- package/build/bootstrap/bootstrap.js +179 -0
- package/build/bootstrap/bootstrap.js.map +1 -0
- package/build/bootstrap/index.d.ts +9 -0
- package/build/bootstrap/index.d.ts.map +1 -0
- package/build/bootstrap/index.js +14 -0
- package/build/bootstrap/index.js.map +1 -0
- package/build/bootstrap/types.d.ts +105 -0
- package/build/bootstrap/types.d.ts.map +1 -0
- package/build/bootstrap/types.js +26 -0
- package/build/bootstrap/types.js.map +1 -0
- package/build/component/Component.d.ts +126 -0
- package/build/component/Component.d.ts.map +1 -0
- package/build/component/Component.js +123 -0
- package/build/component/Component.js.map +1 -0
- package/build/component/GraphRuntime.d.ts +457 -0
- package/build/component/GraphRuntime.d.ts.map +1 -0
- package/build/component/GraphRuntime.js +1168 -0
- package/build/component/GraphRuntime.js.map +1 -0
- package/build/component/constants.d.ts +1 -0
- package/build/component/constants.d.ts.map +1 -0
- package/build/component/constants.js +2 -0
- package/build/component/constants.js.map +1 -0
- package/build/component/context.d.ts +199 -0
- package/build/component/context.d.ts.map +1 -0
- package/build/component/context.js +262 -0
- package/build/component/context.js.map +1 -0
- package/build/component/graphRuntime.constants.d.ts +13 -0
- package/build/component/graphRuntime.constants.d.ts.map +1 -0
- package/build/component/graphRuntime.constants.js +15 -0
- package/build/component/graphRuntime.constants.js.map +1 -0
- package/build/component/h.d.ts +48 -0
- package/build/component/h.d.ts.map +1 -0
- package/build/component/h.js +72 -0
- package/build/component/h.js.map +1 -0
- package/build/component/index.d.ts +19 -0
- package/build/component/index.d.ts.map +1 -0
- package/build/component/index.js +39 -0
- package/build/component/index.js.map +1 -0
- package/build/component/lifecycle.d.ts +179 -0
- package/build/component/lifecycle.d.ts.map +1 -0
- package/build/component/lifecycle.js +367 -0
- package/build/component/lifecycle.js.map +1 -0
- package/build/component/refs.d.ts +105 -0
- package/build/component/refs.d.ts.map +1 -0
- package/build/component/refs.js +128 -0
- package/build/component/refs.js.map +1 -0
- package/build/component/types.d.ts +169 -0
- package/build/component/types.d.ts.map +1 -0
- package/build/component/types.js +40 -0
- package/build/component/types.js.map +1 -0
- package/build/connect/connect.d.ts +31 -0
- package/build/connect/connect.d.ts.map +1 -0
- package/build/connect/connect.js +500 -0
- package/build/connect/connect.js.map +1 -0
- package/build/connect/index.d.ts +8 -0
- package/build/connect/index.d.ts.map +1 -0
- package/build/connect/index.js +11 -0
- package/build/connect/index.js.map +1 -0
- package/build/connect/types.d.ts +90 -0
- package/build/connect/types.d.ts.map +1 -0
- package/build/connect/types.js +8 -0
- package/build/connect/types.js.map +1 -0
- package/build/index.d.ts +26 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +60 -0
- package/build/index.js.map +1 -0
- package/build/runtime/BusDecorators.d.ts +113 -0
- package/build/runtime/BusDecorators.d.ts.map +1 -0
- package/build/runtime/BusDecorators.js +302 -0
- package/build/runtime/BusDecorators.js.map +1 -0
- package/build/runtime/CommandBus.d.ts +43 -0
- package/build/runtime/CommandBus.d.ts.map +1 -0
- package/build/runtime/CommandBus.js +65 -0
- package/build/runtime/CommandBus.js.map +1 -0
- package/build/runtime/EventBus.d.ts +50 -0
- package/build/runtime/EventBus.d.ts.map +1 -0
- package/build/runtime/EventBus.js +90 -0
- package/build/runtime/EventBus.js.map +1 -0
- package/build/runtime/HandleRegistry.d.ts +143 -0
- package/build/runtime/HandleRegistry.d.ts.map +1 -0
- package/build/runtime/HandleRegistry.js +244 -0
- package/build/runtime/HandleRegistry.js.map +1 -0
- package/build/runtime/QueryBus.d.ts +43 -0
- package/build/runtime/QueryBus.d.ts.map +1 -0
- package/build/runtime/QueryBus.js +65 -0
- package/build/runtime/QueryBus.js.map +1 -0
- package/build/runtime/index.d.ts +13 -0
- package/build/runtime/index.d.ts.map +1 -0
- package/build/runtime/index.js +32 -0
- package/build/runtime/index.js.map +1 -0
- package/build/runtime/types.d.ts +79 -0
- package/build/runtime/types.d.ts.map +1 -0
- package/build/runtime/types.js +8 -0
- package/build/runtime/types.js.map +1 -0
- package/build/store/createStore.d.ts +36 -0
- package/build/store/createStore.d.ts.map +1 -0
- package/build/store/createStore.js +131 -0
- package/build/store/createStore.js.map +1 -0
- package/build/store/index.d.ts +14 -0
- package/build/store/index.d.ts.map +1 -0
- package/build/store/index.js +39 -0
- package/build/store/index.js.map +1 -0
- package/build/store/middleware.d.ts +38 -0
- package/build/store/middleware.d.ts.map +1 -0
- package/build/store/middleware.js +99 -0
- package/build/store/middleware.js.map +1 -0
- package/build/store/selector.d.ts +62 -0
- package/build/store/selector.d.ts.map +1 -0
- package/build/store/selector.js +226 -0
- package/build/store/selector.js.map +1 -0
- package/build/store/semanticStateTree.d.ts +91 -0
- package/build/store/semanticStateTree.d.ts.map +1 -0
- package/build/store/semanticStateTree.js +263 -0
- package/build/store/semanticStateTree.js.map +1 -0
- package/build/store/types.d.ts +259 -0
- package/build/store/types.d.ts.map +1 -0
- package/build/store/types.js +28 -0
- package/build/store/types.js.map +1 -0
- package/package.json +109 -0
|
@@ -0,0 +1,367 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Node lifecycle engine (`LifecycleEngine`) and transition result type.
|
|
4
|
+
*
|
|
5
|
+
* The state machine defines stage order: `registered` → `resolved` → `created` →
|
|
6
|
+
* `mounted` → `ready` → `unmounting` → `unmounted` → `destroyed`.
|
|
7
|
+
* Any stage may transition to `failed`; there is no reverse transition from `failed`
|
|
8
|
+
* (except forced `destroy` via teardown scenarios).
|
|
9
|
+
*
|
|
10
|
+
* Public component hooks are called in the expected order:
|
|
11
|
+
* - startup: `onMount`
|
|
12
|
+
* - in stage `ready`: `onUpdate` (as decided by GraphRuntime)
|
|
13
|
+
* - shutdown / cleanup: `onUnmount`
|
|
14
|
+
*
|
|
15
|
+
* @module Effectable/component/lifecycle
|
|
16
|
+
*/
|
|
17
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
+
exports.LifecycleEngine = void 0;
|
|
19
|
+
/**
|
|
20
|
+
* Numeric lifecycle stage codes for O(1) comparisons.
|
|
21
|
+
*
|
|
22
|
+
* Used instead of repeated lookups by string stage-order keys.
|
|
23
|
+
* Object constant instead of `const enum` — compatibility with `isolatedModules`.
|
|
24
|
+
*
|
|
25
|
+
* Keys: Registered … Failed; values — monotonically increasing numbers for stage comparison.
|
|
26
|
+
*/
|
|
27
|
+
const STAGE = {
|
|
28
|
+
Registered: 0,
|
|
29
|
+
Resolved: 1,
|
|
30
|
+
Created: 2,
|
|
31
|
+
Mounted: 3,
|
|
32
|
+
Ready: 4,
|
|
33
|
+
Unmounting: 5,
|
|
34
|
+
Unmounted: 6,
|
|
35
|
+
Destroyed: 7,
|
|
36
|
+
Failed: 8,
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* Array index = numeric stage code; value = string `NodeLifecycleStatus`.
|
|
40
|
+
* Used by {@link LifecycleEngine.getStatus}.
|
|
41
|
+
*/
|
|
42
|
+
const STAGE_TO_STATUS = [
|
|
43
|
+
'registered', // 0
|
|
44
|
+
'resolved', // 1
|
|
45
|
+
'created', // 2
|
|
46
|
+
'mounted', // 3
|
|
47
|
+
'ready', // 4
|
|
48
|
+
'unmounting', // 5
|
|
49
|
+
'unmounted', // 6
|
|
50
|
+
'destroyed', // 7
|
|
51
|
+
'failed', // 8
|
|
52
|
+
];
|
|
53
|
+
/**
|
|
54
|
+
* Mapping from string target stage (`ForwardStage`) to numeric code for comparison
|
|
55
|
+
* with `currentStage` in {@link LifecycleEngine.canTransitionTo}.
|
|
56
|
+
*/
|
|
57
|
+
const STAGE_FROM_FORWARD = {
|
|
58
|
+
resolved: STAGE.Resolved,
|
|
59
|
+
created: STAGE.Created,
|
|
60
|
+
mounted: STAGE.Mounted,
|
|
61
|
+
ready: STAGE.Ready,
|
|
62
|
+
unmounting: STAGE.Unmounting,
|
|
63
|
+
unmounted: STAGE.Unmounted,
|
|
64
|
+
destroyed: STAGE.Destroyed,
|
|
65
|
+
failed: STAGE.Failed,
|
|
66
|
+
};
|
|
67
|
+
/**
|
|
68
|
+
* Bits indicating presence of the corresponding hook methods on the component instance.
|
|
69
|
+
*
|
|
70
|
+
* Filled in {@link LifecycleEngine.initHookFlags}; when `hookFlags === 0`
|
|
71
|
+
* startup/shutdown can finish without `typeof` checks on each hook.
|
|
72
|
+
*/
|
|
73
|
+
const HookBit = {
|
|
74
|
+
Mount: 1 << 0,
|
|
75
|
+
Update: 1 << 1,
|
|
76
|
+
Unmount: 1 << 2,
|
|
77
|
+
};
|
|
78
|
+
/**
|
|
79
|
+
* Checks whether a value is thenable (Promise-like).
|
|
80
|
+
* Used for the sync fast-path of hooks (3.55x speedup):
|
|
81
|
+
* if the hook returned a non-Promise — skip await and the related microtask hop.
|
|
82
|
+
*
|
|
83
|
+
* @param {unknown} value - hook return value
|
|
84
|
+
* @returns {boolean} true if the value is Promise-like
|
|
85
|
+
*/
|
|
86
|
+
function isThenable(value) {
|
|
87
|
+
return (value !== null &&
|
|
88
|
+
typeof value === 'object' &&
|
|
89
|
+
typeof value.then === 'function');
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Lifecycle state machine for one node in GraphRuntime: one instance
|
|
93
|
+
* per node (fiber).
|
|
94
|
+
*
|
|
95
|
+
* Invariants:
|
|
96
|
+
* - stages mostly advance monotonically; update passes are allowed in `ready`;
|
|
97
|
+
* - after `failed`, further transitions are limited (see {@link canTransitionTo});
|
|
98
|
+
* - {@link Component.onUnmount} is called at most once per instance.
|
|
99
|
+
*
|
|
100
|
+
* @example
|
|
101
|
+
* const engine = new LifecycleEngine();
|
|
102
|
+
* engine.initHookFlags(component);
|
|
103
|
+
* await engine.runStartup(component);
|
|
104
|
+
*/
|
|
105
|
+
class LifecycleEngine {
|
|
106
|
+
/**
|
|
107
|
+
* Current stage as a number (see {@link STAGE}): comparisons without string lookups.
|
|
108
|
+
*/
|
|
109
|
+
currentStage = STAGE.Registered;
|
|
110
|
+
unmountCalled = false;
|
|
111
|
+
/**
|
|
112
|
+
* Bit flags for which hooks the component has.
|
|
113
|
+
* 0 — hooks not initialized or absent (fast-exit in runStartup/runShutdown).
|
|
114
|
+
* Set via initHookFlags() after instance creation.
|
|
115
|
+
*/
|
|
116
|
+
hookFlags = 0;
|
|
117
|
+
/**
|
|
118
|
+
* Whether hookFlags were initialized via initHookFlags().
|
|
119
|
+
* Without this, the fast-exit on hookFlags === 0 would apply before initialization.
|
|
120
|
+
*/
|
|
121
|
+
hookFlagsInitialized = false;
|
|
122
|
+
/**
|
|
123
|
+
* Returns the string node status for the external API (GraphRuntime, debugging, UI).
|
|
124
|
+
*
|
|
125
|
+
* @returns {NodeLifecycleStatus} current stage as `NodeLifecycleStatus`
|
|
126
|
+
*/
|
|
127
|
+
getStatus() {
|
|
128
|
+
return STAGE_TO_STATUS[this.currentStage];
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Computes and stores a bit mask of hook methods present on the instance.
|
|
132
|
+
* Must be called exactly once after instance creation (e.g. from materialize).
|
|
133
|
+
* Lets {@link runStartup} and {@link runShutdown} skip per-hook checks
|
|
134
|
+
* when none are declared.
|
|
135
|
+
*
|
|
136
|
+
* @param {Component<unknown, unknown>} instance - component instance with optional hooks
|
|
137
|
+
* @returns {void}
|
|
138
|
+
*/
|
|
139
|
+
initHookFlags(instance) {
|
|
140
|
+
this.hookFlags =
|
|
141
|
+
(typeof instance.onMount === 'function' ? HookBit.Mount : 0) |
|
|
142
|
+
(typeof instance.onUpdate === 'function' ? HookBit.Update : 0) |
|
|
143
|
+
(typeof instance.onUnmount === 'function' ? HookBit.Unmount : 0);
|
|
144
|
+
this.hookFlagsInitialized = true;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Startup phase: if present — call `onMount`, advance stages to `ready`.
|
|
148
|
+
* On exception: stage already `Mounted` → {@link runFailedCleanup}(`wasMounted=true`)
|
|
149
|
+
* (attempt `onUnmount` + teardown), result `{ ok: false, error }`.
|
|
150
|
+
*
|
|
151
|
+
* Returns a synchronous {@link LifecycleTransitionResult} if `onMount` returned
|
|
152
|
+
* a non-thenable value (sync fast-path); otherwise a Promise.
|
|
153
|
+
* `await` works correctly with either union branch.
|
|
154
|
+
*
|
|
155
|
+
* @param {Component<unknown, unknown>} instance - component instance
|
|
156
|
+
* @returns {LifecycleTransitionResult | Promise<LifecycleTransitionResult>}
|
|
157
|
+
*/
|
|
158
|
+
runStartup(instance) {
|
|
159
|
+
this.currentStage = STAGE.Resolved;
|
|
160
|
+
this.currentStage = STAGE.Created;
|
|
161
|
+
// Fast-exit for pure components without startup hooks (1.15x)
|
|
162
|
+
if (this.hookFlagsInitialized && this.hookFlags === 0) {
|
|
163
|
+
this.currentStage = STAGE.Mounted;
|
|
164
|
+
this.currentStage = STAGE.Ready;
|
|
165
|
+
return { ok: true };
|
|
166
|
+
}
|
|
167
|
+
try {
|
|
168
|
+
this.currentStage = STAGE.Mounted;
|
|
169
|
+
if (typeof instance.onMount === 'function') {
|
|
170
|
+
const r = instance.onMount();
|
|
171
|
+
if (isThenable(r)) {
|
|
172
|
+
return this.continueStartupAsync(instance, r);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
this.currentStage = STAGE.Ready;
|
|
176
|
+
return { ok: true };
|
|
177
|
+
}
|
|
178
|
+
catch (error) {
|
|
179
|
+
// Stage is already Mounted before onMount — cleanup must attempt onUnmount.
|
|
180
|
+
const cleanupResult = this.runFailedCleanup(instance, true);
|
|
181
|
+
if (isThenable(cleanupResult)) {
|
|
182
|
+
return cleanupResult.then(() => ({ ok: false, error }));
|
|
183
|
+
}
|
|
184
|
+
return { ok: false, error };
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Async continuation of {@link runStartup} after `onMount` returned a Promise.
|
|
189
|
+
*
|
|
190
|
+
* @param {Component<unknown, unknown>} instance - component instance
|
|
191
|
+
* @param {PromiseLike<unknown>} pending - Promise from onMount
|
|
192
|
+
* @returns {Promise<LifecycleTransitionResult>}
|
|
193
|
+
*/
|
|
194
|
+
async continueStartupAsync(instance, pending) {
|
|
195
|
+
try {
|
|
196
|
+
await pending;
|
|
197
|
+
this.currentStage = STAGE.Ready;
|
|
198
|
+
return { ok: true };
|
|
199
|
+
}
|
|
200
|
+
catch (error) {
|
|
201
|
+
const cleanupResult = this.runFailedCleanup(instance, true);
|
|
202
|
+
if (isThenable(cleanupResult)) {
|
|
203
|
+
await cleanupResult;
|
|
204
|
+
}
|
|
205
|
+
return { ok: false, error };
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Shutdown phase: if needed `onUnmount`, stages `unmounting` → `unmounted` → `destroyed`.
|
|
210
|
+
* If the node is already `destroyed`, noop. An error in `onUnmount` is returned as `{ ok: false, error }`.
|
|
211
|
+
*
|
|
212
|
+
* Returns a synchronous {@link LifecycleTransitionResult} if `onUnmount` returned non-thenable
|
|
213
|
+
* (sync fast-path); otherwise a Promise. `await` works correctly
|
|
214
|
+
* with either union branch.
|
|
215
|
+
*
|
|
216
|
+
* @param {Component<unknown, unknown>} instance - component instance
|
|
217
|
+
* @returns {LifecycleTransitionResult | Promise<LifecycleTransitionResult>}
|
|
218
|
+
*/
|
|
219
|
+
runShutdown(instance) {
|
|
220
|
+
if (this.currentStage === STAGE.Destroyed) {
|
|
221
|
+
return { ok: true };
|
|
222
|
+
}
|
|
223
|
+
// Numeric comparisons instead of 4 STAGE_ORDER string lookups (1.10x)
|
|
224
|
+
const wasReady = this.currentStage >= STAGE.Mounted &&
|
|
225
|
+
this.currentStage <= STAGE.Ready;
|
|
226
|
+
this.currentStage = STAGE.Unmounting;
|
|
227
|
+
let unmountError = null;
|
|
228
|
+
if (wasReady && !this.unmountCalled && typeof instance.onUnmount === 'function') {
|
|
229
|
+
this.unmountCalled = true;
|
|
230
|
+
try {
|
|
231
|
+
const r = instance.onUnmount();
|
|
232
|
+
if (isThenable(r)) {
|
|
233
|
+
return this.continueShutdownAsync(r);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
catch (error) {
|
|
237
|
+
unmountError = error;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
this.currentStage = STAGE.Unmounted;
|
|
241
|
+
this.currentStage = STAGE.Destroyed;
|
|
242
|
+
if (unmountError !== null) {
|
|
243
|
+
return { ok: false, error: unmountError };
|
|
244
|
+
}
|
|
245
|
+
return { ok: true };
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Async continuation of {@link runShutdown} after `onUnmount` returned a Promise.
|
|
249
|
+
*
|
|
250
|
+
* @param {PromiseLike<unknown>} pendingUnmount - Promise from onUnmount
|
|
251
|
+
* @returns {Promise<LifecycleTransitionResult>}
|
|
252
|
+
*/
|
|
253
|
+
async continueShutdownAsync(pendingUnmount) {
|
|
254
|
+
let unmountError = null;
|
|
255
|
+
try {
|
|
256
|
+
await pendingUnmount;
|
|
257
|
+
}
|
|
258
|
+
catch (error) {
|
|
259
|
+
unmountError = error;
|
|
260
|
+
}
|
|
261
|
+
this.currentStage = STAGE.Unmounted;
|
|
262
|
+
this.currentStage = STAGE.Destroyed;
|
|
263
|
+
if (unmountError !== null) {
|
|
264
|
+
return { ok: false, error: unmountError };
|
|
265
|
+
}
|
|
266
|
+
return { ok: true };
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Forced cleanup after failure: stage `failed`, if `wasMounted` — attempt
|
|
270
|
+
* `onUnmount` (errors swallowed), then final teardown.
|
|
271
|
+
* Used on `onMount` fail (stage already `Mounted`) and by GraphRuntime on errors
|
|
272
|
+
* outside startup (e.g. during update).
|
|
273
|
+
*
|
|
274
|
+
* Returns `void` synchronously if `onUnmount` is absent or returned non-thenable;
|
|
275
|
+
* otherwise a Promise.
|
|
276
|
+
*
|
|
277
|
+
* @param {Component<unknown, unknown>} instance - component instance
|
|
278
|
+
* @param {boolean} wasMounted - `true` if the node had already mounted before the error
|
|
279
|
+
* @returns {void | Promise<void>}
|
|
280
|
+
*/
|
|
281
|
+
runFailedCleanup(instance, wasMounted) {
|
|
282
|
+
this.currentStage = STAGE.Failed;
|
|
283
|
+
if (wasMounted && !this.unmountCalled && typeof instance.onUnmount === 'function') {
|
|
284
|
+
this.unmountCalled = true;
|
|
285
|
+
try {
|
|
286
|
+
const r = instance.onUnmount();
|
|
287
|
+
if (isThenable(r)) {
|
|
288
|
+
return this.continueFailedCleanupAsync(r);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
catch {
|
|
292
|
+
// Continue teardown even if onUnmount fails
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
return this.runForcedDestroy();
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* Async continuation of {@link runFailedCleanup} after async unmount.
|
|
299
|
+
*
|
|
300
|
+
* @param {PromiseLike<unknown>} pendingUnmount - Promise from onUnmount
|
|
301
|
+
* @returns {Promise<void>}
|
|
302
|
+
*/
|
|
303
|
+
async continueFailedCleanupAsync(pendingUnmount) {
|
|
304
|
+
try {
|
|
305
|
+
await pendingUnmount;
|
|
306
|
+
}
|
|
307
|
+
catch {
|
|
308
|
+
// Continue teardown even if onUnmount fails
|
|
309
|
+
}
|
|
310
|
+
const destroyResult = this.runForcedDestroy();
|
|
311
|
+
if (isThenable(destroyResult)) {
|
|
312
|
+
await destroyResult;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Idempotent teardown: marks the node as `destroyed`. No `onDestroy` call
|
|
317
|
+
* (legacy hook removed); side-effect cleanup happens in `onUnmount`.
|
|
318
|
+
*
|
|
319
|
+
* @returns {void | Promise<void>} always `void` (signature kept for compatibility)
|
|
320
|
+
*/
|
|
321
|
+
runForcedDestroy() {
|
|
322
|
+
this.currentStage = STAGE.Destroyed;
|
|
323
|
+
}
|
|
324
|
+
/**
|
|
325
|
+
* Whether the node can accept an update pass (`onUpdate`): only stage `ready`.
|
|
326
|
+
*
|
|
327
|
+
* @returns {boolean} `true` if an update-pass may be called
|
|
328
|
+
*/
|
|
329
|
+
canUpdate() {
|
|
330
|
+
return this.currentStage === STAGE.Ready;
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Whether the node is in a terminal stage: `destroyed` or `failed` (further work with the node is not expected).
|
|
334
|
+
*
|
|
335
|
+
* @returns {boolean} `true` for `destroyed` and `failed`
|
|
336
|
+
*/
|
|
337
|
+
isTerminated() {
|
|
338
|
+
return (this.currentStage === STAGE.Destroyed || this.currentStage === STAGE.Failed);
|
|
339
|
+
}
|
|
340
|
+
/**
|
|
341
|
+
* Moves the node to `failed` without calling hooks (external error, marking in GraphRuntime).
|
|
342
|
+
* If the node is already terminal, state is unchanged.
|
|
343
|
+
*
|
|
344
|
+
* @returns {void}
|
|
345
|
+
*/
|
|
346
|
+
markFailed() {
|
|
347
|
+
if (!this.isTerminated()) {
|
|
348
|
+
this.currentStage = STAGE.Failed;
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* Whether a “forward” transition to `target` is allowed relative to the current numeric stage.
|
|
353
|
+
* From `failed` only a transition to `destroyed` is allowed (aligned with forced teardown).
|
|
354
|
+
*
|
|
355
|
+
* @param {ForwardStage} target - target stage under test by string name
|
|
356
|
+
* @returns {boolean} `true` if the target stage is strictly “later” than current (or special case `failed`→`destroyed`)
|
|
357
|
+
*/
|
|
358
|
+
canTransitionTo(target) {
|
|
359
|
+
if (this.currentStage === STAGE.Failed) {
|
|
360
|
+
return target === 'destroyed';
|
|
361
|
+
}
|
|
362
|
+
// Numeric comparison instead of two STAGE_ORDER string lookups (1.11x)
|
|
363
|
+
return STAGE_FROM_FORWARD[target] > this.currentStage;
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
exports.LifecycleEngine = LifecycleEngine;
|
|
367
|
+
//# sourceMappingURL=lifecycle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lifecycle.js","sourceRoot":"","sources":["../../src/component/lifecycle.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ref machinery for declarative component composition in GraphRuntime.
|
|
3
|
+
*
|
|
4
|
+
* - {@link UseRef} — property decorator: lazily creates a `RefObject` and registers the field for runtime binding.
|
|
5
|
+
* - {@link UseImperativeHandle} — method decorator: marks a method as part of the child node's public imperative API.
|
|
6
|
+
*
|
|
7
|
+
* **Ref usage rules**
|
|
8
|
+
*
|
|
9
|
+
* - Ref is a controlled escape hatch; do not use it as a service locator.
|
|
10
|
+
* - Only for a narrow imperative API (e.g. reset, focus, flush).
|
|
11
|
+
* - Does not replace DI, CommandBus, or context.
|
|
12
|
+
* - After the node unmounts, GraphRuntime clears `ref.current`.
|
|
13
|
+
*
|
|
14
|
+
* @module Effectable/component/refs
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Metadata symbol key: list of class fields marked with {@link UseRef}.
|
|
18
|
+
*
|
|
19
|
+
* Filled by the decorator on the constructor; read by {@link getRefFields} and GraphRuntime on mount
|
|
20
|
+
* to match the field with the node passed via `h(..., ref)`.
|
|
21
|
+
*/
|
|
22
|
+
export declare const REF_FIELDS_META_KEY: unique symbol;
|
|
23
|
+
/**
|
|
24
|
+
* Metadata symbol key: list of methods marked with {@link UseImperativeHandle}.
|
|
25
|
+
*
|
|
26
|
+
* GraphRuntime builds a limited public handle (imperative API) from them without exposing other class methods.
|
|
27
|
+
*/
|
|
28
|
+
export declare const IMPERATIVE_HANDLE_META_KEY: unique symbol;
|
|
29
|
+
/**
|
|
30
|
+
* Record for a field registered by the {@link UseRef} decorator.
|
|
31
|
+
*
|
|
32
|
+
* Used by the runtime to bind a child component instance to the parent's ref.
|
|
33
|
+
*/
|
|
34
|
+
export interface RefFieldMeta {
|
|
35
|
+
/** Property key on the component instance (`string` or `symbol`). */
|
|
36
|
+
propertyKey: string | symbol;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Record for a method registered by the {@link UseImperativeHandle} decorator.
|
|
40
|
+
*
|
|
41
|
+
* Participates in building the public imperative API of the child node's ref.
|
|
42
|
+
*/
|
|
43
|
+
export interface ImperativeHandleMeta {
|
|
44
|
+
/** Method key on the component instance (`string` or `symbol`). */
|
|
45
|
+
methodKey: string | symbol;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Component class property decorator: lazily creates a `RefObject` and registers the field in {@link REF_FIELDS_META_KEY}.
|
|
49
|
+
*
|
|
50
|
+
* On first getter access, one `RefObject` is created per instance; the same ref is passed to `h(Child, {}, this.childRef)`.
|
|
51
|
+
* GraphRuntime fills `current` when the child node mounts.
|
|
52
|
+
*
|
|
53
|
+
* @returns {PropertyDecorator} property decorator: getter returns a stable `RefObject` for the child node
|
|
54
|
+
* @example
|
|
55
|
+
* class Parent extends Component {
|
|
56
|
+
* @UseRef()
|
|
57
|
+
* private declare childRef: RefObject<Child>;
|
|
58
|
+
*
|
|
59
|
+
* compose() {
|
|
60
|
+
* return h(Child, {}, this.childRef);
|
|
61
|
+
* }
|
|
62
|
+
* }
|
|
63
|
+
*/
|
|
64
|
+
export declare function UseRef(): PropertyDecorator;
|
|
65
|
+
/**
|
|
66
|
+
* Component class method decorator: adds the method to the {@link IMPERATIVE_HANDLE_META_KEY} list.
|
|
67
|
+
*
|
|
68
|
+
* GraphRuntime builds the public imperative handle only from such methods; other class methods
|
|
69
|
+
* are not reachable via ref. The method itself is not overridden — only registered as metadata on the constructor.
|
|
70
|
+
*
|
|
71
|
+
* @returns {MethodDecorator} method decorator that leaves `descriptor` unchanged (side effect only — write meta)
|
|
72
|
+
* @example
|
|
73
|
+
* class Child extends Component {
|
|
74
|
+
* @UseImperativeHandle()
|
|
75
|
+
* public async reset(): Promise<void> {
|
|
76
|
+
* // ...
|
|
77
|
+
* }
|
|
78
|
+
* }
|
|
79
|
+
*/
|
|
80
|
+
export declare function UseImperativeHandle(): MethodDecorator;
|
|
81
|
+
/**
|
|
82
|
+
* Returns the array of fields registered by {@link UseRef} on the given component constructor.
|
|
83
|
+
*
|
|
84
|
+
* If meta is absent, returns a new empty array. If meta is present, returns the same array stored
|
|
85
|
+
* on the constructor (external mutations affect the metadata).
|
|
86
|
+
*
|
|
87
|
+
* @param {object} componentClass - component constructor: object with optional {@link REF_FIELDS_META_KEY}
|
|
88
|
+
* @returns {RefFieldMeta[]} ref field records; order matches decorator application order
|
|
89
|
+
*/
|
|
90
|
+
export declare function getRefFields(componentClass: {
|
|
91
|
+
[REF_FIELDS_META_KEY]?: RefFieldMeta[];
|
|
92
|
+
}): RefFieldMeta[];
|
|
93
|
+
/**
|
|
94
|
+
* Returns the array of methods registered by {@link UseImperativeHandle} on the given constructor.
|
|
95
|
+
*
|
|
96
|
+
* If meta is absent, returns a new empty array. If meta is present, returns the same array stored
|
|
97
|
+
* on the constructor (external mutations affect the metadata).
|
|
98
|
+
*
|
|
99
|
+
* @param {object} componentClass - component constructor: object with optional {@link IMPERATIVE_HANDLE_META_KEY}
|
|
100
|
+
* @returns {ImperativeHandleMeta[]} imperative API method records; order matches decorator application order
|
|
101
|
+
*/
|
|
102
|
+
export declare function getImperativeHandleMethods(componentClass: {
|
|
103
|
+
[IMPERATIVE_HANDLE_META_KEY]?: ImperativeHandleMeta[];
|
|
104
|
+
}): ImperativeHandleMeta[];
|
|
105
|
+
//# sourceMappingURL=refs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"refs.d.ts","sourceRoot":"","sources":["../../src/component/refs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAIH;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,eAAkC,CAAC;AAEnE;;;;GAIG;AACH,eAAO,MAAM,0BAA0B,eAAyC,CAAC;AAEjF;;;;GAIG;AACH,MAAM,WAAW,YAAY;IAC3B,qEAAqE;IACrE,WAAW,EAAE,MAAM,GAAG,MAAM,CAAC;CAC9B;AAED;;;;GAIG;AACH,MAAM,WAAW,oBAAoB;IACnC,mEAAmE;IACnE,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC;CAC5B;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,MAAM,IAAK,iBAAiB,CA+B3C;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,mBAAmB,IAAK,eAAe,CAoBtD;AAED;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAC1B,cAAc,EAAE;IAAE,CAAC,mBAAmB,CAAC,CAAC,EAAE,YAAY,EAAE,CAAA;CAAE,GACzD,YAAY,EAAE,CAEhB;AAED;;;;;;;;GAQG;AACH,wBAAgB,0BAA0B,CACxC,cAAc,EAAE;IAAE,CAAC,0BAA0B,CAAC,CAAC,EAAE,oBAAoB,EAAE,CAAA;CAAE,GACxE,oBAAoB,EAAE,CAExB"}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Ref machinery for declarative component composition in GraphRuntime.
|
|
4
|
+
*
|
|
5
|
+
* - {@link UseRef} — property decorator: lazily creates a `RefObject` and registers the field for runtime binding.
|
|
6
|
+
* - {@link UseImperativeHandle} — method decorator: marks a method as part of the child node's public imperative API.
|
|
7
|
+
*
|
|
8
|
+
* **Ref usage rules**
|
|
9
|
+
*
|
|
10
|
+
* - Ref is a controlled escape hatch; do not use it as a service locator.
|
|
11
|
+
* - Only for a narrow imperative API (e.g. reset, focus, flush).
|
|
12
|
+
* - Does not replace DI, CommandBus, or context.
|
|
13
|
+
* - After the node unmounts, GraphRuntime clears `ref.current`.
|
|
14
|
+
*
|
|
15
|
+
* @module Effectable/component/refs
|
|
16
|
+
*/
|
|
17
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
+
exports.IMPERATIVE_HANDLE_META_KEY = exports.REF_FIELDS_META_KEY = void 0;
|
|
19
|
+
exports.UseRef = UseRef;
|
|
20
|
+
exports.UseImperativeHandle = UseImperativeHandle;
|
|
21
|
+
exports.getRefFields = getRefFields;
|
|
22
|
+
exports.getImperativeHandleMethods = getImperativeHandleMethods;
|
|
23
|
+
/**
|
|
24
|
+
* Metadata symbol key: list of class fields marked with {@link UseRef}.
|
|
25
|
+
*
|
|
26
|
+
* Filled by the decorator on the constructor; read by {@link getRefFields} and GraphRuntime on mount
|
|
27
|
+
* to match the field with the node passed via `h(..., ref)`.
|
|
28
|
+
*/
|
|
29
|
+
exports.REF_FIELDS_META_KEY = Symbol('effectable:ref_fields');
|
|
30
|
+
/**
|
|
31
|
+
* Metadata symbol key: list of methods marked with {@link UseImperativeHandle}.
|
|
32
|
+
*
|
|
33
|
+
* GraphRuntime builds a limited public handle (imperative API) from them without exposing other class methods.
|
|
34
|
+
*/
|
|
35
|
+
exports.IMPERATIVE_HANDLE_META_KEY = Symbol('effectable:imperative_handle');
|
|
36
|
+
/**
|
|
37
|
+
* Component class property decorator: lazily creates a `RefObject` and registers the field in {@link REF_FIELDS_META_KEY}.
|
|
38
|
+
*
|
|
39
|
+
* On first getter access, one `RefObject` is created per instance; the same ref is passed to `h(Child, {}, this.childRef)`.
|
|
40
|
+
* GraphRuntime fills `current` when the child node mounts.
|
|
41
|
+
*
|
|
42
|
+
* @returns {PropertyDecorator} property decorator: getter returns a stable `RefObject` for the child node
|
|
43
|
+
* @example
|
|
44
|
+
* class Parent extends Component {
|
|
45
|
+
* @UseRef()
|
|
46
|
+
* private declare childRef: RefObject<Child>;
|
|
47
|
+
*
|
|
48
|
+
* compose() {
|
|
49
|
+
* return h(Child, {}, this.childRef);
|
|
50
|
+
* }
|
|
51
|
+
* }
|
|
52
|
+
*/
|
|
53
|
+
function UseRef() {
|
|
54
|
+
return function (target, propertyKey) {
|
|
55
|
+
const constructor = target.constructor;
|
|
56
|
+
if (!Array.isArray(constructor[exports.REF_FIELDS_META_KEY])) {
|
|
57
|
+
constructor[exports.REF_FIELDS_META_KEY] = [];
|
|
58
|
+
}
|
|
59
|
+
const existing = constructor[exports.REF_FIELDS_META_KEY];
|
|
60
|
+
if (existing !== undefined) {
|
|
61
|
+
existing.push({ propertyKey });
|
|
62
|
+
}
|
|
63
|
+
// Pre-compute storage key once in closure (30.9x speedup vs string concat per getter call)
|
|
64
|
+
const refKey = `__ref_${String(propertyKey)}`;
|
|
65
|
+
Object.defineProperty(target, propertyKey, {
|
|
66
|
+
get() {
|
|
67
|
+
if (this[refKey] === undefined) {
|
|
68
|
+
this[refKey] = { current: null };
|
|
69
|
+
}
|
|
70
|
+
return this[refKey];
|
|
71
|
+
},
|
|
72
|
+
enumerable: true,
|
|
73
|
+
configurable: true,
|
|
74
|
+
});
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Component class method decorator: adds the method to the {@link IMPERATIVE_HANDLE_META_KEY} list.
|
|
79
|
+
*
|
|
80
|
+
* GraphRuntime builds the public imperative handle only from such methods; other class methods
|
|
81
|
+
* are not reachable via ref. The method itself is not overridden — only registered as metadata on the constructor.
|
|
82
|
+
*
|
|
83
|
+
* @returns {MethodDecorator} method decorator that leaves `descriptor` unchanged (side effect only — write meta)
|
|
84
|
+
* @example
|
|
85
|
+
* class Child extends Component {
|
|
86
|
+
* @UseImperativeHandle()
|
|
87
|
+
* public async reset(): Promise<void> {
|
|
88
|
+
* // ...
|
|
89
|
+
* }
|
|
90
|
+
* }
|
|
91
|
+
*/
|
|
92
|
+
function UseImperativeHandle() {
|
|
93
|
+
return function (target, methodKey, _descriptor) {
|
|
94
|
+
const constructor = target.constructor;
|
|
95
|
+
if (!Array.isArray(constructor[exports.IMPERATIVE_HANDLE_META_KEY])) {
|
|
96
|
+
constructor[exports.IMPERATIVE_HANDLE_META_KEY] = [];
|
|
97
|
+
}
|
|
98
|
+
const existing = constructor[exports.IMPERATIVE_HANDLE_META_KEY];
|
|
99
|
+
if (existing !== undefined) {
|
|
100
|
+
existing.push({ methodKey });
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Returns the array of fields registered by {@link UseRef} on the given component constructor.
|
|
106
|
+
*
|
|
107
|
+
* If meta is absent, returns a new empty array. If meta is present, returns the same array stored
|
|
108
|
+
* on the constructor (external mutations affect the metadata).
|
|
109
|
+
*
|
|
110
|
+
* @param {object} componentClass - component constructor: object with optional {@link REF_FIELDS_META_KEY}
|
|
111
|
+
* @returns {RefFieldMeta[]} ref field records; order matches decorator application order
|
|
112
|
+
*/
|
|
113
|
+
function getRefFields(componentClass) {
|
|
114
|
+
return componentClass[exports.REF_FIELDS_META_KEY] ?? [];
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Returns the array of methods registered by {@link UseImperativeHandle} on the given constructor.
|
|
118
|
+
*
|
|
119
|
+
* If meta is absent, returns a new empty array. If meta is present, returns the same array stored
|
|
120
|
+
* on the constructor (external mutations affect the metadata).
|
|
121
|
+
*
|
|
122
|
+
* @param {object} componentClass - component constructor: object with optional {@link IMPERATIVE_HANDLE_META_KEY}
|
|
123
|
+
* @returns {ImperativeHandleMeta[]} imperative API method records; order matches decorator application order
|
|
124
|
+
*/
|
|
125
|
+
function getImperativeHandleMethods(componentClass) {
|
|
126
|
+
return componentClass[exports.IMPERATIVE_HANDLE_META_KEY] ?? [];
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=refs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"refs.js","sourceRoot":"","sources":["../../src/component/refs.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;GAcG;;;AAwDH,wBA+BC;AAiBD,kDAoBC;AAWD,oCAIC;AAWD,gEAIC;AAtJD;;;;;GAKG;AACU,QAAA,mBAAmB,GAAG,MAAM,CAAC,uBAAuB,CAAC,CAAC;AAEnE;;;;GAIG;AACU,QAAA,0BAA0B,GAAG,MAAM,CAAC,8BAA8B,CAAC,CAAC;AAsBjF;;;;;;;;;;;;;;;;GAgBG;AACH,SAAgB,MAAM;IACpB,OAAO,UAAU,MAAc,EAAE,WAA4B;QAC3D,MAAM,WAAW,GAAG,MAAM,CAAC,WAE1B,CAAC;QAEF,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,2BAAmB,CAAC,CAAC,EAAE,CAAC;YACrD,WAAW,CAAC,2BAAmB,CAAC,GAAG,EAAE,CAAC;QACxC,CAAC;QAED,MAAM,QAAQ,GAAG,WAAW,CAAC,2BAAmB,CAAC,CAAC;QAElD,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;YAC3B,QAAQ,CAAC,IAAI,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC;QACjC,CAAC;QAED,2FAA2F;QAC3F,MAAM,MAAM,GAAG,SAAS,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC;QAE9C,MAAM,CAAC,cAAc,CAAC,MAAM,EAAE,WAAW,EAAE;YACzC,GAAG;gBACD,IAAI,IAAI,CAAC,MAAM,CAAC,KAAK,SAAS,EAAE,CAAC;oBAC/B,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAwB,CAAC;gBACzD,CAAC;gBAED,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC;YACtB,CAAC;YACD,UAAU,EAAE,IAAI;YAChB,YAAY,EAAE,IAAI;SACnB,CAAC,CAAC;IACL,CAAC,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,SAAgB,mBAAmB;IACjC,OAAO,UACL,MAAc,EACd,SAA0B,EAC1B,WAA+B;QAE/B,MAAM,WAAW,GAAG,MAAM,CAAC,WAE1B,CAAC;QAEF,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,kCAA0B,CAAC,CAAC,EAAE,CAAC;YAC5D,WAAW,CAAC,kCAA0B,CAAC,GAAG,EAAE,CAAC;QAC/C,CAAC;QAED,MAAM,QAAQ,GAAG,WAAW,CAAC,kCAA0B,CAAC,CAAC;QAEzD,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;YAC3B,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC;QAC/B,CAAC;IACH,CAAC,CAAC;AACJ,CAAC;AAED;;;;;;;;GAQG;AACH,SAAgB,YAAY,CAC1B,cAA0D;IAE1D,OAAO,cAAc,CAAC,2BAAmB,CAAC,IAAI,EAAE,CAAC;AACnD,CAAC;AAED;;;;;;;;GAQG;AACH,SAAgB,0BAA0B,CACxC,cAAyE;IAEzE,OAAO,cAAc,CAAC,kCAA0B,CAAC,IAAI,EAAE,CAAC;AAC1D,CAAC"}
|