Skip to content

Commit 55c390f

Browse files
committed
#develop fixed typos
1 parent 9f58ec4 commit 55c390f

File tree

3 files changed

+172
-11
lines changed

3 files changed

+172
-11
lines changed

packages/feature-state/src/create-state.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { getQueue } from './queue';
1+
import { createQueue, getQueue } from './queue';
22
import type { TListener, TListenerContext, TState } from './types';
33

44
export const SET_SOURCE_KEY = 'state_set';
@@ -8,9 +8,11 @@ export function createState<GValue>(
88
options: TCreateStateOptions = {}
99
): TState<GValue, []> {
1010
const { queue: queueName = 'async' } = options;
11-
const queue = getQueue(queueName);
11+
12+
let queue = getQueue(queueName);
1213
if (queue == null) {
13-
throw new Error(`Queue "${queueName}" not found`);
14+
// Auto-create any queue - sync if named 'sync', otherwise async
15+
queue = createQueue(queueName, { sync: queueName === 'sync' });
1416
}
1517

1618
return {
@@ -90,7 +92,7 @@ export function createState<GValue>(
9092
}
9193

9294
interface TCreateStateOptions {
93-
queue?: string;
95+
queue?: 'sync' | 'async' | string;
9496
}
9597

9698
export enum EStateListenerQueuePriority {
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
import { beforeEach, describe, expect, it, vi } from 'vitest';
2+
import { createState } from './create-state';
3+
import {
4+
createQueue,
5+
getQueue,
6+
GLOBAL_STATE_QUEUES,
7+
processAllQueues,
8+
processQueue
9+
} from './queue';
10+
11+
describe('Queue system', () => {
12+
beforeEach(() => {
13+
// Clear global state for clean reset
14+
GLOBAL_STATE_QUEUES.clear();
15+
});
16+
17+
it('should create, retrieve and handle queues correctly', () => {
18+
// Create queues
19+
createQueue('test-sync', { sync: true });
20+
createQueue('test-async', { sync: false });
21+
22+
// Direct access to global state
23+
expect(GLOBAL_STATE_QUEUES.size).toBe(2);
24+
expect(GLOBAL_STATE_QUEUES.has('test-sync')).toBe(true);
25+
expect(GLOBAL_STATE_QUEUES.has('test-async')).toBe(true);
26+
27+
// Retrieve queues
28+
const syncQueue = getQueue('test-sync');
29+
const asyncQueue = getQueue('test-async');
30+
const nonExistent = getQueue('non-existent');
31+
32+
// Assert
33+
expect(syncQueue?.sync).toBe(true);
34+
expect(asyncQueue?.sync).toBe(false);
35+
expect(nonExistent).toBeUndefined();
36+
37+
// Override queue
38+
createQueue('test-sync', { sync: false });
39+
expect(getQueue('test-sync')?.sync).toBe(false);
40+
expect(GLOBAL_STATE_QUEUES.size).toBe(2); // Size should remain same
41+
});
42+
43+
it('should create states with auto-created queues', () => {
44+
// States should auto-create default queues
45+
const defaultState = createState('default');
46+
const syncState = createState('sync', { queue: 'sync' });
47+
const customState = createState('custom', { queue: 'my-custom-queue' });
48+
49+
// Check auto-created queues
50+
expect(GLOBAL_STATE_QUEUES.has('async')).toBe(true);
51+
expect(GLOBAL_STATE_QUEUES.has('sync')).toBe(true);
52+
expect(GLOBAL_STATE_QUEUES.has('my-custom-queue')).toBe(true);
53+
54+
expect(GLOBAL_STATE_QUEUES.get('async')?.sync).toBe(false);
55+
expect(GLOBAL_STATE_QUEUES.get('sync')?.sync).toBe(true);
56+
expect(GLOBAL_STATE_QUEUES.get('my-custom-queue')?.sync).toBe(false); // Custom queues default to async
57+
58+
// Verify states reference the correct queues
59+
expect(defaultState._queue).toBe(GLOBAL_STATE_QUEUES.get('async'));
60+
expect(syncState._queue).toBe(GLOBAL_STATE_QUEUES.get('sync'));
61+
expect(customState._queue).toBe(GLOBAL_STATE_QUEUES.get('my-custom-queue'));
62+
});
63+
64+
it('should handle shared queues and isolation correctly', () => {
65+
createQueue('shared', { sync: true });
66+
67+
const state1 = createState(0, { queue: 'shared' });
68+
const state2 = createState(0, { queue: 'shared' });
69+
const isolatedState = createState(0, { queue: 'sync' });
70+
71+
// Verify queue sharing
72+
expect(state1._queue).toBe(state2._queue);
73+
expect(state1._queue).not.toBe(isolatedState._queue);
74+
75+
// Test isolation
76+
const listener1 = vi.fn();
77+
const listener2 = vi.fn();
78+
const isolatedListener = vi.fn();
79+
80+
state1.listen(listener1);
81+
state2.listen(listener2);
82+
isolatedState.listen(isolatedListener);
83+
84+
state1.set(1);
85+
expect(listener1).toHaveBeenCalled();
86+
expect(listener2).not.toHaveBeenCalled();
87+
expect(isolatedListener).not.toHaveBeenCalled();
88+
});
89+
90+
it('should process sync immediately and async in next tick', async () => {
91+
const syncState = createState(0, { queue: 'sync' });
92+
const asyncState = createState(0, { queue: 'async' });
93+
const syncListener = vi.fn();
94+
const asyncListener = vi.fn();
95+
96+
syncState.listen((context) => {
97+
syncListener(context);
98+
});
99+
asyncState.listen(async (context) => {
100+
await new Promise((resolve) => setTimeout(resolve, 10));
101+
asyncListener(context);
102+
});
103+
104+
// Act
105+
syncState.set(1);
106+
asyncState.set(2);
107+
108+
// Sync should be immediate
109+
expect(syncListener).toHaveBeenCalledWith({
110+
source: 'state_set',
111+
value: 1,
112+
prevValue: 0
113+
});
114+
115+
// Async should be deferred to next microtask
116+
expect(asyncListener).not.toHaveBeenCalled();
117+
118+
// Wait for async processing to complete
119+
await new Promise((resolve) => setTimeout(resolve, 10));
120+
expect(asyncListener).toHaveBeenCalledWith({
121+
source: 'state_set',
122+
value: 2,
123+
prevValue: 0
124+
});
125+
});
126+
127+
it('should handle manual processing and queue inspection', () => {
128+
const state = createState(0, { queue: 'sync' });
129+
const listener = vi.fn();
130+
state.listen(listener);
131+
132+
// Disable auto-processing
133+
state.set(1, { processListenerQueue: false });
134+
135+
// Queue should have items
136+
expect(GLOBAL_STATE_QUEUES.get('sync')?.length).toBe(1);
137+
expect(listener).not.toHaveBeenCalled();
138+
139+
// Manual processing
140+
processQueue('sync');
141+
expect(GLOBAL_STATE_QUEUES.get('sync')?.length).toBe(0);
142+
expect(listener).toHaveBeenCalled();
143+
144+
// Test processAllQueues
145+
createQueue('test-queue', { sync: true });
146+
const testState = createState(0, { queue: 'test-queue' });
147+
const testListener = vi.fn();
148+
testState.listen(testListener);
149+
150+
state.set(2, { processListenerQueue: false });
151+
testState.set(3, { processListenerQueue: false });
152+
153+
processAllQueues();
154+
155+
expect(listener).toHaveBeenCalledTimes(2);
156+
expect(testListener).toHaveBeenCalled();
157+
158+
// Test non-existent queue handling
159+
expect(() => processQueue('non-existent')).not.toThrow();
160+
});
161+
});

packages/feature-state/src/queue.ts

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
11
import { ListenerQueue } from './ListenerQueue';
22

3-
const GLOBAL_STATE_QUEUES = new Map<string, ListenerQueue>();
3+
export const GLOBAL_STATE_QUEUES = new Map<string, ListenerQueue>();
44

5-
// Initialize default queues
6-
GLOBAL_STATE_QUEUES.set('async', new ListenerQueue(false));
7-
GLOBAL_STATE_QUEUES.set('sync', new ListenerQueue(true));
8-
9-
export function createQueue(name: string, options: { sync: boolean }): void {
10-
GLOBAL_STATE_QUEUES.set(name, new ListenerQueue(options.sync));
5+
export function createQueue(name: string, options: { sync: boolean }): ListenerQueue {
6+
const queue = new ListenerQueue(options.sync);
7+
GLOBAL_STATE_QUEUES.set(name, queue);
8+
return queue;
119
}
1210

1311
export function getQueue(name: string): ListenerQueue | undefined {

0 commit comments

Comments
 (0)