@blac/core 2.0.0-rc.10 → 2.0.0-rc.13
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/dist/index.cjs +435 -197
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +1325 -21
- package/dist/index.d.ts +1325 -21
- package/dist/index.js +436 -189
- package/dist/index.js.map +1 -0
- package/package.json +10 -6
- package/dist/adapter/framework-adapter.d.ts +0 -33
- package/dist/adapter/index.d.ts +0 -8
- package/dist/constants.d.ts +0 -82
- package/dist/core/Cubit.d.ts +0 -40
- package/dist/core/StateContainer.d.ts +0 -78
- package/dist/core/StateContainerRegistry.d.ts +0 -119
- package/dist/core/Vertex.d.ts +0 -74
- package/dist/decorators/blac.d.ts +0 -31
- package/dist/decorators/index.d.ts +0 -2
- package/dist/logging/Logger.d.ts +0 -57
- package/dist/plugin/BlacPlugin.d.ts +0 -46
- package/dist/plugin/PluginManager.d.ts +0 -38
- package/dist/registry/index.d.ts +0 -20
- package/dist/test-utils/index.d.ts +0 -43
- package/dist/tracking/dependency-tracker.d.ts +0 -21
- package/dist/tracking/getter-tracker.d.ts +0 -31
- package/dist/tracking/index.d.ts +0 -38
- package/dist/tracking/path-utils.d.ts +0 -39
- package/dist/tracking/proxy-tracker.d.ts +0 -88
- package/dist/types/branded.d.ts +0 -9
- package/dist/types/events.d.ts +0 -13
- package/dist/types/utilities.d.ts +0 -19
- package/dist/utils/equality.d.ts +0 -9
- package/dist/utils/idGenerator.d.ts +0 -76
- package/dist/utils/immutable.d.ts +0 -16
- package/dist/utils/stack-trace.d.ts +0 -19
- package/dist/utils/static-props.d.ts +0 -29
package/dist/index.cjs
CHANGED
|
@@ -39,10 +39,8 @@ function createIdGenerator(prefix) {
|
|
|
39
39
|
* @returns Branded ID string
|
|
40
40
|
*
|
|
41
41
|
* @example
|
|
42
|
-
* ```ts
|
|
43
42
|
* const id = generateId('sub');
|
|
44
43
|
* // Returns: "sub:1698765432100_1_a3k9d7f2q"
|
|
45
|
-
* ```
|
|
46
44
|
*/
|
|
47
45
|
function generateId(prefix) {
|
|
48
46
|
const counter = (globalCounters.get(prefix) ?? 0) + 1;
|
|
@@ -97,12 +95,32 @@ function isIsolatedKey(key) {
|
|
|
97
95
|
|
|
98
96
|
//#endregion
|
|
99
97
|
//#region src/plugin/PluginManager.ts
|
|
98
|
+
/**
|
|
99
|
+
* Manages plugin lifecycle for the BlaC state management system.
|
|
100
|
+
* Plugins receive notifications about state container lifecycle events.
|
|
101
|
+
*
|
|
102
|
+
* @example
|
|
103
|
+
* ```ts
|
|
104
|
+
* const manager = createPluginManager(registry);
|
|
105
|
+
* manager.install(myPlugin, { environment: 'development' });
|
|
106
|
+
* ```
|
|
107
|
+
*/
|
|
100
108
|
var PluginManager = class {
|
|
109
|
+
/**
|
|
110
|
+
* Create a new PluginManager
|
|
111
|
+
* @param registry - The StateContainerRegistry to monitor for lifecycle events
|
|
112
|
+
*/
|
|
101
113
|
constructor(registry) {
|
|
102
114
|
this.plugins = /* @__PURE__ */ new Map();
|
|
103
115
|
this.registry = registry;
|
|
104
116
|
this.setupLifecycleHooks();
|
|
105
117
|
}
|
|
118
|
+
/**
|
|
119
|
+
* Install a plugin with optional configuration
|
|
120
|
+
* @param plugin - The plugin to install
|
|
121
|
+
* @param config - Optional plugin configuration
|
|
122
|
+
* @throws Error if plugin is already installed
|
|
123
|
+
*/
|
|
106
124
|
install(plugin, config = {}) {
|
|
107
125
|
const effectiveConfig = {
|
|
108
126
|
enabled: true,
|
|
@@ -129,6 +147,11 @@ var PluginManager = class {
|
|
|
129
147
|
}
|
|
130
148
|
console.log(`[BlaC] Plugin "${plugin.name}" v${plugin.version} installed`);
|
|
131
149
|
}
|
|
150
|
+
/**
|
|
151
|
+
* Uninstall a plugin by name
|
|
152
|
+
* @param pluginName - The name of the plugin to uninstall
|
|
153
|
+
* @throws Error if plugin is not installed
|
|
154
|
+
*/
|
|
132
155
|
uninstall(pluginName) {
|
|
133
156
|
const installed = this.plugins.get(pluginName);
|
|
134
157
|
if (!installed) throw new Error(`Plugin "${pluginName}" is not installed`);
|
|
@@ -140,15 +163,32 @@ var PluginManager = class {
|
|
|
140
163
|
this.plugins.delete(pluginName);
|
|
141
164
|
console.log(`[BlaC] Plugin "${pluginName}" uninstalled`);
|
|
142
165
|
}
|
|
166
|
+
/**
|
|
167
|
+
* Get an installed plugin by name
|
|
168
|
+
* @param pluginName - The name of the plugin to retrieve
|
|
169
|
+
* @returns The plugin instance or undefined if not found
|
|
170
|
+
*/
|
|
143
171
|
getPlugin(pluginName) {
|
|
144
172
|
return this.plugins.get(pluginName)?.plugin;
|
|
145
173
|
}
|
|
174
|
+
/**
|
|
175
|
+
* Get all installed plugins
|
|
176
|
+
* @returns Array of all installed plugins
|
|
177
|
+
*/
|
|
146
178
|
getAllPlugins() {
|
|
147
179
|
return Array.from(this.plugins.values()).map((p) => p.plugin);
|
|
148
180
|
}
|
|
181
|
+
/**
|
|
182
|
+
* Check if a plugin is installed
|
|
183
|
+
* @param pluginName - The name of the plugin to check
|
|
184
|
+
* @returns true if the plugin is installed
|
|
185
|
+
*/
|
|
149
186
|
hasPlugin(pluginName) {
|
|
150
187
|
return this.plugins.has(pluginName);
|
|
151
188
|
}
|
|
189
|
+
/**
|
|
190
|
+
* Uninstall all plugins
|
|
191
|
+
*/
|
|
152
192
|
clear() {
|
|
153
193
|
for (const name of this.plugins.keys()) this.uninstall(name);
|
|
154
194
|
}
|
|
@@ -295,9 +335,15 @@ const getterExecutionContext = {
|
|
|
295
335
|
visitedBlocs: /* @__PURE__ */ new Set()
|
|
296
336
|
};
|
|
297
337
|
const MAX_GETTER_DEPTH = BLAC_DEFAULTS.MAX_GETTER_DEPTH;
|
|
338
|
+
/**
|
|
339
|
+
* @internal
|
|
340
|
+
*/
|
|
298
341
|
function getGetterExecutionContext() {
|
|
299
342
|
return getterExecutionContext;
|
|
300
343
|
}
|
|
344
|
+
/**
|
|
345
|
+
* @internal
|
|
346
|
+
*/
|
|
301
347
|
function getDescriptor(obj, prop) {
|
|
302
348
|
const constructor = obj.constructor;
|
|
303
349
|
let constructorCache = descriptorCache.get(constructor);
|
|
@@ -316,9 +362,15 @@ function getDescriptor(obj, prop) {
|
|
|
316
362
|
constructorCache.set(prop, descriptor);
|
|
317
363
|
return descriptor;
|
|
318
364
|
}
|
|
365
|
+
/**
|
|
366
|
+
* @internal
|
|
367
|
+
*/
|
|
319
368
|
function isGetter(obj, prop) {
|
|
320
369
|
return getDescriptor(obj, prop)?.get !== void 0;
|
|
321
370
|
}
|
|
371
|
+
/**
|
|
372
|
+
* @internal
|
|
373
|
+
*/
|
|
322
374
|
function createGetterTracker() {
|
|
323
375
|
return {
|
|
324
376
|
trackedValues: /* @__PURE__ */ new Map(),
|
|
@@ -330,19 +382,34 @@ function createGetterTracker() {
|
|
|
330
382
|
externalDependencies: /* @__PURE__ */ new Set()
|
|
331
383
|
};
|
|
332
384
|
}
|
|
385
|
+
/**
|
|
386
|
+
* @internal
|
|
387
|
+
*/
|
|
333
388
|
function setActiveTracker(bloc, tracker) {
|
|
334
389
|
activeTrackerMap.set(bloc, tracker);
|
|
335
390
|
}
|
|
391
|
+
/**
|
|
392
|
+
* @internal
|
|
393
|
+
*/
|
|
336
394
|
function clearActiveTracker(bloc) {
|
|
337
395
|
activeTrackerMap.delete(bloc);
|
|
338
396
|
}
|
|
397
|
+
/**
|
|
398
|
+
* @internal
|
|
399
|
+
*/
|
|
339
400
|
function getActiveTracker(bloc) {
|
|
340
401
|
return activeTrackerMap.get(bloc);
|
|
341
402
|
}
|
|
403
|
+
/**
|
|
404
|
+
* @internal
|
|
405
|
+
*/
|
|
342
406
|
function commitTrackedGetters(tracker) {
|
|
343
407
|
if (tracker.currentlyAccessing.size > 0) tracker.trackedGetters = new Set(tracker.currentlyAccessing);
|
|
344
408
|
tracker.currentlyAccessing.clear();
|
|
345
409
|
}
|
|
410
|
+
/**
|
|
411
|
+
* @internal
|
|
412
|
+
*/
|
|
346
413
|
function createBlocProxy(bloc) {
|
|
347
414
|
const cached = blocProxyCache.get(bloc);
|
|
348
415
|
if (cached) return cached;
|
|
@@ -392,6 +459,9 @@ function createBlocProxy(bloc) {
|
|
|
392
459
|
blocProxyCache.set(bloc, proxy);
|
|
393
460
|
return proxy;
|
|
394
461
|
}
|
|
462
|
+
/**
|
|
463
|
+
* @internal
|
|
464
|
+
*/
|
|
395
465
|
function hasGetterChanges(bloc, tracker) {
|
|
396
466
|
if (!tracker || tracker.trackedGetters.size === 0) return false;
|
|
397
467
|
tracker.renderCache.clear();
|
|
@@ -414,12 +484,21 @@ function hasGetterChanges(bloc, tracker) {
|
|
|
414
484
|
tracker.cacheValid = true;
|
|
415
485
|
return hasAnyChange;
|
|
416
486
|
}
|
|
487
|
+
/**
|
|
488
|
+
* @internal
|
|
489
|
+
*/
|
|
417
490
|
function invalidateRenderCache(tracker) {
|
|
418
491
|
tracker.cacheValid = false;
|
|
419
492
|
}
|
|
493
|
+
/**
|
|
494
|
+
* @internal
|
|
495
|
+
*/
|
|
420
496
|
function clearExternalDependencies(tracker) {
|
|
421
497
|
tracker.externalDependencies.clear();
|
|
422
498
|
}
|
|
499
|
+
/**
|
|
500
|
+
* @internal
|
|
501
|
+
*/
|
|
423
502
|
function resetGetterTracker(tracker) {
|
|
424
503
|
tracker.trackedValues.clear();
|
|
425
504
|
tracker.currentlyAccessing.clear();
|
|
@@ -471,6 +550,19 @@ function isExcludedFromDevTools(Type) {
|
|
|
471
550
|
|
|
472
551
|
//#endregion
|
|
473
552
|
//#region src/core/StateContainerRegistry.ts
|
|
553
|
+
/**
|
|
554
|
+
* Central registry for managing StateContainer instances.
|
|
555
|
+
* Handles instance lifecycle, ref counting, and lifecycle event emission.
|
|
556
|
+
*
|
|
557
|
+
* @example
|
|
558
|
+
* ```ts
|
|
559
|
+
* const registry = new StateContainerRegistry();
|
|
560
|
+
* const instance = registry.resolve(MyBloc);
|
|
561
|
+
* registry.on('stateChanged', (container, prev, next) => {
|
|
562
|
+
* console.log('State changed:', prev, '->', next);
|
|
563
|
+
* });
|
|
564
|
+
* ```
|
|
565
|
+
*/
|
|
474
566
|
var StateContainerRegistry = class {
|
|
475
567
|
constructor() {
|
|
476
568
|
this.instancesByConstructor = /* @__PURE__ */ new WeakMap();
|
|
@@ -478,9 +570,19 @@ var StateContainerRegistry = class {
|
|
|
478
570
|
this.typeConfigs = /* @__PURE__ */ new Map();
|
|
479
571
|
this.listeners = /* @__PURE__ */ new Map();
|
|
480
572
|
}
|
|
573
|
+
/**
|
|
574
|
+
* Register a type for lifecycle event tracking
|
|
575
|
+
* @param constructor - The StateContainer class constructor
|
|
576
|
+
*/
|
|
481
577
|
registerType(constructor) {
|
|
482
578
|
this.types.add(constructor);
|
|
483
579
|
}
|
|
580
|
+
/**
|
|
581
|
+
* Register a StateContainer class with configuration
|
|
582
|
+
* @param constructor - The StateContainer class constructor
|
|
583
|
+
* @param isolated - Whether instances should be isolated (component-scoped)
|
|
584
|
+
* @throws Error if type is already registered
|
|
585
|
+
*/
|
|
484
586
|
register(constructor, isolated = false) {
|
|
485
587
|
const className = constructor.name;
|
|
486
588
|
if (!isolated && isIsolatedClass(constructor)) isolated = true;
|
|
@@ -733,6 +835,26 @@ function getPluginManager() {
|
|
|
733
835
|
|
|
734
836
|
//#endregion
|
|
735
837
|
//#region src/core/StateContainer.ts
|
|
838
|
+
/**
|
|
839
|
+
* Abstract base class for all state containers in BlaC.
|
|
840
|
+
* Provides lifecycle management, subscription handling, ref counting,
|
|
841
|
+
* and integration with the global registry.
|
|
842
|
+
*
|
|
843
|
+
* @template S - State type managed by this container
|
|
844
|
+
* @template P - Props type passed to the container (optional)
|
|
845
|
+
*
|
|
846
|
+
* @example
|
|
847
|
+
* ```ts
|
|
848
|
+
* class CounterBloc extends StateContainer<number> {
|
|
849
|
+
* constructor() {
|
|
850
|
+
* super(0);
|
|
851
|
+
* }
|
|
852
|
+
* increment() {
|
|
853
|
+
* this.emit(this.state + 1);
|
|
854
|
+
* }
|
|
855
|
+
* }
|
|
856
|
+
* ```
|
|
857
|
+
*/
|
|
736
858
|
var StateContainer = class StateContainer {
|
|
737
859
|
static {
|
|
738
860
|
this.__excludeFromDevTools = false;
|
|
@@ -740,52 +862,132 @@ var StateContainer = class StateContainer {
|
|
|
740
862
|
static {
|
|
741
863
|
this._registry = globalRegistry;
|
|
742
864
|
}
|
|
865
|
+
/**
|
|
866
|
+
* Get the global StateContainerRegistry
|
|
867
|
+
* @returns The registry managing all state container instances
|
|
868
|
+
*/
|
|
743
869
|
static getRegistry() {
|
|
744
870
|
return StateContainer._registry;
|
|
745
871
|
}
|
|
872
|
+
/**
|
|
873
|
+
* Replace the global registry (clears existing instances)
|
|
874
|
+
* @param registry - The new registry to use
|
|
875
|
+
*/
|
|
746
876
|
static setRegistry(registry) {
|
|
747
877
|
StateContainer._registry.clearAll();
|
|
748
878
|
StateContainer._registry = registry;
|
|
749
879
|
}
|
|
880
|
+
/**
|
|
881
|
+
* Register this class with the global registry
|
|
882
|
+
* @param isolated - Whether instances should be isolated (component-scoped)
|
|
883
|
+
*/
|
|
750
884
|
static register(isolated = false) {
|
|
751
885
|
StateContainer._registry.register(this, isolated);
|
|
752
886
|
}
|
|
887
|
+
/**
|
|
888
|
+
* Resolve an instance with ref counting (ownership semantics).
|
|
889
|
+
* Creates a new instance if one doesn't exist, or returns existing and increments ref count.
|
|
890
|
+
* @template S - Optional state type override for generic StateContainers
|
|
891
|
+
* @template T - The StateContainer type (inferred from class)
|
|
892
|
+
* @param instanceKey - Optional instance key (defaults to 'default')
|
|
893
|
+
* @param constructorArgs - Arguments to pass to constructor if creating new instance
|
|
894
|
+
* @returns The state container instance
|
|
895
|
+
*/
|
|
753
896
|
static resolve(instanceKey, constructorArgs) {
|
|
754
897
|
return StateContainer._registry.resolve(this, instanceKey, constructorArgs);
|
|
755
898
|
}
|
|
899
|
+
/**
|
|
900
|
+
* Get an existing instance without incrementing ref count (borrowing semantics).
|
|
901
|
+
* @template S - Optional state type override for generic StateContainers
|
|
902
|
+
* @template T - The StateContainer type (inferred from class)
|
|
903
|
+
* @param instanceKey - Optional instance key (defaults to 'default')
|
|
904
|
+
* @returns The state container instance
|
|
905
|
+
* @throws Error if instance doesn't exist
|
|
906
|
+
*/
|
|
756
907
|
static get(instanceKey) {
|
|
757
908
|
return StateContainer._registry.get(this, instanceKey);
|
|
758
909
|
}
|
|
910
|
+
/**
|
|
911
|
+
* Safely get an existing instance with error handling.
|
|
912
|
+
* @template S - Optional state type override for generic StateContainers
|
|
913
|
+
* @template T - The StateContainer type (inferred from class)
|
|
914
|
+
* @param instanceKey - Optional instance key (defaults to 'default')
|
|
915
|
+
* @returns Discriminated union with either the instance or an error
|
|
916
|
+
*/
|
|
759
917
|
static getSafe(instanceKey) {
|
|
760
918
|
return StateContainer._registry.getSafe(this, instanceKey);
|
|
761
919
|
}
|
|
920
|
+
/**
|
|
921
|
+
* Connect to an instance for bloc-to-bloc communication (borrowing semantics).
|
|
922
|
+
* Gets or creates instance without incrementing ref count.
|
|
923
|
+
* @template S - Optional state type override for generic StateContainers
|
|
924
|
+
* @template T - The StateContainer type (inferred from class)
|
|
925
|
+
* @param instanceKey - Optional instance key (defaults to 'default')
|
|
926
|
+
* @param constructorArgs - Arguments to pass to constructor if creating new instance
|
|
927
|
+
* @returns The state container instance
|
|
928
|
+
*/
|
|
762
929
|
static connect(instanceKey, constructorArgs) {
|
|
763
930
|
return StateContainer._registry.connect(this, instanceKey, constructorArgs);
|
|
764
931
|
}
|
|
932
|
+
/**
|
|
933
|
+
* Release a reference to an instance.
|
|
934
|
+
* Decrements ref count and disposes when it reaches 0 (unless keepAlive).
|
|
935
|
+
* @param instanceKey - Optional instance key (defaults to 'default')
|
|
936
|
+
* @param forceDispose - Force immediate disposal regardless of ref count
|
|
937
|
+
*/
|
|
765
938
|
static release(instanceKey, forceDispose = false) {
|
|
766
939
|
StateContainer._registry.release(this, instanceKey, forceDispose);
|
|
767
940
|
}
|
|
941
|
+
/**
|
|
942
|
+
* Get all instances of this class
|
|
943
|
+
* @returns Array of all instances
|
|
944
|
+
*/
|
|
768
945
|
static getAll() {
|
|
769
946
|
return StateContainer._registry.getAll(this);
|
|
770
947
|
}
|
|
948
|
+
/**
|
|
949
|
+
* Iterate over all instances of this class
|
|
950
|
+
* @param callback - Function to call for each instance
|
|
951
|
+
*/
|
|
771
952
|
static forEach(callback) {
|
|
772
953
|
StateContainer._registry.forEach(this, callback);
|
|
773
954
|
}
|
|
955
|
+
/**
|
|
956
|
+
* Clear all instances of this class (disposes them)
|
|
957
|
+
*/
|
|
774
958
|
static clear() {
|
|
775
959
|
StateContainer._registry.clear(this);
|
|
776
960
|
}
|
|
961
|
+
/**
|
|
962
|
+
* Clear all instances from all registered types
|
|
963
|
+
*/
|
|
777
964
|
static clearAllInstances() {
|
|
778
965
|
StateContainer._registry.clearAll();
|
|
779
966
|
}
|
|
967
|
+
/**
|
|
968
|
+
* Get registry statistics for debugging
|
|
969
|
+
* @returns Object with registeredTypes, totalInstances, and typeBreakdown
|
|
970
|
+
*/
|
|
780
971
|
static getStats() {
|
|
781
972
|
return StateContainer._registry.getStats();
|
|
782
973
|
}
|
|
974
|
+
/**
|
|
975
|
+
* Get reference count for an instance
|
|
976
|
+
* @param instanceKey - Optional instance key (defaults to 'default')
|
|
977
|
+
* @returns Current ref count (0 if instance doesn't exist)
|
|
978
|
+
*/
|
|
783
979
|
static getRefCount(instanceKey) {
|
|
784
980
|
return StateContainer._registry.getRefCount(this, instanceKey);
|
|
785
981
|
}
|
|
982
|
+
/**
|
|
983
|
+
* Check if an instance exists
|
|
984
|
+
* @param instanceKey - Optional instance key (defaults to 'default')
|
|
985
|
+
* @returns true if instance exists
|
|
986
|
+
*/
|
|
786
987
|
static hasInstance(instanceKey) {
|
|
787
988
|
return StateContainer._registry.hasInstance(this, instanceKey);
|
|
788
989
|
}
|
|
990
|
+
/** Current props value passed to this container */
|
|
789
991
|
get props() {
|
|
790
992
|
return this._props;
|
|
791
993
|
}
|
|
@@ -813,6 +1015,11 @@ var StateContainer = class StateContainer {
|
|
|
813
1015
|
};
|
|
814
1016
|
this._state = initialState;
|
|
815
1017
|
}
|
|
1018
|
+
/**
|
|
1019
|
+
* Initialize configuration for this instance.
|
|
1020
|
+
* Called by the registry after construction.
|
|
1021
|
+
* @param config - Configuration options
|
|
1022
|
+
*/
|
|
816
1023
|
initConfig(config) {
|
|
817
1024
|
this.config = { ...config };
|
|
818
1025
|
this.name = this.config.name || this.constructor.name;
|
|
@@ -820,17 +1027,28 @@ var StateContainer = class StateContainer {
|
|
|
820
1027
|
this.instanceId = generateSimpleId(this.constructor.name, this.config.instanceId);
|
|
821
1028
|
StateContainer._registry.emit("created", this);
|
|
822
1029
|
}
|
|
1030
|
+
/** Current state value */
|
|
823
1031
|
get state() {
|
|
824
1032
|
return this._state;
|
|
825
1033
|
}
|
|
1034
|
+
/** Whether this instance has been disposed */
|
|
826
1035
|
get isDisposed() {
|
|
827
1036
|
return this._disposed;
|
|
828
1037
|
}
|
|
1038
|
+
/**
|
|
1039
|
+
* Subscribe to state changes
|
|
1040
|
+
* @param listener - Function called when state changes
|
|
1041
|
+
* @returns Unsubscribe function
|
|
1042
|
+
*/
|
|
829
1043
|
subscribe(listener) {
|
|
830
1044
|
if (this._disposed) throw new Error(`Cannot subscribe to disposed container ${this.name}`);
|
|
831
1045
|
this.listeners.add(listener);
|
|
832
1046
|
return () => this.listeners.delete(listener);
|
|
833
1047
|
}
|
|
1048
|
+
/**
|
|
1049
|
+
* Dispose this instance and clean up resources.
|
|
1050
|
+
* Clears all listeners and emits the 'dispose' system event.
|
|
1051
|
+
*/
|
|
834
1052
|
dispose() {
|
|
835
1053
|
if (this._disposed) return;
|
|
836
1054
|
if (this.debug) console.log(`[${this.name}] Disposing...`);
|
|
@@ -841,6 +1059,11 @@ var StateContainer = class StateContainer {
|
|
|
841
1059
|
StateContainer._registry.emit("disposed", this);
|
|
842
1060
|
if (this.debug) console.log(`[${this.name}] Disposed successfully`);
|
|
843
1061
|
}
|
|
1062
|
+
/**
|
|
1063
|
+
* Emit a new state value and notify all listeners.
|
|
1064
|
+
* @param newState - The new state value
|
|
1065
|
+
* @protected
|
|
1066
|
+
*/
|
|
844
1067
|
emit(newState) {
|
|
845
1068
|
if (this._disposed) throw new Error(`Cannot emit state from disposed container ${this.name}`);
|
|
846
1069
|
if (this._state === newState) return;
|
|
@@ -900,6 +1123,11 @@ var StateContainer = class StateContainer {
|
|
|
900
1123
|
if (segments.length > 3) path = segments.slice(-3).join("/");
|
|
901
1124
|
return path;
|
|
902
1125
|
}
|
|
1126
|
+
/**
|
|
1127
|
+
* Update state using a transform function.
|
|
1128
|
+
* @param updater - Function that receives current state and returns new state
|
|
1129
|
+
* @protected
|
|
1130
|
+
*/
|
|
903
1131
|
update(updater) {
|
|
904
1132
|
if (this._disposed) throw new Error(`Cannot update state from disposed container ${this.name}`);
|
|
905
1133
|
this.emit(updater(this._state));
|
|
@@ -913,6 +1141,11 @@ var StateContainer = class StateContainer {
|
|
|
913
1141
|
console.error(`[${this.name}] Error in system event handler:`, error$1);
|
|
914
1142
|
}
|
|
915
1143
|
}
|
|
1144
|
+
/**
|
|
1145
|
+
* Update the props for this container.
|
|
1146
|
+
* Emits the 'propsUpdated' system event.
|
|
1147
|
+
* @param newProps - The new props value
|
|
1148
|
+
*/
|
|
916
1149
|
updateProps(newProps) {
|
|
917
1150
|
if (this._disposed) throw new Error(`Cannot update props on disposed container ${this.name}`);
|
|
918
1151
|
const previousProps = this._props;
|
|
@@ -930,6 +1163,13 @@ var StateContainer = class StateContainer {
|
|
|
930
1163
|
|
|
931
1164
|
//#endregion
|
|
932
1165
|
//#region src/core/Cubit.ts
|
|
1166
|
+
/**
|
|
1167
|
+
* Simple state container with direct state emission.
|
|
1168
|
+
* Extends StateContainer with public methods for emitting and updating state.
|
|
1169
|
+
*
|
|
1170
|
+
* @template S - State type
|
|
1171
|
+
* @template P - Props type (optional)
|
|
1172
|
+
*/
|
|
933
1173
|
var Cubit = class extends StateContainer {
|
|
934
1174
|
constructor(initialState) {
|
|
935
1175
|
super(initialState);
|
|
@@ -941,89 +1181,32 @@ var Cubit = class extends StateContainer {
|
|
|
941
1181
|
}));
|
|
942
1182
|
});
|
|
943
1183
|
}
|
|
1184
|
+
/**
|
|
1185
|
+
* Replace state with a new value and notify all listeners
|
|
1186
|
+
* @param newState - The new state value
|
|
1187
|
+
*/
|
|
944
1188
|
emit(newState) {
|
|
945
1189
|
super["emit"](newState);
|
|
946
1190
|
}
|
|
1191
|
+
/**
|
|
1192
|
+
* Transform current state using an updater function and emit the new state
|
|
1193
|
+
* @param updater - Function that receives current state and returns new state
|
|
1194
|
+
*/
|
|
947
1195
|
update(updater) {
|
|
948
1196
|
super["update"](updater);
|
|
949
1197
|
}
|
|
950
1198
|
};
|
|
951
|
-
var CounterCubit = class extends Cubit {
|
|
952
|
-
constructor() {
|
|
953
|
-
super(0);
|
|
954
|
-
this.increment = () => {
|
|
955
|
-
this.emit(this.state + 1);
|
|
956
|
-
};
|
|
957
|
-
this.decrement = () => {
|
|
958
|
-
this.emit(this.state - 1);
|
|
959
|
-
};
|
|
960
|
-
this.reset = () => {
|
|
961
|
-
this.emit(0);
|
|
962
|
-
};
|
|
963
|
-
this.addAmount = (amount) => {
|
|
964
|
-
this.emit(this.state + amount);
|
|
965
|
-
};
|
|
966
|
-
}
|
|
967
|
-
};
|
|
968
|
-
var TodoCubit = class extends Cubit {
|
|
969
|
-
static {
|
|
970
|
-
this.keepAlive = true;
|
|
971
|
-
}
|
|
972
|
-
constructor() {
|
|
973
|
-
super({
|
|
974
|
-
todos: [],
|
|
975
|
-
filter: "all",
|
|
976
|
-
isLoading: false
|
|
977
|
-
});
|
|
978
|
-
this.nextId = 0;
|
|
979
|
-
this.addTodo = (text) => {
|
|
980
|
-
this.update((state) => ({
|
|
981
|
-
...state,
|
|
982
|
-
todos: [...state.todos, {
|
|
983
|
-
id: `todo-${Date.now()}-${this.nextId++}`,
|
|
984
|
-
text,
|
|
985
|
-
done: false
|
|
986
|
-
}]
|
|
987
|
-
}));
|
|
988
|
-
};
|
|
989
|
-
this.toggleTodo = (id) => {
|
|
990
|
-
this.update((state) => ({
|
|
991
|
-
...state,
|
|
992
|
-
todos: state.todos.map((todo) => todo.id === id ? {
|
|
993
|
-
...todo,
|
|
994
|
-
done: !todo.done
|
|
995
|
-
} : todo)
|
|
996
|
-
}));
|
|
997
|
-
};
|
|
998
|
-
this.removeTodo = (id) => {
|
|
999
|
-
this.update((state) => ({
|
|
1000
|
-
...state,
|
|
1001
|
-
todos: state.todos.filter((todo) => todo.id !== id)
|
|
1002
|
-
}));
|
|
1003
|
-
};
|
|
1004
|
-
this.setFilter = (filter) => {
|
|
1005
|
-
this.patch({ filter });
|
|
1006
|
-
};
|
|
1007
|
-
this.setLoading = (isLoading) => {
|
|
1008
|
-
this.patch({ isLoading });
|
|
1009
|
-
};
|
|
1010
|
-
}
|
|
1011
|
-
get visibleTodos() {
|
|
1012
|
-
const todos = this.state.todos;
|
|
1013
|
-
switch (this.state.filter) {
|
|
1014
|
-
case "active": return todos.filter((t) => !t.done);
|
|
1015
|
-
case "completed": return todos.filter((t) => t.done);
|
|
1016
|
-
case "all":
|
|
1017
|
-
default: return todos;
|
|
1018
|
-
}
|
|
1019
|
-
}
|
|
1020
|
-
get activeTodoCount() {
|
|
1021
|
-
return this.state.todos.filter((t) => !t.done).length;
|
|
1022
|
-
}
|
|
1023
|
-
};
|
|
1024
1199
|
|
|
1025
1200
|
//#endregion
|
|
1026
1201
|
//#region src/core/Vertex.ts
|
|
1202
|
+
/**
|
|
1203
|
+
* Event-driven state container that processes events to update state.
|
|
1204
|
+
* Use with event handlers registered via the on() method.
|
|
1205
|
+
*
|
|
1206
|
+
* @template S - State type
|
|
1207
|
+
* @template E - Event type (extends BaseEvent)
|
|
1208
|
+
* @template P - Props type (optional)
|
|
1209
|
+
*/
|
|
1027
1210
|
var Vertex = class extends StateContainer {
|
|
1028
1211
|
constructor(initialState) {
|
|
1029
1212
|
super(initialState);
|
|
@@ -1077,122 +1260,22 @@ var Vertex = class extends StateContainer {
|
|
|
1077
1260
|
this.onEventError(event, error$1);
|
|
1078
1261
|
}
|
|
1079
1262
|
}
|
|
1263
|
+
/**
|
|
1264
|
+
* Handle errors that occur during event processing.
|
|
1265
|
+
* Override this method to implement custom error handling.
|
|
1266
|
+
* @param _event - The event that caused the error
|
|
1267
|
+
* @param _error - The error that occurred
|
|
1268
|
+
*/
|
|
1080
1269
|
onEventError(_event, _error) {}
|
|
1081
1270
|
};
|
|
1082
|
-
/**
|
|
1083
|
-
* Example: Counter Events
|
|
1084
|
-
*/
|
|
1085
|
-
var IncrementEvent = class {
|
|
1086
|
-
constructor(amount = 1) {
|
|
1087
|
-
this.amount = amount;
|
|
1088
|
-
this.type = "increment";
|
|
1089
|
-
this.timestamp = Date.now();
|
|
1090
|
-
}
|
|
1091
|
-
};
|
|
1092
|
-
var DecrementEvent = class {
|
|
1093
|
-
constructor(amount = 1) {
|
|
1094
|
-
this.amount = amount;
|
|
1095
|
-
this.type = "decrement";
|
|
1096
|
-
this.timestamp = Date.now();
|
|
1097
|
-
}
|
|
1098
|
-
};
|
|
1099
|
-
var ResetEvent = class {
|
|
1100
|
-
constructor() {
|
|
1101
|
-
this.type = "reset";
|
|
1102
|
-
this.timestamp = Date.now();
|
|
1103
|
-
}
|
|
1104
|
-
};
|
|
1105
|
-
/**
|
|
1106
|
-
* Example: Counter Vertex
|
|
1107
|
-
* Demonstrates proper typing and event handling
|
|
1108
|
-
*/
|
|
1109
|
-
var CounterVertex = class extends Vertex {
|
|
1110
|
-
constructor() {
|
|
1111
|
-
super(0);
|
|
1112
|
-
this.increment = (amount = 1) => {
|
|
1113
|
-
this.add(new IncrementEvent(amount));
|
|
1114
|
-
};
|
|
1115
|
-
this.decrement = (amount = 1) => {
|
|
1116
|
-
this.add(new DecrementEvent(amount));
|
|
1117
|
-
};
|
|
1118
|
-
this.reset = () => {
|
|
1119
|
-
this.add(new ResetEvent());
|
|
1120
|
-
};
|
|
1121
|
-
this.on(IncrementEvent, (event, emit) => {
|
|
1122
|
-
emit(this.state + event.amount);
|
|
1123
|
-
});
|
|
1124
|
-
this.on(DecrementEvent, (event, emit) => {
|
|
1125
|
-
emit(this.state - event.amount);
|
|
1126
|
-
});
|
|
1127
|
-
this.on(ResetEvent, (_, emit) => {
|
|
1128
|
-
emit(0);
|
|
1129
|
-
});
|
|
1130
|
-
}
|
|
1131
|
-
};
|
|
1132
|
-
var LoginEvent = class {
|
|
1133
|
-
constructor(email, password) {
|
|
1134
|
-
this.email = email;
|
|
1135
|
-
this.password = password;
|
|
1136
|
-
this.type = "login";
|
|
1137
|
-
this.timestamp = Date.now();
|
|
1138
|
-
}
|
|
1139
|
-
};
|
|
1140
|
-
var LogoutEvent = class {
|
|
1141
|
-
constructor() {
|
|
1142
|
-
this.type = "logout";
|
|
1143
|
-
this.timestamp = Date.now();
|
|
1144
|
-
}
|
|
1145
|
-
};
|
|
1146
|
-
var AuthVertex = class extends Vertex {
|
|
1147
|
-
constructor() {
|
|
1148
|
-
super({
|
|
1149
|
-
isAuthenticated: false,
|
|
1150
|
-
isLoading: false,
|
|
1151
|
-
user: null,
|
|
1152
|
-
error: null
|
|
1153
|
-
});
|
|
1154
|
-
this.login = (email, password) => {
|
|
1155
|
-
this.add(new LoginEvent(email, password));
|
|
1156
|
-
};
|
|
1157
|
-
this.logout = () => {
|
|
1158
|
-
this.add(new LogoutEvent());
|
|
1159
|
-
};
|
|
1160
|
-
this.on(LoginEvent, (event, emit) => {
|
|
1161
|
-
emit({
|
|
1162
|
-
...this.state,
|
|
1163
|
-
isLoading: true,
|
|
1164
|
-
error: null
|
|
1165
|
-
});
|
|
1166
|
-
if (event.email === "user@example.com" && event.password === "password") emit({
|
|
1167
|
-
isAuthenticated: true,
|
|
1168
|
-
isLoading: false,
|
|
1169
|
-
user: {
|
|
1170
|
-
id: "123",
|
|
1171
|
-
name: "Test User",
|
|
1172
|
-
email: "user@example.com"
|
|
1173
|
-
},
|
|
1174
|
-
error: null
|
|
1175
|
-
});
|
|
1176
|
-
else emit({
|
|
1177
|
-
isAuthenticated: false,
|
|
1178
|
-
isLoading: false,
|
|
1179
|
-
user: null,
|
|
1180
|
-
error: "Invalid credentials"
|
|
1181
|
-
});
|
|
1182
|
-
});
|
|
1183
|
-
this.on(LogoutEvent, (_, emit) => {
|
|
1184
|
-
emit({
|
|
1185
|
-
isAuthenticated: false,
|
|
1186
|
-
isLoading: false,
|
|
1187
|
-
user: null,
|
|
1188
|
-
error: null
|
|
1189
|
-
});
|
|
1190
|
-
});
|
|
1191
|
-
}
|
|
1192
|
-
};
|
|
1193
1271
|
|
|
1194
1272
|
//#endregion
|
|
1195
1273
|
//#region src/plugin/BlacPlugin.ts
|
|
1274
|
+
/**
|
|
1275
|
+
* Type guard to check if a plugin has a required onInstall hook
|
|
1276
|
+
* @param plugin - The plugin to check
|
|
1277
|
+
* @returns true if the plugin implements BlacPluginWithInit
|
|
1278
|
+
*/
|
|
1196
1279
|
function hasInitHook(plugin) {
|
|
1197
1280
|
return typeof plugin.onInstall === "function";
|
|
1198
1281
|
}
|
|
@@ -1205,12 +1288,16 @@ function hasInitHook(plugin) {
|
|
|
1205
1288
|
* This module provides a functional approach to proxy-based dependency tracking.
|
|
1206
1289
|
* Unlike the class-based ProxyTracker, this uses a state object pattern that's
|
|
1207
1290
|
* easier to integrate with functional programming patterns and framework hooks.
|
|
1291
|
+
*
|
|
1292
|
+
* @internal
|
|
1208
1293
|
*/
|
|
1209
1294
|
/**
|
|
1210
1295
|
* Check if a value can be proxied
|
|
1211
1296
|
*
|
|
1212
1297
|
* Returns true for plain objects and arrays only.
|
|
1213
1298
|
* Excludes built-in objects like Date, Map, Set, etc.
|
|
1299
|
+
*
|
|
1300
|
+
* @internal
|
|
1214
1301
|
*/
|
|
1215
1302
|
function isProxyable(value) {
|
|
1216
1303
|
if (typeof value !== "object" || value === null) return false;
|
|
@@ -1226,6 +1313,8 @@ function isProxyable(value) {
|
|
|
1226
1313
|
* const proxy = createProxyForTarget(state, myObject);
|
|
1227
1314
|
* // ... use proxy ...
|
|
1228
1315
|
* const paths = stopProxyTracking(state);
|
|
1316
|
+
*
|
|
1317
|
+
* @internal
|
|
1229
1318
|
*/
|
|
1230
1319
|
function createProxyTrackerState() {
|
|
1231
1320
|
return {
|
|
@@ -1242,6 +1331,8 @@ function createProxyTrackerState() {
|
|
|
1242
1331
|
* Start tracking property accesses
|
|
1243
1332
|
*
|
|
1244
1333
|
* Clears previous tracked paths and enables tracking mode.
|
|
1334
|
+
*
|
|
1335
|
+
* @internal
|
|
1245
1336
|
*/
|
|
1246
1337
|
function startProxyTracking(state) {
|
|
1247
1338
|
state.isTracking = true;
|
|
@@ -1251,6 +1342,8 @@ function startProxyTracking(state) {
|
|
|
1251
1342
|
* Stop tracking and return the tracked paths
|
|
1252
1343
|
*
|
|
1253
1344
|
* Returns a new Set containing all tracked paths.
|
|
1345
|
+
*
|
|
1346
|
+
* @internal
|
|
1254
1347
|
*/
|
|
1255
1348
|
function stopProxyTracking(state) {
|
|
1256
1349
|
state.isTracking = false;
|
|
@@ -1263,6 +1356,8 @@ function stopProxyTracking(state) {
|
|
|
1263
1356
|
* - Array element access (arr[0])
|
|
1264
1357
|
* - Length access (arr.length)
|
|
1265
1358
|
* - Array method calls (arr.map, arr.filter, etc.)
|
|
1359
|
+
*
|
|
1360
|
+
* @internal
|
|
1266
1361
|
*/
|
|
1267
1362
|
function createArrayProxy(state, target, path, depth = 0) {
|
|
1268
1363
|
const proxy = new Proxy(target, { get: (arr, prop) => {
|
|
@@ -1307,6 +1402,8 @@ function createArrayProxy(state, target, path, depth = 0) {
|
|
|
1307
1402
|
* - Nested property access (obj.nested.prop)
|
|
1308
1403
|
* - 'in' operator usage ('prop' in obj)
|
|
1309
1404
|
* - Object.keys, Object.entries, etc.
|
|
1405
|
+
*
|
|
1406
|
+
* @internal
|
|
1310
1407
|
*/
|
|
1311
1408
|
function createProxyInternal(state, target, path = "", depth = 0) {
|
|
1312
1409
|
if (!state.isTracking || !isProxyable(target)) return target;
|
|
@@ -1354,6 +1451,8 @@ function createProxyInternal(state, target, path = "", depth = 0) {
|
|
|
1354
1451
|
* Otherwise, creates a new proxy and caches it.
|
|
1355
1452
|
*
|
|
1356
1453
|
* This is the main entry point for creating tracked proxies.
|
|
1454
|
+
*
|
|
1455
|
+
* @internal
|
|
1357
1456
|
*/
|
|
1358
1457
|
function createProxyForTarget(state, target) {
|
|
1359
1458
|
if (state.lastProxiedState === target && state.lastProxy) return state.lastProxy;
|
|
@@ -1372,16 +1471,22 @@ function createProxyForTarget(state, target) {
|
|
|
1372
1471
|
*
|
|
1373
1472
|
* Provides utilities for parsing property paths and extracting values
|
|
1374
1473
|
* from nested objects using path strings.
|
|
1474
|
+
*
|
|
1475
|
+
* @internal
|
|
1375
1476
|
*/
|
|
1376
1477
|
/**
|
|
1377
1478
|
* Parse a property path string into an array of segments
|
|
1378
1479
|
*
|
|
1480
|
+
* @internal
|
|
1481
|
+
*
|
|
1379
1482
|
* Handles both dot notation (a.b.c) and bracket notation (a[0].b)
|
|
1380
1483
|
*
|
|
1381
1484
|
* @example
|
|
1485
|
+
* ```ts
|
|
1382
1486
|
* parsePath('user.name') // ['user', 'name']
|
|
1383
1487
|
* parsePath('items[0].name') // ['items', '0', 'name']
|
|
1384
1488
|
* parsePath('data.users[2].address.city') // ['data', 'users', '2', 'address', 'city']
|
|
1489
|
+
* ```
|
|
1385
1490
|
*/
|
|
1386
1491
|
function parsePath(path) {
|
|
1387
1492
|
const segments = [];
|
|
@@ -1409,10 +1514,14 @@ function parsePath(path) {
|
|
|
1409
1514
|
* Get a value from an object using a path of segments
|
|
1410
1515
|
*
|
|
1411
1516
|
* @example
|
|
1517
|
+
* ```ts
|
|
1412
1518
|
* const obj = { user: { name: 'Alice', age: 30 } }
|
|
1413
1519
|
* getValueAtPath(obj, ['user', 'name']) // 'Alice'
|
|
1414
1520
|
* getValueAtPath(obj, ['user', 'age']) // 30
|
|
1415
1521
|
* getValueAtPath(obj, ['user', 'missing']) // undefined
|
|
1522
|
+
* ```
|
|
1523
|
+
*
|
|
1524
|
+
* @internal
|
|
1416
1525
|
*/
|
|
1417
1526
|
function getValueAtPath(obj, segments) {
|
|
1418
1527
|
if (obj == null) return void 0;
|
|
@@ -1429,9 +1538,13 @@ function getValueAtPath(obj, segments) {
|
|
|
1429
1538
|
* Compares two arrays element-by-element using Object.is
|
|
1430
1539
|
*
|
|
1431
1540
|
* @example
|
|
1541
|
+
* ```ts
|
|
1432
1542
|
* shallowEqual([1, 2, 3], [1, 2, 3]) // true
|
|
1433
1543
|
* shallowEqual([1, 2, 3], [1, 2, 4]) // false
|
|
1434
1544
|
* shallowEqual([1, 2], [1, 2, 3]) // false
|
|
1545
|
+
* ```
|
|
1546
|
+
*
|
|
1547
|
+
* @internal
|
|
1435
1548
|
*/
|
|
1436
1549
|
function shallowEqual(arr1, arr2) {
|
|
1437
1550
|
if (arr1.length !== arr2.length) return false;
|
|
@@ -1459,6 +1572,9 @@ function getArrayParentPath(path) {
|
|
|
1459
1572
|
if (arrayIndexMatch) return arrayIndexMatch[1];
|
|
1460
1573
|
return null;
|
|
1461
1574
|
}
|
|
1575
|
+
/**
|
|
1576
|
+
* @internal
|
|
1577
|
+
*/
|
|
1462
1578
|
function optimizeTrackedPaths(paths) {
|
|
1463
1579
|
if (paths.size === 0) return /* @__PURE__ */ new Set();
|
|
1464
1580
|
if (paths.size === 1) return new Set(paths);
|
|
@@ -1480,6 +1596,9 @@ function optimizeTrackedPaths(paths) {
|
|
|
1480
1596
|
for (const arrayParent of arrayParents) optimized.add(arrayParent);
|
|
1481
1597
|
return optimized;
|
|
1482
1598
|
}
|
|
1599
|
+
/**
|
|
1600
|
+
* @internal
|
|
1601
|
+
*/
|
|
1483
1602
|
function createTrackerState() {
|
|
1484
1603
|
return {
|
|
1485
1604
|
proxyTrackerState: createProxyTrackerState(),
|
|
@@ -1490,12 +1609,21 @@ function createTrackerState() {
|
|
|
1490
1609
|
lastCheckedValues: /* @__PURE__ */ new Map()
|
|
1491
1610
|
};
|
|
1492
1611
|
}
|
|
1612
|
+
/**
|
|
1613
|
+
* @internal
|
|
1614
|
+
*/
|
|
1493
1615
|
function startTracking(tracker) {
|
|
1494
1616
|
startProxyTracking(tracker.proxyTrackerState);
|
|
1495
1617
|
}
|
|
1618
|
+
/**
|
|
1619
|
+
* @internal
|
|
1620
|
+
*/
|
|
1496
1621
|
function createProxy(tracker, state) {
|
|
1497
1622
|
return createProxyForTarget(tracker.proxyTrackerState, state);
|
|
1498
1623
|
}
|
|
1624
|
+
/**
|
|
1625
|
+
* @internal
|
|
1626
|
+
*/
|
|
1499
1627
|
function captureTrackedPaths(tracker, state) {
|
|
1500
1628
|
tracker.previousRenderPaths = tracker.currentRenderPaths;
|
|
1501
1629
|
tracker.currentRenderPaths = optimizeTrackedPaths(stopProxyTracking(tracker.proxyTrackerState));
|
|
@@ -1516,6 +1644,9 @@ function captureTrackedPaths(tracker, state) {
|
|
|
1516
1644
|
}
|
|
1517
1645
|
tracker.lastCheckedValues.clear();
|
|
1518
1646
|
}
|
|
1647
|
+
/**
|
|
1648
|
+
* @internal
|
|
1649
|
+
*/
|
|
1519
1650
|
function hasChanges(tracker, state) {
|
|
1520
1651
|
if (tracker.pathCache.size === 0) return true;
|
|
1521
1652
|
tracker.lastCheckedValues.clear();
|
|
@@ -1530,12 +1661,20 @@ function hasChanges(tracker, state) {
|
|
|
1530
1661
|
tracker.lastCheckedState = state;
|
|
1531
1662
|
return false;
|
|
1532
1663
|
}
|
|
1664
|
+
/**
|
|
1665
|
+
* @internal
|
|
1666
|
+
*/
|
|
1533
1667
|
function hasTrackedData(tracker) {
|
|
1534
1668
|
return tracker.proxyTrackerState.trackedPaths.size > 0 || tracker.pathCache.size > 0 || tracker.previousRenderPaths.size > 0;
|
|
1535
1669
|
}
|
|
1536
1670
|
|
|
1537
1671
|
//#endregion
|
|
1538
1672
|
//#region src/adapter/framework-adapter.ts
|
|
1673
|
+
/**
|
|
1674
|
+
* Manages subscriptions to external bloc dependencies for getter tracking.
|
|
1675
|
+
* When a getter accesses another bloc's state, this manager ensures
|
|
1676
|
+
* re-renders occur when those external dependencies change.
|
|
1677
|
+
*/
|
|
1539
1678
|
var ExternalDependencyManager = class {
|
|
1540
1679
|
constructor() {
|
|
1541
1680
|
this.subscriptions = [];
|
|
@@ -1546,6 +1685,14 @@ var ExternalDependencyManager = class {
|
|
|
1546
1685
|
for (const dep of newDeps) if (!oldDeps.has(dep)) return false;
|
|
1547
1686
|
return true;
|
|
1548
1687
|
}
|
|
1688
|
+
/**
|
|
1689
|
+
* Update subscriptions to external bloc dependencies.
|
|
1690
|
+
* Creates subscriptions to blocs accessed via getters.
|
|
1691
|
+
* @param getterTracker - The getter tracker state with external dependencies
|
|
1692
|
+
* @param rawInstance - The primary bloc instance (excluded from subscriptions)
|
|
1693
|
+
* @param onGetterChange - Callback to invoke when external dependency changes
|
|
1694
|
+
* @returns true if subscriptions were updated, false if unchanged
|
|
1695
|
+
*/
|
|
1549
1696
|
updateSubscriptions(getterTracker, rawInstance, onGetterChange) {
|
|
1550
1697
|
if (!getterTracker?.externalDependencies) return false;
|
|
1551
1698
|
const currentDeps = getterTracker.externalDependencies;
|
|
@@ -1566,11 +1713,21 @@ var ExternalDependencyManager = class {
|
|
|
1566
1713
|
clearExternalDependencies(getterTracker);
|
|
1567
1714
|
return true;
|
|
1568
1715
|
}
|
|
1716
|
+
/**
|
|
1717
|
+
* Clean up all active subscriptions
|
|
1718
|
+
*/
|
|
1569
1719
|
cleanup() {
|
|
1570
1720
|
this.subscriptions.forEach((unsub) => unsub());
|
|
1571
1721
|
this.subscriptions = [];
|
|
1572
1722
|
}
|
|
1573
1723
|
};
|
|
1724
|
+
/**
|
|
1725
|
+
* Create a subscribe function for auto-tracking mode.
|
|
1726
|
+
* Only triggers callback when tracked properties change.
|
|
1727
|
+
* @param instance - The state container instance
|
|
1728
|
+
* @param adapterState - The adapter state for tracking
|
|
1729
|
+
* @returns Subscribe function for use with useSyncExternalStore
|
|
1730
|
+
*/
|
|
1574
1731
|
function createAutoTrackSubscribe(instance, adapterState) {
|
|
1575
1732
|
return (callback) => {
|
|
1576
1733
|
return instance.subscribe(() => {
|
|
@@ -1589,6 +1746,14 @@ function createAutoTrackSubscribe(instance, adapterState) {
|
|
|
1589
1746
|
});
|
|
1590
1747
|
};
|
|
1591
1748
|
}
|
|
1749
|
+
/**
|
|
1750
|
+
* Create a subscribe function for manual dependency tracking mode.
|
|
1751
|
+
* Only triggers callback when dependencies array changes.
|
|
1752
|
+
* @param instance - The state container instance
|
|
1753
|
+
* @param adapterState - The adapter state for caching
|
|
1754
|
+
* @param config - Configuration with dependencies function
|
|
1755
|
+
* @returns Subscribe function for use with useSyncExternalStore
|
|
1756
|
+
*/
|
|
1592
1757
|
function createManualDepsSubscribe(instance, adapterState, config) {
|
|
1593
1758
|
return (callback) => {
|
|
1594
1759
|
return instance.subscribe(() => {
|
|
@@ -1600,9 +1765,22 @@ function createManualDepsSubscribe(instance, adapterState, config) {
|
|
|
1600
1765
|
});
|
|
1601
1766
|
};
|
|
1602
1767
|
}
|
|
1768
|
+
/**
|
|
1769
|
+
* Create a subscribe function for no-tracking mode.
|
|
1770
|
+
* Triggers callback on every state change.
|
|
1771
|
+
* @param instance - The state container instance
|
|
1772
|
+
* @returns Subscribe function for use with useSyncExternalStore
|
|
1773
|
+
*/
|
|
1603
1774
|
function createNoTrackSubscribe(instance) {
|
|
1604
1775
|
return (callback) => instance.subscribe(callback);
|
|
1605
1776
|
}
|
|
1777
|
+
/**
|
|
1778
|
+
* Create a snapshot function for auto-tracking mode.
|
|
1779
|
+
* Returns a proxied state that tracks property access.
|
|
1780
|
+
* @param instance - The state container instance
|
|
1781
|
+
* @param adapterState - The adapter state for tracking
|
|
1782
|
+
* @returns Snapshot function for use with useSyncExternalStore
|
|
1783
|
+
*/
|
|
1606
1784
|
function createAutoTrackSnapshot(instance, adapterState) {
|
|
1607
1785
|
return () => {
|
|
1608
1786
|
const tracker = adapterState.tracker || (adapterState.tracker = createTrackerState());
|
|
@@ -1617,15 +1795,35 @@ function createAutoTrackSnapshot(instance, adapterState) {
|
|
|
1617
1795
|
return createProxy(tracker, instance.state);
|
|
1618
1796
|
};
|
|
1619
1797
|
}
|
|
1798
|
+
/**
|
|
1799
|
+
* Create a snapshot function for manual dependency tracking mode.
|
|
1800
|
+
* Caches dependencies for comparison on next render.
|
|
1801
|
+
* @param instance - The state container instance
|
|
1802
|
+
* @param adapterState - The adapter state for caching
|
|
1803
|
+
* @param config - Configuration with dependencies function
|
|
1804
|
+
* @returns Snapshot function for use with useSyncExternalStore
|
|
1805
|
+
*/
|
|
1620
1806
|
function createManualDepsSnapshot(instance, adapterState, config) {
|
|
1621
1807
|
return () => {
|
|
1622
1808
|
adapterState.manualDepsCache = config.dependencies(instance.state, instance);
|
|
1623
1809
|
return instance.state;
|
|
1624
1810
|
};
|
|
1625
1811
|
}
|
|
1812
|
+
/**
|
|
1813
|
+
* Create a snapshot function for no-tracking mode.
|
|
1814
|
+
* Returns the raw state directly.
|
|
1815
|
+
* @param instance - The state container instance
|
|
1816
|
+
* @returns Snapshot function for use with useSyncExternalStore
|
|
1817
|
+
*/
|
|
1626
1818
|
function createNoTrackSnapshot(instance) {
|
|
1627
1819
|
return () => instance.state;
|
|
1628
1820
|
}
|
|
1821
|
+
/**
|
|
1822
|
+
* Initialize adapter state for auto-tracking mode.
|
|
1823
|
+
* Creates getter tracker and proxied bloc instance.
|
|
1824
|
+
* @param instance - The state container instance
|
|
1825
|
+
* @returns Initialized adapter state
|
|
1826
|
+
*/
|
|
1629
1827
|
function initAutoTrackState(instance) {
|
|
1630
1828
|
return {
|
|
1631
1829
|
tracker: null,
|
|
@@ -1634,6 +1832,12 @@ function initAutoTrackState(instance) {
|
|
|
1634
1832
|
proxiedBloc: createBlocProxy(instance)
|
|
1635
1833
|
};
|
|
1636
1834
|
}
|
|
1835
|
+
/**
|
|
1836
|
+
* Initialize adapter state for manual dependency tracking mode.
|
|
1837
|
+
* No proxy is created; bloc is used directly.
|
|
1838
|
+
* @param instance - The state container instance
|
|
1839
|
+
* @returns Initialized adapter state
|
|
1840
|
+
*/
|
|
1637
1841
|
function initManualDepsState(instance) {
|
|
1638
1842
|
return {
|
|
1639
1843
|
tracker: null,
|
|
@@ -1642,6 +1846,12 @@ function initManualDepsState(instance) {
|
|
|
1642
1846
|
proxiedBloc: instance
|
|
1643
1847
|
};
|
|
1644
1848
|
}
|
|
1849
|
+
/**
|
|
1850
|
+
* Initialize adapter state for no-tracking mode.
|
|
1851
|
+
* No tracking or proxy is created.
|
|
1852
|
+
* @param instance - The state container instance
|
|
1853
|
+
* @returns Initialized adapter state
|
|
1854
|
+
*/
|
|
1645
1855
|
function initNoTrackState(instance) {
|
|
1646
1856
|
return {
|
|
1647
1857
|
tracker: null,
|
|
@@ -1650,6 +1860,12 @@ function initNoTrackState(instance) {
|
|
|
1650
1860
|
proxiedBloc: instance
|
|
1651
1861
|
};
|
|
1652
1862
|
}
|
|
1863
|
+
/**
|
|
1864
|
+
* Disable getter tracking after render phase completes.
|
|
1865
|
+
* Clears the active tracker to prevent tracking outside of render.
|
|
1866
|
+
* @param adapterState - The adapter state
|
|
1867
|
+
* @param rawInstance - The raw bloc instance
|
|
1868
|
+
*/
|
|
1653
1869
|
function disableGetterTracking(adapterState, rawInstance) {
|
|
1654
1870
|
if (adapterState.getterTracker) {
|
|
1655
1871
|
adapterState.getterTracker.isTracking = false;
|
|
@@ -1659,10 +1875,17 @@ function disableGetterTracking(adapterState, rawInstance) {
|
|
|
1659
1875
|
|
|
1660
1876
|
//#endregion
|
|
1661
1877
|
//#region src/logging/Logger.ts
|
|
1878
|
+
/**
|
|
1879
|
+
* Log severity levels (lower number = higher severity)
|
|
1880
|
+
*/
|
|
1662
1881
|
let LogLevel = /* @__PURE__ */ function(LogLevel$1) {
|
|
1882
|
+
/** Critical errors that may cause application failure */
|
|
1663
1883
|
LogLevel$1[LogLevel$1["ERROR"] = 0] = "ERROR";
|
|
1884
|
+
/** Warning conditions that should be addressed */
|
|
1664
1885
|
LogLevel$1[LogLevel$1["WARN"] = 1] = "WARN";
|
|
1886
|
+
/** Informational messages about application state */
|
|
1665
1887
|
LogLevel$1[LogLevel$1["INFO"] = 2] = "INFO";
|
|
1888
|
+
/** Detailed debugging information */
|
|
1666
1889
|
LogLevel$1[LogLevel$1["DEBUG"] = 3] = "DEBUG";
|
|
1667
1890
|
return LogLevel$1;
|
|
1668
1891
|
}({});
|
|
@@ -1731,9 +1954,33 @@ let currentConfig = {
|
|
|
1731
1954
|
output: (entry) => console.log(JSON.stringify(entry))
|
|
1732
1955
|
};
|
|
1733
1956
|
let defaultLogger = createLogger(currentConfig);
|
|
1957
|
+
/**
|
|
1958
|
+
* Log a debug message (tree-shakeable export)
|
|
1959
|
+
* @param context - Context identifier (module or component name)
|
|
1960
|
+
* @param message - Log message
|
|
1961
|
+
* @param data - Optional structured data
|
|
1962
|
+
*/
|
|
1734
1963
|
const debug = (context, message, data) => defaultLogger.debug(context, message, data);
|
|
1964
|
+
/**
|
|
1965
|
+
* Log an info message (tree-shakeable export)
|
|
1966
|
+
* @param context - Context identifier (module or component name)
|
|
1967
|
+
* @param message - Log message
|
|
1968
|
+
* @param data - Optional structured data
|
|
1969
|
+
*/
|
|
1735
1970
|
const info = (context, message, data) => defaultLogger.info(context, message, data);
|
|
1971
|
+
/**
|
|
1972
|
+
* Log a warning message (tree-shakeable export)
|
|
1973
|
+
* @param context - Context identifier (module or component name)
|
|
1974
|
+
* @param message - Log message
|
|
1975
|
+
* @param data - Optional structured data
|
|
1976
|
+
*/
|
|
1736
1977
|
const warn = (context, message, data) => defaultLogger.warn(context, message, data);
|
|
1978
|
+
/**
|
|
1979
|
+
* Log an error message (tree-shakeable export)
|
|
1980
|
+
* @param context - Context identifier (module or component name)
|
|
1981
|
+
* @param message - Log message
|
|
1982
|
+
* @param data - Optional structured data
|
|
1983
|
+
*/
|
|
1737
1984
|
const error = (context, message, data) => defaultLogger.error(context, message, data);
|
|
1738
1985
|
/**
|
|
1739
1986
|
* Configuration function that recreates the default logger
|
|
@@ -1759,7 +2006,7 @@ function configureLogger(opts) {
|
|
|
1759
2006
|
* Decorator to configure StateContainer classes.
|
|
1760
2007
|
*
|
|
1761
2008
|
* @example Decorator syntax (requires experimentalDecorators or TC39 decorators)
|
|
1762
|
-
* ```
|
|
2009
|
+
* ```ts
|
|
1763
2010
|
* @blac({ isolated: true })
|
|
1764
2011
|
* class FormBloc extends Cubit<FormState> {}
|
|
1765
2012
|
*
|
|
@@ -1771,7 +2018,7 @@ function configureLogger(opts) {
|
|
|
1771
2018
|
* ```
|
|
1772
2019
|
*
|
|
1773
2020
|
* @example Function syntax (no decorator support needed)
|
|
1774
|
-
* ```
|
|
2021
|
+
* ```ts
|
|
1775
2022
|
* const FormBloc = blac({ isolated: true })(
|
|
1776
2023
|
* class extends Cubit<FormState> {}
|
|
1777
2024
|
* );
|
|
@@ -1787,25 +2034,16 @@ function blac(options) {
|
|
|
1787
2034
|
}
|
|
1788
2035
|
|
|
1789
2036
|
//#endregion
|
|
1790
|
-
exports.AuthVertex = AuthVertex;
|
|
1791
2037
|
exports.BLAC_DEFAULTS = BLAC_DEFAULTS;
|
|
1792
2038
|
exports.BLAC_ERROR_PREFIX = BLAC_ERROR_PREFIX;
|
|
1793
2039
|
exports.BLAC_ID_PATTERNS = BLAC_ID_PATTERNS;
|
|
1794
2040
|
exports.BLAC_STATIC_PROPS = BLAC_STATIC_PROPS;
|
|
1795
|
-
exports.CounterCubit = CounterCubit;
|
|
1796
|
-
exports.CounterVertex = CounterVertex;
|
|
1797
2041
|
exports.Cubit = Cubit;
|
|
1798
|
-
exports.DecrementEvent = DecrementEvent;
|
|
1799
2042
|
exports.ExternalDependencyManager = ExternalDependencyManager;
|
|
1800
|
-
exports.IncrementEvent = IncrementEvent;
|
|
1801
2043
|
exports.LogLevel = LogLevel;
|
|
1802
|
-
exports.LoginEvent = LoginEvent;
|
|
1803
|
-
exports.LogoutEvent = LogoutEvent;
|
|
1804
2044
|
exports.PluginManager = PluginManager;
|
|
1805
|
-
exports.ResetEvent = ResetEvent;
|
|
1806
2045
|
exports.StateContainer = StateContainer;
|
|
1807
2046
|
exports.StateContainerRegistry = StateContainerRegistry;
|
|
1808
|
-
exports.TodoCubit = TodoCubit;
|
|
1809
2047
|
exports.Vertex = Vertex;
|
|
1810
2048
|
exports.__resetIdCounters = __resetIdCounters;
|
|
1811
2049
|
exports.blac = blac;
|