@blac/core 2.0.0-rc-5 → 2.0.0-rc-7
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/README.md +42 -0
- package/dist/index.cjs.js +10 -1
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +134 -8
- package/dist/index.es.js +448 -206
- package/dist/index.es.js.map +1 -1
- package/package.json +1 -1
- package/src/Blac.ts +53 -17
- package/src/BlacObserver.ts +33 -19
- package/src/Bloc.ts +82 -21
- package/src/BlocBase.ts +115 -47
- package/src/index.ts +7 -0
- package/src/testing.ts +239 -0
- package/src/types.ts +25 -2
- package/src/utils/uuid.ts +22 -0
package/dist/index.es.js
CHANGED
|
@@ -1,92 +1,96 @@
|
|
|
1
|
-
var
|
|
2
|
-
var
|
|
3
|
-
var
|
|
4
|
-
const
|
|
1
|
+
var m = Object.defineProperty;
|
|
2
|
+
var y = (d, e, t) => e in d ? m(d, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : d[e] = t;
|
|
3
|
+
var i = (d, e, t) => y(d, typeof e != "symbol" ? e + "" : e, t);
|
|
4
|
+
const u = class u {
|
|
5
5
|
getInstance() {
|
|
6
|
-
return
|
|
6
|
+
return u._instance || (u._instance = new l({ __unsafe_ignore_singleton: !0 })), u._instance;
|
|
7
7
|
}
|
|
8
8
|
setInstance(e) {
|
|
9
|
-
|
|
9
|
+
u._instance = e;
|
|
10
10
|
}
|
|
11
11
|
resetInstance() {
|
|
12
|
-
const e =
|
|
13
|
-
if (
|
|
12
|
+
const e = u._instance;
|
|
13
|
+
if (u._instance = new l({ __unsafe_ignore_singleton: !0 }), e)
|
|
14
14
|
for (const t of e.keepAliveBlocs)
|
|
15
|
-
|
|
15
|
+
u._instance.keepAliveBlocs.add(t), u._instance.uidRegistry.set(t.uid, t);
|
|
16
16
|
}
|
|
17
17
|
};
|
|
18
|
-
|
|
19
|
-
let
|
|
20
|
-
function
|
|
21
|
-
|
|
18
|
+
i(u, "_instance");
|
|
19
|
+
let v = u, g = new v();
|
|
20
|
+
function M(d) {
|
|
21
|
+
g = d;
|
|
22
22
|
}
|
|
23
|
-
const
|
|
23
|
+
const c = class c {
|
|
24
24
|
/**
|
|
25
25
|
* Creates a new Blac instance.
|
|
26
26
|
* @param options - Configuration options including singleton control
|
|
27
27
|
*/
|
|
28
28
|
constructor(e = {}) {
|
|
29
29
|
/** Timestamp when the instance was created */
|
|
30
|
-
|
|
30
|
+
i(this, "createdAt", Date.now());
|
|
31
31
|
/** Map storing all registered bloc instances by their class name and ID */
|
|
32
|
-
|
|
32
|
+
i(this, "blocInstanceMap", /* @__PURE__ */ new Map());
|
|
33
33
|
/** Map storing isolated bloc instances grouped by their constructor */
|
|
34
|
-
|
|
34
|
+
i(this, "isolatedBlocMap", /* @__PURE__ */ new Map());
|
|
35
35
|
/** Map for O(1) lookup of isolated blocs by UID */
|
|
36
|
-
|
|
36
|
+
i(this, "isolatedBlocIndex", /* @__PURE__ */ new Map());
|
|
37
37
|
/** Map tracking UIDs to prevent memory leaks */
|
|
38
|
-
|
|
38
|
+
i(this, "uidRegistry", /* @__PURE__ */ new Map());
|
|
39
39
|
/** Set of keep-alive blocs for controlled cleanup */
|
|
40
|
-
|
|
40
|
+
i(this, "keepAliveBlocs", /* @__PURE__ */ new Set());
|
|
41
41
|
/** Flag to control whether changes should be posted to document */
|
|
42
|
-
|
|
42
|
+
i(this, "postChangesToDocument", !1);
|
|
43
43
|
/**
|
|
44
44
|
* Logs messages to console when logging is enabled
|
|
45
45
|
* @param args - Arguments to log
|
|
46
46
|
*/
|
|
47
|
-
|
|
48
|
-
|
|
47
|
+
i(this, "log", (...e) => {
|
|
48
|
+
c.enableLog && console.warn(`☢️ [Blac ${this.createdAt.toString()}]`, ...e);
|
|
49
49
|
});
|
|
50
50
|
/**
|
|
51
51
|
* Logs a warning message
|
|
52
52
|
* @param message - Warning message
|
|
53
53
|
* @param args - Additional arguments
|
|
54
54
|
*/
|
|
55
|
-
|
|
56
|
-
|
|
55
|
+
i(this, "warn", (e, ...t) => {
|
|
56
|
+
c.enableLog && console.warn(`🚨 [Blac ${String(c.instance.createdAt)}]`, e, ...t);
|
|
57
57
|
});
|
|
58
58
|
/**
|
|
59
59
|
* Logs an error message
|
|
60
60
|
* @param message - Error message
|
|
61
61
|
* @param args - Additional arguments
|
|
62
62
|
*/
|
|
63
|
-
|
|
64
|
-
|
|
63
|
+
i(this, "error", (e, ...t) => {
|
|
64
|
+
c.enableLog && console.error(`🚨 [Blac ${String(c.instance.createdAt)}]`, e, ...t);
|
|
65
65
|
});
|
|
66
66
|
/**
|
|
67
67
|
* Resets the Blac instance to a new one, disposing non-keepAlive blocs
|
|
68
68
|
* from the old instance.
|
|
69
69
|
*/
|
|
70
|
-
|
|
70
|
+
i(this, "resetInstance", () => {
|
|
71
71
|
this.log("Reset Blac instance");
|
|
72
72
|
const e = new Map(this.blocInstanceMap), t = new Map(this.isolatedBlocMap);
|
|
73
73
|
e.forEach((s) => {
|
|
74
|
-
s._keepAlive
|
|
74
|
+
!s._keepAlive && s._disposalState === "active" && this.disposeBloc(s);
|
|
75
75
|
}), t.forEach((s) => {
|
|
76
|
-
s.forEach((
|
|
77
|
-
|
|
76
|
+
s.forEach((n) => {
|
|
77
|
+
!n._keepAlive && n._disposalState === "active" && this.disposeBloc(n);
|
|
78
78
|
});
|
|
79
|
-
}), this.blocInstanceMap.clear(), this.isolatedBlocMap.clear(), this.isolatedBlocIndex.clear(),
|
|
79
|
+
}), this.blocInstanceMap.clear(), this.isolatedBlocMap.clear(), this.isolatedBlocIndex.clear(), g.resetInstance();
|
|
80
80
|
});
|
|
81
81
|
/**
|
|
82
82
|
* Disposes of a bloc instance by removing it from the appropriate registry
|
|
83
83
|
* @param bloc - The bloc instance to dispose
|
|
84
84
|
*/
|
|
85
|
-
|
|
85
|
+
i(this, "disposeBloc", (e) => {
|
|
86
|
+
if (e._disposalState !== "active") {
|
|
87
|
+
this.log(`[${e._name}:${String(e._id)}] disposeBloc called on already disposed bloc`);
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
86
90
|
const t = e.constructor, s = this.createBlocInstanceMapKey(e._name, e._id);
|
|
87
|
-
this.log(`[${e._name}:${String(e._id)}] disposeBloc called. Isolated: ${String(t.isolated)}`), t.isolated ? (this.unregisterIsolatedBlocInstance(e), this.blocInstanceMap.delete(s)) : this.unregisterBlocInstance(e), this.log("dispatched bloc", e);
|
|
91
|
+
this.log(`[${e._name}:${String(e._id)}] disposeBloc called. Isolated: ${String(t.isolated)}`), e._dispose(), t.isolated ? (this.unregisterIsolatedBlocInstance(e), this.blocInstanceMap.delete(s)) : this.unregisterBlocInstance(e), this.log("dispatched bloc", e);
|
|
88
92
|
});
|
|
89
|
-
|
|
93
|
+
i(this, "activateBloc", (e) => {
|
|
90
94
|
const t = e.constructor;
|
|
91
95
|
(e.isIsolated ? this.findIsolatedBlocInstance(t, e._id) : this.findRegisteredBlocInstance(t, e._id)) || (this.log(`[${e._name}:${String(e._id)}] activateBloc called. Isolated: ${String(e.isIsolated)}`), e.isIsolated ? this.registerIsolatedBlocInstance(e) : this.registerBlocInstance(e));
|
|
92
96
|
});
|
|
@@ -101,27 +105,29 @@ const r = class r {
|
|
|
101
105
|
* - instanceRef: Optional reference string for the instance
|
|
102
106
|
* @returns The bloc instance
|
|
103
107
|
*/
|
|
104
|
-
|
|
105
|
-
const { id: s } = t,
|
|
106
|
-
if (
|
|
107
|
-
const
|
|
108
|
-
if (
|
|
109
|
-
return this.log(`[${e.name}:${String(
|
|
108
|
+
i(this, "getBloc", (e, t = {}) => {
|
|
109
|
+
const { id: s } = t, n = e, o = s ?? e.name;
|
|
110
|
+
if (n.isolated) {
|
|
111
|
+
const r = this.findIsolatedBlocInstance(e, o);
|
|
112
|
+
if (r)
|
|
113
|
+
return this.log(`[${e.name}:${String(o)}] (getBloc) Found existing isolated instance.`, t), r;
|
|
110
114
|
if (t.throwIfNotFound)
|
|
111
115
|
throw new Error(`Isolated bloc ${e.name} not found`);
|
|
112
116
|
} else {
|
|
113
|
-
const
|
|
114
|
-
if (
|
|
115
|
-
return this.log(`[${e.name}:${String(
|
|
117
|
+
const r = this.findRegisteredBlocInstance(e, o);
|
|
118
|
+
if (r)
|
|
119
|
+
return this.log(`[${e.name}:${String(o)}] (getBloc) Found existing registered instance.`, t), r;
|
|
116
120
|
if (t.throwIfNotFound)
|
|
117
121
|
throw new Error(`Registered bloc ${e.name} not found`);
|
|
118
122
|
}
|
|
119
|
-
const
|
|
123
|
+
const a = this.createNewBlocInstance(
|
|
120
124
|
e,
|
|
121
|
-
|
|
125
|
+
o,
|
|
122
126
|
t
|
|
123
127
|
);
|
|
124
|
-
|
|
128
|
+
if (this.log(`[${e.name}:${String(o)}] (getBloc) No existing instance found. Creating new one.`, t, a), !a)
|
|
129
|
+
throw new Error(`[getBloc] Failed to create bloc instance for ${e.name}. This should never happen.`);
|
|
130
|
+
return a;
|
|
125
131
|
});
|
|
126
132
|
/**
|
|
127
133
|
* Gets a bloc instance or throws an error if it doesn't exist
|
|
@@ -131,10 +137,10 @@ const r = class r {
|
|
|
131
137
|
* - props: Properties to pass to the bloc constructor
|
|
132
138
|
* - instanceRef: Optional reference string for the instance
|
|
133
139
|
*/
|
|
134
|
-
|
|
135
|
-
const s = e.isolated,
|
|
136
|
-
if (
|
|
137
|
-
return
|
|
140
|
+
i(this, "getBlocOrThrow", (e, t = {}) => {
|
|
141
|
+
const s = e.isolated, n = t.id || e.name, o = s ? this.findIsolatedBlocInstance(e, n) : this.findRegisteredBlocInstance(e, n);
|
|
142
|
+
if (o)
|
|
143
|
+
return o;
|
|
138
144
|
throw new Error(`Bloc ${e.name} not found`);
|
|
139
145
|
});
|
|
140
146
|
/**
|
|
@@ -144,13 +150,13 @@ const r = class r {
|
|
|
144
150
|
* - searchIsolated: Whether to search in isolated blocs (defaults to bloc's isolated property)
|
|
145
151
|
* @returns Array of matching bloc instances
|
|
146
152
|
*/
|
|
147
|
-
|
|
153
|
+
i(this, "getAllBlocs", (e, t = {}) => {
|
|
148
154
|
const s = [];
|
|
149
|
-
if (this.blocInstanceMap.forEach((
|
|
150
|
-
|
|
155
|
+
if (this.blocInstanceMap.forEach((n) => {
|
|
156
|
+
n.constructor === e && s.push(n);
|
|
151
157
|
}), t.searchIsolated !== !1) {
|
|
152
|
-
const
|
|
153
|
-
|
|
158
|
+
const n = this.isolatedBlocMap.get(e);
|
|
159
|
+
n && s.push(...n.map((o) => o));
|
|
154
160
|
}
|
|
155
161
|
return s;
|
|
156
162
|
});
|
|
@@ -158,7 +164,7 @@ const r = class r {
|
|
|
158
164
|
* Disposes all keep-alive blocs of a specific type
|
|
159
165
|
* @param blocClass - The bloc class to dispose
|
|
160
166
|
*/
|
|
161
|
-
|
|
167
|
+
i(this, "disposeKeepAliveBlocs", (e) => {
|
|
162
168
|
const t = [];
|
|
163
169
|
for (const s of this.keepAliveBlocs)
|
|
164
170
|
(!e || s.constructor === e) && t.push(s);
|
|
@@ -168,19 +174,19 @@ const r = class r {
|
|
|
168
174
|
* Disposes all blocs matching a pattern
|
|
169
175
|
* @param predicate - Function to test each bloc for disposal
|
|
170
176
|
*/
|
|
171
|
-
|
|
177
|
+
i(this, "disposeBlocs", (e) => {
|
|
172
178
|
const t = [];
|
|
173
179
|
for (const s of this.blocInstanceMap.values())
|
|
174
180
|
e(s) && t.push(s);
|
|
175
181
|
for (const s of this.isolatedBlocMap.values())
|
|
176
|
-
for (const
|
|
177
|
-
e(
|
|
182
|
+
for (const n of s)
|
|
183
|
+
e(n) && t.push(n);
|
|
178
184
|
t.forEach((s) => s._dispose());
|
|
179
185
|
});
|
|
180
186
|
/**
|
|
181
187
|
* Gets memory usage statistics for debugging
|
|
182
188
|
*/
|
|
183
|
-
|
|
189
|
+
i(this, "getMemoryStats", () => ({
|
|
184
190
|
totalBlocs: this.uidRegistry.size,
|
|
185
191
|
registeredBlocs: this.blocInstanceMap.size,
|
|
186
192
|
isolatedBlocs: Array.from(this.isolatedBlocMap.values()).reduce((e, t) => e + t.length, 0),
|
|
@@ -190,39 +196,42 @@ const r = class r {
|
|
|
190
196
|
/**
|
|
191
197
|
* Validates consumer references and cleans up orphaned consumers
|
|
192
198
|
*/
|
|
193
|
-
|
|
199
|
+
i(this, "validateConsumers", () => {
|
|
194
200
|
for (const e of this.uidRegistry.values())
|
|
195
|
-
e._consumers.size === 0 && !e._keepAlive && setTimeout(() => {
|
|
196
|
-
e._consumers.size === 0 && !e._keepAlive && e.
|
|
201
|
+
e._validateConsumers(), e._consumers.size === 0 && !e._keepAlive && e._disposalState === "active" && setTimeout(() => {
|
|
202
|
+
e._consumers.size === 0 && !e._keepAlive && e._disposalState === "active" && this.disposeBloc(e);
|
|
197
203
|
}, 1e3);
|
|
198
204
|
});
|
|
199
205
|
const { __unsafe_ignore_singleton: t = !1 } = e;
|
|
200
206
|
if (!t)
|
|
201
|
-
return
|
|
202
|
-
|
|
207
|
+
return c.instance;
|
|
208
|
+
g.setInstance(this);
|
|
203
209
|
}
|
|
204
210
|
/** @deprecated Use getInstance() instead */
|
|
205
211
|
static get instance() {
|
|
206
|
-
return
|
|
212
|
+
return g.getInstance();
|
|
207
213
|
}
|
|
208
214
|
static get getAllBlocs() {
|
|
209
|
-
return
|
|
215
|
+
return c.instance.getAllBlocs;
|
|
210
216
|
}
|
|
211
217
|
static get log() {
|
|
212
|
-
return
|
|
218
|
+
return c.instance.log;
|
|
213
219
|
}
|
|
214
220
|
/**
|
|
215
221
|
* Gets the current Blac instance
|
|
216
222
|
* @returns The Blac instance
|
|
217
223
|
*/
|
|
218
224
|
static getInstance() {
|
|
219
|
-
return
|
|
225
|
+
return g.getInstance();
|
|
220
226
|
}
|
|
221
227
|
static get warn() {
|
|
222
|
-
return
|
|
228
|
+
return c.instance.warn;
|
|
223
229
|
}
|
|
224
230
|
static get error() {
|
|
225
|
-
return
|
|
231
|
+
return c.instance.error;
|
|
232
|
+
}
|
|
233
|
+
static get disposeBloc() {
|
|
234
|
+
return c.instance.disposeBloc;
|
|
226
235
|
}
|
|
227
236
|
/**
|
|
228
237
|
* Creates a unique key for a bloc instance in the map based on the bloc class name and instance ID
|
|
@@ -257,8 +266,8 @@ const r = class r {
|
|
|
257
266
|
*/
|
|
258
267
|
findRegisteredBlocInstance(e, t) {
|
|
259
268
|
if (e.isolated) return;
|
|
260
|
-
const
|
|
261
|
-
return this.blocInstanceMap.get(
|
|
269
|
+
const n = this.createBlocInstanceMapKey(e.name, t);
|
|
270
|
+
return this.blocInstanceMap.get(n);
|
|
262
271
|
}
|
|
263
272
|
/**
|
|
264
273
|
* Registers an isolated bloc instance in the isolated registry
|
|
@@ -274,19 +283,23 @@ const r = class r {
|
|
|
274
283
|
*/
|
|
275
284
|
unregisterIsolatedBlocInstance(e) {
|
|
276
285
|
const t = e.constructor, s = this.isolatedBlocMap.get(t);
|
|
286
|
+
let n = !1;
|
|
277
287
|
if (s) {
|
|
278
|
-
const
|
|
279
|
-
|
|
288
|
+
const a = s.findIndex((r) => r.uid === e.uid);
|
|
289
|
+
a !== -1 && (s.splice(a, 1), n = !0), s.length === 0 && this.isolatedBlocMap.delete(t);
|
|
280
290
|
}
|
|
281
|
-
this.isolatedBlocIndex.delete(e.uid)
|
|
291
|
+
const o = this.isolatedBlocIndex.delete(e.uid);
|
|
292
|
+
this.uidRegistry.delete(e.uid), this.keepAliveBlocs.delete(e), n !== o && this.warn(
|
|
293
|
+
`[Blac] Inconsistent state detected during isolated bloc cleanup for ${e._name}:${e.uid}. Map removal: ${n}, Index removal: ${o}`
|
|
294
|
+
);
|
|
282
295
|
}
|
|
283
296
|
/**
|
|
284
297
|
* Finds an isolated bloc instance by its class and ID (O(n) lookup)
|
|
285
298
|
*/
|
|
286
299
|
findIsolatedBlocInstance(e, t) {
|
|
287
300
|
if (!e.isolated) return;
|
|
288
|
-
const
|
|
289
|
-
return
|
|
301
|
+
const n = this.isolatedBlocMap.get(e);
|
|
302
|
+
return n ? n.find((a) => a._id === t) : void 0;
|
|
290
303
|
}
|
|
291
304
|
/**
|
|
292
305
|
* Finds an isolated bloc instance by UID (O(1) lookup)
|
|
@@ -303,45 +316,45 @@ const r = class r {
|
|
|
303
316
|
* @returns The newly created bloc instance
|
|
304
317
|
*/
|
|
305
318
|
createNewBlocInstance(e, t, s = {}) {
|
|
306
|
-
const { props:
|
|
307
|
-
return
|
|
319
|
+
const { props: n, instanceRef: o } = s, a = new e(n);
|
|
320
|
+
return a._instanceRef = o, a.props = n || null, a._updateId(t), a._setDisposalHandler((r) => this.disposeBloc(r)), a.isIsolated ? (this.registerIsolatedBlocInstance(a), a) : (this.registerBlocInstance(a), a);
|
|
308
321
|
}
|
|
309
322
|
static get activateBloc() {
|
|
310
|
-
return
|
|
323
|
+
return c.instance.activateBloc;
|
|
311
324
|
}
|
|
312
325
|
static get getBloc() {
|
|
313
|
-
return
|
|
326
|
+
return c.instance.getBloc;
|
|
314
327
|
}
|
|
315
328
|
static get getBlocOrThrow() {
|
|
316
|
-
return
|
|
329
|
+
return c.instance.getBlocOrThrow;
|
|
317
330
|
}
|
|
318
331
|
static get disposeKeepAliveBlocs() {
|
|
319
|
-
return
|
|
332
|
+
return c.instance.disposeKeepAliveBlocs;
|
|
320
333
|
}
|
|
321
334
|
static get disposeBlocs() {
|
|
322
|
-
return
|
|
335
|
+
return c.instance.disposeBlocs;
|
|
323
336
|
}
|
|
324
337
|
static get getMemoryStats() {
|
|
325
|
-
return
|
|
338
|
+
return c.instance.getMemoryStats;
|
|
326
339
|
}
|
|
327
340
|
static get validateConsumers() {
|
|
328
|
-
return
|
|
341
|
+
return c.instance.validateConsumers;
|
|
329
342
|
}
|
|
330
343
|
};
|
|
331
344
|
/** Flag to enable/disable logging */
|
|
332
|
-
|
|
333
|
-
|
|
345
|
+
i(c, "enableLog", !1), i(c, "resetInstance", () => {
|
|
346
|
+
g.resetInstance();
|
|
334
347
|
});
|
|
335
|
-
let
|
|
336
|
-
class
|
|
348
|
+
let l = c;
|
|
349
|
+
class w {
|
|
337
350
|
/**
|
|
338
351
|
* Creates a new BlacObservable instance
|
|
339
352
|
* @param bloc - The Bloc instance to observe
|
|
340
353
|
*/
|
|
341
354
|
constructor(e) {
|
|
342
355
|
/** The Bloc instance this observable is associated with */
|
|
343
|
-
|
|
344
|
-
|
|
356
|
+
i(this, "bloc");
|
|
357
|
+
i(this, "_observers", /* @__PURE__ */ new Set());
|
|
345
358
|
this.bloc = e;
|
|
346
359
|
}
|
|
347
360
|
/**
|
|
@@ -364,8 +377,8 @@ class m {
|
|
|
364
377
|
* @returns A function that can be called to unsubscribe the observer
|
|
365
378
|
*/
|
|
366
379
|
subscribe(e) {
|
|
367
|
-
return
|
|
368
|
-
|
|
380
|
+
return l.log("BlacObservable.subscribe: Subscribing observer.", this.bloc, e), this._observers.add(e), () => {
|
|
381
|
+
l.log("BlacObservable.subscribe: Unsubscribing observer.", this.bloc, e), this.unsubscribe(e);
|
|
369
382
|
};
|
|
370
383
|
}
|
|
371
384
|
/**
|
|
@@ -373,7 +386,7 @@ class m {
|
|
|
373
386
|
* @param observer - The observer to unsubscribe
|
|
374
387
|
*/
|
|
375
388
|
unsubscribe(e) {
|
|
376
|
-
this._observers.delete(e), this.size === 0 &&
|
|
389
|
+
this._observers.delete(e), this.size === 0 && l.log("BlacObservable.unsubscribe: No observers left.", this.bloc);
|
|
377
390
|
}
|
|
378
391
|
/**
|
|
379
392
|
* Notifies all observers of a state change
|
|
@@ -382,34 +395,48 @@ class m {
|
|
|
382
395
|
* @param action - Optional action that triggered the state change
|
|
383
396
|
*/
|
|
384
397
|
notify(e, t, s) {
|
|
385
|
-
this._observers.forEach((
|
|
386
|
-
let
|
|
387
|
-
if (
|
|
388
|
-
const
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
398
|
+
this._observers.forEach((n) => {
|
|
399
|
+
let o = !1;
|
|
400
|
+
if (n.dependencyArray) {
|
|
401
|
+
const a = n.lastState, r = n.dependencyArray(e);
|
|
402
|
+
if (!a)
|
|
403
|
+
o = !0;
|
|
404
|
+
else if (a.length !== r.length)
|
|
405
|
+
o = !0;
|
|
406
|
+
else
|
|
407
|
+
for (let h = 0; h < r.length; h++) {
|
|
408
|
+
const _ = r[h], p = a[h] || [];
|
|
409
|
+
if (_.length !== p.length) {
|
|
410
|
+
o = !0;
|
|
394
411
|
break;
|
|
395
412
|
}
|
|
396
|
-
|
|
397
|
-
|
|
413
|
+
for (let f = 0; f < _.length; f++)
|
|
414
|
+
if (!Object.is(_[f], p[f])) {
|
|
415
|
+
o = !0;
|
|
416
|
+
break;
|
|
417
|
+
}
|
|
418
|
+
if (o) break;
|
|
419
|
+
}
|
|
420
|
+
n.lastState = r;
|
|
398
421
|
} else
|
|
399
|
-
|
|
400
|
-
|
|
422
|
+
o = !0;
|
|
423
|
+
o && n.fn(e, t, s);
|
|
401
424
|
});
|
|
402
425
|
}
|
|
403
426
|
/**
|
|
404
427
|
* Clears the observer set
|
|
405
428
|
*/
|
|
406
429
|
clear() {
|
|
407
|
-
this._observers.
|
|
408
|
-
this.unsubscribe(e);
|
|
409
|
-
}), this._observers.clear();
|
|
430
|
+
this._observers.clear();
|
|
410
431
|
}
|
|
411
432
|
}
|
|
412
|
-
|
|
433
|
+
function S() {
|
|
434
|
+
return typeof crypto < "u" && crypto.randomUUID ? crypto.randomUUID() : "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(d) {
|
|
435
|
+
const e = Math.random() * 16 | 0;
|
|
436
|
+
return (d === "x" ? e : e & 3 | 8).toString(16);
|
|
437
|
+
});
|
|
438
|
+
}
|
|
439
|
+
class B {
|
|
413
440
|
/**
|
|
414
441
|
* Creates a new BlocBase instance with the given initial state.
|
|
415
442
|
* Sets up the observer, registers with the Blac manager, and initializes addons.
|
|
@@ -417,57 +444,90 @@ class g {
|
|
|
417
444
|
* @param initialState The initial state value for this Bloc
|
|
418
445
|
*/
|
|
419
446
|
constructor(e) {
|
|
420
|
-
|
|
447
|
+
i(this, "uid", S());
|
|
421
448
|
/**
|
|
422
449
|
* Defines how dependencies are selected from the state for efficient updates.
|
|
423
450
|
* When provided, observers will only be notified when selected dependencies change.
|
|
424
451
|
*/
|
|
425
|
-
|
|
452
|
+
i(this, "defaultDependencySelector");
|
|
426
453
|
/**
|
|
427
454
|
* @internal
|
|
428
455
|
* Indicates if this specific Bloc instance is isolated from others of the same type.
|
|
429
456
|
*/
|
|
430
|
-
|
|
457
|
+
i(this, "_isolated", !1);
|
|
431
458
|
/**
|
|
432
459
|
* @internal
|
|
433
460
|
* Observable responsible for managing state listeners and notifying consumers.
|
|
434
461
|
*/
|
|
435
|
-
|
|
462
|
+
i(this, "_observer");
|
|
436
463
|
/**
|
|
437
464
|
* The unique identifier for this Bloc instance.
|
|
438
465
|
* Defaults to the class name, but can be customized.
|
|
439
466
|
*/
|
|
440
|
-
|
|
467
|
+
i(this, "_id");
|
|
441
468
|
/**
|
|
442
469
|
* @internal
|
|
443
470
|
* Reference string used internally for tracking and debugging.
|
|
444
471
|
*/
|
|
445
|
-
|
|
472
|
+
i(this, "_instanceRef");
|
|
446
473
|
/**
|
|
447
474
|
* @internal
|
|
448
475
|
* Indicates if this specific Bloc instance should be kept alive when no consumers are present.
|
|
449
476
|
*/
|
|
450
|
-
|
|
477
|
+
i(this, "_keepAlive", !1);
|
|
451
478
|
/**
|
|
452
479
|
* @readonly
|
|
453
480
|
* Timestamp when this Bloc instance was created, useful for debugging and performance tracking.
|
|
454
481
|
*/
|
|
455
|
-
|
|
482
|
+
i(this, "_createdAt", Date.now());
|
|
483
|
+
/**
|
|
484
|
+
* @internal
|
|
485
|
+
* Disposal state to prevent race conditions
|
|
486
|
+
*/
|
|
487
|
+
i(this, "_disposalState", "active");
|
|
456
488
|
/**
|
|
457
489
|
* @internal
|
|
458
490
|
* The current state of the Bloc.
|
|
459
491
|
*/
|
|
460
|
-
|
|
492
|
+
i(this, "_state");
|
|
461
493
|
/**
|
|
462
494
|
* @internal
|
|
463
495
|
* The previous state of the Bloc, maintained for comparison and history.
|
|
464
496
|
*/
|
|
465
|
-
|
|
497
|
+
i(this, "_oldState");
|
|
466
498
|
/**
|
|
467
499
|
* Props passed during Bloc instance creation.
|
|
468
500
|
* Can be used to configure or parameterize the Bloc's behavior.
|
|
469
501
|
*/
|
|
470
|
-
|
|
502
|
+
i(this, "props", null);
|
|
503
|
+
/**
|
|
504
|
+
* @internal
|
|
505
|
+
* Flag to prevent batching race conditions
|
|
506
|
+
*/
|
|
507
|
+
i(this, "_batchingLock", !1);
|
|
508
|
+
/**
|
|
509
|
+
* @internal
|
|
510
|
+
* Pending batched updates
|
|
511
|
+
*/
|
|
512
|
+
i(this, "_pendingUpdates", []);
|
|
513
|
+
/**
|
|
514
|
+
* @internal
|
|
515
|
+
* Map of consumer IDs to their WeakRef objects for proper cleanup
|
|
516
|
+
*/
|
|
517
|
+
i(this, "_consumerRefs", /* @__PURE__ */ new Map());
|
|
518
|
+
/**
|
|
519
|
+
* @internal
|
|
520
|
+
* Validates that all consumer references are still alive
|
|
521
|
+
* Removes dead consumers automatically
|
|
522
|
+
*/
|
|
523
|
+
i(this, "_validateConsumers", () => {
|
|
524
|
+
const e = [];
|
|
525
|
+
for (const [t, s] of this._consumerRefs)
|
|
526
|
+
s.deref() === void 0 && e.push(t);
|
|
527
|
+
for (const t of e)
|
|
528
|
+
this._consumers.delete(t), this._consumerRefs.delete(t);
|
|
529
|
+
this._consumers.size === 0 && !this._keepAlive && this._disposalState === "active" && this._scheduleDisposal();
|
|
530
|
+
});
|
|
471
531
|
/**
|
|
472
532
|
* @internal
|
|
473
533
|
* Updates the Bloc instance's ID to a new value.
|
|
@@ -475,7 +535,7 @@ class g {
|
|
|
475
535
|
*
|
|
476
536
|
* @param id The new ID to assign to this Bloc instance
|
|
477
537
|
*/
|
|
478
|
-
|
|
538
|
+
i(this, "_updateId", (e) => {
|
|
479
539
|
const t = this._id;
|
|
480
540
|
!e || e === t || (this._id = e);
|
|
481
541
|
});
|
|
@@ -483,17 +543,12 @@ class g {
|
|
|
483
543
|
* @internal
|
|
484
544
|
* Optional function to be called when the Bloc is disposed.
|
|
485
545
|
*/
|
|
486
|
-
|
|
546
|
+
i(this, "onDispose");
|
|
487
547
|
/**
|
|
488
548
|
* @internal
|
|
489
549
|
* Set of consumer IDs currently listening to this Bloc's state changes.
|
|
490
550
|
*/
|
|
491
|
-
|
|
492
|
-
/**
|
|
493
|
-
* @internal
|
|
494
|
-
* WeakSet to track consumer references for cleanup validation
|
|
495
|
-
*/
|
|
496
|
-
n(this, "_consumerRefs", /* @__PURE__ */ new WeakSet());
|
|
551
|
+
i(this, "_consumers", /* @__PURE__ */ new Set());
|
|
497
552
|
/**
|
|
498
553
|
* @internal
|
|
499
554
|
* Registers a new consumer to this Bloc instance.
|
|
@@ -502,8 +557,8 @@ class g {
|
|
|
502
557
|
* @param consumerId The unique ID of the consumer being added
|
|
503
558
|
* @param consumerRef Optional reference to the consumer object for cleanup validation
|
|
504
559
|
*/
|
|
505
|
-
|
|
506
|
-
this._consumers.has(e) || (this._consumers.add(e), t && this._consumerRefs.
|
|
560
|
+
i(this, "_addConsumer", (e, t) => {
|
|
561
|
+
this._disposalState === "active" && (this._consumers.has(e) || (this._consumers.add(e), t && this._consumerRefs.set(e, new WeakRef(t))));
|
|
507
562
|
});
|
|
508
563
|
/**
|
|
509
564
|
* @internal
|
|
@@ -512,25 +567,20 @@ class g {
|
|
|
512
567
|
*
|
|
513
568
|
* @param consumerId The unique ID of the consumer being removed
|
|
514
569
|
*/
|
|
515
|
-
|
|
516
|
-
this._consumers.has(e) && (this._consumers.delete(e), this._consumers.size === 0 && !this._keepAlive && this._scheduleDisposal());
|
|
570
|
+
i(this, "_removeConsumer", (e) => {
|
|
571
|
+
this._consumers.has(e) && (this._consumers.delete(e), this._consumerRefs.delete(e), this._consumers.size === 0 && !this._keepAlive && this._disposalState === "active" && this._scheduleDisposal());
|
|
517
572
|
});
|
|
518
573
|
/**
|
|
519
574
|
* @internal
|
|
520
575
|
* Handler function for disposal (can be set by Blac manager)
|
|
521
576
|
*/
|
|
522
|
-
|
|
523
|
-
|
|
577
|
+
i(this, "_disposalHandler");
|
|
578
|
+
i(this, "lastUpdate", Date.now());
|
|
524
579
|
/**
|
|
525
580
|
* @internal
|
|
526
581
|
* Flag to indicate if batching is enabled for this bloc
|
|
527
582
|
*/
|
|
528
|
-
|
|
529
|
-
/**
|
|
530
|
-
* @internal
|
|
531
|
-
* Pending state updates when batching is enabled
|
|
532
|
-
*/
|
|
533
|
-
n(this, "_pendingUpdates", []);
|
|
583
|
+
i(this, "_batchingEnabled", !1);
|
|
534
584
|
/**
|
|
535
585
|
* @internal
|
|
536
586
|
* Updates the state and notifies all observers of the change.
|
|
@@ -539,17 +589,17 @@ class g {
|
|
|
539
589
|
* @param oldState The previous state for comparison
|
|
540
590
|
* @param action Optional metadata about what caused the state change
|
|
541
591
|
*/
|
|
542
|
-
|
|
592
|
+
i(this, "_pushState", (e, t, s) => {
|
|
543
593
|
if (e === void 0) {
|
|
544
594
|
console.warn("BlocBase._pushState: newState is undefined", this);
|
|
545
595
|
return;
|
|
546
596
|
}
|
|
547
|
-
if (s !=
|
|
548
|
-
|
|
549
|
-
|
|
597
|
+
if (s !== void 0 && typeof s != "object" && typeof s != "function") {
|
|
598
|
+
console.warn("BlocBase._pushState: Invalid action type", this, s);
|
|
599
|
+
return;
|
|
550
600
|
}
|
|
551
601
|
if (this._batchingEnabled) {
|
|
552
|
-
this._pendingUpdates.push({ newState: e, oldState: t, action: s });
|
|
602
|
+
this._pendingUpdates.push({ newState: e, oldState: t, action: s }), this._oldState = t, this._state = e;
|
|
553
603
|
return;
|
|
554
604
|
}
|
|
555
605
|
this._oldState = t, this._state = e, this._observer.notify(e, t, s), this.lastUpdate = Date.now();
|
|
@@ -558,21 +608,22 @@ class g {
|
|
|
558
608
|
* Enables batching for multiple state updates
|
|
559
609
|
* @param batchFn Function to execute with batching enabled
|
|
560
610
|
*/
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
611
|
+
i(this, "batch", (e) => {
|
|
612
|
+
if (this._batchingLock)
|
|
613
|
+
return e();
|
|
614
|
+
this._batchingLock = !0, this._batchingEnabled = !0, this._pendingUpdates = [];
|
|
564
615
|
try {
|
|
565
|
-
const
|
|
616
|
+
const t = e();
|
|
566
617
|
if (this._pendingUpdates.length > 0) {
|
|
567
|
-
const
|
|
568
|
-
this.
|
|
618
|
+
const s = this._pendingUpdates[this._pendingUpdates.length - 1];
|
|
619
|
+
this._observer.notify(s.newState, s.oldState, s.action), this.lastUpdate = Date.now();
|
|
569
620
|
}
|
|
570
|
-
return
|
|
621
|
+
return t;
|
|
571
622
|
} finally {
|
|
572
|
-
this._batchingEnabled =
|
|
623
|
+
this._batchingEnabled = !1, this._batchingLock = !1, this._pendingUpdates = [];
|
|
573
624
|
}
|
|
574
625
|
});
|
|
575
|
-
this._state = e, this._observer = new
|
|
626
|
+
this._state = e, this._observer = new w(this), this._id = this.constructor.name;
|
|
576
627
|
const t = this.constructor;
|
|
577
628
|
this._keepAlive = typeof t.keepAlive == "boolean" ? t.keepAlive : !1, this._isolated = typeof t.isolated == "boolean" ? t.isolated : !1;
|
|
578
629
|
}
|
|
@@ -603,7 +654,7 @@ class g {
|
|
|
603
654
|
*/
|
|
604
655
|
_dispose() {
|
|
605
656
|
var e;
|
|
606
|
-
this._consumers.clear(), this._observer.clear(), (e = this.onDispose) == null || e.call(this);
|
|
657
|
+
this._disposalState === "active" && (this._disposalState = "disposing", this._consumers.clear(), this._consumerRefs.clear(), this._observer.clear(), (e = this.onDispose) == null || e.call(this), this._disposalState = "disposed");
|
|
607
658
|
}
|
|
608
659
|
/**
|
|
609
660
|
* @internal
|
|
@@ -617,9 +668,7 @@ class g {
|
|
|
617
668
|
* Schedules disposal of this bloc instance if it has no consumers
|
|
618
669
|
*/
|
|
619
670
|
_scheduleDisposal() {
|
|
620
|
-
|
|
621
|
-
this._consumers.size === 0 && !this._keepAlive && (this._disposalHandler ? this._disposalHandler(this) : this._dispose());
|
|
622
|
-
}, 0);
|
|
671
|
+
this._disposalState === "active" && this._consumers.size === 0 && !this._keepAlive && (this._disposalHandler ? this._disposalHandler(this) : this._dispose());
|
|
623
672
|
}
|
|
624
673
|
}
|
|
625
674
|
/**
|
|
@@ -627,49 +676,36 @@ class g {
|
|
|
627
676
|
* Use this when state should not be shared between components.
|
|
628
677
|
* @default false
|
|
629
678
|
*/
|
|
630
|
-
|
|
679
|
+
i(B, "isolated", !1), /**
|
|
631
680
|
* When true, the Bloc instance persists even when there are no active consumers.
|
|
632
681
|
* Useful for maintaining state between component unmount/remount cycles.
|
|
633
682
|
* @default false
|
|
634
683
|
*/
|
|
635
|
-
|
|
636
|
-
class
|
|
684
|
+
i(B, "keepAlive", !1);
|
|
685
|
+
class b extends B {
|
|
637
686
|
constructor() {
|
|
638
687
|
super(...arguments);
|
|
639
688
|
// Stores handlers: Map<EventConstructor (subtype of A), HandlerFunction>
|
|
640
689
|
// The handler's event parameter will be correctly typed to the specific EventConstructor
|
|
641
690
|
// by the 'on' method's signature.
|
|
642
|
-
|
|
691
|
+
i(this, "eventHandlers", /* @__PURE__ */ new Map());
|
|
692
|
+
/**
|
|
693
|
+
* @internal
|
|
694
|
+
* Event queue to ensure sequential processing of async events
|
|
695
|
+
*/
|
|
696
|
+
i(this, "_eventQueue", []);
|
|
697
|
+
/**
|
|
698
|
+
* @internal
|
|
699
|
+
* Flag indicating if an event is currently being processed
|
|
700
|
+
*/
|
|
701
|
+
i(this, "_isProcessingEvent", !1);
|
|
643
702
|
/**
|
|
644
703
|
* Dispatches an action/event to the Bloc.
|
|
645
|
-
*
|
|
646
|
-
* Asynchronous handlers are awaited.
|
|
704
|
+
* Events are queued and processed sequentially to prevent race conditions.
|
|
647
705
|
* @param action The action/event instance to be processed.
|
|
648
706
|
*/
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
if (i) {
|
|
652
|
-
const a = (o) => {
|
|
653
|
-
const c = this.state;
|
|
654
|
-
this._pushState(o, c, t);
|
|
655
|
-
};
|
|
656
|
-
try {
|
|
657
|
-
await i(t, a);
|
|
658
|
-
} catch (o) {
|
|
659
|
-
h.error(
|
|
660
|
-
`[Bloc ${this._name}:${String(this._id)}] Error in event handler for '${s.name}':`,
|
|
661
|
-
o,
|
|
662
|
-
"Action:",
|
|
663
|
-
t
|
|
664
|
-
);
|
|
665
|
-
}
|
|
666
|
-
} else {
|
|
667
|
-
const a = t.constructor.name || "UnnamedConstructor";
|
|
668
|
-
h.warn(
|
|
669
|
-
`[Bloc ${this._name}:${String(this._id)}] No handler registered for action type: '${a}'. Action was:`,
|
|
670
|
-
t
|
|
671
|
-
);
|
|
672
|
-
}
|
|
707
|
+
i(this, "add", async (t) => {
|
|
708
|
+
this._eventQueue.push(t), this._isProcessingEvent || await this._processEventQueue();
|
|
673
709
|
});
|
|
674
710
|
}
|
|
675
711
|
/**
|
|
@@ -680,15 +716,73 @@ class A extends g {
|
|
|
680
716
|
* The 'event' parameter in the handler will be typed to the specific eventConstructor.
|
|
681
717
|
*/
|
|
682
718
|
on(t, s) {
|
|
683
|
-
this.eventHandlers.has(t) &&
|
|
719
|
+
this.eventHandlers.has(t) && l.warn(
|
|
684
720
|
`[Bloc ${this._name}:${String(this._id)}] Handler for event '${t.name}' already registered. It will be overwritten.`
|
|
685
721
|
), this.eventHandlers.set(
|
|
686
722
|
t,
|
|
687
723
|
s
|
|
688
724
|
);
|
|
689
725
|
}
|
|
726
|
+
/**
|
|
727
|
+
* @internal
|
|
728
|
+
* Processes events from the queue sequentially
|
|
729
|
+
*/
|
|
730
|
+
async _processEventQueue() {
|
|
731
|
+
if (!this._isProcessingEvent) {
|
|
732
|
+
this._isProcessingEvent = !0;
|
|
733
|
+
try {
|
|
734
|
+
for (; this._eventQueue.length > 0; ) {
|
|
735
|
+
const t = this._eventQueue.shift();
|
|
736
|
+
await this._processEvent(t);
|
|
737
|
+
}
|
|
738
|
+
} finally {
|
|
739
|
+
this._isProcessingEvent = !1;
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
/**
|
|
744
|
+
* @internal
|
|
745
|
+
* Processes a single event
|
|
746
|
+
*/
|
|
747
|
+
async _processEvent(t) {
|
|
748
|
+
const s = t.constructor, n = this.eventHandlers.get(s);
|
|
749
|
+
if (n) {
|
|
750
|
+
const o = (a) => {
|
|
751
|
+
const r = this.state;
|
|
752
|
+
this._pushState(a, r, t);
|
|
753
|
+
};
|
|
754
|
+
try {
|
|
755
|
+
await n(t, o);
|
|
756
|
+
} catch (a) {
|
|
757
|
+
const r = t.constructor.name || "UnnamedConstructor", h = {
|
|
758
|
+
blocName: this._name,
|
|
759
|
+
blocId: String(this._id),
|
|
760
|
+
eventType: r,
|
|
761
|
+
currentState: this.state,
|
|
762
|
+
action: t,
|
|
763
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
764
|
+
};
|
|
765
|
+
if (l.error(
|
|
766
|
+
`[Bloc ${this._name}:${String(this._id)}] Error in event handler for '${r}':`,
|
|
767
|
+
a,
|
|
768
|
+
"Context:",
|
|
769
|
+
h
|
|
770
|
+
), a instanceof Error && a.name === "CriticalError")
|
|
771
|
+
throw a;
|
|
772
|
+
}
|
|
773
|
+
} else {
|
|
774
|
+
const o = t.constructor.name || "UnnamedConstructor";
|
|
775
|
+
l.warn(
|
|
776
|
+
`[Bloc ${this._name}:${String(this._id)}] No handler registered for action type: '${o}'.`,
|
|
777
|
+
"Registered handlers:",
|
|
778
|
+
Array.from(this.eventHandlers.keys()).map((a) => a.name),
|
|
779
|
+
"Action was:",
|
|
780
|
+
t
|
|
781
|
+
);
|
|
782
|
+
}
|
|
783
|
+
}
|
|
690
784
|
}
|
|
691
|
-
class
|
|
785
|
+
class k extends B {
|
|
692
786
|
/**
|
|
693
787
|
* Updates the current state and notifies all observers of the change.
|
|
694
788
|
* If the new state is identical to the current state (using Object.is),
|
|
@@ -711,7 +805,7 @@ class M extends g {
|
|
|
711
805
|
*/
|
|
712
806
|
patch(e, t = !1) {
|
|
713
807
|
if (typeof this.state != "object" || this.state === null) {
|
|
714
|
-
|
|
808
|
+
l.warn(
|
|
715
809
|
"Cubit.patch: was called on a cubit where the state is not an object. This is a no-op."
|
|
716
810
|
);
|
|
717
811
|
return;
|
|
@@ -720,10 +814,10 @@ class M extends g {
|
|
|
720
814
|
if (t)
|
|
721
815
|
s = !0;
|
|
722
816
|
else
|
|
723
|
-
for (const
|
|
724
|
-
if (Object.prototype.hasOwnProperty.call(e,
|
|
725
|
-
const
|
|
726
|
-
if (!Object.is(e[
|
|
817
|
+
for (const n in e)
|
|
818
|
+
if (Object.prototype.hasOwnProperty.call(e, n)) {
|
|
819
|
+
const a = this.state[n];
|
|
820
|
+
if (!Object.is(e[n], a)) {
|
|
727
821
|
s = !0;
|
|
728
822
|
break;
|
|
729
823
|
}
|
|
@@ -734,12 +828,160 @@ class M extends g {
|
|
|
734
828
|
});
|
|
735
829
|
}
|
|
736
830
|
}
|
|
831
|
+
class x {
|
|
832
|
+
/**
|
|
833
|
+
* Sets up a clean test environment
|
|
834
|
+
*/
|
|
835
|
+
static setUp() {
|
|
836
|
+
this.originalInstance = l.instance, l.resetInstance(), l.enableLog = !1;
|
|
837
|
+
}
|
|
838
|
+
/**
|
|
839
|
+
* Tears down the test environment and restores original state
|
|
840
|
+
*/
|
|
841
|
+
static tearDown() {
|
|
842
|
+
l.resetInstance();
|
|
843
|
+
}
|
|
844
|
+
/**
|
|
845
|
+
* Creates a test bloc with automatic cleanup
|
|
846
|
+
*/
|
|
847
|
+
static createBloc(e, ...t) {
|
|
848
|
+
const s = new e(...t);
|
|
849
|
+
return l.activateBloc(s), s;
|
|
850
|
+
}
|
|
851
|
+
/**
|
|
852
|
+
* Waits for a bloc to emit a specific state
|
|
853
|
+
*/
|
|
854
|
+
static async waitForState(e, t, s = 5e3) {
|
|
855
|
+
return new Promise((n, o) => {
|
|
856
|
+
const a = setTimeout(() => {
|
|
857
|
+
o(new Error(`Timeout waiting for state matching predicate after ${s}ms`));
|
|
858
|
+
}, s), r = e._observer.subscribe({
|
|
859
|
+
id: `test-waiter-${crypto.randomUUID()}`,
|
|
860
|
+
fn: (h) => {
|
|
861
|
+
t(h) && (clearTimeout(a), r(), n(h));
|
|
862
|
+
}
|
|
863
|
+
});
|
|
864
|
+
t(e.state) && (clearTimeout(a), r(), n(e.state));
|
|
865
|
+
});
|
|
866
|
+
}
|
|
867
|
+
/**
|
|
868
|
+
* Expects a bloc to emit specific states in order
|
|
869
|
+
*/
|
|
870
|
+
static async expectStates(e, t, s = 5e3) {
|
|
871
|
+
const n = [];
|
|
872
|
+
return new Promise((o, a) => {
|
|
873
|
+
const r = setTimeout(() => {
|
|
874
|
+
a(new Error(
|
|
875
|
+
`Timeout waiting for states. Expected: ${JSON.stringify(t)}, Received: ${JSON.stringify(n)}`
|
|
876
|
+
));
|
|
877
|
+
}, s), h = e._observer.subscribe({
|
|
878
|
+
id: `test-expecter-${crypto.randomUUID()}`,
|
|
879
|
+
fn: (_) => {
|
|
880
|
+
if (n.push(_), n.length === t.length) {
|
|
881
|
+
clearTimeout(r), h();
|
|
882
|
+
for (let p = 0; p < t.length; p++) {
|
|
883
|
+
const f = t[p], I = n[p];
|
|
884
|
+
if (JSON.stringify(f) !== JSON.stringify(I)) {
|
|
885
|
+
a(new Error(
|
|
886
|
+
`State mismatch at index ${p}. Expected: ${JSON.stringify(f)}, Received: ${JSON.stringify(I)}`
|
|
887
|
+
));
|
|
888
|
+
return;
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
o();
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
});
|
|
895
|
+
});
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
i(x, "originalInstance");
|
|
899
|
+
class A extends b {
|
|
900
|
+
constructor(t) {
|
|
901
|
+
super(t);
|
|
902
|
+
i(this, "mockHandlers", /* @__PURE__ */ new Map());
|
|
903
|
+
}
|
|
904
|
+
/**
|
|
905
|
+
* Mock an event handler for testing
|
|
906
|
+
*/
|
|
907
|
+
mockEventHandler(t, s) {
|
|
908
|
+
this.on(t, s);
|
|
909
|
+
}
|
|
910
|
+
/**
|
|
911
|
+
* Get the number of registered handlers
|
|
912
|
+
*/
|
|
913
|
+
getHandlerCount() {
|
|
914
|
+
return this.eventHandlers.size;
|
|
915
|
+
}
|
|
916
|
+
/**
|
|
917
|
+
* Check if a handler is registered for an event type
|
|
918
|
+
*/
|
|
919
|
+
hasHandler(t) {
|
|
920
|
+
return this.eventHandlers.has(t);
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
class E extends k {
|
|
924
|
+
constructor(t) {
|
|
925
|
+
super(t);
|
|
926
|
+
i(this, "stateHistory", []);
|
|
927
|
+
this.stateHistory.push(t);
|
|
928
|
+
}
|
|
929
|
+
/**
|
|
930
|
+
* Override emit to track state history
|
|
931
|
+
*/
|
|
932
|
+
emit(t) {
|
|
933
|
+
this.stateHistory.push(t), super.emit(t);
|
|
934
|
+
}
|
|
935
|
+
/**
|
|
936
|
+
* Get the history of all states
|
|
937
|
+
*/
|
|
938
|
+
getStateHistory() {
|
|
939
|
+
return [...this.stateHistory];
|
|
940
|
+
}
|
|
941
|
+
/**
|
|
942
|
+
* Clear state history
|
|
943
|
+
*/
|
|
944
|
+
clearStateHistory() {
|
|
945
|
+
this.stateHistory = [this.state];
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
class R {
|
|
949
|
+
constructor() {
|
|
950
|
+
i(this, "initialStats");
|
|
951
|
+
this.initialStats = l.getMemoryStats();
|
|
952
|
+
}
|
|
953
|
+
/**
|
|
954
|
+
* Check for memory leaks and return a report
|
|
955
|
+
*/
|
|
956
|
+
checkForLeaks() {
|
|
957
|
+
const e = l.getMemoryStats(), t = e.registeredBlocs > this.initialStats.registeredBlocs || e.isolatedBlocs > this.initialStats.isolatedBlocs || e.keepAliveBlocs > this.initialStats.keepAliveBlocs, s = `
|
|
958
|
+
Memory Leak Detection Report:
|
|
959
|
+
- Initial registered blocs: ${this.initialStats.registeredBlocs}
|
|
960
|
+
- Current registered blocs: ${e.registeredBlocs}
|
|
961
|
+
- Initial isolated blocs: ${this.initialStats.isolatedBlocs}
|
|
962
|
+
- Current isolated blocs: ${e.isolatedBlocs}
|
|
963
|
+
- Initial keep-alive blocs: ${this.initialStats.keepAliveBlocs}
|
|
964
|
+
- Current keep-alive blocs: ${e.keepAliveBlocs}
|
|
965
|
+
- Potential leaks detected: ${t ? "YES" : "NO"}
|
|
966
|
+
`.trim();
|
|
967
|
+
return {
|
|
968
|
+
hasLeaks: t,
|
|
969
|
+
report: s,
|
|
970
|
+
stats: e
|
|
971
|
+
};
|
|
972
|
+
}
|
|
973
|
+
}
|
|
737
974
|
export {
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
975
|
+
l as Blac,
|
|
976
|
+
w as BlacObservable,
|
|
977
|
+
b as Bloc,
|
|
978
|
+
B as BlocBase,
|
|
979
|
+
x as BlocTest,
|
|
980
|
+
k as Cubit,
|
|
981
|
+
R as MemoryLeakDetector,
|
|
982
|
+
A as MockBloc,
|
|
983
|
+
E as MockCubit,
|
|
984
|
+
S as generateUUID,
|
|
985
|
+
M as setBlacInstanceManager
|
|
744
986
|
};
|
|
745
987
|
//# sourceMappingURL=index.es.js.map
|