@blac/core 2.0.0-rn-12 → 2.0.1
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 +178 -244
- package/dist/index.cjs +2993 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +1895 -0
- package/dist/index.d.ts +1715 -644
- package/dist/index.js +2884 -0
- package/dist/index.js.map +1 -0
- package/package.json +48 -18
- package/dist/index.cjs.js +0 -11
- package/dist/index.cjs.js.map +0 -1
- package/dist/index.es.js +0 -1588
- package/dist/index.es.js.map +0 -1
- package/src/Blac.ts +0 -789
- package/src/BlacObserver.ts +0 -186
- package/src/Bloc.ts +0 -138
- package/src/BlocBase.ts +0 -589
- package/src/Cubit.ts +0 -83
- package/src/__tests__/Blac.config.test.ts +0 -86
- package/src/__tests__/Bloc.event.test.ts +0 -419
- package/src/__tests__/BlocBase.lifecycle.test.ts +0 -441
- package/src/__tests__/Cubit.test.ts +0 -473
- package/src/__tests__/props.test.ts +0 -256
- package/src/adapter/BlacAdapter.ts +0 -327
- package/src/adapter/ConsumerTracker.ts +0 -241
- package/src/adapter/ProxyFactory.ts +0 -308
- package/src/adapter/__tests__/BlacAdapter.test.ts +0 -561
- package/src/adapter/__tests__/ConsumerTracker.test.ts +0 -562
- package/src/adapter/__tests__/ProxyFactory.test.ts +0 -655
- package/src/adapter/index.ts +0 -3
- package/src/events.ts +0 -3
- package/src/index.ts +0 -17
- package/src/testing.ts +0 -252
- package/src/types.ts +0 -91
- package/src/utils/shallowEqual.ts +0 -40
- package/src/utils/uuid.ts +0 -22
package/src/testing.ts
DELETED
|
@@ -1,252 +0,0 @@
|
|
|
1
|
-
import { Blac } from './Blac';
|
|
2
|
-
import { Bloc } from './Bloc';
|
|
3
|
-
import { BlocBase } from './BlocBase';
|
|
4
|
-
import { Cubit } from './Cubit';
|
|
5
|
-
import { BlocEventConstraint } from './types';
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Test utilities for Blac state management
|
|
9
|
-
*/
|
|
10
|
-
export class BlocTest {
|
|
11
|
-
private static originalInstance: Blac;
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Sets up a clean test environment
|
|
15
|
-
*/
|
|
16
|
-
static setUp(): void {
|
|
17
|
-
this.originalInstance = Blac.instance;
|
|
18
|
-
Blac.resetInstance();
|
|
19
|
-
Blac.enableLog = false; // Disable logging in tests by default
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Tears down the test environment and restores original state
|
|
24
|
-
*/
|
|
25
|
-
static tearDown(): void {
|
|
26
|
-
Blac.resetInstance();
|
|
27
|
-
// Note: Cannot restore original instance due to singleton pattern
|
|
28
|
-
// Tests should use setUp/tearDown properly to manage state
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Creates a test bloc with automatic cleanup
|
|
33
|
-
*/
|
|
34
|
-
static createBloc<T extends BlocBase<any>>(
|
|
35
|
-
BlocClass: new (...args: any[]) => T,
|
|
36
|
-
...args: any[]
|
|
37
|
-
): T {
|
|
38
|
-
const bloc = new BlocClass(...args);
|
|
39
|
-
Blac.activateBloc(bloc);
|
|
40
|
-
return bloc;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Waits for a bloc to emit a specific state
|
|
45
|
-
*/
|
|
46
|
-
static async waitForState<T extends BlocBase<S>, S>(
|
|
47
|
-
bloc: T,
|
|
48
|
-
predicate: (state: S) => boolean,
|
|
49
|
-
timeout = 5000,
|
|
50
|
-
): Promise<S> {
|
|
51
|
-
return new Promise<S>((resolve, reject) => {
|
|
52
|
-
const timeoutId = setTimeout(() => {
|
|
53
|
-
reject(
|
|
54
|
-
new Error(
|
|
55
|
-
`Timeout waiting for state matching predicate after ${timeout}ms`,
|
|
56
|
-
),
|
|
57
|
-
);
|
|
58
|
-
}, timeout);
|
|
59
|
-
|
|
60
|
-
const unsubscribe = bloc._observer.subscribe({
|
|
61
|
-
id: `test-waiter-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
|
|
62
|
-
fn: (newState: S) => {
|
|
63
|
-
if (predicate(newState)) {
|
|
64
|
-
clearTimeout(timeoutId);
|
|
65
|
-
unsubscribe();
|
|
66
|
-
resolve(newState);
|
|
67
|
-
}
|
|
68
|
-
},
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
// Check current state immediately
|
|
72
|
-
if (predicate(bloc.state)) {
|
|
73
|
-
clearTimeout(timeoutId);
|
|
74
|
-
unsubscribe();
|
|
75
|
-
resolve(bloc.state);
|
|
76
|
-
}
|
|
77
|
-
});
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* Expects a bloc to emit specific states in order
|
|
82
|
-
*/
|
|
83
|
-
static async expectStates<T extends BlocBase<S>, S>(
|
|
84
|
-
bloc: T,
|
|
85
|
-
expectedStates: S[],
|
|
86
|
-
timeout = 5000,
|
|
87
|
-
): Promise<void> {
|
|
88
|
-
const receivedStates: S[] = [];
|
|
89
|
-
|
|
90
|
-
return new Promise<void>((resolve, reject) => {
|
|
91
|
-
const timeoutId = setTimeout(() => {
|
|
92
|
-
reject(
|
|
93
|
-
new Error(
|
|
94
|
-
`Timeout waiting for states. Expected: ${JSON.stringify(expectedStates)}, ` +
|
|
95
|
-
`Received: ${JSON.stringify(receivedStates)}`,
|
|
96
|
-
),
|
|
97
|
-
);
|
|
98
|
-
}, timeout);
|
|
99
|
-
|
|
100
|
-
const unsubscribe = bloc._observer.subscribe({
|
|
101
|
-
id: `test-expecter-${crypto.randomUUID()}`,
|
|
102
|
-
fn: (newState: S) => {
|
|
103
|
-
receivedStates.push(newState);
|
|
104
|
-
|
|
105
|
-
// Check if we have all expected states
|
|
106
|
-
if (receivedStates.length === expectedStates.length) {
|
|
107
|
-
clearTimeout(timeoutId);
|
|
108
|
-
unsubscribe();
|
|
109
|
-
|
|
110
|
-
// Verify all states match using deep equality
|
|
111
|
-
for (let i = 0; i < expectedStates.length; i++) {
|
|
112
|
-
const expected = expectedStates[i];
|
|
113
|
-
const received = receivedStates[i];
|
|
114
|
-
|
|
115
|
-
// Use JSON comparison for deep equality
|
|
116
|
-
if (JSON.stringify(expected) !== JSON.stringify(received)) {
|
|
117
|
-
reject(
|
|
118
|
-
new Error(
|
|
119
|
-
`State mismatch at index ${i}. Expected: ${JSON.stringify(expected)}, ` +
|
|
120
|
-
`Received: ${JSON.stringify(received)}`,
|
|
121
|
-
),
|
|
122
|
-
);
|
|
123
|
-
return;
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
resolve();
|
|
128
|
-
}
|
|
129
|
-
},
|
|
130
|
-
});
|
|
131
|
-
});
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
/**
|
|
136
|
-
* Mock Bloc for testing
|
|
137
|
-
*/
|
|
138
|
-
export class MockBloc<
|
|
139
|
-
S,
|
|
140
|
-
A extends BlocEventConstraint = BlocEventConstraint,
|
|
141
|
-
> extends Bloc<S, A> {
|
|
142
|
-
private mockHandlers = new Map<
|
|
143
|
-
string,
|
|
144
|
-
(event: A, emit: (newState: S) => void) => void | Promise<void>
|
|
145
|
-
>();
|
|
146
|
-
|
|
147
|
-
constructor(initialState: S) {
|
|
148
|
-
super(initialState);
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
/**
|
|
152
|
-
* Mock an event handler for testing
|
|
153
|
-
*/
|
|
154
|
-
mockEventHandler<E extends A>(
|
|
155
|
-
eventConstructor: new (...args: any[]) => E,
|
|
156
|
-
handler: (event: E, emit: (newState: S) => void) => void | Promise<void>,
|
|
157
|
-
): void {
|
|
158
|
-
// Use the on method to register the mock handler
|
|
159
|
-
this.on(eventConstructor, handler);
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
/**
|
|
163
|
-
* Get the number of registered handlers
|
|
164
|
-
*/
|
|
165
|
-
getHandlerCount(): number {
|
|
166
|
-
return this.eventHandlers.size;
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
/**
|
|
170
|
-
* Check if a handler is registered for an event type
|
|
171
|
-
*/
|
|
172
|
-
hasHandler(eventConstructor: new (...args: any[]) => A): boolean {
|
|
173
|
-
return this.eventHandlers.has(eventConstructor);
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
/**
|
|
178
|
-
* Mock Cubit for testing
|
|
179
|
-
*/
|
|
180
|
-
export class MockCubit<S> extends Cubit<S> {
|
|
181
|
-
private stateHistory: S[] = [];
|
|
182
|
-
|
|
183
|
-
constructor(initialState: S) {
|
|
184
|
-
super(initialState);
|
|
185
|
-
this.stateHistory.push(initialState);
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
/**
|
|
189
|
-
* Override emit to track state history
|
|
190
|
-
*/
|
|
191
|
-
emit(newState: S): void {
|
|
192
|
-
this.stateHistory.push(newState);
|
|
193
|
-
super.emit(newState);
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
/**
|
|
197
|
-
* Get the history of all states
|
|
198
|
-
*/
|
|
199
|
-
getStateHistory(): S[] {
|
|
200
|
-
return [...this.stateHistory];
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
/**
|
|
204
|
-
* Clear state history
|
|
205
|
-
*/
|
|
206
|
-
clearStateHistory(): void {
|
|
207
|
-
this.stateHistory = [this.state];
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
/**
|
|
212
|
-
* Memory leak detector for tests
|
|
213
|
-
*/
|
|
214
|
-
export class MemoryLeakDetector {
|
|
215
|
-
private initialStats: ReturnType<typeof Blac.getMemoryStats>;
|
|
216
|
-
|
|
217
|
-
constructor() {
|
|
218
|
-
this.initialStats = Blac.getMemoryStats();
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
/**
|
|
222
|
-
* Check for memory leaks and return a report
|
|
223
|
-
*/
|
|
224
|
-
checkForLeaks(): {
|
|
225
|
-
hasLeaks: boolean;
|
|
226
|
-
report: string;
|
|
227
|
-
stats: ReturnType<typeof Blac.getMemoryStats>;
|
|
228
|
-
} {
|
|
229
|
-
const currentStats = Blac.getMemoryStats();
|
|
230
|
-
const hasLeaks =
|
|
231
|
-
currentStats.registeredBlocs > this.initialStats.registeredBlocs ||
|
|
232
|
-
currentStats.isolatedBlocs > this.initialStats.isolatedBlocs ||
|
|
233
|
-
currentStats.keepAliveBlocs > this.initialStats.keepAliveBlocs;
|
|
234
|
-
|
|
235
|
-
const report = `
|
|
236
|
-
Memory Leak Detection Report:
|
|
237
|
-
- Initial registered blocs: ${this.initialStats.registeredBlocs}
|
|
238
|
-
- Current registered blocs: ${currentStats.registeredBlocs}
|
|
239
|
-
- Initial isolated blocs: ${this.initialStats.isolatedBlocs}
|
|
240
|
-
- Current isolated blocs: ${currentStats.isolatedBlocs}
|
|
241
|
-
- Initial keep-alive blocs: ${this.initialStats.keepAliveBlocs}
|
|
242
|
-
- Current keep-alive blocs: ${currentStats.keepAliveBlocs}
|
|
243
|
-
- Potential leaks detected: ${hasLeaks ? 'YES' : 'NO'}
|
|
244
|
-
`.trim();
|
|
245
|
-
|
|
246
|
-
return {
|
|
247
|
-
hasLeaks,
|
|
248
|
-
report,
|
|
249
|
-
stats: currentStats,
|
|
250
|
-
};
|
|
251
|
-
}
|
|
252
|
-
}
|
package/src/types.ts
DELETED
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
-
import { Bloc } from './Bloc';
|
|
3
|
-
import { BlocBase } from './BlocBase';
|
|
4
|
-
import { Cubit } from './Cubit';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Represents a constructor type for a Bloc that takes no parameters
|
|
8
|
-
* @template B - The type of the Bloc instance
|
|
9
|
-
*/
|
|
10
|
-
export type BlocClassNoParams<B> = new (args: never[]) => B;
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Represents the abstract base types for Bloc and Cubit
|
|
14
|
-
*/
|
|
15
|
-
export type BlocBaseAbstract =
|
|
16
|
-
| typeof Bloc<any, any, any>
|
|
17
|
-
| typeof Cubit<any, any>;
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Represents a constructor type for a Bloc that can take any parameters
|
|
21
|
-
* @template B - The type of the Bloc instance
|
|
22
|
-
*/
|
|
23
|
-
export type BlocConstructor<B> = (new (...args: any) => B) & {
|
|
24
|
-
isolated?: boolean;
|
|
25
|
-
keepAlive?: boolean;
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Extracts the state type from a BlocBase instance
|
|
30
|
-
* @template B - The BlocBase type to extract the state from
|
|
31
|
-
*/
|
|
32
|
-
export type ValueType<B extends BlocBase<any>> =
|
|
33
|
-
B extends BlocBase<infer U> ? U : never;
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Extracts the state type from either a Bloc or Cubit
|
|
37
|
-
* @template T - The Bloc or Cubit type to extract the state from
|
|
38
|
-
*/
|
|
39
|
-
export type BlocState<T> = T extends BlocBase<infer S> ? S : never;
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Extracts the props type from either a Bloc or Cubit
|
|
43
|
-
* @template T - The Bloc or Cubit type to extract the props from
|
|
44
|
-
*/
|
|
45
|
-
export type InferPropsFromGeneric<T> =
|
|
46
|
-
T extends Bloc<any, any, infer P>
|
|
47
|
-
? P
|
|
48
|
-
: T extends Cubit<any, infer P>
|
|
49
|
-
? P
|
|
50
|
-
: never;
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Extracts the constructor parameters type from a BlocBase
|
|
54
|
-
* @template B - The BlocBase type to extract the constructor parameters from
|
|
55
|
-
*/
|
|
56
|
-
export type BlocConstructorParameters<B extends BlocBase<any>> =
|
|
57
|
-
BlocConstructor<B> extends new (...args: infer P) => B ? P : never;
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Enhanced constraint for Bloc events - must be objects with proper constructor
|
|
61
|
-
*/
|
|
62
|
-
export type BlocEventConstraint = object;
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* Error boundary interface for Bloc error handling
|
|
66
|
-
*/
|
|
67
|
-
export interface BlocErrorBoundary<S, A extends BlocEventConstraint> {
|
|
68
|
-
onError: (
|
|
69
|
-
error: Error,
|
|
70
|
-
event: A,
|
|
71
|
-
currentState: S,
|
|
72
|
-
bloc: { name: string; id: string },
|
|
73
|
-
) => void | Promise<void>;
|
|
74
|
-
shouldRethrow?: (error: Error, event: A) => boolean;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* Function type for determining dependencies that trigger re-renders
|
|
79
|
-
* Similar to React's useEffect dependency array - if any dependency changes, a re-render is triggered
|
|
80
|
-
* @template S The state type
|
|
81
|
-
* @template I The bloc instance type
|
|
82
|
-
* @param currentState The current state
|
|
83
|
-
* @param previousState The previous state (undefined on first call)
|
|
84
|
-
* @param instance The bloc instance
|
|
85
|
-
* @returns Array of dependencies - if any dependency changes, a re-render is triggered
|
|
86
|
-
*/
|
|
87
|
-
export type BlocHookDependencyArrayFn<S, I = any> = (
|
|
88
|
-
currentState: S,
|
|
89
|
-
previousState: S | undefined,
|
|
90
|
-
instance: I,
|
|
91
|
-
) => unknown[];
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Performs a shallow equality comparison between two values.
|
|
3
|
-
* For objects, it checks if all top-level properties are equal using Object.is.
|
|
4
|
-
* @param a First value to compare
|
|
5
|
-
* @param b Second value to compare
|
|
6
|
-
* @returns true if values are shallowly equal, false otherwise
|
|
7
|
-
*/
|
|
8
|
-
export function shallowEqual(a: any, b: any): boolean {
|
|
9
|
-
if (Object.is(a, b)) {
|
|
10
|
-
return true;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
if (
|
|
14
|
-
typeof a !== 'object' ||
|
|
15
|
-
a === null ||
|
|
16
|
-
typeof b !== 'object' ||
|
|
17
|
-
b === null
|
|
18
|
-
) {
|
|
19
|
-
return false;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
const keysA = Object.keys(a);
|
|
23
|
-
const keysB = Object.keys(b);
|
|
24
|
-
|
|
25
|
-
if (keysA.length !== keysB.length) {
|
|
26
|
-
return false;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
for (let i = 0; i < keysA.length; i++) {
|
|
30
|
-
const key = keysA[i];
|
|
31
|
-
if (
|
|
32
|
-
!Object.prototype.hasOwnProperty.call(b, key) ||
|
|
33
|
-
!Object.is(a[key], b[key])
|
|
34
|
-
) {
|
|
35
|
-
return false;
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
return true;
|
|
40
|
-
}
|
package/src/utils/uuid.ts
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Cross-platform UUID v4 generator that works in all environments including React Native/Hermes
|
|
3
|
-
* Falls back to crypto.randomUUID() when available, otherwise uses Math.random()
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Generates a UUID v4 string compatible with all JavaScript environments
|
|
8
|
-
* @returns A UUID v4 string in the format xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
|
|
9
|
-
*/
|
|
10
|
-
export function generateUUID(): string {
|
|
11
|
-
// Try to use crypto.randomUUID() if available (Node.js 16+, modern browsers)
|
|
12
|
-
if (typeof crypto !== 'undefined' && crypto.randomUUID) {
|
|
13
|
-
return crypto.randomUUID();
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
// Fallback implementation for React Native/Hermes and older environments
|
|
17
|
-
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
|
|
18
|
-
const r = (Math.random() * 16) | 0;
|
|
19
|
-
const v = c === 'x' ? r : (r & 0x3) | 0x8;
|
|
20
|
-
return v.toString(16);
|
|
21
|
-
});
|
|
22
|
-
}
|