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 CHANGED
@@ -1,216 +1,229 @@
1
+ type Entry<K, V> = [K, V];
2
+ type Entries<K, V> = Entry<K, V>[];
1
3
  /**
2
- * A map of providers to their instances.
3
- * Passed to the provider call to resolve instances
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
- declare const createScope: () => Scope;
15
-
16
- type MockMapEntries = [Provider<any>, Provider<any>][];
17
- /**
18
- * Stores and provides provider mocks.
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
- * Returns the provider's mock or the provider itself
24
- * depending on the presence of the mock.
13
+ * Retrieves a possibly existing value under a key.
25
14
  *
26
- * @param provider - An original provider whose mock is needed to get.
15
+ * @param key - The key associated with the value.
27
16
  *
28
- * @returns The passed provider or its mock.
17
+ * @returns The value or undefined.
29
18
  */
30
- map<T>(provider: Provider<T>): Provider<T>;
19
+ get(key: K): V | undefined;
31
20
  /**
32
- * Registers a mock provider and retursns a new mock map with that mock.
21
+ * Sets a value under a key.
33
22
  *
34
- * @param provider - An original provider.
35
- * @param replacement - A provider that will be a mock of the first provider.
23
+ * @param key - The key that will be associated with the value.
24
+ * @param value - The value to set.
36
25
  *
37
- * @returns A new mock map with added mock.
26
+ * @returns A modified immutable map with the value being set in it.
38
27
  */
39
- add<T>(provider: Provider<T>, replacement: Provider<T>): MockMap;
28
+ set(key: K, value: V): ImmutableMap<K, V>;
40
29
  /**
41
- * Applies mocks from another map to the current one and returns a new map.
42
- * If there are identical keys (original providers),
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 otherMockMap - A mock map that will be applied.
33
+ * @param other The second immutable map.
46
34
  *
47
- * @returns A new mock map with applied mocks.
35
+ * @returns A new immutable map as a result of merging two maps.
48
36
  */
49
- apply(otherMockMap: MockMap): MockMap;
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 new mock map that stores and provides provider mocks.
52
+ * Creates a mock map instance.
53
53
  *
54
- * @param entries - Entries of a mock map.
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 A new mock map.
61
+ * @returns The mock map instance.
57
62
  */
58
- declare const createMockMap: (entries?: MockMapEntries) => {
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
- * Calls a resolver(factory) with an optional scope and a mock map
67
- * and returns an instance.
66
+ * A map of providers to their instances.
68
67
  *
69
- * A passed scope will be propagated up a graph and will be passed
70
- * to all scoped providers to resolve their instance within this scope.
71
- * If a provider is scoped, it will either create a new instance
72
- * and store it in the scope, or retrieve an already created instance
73
- * from the scope.
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
- * It is also possible to explicitly pass a mock map, but It's not recommended.
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
- type ProviderCallable<T> = (scope?: Scope, mockMap?: MockMap) => T;
88
+ declare const createScope: () => Scope;
89
+
80
90
  /**
81
- * Instance factory with lifetime and dynamic context.
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 resolves an instance of a passed provider.
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 UseFn = <T>(provider: Provider<T>) => T;
123
+ type Resolver<T> = (context?: ResolutionContext) => T;
104
124
  /**
105
- * A function that creates an instance by resolving its dependencies.
106
- * If there are dependencies, you must use `use` function passed
107
- * in the first argument.
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 Resolver<T> = (use: UseFn) => T;
129
+ type ResolutionContext = {
130
+ scope?: Scope;
131
+ mocks?: MockMap;
132
+ };
110
133
  /**
111
- * Creates a new provider, instance factory with lifetime and dynamic context.
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
- * @param lifetime - Instance lifetime.
143
+ * `"singleton"` forces the resolver to create an instance once
144
+ * and return it in subsequent requests.
114
145
  *
115
- * @param resolver - A function that creates an instance
116
- * by resolving its dependencies
117
- * If there are dependencies, you must use `use` function passed
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 mockMap - An optional mock map. Not recommended to specify explicitly,
121
- * use `mock` method to mock providers.
150
+ * @param resolver
151
+ * The function that creates an instance using a resolution context.
122
152
  *
123
- * @returns A new provider.
153
+ * @returns The provider instance.
124
154
  */
125
- declare const provide: <T>(lifetime: Lifetime, resolver: Resolver<T>, mockMap?: MockMap) => Provider<T>;
155
+ declare const provide: <T>(lifetime: Lifetime, resolver: Resolver<T>) => Provider<T>;
126
156
  /**
127
- * Creates a new transient provider.
128
- * This provider will return a new instance on each resolution.
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 - A function that creates an instance
131
- * by resolving its dependencies
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 A new transient provider.
164
+ * @returns The transient provider instance.
136
165
  */
137
166
  declare const transient: <T>(resolver: Resolver<T>) => Provider<T>;
138
167
  /**
139
- * Creates a new singleton provider.
140
- * This provider will create an instance once and return it on every request.
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 - A function that creates an instance
143
- * by resolving its dependencies
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 A new singleton provider.
175
+ * @returns The singleton provider instance.
148
176
  */
149
177
  declare const singleton: <T>(resolver: Resolver<T>) => Provider<T>;
150
178
  /**
151
- * Creates a new transient provider.
152
- * This provider will save the instance in scope on first resolution
153
- * and will retrieve it from scope on next resolutions.
154
- * If scope was not specified, will create a new instance on each resolution.
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 - A function that creates an instance
157
- * by resolving its dependencies
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 A new scoped provider.
188
+ * @returns The scoped provider instance.
162
189
  */
163
190
  declare const scoped: <T>(resolver: Resolver<T>) => Provider<T>;
164
191
 
165
- /**
166
- * A map of string keys to providers.
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
- * Resolves all providers in a `ProviderMap` and
174
- * returns an object containing their instances.
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 ProviderSelectionCallable<Providers extends ProviderMap> = (scope?: Scope, mockMap?: MockMap) => InferProviderMapOutputs<Providers>;
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
- * A selection of providers.
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
- * @property map - The `ProviderMap` that the selection is based on.
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
- type ProviderSelection<Providers extends ProviderMap> = ProviderSelectionCallable<Providers> & {
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
- * Creates a new provider selection from a provider map.
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 map - A map of string keys to providers.
222
+ * @param providers - The map of providers.
223
+ * @param context - The resolution context.
211
224
  *
212
- * @returns A new provider selection.
225
+ * @returns The map of resolutions.
213
226
  */
214
- declare const select: <Providers extends ProviderMap>(map: Providers) => ProviderSelection<Providers>;
227
+ declare const resolveMap: <const Providers extends ProviderRecord>(providers: Providers, context?: ResolutionContext) => AwaitAllValuesInCollection<InferProviderCollectionResolutions<Providers>>;
215
228
 
216
- export { type MockMap, type Provider, type ProviderSelection, type Scope, createMockMap, createScope, provide, scoped, select, singleton, transient };
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
- * A map of providers to their instances.
3
- * Passed to the provider call to resolve instances
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
- declare const createScope: () => Scope;
15
-
16
- type MockMapEntries = [Provider<any>, Provider<any>][];
17
- /**
18
- * Stores and provides provider mocks.
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
- * Returns the provider's mock or the provider itself
24
- * depending on the presence of the mock.
13
+ * Retrieves a possibly existing value under a key.
25
14
  *
26
- * @param provider - An original provider whose mock is needed to get.
15
+ * @param key - The key associated with the value.
27
16
  *
28
- * @returns The passed provider or its mock.
17
+ * @returns The value or undefined.
29
18
  */
30
- map<T>(provider: Provider<T>): Provider<T>;
19
+ get(key: K): V | undefined;
31
20
  /**
32
- * Registers a mock provider and retursns a new mock map with that mock.
21
+ * Sets a value under a key.
33
22
  *
34
- * @param provider - An original provider.
35
- * @param replacement - A provider that will be a mock of the first provider.
23
+ * @param key - The key that will be associated with the value.
24
+ * @param value - The value to set.
36
25
  *
37
- * @returns A new mock map with added mock.
26
+ * @returns A modified immutable map with the value being set in it.
38
27
  */
39
- add<T>(provider: Provider<T>, replacement: Provider<T>): MockMap;
28
+ set(key: K, value: V): ImmutableMap<K, V>;
40
29
  /**
41
- * Applies mocks from another map to the current one and returns a new map.
42
- * If there are identical keys (original providers),
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 otherMockMap - A mock map that will be applied.
33
+ * @param other The second immutable map.
46
34
  *
47
- * @returns A new mock map with applied mocks.
35
+ * @returns A new immutable map as a result of merging two maps.
48
36
  */
49
- apply(otherMockMap: MockMap): MockMap;
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 new mock map that stores and provides provider mocks.
52
+ * Creates a mock map instance.
53
53
  *
54
- * @param entries - Entries of a mock map.
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 A new mock map.
61
+ * @returns The mock map instance.
57
62
  */
58
- declare const createMockMap: (entries?: MockMapEntries) => {
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
- * Calls a resolver(factory) with an optional scope and a mock map
67
- * and returns an instance.
66
+ * A map of providers to their instances.
68
67
  *
69
- * A passed scope will be propagated up a graph and will be passed
70
- * to all scoped providers to resolve their instance within this scope.
71
- * If a provider is scoped, it will either create a new instance
72
- * and store it in the scope, or retrieve an already created instance
73
- * from the scope.
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
- * It is also possible to explicitly pass a mock map, but It's not recommended.
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
- type ProviderCallable<T> = (scope?: Scope, mockMap?: MockMap) => T;
88
+ declare const createScope: () => Scope;
89
+
80
90
  /**
81
- * Instance factory with lifetime and dynamic context.
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 resolves an instance of a passed provider.
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 UseFn = <T>(provider: Provider<T>) => T;
123
+ type Resolver<T> = (context?: ResolutionContext) => T;
104
124
  /**
105
- * A function that creates an instance by resolving its dependencies.
106
- * If there are dependencies, you must use `use` function passed
107
- * in the first argument.
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 Resolver<T> = (use: UseFn) => T;
129
+ type ResolutionContext = {
130
+ scope?: Scope;
131
+ mocks?: MockMap;
132
+ };
110
133
  /**
111
- * Creates a new provider, instance factory with lifetime and dynamic context.
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
- * @param lifetime - Instance lifetime.
143
+ * `"singleton"` forces the resolver to create an instance once
144
+ * and return it in subsequent requests.
114
145
  *
115
- * @param resolver - A function that creates an instance
116
- * by resolving its dependencies
117
- * If there are dependencies, you must use `use` function passed
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 mockMap - An optional mock map. Not recommended to specify explicitly,
121
- * use `mock` method to mock providers.
150
+ * @param resolver
151
+ * The function that creates an instance using a resolution context.
122
152
  *
123
- * @returns A new provider.
153
+ * @returns The provider instance.
124
154
  */
125
- declare const provide: <T>(lifetime: Lifetime, resolver: Resolver<T>, mockMap?: MockMap) => Provider<T>;
155
+ declare const provide: <T>(lifetime: Lifetime, resolver: Resolver<T>) => Provider<T>;
126
156
  /**
127
- * Creates a new transient provider.
128
- * This provider will return a new instance on each resolution.
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 - A function that creates an instance
131
- * by resolving its dependencies
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 A new transient provider.
164
+ * @returns The transient provider instance.
136
165
  */
137
166
  declare const transient: <T>(resolver: Resolver<T>) => Provider<T>;
138
167
  /**
139
- * Creates a new singleton provider.
140
- * This provider will create an instance once and return it on every request.
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 - A function that creates an instance
143
- * by resolving its dependencies
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 A new singleton provider.
175
+ * @returns The singleton provider instance.
148
176
  */
149
177
  declare const singleton: <T>(resolver: Resolver<T>) => Provider<T>;
150
178
  /**
151
- * Creates a new transient provider.
152
- * This provider will save the instance in scope on first resolution
153
- * and will retrieve it from scope on next resolutions.
154
- * If scope was not specified, will create a new instance on each resolution.
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 - A function that creates an instance
157
- * by resolving its dependencies
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 A new scoped provider.
188
+ * @returns The scoped provider instance.
162
189
  */
163
190
  declare const scoped: <T>(resolver: Resolver<T>) => Provider<T>;
164
191
 
165
- /**
166
- * A map of string keys to providers.
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
- * Resolves all providers in a `ProviderMap` and
174
- * returns an object containing their instances.
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 ProviderSelectionCallable<Providers extends ProviderMap> = (scope?: Scope, mockMap?: MockMap) => InferProviderMapOutputs<Providers>;
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
- * A selection of providers.
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
- * @property map - The `ProviderMap` that the selection is based on.
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
- type ProviderSelection<Providers extends ProviderMap> = ProviderSelectionCallable<Providers> & {
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
- * Creates a new provider selection from a provider map.
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 map - A map of string keys to providers.
222
+ * @param providers - The map of providers.
223
+ * @param context - The resolution context.
211
224
  *
212
- * @returns A new provider selection.
225
+ * @returns The map of resolutions.
213
226
  */
214
- declare const select: <Providers extends ProviderMap>(map: Providers) => ProviderSelection<Providers>;
227
+ declare const resolveMap: <const Providers extends ProviderRecord>(providers: Providers, context?: ResolutionContext) => AwaitAllValuesInCollection<InferProviderCollectionResolutions<Providers>>;
215
228
 
216
- export { type MockMap, type Provider, type ProviderSelection, type Scope, createMockMap, createScope, provide, scoped, select, singleton, transient };
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 cachedResult;
35
- return Object.assign(
36
- (...args) => cachedResult ?? (cachedResult = fn(...args)),
37
- fn
38
- );
39
- };
40
-
41
- // src/mock-map.ts
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, mockMap = createMockMap()) => {
66
- const getSelf = once(() => Object.assign(resolve, properties));
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 = (scope, requestMockMap) => {
70
- const currentMockMap = requestMockMap ? mockMap.apply(requestMockMap) : mockMap;
71
- const use = (provider) => currentMockMap.map(provider)(scope, currentMockMap);
72
- if (lifetime !== "scoped" || !scope) return resolver(use);
73
- const resolution = scope.get(getSelf()) || resolver(use);
74
- scope.set(getSelf(), resolution);
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 WeakMap();
65
+ var createScope = () => /* @__PURE__ */ new Map();
93
66
 
94
- // src/selection.ts
95
- var select = (map) => {
96
- const resolveAll = (scope, mockMap) => {
97
- const resultEntries = Object.entries(map).map(
98
- ([key, provider]) => mockMap ? [key, mockMap.map(provider)(scope, mockMap)] : [key, provider(scope, mockMap)]
99
- );
100
- return Object.fromEntries(
101
- resultEntries
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 mock = (dependencyProvider, replacement) => {
105
- const newEntries = Object.entries(map).map(
106
- ([key, provider]) => provider === dependencyProvider ? [key, replacement] : [key, provider.mock(dependencyProvider, replacement)]
107
- );
108
- return select(Object.fromEntries(newEntries));
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.assign(resolveAll, { map, mock });
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":"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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 cachedResult;
4
- return Object.assign(
5
- (...args) => cachedResult ?? (cachedResult = fn(...args)),
6
- fn
7
- );
8
- };
9
-
10
- // src/mock-map.ts
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, mockMap = createMockMap()) => {
35
- const getSelf = once(() => Object.assign(resolve, properties));
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 = (scope, requestMockMap) => {
39
- const currentMockMap = requestMockMap ? mockMap.apply(requestMockMap) : mockMap;
40
- const use = (provider) => currentMockMap.map(provider)(scope, currentMockMap);
41
- if (lifetime !== "scoped" || !scope) return resolver(use);
42
- const resolution = scope.get(getSelf()) || resolver(use);
43
- scope.set(getSelf(), resolution);
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 WeakMap();
33
+ var createScope = () => /* @__PURE__ */ new Map();
62
34
 
63
- // src/selection.ts
64
- var select = (map) => {
65
- const resolveAll = (scope, mockMap) => {
66
- const resultEntries = Object.entries(map).map(
67
- ([key, provider]) => mockMap ? [key, mockMap.map(provider)(scope, mockMap)] : [key, provider(scope, mockMap)]
68
- );
69
- return Object.fromEntries(
70
- resultEntries
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 mock = (dependencyProvider, replacement) => {
74
- const newEntries = Object.entries(map).map(
75
- ([key, provider]) => provider === dependencyProvider ? [key, replacement] : [key, provider.mock(dependencyProvider, replacement)]
76
- );
77
- return select(Object.fromEntries(newEntries));
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.assign(resolveAll, { map, mock });
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
  };
@@ -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"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "atomic-di",
3
- "version": "0.7.1-beta.1",
3
+ "version": "0.8.0-beta.1",
4
4
  "description": "A toolset for containerless dependency injection.",
5
5
  "repository": {
6
6
  "type": "git",