@blac/core 2.0.0-rc.10 → 2.0.0-rc.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +435 -197
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +1325 -21
- package/dist/index.d.ts +1325 -21
- package/dist/index.js +436 -189
- package/dist/index.js.map +1 -0
- package/package.json +10 -6
- package/dist/adapter/framework-adapter.d.ts +0 -33
- package/dist/adapter/index.d.ts +0 -8
- package/dist/constants.d.ts +0 -82
- package/dist/core/Cubit.d.ts +0 -40
- package/dist/core/StateContainer.d.ts +0 -78
- package/dist/core/StateContainerRegistry.d.ts +0 -119
- package/dist/core/Vertex.d.ts +0 -74
- package/dist/decorators/blac.d.ts +0 -31
- package/dist/decorators/index.d.ts +0 -2
- package/dist/logging/Logger.d.ts +0 -57
- package/dist/plugin/BlacPlugin.d.ts +0 -46
- package/dist/plugin/PluginManager.d.ts +0 -38
- package/dist/registry/index.d.ts +0 -20
- package/dist/test-utils/index.d.ts +0 -43
- package/dist/tracking/dependency-tracker.d.ts +0 -21
- package/dist/tracking/getter-tracker.d.ts +0 -31
- package/dist/tracking/index.d.ts +0 -38
- package/dist/tracking/path-utils.d.ts +0 -39
- package/dist/tracking/proxy-tracker.d.ts +0 -88
- package/dist/types/branded.d.ts +0 -9
- package/dist/types/events.d.ts +0 -13
- package/dist/types/utilities.d.ts +0 -19
- package/dist/utils/equality.d.ts +0 -9
- package/dist/utils/idGenerator.d.ts +0 -76
- package/dist/utils/immutable.d.ts +0 -16
- package/dist/utils/stack-trace.d.ts +0 -19
- package/dist/utils/static-props.d.ts +0 -29
package/dist/index.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,132 @@ 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
|
+
* @template S - Optional state type override for generic StateContainers
|
|
890
|
+
* @template T - The StateContainer type (inferred from class)
|
|
891
|
+
* @param instanceKey - Optional instance key (defaults to 'default')
|
|
892
|
+
* @param constructorArgs - Arguments to pass to constructor if creating new instance
|
|
893
|
+
* @returns The state container instance
|
|
894
|
+
*/
|
|
752
895
|
static resolve(instanceKey, constructorArgs) {
|
|
753
896
|
return StateContainer._registry.resolve(this, instanceKey, constructorArgs);
|
|
754
897
|
}
|
|
898
|
+
/**
|
|
899
|
+
* Get an existing instance without incrementing ref count (borrowing semantics).
|
|
900
|
+
* @template S - Optional state type override for generic StateContainers
|
|
901
|
+
* @template T - The StateContainer type (inferred from class)
|
|
902
|
+
* @param instanceKey - Optional instance key (defaults to 'default')
|
|
903
|
+
* @returns The state container instance
|
|
904
|
+
* @throws Error if instance doesn't exist
|
|
905
|
+
*/
|
|
755
906
|
static get(instanceKey) {
|
|
756
907
|
return StateContainer._registry.get(this, instanceKey);
|
|
757
908
|
}
|
|
909
|
+
/**
|
|
910
|
+
* Safely get an existing instance with error handling.
|
|
911
|
+
* @template S - Optional state type override for generic StateContainers
|
|
912
|
+
* @template T - The StateContainer type (inferred from class)
|
|
913
|
+
* @param instanceKey - Optional instance key (defaults to 'default')
|
|
914
|
+
* @returns Discriminated union with either the instance or an error
|
|
915
|
+
*/
|
|
758
916
|
static getSafe(instanceKey) {
|
|
759
917
|
return StateContainer._registry.getSafe(this, instanceKey);
|
|
760
918
|
}
|
|
919
|
+
/**
|
|
920
|
+
* Connect to an instance for bloc-to-bloc communication (borrowing semantics).
|
|
921
|
+
* Gets or creates instance without incrementing ref count.
|
|
922
|
+
* @template S - Optional state type override for generic StateContainers
|
|
923
|
+
* @template T - The StateContainer type (inferred from class)
|
|
924
|
+
* @param instanceKey - Optional instance key (defaults to 'default')
|
|
925
|
+
* @param constructorArgs - Arguments to pass to constructor if creating new instance
|
|
926
|
+
* @returns The state container instance
|
|
927
|
+
*/
|
|
761
928
|
static connect(instanceKey, constructorArgs) {
|
|
762
929
|
return StateContainer._registry.connect(this, instanceKey, constructorArgs);
|
|
763
930
|
}
|
|
931
|
+
/**
|
|
932
|
+
* Release a reference to an instance.
|
|
933
|
+
* Decrements ref count and disposes when it reaches 0 (unless keepAlive).
|
|
934
|
+
* @param instanceKey - Optional instance key (defaults to 'default')
|
|
935
|
+
* @param forceDispose - Force immediate disposal regardless of ref count
|
|
936
|
+
*/
|
|
764
937
|
static release(instanceKey, forceDispose = false) {
|
|
765
938
|
StateContainer._registry.release(this, instanceKey, forceDispose);
|
|
766
939
|
}
|
|
940
|
+
/**
|
|
941
|
+
* Get all instances of this class
|
|
942
|
+
* @returns Array of all instances
|
|
943
|
+
*/
|
|
767
944
|
static getAll() {
|
|
768
945
|
return StateContainer._registry.getAll(this);
|
|
769
946
|
}
|
|
947
|
+
/**
|
|
948
|
+
* Iterate over all instances of this class
|
|
949
|
+
* @param callback - Function to call for each instance
|
|
950
|
+
*/
|
|
770
951
|
static forEach(callback) {
|
|
771
952
|
StateContainer._registry.forEach(this, callback);
|
|
772
953
|
}
|
|
954
|
+
/**
|
|
955
|
+
* Clear all instances of this class (disposes them)
|
|
956
|
+
*/
|
|
773
957
|
static clear() {
|
|
774
958
|
StateContainer._registry.clear(this);
|
|
775
959
|
}
|
|
960
|
+
/**
|
|
961
|
+
* Clear all instances from all registered types
|
|
962
|
+
*/
|
|
776
963
|
static clearAllInstances() {
|
|
777
964
|
StateContainer._registry.clearAll();
|
|
778
965
|
}
|
|
966
|
+
/**
|
|
967
|
+
* Get registry statistics for debugging
|
|
968
|
+
* @returns Object with registeredTypes, totalInstances, and typeBreakdown
|
|
969
|
+
*/
|
|
779
970
|
static getStats() {
|
|
780
971
|
return StateContainer._registry.getStats();
|
|
781
972
|
}
|
|
973
|
+
/**
|
|
974
|
+
* Get reference count for an instance
|
|
975
|
+
* @param instanceKey - Optional instance key (defaults to 'default')
|
|
976
|
+
* @returns Current ref count (0 if instance doesn't exist)
|
|
977
|
+
*/
|
|
782
978
|
static getRefCount(instanceKey) {
|
|
783
979
|
return StateContainer._registry.getRefCount(this, instanceKey);
|
|
784
980
|
}
|
|
981
|
+
/**
|
|
982
|
+
* Check if an instance exists
|
|
983
|
+
* @param instanceKey - Optional instance key (defaults to 'default')
|
|
984
|
+
* @returns true if instance exists
|
|
985
|
+
*/
|
|
785
986
|
static hasInstance(instanceKey) {
|
|
786
987
|
return StateContainer._registry.hasInstance(this, instanceKey);
|
|
787
988
|
}
|
|
989
|
+
/** Current props value passed to this container */
|
|
788
990
|
get props() {
|
|
789
991
|
return this._props;
|
|
790
992
|
}
|
|
@@ -812,6 +1014,11 @@ var StateContainer = class StateContainer {
|
|
|
812
1014
|
};
|
|
813
1015
|
this._state = initialState;
|
|
814
1016
|
}
|
|
1017
|
+
/**
|
|
1018
|
+
* Initialize configuration for this instance.
|
|
1019
|
+
* Called by the registry after construction.
|
|
1020
|
+
* @param config - Configuration options
|
|
1021
|
+
*/
|
|
815
1022
|
initConfig(config) {
|
|
816
1023
|
this.config = { ...config };
|
|
817
1024
|
this.name = this.config.name || this.constructor.name;
|
|
@@ -819,17 +1026,28 @@ var StateContainer = class StateContainer {
|
|
|
819
1026
|
this.instanceId = generateSimpleId(this.constructor.name, this.config.instanceId);
|
|
820
1027
|
StateContainer._registry.emit("created", this);
|
|
821
1028
|
}
|
|
1029
|
+
/** Current state value */
|
|
822
1030
|
get state() {
|
|
823
1031
|
return this._state;
|
|
824
1032
|
}
|
|
1033
|
+
/** Whether this instance has been disposed */
|
|
825
1034
|
get isDisposed() {
|
|
826
1035
|
return this._disposed;
|
|
827
1036
|
}
|
|
1037
|
+
/**
|
|
1038
|
+
* Subscribe to state changes
|
|
1039
|
+
* @param listener - Function called when state changes
|
|
1040
|
+
* @returns Unsubscribe function
|
|
1041
|
+
*/
|
|
828
1042
|
subscribe(listener) {
|
|
829
1043
|
if (this._disposed) throw new Error(`Cannot subscribe to disposed container ${this.name}`);
|
|
830
1044
|
this.listeners.add(listener);
|
|
831
1045
|
return () => this.listeners.delete(listener);
|
|
832
1046
|
}
|
|
1047
|
+
/**
|
|
1048
|
+
* Dispose this instance and clean up resources.
|
|
1049
|
+
* Clears all listeners and emits the 'dispose' system event.
|
|
1050
|
+
*/
|
|
833
1051
|
dispose() {
|
|
834
1052
|
if (this._disposed) return;
|
|
835
1053
|
if (this.debug) console.log(`[${this.name}] Disposing...`);
|
|
@@ -840,6 +1058,11 @@ var StateContainer = class StateContainer {
|
|
|
840
1058
|
StateContainer._registry.emit("disposed", this);
|
|
841
1059
|
if (this.debug) console.log(`[${this.name}] Disposed successfully`);
|
|
842
1060
|
}
|
|
1061
|
+
/**
|
|
1062
|
+
* Emit a new state value and notify all listeners.
|
|
1063
|
+
* @param newState - The new state value
|
|
1064
|
+
* @protected
|
|
1065
|
+
*/
|
|
843
1066
|
emit(newState) {
|
|
844
1067
|
if (this._disposed) throw new Error(`Cannot emit state from disposed container ${this.name}`);
|
|
845
1068
|
if (this._state === newState) return;
|
|
@@ -899,6 +1122,11 @@ var StateContainer = class StateContainer {
|
|
|
899
1122
|
if (segments.length > 3) path = segments.slice(-3).join("/");
|
|
900
1123
|
return path;
|
|
901
1124
|
}
|
|
1125
|
+
/**
|
|
1126
|
+
* Update state using a transform function.
|
|
1127
|
+
* @param updater - Function that receives current state and returns new state
|
|
1128
|
+
* @protected
|
|
1129
|
+
*/
|
|
902
1130
|
update(updater) {
|
|
903
1131
|
if (this._disposed) throw new Error(`Cannot update state from disposed container ${this.name}`);
|
|
904
1132
|
this.emit(updater(this._state));
|
|
@@ -912,6 +1140,11 @@ var StateContainer = class StateContainer {
|
|
|
912
1140
|
console.error(`[${this.name}] Error in system event handler:`, error$1);
|
|
913
1141
|
}
|
|
914
1142
|
}
|
|
1143
|
+
/**
|
|
1144
|
+
* Update the props for this container.
|
|
1145
|
+
* Emits the 'propsUpdated' system event.
|
|
1146
|
+
* @param newProps - The new props value
|
|
1147
|
+
*/
|
|
915
1148
|
updateProps(newProps) {
|
|
916
1149
|
if (this._disposed) throw new Error(`Cannot update props on disposed container ${this.name}`);
|
|
917
1150
|
const previousProps = this._props;
|
|
@@ -929,6 +1162,13 @@ var StateContainer = class StateContainer {
|
|
|
929
1162
|
|
|
930
1163
|
//#endregion
|
|
931
1164
|
//#region src/core/Cubit.ts
|
|
1165
|
+
/**
|
|
1166
|
+
* Simple state container with direct state emission.
|
|
1167
|
+
* Extends StateContainer with public methods for emitting and updating state.
|
|
1168
|
+
*
|
|
1169
|
+
* @template S - State type
|
|
1170
|
+
* @template P - Props type (optional)
|
|
1171
|
+
*/
|
|
932
1172
|
var Cubit = class extends StateContainer {
|
|
933
1173
|
constructor(initialState) {
|
|
934
1174
|
super(initialState);
|
|
@@ -940,89 +1180,32 @@ var Cubit = class extends StateContainer {
|
|
|
940
1180
|
}));
|
|
941
1181
|
});
|
|
942
1182
|
}
|
|
1183
|
+
/**
|
|
1184
|
+
* Replace state with a new value and notify all listeners
|
|
1185
|
+
* @param newState - The new state value
|
|
1186
|
+
*/
|
|
943
1187
|
emit(newState) {
|
|
944
1188
|
super["emit"](newState);
|
|
945
1189
|
}
|
|
1190
|
+
/**
|
|
1191
|
+
* Transform current state using an updater function and emit the new state
|
|
1192
|
+
* @param updater - Function that receives current state and returns new state
|
|
1193
|
+
*/
|
|
946
1194
|
update(updater) {
|
|
947
1195
|
super["update"](updater);
|
|
948
1196
|
}
|
|
949
1197
|
};
|
|
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
1198
|
|
|
1024
1199
|
//#endregion
|
|
1025
1200
|
//#region src/core/Vertex.ts
|
|
1201
|
+
/**
|
|
1202
|
+
* Event-driven state container that processes events to update state.
|
|
1203
|
+
* Use with event handlers registered via the on() method.
|
|
1204
|
+
*
|
|
1205
|
+
* @template S - State type
|
|
1206
|
+
* @template E - Event type (extends BaseEvent)
|
|
1207
|
+
* @template P - Props type (optional)
|
|
1208
|
+
*/
|
|
1026
1209
|
var Vertex = class extends StateContainer {
|
|
1027
1210
|
constructor(initialState) {
|
|
1028
1211
|
super(initialState);
|
|
@@ -1076,122 +1259,22 @@ var Vertex = class extends StateContainer {
|
|
|
1076
1259
|
this.onEventError(event, error$1);
|
|
1077
1260
|
}
|
|
1078
1261
|
}
|
|
1262
|
+
/**
|
|
1263
|
+
* Handle errors that occur during event processing.
|
|
1264
|
+
* Override this method to implement custom error handling.
|
|
1265
|
+
* @param _event - The event that caused the error
|
|
1266
|
+
* @param _error - The error that occurred
|
|
1267
|
+
*/
|
|
1079
1268
|
onEventError(_event, _error) {}
|
|
1080
1269
|
};
|
|
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
1270
|
|
|
1193
1271
|
//#endregion
|
|
1194
1272
|
//#region src/plugin/BlacPlugin.ts
|
|
1273
|
+
/**
|
|
1274
|
+
* Type guard to check if a plugin has a required onInstall hook
|
|
1275
|
+
* @param plugin - The plugin to check
|
|
1276
|
+
* @returns true if the plugin implements BlacPluginWithInit
|
|
1277
|
+
*/
|
|
1195
1278
|
function hasInitHook(plugin) {
|
|
1196
1279
|
return typeof plugin.onInstall === "function";
|
|
1197
1280
|
}
|
|
@@ -1204,12 +1287,16 @@ function hasInitHook(plugin) {
|
|
|
1204
1287
|
* This module provides a functional approach to proxy-based dependency tracking.
|
|
1205
1288
|
* Unlike the class-based ProxyTracker, this uses a state object pattern that's
|
|
1206
1289
|
* easier to integrate with functional programming patterns and framework hooks.
|
|
1290
|
+
*
|
|
1291
|
+
* @internal
|
|
1207
1292
|
*/
|
|
1208
1293
|
/**
|
|
1209
1294
|
* Check if a value can be proxied
|
|
1210
1295
|
*
|
|
1211
1296
|
* Returns true for plain objects and arrays only.
|
|
1212
1297
|
* Excludes built-in objects like Date, Map, Set, etc.
|
|
1298
|
+
*
|
|
1299
|
+
* @internal
|
|
1213
1300
|
*/
|
|
1214
1301
|
function isProxyable(value) {
|
|
1215
1302
|
if (typeof value !== "object" || value === null) return false;
|
|
@@ -1225,6 +1312,8 @@ function isProxyable(value) {
|
|
|
1225
1312
|
* const proxy = createProxyForTarget(state, myObject);
|
|
1226
1313
|
* // ... use proxy ...
|
|
1227
1314
|
* const paths = stopProxyTracking(state);
|
|
1315
|
+
*
|
|
1316
|
+
* @internal
|
|
1228
1317
|
*/
|
|
1229
1318
|
function createProxyTrackerState() {
|
|
1230
1319
|
return {
|
|
@@ -1241,6 +1330,8 @@ function createProxyTrackerState() {
|
|
|
1241
1330
|
* Start tracking property accesses
|
|
1242
1331
|
*
|
|
1243
1332
|
* Clears previous tracked paths and enables tracking mode.
|
|
1333
|
+
*
|
|
1334
|
+
* @internal
|
|
1244
1335
|
*/
|
|
1245
1336
|
function startProxyTracking(state) {
|
|
1246
1337
|
state.isTracking = true;
|
|
@@ -1250,6 +1341,8 @@ function startProxyTracking(state) {
|
|
|
1250
1341
|
* Stop tracking and return the tracked paths
|
|
1251
1342
|
*
|
|
1252
1343
|
* Returns a new Set containing all tracked paths.
|
|
1344
|
+
*
|
|
1345
|
+
* @internal
|
|
1253
1346
|
*/
|
|
1254
1347
|
function stopProxyTracking(state) {
|
|
1255
1348
|
state.isTracking = false;
|
|
@@ -1262,6 +1355,8 @@ function stopProxyTracking(state) {
|
|
|
1262
1355
|
* - Array element access (arr[0])
|
|
1263
1356
|
* - Length access (arr.length)
|
|
1264
1357
|
* - Array method calls (arr.map, arr.filter, etc.)
|
|
1358
|
+
*
|
|
1359
|
+
* @internal
|
|
1265
1360
|
*/
|
|
1266
1361
|
function createArrayProxy(state, target, path, depth = 0) {
|
|
1267
1362
|
const proxy = new Proxy(target, { get: (arr, prop) => {
|
|
@@ -1306,6 +1401,8 @@ function createArrayProxy(state, target, path, depth = 0) {
|
|
|
1306
1401
|
* - Nested property access (obj.nested.prop)
|
|
1307
1402
|
* - 'in' operator usage ('prop' in obj)
|
|
1308
1403
|
* - Object.keys, Object.entries, etc.
|
|
1404
|
+
*
|
|
1405
|
+
* @internal
|
|
1309
1406
|
*/
|
|
1310
1407
|
function createProxyInternal(state, target, path = "", depth = 0) {
|
|
1311
1408
|
if (!state.isTracking || !isProxyable(target)) return target;
|
|
@@ -1353,6 +1450,8 @@ function createProxyInternal(state, target, path = "", depth = 0) {
|
|
|
1353
1450
|
* Otherwise, creates a new proxy and caches it.
|
|
1354
1451
|
*
|
|
1355
1452
|
* This is the main entry point for creating tracked proxies.
|
|
1453
|
+
*
|
|
1454
|
+
* @internal
|
|
1356
1455
|
*/
|
|
1357
1456
|
function createProxyForTarget(state, target) {
|
|
1358
1457
|
if (state.lastProxiedState === target && state.lastProxy) return state.lastProxy;
|
|
@@ -1371,16 +1470,22 @@ function createProxyForTarget(state, target) {
|
|
|
1371
1470
|
*
|
|
1372
1471
|
* Provides utilities for parsing property paths and extracting values
|
|
1373
1472
|
* from nested objects using path strings.
|
|
1473
|
+
*
|
|
1474
|
+
* @internal
|
|
1374
1475
|
*/
|
|
1375
1476
|
/**
|
|
1376
1477
|
* Parse a property path string into an array of segments
|
|
1377
1478
|
*
|
|
1479
|
+
* @internal
|
|
1480
|
+
*
|
|
1378
1481
|
* Handles both dot notation (a.b.c) and bracket notation (a[0].b)
|
|
1379
1482
|
*
|
|
1380
1483
|
* @example
|
|
1484
|
+
* ```ts
|
|
1381
1485
|
* parsePath('user.name') // ['user', 'name']
|
|
1382
1486
|
* parsePath('items[0].name') // ['items', '0', 'name']
|
|
1383
1487
|
* parsePath('data.users[2].address.city') // ['data', 'users', '2', 'address', 'city']
|
|
1488
|
+
* ```
|
|
1384
1489
|
*/
|
|
1385
1490
|
function parsePath(path) {
|
|
1386
1491
|
const segments = [];
|
|
@@ -1408,10 +1513,14 @@ function parsePath(path) {
|
|
|
1408
1513
|
* Get a value from an object using a path of segments
|
|
1409
1514
|
*
|
|
1410
1515
|
* @example
|
|
1516
|
+
* ```ts
|
|
1411
1517
|
* const obj = { user: { name: 'Alice', age: 30 } }
|
|
1412
1518
|
* getValueAtPath(obj, ['user', 'name']) // 'Alice'
|
|
1413
1519
|
* getValueAtPath(obj, ['user', 'age']) // 30
|
|
1414
1520
|
* getValueAtPath(obj, ['user', 'missing']) // undefined
|
|
1521
|
+
* ```
|
|
1522
|
+
*
|
|
1523
|
+
* @internal
|
|
1415
1524
|
*/
|
|
1416
1525
|
function getValueAtPath(obj, segments) {
|
|
1417
1526
|
if (obj == null) return void 0;
|
|
@@ -1428,9 +1537,13 @@ function getValueAtPath(obj, segments) {
|
|
|
1428
1537
|
* Compares two arrays element-by-element using Object.is
|
|
1429
1538
|
*
|
|
1430
1539
|
* @example
|
|
1540
|
+
* ```ts
|
|
1431
1541
|
* shallowEqual([1, 2, 3], [1, 2, 3]) // true
|
|
1432
1542
|
* shallowEqual([1, 2, 3], [1, 2, 4]) // false
|
|
1433
1543
|
* shallowEqual([1, 2], [1, 2, 3]) // false
|
|
1544
|
+
* ```
|
|
1545
|
+
*
|
|
1546
|
+
* @internal
|
|
1434
1547
|
*/
|
|
1435
1548
|
function shallowEqual(arr1, arr2) {
|
|
1436
1549
|
if (arr1.length !== arr2.length) return false;
|
|
@@ -1458,6 +1571,9 @@ function getArrayParentPath(path) {
|
|
|
1458
1571
|
if (arrayIndexMatch) return arrayIndexMatch[1];
|
|
1459
1572
|
return null;
|
|
1460
1573
|
}
|
|
1574
|
+
/**
|
|
1575
|
+
* @internal
|
|
1576
|
+
*/
|
|
1461
1577
|
function optimizeTrackedPaths(paths) {
|
|
1462
1578
|
if (paths.size === 0) return /* @__PURE__ */ new Set();
|
|
1463
1579
|
if (paths.size === 1) return new Set(paths);
|
|
@@ -1479,6 +1595,9 @@ function optimizeTrackedPaths(paths) {
|
|
|
1479
1595
|
for (const arrayParent of arrayParents) optimized.add(arrayParent);
|
|
1480
1596
|
return optimized;
|
|
1481
1597
|
}
|
|
1598
|
+
/**
|
|
1599
|
+
* @internal
|
|
1600
|
+
*/
|
|
1482
1601
|
function createTrackerState() {
|
|
1483
1602
|
return {
|
|
1484
1603
|
proxyTrackerState: createProxyTrackerState(),
|
|
@@ -1489,12 +1608,21 @@ function createTrackerState() {
|
|
|
1489
1608
|
lastCheckedValues: /* @__PURE__ */ new Map()
|
|
1490
1609
|
};
|
|
1491
1610
|
}
|
|
1611
|
+
/**
|
|
1612
|
+
* @internal
|
|
1613
|
+
*/
|
|
1492
1614
|
function startTracking(tracker) {
|
|
1493
1615
|
startProxyTracking(tracker.proxyTrackerState);
|
|
1494
1616
|
}
|
|
1617
|
+
/**
|
|
1618
|
+
* @internal
|
|
1619
|
+
*/
|
|
1495
1620
|
function createProxy(tracker, state) {
|
|
1496
1621
|
return createProxyForTarget(tracker.proxyTrackerState, state);
|
|
1497
1622
|
}
|
|
1623
|
+
/**
|
|
1624
|
+
* @internal
|
|
1625
|
+
*/
|
|
1498
1626
|
function captureTrackedPaths(tracker, state) {
|
|
1499
1627
|
tracker.previousRenderPaths = tracker.currentRenderPaths;
|
|
1500
1628
|
tracker.currentRenderPaths = optimizeTrackedPaths(stopProxyTracking(tracker.proxyTrackerState));
|
|
@@ -1515,6 +1643,9 @@ function captureTrackedPaths(tracker, state) {
|
|
|
1515
1643
|
}
|
|
1516
1644
|
tracker.lastCheckedValues.clear();
|
|
1517
1645
|
}
|
|
1646
|
+
/**
|
|
1647
|
+
* @internal
|
|
1648
|
+
*/
|
|
1518
1649
|
function hasChanges(tracker, state) {
|
|
1519
1650
|
if (tracker.pathCache.size === 0) return true;
|
|
1520
1651
|
tracker.lastCheckedValues.clear();
|
|
@@ -1529,12 +1660,20 @@ function hasChanges(tracker, state) {
|
|
|
1529
1660
|
tracker.lastCheckedState = state;
|
|
1530
1661
|
return false;
|
|
1531
1662
|
}
|
|
1663
|
+
/**
|
|
1664
|
+
* @internal
|
|
1665
|
+
*/
|
|
1532
1666
|
function hasTrackedData(tracker) {
|
|
1533
1667
|
return tracker.proxyTrackerState.trackedPaths.size > 0 || tracker.pathCache.size > 0 || tracker.previousRenderPaths.size > 0;
|
|
1534
1668
|
}
|
|
1535
1669
|
|
|
1536
1670
|
//#endregion
|
|
1537
1671
|
//#region src/adapter/framework-adapter.ts
|
|
1672
|
+
/**
|
|
1673
|
+
* Manages subscriptions to external bloc dependencies for getter tracking.
|
|
1674
|
+
* When a getter accesses another bloc's state, this manager ensures
|
|
1675
|
+
* re-renders occur when those external dependencies change.
|
|
1676
|
+
*/
|
|
1538
1677
|
var ExternalDependencyManager = class {
|
|
1539
1678
|
constructor() {
|
|
1540
1679
|
this.subscriptions = [];
|
|
@@ -1545,6 +1684,14 @@ var ExternalDependencyManager = class {
|
|
|
1545
1684
|
for (const dep of newDeps) if (!oldDeps.has(dep)) return false;
|
|
1546
1685
|
return true;
|
|
1547
1686
|
}
|
|
1687
|
+
/**
|
|
1688
|
+
* Update subscriptions to external bloc dependencies.
|
|
1689
|
+
* Creates subscriptions to blocs accessed via getters.
|
|
1690
|
+
* @param getterTracker - The getter tracker state with external dependencies
|
|
1691
|
+
* @param rawInstance - The primary bloc instance (excluded from subscriptions)
|
|
1692
|
+
* @param onGetterChange - Callback to invoke when external dependency changes
|
|
1693
|
+
* @returns true if subscriptions were updated, false if unchanged
|
|
1694
|
+
*/
|
|
1548
1695
|
updateSubscriptions(getterTracker, rawInstance, onGetterChange) {
|
|
1549
1696
|
if (!getterTracker?.externalDependencies) return false;
|
|
1550
1697
|
const currentDeps = getterTracker.externalDependencies;
|
|
@@ -1565,11 +1712,21 @@ var ExternalDependencyManager = class {
|
|
|
1565
1712
|
clearExternalDependencies(getterTracker);
|
|
1566
1713
|
return true;
|
|
1567
1714
|
}
|
|
1715
|
+
/**
|
|
1716
|
+
* Clean up all active subscriptions
|
|
1717
|
+
*/
|
|
1568
1718
|
cleanup() {
|
|
1569
1719
|
this.subscriptions.forEach((unsub) => unsub());
|
|
1570
1720
|
this.subscriptions = [];
|
|
1571
1721
|
}
|
|
1572
1722
|
};
|
|
1723
|
+
/**
|
|
1724
|
+
* Create a subscribe function for auto-tracking mode.
|
|
1725
|
+
* Only triggers callback when tracked properties change.
|
|
1726
|
+
* @param instance - The state container instance
|
|
1727
|
+
* @param adapterState - The adapter state for tracking
|
|
1728
|
+
* @returns Subscribe function for use with useSyncExternalStore
|
|
1729
|
+
*/
|
|
1573
1730
|
function createAutoTrackSubscribe(instance, adapterState) {
|
|
1574
1731
|
return (callback) => {
|
|
1575
1732
|
return instance.subscribe(() => {
|
|
@@ -1588,6 +1745,14 @@ function createAutoTrackSubscribe(instance, adapterState) {
|
|
|
1588
1745
|
});
|
|
1589
1746
|
};
|
|
1590
1747
|
}
|
|
1748
|
+
/**
|
|
1749
|
+
* Create a subscribe function for manual dependency tracking mode.
|
|
1750
|
+
* Only triggers callback when dependencies array changes.
|
|
1751
|
+
* @param instance - The state container instance
|
|
1752
|
+
* @param adapterState - The adapter state for caching
|
|
1753
|
+
* @param config - Configuration with dependencies function
|
|
1754
|
+
* @returns Subscribe function for use with useSyncExternalStore
|
|
1755
|
+
*/
|
|
1591
1756
|
function createManualDepsSubscribe(instance, adapterState, config) {
|
|
1592
1757
|
return (callback) => {
|
|
1593
1758
|
return instance.subscribe(() => {
|
|
@@ -1599,9 +1764,22 @@ function createManualDepsSubscribe(instance, adapterState, config) {
|
|
|
1599
1764
|
});
|
|
1600
1765
|
};
|
|
1601
1766
|
}
|
|
1767
|
+
/**
|
|
1768
|
+
* Create a subscribe function for no-tracking mode.
|
|
1769
|
+
* Triggers callback on every state change.
|
|
1770
|
+
* @param instance - The state container instance
|
|
1771
|
+
* @returns Subscribe function for use with useSyncExternalStore
|
|
1772
|
+
*/
|
|
1602
1773
|
function createNoTrackSubscribe(instance) {
|
|
1603
1774
|
return (callback) => instance.subscribe(callback);
|
|
1604
1775
|
}
|
|
1776
|
+
/**
|
|
1777
|
+
* Create a snapshot function for auto-tracking mode.
|
|
1778
|
+
* Returns a proxied state that tracks property access.
|
|
1779
|
+
* @param instance - The state container instance
|
|
1780
|
+
* @param adapterState - The adapter state for tracking
|
|
1781
|
+
* @returns Snapshot function for use with useSyncExternalStore
|
|
1782
|
+
*/
|
|
1605
1783
|
function createAutoTrackSnapshot(instance, adapterState) {
|
|
1606
1784
|
return () => {
|
|
1607
1785
|
const tracker = adapterState.tracker || (adapterState.tracker = createTrackerState());
|
|
@@ -1616,15 +1794,35 @@ function createAutoTrackSnapshot(instance, adapterState) {
|
|
|
1616
1794
|
return createProxy(tracker, instance.state);
|
|
1617
1795
|
};
|
|
1618
1796
|
}
|
|
1797
|
+
/**
|
|
1798
|
+
* Create a snapshot function for manual dependency tracking mode.
|
|
1799
|
+
* Caches dependencies for comparison on next render.
|
|
1800
|
+
* @param instance - The state container instance
|
|
1801
|
+
* @param adapterState - The adapter state for caching
|
|
1802
|
+
* @param config - Configuration with dependencies function
|
|
1803
|
+
* @returns Snapshot function for use with useSyncExternalStore
|
|
1804
|
+
*/
|
|
1619
1805
|
function createManualDepsSnapshot(instance, adapterState, config) {
|
|
1620
1806
|
return () => {
|
|
1621
1807
|
adapterState.manualDepsCache = config.dependencies(instance.state, instance);
|
|
1622
1808
|
return instance.state;
|
|
1623
1809
|
};
|
|
1624
1810
|
}
|
|
1811
|
+
/**
|
|
1812
|
+
* Create a snapshot function for no-tracking mode.
|
|
1813
|
+
* Returns the raw state directly.
|
|
1814
|
+
* @param instance - The state container instance
|
|
1815
|
+
* @returns Snapshot function for use with useSyncExternalStore
|
|
1816
|
+
*/
|
|
1625
1817
|
function createNoTrackSnapshot(instance) {
|
|
1626
1818
|
return () => instance.state;
|
|
1627
1819
|
}
|
|
1820
|
+
/**
|
|
1821
|
+
* Initialize adapter state for auto-tracking mode.
|
|
1822
|
+
* Creates getter tracker and proxied bloc instance.
|
|
1823
|
+
* @param instance - The state container instance
|
|
1824
|
+
* @returns Initialized adapter state
|
|
1825
|
+
*/
|
|
1628
1826
|
function initAutoTrackState(instance) {
|
|
1629
1827
|
return {
|
|
1630
1828
|
tracker: null,
|
|
@@ -1633,6 +1831,12 @@ function initAutoTrackState(instance) {
|
|
|
1633
1831
|
proxiedBloc: createBlocProxy(instance)
|
|
1634
1832
|
};
|
|
1635
1833
|
}
|
|
1834
|
+
/**
|
|
1835
|
+
* Initialize adapter state for manual dependency tracking mode.
|
|
1836
|
+
* No proxy is created; bloc is used directly.
|
|
1837
|
+
* @param instance - The state container instance
|
|
1838
|
+
* @returns Initialized adapter state
|
|
1839
|
+
*/
|
|
1636
1840
|
function initManualDepsState(instance) {
|
|
1637
1841
|
return {
|
|
1638
1842
|
tracker: null,
|
|
@@ -1641,6 +1845,12 @@ function initManualDepsState(instance) {
|
|
|
1641
1845
|
proxiedBloc: instance
|
|
1642
1846
|
};
|
|
1643
1847
|
}
|
|
1848
|
+
/**
|
|
1849
|
+
* Initialize adapter state for no-tracking mode.
|
|
1850
|
+
* No tracking or proxy is created.
|
|
1851
|
+
* @param instance - The state container instance
|
|
1852
|
+
* @returns Initialized adapter state
|
|
1853
|
+
*/
|
|
1644
1854
|
function initNoTrackState(instance) {
|
|
1645
1855
|
return {
|
|
1646
1856
|
tracker: null,
|
|
@@ -1649,6 +1859,12 @@ function initNoTrackState(instance) {
|
|
|
1649
1859
|
proxiedBloc: instance
|
|
1650
1860
|
};
|
|
1651
1861
|
}
|
|
1862
|
+
/**
|
|
1863
|
+
* Disable getter tracking after render phase completes.
|
|
1864
|
+
* Clears the active tracker to prevent tracking outside of render.
|
|
1865
|
+
* @param adapterState - The adapter state
|
|
1866
|
+
* @param rawInstance - The raw bloc instance
|
|
1867
|
+
*/
|
|
1652
1868
|
function disableGetterTracking(adapterState, rawInstance) {
|
|
1653
1869
|
if (adapterState.getterTracker) {
|
|
1654
1870
|
adapterState.getterTracker.isTracking = false;
|
|
@@ -1658,10 +1874,17 @@ function disableGetterTracking(adapterState, rawInstance) {
|
|
|
1658
1874
|
|
|
1659
1875
|
//#endregion
|
|
1660
1876
|
//#region src/logging/Logger.ts
|
|
1877
|
+
/**
|
|
1878
|
+
* Log severity levels (lower number = higher severity)
|
|
1879
|
+
*/
|
|
1661
1880
|
let LogLevel = /* @__PURE__ */ function(LogLevel$1) {
|
|
1881
|
+
/** Critical errors that may cause application failure */
|
|
1662
1882
|
LogLevel$1[LogLevel$1["ERROR"] = 0] = "ERROR";
|
|
1883
|
+
/** Warning conditions that should be addressed */
|
|
1663
1884
|
LogLevel$1[LogLevel$1["WARN"] = 1] = "WARN";
|
|
1885
|
+
/** Informational messages about application state */
|
|
1664
1886
|
LogLevel$1[LogLevel$1["INFO"] = 2] = "INFO";
|
|
1887
|
+
/** Detailed debugging information */
|
|
1665
1888
|
LogLevel$1[LogLevel$1["DEBUG"] = 3] = "DEBUG";
|
|
1666
1889
|
return LogLevel$1;
|
|
1667
1890
|
}({});
|
|
@@ -1730,9 +1953,33 @@ let currentConfig = {
|
|
|
1730
1953
|
output: (entry) => console.log(JSON.stringify(entry))
|
|
1731
1954
|
};
|
|
1732
1955
|
let defaultLogger = createLogger(currentConfig);
|
|
1956
|
+
/**
|
|
1957
|
+
* Log a debug 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
|
+
*/
|
|
1733
1962
|
const debug = (context, message, data) => defaultLogger.debug(context, message, data);
|
|
1963
|
+
/**
|
|
1964
|
+
* Log an info 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
|
+
*/
|
|
1734
1969
|
const info = (context, message, data) => defaultLogger.info(context, message, data);
|
|
1970
|
+
/**
|
|
1971
|
+
* Log a warning 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
|
+
*/
|
|
1735
1976
|
const warn = (context, message, data) => defaultLogger.warn(context, message, data);
|
|
1977
|
+
/**
|
|
1978
|
+
* Log an error message (tree-shakeable export)
|
|
1979
|
+
* @param context - Context identifier (module or component name)
|
|
1980
|
+
* @param message - Log message
|
|
1981
|
+
* @param data - Optional structured data
|
|
1982
|
+
*/
|
|
1736
1983
|
const error = (context, message, data) => defaultLogger.error(context, message, data);
|
|
1737
1984
|
/**
|
|
1738
1985
|
* Configuration function that recreates the default logger
|
|
@@ -1758,7 +2005,7 @@ function configureLogger(opts) {
|
|
|
1758
2005
|
* Decorator to configure StateContainer classes.
|
|
1759
2006
|
*
|
|
1760
2007
|
* @example Decorator syntax (requires experimentalDecorators or TC39 decorators)
|
|
1761
|
-
* ```
|
|
2008
|
+
* ```ts
|
|
1762
2009
|
* @blac({ isolated: true })
|
|
1763
2010
|
* class FormBloc extends Cubit<FormState> {}
|
|
1764
2011
|
*
|
|
@@ -1770,7 +2017,7 @@ function configureLogger(opts) {
|
|
|
1770
2017
|
* ```
|
|
1771
2018
|
*
|
|
1772
2019
|
* @example Function syntax (no decorator support needed)
|
|
1773
|
-
* ```
|
|
2020
|
+
* ```ts
|
|
1774
2021
|
* const FormBloc = blac({ isolated: true })(
|
|
1775
2022
|
* class extends Cubit<FormState> {}
|
|
1776
2023
|
* );
|
|
@@ -1786,5 +2033,5 @@ function blac(options) {
|
|
|
1786
2033
|
}
|
|
1787
2034
|
|
|
1788
2035
|
//#endregion
|
|
1789
|
-
export {
|
|
2036
|
+
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
2037
|
//# sourceMappingURL=index.js.map
|