@loopback/context 4.0.0-alpha.8 → 4.1.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/LICENSE +25 -0
- package/README.md +116 -0
- package/dist/binding-config.d.ts +40 -0
- package/dist/binding-config.js +33 -0
- package/dist/binding-config.js.map +1 -0
- package/dist/binding-decorator.d.ts +45 -0
- package/dist/binding-decorator.js +118 -0
- package/dist/binding-decorator.js.map +1 -0
- package/dist/binding-filter.d.ts +108 -0
- package/dist/binding-filter.js +162 -0
- package/dist/binding-filter.js.map +1 -0
- package/dist/binding-inspector.d.ts +150 -0
- package/dist/binding-inspector.js +249 -0
- package/dist/binding-inspector.js.map +1 -0
- package/dist/binding-key.d.ts +66 -0
- package/dist/binding-key.js +121 -0
- package/dist/binding-key.js.map +1 -0
- package/dist/binding-sorter.d.ts +71 -0
- package/dist/binding-sorter.js +89 -0
- package/dist/binding-sorter.js.map +1 -0
- package/dist/binding.d.ts +577 -0
- package/dist/binding.js +788 -0
- package/dist/binding.js.map +1 -0
- package/dist/context-event.d.ts +23 -0
- package/dist/context-event.js +7 -0
- package/dist/context-event.js.map +1 -0
- package/dist/context-observer.d.ts +36 -0
- package/dist/context-observer.js +7 -0
- package/dist/context-observer.js.map +1 -0
- package/dist/context-subscription.d.ts +147 -0
- package/dist/context-subscription.js +317 -0
- package/dist/context-subscription.js.map +1 -0
- package/dist/context-tag-indexer.d.ts +42 -0
- package/dist/context-tag-indexer.js +135 -0
- package/dist/context-tag-indexer.js.map +1 -0
- package/dist/context-view.d.ts +209 -0
- package/dist/context-view.js +240 -0
- package/dist/context-view.js.map +1 -0
- package/dist/context.d.ts +513 -0
- package/dist/context.js +717 -0
- package/dist/context.js.map +1 -0
- package/dist/index.d.ts +52 -0
- package/dist/index.js +60 -0
- package/dist/index.js.map +1 -0
- package/dist/inject-config.d.ts +67 -0
- package/dist/inject-config.js +181 -0
- package/dist/inject-config.js.map +1 -0
- package/dist/inject.d.ts +250 -0
- package/dist/inject.js +535 -0
- package/dist/inject.js.map +1 -0
- package/dist/interception-proxy.d.ts +76 -0
- package/dist/interception-proxy.js +67 -0
- package/dist/interception-proxy.js.map +1 -0
- package/dist/interceptor-chain.d.ts +121 -0
- package/dist/interceptor-chain.js +148 -0
- package/dist/interceptor-chain.js.map +1 -0
- package/dist/interceptor.d.ts +138 -0
- package/dist/interceptor.js +299 -0
- package/dist/interceptor.js.map +1 -0
- package/dist/invocation.d.ts +101 -0
- package/dist/invocation.js +163 -0
- package/dist/invocation.js.map +1 -0
- package/dist/json-types.d.ts +28 -0
- package/{lib/src/provider.js → dist/json-types.js} +3 -3
- package/dist/json-types.js.map +1 -0
- package/dist/keys.d.ts +65 -0
- package/dist/keys.js +74 -0
- package/dist/keys.js.map +1 -0
- package/dist/provider.d.ts +31 -0
- package/{lib6/src → dist}/provider.js +2 -2
- package/dist/provider.js.map +1 -0
- package/dist/resolution-session.d.ts +180 -0
- package/dist/resolution-session.js +274 -0
- package/dist/resolution-session.js.map +1 -0
- package/dist/resolver.d.ts +46 -0
- package/dist/resolver.js +203 -0
- package/dist/resolver.js.map +1 -0
- package/dist/unique-id.d.ts +14 -0
- package/dist/unique-id.js +26 -0
- package/dist/unique-id.js.map +1 -0
- package/dist/value-promise.d.ts +134 -0
- package/dist/value-promise.js +277 -0
- package/dist/value-promise.js.map +1 -0
- package/package.json +49 -34
- package/src/binding-config.ts +73 -0
- package/src/binding-decorator.ts +136 -0
- package/src/binding-filter.ts +250 -0
- package/src/binding-inspector.ts +371 -0
- package/src/binding-key.ts +136 -0
- package/src/binding-sorter.ts +124 -0
- package/src/binding.ts +1107 -0
- package/src/context-event.ts +30 -0
- package/src/context-observer.ts +50 -0
- package/src/context-subscription.ts +402 -0
- package/src/context-tag-indexer.ts +147 -0
- package/src/context-view.ts +440 -0
- package/src/context.ts +1079 -0
- package/src/index.ts +58 -0
- package/src/inject-config.ts +239 -0
- package/src/inject.ts +796 -0
- package/src/interception-proxy.ts +127 -0
- package/src/interceptor-chain.ts +268 -0
- package/src/interceptor.ts +430 -0
- package/src/invocation.ts +269 -0
- package/src/json-types.ts +35 -0
- package/src/keys.ts +85 -0
- package/src/provider.ts +37 -0
- package/src/resolution-session.ts +414 -0
- package/src/resolver.ts +282 -0
- package/src/unique-id.ts +24 -0
- package/src/value-promise.ts +318 -0
- package/index.d.ts +0 -6
- package/index.js +0 -9
- package/lib/binding.d.ts +0 -75
- package/lib/binding.js +0 -103
- package/lib/binding.js.map +0 -1
- package/lib/context.d.ts +0 -14
- package/lib/context.js +0 -97
- package/lib/context.js.map +0 -1
- package/lib/index.d.ts +0 -1
- package/lib/index.js +0 -12
- package/lib/index.js.map +0 -1
- package/lib/inject.d.ts +0 -46
- package/lib/inject.js +0 -74
- package/lib/inject.js.map +0 -1
- package/lib/isPromise.d.ts +0 -1
- package/lib/isPromise.js +0 -15
- package/lib/isPromise.js.map +0 -1
- package/lib/reflect.d.ts +0 -39
- package/lib/reflect.js +0 -20
- package/lib/reflect.js.map +0 -1
- package/lib/resolver.d.ts +0 -30
- package/lib/resolver.js +0 -129
- package/lib/resolver.js.map +0 -1
- package/lib/src/binding.d.ts +0 -85
- package/lib/src/binding.js +0 -123
- package/lib/src/binding.js.map +0 -1
- package/lib/src/context.d.ts +0 -14
- package/lib/src/context.js +0 -97
- package/lib/src/context.js.map +0 -1
- package/lib/src/index.d.ts +0 -10
- package/lib/src/index.js +0 -27
- package/lib/src/index.js.map +0 -1
- package/lib/src/inject.d.ts +0 -46
- package/lib/src/inject.js +0 -74
- package/lib/src/inject.js.map +0 -1
- package/lib/src/isPromise.d.ts +0 -1
- package/lib/src/isPromise.js +0 -15
- package/lib/src/isPromise.js.map +0 -1
- package/lib/src/provider.d.ts +0 -29
- package/lib/src/provider.js.map +0 -1
- package/lib/src/reflect.d.ts +0 -38
- package/lib/src/reflect.js +0 -143
- package/lib/src/reflect.js.map +0 -1
- package/lib/src/resolver.d.ts +0 -34
- package/lib/src/resolver.js +0 -144
- package/lib/src/resolver.js.map +0 -1
- package/lib6/binding.d.ts +0 -75
- package/lib6/binding.js +0 -103
- package/lib6/binding.js.map +0 -1
- package/lib6/context.d.ts +0 -14
- package/lib6/context.js +0 -97
- package/lib6/context.js.map +0 -1
- package/lib6/index.d.ts +0 -1
- package/lib6/index.js +0 -12
- package/lib6/index.js.map +0 -1
- package/lib6/inject.d.ts +0 -46
- package/lib6/inject.js +0 -74
- package/lib6/inject.js.map +0 -1
- package/lib6/isPromise.d.ts +0 -1
- package/lib6/isPromise.js +0 -15
- package/lib6/isPromise.js.map +0 -1
- package/lib6/reflect.d.ts +0 -39
- package/lib6/reflect.js +0 -20
- package/lib6/reflect.js.map +0 -1
- package/lib6/resolver.d.ts +0 -30
- package/lib6/resolver.js +0 -129
- package/lib6/resolver.js.map +0 -1
- package/lib6/src/binding.d.ts +0 -85
- package/lib6/src/binding.js +0 -133
- package/lib6/src/binding.js.map +0 -1
- package/lib6/src/context.d.ts +0 -14
- package/lib6/src/context.js +0 -97
- package/lib6/src/context.js.map +0 -1
- package/lib6/src/index.d.ts +0 -10
- package/lib6/src/index.js +0 -27
- package/lib6/src/index.js.map +0 -1
- package/lib6/src/inject.d.ts +0 -46
- package/lib6/src/inject.js +0 -74
- package/lib6/src/inject.js.map +0 -1
- package/lib6/src/isPromise.d.ts +0 -1
- package/lib6/src/isPromise.js +0 -15
- package/lib6/src/isPromise.js.map +0 -1
- package/lib6/src/provider.d.ts +0 -29
- package/lib6/src/provider.js.map +0 -1
- package/lib6/src/reflect.d.ts +0 -38
- package/lib6/src/reflect.js +0 -143
- package/lib6/src/reflect.js.map +0 -1
- package/lib6/src/resolver.d.ts +0 -34
- package/lib6/src/resolver.js +0 -154
- package/lib6/src/resolver.js.map +0 -1
|
@@ -0,0 +1,440 @@
|
|
|
1
|
+
// Copyright IBM Corp. 2019,2020. All Rights Reserved.
|
|
2
|
+
// Node module: @loopback/context
|
|
3
|
+
// This file is licensed under the MIT License.
|
|
4
|
+
// License text available at https://opensource.org/licenses/MIT
|
|
5
|
+
|
|
6
|
+
import debugFactory from 'debug';
|
|
7
|
+
import {EventEmitter} from 'events';
|
|
8
|
+
import {promisify} from 'util';
|
|
9
|
+
import {Binding} from './binding';
|
|
10
|
+
import {BindingFilter} from './binding-filter';
|
|
11
|
+
import {BindingComparator} from './binding-sorter';
|
|
12
|
+
import {Context} from './context';
|
|
13
|
+
import {ContextEvent} from './context-event';
|
|
14
|
+
import {ContextEventType, ContextObserver} from './context-observer';
|
|
15
|
+
import {Subscription} from './context-subscription';
|
|
16
|
+
import {Getter} from './inject';
|
|
17
|
+
import {
|
|
18
|
+
asResolutionOptions,
|
|
19
|
+
ResolutionOptions,
|
|
20
|
+
ResolutionOptionsOrSession,
|
|
21
|
+
ResolutionSession,
|
|
22
|
+
} from './resolution-session';
|
|
23
|
+
import {isPromiseLike, resolveList, ValueOrPromise} from './value-promise';
|
|
24
|
+
const debug = debugFactory('loopback:context:view');
|
|
25
|
+
const nextTick = promisify(process.nextTick);
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* An event emitted by a `ContextView`
|
|
29
|
+
*/
|
|
30
|
+
export interface ContextViewEvent<T> extends ContextEvent {
|
|
31
|
+
/**
|
|
32
|
+
* Optional cached value for an `unbind` event
|
|
33
|
+
*/
|
|
34
|
+
cachedValue?: T;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* `ContextView` provides a view for a given context chain to maintain a live
|
|
39
|
+
* list of matching bindings and their resolved values within the context
|
|
40
|
+
* hierarchy.
|
|
41
|
+
*
|
|
42
|
+
* This class is the key utility to implement dynamic extensions for extension
|
|
43
|
+
* points. For example, the RestServer can react to `controller` bindings even
|
|
44
|
+
* they are added/removed/updated after the application starts.
|
|
45
|
+
*
|
|
46
|
+
* `ContextView` is an event emitter that emits the following events:
|
|
47
|
+
* - 'bind': when a binding is added to the view
|
|
48
|
+
* - 'unbind': when a binding is removed from the view
|
|
49
|
+
* - 'close': when the view is closed (stopped observing context events)
|
|
50
|
+
* - 'refresh': when the view is refreshed as bindings are added/removed
|
|
51
|
+
* - 'resolve': when the cached values are resolved and updated
|
|
52
|
+
*/
|
|
53
|
+
export class ContextView<T = unknown>
|
|
54
|
+
extends EventEmitter
|
|
55
|
+
implements ContextObserver
|
|
56
|
+
{
|
|
57
|
+
/**
|
|
58
|
+
* An array of cached bindings that matches the binding filter
|
|
59
|
+
*/
|
|
60
|
+
protected _cachedBindings: Readonly<Binding<T>>[] | undefined;
|
|
61
|
+
/**
|
|
62
|
+
* A map of cached values by binding
|
|
63
|
+
*/
|
|
64
|
+
protected _cachedValues: Map<Readonly<Binding<T>>, T> | undefined;
|
|
65
|
+
private _subscription: Subscription | undefined;
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Create a context view
|
|
69
|
+
* @param context - Context object to watch
|
|
70
|
+
* @param filter - Binding filter to match bindings of interest
|
|
71
|
+
* @param comparator - Comparator to sort the matched bindings
|
|
72
|
+
*/
|
|
73
|
+
constructor(
|
|
74
|
+
public readonly context: Context,
|
|
75
|
+
public readonly filter: BindingFilter,
|
|
76
|
+
public readonly comparator?: BindingComparator,
|
|
77
|
+
private resolutionOptions?: Omit<ResolutionOptions, 'session'>,
|
|
78
|
+
) {
|
|
79
|
+
super();
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Update the cached values keyed by binding
|
|
84
|
+
* @param values - An array of resolved values
|
|
85
|
+
*/
|
|
86
|
+
private updateCachedValues(values: T[]) {
|
|
87
|
+
if (this._cachedBindings == null) return undefined;
|
|
88
|
+
this._cachedValues = new Map();
|
|
89
|
+
for (let i = 0; i < this._cachedBindings?.length; i++) {
|
|
90
|
+
this._cachedValues.set(this._cachedBindings[i], values[i]);
|
|
91
|
+
}
|
|
92
|
+
return this._cachedValues;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Get an array of cached values
|
|
97
|
+
*/
|
|
98
|
+
private getCachedValues() {
|
|
99
|
+
return Array.from(this._cachedValues?.values() ?? []);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Start listening events from the context
|
|
104
|
+
*/
|
|
105
|
+
open() {
|
|
106
|
+
debug('Start listening on changes of context %s', this.context.name);
|
|
107
|
+
if (this.context.isSubscribed(this)) {
|
|
108
|
+
return this._subscription;
|
|
109
|
+
}
|
|
110
|
+
this._subscription = this.context.subscribe(this);
|
|
111
|
+
return this._subscription;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Stop listening events from the context
|
|
116
|
+
*/
|
|
117
|
+
close() {
|
|
118
|
+
debug('Stop listening on changes of context %s', this.context.name);
|
|
119
|
+
if (!this._subscription || this._subscription.closed) return;
|
|
120
|
+
this._subscription.unsubscribe();
|
|
121
|
+
this._subscription = undefined;
|
|
122
|
+
this.emit('close');
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Get the list of matched bindings. If they are not cached, it tries to find
|
|
127
|
+
* them from the context.
|
|
128
|
+
*/
|
|
129
|
+
get bindings(): Readonly<Binding<T>>[] {
|
|
130
|
+
debug('Reading bindings');
|
|
131
|
+
if (this._cachedBindings == null) {
|
|
132
|
+
this._cachedBindings = this.findBindings();
|
|
133
|
+
}
|
|
134
|
+
return this._cachedBindings;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Find matching bindings and refresh the cache
|
|
139
|
+
*/
|
|
140
|
+
protected findBindings(): Readonly<Binding<T>>[] {
|
|
141
|
+
debug('Finding matching bindings');
|
|
142
|
+
const found = this.context.find(this.filter);
|
|
143
|
+
if (typeof this.comparator === 'function') {
|
|
144
|
+
found.sort(this.comparator);
|
|
145
|
+
}
|
|
146
|
+
/* istanbul ignore if */
|
|
147
|
+
if (debug.enabled) {
|
|
148
|
+
debug(
|
|
149
|
+
'Bindings found',
|
|
150
|
+
found.map(b => b.key),
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
return found;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Listen on `bind` or `unbind` and invalidate the cache
|
|
158
|
+
*/
|
|
159
|
+
observe(
|
|
160
|
+
event: ContextEventType,
|
|
161
|
+
binding: Readonly<Binding<unknown>>,
|
|
162
|
+
context: Context,
|
|
163
|
+
) {
|
|
164
|
+
const ctxEvent: ContextViewEvent<T> = {
|
|
165
|
+
context,
|
|
166
|
+
binding,
|
|
167
|
+
type: event,
|
|
168
|
+
};
|
|
169
|
+
debug('Observed event %s %s %s', event, binding.key, context.name);
|
|
170
|
+
|
|
171
|
+
if (event === 'unbind') {
|
|
172
|
+
const cachedValue = this._cachedValues?.get(
|
|
173
|
+
binding as Readonly<Binding<T>>,
|
|
174
|
+
);
|
|
175
|
+
this.emit(event, {...ctxEvent, cachedValue});
|
|
176
|
+
} else {
|
|
177
|
+
this.emit(event, ctxEvent);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
this.refresh();
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Refresh the view by invalidating its cache
|
|
185
|
+
*/
|
|
186
|
+
refresh() {
|
|
187
|
+
debug('Refreshing the view by invalidating cache');
|
|
188
|
+
this._cachedBindings = undefined;
|
|
189
|
+
this._cachedValues = undefined;
|
|
190
|
+
this.emit('refresh');
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Resolve values for the matching bindings
|
|
195
|
+
* @param session - Resolution session
|
|
196
|
+
*/
|
|
197
|
+
resolve(session?: ResolutionOptionsOrSession): ValueOrPromise<T[]> {
|
|
198
|
+
debug('Resolving values');
|
|
199
|
+
if (this._cachedValues != null) {
|
|
200
|
+
return this.getCachedValues();
|
|
201
|
+
}
|
|
202
|
+
const bindings = this.bindings;
|
|
203
|
+
let result = resolveList(bindings, b => {
|
|
204
|
+
const options = {
|
|
205
|
+
...this.resolutionOptions,
|
|
206
|
+
...asResolutionOptions(session),
|
|
207
|
+
};
|
|
208
|
+
options.session = ResolutionSession.fork(options.session);
|
|
209
|
+
return b.getValue(this.context, options);
|
|
210
|
+
});
|
|
211
|
+
if (isPromiseLike(result)) {
|
|
212
|
+
result = result.then(values => {
|
|
213
|
+
const list = values.filter(v => v != null) as T[];
|
|
214
|
+
this.updateCachedValues(list);
|
|
215
|
+
this.emit('resolve', list);
|
|
216
|
+
return list;
|
|
217
|
+
});
|
|
218
|
+
} else {
|
|
219
|
+
// Clone the array so that the cached values won't be mutated
|
|
220
|
+
const list = (result = result.filter(v => v != null) as T[]);
|
|
221
|
+
this.updateCachedValues(list);
|
|
222
|
+
this.emit('resolve', list);
|
|
223
|
+
}
|
|
224
|
+
return result as ValueOrPromise<T[]>;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Get the list of resolved values. If they are not cached, it tries to find
|
|
229
|
+
* and resolve them.
|
|
230
|
+
*/
|
|
231
|
+
async values(session?: ResolutionOptionsOrSession): Promise<T[]> {
|
|
232
|
+
debug('Reading values');
|
|
233
|
+
// Wait for the next tick so that context event notification can be emitted
|
|
234
|
+
await nextTick();
|
|
235
|
+
if (this._cachedValues == null) {
|
|
236
|
+
return this.resolve(session);
|
|
237
|
+
}
|
|
238
|
+
return this.getCachedValues();
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* As a `Getter` function
|
|
243
|
+
*/
|
|
244
|
+
asGetter(session?: ResolutionOptionsOrSession): Getter<T[]> {
|
|
245
|
+
return () => this.values(session);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Get the single value
|
|
250
|
+
*/
|
|
251
|
+
async singleValue(
|
|
252
|
+
session?: ResolutionOptionsOrSession,
|
|
253
|
+
): Promise<T | undefined> {
|
|
254
|
+
const values = await this.values(session);
|
|
255
|
+
if (values.length === 0) return undefined;
|
|
256
|
+
if (values.length === 1) return values[0];
|
|
257
|
+
throw new Error(
|
|
258
|
+
'The ContextView has more than one value. Use values() to access them.',
|
|
259
|
+
);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* The "bind" event is emitted when a new binding is added to the view.
|
|
264
|
+
*
|
|
265
|
+
* @param eventName The name of the event - always `bind`.
|
|
266
|
+
* @param listener The listener function to call when the event is emitted.
|
|
267
|
+
*/
|
|
268
|
+
on(
|
|
269
|
+
eventName: 'bind',
|
|
270
|
+
listener: <V>(event: ContextViewEvent<V>) => void,
|
|
271
|
+
): this;
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* The "unbind" event is emitted a new binding is removed from the view.
|
|
275
|
+
*
|
|
276
|
+
* @param eventName The name of the event - always `unbind`.
|
|
277
|
+
* @param listener The listener function to call when the event is emitted.
|
|
278
|
+
*/
|
|
279
|
+
on(
|
|
280
|
+
eventName: 'unbind',
|
|
281
|
+
listener: <V>(event: ContextViewEvent<V> & {cachedValue?: V}) => void,
|
|
282
|
+
): this;
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* The "refresh" event is emitted when the view is refreshed as bindings are
|
|
286
|
+
* added/removed.
|
|
287
|
+
*
|
|
288
|
+
* @param eventName The name of the event - always `refresh`.
|
|
289
|
+
* @param listener The listener function to call when the event is emitted.
|
|
290
|
+
*/
|
|
291
|
+
on(eventName: 'refresh', listener: () => void): this;
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* The "resolve" event is emitted when the cached values are resolved and
|
|
295
|
+
* updated.
|
|
296
|
+
*
|
|
297
|
+
* @param eventName The name of the event - always `refresh`.
|
|
298
|
+
* @param listener The listener function to call when the event is emitted.
|
|
299
|
+
*/
|
|
300
|
+
// eslint-disable-next-line @typescript-eslint/unified-signatures
|
|
301
|
+
on(eventName: 'refresh', listener: <V>(result: V[]) => void): this;
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* The "close" event is emitted when the view is closed (stopped observing
|
|
305
|
+
* context events)
|
|
306
|
+
*
|
|
307
|
+
* @param eventName The name of the event - always `close`.
|
|
308
|
+
* @param listener The listener function to call when the event is emitted.
|
|
309
|
+
*/
|
|
310
|
+
// eslint-disable-next-line @typescript-eslint/unified-signatures
|
|
311
|
+
on(eventName: 'close', listener: () => void): this;
|
|
312
|
+
|
|
313
|
+
// The generic variant inherited from EventEmitter
|
|
314
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
315
|
+
on(event: string | symbol, listener: (...args: any[]) => void): this;
|
|
316
|
+
|
|
317
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
318
|
+
on(event: string | symbol, listener: (...args: any[]) => void): this {
|
|
319
|
+
return super.on(event, listener);
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* The "bind" event is emitted when a new binding is added to the view.
|
|
324
|
+
*
|
|
325
|
+
* @param eventName The name of the event - always `bind`.
|
|
326
|
+
* @param listener The listener function to call when the event is emitted.
|
|
327
|
+
*/
|
|
328
|
+
once(
|
|
329
|
+
eventName: 'bind',
|
|
330
|
+
listener: <V>(event: ContextViewEvent<V>) => void,
|
|
331
|
+
): this;
|
|
332
|
+
|
|
333
|
+
/**
|
|
334
|
+
* The "unbind" event is emitted a new binding is removed from the view.
|
|
335
|
+
*
|
|
336
|
+
* @param eventName The name of the event - always `unbind`.
|
|
337
|
+
* @param listener The listener function to call when the event is emitted.
|
|
338
|
+
*/
|
|
339
|
+
once(
|
|
340
|
+
eventName: 'unbind',
|
|
341
|
+
listener: <V>(event: ContextViewEvent<V> & {cachedValue?: V}) => void,
|
|
342
|
+
): this;
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* The "refresh" event is emitted when the view is refreshed as bindings are
|
|
346
|
+
* added/removed.
|
|
347
|
+
*
|
|
348
|
+
* @param eventName The name of the event - always `refresh`.
|
|
349
|
+
* @param listener The listener function to call when the event is emitted.
|
|
350
|
+
*/
|
|
351
|
+
once(eventName: 'refresh', listener: () => void): this;
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* The "resolve" event is emitted when the cached values are resolved and
|
|
355
|
+
* updated.
|
|
356
|
+
*
|
|
357
|
+
* @param eventName The name of the event - always `refresh`.
|
|
358
|
+
* @param listener The listener function to call when the event is emitted.
|
|
359
|
+
*/
|
|
360
|
+
// eslint-disable-next-line @typescript-eslint/unified-signatures
|
|
361
|
+
once(eventName: 'refresh', listener: <V>(result: V[]) => void): this;
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* The "close" event is emitted when the view is closed (stopped observing
|
|
365
|
+
* context events)
|
|
366
|
+
*
|
|
367
|
+
* @param eventName The name of the event - always `close`.
|
|
368
|
+
* @param listener The listener function to call when the event is emitted.
|
|
369
|
+
*/
|
|
370
|
+
// eslint-disable-next-line @typescript-eslint/unified-signatures
|
|
371
|
+
once(eventName: 'close', listener: () => void): this;
|
|
372
|
+
|
|
373
|
+
// The generic variant inherited from EventEmitter
|
|
374
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
375
|
+
once(event: string | symbol, listener: (...args: any[]) => void): this;
|
|
376
|
+
|
|
377
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
378
|
+
once(event: string | symbol, listener: (...args: any[]) => void): this {
|
|
379
|
+
return super.once(event, listener);
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
/**
|
|
384
|
+
* Create a context view as a getter with the given filter
|
|
385
|
+
* @param ctx - Context object
|
|
386
|
+
* @param bindingFilter - A function to match bindings
|
|
387
|
+
* @param session - Resolution session
|
|
388
|
+
*/
|
|
389
|
+
export function createViewGetter<T = unknown>(
|
|
390
|
+
ctx: Context,
|
|
391
|
+
bindingFilter: BindingFilter,
|
|
392
|
+
session?: ResolutionSession,
|
|
393
|
+
): Getter<T[]>;
|
|
394
|
+
|
|
395
|
+
/**
|
|
396
|
+
* Create a context view as a getter with the given filter and sort matched
|
|
397
|
+
* bindings by the comparator.
|
|
398
|
+
* @param ctx - Context object
|
|
399
|
+
* @param bindingFilter - A function to match bindings
|
|
400
|
+
* @param bindingComparator - A function to compare two bindings
|
|
401
|
+
* @param session - Resolution session
|
|
402
|
+
*/
|
|
403
|
+
export function createViewGetter<T = unknown>(
|
|
404
|
+
ctx: Context,
|
|
405
|
+
bindingFilter: BindingFilter,
|
|
406
|
+
bindingComparator?: BindingComparator,
|
|
407
|
+
session?: ResolutionOptionsOrSession,
|
|
408
|
+
): Getter<T[]>;
|
|
409
|
+
|
|
410
|
+
/**
|
|
411
|
+
* Create a context view as a getter
|
|
412
|
+
* @param ctx - Context object
|
|
413
|
+
* @param bindingFilter - A function to match bindings
|
|
414
|
+
* @param bindingComparatorOrSession - A function to sort matched bindings or
|
|
415
|
+
* resolution session if the comparator is not needed
|
|
416
|
+
* @param session - Resolution session if the comparator is provided
|
|
417
|
+
*/
|
|
418
|
+
export function createViewGetter<T = unknown>(
|
|
419
|
+
ctx: Context,
|
|
420
|
+
bindingFilter: BindingFilter,
|
|
421
|
+
bindingComparatorOrSession?: BindingComparator | ResolutionSession,
|
|
422
|
+
session?: ResolutionOptionsOrSession,
|
|
423
|
+
): Getter<T[]> {
|
|
424
|
+
let bindingComparator: BindingComparator | undefined = undefined;
|
|
425
|
+
if (typeof bindingComparatorOrSession === 'function') {
|
|
426
|
+
bindingComparator = bindingComparatorOrSession;
|
|
427
|
+
} else if (bindingComparatorOrSession instanceof ResolutionSession) {
|
|
428
|
+
session = bindingComparatorOrSession;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
const options = asResolutionOptions(session);
|
|
432
|
+
const view = new ContextView<T>(
|
|
433
|
+
ctx,
|
|
434
|
+
bindingFilter,
|
|
435
|
+
bindingComparator,
|
|
436
|
+
options,
|
|
437
|
+
);
|
|
438
|
+
view.open();
|
|
439
|
+
return view.asGetter(options);
|
|
440
|
+
}
|