lanka 1.1.1 → 1.3.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/README.md +3 -1
- package/dist/{ALankaGateway-CkW1LbKE.d.ts → ALankaGateway-BrVPaZN5.d.ts} +1 -1
- package/dist/ILankaFieldError-D5931-vT.d.ts +34 -0
- package/dist/{ILankaScenarioMetadata-GoWWNEQL.d.ts → ILankaScenarioMetadata-Dj4GCqmX.d.ts} +1 -1
- package/dist/{ILankaScenarioVM-DUsI-fSc.d.ts → ILankaScenarioVM-DpKFL3iE.d.ts} +5 -4
- package/dist/{LankaError-xpI-qj35.d.ts → LankaError-D6RWNyLM.d.ts} +18 -0
- package/dist/{LankaScenarioLocator-D86TIwiu.d.ts → LankaScenarioLocator-CAENLhDO.d.ts} +3 -3
- package/dist/_extend/index.d.ts +6 -5
- package/dist/_extend/index.js +3 -3
- package/dist/_internal/index.d.ts +61 -8
- package/dist/_internal/index.js +25 -0
- package/dist/_internal/index.js.map +1 -1
- package/dist/{activeRuntime-B336NU5I.d.ts → activeRuntime-BYd2D6Lx.d.ts} +2 -2
- package/dist/bootstrap/index.d.ts +9 -8
- package/dist/bootstrap/index.js +4 -4
- package/dist/cache/index.d.ts +99 -0
- package/dist/cache/index.js +1 -0
- package/dist/cache/index.js.map +1 -0
- package/dist/{chunk-GK3E4CVW.js → chunk-5MAQVBI2.js} +4 -4
- package/dist/{chunk-UGXSGQPW.js → chunk-B7EYIAW7.js} +39 -3
- package/dist/chunk-B7EYIAW7.js.map +1 -0
- package/dist/chunk-CRIRTOLB.js +27 -0
- package/dist/chunk-CRIRTOLB.js.map +1 -0
- package/dist/{chunk-Q7QESSYF.js → chunk-G32H73QY.js} +10 -1
- package/dist/chunk-G32H73QY.js.map +1 -0
- package/dist/chunk-HVSQOMRE.js +69 -0
- package/dist/chunk-HVSQOMRE.js.map +1 -0
- package/dist/{chunk-73IVH3C6.js → chunk-NDCJBO47.js} +2 -2
- package/dist/{chunk-ECM2HZHS.js → chunk-UBGXDTXC.js} +16 -7
- package/dist/chunk-UBGXDTXC.js.map +1 -0
- package/dist/{createLanka-DI1CSy2Q.d.ts → createLanka-NrlvN-WQ.d.ts} +1 -1
- package/dist/errors/index.d.ts +22 -3
- package/dist/errors/index.js +8 -3
- package/dist/errors/index.js.map +1 -1
- package/dist/gateway/index.d.ts +4 -3
- package/dist/gateway/index.js +4 -3
- package/dist/gateway/index.js.map +1 -1
- package/dist/index.d.ts +9 -8
- package/dist/index.js +5 -5
- package/dist/{lankaStandardValidator-CL-r-zEV.d.ts → lankaStandardValidator-BUFnysK0.d.ts} +10 -0
- package/dist/locator/index.d.ts +3 -2
- package/dist/scenario/index.d.ts +56 -6
- package/dist/scenario/index.js +1 -1
- package/dist/storage/index.d.ts +120 -0
- package/dist/storage/index.js +1 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/stream/index.d.ts +8 -7
- package/dist/validation/index.d.ts +7 -4
- package/dist/validation/index.js +5 -3
- package/dist/viewmodel/index.d.ts +101 -13
- package/dist/viewmodel/index.js +90 -48
- package/dist/viewmodel/index.js.map +1 -1
- package/package.json +11 -3
- package/skills/lanka-core/SKILL.md +68 -1
- package/skills/lanka-core/reference.md +312 -6
- package/skills/lanka-packages/SKILL.md +1 -1
- package/dist/chunk-ECM2HZHS.js.map +0 -1
- package/dist/chunk-GV5DUYST.js +0 -64
- package/dist/chunk-GV5DUYST.js.map +0 -1
- package/dist/chunk-Q7QESSYF.js.map +0 -1
- package/dist/chunk-UGXSGQPW.js.map +0 -1
- /package/dist/{chunk-GK3E4CVW.js.map → chunk-5MAQVBI2.js.map} +0 -0
- /package/dist/{chunk-73IVH3C6.js.map → chunk-NDCJBO47.js.map} +0 -0
package/dist/validation/index.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
|
-
LankaValidationError,
|
|
3
2
|
lankaStandardValidator
|
|
4
|
-
} from "../chunk-
|
|
5
|
-
import
|
|
3
|
+
} from "../chunk-HVSQOMRE.js";
|
|
4
|
+
import {
|
|
5
|
+
LankaValidationError
|
|
6
|
+
} from "../chunk-CRIRTOLB.js";
|
|
7
|
+
import "../chunk-G32H73QY.js";
|
|
6
8
|
export {
|
|
7
9
|
LankaValidationError,
|
|
8
10
|
lankaStandardValidator
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { StoreApi, StateCreator, UseBoundStore } from 'zustand';
|
|
2
|
-
import { a as ILankaScenario, T as TLankaReplayRequest, I as ILankaScenarioVM } from '../ILankaScenarioVM-
|
|
2
|
+
import { a as ILankaScenario, T as TLankaReplayRequest, I as ILankaScenarioVM } from '../ILankaScenarioVM-DpKFL3iE.js';
|
|
3
3
|
import { A as ALankaSharedStore } from '../ALankaSharedStore-B7uepuuk.js';
|
|
4
4
|
import { StoreApi as StoreApi$1 } from 'zustand/vanilla';
|
|
5
5
|
|
|
@@ -45,6 +45,30 @@ interface ILankaScenarioBinding<TData, TState extends object, TGateways extends
|
|
|
45
45
|
|
|
46
46
|
type TUnknownLankaScenarioBinding<TState extends object, TGateways extends object, TServices extends object> = ILankaScenarioBinding<unknown, TState & ILankaScenarioVM, TGateways, TServices>;
|
|
47
47
|
|
|
48
|
+
/**
|
|
49
|
+
* Scenario bindings as a ViewModel declares them: the list, or a factory for it.
|
|
50
|
+
*
|
|
51
|
+
* The factory form exists for the same reason `TLankaDependencyBag` has one, and
|
|
52
|
+
* for a sharper case. A ViewModel declared at module level writes its bindings as
|
|
53
|
+
* an array literal, and each entry names its scenario — `lankaScenarios.<name>`,
|
|
54
|
+
* which is a LOCATOR read. Written directly, that read happens while the module
|
|
55
|
+
* is being evaluated, and a module body can run before `createLanka` has: then
|
|
56
|
+
* the locator refuses with "lanka used before an instance existed" and nothing
|
|
57
|
+
* renders.
|
|
58
|
+
*
|
|
59
|
+
* Import order is not a defence. It holds inside one chunk, and a bundler decides
|
|
60
|
+
* chunks — in ES modules the body of an imported chunk runs before the body of
|
|
61
|
+
* the chunk importing it, so an application that put its ViewModels in their own
|
|
62
|
+
* chunks evaluated them ahead of its own `createLanka` call. Measured in a real
|
|
63
|
+
* app: 44 application chunks were statically imported by the entry, and its whole
|
|
64
|
+
* browser-level suite died on the first of them.
|
|
65
|
+
*
|
|
66
|
+
* `gateways` and `services` already accept a factory for the identical reason.
|
|
67
|
+
* Bindings were the one field left out, and they are the field that reads the
|
|
68
|
+
* locator most.
|
|
69
|
+
*/
|
|
70
|
+
type TLankaScenarioBindingsDeclaration<TBinding> = readonly TBinding[] | (() => readonly TBinding[]);
|
|
71
|
+
|
|
48
72
|
type TLankaAnyMutators = any;
|
|
49
73
|
|
|
50
74
|
type TLankaVMEnhancer<TState> = (creator: StateCreator<TState, TLankaAnyMutators, TLankaAnyMutators>) => StateCreator<TState, TLankaAnyMutators, TLankaAnyMutators>;
|
|
@@ -59,7 +83,12 @@ interface ILankaVMConfig<State extends object, Actions extends object, TGateways
|
|
|
59
83
|
enableAccessTrackingOptimization?: boolean;
|
|
60
84
|
states?: State;
|
|
61
85
|
createActions: (ctx: ILankaVMContext<State & Actions & ILankaScenarioVM, TGateways, Services>) => Actions;
|
|
62
|
-
|
|
86
|
+
/**
|
|
87
|
+
* A FACTORY postpones building the list until bind time — see
|
|
88
|
+
* `TLankaScenarioBindingsDeclaration` for the module-scope locator read it
|
|
89
|
+
* exists to avoid.
|
|
90
|
+
*/
|
|
91
|
+
scenarioHandlers?: TLankaScenarioBindingsDeclaration<TUnknownLankaScenarioBinding<State & Actions, TGateways, Services>>;
|
|
63
92
|
/** Non-gateway services. */
|
|
64
93
|
services?: Services | (() => Services);
|
|
65
94
|
/** TGateways (data layer) separated from services. */
|
|
@@ -130,7 +159,8 @@ interface ILankaStatelessScenarioBinding<TData, TState extends object, TGateways
|
|
|
130
159
|
type TLankaStatelessVMConfig$1<Actions extends object, TGateways extends object = Record<string, never>, Services extends object = Record<string, never>> = {
|
|
131
160
|
name: string;
|
|
132
161
|
createActions: (ctx: ILankaStatelessVMContext<Actions & ILankaScenarioVM, TGateways, Services>) => Actions;
|
|
133
|
-
|
|
162
|
+
/** A FACTORY is read at bind time — see `TLankaScenarioBindingsDeclaration`. */
|
|
163
|
+
scenarioHandlers?: TLankaScenarioBindingsDeclaration<ILankaStatelessScenarioBinding<unknown, Actions & ILankaScenarioVM, TGateways, Services>>;
|
|
134
164
|
services?: Services | (() => Services);
|
|
135
165
|
gateways?: TGateways | (() => TGateways);
|
|
136
166
|
onInit?: (ctx: ILankaStatelessVMContext<Actions & ILankaScenarioVM, TGateways, Services>) => void;
|
|
@@ -193,7 +223,8 @@ interface ILankaSharedStoreVMConfig<TStoreState extends object, TActions extends
|
|
|
193
223
|
enableAccessTrackingOptimization?: boolean;
|
|
194
224
|
store: TStore;
|
|
195
225
|
createActions: (ctx: ILankaSharedStoreVMContext<TStoreState, TStoreState & TActions & ILankaScenarioVM, TStore, TGateways, TServices>) => TActions;
|
|
196
|
-
|
|
226
|
+
/** A FACTORY is read at bind time — see `TLankaScenarioBindingsDeclaration`. */
|
|
227
|
+
scenarioHandlers?: TLankaScenarioBindingsDeclaration<ILankaSharedStoreScenarioBinding<unknown, TStoreState, TActions, TStore, TGateways, TServices>>;
|
|
197
228
|
services?: TServices | (() => TServices);
|
|
198
229
|
gateways?: TGateways | (() => TGateways);
|
|
199
230
|
onInit?: (ctx: ILankaSharedStoreVMContext<TStoreState, TStoreState & TActions & ILankaScenarioVM, TStore, TGateways, TServices>) => void;
|
|
@@ -226,6 +257,19 @@ declare function createLazySharedStoreLankaVM<StoreState extends object, Actions
|
|
|
226
257
|
declare function createLazySharedStoreLankaVM<StoreState extends object, Actions extends object, Store extends ALankaSharedStore<StoreState>, TGateways extends object>(config: ILankaSharedStoreVMConfig<StoreState, Actions, Store, TGateways, Record<string, never>>): TLazySharedStoreReturn<StoreState, Actions, Store, TGateways, Record<string, never>>;
|
|
227
258
|
declare function createLazySharedStoreLankaVM<StoreState extends object, Actions extends object, Store extends ALankaSharedStore<StoreState>, TGateways extends object, Services extends object>(config: ILankaSharedStoreVMConfig<StoreState, Actions, Store, TGateways, Services>): TLazySharedStoreReturn<StoreState, Actions, Store, TGateways, Services>;
|
|
228
259
|
|
|
260
|
+
/**
|
|
261
|
+
* The lifecycle moments a ViewModel took, as the scenario binder receives them.
|
|
262
|
+
*
|
|
263
|
+
* A hook is present only when the ViewModel DECLARED it — overrode the method,
|
|
264
|
+
* or passed it in config. Bootstrap registers a ViewModel for the sake of these
|
|
265
|
+
* calls, so "declared" is what decides registration; a default no-op must not
|
|
266
|
+
* count, or every ViewModel would sit in the scenario registry for nothing.
|
|
267
|
+
*/
|
|
268
|
+
interface ILankaVMLifecycleHooks {
|
|
269
|
+
onInit?: () => void;
|
|
270
|
+
onReset?: () => void;
|
|
271
|
+
}
|
|
272
|
+
|
|
229
273
|
/**
|
|
230
274
|
* What every ViewModel is given, and the two moments it is told about.
|
|
231
275
|
*
|
|
@@ -250,10 +294,36 @@ declare abstract class ALankaVMEnvironment<TGateways extends object = Record<str
|
|
|
250
294
|
protected createGateways(): TGateways;
|
|
251
295
|
/** Non-gateway collaborators, built once per ViewModel. */
|
|
252
296
|
protected createServices(): Services;
|
|
253
|
-
/**
|
|
297
|
+
/**
|
|
298
|
+
* Runs once the scenarios are bound: inside `startLanka()` for a ViewModel built
|
|
299
|
+
* at module level, inside `build()` for one built after bootstrap — in both
|
|
300
|
+
* cases before any screen has read the hook the build returns.
|
|
301
|
+
*/
|
|
254
302
|
protected onInit(): void;
|
|
255
|
-
/**
|
|
303
|
+
/**
|
|
304
|
+
* Runs when the ViewModel is released — the framework instance disposed, or a
|
|
305
|
+
* lazy ViewModel's `dispose()` — after its scenario subscriptions are gone.
|
|
306
|
+
*/
|
|
256
307
|
protected onReset(): void;
|
|
308
|
+
/**
|
|
309
|
+
* The two moments above as the scenario binder receives them: present only
|
|
310
|
+
* where this ViewModel took them.
|
|
311
|
+
*
|
|
312
|
+
* Framework plumbing, not an extension point — a ViewModel overrides `onInit`
|
|
313
|
+
* and `onReset`, never this. Protected because the three bases call it, and
|
|
314
|
+
* named after `toStyleContext` for the same reason: a derived view of the
|
|
315
|
+
* protected surface, assembled by the framework.
|
|
316
|
+
*
|
|
317
|
+
* Why "took them" decides anything: `onInit` runs inside `initializeScenario`,
|
|
318
|
+
* which bootstrap alone calls, on the ViewModels registered with it.
|
|
319
|
+
* Registration used to follow scenario bindings only, so a ViewModel that
|
|
320
|
+
* overrode `onInit` and bound nothing was never initialised — silently. Now a
|
|
321
|
+
* declared hook registers the ViewModel too, and a default no-op must not
|
|
322
|
+
* count, or every ViewModel would sit in the scenario registry for nothing.
|
|
323
|
+
* The functional bridges declare theirs as own properties over these methods,
|
|
324
|
+
* which is what this comparison sees.
|
|
325
|
+
*/
|
|
326
|
+
protected toLifecycleHooks(): ILankaVMLifecycleHooks;
|
|
257
327
|
}
|
|
258
328
|
|
|
259
329
|
/**
|
|
@@ -269,7 +339,9 @@ declare abstract class ALankaVMEnvironment<TGateways extends object = Record<str
|
|
|
269
339
|
* value or a thunk, the class supplies by overriding a method of the same name —
|
|
270
340
|
* `states`, `scenarioHandlers`, `enhancers`, `onInit`, `onReset` — with the two
|
|
271
341
|
* dependency suppliers named `createGateways` and `createServices`, because
|
|
272
|
-
* `gateways` and `services` already name what they answer.
|
|
342
|
+
* `gateways` and `services` already name what they answer. `toLifecycleHooks`
|
|
343
|
+
* is protected too and is not one of these: it is how the framework reads the
|
|
344
|
+
* two hooks, and a ViewModel overrides the hooks, never it.
|
|
273
345
|
*
|
|
274
346
|
* ```ts
|
|
275
347
|
* class TodoVM extends ALankaVM<ITodoState, ITodoActions, ITodoGateways> {
|
|
@@ -321,8 +393,14 @@ declare abstract class ALankaVM<State extends object, Actions extends object, TG
|
|
|
321
393
|
protected trigger: <TData>(scenario: ILankaScenario<TData>, data?: TData) => void;
|
|
322
394
|
/** The reactive fields the screen reads. */
|
|
323
395
|
protected states(): State;
|
|
324
|
-
/**
|
|
325
|
-
|
|
396
|
+
/**
|
|
397
|
+
* The scenarios this ViewModel listens to, unsubscribed for it on reset.
|
|
398
|
+
*
|
|
399
|
+
* Returning a FACTORY postpones building the list until bind time, which is
|
|
400
|
+
* what a ViewModel declared at module level needs when its entries name their
|
|
401
|
+
* scenarios through the locator. See `TLankaScenarioBindingsDeclaration`.
|
|
402
|
+
*/
|
|
403
|
+
protected scenarioHandlers(): TLankaScenarioBindingsDeclaration<TUnknownLankaScenarioBinding<State & Actions, TGateways, Services>>;
|
|
326
404
|
/** Store middleware — `persist`, `lankaDevtools` — the last one applied outermost. */
|
|
327
405
|
protected enhancers(): TLankaVMEnhancer<State & Actions & ILankaScenarioVM>[];
|
|
328
406
|
/** The actions the screen calls. Written against `this.set` and `this.get`. */
|
|
@@ -352,6 +430,9 @@ declare abstract class ALankaVM<State extends object, Actions extends object, TG
|
|
|
352
430
|
* or a thunk, the class supplies by overriding a method of the same name, with
|
|
353
431
|
* the two dependency suppliers named `createGateways` and `createServices`
|
|
354
432
|
* because `gateways` and `services` already name what they answer.
|
|
433
|
+
* `toLifecycleHooks` is protected too and is not one of these: it is how the
|
|
434
|
+
* framework reads `onInit` and `onReset`, and a ViewModel overrides those,
|
|
435
|
+
* never it.
|
|
355
436
|
*
|
|
356
437
|
* ```ts
|
|
357
438
|
* class SessionVM extends ALankaStatelessVM<ISessionActions, ISessionGateways> {
|
|
@@ -385,8 +466,13 @@ declare abstract class ALankaStatelessVM<Actions extends object, TGateways exten
|
|
|
385
466
|
protected get: () => Actions & ILankaScenarioVM;
|
|
386
467
|
/** Fires a scenario, which every ViewModel bound to it then hears. */
|
|
387
468
|
protected trigger: <TData>(scenario: ILankaScenario<TData>, data?: TData) => void;
|
|
388
|
-
/**
|
|
389
|
-
|
|
469
|
+
/**
|
|
470
|
+
* The scenarios this ViewModel listens to, unsubscribed for it on reset.
|
|
471
|
+
*
|
|
472
|
+
* Returning a FACTORY postpones building the list until bind time. See
|
|
473
|
+
* `TLankaScenarioBindingsDeclaration`.
|
|
474
|
+
*/
|
|
475
|
+
protected scenarioHandlers(): TLankaScenarioBindingsDeclaration<ILankaStatelessScenarioBinding<unknown, Actions & ILankaScenarioVM, TGateways, Services>>;
|
|
390
476
|
/** The actions the screen calls. Written against `this.set` and `this.get`. */
|
|
391
477
|
protected abstract createActions(): Actions;
|
|
392
478
|
/**
|
|
@@ -427,7 +513,9 @@ declare abstract class ALankaStatelessVM<Actions extends object, TGateways exten
|
|
|
427
513
|
* implementation: the store, the tracked hook and the two memoised state
|
|
428
514
|
* references are the factory's, and duplicating them here would be the second
|
|
429
515
|
* implementation the parity canon exists to prevent. What it gives a class-style
|
|
430
|
-
* consumer is the same protected surface under the same names
|
|
516
|
+
* consumer is the same protected surface under the same names — plus
|
|
517
|
+
* `toLifecycleHooks`, the framework's reading of `onInit`/`onReset`, which is
|
|
518
|
+
* not an extension point.
|
|
431
519
|
*
|
|
432
520
|
* Canon: `skills/parity/SKILL.md`.
|
|
433
521
|
*/
|
|
@@ -451,7 +539,7 @@ declare abstract class ALankaSharedStoreVM<StoreState extends object, Actions ex
|
|
|
451
539
|
*/
|
|
452
540
|
protected readonly enableAccessTrackingOptimization: boolean;
|
|
453
541
|
/** The scenarios this ViewModel listens to, unsubscribed for it on reset. */
|
|
454
|
-
protected scenarioHandlers(): ILankaSharedStoreScenarioBinding<unknown, StoreState, Actions, Store, TGateways, Services
|
|
542
|
+
protected scenarioHandlers(): TLankaScenarioBindingsDeclaration<ILankaSharedStoreScenarioBinding<unknown, StoreState, Actions, Store, TGateways, Services>>;
|
|
455
543
|
/** The actions the screen calls. Written against `this.set` and `this.get`. */
|
|
456
544
|
protected abstract createActions(): Actions;
|
|
457
545
|
/** Builds the hook a screen calls. One ViewModel per call. */
|
package/dist/viewmodel/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import {
|
|
3
3
|
lankaScenarioBootstrap
|
|
4
|
-
} from "../chunk-
|
|
4
|
+
} from "../chunk-B7EYIAW7.js";
|
|
5
5
|
import "../chunk-O5ROO7QF.js";
|
|
6
6
|
import {
|
|
7
7
|
lankaLogger
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
import "../chunk-BGVDPDX4.js";
|
|
13
13
|
|
|
14
14
|
// src/viewmodel/_abstractions/lanka-vm-environment/ALankaVMEnvironment.ts
|
|
15
|
-
var ALankaVMEnvironment = class {
|
|
15
|
+
var ALankaVMEnvironment = class _ALankaVMEnvironment {
|
|
16
16
|
/** What `createGateways` answered: the data layer, kept apart from services. */
|
|
17
17
|
gateways;
|
|
18
18
|
/** What `createServices` answered: everything that is not a gateway. */
|
|
@@ -25,12 +25,44 @@ var ALankaVMEnvironment = class {
|
|
|
25
25
|
createServices() {
|
|
26
26
|
return {};
|
|
27
27
|
}
|
|
28
|
-
/**
|
|
28
|
+
/**
|
|
29
|
+
* Runs once the scenarios are bound: inside `startLanka()` for a ViewModel built
|
|
30
|
+
* at module level, inside `build()` for one built after bootstrap — in both
|
|
31
|
+
* cases before any screen has read the hook the build returns.
|
|
32
|
+
*/
|
|
29
33
|
onInit() {
|
|
30
34
|
}
|
|
31
|
-
/**
|
|
35
|
+
/**
|
|
36
|
+
* Runs when the ViewModel is released — the framework instance disposed, or a
|
|
37
|
+
* lazy ViewModel's `dispose()` — after its scenario subscriptions are gone.
|
|
38
|
+
*/
|
|
32
39
|
onReset() {
|
|
33
40
|
}
|
|
41
|
+
/**
|
|
42
|
+
* The two moments above as the scenario binder receives them: present only
|
|
43
|
+
* where this ViewModel took them.
|
|
44
|
+
*
|
|
45
|
+
* Framework plumbing, not an extension point — a ViewModel overrides `onInit`
|
|
46
|
+
* and `onReset`, never this. Protected because the three bases call it, and
|
|
47
|
+
* named after `toStyleContext` for the same reason: a derived view of the
|
|
48
|
+
* protected surface, assembled by the framework.
|
|
49
|
+
*
|
|
50
|
+
* Why "took them" decides anything: `onInit` runs inside `initializeScenario`,
|
|
51
|
+
* which bootstrap alone calls, on the ViewModels registered with it.
|
|
52
|
+
* Registration used to follow scenario bindings only, so a ViewModel that
|
|
53
|
+
* overrode `onInit` and bound nothing was never initialised — silently. Now a
|
|
54
|
+
* declared hook registers the ViewModel too, and a default no-op must not
|
|
55
|
+
* count, or every ViewModel would sit in the scenario registry for nothing.
|
|
56
|
+
* The functional bridges declare theirs as own properties over these methods,
|
|
57
|
+
* which is what this comparison sees.
|
|
58
|
+
*/
|
|
59
|
+
toLifecycleHooks() {
|
|
60
|
+
const defaults = _ALankaVMEnvironment.prototype;
|
|
61
|
+
const hooks = {};
|
|
62
|
+
if (this.onInit !== defaults.onInit) hooks.onInit = () => this.onInit();
|
|
63
|
+
if (this.onReset !== defaults.onReset) hooks.onReset = () => this.onReset();
|
|
64
|
+
return hooks;
|
|
65
|
+
}
|
|
34
66
|
};
|
|
35
67
|
|
|
36
68
|
// src/viewmodel/_abstractions/lanka-vm/ALankaVM.ts
|
|
@@ -105,17 +137,20 @@ var createLankaBlindSpotTrap = (viewModelName, isArmed) => {
|
|
|
105
137
|
};
|
|
106
138
|
|
|
107
139
|
// src/viewmodel/_internal/create-lanka-scenario-binder/createLankaScenarioBinder.ts
|
|
140
|
+
var readBindings = (declared) => typeof declared === "function" ? declared() : declared ?? [];
|
|
141
|
+
var needsBootstrap = (config) => typeof config.bindings === "function" || config.bindings !== void 0 && config.bindings.length > 0 || config.onInit !== void 0 || config.onReset !== void 0;
|
|
108
142
|
var createLankaScenarioBinder = (config) => {
|
|
109
143
|
const subscriptions = /* @__PURE__ */ new Map();
|
|
110
144
|
let isInitialized = false;
|
|
111
145
|
return {
|
|
146
|
+
needsBootstrap: needsBootstrap(config),
|
|
112
147
|
get isInitialized() {
|
|
113
148
|
return isInitialized;
|
|
114
149
|
},
|
|
115
150
|
initializeScenario() {
|
|
116
151
|
if (isInitialized) return;
|
|
117
152
|
const context = config.context();
|
|
118
|
-
for (const binding of config.bindings
|
|
153
|
+
for (const binding of readBindings(config.bindings)) {
|
|
119
154
|
const key = binding.scenario.eventType;
|
|
120
155
|
if (subscriptions.has(key)) continue;
|
|
121
156
|
subscriptions.set(
|
|
@@ -221,7 +256,13 @@ var ALankaVM = class extends ALankaVMEnvironment {
|
|
|
221
256
|
states() {
|
|
222
257
|
return {};
|
|
223
258
|
}
|
|
224
|
-
/**
|
|
259
|
+
/**
|
|
260
|
+
* The scenarios this ViewModel listens to, unsubscribed for it on reset.
|
|
261
|
+
*
|
|
262
|
+
* Returning a FACTORY postpones building the list until bind time, which is
|
|
263
|
+
* what a ViewModel declared at module level needs when its entries name their
|
|
264
|
+
* scenarios through the locator. See `TLankaScenarioBindingsDeclaration`.
|
|
265
|
+
*/
|
|
225
266
|
scenarioHandlers() {
|
|
226
267
|
return [];
|
|
227
268
|
}
|
|
@@ -252,24 +293,20 @@ var ALankaVM = class extends ALankaVMEnvironment {
|
|
|
252
293
|
this.name,
|
|
253
294
|
getLankaFlags().isDevelopment === true
|
|
254
295
|
);
|
|
255
|
-
const
|
|
296
|
+
const hooks = this.toLifecycleHooks();
|
|
297
|
+
const { initializeScenario, resetScenario, needsBootstrap: needsBootstrap2 } = createLankaScenarioBinder({
|
|
298
|
+
name: this.name,
|
|
299
|
+
bindings: this.scenarioHandlers(),
|
|
300
|
+
context: () => this.toStyleContext(),
|
|
301
|
+
onInit: hooks.onInit,
|
|
302
|
+
onReset: hooks.onReset
|
|
303
|
+
});
|
|
256
304
|
const stateCreator = (set, get) => {
|
|
257
305
|
this.set = set;
|
|
258
306
|
this.get = blindSpot.observeGet(get);
|
|
259
307
|
this.gateways = this.createGateways();
|
|
260
308
|
this.services = this.createServices();
|
|
261
309
|
const actions = blindSpot.observeActions(this.createActions());
|
|
262
|
-
const { initializeScenario, resetScenario } = createLankaScenarioBinder({
|
|
263
|
-
name: this.name,
|
|
264
|
-
bindings,
|
|
265
|
-
context: () => this.toStyleContext(),
|
|
266
|
-
onInit: () => {
|
|
267
|
-
this.onInit();
|
|
268
|
-
},
|
|
269
|
-
onReset: () => {
|
|
270
|
-
this.onReset();
|
|
271
|
-
}
|
|
272
|
-
});
|
|
273
310
|
return {
|
|
274
311
|
...this.states(),
|
|
275
312
|
...actions,
|
|
@@ -283,7 +320,7 @@ var ALankaVM = class extends ALankaVMEnvironment {
|
|
|
283
320
|
);
|
|
284
321
|
const store = create()(enhancedCreator);
|
|
285
322
|
const registerScenarioViewModel = (viewModel) => {
|
|
286
|
-
if (
|
|
323
|
+
if (needsBootstrap2) {
|
|
287
324
|
lankaScenarioBootstrap.registerViewModel(viewModel, this.name);
|
|
288
325
|
}
|
|
289
326
|
};
|
|
@@ -336,11 +373,16 @@ function createLankaVM(config) {
|
|
|
336
373
|
createActions() {
|
|
337
374
|
return config.createActions(this.toStyleContext());
|
|
338
375
|
}
|
|
339
|
-
onInit
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
376
|
+
// The config's hooks become this instance's OWN `onInit`/`onReset`, assigned
|
|
377
|
+
// only when declared. An unconditional method override would make the base
|
|
378
|
+
// read every functional ViewModel as taking both hooks and register it with
|
|
379
|
+
// bootstrap for nothing; an own property is seen by the same test a class
|
|
380
|
+
// override is, and `this.onInit()` means the same thing in both styles.
|
|
381
|
+
constructor() {
|
|
382
|
+
super();
|
|
383
|
+
const { onInit, onReset } = config;
|
|
384
|
+
if (onInit) this.onInit = () => onInit(this.toStyleContext());
|
|
385
|
+
if (onReset) this.onReset = () => onReset(this.toStyleContext());
|
|
344
386
|
}
|
|
345
387
|
}
|
|
346
388
|
return new FunctionalVM().build();
|
|
@@ -417,7 +459,12 @@ var ALankaStatelessVM = class extends ALankaVMEnvironment {
|
|
|
417
459
|
trigger = (scenario, data) => {
|
|
418
460
|
scenario.trigger(data);
|
|
419
461
|
};
|
|
420
|
-
/**
|
|
462
|
+
/**
|
|
463
|
+
* The scenarios this ViewModel listens to, unsubscribed for it on reset.
|
|
464
|
+
*
|
|
465
|
+
* Returning a FACTORY postpones building the list until bind time. See
|
|
466
|
+
* `TLankaScenarioBindingsDeclaration`.
|
|
467
|
+
*/
|
|
421
468
|
scenarioHandlers() {
|
|
422
469
|
return [];
|
|
423
470
|
}
|
|
@@ -448,20 +495,16 @@ var ALankaStatelessVM = class extends ALankaVMEnvironment {
|
|
|
448
495
|
this.gateways = this.createGateways();
|
|
449
496
|
this.services = this.createServices();
|
|
450
497
|
const actions = this.createActions();
|
|
451
|
-
const
|
|
452
|
-
const { initializeScenario, resetScenario } = createLankaScenarioBinder({
|
|
498
|
+
const hooks = this.toLifecycleHooks();
|
|
499
|
+
const { initializeScenario, resetScenario, needsBootstrap: needsBootstrap2 } = createLankaScenarioBinder({
|
|
453
500
|
name: this.name,
|
|
454
|
-
bindings,
|
|
501
|
+
bindings: this.scenarioHandlers(),
|
|
455
502
|
context: () => this.toStyleContext(),
|
|
456
|
-
onInit:
|
|
457
|
-
|
|
458
|
-
},
|
|
459
|
-
onReset: () => {
|
|
460
|
-
this.onReset();
|
|
461
|
-
}
|
|
503
|
+
onInit: hooks.onInit,
|
|
504
|
+
onReset: hooks.onReset
|
|
462
505
|
});
|
|
463
506
|
state = { ...state, ...actions, initializeScenario, resetScenario };
|
|
464
|
-
if (
|
|
507
|
+
if (needsBootstrap2) {
|
|
465
508
|
lankaScenarioBootstrap.registerViewModel(state, this.name);
|
|
466
509
|
}
|
|
467
510
|
const useStatelessViewModel = ((selector) => selector ? selector(state) : state);
|
|
@@ -487,11 +530,13 @@ function createStatelessLankaVM(config) {
|
|
|
487
530
|
createActions() {
|
|
488
531
|
return config.createActions(this.toStyleContext());
|
|
489
532
|
}
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
config
|
|
533
|
+
// Own properties, assigned only when declared — see the same constructor in
|
|
534
|
+
// `createLankaVM` for why not a method override.
|
|
535
|
+
constructor() {
|
|
536
|
+
super();
|
|
537
|
+
const { onInit, onReset } = config;
|
|
538
|
+
if (onInit) this.onInit = () => onInit(this.toStyleContext());
|
|
539
|
+
if (onReset) this.onReset = () => onReset(this.toStyleContext());
|
|
495
540
|
}
|
|
496
541
|
}
|
|
497
542
|
return new FunctionalStatelessVM().build();
|
|
@@ -538,7 +583,7 @@ function createSharedStoreLankaVM(config) {
|
|
|
538
583
|
services,
|
|
539
584
|
trigger: (scenario, data) => scenario.trigger(data)
|
|
540
585
|
};
|
|
541
|
-
const { initializeScenario, resetScenario } = createLankaScenarioBinder({
|
|
586
|
+
const { initializeScenario, resetScenario, needsBootstrap: needsBootstrap2 } = createLankaScenarioBinder({
|
|
542
587
|
name: config.name,
|
|
543
588
|
bindings: config.scenarioHandlers,
|
|
544
589
|
context: () => ctx,
|
|
@@ -565,7 +610,7 @@ function createSharedStoreLankaVM(config) {
|
|
|
565
610
|
const useSharedStoreViewModel = isAccessTrackingEnabled ? useTrackedSharedStoreViewModel : useUntrackedSharedStoreViewModel;
|
|
566
611
|
useSharedStoreViewModel.getState = () => getFullState();
|
|
567
612
|
useSharedStoreViewModel.getStoreState = () => config.store.getState();
|
|
568
|
-
if (
|
|
613
|
+
if (needsBootstrap2) {
|
|
569
614
|
const scenarioViewModel = {
|
|
570
615
|
initializeScenario,
|
|
571
616
|
resetScenario
|
|
@@ -612,6 +657,7 @@ var ALankaSharedStoreVM = class extends ALankaVMEnvironment {
|
|
|
612
657
|
}
|
|
613
658
|
/** Builds the hook a screen calls. One ViewModel per call. */
|
|
614
659
|
build() {
|
|
660
|
+
const hooks = this.toLifecycleHooks();
|
|
615
661
|
return createSharedStoreLankaVM({
|
|
616
662
|
name: this.name,
|
|
617
663
|
store: this.store,
|
|
@@ -628,12 +674,8 @@ var ALankaSharedStoreVM = class extends ALankaVMEnvironment {
|
|
|
628
674
|
this.trigger = context.trigger;
|
|
629
675
|
return this.createActions();
|
|
630
676
|
},
|
|
631
|
-
onInit:
|
|
632
|
-
|
|
633
|
-
},
|
|
634
|
-
onReset: () => {
|
|
635
|
-
this.onReset();
|
|
636
|
-
}
|
|
677
|
+
onInit: hooks.onInit,
|
|
678
|
+
onReset: hooks.onReset
|
|
637
679
|
});
|
|
638
680
|
}
|
|
639
681
|
};
|