lanka 1.2.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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/ILankaReadableVM-BoPzHEPV.d.ts +72 -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-Dki2Es3O.d.ts} +5 -5
- package/dist/{LankaSharedStoreLocator-zS2kLu-S.d.ts → LankaSharedStoreLocator-jsz_gnUm.d.ts} +1 -1
- package/dist/_extend/index.d.ts +233 -9
- package/dist/_extend/index.js +137 -8
- package/dist/_extend/index.js.map +1 -1
- package/dist/_internal/index.d.ts +62 -9
- package/dist/_internal/index.js +34 -3
- package/dist/_internal/index.js.map +1 -1
- package/dist/{activeRuntime-B336NU5I.d.ts → activeRuntime-BO-qY0yY.d.ts} +51 -4
- package/dist/bootstrap/index.d.ts +11 -10
- package/dist/bootstrap/index.js +7 -8
- 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-D27MREPB.js → chunk-7DQUF2QR.js} +2 -2
- package/dist/{chunk-UJEC7H6K.js → chunk-BHQ2SQ7P.js} +2 -2
- package/dist/chunk-CRIRTOLB.js +27 -0
- package/dist/chunk-CRIRTOLB.js.map +1 -0
- package/dist/chunk-EYDMBI5T.js +550 -0
- package/dist/chunk-EYDMBI5T.js.map +1 -0
- package/dist/{chunk-C2HP7CRD.js → chunk-FII3PW2G.js} +2 -2
- package/dist/{chunk-Q7QESSYF.js → chunk-G32H73QY.js} +10 -1
- package/dist/chunk-G32H73QY.js.map +1 -0
- package/dist/{chunk-DTO27QFR.js → chunk-H5TIUKRK.js} +2 -2
- package/dist/chunk-HVSQOMRE.js +69 -0
- package/dist/chunk-HVSQOMRE.js.map +1 -0
- package/dist/{chunk-73IVH3C6.js → chunk-O5EUTNR6.js} +3 -3
- package/dist/{chunk-RKYKK6MN.js → chunk-RUMUFHSL.js} +2 -2
- package/dist/{chunk-G3I7QIZR.js → chunk-SZVNPK24.js} +21 -14
- package/dist/chunk-SZVNPK24.js.map +1 -0
- package/dist/chunk-UDP6IXDS.js +17 -0
- package/dist/chunk-UDP6IXDS.js.map +1 -0
- package/dist/{chunk-5MAQVBI2.js → chunk-UMPSR4US.js} +3 -3
- package/dist/{chunk-BGVDPDX4.js → chunk-XGMXT4XZ.js} +20 -3
- package/dist/chunk-XGMXT4XZ.js.map +1 -0
- package/dist/config/index.js +3 -3
- package/dist/{createLanka-DI1CSy2Q.d.ts → createLanka-x4oSMs7P.d.ts} +2 -2
- package/dist/{createLankaScope-BiFxNQgl.d.ts → createLankaScope-DomNbEvb.d.ts} +1 -1
- package/dist/errors/index.d.ts +22 -3
- package/dist/errors/index.js +10 -5
- package/dist/errors/index.js.map +1 -1
- package/dist/gateway/index.d.ts +4 -3
- package/dist/gateway/index.js +9 -8
- package/dist/gateway/index.js.map +1 -1
- package/dist/index.d.ts +11 -10
- package/dist/index.js +9 -10
- package/dist/{lankaStandardValidator-CL-r-zEV.d.ts → lankaStandardValidator-BUFnysK0.d.ts} +10 -0
- package/dist/locator/index.d.ts +5 -4
- package/dist/locator/index.js +2 -2
- package/dist/logger/index.js +3 -3
- package/dist/mock/index.js +3 -3
- package/dist/scenario/index.d.ts +81 -6
- package/dist/scenario/index.js +6 -8
- package/dist/scenario/index.js.map +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 +10 -9
- package/dist/validation/index.d.ts +7 -4
- package/dist/validation/index.js +5 -3
- package/dist/viewmodel/index.d.ts +188 -32
- package/dist/viewmodel/index.js +167 -171
- package/dist/viewmodel/index.js.map +1 -1
- package/package.json +11 -4
- package/skills/lanka-core/SKILL.md +70 -10
- package/skills/lanka-core/reference.md +417 -34
- package/skills/lanka-packages/SKILL.md +94 -22
- package/dist/chunk-BGVDPDX4.js.map +0 -1
- package/dist/chunk-G3I7QIZR.js.map +0 -1
- package/dist/chunk-GV5DUYST.js +0 -64
- package/dist/chunk-GV5DUYST.js.map +0 -1
- package/dist/chunk-O5ROO7QF.js +0 -315
- package/dist/chunk-O5ROO7QF.js.map +0 -1
- package/dist/chunk-Q7QESSYF.js.map +0 -1
- package/dist/chunk-UGXSGQPW.js +0 -180
- package/dist/chunk-UGXSGQPW.js.map +0 -1
- /package/dist/{chunk-D27MREPB.js.map → chunk-7DQUF2QR.js.map} +0 -0
- /package/dist/{chunk-UJEC7H6K.js.map → chunk-BHQ2SQ7P.js.map} +0 -0
- /package/dist/{chunk-C2HP7CRD.js.map → chunk-FII3PW2G.js.map} +0 -0
- /package/dist/{chunk-DTO27QFR.js.map → chunk-H5TIUKRK.js.map} +0 -0
- /package/dist/{chunk-73IVH3C6.js.map → chunk-O5EUTNR6.js.map} +0 -0
- /package/dist/{chunk-RKYKK6MN.js.map → chunk-RUMUFHSL.js.map} +0 -0
- /package/dist/{chunk-5MAQVBI2.js.map → chunk-UMPSR4US.js.map} +0 -0
package/dist/viewmodel/index.js
CHANGED
|
@@ -1,18 +1,19 @@
|
|
|
1
|
-
|
|
1
|
+
import {
|
|
2
|
+
lankaBlindSpotRegistry
|
|
3
|
+
} from "../chunk-UDP6IXDS.js";
|
|
2
4
|
import {
|
|
3
5
|
lankaScenarioBootstrap
|
|
4
|
-
} from "../chunk-
|
|
5
|
-
import "../chunk-O5ROO7QF.js";
|
|
6
|
+
} from "../chunk-EYDMBI5T.js";
|
|
6
7
|
import {
|
|
7
8
|
lankaLogger
|
|
8
|
-
} from "../chunk-
|
|
9
|
+
} from "../chunk-FII3PW2G.js";
|
|
9
10
|
import {
|
|
10
11
|
getLankaFlags
|
|
11
|
-
} from "../chunk-
|
|
12
|
-
import "../chunk-
|
|
12
|
+
} from "../chunk-7DQUF2QR.js";
|
|
13
|
+
import "../chunk-XGMXT4XZ.js";
|
|
13
14
|
|
|
14
15
|
// src/viewmodel/_abstractions/lanka-vm-environment/ALankaVMEnvironment.ts
|
|
15
|
-
var ALankaVMEnvironment = class {
|
|
16
|
+
var ALankaVMEnvironment = class _ALankaVMEnvironment {
|
|
16
17
|
/** What `createGateways` answered: the data layer, kept apart from services. */
|
|
17
18
|
gateways;
|
|
18
19
|
/** What `createServices` answered: everything that is not a gateway. */
|
|
@@ -25,16 +26,48 @@ var ALankaVMEnvironment = class {
|
|
|
25
26
|
createServices() {
|
|
26
27
|
return {};
|
|
27
28
|
}
|
|
28
|
-
/**
|
|
29
|
+
/**
|
|
30
|
+
* Runs once the scenarios are bound: inside `startLanka()` for a ViewModel built
|
|
31
|
+
* at module level, inside `build()` for one built after bootstrap — in both
|
|
32
|
+
* cases before any screen has read the hook the build returns.
|
|
33
|
+
*/
|
|
29
34
|
onInit() {
|
|
30
35
|
}
|
|
31
|
-
/**
|
|
36
|
+
/**
|
|
37
|
+
* Runs when the ViewModel is released — the framework instance disposed, or a
|
|
38
|
+
* lazy ViewModel's `dispose()` — after its scenario subscriptions are gone.
|
|
39
|
+
*/
|
|
32
40
|
onReset() {
|
|
33
41
|
}
|
|
42
|
+
/**
|
|
43
|
+
* The two moments above as the scenario binder receives them: present only
|
|
44
|
+
* where this ViewModel took them.
|
|
45
|
+
*
|
|
46
|
+
* Framework plumbing, not an extension point — a ViewModel overrides `onInit`
|
|
47
|
+
* and `onReset`, never this. Protected because the three bases call it, and
|
|
48
|
+
* named after `toStyleContext` for the same reason: a derived view of the
|
|
49
|
+
* protected surface, assembled by the framework.
|
|
50
|
+
*
|
|
51
|
+
* Why "took them" decides anything: `onInit` runs inside `initializeScenario`,
|
|
52
|
+
* which bootstrap alone calls, on the ViewModels registered with it.
|
|
53
|
+
* Registration used to follow scenario bindings only, so a ViewModel that
|
|
54
|
+
* overrode `onInit` and bound nothing was never initialised — silently. Now a
|
|
55
|
+
* declared hook registers the ViewModel too, and a default no-op must not
|
|
56
|
+
* count, or every ViewModel would sit in the scenario registry for nothing.
|
|
57
|
+
* The functional bridges declare theirs as own properties over these methods,
|
|
58
|
+
* which is what this comparison sees.
|
|
59
|
+
*/
|
|
60
|
+
toLifecycleHooks() {
|
|
61
|
+
const defaults = _ALankaVMEnvironment.prototype;
|
|
62
|
+
const hooks = {};
|
|
63
|
+
if (this.onInit !== defaults.onInit) hooks.onInit = () => this.onInit();
|
|
64
|
+
if (this.onReset !== defaults.onReset) hooks.onReset = () => this.onReset();
|
|
65
|
+
return hooks;
|
|
66
|
+
}
|
|
34
67
|
};
|
|
35
68
|
|
|
36
69
|
// src/viewmodel/_abstractions/lanka-vm/ALankaVM.ts
|
|
37
|
-
import {
|
|
70
|
+
import { createStore } from "zustand/vanilla";
|
|
38
71
|
|
|
39
72
|
// src/viewmodel/_internal/create-lanka-blind-spot-trap/createLankaBlindSpotTrap.ts
|
|
40
73
|
var createLankaBlindSpotTrap = (viewModelName, isArmed) => {
|
|
@@ -106,10 +139,12 @@ var createLankaBlindSpotTrap = (viewModelName, isArmed) => {
|
|
|
106
139
|
|
|
107
140
|
// src/viewmodel/_internal/create-lanka-scenario-binder/createLankaScenarioBinder.ts
|
|
108
141
|
var readBindings = (declared) => typeof declared === "function" ? declared() : declared ?? [];
|
|
142
|
+
var needsBootstrap = (config) => typeof config.bindings === "function" || config.bindings !== void 0 && config.bindings.length > 0 || config.onInit !== void 0 || config.onReset !== void 0;
|
|
109
143
|
var createLankaScenarioBinder = (config) => {
|
|
110
144
|
const subscriptions = /* @__PURE__ */ new Map();
|
|
111
145
|
let isInitialized = false;
|
|
112
146
|
return {
|
|
147
|
+
needsBootstrap: needsBootstrap(config),
|
|
113
148
|
get isInitialized() {
|
|
114
149
|
return isInitialized;
|
|
115
150
|
},
|
|
@@ -139,69 +174,6 @@ var createLankaScenarioBinder = (config) => {
|
|
|
139
174
|
};
|
|
140
175
|
};
|
|
141
176
|
|
|
142
|
-
// src/viewmodel/_internal/create-lanka-tracked-hook/createLankaTrackedHook.ts
|
|
143
|
-
import { useCallback, useRef, useSyncExternalStore } from "react";
|
|
144
|
-
var asRecord = (state) => state;
|
|
145
|
-
var createLankaTrackedHook = (config) => {
|
|
146
|
-
return (selector) => {
|
|
147
|
-
const selectorRef = useRef(selector);
|
|
148
|
-
selectorRef.current = selector;
|
|
149
|
-
const trackedKeysRef = useRef(/* @__PURE__ */ new Set());
|
|
150
|
-
const trackedStateRef = useRef(null);
|
|
151
|
-
const trackedProxyRef = useRef(null);
|
|
152
|
-
const subscribe = useCallback(
|
|
153
|
-
(onStoreChange) => config.subscribe((nextState, prevState) => {
|
|
154
|
-
if (selectorRef.current) {
|
|
155
|
-
onStoreChange();
|
|
156
|
-
return;
|
|
157
|
-
}
|
|
158
|
-
const trackedKeys = trackedKeysRef.current;
|
|
159
|
-
if (trackedKeys.size === 0) {
|
|
160
|
-
onStoreChange();
|
|
161
|
-
return;
|
|
162
|
-
}
|
|
163
|
-
const next = asRecord(nextState);
|
|
164
|
-
const prev = asRecord(prevState);
|
|
165
|
-
for (const key of trackedKeys) {
|
|
166
|
-
if (!Object.is(next[key], prev[key])) {
|
|
167
|
-
onStoreChange();
|
|
168
|
-
return;
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
config.onUntrackedChange?.(trackedKeys, next, prev);
|
|
172
|
-
}),
|
|
173
|
-
[]
|
|
174
|
-
);
|
|
175
|
-
return useSyncExternalStore(subscribe, readTracked, readUntracked);
|
|
176
|
-
function readTracked() {
|
|
177
|
-
const state = config.readState();
|
|
178
|
-
const activeSelector = selectorRef.current;
|
|
179
|
-
if (activeSelector) return activeSelector(state);
|
|
180
|
-
if (trackedStateRef.current === state && trackedProxyRef.current) {
|
|
181
|
-
return trackedProxyRef.current;
|
|
182
|
-
}
|
|
183
|
-
const trackedKeys = /* @__PURE__ */ new Set();
|
|
184
|
-
const proxyState = new Proxy(state, {
|
|
185
|
-
get(target, prop, receiver) {
|
|
186
|
-
if (typeof prop === "string") {
|
|
187
|
-
trackedKeys.add(prop);
|
|
188
|
-
}
|
|
189
|
-
return Reflect.get(target, prop, receiver);
|
|
190
|
-
}
|
|
191
|
-
});
|
|
192
|
-
trackedKeysRef.current = trackedKeys;
|
|
193
|
-
trackedStateRef.current = state;
|
|
194
|
-
trackedProxyRef.current = proxyState;
|
|
195
|
-
return proxyState;
|
|
196
|
-
}
|
|
197
|
-
function readUntracked() {
|
|
198
|
-
const state = config.readState();
|
|
199
|
-
const activeSelector = selectorRef.current;
|
|
200
|
-
return activeSelector ? activeSelector(state) : state;
|
|
201
|
-
}
|
|
202
|
-
};
|
|
203
|
-
};
|
|
204
|
-
|
|
205
177
|
// src/viewmodel/_abstractions/lanka-vm/ALankaVM.ts
|
|
206
178
|
var ALankaVM = class extends ALankaVMEnvironment {
|
|
207
179
|
/**
|
|
@@ -252,32 +224,35 @@ var ALankaVM = class extends ALankaVMEnvironment {
|
|
|
252
224
|
trigger: this.trigger
|
|
253
225
|
};
|
|
254
226
|
}
|
|
255
|
-
/**
|
|
227
|
+
/**
|
|
228
|
+
* Builds the ViewModel a screen reads. One store per call.
|
|
229
|
+
*
|
|
230
|
+
* What comes back is a STORE, not a hook: `getState`, `subscribe`, `setState`,
|
|
231
|
+
* plus the name and the tracking flag. A screen reaches it through its
|
|
232
|
+
* framework's binding — `useLankaVM(todoVM)` from `@lankajs/react`,
|
|
233
|
+
* `@lankajs/vue` and the rest of the shelf — and a program with no framework
|
|
234
|
+
* at all reads `getState()` and `subscribe()` directly.
|
|
235
|
+
*/
|
|
256
236
|
build() {
|
|
257
237
|
lankaLogger.printViewModelLog("START Create VM", this.name);
|
|
258
238
|
const blindSpot = createLankaBlindSpotTrap(
|
|
259
239
|
this.name,
|
|
260
240
|
getLankaFlags().isDevelopment === true
|
|
261
241
|
);
|
|
262
|
-
const
|
|
263
|
-
const
|
|
242
|
+
const hooks = this.toLifecycleHooks();
|
|
243
|
+
const { initializeScenario, resetScenario, needsBootstrap: needsBootstrap2 } = createLankaScenarioBinder({
|
|
244
|
+
name: this.name,
|
|
245
|
+
bindings: this.scenarioHandlers(),
|
|
246
|
+
context: () => this.toStyleContext(),
|
|
247
|
+
onInit: hooks.onInit,
|
|
248
|
+
onReset: hooks.onReset
|
|
249
|
+
});
|
|
264
250
|
const stateCreator = (set, get) => {
|
|
265
251
|
this.set = set;
|
|
266
252
|
this.get = blindSpot.observeGet(get);
|
|
267
253
|
this.gateways = this.createGateways();
|
|
268
254
|
this.services = this.createServices();
|
|
269
255
|
const actions = blindSpot.observeActions(this.createActions());
|
|
270
|
-
const { initializeScenario, resetScenario } = createLankaScenarioBinder({
|
|
271
|
-
name: this.name,
|
|
272
|
-
bindings,
|
|
273
|
-
context: () => this.toStyleContext(),
|
|
274
|
-
onInit: () => {
|
|
275
|
-
this.onInit();
|
|
276
|
-
},
|
|
277
|
-
onReset: () => {
|
|
278
|
-
this.onReset();
|
|
279
|
-
}
|
|
280
|
-
});
|
|
281
256
|
return {
|
|
282
257
|
...this.states(),
|
|
283
258
|
...actions,
|
|
@@ -289,29 +264,21 @@ var ALankaVM = class extends ALankaVMEnvironment {
|
|
|
289
264
|
(creator, enhance) => enhance(creator),
|
|
290
265
|
stateCreator
|
|
291
266
|
);
|
|
292
|
-
const store =
|
|
293
|
-
const
|
|
294
|
-
|
|
295
|
-
|
|
267
|
+
const store = createStore()(enhancedCreator);
|
|
268
|
+
const viewModel = Object.defineProperties(store, {
|
|
269
|
+
name: { value: this.name, enumerable: false, configurable: true },
|
|
270
|
+
isAccessTracked: {
|
|
271
|
+
value: this.enableAccessTrackingOptimization,
|
|
272
|
+
enumerable: false,
|
|
273
|
+
configurable: true
|
|
296
274
|
}
|
|
297
|
-
};
|
|
298
|
-
if (!this.enableAccessTrackingOptimization) {
|
|
299
|
-
registerScenarioViewModel(store.getState());
|
|
300
|
-
lankaLogger.printViewModelLog("FINISH Create VM", this.name);
|
|
301
|
-
return store;
|
|
302
|
-
}
|
|
303
|
-
const useOptimizedViewModel = createLankaTrackedHook({
|
|
304
|
-
subscribe: (onChange) => store.subscribe(onChange),
|
|
305
|
-
readState: () => store.getState(),
|
|
306
|
-
onUntrackedChange: blindSpot.isArmed ? blindSpot.report : void 0
|
|
307
275
|
});
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
registerScenarioViewModel(useOptimizedViewModel.getState());
|
|
276
|
+
lankaBlindSpotRegistry.remember(viewModel, blindSpot);
|
|
277
|
+
if (needsBootstrap2) {
|
|
278
|
+
lankaScenarioBootstrap.registerViewModel(store.getState(), this.name);
|
|
279
|
+
}
|
|
313
280
|
lankaLogger.printViewModelLog("FINISH Create VM", this.name);
|
|
314
|
-
return
|
|
281
|
+
return viewModel;
|
|
315
282
|
}
|
|
316
283
|
};
|
|
317
284
|
|
|
@@ -344,17 +311,22 @@ function createLankaVM(config) {
|
|
|
344
311
|
createActions() {
|
|
345
312
|
return config.createActions(this.toStyleContext());
|
|
346
313
|
}
|
|
347
|
-
onInit
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
314
|
+
// The config's hooks become this instance's OWN `onInit`/`onReset`, assigned
|
|
315
|
+
// only when declared. An unconditional method override would make the base
|
|
316
|
+
// read every functional ViewModel as taking both hooks and register it with
|
|
317
|
+
// bootstrap for nothing; an own property is seen by the same test a class
|
|
318
|
+
// override is, and `this.onInit()` means the same thing in both styles.
|
|
319
|
+
constructor() {
|
|
320
|
+
super();
|
|
321
|
+
const { onInit, onReset } = config;
|
|
322
|
+
if (onInit) this.onInit = () => onInit(this.toStyleContext());
|
|
323
|
+
if (onReset) this.onReset = () => onReset(this.toStyleContext());
|
|
352
324
|
}
|
|
353
325
|
}
|
|
354
326
|
return new FunctionalVM().build();
|
|
355
327
|
}
|
|
356
328
|
|
|
357
|
-
// src/viewmodel/_internal/create-lazy-lanka-
|
|
329
|
+
// src/viewmodel/_internal/create-lazy-lanka-vm-proxy/createLazyLankaVMProxy.ts
|
|
358
330
|
var lazySlot = (config) => {
|
|
359
331
|
let store = null;
|
|
360
332
|
return {
|
|
@@ -388,29 +360,31 @@ var lazySlot = (config) => {
|
|
|
388
360
|
};
|
|
389
361
|
};
|
|
390
362
|
var PROMISE_MEMBERS = /* @__PURE__ */ new Set(["then", "catch", "finally"]);
|
|
391
|
-
var forwardEveryMember = (slot) => (_target, property) => {
|
|
363
|
+
var forwardEveryMember = (slot, config) => (_target, property) => {
|
|
392
364
|
if (property === "dispose") return slot.release;
|
|
393
365
|
if (PROMISE_MEMBERS.has(property)) return void 0;
|
|
366
|
+
if (property === "name") return config.name;
|
|
367
|
+
if (property === "isAccessTracked") return config.isAccessTracked;
|
|
394
368
|
return (...args) => {
|
|
395
369
|
const built = slot.get();
|
|
396
370
|
const member = built[property];
|
|
397
371
|
return typeof member === "function" ? member.apply(built, args) : member;
|
|
398
372
|
};
|
|
399
373
|
};
|
|
400
|
-
var
|
|
374
|
+
var createLazyLankaVMProxy = (config) => {
|
|
401
375
|
const slot = lazySlot(config);
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
return new Proxy(hook, { get: forwardEveryMember(slot) });
|
|
376
|
+
return new Proxy(
|
|
377
|
+
{},
|
|
378
|
+
{ get: forwardEveryMember(slot, config) }
|
|
379
|
+
);
|
|
407
380
|
};
|
|
408
381
|
|
|
409
382
|
// src/viewmodel/_factories/create-lazy-lanka-vm/createLazyLankaVM.ts
|
|
410
383
|
function createLazyLankaVM(config) {
|
|
411
|
-
return
|
|
384
|
+
return createLazyLankaVMProxy({
|
|
412
385
|
name: config.name,
|
|
413
386
|
kind: "VM",
|
|
387
|
+
isAccessTracked: config.enableAccessTrackingOptimization ?? true,
|
|
414
388
|
create: () => createLankaVM(config)
|
|
415
389
|
});
|
|
416
390
|
}
|
|
@@ -449,7 +423,12 @@ var ALankaStatelessVM = class extends ALankaVMEnvironment {
|
|
|
449
423
|
trigger: this.trigger
|
|
450
424
|
};
|
|
451
425
|
}
|
|
452
|
-
/**
|
|
426
|
+
/**
|
|
427
|
+
* Builds the ViewModel a screen reads. One per call.
|
|
428
|
+
*
|
|
429
|
+
* What comes back answers the read half of the port and nothing more: there
|
|
430
|
+
* is no store to write to from outside, because there is no state to write.
|
|
431
|
+
*/
|
|
453
432
|
build() {
|
|
454
433
|
lankaLogger.printViewModelLog("START Create slVM", this.name);
|
|
455
434
|
let state = {};
|
|
@@ -461,26 +440,26 @@ var ALankaStatelessVM = class extends ALankaVMEnvironment {
|
|
|
461
440
|
this.gateways = this.createGateways();
|
|
462
441
|
this.services = this.createServices();
|
|
463
442
|
const actions = this.createActions();
|
|
464
|
-
const
|
|
465
|
-
const { initializeScenario, resetScenario } = createLankaScenarioBinder({
|
|
443
|
+
const hooks = this.toLifecycleHooks();
|
|
444
|
+
const { initializeScenario, resetScenario, needsBootstrap: needsBootstrap2 } = createLankaScenarioBinder({
|
|
466
445
|
name: this.name,
|
|
467
|
-
bindings,
|
|
446
|
+
bindings: this.scenarioHandlers(),
|
|
468
447
|
context: () => this.toStyleContext(),
|
|
469
|
-
onInit:
|
|
470
|
-
|
|
471
|
-
},
|
|
472
|
-
onReset: () => {
|
|
473
|
-
this.onReset();
|
|
474
|
-
}
|
|
448
|
+
onInit: hooks.onInit,
|
|
449
|
+
onReset: hooks.onReset
|
|
475
450
|
});
|
|
476
451
|
state = { ...state, ...actions, initializeScenario, resetScenario };
|
|
477
|
-
if (
|
|
452
|
+
if (needsBootstrap2) {
|
|
478
453
|
lankaScenarioBootstrap.registerViewModel(state, this.name);
|
|
479
454
|
}
|
|
480
|
-
const
|
|
481
|
-
|
|
455
|
+
const statelessViewModel = {
|
|
456
|
+
name: this.name,
|
|
457
|
+
getState: () => state,
|
|
458
|
+
subscribe: () => () => void 0,
|
|
459
|
+
isAccessTracked: false
|
|
460
|
+
};
|
|
482
461
|
lankaLogger.printViewModelLog("FINISH Create slVM", this.name);
|
|
483
|
-
return
|
|
462
|
+
return statelessViewModel;
|
|
484
463
|
}
|
|
485
464
|
};
|
|
486
465
|
|
|
@@ -500,11 +479,13 @@ function createStatelessLankaVM(config) {
|
|
|
500
479
|
createActions() {
|
|
501
480
|
return config.createActions(this.toStyleContext());
|
|
502
481
|
}
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
config
|
|
482
|
+
// Own properties, assigned only when declared — see the same constructor in
|
|
483
|
+
// `createLankaVM` for why not a method override.
|
|
484
|
+
constructor() {
|
|
485
|
+
super();
|
|
486
|
+
const { onInit, onReset } = config;
|
|
487
|
+
if (onInit) this.onInit = () => onInit(this.toStyleContext());
|
|
488
|
+
if (onReset) this.onReset = () => onReset(this.toStyleContext());
|
|
508
489
|
}
|
|
509
490
|
}
|
|
510
491
|
return new FunctionalStatelessVM().build();
|
|
@@ -512,15 +493,17 @@ function createStatelessLankaVM(config) {
|
|
|
512
493
|
|
|
513
494
|
// src/viewmodel/_factories/create-lazy-stateless-lanka-vm/createLazyStatelessLankaVM.ts
|
|
514
495
|
function createLazyStatelessLankaVM(config) {
|
|
515
|
-
return
|
|
496
|
+
return createLazyLankaVMProxy({
|
|
516
497
|
name: config.name,
|
|
517
498
|
kind: "slVM",
|
|
499
|
+
// A stateless ViewModel has no reactive fields, so there is nothing whose
|
|
500
|
+
// reads could be worth recording — the eager one answers false too.
|
|
501
|
+
isAccessTracked: false,
|
|
518
502
|
create: () => createStatelessLankaVM(config)
|
|
519
503
|
});
|
|
520
504
|
}
|
|
521
505
|
|
|
522
506
|
// src/viewmodel/_factories/create-shared-store-lanka-vm/createSharedStoreLankaVM.ts
|
|
523
|
-
import { useStore } from "zustand";
|
|
524
507
|
function createSharedStoreLankaVM(config) {
|
|
525
508
|
lankaLogger.printViewModelLog("START Create ssVM", config.name);
|
|
526
509
|
let actions = {};
|
|
@@ -551,7 +534,7 @@ function createSharedStoreLankaVM(config) {
|
|
|
551
534
|
services,
|
|
552
535
|
trigger: (scenario, data) => scenario.trigger(data)
|
|
553
536
|
};
|
|
554
|
-
const { initializeScenario, resetScenario } = createLankaScenarioBinder({
|
|
537
|
+
const { initializeScenario, resetScenario, needsBootstrap: needsBootstrap2 } = createLankaScenarioBinder({
|
|
555
538
|
name: config.name,
|
|
556
539
|
bindings: config.scenarioHandlers,
|
|
557
540
|
context: () => ctx,
|
|
@@ -562,24 +545,16 @@ function createSharedStoreLankaVM(config) {
|
|
|
562
545
|
lastStoreStateRef = null;
|
|
563
546
|
lastFullStateRef = null;
|
|
564
547
|
const isAccessTrackingEnabled = config.enableAccessTrackingOptimization ?? true;
|
|
565
|
-
const
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
}
|
|
576
|
-
return fullState;
|
|
577
|
-
}));
|
|
578
|
-
const useSharedStoreViewModel = isAccessTrackingEnabled ? useTrackedSharedStoreViewModel : useUntrackedSharedStoreViewModel;
|
|
579
|
-
useSharedStoreViewModel.getState = () => getFullState();
|
|
580
|
-
useSharedStoreViewModel.getStoreState = () => config.store.getState();
|
|
581
|
-
const declaredBindings = config.scenarioHandlers;
|
|
582
|
-
if (typeof declaredBindings === "function" || declaredBindings !== void 0 && declaredBindings.length > 0) {
|
|
548
|
+
const sharedStoreViewModel = {
|
|
549
|
+
name: config.name,
|
|
550
|
+
getState: getFullState,
|
|
551
|
+
getStoreState: () => config.store.getState(),
|
|
552
|
+
isAccessTracked: isAccessTrackingEnabled,
|
|
553
|
+
subscribe: (listener) => config.store.subscribe((storeState, prevStoreState) => {
|
|
554
|
+
listener(buildFullState(storeState), buildFullState(prevStoreState));
|
|
555
|
+
})
|
|
556
|
+
};
|
|
557
|
+
if (needsBootstrap2) {
|
|
583
558
|
const scenarioViewModel = {
|
|
584
559
|
initializeScenario,
|
|
585
560
|
resetScenario
|
|
@@ -587,14 +562,15 @@ function createSharedStoreLankaVM(config) {
|
|
|
587
562
|
lankaScenarioBootstrap.registerViewModel(scenarioViewModel, config.name);
|
|
588
563
|
}
|
|
589
564
|
lankaLogger.printViewModelLog("FINISH Create ssVM", config.name);
|
|
590
|
-
return
|
|
565
|
+
return sharedStoreViewModel;
|
|
591
566
|
}
|
|
592
567
|
|
|
593
568
|
// src/viewmodel/_factories/create-lazy-shared-store-lanka-vm/createLazySharedStoreLankaVM.ts
|
|
594
569
|
function createLazySharedStoreLankaVM(config) {
|
|
595
|
-
return
|
|
570
|
+
return createLazyLankaVMProxy({
|
|
596
571
|
name: config.name,
|
|
597
572
|
kind: "ssVM",
|
|
573
|
+
isAccessTracked: config.enableAccessTrackingOptimization ?? true,
|
|
598
574
|
create: () => createSharedStoreLankaVM(config)
|
|
599
575
|
});
|
|
600
576
|
}
|
|
@@ -626,6 +602,7 @@ var ALankaSharedStoreVM = class extends ALankaVMEnvironment {
|
|
|
626
602
|
}
|
|
627
603
|
/** Builds the hook a screen calls. One ViewModel per call. */
|
|
628
604
|
build() {
|
|
605
|
+
const hooks = this.toLifecycleHooks();
|
|
629
606
|
return createSharedStoreLankaVM({
|
|
630
607
|
name: this.name,
|
|
631
608
|
store: this.store,
|
|
@@ -642,24 +619,20 @@ var ALankaSharedStoreVM = class extends ALankaVMEnvironment {
|
|
|
642
619
|
this.trigger = context.trigger;
|
|
643
620
|
return this.createActions();
|
|
644
621
|
},
|
|
645
|
-
onInit:
|
|
646
|
-
|
|
647
|
-
},
|
|
648
|
-
onReset: () => {
|
|
649
|
-
this.onReset();
|
|
650
|
-
}
|
|
622
|
+
onInit: hooks.onInit,
|
|
623
|
+
onReset: hooks.onReset
|
|
651
624
|
});
|
|
652
625
|
}
|
|
653
626
|
};
|
|
654
627
|
|
|
655
628
|
// src/viewmodel/_abstractions/lanka-shared-store/ALankaSharedStore.ts
|
|
656
|
-
import { createStore } from "zustand/vanilla";
|
|
629
|
+
import { createStore as createStore2 } from "zustand/vanilla";
|
|
657
630
|
var ALankaSharedStore = class {
|
|
658
631
|
api;
|
|
659
632
|
createInitialState;
|
|
660
633
|
constructor(createInitialState) {
|
|
661
634
|
this.createInitialState = createInitialState;
|
|
662
|
-
this.api =
|
|
635
|
+
this.api = createStore2()(() => this.createInitialState());
|
|
663
636
|
}
|
|
664
637
|
getApi() {
|
|
665
638
|
return this.api;
|
|
@@ -701,11 +674,34 @@ var createLankaSharedStore = (createInitialState) => {
|
|
|
701
674
|
}
|
|
702
675
|
return new FunctionalSharedStore();
|
|
703
676
|
};
|
|
677
|
+
|
|
678
|
+
// src/viewmodel/_factories/create-lanka-shallow-hold/createLankaShallowHold.ts
|
|
679
|
+
var isShallowEqual = (a, b) => {
|
|
680
|
+
if (Object.is(a, b)) return true;
|
|
681
|
+
if (typeof a !== "object" || a === null || typeof b !== "object" || b === null) return false;
|
|
682
|
+
const left = Object.keys(a);
|
|
683
|
+
const right = Object.keys(b);
|
|
684
|
+
if (left.length !== right.length) return false;
|
|
685
|
+
return left.every(
|
|
686
|
+
(key) => Object.hasOwn(b, key) && Object.is(a[key], b[key])
|
|
687
|
+
);
|
|
688
|
+
};
|
|
689
|
+
var createLankaShallowHold = () => {
|
|
690
|
+
let held;
|
|
691
|
+
let holding = false;
|
|
692
|
+
return (next) => {
|
|
693
|
+
if (holding && isShallowEqual(held, next)) return held;
|
|
694
|
+
holding = true;
|
|
695
|
+
held = next;
|
|
696
|
+
return next;
|
|
697
|
+
};
|
|
698
|
+
};
|
|
704
699
|
export {
|
|
705
700
|
ALankaSharedStore,
|
|
706
701
|
ALankaSharedStoreVM,
|
|
707
702
|
ALankaStatelessVM,
|
|
708
703
|
ALankaVM,
|
|
704
|
+
createLankaShallowHold,
|
|
709
705
|
createLankaSharedStore,
|
|
710
706
|
createLankaVM,
|
|
711
707
|
createLazyLankaVM,
|