@fluid-internal/client-utils 2.10.0 → 2.12.0
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/CHANGELOG.md +15 -0
- package/dist/events/emitter.d.ts +99 -0
- package/dist/events/emitter.d.ts.map +1 -0
- package/dist/events/emitter.js +182 -0
- package/dist/events/emitter.js.map +1 -0
- package/dist/events/index.d.ts +6 -0
- package/dist/events/index.d.ts.map +1 -0
- package/dist/events/index.js +11 -0
- package/dist/events/index.js.map +1 -0
- package/dist/indexBrowser.d.ts +1 -0
- package/dist/indexBrowser.d.ts.map +1 -1
- package/dist/indexBrowser.js +3 -1
- package/dist/indexBrowser.js.map +1 -1
- package/dist/indexNode.d.ts +1 -0
- package/dist/indexNode.d.ts.map +1 -1
- package/dist/indexNode.js +3 -1
- package/dist/indexNode.js.map +1 -1
- package/lib/events/emitter.d.ts +99 -0
- package/lib/events/emitter.d.ts.map +1 -0
- package/lib/events/emitter.js +177 -0
- package/lib/events/emitter.js.map +1 -0
- package/lib/events/index.d.ts +6 -0
- package/lib/events/index.d.ts.map +1 -0
- package/lib/events/index.js +6 -0
- package/lib/events/index.js.map +1 -0
- package/lib/indexBrowser.d.ts +1 -0
- package/lib/indexBrowser.d.ts.map +1 -1
- package/lib/indexBrowser.js +1 -0
- package/lib/indexBrowser.js.map +1 -1
- package/lib/indexNode.d.ts +1 -0
- package/lib/indexNode.d.ts.map +1 -1
- package/lib/indexNode.js +1 -0
- package/lib/indexNode.js.map +1 -1
- package/package.json +8 -8
- package/src/events/README.md +3 -0
- package/src/events/emitter.ts +228 -0
- package/src/events/index.ts +6 -0
- package/src/indexBrowser.ts +2 -0
- package/src/indexNode.ts +2 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# @fluid-internal/client-utils
|
|
2
2
|
|
|
3
|
+
## 2.12.0
|
|
4
|
+
|
|
5
|
+
Dependency updates only.
|
|
6
|
+
|
|
7
|
+
## 2.11.0
|
|
8
|
+
|
|
9
|
+
### Minor Changes
|
|
10
|
+
|
|
11
|
+
- The events library has been moved from the tree package ([#23141](https://github.com/microsoft/FluidFramework/pull/23141)) [cae07b5c8c](https://github.com/microsoft/FluidFramework/commit/cae07b5c8c7904184b5fbf8c677f302da19cc697)
|
|
12
|
+
|
|
13
|
+
In previous releases, the `@fluidframework/tree` package contained an internal events library. The events-related types and interfaces have been moved to
|
|
14
|
+
`@fluidframework/core-interfaces`, while the implementation has been relocated to `@fluid-internal/client-utils`. There are
|
|
15
|
+
no changes to how the events library is used; the relocation simply organizes the library into more appropriate
|
|
16
|
+
packages. This change should have no impact on developers using the Fluid Framework.
|
|
17
|
+
|
|
3
18
|
## 2.10.0
|
|
4
19
|
|
|
5
20
|
Dependency updates only.
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
import type { HasListeners, IEmitter, Listenable, Listeners, NoListenersCallback, Off } from "@fluidframework/core-interfaces/internal";
|
|
6
|
+
/**
|
|
7
|
+
* Provides an API for subscribing to and listening to events.
|
|
8
|
+
*
|
|
9
|
+
* @remarks Classes wishing to emit events may either extend this class, compose over it, or expose it as a property of type {@link @fluidframework/core-interfaces#Listenable}.
|
|
10
|
+
*
|
|
11
|
+
* @example Extending this class
|
|
12
|
+
*
|
|
13
|
+
* ```typescript
|
|
14
|
+
* interface MyEvents {
|
|
15
|
+
* loaded: () => void;
|
|
16
|
+
* computed: () => number;
|
|
17
|
+
* }
|
|
18
|
+
*
|
|
19
|
+
* class MyInheritanceClass extends EventEmitter<MyEvents> {
|
|
20
|
+
* private load() {
|
|
21
|
+
* this.emit("loaded");
|
|
22
|
+
* const results: number[] = this.emitAndCollect("computed");
|
|
23
|
+
* }
|
|
24
|
+
* }
|
|
25
|
+
* ```
|
|
26
|
+
*
|
|
27
|
+
* @example Composing over this class
|
|
28
|
+
*
|
|
29
|
+
* ```typescript
|
|
30
|
+
* class MyCompositionClass implements Listenable<MyEvents> {
|
|
31
|
+
* private readonly events = createEmitter<MyEvents>();
|
|
32
|
+
*
|
|
33
|
+
* private load() {
|
|
34
|
+
* this.events.emit("loaded");
|
|
35
|
+
* const results: number[] = this.events.emitAndCollect("computed");
|
|
36
|
+
* }
|
|
37
|
+
*
|
|
38
|
+
* public on<K extends keyof MyEvents>(eventName: K, listener: MyEvents[K]): () => void {
|
|
39
|
+
* return this.events.on(eventName, listener);
|
|
40
|
+
* }
|
|
41
|
+
* }
|
|
42
|
+
* ```
|
|
43
|
+
*
|
|
44
|
+
* @example Exposing this class as a property
|
|
45
|
+
*
|
|
46
|
+
* ```typescript
|
|
47
|
+
* class MyExposingClass {
|
|
48
|
+
* private readonly _events = createEmitter<MyEvents>();
|
|
49
|
+
* public readonly events: Listenable<MyEvents> = this._events;
|
|
50
|
+
*
|
|
51
|
+
* private load() {
|
|
52
|
+
* this._events.emit("loaded");
|
|
53
|
+
* const results: number[] = this._events.emitAndCollect("computed");
|
|
54
|
+
* }
|
|
55
|
+
* }
|
|
56
|
+
* ```
|
|
57
|
+
* @internal
|
|
58
|
+
*/
|
|
59
|
+
export declare class CustomEventEmitter<TListeners extends Listeners<TListeners>> implements Listenable<TListeners>, HasListeners<TListeners> {
|
|
60
|
+
private readonly noListeners?;
|
|
61
|
+
protected readonly listeners: Map<keyof TListeners, Set<(...args: any[]) => TListeners[keyof TListeners]>>;
|
|
62
|
+
protected constructor(noListeners?: NoListenersCallback<TListeners> | undefined);
|
|
63
|
+
protected emit<K extends keyof TListeners>(eventName: K, ...args: Parameters<TListeners[K]>): void;
|
|
64
|
+
protected emitAndCollect<K extends keyof TListeners>(eventName: K, ...args: Parameters<TListeners[K]>): ReturnType<TListeners[K]>[];
|
|
65
|
+
on<K extends keyof Listeners<TListeners>>(eventName: K, listener: TListeners[K]): Off;
|
|
66
|
+
off<K extends keyof Listeners<TListeners>>(eventName: K, listener: TListeners[K]): void;
|
|
67
|
+
hasListeners(eventName?: keyof TListeners): boolean;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Create a {@link @fluidframework/core-interfaces#Listenable} that can be instructed to emit events via the {@link @fluidframework/core-interfaces#IEmitter} interface.
|
|
71
|
+
*
|
|
72
|
+
* A class can delegate handling {@link @fluidframework/core-interfaces#Listenable} to the returned value while using it to emit the events.
|
|
73
|
+
* See also CustomEventEmitter which be used as a base class to implement {@link @fluidframework/core-interfaces#Listenable} via extension.
|
|
74
|
+
* @example Forwarding events to the emitter
|
|
75
|
+
* ```typescript
|
|
76
|
+
* interface MyEvents {
|
|
77
|
+
* loaded(): void;
|
|
78
|
+
* }
|
|
79
|
+
*
|
|
80
|
+
* class MyClass implements Listenable<MyEvents> {
|
|
81
|
+
* private readonly events = createEmitter<MyEvents>();
|
|
82
|
+
*
|
|
83
|
+
* private load(): void {
|
|
84
|
+
* this.events.emit("loaded");
|
|
85
|
+
* }
|
|
86
|
+
*
|
|
87
|
+
* public on<K extends keyof MyEvents>(eventName: K, listener: MyEvents[K]): Off {
|
|
88
|
+
* return this.events.on(eventName, listener);
|
|
89
|
+
* }
|
|
90
|
+
*
|
|
91
|
+
* public off<K extends keyof MyEvents>(eventName: K, listener: MyEvents[K]): void {
|
|
92
|
+
* return this.events.off(eventName, listener);
|
|
93
|
+
* }
|
|
94
|
+
* }
|
|
95
|
+
* ```
|
|
96
|
+
* @internal
|
|
97
|
+
*/
|
|
98
|
+
export declare function createEmitter<TListeners extends object>(noListeners?: NoListenersCallback<TListeners>): Listenable<TListeners> & IEmitter<TListeners> & HasListeners<TListeners>;
|
|
99
|
+
//# sourceMappingURL=emitter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emitter.d.ts","sourceRoot":"","sources":["../../src/events/emitter.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EACX,YAAY,EACZ,QAAQ,EACR,UAAU,EACV,SAAS,EAET,mBAAmB,EACnB,GAAG,EACH,MAAM,0CAA0C,CAAC;AAmBlD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoDG;AACH,qBAAa,kBAAkB,CAAC,UAAU,SAAS,SAAS,CAAC,UAAU,CAAC,CACvE,YAAW,UAAU,CAAC,UAAU,CAAC,EAAE,YAAY,CAAC,UAAU,CAAC;IASrC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC;IAPnD,SAAS,CAAC,QAAQ,CAAC,SAAS,sCAEb,GAAG,EAAE,KAAK,UAAU,CAAC,MAAM,UAAU,CAAC,GACjD;IAIJ,SAAS,aAA8B,WAAW,CAAC,6CAAiC;IAEpF,SAAS,CAAC,IAAI,CAAC,CAAC,SAAS,MAAM,UAAU,EACxC,SAAS,EAAE,CAAC,EACZ,GAAG,IAAI,EAAE,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,GAChC,IAAI;IAeP,SAAS,CAAC,cAAc,CAAC,CAAC,SAAS,MAAM,UAAU,EAClD,SAAS,EAAE,CAAC,EACZ,GAAG,IAAI,EAAE,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,GAChC,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,EAAE;IAavB,EAAE,CAAC,CAAC,SAAS,MAAM,SAAS,CAAC,UAAU,CAAC,EAC9C,SAAS,EAAE,CAAC,EACZ,QAAQ,EAAE,UAAU,CAAC,CAAC,CAAC,GACrB,GAAG;IAcC,GAAG,CAAC,CAAC,SAAS,MAAM,SAAS,CAAC,UAAU,CAAC,EAC/C,SAAS,EAAE,CAAC,EACZ,QAAQ,EAAE,UAAU,CAAC,CAAC,CAAC,GACrB,IAAI;IAQA,YAAY,CAAC,SAAS,CAAC,EAAE,MAAM,UAAU,GAAG,OAAO;CAM1D;AA6BD;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,aAAa,CAAC,UAAU,SAAS,MAAM,EACtD,WAAW,CAAC,EAAE,mBAAmB,CAAC,UAAU,CAAC,GAC3C,UAAU,CAAC,UAAU,CAAC,GAAG,QAAQ,CAAC,UAAU,CAAC,GAAG,YAAY,CAAC,UAAU,CAAC,CAE1E"}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*!
|
|
3
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
4
|
+
* Licensed under the MIT License.
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.createEmitter = exports.CustomEventEmitter = void 0;
|
|
8
|
+
/**
|
|
9
|
+
* Retrieve a value from a map with the given key, or create a new entry if the key is not in the map.
|
|
10
|
+
* @param map - The map to query/update
|
|
11
|
+
* @param key - The key to lookup in the map
|
|
12
|
+
* @param defaultValue - a function which returns a default value. This is called and used to set an initial value for the given key in the map if none exists
|
|
13
|
+
* @returns either the existing value for the given key, or the newly-created value (the result of `defaultValue`)
|
|
14
|
+
* @internal
|
|
15
|
+
*/
|
|
16
|
+
function getOrCreate(map, key, defaultValue) {
|
|
17
|
+
let value = map.get(key);
|
|
18
|
+
if (value === undefined) {
|
|
19
|
+
value = defaultValue(key);
|
|
20
|
+
map.set(key, value);
|
|
21
|
+
}
|
|
22
|
+
return value;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Provides an API for subscribing to and listening to events.
|
|
26
|
+
*
|
|
27
|
+
* @remarks Classes wishing to emit events may either extend this class, compose over it, or expose it as a property of type {@link @fluidframework/core-interfaces#Listenable}.
|
|
28
|
+
*
|
|
29
|
+
* @example Extending this class
|
|
30
|
+
*
|
|
31
|
+
* ```typescript
|
|
32
|
+
* interface MyEvents {
|
|
33
|
+
* loaded: () => void;
|
|
34
|
+
* computed: () => number;
|
|
35
|
+
* }
|
|
36
|
+
*
|
|
37
|
+
* class MyInheritanceClass extends EventEmitter<MyEvents> {
|
|
38
|
+
* private load() {
|
|
39
|
+
* this.emit("loaded");
|
|
40
|
+
* const results: number[] = this.emitAndCollect("computed");
|
|
41
|
+
* }
|
|
42
|
+
* }
|
|
43
|
+
* ```
|
|
44
|
+
*
|
|
45
|
+
* @example Composing over this class
|
|
46
|
+
*
|
|
47
|
+
* ```typescript
|
|
48
|
+
* class MyCompositionClass implements Listenable<MyEvents> {
|
|
49
|
+
* private readonly events = createEmitter<MyEvents>();
|
|
50
|
+
*
|
|
51
|
+
* private load() {
|
|
52
|
+
* this.events.emit("loaded");
|
|
53
|
+
* const results: number[] = this.events.emitAndCollect("computed");
|
|
54
|
+
* }
|
|
55
|
+
*
|
|
56
|
+
* public on<K extends keyof MyEvents>(eventName: K, listener: MyEvents[K]): () => void {
|
|
57
|
+
* return this.events.on(eventName, listener);
|
|
58
|
+
* }
|
|
59
|
+
* }
|
|
60
|
+
* ```
|
|
61
|
+
*
|
|
62
|
+
* @example Exposing this class as a property
|
|
63
|
+
*
|
|
64
|
+
* ```typescript
|
|
65
|
+
* class MyExposingClass {
|
|
66
|
+
* private readonly _events = createEmitter<MyEvents>();
|
|
67
|
+
* public readonly events: Listenable<MyEvents> = this._events;
|
|
68
|
+
*
|
|
69
|
+
* private load() {
|
|
70
|
+
* this._events.emit("loaded");
|
|
71
|
+
* const results: number[] = this._events.emitAndCollect("computed");
|
|
72
|
+
* }
|
|
73
|
+
* }
|
|
74
|
+
* ```
|
|
75
|
+
* @internal
|
|
76
|
+
*/
|
|
77
|
+
class CustomEventEmitter {
|
|
78
|
+
// Because this is protected and not public, calling this externally (not from a subclass) makes sending events to the constructed instance impossible.
|
|
79
|
+
// Instead, use the static `create` function to get an instance which allows emitting events.
|
|
80
|
+
constructor(noListeners) {
|
|
81
|
+
this.noListeners = noListeners;
|
|
82
|
+
this.listeners = new Map();
|
|
83
|
+
}
|
|
84
|
+
emit(eventName, ...args) {
|
|
85
|
+
const listeners = this.listeners.get(eventName);
|
|
86
|
+
if (listeners !== undefined) {
|
|
87
|
+
// Current tsc (5.4.5) cannot spread `args` into `listener()`.
|
|
88
|
+
const argArray = args;
|
|
89
|
+
// This explicitly copies listeners so that new listeners added during this call to emit will not receive this event.
|
|
90
|
+
for (const listener of [...listeners]) {
|
|
91
|
+
// If listener has been unsubscribed while invoking other listeners, skip it.
|
|
92
|
+
if (listeners.has(listener)) {
|
|
93
|
+
listener(...argArray);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
emitAndCollect(eventName, ...args) {
|
|
99
|
+
const listeners = this.listeners.get(eventName);
|
|
100
|
+
if (listeners !== undefined) {
|
|
101
|
+
const argArray = args;
|
|
102
|
+
const resultArray = [];
|
|
103
|
+
for (const listener of [...listeners.values()]) {
|
|
104
|
+
resultArray.push(listener(...argArray));
|
|
105
|
+
}
|
|
106
|
+
return resultArray;
|
|
107
|
+
}
|
|
108
|
+
return [];
|
|
109
|
+
}
|
|
110
|
+
on(eventName, listener) {
|
|
111
|
+
const listeners = getOrCreate(this.listeners, eventName, () => new Set());
|
|
112
|
+
if (listeners.has(listener)) {
|
|
113
|
+
const eventDescription = typeof eventName === "symbol" ? eventName.description : String(eventName.toString());
|
|
114
|
+
throw new Error(`Attempted to register the same listener object twice for event ${eventDescription}`);
|
|
115
|
+
}
|
|
116
|
+
listeners.add(listener);
|
|
117
|
+
return () => this.off(eventName, listener);
|
|
118
|
+
}
|
|
119
|
+
off(eventName, listener) {
|
|
120
|
+
const listeners = this.listeners.get(eventName);
|
|
121
|
+
if (listeners?.delete(listener) === true && listeners.size === 0) {
|
|
122
|
+
this.listeners.delete(eventName);
|
|
123
|
+
this.noListeners?.(eventName);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
hasListeners(eventName) {
|
|
127
|
+
if (eventName === undefined) {
|
|
128
|
+
return this.listeners.size > 0;
|
|
129
|
+
}
|
|
130
|
+
return this.listeners.has(eventName);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
exports.CustomEventEmitter = CustomEventEmitter;
|
|
134
|
+
/**
|
|
135
|
+
* This class exposes the constructor and the `emit` method of `EventEmitter`, elevating them from protected to public
|
|
136
|
+
* @internal
|
|
137
|
+
*/
|
|
138
|
+
class ComposableEventEmitter extends CustomEventEmitter {
|
|
139
|
+
constructor(noListeners) {
|
|
140
|
+
super(noListeners);
|
|
141
|
+
}
|
|
142
|
+
emit(eventName, ...args) {
|
|
143
|
+
return super.emit(eventName, ...args);
|
|
144
|
+
}
|
|
145
|
+
emitAndCollect(eventName, ...args) {
|
|
146
|
+
return super.emitAndCollect(eventName, ...args);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Create a {@link @fluidframework/core-interfaces#Listenable} that can be instructed to emit events via the {@link @fluidframework/core-interfaces#IEmitter} interface.
|
|
151
|
+
*
|
|
152
|
+
* A class can delegate handling {@link @fluidframework/core-interfaces#Listenable} to the returned value while using it to emit the events.
|
|
153
|
+
* See also CustomEventEmitter which be used as a base class to implement {@link @fluidframework/core-interfaces#Listenable} via extension.
|
|
154
|
+
* @example Forwarding events to the emitter
|
|
155
|
+
* ```typescript
|
|
156
|
+
* interface MyEvents {
|
|
157
|
+
* loaded(): void;
|
|
158
|
+
* }
|
|
159
|
+
*
|
|
160
|
+
* class MyClass implements Listenable<MyEvents> {
|
|
161
|
+
* private readonly events = createEmitter<MyEvents>();
|
|
162
|
+
*
|
|
163
|
+
* private load(): void {
|
|
164
|
+
* this.events.emit("loaded");
|
|
165
|
+
* }
|
|
166
|
+
*
|
|
167
|
+
* public on<K extends keyof MyEvents>(eventName: K, listener: MyEvents[K]): Off {
|
|
168
|
+
* return this.events.on(eventName, listener);
|
|
169
|
+
* }
|
|
170
|
+
*
|
|
171
|
+
* public off<K extends keyof MyEvents>(eventName: K, listener: MyEvents[K]): void {
|
|
172
|
+
* return this.events.off(eventName, listener);
|
|
173
|
+
* }
|
|
174
|
+
* }
|
|
175
|
+
* ```
|
|
176
|
+
* @internal
|
|
177
|
+
*/
|
|
178
|
+
function createEmitter(noListeners) {
|
|
179
|
+
return new ComposableEventEmitter(noListeners);
|
|
180
|
+
}
|
|
181
|
+
exports.createEmitter = createEmitter;
|
|
182
|
+
//# sourceMappingURL=emitter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emitter.js","sourceRoot":"","sources":["../../src/events/emitter.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport type {\n\tHasListeners,\n\tIEmitter,\n\tListenable,\n\tListeners,\n\tMapGetSet,\n\tNoListenersCallback,\n\tOff,\n} from \"@fluidframework/core-interfaces/internal\";\n\n/**\n * Retrieve a value from a map with the given key, or create a new entry if the key is not in the map.\n * @param map - The map to query/update\n * @param key - The key to lookup in the map\n * @param defaultValue - a function which returns a default value. This is called and used to set an initial value for the given key in the map if none exists\n * @returns either the existing value for the given key, or the newly-created value (the result of `defaultValue`)\n * @internal\n */\nfunction getOrCreate<K, V>(map: MapGetSet<K, V>, key: K, defaultValue: (key: K) => V): V {\n\tlet value = map.get(key);\n\tif (value === undefined) {\n\t\tvalue = defaultValue(key);\n\t\tmap.set(key, value);\n\t}\n\treturn value;\n}\n\n/**\n * Provides an API for subscribing to and listening to events.\n *\n * @remarks Classes wishing to emit events may either extend this class, compose over it, or expose it as a property of type {@link @fluidframework/core-interfaces#Listenable}.\n *\n * @example Extending this class\n *\n * ```typescript\n * interface MyEvents {\n * \tloaded: () => void;\n * \tcomputed: () => number;\n * }\n *\n * class MyInheritanceClass extends EventEmitter<MyEvents> {\n * \tprivate load() {\n * \t\tthis.emit(\"loaded\");\n * \t\tconst results: number[] = this.emitAndCollect(\"computed\");\n * \t}\n * }\n * ```\n *\n * @example Composing over this class\n *\n * ```typescript\n * class MyCompositionClass implements Listenable<MyEvents> {\n * \tprivate readonly events = createEmitter<MyEvents>();\n *\n * \tprivate load() {\n * \t\tthis.events.emit(\"loaded\");\n * \t\tconst results: number[] = this.events.emitAndCollect(\"computed\");\n * \t}\n *\n * \tpublic on<K extends keyof MyEvents>(eventName: K, listener: MyEvents[K]): () => void {\n * \t\treturn this.events.on(eventName, listener);\n * \t}\n * }\n * ```\n *\n * @example Exposing this class as a property\n *\n * ```typescript\n * class MyExposingClass {\n * \tprivate readonly _events = createEmitter<MyEvents>();\n * \tpublic readonly events: Listenable<MyEvents> = this._events;\n *\n * \tprivate load() {\n * \t\tthis._events.emit(\"loaded\");\n * \t\tconst results: number[] = this._events.emitAndCollect(\"computed\");\n * \t}\n * }\n * ```\n * @internal\n */\nexport class CustomEventEmitter<TListeners extends Listeners<TListeners>>\n\timplements Listenable<TListeners>, HasListeners<TListeners>\n{\n\tprotected readonly listeners = new Map<\n\t\tkeyof TListeners,\n\t\tSet<(...args: any[]) => TListeners[keyof TListeners]>\n\t>();\n\n\t// Because this is protected and not public, calling this externally (not from a subclass) makes sending events to the constructed instance impossible.\n\t// Instead, use the static `create` function to get an instance which allows emitting events.\n\tprotected constructor(private readonly noListeners?: NoListenersCallback<TListeners>) {}\n\n\tprotected emit<K extends keyof TListeners>(\n\t\teventName: K,\n\t\t...args: Parameters<TListeners[K]>\n\t): void {\n\t\tconst listeners = this.listeners.get(eventName);\n\t\tif (listeners !== undefined) {\n\t\t\t// Current tsc (5.4.5) cannot spread `args` into `listener()`.\n\t\t\tconst argArray: unknown[] = args;\n\t\t\t// This explicitly copies listeners so that new listeners added during this call to emit will not receive this event.\n\t\t\tfor (const listener of [...listeners]) {\n\t\t\t\t// If listener has been unsubscribed while invoking other listeners, skip it.\n\t\t\t\tif (listeners.has(listener)) {\n\t\t\t\t\tlistener(...argArray);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprotected emitAndCollect<K extends keyof TListeners>(\n\t\teventName: K,\n\t\t...args: Parameters<TListeners[K]>\n\t): ReturnType<TListeners[K]>[] {\n\t\tconst listeners = this.listeners.get(eventName);\n\t\tif (listeners !== undefined) {\n\t\t\tconst argArray: unknown[] = args;\n\t\t\tconst resultArray: ReturnType<TListeners[K]>[] = [];\n\t\t\tfor (const listener of [...listeners.values()]) {\n\t\t\t\tresultArray.push(listener(...argArray));\n\t\t\t}\n\t\t\treturn resultArray;\n\t\t}\n\t\treturn [];\n\t}\n\n\tpublic on<K extends keyof Listeners<TListeners>>(\n\t\teventName: K,\n\t\tlistener: TListeners[K],\n\t): Off {\n\t\tconst listeners = getOrCreate(this.listeners, eventName, () => new Set());\n\t\tif (listeners.has(listener)) {\n\t\t\tconst eventDescription =\n\t\t\t\ttypeof eventName === \"symbol\" ? eventName.description : String(eventName.toString());\n\n\t\t\tthrow new Error(\n\t\t\t\t`Attempted to register the same listener object twice for event ${eventDescription}`,\n\t\t\t);\n\t\t}\n\t\tlisteners.add(listener);\n\t\treturn () => this.off(eventName, listener);\n\t}\n\n\tpublic off<K extends keyof Listeners<TListeners>>(\n\t\teventName: K,\n\t\tlistener: TListeners[K],\n\t): void {\n\t\tconst listeners = this.listeners.get(eventName);\n\t\tif (listeners?.delete(listener) === true && listeners.size === 0) {\n\t\t\tthis.listeners.delete(eventName);\n\t\t\tthis.noListeners?.(eventName);\n\t\t}\n\t}\n\n\tpublic hasListeners(eventName?: keyof TListeners): boolean {\n\t\tif (eventName === undefined) {\n\t\t\treturn this.listeners.size > 0;\n\t\t}\n\t\treturn this.listeners.has(eventName);\n\t}\n}\n\n/**\n * This class exposes the constructor and the `emit` method of `EventEmitter`, elevating them from protected to public\n * @internal\n */\nclass ComposableEventEmitter<TListeners extends Listeners<TListeners>>\n\textends CustomEventEmitter<TListeners>\n\timplements IEmitter<TListeners>\n{\n\tpublic constructor(noListeners?: NoListenersCallback<TListeners>) {\n\t\tsuper(noListeners);\n\t}\n\n\tpublic override emit<K extends keyof TListeners>(\n\t\teventName: K,\n\t\t...args: Parameters<TListeners[K]>\n\t): void {\n\t\treturn super.emit(eventName, ...args);\n\t}\n\n\tpublic override emitAndCollect<K extends keyof TListeners>(\n\t\teventName: K,\n\t\t...args: Parameters<TListeners[K]>\n\t): ReturnType<TListeners[K]>[] {\n\t\treturn super.emitAndCollect(eventName, ...args);\n\t}\n}\n\n/**\n * Create a {@link @fluidframework/core-interfaces#Listenable} that can be instructed to emit events via the {@link @fluidframework/core-interfaces#IEmitter} interface.\n *\n * A class can delegate handling {@link @fluidframework/core-interfaces#Listenable} to the returned value while using it to emit the events.\n * See also CustomEventEmitter which be used as a base class to implement {@link @fluidframework/core-interfaces#Listenable} via extension.\n * @example Forwarding events to the emitter\n * ```typescript\n * interface MyEvents {\n * \tloaded(): void;\n * }\n *\n * class MyClass implements Listenable<MyEvents> {\n * \tprivate readonly events = createEmitter<MyEvents>();\n *\n * \tprivate load(): void {\n * \t\tthis.events.emit(\"loaded\");\n * \t}\n *\n * \tpublic on<K extends keyof MyEvents>(eventName: K, listener: MyEvents[K]): Off {\n * \t\treturn this.events.on(eventName, listener);\n * \t}\n *\n * \tpublic off<K extends keyof MyEvents>(eventName: K, listener: MyEvents[K]): void {\n * \t\treturn this.events.off(eventName, listener);\n * \t}\n * }\n * ```\n * @internal\n */\nexport function createEmitter<TListeners extends object>(\n\tnoListeners?: NoListenersCallback<TListeners>,\n): Listenable<TListeners> & IEmitter<TListeners> & HasListeners<TListeners> {\n\treturn new ComposableEventEmitter<TListeners>(noListeners);\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/events/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/*!
|
|
3
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
4
|
+
* Licensed under the MIT License.
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.CustomEventEmitter = exports.createEmitter = void 0;
|
|
8
|
+
var emitter_js_1 = require("./emitter.js");
|
|
9
|
+
Object.defineProperty(exports, "createEmitter", { enumerable: true, get: function () { return emitter_js_1.createEmitter; } });
|
|
10
|
+
Object.defineProperty(exports, "CustomEventEmitter", { enumerable: true, get: function () { return emitter_js_1.CustomEventEmitter; } });
|
|
11
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/events/index.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,2CAAiE;AAAxD,2GAAA,aAAa,OAAA;AAAE,gHAAA,kBAAkB,OAAA","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nexport { createEmitter, CustomEventEmitter } from \"./emitter.js\";\n"]}
|
package/dist/indexBrowser.d.ts
CHANGED
|
@@ -11,4 +11,5 @@ export { EventEmitter } from "./eventEmitter.cjs";
|
|
|
11
11
|
export { type IsomorphicPerformance } from "./performanceIsomorphic.js";
|
|
12
12
|
export { type ITraceEvent, Trace } from "./trace.js";
|
|
13
13
|
export { type EventEmitterEventType, TypedEventEmitter, type TypedEventTransform, } from "./typedEventEmitter.js";
|
|
14
|
+
export { createEmitter } from "./events/index.js";
|
|
14
15
|
//# sourceMappingURL=indexBrowser.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"indexBrowser.d.ts","sourceRoot":"","sources":["../src/indexBrowser.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,EACN,cAAc,EACd,aAAa,EACb,SAAS,EACT,cAAc,EACd,kBAAkB,GAClB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAEzD,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAC;AACxF,OAAO,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,KAAK,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AACxE,OAAO,EAAE,KAAK,WAAW,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EACN,KAAK,qBAAqB,EAC1B,iBAAiB,EACjB,KAAK,mBAAmB,GACxB,MAAM,wBAAwB,CAAC"}
|
|
1
|
+
{"version":3,"file":"indexBrowser.d.ts","sourceRoot":"","sources":["../src/indexBrowser.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,EACN,cAAc,EACd,aAAa,EACb,SAAS,EACT,cAAc,EACd,kBAAkB,GAClB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAEzD,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAC;AACxF,OAAO,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,KAAK,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AACxE,OAAO,EAAE,KAAK,WAAW,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EACN,KAAK,qBAAqB,EAC1B,iBAAiB,EACjB,KAAK,mBAAmB,GACxB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC"}
|
package/dist/indexBrowser.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Licensed under the MIT License.
|
|
5
5
|
*/
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.TypedEventEmitter = exports.Trace = exports.EventEmitter = exports.Uint8ArrayToArrayBuffer = exports.toUtf8 = exports.fromUtf8ToBase64 = exports.fromBase64ToUtf8 = exports.performance = exports.hashFile = exports.gitHashFile = exports.Uint8ArrayToString = exports.stringToBuffer = exports.IsoBuffer = exports.isArrayBuffer = exports.bufferToString = void 0;
|
|
7
|
+
exports.createEmitter = exports.TypedEventEmitter = exports.Trace = exports.EventEmitter = exports.Uint8ArrayToArrayBuffer = exports.toUtf8 = exports.fromUtf8ToBase64 = exports.fromBase64ToUtf8 = exports.performance = exports.hashFile = exports.gitHashFile = exports.Uint8ArrayToString = exports.stringToBuffer = exports.IsoBuffer = exports.isArrayBuffer = exports.bufferToString = void 0;
|
|
8
8
|
// Entrypoint for browser-specific code in the package.
|
|
9
9
|
// (See 'Isomorphic Code' section in the package README.md.)
|
|
10
10
|
var bufferBrowser_js_1 = require("./bufferBrowser.js");
|
|
@@ -30,4 +30,6 @@ var trace_js_1 = require("./trace.js");
|
|
|
30
30
|
Object.defineProperty(exports, "Trace", { enumerable: true, get: function () { return trace_js_1.Trace; } });
|
|
31
31
|
var typedEventEmitter_js_1 = require("./typedEventEmitter.js");
|
|
32
32
|
Object.defineProperty(exports, "TypedEventEmitter", { enumerable: true, get: function () { return typedEventEmitter_js_1.TypedEventEmitter; } });
|
|
33
|
+
var index_js_1 = require("./events/index.js");
|
|
34
|
+
Object.defineProperty(exports, "createEmitter", { enumerable: true, get: function () { return index_js_1.createEmitter; } });
|
|
33
35
|
//# sourceMappingURL=indexBrowser.js.map
|
package/dist/indexBrowser.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"indexBrowser.js","sourceRoot":"","sources":["../src/indexBrowser.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,uDAAuD;AACvD,4DAA4D;AAE5D,uDAM4B;AAL3B,kHAAA,cAAc,OAAA;AACd,iHAAA,aAAa,OAAA;AACb,6GAAA,SAAS,OAAA;AACT,kHAAA,cAAc,OAAA;AACd,sHAAA,kBAAkB,OAAA;AAEnB,2DAA6D;AAApD,iHAAA,WAAW,OAAA;AAAE,8GAAA,QAAQ,OAAA;AAC9B,uEAAyD;AAAhD,uHAAA,WAAW,OAAA;AAEpB,uEAAwF;AAA/E,4HAAA,gBAAgB,OAAA;AAAE,4HAAA,gBAAgB,OAAA;AAAE,kHAAA,MAAM,OAAA;AACnD,qDAA4D;AAAnD,0HAAA,uBAAuB,OAAA;AAChC,uDAAkD;AAAzC,gHAAA,YAAY,OAAA;AAErB,uCAAqD;AAA1B,iGAAA,KAAK,OAAA;AAChC,+DAIgC;AAF/B,yHAAA,iBAAiB,OAAA","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\n// Entrypoint for browser-specific code in the package.\n// (See 'Isomorphic Code' section in the package README.md.)\n\nexport {\n\tbufferToString,\n\tisArrayBuffer,\n\tIsoBuffer,\n\tstringToBuffer,\n\tUint8ArrayToString,\n} from \"./bufferBrowser.js\";\nexport { gitHashFile, hashFile } from \"./hashFileBrowser.js\";\nexport { performance } from \"./performanceIsomorphic.js\";\n\nexport { fromBase64ToUtf8, fromUtf8ToBase64, toUtf8 } from \"./base64EncodingBrowser.js\";\nexport { Uint8ArrayToArrayBuffer } from \"./bufferShared.js\";\nexport { EventEmitter } from \"./eventEmitter.cjs\";\nexport { type IsomorphicPerformance } from \"./performanceIsomorphic.js\";\nexport { type ITraceEvent, Trace } from \"./trace.js\";\nexport {\n\ttype EventEmitterEventType,\n\tTypedEventEmitter,\n\ttype TypedEventTransform,\n} from \"./typedEventEmitter.js\";\n"]}
|
|
1
|
+
{"version":3,"file":"indexBrowser.js","sourceRoot":"","sources":["../src/indexBrowser.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,uDAAuD;AACvD,4DAA4D;AAE5D,uDAM4B;AAL3B,kHAAA,cAAc,OAAA;AACd,iHAAA,aAAa,OAAA;AACb,6GAAA,SAAS,OAAA;AACT,kHAAA,cAAc,OAAA;AACd,sHAAA,kBAAkB,OAAA;AAEnB,2DAA6D;AAApD,iHAAA,WAAW,OAAA;AAAE,8GAAA,QAAQ,OAAA;AAC9B,uEAAyD;AAAhD,uHAAA,WAAW,OAAA;AAEpB,uEAAwF;AAA/E,4HAAA,gBAAgB,OAAA;AAAE,4HAAA,gBAAgB,OAAA;AAAE,kHAAA,MAAM,OAAA;AACnD,qDAA4D;AAAnD,0HAAA,uBAAuB,OAAA;AAChC,uDAAkD;AAAzC,gHAAA,YAAY,OAAA;AAErB,uCAAqD;AAA1B,iGAAA,KAAK,OAAA;AAChC,+DAIgC;AAF/B,yHAAA,iBAAiB,OAAA;AAIlB,8CAAkD;AAAzC,yGAAA,aAAa,OAAA","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\n// Entrypoint for browser-specific code in the package.\n// (See 'Isomorphic Code' section in the package README.md.)\n\nexport {\n\tbufferToString,\n\tisArrayBuffer,\n\tIsoBuffer,\n\tstringToBuffer,\n\tUint8ArrayToString,\n} from \"./bufferBrowser.js\";\nexport { gitHashFile, hashFile } from \"./hashFileBrowser.js\";\nexport { performance } from \"./performanceIsomorphic.js\";\n\nexport { fromBase64ToUtf8, fromUtf8ToBase64, toUtf8 } from \"./base64EncodingBrowser.js\";\nexport { Uint8ArrayToArrayBuffer } from \"./bufferShared.js\";\nexport { EventEmitter } from \"./eventEmitter.cjs\";\nexport { type IsomorphicPerformance } from \"./performanceIsomorphic.js\";\nexport { type ITraceEvent, Trace } from \"./trace.js\";\nexport {\n\ttype EventEmitterEventType,\n\tTypedEventEmitter,\n\ttype TypedEventTransform,\n} from \"./typedEventEmitter.js\";\n\nexport { createEmitter } from \"./events/index.js\";\n"]}
|
package/dist/indexNode.d.ts
CHANGED
|
@@ -12,4 +12,5 @@ export { EventEmitter } from "./eventEmitter.cjs";
|
|
|
12
12
|
export type { IsomorphicPerformance } from "./performanceIsomorphic.js";
|
|
13
13
|
export { type ITraceEvent, Trace } from "./trace.js";
|
|
14
14
|
export { type EventEmitterEventType, TypedEventEmitter, type TypedEventTransform, } from "./typedEventEmitter.js";
|
|
15
|
+
export { createEmitter } from "./events/index.js";
|
|
15
16
|
//# sourceMappingURL=indexNode.d.ts.map
|
package/dist/indexNode.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"indexNode.d.ts","sourceRoot":"","sources":["../src/indexNode.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EACN,cAAc,EACd,SAAS,EACT,cAAc,EACd,kBAAkB,GAClB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC1D,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAEzD,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AACrF,OAAO,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,YAAY,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AACxE,OAAO,EAAE,KAAK,WAAW,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EACN,KAAK,qBAAqB,EAC1B,iBAAiB,EACjB,KAAK,mBAAmB,GACxB,MAAM,wBAAwB,CAAC"}
|
|
1
|
+
{"version":3,"file":"indexNode.d.ts","sourceRoot":"","sources":["../src/indexNode.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EACN,cAAc,EACd,SAAS,EACT,cAAc,EACd,kBAAkB,GAClB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC1D,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAEzD,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AACrF,OAAO,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,YAAY,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AACxE,OAAO,EAAE,KAAK,WAAW,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EACN,KAAK,qBAAqB,EAC1B,iBAAiB,EACjB,KAAK,mBAAmB,GACxB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC"}
|
package/dist/indexNode.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Licensed under the MIT License.
|
|
5
5
|
*/
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.TypedEventEmitter = exports.Trace = exports.EventEmitter = exports.Uint8ArrayToArrayBuffer = exports.toUtf8 = exports.fromUtf8ToBase64 = exports.fromBase64ToUtf8 = exports.performance = exports.hashFile = exports.gitHashFile = exports.Uint8ArrayToString = exports.stringToBuffer = exports.IsoBuffer = exports.bufferToString = void 0;
|
|
7
|
+
exports.createEmitter = exports.TypedEventEmitter = exports.Trace = exports.EventEmitter = exports.Uint8ArrayToArrayBuffer = exports.toUtf8 = exports.fromUtf8ToBase64 = exports.fromBase64ToUtf8 = exports.performance = exports.hashFile = exports.gitHashFile = exports.Uint8ArrayToString = exports.stringToBuffer = exports.IsoBuffer = exports.bufferToString = void 0;
|
|
8
8
|
var bufferNode_js_1 = require("./bufferNode.js");
|
|
9
9
|
Object.defineProperty(exports, "bufferToString", { enumerable: true, get: function () { return bufferNode_js_1.bufferToString; } });
|
|
10
10
|
Object.defineProperty(exports, "IsoBuffer", { enumerable: true, get: function () { return bufferNode_js_1.IsoBuffer; } });
|
|
@@ -27,4 +27,6 @@ var trace_js_1 = require("./trace.js");
|
|
|
27
27
|
Object.defineProperty(exports, "Trace", { enumerable: true, get: function () { return trace_js_1.Trace; } });
|
|
28
28
|
var typedEventEmitter_js_1 = require("./typedEventEmitter.js");
|
|
29
29
|
Object.defineProperty(exports, "TypedEventEmitter", { enumerable: true, get: function () { return typedEventEmitter_js_1.TypedEventEmitter; } });
|
|
30
|
+
var index_js_1 = require("./events/index.js");
|
|
31
|
+
Object.defineProperty(exports, "createEmitter", { enumerable: true, get: function () { return index_js_1.createEmitter; } });
|
|
30
32
|
//# sourceMappingURL=indexNode.js.map
|
package/dist/indexNode.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"indexNode.js","sourceRoot":"","sources":["../src/indexNode.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAMH,iDAKyB;AAJxB,+GAAA,cAAc,OAAA;AACd,0GAAA,SAAS,OAAA;AACT,+GAAA,cAAc,OAAA;AACd,mHAAA,kBAAkB,OAAA;AAEnB,qDAA0D;AAAjD,8GAAA,WAAW,OAAA;AAAE,2GAAA,QAAQ,OAAA;AAC9B,uEAAyD;AAAhD,uHAAA,WAAW,OAAA;AAEpB,iEAAqF;AAA5E,yHAAA,gBAAgB,OAAA;AAAE,yHAAA,gBAAgB,OAAA;AAAE,+GAAA,MAAM,OAAA;AACnD,qDAA4D;AAAnD,0HAAA,uBAAuB,OAAA;AAChC,uDAAkD;AAAzC,gHAAA,YAAY,OAAA;AAErB,uCAAqD;AAA1B,iGAAA,KAAK,OAAA;AAChC,+DAIgC;AAF/B,yHAAA,iBAAiB,OAAA","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\n// Entrypoint for Node.js-specific code in the package.\n// (See 'Isomorphic Code' section in the package README.md.)\n\nexport { type Buffer } from \"./bufferNode.js\";\nexport {\n\tbufferToString,\n\tIsoBuffer,\n\tstringToBuffer,\n\tUint8ArrayToString,\n} from \"./bufferNode.js\";\nexport { gitHashFile, hashFile } from \"./hashFileNode.js\";\nexport { performance } from \"./performanceIsomorphic.js\";\n\nexport { fromBase64ToUtf8, fromUtf8ToBase64, toUtf8 } from \"./base64EncodingNode.js\";\nexport { Uint8ArrayToArrayBuffer } from \"./bufferShared.js\";\nexport { EventEmitter } from \"./eventEmitter.cjs\";\nexport type { IsomorphicPerformance } from \"./performanceIsomorphic.js\";\nexport { type ITraceEvent, Trace } from \"./trace.js\";\nexport {\n\ttype EventEmitterEventType,\n\tTypedEventEmitter,\n\ttype TypedEventTransform,\n} from \"./typedEventEmitter.js\";\n"]}
|
|
1
|
+
{"version":3,"file":"indexNode.js","sourceRoot":"","sources":["../src/indexNode.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAMH,iDAKyB;AAJxB,+GAAA,cAAc,OAAA;AACd,0GAAA,SAAS,OAAA;AACT,+GAAA,cAAc,OAAA;AACd,mHAAA,kBAAkB,OAAA;AAEnB,qDAA0D;AAAjD,8GAAA,WAAW,OAAA;AAAE,2GAAA,QAAQ,OAAA;AAC9B,uEAAyD;AAAhD,uHAAA,WAAW,OAAA;AAEpB,iEAAqF;AAA5E,yHAAA,gBAAgB,OAAA;AAAE,yHAAA,gBAAgB,OAAA;AAAE,+GAAA,MAAM,OAAA;AACnD,qDAA4D;AAAnD,0HAAA,uBAAuB,OAAA;AAChC,uDAAkD;AAAzC,gHAAA,YAAY,OAAA;AAErB,uCAAqD;AAA1B,iGAAA,KAAK,OAAA;AAChC,+DAIgC;AAF/B,yHAAA,iBAAiB,OAAA;AAIlB,8CAAkD;AAAzC,yGAAA,aAAa,OAAA","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\n// Entrypoint for Node.js-specific code in the package.\n// (See 'Isomorphic Code' section in the package README.md.)\n\nexport { type Buffer } from \"./bufferNode.js\";\nexport {\n\tbufferToString,\n\tIsoBuffer,\n\tstringToBuffer,\n\tUint8ArrayToString,\n} from \"./bufferNode.js\";\nexport { gitHashFile, hashFile } from \"./hashFileNode.js\";\nexport { performance } from \"./performanceIsomorphic.js\";\n\nexport { fromBase64ToUtf8, fromUtf8ToBase64, toUtf8 } from \"./base64EncodingNode.js\";\nexport { Uint8ArrayToArrayBuffer } from \"./bufferShared.js\";\nexport { EventEmitter } from \"./eventEmitter.cjs\";\nexport type { IsomorphicPerformance } from \"./performanceIsomorphic.js\";\nexport { type ITraceEvent, Trace } from \"./trace.js\";\nexport {\n\ttype EventEmitterEventType,\n\tTypedEventEmitter,\n\ttype TypedEventTransform,\n} from \"./typedEventEmitter.js\";\n\nexport { createEmitter } from \"./events/index.js\";\n"]}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
import type { HasListeners, IEmitter, Listenable, Listeners, NoListenersCallback, Off } from "@fluidframework/core-interfaces/internal";
|
|
6
|
+
/**
|
|
7
|
+
* Provides an API for subscribing to and listening to events.
|
|
8
|
+
*
|
|
9
|
+
* @remarks Classes wishing to emit events may either extend this class, compose over it, or expose it as a property of type {@link @fluidframework/core-interfaces#Listenable}.
|
|
10
|
+
*
|
|
11
|
+
* @example Extending this class
|
|
12
|
+
*
|
|
13
|
+
* ```typescript
|
|
14
|
+
* interface MyEvents {
|
|
15
|
+
* loaded: () => void;
|
|
16
|
+
* computed: () => number;
|
|
17
|
+
* }
|
|
18
|
+
*
|
|
19
|
+
* class MyInheritanceClass extends EventEmitter<MyEvents> {
|
|
20
|
+
* private load() {
|
|
21
|
+
* this.emit("loaded");
|
|
22
|
+
* const results: number[] = this.emitAndCollect("computed");
|
|
23
|
+
* }
|
|
24
|
+
* }
|
|
25
|
+
* ```
|
|
26
|
+
*
|
|
27
|
+
* @example Composing over this class
|
|
28
|
+
*
|
|
29
|
+
* ```typescript
|
|
30
|
+
* class MyCompositionClass implements Listenable<MyEvents> {
|
|
31
|
+
* private readonly events = createEmitter<MyEvents>();
|
|
32
|
+
*
|
|
33
|
+
* private load() {
|
|
34
|
+
* this.events.emit("loaded");
|
|
35
|
+
* const results: number[] = this.events.emitAndCollect("computed");
|
|
36
|
+
* }
|
|
37
|
+
*
|
|
38
|
+
* public on<K extends keyof MyEvents>(eventName: K, listener: MyEvents[K]): () => void {
|
|
39
|
+
* return this.events.on(eventName, listener);
|
|
40
|
+
* }
|
|
41
|
+
* }
|
|
42
|
+
* ```
|
|
43
|
+
*
|
|
44
|
+
* @example Exposing this class as a property
|
|
45
|
+
*
|
|
46
|
+
* ```typescript
|
|
47
|
+
* class MyExposingClass {
|
|
48
|
+
* private readonly _events = createEmitter<MyEvents>();
|
|
49
|
+
* public readonly events: Listenable<MyEvents> = this._events;
|
|
50
|
+
*
|
|
51
|
+
* private load() {
|
|
52
|
+
* this._events.emit("loaded");
|
|
53
|
+
* const results: number[] = this._events.emitAndCollect("computed");
|
|
54
|
+
* }
|
|
55
|
+
* }
|
|
56
|
+
* ```
|
|
57
|
+
* @internal
|
|
58
|
+
*/
|
|
59
|
+
export declare class CustomEventEmitter<TListeners extends Listeners<TListeners>> implements Listenable<TListeners>, HasListeners<TListeners> {
|
|
60
|
+
private readonly noListeners?;
|
|
61
|
+
protected readonly listeners: Map<keyof TListeners, Set<(...args: any[]) => TListeners[keyof TListeners]>>;
|
|
62
|
+
protected constructor(noListeners?: NoListenersCallback<TListeners> | undefined);
|
|
63
|
+
protected emit<K extends keyof TListeners>(eventName: K, ...args: Parameters<TListeners[K]>): void;
|
|
64
|
+
protected emitAndCollect<K extends keyof TListeners>(eventName: K, ...args: Parameters<TListeners[K]>): ReturnType<TListeners[K]>[];
|
|
65
|
+
on<K extends keyof Listeners<TListeners>>(eventName: K, listener: TListeners[K]): Off;
|
|
66
|
+
off<K extends keyof Listeners<TListeners>>(eventName: K, listener: TListeners[K]): void;
|
|
67
|
+
hasListeners(eventName?: keyof TListeners): boolean;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Create a {@link @fluidframework/core-interfaces#Listenable} that can be instructed to emit events via the {@link @fluidframework/core-interfaces#IEmitter} interface.
|
|
71
|
+
*
|
|
72
|
+
* A class can delegate handling {@link @fluidframework/core-interfaces#Listenable} to the returned value while using it to emit the events.
|
|
73
|
+
* See also CustomEventEmitter which be used as a base class to implement {@link @fluidframework/core-interfaces#Listenable} via extension.
|
|
74
|
+
* @example Forwarding events to the emitter
|
|
75
|
+
* ```typescript
|
|
76
|
+
* interface MyEvents {
|
|
77
|
+
* loaded(): void;
|
|
78
|
+
* }
|
|
79
|
+
*
|
|
80
|
+
* class MyClass implements Listenable<MyEvents> {
|
|
81
|
+
* private readonly events = createEmitter<MyEvents>();
|
|
82
|
+
*
|
|
83
|
+
* private load(): void {
|
|
84
|
+
* this.events.emit("loaded");
|
|
85
|
+
* }
|
|
86
|
+
*
|
|
87
|
+
* public on<K extends keyof MyEvents>(eventName: K, listener: MyEvents[K]): Off {
|
|
88
|
+
* return this.events.on(eventName, listener);
|
|
89
|
+
* }
|
|
90
|
+
*
|
|
91
|
+
* public off<K extends keyof MyEvents>(eventName: K, listener: MyEvents[K]): void {
|
|
92
|
+
* return this.events.off(eventName, listener);
|
|
93
|
+
* }
|
|
94
|
+
* }
|
|
95
|
+
* ```
|
|
96
|
+
* @internal
|
|
97
|
+
*/
|
|
98
|
+
export declare function createEmitter<TListeners extends object>(noListeners?: NoListenersCallback<TListeners>): Listenable<TListeners> & IEmitter<TListeners> & HasListeners<TListeners>;
|
|
99
|
+
//# sourceMappingURL=emitter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emitter.d.ts","sourceRoot":"","sources":["../../src/events/emitter.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EACX,YAAY,EACZ,QAAQ,EACR,UAAU,EACV,SAAS,EAET,mBAAmB,EACnB,GAAG,EACH,MAAM,0CAA0C,CAAC;AAmBlD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoDG;AACH,qBAAa,kBAAkB,CAAC,UAAU,SAAS,SAAS,CAAC,UAAU,CAAC,CACvE,YAAW,UAAU,CAAC,UAAU,CAAC,EAAE,YAAY,CAAC,UAAU,CAAC;IASrC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC;IAPnD,SAAS,CAAC,QAAQ,CAAC,SAAS,sCAEb,GAAG,EAAE,KAAK,UAAU,CAAC,MAAM,UAAU,CAAC,GACjD;IAIJ,SAAS,aAA8B,WAAW,CAAC,6CAAiC;IAEpF,SAAS,CAAC,IAAI,CAAC,CAAC,SAAS,MAAM,UAAU,EACxC,SAAS,EAAE,CAAC,EACZ,GAAG,IAAI,EAAE,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,GAChC,IAAI;IAeP,SAAS,CAAC,cAAc,CAAC,CAAC,SAAS,MAAM,UAAU,EAClD,SAAS,EAAE,CAAC,EACZ,GAAG,IAAI,EAAE,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,GAChC,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,EAAE;IAavB,EAAE,CAAC,CAAC,SAAS,MAAM,SAAS,CAAC,UAAU,CAAC,EAC9C,SAAS,EAAE,CAAC,EACZ,QAAQ,EAAE,UAAU,CAAC,CAAC,CAAC,GACrB,GAAG;IAcC,GAAG,CAAC,CAAC,SAAS,MAAM,SAAS,CAAC,UAAU,CAAC,EAC/C,SAAS,EAAE,CAAC,EACZ,QAAQ,EAAE,UAAU,CAAC,CAAC,CAAC,GACrB,IAAI;IAQA,YAAY,CAAC,SAAS,CAAC,EAAE,MAAM,UAAU,GAAG,OAAO;CAM1D;AA6BD;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,aAAa,CAAC,UAAU,SAAS,MAAM,EACtD,WAAW,CAAC,EAAE,mBAAmB,CAAC,UAAU,CAAC,GAC3C,UAAU,CAAC,UAAU,CAAC,GAAG,QAAQ,CAAC,UAAU,CAAC,GAAG,YAAY,CAAC,UAAU,CAAC,CAE1E"}
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Retrieve a value from a map with the given key, or create a new entry if the key is not in the map.
|
|
7
|
+
* @param map - The map to query/update
|
|
8
|
+
* @param key - The key to lookup in the map
|
|
9
|
+
* @param defaultValue - a function which returns a default value. This is called and used to set an initial value for the given key in the map if none exists
|
|
10
|
+
* @returns either the existing value for the given key, or the newly-created value (the result of `defaultValue`)
|
|
11
|
+
* @internal
|
|
12
|
+
*/
|
|
13
|
+
function getOrCreate(map, key, defaultValue) {
|
|
14
|
+
let value = map.get(key);
|
|
15
|
+
if (value === undefined) {
|
|
16
|
+
value = defaultValue(key);
|
|
17
|
+
map.set(key, value);
|
|
18
|
+
}
|
|
19
|
+
return value;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Provides an API for subscribing to and listening to events.
|
|
23
|
+
*
|
|
24
|
+
* @remarks Classes wishing to emit events may either extend this class, compose over it, or expose it as a property of type {@link @fluidframework/core-interfaces#Listenable}.
|
|
25
|
+
*
|
|
26
|
+
* @example Extending this class
|
|
27
|
+
*
|
|
28
|
+
* ```typescript
|
|
29
|
+
* interface MyEvents {
|
|
30
|
+
* loaded: () => void;
|
|
31
|
+
* computed: () => number;
|
|
32
|
+
* }
|
|
33
|
+
*
|
|
34
|
+
* class MyInheritanceClass extends EventEmitter<MyEvents> {
|
|
35
|
+
* private load() {
|
|
36
|
+
* this.emit("loaded");
|
|
37
|
+
* const results: number[] = this.emitAndCollect("computed");
|
|
38
|
+
* }
|
|
39
|
+
* }
|
|
40
|
+
* ```
|
|
41
|
+
*
|
|
42
|
+
* @example Composing over this class
|
|
43
|
+
*
|
|
44
|
+
* ```typescript
|
|
45
|
+
* class MyCompositionClass implements Listenable<MyEvents> {
|
|
46
|
+
* private readonly events = createEmitter<MyEvents>();
|
|
47
|
+
*
|
|
48
|
+
* private load() {
|
|
49
|
+
* this.events.emit("loaded");
|
|
50
|
+
* const results: number[] = this.events.emitAndCollect("computed");
|
|
51
|
+
* }
|
|
52
|
+
*
|
|
53
|
+
* public on<K extends keyof MyEvents>(eventName: K, listener: MyEvents[K]): () => void {
|
|
54
|
+
* return this.events.on(eventName, listener);
|
|
55
|
+
* }
|
|
56
|
+
* }
|
|
57
|
+
* ```
|
|
58
|
+
*
|
|
59
|
+
* @example Exposing this class as a property
|
|
60
|
+
*
|
|
61
|
+
* ```typescript
|
|
62
|
+
* class MyExposingClass {
|
|
63
|
+
* private readonly _events = createEmitter<MyEvents>();
|
|
64
|
+
* public readonly events: Listenable<MyEvents> = this._events;
|
|
65
|
+
*
|
|
66
|
+
* private load() {
|
|
67
|
+
* this._events.emit("loaded");
|
|
68
|
+
* const results: number[] = this._events.emitAndCollect("computed");
|
|
69
|
+
* }
|
|
70
|
+
* }
|
|
71
|
+
* ```
|
|
72
|
+
* @internal
|
|
73
|
+
*/
|
|
74
|
+
export class CustomEventEmitter {
|
|
75
|
+
// Because this is protected and not public, calling this externally (not from a subclass) makes sending events to the constructed instance impossible.
|
|
76
|
+
// Instead, use the static `create` function to get an instance which allows emitting events.
|
|
77
|
+
constructor(noListeners) {
|
|
78
|
+
this.noListeners = noListeners;
|
|
79
|
+
this.listeners = new Map();
|
|
80
|
+
}
|
|
81
|
+
emit(eventName, ...args) {
|
|
82
|
+
const listeners = this.listeners.get(eventName);
|
|
83
|
+
if (listeners !== undefined) {
|
|
84
|
+
// Current tsc (5.4.5) cannot spread `args` into `listener()`.
|
|
85
|
+
const argArray = args;
|
|
86
|
+
// This explicitly copies listeners so that new listeners added during this call to emit will not receive this event.
|
|
87
|
+
for (const listener of [...listeners]) {
|
|
88
|
+
// If listener has been unsubscribed while invoking other listeners, skip it.
|
|
89
|
+
if (listeners.has(listener)) {
|
|
90
|
+
listener(...argArray);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
emitAndCollect(eventName, ...args) {
|
|
96
|
+
const listeners = this.listeners.get(eventName);
|
|
97
|
+
if (listeners !== undefined) {
|
|
98
|
+
const argArray = args;
|
|
99
|
+
const resultArray = [];
|
|
100
|
+
for (const listener of [...listeners.values()]) {
|
|
101
|
+
resultArray.push(listener(...argArray));
|
|
102
|
+
}
|
|
103
|
+
return resultArray;
|
|
104
|
+
}
|
|
105
|
+
return [];
|
|
106
|
+
}
|
|
107
|
+
on(eventName, listener) {
|
|
108
|
+
const listeners = getOrCreate(this.listeners, eventName, () => new Set());
|
|
109
|
+
if (listeners.has(listener)) {
|
|
110
|
+
const eventDescription = typeof eventName === "symbol" ? eventName.description : String(eventName.toString());
|
|
111
|
+
throw new Error(`Attempted to register the same listener object twice for event ${eventDescription}`);
|
|
112
|
+
}
|
|
113
|
+
listeners.add(listener);
|
|
114
|
+
return () => this.off(eventName, listener);
|
|
115
|
+
}
|
|
116
|
+
off(eventName, listener) {
|
|
117
|
+
const listeners = this.listeners.get(eventName);
|
|
118
|
+
if (listeners?.delete(listener) === true && listeners.size === 0) {
|
|
119
|
+
this.listeners.delete(eventName);
|
|
120
|
+
this.noListeners?.(eventName);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
hasListeners(eventName) {
|
|
124
|
+
if (eventName === undefined) {
|
|
125
|
+
return this.listeners.size > 0;
|
|
126
|
+
}
|
|
127
|
+
return this.listeners.has(eventName);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* This class exposes the constructor and the `emit` method of `EventEmitter`, elevating them from protected to public
|
|
132
|
+
* @internal
|
|
133
|
+
*/
|
|
134
|
+
class ComposableEventEmitter extends CustomEventEmitter {
|
|
135
|
+
constructor(noListeners) {
|
|
136
|
+
super(noListeners);
|
|
137
|
+
}
|
|
138
|
+
emit(eventName, ...args) {
|
|
139
|
+
return super.emit(eventName, ...args);
|
|
140
|
+
}
|
|
141
|
+
emitAndCollect(eventName, ...args) {
|
|
142
|
+
return super.emitAndCollect(eventName, ...args);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Create a {@link @fluidframework/core-interfaces#Listenable} that can be instructed to emit events via the {@link @fluidframework/core-interfaces#IEmitter} interface.
|
|
147
|
+
*
|
|
148
|
+
* A class can delegate handling {@link @fluidframework/core-interfaces#Listenable} to the returned value while using it to emit the events.
|
|
149
|
+
* See also CustomEventEmitter which be used as a base class to implement {@link @fluidframework/core-interfaces#Listenable} via extension.
|
|
150
|
+
* @example Forwarding events to the emitter
|
|
151
|
+
* ```typescript
|
|
152
|
+
* interface MyEvents {
|
|
153
|
+
* loaded(): void;
|
|
154
|
+
* }
|
|
155
|
+
*
|
|
156
|
+
* class MyClass implements Listenable<MyEvents> {
|
|
157
|
+
* private readonly events = createEmitter<MyEvents>();
|
|
158
|
+
*
|
|
159
|
+
* private load(): void {
|
|
160
|
+
* this.events.emit("loaded");
|
|
161
|
+
* }
|
|
162
|
+
*
|
|
163
|
+
* public on<K extends keyof MyEvents>(eventName: K, listener: MyEvents[K]): Off {
|
|
164
|
+
* return this.events.on(eventName, listener);
|
|
165
|
+
* }
|
|
166
|
+
*
|
|
167
|
+
* public off<K extends keyof MyEvents>(eventName: K, listener: MyEvents[K]): void {
|
|
168
|
+
* return this.events.off(eventName, listener);
|
|
169
|
+
* }
|
|
170
|
+
* }
|
|
171
|
+
* ```
|
|
172
|
+
* @internal
|
|
173
|
+
*/
|
|
174
|
+
export function createEmitter(noListeners) {
|
|
175
|
+
return new ComposableEventEmitter(noListeners);
|
|
176
|
+
}
|
|
177
|
+
//# sourceMappingURL=emitter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emitter.js","sourceRoot":"","sources":["../../src/events/emitter.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport type {\n\tHasListeners,\n\tIEmitter,\n\tListenable,\n\tListeners,\n\tMapGetSet,\n\tNoListenersCallback,\n\tOff,\n} from \"@fluidframework/core-interfaces/internal\";\n\n/**\n * Retrieve a value from a map with the given key, or create a new entry if the key is not in the map.\n * @param map - The map to query/update\n * @param key - The key to lookup in the map\n * @param defaultValue - a function which returns a default value. This is called and used to set an initial value for the given key in the map if none exists\n * @returns either the existing value for the given key, or the newly-created value (the result of `defaultValue`)\n * @internal\n */\nfunction getOrCreate<K, V>(map: MapGetSet<K, V>, key: K, defaultValue: (key: K) => V): V {\n\tlet value = map.get(key);\n\tif (value === undefined) {\n\t\tvalue = defaultValue(key);\n\t\tmap.set(key, value);\n\t}\n\treturn value;\n}\n\n/**\n * Provides an API for subscribing to and listening to events.\n *\n * @remarks Classes wishing to emit events may either extend this class, compose over it, or expose it as a property of type {@link @fluidframework/core-interfaces#Listenable}.\n *\n * @example Extending this class\n *\n * ```typescript\n * interface MyEvents {\n * \tloaded: () => void;\n * \tcomputed: () => number;\n * }\n *\n * class MyInheritanceClass extends EventEmitter<MyEvents> {\n * \tprivate load() {\n * \t\tthis.emit(\"loaded\");\n * \t\tconst results: number[] = this.emitAndCollect(\"computed\");\n * \t}\n * }\n * ```\n *\n * @example Composing over this class\n *\n * ```typescript\n * class MyCompositionClass implements Listenable<MyEvents> {\n * \tprivate readonly events = createEmitter<MyEvents>();\n *\n * \tprivate load() {\n * \t\tthis.events.emit(\"loaded\");\n * \t\tconst results: number[] = this.events.emitAndCollect(\"computed\");\n * \t}\n *\n * \tpublic on<K extends keyof MyEvents>(eventName: K, listener: MyEvents[K]): () => void {\n * \t\treturn this.events.on(eventName, listener);\n * \t}\n * }\n * ```\n *\n * @example Exposing this class as a property\n *\n * ```typescript\n * class MyExposingClass {\n * \tprivate readonly _events = createEmitter<MyEvents>();\n * \tpublic readonly events: Listenable<MyEvents> = this._events;\n *\n * \tprivate load() {\n * \t\tthis._events.emit(\"loaded\");\n * \t\tconst results: number[] = this._events.emitAndCollect(\"computed\");\n * \t}\n * }\n * ```\n * @internal\n */\nexport class CustomEventEmitter<TListeners extends Listeners<TListeners>>\n\timplements Listenable<TListeners>, HasListeners<TListeners>\n{\n\tprotected readonly listeners = new Map<\n\t\tkeyof TListeners,\n\t\tSet<(...args: any[]) => TListeners[keyof TListeners]>\n\t>();\n\n\t// Because this is protected and not public, calling this externally (not from a subclass) makes sending events to the constructed instance impossible.\n\t// Instead, use the static `create` function to get an instance which allows emitting events.\n\tprotected constructor(private readonly noListeners?: NoListenersCallback<TListeners>) {}\n\n\tprotected emit<K extends keyof TListeners>(\n\t\teventName: K,\n\t\t...args: Parameters<TListeners[K]>\n\t): void {\n\t\tconst listeners = this.listeners.get(eventName);\n\t\tif (listeners !== undefined) {\n\t\t\t// Current tsc (5.4.5) cannot spread `args` into `listener()`.\n\t\t\tconst argArray: unknown[] = args;\n\t\t\t// This explicitly copies listeners so that new listeners added during this call to emit will not receive this event.\n\t\t\tfor (const listener of [...listeners]) {\n\t\t\t\t// If listener has been unsubscribed while invoking other listeners, skip it.\n\t\t\t\tif (listeners.has(listener)) {\n\t\t\t\t\tlistener(...argArray);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tprotected emitAndCollect<K extends keyof TListeners>(\n\t\teventName: K,\n\t\t...args: Parameters<TListeners[K]>\n\t): ReturnType<TListeners[K]>[] {\n\t\tconst listeners = this.listeners.get(eventName);\n\t\tif (listeners !== undefined) {\n\t\t\tconst argArray: unknown[] = args;\n\t\t\tconst resultArray: ReturnType<TListeners[K]>[] = [];\n\t\t\tfor (const listener of [...listeners.values()]) {\n\t\t\t\tresultArray.push(listener(...argArray));\n\t\t\t}\n\t\t\treturn resultArray;\n\t\t}\n\t\treturn [];\n\t}\n\n\tpublic on<K extends keyof Listeners<TListeners>>(\n\t\teventName: K,\n\t\tlistener: TListeners[K],\n\t): Off {\n\t\tconst listeners = getOrCreate(this.listeners, eventName, () => new Set());\n\t\tif (listeners.has(listener)) {\n\t\t\tconst eventDescription =\n\t\t\t\ttypeof eventName === \"symbol\" ? eventName.description : String(eventName.toString());\n\n\t\t\tthrow new Error(\n\t\t\t\t`Attempted to register the same listener object twice for event ${eventDescription}`,\n\t\t\t);\n\t\t}\n\t\tlisteners.add(listener);\n\t\treturn () => this.off(eventName, listener);\n\t}\n\n\tpublic off<K extends keyof Listeners<TListeners>>(\n\t\teventName: K,\n\t\tlistener: TListeners[K],\n\t): void {\n\t\tconst listeners = this.listeners.get(eventName);\n\t\tif (listeners?.delete(listener) === true && listeners.size === 0) {\n\t\t\tthis.listeners.delete(eventName);\n\t\t\tthis.noListeners?.(eventName);\n\t\t}\n\t}\n\n\tpublic hasListeners(eventName?: keyof TListeners): boolean {\n\t\tif (eventName === undefined) {\n\t\t\treturn this.listeners.size > 0;\n\t\t}\n\t\treturn this.listeners.has(eventName);\n\t}\n}\n\n/**\n * This class exposes the constructor and the `emit` method of `EventEmitter`, elevating them from protected to public\n * @internal\n */\nclass ComposableEventEmitter<TListeners extends Listeners<TListeners>>\n\textends CustomEventEmitter<TListeners>\n\timplements IEmitter<TListeners>\n{\n\tpublic constructor(noListeners?: NoListenersCallback<TListeners>) {\n\t\tsuper(noListeners);\n\t}\n\n\tpublic override emit<K extends keyof TListeners>(\n\t\teventName: K,\n\t\t...args: Parameters<TListeners[K]>\n\t): void {\n\t\treturn super.emit(eventName, ...args);\n\t}\n\n\tpublic override emitAndCollect<K extends keyof TListeners>(\n\t\teventName: K,\n\t\t...args: Parameters<TListeners[K]>\n\t): ReturnType<TListeners[K]>[] {\n\t\treturn super.emitAndCollect(eventName, ...args);\n\t}\n}\n\n/**\n * Create a {@link @fluidframework/core-interfaces#Listenable} that can be instructed to emit events via the {@link @fluidframework/core-interfaces#IEmitter} interface.\n *\n * A class can delegate handling {@link @fluidframework/core-interfaces#Listenable} to the returned value while using it to emit the events.\n * See also CustomEventEmitter which be used as a base class to implement {@link @fluidframework/core-interfaces#Listenable} via extension.\n * @example Forwarding events to the emitter\n * ```typescript\n * interface MyEvents {\n * \tloaded(): void;\n * }\n *\n * class MyClass implements Listenable<MyEvents> {\n * \tprivate readonly events = createEmitter<MyEvents>();\n *\n * \tprivate load(): void {\n * \t\tthis.events.emit(\"loaded\");\n * \t}\n *\n * \tpublic on<K extends keyof MyEvents>(eventName: K, listener: MyEvents[K]): Off {\n * \t\treturn this.events.on(eventName, listener);\n * \t}\n *\n * \tpublic off<K extends keyof MyEvents>(eventName: K, listener: MyEvents[K]): void {\n * \t\treturn this.events.off(eventName, listener);\n * \t}\n * }\n * ```\n * @internal\n */\nexport function createEmitter<TListeners extends object>(\n\tnoListeners?: NoListenersCallback<TListeners>,\n): Listenable<TListeners> & IEmitter<TListeners> & HasListeners<TListeners> {\n\treturn new ComposableEventEmitter<TListeners>(noListeners);\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/events/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/events/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nexport { createEmitter, CustomEventEmitter } from \"./emitter.js\";\n"]}
|
package/lib/indexBrowser.d.ts
CHANGED
|
@@ -11,4 +11,5 @@ export { EventEmitter } from "./eventEmitter.cjs";
|
|
|
11
11
|
export { type IsomorphicPerformance } from "./performanceIsomorphic.js";
|
|
12
12
|
export { type ITraceEvent, Trace } from "./trace.js";
|
|
13
13
|
export { type EventEmitterEventType, TypedEventEmitter, type TypedEventTransform, } from "./typedEventEmitter.js";
|
|
14
|
+
export { createEmitter } from "./events/index.js";
|
|
14
15
|
//# sourceMappingURL=indexBrowser.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"indexBrowser.d.ts","sourceRoot":"","sources":["../src/indexBrowser.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,EACN,cAAc,EACd,aAAa,EACb,SAAS,EACT,cAAc,EACd,kBAAkB,GAClB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAEzD,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAC;AACxF,OAAO,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,KAAK,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AACxE,OAAO,EAAE,KAAK,WAAW,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EACN,KAAK,qBAAqB,EAC1B,iBAAiB,EACjB,KAAK,mBAAmB,GACxB,MAAM,wBAAwB,CAAC"}
|
|
1
|
+
{"version":3,"file":"indexBrowser.d.ts","sourceRoot":"","sources":["../src/indexBrowser.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,EACN,cAAc,EACd,aAAa,EACb,SAAS,EACT,cAAc,EACd,kBAAkB,GAClB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAEzD,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAC;AACxF,OAAO,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,KAAK,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AACxE,OAAO,EAAE,KAAK,WAAW,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EACN,KAAK,qBAAqB,EAC1B,iBAAiB,EACjB,KAAK,mBAAmB,GACxB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC"}
|
package/lib/indexBrowser.js
CHANGED
|
@@ -12,4 +12,5 @@ export { Uint8ArrayToArrayBuffer } from "./bufferShared.js";
|
|
|
12
12
|
export { EventEmitter } from "./eventEmitter.cjs";
|
|
13
13
|
export { Trace } from "./trace.js";
|
|
14
14
|
export { TypedEventEmitter, } from "./typedEventEmitter.js";
|
|
15
|
+
export { createEmitter } from "./events/index.js";
|
|
15
16
|
//# sourceMappingURL=indexBrowser.js.map
|
package/lib/indexBrowser.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"indexBrowser.js","sourceRoot":"","sources":["../src/indexBrowser.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,uDAAuD;AACvD,4DAA4D;AAE5D,OAAO,EACN,cAAc,EACd,aAAa,EACb,SAAS,EACT,cAAc,EACd,kBAAkB,GAClB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAEzD,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAC;AACxF,OAAO,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,OAAO,EAAoB,KAAK,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EAEN,iBAAiB,GAEjB,MAAM,wBAAwB,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\n// Entrypoint for browser-specific code in the package.\n// (See 'Isomorphic Code' section in the package README.md.)\n\nexport {\n\tbufferToString,\n\tisArrayBuffer,\n\tIsoBuffer,\n\tstringToBuffer,\n\tUint8ArrayToString,\n} from \"./bufferBrowser.js\";\nexport { gitHashFile, hashFile } from \"./hashFileBrowser.js\";\nexport { performance } from \"./performanceIsomorphic.js\";\n\nexport { fromBase64ToUtf8, fromUtf8ToBase64, toUtf8 } from \"./base64EncodingBrowser.js\";\nexport { Uint8ArrayToArrayBuffer } from \"./bufferShared.js\";\nexport { EventEmitter } from \"./eventEmitter.cjs\";\nexport { type IsomorphicPerformance } from \"./performanceIsomorphic.js\";\nexport { type ITraceEvent, Trace } from \"./trace.js\";\nexport {\n\ttype EventEmitterEventType,\n\tTypedEventEmitter,\n\ttype TypedEventTransform,\n} from \"./typedEventEmitter.js\";\n"]}
|
|
1
|
+
{"version":3,"file":"indexBrowser.js","sourceRoot":"","sources":["../src/indexBrowser.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,uDAAuD;AACvD,4DAA4D;AAE5D,OAAO,EACN,cAAc,EACd,aAAa,EACb,SAAS,EACT,cAAc,EACd,kBAAkB,GAClB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAEzD,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,4BAA4B,CAAC;AACxF,OAAO,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,OAAO,EAAoB,KAAK,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EAEN,iBAAiB,GAEjB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\n// Entrypoint for browser-specific code in the package.\n// (See 'Isomorphic Code' section in the package README.md.)\n\nexport {\n\tbufferToString,\n\tisArrayBuffer,\n\tIsoBuffer,\n\tstringToBuffer,\n\tUint8ArrayToString,\n} from \"./bufferBrowser.js\";\nexport { gitHashFile, hashFile } from \"./hashFileBrowser.js\";\nexport { performance } from \"./performanceIsomorphic.js\";\n\nexport { fromBase64ToUtf8, fromUtf8ToBase64, toUtf8 } from \"./base64EncodingBrowser.js\";\nexport { Uint8ArrayToArrayBuffer } from \"./bufferShared.js\";\nexport { EventEmitter } from \"./eventEmitter.cjs\";\nexport { type IsomorphicPerformance } from \"./performanceIsomorphic.js\";\nexport { type ITraceEvent, Trace } from \"./trace.js\";\nexport {\n\ttype EventEmitterEventType,\n\tTypedEventEmitter,\n\ttype TypedEventTransform,\n} from \"./typedEventEmitter.js\";\n\nexport { createEmitter } from \"./events/index.js\";\n"]}
|
package/lib/indexNode.d.ts
CHANGED
|
@@ -12,4 +12,5 @@ export { EventEmitter } from "./eventEmitter.cjs";
|
|
|
12
12
|
export type { IsomorphicPerformance } from "./performanceIsomorphic.js";
|
|
13
13
|
export { type ITraceEvent, Trace } from "./trace.js";
|
|
14
14
|
export { type EventEmitterEventType, TypedEventEmitter, type TypedEventTransform, } from "./typedEventEmitter.js";
|
|
15
|
+
export { createEmitter } from "./events/index.js";
|
|
15
16
|
//# sourceMappingURL=indexNode.d.ts.map
|
package/lib/indexNode.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"indexNode.d.ts","sourceRoot":"","sources":["../src/indexNode.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EACN,cAAc,EACd,SAAS,EACT,cAAc,EACd,kBAAkB,GAClB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC1D,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAEzD,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AACrF,OAAO,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,YAAY,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AACxE,OAAO,EAAE,KAAK,WAAW,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EACN,KAAK,qBAAqB,EAC1B,iBAAiB,EACjB,KAAK,mBAAmB,GACxB,MAAM,wBAAwB,CAAC"}
|
|
1
|
+
{"version":3,"file":"indexNode.d.ts","sourceRoot":"","sources":["../src/indexNode.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EACN,cAAc,EACd,SAAS,EACT,cAAc,EACd,kBAAkB,GAClB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC1D,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAEzD,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AACrF,OAAO,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,YAAY,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AACxE,OAAO,EAAE,KAAK,WAAW,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EACN,KAAK,qBAAqB,EAC1B,iBAAiB,EACjB,KAAK,mBAAmB,GACxB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC"}
|
package/lib/indexNode.js
CHANGED
|
@@ -10,4 +10,5 @@ export { Uint8ArrayToArrayBuffer } from "./bufferShared.js";
|
|
|
10
10
|
export { EventEmitter } from "./eventEmitter.cjs";
|
|
11
11
|
export { Trace } from "./trace.js";
|
|
12
12
|
export { TypedEventEmitter, } from "./typedEventEmitter.js";
|
|
13
|
+
export { createEmitter } from "./events/index.js";
|
|
13
14
|
//# sourceMappingURL=indexNode.js.map
|
package/lib/indexNode.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"indexNode.js","sourceRoot":"","sources":["../src/indexNode.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,OAAO,EACN,cAAc,EACd,SAAS,EACT,cAAc,EACd,kBAAkB,GAClB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC1D,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAEzD,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AACrF,OAAO,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,OAAO,EAAoB,KAAK,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EAEN,iBAAiB,GAEjB,MAAM,wBAAwB,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\n// Entrypoint for Node.js-specific code in the package.\n// (See 'Isomorphic Code' section in the package README.md.)\n\nexport { type Buffer } from \"./bufferNode.js\";\nexport {\n\tbufferToString,\n\tIsoBuffer,\n\tstringToBuffer,\n\tUint8ArrayToString,\n} from \"./bufferNode.js\";\nexport { gitHashFile, hashFile } from \"./hashFileNode.js\";\nexport { performance } from \"./performanceIsomorphic.js\";\n\nexport { fromBase64ToUtf8, fromUtf8ToBase64, toUtf8 } from \"./base64EncodingNode.js\";\nexport { Uint8ArrayToArrayBuffer } from \"./bufferShared.js\";\nexport { EventEmitter } from \"./eventEmitter.cjs\";\nexport type { IsomorphicPerformance } from \"./performanceIsomorphic.js\";\nexport { type ITraceEvent, Trace } from \"./trace.js\";\nexport {\n\ttype EventEmitterEventType,\n\tTypedEventEmitter,\n\ttype TypedEventTransform,\n} from \"./typedEventEmitter.js\";\n"]}
|
|
1
|
+
{"version":3,"file":"indexNode.js","sourceRoot":"","sources":["../src/indexNode.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,OAAO,EACN,cAAc,EACd,SAAS,EACT,cAAc,EACd,kBAAkB,GAClB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC1D,OAAO,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAEzD,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AACrF,OAAO,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,OAAO,EAAoB,KAAK,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EAEN,iBAAiB,GAEjB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\n// Entrypoint for Node.js-specific code in the package.\n// (See 'Isomorphic Code' section in the package README.md.)\n\nexport { type Buffer } from \"./bufferNode.js\";\nexport {\n\tbufferToString,\n\tIsoBuffer,\n\tstringToBuffer,\n\tUint8ArrayToString,\n} from \"./bufferNode.js\";\nexport { gitHashFile, hashFile } from \"./hashFileNode.js\";\nexport { performance } from \"./performanceIsomorphic.js\";\n\nexport { fromBase64ToUtf8, fromUtf8ToBase64, toUtf8 } from \"./base64EncodingNode.js\";\nexport { Uint8ArrayToArrayBuffer } from \"./bufferShared.js\";\nexport { EventEmitter } from \"./eventEmitter.cjs\";\nexport type { IsomorphicPerformance } from \"./performanceIsomorphic.js\";\nexport { type ITraceEvent, Trace } from \"./trace.js\";\nexport {\n\ttype EventEmitterEventType,\n\tTypedEventEmitter,\n\ttype TypedEventTransform,\n} from \"./typedEventEmitter.js\";\n\nexport { createEmitter } from \"./events/index.js\";\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fluid-internal/client-utils",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.12.0",
|
|
4
4
|
"description": "Not intended for use outside the Fluid Framework.",
|
|
5
5
|
"homepage": "https://fluidframework.com",
|
|
6
6
|
"repository": {
|
|
@@ -69,8 +69,8 @@
|
|
|
69
69
|
"temp-directory": "nyc/.nyc_output"
|
|
70
70
|
},
|
|
71
71
|
"dependencies": {
|
|
72
|
-
"@fluidframework/core-interfaces": "~2.
|
|
73
|
-
"@fluidframework/core-utils": "~2.
|
|
72
|
+
"@fluidframework/core-interfaces": "~2.12.0",
|
|
73
|
+
"@fluidframework/core-utils": "~2.12.0",
|
|
74
74
|
"@types/events_pkg": "npm:@types/events@^3.0.0",
|
|
75
75
|
"base64-js": "^1.5.1",
|
|
76
76
|
"buffer": "^6.0.3",
|
|
@@ -78,18 +78,18 @@
|
|
|
78
78
|
"sha.js": "^2.4.11"
|
|
79
79
|
},
|
|
80
80
|
"devDependencies": {
|
|
81
|
-
"@arethetypeswrong/cli": "^0.
|
|
81
|
+
"@arethetypeswrong/cli": "^0.17.1",
|
|
82
82
|
"@biomejs/biome": "~1.9.3",
|
|
83
|
-
"@fluid-internal/client-utils-previous": "npm:@fluid-internal/client-utils@2.
|
|
84
|
-
"@fluid-internal/mocha-test-setup": "~2.
|
|
83
|
+
"@fluid-internal/client-utils-previous": "npm:@fluid-internal/client-utils@2.11.0",
|
|
84
|
+
"@fluid-internal/mocha-test-setup": "~2.12.0",
|
|
85
85
|
"@fluid-tools/build-cli": "^0.51.0",
|
|
86
86
|
"@fluidframework/build-common": "^2.0.3",
|
|
87
87
|
"@fluidframework/build-tools": "^0.51.0",
|
|
88
|
-
"@fluidframework/eslint-config-fluid": "^5.
|
|
88
|
+
"@fluidframework/eslint-config-fluid": "^5.6.0",
|
|
89
89
|
"@microsoft/api-extractor": "7.47.8",
|
|
90
90
|
"@types/base64-js": "^1.3.0",
|
|
91
91
|
"@types/jest": "29.5.3",
|
|
92
|
-
"@types/jest-environment-puppeteer": "~2.
|
|
92
|
+
"@types/jest-environment-puppeteer": "~2.12.0",
|
|
93
93
|
"@types/mocha": "^9.1.1",
|
|
94
94
|
"@types/node": "^18.19.0",
|
|
95
95
|
"@types/rewire": "^2.5.28",
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type {
|
|
7
|
+
HasListeners,
|
|
8
|
+
IEmitter,
|
|
9
|
+
Listenable,
|
|
10
|
+
Listeners,
|
|
11
|
+
MapGetSet,
|
|
12
|
+
NoListenersCallback,
|
|
13
|
+
Off,
|
|
14
|
+
} from "@fluidframework/core-interfaces/internal";
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Retrieve a value from a map with the given key, or create a new entry if the key is not in the map.
|
|
18
|
+
* @param map - The map to query/update
|
|
19
|
+
* @param key - The key to lookup in the map
|
|
20
|
+
* @param defaultValue - a function which returns a default value. This is called and used to set an initial value for the given key in the map if none exists
|
|
21
|
+
* @returns either the existing value for the given key, or the newly-created value (the result of `defaultValue`)
|
|
22
|
+
* @internal
|
|
23
|
+
*/
|
|
24
|
+
function getOrCreate<K, V>(map: MapGetSet<K, V>, key: K, defaultValue: (key: K) => V): V {
|
|
25
|
+
let value = map.get(key);
|
|
26
|
+
if (value === undefined) {
|
|
27
|
+
value = defaultValue(key);
|
|
28
|
+
map.set(key, value);
|
|
29
|
+
}
|
|
30
|
+
return value;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Provides an API for subscribing to and listening to events.
|
|
35
|
+
*
|
|
36
|
+
* @remarks Classes wishing to emit events may either extend this class, compose over it, or expose it as a property of type {@link @fluidframework/core-interfaces#Listenable}.
|
|
37
|
+
*
|
|
38
|
+
* @example Extending this class
|
|
39
|
+
*
|
|
40
|
+
* ```typescript
|
|
41
|
+
* interface MyEvents {
|
|
42
|
+
* loaded: () => void;
|
|
43
|
+
* computed: () => number;
|
|
44
|
+
* }
|
|
45
|
+
*
|
|
46
|
+
* class MyInheritanceClass extends EventEmitter<MyEvents> {
|
|
47
|
+
* private load() {
|
|
48
|
+
* this.emit("loaded");
|
|
49
|
+
* const results: number[] = this.emitAndCollect("computed");
|
|
50
|
+
* }
|
|
51
|
+
* }
|
|
52
|
+
* ```
|
|
53
|
+
*
|
|
54
|
+
* @example Composing over this class
|
|
55
|
+
*
|
|
56
|
+
* ```typescript
|
|
57
|
+
* class MyCompositionClass implements Listenable<MyEvents> {
|
|
58
|
+
* private readonly events = createEmitter<MyEvents>();
|
|
59
|
+
*
|
|
60
|
+
* private load() {
|
|
61
|
+
* this.events.emit("loaded");
|
|
62
|
+
* const results: number[] = this.events.emitAndCollect("computed");
|
|
63
|
+
* }
|
|
64
|
+
*
|
|
65
|
+
* public on<K extends keyof MyEvents>(eventName: K, listener: MyEvents[K]): () => void {
|
|
66
|
+
* return this.events.on(eventName, listener);
|
|
67
|
+
* }
|
|
68
|
+
* }
|
|
69
|
+
* ```
|
|
70
|
+
*
|
|
71
|
+
* @example Exposing this class as a property
|
|
72
|
+
*
|
|
73
|
+
* ```typescript
|
|
74
|
+
* class MyExposingClass {
|
|
75
|
+
* private readonly _events = createEmitter<MyEvents>();
|
|
76
|
+
* public readonly events: Listenable<MyEvents> = this._events;
|
|
77
|
+
*
|
|
78
|
+
* private load() {
|
|
79
|
+
* this._events.emit("loaded");
|
|
80
|
+
* const results: number[] = this._events.emitAndCollect("computed");
|
|
81
|
+
* }
|
|
82
|
+
* }
|
|
83
|
+
* ```
|
|
84
|
+
* @internal
|
|
85
|
+
*/
|
|
86
|
+
export class CustomEventEmitter<TListeners extends Listeners<TListeners>>
|
|
87
|
+
implements Listenable<TListeners>, HasListeners<TListeners>
|
|
88
|
+
{
|
|
89
|
+
protected readonly listeners = new Map<
|
|
90
|
+
keyof TListeners,
|
|
91
|
+
Set<(...args: any[]) => TListeners[keyof TListeners]>
|
|
92
|
+
>();
|
|
93
|
+
|
|
94
|
+
// Because this is protected and not public, calling this externally (not from a subclass) makes sending events to the constructed instance impossible.
|
|
95
|
+
// Instead, use the static `create` function to get an instance which allows emitting events.
|
|
96
|
+
protected constructor(private readonly noListeners?: NoListenersCallback<TListeners>) {}
|
|
97
|
+
|
|
98
|
+
protected emit<K extends keyof TListeners>(
|
|
99
|
+
eventName: K,
|
|
100
|
+
...args: Parameters<TListeners[K]>
|
|
101
|
+
): void {
|
|
102
|
+
const listeners = this.listeners.get(eventName);
|
|
103
|
+
if (listeners !== undefined) {
|
|
104
|
+
// Current tsc (5.4.5) cannot spread `args` into `listener()`.
|
|
105
|
+
const argArray: unknown[] = args;
|
|
106
|
+
// This explicitly copies listeners so that new listeners added during this call to emit will not receive this event.
|
|
107
|
+
for (const listener of [...listeners]) {
|
|
108
|
+
// If listener has been unsubscribed while invoking other listeners, skip it.
|
|
109
|
+
if (listeners.has(listener)) {
|
|
110
|
+
listener(...argArray);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
protected emitAndCollect<K extends keyof TListeners>(
|
|
117
|
+
eventName: K,
|
|
118
|
+
...args: Parameters<TListeners[K]>
|
|
119
|
+
): ReturnType<TListeners[K]>[] {
|
|
120
|
+
const listeners = this.listeners.get(eventName);
|
|
121
|
+
if (listeners !== undefined) {
|
|
122
|
+
const argArray: unknown[] = args;
|
|
123
|
+
const resultArray: ReturnType<TListeners[K]>[] = [];
|
|
124
|
+
for (const listener of [...listeners.values()]) {
|
|
125
|
+
resultArray.push(listener(...argArray));
|
|
126
|
+
}
|
|
127
|
+
return resultArray;
|
|
128
|
+
}
|
|
129
|
+
return [];
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
public on<K extends keyof Listeners<TListeners>>(
|
|
133
|
+
eventName: K,
|
|
134
|
+
listener: TListeners[K],
|
|
135
|
+
): Off {
|
|
136
|
+
const listeners = getOrCreate(this.listeners, eventName, () => new Set());
|
|
137
|
+
if (listeners.has(listener)) {
|
|
138
|
+
const eventDescription =
|
|
139
|
+
typeof eventName === "symbol" ? eventName.description : String(eventName.toString());
|
|
140
|
+
|
|
141
|
+
throw new Error(
|
|
142
|
+
`Attempted to register the same listener object twice for event ${eventDescription}`,
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
listeners.add(listener);
|
|
146
|
+
return () => this.off(eventName, listener);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
public off<K extends keyof Listeners<TListeners>>(
|
|
150
|
+
eventName: K,
|
|
151
|
+
listener: TListeners[K],
|
|
152
|
+
): void {
|
|
153
|
+
const listeners = this.listeners.get(eventName);
|
|
154
|
+
if (listeners?.delete(listener) === true && listeners.size === 0) {
|
|
155
|
+
this.listeners.delete(eventName);
|
|
156
|
+
this.noListeners?.(eventName);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
public hasListeners(eventName?: keyof TListeners): boolean {
|
|
161
|
+
if (eventName === undefined) {
|
|
162
|
+
return this.listeners.size > 0;
|
|
163
|
+
}
|
|
164
|
+
return this.listeners.has(eventName);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* This class exposes the constructor and the `emit` method of `EventEmitter`, elevating them from protected to public
|
|
170
|
+
* @internal
|
|
171
|
+
*/
|
|
172
|
+
class ComposableEventEmitter<TListeners extends Listeners<TListeners>>
|
|
173
|
+
extends CustomEventEmitter<TListeners>
|
|
174
|
+
implements IEmitter<TListeners>
|
|
175
|
+
{
|
|
176
|
+
public constructor(noListeners?: NoListenersCallback<TListeners>) {
|
|
177
|
+
super(noListeners);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
public override emit<K extends keyof TListeners>(
|
|
181
|
+
eventName: K,
|
|
182
|
+
...args: Parameters<TListeners[K]>
|
|
183
|
+
): void {
|
|
184
|
+
return super.emit(eventName, ...args);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
public override emitAndCollect<K extends keyof TListeners>(
|
|
188
|
+
eventName: K,
|
|
189
|
+
...args: Parameters<TListeners[K]>
|
|
190
|
+
): ReturnType<TListeners[K]>[] {
|
|
191
|
+
return super.emitAndCollect(eventName, ...args);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Create a {@link @fluidframework/core-interfaces#Listenable} that can be instructed to emit events via the {@link @fluidframework/core-interfaces#IEmitter} interface.
|
|
197
|
+
*
|
|
198
|
+
* A class can delegate handling {@link @fluidframework/core-interfaces#Listenable} to the returned value while using it to emit the events.
|
|
199
|
+
* See also CustomEventEmitter which be used as a base class to implement {@link @fluidframework/core-interfaces#Listenable} via extension.
|
|
200
|
+
* @example Forwarding events to the emitter
|
|
201
|
+
* ```typescript
|
|
202
|
+
* interface MyEvents {
|
|
203
|
+
* loaded(): void;
|
|
204
|
+
* }
|
|
205
|
+
*
|
|
206
|
+
* class MyClass implements Listenable<MyEvents> {
|
|
207
|
+
* private readonly events = createEmitter<MyEvents>();
|
|
208
|
+
*
|
|
209
|
+
* private load(): void {
|
|
210
|
+
* this.events.emit("loaded");
|
|
211
|
+
* }
|
|
212
|
+
*
|
|
213
|
+
* public on<K extends keyof MyEvents>(eventName: K, listener: MyEvents[K]): Off {
|
|
214
|
+
* return this.events.on(eventName, listener);
|
|
215
|
+
* }
|
|
216
|
+
*
|
|
217
|
+
* public off<K extends keyof MyEvents>(eventName: K, listener: MyEvents[K]): void {
|
|
218
|
+
* return this.events.off(eventName, listener);
|
|
219
|
+
* }
|
|
220
|
+
* }
|
|
221
|
+
* ```
|
|
222
|
+
* @internal
|
|
223
|
+
*/
|
|
224
|
+
export function createEmitter<TListeners extends object>(
|
|
225
|
+
noListeners?: NoListenersCallback<TListeners>,
|
|
226
|
+
): Listenable<TListeners> & IEmitter<TListeners> & HasListeners<TListeners> {
|
|
227
|
+
return new ComposableEventEmitter<TListeners>(noListeners);
|
|
228
|
+
}
|
package/src/indexBrowser.ts
CHANGED