@blac/core 2.0.0-rc.10 → 2.0.0-rc.11
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 +427 -197
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +1298 -21
- package/dist/index.d.ts +1298 -21
- package/dist/index.js +428 -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,124 @@ 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
|
+
* @param instanceKey - Optional instance key (defaults to 'default')
|
|
891
|
+
* @param constructorArgs - Arguments to pass to constructor if creating new instance
|
|
892
|
+
* @returns The state container instance
|
|
893
|
+
*/
|
|
753
894
|
static resolve(instanceKey, constructorArgs) {
|
|
754
895
|
return StateContainer._registry.resolve(this, instanceKey, constructorArgs);
|
|
755
896
|
}
|
|
897
|
+
/**
|
|
898
|
+
* Get an existing instance without incrementing ref count (borrowing semantics).
|
|
899
|
+
* @param instanceKey - Optional instance key (defaults to 'default')
|
|
900
|
+
* @returns The state container instance
|
|
901
|
+
* @throws Error if instance doesn't exist
|
|
902
|
+
*/
|
|
756
903
|
static get(instanceKey) {
|
|
757
904
|
return StateContainer._registry.get(this, instanceKey);
|
|
758
905
|
}
|
|
906
|
+
/**
|
|
907
|
+
* Safely get an existing instance with error handling.
|
|
908
|
+
* @param instanceKey - Optional instance key (defaults to 'default')
|
|
909
|
+
* @returns Discriminated union with either the instance or an error
|
|
910
|
+
*/
|
|
759
911
|
static getSafe(instanceKey) {
|
|
760
912
|
return StateContainer._registry.getSafe(this, instanceKey);
|
|
761
913
|
}
|
|
914
|
+
/**
|
|
915
|
+
* Connect to an instance for bloc-to-bloc communication (borrowing semantics).
|
|
916
|
+
* Gets or creates instance without incrementing ref count.
|
|
917
|
+
* @param instanceKey - Optional instance key (defaults to 'default')
|
|
918
|
+
* @param constructorArgs - Arguments to pass to constructor if creating new instance
|
|
919
|
+
* @returns The state container instance
|
|
920
|
+
*/
|
|
762
921
|
static connect(instanceKey, constructorArgs) {
|
|
763
922
|
return StateContainer._registry.connect(this, instanceKey, constructorArgs);
|
|
764
923
|
}
|
|
924
|
+
/**
|
|
925
|
+
* Release a reference to an instance.
|
|
926
|
+
* Decrements ref count and disposes when it reaches 0 (unless keepAlive).
|
|
927
|
+
* @param instanceKey - Optional instance key (defaults to 'default')
|
|
928
|
+
* @param forceDispose - Force immediate disposal regardless of ref count
|
|
929
|
+
*/
|
|
765
930
|
static release(instanceKey, forceDispose = false) {
|
|
766
931
|
StateContainer._registry.release(this, instanceKey, forceDispose);
|
|
767
932
|
}
|
|
933
|
+
/**
|
|
934
|
+
* Get all instances of this class
|
|
935
|
+
* @returns Array of all instances
|
|
936
|
+
*/
|
|
768
937
|
static getAll() {
|
|
769
938
|
return StateContainer._registry.getAll(this);
|
|
770
939
|
}
|
|
940
|
+
/**
|
|
941
|
+
* Iterate over all instances of this class
|
|
942
|
+
* @param callback - Function to call for each instance
|
|
943
|
+
*/
|
|
771
944
|
static forEach(callback) {
|
|
772
945
|
StateContainer._registry.forEach(this, callback);
|
|
773
946
|
}
|
|
947
|
+
/**
|
|
948
|
+
* Clear all instances of this class (disposes them)
|
|
949
|
+
*/
|
|
774
950
|
static clear() {
|
|
775
951
|
StateContainer._registry.clear(this);
|
|
776
952
|
}
|
|
953
|
+
/**
|
|
954
|
+
* Clear all instances from all registered types
|
|
955
|
+
*/
|
|
777
956
|
static clearAllInstances() {
|
|
778
957
|
StateContainer._registry.clearAll();
|
|
779
958
|
}
|
|
959
|
+
/**
|
|
960
|
+
* Get registry statistics for debugging
|
|
961
|
+
* @returns Object with registeredTypes, totalInstances, and typeBreakdown
|
|
962
|
+
*/
|
|
780
963
|
static getStats() {
|
|
781
964
|
return StateContainer._registry.getStats();
|
|
782
965
|
}
|
|
966
|
+
/**
|
|
967
|
+
* Get reference count for an instance
|
|
968
|
+
* @param instanceKey - Optional instance key (defaults to 'default')
|
|
969
|
+
* @returns Current ref count (0 if instance doesn't exist)
|
|
970
|
+
*/
|
|
783
971
|
static getRefCount(instanceKey) {
|
|
784
972
|
return StateContainer._registry.getRefCount(this, instanceKey);
|
|
785
973
|
}
|
|
974
|
+
/**
|
|
975
|
+
* Check if an instance exists
|
|
976
|
+
* @param instanceKey - Optional instance key (defaults to 'default')
|
|
977
|
+
* @returns true if instance exists
|
|
978
|
+
*/
|
|
786
979
|
static hasInstance(instanceKey) {
|
|
787
980
|
return StateContainer._registry.hasInstance(this, instanceKey);
|
|
788
981
|
}
|
|
982
|
+
/** Current props value passed to this container */
|
|
789
983
|
get props() {
|
|
790
984
|
return this._props;
|
|
791
985
|
}
|
|
@@ -813,6 +1007,11 @@ var StateContainer = class StateContainer {
|
|
|
813
1007
|
};
|
|
814
1008
|
this._state = initialState;
|
|
815
1009
|
}
|
|
1010
|
+
/**
|
|
1011
|
+
* Initialize configuration for this instance.
|
|
1012
|
+
* Called by the registry after construction.
|
|
1013
|
+
* @param config - Configuration options
|
|
1014
|
+
*/
|
|
816
1015
|
initConfig(config) {
|
|
817
1016
|
this.config = { ...config };
|
|
818
1017
|
this.name = this.config.name || this.constructor.name;
|
|
@@ -820,17 +1019,28 @@ var StateContainer = class StateContainer {
|
|
|
820
1019
|
this.instanceId = generateSimpleId(this.constructor.name, this.config.instanceId);
|
|
821
1020
|
StateContainer._registry.emit("created", this);
|
|
822
1021
|
}
|
|
1022
|
+
/** Current state value */
|
|
823
1023
|
get state() {
|
|
824
1024
|
return this._state;
|
|
825
1025
|
}
|
|
1026
|
+
/** Whether this instance has been disposed */
|
|
826
1027
|
get isDisposed() {
|
|
827
1028
|
return this._disposed;
|
|
828
1029
|
}
|
|
1030
|
+
/**
|
|
1031
|
+
* Subscribe to state changes
|
|
1032
|
+
* @param listener - Function called when state changes
|
|
1033
|
+
* @returns Unsubscribe function
|
|
1034
|
+
*/
|
|
829
1035
|
subscribe(listener) {
|
|
830
1036
|
if (this._disposed) throw new Error(`Cannot subscribe to disposed container ${this.name}`);
|
|
831
1037
|
this.listeners.add(listener);
|
|
832
1038
|
return () => this.listeners.delete(listener);
|
|
833
1039
|
}
|
|
1040
|
+
/**
|
|
1041
|
+
* Dispose this instance and clean up resources.
|
|
1042
|
+
* Clears all listeners and emits the 'dispose' system event.
|
|
1043
|
+
*/
|
|
834
1044
|
dispose() {
|
|
835
1045
|
if (this._disposed) return;
|
|
836
1046
|
if (this.debug) console.log(`[${this.name}] Disposing...`);
|
|
@@ -841,6 +1051,11 @@ var StateContainer = class StateContainer {
|
|
|
841
1051
|
StateContainer._registry.emit("disposed", this);
|
|
842
1052
|
if (this.debug) console.log(`[${this.name}] Disposed successfully`);
|
|
843
1053
|
}
|
|
1054
|
+
/**
|
|
1055
|
+
* Emit a new state value and notify all listeners.
|
|
1056
|
+
* @param newState - The new state value
|
|
1057
|
+
* @protected
|
|
1058
|
+
*/
|
|
844
1059
|
emit(newState) {
|
|
845
1060
|
if (this._disposed) throw new Error(`Cannot emit state from disposed container ${this.name}`);
|
|
846
1061
|
if (this._state === newState) return;
|
|
@@ -900,6 +1115,11 @@ var StateContainer = class StateContainer {
|
|
|
900
1115
|
if (segments.length > 3) path = segments.slice(-3).join("/");
|
|
901
1116
|
return path;
|
|
902
1117
|
}
|
|
1118
|
+
/**
|
|
1119
|
+
* Update state using a transform function.
|
|
1120
|
+
* @param updater - Function that receives current state and returns new state
|
|
1121
|
+
* @protected
|
|
1122
|
+
*/
|
|
903
1123
|
update(updater) {
|
|
904
1124
|
if (this._disposed) throw new Error(`Cannot update state from disposed container ${this.name}`);
|
|
905
1125
|
this.emit(updater(this._state));
|
|
@@ -913,6 +1133,11 @@ var StateContainer = class StateContainer {
|
|
|
913
1133
|
console.error(`[${this.name}] Error in system event handler:`, error$1);
|
|
914
1134
|
}
|
|
915
1135
|
}
|
|
1136
|
+
/**
|
|
1137
|
+
* Update the props for this container.
|
|
1138
|
+
* Emits the 'propsUpdated' system event.
|
|
1139
|
+
* @param newProps - The new props value
|
|
1140
|
+
*/
|
|
916
1141
|
updateProps(newProps) {
|
|
917
1142
|
if (this._disposed) throw new Error(`Cannot update props on disposed container ${this.name}`);
|
|
918
1143
|
const previousProps = this._props;
|
|
@@ -930,6 +1155,13 @@ var StateContainer = class StateContainer {
|
|
|
930
1155
|
|
|
931
1156
|
//#endregion
|
|
932
1157
|
//#region src/core/Cubit.ts
|
|
1158
|
+
/**
|
|
1159
|
+
* Simple state container with direct state emission.
|
|
1160
|
+
* Extends StateContainer with public methods for emitting and updating state.
|
|
1161
|
+
*
|
|
1162
|
+
* @template S - State type
|
|
1163
|
+
* @template P - Props type (optional)
|
|
1164
|
+
*/
|
|
933
1165
|
var Cubit = class extends StateContainer {
|
|
934
1166
|
constructor(initialState) {
|
|
935
1167
|
super(initialState);
|
|
@@ -941,89 +1173,32 @@ var Cubit = class extends StateContainer {
|
|
|
941
1173
|
}));
|
|
942
1174
|
});
|
|
943
1175
|
}
|
|
1176
|
+
/**
|
|
1177
|
+
* Replace state with a new value and notify all listeners
|
|
1178
|
+
* @param newState - The new state value
|
|
1179
|
+
*/
|
|
944
1180
|
emit(newState) {
|
|
945
1181
|
super["emit"](newState);
|
|
946
1182
|
}
|
|
1183
|
+
/**
|
|
1184
|
+
* Transform current state using an updater function and emit the new state
|
|
1185
|
+
* @param updater - Function that receives current state and returns new state
|
|
1186
|
+
*/
|
|
947
1187
|
update(updater) {
|
|
948
1188
|
super["update"](updater);
|
|
949
1189
|
}
|
|
950
1190
|
};
|
|
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
1191
|
|
|
1025
1192
|
//#endregion
|
|
1026
1193
|
//#region src/core/Vertex.ts
|
|
1194
|
+
/**
|
|
1195
|
+
* Event-driven state container that processes events to update state.
|
|
1196
|
+
* Use with event handlers registered via the on() method.
|
|
1197
|
+
*
|
|
1198
|
+
* @template S - State type
|
|
1199
|
+
* @template E - Event type (extends BaseEvent)
|
|
1200
|
+
* @template P - Props type (optional)
|
|
1201
|
+
*/
|
|
1027
1202
|
var Vertex = class extends StateContainer {
|
|
1028
1203
|
constructor(initialState) {
|
|
1029
1204
|
super(initialState);
|
|
@@ -1077,122 +1252,22 @@ var Vertex = class extends StateContainer {
|
|
|
1077
1252
|
this.onEventError(event, error$1);
|
|
1078
1253
|
}
|
|
1079
1254
|
}
|
|
1255
|
+
/**
|
|
1256
|
+
* Handle errors that occur during event processing.
|
|
1257
|
+
* Override this method to implement custom error handling.
|
|
1258
|
+
* @param _event - The event that caused the error
|
|
1259
|
+
* @param _error - The error that occurred
|
|
1260
|
+
*/
|
|
1080
1261
|
onEventError(_event, _error) {}
|
|
1081
1262
|
};
|
|
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
1263
|
|
|
1194
1264
|
//#endregion
|
|
1195
1265
|
//#region src/plugin/BlacPlugin.ts
|
|
1266
|
+
/**
|
|
1267
|
+
* Type guard to check if a plugin has a required onInstall hook
|
|
1268
|
+
* @param plugin - The plugin to check
|
|
1269
|
+
* @returns true if the plugin implements BlacPluginWithInit
|
|
1270
|
+
*/
|
|
1196
1271
|
function hasInitHook(plugin) {
|
|
1197
1272
|
return typeof plugin.onInstall === "function";
|
|
1198
1273
|
}
|
|
@@ -1205,12 +1280,16 @@ function hasInitHook(plugin) {
|
|
|
1205
1280
|
* This module provides a functional approach to proxy-based dependency tracking.
|
|
1206
1281
|
* Unlike the class-based ProxyTracker, this uses a state object pattern that's
|
|
1207
1282
|
* easier to integrate with functional programming patterns and framework hooks.
|
|
1283
|
+
*
|
|
1284
|
+
* @internal
|
|
1208
1285
|
*/
|
|
1209
1286
|
/**
|
|
1210
1287
|
* Check if a value can be proxied
|
|
1211
1288
|
*
|
|
1212
1289
|
* Returns true for plain objects and arrays only.
|
|
1213
1290
|
* Excludes built-in objects like Date, Map, Set, etc.
|
|
1291
|
+
*
|
|
1292
|
+
* @internal
|
|
1214
1293
|
*/
|
|
1215
1294
|
function isProxyable(value) {
|
|
1216
1295
|
if (typeof value !== "object" || value === null) return false;
|
|
@@ -1226,6 +1305,8 @@ function isProxyable(value) {
|
|
|
1226
1305
|
* const proxy = createProxyForTarget(state, myObject);
|
|
1227
1306
|
* // ... use proxy ...
|
|
1228
1307
|
* const paths = stopProxyTracking(state);
|
|
1308
|
+
*
|
|
1309
|
+
* @internal
|
|
1229
1310
|
*/
|
|
1230
1311
|
function createProxyTrackerState() {
|
|
1231
1312
|
return {
|
|
@@ -1242,6 +1323,8 @@ function createProxyTrackerState() {
|
|
|
1242
1323
|
* Start tracking property accesses
|
|
1243
1324
|
*
|
|
1244
1325
|
* Clears previous tracked paths and enables tracking mode.
|
|
1326
|
+
*
|
|
1327
|
+
* @internal
|
|
1245
1328
|
*/
|
|
1246
1329
|
function startProxyTracking(state) {
|
|
1247
1330
|
state.isTracking = true;
|
|
@@ -1251,6 +1334,8 @@ function startProxyTracking(state) {
|
|
|
1251
1334
|
* Stop tracking and return the tracked paths
|
|
1252
1335
|
*
|
|
1253
1336
|
* Returns a new Set containing all tracked paths.
|
|
1337
|
+
*
|
|
1338
|
+
* @internal
|
|
1254
1339
|
*/
|
|
1255
1340
|
function stopProxyTracking(state) {
|
|
1256
1341
|
state.isTracking = false;
|
|
@@ -1263,6 +1348,8 @@ function stopProxyTracking(state) {
|
|
|
1263
1348
|
* - Array element access (arr[0])
|
|
1264
1349
|
* - Length access (arr.length)
|
|
1265
1350
|
* - Array method calls (arr.map, arr.filter, etc.)
|
|
1351
|
+
*
|
|
1352
|
+
* @internal
|
|
1266
1353
|
*/
|
|
1267
1354
|
function createArrayProxy(state, target, path, depth = 0) {
|
|
1268
1355
|
const proxy = new Proxy(target, { get: (arr, prop) => {
|
|
@@ -1307,6 +1394,8 @@ function createArrayProxy(state, target, path, depth = 0) {
|
|
|
1307
1394
|
* - Nested property access (obj.nested.prop)
|
|
1308
1395
|
* - 'in' operator usage ('prop' in obj)
|
|
1309
1396
|
* - Object.keys, Object.entries, etc.
|
|
1397
|
+
*
|
|
1398
|
+
* @internal
|
|
1310
1399
|
*/
|
|
1311
1400
|
function createProxyInternal(state, target, path = "", depth = 0) {
|
|
1312
1401
|
if (!state.isTracking || !isProxyable(target)) return target;
|
|
@@ -1354,6 +1443,8 @@ function createProxyInternal(state, target, path = "", depth = 0) {
|
|
|
1354
1443
|
* Otherwise, creates a new proxy and caches it.
|
|
1355
1444
|
*
|
|
1356
1445
|
* This is the main entry point for creating tracked proxies.
|
|
1446
|
+
*
|
|
1447
|
+
* @internal
|
|
1357
1448
|
*/
|
|
1358
1449
|
function createProxyForTarget(state, target) {
|
|
1359
1450
|
if (state.lastProxiedState === target && state.lastProxy) return state.lastProxy;
|
|
@@ -1372,16 +1463,22 @@ function createProxyForTarget(state, target) {
|
|
|
1372
1463
|
*
|
|
1373
1464
|
* Provides utilities for parsing property paths and extracting values
|
|
1374
1465
|
* from nested objects using path strings.
|
|
1466
|
+
*
|
|
1467
|
+
* @internal
|
|
1375
1468
|
*/
|
|
1376
1469
|
/**
|
|
1377
1470
|
* Parse a property path string into an array of segments
|
|
1378
1471
|
*
|
|
1472
|
+
* @internal
|
|
1473
|
+
*
|
|
1379
1474
|
* Handles both dot notation (a.b.c) and bracket notation (a[0].b)
|
|
1380
1475
|
*
|
|
1381
1476
|
* @example
|
|
1477
|
+
* ```ts
|
|
1382
1478
|
* parsePath('user.name') // ['user', 'name']
|
|
1383
1479
|
* parsePath('items[0].name') // ['items', '0', 'name']
|
|
1384
1480
|
* parsePath('data.users[2].address.city') // ['data', 'users', '2', 'address', 'city']
|
|
1481
|
+
* ```
|
|
1385
1482
|
*/
|
|
1386
1483
|
function parsePath(path) {
|
|
1387
1484
|
const segments = [];
|
|
@@ -1409,10 +1506,14 @@ function parsePath(path) {
|
|
|
1409
1506
|
* Get a value from an object using a path of segments
|
|
1410
1507
|
*
|
|
1411
1508
|
* @example
|
|
1509
|
+
* ```ts
|
|
1412
1510
|
* const obj = { user: { name: 'Alice', age: 30 } }
|
|
1413
1511
|
* getValueAtPath(obj, ['user', 'name']) // 'Alice'
|
|
1414
1512
|
* getValueAtPath(obj, ['user', 'age']) // 30
|
|
1415
1513
|
* getValueAtPath(obj, ['user', 'missing']) // undefined
|
|
1514
|
+
* ```
|
|
1515
|
+
*
|
|
1516
|
+
* @internal
|
|
1416
1517
|
*/
|
|
1417
1518
|
function getValueAtPath(obj, segments) {
|
|
1418
1519
|
if (obj == null) return void 0;
|
|
@@ -1429,9 +1530,13 @@ function getValueAtPath(obj, segments) {
|
|
|
1429
1530
|
* Compares two arrays element-by-element using Object.is
|
|
1430
1531
|
*
|
|
1431
1532
|
* @example
|
|
1533
|
+
* ```ts
|
|
1432
1534
|
* shallowEqual([1, 2, 3], [1, 2, 3]) // true
|
|
1433
1535
|
* shallowEqual([1, 2, 3], [1, 2, 4]) // false
|
|
1434
1536
|
* shallowEqual([1, 2], [1, 2, 3]) // false
|
|
1537
|
+
* ```
|
|
1538
|
+
*
|
|
1539
|
+
* @internal
|
|
1435
1540
|
*/
|
|
1436
1541
|
function shallowEqual(arr1, arr2) {
|
|
1437
1542
|
if (arr1.length !== arr2.length) return false;
|
|
@@ -1459,6 +1564,9 @@ function getArrayParentPath(path) {
|
|
|
1459
1564
|
if (arrayIndexMatch) return arrayIndexMatch[1];
|
|
1460
1565
|
return null;
|
|
1461
1566
|
}
|
|
1567
|
+
/**
|
|
1568
|
+
* @internal
|
|
1569
|
+
*/
|
|
1462
1570
|
function optimizeTrackedPaths(paths) {
|
|
1463
1571
|
if (paths.size === 0) return /* @__PURE__ */ new Set();
|
|
1464
1572
|
if (paths.size === 1) return new Set(paths);
|
|
@@ -1480,6 +1588,9 @@ function optimizeTrackedPaths(paths) {
|
|
|
1480
1588
|
for (const arrayParent of arrayParents) optimized.add(arrayParent);
|
|
1481
1589
|
return optimized;
|
|
1482
1590
|
}
|
|
1591
|
+
/**
|
|
1592
|
+
* @internal
|
|
1593
|
+
*/
|
|
1483
1594
|
function createTrackerState() {
|
|
1484
1595
|
return {
|
|
1485
1596
|
proxyTrackerState: createProxyTrackerState(),
|
|
@@ -1490,12 +1601,21 @@ function createTrackerState() {
|
|
|
1490
1601
|
lastCheckedValues: /* @__PURE__ */ new Map()
|
|
1491
1602
|
};
|
|
1492
1603
|
}
|
|
1604
|
+
/**
|
|
1605
|
+
* @internal
|
|
1606
|
+
*/
|
|
1493
1607
|
function startTracking(tracker) {
|
|
1494
1608
|
startProxyTracking(tracker.proxyTrackerState);
|
|
1495
1609
|
}
|
|
1610
|
+
/**
|
|
1611
|
+
* @internal
|
|
1612
|
+
*/
|
|
1496
1613
|
function createProxy(tracker, state) {
|
|
1497
1614
|
return createProxyForTarget(tracker.proxyTrackerState, state);
|
|
1498
1615
|
}
|
|
1616
|
+
/**
|
|
1617
|
+
* @internal
|
|
1618
|
+
*/
|
|
1499
1619
|
function captureTrackedPaths(tracker, state) {
|
|
1500
1620
|
tracker.previousRenderPaths = tracker.currentRenderPaths;
|
|
1501
1621
|
tracker.currentRenderPaths = optimizeTrackedPaths(stopProxyTracking(tracker.proxyTrackerState));
|
|
@@ -1516,6 +1636,9 @@ function captureTrackedPaths(tracker, state) {
|
|
|
1516
1636
|
}
|
|
1517
1637
|
tracker.lastCheckedValues.clear();
|
|
1518
1638
|
}
|
|
1639
|
+
/**
|
|
1640
|
+
* @internal
|
|
1641
|
+
*/
|
|
1519
1642
|
function hasChanges(tracker, state) {
|
|
1520
1643
|
if (tracker.pathCache.size === 0) return true;
|
|
1521
1644
|
tracker.lastCheckedValues.clear();
|
|
@@ -1530,12 +1653,20 @@ function hasChanges(tracker, state) {
|
|
|
1530
1653
|
tracker.lastCheckedState = state;
|
|
1531
1654
|
return false;
|
|
1532
1655
|
}
|
|
1656
|
+
/**
|
|
1657
|
+
* @internal
|
|
1658
|
+
*/
|
|
1533
1659
|
function hasTrackedData(tracker) {
|
|
1534
1660
|
return tracker.proxyTrackerState.trackedPaths.size > 0 || tracker.pathCache.size > 0 || tracker.previousRenderPaths.size > 0;
|
|
1535
1661
|
}
|
|
1536
1662
|
|
|
1537
1663
|
//#endregion
|
|
1538
1664
|
//#region src/adapter/framework-adapter.ts
|
|
1665
|
+
/**
|
|
1666
|
+
* Manages subscriptions to external bloc dependencies for getter tracking.
|
|
1667
|
+
* When a getter accesses another bloc's state, this manager ensures
|
|
1668
|
+
* re-renders occur when those external dependencies change.
|
|
1669
|
+
*/
|
|
1539
1670
|
var ExternalDependencyManager = class {
|
|
1540
1671
|
constructor() {
|
|
1541
1672
|
this.subscriptions = [];
|
|
@@ -1546,6 +1677,14 @@ var ExternalDependencyManager = class {
|
|
|
1546
1677
|
for (const dep of newDeps) if (!oldDeps.has(dep)) return false;
|
|
1547
1678
|
return true;
|
|
1548
1679
|
}
|
|
1680
|
+
/**
|
|
1681
|
+
* Update subscriptions to external bloc dependencies.
|
|
1682
|
+
* Creates subscriptions to blocs accessed via getters.
|
|
1683
|
+
* @param getterTracker - The getter tracker state with external dependencies
|
|
1684
|
+
* @param rawInstance - The primary bloc instance (excluded from subscriptions)
|
|
1685
|
+
* @param onGetterChange - Callback to invoke when external dependency changes
|
|
1686
|
+
* @returns true if subscriptions were updated, false if unchanged
|
|
1687
|
+
*/
|
|
1549
1688
|
updateSubscriptions(getterTracker, rawInstance, onGetterChange) {
|
|
1550
1689
|
if (!getterTracker?.externalDependencies) return false;
|
|
1551
1690
|
const currentDeps = getterTracker.externalDependencies;
|
|
@@ -1566,11 +1705,21 @@ var ExternalDependencyManager = class {
|
|
|
1566
1705
|
clearExternalDependencies(getterTracker);
|
|
1567
1706
|
return true;
|
|
1568
1707
|
}
|
|
1708
|
+
/**
|
|
1709
|
+
* Clean up all active subscriptions
|
|
1710
|
+
*/
|
|
1569
1711
|
cleanup() {
|
|
1570
1712
|
this.subscriptions.forEach((unsub) => unsub());
|
|
1571
1713
|
this.subscriptions = [];
|
|
1572
1714
|
}
|
|
1573
1715
|
};
|
|
1716
|
+
/**
|
|
1717
|
+
* Create a subscribe function for auto-tracking mode.
|
|
1718
|
+
* Only triggers callback when tracked properties change.
|
|
1719
|
+
* @param instance - The state container instance
|
|
1720
|
+
* @param adapterState - The adapter state for tracking
|
|
1721
|
+
* @returns Subscribe function for use with useSyncExternalStore
|
|
1722
|
+
*/
|
|
1574
1723
|
function createAutoTrackSubscribe(instance, adapterState) {
|
|
1575
1724
|
return (callback) => {
|
|
1576
1725
|
return instance.subscribe(() => {
|
|
@@ -1589,6 +1738,14 @@ function createAutoTrackSubscribe(instance, adapterState) {
|
|
|
1589
1738
|
});
|
|
1590
1739
|
};
|
|
1591
1740
|
}
|
|
1741
|
+
/**
|
|
1742
|
+
* Create a subscribe function for manual dependency tracking mode.
|
|
1743
|
+
* Only triggers callback when dependencies array changes.
|
|
1744
|
+
* @param instance - The state container instance
|
|
1745
|
+
* @param adapterState - The adapter state for caching
|
|
1746
|
+
* @param config - Configuration with dependencies function
|
|
1747
|
+
* @returns Subscribe function for use with useSyncExternalStore
|
|
1748
|
+
*/
|
|
1592
1749
|
function createManualDepsSubscribe(instance, adapterState, config) {
|
|
1593
1750
|
return (callback) => {
|
|
1594
1751
|
return instance.subscribe(() => {
|
|
@@ -1600,9 +1757,22 @@ function createManualDepsSubscribe(instance, adapterState, config) {
|
|
|
1600
1757
|
});
|
|
1601
1758
|
};
|
|
1602
1759
|
}
|
|
1760
|
+
/**
|
|
1761
|
+
* Create a subscribe function for no-tracking mode.
|
|
1762
|
+
* Triggers callback on every state change.
|
|
1763
|
+
* @param instance - The state container instance
|
|
1764
|
+
* @returns Subscribe function for use with useSyncExternalStore
|
|
1765
|
+
*/
|
|
1603
1766
|
function createNoTrackSubscribe(instance) {
|
|
1604
1767
|
return (callback) => instance.subscribe(callback);
|
|
1605
1768
|
}
|
|
1769
|
+
/**
|
|
1770
|
+
* Create a snapshot function for auto-tracking mode.
|
|
1771
|
+
* Returns a proxied state that tracks property access.
|
|
1772
|
+
* @param instance - The state container instance
|
|
1773
|
+
* @param adapterState - The adapter state for tracking
|
|
1774
|
+
* @returns Snapshot function for use with useSyncExternalStore
|
|
1775
|
+
*/
|
|
1606
1776
|
function createAutoTrackSnapshot(instance, adapterState) {
|
|
1607
1777
|
return () => {
|
|
1608
1778
|
const tracker = adapterState.tracker || (adapterState.tracker = createTrackerState());
|
|
@@ -1617,15 +1787,35 @@ function createAutoTrackSnapshot(instance, adapterState) {
|
|
|
1617
1787
|
return createProxy(tracker, instance.state);
|
|
1618
1788
|
};
|
|
1619
1789
|
}
|
|
1790
|
+
/**
|
|
1791
|
+
* Create a snapshot function for manual dependency tracking mode.
|
|
1792
|
+
* Caches dependencies for comparison on next render.
|
|
1793
|
+
* @param instance - The state container instance
|
|
1794
|
+
* @param adapterState - The adapter state for caching
|
|
1795
|
+
* @param config - Configuration with dependencies function
|
|
1796
|
+
* @returns Snapshot function for use with useSyncExternalStore
|
|
1797
|
+
*/
|
|
1620
1798
|
function createManualDepsSnapshot(instance, adapterState, config) {
|
|
1621
1799
|
return () => {
|
|
1622
1800
|
adapterState.manualDepsCache = config.dependencies(instance.state, instance);
|
|
1623
1801
|
return instance.state;
|
|
1624
1802
|
};
|
|
1625
1803
|
}
|
|
1804
|
+
/**
|
|
1805
|
+
* Create a snapshot function for no-tracking mode.
|
|
1806
|
+
* Returns the raw state directly.
|
|
1807
|
+
* @param instance - The state container instance
|
|
1808
|
+
* @returns Snapshot function for use with useSyncExternalStore
|
|
1809
|
+
*/
|
|
1626
1810
|
function createNoTrackSnapshot(instance) {
|
|
1627
1811
|
return () => instance.state;
|
|
1628
1812
|
}
|
|
1813
|
+
/**
|
|
1814
|
+
* Initialize adapter state for auto-tracking mode.
|
|
1815
|
+
* Creates getter tracker and proxied bloc instance.
|
|
1816
|
+
* @param instance - The state container instance
|
|
1817
|
+
* @returns Initialized adapter state
|
|
1818
|
+
*/
|
|
1629
1819
|
function initAutoTrackState(instance) {
|
|
1630
1820
|
return {
|
|
1631
1821
|
tracker: null,
|
|
@@ -1634,6 +1824,12 @@ function initAutoTrackState(instance) {
|
|
|
1634
1824
|
proxiedBloc: createBlocProxy(instance)
|
|
1635
1825
|
};
|
|
1636
1826
|
}
|
|
1827
|
+
/**
|
|
1828
|
+
* Initialize adapter state for manual dependency tracking mode.
|
|
1829
|
+
* No proxy is created; bloc is used directly.
|
|
1830
|
+
* @param instance - The state container instance
|
|
1831
|
+
* @returns Initialized adapter state
|
|
1832
|
+
*/
|
|
1637
1833
|
function initManualDepsState(instance) {
|
|
1638
1834
|
return {
|
|
1639
1835
|
tracker: null,
|
|
@@ -1642,6 +1838,12 @@ function initManualDepsState(instance) {
|
|
|
1642
1838
|
proxiedBloc: instance
|
|
1643
1839
|
};
|
|
1644
1840
|
}
|
|
1841
|
+
/**
|
|
1842
|
+
* Initialize adapter state for no-tracking mode.
|
|
1843
|
+
* No tracking or proxy is created.
|
|
1844
|
+
* @param instance - The state container instance
|
|
1845
|
+
* @returns Initialized adapter state
|
|
1846
|
+
*/
|
|
1645
1847
|
function initNoTrackState(instance) {
|
|
1646
1848
|
return {
|
|
1647
1849
|
tracker: null,
|
|
@@ -1650,6 +1852,12 @@ function initNoTrackState(instance) {
|
|
|
1650
1852
|
proxiedBloc: instance
|
|
1651
1853
|
};
|
|
1652
1854
|
}
|
|
1855
|
+
/**
|
|
1856
|
+
* Disable getter tracking after render phase completes.
|
|
1857
|
+
* Clears the active tracker to prevent tracking outside of render.
|
|
1858
|
+
* @param adapterState - The adapter state
|
|
1859
|
+
* @param rawInstance - The raw bloc instance
|
|
1860
|
+
*/
|
|
1653
1861
|
function disableGetterTracking(adapterState, rawInstance) {
|
|
1654
1862
|
if (adapterState.getterTracker) {
|
|
1655
1863
|
adapterState.getterTracker.isTracking = false;
|
|
@@ -1659,10 +1867,17 @@ function disableGetterTracking(adapterState, rawInstance) {
|
|
|
1659
1867
|
|
|
1660
1868
|
//#endregion
|
|
1661
1869
|
//#region src/logging/Logger.ts
|
|
1870
|
+
/**
|
|
1871
|
+
* Log severity levels (lower number = higher severity)
|
|
1872
|
+
*/
|
|
1662
1873
|
let LogLevel = /* @__PURE__ */ function(LogLevel$1) {
|
|
1874
|
+
/** Critical errors that may cause application failure */
|
|
1663
1875
|
LogLevel$1[LogLevel$1["ERROR"] = 0] = "ERROR";
|
|
1876
|
+
/** Warning conditions that should be addressed */
|
|
1664
1877
|
LogLevel$1[LogLevel$1["WARN"] = 1] = "WARN";
|
|
1878
|
+
/** Informational messages about application state */
|
|
1665
1879
|
LogLevel$1[LogLevel$1["INFO"] = 2] = "INFO";
|
|
1880
|
+
/** Detailed debugging information */
|
|
1666
1881
|
LogLevel$1[LogLevel$1["DEBUG"] = 3] = "DEBUG";
|
|
1667
1882
|
return LogLevel$1;
|
|
1668
1883
|
}({});
|
|
@@ -1731,9 +1946,33 @@ let currentConfig = {
|
|
|
1731
1946
|
output: (entry) => console.log(JSON.stringify(entry))
|
|
1732
1947
|
};
|
|
1733
1948
|
let defaultLogger = createLogger(currentConfig);
|
|
1949
|
+
/**
|
|
1950
|
+
* Log a debug message (tree-shakeable export)
|
|
1951
|
+
* @param context - Context identifier (module or component name)
|
|
1952
|
+
* @param message - Log message
|
|
1953
|
+
* @param data - Optional structured data
|
|
1954
|
+
*/
|
|
1734
1955
|
const debug = (context, message, data) => defaultLogger.debug(context, message, data);
|
|
1956
|
+
/**
|
|
1957
|
+
* Log an info message (tree-shakeable export)
|
|
1958
|
+
* @param context - Context identifier (module or component name)
|
|
1959
|
+
* @param message - Log message
|
|
1960
|
+
* @param data - Optional structured data
|
|
1961
|
+
*/
|
|
1735
1962
|
const info = (context, message, data) => defaultLogger.info(context, message, data);
|
|
1963
|
+
/**
|
|
1964
|
+
* Log a warning message (tree-shakeable export)
|
|
1965
|
+
* @param context - Context identifier (module or component name)
|
|
1966
|
+
* @param message - Log message
|
|
1967
|
+
* @param data - Optional structured data
|
|
1968
|
+
*/
|
|
1736
1969
|
const warn = (context, message, data) => defaultLogger.warn(context, message, data);
|
|
1970
|
+
/**
|
|
1971
|
+
* Log an error message (tree-shakeable export)
|
|
1972
|
+
* @param context - Context identifier (module or component name)
|
|
1973
|
+
* @param message - Log message
|
|
1974
|
+
* @param data - Optional structured data
|
|
1975
|
+
*/
|
|
1737
1976
|
const error = (context, message, data) => defaultLogger.error(context, message, data);
|
|
1738
1977
|
/**
|
|
1739
1978
|
* Configuration function that recreates the default logger
|
|
@@ -1759,7 +1998,7 @@ function configureLogger(opts) {
|
|
|
1759
1998
|
* Decorator to configure StateContainer classes.
|
|
1760
1999
|
*
|
|
1761
2000
|
* @example Decorator syntax (requires experimentalDecorators or TC39 decorators)
|
|
1762
|
-
* ```
|
|
2001
|
+
* ```ts
|
|
1763
2002
|
* @blac({ isolated: true })
|
|
1764
2003
|
* class FormBloc extends Cubit<FormState> {}
|
|
1765
2004
|
*
|
|
@@ -1771,7 +2010,7 @@ function configureLogger(opts) {
|
|
|
1771
2010
|
* ```
|
|
1772
2011
|
*
|
|
1773
2012
|
* @example Function syntax (no decorator support needed)
|
|
1774
|
-
* ```
|
|
2013
|
+
* ```ts
|
|
1775
2014
|
* const FormBloc = blac({ isolated: true })(
|
|
1776
2015
|
* class extends Cubit<FormState> {}
|
|
1777
2016
|
* );
|
|
@@ -1787,25 +2026,16 @@ function blac(options) {
|
|
|
1787
2026
|
}
|
|
1788
2027
|
|
|
1789
2028
|
//#endregion
|
|
1790
|
-
exports.AuthVertex = AuthVertex;
|
|
1791
2029
|
exports.BLAC_DEFAULTS = BLAC_DEFAULTS;
|
|
1792
2030
|
exports.BLAC_ERROR_PREFIX = BLAC_ERROR_PREFIX;
|
|
1793
2031
|
exports.BLAC_ID_PATTERNS = BLAC_ID_PATTERNS;
|
|
1794
2032
|
exports.BLAC_STATIC_PROPS = BLAC_STATIC_PROPS;
|
|
1795
|
-
exports.CounterCubit = CounterCubit;
|
|
1796
|
-
exports.CounterVertex = CounterVertex;
|
|
1797
2033
|
exports.Cubit = Cubit;
|
|
1798
|
-
exports.DecrementEvent = DecrementEvent;
|
|
1799
2034
|
exports.ExternalDependencyManager = ExternalDependencyManager;
|
|
1800
|
-
exports.IncrementEvent = IncrementEvent;
|
|
1801
2035
|
exports.LogLevel = LogLevel;
|
|
1802
|
-
exports.LoginEvent = LoginEvent;
|
|
1803
|
-
exports.LogoutEvent = LogoutEvent;
|
|
1804
2036
|
exports.PluginManager = PluginManager;
|
|
1805
|
-
exports.ResetEvent = ResetEvent;
|
|
1806
2037
|
exports.StateContainer = StateContainer;
|
|
1807
2038
|
exports.StateContainerRegistry = StateContainerRegistry;
|
|
1808
|
-
exports.TodoCubit = TodoCubit;
|
|
1809
2039
|
exports.Vertex = Vertex;
|
|
1810
2040
|
exports.__resetIdCounters = __resetIdCounters;
|
|
1811
2041
|
exports.blac = blac;
|