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