@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.
Files changed (201) hide show
  1. package/LICENSE +25 -0
  2. package/README.md +116 -0
  3. package/dist/binding-config.d.ts +40 -0
  4. package/dist/binding-config.js +33 -0
  5. package/dist/binding-config.js.map +1 -0
  6. package/dist/binding-decorator.d.ts +45 -0
  7. package/dist/binding-decorator.js +118 -0
  8. package/dist/binding-decorator.js.map +1 -0
  9. package/dist/binding-filter.d.ts +108 -0
  10. package/dist/binding-filter.js +162 -0
  11. package/dist/binding-filter.js.map +1 -0
  12. package/dist/binding-inspector.d.ts +150 -0
  13. package/dist/binding-inspector.js +249 -0
  14. package/dist/binding-inspector.js.map +1 -0
  15. package/dist/binding-key.d.ts +66 -0
  16. package/dist/binding-key.js +121 -0
  17. package/dist/binding-key.js.map +1 -0
  18. package/dist/binding-sorter.d.ts +71 -0
  19. package/dist/binding-sorter.js +89 -0
  20. package/dist/binding-sorter.js.map +1 -0
  21. package/dist/binding.d.ts +577 -0
  22. package/dist/binding.js +788 -0
  23. package/dist/binding.js.map +1 -0
  24. package/dist/context-event.d.ts +23 -0
  25. package/dist/context-event.js +7 -0
  26. package/dist/context-event.js.map +1 -0
  27. package/dist/context-observer.d.ts +36 -0
  28. package/dist/context-observer.js +7 -0
  29. package/dist/context-observer.js.map +1 -0
  30. package/dist/context-subscription.d.ts +147 -0
  31. package/dist/context-subscription.js +317 -0
  32. package/dist/context-subscription.js.map +1 -0
  33. package/dist/context-tag-indexer.d.ts +42 -0
  34. package/dist/context-tag-indexer.js +135 -0
  35. package/dist/context-tag-indexer.js.map +1 -0
  36. package/dist/context-view.d.ts +209 -0
  37. package/dist/context-view.js +240 -0
  38. package/dist/context-view.js.map +1 -0
  39. package/dist/context.d.ts +513 -0
  40. package/dist/context.js +717 -0
  41. package/dist/context.js.map +1 -0
  42. package/dist/index.d.ts +52 -0
  43. package/dist/index.js +60 -0
  44. package/dist/index.js.map +1 -0
  45. package/dist/inject-config.d.ts +67 -0
  46. package/dist/inject-config.js +181 -0
  47. package/dist/inject-config.js.map +1 -0
  48. package/dist/inject.d.ts +250 -0
  49. package/dist/inject.js +535 -0
  50. package/dist/inject.js.map +1 -0
  51. package/dist/interception-proxy.d.ts +76 -0
  52. package/dist/interception-proxy.js +67 -0
  53. package/dist/interception-proxy.js.map +1 -0
  54. package/dist/interceptor-chain.d.ts +121 -0
  55. package/dist/interceptor-chain.js +148 -0
  56. package/dist/interceptor-chain.js.map +1 -0
  57. package/dist/interceptor.d.ts +138 -0
  58. package/dist/interceptor.js +299 -0
  59. package/dist/interceptor.js.map +1 -0
  60. package/dist/invocation.d.ts +101 -0
  61. package/dist/invocation.js +163 -0
  62. package/dist/invocation.js.map +1 -0
  63. package/dist/json-types.d.ts +28 -0
  64. package/{lib/src/provider.js → dist/json-types.js} +3 -3
  65. package/dist/json-types.js.map +1 -0
  66. package/dist/keys.d.ts +65 -0
  67. package/dist/keys.js +74 -0
  68. package/dist/keys.js.map +1 -0
  69. package/dist/provider.d.ts +31 -0
  70. package/{lib6/src → dist}/provider.js +2 -2
  71. package/dist/provider.js.map +1 -0
  72. package/dist/resolution-session.d.ts +180 -0
  73. package/dist/resolution-session.js +274 -0
  74. package/dist/resolution-session.js.map +1 -0
  75. package/dist/resolver.d.ts +46 -0
  76. package/dist/resolver.js +203 -0
  77. package/dist/resolver.js.map +1 -0
  78. package/dist/unique-id.d.ts +14 -0
  79. package/dist/unique-id.js +26 -0
  80. package/dist/unique-id.js.map +1 -0
  81. package/dist/value-promise.d.ts +134 -0
  82. package/dist/value-promise.js +277 -0
  83. package/dist/value-promise.js.map +1 -0
  84. package/package.json +49 -34
  85. package/src/binding-config.ts +73 -0
  86. package/src/binding-decorator.ts +136 -0
  87. package/src/binding-filter.ts +250 -0
  88. package/src/binding-inspector.ts +371 -0
  89. package/src/binding-key.ts +136 -0
  90. package/src/binding-sorter.ts +124 -0
  91. package/src/binding.ts +1107 -0
  92. package/src/context-event.ts +30 -0
  93. package/src/context-observer.ts +50 -0
  94. package/src/context-subscription.ts +402 -0
  95. package/src/context-tag-indexer.ts +147 -0
  96. package/src/context-view.ts +440 -0
  97. package/src/context.ts +1079 -0
  98. package/src/index.ts +58 -0
  99. package/src/inject-config.ts +239 -0
  100. package/src/inject.ts +796 -0
  101. package/src/interception-proxy.ts +127 -0
  102. package/src/interceptor-chain.ts +268 -0
  103. package/src/interceptor.ts +430 -0
  104. package/src/invocation.ts +269 -0
  105. package/src/json-types.ts +35 -0
  106. package/src/keys.ts +85 -0
  107. package/src/provider.ts +37 -0
  108. package/src/resolution-session.ts +414 -0
  109. package/src/resolver.ts +282 -0
  110. package/src/unique-id.ts +24 -0
  111. package/src/value-promise.ts +318 -0
  112. package/index.d.ts +0 -6
  113. package/index.js +0 -9
  114. package/lib/binding.d.ts +0 -75
  115. package/lib/binding.js +0 -103
  116. package/lib/binding.js.map +0 -1
  117. package/lib/context.d.ts +0 -14
  118. package/lib/context.js +0 -97
  119. package/lib/context.js.map +0 -1
  120. package/lib/index.d.ts +0 -1
  121. package/lib/index.js +0 -12
  122. package/lib/index.js.map +0 -1
  123. package/lib/inject.d.ts +0 -46
  124. package/lib/inject.js +0 -74
  125. package/lib/inject.js.map +0 -1
  126. package/lib/isPromise.d.ts +0 -1
  127. package/lib/isPromise.js +0 -15
  128. package/lib/isPromise.js.map +0 -1
  129. package/lib/reflect.d.ts +0 -39
  130. package/lib/reflect.js +0 -20
  131. package/lib/reflect.js.map +0 -1
  132. package/lib/resolver.d.ts +0 -30
  133. package/lib/resolver.js +0 -129
  134. package/lib/resolver.js.map +0 -1
  135. package/lib/src/binding.d.ts +0 -85
  136. package/lib/src/binding.js +0 -123
  137. package/lib/src/binding.js.map +0 -1
  138. package/lib/src/context.d.ts +0 -14
  139. package/lib/src/context.js +0 -97
  140. package/lib/src/context.js.map +0 -1
  141. package/lib/src/index.d.ts +0 -10
  142. package/lib/src/index.js +0 -27
  143. package/lib/src/index.js.map +0 -1
  144. package/lib/src/inject.d.ts +0 -46
  145. package/lib/src/inject.js +0 -74
  146. package/lib/src/inject.js.map +0 -1
  147. package/lib/src/isPromise.d.ts +0 -1
  148. package/lib/src/isPromise.js +0 -15
  149. package/lib/src/isPromise.js.map +0 -1
  150. package/lib/src/provider.d.ts +0 -29
  151. package/lib/src/provider.js.map +0 -1
  152. package/lib/src/reflect.d.ts +0 -38
  153. package/lib/src/reflect.js +0 -143
  154. package/lib/src/reflect.js.map +0 -1
  155. package/lib/src/resolver.d.ts +0 -34
  156. package/lib/src/resolver.js +0 -144
  157. package/lib/src/resolver.js.map +0 -1
  158. package/lib6/binding.d.ts +0 -75
  159. package/lib6/binding.js +0 -103
  160. package/lib6/binding.js.map +0 -1
  161. package/lib6/context.d.ts +0 -14
  162. package/lib6/context.js +0 -97
  163. package/lib6/context.js.map +0 -1
  164. package/lib6/index.d.ts +0 -1
  165. package/lib6/index.js +0 -12
  166. package/lib6/index.js.map +0 -1
  167. package/lib6/inject.d.ts +0 -46
  168. package/lib6/inject.js +0 -74
  169. package/lib6/inject.js.map +0 -1
  170. package/lib6/isPromise.d.ts +0 -1
  171. package/lib6/isPromise.js +0 -15
  172. package/lib6/isPromise.js.map +0 -1
  173. package/lib6/reflect.d.ts +0 -39
  174. package/lib6/reflect.js +0 -20
  175. package/lib6/reflect.js.map +0 -1
  176. package/lib6/resolver.d.ts +0 -30
  177. package/lib6/resolver.js +0 -129
  178. package/lib6/resolver.js.map +0 -1
  179. package/lib6/src/binding.d.ts +0 -85
  180. package/lib6/src/binding.js +0 -133
  181. package/lib6/src/binding.js.map +0 -1
  182. package/lib6/src/context.d.ts +0 -14
  183. package/lib6/src/context.js +0 -97
  184. package/lib6/src/context.js.map +0 -1
  185. package/lib6/src/index.d.ts +0 -10
  186. package/lib6/src/index.js +0 -27
  187. package/lib6/src/index.js.map +0 -1
  188. package/lib6/src/inject.d.ts +0 -46
  189. package/lib6/src/inject.js +0 -74
  190. package/lib6/src/inject.js.map +0 -1
  191. package/lib6/src/isPromise.d.ts +0 -1
  192. package/lib6/src/isPromise.js +0 -15
  193. package/lib6/src/isPromise.js.map +0 -1
  194. package/lib6/src/provider.d.ts +0 -29
  195. package/lib6/src/provider.js.map +0 -1
  196. package/lib6/src/reflect.d.ts +0 -38
  197. package/lib6/src/reflect.js +0 -143
  198. package/lib6/src/reflect.js.map +0 -1
  199. package/lib6/src/resolver.d.ts +0 -34
  200. package/lib6/src/resolver.js +0 -154
  201. 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
+ }