fastevent 0.0.1 → 1.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.
Files changed (41) hide show
  1. package/.changeset/README.md +8 -0
  2. package/.changeset/config.json +11 -0
  3. package/.github/workflows/publish.yaml +50 -0
  4. package/.vscode/launch.json +20 -0
  5. package/CHANGELOG.md +14 -0
  6. package/LICENSE +21 -0
  7. package/bench.png +0 -0
  8. package/dist/index.d.mts +205 -0
  9. package/dist/index.d.ts +205 -0
  10. package/dist/index.js +2 -0
  11. package/dist/index.js.map +1 -0
  12. package/dist/index.mjs +2 -0
  13. package/dist/index.mjs.map +1 -0
  14. package/package.json +34 -12
  15. package/readme.md +282 -0
  16. package/readme_cn.md +282 -0
  17. package/src/__benchmarks__/index.ts +3 -0
  18. package/src/__benchmarks__/multi-level.ts +40 -0
  19. package/src/__benchmarks__/sample.ts +40 -0
  20. package/src/__benchmarks__/wildcard.ts +41 -0
  21. package/src/__tests__/emit.test.ts +94 -0
  22. package/src/__tests__/emitAsync.test.ts +65 -0
  23. package/src/__tests__/isPathMatched.test.ts +205 -0
  24. package/src/__tests__/many.test.ts +23 -0
  25. package/src/__tests__/meta.test.ts +29 -0
  26. package/src/__tests__/off.test.ts +214 -0
  27. package/src/__tests__/onany.test.ts +173 -0
  28. package/src/__tests__/once.test.ts +71 -0
  29. package/src/__tests__/retain.test.ts +66 -0
  30. package/src/__tests__/scope.test.ts +111 -0
  31. package/src/__tests__/waitFor.test.ts +109 -0
  32. package/src/__tests__/wildcard.test.ts +186 -0
  33. package/src/event.ts +470 -5
  34. package/src/index.ts +3 -1
  35. package/src/scope.ts +88 -0
  36. package/src/types.ts +57 -0
  37. package/src/typestest.ts +102 -0
  38. package/src/utils/isPathMatched.ts +40 -0
  39. package/src/utils/removeItem.ts +16 -0
  40. package/tsconfig.json +112 -0
  41. package/tsup.config.ts +19 -0
@@ -0,0 +1,71 @@
1
+ import { describe, test, expect } from "vitest"
2
+ import { FastEvent } from "../event"
3
+
4
+ describe("只订阅一次的事件的发布与订阅",async ()=>{
5
+ test("简单发布只订阅一次事件",()=>{
6
+ const emitter = new FastEvent()
7
+ const events:string[] =[]
8
+ emitter.once("x",(payload,{type})=>{
9
+ expect(type).toBe("x")
10
+ expect(payload).toBe(1)
11
+ events.push(type)
12
+ })
13
+ emitter.emit("x",1)
14
+ emitter.emit("x",1)
15
+ emitter.emit("x",1)
16
+ emitter.emit("x",1)
17
+ expect(events).toEqual(["x"])
18
+ })
19
+ test("简单发布只订阅一次事件后取消",()=>{
20
+ const emitter = new FastEvent()
21
+ const events:string[]=[]
22
+ const subscriber = emitter.once("x",(payload,{type})=>{
23
+ expect(type).toBe("x")
24
+ expect(payload).toBe(1)
25
+ events.push(type)
26
+ })
27
+ subscriber.off()
28
+ emitter.emit("x",1)
29
+ emitter.emit("x",1)
30
+ emitter.emit("x",1)
31
+ expect(events).toEqual([])
32
+ })
33
+ test("简单发布只订阅一次的多级事件",()=>{
34
+ const emitter = new FastEvent()
35
+ const events:string[] =[]
36
+ emitter.once("a.b.c.d",(payload,{type})=>{
37
+ expect(type).toBe("a.b.c.d")
38
+ expect(payload).toBe(1)
39
+ events.push(type)
40
+ })
41
+ emitter.emit("a.b.c.d",1)
42
+ emitter.emit("a.b.c.d",2)
43
+ emitter.emit("a.b.c.d",3)
44
+ emitter.emit("a.b.c.d",4)
45
+ expect(events).toEqual(["a.b.c.d"])
46
+ })
47
+ test("混合发布只订阅一次的多级事件",()=>{
48
+ const emitter = new FastEvent()
49
+ const events:string[] =[]
50
+ const values:number[]=[]
51
+ emitter.once("a.b.c.d",(payload,{type})=>{
52
+ expect(type).toBe("a.b.c.d")
53
+ values.push(payload)
54
+ events.push(type)
55
+ })
56
+ emitter.on("a.b.c.d",(payload,{type})=>{
57
+ expect(type).toBe("a.b.c.d")
58
+ values.push(payload)
59
+ events.push(type)
60
+ })
61
+ emitter.emit("a.b.c.d",1)
62
+ emitter.emit("a.b.c.d",2)
63
+ emitter.emit("a.b.c.d",3)
64
+ emitter.emit("a.b.c.d",4)
65
+ expect(events).toEqual(["a.b.c.d","a.b.c.d","a.b.c.d","a.b.c.d","a.b.c.d"])
66
+ expect(values).toEqual([1,1,2,3,4])
67
+ })
68
+
69
+
70
+ })
71
+
@@ -0,0 +1,66 @@
1
+ import { describe, test, expect } from "vitest"
2
+ import { FastEvent } from "../event"
3
+
4
+
5
+
6
+ describe("订阅与发布retain事件",async ()=>{
7
+ test("简单发布订阅retain事件",()=>{
8
+ const emitter = new FastEvent()
9
+ emitter.emit("x",1,true)
10
+ emitter.on("x",(payload,{type})=>{
11
+ expect(type).toBe("x")
12
+ expect(payload).toBe(1)
13
+ })
14
+ emitter.emit("a.b.c1",1,true)
15
+ emitter.emit("a.b.c2",2,true)
16
+ emitter.on("a.b.c1",(payload,{type})=>{
17
+ expect(type).toBe("a.b.c1")
18
+ expect(payload).toBe(1)
19
+ })
20
+ emitter.on("a.b.c2",(payload,{type})=>{
21
+ expect(type).toBe("a.b.c2")
22
+ expect(payload).toBe(2)
23
+ })
24
+ })
25
+ test("不处理通配符的retain事件",()=>{
26
+ const emitter = new FastEvent()
27
+ emitter.emit("a.b.c1",1,true)
28
+ emitter.emit("a.b.c2",2,true)
29
+ const events:string[] = []
30
+ // 订阅所有a.b.*事件,由于c1,c2是
31
+ emitter.on("a.b.*",(payload,{type})=>{
32
+ events.push(type)
33
+ })
34
+ expect(events).toEqual([])
35
+ })
36
+ test("简单发布订阅retain事件",()=>{
37
+ const emitter = new FastEvent()
38
+ const events:string[] = []
39
+ emitter.emit("a",1,true)
40
+ emitter.emit("a.b",2,true)
41
+ emitter.emit("a.b.c",3,true)
42
+ emitter.emit("a.b.c.d",4,true)
43
+
44
+ emitter.on("a",(payload,{type})=>{
45
+ expect(type).toBe("a")
46
+ expect(payload).toBe(1)
47
+ events.push(type)
48
+ })
49
+ emitter.on("a.b",(payload,{type})=>{
50
+ expect(type).toBe("a.b")
51
+ expect(payload).toBe(2)
52
+ events.push(type)
53
+ })
54
+ emitter.on("a.b.c",(payload,{type})=>{
55
+ expect(type).toBe("a.b.c")
56
+ expect(payload).toBe(3)
57
+ events.push(type)
58
+ })
59
+ emitter.on("a.b.c.d",(payload,{type})=>{
60
+ expect(type).toBe("a.b.c.d")
61
+ expect(payload).toBe(4)
62
+ events.push(type)
63
+ })
64
+ expect(events).toEqual(["a","a.b","a.b.c","a.b.c.d"])
65
+ })
66
+ })
@@ -0,0 +1,111 @@
1
+ import { describe, test, expect } from "vitest"
2
+ import { FastEvent } from "../event"
3
+
4
+
5
+ describe("scope", ()=>{
6
+ test("scope简单的发布订阅事件",()=>{
7
+ const emitter = new FastEvent()
8
+ const scope = emitter.scope("a/b/c")
9
+ const events:string[] =[]
10
+ scope.on("x", (payload,{type})=>{
11
+ events.push(type)
12
+ })
13
+ emitter.on("a/b/c/x", (payload,{type})=>{
14
+ events.push(type)
15
+ })
16
+ scope.emit("x",1)
17
+ expect(events).toEqual(["x","a/b/c/x"])
18
+ })
19
+
20
+ test("scope通过off简单的退订事件",()=>{
21
+ const emitter = new FastEvent()
22
+ const scope = emitter.scope("a/b/c")
23
+
24
+ const events:string[] =[]
25
+ const subscriber =scope.on("x", (payload,{type})=>{
26
+ events.push(type)
27
+ })
28
+ emitter.on("a/b/c/x", (payload,{type})=>{
29
+ events.push(type)
30
+ })
31
+ scope.emit("x",1)
32
+ subscriber.off()
33
+ scope.emit("x",1)
34
+ expect(events).toEqual(["x","a/b/c/x","a/b/c/x"])
35
+ })
36
+
37
+ test("scope off退订事件",()=>{
38
+ const emitter = new FastEvent()
39
+ const scope = emitter.scope("a/b/c")
40
+
41
+ const events:string[] =[]
42
+ scope.on("x", (payload,{type})=>{
43
+ events.push(type)
44
+ })
45
+ emitter.on("a/b/c/x", (payload,{type})=>{
46
+ events.push(type)
47
+ })
48
+ scope.emit("x",1)
49
+ scope.off('x') // 等效于退订a/b/c/x事件
50
+ scope.emit("x",1)
51
+ expect(events).toEqual(["x","a/b/c/x"])
52
+ })
53
+ test("scope once布订阅事件",()=>{
54
+ const emitter = new FastEvent()
55
+ const scope = emitter.scope("a/b/c")
56
+ const events:string[] =[]
57
+ scope.once("x", (payload,{type})=>{
58
+ events.push(type)
59
+ })
60
+ emitter.once("a/b/c/x", (payload,{type})=>{
61
+ events.push(type)
62
+ })
63
+ scope.emit("x",1)
64
+ expect(events).toEqual(["x","a/b/c/x"])
65
+ })
66
+
67
+ test('scope waitFor', async () => {
68
+ const emitter = new FastEvent();
69
+ const scope = emitter.scope("a/b/c")
70
+
71
+ // Arrange
72
+ const event1Promise = scope.waitFor('x', 500);
73
+ const event2Promise = scope.waitFor('y', 200);
74
+ const event3Promise = scope.waitFor('z', 1000);
75
+
76
+ // Act
77
+ setTimeout(() => {
78
+ scope.emit('x', 'payload1');
79
+ }, 100);
80
+
81
+ setTimeout(() => {
82
+ scope.emit('y', 'payload2');
83
+ }, 300);
84
+
85
+ // Event2 will timeout before emission
86
+ setTimeout(() => {
87
+ scope.emit('z', 'payload3');
88
+ }, 300);
89
+
90
+ // Assert
91
+ const results = await Promise.allSettled([
92
+ event1Promise,
93
+ event2Promise,
94
+ event3Promise
95
+ ]);
96
+
97
+ expect(results[0].status).toBe('fulfilled');
98
+ expect(results[0]).toHaveProperty('value', 'payload1');
99
+
100
+ expect(results[1].status).toBe('rejected');
101
+ //@ts-ignore
102
+ expect(results[1].reason).toBeInstanceOf(Error);
103
+
104
+ expect(results[2].status).toBe('fulfilled');
105
+ expect(results[2]).toHaveProperty('value', 'payload3');
106
+ });
107
+
108
+
109
+ })
110
+
111
+
@@ -0,0 +1,109 @@
1
+ import { describe, test, expect } from "vitest"
2
+ import { FastEvent } from "../event"
3
+
4
+
5
+
6
+ describe("waitfor",()=>{
7
+
8
+ test('should resolve promise when event is emitted immediately', () => {
9
+ return new Promise<void>((resolve) => {
10
+ const emitter = new FastEvent();
11
+ // Arrange
12
+ const eventType = 'test-event';
13
+ const expectedPayload = { data: 'test data' };
14
+
15
+ // Act
16
+ // Create a promise for waitFor and store it
17
+ const waitPromise = emitter.waitFor(eventType);
18
+
19
+ // Emit the event immediately after calling waitFor
20
+ emitter.emit(eventType, expectedPayload);
21
+
22
+ // Assert
23
+ // Wait for the promise to resolve and check the result
24
+ waitPromise.then(result=>{
25
+ expect(result).toEqual(expectedPayload);
26
+ resolve()
27
+ })
28
+
29
+ })
30
+ });
31
+ test('should handle multiple events waiting simultaneously', async () => {
32
+ return new Promise<void>((resolve) => {
33
+ const emitter = new FastEvent();
34
+ // Arrange
35
+ const event1Promise = emitter.waitFor('event1');
36
+ const event2Promise = emitter.waitFor('event2');
37
+ const event3Promise = emitter.waitFor('event3');
38
+
39
+ // Act
40
+ setTimeout(() => {
41
+ emitter.emit('event2', 'payload2');
42
+ }, 100);
43
+
44
+ setTimeout(() => {
45
+ emitter.emit('event1', 'payload1');
46
+ }, 200);
47
+
48
+ setTimeout(() => {
49
+ emitter.emit('event3', 'payload3');
50
+ }, 300);
51
+
52
+ // Assert
53
+ Promise.all([
54
+ event1Promise,
55
+ event2Promise,
56
+ event3Promise
57
+ ]).then(results=>{
58
+ expect(results).toEqual([
59
+ 'payload1',
60
+ 'payload2',
61
+ 'payload3'
62
+ ]);
63
+ resolve()
64
+ })
65
+ })
66
+ });
67
+
68
+ test('should handle multiple events with different timeouts', async () => {
69
+ const emitter = new FastEvent();
70
+ // Arrange
71
+ const event1Promise = emitter.waitFor('event1', 500);
72
+ const event2Promise = emitter.waitFor('event2', 200);
73
+ const event3Promise = emitter.waitFor('event3', 1000);
74
+
75
+ // Act
76
+ setTimeout(() => {
77
+ emitter.emit('event1', 'payload1');
78
+ }, 100);
79
+
80
+ setTimeout(() => {
81
+ emitter.emit('event3', 'payload2');
82
+ }, 300);
83
+
84
+ // Event2 will timeout before emission
85
+ setTimeout(() => {
86
+ emitter.emit('event2', 'payload3');
87
+ }, 300);
88
+
89
+ // Assert
90
+ const results = await Promise.allSettled([
91
+ event1Promise,
92
+ event2Promise,
93
+ event3Promise
94
+ ]);
95
+
96
+ expect(results[0].status).toBe('fulfilled');
97
+ expect(results[0]).toHaveProperty('value', 'payload1');
98
+
99
+ expect(results[1].status).toBe('rejected');
100
+ //@ts-ignore
101
+ expect(results[1].reason).toBeInstanceOf(Error);
102
+
103
+ expect(results[2].status).toBe('fulfilled');
104
+ expect(results[2]).toHaveProperty('value', 'payload2');
105
+ });
106
+
107
+
108
+
109
+ })
@@ -0,0 +1,186 @@
1
+ import { describe, test, expect } from "vitest"
2
+ import { FastEvent } from "../event"
3
+ import { FastEventSubscriber } from "../types"
4
+
5
+
6
+ describe("基于通配符的发布与订阅",async ()=>{
7
+
8
+ test("使用通配符发布订阅层级事件",()=>{
9
+ const emitter = new FastEvent()
10
+ const events:string[]=[]
11
+ const subscribers:FastEventSubscriber[]=[]
12
+ subscribers.push(emitter.on("*/*/*",(payload,{type})=>{
13
+ expect(type).toBe("a/b/c")
14
+ expect(payload).toBe(1)
15
+ events.push(type)
16
+ }))
17
+ subscribers.push(emitter.on("a/*/*",(payload,{type})=>{
18
+ expect(type).toBe("a/b/c")
19
+ expect(payload).toBe(1)
20
+ events.push(type)
21
+ }))
22
+ subscribers.push(emitter.on("a/b/*",(payload,{type})=>{
23
+ expect(type).toBe("a/b/c")
24
+ expect(payload).toBe(1)
25
+ events.push(type)
26
+ }))
27
+ emitter.emit("a/b/c",1)
28
+ expect(events).toEqual(["a/b/c","a/b/c","a/b/c"])
29
+ emitter.emit("a/b/c",1)
30
+ expect(events).toEqual(["a/b/c","a/b/c","a/b/c","a/b/c","a/b/c","a/b/c"])
31
+ subscribers.forEach(subscriber=>subscriber.off())
32
+ expect(events).toEqual(["a/b/c","a/b/c","a/b/c","a/b/c","a/b/c","a/b/c"])
33
+ })
34
+
35
+ test("使用通配符发布订阅层级事件11",()=>{
36
+ const emitter = new FastEvent()
37
+ const events:string[]=[]
38
+ const subscribers:FastEventSubscriber[]=[]
39
+ subscribers.push(emitter.on("*/*/*",(payload,{type})=>{
40
+ expect(type).toBe("a/b/c")
41
+ expect(payload).toBe(1)
42
+ events.push(type)
43
+ }))
44
+ emitter.emit("a/b/c",1)
45
+ expect(events).toEqual(["a/b/c"])
46
+ })
47
+
48
+
49
+ test("使用通配符发布订阅层级事件12",()=>{
50
+ const emitter = new FastEvent()
51
+ const events:string[]=[]
52
+ const subscribers:FastEventSubscriber[]=[]
53
+ subscribers.push(emitter.on("a/*/*",(payload,{type})=>{
54
+ expect(type).toBe("a/b/c")
55
+ expect(payload).toBe(1)
56
+ events.push(type)
57
+ }))
58
+ emitter.emit("a/b/c",1)
59
+ expect(events).toEqual(["a/b/c"])
60
+ })
61
+ test("使用通配符发布订阅层级事件13",()=>{
62
+ const emitter = new FastEvent()
63
+ const events:string[]=[]
64
+ const subscribers:FastEventSubscriber[]=[]
65
+ subscribers.push(emitter.on("a/b/*",(payload,{type})=>{
66
+ expect(type).toBe("a/b/c")
67
+ expect(payload).toBe(1)
68
+ events.push(type)
69
+ }))
70
+ emitter.emit("a/b/c",1)
71
+ expect(events).toEqual(["a/b/c"])
72
+ })
73
+
74
+ test("使用通配符发布订阅层级事件14",()=>{
75
+ const emitter = new FastEvent()
76
+ const events:string[]=[]
77
+ const subscribers:FastEventSubscriber[]=[]
78
+ subscribers.push(emitter.on("*/*/*",(payload,{type})=>{
79
+ expect(type).toBe("a/b/c")
80
+ expect(payload).toBe(1)
81
+ events.push(type)
82
+ }))
83
+ subscribers.push(emitter.on("*/*/c",(payload,{type})=>{
84
+ expect(type).toBe("a/b/c")
85
+ expect(payload).toBe(1)
86
+ events.push(type)
87
+ }))
88
+ subscribers.push(emitter.on("*/b/c",(payload,{type})=>{
89
+ expect(type).toBe("a/b/c")
90
+ expect(payload).toBe(1)
91
+ events.push(type)
92
+ }))
93
+ emitter.emit("a/b/c",1)
94
+ expect(events).toEqual(["a/b/c","a/b/c","a/b/c"])
95
+ emitter.emit("a/b/c",1)
96
+ expect(events).toEqual(["a/b/c","a/b/c","a/b/c","a/b/c","a/b/c","a/b/c"])
97
+ subscribers.forEach(subscriber=>subscriber.off())
98
+ expect(events).toEqual(["a/b/c","a/b/c","a/b/c","a/b/c","a/b/c","a/b/c"])
99
+ })
100
+ test("使用通配符发布订阅层级事件15",()=>{
101
+ const emitter = new FastEvent()
102
+ const events:string[]=[]
103
+ const subscribers:FastEventSubscriber[]=[]
104
+ subscribers.push(emitter.on("*/b/c",(payload,{type})=>{
105
+ expect(type).toBe("a/b/c")
106
+ expect(payload).toBe(1)
107
+ events.push(type)
108
+ }))
109
+ emitter.emit("a/b/c",1)
110
+ expect(events).toEqual(["a/b/c"])
111
+ })
112
+ test("使用通配符发布订阅层级事件16",()=>{
113
+ const emitter = new FastEvent()
114
+ const events:string[]=[]
115
+ const subscribers:FastEventSubscriber[]=[]
116
+ subscribers.push(emitter.on("*/b/*/d/*/f",(payload,{type})=>{
117
+ events.push(type)
118
+ }))
119
+ emitter.emit("1/b/1/d/1/f",1)
120
+ emitter.emit("2/b/2/d/2/f",1)
121
+ emitter.emit("3/b/3/d/3/f",1)
122
+ emitter.emit("4/b/4/d/4/f",1)
123
+ emitter.emit("5/b/5/d/5/f",1)
124
+ expect(events).toEqual(["1/b/1/d/1/f","2/b/2/d/2/f","3/b/3/d/3/f","4/b/4/d/4/f","5/b/5/d/5/f"])
125
+ })
126
+ test("使用通配符发布订阅层级事件17",()=>{
127
+ return new Promise<void>((resolve) => {
128
+ const emitter = new FastEvent()
129
+ emitter.on('a/b/c/*', () => {
130
+ resolve()
131
+ })
132
+ emitter.emit('a/b/c/x', 1)
133
+ emitter.emit('a/b/c/x', 1)
134
+ })
135
+ })
136
+ test("使用多级路径匹配",()=>{
137
+ const emitter = new FastEvent()
138
+ const payloads:number[]=[]
139
+ const events:string[]=[]
140
+ emitter.on("a/**",(payload,{type})=>{
141
+ events.push(type)
142
+ payloads.push(payload)
143
+ })
144
+ emitter.emit("a/b/c/d/e/f",1)
145
+ expect(events).toEqual(["a/b/c/d/e/f"])
146
+ expect(payloads).toEqual([1])
147
+ })
148
+ test("使用多级路径匹配2",()=>{
149
+ const emitter = new FastEvent()
150
+ const payloads:number[]=[]
151
+ const events:string[]=[]
152
+ emitter.on("a/**",(payload,{type})=>{
153
+ events.push(type)
154
+ payloads.push(payload)
155
+ })
156
+
157
+ emitter.emit("a/b",1)
158
+ emitter.emit("a/b/c",2)
159
+ emitter.emit("a/b/c/d",3)
160
+ emitter.emit("a/b/c/d/e",4)
161
+ emitter.emit("a/b/c/d/e/f",5)
162
+ expect(events).toEqual(["a/b","a/b/c","a/b/c/d","a/b/c/d/e","a/b/c/d/e/f"])
163
+ expect(payloads).toEqual([1,2,3,4,5])
164
+ })
165
+ test("使用多级路径匹配3",()=>{
166
+ const emitter = new FastEvent()
167
+ const payloads:number[]=[]
168
+ const events:string[]=[]
169
+ emitter.on("a/**",(payload,{type})=>{
170
+ events.push(type)
171
+ payloads.push(payload)
172
+ })
173
+ emitter.on("a/b/*",(payload,{type})=>{
174
+ events.push(type)
175
+ payloads.push(payload)
176
+ })
177
+ emitter.emit("a/b/c",1)
178
+ emitter.emit("a/b/c/d",2)
179
+ emitter.emit("a/b/c/d/e",3)
180
+ emitter.emit("a/b/c/d/e/f",4)
181
+ expect(events).toEqual(["a/b/c","a/b/c","a/b/c/d","a/b/c/d/e","a/b/c/d/e/f"])
182
+ expect(payloads).toEqual([1,1,2,3,4])
183
+ })
184
+ })
185
+
186
+