@blac/core 2.0.0-rc-16 → 2.0.0-rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (157) hide show
  1. package/dist/.tsbuildinfo +1 -0
  2. package/dist/Blac.d.ts +246 -0
  3. package/dist/Blac.d.ts.map +1 -0
  4. package/dist/Blac.js +625 -0
  5. package/dist/Blac.js.map +1 -0
  6. package/dist/Bloc.d.ts +41 -0
  7. package/dist/Bloc.d.ts.map +1 -0
  8. package/dist/Bloc.js +140 -0
  9. package/dist/Bloc.js.map +1 -0
  10. package/dist/BlocBase.d.ts +110 -0
  11. package/dist/BlocBase.d.ts.map +1 -0
  12. package/dist/BlocBase.js +287 -0
  13. package/dist/BlocBase.js.map +1 -0
  14. package/dist/Cubit.d.ts +25 -0
  15. package/dist/Cubit.d.ts.map +1 -0
  16. package/dist/Cubit.js +64 -0
  17. package/dist/Cubit.js.map +1 -0
  18. package/dist/adapter/BlacAdapter.d.ts +71 -0
  19. package/dist/adapter/BlacAdapter.d.ts.map +1 -0
  20. package/dist/adapter/BlacAdapter.js +373 -0
  21. package/dist/adapter/BlacAdapter.js.map +1 -0
  22. package/dist/adapter/ProxyFactory.d.ts +50 -0
  23. package/dist/adapter/ProxyFactory.d.ts.map +1 -0
  24. package/dist/adapter/ProxyFactory.js +150 -0
  25. package/dist/adapter/ProxyFactory.js.map +1 -0
  26. package/{src/adapter/index.ts → dist/adapter/index.d.ts} +1 -0
  27. package/dist/adapter/index.d.ts.map +1 -0
  28. package/dist/adapter/index.js +19 -0
  29. package/dist/adapter/index.js.map +1 -0
  30. package/dist/errors/BlacError.d.ts +38 -0
  31. package/dist/errors/BlacError.d.ts.map +1 -0
  32. package/dist/errors/BlacError.js +55 -0
  33. package/dist/errors/BlacError.js.map +1 -0
  34. package/dist/errors/ErrorManager.d.ts +39 -0
  35. package/dist/errors/ErrorManager.d.ts.map +1 -0
  36. package/dist/errors/ErrorManager.js +91 -0
  37. package/dist/errors/ErrorManager.js.map +1 -0
  38. package/dist/errors/handleError.d.ts +24 -0
  39. package/dist/errors/handleError.d.ts.map +1 -0
  40. package/dist/errors/handleError.js +62 -0
  41. package/dist/errors/handleError.js.map +1 -0
  42. package/dist/errors/index.d.ts +5 -0
  43. package/dist/errors/index.d.ts.map +1 -0
  44. package/dist/errors/index.js +13 -0
  45. package/dist/errors/index.js.map +1 -0
  46. package/{src/events.ts → dist/events.d.ts} +4 -2
  47. package/dist/events.d.ts.map +1 -0
  48. package/dist/events.js +17 -0
  49. package/dist/events.js.map +1 -0
  50. package/dist/index.cjs +38 -0
  51. package/{src/index.ts → dist/index.d.ts} +1 -10
  52. package/dist/index.d.ts.map +1 -0
  53. package/dist/index.js +38 -0
  54. package/dist/index.js.map +1 -0
  55. package/dist/lifecycle/BlocLifecycle.d.ts +51 -0
  56. package/dist/lifecycle/BlocLifecycle.d.ts.map +1 -0
  57. package/dist/lifecycle/BlocLifecycle.js +123 -0
  58. package/dist/lifecycle/BlocLifecycle.js.map +1 -0
  59. package/dist/lifecycle/index.d.ts +2 -0
  60. package/dist/lifecycle/index.d.ts.map +1 -0
  61. package/dist/lifecycle/index.js +18 -0
  62. package/dist/lifecycle/index.js.map +1 -0
  63. package/dist/plugins/BlocPluginRegistry.d.ts +58 -0
  64. package/dist/plugins/BlocPluginRegistry.d.ts.map +1 -0
  65. package/dist/plugins/BlocPluginRegistry.js +201 -0
  66. package/dist/plugins/BlocPluginRegistry.js.map +1 -0
  67. package/dist/plugins/SystemPluginRegistry.d.ts +79 -0
  68. package/dist/plugins/SystemPluginRegistry.d.ts.map +1 -0
  69. package/dist/plugins/SystemPluginRegistry.js +184 -0
  70. package/dist/plugins/SystemPluginRegistry.js.map +1 -0
  71. package/{src/plugins/index.ts → dist/plugins/index.d.ts} +1 -5
  72. package/dist/plugins/index.d.ts.map +1 -0
  73. package/dist/plugins/index.js +26 -0
  74. package/dist/plugins/index.js.map +1 -0
  75. package/dist/plugins/types.d.ts +103 -0
  76. package/dist/plugins/types.d.ts.map +1 -0
  77. package/dist/plugins/types.js +3 -0
  78. package/dist/plugins/types.js.map +1 -0
  79. package/dist/subscription/SubscriptionManager.d.ts +67 -0
  80. package/dist/subscription/SubscriptionManager.d.ts.map +1 -0
  81. package/dist/subscription/SubscriptionManager.js +317 -0
  82. package/dist/subscription/SubscriptionManager.js.map +1 -0
  83. package/{src/subscription/index.ts → dist/subscription/index.d.ts} +1 -0
  84. package/dist/subscription/index.d.ts.map +1 -0
  85. package/dist/subscription/index.js +19 -0
  86. package/dist/subscription/index.js.map +1 -0
  87. package/dist/subscription/types.d.ts +65 -0
  88. package/dist/subscription/types.d.ts.map +1 -0
  89. package/dist/subscription/types.js +3 -0
  90. package/dist/subscription/types.js.map +1 -0
  91. package/dist/testing.d.ts +85 -0
  92. package/dist/testing.d.ts.map +1 -0
  93. package/dist/testing.js +186 -0
  94. package/dist/testing.js.map +1 -0
  95. package/{src/types.ts → dist/types.d.ts} +11 -28
  96. package/dist/types.d.ts.map +1 -0
  97. package/dist/types.js +3 -0
  98. package/dist/types.js.map +1 -0
  99. package/dist/utils/BatchingManager.d.ts +28 -0
  100. package/dist/utils/BatchingManager.d.ts.map +1 -0
  101. package/dist/utils/BatchingManager.js +48 -0
  102. package/dist/utils/BatchingManager.js.map +1 -0
  103. package/dist/utils/RerenderLogger.d.ts +60 -0
  104. package/dist/utils/RerenderLogger.d.ts.map +1 -0
  105. package/dist/utils/RerenderLogger.js +205 -0
  106. package/dist/utils/RerenderLogger.js.map +1 -0
  107. package/dist/utils/generateInstanceId.d.ts +11 -0
  108. package/dist/utils/generateInstanceId.d.ts.map +1 -0
  109. package/dist/utils/generateInstanceId.js +50 -0
  110. package/dist/utils/generateInstanceId.js.map +1 -0
  111. package/dist/utils/shallowEqual.d.ts +9 -0
  112. package/dist/utils/shallowEqual.d.ts.map +1 -0
  113. package/dist/utils/shallowEqual.js +35 -0
  114. package/dist/utils/shallowEqual.js.map +1 -0
  115. package/dist/utils/uuid.d.ts +10 -0
  116. package/dist/utils/uuid.d.ts.map +1 -0
  117. package/dist/utils/uuid.js +24 -0
  118. package/dist/utils/uuid.js.map +1 -0
  119. package/package.json +17 -6
  120. package/src/Blac.ts +0 -802
  121. package/src/Bloc.ts +0 -180
  122. package/src/BlocBase.ts +0 -398
  123. package/src/Cubit.ts +0 -68
  124. package/src/__tests__/Blac.config.test.ts +0 -79
  125. package/src/__tests__/Bloc.event.test.ts +0 -394
  126. package/src/__tests__/BlocBase.subscription.test.ts +0 -349
  127. package/src/__tests__/Cubit.test.ts +0 -462
  128. package/src/__tests__/memory-leaks.test.ts +0 -383
  129. package/src/__tests__/plugins.test.ts +0 -464
  130. package/src/adapter/BlacAdapter.ts +0 -467
  131. package/src/adapter/ProxyFactory.ts +0 -249
  132. package/src/adapter/__tests__/BlacAdapter.test.ts +0 -555
  133. package/src/adapter/__tests__/ProxyFactory.test.ts +0 -655
  134. package/src/errors/BlacError.ts +0 -69
  135. package/src/errors/ErrorManager.ts +0 -101
  136. package/src/errors/handleError.ts +0 -114
  137. package/src/errors/index.ts +0 -13
  138. package/src/lifecycle/BlocLifecycle.ts +0 -156
  139. package/src/lifecycle/index.ts +0 -1
  140. package/src/plugins/BlocPluginRegistry.ts +0 -240
  141. package/src/plugins/SystemPluginRegistry.ts +0 -242
  142. package/src/plugins/__tests__/BlocPluginRegistry.test.ts +0 -450
  143. package/src/plugins/__tests__/SystemPluginRegistry.test.ts +0 -404
  144. package/src/plugins/types.ts +0 -129
  145. package/src/subscription/README.md +0 -132
  146. package/src/subscription/SubscriptionManager.ts +0 -395
  147. package/src/subscription/__tests__/SubscriptionManager.test.ts +0 -355
  148. package/src/subscription/types.ts +0 -90
  149. package/src/testing.ts +0 -246
  150. package/src/utils/BatchingManager.ts +0 -59
  151. package/src/utils/RerenderLogger.ts +0 -265
  152. package/src/utils/__tests__/generateInstanceId.test.ts +0 -104
  153. package/src/utils/__tests__/shallowEqual.test.ts +0 -171
  154. package/src/utils/__tests__/uuid.test.ts +0 -144
  155. package/src/utils/generateInstanceId.ts +0 -54
  156. package/src/utils/shallowEqual.ts +0 -40
  157. package/src/utils/uuid.ts +0 -22
package/src/Bloc.ts DELETED
@@ -1,180 +0,0 @@
1
- import { Blac } from './Blac';
2
- import { BlocBase } from './BlocBase';
3
- import { BlocEventConstraint } from './types';
4
-
5
- export abstract class Bloc<
6
- S, // State type
7
- A extends BlocEventConstraint = BlocEventConstraint, // Base Action/Event type with proper constraints
8
- > extends BlocBase<S> {
9
- readonly eventHandlers: Map<
10
- new (...args: any[]) => A,
11
- (event: A, emit: (newState: S) => void) => void | Promise<void>
12
- > = new Map();
13
-
14
- /**
15
- * @internal
16
- * Event queue to ensure sequential processing of async events
17
- */
18
- private _eventQueue: A[] = [];
19
-
20
- /**
21
- * @internal
22
- * Flag indicating if an event is currently being processed
23
- */
24
- private _isProcessingEvent = false;
25
-
26
- /**
27
- * Registers an event handler for a specific event type.
28
- * This method is typically called in the constructor of a derived Bloc class.
29
- * @param eventConstructor The constructor of the event to handle (e.g., LoadDataEvent).
30
- * @param handler A function that processes the event and can emit new states.
31
- * The 'event' parameter in the handler will be typed to the specific eventConstructor.
32
- */
33
- protected on<E extends A>(
34
- eventConstructor: new (...args: any[]) => E,
35
- handler: (event: E, emit: (newState: S) => void) => void | Promise<void>,
36
- ): void {
37
- if (this.eventHandlers.has(eventConstructor)) {
38
- Blac.warn(
39
- `[Bloc ${this._name}:${String(this._id)}] Handler for event '${eventConstructor.name}' already registered. It will be overwritten.`,
40
- );
41
- }
42
- this.eventHandlers.set(
43
- eventConstructor,
44
- handler as (
45
- event: A,
46
- emit: (newState: S) => void,
47
- ) => void | Promise<void>,
48
- );
49
- }
50
-
51
- /**
52
- * Dispatches an action/event to the Bloc.
53
- * Events are queued and processed sequentially to prevent race conditions.
54
- * @param action The action/event instance to be processed.
55
- */
56
- public add = async (action: A): Promise<void> => {
57
- // Transform event through plugins
58
- let transformedAction: A | null = action;
59
- try {
60
- transformedAction = (this._plugins as any).transformEvent(action);
61
- } catch (error) {
62
- console.error('Error transforming event:', error);
63
- // Continue with original event if transformation fails
64
- }
65
-
66
- // If event was cancelled by plugin, don't process it
67
- if (transformedAction === null) {
68
- return;
69
- }
70
-
71
- // Notify bloc plugins of event
72
- try {
73
- (this._plugins as any).notifyEvent(transformedAction);
74
- } catch (error) {
75
- console.error('Error notifying plugins of event:', error);
76
- }
77
-
78
- // Notify system plugins of event
79
- Blac.instance.plugins.notifyEventAdded(this as any, transformedAction);
80
-
81
- this._eventQueue.push(transformedAction);
82
-
83
- if (!this._isProcessingEvent) {
84
- await this._processEventQueue();
85
- }
86
- };
87
-
88
- /**
89
- * @internal
90
- * Processes events from the queue sequentially
91
- */
92
- private async _processEventQueue(): Promise<void> {
93
- if (this._isProcessingEvent) {
94
- return;
95
- }
96
-
97
- this._isProcessingEvent = true;
98
-
99
- try {
100
- while (this._eventQueue.length > 0) {
101
- const action = this._eventQueue.shift()!;
102
- await this._processEvent(action);
103
- }
104
- } finally {
105
- this._isProcessingEvent = false;
106
- }
107
- }
108
-
109
- /**
110
- * @internal
111
- * Processes a single event
112
- */
113
- private async _processEvent(action: A): Promise<void> {
114
- const eventConstructor = action.constructor as new (...args: any[]) => A;
115
- const handler = this.eventHandlers.get(eventConstructor);
116
-
117
- if (handler) {
118
- const emit = (newState: S): void => {
119
- const previousState = this.state; // State just before this specific emission
120
- this._pushState(newState, previousState, action);
121
- };
122
-
123
- try {
124
- await handler(action, emit);
125
- } catch (error) {
126
- const constructorName =
127
- (action.constructor as { name?: string }).name ||
128
- 'UnnamedConstructor';
129
- const errorContext = {
130
- blocName: this._name,
131
- blocId: String(this._id),
132
- eventType: constructorName,
133
- currentState: this.state,
134
- action: action,
135
- timestamp: new Date().toISOString(),
136
- };
137
-
138
- Blac.error(
139
- `[Bloc ${this._name}:${String(this._id)}] Error in event handler for '${constructorName}':`,
140
- error,
141
- 'Context:',
142
- errorContext,
143
- );
144
-
145
- // Notify plugins of the error
146
- if (error instanceof Error) {
147
- try {
148
- this._plugins.notifyError(error, {
149
- phase: 'event-processing',
150
- operation: 'handler',
151
- metadata: { event: action },
152
- });
153
-
154
- Blac.instance.plugins.notifyError(error, this as any, {
155
- phase: 'event-processing',
156
- operation: 'handler',
157
- metadata: { event: action },
158
- });
159
- } catch (pluginError) {
160
- console.error('Error notifying plugins:', pluginError);
161
- }
162
- }
163
-
164
- if (error instanceof Error && error.name === 'CriticalError') {
165
- throw error;
166
- }
167
- }
168
- } else {
169
- const constructorName =
170
- (action.constructor as { name?: string }).name || 'UnnamedConstructor';
171
- Blac.warn(
172
- `[Bloc ${this._name}:${String(this._id)}] No handler registered for action type: '${constructorName}'.`,
173
- 'Registered handlers:',
174
- Array.from(this.eventHandlers.keys()).map((k) => k.name),
175
- 'Action was:',
176
- action,
177
- );
178
- }
179
- }
180
- }
package/src/BlocBase.ts DELETED
@@ -1,398 +0,0 @@
1
- import { generateUUID } from './utils/uuid';
2
- import { BlocPlugin } from './plugins/types';
3
- import { BlocPluginRegistry } from './plugins/BlocPluginRegistry';
4
- import { SubscriptionManager } from './subscription/SubscriptionManager';
5
- import {
6
- BlocLifecycleManager,
7
- BlocLifecycleState,
8
- StateTransitionResult,
9
- } from './lifecycle/BlocLifecycle';
10
- import { BatchingManager } from './utils/BatchingManager';
11
- import type { Blac } from './Blac';
12
-
13
- export type BlocInstanceId = string | number | undefined;
14
-
15
- interface BlocStaticProperties {
16
- isolated: boolean;
17
- keepAlive: boolean;
18
- plugins?: BlocPlugin<any, any>[];
19
- }
20
-
21
- /**
22
- * Base class for both Blocs and Cubits using unified subscription model.
23
- */
24
- export abstract class BlocBase<S> {
25
- public uid = generateUUID();
26
- blacInstance?: Blac;
27
-
28
- static isolated = false;
29
- get isIsolated() {
30
- return this._isolated;
31
- }
32
-
33
- static keepAlive = false;
34
- get isKeepAlive() {
35
- return this._keepAlive;
36
- }
37
-
38
- public _isolated = false;
39
- public _id: BlocInstanceId;
40
- public _instanceRef?: string;
41
- public _name: string;
42
-
43
- /**
44
- * Unified subscription manager for all state notifications
45
- */
46
- public _subscriptionManager: SubscriptionManager<S>;
47
-
48
- _state: S;
49
- private _lifecycleManager = new BlocLifecycleManager();
50
- private _batchingManager = new BatchingManager<S>();
51
- _keepAlive = false;
52
- public lastUpdate?: number;
53
-
54
- _plugins = new BlocPluginRegistry<S, any>();
55
-
56
- onDispose?: () => void;
57
-
58
- /**
59
- * Creates a new BlocBase instance with unified subscription management
60
- */
61
- constructor(initialState: S) {
62
- this._state = initialState;
63
- this._id = this.constructor.name;
64
- this._name = this.constructor.name;
65
-
66
- // Initialize unified subscription system
67
- this._subscriptionManager = new SubscriptionManager(this as any);
68
-
69
- // Access static properties
70
- const Constructor = this.constructor as typeof BlocBase &
71
- BlocStaticProperties;
72
-
73
- this._keepAlive =
74
- typeof Constructor.keepAlive === 'boolean'
75
- ? Constructor.keepAlive
76
- : false;
77
- this._isolated =
78
- typeof Constructor.isolated === 'boolean' ? Constructor.isolated : false;
79
-
80
- // Initialize plugin registry
81
- this._plugins = new BlocPluginRegistry<S, any>();
82
-
83
- // Register static plugins
84
- if (Constructor.plugins && Array.isArray(Constructor.plugins)) {
85
- for (const plugin of Constructor.plugins) {
86
- this._plugins.add(plugin);
87
- }
88
- }
89
-
90
- // Attach all plugins
91
- this._plugins.attach(this);
92
- }
93
-
94
- /**
95
- * Returns the current state
96
- */
97
- get state(): S {
98
- if (this._lifecycleManager.isDisposed) {
99
- return this._state; // Return last known state for disposed blocs
100
- }
101
- return this._state;
102
- }
103
-
104
- /**
105
- * Subscribe to all state changes
106
- */
107
- subscribe(callback: (state: S) => void): () => void {
108
- return this._subscriptionManager.subscribe({
109
- type: 'observer',
110
- notify: (state) => callback(state as S),
111
- });
112
- }
113
-
114
- /**
115
- * Subscribe with a selector for optimized updates
116
- */
117
- subscribeWithSelector<T>(
118
- selector: (state: S) => T,
119
- callback: (value: T) => void,
120
- equalityFn?: (a: T, b: T) => boolean,
121
- ): () => void {
122
- return this._subscriptionManager.subscribe({
123
- type: 'consumer',
124
- selector: selector as any,
125
- equalityFn: equalityFn as any,
126
- notify: (value) => callback(value as T),
127
- });
128
- }
129
-
130
- /**
131
- * Subscribe with React component reference for automatic cleanup
132
- */
133
- subscribeComponent(
134
- componentRef: WeakRef<object>,
135
- callback: () => void,
136
- ): () => void {
137
- return this._subscriptionManager.subscribe({
138
- type: 'consumer',
139
- weakRef: componentRef,
140
- notify: callback,
141
- });
142
- }
143
-
144
- /**
145
- * Get current subscription count
146
- */
147
- get subscriptionCount(): number {
148
- return this._subscriptionManager.size;
149
- }
150
-
151
- /**
152
- * Track property access for a subscription
153
- */
154
- trackAccess(subscriptionId: string, path: string, value?: unknown): void {
155
- this._subscriptionManager.trackAccess(subscriptionId, path, value);
156
- }
157
-
158
- /**
159
- * Emit a new state
160
- */
161
- protected emit(newState: S, action?: unknown): void {
162
- this._pushState(newState, this._state, action);
163
- }
164
-
165
- /**
166
- * Internal state push method used by Bloc
167
- */
168
- _pushState(newState: S, oldState: S, action?: unknown): void {
169
- // Validate state emission conditions
170
- if (this._lifecycleManager.currentState !== BlocLifecycleState.ACTIVE) {
171
- this.blacInstance?.error(
172
- `[${this._name}:${this._id}] Attempted state update on ${this._lifecycleManager.currentState} bloc. Update ignored.`,
173
- );
174
- return;
175
- }
176
-
177
- if (newState === undefined) {
178
- return; // Silent failure for undefined states
179
- }
180
-
181
- this._state = newState;
182
-
183
- // Apply plugins
184
- const transformedState = this._plugins.transformState(
185
- oldState,
186
- newState,
187
- ) as S;
188
- this._state = transformedState;
189
-
190
- // Notify plugins of state change
191
- this._plugins.notifyStateChange(oldState, transformedState);
192
-
193
- // Notify system plugins of state change
194
- this.blacInstance?.plugins.notifyStateChanged(
195
- this as any,
196
- oldState,
197
- transformedState,
198
- );
199
-
200
- // Handle batching
201
- if (this._batchingManager.isCurrentlyBatching) {
202
- this._batchingManager.addUpdate({
203
- newState: transformedState,
204
- oldState,
205
- action,
206
- });
207
- return;
208
- }
209
-
210
- // Notify all subscriptions
211
- this._subscriptionManager.notify(transformedState, oldState, action);
212
- this.lastUpdate = Date.now();
213
- }
214
-
215
- _batchUpdates(callback: () => void): void {
216
- this._batchingManager.batchUpdates(callback, (finalUpdate) => {
217
- this._subscriptionManager.notify(
218
- finalUpdate.newState,
219
- finalUpdate.oldState,
220
- finalUpdate.action,
221
- );
222
- });
223
- }
224
-
225
- /**
226
- * Add a plugin
227
- */
228
- addPlugin(plugin: BlocPlugin<S, any>): void {
229
- this._plugins.add(plugin);
230
-
231
- // If plugins are already attached (bloc is active), attach the new plugin
232
- if ((this._plugins as any).attached && plugin.onAttach) {
233
- try {
234
- plugin.onAttach(this);
235
- } catch (error) {
236
- console.error(`Plugin '${plugin.name}' error in onAttach:`, error);
237
- }
238
- }
239
- }
240
-
241
- /**
242
- * Remove a plugin
243
- */
244
- removePlugin(plugin: BlocPlugin<S, any>): void {
245
- this._plugins.remove(plugin.name);
246
- }
247
-
248
- /**
249
- * Get all plugins
250
- */
251
- get plugins(): ReadonlyArray<BlocPlugin<S, any>> {
252
- return this._plugins.getAll();
253
- }
254
-
255
- /**
256
- * Disposal management
257
- */
258
- get isDisposed(): boolean {
259
- return this._lifecycleManager.isDisposed;
260
- }
261
-
262
- /**
263
- * Atomic state transition for disposal
264
- */
265
- _atomicStateTransition(
266
- expectedState: BlocLifecycleState,
267
- newState: BlocLifecycleState,
268
- ): StateTransitionResult {
269
- return this._lifecycleManager.atomicStateTransition(
270
- expectedState,
271
- newState,
272
- );
273
- }
274
-
275
- /**
276
- * Dispose the bloc and clean up resources
277
- */
278
- async dispose(): Promise<void> {
279
- const transitionResult = this._lifecycleManager.atomicStateTransition(
280
- BlocLifecycleState.ACTIVE,
281
- BlocLifecycleState.DISPOSING,
282
- );
283
-
284
- if (!transitionResult.success) {
285
- if (
286
- this._lifecycleManager.currentState ===
287
- BlocLifecycleState.DISPOSAL_REQUESTED
288
- ) {
289
- this._lifecycleManager.atomicStateTransition(
290
- BlocLifecycleState.DISPOSAL_REQUESTED,
291
- BlocLifecycleState.DISPOSING,
292
- );
293
- } else {
294
- return;
295
- }
296
- }
297
-
298
- try {
299
- // Clear subscriptions
300
- this._subscriptionManager.clear();
301
-
302
- // Call disposal hook
303
- if (this.onDispose) {
304
- this.onDispose();
305
- }
306
-
307
- // Notify plugins of disposal
308
- for (const plugin of this._plugins.getAll()) {
309
- try {
310
- if ('onDispose' in plugin && typeof plugin.onDispose === 'function') {
311
- plugin.onDispose(this as any);
312
- }
313
- } catch (error) {
314
- console.error('Plugin disposal error:', error);
315
- }
316
- }
317
-
318
- // Call disposal handler
319
- const handler = this._lifecycleManager.getDisposalHandler();
320
- if (handler) {
321
- handler(this as any);
322
- }
323
- } finally {
324
- this._lifecycleManager.atomicStateTransition(
325
- BlocLifecycleState.DISPOSING,
326
- BlocLifecycleState.DISPOSED,
327
- );
328
- }
329
- }
330
-
331
- /**
332
- * Schedule disposal when no subscriptions remain
333
- */
334
- _scheduleDisposal(): void {
335
- const shouldDispose =
336
- this._subscriptionManager.size === 0 && !this._keepAlive;
337
-
338
- if (!shouldDispose) {
339
- return;
340
- }
341
-
342
- this._lifecycleManager.scheduleDisposal(
343
- 16,
344
- () => this._subscriptionManager.size === 0 && !this._keepAlive,
345
- () => this.dispose(),
346
- );
347
- }
348
-
349
- /**
350
- * Set disposal handler
351
- */
352
- setDisposalHandler(handler: (bloc: BlocBase<unknown>) => void): void {
353
- this._lifecycleManager.setDisposalHandler(
354
- handler as (bloc: unknown) => void,
355
- );
356
- }
357
-
358
- /**
359
- * Check if disposal should be scheduled (called by subscription manager)
360
- */
361
- checkDisposal(): void {
362
- if (
363
- this._subscriptionManager.size === 0 &&
364
- !this._keepAlive &&
365
- this._lifecycleManager.currentState === BlocLifecycleState.ACTIVE
366
- ) {
367
- this._scheduleDisposal();
368
- }
369
- }
370
-
371
- /**
372
- * Cancel disposal if bloc is in disposal_requested state
373
- */
374
- _cancelDisposalIfRequested(): void {
375
- this.blacInstance?.log(
376
- `[${this._name}:${this._id}] _cancelDisposalIfRequested called. Current state: ${this._lifecycleManager.currentState}`,
377
- );
378
-
379
- const success = this._lifecycleManager.cancelDisposal();
380
-
381
- if (success) {
382
- this.blacInstance?.log(
383
- `[${this._name}:${this._id}] Disposal cancelled - new subscription added`,
384
- );
385
- } else if (
386
- this._lifecycleManager.currentState ===
387
- BlocLifecycleState.DISPOSAL_REQUESTED
388
- ) {
389
- this.blacInstance?.warn(
390
- `[${this._name}:${this._id}] Failed to cancel disposal. Current state: ${this._lifecycleManager.currentState}`,
391
- );
392
- } else if (this._lifecycleManager.isDisposed) {
393
- this.blacInstance?.error(
394
- `[${this._name}:${this._id}] Cannot cancel disposal - bloc is already disposed`,
395
- );
396
- }
397
- }
398
- }
package/src/Cubit.ts DELETED
@@ -1,68 +0,0 @@
1
- import { Blac } from './Blac';
2
- import { BlocBase } from './BlocBase';
3
-
4
- /**
5
- * A Cubit is a simpler version of a Bloc that doesn't handle events.
6
- * It manages state and provides methods to update it.
7
- * @template S - The type of state this Cubit manages
8
- */
9
- export abstract class Cubit<S> extends BlocBase<S> {
10
- /**
11
- * Updates the current state and notifies all observers of the change.
12
- * If the new state is identical to the current state (using Object.is),
13
- * no update will occur.
14
- * @param state - The new state to set
15
- */
16
- emit(state: S): void {
17
- if (Object.is(state, this.state)) {
18
- return;
19
- }
20
-
21
- const oldState = this.state;
22
- const newState = state;
23
- this._pushState(newState, oldState);
24
- }
25
-
26
- /**
27
- * Partially updates the current state by merging it with the provided state patch.
28
- * This method is only applicable when the state is an object type.
29
- *
30
- * @param statePatch - A partial state object containing only the properties to update
31
- * @param ignoreChangeCheck - If true, skips checking if the state has actually changed
32
- * @throws {TypeError} If the state is not an object type
33
- */
34
- patch(
35
- statePatch: S extends object ? Partial<S> : S,
36
- ignoreChangeCheck = false,
37
- ): void {
38
- if (typeof this.state !== 'object' || this.state === null) {
39
- Blac.warn(
40
- 'Cubit.patch: was called on a cubit where the state is not an object. This is a no-op.',
41
- );
42
- return;
43
- }
44
-
45
- let changes = false;
46
- if (!ignoreChangeCheck) {
47
- for (const key in statePatch) {
48
- if (Object.prototype.hasOwnProperty.call(statePatch, key)) {
49
- const s = this.state;
50
- const current = s[key as keyof S];
51
- if (!Object.is(statePatch[key as keyof S], current)) {
52
- changes = true;
53
- break;
54
- }
55
- }
56
- }
57
- } else {
58
- changes = true;
59
- }
60
-
61
- if (changes) {
62
- this.emit({
63
- ...this.state,
64
- ...(statePatch as Partial<S>),
65
- } as S);
66
- }
67
- }
68
- }