atomic-di 0.7.1-beta.1 → 0.8.0-beta.1
Sign up to get free protection for your applications and to get access to all the features.
- package/dist/index.d.mts +164 -151
- package/dist/index.d.ts +164 -151
- package/dist/index.js +77 -63
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +75 -62
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
@@ -1,216 +1,229 @@
|
|
1
|
+
type Entry<K, V> = [K, V];
|
2
|
+
type Entries<K, V> = Entry<K, V>[];
|
1
3
|
/**
|
2
|
-
*
|
3
|
-
*
|
4
|
-
* of scoped providers within it.
|
5
|
-
*/
|
6
|
-
type Scope = WeakMap<Provider<any>, any>;
|
7
|
-
/**
|
8
|
-
* Creates a new scope, map of providers to their instances.
|
9
|
-
* Scope is passed to the provider call to resolve instances
|
10
|
-
* of scoped providers within it.
|
11
|
-
*
|
12
|
-
* @returns A new scope.
|
4
|
+
* An immutable map. It's similar to `Map`,
|
5
|
+
* but with reduced functionality and readonly builder behavior.
|
13
6
|
*/
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
*/
|
20
|
-
type MockMap = {
|
21
|
-
entries: MockMapEntries;
|
7
|
+
type ImmutableMap<K, V> = {
|
8
|
+
/**
|
9
|
+
* Map's entries.
|
10
|
+
*/
|
11
|
+
readonly entries: Entries<K, V>;
|
22
12
|
/**
|
23
|
-
*
|
24
|
-
* depending on the presence of the mock.
|
13
|
+
* Retrieves a possibly existing value under a key.
|
25
14
|
*
|
26
|
-
* @param
|
15
|
+
* @param key - The key associated with the value.
|
27
16
|
*
|
28
|
-
* @returns The
|
17
|
+
* @returns The value or undefined.
|
29
18
|
*/
|
30
|
-
|
19
|
+
get(key: K): V | undefined;
|
31
20
|
/**
|
32
|
-
*
|
21
|
+
* Sets a value under a key.
|
33
22
|
*
|
34
|
-
* @param
|
35
|
-
* @param
|
23
|
+
* @param key - The key that will be associated with the value.
|
24
|
+
* @param value - The value to set.
|
36
25
|
*
|
37
|
-
* @returns A
|
26
|
+
* @returns A modified immutable map with the value being set in it.
|
38
27
|
*/
|
39
|
-
|
28
|
+
set(key: K, value: V): ImmutableMap<K, V>;
|
40
29
|
/**
|
41
|
-
*
|
42
|
-
*
|
43
|
-
* they will be overwritten by mocks from the other map.
|
30
|
+
* Merges two immutable maps. If there're any matching keys,
|
31
|
+
* values from the second map will override values from the first map.
|
44
32
|
*
|
45
|
-
* @param
|
33
|
+
* @param other The second immutable map.
|
46
34
|
*
|
47
|
-
* @returns A new
|
35
|
+
* @returns A new immutable map as a result of merging two maps.
|
48
36
|
*/
|
49
|
-
|
37
|
+
merge(other: ImmutableMap<K, V>): ImmutableMap<K, V>;
|
50
38
|
};
|
39
|
+
|
40
|
+
/**
|
41
|
+
* A map of providers to their compatible versions.
|
42
|
+
*
|
43
|
+
* Passed to a provider call in a resolution context object
|
44
|
+
* in order to replace providers with their mocks.
|
45
|
+
* ```ts
|
46
|
+
* const mocks = createMockMap().set(otherProvider, otherProviderMock)
|
47
|
+
* provider({ mocks })
|
48
|
+
* ```
|
49
|
+
*/
|
50
|
+
type MockMap = ImmutableMap<Provider<any>, Provider<any>>;
|
51
51
|
/**
|
52
|
-
* Creates a
|
52
|
+
* Creates a mock map instance.
|
53
53
|
*
|
54
|
-
*
|
54
|
+
* Passed to a provider call in a resolution context object
|
55
|
+
* in order to replace providers with their mocks.
|
56
|
+
* ```ts
|
57
|
+
* const mocks = createMockMap().set(otherProvider, otherProviderMock)
|
58
|
+
* provider({ mocks })
|
59
|
+
* ```
|
55
60
|
*
|
56
|
-
* @returns
|
61
|
+
* @returns The mock map instance.
|
57
62
|
*/
|
58
|
-
declare const createMockMap: (
|
59
|
-
entries: MockMapEntries;
|
60
|
-
map: <T>(provider: Provider<T>) => Provider<T>;
|
61
|
-
add: <T>(provider: Provider<T>, replacement: Provider<T>) => MockMap;
|
62
|
-
apply: (otherMockMap: MockMap) => MockMap;
|
63
|
-
};
|
63
|
+
declare const createMockMap: () => MockMap;
|
64
64
|
|
65
65
|
/**
|
66
|
-
*
|
67
|
-
* and returns an instance.
|
66
|
+
* A map of providers to their instances.
|
68
67
|
*
|
69
|
-
*
|
70
|
-
* to
|
71
|
-
*
|
72
|
-
*
|
73
|
-
*
|
68
|
+
* Passed to a provider call in a resolution context object
|
69
|
+
* to resolve instances of scoped providers within it.
|
70
|
+
* ```ts
|
71
|
+
* const scope = createScope()
|
72
|
+
* provider({ scope })
|
73
|
+
* ```
|
74
|
+
*/
|
75
|
+
type Scope = Map<Provider<any>, any>;
|
76
|
+
/**
|
77
|
+
* Creates a scope instance.
|
78
|
+
*
|
79
|
+
* Scope is passed to a provider call in a resolution context object
|
80
|
+
* to resolve instances of scoped providers within it.
|
81
|
+
* ```ts
|
82
|
+
* const scope = createScope()
|
83
|
+
* provider({ scope })
|
84
|
+
* ```
|
74
85
|
*
|
75
|
-
*
|
76
|
-
* If you want to mock(replace) providers for a resolution,
|
77
|
-
* it's best to use `mock` method.
|
86
|
+
* @returns The scope instance.
|
78
87
|
*/
|
79
|
-
|
88
|
+
declare const createScope: () => Scope;
|
89
|
+
|
80
90
|
/**
|
81
|
-
*
|
91
|
+
* A wrapper around the resolver for contextual dependency resolution.
|
92
|
+
*
|
93
|
+
* Resolves an instance by calling a resolver
|
94
|
+
* with a resolution context that will be propagated
|
95
|
+
* throughout a dependency tree.
|
96
|
+
*
|
97
|
+
* When passing a scope it will try to get an instance from it
|
98
|
+
* or create a new one and put it there.
|
99
|
+
*
|
100
|
+
* When passing mocks, it will try to get its own mock version,
|
101
|
+
* and if there is one, it will use it instead of itself.
|
102
|
+
*/
|
103
|
+
type Provider<T> = (context?: ResolutionContext) => T;
|
104
|
+
/**
|
105
|
+
* A resolution lifetime.
|
106
|
+
*
|
107
|
+
* Passed when creating a provider to determine its behavior.
|
108
|
+
*
|
109
|
+
* `"transient"` doesn't provide any modifications to a resolver behaviour,
|
110
|
+
* so the resolver will create a new instance on each request.
|
111
|
+
*
|
112
|
+
* `"singleton"` forces the resolver to create an instance once
|
113
|
+
* and return it in subsequent requests.
|
114
|
+
*
|
115
|
+
* `"scoped"` forces the resolver to take its instance from a provided scope
|
116
|
+
* or create a new one and save it if there is none.
|
117
|
+
* If no scope is passed, it will create a new instance on each request.
|
82
118
|
*/
|
83
|
-
type Provider<T> = ProviderCallable<T> & {
|
84
|
-
/**
|
85
|
-
* Mocks(replaces) a provider within the visible graph,
|
86
|
-
* returning a new provider with that mock.
|
87
|
-
*
|
88
|
-
* @param dependencyProvider A provider used by the current provider
|
89
|
-
* that needs to be replaced.
|
90
|
-
* @param replacement A provider with a same interface
|
91
|
-
* that will be a replacement for the first one.
|
92
|
-
*
|
93
|
-
* @returns A new provider with the mocked dependency provider.
|
94
|
-
*/
|
95
|
-
mock<U>(dependencyProvider: Provider<U>, replacement: Provider<U>): Provider<T>;
|
96
|
-
};
|
97
119
|
type Lifetime = "transient" | "singleton" | "scoped";
|
98
120
|
/**
|
99
|
-
* A function that
|
100
|
-
* It's needed to resolve correct instance in a scope
|
101
|
-
* and to use mock of the passed provider, if any.
|
121
|
+
* A function that creates an instance using a resolution context.
|
102
122
|
*/
|
103
|
-
type
|
123
|
+
type Resolver<T> = (context?: ResolutionContext) => T;
|
104
124
|
/**
|
105
|
-
*
|
106
|
-
*
|
107
|
-
*
|
125
|
+
* An object that holds information about a scope and provider mocks.
|
126
|
+
*
|
127
|
+
* Passed to the provider call to resolve scope instances and mock providers.
|
108
128
|
*/
|
109
|
-
type
|
129
|
+
type ResolutionContext = {
|
130
|
+
scope?: Scope;
|
131
|
+
mocks?: MockMap;
|
132
|
+
};
|
110
133
|
/**
|
111
|
-
* Creates a
|
134
|
+
* Creates a provider instance,
|
135
|
+
* a wrapper around a resolver for contextual dependency resolution.
|
136
|
+
*
|
137
|
+
* @param lifetime
|
138
|
+
* A resolution lifetime.
|
139
|
+
*
|
140
|
+
* `"transient"` doesn't provide any modifications to a resolver behaviour,
|
141
|
+
* so the resolver will create a new instance on each request.
|
112
142
|
*
|
113
|
-
*
|
143
|
+
* `"singleton"` forces the resolver to create an instance once
|
144
|
+
* and return it in subsequent requests.
|
114
145
|
*
|
115
|
-
*
|
116
|
-
*
|
117
|
-
* If
|
118
|
-
* in the first argument.
|
146
|
+
* `"scoped"` forces the resolver to take its resolution from a provided scope
|
147
|
+
* or create a new one and save it if there is none.
|
148
|
+
* If no scope is passed, it will create a new instance on each request.
|
119
149
|
*
|
120
|
-
* @param
|
121
|
-
*
|
150
|
+
* @param resolver
|
151
|
+
* The function that creates an instance using a resolution context.
|
122
152
|
*
|
123
|
-
* @returns
|
153
|
+
* @returns The provider instance.
|
124
154
|
*/
|
125
|
-
declare const provide: <T>(lifetime: Lifetime, resolver: Resolver<T
|
155
|
+
declare const provide: <T>(lifetime: Lifetime, resolver: Resolver<T>) => Provider<T>;
|
126
156
|
/**
|
127
|
-
* Creates a
|
128
|
-
*
|
157
|
+
* Creates a transient provider instance,
|
158
|
+
* a wrapper around a resolver for contextual dependency resolution
|
159
|
+
* that will create a new instance on each request.
|
129
160
|
*
|
130
|
-
* @param resolver
|
131
|
-
*
|
132
|
-
* If there are dependencies, you must use `use` function passed
|
133
|
-
* in the first argument.
|
161
|
+
* @param resolver
|
162
|
+
* The function that creates an instance using a resolution context.
|
134
163
|
*
|
135
|
-
* @returns
|
164
|
+
* @returns The transient provider instance.
|
136
165
|
*/
|
137
166
|
declare const transient: <T>(resolver: Resolver<T>) => Provider<T>;
|
138
167
|
/**
|
139
|
-
* Creates a
|
140
|
-
*
|
168
|
+
* Creates a transient provider instance,
|
169
|
+
* a wrapper around a resolver for contextual dependency resolution
|
170
|
+
* that will create an instance once and return it in subsequent requests.
|
141
171
|
*
|
142
|
-
* @param resolver
|
143
|
-
*
|
144
|
-
* If there are dependencies, you must use `use` function passed
|
145
|
-
* in the first argument.
|
172
|
+
* @param resolver
|
173
|
+
* The function that creates an instance using a resolution context.
|
146
174
|
*
|
147
|
-
* @returns
|
175
|
+
* @returns The singleton provider instance.
|
148
176
|
*/
|
149
177
|
declare const singleton: <T>(resolver: Resolver<T>) => Provider<T>;
|
150
178
|
/**
|
151
|
-
* Creates a
|
152
|
-
*
|
153
|
-
*
|
154
|
-
*
|
179
|
+
* Creates a transient provider instance,
|
180
|
+
* a wrapper around a resolver for contextual dependency resolution
|
181
|
+
* that will take its resolution from a provided scope
|
182
|
+
* or create a new one and save it if there is none.
|
183
|
+
* If no scope is passed, it will create a new instance on each request.
|
155
184
|
*
|
156
|
-
* @param resolver
|
157
|
-
*
|
158
|
-
* If there are dependencies, you must use `use` function passed
|
159
|
-
* in the first argument.
|
185
|
+
* @param resolver
|
186
|
+
* The function that creates an instance using a resolution context.
|
160
187
|
*
|
161
|
-
* @returns
|
188
|
+
* @returns The scoped provider instance.
|
162
189
|
*/
|
163
190
|
declare const scoped: <T>(resolver: Resolver<T>) => Provider<T>;
|
164
191
|
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
type ProviderMap = Record<string, Provider<any>>;
|
169
|
-
type InferProviderMapOutputs<Providers extends ProviderMap> = {
|
192
|
+
type ProviderList = Provider<any>[];
|
193
|
+
type ProviderRecord = Record<string, Provider<any>>;
|
194
|
+
type InferProviderCollectionResolutions<Providers extends ProviderList | ProviderRecord> = {
|
170
195
|
[K in keyof Providers]: Providers[K] extends Provider<infer T> ? T : never;
|
171
196
|
};
|
172
197
|
/**
|
173
|
-
*
|
174
|
-
*
|
175
|
-
*
|
176
|
-
* @param scope - An optional scope to use for scoped providers.
|
177
|
-
* @param mockMap - An optional mock map to use for mocking providers.
|
178
|
-
*
|
179
|
-
* @returns An object containing the resolved instances of the providers.
|
198
|
+
* Awaits all promises and wraps the collection in a promise
|
199
|
+
* if there'ss at least one `Promise` in the collection,
|
200
|
+
* otherwise returns an untouched type.
|
180
201
|
*/
|
181
|
-
type
|
202
|
+
type AwaitAllValuesInCollection<T extends any[] | Record<any, any>> = Promise<any> extends T[keyof T] ? Promise<{
|
203
|
+
[I in keyof T]: T[I] extends Promise<infer T> ? T : T[I];
|
204
|
+
}> : T;
|
182
205
|
/**
|
183
|
-
*
|
206
|
+
* Calls every provider in a list with a provided resolution context
|
207
|
+
* and returns a list of resolutions. Returns a promise of a list
|
208
|
+
* of awaited resolutions if there's at least one promise in the resolutions.
|
209
|
+
*
|
210
|
+
* @param providers - The list of providers.
|
211
|
+
* @param context - The resolution context.
|
184
212
|
*
|
185
|
-
* @
|
186
|
-
* @property mock - A function that mocks a provider within the selection,
|
187
|
-
* returning a new `ProviderSelection` with the mock applied.
|
213
|
+
* @returns The list of resolutions.
|
188
214
|
*/
|
189
|
-
|
190
|
-
/**
|
191
|
-
* The `ProviderMap` that the selection is based on.
|
192
|
-
*/
|
193
|
-
map: Providers;
|
194
|
-
/**
|
195
|
-
* Mocks a provider within the selection, returning a new
|
196
|
-
* `ProviderSelection` with the mock applied.
|
197
|
-
*
|
198
|
-
* @param dependencyProvider - A provider used by the current provider
|
199
|
-
* that needs to be replaced.
|
200
|
-
* @param replacement - A provider with a same interface that will be
|
201
|
-
* a replacement for the first one.
|
202
|
-
*
|
203
|
-
* @returns A new `ProviderSelection` with the mocked provider.
|
204
|
-
*/
|
205
|
-
mock<T>(dependencyProvider: Provider<T>, replacement: Provider<T>): ProviderSelection<Providers>;
|
206
|
-
};
|
215
|
+
declare const resolveList: <const Providers extends ProviderList>(providers: Providers, context?: ResolutionContext) => AwaitAllValuesInCollection<InferProviderCollectionResolutions<Providers>>;
|
207
216
|
/**
|
208
|
-
*
|
217
|
+
* Calls every provider in a map with a provided resolution context
|
218
|
+
* and returns a map with identical keys but with resolutions in values instead.
|
219
|
+
* Returns a promise of a map of awaited resolutions if there's at least one
|
220
|
+
* promise in the resolutions.
|
209
221
|
*
|
210
|
-
* @param
|
222
|
+
* @param providers - The map of providers.
|
223
|
+
* @param context - The resolution context.
|
211
224
|
*
|
212
|
-
* @returns
|
225
|
+
* @returns The map of resolutions.
|
213
226
|
*/
|
214
|
-
declare const
|
227
|
+
declare const resolveMap: <const Providers extends ProviderRecord>(providers: Providers, context?: ResolutionContext) => AwaitAllValuesInCollection<InferProviderCollectionResolutions<Providers>>;
|
215
228
|
|
216
|
-
export { type MockMap, type Provider, type
|
229
|
+
export { type Lifetime, type MockMap, type Provider, type ResolutionContext, type Resolver, type Scope, createMockMap, createScope, provide, resolveList, resolveMap, scoped, singleton, transient };
|
package/dist/index.d.ts
CHANGED
@@ -1,216 +1,229 @@
|
|
1
|
+
type Entry<K, V> = [K, V];
|
2
|
+
type Entries<K, V> = Entry<K, V>[];
|
1
3
|
/**
|
2
|
-
*
|
3
|
-
*
|
4
|
-
* of scoped providers within it.
|
5
|
-
*/
|
6
|
-
type Scope = WeakMap<Provider<any>, any>;
|
7
|
-
/**
|
8
|
-
* Creates a new scope, map of providers to their instances.
|
9
|
-
* Scope is passed to the provider call to resolve instances
|
10
|
-
* of scoped providers within it.
|
11
|
-
*
|
12
|
-
* @returns A new scope.
|
4
|
+
* An immutable map. It's similar to `Map`,
|
5
|
+
* but with reduced functionality and readonly builder behavior.
|
13
6
|
*/
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
*/
|
20
|
-
type MockMap = {
|
21
|
-
entries: MockMapEntries;
|
7
|
+
type ImmutableMap<K, V> = {
|
8
|
+
/**
|
9
|
+
* Map's entries.
|
10
|
+
*/
|
11
|
+
readonly entries: Entries<K, V>;
|
22
12
|
/**
|
23
|
-
*
|
24
|
-
* depending on the presence of the mock.
|
13
|
+
* Retrieves a possibly existing value under a key.
|
25
14
|
*
|
26
|
-
* @param
|
15
|
+
* @param key - The key associated with the value.
|
27
16
|
*
|
28
|
-
* @returns The
|
17
|
+
* @returns The value or undefined.
|
29
18
|
*/
|
30
|
-
|
19
|
+
get(key: K): V | undefined;
|
31
20
|
/**
|
32
|
-
*
|
21
|
+
* Sets a value under a key.
|
33
22
|
*
|
34
|
-
* @param
|
35
|
-
* @param
|
23
|
+
* @param key - The key that will be associated with the value.
|
24
|
+
* @param value - The value to set.
|
36
25
|
*
|
37
|
-
* @returns A
|
26
|
+
* @returns A modified immutable map with the value being set in it.
|
38
27
|
*/
|
39
|
-
|
28
|
+
set(key: K, value: V): ImmutableMap<K, V>;
|
40
29
|
/**
|
41
|
-
*
|
42
|
-
*
|
43
|
-
* they will be overwritten by mocks from the other map.
|
30
|
+
* Merges two immutable maps. If there're any matching keys,
|
31
|
+
* values from the second map will override values from the first map.
|
44
32
|
*
|
45
|
-
* @param
|
33
|
+
* @param other The second immutable map.
|
46
34
|
*
|
47
|
-
* @returns A new
|
35
|
+
* @returns A new immutable map as a result of merging two maps.
|
48
36
|
*/
|
49
|
-
|
37
|
+
merge(other: ImmutableMap<K, V>): ImmutableMap<K, V>;
|
50
38
|
};
|
39
|
+
|
40
|
+
/**
|
41
|
+
* A map of providers to their compatible versions.
|
42
|
+
*
|
43
|
+
* Passed to a provider call in a resolution context object
|
44
|
+
* in order to replace providers with their mocks.
|
45
|
+
* ```ts
|
46
|
+
* const mocks = createMockMap().set(otherProvider, otherProviderMock)
|
47
|
+
* provider({ mocks })
|
48
|
+
* ```
|
49
|
+
*/
|
50
|
+
type MockMap = ImmutableMap<Provider<any>, Provider<any>>;
|
51
51
|
/**
|
52
|
-
* Creates a
|
52
|
+
* Creates a mock map instance.
|
53
53
|
*
|
54
|
-
*
|
54
|
+
* Passed to a provider call in a resolution context object
|
55
|
+
* in order to replace providers with their mocks.
|
56
|
+
* ```ts
|
57
|
+
* const mocks = createMockMap().set(otherProvider, otherProviderMock)
|
58
|
+
* provider({ mocks })
|
59
|
+
* ```
|
55
60
|
*
|
56
|
-
* @returns
|
61
|
+
* @returns The mock map instance.
|
57
62
|
*/
|
58
|
-
declare const createMockMap: (
|
59
|
-
entries: MockMapEntries;
|
60
|
-
map: <T>(provider: Provider<T>) => Provider<T>;
|
61
|
-
add: <T>(provider: Provider<T>, replacement: Provider<T>) => MockMap;
|
62
|
-
apply: (otherMockMap: MockMap) => MockMap;
|
63
|
-
};
|
63
|
+
declare const createMockMap: () => MockMap;
|
64
64
|
|
65
65
|
/**
|
66
|
-
*
|
67
|
-
* and returns an instance.
|
66
|
+
* A map of providers to their instances.
|
68
67
|
*
|
69
|
-
*
|
70
|
-
* to
|
71
|
-
*
|
72
|
-
*
|
73
|
-
*
|
68
|
+
* Passed to a provider call in a resolution context object
|
69
|
+
* to resolve instances of scoped providers within it.
|
70
|
+
* ```ts
|
71
|
+
* const scope = createScope()
|
72
|
+
* provider({ scope })
|
73
|
+
* ```
|
74
|
+
*/
|
75
|
+
type Scope = Map<Provider<any>, any>;
|
76
|
+
/**
|
77
|
+
* Creates a scope instance.
|
78
|
+
*
|
79
|
+
* Scope is passed to a provider call in a resolution context object
|
80
|
+
* to resolve instances of scoped providers within it.
|
81
|
+
* ```ts
|
82
|
+
* const scope = createScope()
|
83
|
+
* provider({ scope })
|
84
|
+
* ```
|
74
85
|
*
|
75
|
-
*
|
76
|
-
* If you want to mock(replace) providers for a resolution,
|
77
|
-
* it's best to use `mock` method.
|
86
|
+
* @returns The scope instance.
|
78
87
|
*/
|
79
|
-
|
88
|
+
declare const createScope: () => Scope;
|
89
|
+
|
80
90
|
/**
|
81
|
-
*
|
91
|
+
* A wrapper around the resolver for contextual dependency resolution.
|
92
|
+
*
|
93
|
+
* Resolves an instance by calling a resolver
|
94
|
+
* with a resolution context that will be propagated
|
95
|
+
* throughout a dependency tree.
|
96
|
+
*
|
97
|
+
* When passing a scope it will try to get an instance from it
|
98
|
+
* or create a new one and put it there.
|
99
|
+
*
|
100
|
+
* When passing mocks, it will try to get its own mock version,
|
101
|
+
* and if there is one, it will use it instead of itself.
|
102
|
+
*/
|
103
|
+
type Provider<T> = (context?: ResolutionContext) => T;
|
104
|
+
/**
|
105
|
+
* A resolution lifetime.
|
106
|
+
*
|
107
|
+
* Passed when creating a provider to determine its behavior.
|
108
|
+
*
|
109
|
+
* `"transient"` doesn't provide any modifications to a resolver behaviour,
|
110
|
+
* so the resolver will create a new instance on each request.
|
111
|
+
*
|
112
|
+
* `"singleton"` forces the resolver to create an instance once
|
113
|
+
* and return it in subsequent requests.
|
114
|
+
*
|
115
|
+
* `"scoped"` forces the resolver to take its instance from a provided scope
|
116
|
+
* or create a new one and save it if there is none.
|
117
|
+
* If no scope is passed, it will create a new instance on each request.
|
82
118
|
*/
|
83
|
-
type Provider<T> = ProviderCallable<T> & {
|
84
|
-
/**
|
85
|
-
* Mocks(replaces) a provider within the visible graph,
|
86
|
-
* returning a new provider with that mock.
|
87
|
-
*
|
88
|
-
* @param dependencyProvider A provider used by the current provider
|
89
|
-
* that needs to be replaced.
|
90
|
-
* @param replacement A provider with a same interface
|
91
|
-
* that will be a replacement for the first one.
|
92
|
-
*
|
93
|
-
* @returns A new provider with the mocked dependency provider.
|
94
|
-
*/
|
95
|
-
mock<U>(dependencyProvider: Provider<U>, replacement: Provider<U>): Provider<T>;
|
96
|
-
};
|
97
119
|
type Lifetime = "transient" | "singleton" | "scoped";
|
98
120
|
/**
|
99
|
-
* A function that
|
100
|
-
* It's needed to resolve correct instance in a scope
|
101
|
-
* and to use mock of the passed provider, if any.
|
121
|
+
* A function that creates an instance using a resolution context.
|
102
122
|
*/
|
103
|
-
type
|
123
|
+
type Resolver<T> = (context?: ResolutionContext) => T;
|
104
124
|
/**
|
105
|
-
*
|
106
|
-
*
|
107
|
-
*
|
125
|
+
* An object that holds information about a scope and provider mocks.
|
126
|
+
*
|
127
|
+
* Passed to the provider call to resolve scope instances and mock providers.
|
108
128
|
*/
|
109
|
-
type
|
129
|
+
type ResolutionContext = {
|
130
|
+
scope?: Scope;
|
131
|
+
mocks?: MockMap;
|
132
|
+
};
|
110
133
|
/**
|
111
|
-
* Creates a
|
134
|
+
* Creates a provider instance,
|
135
|
+
* a wrapper around a resolver for contextual dependency resolution.
|
136
|
+
*
|
137
|
+
* @param lifetime
|
138
|
+
* A resolution lifetime.
|
139
|
+
*
|
140
|
+
* `"transient"` doesn't provide any modifications to a resolver behaviour,
|
141
|
+
* so the resolver will create a new instance on each request.
|
112
142
|
*
|
113
|
-
*
|
143
|
+
* `"singleton"` forces the resolver to create an instance once
|
144
|
+
* and return it in subsequent requests.
|
114
145
|
*
|
115
|
-
*
|
116
|
-
*
|
117
|
-
* If
|
118
|
-
* in the first argument.
|
146
|
+
* `"scoped"` forces the resolver to take its resolution from a provided scope
|
147
|
+
* or create a new one and save it if there is none.
|
148
|
+
* If no scope is passed, it will create a new instance on each request.
|
119
149
|
*
|
120
|
-
* @param
|
121
|
-
*
|
150
|
+
* @param resolver
|
151
|
+
* The function that creates an instance using a resolution context.
|
122
152
|
*
|
123
|
-
* @returns
|
153
|
+
* @returns The provider instance.
|
124
154
|
*/
|
125
|
-
declare const provide: <T>(lifetime: Lifetime, resolver: Resolver<T
|
155
|
+
declare const provide: <T>(lifetime: Lifetime, resolver: Resolver<T>) => Provider<T>;
|
126
156
|
/**
|
127
|
-
* Creates a
|
128
|
-
*
|
157
|
+
* Creates a transient provider instance,
|
158
|
+
* a wrapper around a resolver for contextual dependency resolution
|
159
|
+
* that will create a new instance on each request.
|
129
160
|
*
|
130
|
-
* @param resolver
|
131
|
-
*
|
132
|
-
* If there are dependencies, you must use `use` function passed
|
133
|
-
* in the first argument.
|
161
|
+
* @param resolver
|
162
|
+
* The function that creates an instance using a resolution context.
|
134
163
|
*
|
135
|
-
* @returns
|
164
|
+
* @returns The transient provider instance.
|
136
165
|
*/
|
137
166
|
declare const transient: <T>(resolver: Resolver<T>) => Provider<T>;
|
138
167
|
/**
|
139
|
-
* Creates a
|
140
|
-
*
|
168
|
+
* Creates a transient provider instance,
|
169
|
+
* a wrapper around a resolver for contextual dependency resolution
|
170
|
+
* that will create an instance once and return it in subsequent requests.
|
141
171
|
*
|
142
|
-
* @param resolver
|
143
|
-
*
|
144
|
-
* If there are dependencies, you must use `use` function passed
|
145
|
-
* in the first argument.
|
172
|
+
* @param resolver
|
173
|
+
* The function that creates an instance using a resolution context.
|
146
174
|
*
|
147
|
-
* @returns
|
175
|
+
* @returns The singleton provider instance.
|
148
176
|
*/
|
149
177
|
declare const singleton: <T>(resolver: Resolver<T>) => Provider<T>;
|
150
178
|
/**
|
151
|
-
* Creates a
|
152
|
-
*
|
153
|
-
*
|
154
|
-
*
|
179
|
+
* Creates a transient provider instance,
|
180
|
+
* a wrapper around a resolver for contextual dependency resolution
|
181
|
+
* that will take its resolution from a provided scope
|
182
|
+
* or create a new one and save it if there is none.
|
183
|
+
* If no scope is passed, it will create a new instance on each request.
|
155
184
|
*
|
156
|
-
* @param resolver
|
157
|
-
*
|
158
|
-
* If there are dependencies, you must use `use` function passed
|
159
|
-
* in the first argument.
|
185
|
+
* @param resolver
|
186
|
+
* The function that creates an instance using a resolution context.
|
160
187
|
*
|
161
|
-
* @returns
|
188
|
+
* @returns The scoped provider instance.
|
162
189
|
*/
|
163
190
|
declare const scoped: <T>(resolver: Resolver<T>) => Provider<T>;
|
164
191
|
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
type ProviderMap = Record<string, Provider<any>>;
|
169
|
-
type InferProviderMapOutputs<Providers extends ProviderMap> = {
|
192
|
+
type ProviderList = Provider<any>[];
|
193
|
+
type ProviderRecord = Record<string, Provider<any>>;
|
194
|
+
type InferProviderCollectionResolutions<Providers extends ProviderList | ProviderRecord> = {
|
170
195
|
[K in keyof Providers]: Providers[K] extends Provider<infer T> ? T : never;
|
171
196
|
};
|
172
197
|
/**
|
173
|
-
*
|
174
|
-
*
|
175
|
-
*
|
176
|
-
* @param scope - An optional scope to use for scoped providers.
|
177
|
-
* @param mockMap - An optional mock map to use for mocking providers.
|
178
|
-
*
|
179
|
-
* @returns An object containing the resolved instances of the providers.
|
198
|
+
* Awaits all promises and wraps the collection in a promise
|
199
|
+
* if there'ss at least one `Promise` in the collection,
|
200
|
+
* otherwise returns an untouched type.
|
180
201
|
*/
|
181
|
-
type
|
202
|
+
type AwaitAllValuesInCollection<T extends any[] | Record<any, any>> = Promise<any> extends T[keyof T] ? Promise<{
|
203
|
+
[I in keyof T]: T[I] extends Promise<infer T> ? T : T[I];
|
204
|
+
}> : T;
|
182
205
|
/**
|
183
|
-
*
|
206
|
+
* Calls every provider in a list with a provided resolution context
|
207
|
+
* and returns a list of resolutions. Returns a promise of a list
|
208
|
+
* of awaited resolutions if there's at least one promise in the resolutions.
|
209
|
+
*
|
210
|
+
* @param providers - The list of providers.
|
211
|
+
* @param context - The resolution context.
|
184
212
|
*
|
185
|
-
* @
|
186
|
-
* @property mock - A function that mocks a provider within the selection,
|
187
|
-
* returning a new `ProviderSelection` with the mock applied.
|
213
|
+
* @returns The list of resolutions.
|
188
214
|
*/
|
189
|
-
|
190
|
-
/**
|
191
|
-
* The `ProviderMap` that the selection is based on.
|
192
|
-
*/
|
193
|
-
map: Providers;
|
194
|
-
/**
|
195
|
-
* Mocks a provider within the selection, returning a new
|
196
|
-
* `ProviderSelection` with the mock applied.
|
197
|
-
*
|
198
|
-
* @param dependencyProvider - A provider used by the current provider
|
199
|
-
* that needs to be replaced.
|
200
|
-
* @param replacement - A provider with a same interface that will be
|
201
|
-
* a replacement for the first one.
|
202
|
-
*
|
203
|
-
* @returns A new `ProviderSelection` with the mocked provider.
|
204
|
-
*/
|
205
|
-
mock<T>(dependencyProvider: Provider<T>, replacement: Provider<T>): ProviderSelection<Providers>;
|
206
|
-
};
|
215
|
+
declare const resolveList: <const Providers extends ProviderList>(providers: Providers, context?: ResolutionContext) => AwaitAllValuesInCollection<InferProviderCollectionResolutions<Providers>>;
|
207
216
|
/**
|
208
|
-
*
|
217
|
+
* Calls every provider in a map with a provided resolution context
|
218
|
+
* and returns a map with identical keys but with resolutions in values instead.
|
219
|
+
* Returns a promise of a map of awaited resolutions if there's at least one
|
220
|
+
* promise in the resolutions.
|
209
221
|
*
|
210
|
-
* @param
|
222
|
+
* @param providers - The map of providers.
|
223
|
+
* @param context - The resolution context.
|
211
224
|
*
|
212
|
-
* @returns
|
225
|
+
* @returns The map of resolutions.
|
213
226
|
*/
|
214
|
-
declare const
|
227
|
+
declare const resolveMap: <const Providers extends ProviderRecord>(providers: Providers, context?: ResolutionContext) => AwaitAllValuesInCollection<InferProviderCollectionResolutions<Providers>>;
|
215
228
|
|
216
|
-
export { type MockMap, type Provider, type
|
229
|
+
export { type Lifetime, type MockMap, type Provider, type ResolutionContext, type Resolver, type Scope, createMockMap, createScope, provide, resolveList, resolveMap, scoped, singleton, transient };
|
package/dist/index.js
CHANGED
@@ -22,8 +22,9 @@ __export(src_exports, {
|
|
22
22
|
createMockMap: () => createMockMap,
|
23
23
|
createScope: () => createScope,
|
24
24
|
provide: () => provide,
|
25
|
+
resolveList: () => resolveList,
|
26
|
+
resolveMap: () => resolveMap,
|
25
27
|
scoped: () => scoped,
|
26
|
-
select: () => select,
|
27
28
|
singleton: () => singleton,
|
28
29
|
transient: () => transient
|
29
30
|
});
|
@@ -31,57 +32,29 @@ module.exports = __toCommonJS(src_exports);
|
|
31
32
|
|
32
33
|
// src/helpers.ts
|
33
34
|
var once = (fn) => {
|
34
|
-
let
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
var createMockMap = (entries = []) => {
|
43
|
-
const map = (provider) => {
|
44
|
-
var _a;
|
45
|
-
return ((_a = entries.find((e) => e[0] === provider)) == null ? void 0 : _a[1]) || provider;
|
46
|
-
};
|
47
|
-
const add = (provider, replacement) => {
|
48
|
-
const newEntries = entries.map(
|
49
|
-
(e) => e[0] === provider ? [e[0], replacement] : e
|
50
|
-
);
|
51
|
-
if (newEntries.length === entries.length)
|
52
|
-
newEntries.push([provider, replacement]);
|
53
|
-
return createMockMap(newEntries);
|
54
|
-
};
|
55
|
-
const apply = (otherMockMap) => createMockMap([
|
56
|
-
...entries.filter(
|
57
|
-
(e) => otherMockMap.entries.find((oe) => oe[0] === e[0]) === void 0
|
58
|
-
),
|
59
|
-
...otherMockMap.entries
|
60
|
-
]);
|
61
|
-
return { entries, map, add, apply };
|
35
|
+
let returned = false;
|
36
|
+
let result;
|
37
|
+
return Object.assign((...args) => {
|
38
|
+
if (returned) return result;
|
39
|
+
result = fn(...args);
|
40
|
+
returned = true;
|
41
|
+
return result;
|
42
|
+
}, fn);
|
62
43
|
};
|
63
44
|
|
64
45
|
// src/provider.ts
|
65
|
-
var provide = (lifetime, resolver
|
66
|
-
const getSelf = once(() =>
|
67
|
-
const originalResolver = resolver;
|
46
|
+
var provide = (lifetime, resolver) => {
|
47
|
+
const getSelf = once(() => resolve);
|
68
48
|
resolver = lifetime === "singleton" ? once(resolver) : resolver;
|
69
|
-
const resolve = (
|
70
|
-
|
71
|
-
const
|
72
|
-
if (
|
73
|
-
|
74
|
-
scope.
|
49
|
+
const resolve = (context) => {
|
50
|
+
var _a;
|
51
|
+
const maybeOwnMock = (_a = context == null ? void 0 : context.mocks) == null ? void 0 : _a.get(getSelf());
|
52
|
+
if (maybeOwnMock) return maybeOwnMock(context);
|
53
|
+
if (lifetime !== "scoped" || !(context == null ? void 0 : context.scope)) return resolver(context);
|
54
|
+
const resolution = context.scope.has(getSelf()) ? context.scope.get(getSelf()) : resolver(context);
|
55
|
+
context.scope.set(getSelf(), resolution);
|
75
56
|
return resolution;
|
76
57
|
};
|
77
|
-
const mock = (dependencyProvider, replacement) => provide(
|
78
|
-
lifetime,
|
79
|
-
originalResolver,
|
80
|
-
mockMap.add(dependencyProvider, replacement)
|
81
|
-
);
|
82
|
-
const properties = {
|
83
|
-
mock
|
84
|
-
};
|
85
58
|
return getSelf();
|
86
59
|
};
|
87
60
|
var transient = (resolver) => provide("transient", resolver);
|
@@ -89,33 +62,74 @@ var singleton = (resolver) => provide("singleton", resolver);
|
|
89
62
|
var scoped = (resolver) => provide("scoped", resolver);
|
90
63
|
|
91
64
|
// src/scope.ts
|
92
|
-
var createScope = () => /* @__PURE__ */ new
|
65
|
+
var createScope = () => /* @__PURE__ */ new Map();
|
93
66
|
|
94
|
-
// src/
|
95
|
-
var
|
96
|
-
const
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
67
|
+
// src/readonly-map.ts
|
68
|
+
var createImmutableMap = (entries = []) => {
|
69
|
+
const get = (key) => {
|
70
|
+
var _a;
|
71
|
+
return (_a = entries.find((entry) => entry[0] === key)) == null ? void 0 : _a[1];
|
72
|
+
};
|
73
|
+
const set = (key, value) => {
|
74
|
+
if (get(key) !== void 0) {
|
75
|
+
const newEntries2 = entries.map(
|
76
|
+
(entry) => entry[0] === key ? [entry[0], value] : entry
|
77
|
+
);
|
78
|
+
return createImmutableMap(newEntries2);
|
79
|
+
}
|
80
|
+
const newEntries = [...entries, [key, value]];
|
81
|
+
return createImmutableMap(newEntries);
|
103
82
|
};
|
104
|
-
const
|
105
|
-
const newEntries =
|
106
|
-
(
|
107
|
-
|
108
|
-
|
83
|
+
const merge = (other) => {
|
84
|
+
const newEntries = [
|
85
|
+
...entries.filter((entry) => other.get(entry[0]) === void 0),
|
86
|
+
...other.entries
|
87
|
+
];
|
88
|
+
return createImmutableMap(newEntries);
|
109
89
|
};
|
110
|
-
return Object.
|
90
|
+
return Object.freeze({
|
91
|
+
entries,
|
92
|
+
get,
|
93
|
+
set,
|
94
|
+
merge
|
95
|
+
});
|
96
|
+
};
|
97
|
+
|
98
|
+
// src/mock-map.ts
|
99
|
+
var createMockMap = () => createImmutableMap();
|
100
|
+
|
101
|
+
// src/collection-resolution.ts
|
102
|
+
var resolveList = (providers, context) => {
|
103
|
+
const resolutions = providers.map((provider) => provider(context));
|
104
|
+
return resolutions.some((resolution) => resolution instanceof Promise) ? Promise.all(resolutions) : resolutions;
|
105
|
+
};
|
106
|
+
var resolveMap = (providers, context) => {
|
107
|
+
let resolutionMapEntries = Object.entries(providers).map(
|
108
|
+
([key, provider]) => [key, provider(context)]
|
109
|
+
);
|
110
|
+
if (resolutionMapEntries.some(
|
111
|
+
([, resolution]) => resolution instanceof Promise
|
112
|
+
)) {
|
113
|
+
return (async () => {
|
114
|
+
resolutionMapEntries = await Promise.all(
|
115
|
+
resolutionMapEntries.map(async ([key, resolution]) => [
|
116
|
+
key,
|
117
|
+
await resolution
|
118
|
+
])
|
119
|
+
);
|
120
|
+
return Object.fromEntries(resolutionMapEntries);
|
121
|
+
})();
|
122
|
+
}
|
123
|
+
return Object.fromEntries(resolutionMapEntries);
|
111
124
|
};
|
112
125
|
// Annotate the CommonJS export names for ESM import in node:
|
113
126
|
0 && (module.exports = {
|
114
127
|
createMockMap,
|
115
128
|
createScope,
|
116
129
|
provide,
|
130
|
+
resolveList,
|
131
|
+
resolveMap,
|
117
132
|
scoped,
|
118
|
-
select,
|
119
133
|
singleton,
|
120
134
|
transient
|
121
135
|
});
|
package/dist/index.js.map
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/helpers.ts","../src/mock-map.ts","../src/provider.ts","../src/scope.ts","../src/selection.ts"],"sourcesContent":["export * from \"./provider\";\nexport * from \"./scope\";\nexport * from \"./selection\";\nexport * from \"./mock-map\";\n","/**\n * Creates a function that will invoke the provided function `fn` only once,\n * caching the result for subsequent calls with the same arguments.\n *\n * @param fn - The function to invoke once and cache the result.\n * @returns A new function that returns the cached result after the first call.\n */\nexport const once = <A extends any[], R>(fn: (...args: A) => R) => {\n let cachedResult: R | undefined;\n\n return Object.assign(\n (...args: A) => cachedResult ?? (cachedResult = fn(...args)),\n fn,\n );\n};\n","import { Provider } from \"./provider\";\n\ntype MockMapEntries = [Provider<any>, Provider<any>][];\n\n/**\n * Stores and provides provider mocks.\n */\nexport type MockMap = {\n entries: MockMapEntries;\n\n /**\n * Returns the provider's mock or the provider itself\n * depending on the presence of the mock.\n *\n * @param provider - An original provider whose mock is needed to get.\n *\n * @returns The passed provider or its mock.\n */\n map<T>(provider: Provider<T>): Provider<T>;\n\n /**\n * Registers a mock provider and retursns a new mock map with that mock.\n *\n * @param provider - An original provider.\n * @param replacement - A provider that will be a mock of the first provider.\n *\n * @returns A new mock map with added mock.\n */\n add<T>(provider: Provider<T>, replacement: Provider<T>): MockMap;\n\n /**\n * Applies mocks from another map to the current one and returns a new map.\n * If there are identical keys (original providers),\n * they will be overwritten by mocks from the other map.\n *\n * @param otherMockMap - A mock map that will be applied.\n *\n * @returns A new mock map with applied mocks.\n */\n apply(otherMockMap: MockMap): MockMap;\n};\n\n/**\n * Creates a new mock map that stores and provides provider mocks.\n *\n * @param entries - Entries of a mock map.\n *\n * @returns A new mock map.\n */\nexport const createMockMap = (entries: MockMapEntries = []) => {\n const map: MockMap[\"map\"] = (provider) =>\n entries.find((e) => e[0] === provider)?.[1] || provider;\n\n const add: MockMap[\"add\"] = (provider, replacement) => {\n const newEntries: MockMapEntries = entries.map((e) =>\n e[0] === provider ? [e[0], replacement] : e,\n );\n\n if (newEntries.length === entries.length)\n newEntries.push([provider, replacement]);\n\n return createMockMap(newEntries);\n };\n\n const apply: MockMap[\"apply\"] = (otherMockMap) =>\n createMockMap([\n ...entries.filter(\n (e) =>\n otherMockMap.entries.find((oe) => oe[0] === e[0]) ===\n undefined,\n ),\n ...otherMockMap.entries,\n ]);\n\n return { entries, map, add, apply };\n};\n","import { once } from \"./helpers\";\nimport { Scope } from \"./scope\";\nimport { createMockMap, MockMap } from \"./mock-map\";\n\n/**\n * Calls a resolver(factory) with an optional scope and a mock map\n * and returns an instance.\n *\n * A passed scope will be propagated up a graph and will be passed\n * to all scoped providers to resolve their instance within this scope.\n * If a provider is scoped, it will either create a new instance\n * and store it in the scope, or retrieve an already created instance\n * from the scope.\n *\n * It is also possible to explicitly pass a mock map, but It's not recommended.\n * If you want to mock(replace) providers for a resolution,\n * it's best to use `mock` method.\n */\ntype ProviderCallable<T> = (scope?: Scope, mockMap?: MockMap) => T;\n\n/**\n * Instance factory with lifetime and dynamic context.\n */\nexport type Provider<T> = ProviderCallable<T> & {\n /**\n * Mocks(replaces) a provider within the visible graph,\n * returning a new provider with that mock.\n *\n * @param dependencyProvider A provider used by the current provider\n * that needs to be replaced.\n * @param replacement A provider with a same interface\n * that will be a replacement for the first one.\n *\n * @returns A new provider with the mocked dependency provider.\n */\n mock<U>(\n dependencyProvider: Provider<U>,\n replacement: Provider<U>,\n ): Provider<T>;\n};\n\ntype Lifetime = \"transient\" | \"singleton\" | \"scoped\";\n\n/**\n * A function that resolves an instance of a passed provider.\n * It's needed to resolve correct instance in a scope\n * and to use mock of the passed provider, if any.\n */\ntype UseFn = <T>(provider: Provider<T>) => T;\n\n/**\n * A function that creates an instance by resolving its dependencies.\n * If there are dependencies, you must use `use` function passed\n * in the first argument.\n */\ntype Resolver<T> = (use: UseFn) => T;\n\n/**\n * Creates a new provider, instance factory with lifetime and dynamic context.\n *\n * @param lifetime - Instance lifetime.\n *\n * @param resolver - A function that creates an instance\n * by resolving its dependencies\n * If there are dependencies, you must use `use` function passed\n * in the first argument.\n *\n * @param mockMap - An optional mock map. Not recommended to specify explicitly,\n * use `mock` method to mock providers.\n *\n * @returns A new provider.\n */\nexport const provide = <T>(\n /**\n * Instance lifetime. Can be `\"transient\"`, `\"singleton\"` or `\"scoped\"`.\n *\n * If `\"transient\"`, will return a new instance on each resolution.\n *\n * If `\"singleton\"`, will create an instance once and return it on every request.\n *\n * If `\"scoped\"`, will save the instance in scope on first resolution\n * and will retrieve it from scope on next resolutions.\n * If scope was not specified, will create a new instance on each resolution.\n */\n lifetime: Lifetime,\n\n /**\n * A function that creates an instance by resolving its dependencies.\n * If there are dependencies, you must use `use` function passed\n * in the first argument.\n */\n resolver: Resolver<T>,\n\n /**\n * An optional mock map. Not recommended to specify explicitly,\n * use `mock` method to mock providers.\n */\n mockMap: MockMap = createMockMap(),\n): Provider<T> => {\n type ProviderType = Provider<T>;\n\n const getSelf = once(() => Object.assign(resolve, properties));\n\n const originalResolver = resolver;\n resolver = lifetime === \"singleton\" ? once(resolver) : resolver;\n\n const resolve: ProviderCallable<T> = (scope, requestMockMap) => {\n const currentMockMap = requestMockMap\n ? mockMap.apply(requestMockMap)\n : mockMap;\n\n const use: UseFn = (provider) =>\n currentMockMap.map(provider)(scope, currentMockMap);\n\n if (lifetime !== \"scoped\" || !scope) return resolver(use);\n\n const resolution = scope.get(getSelf()) || resolver(use);\n scope.set(getSelf(), resolution);\n\n return resolution;\n };\n\n const mock: ProviderType[\"mock\"] = (dependencyProvider, replacement) =>\n provide(\n lifetime,\n originalResolver,\n mockMap.add(dependencyProvider, replacement),\n );\n\n const properties = {\n mock,\n };\n\n return getSelf();\n};\n\n/**\n * Creates a new transient provider.\n * This provider will return a new instance on each resolution.\n *\n * @param resolver - A function that creates an instance\n * by resolving its dependencies\n * If there are dependencies, you must use `use` function passed\n * in the first argument.\n *\n * @returns A new transient provider.\n */\nexport const transient = <T>(resolver: Resolver<T>) =>\n provide(\"transient\", resolver);\n\n/**\n * Creates a new singleton provider.\n * This provider will create an instance once and return it on every request.\n *\n * @param resolver - A function that creates an instance\n * by resolving its dependencies\n * If there are dependencies, you must use `use` function passed\n * in the first argument.\n *\n * @returns A new singleton provider.\n */\nexport const singleton = <T>(resolver: Resolver<T>) =>\n provide(\"singleton\", resolver);\n\n/**\n * Creates a new transient provider.\n * This provider will save the instance in scope on first resolution\n * and will retrieve it from scope on next resolutions.\n * If scope was not specified, will create a new instance on each resolution.\n *\n * @param resolver - A function that creates an instance\n * by resolving its dependencies\n * If there are dependencies, you must use `use` function passed\n * in the first argument.\n *\n * @returns A new scoped provider.\n */\nexport const scoped = <T>(resolver: Resolver<T>) => provide(\"scoped\", resolver);\n","import { Provider } from \"./provider\";\n\n/**\n * A map of providers to their instances.\n * Passed to the provider call to resolve instances\n * of scoped providers within it.\n */\nexport type Scope = WeakMap<Provider<any>, any>;\n\n/**\n * Creates a new scope, map of providers to their instances.\n * Scope is passed to the provider call to resolve instances\n * of scoped providers within it.\n *\n * @returns A new scope.\n */\nexport const createScope = (): Scope => new WeakMap();\n","import { Provider } from \"./provider\";\nimport { Scope } from \"./scope\";\nimport { MockMap } from \"./mock-map\";\n\n/**\n * A map of string keys to providers.\n */\ntype ProviderMap = Record<string, Provider<any>>;\n\ntype InferProviderMapOutputs<Providers extends ProviderMap> = {\n [K in keyof Providers]: Providers[K] extends Provider<infer T> ? T : never;\n};\n\n/**\n * Resolves all providers in a `ProviderMap` and\n * returns an object containing their instances.\n *\n * @param scope - An optional scope to use for scoped providers.\n * @param mockMap - An optional mock map to use for mocking providers.\n *\n * @returns An object containing the resolved instances of the providers.\n */\ntype ProviderSelectionCallable<Providers extends ProviderMap> = (\n scope?: Scope,\n mockMap?: MockMap,\n) => InferProviderMapOutputs<Providers>;\n\n/**\n * A selection of providers.\n *\n * @property map - The `ProviderMap` that the selection is based on.\n * @property mock - A function that mocks a provider within the selection,\n * returning a new `ProviderSelection` with the mock applied.\n */\nexport type ProviderSelection<Providers extends ProviderMap> =\n ProviderSelectionCallable<Providers> & {\n /**\n * The `ProviderMap` that the selection is based on.\n */\n map: Providers;\n /**\n * Mocks a provider within the selection, returning a new\n * `ProviderSelection` with the mock applied.\n *\n * @param dependencyProvider - A provider used by the current provider\n * that needs to be replaced.\n * @param replacement - A provider with a same interface that will be\n * a replacement for the first one.\n *\n * @returns A new `ProviderSelection` with the mocked provider.\n */\n mock<T>(\n dependencyProvider: Provider<T>,\n replacement: Provider<T>,\n ): ProviderSelection<Providers>;\n };\n\n/**\n * Creates a new provider selection from a provider map.\n *\n * @param map - A map of string keys to providers.\n *\n * @returns A new provider selection.\n */\nexport const select = <Providers extends ProviderMap>(\n map: Providers,\n): ProviderSelection<Providers> => {\n type SelectionType = ProviderSelection<Providers>;\n\n const resolveAll: ProviderSelectionCallable<Providers> = (\n scope,\n mockMap,\n ) => {\n const resultEntries = Object.entries(map).map(([key, provider]) =>\n mockMap\n ? [key, mockMap.map(provider)(scope, mockMap)]\n : [key, provider(scope, mockMap)],\n );\n\n return Object.fromEntries(\n resultEntries,\n ) as InferProviderMapOutputs<Providers>;\n };\n\n const mock: SelectionType[\"mock\"] = (dependencyProvider, replacement) => {\n const newEntries = Object.entries(map).map(([key, provider]) =>\n provider === dependencyProvider\n ? [key, replacement]\n : [key, provider.mock(dependencyProvider, replacement)],\n );\n\n return select(Object.fromEntries(newEntries) as Providers);\n };\n\n return Object.assign(resolveAll, { map, mock });\n};\n"],"mappings":"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","names":[]}
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/helpers.ts","../src/provider.ts","../src/scope.ts","../src/readonly-map.ts","../src/mock-map.ts","../src/collection-resolution.ts"],"sourcesContent":["export * from \"./provider\";\nexport * from \"./scope\";\nexport * from \"./mock-map\";\nexport * from \"./collection-resolution\";\n","/**\n * Creates a function that will invoke the provided function `fn` only once,\n * caching the result for subsequent calls with the same arguments.\n *\n * @returns A new function that returns the cached result after the first call.\n */\nexport const once = <A extends any[], R>(\n /**\n * The function to invoke once and cache the result.\n */\n fn: (...args: A) => R,\n) => {\n let returned = false;\n let result: R | undefined;\n\n return Object.assign((...args: A): R => {\n if (returned) return result!;\n\n result = fn(...args);\n returned = true;\n\n return result;\n }, fn);\n};\n","import { once } from \"./helpers\";\nimport { MockMap } from \"./mock-map\";\nimport { Scope } from \"./scope\";\n\n/**\n * A wrapper around the resolver for contextual dependency resolution.\n *\n * Resolves an instance by calling a resolver\n * with a resolution context that will be propagated\n * throughout a dependency tree.\n *\n * When passing a scope it will try to get an instance from it\n * or create a new one and put it there.\n *\n * When passing mocks, it will try to get its own mock version,\n * and if there is one, it will use it instead of itself.\n */\nexport type Provider<T> = (context?: ResolutionContext) => T;\n\n/**\n * A resolution lifetime.\n *\n * Passed when creating a provider to determine its behavior.\n *\n * `\"transient\"` doesn't provide any modifications to a resolver behaviour,\n * so the resolver will create a new instance on each request.\n *\n * `\"singleton\"` forces the resolver to create an instance once\n * and return it in subsequent requests.\n *\n * `\"scoped\"` forces the resolver to take its instance from a provided scope\n * or create a new one and save it if there is none.\n * If no scope is passed, it will create a new instance on each request.\n */\nexport type Lifetime = \"transient\" | \"singleton\" | \"scoped\";\n\n/**\n * A function that creates an instance using a resolution context.\n */\nexport type Resolver<T> = (context?: ResolutionContext) => T;\n\n/**\n * An object that holds information about a scope and provider mocks.\n *\n * Passed to the provider call to resolve scope instances and mock providers.\n */\nexport type ResolutionContext = {\n scope?: Scope;\n mocks?: MockMap;\n};\n\n/**\n * Creates a provider instance,\n * a wrapper around a resolver for contextual dependency resolution.\n *\n * @param lifetime\n * A resolution lifetime.\n *\n * `\"transient\"` doesn't provide any modifications to a resolver behaviour,\n * so the resolver will create a new instance on each request.\n *\n * `\"singleton\"` forces the resolver to create an instance once\n * and return it in subsequent requests.\n *\n * `\"scoped\"` forces the resolver to take its resolution from a provided scope\n * or create a new one and save it if there is none.\n * If no scope is passed, it will create a new instance on each request.\n *\n * @param resolver\n * The function that creates an instance using a resolution context.\n *\n * @returns The provider instance.\n */\nexport const provide = <T>(\n lifetime: Lifetime,\n resolver: Resolver<T>,\n): Provider<T> => {\n const getSelf = once(() => resolve);\n\n resolver = lifetime === \"singleton\" ? once(resolver) : resolver;\n\n const resolve: Provider<T> = (context) => {\n const maybeOwnMock = context?.mocks?.get(getSelf());\n if (maybeOwnMock) return maybeOwnMock(context);\n\n if (lifetime !== \"scoped\" || !context?.scope) return resolver(context);\n\n const resolution = context.scope.has(getSelf())\n ? context.scope.get(getSelf())\n : resolver(context);\n context.scope.set(getSelf(), resolution);\n\n return resolution;\n };\n\n return getSelf();\n};\n\n/**\n * Creates a transient provider instance,\n * a wrapper around a resolver for contextual dependency resolution\n * that will create a new instance on each request.\n *\n * @param resolver\n * The function that creates an instance using a resolution context.\n *\n * @returns The transient provider instance.\n */\nexport const transient = <T>(resolver: Resolver<T>) =>\n provide(\"transient\", resolver);\n\n/**\n * Creates a transient provider instance,\n * a wrapper around a resolver for contextual dependency resolution\n * that will create an instance once and return it in subsequent requests.\n *\n * @param resolver\n * The function that creates an instance using a resolution context.\n *\n * @returns The singleton provider instance.\n */\nexport const singleton = <T>(resolver: Resolver<T>) =>\n provide(\"singleton\", resolver);\n\n/**\n * Creates a transient provider instance,\n * a wrapper around a resolver for contextual dependency resolution\n * that will take its resolution from a provided scope\n * or create a new one and save it if there is none.\n * If no scope is passed, it will create a new instance on each request.\n *\n * @param resolver\n * The function that creates an instance using a resolution context.\n *\n * @returns The scoped provider instance.\n */\nexport const scoped = <T>(resolver: Resolver<T>) => provide(\"scoped\", resolver);\n","import { Provider } from \"./provider\";\n\n/**\n * A map of providers to their instances.\n *\n * Passed to a provider call in a resolution context object\n * to resolve instances of scoped providers within it.\n * ```ts\n * const scope = createScope()\n * provider({ scope })\n * ```\n */\nexport type Scope = Map<Provider<any>, any>;\n\n/**\n * Creates a scope instance.\n *\n * Scope is passed to a provider call in a resolution context object\n * to resolve instances of scoped providers within it.\n * ```ts\n * const scope = createScope()\n * provider({ scope })\n * ```\n *\n * @returns The scope instance.\n */\nexport const createScope = (): Scope => new Map();\n","export type Entry<K, V> = [K, V];\nexport type Entries<K, V> = Entry<K, V>[];\n\n/**\n * An immutable map. It's similar to `Map`,\n * but with reduced functionality and readonly builder behavior.\n */\nexport type ImmutableMap<K, V> = {\n /**\n * Map's entries.\n */\n readonly entries: Entries<K, V>;\n\n /**\n * Retrieves a possibly existing value under a key.\n *\n * @param key - The key associated with the value.\n *\n * @returns The value or undefined.\n */\n get(key: K): V | undefined;\n\n /**\n * Sets a value under a key.\n *\n * @param key - The key that will be associated with the value.\n * @param value - The value to set.\n *\n * @returns A modified immutable map with the value being set in it.\n */\n set(key: K, value: V): ImmutableMap<K, V>;\n\n /**\n * Merges two immutable maps. If there're any matching keys,\n * values from the second map will override values from the first map.\n *\n * @param other The second immutable map.\n *\n * @returns A new immutable map as a result of merging two maps.\n */\n merge(other: ImmutableMap<K, V>): ImmutableMap<K, V>;\n};\n\n/**\n * Creates an immutable map. It's similar to `Map`,\n * but with reduced functionality and readonly builder behavior.\n *\n * @param entries - Map's entries.\n *\n * @returns The immutable map.\n */\nexport const createImmutableMap = <K, V>(\n entries: Entries<K, V> = [],\n): ImmutableMap<K, V> => {\n const get = (key: K) => entries.find((entry) => entry[0] === key)?.[1];\n\n const set = (key: K, value: V) => {\n if (get(key) !== undefined) {\n const newEntries: Entries<K, V> = entries.map((entry) =>\n entry[0] === key ? [entry[0], value] : entry,\n );\n\n return createImmutableMap(newEntries);\n }\n\n const newEntries: Entries<K, V> = [...entries, [key, value]];\n\n return createImmutableMap(newEntries);\n };\n\n const merge = (other: ImmutableMap<K, V>) => {\n const newEntries: Entries<K, V> = [\n ...entries.filter((entry) => other.get(entry[0]) === undefined),\n ...other.entries,\n ];\n\n return createImmutableMap(newEntries);\n };\n\n return Object.freeze({\n entries,\n get,\n set,\n merge,\n });\n};\n","import { Provider } from \"./provider\";\nimport { createImmutableMap, ImmutableMap } from \"./readonly-map\";\n\n/**\n * A map of providers to their compatible versions.\n *\n * Passed to a provider call in a resolution context object\n * in order to replace providers with their mocks.\n * ```ts\n * const mocks = createMockMap().set(otherProvider, otherProviderMock)\n * provider({ mocks })\n * ```\n */\nexport type MockMap = ImmutableMap<Provider<any>, Provider<any>>;\n\n/**\n * Creates a mock map instance.\n *\n * Passed to a provider call in a resolution context object\n * in order to replace providers with their mocks.\n * ```ts\n * const mocks = createMockMap().set(otherProvider, otherProviderMock)\n * provider({ mocks })\n * ```\n *\n * @returns The mock map instance.\n */\nexport const createMockMap = (): MockMap => createImmutableMap();\n","import { Provider, ResolutionContext } from \"./provider\";\n\ntype ProviderList = Provider<any>[];\ntype ProviderRecord = Record<string, Provider<any>>;\n\ntype InferProviderCollectionResolutions<\n Providers extends ProviderList | ProviderRecord,\n> = {\n [K in keyof Providers]: Providers[K] extends Provider<infer T> ? T : never;\n};\n\n/**\n * Awaits all promises and wraps the collection in a promise\n * if there'ss at least one `Promise` in the collection,\n * otherwise returns an untouched type.\n */\ntype AwaitAllValuesInCollection<T extends any[] | Record<any, any>> =\n Promise<any> extends T[keyof T]\n ? Promise<{\n [I in keyof T]: T[I] extends Promise<infer T> ? T : T[I];\n }>\n : T;\n\n/**\n * Calls every provider in a list with a provided resolution context\n * and returns a list of resolutions. Returns a promise of a list\n * of awaited resolutions if there's at least one promise in the resolutions.\n *\n * @param providers - The list of providers.\n * @param context - The resolution context.\n *\n * @returns The list of resolutions.\n */\nexport const resolveList = <const Providers extends ProviderList>(\n providers: Providers,\n context?: ResolutionContext,\n): AwaitAllValuesInCollection<\n InferProviderCollectionResolutions<Providers>\n> => {\n const resolutions = providers.map((provider) => provider(context));\n\n return (\n resolutions.some((resolution) => resolution instanceof Promise)\n ? Promise.all(resolutions)\n : resolutions\n ) as any;\n};\n\n/**\n * Calls every provider in a map with a provided resolution context\n * and returns a map with identical keys but with resolutions in values instead.\n * Returns a promise of a map of awaited resolutions if there's at least one\n * promise in the resolutions.\n *\n * @param providers - The map of providers.\n * @param context - The resolution context.\n *\n * @returns The map of resolutions.\n */\nexport const resolveMap = <const Providers extends ProviderRecord>(\n providers: Providers,\n context?: ResolutionContext,\n): AwaitAllValuesInCollection<\n InferProviderCollectionResolutions<Providers>\n> => {\n let resolutionMapEntries = Object.entries(providers).map(\n ([key, provider]) => [key, provider(context)],\n );\n\n if (\n resolutionMapEntries.some(\n ([, resolution]) => resolution instanceof Promise,\n )\n ) {\n return (async () => {\n resolutionMapEntries = await Promise.all(\n resolutionMapEntries.map(async ([key, resolution]) => [\n key,\n await resolution,\n ]),\n );\n\n return Object.fromEntries(resolutionMapEntries);\n })() as any;\n }\n\n return Object.fromEntries(resolutionMapEntries);\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACMO,IAAM,OAAO,CAIhB,OACC;AACD,MAAI,WAAW;AACf,MAAI;AAEJ,SAAO,OAAO,OAAO,IAAI,SAAe;AACpC,QAAI,SAAU,QAAO;AAErB,aAAS,GAAG,GAAG,IAAI;AACnB,eAAW;AAEX,WAAO;AAAA,EACX,GAAG,EAAE;AACT;;;ACkDO,IAAM,UAAU,CACnB,UACA,aACc;AACd,QAAM,UAAU,KAAK,MAAM,OAAO;AAElC,aAAW,aAAa,cAAc,KAAK,QAAQ,IAAI;AAEvD,QAAM,UAAuB,CAAC,YAAY;AAjF9C;AAkFQ,UAAM,gBAAe,wCAAS,UAAT,mBAAgB,IAAI,QAAQ;AACjD,QAAI,aAAc,QAAO,aAAa,OAAO;AAE7C,QAAI,aAAa,YAAY,EAAC,mCAAS,OAAO,QAAO,SAAS,OAAO;AAErE,UAAM,aAAa,QAAQ,MAAM,IAAI,QAAQ,CAAC,IACxC,QAAQ,MAAM,IAAI,QAAQ,CAAC,IAC3B,SAAS,OAAO;AACtB,YAAQ,MAAM,IAAI,QAAQ,GAAG,UAAU;AAEvC,WAAO;AAAA,EACX;AAEA,SAAO,QAAQ;AACnB;AAYO,IAAM,YAAY,CAAI,aACzB,QAAQ,aAAa,QAAQ;AAY1B,IAAM,YAAY,CAAI,aACzB,QAAQ,aAAa,QAAQ;AAc1B,IAAM,SAAS,CAAI,aAA0B,QAAQ,UAAU,QAAQ;;;AC9GvE,IAAM,cAAc,MAAa,oBAAI,IAAI;;;ACyBzC,IAAM,qBAAqB,CAC9B,UAAyB,CAAC,MACL;AACrB,QAAM,MAAM,CAAC,QAAQ;AAtDzB;AAsD4B,yBAAQ,KAAK,CAAC,UAAU,MAAM,CAAC,MAAM,GAAG,MAAxC,mBAA4C;AAAA;AAEpE,QAAM,MAAM,CAAC,KAAQ,UAAa;AAC9B,QAAI,IAAI,GAAG,MAAM,QAAW;AACxB,YAAMA,cAA4B,QAAQ;AAAA,QAAI,CAAC,UAC3C,MAAM,CAAC,MAAM,MAAM,CAAC,MAAM,CAAC,GAAG,KAAK,IAAI;AAAA,MAC3C;AAEA,aAAO,mBAAmBA,WAAU;AAAA,IACxC;AAEA,UAAM,aAA4B,CAAC,GAAG,SAAS,CAAC,KAAK,KAAK,CAAC;AAE3D,WAAO,mBAAmB,UAAU;AAAA,EACxC;AAEA,QAAM,QAAQ,CAAC,UAA8B;AACzC,UAAM,aAA4B;AAAA,MAC9B,GAAG,QAAQ,OAAO,CAAC,UAAU,MAAM,IAAI,MAAM,CAAC,CAAC,MAAM,MAAS;AAAA,MAC9D,GAAG,MAAM;AAAA,IACb;AAEA,WAAO,mBAAmB,UAAU;AAAA,EACxC;AAEA,SAAO,OAAO,OAAO;AAAA,IACjB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACJ,CAAC;AACL;;;AC1DO,IAAM,gBAAgB,MAAe,mBAAmB;;;ACMxD,IAAM,cAAc,CACvB,WACA,YAGC;AACD,QAAM,cAAc,UAAU,IAAI,CAAC,aAAa,SAAS,OAAO,CAAC;AAEjE,SACI,YAAY,KAAK,CAAC,eAAe,sBAAsB,OAAO,IACxD,QAAQ,IAAI,WAAW,IACvB;AAEd;AAaO,IAAM,aAAa,CACtB,WACA,YAGC;AACD,MAAI,uBAAuB,OAAO,QAAQ,SAAS,EAAE;AAAA,IACjD,CAAC,CAAC,KAAK,QAAQ,MAAM,CAAC,KAAK,SAAS,OAAO,CAAC;AAAA,EAChD;AAEA,MACI,qBAAqB;AAAA,IACjB,CAAC,CAAC,EAAE,UAAU,MAAM,sBAAsB;AAAA,EAC9C,GACF;AACE,YAAQ,YAAY;AAChB,6BAAuB,MAAM,QAAQ;AAAA,QACjC,qBAAqB,IAAI,OAAO,CAAC,KAAK,UAAU,MAAM;AAAA,UAClD;AAAA,UACA,MAAM;AAAA,QACV,CAAC;AAAA,MACL;AAEA,aAAO,OAAO,YAAY,oBAAoB;AAAA,IAClD,GAAG;AAAA,EACP;AAEA,SAAO,OAAO,YAAY,oBAAoB;AAClD;","names":["newEntries"]}
|
package/dist/index.mjs
CHANGED
@@ -1,56 +1,28 @@
|
|
1
1
|
// src/helpers.ts
|
2
2
|
var once = (fn) => {
|
3
|
-
let
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
var createMockMap = (entries = []) => {
|
12
|
-
const map = (provider) => {
|
13
|
-
var _a;
|
14
|
-
return ((_a = entries.find((e) => e[0] === provider)) == null ? void 0 : _a[1]) || provider;
|
15
|
-
};
|
16
|
-
const add = (provider, replacement) => {
|
17
|
-
const newEntries = entries.map(
|
18
|
-
(e) => e[0] === provider ? [e[0], replacement] : e
|
19
|
-
);
|
20
|
-
if (newEntries.length === entries.length)
|
21
|
-
newEntries.push([provider, replacement]);
|
22
|
-
return createMockMap(newEntries);
|
23
|
-
};
|
24
|
-
const apply = (otherMockMap) => createMockMap([
|
25
|
-
...entries.filter(
|
26
|
-
(e) => otherMockMap.entries.find((oe) => oe[0] === e[0]) === void 0
|
27
|
-
),
|
28
|
-
...otherMockMap.entries
|
29
|
-
]);
|
30
|
-
return { entries, map, add, apply };
|
3
|
+
let returned = false;
|
4
|
+
let result;
|
5
|
+
return Object.assign((...args) => {
|
6
|
+
if (returned) return result;
|
7
|
+
result = fn(...args);
|
8
|
+
returned = true;
|
9
|
+
return result;
|
10
|
+
}, fn);
|
31
11
|
};
|
32
12
|
|
33
13
|
// src/provider.ts
|
34
|
-
var provide = (lifetime, resolver
|
35
|
-
const getSelf = once(() =>
|
36
|
-
const originalResolver = resolver;
|
14
|
+
var provide = (lifetime, resolver) => {
|
15
|
+
const getSelf = once(() => resolve);
|
37
16
|
resolver = lifetime === "singleton" ? once(resolver) : resolver;
|
38
|
-
const resolve = (
|
39
|
-
|
40
|
-
const
|
41
|
-
if (
|
42
|
-
|
43
|
-
scope.
|
17
|
+
const resolve = (context) => {
|
18
|
+
var _a;
|
19
|
+
const maybeOwnMock = (_a = context == null ? void 0 : context.mocks) == null ? void 0 : _a.get(getSelf());
|
20
|
+
if (maybeOwnMock) return maybeOwnMock(context);
|
21
|
+
if (lifetime !== "scoped" || !(context == null ? void 0 : context.scope)) return resolver(context);
|
22
|
+
const resolution = context.scope.has(getSelf()) ? context.scope.get(getSelf()) : resolver(context);
|
23
|
+
context.scope.set(getSelf(), resolution);
|
44
24
|
return resolution;
|
45
25
|
};
|
46
|
-
const mock = (dependencyProvider, replacement) => provide(
|
47
|
-
lifetime,
|
48
|
-
originalResolver,
|
49
|
-
mockMap.add(dependencyProvider, replacement)
|
50
|
-
);
|
51
|
-
const properties = {
|
52
|
-
mock
|
53
|
-
};
|
54
26
|
return getSelf();
|
55
27
|
};
|
56
28
|
var transient = (resolver) => provide("transient", resolver);
|
@@ -58,32 +30,73 @@ var singleton = (resolver) => provide("singleton", resolver);
|
|
58
30
|
var scoped = (resolver) => provide("scoped", resolver);
|
59
31
|
|
60
32
|
// src/scope.ts
|
61
|
-
var createScope = () => /* @__PURE__ */ new
|
33
|
+
var createScope = () => /* @__PURE__ */ new Map();
|
62
34
|
|
63
|
-
// src/
|
64
|
-
var
|
65
|
-
const
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
35
|
+
// src/readonly-map.ts
|
36
|
+
var createImmutableMap = (entries = []) => {
|
37
|
+
const get = (key) => {
|
38
|
+
var _a;
|
39
|
+
return (_a = entries.find((entry) => entry[0] === key)) == null ? void 0 : _a[1];
|
40
|
+
};
|
41
|
+
const set = (key, value) => {
|
42
|
+
if (get(key) !== void 0) {
|
43
|
+
const newEntries2 = entries.map(
|
44
|
+
(entry) => entry[0] === key ? [entry[0], value] : entry
|
45
|
+
);
|
46
|
+
return createImmutableMap(newEntries2);
|
47
|
+
}
|
48
|
+
const newEntries = [...entries, [key, value]];
|
49
|
+
return createImmutableMap(newEntries);
|
72
50
|
};
|
73
|
-
const
|
74
|
-
const newEntries =
|
75
|
-
(
|
76
|
-
|
77
|
-
|
51
|
+
const merge = (other) => {
|
52
|
+
const newEntries = [
|
53
|
+
...entries.filter((entry) => other.get(entry[0]) === void 0),
|
54
|
+
...other.entries
|
55
|
+
];
|
56
|
+
return createImmutableMap(newEntries);
|
78
57
|
};
|
79
|
-
return Object.
|
58
|
+
return Object.freeze({
|
59
|
+
entries,
|
60
|
+
get,
|
61
|
+
set,
|
62
|
+
merge
|
63
|
+
});
|
64
|
+
};
|
65
|
+
|
66
|
+
// src/mock-map.ts
|
67
|
+
var createMockMap = () => createImmutableMap();
|
68
|
+
|
69
|
+
// src/collection-resolution.ts
|
70
|
+
var resolveList = (providers, context) => {
|
71
|
+
const resolutions = providers.map((provider) => provider(context));
|
72
|
+
return resolutions.some((resolution) => resolution instanceof Promise) ? Promise.all(resolutions) : resolutions;
|
73
|
+
};
|
74
|
+
var resolveMap = (providers, context) => {
|
75
|
+
let resolutionMapEntries = Object.entries(providers).map(
|
76
|
+
([key, provider]) => [key, provider(context)]
|
77
|
+
);
|
78
|
+
if (resolutionMapEntries.some(
|
79
|
+
([, resolution]) => resolution instanceof Promise
|
80
|
+
)) {
|
81
|
+
return (async () => {
|
82
|
+
resolutionMapEntries = await Promise.all(
|
83
|
+
resolutionMapEntries.map(async ([key, resolution]) => [
|
84
|
+
key,
|
85
|
+
await resolution
|
86
|
+
])
|
87
|
+
);
|
88
|
+
return Object.fromEntries(resolutionMapEntries);
|
89
|
+
})();
|
90
|
+
}
|
91
|
+
return Object.fromEntries(resolutionMapEntries);
|
80
92
|
};
|
81
93
|
export {
|
82
94
|
createMockMap,
|
83
95
|
createScope,
|
84
96
|
provide,
|
97
|
+
resolveList,
|
98
|
+
resolveMap,
|
85
99
|
scoped,
|
86
|
-
select,
|
87
100
|
singleton,
|
88
101
|
transient
|
89
102
|
};
|
package/dist/index.mjs.map
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"sources":["../src/helpers.ts","../src/mock-map.ts","../src/provider.ts","../src/scope.ts","../src/selection.ts"],"sourcesContent":["/**\n * Creates a function that will invoke the provided function `fn` only once,\n * caching the result for subsequent calls with the same arguments.\n *\n * @param fn - The function to invoke once and cache the result.\n * @returns A new function that returns the cached result after the first call.\n */\nexport const once = <A extends any[], R>(fn: (...args: A) => R) => {\n let cachedResult: R | undefined;\n\n return Object.assign(\n (...args: A) => cachedResult ?? (cachedResult = fn(...args)),\n fn,\n );\n};\n","import { Provider } from \"./provider\";\n\ntype MockMapEntries = [Provider<any>, Provider<any>][];\n\n/**\n * Stores and provides provider mocks.\n */\nexport type MockMap = {\n entries: MockMapEntries;\n\n /**\n * Returns the provider's mock or the provider itself\n * depending on the presence of the mock.\n *\n * @param provider - An original provider whose mock is needed to get.\n *\n * @returns The passed provider or its mock.\n */\n map<T>(provider: Provider<T>): Provider<T>;\n\n /**\n * Registers a mock provider and retursns a new mock map with that mock.\n *\n * @param provider - An original provider.\n * @param replacement - A provider that will be a mock of the first provider.\n *\n * @returns A new mock map with added mock.\n */\n add<T>(provider: Provider<T>, replacement: Provider<T>): MockMap;\n\n /**\n * Applies mocks from another map to the current one and returns a new map.\n * If there are identical keys (original providers),\n * they will be overwritten by mocks from the other map.\n *\n * @param otherMockMap - A mock map that will be applied.\n *\n * @returns A new mock map with applied mocks.\n */\n apply(otherMockMap: MockMap): MockMap;\n};\n\n/**\n * Creates a new mock map that stores and provides provider mocks.\n *\n * @param entries - Entries of a mock map.\n *\n * @returns A new mock map.\n */\nexport const createMockMap = (entries: MockMapEntries = []) => {\n const map: MockMap[\"map\"] = (provider) =>\n entries.find((e) => e[0] === provider)?.[1] || provider;\n\n const add: MockMap[\"add\"] = (provider, replacement) => {\n const newEntries: MockMapEntries = entries.map((e) =>\n e[0] === provider ? [e[0], replacement] : e,\n );\n\n if (newEntries.length === entries.length)\n newEntries.push([provider, replacement]);\n\n return createMockMap(newEntries);\n };\n\n const apply: MockMap[\"apply\"] = (otherMockMap) =>\n createMockMap([\n ...entries.filter(\n (e) =>\n otherMockMap.entries.find((oe) => oe[0] === e[0]) ===\n undefined,\n ),\n ...otherMockMap.entries,\n ]);\n\n return { entries, map, add, apply };\n};\n","import { once } from \"./helpers\";\nimport { Scope } from \"./scope\";\nimport { createMockMap, MockMap } from \"./mock-map\";\n\n/**\n * Calls a resolver(factory) with an optional scope and a mock map\n * and returns an instance.\n *\n * A passed scope will be propagated up a graph and will be passed\n * to all scoped providers to resolve their instance within this scope.\n * If a provider is scoped, it will either create a new instance\n * and store it in the scope, or retrieve an already created instance\n * from the scope.\n *\n * It is also possible to explicitly pass a mock map, but It's not recommended.\n * If you want to mock(replace) providers for a resolution,\n * it's best to use `mock` method.\n */\ntype ProviderCallable<T> = (scope?: Scope, mockMap?: MockMap) => T;\n\n/**\n * Instance factory with lifetime and dynamic context.\n */\nexport type Provider<T> = ProviderCallable<T> & {\n /**\n * Mocks(replaces) a provider within the visible graph,\n * returning a new provider with that mock.\n *\n * @param dependencyProvider A provider used by the current provider\n * that needs to be replaced.\n * @param replacement A provider with a same interface\n * that will be a replacement for the first one.\n *\n * @returns A new provider with the mocked dependency provider.\n */\n mock<U>(\n dependencyProvider: Provider<U>,\n replacement: Provider<U>,\n ): Provider<T>;\n};\n\ntype Lifetime = \"transient\" | \"singleton\" | \"scoped\";\n\n/**\n * A function that resolves an instance of a passed provider.\n * It's needed to resolve correct instance in a scope\n * and to use mock of the passed provider, if any.\n */\ntype UseFn = <T>(provider: Provider<T>) => T;\n\n/**\n * A function that creates an instance by resolving its dependencies.\n * If there are dependencies, you must use `use` function passed\n * in the first argument.\n */\ntype Resolver<T> = (use: UseFn) => T;\n\n/**\n * Creates a new provider, instance factory with lifetime and dynamic context.\n *\n * @param lifetime - Instance lifetime.\n *\n * @param resolver - A function that creates an instance\n * by resolving its dependencies\n * If there are dependencies, you must use `use` function passed\n * in the first argument.\n *\n * @param mockMap - An optional mock map. Not recommended to specify explicitly,\n * use `mock` method to mock providers.\n *\n * @returns A new provider.\n */\nexport const provide = <T>(\n /**\n * Instance lifetime. Can be `\"transient\"`, `\"singleton\"` or `\"scoped\"`.\n *\n * If `\"transient\"`, will return a new instance on each resolution.\n *\n * If `\"singleton\"`, will create an instance once and return it on every request.\n *\n * If `\"scoped\"`, will save the instance in scope on first resolution\n * and will retrieve it from scope on next resolutions.\n * If scope was not specified, will create a new instance on each resolution.\n */\n lifetime: Lifetime,\n\n /**\n * A function that creates an instance by resolving its dependencies.\n * If there are dependencies, you must use `use` function passed\n * in the first argument.\n */\n resolver: Resolver<T>,\n\n /**\n * An optional mock map. Not recommended to specify explicitly,\n * use `mock` method to mock providers.\n */\n mockMap: MockMap = createMockMap(),\n): Provider<T> => {\n type ProviderType = Provider<T>;\n\n const getSelf = once(() => Object.assign(resolve, properties));\n\n const originalResolver = resolver;\n resolver = lifetime === \"singleton\" ? once(resolver) : resolver;\n\n const resolve: ProviderCallable<T> = (scope, requestMockMap) => {\n const currentMockMap = requestMockMap\n ? mockMap.apply(requestMockMap)\n : mockMap;\n\n const use: UseFn = (provider) =>\n currentMockMap.map(provider)(scope, currentMockMap);\n\n if (lifetime !== \"scoped\" || !scope) return resolver(use);\n\n const resolution = scope.get(getSelf()) || resolver(use);\n scope.set(getSelf(), resolution);\n\n return resolution;\n };\n\n const mock: ProviderType[\"mock\"] = (dependencyProvider, replacement) =>\n provide(\n lifetime,\n originalResolver,\n mockMap.add(dependencyProvider, replacement),\n );\n\n const properties = {\n mock,\n };\n\n return getSelf();\n};\n\n/**\n * Creates a new transient provider.\n * This provider will return a new instance on each resolution.\n *\n * @param resolver - A function that creates an instance\n * by resolving its dependencies\n * If there are dependencies, you must use `use` function passed\n * in the first argument.\n *\n * @returns A new transient provider.\n */\nexport const transient = <T>(resolver: Resolver<T>) =>\n provide(\"transient\", resolver);\n\n/**\n * Creates a new singleton provider.\n * This provider will create an instance once and return it on every request.\n *\n * @param resolver - A function that creates an instance\n * by resolving its dependencies\n * If there are dependencies, you must use `use` function passed\n * in the first argument.\n *\n * @returns A new singleton provider.\n */\nexport const singleton = <T>(resolver: Resolver<T>) =>\n provide(\"singleton\", resolver);\n\n/**\n * Creates a new transient provider.\n * This provider will save the instance in scope on first resolution\n * and will retrieve it from scope on next resolutions.\n * If scope was not specified, will create a new instance on each resolution.\n *\n * @param resolver - A function that creates an instance\n * by resolving its dependencies\n * If there are dependencies, you must use `use` function passed\n * in the first argument.\n *\n * @returns A new scoped provider.\n */\nexport const scoped = <T>(resolver: Resolver<T>) => provide(\"scoped\", resolver);\n","import { Provider } from \"./provider\";\n\n/**\n * A map of providers to their instances.\n * Passed to the provider call to resolve instances\n * of scoped providers within it.\n */\nexport type Scope = WeakMap<Provider<any>, any>;\n\n/**\n * Creates a new scope, map of providers to their instances.\n * Scope is passed to the provider call to resolve instances\n * of scoped providers within it.\n *\n * @returns A new scope.\n */\nexport const createScope = (): Scope => new WeakMap();\n","import { Provider } from \"./provider\";\nimport { Scope } from \"./scope\";\nimport { MockMap } from \"./mock-map\";\n\n/**\n * A map of string keys to providers.\n */\ntype ProviderMap = Record<string, Provider<any>>;\n\ntype InferProviderMapOutputs<Providers extends ProviderMap> = {\n [K in keyof Providers]: Providers[K] extends Provider<infer T> ? T : never;\n};\n\n/**\n * Resolves all providers in a `ProviderMap` and\n * returns an object containing their instances.\n *\n * @param scope - An optional scope to use for scoped providers.\n * @param mockMap - An optional mock map to use for mocking providers.\n *\n * @returns An object containing the resolved instances of the providers.\n */\ntype ProviderSelectionCallable<Providers extends ProviderMap> = (\n scope?: Scope,\n mockMap?: MockMap,\n) => InferProviderMapOutputs<Providers>;\n\n/**\n * A selection of providers.\n *\n * @property map - The `ProviderMap` that the selection is based on.\n * @property mock - A function that mocks a provider within the selection,\n * returning a new `ProviderSelection` with the mock applied.\n */\nexport type ProviderSelection<Providers extends ProviderMap> =\n ProviderSelectionCallable<Providers> & {\n /**\n * The `ProviderMap` that the selection is based on.\n */\n map: Providers;\n /**\n * Mocks a provider within the selection, returning a new\n * `ProviderSelection` with the mock applied.\n *\n * @param dependencyProvider - A provider used by the current provider\n * that needs to be replaced.\n * @param replacement - A provider with a same interface that will be\n * a replacement for the first one.\n *\n * @returns A new `ProviderSelection` with the mocked provider.\n */\n mock<T>(\n dependencyProvider: Provider<T>,\n replacement: Provider<T>,\n ): ProviderSelection<Providers>;\n };\n\n/**\n * Creates a new provider selection from a provider map.\n *\n * @param map - A map of string keys to providers.\n *\n * @returns A new provider selection.\n */\nexport const select = <Providers extends ProviderMap>(\n map: Providers,\n): ProviderSelection<Providers> => {\n type SelectionType = ProviderSelection<Providers>;\n\n const resolveAll: ProviderSelectionCallable<Providers> = (\n scope,\n mockMap,\n ) => {\n const resultEntries = Object.entries(map).map(([key, provider]) =>\n mockMap\n ? [key, mockMap.map(provider)(scope, mockMap)]\n : [key, provider(scope, mockMap)],\n );\n\n return Object.fromEntries(\n resultEntries,\n ) as InferProviderMapOutputs<Providers>;\n };\n\n const mock: SelectionType[\"mock\"] = (dependencyProvider, replacement) => {\n const newEntries = Object.entries(map).map(([key, provider]) =>\n provider === dependencyProvider\n ? [key, replacement]\n : [key, provider.mock(dependencyProvider, replacement)],\n );\n\n return select(Object.fromEntries(newEntries) as Providers);\n };\n\n return Object.assign(resolveAll, { map, mock });\n};\n"],"mappings":"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","names":[]}
|
1
|
+
{"version":3,"sources":["../src/helpers.ts","../src/provider.ts","../src/scope.ts","../src/readonly-map.ts","../src/mock-map.ts","../src/collection-resolution.ts"],"sourcesContent":["/**\n * Creates a function that will invoke the provided function `fn` only once,\n * caching the result for subsequent calls with the same arguments.\n *\n * @returns A new function that returns the cached result after the first call.\n */\nexport const once = <A extends any[], R>(\n /**\n * The function to invoke once and cache the result.\n */\n fn: (...args: A) => R,\n) => {\n let returned = false;\n let result: R | undefined;\n\n return Object.assign((...args: A): R => {\n if (returned) return result!;\n\n result = fn(...args);\n returned = true;\n\n return result;\n }, fn);\n};\n","import { once } from \"./helpers\";\nimport { MockMap } from \"./mock-map\";\nimport { Scope } from \"./scope\";\n\n/**\n * A wrapper around the resolver for contextual dependency resolution.\n *\n * Resolves an instance by calling a resolver\n * with a resolution context that will be propagated\n * throughout a dependency tree.\n *\n * When passing a scope it will try to get an instance from it\n * or create a new one and put it there.\n *\n * When passing mocks, it will try to get its own mock version,\n * and if there is one, it will use it instead of itself.\n */\nexport type Provider<T> = (context?: ResolutionContext) => T;\n\n/**\n * A resolution lifetime.\n *\n * Passed when creating a provider to determine its behavior.\n *\n * `\"transient\"` doesn't provide any modifications to a resolver behaviour,\n * so the resolver will create a new instance on each request.\n *\n * `\"singleton\"` forces the resolver to create an instance once\n * and return it in subsequent requests.\n *\n * `\"scoped\"` forces the resolver to take its instance from a provided scope\n * or create a new one and save it if there is none.\n * If no scope is passed, it will create a new instance on each request.\n */\nexport type Lifetime = \"transient\" | \"singleton\" | \"scoped\";\n\n/**\n * A function that creates an instance using a resolution context.\n */\nexport type Resolver<T> = (context?: ResolutionContext) => T;\n\n/**\n * An object that holds information about a scope and provider mocks.\n *\n * Passed to the provider call to resolve scope instances and mock providers.\n */\nexport type ResolutionContext = {\n scope?: Scope;\n mocks?: MockMap;\n};\n\n/**\n * Creates a provider instance,\n * a wrapper around a resolver for contextual dependency resolution.\n *\n * @param lifetime\n * A resolution lifetime.\n *\n * `\"transient\"` doesn't provide any modifications to a resolver behaviour,\n * so the resolver will create a new instance on each request.\n *\n * `\"singleton\"` forces the resolver to create an instance once\n * and return it in subsequent requests.\n *\n * `\"scoped\"` forces the resolver to take its resolution from a provided scope\n * or create a new one and save it if there is none.\n * If no scope is passed, it will create a new instance on each request.\n *\n * @param resolver\n * The function that creates an instance using a resolution context.\n *\n * @returns The provider instance.\n */\nexport const provide = <T>(\n lifetime: Lifetime,\n resolver: Resolver<T>,\n): Provider<T> => {\n const getSelf = once(() => resolve);\n\n resolver = lifetime === \"singleton\" ? once(resolver) : resolver;\n\n const resolve: Provider<T> = (context) => {\n const maybeOwnMock = context?.mocks?.get(getSelf());\n if (maybeOwnMock) return maybeOwnMock(context);\n\n if (lifetime !== \"scoped\" || !context?.scope) return resolver(context);\n\n const resolution = context.scope.has(getSelf())\n ? context.scope.get(getSelf())\n : resolver(context);\n context.scope.set(getSelf(), resolution);\n\n return resolution;\n };\n\n return getSelf();\n};\n\n/**\n * Creates a transient provider instance,\n * a wrapper around a resolver for contextual dependency resolution\n * that will create a new instance on each request.\n *\n * @param resolver\n * The function that creates an instance using a resolution context.\n *\n * @returns The transient provider instance.\n */\nexport const transient = <T>(resolver: Resolver<T>) =>\n provide(\"transient\", resolver);\n\n/**\n * Creates a transient provider instance,\n * a wrapper around a resolver for contextual dependency resolution\n * that will create an instance once and return it in subsequent requests.\n *\n * @param resolver\n * The function that creates an instance using a resolution context.\n *\n * @returns The singleton provider instance.\n */\nexport const singleton = <T>(resolver: Resolver<T>) =>\n provide(\"singleton\", resolver);\n\n/**\n * Creates a transient provider instance,\n * a wrapper around a resolver for contextual dependency resolution\n * that will take its resolution from a provided scope\n * or create a new one and save it if there is none.\n * If no scope is passed, it will create a new instance on each request.\n *\n * @param resolver\n * The function that creates an instance using a resolution context.\n *\n * @returns The scoped provider instance.\n */\nexport const scoped = <T>(resolver: Resolver<T>) => provide(\"scoped\", resolver);\n","import { Provider } from \"./provider\";\n\n/**\n * A map of providers to their instances.\n *\n * Passed to a provider call in a resolution context object\n * to resolve instances of scoped providers within it.\n * ```ts\n * const scope = createScope()\n * provider({ scope })\n * ```\n */\nexport type Scope = Map<Provider<any>, any>;\n\n/**\n * Creates a scope instance.\n *\n * Scope is passed to a provider call in a resolution context object\n * to resolve instances of scoped providers within it.\n * ```ts\n * const scope = createScope()\n * provider({ scope })\n * ```\n *\n * @returns The scope instance.\n */\nexport const createScope = (): Scope => new Map();\n","export type Entry<K, V> = [K, V];\nexport type Entries<K, V> = Entry<K, V>[];\n\n/**\n * An immutable map. It's similar to `Map`,\n * but with reduced functionality and readonly builder behavior.\n */\nexport type ImmutableMap<K, V> = {\n /**\n * Map's entries.\n */\n readonly entries: Entries<K, V>;\n\n /**\n * Retrieves a possibly existing value under a key.\n *\n * @param key - The key associated with the value.\n *\n * @returns The value or undefined.\n */\n get(key: K): V | undefined;\n\n /**\n * Sets a value under a key.\n *\n * @param key - The key that will be associated with the value.\n * @param value - The value to set.\n *\n * @returns A modified immutable map with the value being set in it.\n */\n set(key: K, value: V): ImmutableMap<K, V>;\n\n /**\n * Merges two immutable maps. If there're any matching keys,\n * values from the second map will override values from the first map.\n *\n * @param other The second immutable map.\n *\n * @returns A new immutable map as a result of merging two maps.\n */\n merge(other: ImmutableMap<K, V>): ImmutableMap<K, V>;\n};\n\n/**\n * Creates an immutable map. It's similar to `Map`,\n * but with reduced functionality and readonly builder behavior.\n *\n * @param entries - Map's entries.\n *\n * @returns The immutable map.\n */\nexport const createImmutableMap = <K, V>(\n entries: Entries<K, V> = [],\n): ImmutableMap<K, V> => {\n const get = (key: K) => entries.find((entry) => entry[0] === key)?.[1];\n\n const set = (key: K, value: V) => {\n if (get(key) !== undefined) {\n const newEntries: Entries<K, V> = entries.map((entry) =>\n entry[0] === key ? [entry[0], value] : entry,\n );\n\n return createImmutableMap(newEntries);\n }\n\n const newEntries: Entries<K, V> = [...entries, [key, value]];\n\n return createImmutableMap(newEntries);\n };\n\n const merge = (other: ImmutableMap<K, V>) => {\n const newEntries: Entries<K, V> = [\n ...entries.filter((entry) => other.get(entry[0]) === undefined),\n ...other.entries,\n ];\n\n return createImmutableMap(newEntries);\n };\n\n return Object.freeze({\n entries,\n get,\n set,\n merge,\n });\n};\n","import { Provider } from \"./provider\";\nimport { createImmutableMap, ImmutableMap } from \"./readonly-map\";\n\n/**\n * A map of providers to their compatible versions.\n *\n * Passed to a provider call in a resolution context object\n * in order to replace providers with their mocks.\n * ```ts\n * const mocks = createMockMap().set(otherProvider, otherProviderMock)\n * provider({ mocks })\n * ```\n */\nexport type MockMap = ImmutableMap<Provider<any>, Provider<any>>;\n\n/**\n * Creates a mock map instance.\n *\n * Passed to a provider call in a resolution context object\n * in order to replace providers with their mocks.\n * ```ts\n * const mocks = createMockMap().set(otherProvider, otherProviderMock)\n * provider({ mocks })\n * ```\n *\n * @returns The mock map instance.\n */\nexport const createMockMap = (): MockMap => createImmutableMap();\n","import { Provider, ResolutionContext } from \"./provider\";\n\ntype ProviderList = Provider<any>[];\ntype ProviderRecord = Record<string, Provider<any>>;\n\ntype InferProviderCollectionResolutions<\n Providers extends ProviderList | ProviderRecord,\n> = {\n [K in keyof Providers]: Providers[K] extends Provider<infer T> ? T : never;\n};\n\n/**\n * Awaits all promises and wraps the collection in a promise\n * if there'ss at least one `Promise` in the collection,\n * otherwise returns an untouched type.\n */\ntype AwaitAllValuesInCollection<T extends any[] | Record<any, any>> =\n Promise<any> extends T[keyof T]\n ? Promise<{\n [I in keyof T]: T[I] extends Promise<infer T> ? T : T[I];\n }>\n : T;\n\n/**\n * Calls every provider in a list with a provided resolution context\n * and returns a list of resolutions. Returns a promise of a list\n * of awaited resolutions if there's at least one promise in the resolutions.\n *\n * @param providers - The list of providers.\n * @param context - The resolution context.\n *\n * @returns The list of resolutions.\n */\nexport const resolveList = <const Providers extends ProviderList>(\n providers: Providers,\n context?: ResolutionContext,\n): AwaitAllValuesInCollection<\n InferProviderCollectionResolutions<Providers>\n> => {\n const resolutions = providers.map((provider) => provider(context));\n\n return (\n resolutions.some((resolution) => resolution instanceof Promise)\n ? Promise.all(resolutions)\n : resolutions\n ) as any;\n};\n\n/**\n * Calls every provider in a map with a provided resolution context\n * and returns a map with identical keys but with resolutions in values instead.\n * Returns a promise of a map of awaited resolutions if there's at least one\n * promise in the resolutions.\n *\n * @param providers - The map of providers.\n * @param context - The resolution context.\n *\n * @returns The map of resolutions.\n */\nexport const resolveMap = <const Providers extends ProviderRecord>(\n providers: Providers,\n context?: ResolutionContext,\n): AwaitAllValuesInCollection<\n InferProviderCollectionResolutions<Providers>\n> => {\n let resolutionMapEntries = Object.entries(providers).map(\n ([key, provider]) => [key, provider(context)],\n );\n\n if (\n resolutionMapEntries.some(\n ([, resolution]) => resolution instanceof Promise,\n )\n ) {\n return (async () => {\n resolutionMapEntries = await Promise.all(\n resolutionMapEntries.map(async ([key, resolution]) => [\n key,\n await resolution,\n ]),\n );\n\n return Object.fromEntries(resolutionMapEntries);\n })() as any;\n }\n\n return Object.fromEntries(resolutionMapEntries);\n};\n"],"mappings":"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","names":["newEntries"]}
|