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