@blac/core 2.0.0-rc-13 → 2.0.0-rc-16

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 (54) hide show
  1. package/package.json +10 -15
  2. package/src/Blac.ts +38 -71
  3. package/src/Bloc.ts +8 -9
  4. package/src/BlocBase.ts +246 -540
  5. package/src/Cubit.ts +1 -16
  6. package/src/__tests__/Blac.config.test.ts +10 -17
  7. package/src/__tests__/Bloc.event.test.ts +27 -52
  8. package/src/__tests__/BlocBase.subscription.test.ts +349 -0
  9. package/src/__tests__/Cubit.test.ts +39 -50
  10. package/src/__tests__/memory-leaks.test.ts +383 -0
  11. package/src/__tests__/plugins.test.ts +107 -97
  12. package/src/adapter/BlacAdapter.ts +347 -207
  13. package/src/adapter/ProxyFactory.ts +196 -255
  14. package/src/adapter/__tests__/BlacAdapter.test.ts +71 -77
  15. package/src/adapter/__tests__/ProxyFactory.test.ts +1 -1
  16. package/src/adapter/index.ts +0 -1
  17. package/src/errors/BlacError.ts +69 -0
  18. package/src/errors/ErrorManager.ts +101 -0
  19. package/src/errors/handleError.ts +114 -0
  20. package/src/errors/index.ts +13 -0
  21. package/src/events.ts +7 -1
  22. package/src/index.ts +7 -1
  23. package/src/lifecycle/BlocLifecycle.ts +156 -0
  24. package/src/lifecycle/index.ts +1 -0
  25. package/src/plugins/BlocPluginRegistry.ts +71 -51
  26. package/src/plugins/SystemPluginRegistry.ts +63 -13
  27. package/src/plugins/__tests__/BlocPluginRegistry.test.ts +450 -0
  28. package/src/plugins/__tests__/SystemPluginRegistry.test.ts +404 -0
  29. package/src/plugins/types.ts +32 -3
  30. package/src/subscription/README.md +132 -0
  31. package/src/subscription/SubscriptionManager.ts +395 -0
  32. package/src/subscription/__tests__/SubscriptionManager.test.ts +355 -0
  33. package/src/subscription/index.ts +2 -0
  34. package/src/subscription/types.ts +90 -0
  35. package/src/testing.ts +31 -37
  36. package/src/types.ts +4 -21
  37. package/src/utils/BatchingManager.ts +59 -0
  38. package/src/utils/RerenderLogger.ts +265 -0
  39. package/src/utils/__tests__/generateInstanceId.test.ts +104 -0
  40. package/src/utils/__tests__/shallowEqual.test.ts +171 -0
  41. package/src/utils/__tests__/uuid.test.ts +144 -0
  42. package/src/utils/generateInstanceId.ts +54 -0
  43. package/src/utils/shallowEqual.ts +1 -1
  44. package/README.md +0 -329
  45. package/dist/index.cjs.js +0 -11
  46. package/dist/index.cjs.js.map +0 -1
  47. package/dist/index.d.ts +0 -1078
  48. package/dist/index.es.js +0 -1992
  49. package/dist/index.es.js.map +0 -1
  50. package/src/BlacObserver.ts +0 -189
  51. package/src/__tests__/BlocBase.lifecycle.test.ts +0 -441
  52. package/src/__tests__/props.test.ts +0 -256
  53. package/src/adapter/ConsumerTracker.ts +0 -241
  54. package/src/adapter/__tests__/ConsumerTracker.test.ts +0 -562
@@ -1,241 +0,0 @@
1
- export interface DependencyArray {
2
- statePaths: string[];
3
- classPaths: string[];
4
- }
5
-
6
- export interface TrackedValue {
7
- value: any;
8
- lastAccessTime: number;
9
- }
10
-
11
- export interface ConsumerInfo {
12
- id: string;
13
- lastNotified: number;
14
- hasRendered: boolean;
15
- // Dependency tracking
16
- stateAccesses: Set<string>;
17
- classAccesses: Set<string>;
18
- stateValues: Map<string, TrackedValue>;
19
- classValues: Map<string, TrackedValue>;
20
- accessCount: number;
21
- lastAccessTime: number;
22
- firstAccessTime: number;
23
- }
24
-
25
- /**
26
- * ConsumerTracker manages both consumer registration and dependency tracking.
27
- * It uses a WeakMap for automatic garbage collection when consumers are no longer referenced.
28
- */
29
- export class ConsumerTracker {
30
- private consumers = new WeakMap<object, ConsumerInfo>();
31
- private registrationCount = 0;
32
- private activeConsumers = 0;
33
-
34
- register(consumerRef: object, consumerId: string): void {
35
- this.registrationCount++;
36
-
37
- const existingConsumer = this.consumers.get(consumerRef);
38
- if (!existingConsumer) {
39
- this.activeConsumers++;
40
- }
41
-
42
- this.consumers.set(consumerRef, {
43
- id: consumerId,
44
- lastNotified: Date.now(),
45
- hasRendered: false,
46
- stateAccesses: new Set(),
47
- classAccesses: new Set(),
48
- stateValues: new Map(),
49
- classValues: new Map(),
50
- accessCount: 0,
51
- lastAccessTime: 0,
52
- firstAccessTime: 0,
53
- });
54
- }
55
-
56
- unregister(consumerRef: object): void {
57
- if (consumerRef) {
58
- const consumerInfo = this.consumers.get(consumerRef);
59
- if (consumerInfo) {
60
- this.consumers.delete(consumerRef);
61
- this.activeConsumers = Math.max(0, this.activeConsumers - 1);
62
- }
63
- }
64
- }
65
-
66
- trackAccess(
67
- consumerRef: object,
68
- type: 'state' | 'class',
69
- path: string,
70
- value?: any,
71
- ): void {
72
- const consumerInfo = this.consumers.get(consumerRef);
73
- if (!consumerInfo) return;
74
-
75
- const now = Date.now();
76
-
77
- if (!consumerInfo.firstAccessTime) {
78
- consumerInfo.firstAccessTime = now;
79
- }
80
-
81
- consumerInfo.accessCount++;
82
- consumerInfo.lastAccessTime = now;
83
-
84
- if (type === 'state') {
85
- consumerInfo.stateAccesses.add(path);
86
- if (value !== undefined) {
87
- consumerInfo.stateValues.set(path, { value, lastAccessTime: now });
88
- }
89
- } else {
90
- consumerInfo.classAccesses.add(path);
91
- if (value !== undefined) {
92
- consumerInfo.classValues.set(path, { value, lastAccessTime: now });
93
- }
94
- }
95
- }
96
-
97
- resetTracking(consumerRef: object): void {
98
- const consumerInfo = this.consumers.get(consumerRef);
99
- if (!consumerInfo) return;
100
-
101
- consumerInfo.stateAccesses.clear();
102
- consumerInfo.classAccesses.clear();
103
- consumerInfo.stateValues.clear();
104
- consumerInfo.classValues.clear();
105
- consumerInfo.accessCount = 0;
106
- consumerInfo.firstAccessTime = 0;
107
- }
108
-
109
- getDependencies(consumerRef: object): DependencyArray | null {
110
- const consumerInfo = this.consumers.get(consumerRef);
111
- if (!consumerInfo) return null;
112
-
113
- return {
114
- statePaths: Array.from(consumerInfo.stateAccesses),
115
- classPaths: Array.from(consumerInfo.classAccesses),
116
- };
117
- }
118
-
119
- hasValuesChanged(
120
- consumerRef: object,
121
- newState: any,
122
- newBlocInstance: any,
123
- ): boolean {
124
- const consumerInfo = this.consumers.get(consumerRef);
125
- if (!consumerInfo) return true;
126
-
127
- let hasChanged = false;
128
- const now = Date.now();
129
-
130
- // If we haven't tracked any values yet, consider it changed to establish baseline
131
- if (
132
- consumerInfo.stateValues.size === 0 &&
133
- consumerInfo.classValues.size === 0 &&
134
- (consumerInfo.stateAccesses.size > 0 ||
135
- consumerInfo.classAccesses.size > 0)
136
- ) {
137
- return true;
138
- }
139
-
140
- // Check state values
141
- for (const [path, trackedValue] of consumerInfo.stateValues) {
142
- try {
143
- const currentValue = this.getValueAtPath(newState, path);
144
- if (currentValue !== trackedValue.value) {
145
- consumerInfo.stateValues.set(path, {
146
- value: currentValue,
147
- lastAccessTime: now,
148
- });
149
- hasChanged = true;
150
- }
151
- } catch (error) {
152
- hasChanged = true;
153
- }
154
- }
155
-
156
- // Check class getter values
157
- for (const [path, trackedValue] of consumerInfo.classValues) {
158
- try {
159
- const currentValue = this.getValueAtPath(newBlocInstance, path);
160
- if (currentValue !== trackedValue.value) {
161
- consumerInfo.classValues.set(path, {
162
- value: currentValue,
163
- lastAccessTime: now,
164
- });
165
- hasChanged = true;
166
- }
167
- } catch (error) {
168
- hasChanged = true;
169
- }
170
- }
171
-
172
- return hasChanged;
173
- }
174
-
175
- shouldNotifyConsumer(
176
- consumerRef: object,
177
- changedPaths: Set<string>,
178
- ): boolean {
179
- const consumerInfo = this.consumers.get(consumerRef);
180
- if (!consumerInfo) return false;
181
-
182
- // Check if any changed paths match tracked dependencies
183
- for (const changedPath of changedPaths) {
184
- if (consumerInfo.stateAccesses.has(changedPath)) return true;
185
- if (consumerInfo.classAccesses.has(changedPath)) return true;
186
-
187
- // Check for nested path changes
188
- for (const trackedPath of consumerInfo.stateAccesses) {
189
- if (
190
- changedPath.startsWith(trackedPath + '.') ||
191
- trackedPath.startsWith(changedPath + '.')
192
- ) {
193
- return true;
194
- }
195
- }
196
- }
197
-
198
- return false;
199
- }
200
-
201
- updateLastNotified(consumerRef: object): void {
202
- const consumerInfo = this.consumers.get(consumerRef);
203
- if (consumerInfo) {
204
- consumerInfo.lastNotified = Date.now();
205
- }
206
- }
207
-
208
- getConsumerInfo(consumerRef: object): ConsumerInfo | undefined {
209
- return this.consumers.get(consumerRef);
210
- }
211
-
212
- setHasRendered(consumerRef: object, hasRendered: boolean): void {
213
- const consumerInfo = this.consumers.get(consumerRef);
214
- if (consumerInfo) {
215
- consumerInfo.hasRendered = hasRendered;
216
- }
217
- }
218
-
219
- hasConsumer(consumerRef: object): boolean {
220
- return this.consumers.has(consumerRef);
221
- }
222
-
223
- getStats() {
224
- return {
225
- totalRegistrations: this.registrationCount,
226
- activeConsumers: this.activeConsumers,
227
- };
228
- }
229
-
230
- private getValueAtPath(obj: any, path: string): any {
231
- const parts = path.split('.');
232
- let current = obj;
233
-
234
- for (const part of parts) {
235
- if (current == null) return undefined;
236
- current = current[part];
237
- }
238
-
239
- return current;
240
- }
241
- }