@loopback/context 1.25.0 → 2.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/CHANGELOG.md +80 -0
  2. package/dist/binding-filter.d.ts +20 -2
  3. package/dist/binding-filter.js +58 -9
  4. package/dist/binding-filter.js.map +1 -1
  5. package/dist/binding.d.ts +50 -2
  6. package/dist/binding.js +33 -1
  7. package/dist/binding.js.map +1 -1
  8. package/dist/context-event.d.ts +23 -0
  9. package/dist/context-event.js +7 -0
  10. package/dist/context-event.js.map +1 -0
  11. package/dist/context-observer.d.ts +1 -36
  12. package/dist/context-subscription.d.ts +147 -0
  13. package/dist/context-subscription.js +336 -0
  14. package/dist/context-subscription.js.map +1 -0
  15. package/dist/context-tag-indexer.d.ts +42 -0
  16. package/dist/context-tag-indexer.js +134 -0
  17. package/dist/context-tag-indexer.js.map +1 -0
  18. package/dist/context-view.d.ts +2 -1
  19. package/dist/context-view.js.map +1 -1
  20. package/dist/context.d.ts +44 -68
  21. package/dist/context.js +69 -249
  22. package/dist/context.js.map +1 -1
  23. package/dist/index.d.ts +3 -0
  24. package/dist/index.js +1 -0
  25. package/dist/index.js.map +1 -1
  26. package/dist/inject.d.ts +9 -2
  27. package/dist/inject.js +60 -0
  28. package/dist/inject.js.map +1 -1
  29. package/dist/interceptor.js +4 -4
  30. package/dist/interceptor.js.map +1 -1
  31. package/dist/invocation.d.ts +0 -1
  32. package/dist/invocation.js +1 -5
  33. package/dist/invocation.js.map +1 -1
  34. package/dist/json-types.d.ts +28 -0
  35. package/dist/json-types.js +7 -0
  36. package/dist/json-types.js.map +1 -0
  37. package/dist/resolution-session.d.ts +2 -6
  38. package/dist/resolution-session.js +0 -4
  39. package/dist/resolution-session.js.map +1 -1
  40. package/dist/value-promise.d.ts +1 -3
  41. package/package.json +9 -9
  42. package/src/binding-filter.ts +83 -11
  43. package/src/binding.ts +79 -3
  44. package/src/context-event.ts +30 -0
  45. package/src/context-observer.ts +1 -38
  46. package/src/context-subscription.ts +403 -0
  47. package/src/context-tag-indexer.ts +149 -0
  48. package/src/context-view.ts +2 -5
  49. package/src/context.ts +104 -290
  50. package/src/index.ts +3 -0
  51. package/src/inject.ts +65 -0
  52. package/src/interceptor.ts +7 -6
  53. package/src/invocation.ts +1 -3
  54. package/src/json-types.ts +35 -0
  55. package/src/resolution-session.ts +4 -7
  56. package/src/value-promise.ts +1 -1
@@ -0,0 +1,149 @@
1
+ // Copyright IBM Corp. 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 {Binding, BindingEventListener, BindingTag} from './binding';
7
+ import {BindingFilter, filterByTag} from './binding-filter';
8
+ import {Context} from './context';
9
+ import {ContextEventListener} from './context-event';
10
+ import {BoundValue} from './value-promise';
11
+
12
+ /**
13
+ * Indexer for context bindings by tag
14
+ */
15
+ export class ContextTagIndexer {
16
+ /**
17
+ * Index for bindings by tag names
18
+ */
19
+ readonly bindingsIndexedByTag: Map<
20
+ string,
21
+ Set<Readonly<Binding<unknown>>>
22
+ > = new Map();
23
+
24
+ /**
25
+ * A listener for binding events
26
+ */
27
+ private bindingEventListener: BindingEventListener;
28
+
29
+ /**
30
+ * A listener to maintain tag index for bindings
31
+ */
32
+ private tagIndexListener: ContextEventListener;
33
+
34
+ constructor(protected readonly context: Context) {
35
+ this.setupTagIndexForBindings();
36
+ }
37
+
38
+ /**
39
+ * Set up context/binding listeners and refresh index for bindings by tag
40
+ */
41
+ private setupTagIndexForBindings() {
42
+ this.bindingEventListener = ({binding, operation}) => {
43
+ if (operation === 'tag') {
44
+ this.updateTagIndexForBinding(binding);
45
+ }
46
+ };
47
+ this.tagIndexListener = event => {
48
+ const {binding, type} = event;
49
+ if (event.context !== this.context) return;
50
+ if (type === 'bind') {
51
+ this.updateTagIndexForBinding(binding);
52
+ binding.on('changed', this.bindingEventListener);
53
+ } else if (type === 'unbind') {
54
+ this.removeTagIndexForBinding(binding);
55
+ binding.removeListener('changed', this.bindingEventListener);
56
+ }
57
+ };
58
+ this.context.on('bind', this.tagIndexListener);
59
+ this.context.on('unbind', this.tagIndexListener);
60
+ }
61
+
62
+ /**
63
+ * Remove tag index for the given binding
64
+ * @param binding - Binding object
65
+ */
66
+ private removeTagIndexForBinding(binding: Readonly<Binding<unknown>>) {
67
+ for (const [, bindings] of this.bindingsIndexedByTag) {
68
+ bindings.delete(binding);
69
+ }
70
+ }
71
+
72
+ /**
73
+ * Update tag index for the given binding
74
+ * @param binding - Binding object
75
+ */
76
+ private updateTagIndexForBinding(binding: Readonly<Binding<unknown>>) {
77
+ this.removeTagIndexForBinding(binding);
78
+ for (const tag of binding.tagNames) {
79
+ let bindings = this.bindingsIndexedByTag.get(tag);
80
+ if (bindings == null) {
81
+ bindings = new Set();
82
+ this.bindingsIndexedByTag.set(tag, bindings);
83
+ }
84
+ bindings.add(binding);
85
+ }
86
+ }
87
+
88
+ /**
89
+ * Find bindings by tag leveraging indexes
90
+ * @param tag - Tag name pattern or name/value pairs
91
+ */
92
+ findByTagIndex<ValueType = BoundValue>(
93
+ tag: BindingTag | RegExp,
94
+ ): Readonly<Binding<ValueType>>[] {
95
+ let tagNames: string[];
96
+ // A flag to control if a union of matched bindings should be created
97
+ let union = false;
98
+ if (tag instanceof RegExp) {
99
+ // For wildcard/regexp, a union of matched bindings is desired
100
+ union = true;
101
+ // Find all matching tag names
102
+ tagNames = [];
103
+ for (const t of this.bindingsIndexedByTag.keys()) {
104
+ if (tag.test(t)) {
105
+ tagNames.push(t);
106
+ }
107
+ }
108
+ } else if (typeof tag === 'string') {
109
+ tagNames = [tag];
110
+ } else {
111
+ tagNames = Object.keys(tag);
112
+ }
113
+ let filter: BindingFilter | undefined;
114
+ let bindings: Set<Readonly<Binding<ValueType>>> | undefined;
115
+ for (const t of tagNames) {
116
+ const bindingsByTag = this.bindingsIndexedByTag.get(t);
117
+ if (bindingsByTag == null) break; // One of the tags is not found
118
+ filter = filter ?? filterByTag(tag);
119
+ const matched = new Set(Array.from(bindingsByTag).filter(filter)) as Set<
120
+ Readonly<Binding<ValueType>>
121
+ >;
122
+ if (!union && matched.size === 0) break; // One of the tag name/value is not found
123
+ if (bindings == null) {
124
+ // First set of bindings matching the tag
125
+ bindings = matched;
126
+ } else {
127
+ if (union) {
128
+ matched.forEach(b => bindings?.add(b));
129
+ } else {
130
+ // Now need to find intersected bindings against visited tags
131
+ const intersection = new Set<Readonly<Binding<ValueType>>>();
132
+ bindings.forEach(b => {
133
+ if (matched.has(b)) {
134
+ intersection.add(b);
135
+ }
136
+ });
137
+ bindings = intersection;
138
+ }
139
+ if (!union && bindings.size === 0) break;
140
+ }
141
+ }
142
+ return bindings == null ? [] : Array.from(bindings);
143
+ }
144
+
145
+ close() {
146
+ this.context.removeListener('bind', this.tagIndexListener);
147
+ this.context.removeListener('unbind', this.tagIndexListener);
148
+ }
149
+ }
@@ -10,11 +10,8 @@ import {Binding} from './binding';
10
10
  import {BindingFilter} from './binding-filter';
11
11
  import {BindingComparator} from './binding-sorter';
12
12
  import {Context} from './context';
13
- import {
14
- ContextEventType,
15
- ContextObserver,
16
- Subscription,
17
- } from './context-observer';
13
+ import {ContextEventType, ContextObserver} from './context-observer';
14
+ import {Subscription} from './context-subscription';
18
15
  import {Getter} from './inject';
19
16
  import {ResolutionSession} from './resolution-session';
20
17
  import {isPromiseLike, resolveList, ValueOrPromise} from './value-promise';