atomic-di 0.7.1-beta.1 → 0.8.0-beta.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.
- 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":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACOO,IAAM,OAAO,CAAqB,OAA0B;AAC/D,MAAI;AAEJ,SAAO,OAAO;AAAA,IACV,IAAI,SAAY,iBAAiB,eAAe,GAAG,GAAG,IAAI;AAAA,IAC1D;AAAA,EACJ;AACJ;;;ACmCO,IAAM,gBAAgB,CAAC,UAA0B,CAAC,MAAM;AAC3D,QAAM,MAAsB,CAAC,aAAU;AAlD3C;AAmDQ,0BAAQ,KAAK,CAAC,MAAM,EAAE,CAAC,MAAM,QAAQ,MAArC,mBAAyC,OAAM;AAAA;AAEnD,QAAM,MAAsB,CAAC,UAAU,gBAAgB;AACnD,UAAM,aAA6B,QAAQ;AAAA,MAAI,CAAC,MAC5C,EAAE,CAAC,MAAM,WAAW,CAAC,EAAE,CAAC,GAAG,WAAW,IAAI;AAAA,IAC9C;AAEA,QAAI,WAAW,WAAW,QAAQ;AAC9B,iBAAW,KAAK,CAAC,UAAU,WAAW,CAAC;AAE3C,WAAO,cAAc,UAAU;AAAA,EACnC;AAEA,QAAM,QAA0B,CAAC,iBAC7B,cAAc;AAAA,IACV,GAAG,QAAQ;AAAA,MACP,CAAC,MACG,aAAa,QAAQ,KAAK,CAAC,OAAO,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,MAChD;AAAA,IACR;AAAA,IACA,GAAG,aAAa;AAAA,EACpB,CAAC;AAEL,SAAO,EAAE,SAAS,KAAK,KAAK,MAAM;AACtC;;;ACHO,IAAM,UAAU,CAYnB,UAOA,UAMA,UAAmB,cAAc,MACnB;AAGd,QAAM,UAAU,KAAK,MAAM,OAAO,OAAO,SAAS,UAAU,CAAC;AAE7D,QAAM,mBAAmB;AACzB,aAAW,aAAa,cAAc,KAAK,QAAQ,IAAI;AAEvD,QAAM,UAA+B,CAAC,OAAO,mBAAmB;AAC5D,UAAM,iBAAiB,iBACjB,QAAQ,MAAM,cAAc,IAC5B;AAEN,UAAM,MAAa,CAAC,aAChB,eAAe,IAAI,QAAQ,EAAE,OAAO,cAAc;AAEtD,QAAI,aAAa,YAAY,CAAC,MAAO,QAAO,SAAS,GAAG;AAExD,UAAM,aAAa,MAAM,IAAI,QAAQ,CAAC,KAAK,SAAS,GAAG;AACvD,UAAM,IAAI,QAAQ,GAAG,UAAU;AAE/B,WAAO;AAAA,EACX;AAEA,QAAM,OAA6B,CAAC,oBAAoB,gBACpD;AAAA,IACI;AAAA,IACA;AAAA,IACA,QAAQ,IAAI,oBAAoB,WAAW;AAAA,EAC/C;AAEJ,QAAM,aAAa;AAAA,IACf;AAAA,EACJ;AAEA,SAAO,QAAQ;AACnB;AAaO,IAAM,YAAY,CAAI,aACzB,QAAQ,aAAa,QAAQ;AAa1B,IAAM,YAAY,CAAI,aACzB,QAAQ,aAAa,QAAQ;AAe1B,IAAM,SAAS,CAAI,aAA0B,QAAQ,UAAU,QAAQ;;;ACjKvE,IAAM,cAAc,MAAa,oBAAI,QAAQ;;;ACgD7C,IAAM,SAAS,CAClB,QAC+B;AAG/B,QAAM,aAAmD,CACrD,OACA,YACC;AACD,UAAM,gBAAgB,OAAO,QAAQ,GAAG,EAAE;AAAA,MAAI,CAAC,CAAC,KAAK,QAAQ,MACzD,UACM,CAAC,KAAK,QAAQ,IAAI,QAAQ,EAAE,OAAO,OAAO,CAAC,IAC3C,CAAC,KAAK,SAAS,OAAO,OAAO,CAAC;AAAA,IACxC;AAEA,WAAO,OAAO;AAAA,MACV;AAAA,IACJ;AAAA,EACJ;AAEA,QAAM,OAA8B,CAAC,oBAAoB,gBAAgB;AACrE,UAAM,aAAa,OAAO,QAAQ,GAAG,EAAE;AAAA,MAAI,CAAC,CAAC,KAAK,QAAQ,MACtD,aAAa,qBACP,CAAC,KAAK,WAAW,IACjB,CAAC,KAAK,SAAS,KAAK,oBAAoB,WAAW,CAAC;AAAA,IAC9D;AAEA,WAAO,OAAO,OAAO,YAAY,UAAU,CAAc;AAAA,EAC7D;AAEA,SAAO,OAAO,OAAO,YAAY,EAAE,KAAK,KAAK,CAAC;AAClD;","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":"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","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"]}
|