fastevent 1.0.4 → 1.1.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 (53) hide show
  1. package/.prettierrc.js +20 -0
  2. package/.vscode/settings.json +18 -0
  3. package/CHANGELOG.md +22 -6
  4. package/dist/devTools.d.mts +308 -0
  5. package/dist/devTools.d.ts +308 -0
  6. package/dist/devTools.js +3 -0
  7. package/dist/devTools.js.map +1 -0
  8. package/dist/devTools.mjs +3 -0
  9. package/dist/devTools.mjs.map +1 -0
  10. package/dist/index.d.mts +40 -17
  11. package/dist/index.d.ts +40 -17
  12. package/dist/index.js +1 -1
  13. package/dist/index.js.map +1 -1
  14. package/dist/index.mjs +1 -1
  15. package/dist/index.mjs.map +1 -1
  16. package/example/README.md +54 -0
  17. package/example/eslint.config.js +28 -0
  18. package/example/index.html +13 -0
  19. package/example/package.json +29 -0
  20. package/example/pnpm-lock.yaml +2047 -0
  21. package/example/public/vite.svg +1 -0
  22. package/example/src/App.css +42 -0
  23. package/example/src/App.tsx +60 -0
  24. package/example/src/assets/react.svg +1 -0
  25. package/example/src/index.css +68 -0
  26. package/example/src/main.tsx +10 -0
  27. package/example/src/vite-env.d.ts +1 -0
  28. package/example/tsconfig.app.json +26 -0
  29. package/example/tsconfig.json +7 -0
  30. package/example/tsconfig.node.json +24 -0
  31. package/example/vite.config.ts +7 -0
  32. package/package.json +15 -2
  33. package/readme.md +275 -66
  34. package/readme_cn.md +275 -70
  35. package/src/__tests__/emit.test.ts +68 -69
  36. package/src/__tests__/emitAsync.test.ts +41 -42
  37. package/src/__tests__/many.test.ts +15 -16
  38. package/src/__tests__/meta.test.ts +19 -19
  39. package/src/__tests__/off.test.ts +162 -162
  40. package/src/__tests__/onany.test.ts +97 -98
  41. package/src/__tests__/once.test.ts +42 -43
  42. package/src/__tests__/retain.test.ts +36 -36
  43. package/src/__tests__/scope.test.ts +38 -39
  44. package/src/__tests__/types.test.ts +97 -80
  45. package/src/__tests__/waitFor.test.ts +36 -29
  46. package/src/__tests__/wildcard.test.ts +114 -115
  47. package/src/devTools.ts +166 -0
  48. package/src/event.ts +272 -222
  49. package/src/scope.ts +64 -55
  50. package/src/types.ts +38 -34
  51. package/src/utils/WeakObjectMap.ts +64 -0
  52. package/tsconfig.json +103 -111
  53. package/tsup.config.ts +17 -6
@@ -2,185 +2,184 @@ import { describe, test, expect } from "vitest"
2
2
  import { FastEvent } from "../event"
3
3
  import { FastEventSubscriber } from "../types"
4
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})=>{
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
13
  expect(type).toBe("a/b/c")
14
14
  expect(payload).toBe(1)
15
15
  events.push(type)
16
16
  }))
17
- subscribers.push(emitter.on("a/*/*",(payload,{type})=>{
17
+ subscribers.push(emitter.on("a/*/*", ({ payload, type }) => {
18
18
  expect(type).toBe("a/b/c")
19
19
  expect(payload).toBe(1)
20
20
  events.push(type)
21
21
  }))
22
- subscribers.push(emitter.on("a/b/*",(payload,{type})=>{
22
+ subscribers.push(emitter.on("a/b/*", ({ payload, type }) => {
23
23
  expect(type).toBe("a/b/c")
24
24
  expect(payload).toBe(1)
25
25
  events.push(type)
26
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"])
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
33
  })
34
34
 
35
- test("使用通配符发布订阅层级事件11",()=>{
36
- const emitter = new FastEvent()
37
- const events:string[]=[]
38
- const subscribers:FastEventSubscriber[]=[]
39
- subscribers.push(emitter.on("*/*/*",(payload,{type})=>{
35
+ test("使用通配符发布订阅层级事件11", () => {
36
+ const emitter = new FastEvent()
37
+ const events: string[] = []
38
+ const subscribers: FastEventSubscriber[] = []
39
+ subscribers.push(emitter.on("*/*/*", ({ payload, type }) => {
40
40
  expect(type).toBe("a/b/c")
41
41
  expect(payload).toBe(1)
42
42
  events.push(type)
43
- }))
44
- emitter.emit("a/b/c",1)
45
- expect(events).toEqual(["a/b/c"])
43
+ }))
44
+ emitter.emit("a/b/c", 1)
45
+ expect(events).toEqual(["a/b/c"])
46
46
  })
47
47
 
48
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})=>{
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
54
  expect(type).toBe("a/b/c")
55
55
  expect(payload).toBe(1)
56
56
  events.push(type)
57
- }))
58
- emitter.emit("a/b/c",1)
59
- expect(events).toEqual(["a/b/c"])
57
+ }))
58
+ emitter.emit("a/b/c", 1)
59
+ expect(events).toEqual(["a/b/c"])
60
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})=>{
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
66
  expect(type).toBe("a/b/c")
67
67
  expect(payload).toBe(1)
68
68
  events.push(type)
69
- }))
70
- emitter.emit("a/b/c",1)
71
- expect(events).toEqual(["a/b/c"])
69
+ }))
70
+ emitter.emit("a/b/c", 1)
71
+ expect(events).toEqual(["a/b/c"])
72
72
  })
73
73
 
74
- test("使用通配符发布订阅层级事件14",()=>{
75
- const emitter = new FastEvent()
76
- const events:string[]=[]
77
- const subscribers:FastEventSubscriber[]=[]
78
- subscribers.push(emitter.on("*/*/*",(payload,{type})=>{
74
+ test("使用通配符发布订阅层级事件14", () => {
75
+ const emitter = new FastEvent()
76
+ const events: string[] = []
77
+ const subscribers: FastEventSubscriber[] = []
78
+ subscribers.push(emitter.on("*/*/*", ({ payload, type }) => {
79
79
  expect(type).toBe("a/b/c")
80
80
  expect(payload).toBe(1)
81
81
  events.push(type)
82
82
  }))
83
- subscribers.push(emitter.on("*/*/c",(payload,{type})=>{
83
+ subscribers.push(emitter.on("*/*/c", ({ payload, type }) => {
84
84
  expect(type).toBe("a/b/c")
85
85
  expect(payload).toBe(1)
86
86
  events.push(type)
87
87
  }))
88
- subscribers.push(emitter.on("*/b/c",(payload,{type})=>{
88
+ subscribers.push(emitter.on("*/b/c", ({ payload, type }) => {
89
89
  expect(type).toBe("a/b/c")
90
90
  expect(payload).toBe(1)
91
91
  events.push(type)
92
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"])
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
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})=>{
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
105
  expect(type).toBe("a/b/c")
106
106
  expect(payload).toBe(1)
107
107
  events.push(type)
108
108
  }))
109
- emitter.emit("a/b/c",1)
110
- expect(events).toEqual(["a/b/c"])
109
+ emitter.emit("a/b/c", 1)
110
+ expect(events).toEqual(["a/b/c"])
111
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})=>{
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
117
  events.push(type)
118
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"])
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
125
  })
126
- test("使用通配符发布订阅层级事件17",()=>{
126
+ test("使用通配符发布订阅层级事件17", () => {
127
127
  return new Promise<void>((resolve) => {
128
128
  const emitter = new FastEvent()
129
129
  emitter.on('a/b/c/*', () => {
130
130
  resolve()
131
- })
131
+ })
132
132
  emitter.emit('a/b/c/x', 1)
133
133
  emitter.emit('a/b/c/x', 1)
134
134
  })
135
- })
136
- test("使用多级路径匹配",()=>{
137
- const emitter = new FastEvent()
138
- const payloads:number[]=[]
139
- const events:string[]=[]
140
- emitter.on("a/**",(payload,{type})=>{
135
+ })
136
+ test("使用多级路径匹配", () => {
137
+ const emitter = new FastEvent()
138
+ const payloads: number[] = []
139
+ const events: string[] = []
140
+ emitter.on("a/**", ({ payload, type }) => {
141
141
  events.push(type)
142
- payloads.push(payload)
143
- })
144
- emitter.emit("a/b/c/d/e/f",1)
142
+ payloads.push(payload)
143
+ })
144
+ emitter.emit("a/b/c/d/e/f", 1)
145
145
  expect(events).toEqual(["a/b/c/d/e/f"])
146
- expect(payloads).toEqual([1])
146
+ expect(payloads).toEqual([1])
147
147
  })
148
- test("使用多级路径匹配2",()=>{
149
- const emitter = new FastEvent()
150
- const payloads:number[]=[]
151
- const events:string[]=[]
152
- emitter.on("a/**",(payload,{type})=>{
148
+ test("使用多级路径匹配2", () => {
149
+ const emitter = new FastEvent()
150
+ const payloads: number[] = []
151
+ const events: string[] = []
152
+ emitter.on("a/**", ({ payload, type }) => {
153
153
  events.push(type)
154
- payloads.push(payload)
154
+ payloads.push(payload)
155
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])
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
164
  })
165
- test("使用多级路径匹配3",()=>{
166
- const emitter = new FastEvent()
167
- const payloads:number[]=[]
168
- const events:string[]=[]
169
- emitter.on("a/**",(payload,{type})=>{
165
+ test("使用多级路径匹配3", () => {
166
+ const emitter = new FastEvent()
167
+ const payloads: number[] = []
168
+ const events: string[] = []
169
+ emitter.on("a/**", ({ payload, type }) => {
170
170
  events.push(type)
171
- payloads.push(payload)
171
+ payloads.push(payload)
172
172
  })
173
- emitter.on("a/b/*",(payload,{type})=>{
173
+ emitter.on("a/b/*", ({ payload, type }) => {
174
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])
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
183
  })
184
- })
185
-
186
-
184
+ })
185
+
@@ -0,0 +1,166 @@
1
+ /**
2
+ *
3
+ * 基于开发工具
4
+ *
5
+ * Redux DevTools 是一个实用工具,用于开发和调试 Redux 应用程序。
6
+ * FLEXEVENT是基于Redux DevTools 的简单包装,可以让开发者使用Redux DevTools
7
+ * 来查看FLEXEVENT的状态变化
8
+ *
9
+ * import { createStore } from "@FLEXEVENTjs/react"
10
+ * import { install } from "@FLEXEVENTjs/devtools"
11
+ *
12
+ *
13
+ * const store = createStore({})
14
+ *
15
+ * install()
16
+ *
17
+ */
18
+
19
+ //@ts-ignore
20
+ import { legacy_createStore as createStore } from "redux"
21
+ import { WeakObjectMap } from "./utils/WeakObjectMap"
22
+ import { FastEvent } from "./event"
23
+
24
+ const initialState = {
25
+
26
+ }
27
+
28
+
29
+ function getDefaultFastEventState(instance: FastEvent) {
30
+ return {
31
+ messageCount: 0,
32
+ listenerCount: instance.listenerCount,
33
+ retainMessageCount: instance.retainedMessages.size,
34
+ }
35
+ }
36
+
37
+ export class FlexEventDevTools {
38
+ private reduxStore: any
39
+ private _installed: boolean = false
40
+ fastEvents = new WeakObjectMap()
41
+ constructor() {
42
+ this.install()
43
+ }
44
+ add(instance: FastEvent) {
45
+ this.fastEvents.set(instance.id, instance)
46
+
47
+ instance.options.onAddListener = (type: string[], listener: any) => {
48
+ this.reduxStore.dispatch({
49
+ type: "__ADD_LISTENER__",
50
+ event: type.join("/"),
51
+ listener,
52
+ fastEventId: instance.id
53
+ })
54
+ }
55
+ instance.options.onRemoveListener = (type: string[], listener: any) => {
56
+ this.reduxStore.dispatch({
57
+ type: "__REMOVE_LISTENER__",
58
+ event: type.join("/"),
59
+ listener,
60
+ fastEventId: instance.id
61
+ })
62
+ }
63
+ instance.options.onClearListeners = () => {
64
+ this.reduxStore.dispatch({
65
+ type: "__CLEAR_LISTENERS__",
66
+ fastEventId: instance.id
67
+ })
68
+ }
69
+ instance.options.onExecuteListener = (message, returns, listeners) => {
70
+ const results = returns.map(r => r instanceof Error ? `Error(${r.message})` : r)
71
+ const sresults = listeners.map(listener => (listener as any).name || 'anonymous')
72
+ .reduce((pre, cur, index) => {
73
+ pre[cur] = results[index]
74
+ return pre
75
+ }, {})
76
+ console.log(`FastEvent<\x1B[31m${message.type}<\x1B[30m> is emit, listeners:`, listeners)
77
+ this.reduxStore.dispatch({
78
+ type: message.type,
79
+ payload: message.payload,
80
+ meta: message.meta,
81
+ returns: sresults,
82
+ fastEventId: instance.id
83
+ })
84
+ }
85
+ this.reduxStore.dispatch({
86
+ type: "__ADD_FASTEVENT__",
87
+ fastEventId: instance.id
88
+ })
89
+ }
90
+ remove(instance: FastEvent) {
91
+ if (this.fastEvents.has(instance.id)) {
92
+ this.fastEvents.delete(instance.id)
93
+ }
94
+ }
95
+ private reducer(state: any = initialState, action: any) {
96
+ if (action.type.startsWith("@@")) return state
97
+ const instance = this.fastEvents.get(action.fastEventId) as FastEvent
98
+ if (action.type === '__ADD_FASTEVENT__') {
99
+ return {
100
+ ...state,
101
+ [action.fastEventId]: getDefaultFastEventState(instance)
102
+ }
103
+ } else if (action.type == '__ADD_LISTENER__') {
104
+ const eventState = state[action.fastEventId] || getDefaultFastEventState(instance)
105
+ eventState.listenerCount++
106
+ return {
107
+ ...state,
108
+ [action.fastEventId]: {
109
+ ...eventState
110
+ }
111
+ }
112
+ } else if (action.type == '__REMOVE_LISTENER__') {
113
+ const eventState = state[action.fastEventId]
114
+ if (!eventState) return state
115
+ eventState.listenerCount++
116
+ return {
117
+ ...state,
118
+ [action.fastEventId]: {
119
+ ...eventState
120
+ }
121
+ }
122
+ } else if (action.type === '__CLEAR_LISTENERS__') {
123
+ const eventState = state[action.fastEventId]
124
+ if (!eventState) return state
125
+ eventState.listenerCount++
126
+ return {
127
+ ...state,
128
+ [action.fastEventId]: getDefaultFastEventState(instance)
129
+ }
130
+ } else {
131
+ const eventState = state[action.fastEventId]
132
+ if (!eventState) return state
133
+ eventState.messageCount++
134
+ eventState.listenerCount = instance.listenerCount
135
+ eventState.retainMessageCount = instance.retainedMessages.size
136
+ return {
137
+ ...state,
138
+ [action.fastEventId]: { ...eventState }
139
+ }
140
+ }
141
+ }
142
+ private install() {
143
+ if (this._installed) return
144
+ this.reduxStore = createStore(
145
+ this.reducer.bind(this),
146
+ // @ts-ignore
147
+ window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
148
+ );
149
+ this._installed = true
150
+ console.info('%c FlexEventDevTools installed. Please open <Redux devtools> to view. %c', "color:red;", '')
151
+ }
152
+ }
153
+
154
+ export function install() {
155
+ // @ts-ignore
156
+ if (!globalThis.__FLEXEVENT_DEVTOOLS__) globalThis.__FLEXEVENT_DEVTOOLS__ = new FlexEventDevTools()
157
+ }
158
+
159
+ declare global {
160
+ // @ts-ignore
161
+ var __FLEXEVENT_DEVTOOLS__: FlexEventDevTools
162
+ }
163
+
164
+
165
+ install()
166
+