atomic-di 0.9.1-beta.4 → 1.0.0-rc.1

Sign up to get free protection for your applications and to get access to all the features.
package/dist/index.d.ts CHANGED
@@ -1,222 +1,139 @@
1
1
  /**
2
- * A map of providers to providers of the same type.
3
- * Lifetime is not a part of `Provider` type, so you can use
4
- * a different one if necessary.
5
- *
6
- * Passed to a provider call in a resolution context object
2
+ * A `Map` of providers to providers of the same type
3
+ * which is then passed to a provider call in a resolution context object
7
4
  * in order to replace providers with their mocks.
8
- * ```ts
9
- * const otherProvider =
10
- * transitive(() => ...)
11
- * const otherProviderMock: typeof otherProvider =
12
- * scoped(() => ...)
13
- *
14
- * const mocks = createMockMap()
15
- * mocks.set(otherProvider, otherProviderMock)
16
- *
17
- * provider({ mocks })
18
- * ```
19
5
  */
20
- type MockMap = Omit<Map<Provider<any>, Provider<any>>, "set" | "get"> & {
6
+ type MockMap = Omit<Map<Resolver<any>, Resolver<any>>, "set" | "get"> & {
21
7
  /**
22
8
  * Sets a mock for a provider.
23
9
  *
24
10
  * @param provider - The original provider.
25
11
  * @param mock - The mock provider.
26
12
  */
27
- set<T>(provider: Provider<T>, mock: Provider<T>): MockMap;
13
+ set<T>(provider: Resolver<T>, mock: Resolver<T>): MockMap;
28
14
  /**
29
15
  * Retrieves a mock of a provider. Returns undefined if there's none.
30
16
  *
31
17
  * @param provider - The provider.
32
18
  */
33
- get<T>(provider: Provider<T>): Provider<T> | undefined;
19
+ get<T>(provider: Resolver<T>): Resolver<T> | undefined;
34
20
  };
35
21
  /**
36
- * Creates a mock map instance,
37
- * a map of providers to providers of the same type.
38
- * Lifetime is not a part of `Provider` type, so you can use
39
- * a different one if necessary.
40
- *
41
- * Passed to a provider call in a resolution context object
22
+ * Creates a `Map` of providers to providers of the same type
23
+ * which is then passed to a provider call in a resolution context object
42
24
  * in order to replace providers with their mocks.
43
- * ```ts
44
- * const otherProvider =
45
- * transitive(() => ...)
46
- * const otherProviderMock: typeof otherProvider =
47
- * scoped(() => ...)
48
25
  *
26
+ * @example
27
+ * ```ts
49
28
  * const mocks = createMockMap()
50
- * mocks.set(otherProvider, otherProviderMock)
29
+ * .set(getConfig, getTestConfig)
51
30
  *
52
- * provider({ mocks })
31
+ * getThing({ mocks })
53
32
  * ```
54
33
  *
55
- * @returns The mock map instance.
34
+ * @returns The map instance.
56
35
  */
57
36
  declare const createMockMap: () => MockMap;
58
37
 
59
38
  /**
60
- * A map of providers to their instances.
61
- *
62
- * Passed to a provider call in a resolution context object
39
+ * A `Map` of providers to their instances
40
+ * that is then passed to a provider call in a resolution context object
63
41
  * to resolve instances of scoped providers within it.
64
- * ```ts
65
- * const scope = createScope()
66
- * provider({ scope })
67
- * ```
68
42
  */
69
- type Scope = Map<Provider<any>, any>;
43
+ type Scope = Map<Resolver<any>, any>;
70
44
  /**
71
- * Creates a scope instance.
72
- *
73
- * Scope is passed to a provider call in a resolution context object
45
+ * Creates a `Map` of providers to their instances
46
+ * that is then passed to a provider call in a resolution context object
74
47
  * to resolve instances of scoped providers within it.
48
+ *
49
+ * @example
75
50
  * ```ts
76
- * const scope = createScope()
77
- * provider({ scope })
51
+ * const requestScope = createScope()
52
+ *
53
+ * app.use(() => {
54
+ * const db = getDb({ scope: requestScope })
55
+ * // ...
56
+ * })
78
57
  * ```
79
58
  *
80
- * @returns The scope instance.
59
+ * @returns The map instance.
81
60
  */
82
61
  declare const createScope: () => Scope;
83
62
 
84
63
  /**
85
- * A wrapper around the resolver(factory) for contextual dependency resolution.
86
- *
87
- * Resolves an instance by calling a resolver
88
- * with an **optional** resolution context that will be propagated
89
- * throughout a dependency tree.
90
- * ```ts
91
- * provider({ scope, mocks })
92
- * ```
93
- *
94
- * When passing a scope it will try to get an instance from it
95
- * or create a new one and put it there.
96
- *
97
- * When passing mocks, it will try to get its own mock version,
98
- * and if there is one, it will use it instead of itself.
99
- */
100
- type Provider<T> = (context?: ResolutionContext) => T;
101
- /**
102
- * A resolution lifetime.
103
- *
104
- * Passed when creating a provider to determine its behavior.
105
- *
106
- * `"transient"` doesn't provide any modifications to a resolver behaviour,
107
- * so the resolver will create a new instance on each request.
108
- *
109
- * `"singleton"` forces the resolver to create an instance once
110
- * and return it in subsequent requests.
111
- *
112
- * `"scoped"` forces the resolver to take its instance from a provided scope
113
- * or create a new one and save it if there is none.
114
- * If no scope is passed, it will create a new instance on each request.
64
+ * A function that returns a value of a particular type
65
+ * with a resolution context being passed to it.
115
66
  */
116
- type Lifetime = "transient" | "singleton" | "scoped";
67
+ type Resolver<T> = (context?: ResolutionContext) => T;
117
68
  /**
118
- * A function that creates an instance using a resolution context.
69
+ * A function that resolves an instance or a `Promise` of a particular type
70
+ * based on a resolution context passed to it.
119
71
  */
120
- type Resolver<T> = (context?: ResolutionContext) => T;
72
+ type Provider<T> = Resolver<T>;
121
73
  /**
122
- * An object that holds information about a scope and provider mocks.
123
- *
124
- * Passed to the provider call to resolve scope instances and mock providers.
74
+ * A context used by providers to resolve instances
75
+ * based on current scope and mocks.
125
76
  */
126
77
  type ResolutionContext = {
127
78
  scope?: Scope;
128
79
  mocks?: MockMap;
129
80
  };
130
81
  /**
131
- * Creates a provider instance,
132
- * a wrapper around a resolver(factory) for contextual dependency resolution.
133
- * ```ts
134
- * const getInstance = provide("transient", () =>
135
- * createInstance(
136
- * getOtherInstance(context)
137
- * )
138
- * )
139
- * ```
140
- *
141
- * @param lifetime
142
- * A resolution lifetime.
143
- *
144
- * `"transient"` doesn't provide any modifications to a resolver behaviour,
145
- * so the resolver will create a new instance on each request.
146
- *
147
- * `"singleton"` forces the resolver to create an instance once
148
- * and return it in subsequent requests.
149
- *
150
- * `"scoped"` forces the resolver to take its resolution from a provided scope
151
- * or create a new one and save it if there is none.
152
- * If no scope is passed, it will create a new instance on each request.
82
+ * Creates a transient provider that will resolve a new instance on each call.
153
83
  *
154
- * @param resolver
155
- * The function that creates an instance using a resolution context.
156
- * If the function calls other providers,
157
- * the context **must** be passed to their calls.
158
- *
159
- * @returns The provider instance.
160
- */
161
- declare const provide: <T>(lifetime: Lifetime, resolver: Resolver<T>) => Provider<T>;
162
- /**
163
- * An alias for `provide("transient", ...)`.
164
- * Creates a transient provider instance,
165
- * a wrapper around a resolver(factory) for contextual dependency resolution
166
- * that will create a new instance on each request.
84
+ * @example
167
85
  * ```ts
168
- * const getInstance = transient((context) =>
169
- * createInstance(...)
170
- * )
171
- *
172
- * getInstance() !== getInstance()
86
+ * const getThing = transient(() => createThing())
87
+ * getThing() !== getThing()
173
88
  * ```
174
89
  *
175
90
  * @param resolver
176
- * The function that creates an instance using a resolution context.
91
+ * A function that returns a value of a particular type
92
+ * with a resolution context being passed to it.
177
93
  *
178
- * @returns The transient provider instance.
94
+ * @returns The transient provider.
179
95
  */
180
96
  declare const transient: <T>(resolver: Resolver<T>) => Provider<T>;
181
97
  /**
182
- * An alias for `provide("singleton", ...)`.
183
- * Creates a transient provider instance,
184
- * a wrapper around a resolver(factory) for contextual dependency resolution
185
- * that will create an instance once and return it in subsequent requests.
186
- * ```ts
187
- * const getInstance = singleton((context) =>
188
- * createInstance(...)
189
- * )
98
+ * Creates a singleton provider that will resolve an instance once
99
+ * and return it on every call.
190
100
  *
191
- * getInstance() === getInstance()
101
+ * @example
102
+ * ```ts
103
+ * const getThing = singleton(() => createThing())
104
+ * getThing() === getThing()
192
105
  * ```
193
106
  *
194
107
  * @param resolver
195
- * The function that creates an instance using a resolution context.
108
+ * A function that returns a value of a particular type
109
+ * with a resolution context being passed to it.
196
110
  *
197
- * @returns The singleton provider instance.
111
+ * @returns The singleton provider.
198
112
  */
199
113
  declare const singleton: <T>(resolver: Resolver<T>) => Provider<T>;
200
114
  /**
201
- * An alias for `provide("scoped", ...)`.
202
- * Creates a transient provider instance,
203
- * a wrapper around a resolver(factory) for contextual dependency resolution
204
- * that will take its resolution from a provided scope
115
+ * Creates a scoped provider that will take its resolution from a passed scope
205
116
  * or create a new one and save it if there is none.
206
- * If no scope is passed, it will create a new instance on each request.
117
+ * If no scope is passed, it will create a new instance on each call.
118
+ *
119
+ * @example
207
120
  * ```ts
208
- * const getInstance = scoped((context) =>
209
- * createInstance(...)
210
- * )
121
+ * const getThing = scoped(() => createThing())
122
+ * getThing() !== getThing()
123
+ * ```
211
124
  *
212
- * getInstance() !== getInstance()
213
- * getInstance({ scope }) === getInstance({ scope })
125
+ * @example
126
+ * ```ts
127
+ * const getThing = scoped(() => createThing())
128
+ * const scope = createScope()
129
+ * getThing({ scope }) === getThing({ scope })
214
130
  * ```
215
131
  *
216
132
  * @param resolver
217
- * The function that creates an instance using a resolution context.
133
+ * A function that returns a value of a particular type
134
+ * with a resolution context being passed to it.
218
135
  *
219
- * @returns The scoped provider instance.
136
+ * @returns The scoped provider.
220
137
  */
221
138
  declare const scoped: <T>(resolver: Resolver<T>) => Provider<T>;
222
139
 
@@ -230,18 +147,52 @@ type InferProviderCollectionResolutions<Providers extends ProviderList | Provide
230
147
  * if there'ss at least one `Promise` in the collection,
231
148
  * otherwise returns an untouched type.
232
149
  */
233
- type AwaitAllValuesInCollection<T extends any[] | Record<any, any>> = Promise<any> extends T[keyof T] ? Promise<{
150
+ type AwaitValuesInCollection<T extends any[] | Record<any, any>> = Promise<any> extends T[keyof T] ? Promise<{
234
151
  [I in keyof T]: T[I] extends Promise<infer T> ? T : T[I];
235
152
  }> : T;
236
153
  /**
237
154
  * Calls every provider in a list with a provided resolution context
238
- * and returns a list of resolutions. Returns a promise of a list
239
- * of awaited resolutions if there's at least one promise in the resolutions.
155
+ * and returns a list of resolutions. Returns a `Promise` of a list
156
+ * of awaited resolutions if there's at least one `Promise` in the resolutions.
157
+ *
158
+ * @example
159
+ * Only sync providers:
240
160
  * ```ts
161
+ * const getA = scoped(() => createA())
162
+ * const getB = scoped(() => createB())
163
+ * const getC = scoped(() => createC())
164
+ *
165
+ * const scope = createScope()
241
166
  * const resolutions = resolveList(
242
167
  * [getA, getB, getC],
243
- * { scope, mocks }
168
+ * { scope }
244
169
  * )
170
+ *
171
+ * resolutions == [
172
+ * getA({ scope }),
173
+ * getB({ scope }),
174
+ * getC({ scope })
175
+ * ]
176
+ * ```
177
+ *
178
+ * @example
179
+ * Some provider is async:
180
+ * ```ts
181
+ * const getA = scoped(() => createA())
182
+ * const getB = scoped(async () => await createB())
183
+ * const getC = scoped(() => createC())
184
+ *
185
+ * const scope = createScope()
186
+ * const resolutions = resolveList(
187
+ * [getA, getB, getC],
188
+ * { scope }
189
+ * )
190
+ *
191
+ * resolutions == [
192
+ * getA({ scope }),
193
+ * await getB({ scope }),
194
+ * getC({ scope })
195
+ * ]
245
196
  * ```
246
197
  *
247
198
  * @param providers - The list of providers.
@@ -249,17 +200,51 @@ type AwaitAllValuesInCollection<T extends any[] | Record<any, any>> = Promise<an
249
200
  *
250
201
  * @returns The list of resolutions.
251
202
  */
252
- declare const resolveList: <const Providers extends ProviderList>(providers: Providers, context?: ResolutionContext) => AwaitAllValuesInCollection<InferProviderCollectionResolutions<Providers>>;
203
+ declare const resolveList: <const Providers extends ProviderList>(providers: Providers, context?: ResolutionContext) => AwaitValuesInCollection<InferProviderCollectionResolutions<Providers>>;
253
204
  /**
254
205
  * Calls every provider in a map with a provided resolution context
255
206
  * and returns a map with identical keys but with resolutions in values instead.
256
- * Returns a promise of a map of awaited resolutions if there's at least one
257
- * promise in the resolutions.
207
+ * Returns a `Promise` of a map of awaited resolutions if there's at least one
208
+ * `Promise` in the resolutions.
209
+ *
210
+ * @example
211
+ * Only sync providers:
258
212
  * ```ts
259
- * const resolutionMap = resolveMap(
213
+ * const getA = scoped(() => createA())
214
+ * const getB = scoped(() => createB())
215
+ * const getC = scoped(() => createC())
216
+ *
217
+ * const scope = createScope()
218
+ * const resolutions = resolveMap(
260
219
  * { a: getA, b: getB, c: getC },
261
- * { scope, mocks }
220
+ * { scope }
262
221
  * )
222
+ *
223
+ * resolutions == {
224
+ * a: getA({ scope }),
225
+ * b: getB({ scope }),
226
+ * c: getC({ scope })
227
+ * }
228
+ * ```
229
+ *
230
+ * @example
231
+ * Some provider is async:
232
+ * ```ts
233
+ * const getA = scoped(() => createA())
234
+ * const getB = scoped(async () => await createB())
235
+ * const getC = scoped(() => createC())
236
+ *
237
+ * const scope = createScope()
238
+ * const resolutions = await resolveMap(
239
+ * { a: getA, b: getB, c: getC },
240
+ * { scope }
241
+ * )
242
+ *
243
+ * resolutions == {
244
+ * a: getA({ scope }),
245
+ * b: await getB({ scope }),
246
+ * c: getC({ scope })
247
+ * }
263
248
  * ```
264
249
  *
265
250
  * @param providers - The map of providers.
@@ -267,6 +252,6 @@ declare const resolveList: <const Providers extends ProviderList>(providers: Pro
267
252
  *
268
253
  * @returns The map of resolutions.
269
254
  */
270
- declare const resolveMap: <const Providers extends ProviderRecord>(providers: Providers, context?: ResolutionContext) => AwaitAllValuesInCollection<InferProviderCollectionResolutions<Providers>>;
255
+ declare const resolveMap: <const Providers extends ProviderRecord>(providers: Providers, context?: ResolutionContext) => AwaitValuesInCollection<InferProviderCollectionResolutions<Providers>>;
271
256
 
272
- export { type Lifetime, type MockMap, type Provider, type ResolutionContext, type Resolver, type Scope, createMockMap, createScope, provide, resolveList, resolveMap, scoped, singleton, transient };
257
+ export { type MockMap, type Provider, type ResolutionContext, type Resolver, type Scope, createMockMap, createScope, resolveList, resolveMap, scoped, singleton, transient };
package/dist/index.js CHANGED
@@ -21,7 +21,6 @@ var src_exports = {};
21
21
  __export(src_exports, {
22
22
  createMockMap: () => createMockMap,
23
23
  createScope: () => createScope,
24
- provide: () => provide,
25
24
  resolveList: () => resolveList,
26
25
  resolveMap: () => resolveMap,
27
26
  scoped: () => scoped,
@@ -30,35 +29,42 @@ __export(src_exports, {
30
29
  });
31
30
  module.exports = __toCommonJS(src_exports);
32
31
 
33
- // src/helpers.ts
34
- var once = (fn) => {
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);
43
- };
44
-
45
32
  // src/provider.ts
46
- var provide = (lifetime, resolver) => {
47
- resolver = lifetime === "singleton" ? once(resolver) : resolver;
48
- const resolve = (context) => {
33
+ var transient = (resolver) => {
34
+ const instance = (context) => {
35
+ var _a;
36
+ const maybeMock = (_a = context == null ? void 0 : context.mocks) == null ? void 0 : _a.get(instance);
37
+ if (maybeMock) return maybeMock(context);
38
+ return resolver(context);
39
+ };
40
+ return instance;
41
+ };
42
+ var singleton = (resolver) => {
43
+ let resolved = false;
44
+ let resolution;
45
+ const instance = (context) => {
49
46
  var _a;
50
- const maybeOwnMock = (_a = context == null ? void 0 : context.mocks) == null ? void 0 : _a.get(resolve);
51
- if (maybeOwnMock) return maybeOwnMock(context);
52
- if (lifetime !== "scoped" || !(context == null ? void 0 : context.scope)) return resolver(context);
53
- const resolution = context.scope.has(resolve) ? context.scope.get(resolve) : resolver(context);
54
- context.scope.set(resolve, resolution);
47
+ const maybeMock = (_a = context == null ? void 0 : context.mocks) == null ? void 0 : _a.get(instance);
48
+ if (maybeMock) return maybeMock(context);
49
+ if (resolved) return resolution;
50
+ resolution = resolver(context);
51
+ resolved = true;
55
52
  return resolution;
56
53
  };
57
- return resolve;
54
+ return instance;
55
+ };
56
+ var scoped = (resolver) => {
57
+ const instance = (context) => {
58
+ var _a;
59
+ const maybeMock = (_a = context == null ? void 0 : context.mocks) == null ? void 0 : _a.get(instance);
60
+ if (maybeMock) return maybeMock(context);
61
+ if (!(context == null ? void 0 : context.scope)) return resolver(context);
62
+ const resolution = context.scope.has(resolver) ? context.scope.get(resolver) : resolver(context);
63
+ context.scope.set(resolver, resolution);
64
+ return resolution;
65
+ };
66
+ return instance;
58
67
  };
59
- var transient = (resolver) => provide("transient", resolver);
60
- var singleton = (resolver) => provide("singleton", resolver);
61
- var scoped = (resolver) => provide("scoped", resolver);
62
68
 
63
69
  // src/scope.ts
64
70
  var createScope = () => /* @__PURE__ */ new Map();
@@ -69,23 +75,27 @@ var createMockMap = () => /* @__PURE__ */ new Map();
69
75
  // src/collection-resolution.ts
70
76
  var resolveList = (providers, context) => {
71
77
  const resolutions = providers.map((provider) => provider(context));
72
- return resolutions.some((resolution) => resolution instanceof Promise) ? Promise.all(resolutions) : resolutions;
78
+ const hasPromises = resolutions.some(
79
+ (resolution) => resolution instanceof Promise
80
+ );
81
+ return hasPromises ? Promise.all(resolutions) : resolutions;
73
82
  };
74
83
  var resolveMap = (providers, context) => {
75
- let resolutionMapEntries = Object.entries(providers).map(
84
+ const resolutionMapEntries = Object.entries(providers).map(
76
85
  ([key, provider]) => [key, provider(context)]
77
86
  );
78
- if (resolutionMapEntries.some(
87
+ const hasPromises = resolutionMapEntries.some(
79
88
  ([, resolution]) => resolution instanceof Promise
80
- )) {
89
+ );
90
+ if (hasPromises) {
81
91
  return (async () => {
82
- resolutionMapEntries = await Promise.all(
92
+ const awaitedEntries = await Promise.all(
83
93
  resolutionMapEntries.map(async ([key, resolution]) => [
84
94
  key,
85
95
  await resolution
86
96
  ])
87
97
  );
88
- return Object.fromEntries(resolutionMapEntries);
98
+ return Object.fromEntries(awaitedEntries);
89
99
  })();
90
100
  }
91
101
  return Object.fromEntries(resolutionMapEntries);
@@ -94,7 +104,6 @@ var resolveMap = (providers, context) => {
94
104
  0 && (module.exports = {
95
105
  createMockMap,
96
106
  createScope,
97
- provide,
98
107
  resolveList,
99
108
  resolveMap,
100
109
  scoped,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/helpers.ts","../src/provider.ts","../src/scope.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 * @param fn - The function to invoke once and cache the result.\n *\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 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(factory) for contextual dependency resolution.\n *\n * Resolves an instance by calling a resolver\n * with an **optional** resolution context that will be propagated\n * throughout a dependency tree.\n * ```ts\n * provider({ scope, mocks })\n * ```\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(factory) for contextual dependency resolution.\n * ```ts\n * const getInstance = provide(\"transient\", () =>\n * createInstance(\n * getOtherInstance(context)\n * )\n * )\n * ```\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 * If the function calls other providers,\n * the context **must** be passed to their calls.\n *\n * @returns The provider instance.\n */\nexport const provide = <T>(\n lifetime: Lifetime,\n resolver: Resolver<T>,\n): Provider<T> => {\n resolver = lifetime === \"singleton\" ? once(resolver) : resolver;\n\n const resolve: Provider<T> = (context) => {\n const maybeOwnMock = context?.mocks?.get(resolve);\n if (maybeOwnMock) return maybeOwnMock(context);\n\n if (lifetime !== \"scoped\" || !context?.scope) return resolver(context);\n\n const resolution = context.scope.has(resolve)\n ? context.scope.get(resolve)\n : resolver(context);\n context.scope.set(resolve, resolution);\n\n return resolution;\n };\n\n return resolve;\n};\n\n/**\n * An alias for `provide(\"transient\", ...)`.\n * Creates a transient provider instance,\n * a wrapper around a resolver(factory) for contextual dependency resolution\n * that will create a new instance on each request.\n * ```ts\n * const getInstance = transient((context) =>\n * createInstance(...)\n * )\n *\n * getInstance() !== getInstance()\n * ```\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>): Provider<T> =>\n provide(\"transient\", resolver);\n\n/**\n * An alias for `provide(\"singleton\", ...)`.\n * Creates a transient provider instance,\n * a wrapper around a resolver(factory) for contextual dependency resolution\n * that will create an instance once and return it in subsequent requests.\n * ```ts\n * const getInstance = singleton((context) =>\n * createInstance(...)\n * )\n *\n * getInstance() === getInstance()\n * ```\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>): Provider<T> =>\n provide(\"singleton\", resolver);\n\n/**\n * An alias for `provide(\"scoped\", ...)`.\n * Creates a transient provider instance,\n * a wrapper around a resolver(factory) 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 * ```ts\n * const getInstance = scoped((context) =>\n * createInstance(...)\n * )\n *\n * getInstance() !== getInstance()\n * getInstance({ scope }) === getInstance({ scope })\n * ```\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>): Provider<T> =>\n 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","import { Provider } from \"./provider\";\n\n/**\n * A map of providers to providers of the same type.\n * Lifetime is not a part of `Provider` type, so you can use\n * a different one if necessary.\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 otherProvider =\n * transitive(() => ...)\n * const otherProviderMock: typeof otherProvider =\n * scoped(() => ...)\n *\n * const mocks = createMockMap()\n * mocks.set(otherProvider, otherProviderMock)\n *\n * provider({ mocks })\n * ```\n */\nexport type MockMap = Omit<Map<Provider<any>, Provider<any>>, \"set\" | \"get\"> & {\n /**\n * Sets a mock for a provider.\n *\n * @param provider - The original provider.\n * @param mock - The mock provider.\n */\n set<T>(provider: Provider<T>, mock: Provider<T>): MockMap;\n /**\n * Retrieves a mock of a provider. Returns undefined if there's none.\n *\n * @param provider - The provider.\n */\n get<T>(provider: Provider<T>): Provider<T> | undefined;\n};\n\n/**\n * Creates a mock map instance,\n * a map of providers to providers of the same type.\n * Lifetime is not a part of `Provider` type, so you can use\n * a different one if necessary.\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 otherProvider =\n * transitive(() => ...)\n * const otherProviderMock: typeof otherProvider =\n * scoped(() => ...)\n *\n * const mocks = createMockMap()\n * mocks.set(otherProvider, otherProviderMock)\n *\n * provider({ mocks })\n * ```\n *\n * @returns The mock map instance.\n */\nexport const createMockMap = (): MockMap => new Map();\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 * ```ts\n * const resolutions = resolveList(\n * [getA, getB, getC],\n * { scope, mocks }\n * )\n * ```\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 * ```ts\n * const resolutionMap = resolveMap(\n * { a: getA, b: getB, c: getC },\n * { scope, mocks }\n * )\n * ```\n *\n * @param providers - The map of providers.\n * @param context - The resolution context.\n *\n * @returns The map of resolutions.\n */\nexport const resolveMap = <const Providers extends ProviderRecord>(\n providers: Providers,\n context?: ResolutionContext,\n): AwaitAllValuesInCollection<\n InferProviderCollectionResolutions<Providers>\n> => {\n let resolutionMapEntries = Object.entries(providers).map(\n ([key, provider]) => [key, provider(context)],\n );\n\n if (\n resolutionMapEntries.some(\n ([, resolution]) => resolution instanceof Promise,\n )\n ) {\n return (async () => {\n resolutionMapEntries = await Promise.all(\n resolutionMapEntries.map(async ([key, resolution]) => [\n key,\n await resolution,\n ]),\n );\n\n return Object.fromEntries(resolutionMapEntries);\n })() as any;\n }\n\n return Object.fromEntries(resolutionMapEntries);\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACQO,IAAM,OAAO,CAAqB,OAA0B;AAC/D,MAAI,WAAW;AACf,MAAI;AAEJ,SAAO,OAAO,OAAO,IAAI,SAAe;AACpC,QAAI,SAAU,QAAO;AAErB,aAAS,GAAG,GAAG,IAAI;AACnB,eAAW;AAEX,WAAO;AAAA,EACX,GAAG,EAAE;AACT;;;ACiEO,IAAM,UAAU,CACnB,UACA,aACc;AACd,aAAW,aAAa,cAAc,KAAK,QAAQ,IAAI;AAEvD,QAAM,UAAuB,CAAC,YAAY;AA3F9C;AA4FQ,UAAM,gBAAe,wCAAS,UAAT,mBAAgB,IAAI;AACzC,QAAI,aAAc,QAAO,aAAa,OAAO;AAE7C,QAAI,aAAa,YAAY,EAAC,mCAAS,OAAO,QAAO,SAAS,OAAO;AAErE,UAAM,aAAa,QAAQ,MAAM,IAAI,OAAO,IACtC,QAAQ,MAAM,IAAI,OAAO,IACzB,SAAS,OAAO;AACtB,YAAQ,MAAM,IAAI,SAAS,UAAU;AAErC,WAAO;AAAA,EACX;AAEA,SAAO;AACX;AAoBO,IAAM,YAAY,CAAI,aACzB,QAAQ,aAAa,QAAQ;AAoB1B,IAAM,YAAY,CAAI,aACzB,QAAQ,aAAa,QAAQ;AAuB1B,IAAM,SAAS,CAAI,aACtB,QAAQ,UAAU,QAAQ;;;AClJvB,IAAM,cAAc,MAAa,oBAAI,IAAI;;;ACiCzC,IAAM,gBAAgB,MAAe,oBAAI,IAAI;;;ACpB7C,IAAM,cAAc,CACvB,WACA,YAGC;AACD,QAAM,cAAc,UAAU,IAAI,CAAC,aAAa,SAAS,OAAO,CAAC;AAEjE,SACI,YAAY,KAAK,CAAC,eAAe,sBAAsB,OAAO,IACxD,QAAQ,IAAI,WAAW,IACvB;AAEd;AAmBO,IAAM,aAAa,CACtB,WACA,YAGC;AACD,MAAI,uBAAuB,OAAO,QAAQ,SAAS,EAAE;AAAA,IACjD,CAAC,CAAC,KAAK,QAAQ,MAAM,CAAC,KAAK,SAAS,OAAO,CAAC;AAAA,EAChD;AAEA,MACI,qBAAqB;AAAA,IACjB,CAAC,CAAC,EAAE,UAAU,MAAM,sBAAsB;AAAA,EAC9C,GACF;AACE,YAAQ,YAAY;AAChB,6BAAuB,MAAM,QAAQ;AAAA,QACjC,qBAAqB,IAAI,OAAO,CAAC,KAAK,UAAU,MAAM;AAAA,UAClD;AAAA,UACA,MAAM;AAAA,QACV,CAAC;AAAA,MACL;AAEA,aAAO,OAAO,YAAY,oBAAoB;AAAA,IAClD,GAAG;AAAA,EACP;AAEA,SAAO,OAAO,YAAY,oBAAoB;AAClD;","names":[]}
1
+ {"version":3,"sources":["../src/index.ts","../src/provider.ts","../src/scope.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","import { MockMap } from \"./mock-map\";\nimport { Scope } from \"./scope\";\n\n/**\n * A function that returns a value of a particular type\n * with a resolution context being passed to it.\n */\nexport type Resolver<T> = (context?: ResolutionContext) => T;\n\n/**\n * A function that resolves an instance or a `Promise` of a particular type\n * based on a resolution context passed to it.\n */\nexport type Provider<T> = Resolver<T>;\n\n/**\n * A context used by providers to resolve instances\n * based on current scope and mocks.\n */\nexport type ResolutionContext = {\n scope?: Scope;\n mocks?: MockMap;\n};\n\n/**\n * Creates a transient provider that will resolve a new instance on each call.\n *\n * @example\n * ```ts\n * const getThing = transient(() => createThing())\n * getThing() !== getThing()\n * ```\n *\n * @param resolver\n * A function that returns a value of a particular type\n * with a resolution context being passed to it.\n *\n * @returns The transient provider.\n */\nexport const transient = <T>(resolver: Resolver<T>): Provider<T> => {\n const instance: Resolver<T> = (context) => {\n const maybeMock = context?.mocks?.get(instance);\n if (maybeMock) return maybeMock(context);\n\n return resolver(context);\n };\n\n return instance;\n};\n\n/**\n * Creates a singleton provider that will resolve an instance once\n * and return it on every call.\n *\n * @example\n * ```ts\n * const getThing = singleton(() => createThing())\n * getThing() === getThing()\n * ```\n *\n * @param resolver\n * A function that returns a value of a particular type\n * with a resolution context being passed to it.\n *\n * @returns The singleton provider.\n */\nexport const singleton = <T>(resolver: Resolver<T>): Provider<T> => {\n let resolved = false;\n let resolution: T | undefined;\n\n const instance: Resolver<T> = (context) => {\n const maybeMock = context?.mocks?.get(instance);\n if (maybeMock) return maybeMock(context);\n\n if (resolved) return resolution!;\n\n resolution = resolver(context);\n resolved = true;\n\n return resolution;\n };\n\n return instance;\n};\n\n/**\n * Creates a scoped provider that will take its resolution from a passed 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 call.\n *\n * @example\n * ```ts\n * const getThing = scoped(() => createThing())\n * getThing() !== getThing()\n * ```\n *\n * @example\n * ```ts\n * const getThing = scoped(() => createThing())\n * const scope = createScope()\n * getThing({ scope }) === getThing({ scope })\n * ```\n *\n * @param resolver\n * A function that returns a value of a particular type\n * with a resolution context being passed to it.\n *\n * @returns The scoped provider.\n */\nexport const scoped = <T>(resolver: Resolver<T>): Provider<T> => {\n const instance: Resolver<T> = (context) => {\n const maybeMock = context?.mocks?.get(instance);\n if (maybeMock) return maybeMock(context);\n\n if (!context?.scope) return resolver(context);\n\n const resolution = context.scope.has(resolver)\n ? context.scope.get(resolver)\n : resolver(context);\n context.scope.set(resolver, resolution);\n\n return resolution;\n };\n\n return instance;\n};\n","import { Resolver } from \"./provider\";\n\n/**\n * A `Map` of providers to their instances\n * that is then passed to a provider call in a resolution context object\n * to resolve instances of scoped providers within it.\n */\nexport type Scope = Map<Resolver<any>, any>;\n\n/**\n * Creates a `Map` of providers to their instances\n * that is then passed to a provider call in a resolution context object\n * to resolve instances of scoped providers within it.\n *\n * @example\n * ```ts\n * const requestScope = createScope()\n *\n * app.use(() => {\n * const db = getDb({ scope: requestScope })\n * // ...\n * })\n * ```\n *\n * @returns The map instance.\n */\nexport const createScope = (): Scope => new Map();\n","import { Resolver } from \"./provider\";\n\n/**\n * A `Map` of providers to providers of the same type\n * which is then passed to a provider call in a resolution context object\n * in order to replace providers with their mocks.\n */\nexport type MockMap = Omit<Map<Resolver<any>, Resolver<any>>, \"set\" | \"get\"> & {\n /**\n * Sets a mock for a provider.\n *\n * @param provider - The original provider.\n * @param mock - The mock provider.\n */\n set<T>(provider: Resolver<T>, mock: Resolver<T>): MockMap;\n /**\n * Retrieves a mock of a provider. Returns undefined if there's none.\n *\n * @param provider - The provider.\n */\n get<T>(provider: Resolver<T>): Resolver<T> | undefined;\n};\n\n/**\n * Creates a `Map` of providers to providers of the same type\n * which is then passed to a provider call in a resolution context object\n * in order to replace providers with their mocks.\n *\n * @example\n * ```ts\n * const mocks = createMockMap()\n * .set(getConfig, getTestConfig)\n *\n * getThing({ mocks })\n * ```\n *\n * @returns The map instance.\n */\nexport const createMockMap = (): MockMap => new Map();\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 AwaitValuesInCollection<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 * @example\n * Only sync providers:\n * ```ts\n * const getA = scoped(() => createA())\n * const getB = scoped(() => createB())\n * const getC = scoped(() => createC())\n *\n * const scope = createScope()\n * const resolutions = resolveList(\n * [getA, getB, getC],\n * { scope }\n * )\n *\n * resolutions == [\n * getA({ scope }),\n * getB({ scope }),\n * getC({ scope })\n * ]\n * ```\n *\n * @example\n * Some provider is async:\n * ```ts\n * const getA = scoped(() => createA())\n * const getB = scoped(async () => await createB())\n * const getC = scoped(() => createC())\n *\n * const scope = createScope()\n * const resolutions = resolveList(\n * [getA, getB, getC],\n * { scope }\n * )\n *\n * resolutions == [\n * getA({ scope }),\n * await getB({ scope }),\n * getC({ scope })\n * ]\n * ```\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): AwaitValuesInCollection<\n InferProviderCollectionResolutions<Providers>\n> => {\n const resolutions = providers.map((provider) => provider(context));\n\n const hasPromises = resolutions.some(\n (resolution) => resolution instanceof Promise,\n );\n\n return (hasPromises ? Promise.all(resolutions) : resolutions) 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 * @example\n * Only sync providers:\n * ```ts\n * const getA = scoped(() => createA())\n * const getB = scoped(() => createB())\n * const getC = scoped(() => createC())\n *\n * const scope = createScope()\n * const resolutions = resolveMap(\n * { a: getA, b: getB, c: getC },\n * { scope }\n * )\n *\n * resolutions == {\n * a: getA({ scope }),\n * b: getB({ scope }),\n * c: getC({ scope })\n * }\n * ```\n *\n * @example\n * Some provider is async:\n * ```ts\n * const getA = scoped(() => createA())\n * const getB = scoped(async () => await createB())\n * const getC = scoped(() => createC())\n *\n * const scope = createScope()\n * const resolutions = await resolveMap(\n * { a: getA, b: getB, c: getC },\n * { scope }\n * )\n *\n * resolutions == {\n * a: getA({ scope }),\n * b: await getB({ scope }),\n * c: getC({ scope })\n * }\n * ```\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): AwaitValuesInCollection<\n InferProviderCollectionResolutions<Providers>\n> => {\n const resolutionMapEntries = Object.entries(providers).map(\n ([key, provider]) => [key, provider(context)],\n );\n\n const hasPromises = resolutionMapEntries.some(\n ([, resolution]) => resolution instanceof Promise,\n );\n\n if (hasPromises) {\n return (async () => {\n const awaitedEntries = await Promise.all(\n resolutionMapEntries.map(async ([key, resolution]) => [\n key,\n await resolution,\n ]),\n );\n return Object.fromEntries(awaitedEntries);\n })() as any;\n }\n\n return Object.fromEntries(resolutionMapEntries);\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACuCO,IAAM,YAAY,CAAI,aAAuC;AAChE,QAAM,WAAwB,CAAC,YAAY;AAxC/C;AAyCQ,UAAM,aAAY,wCAAS,UAAT,mBAAgB,IAAI;AACtC,QAAI,UAAW,QAAO,UAAU,OAAO;AAEvC,WAAO,SAAS,OAAO;AAAA,EAC3B;AAEA,SAAO;AACX;AAkBO,IAAM,YAAY,CAAI,aAAuC;AAChE,MAAI,WAAW;AACf,MAAI;AAEJ,QAAM,WAAwB,CAAC,YAAY;AAtE/C;AAuEQ,UAAM,aAAY,wCAAS,UAAT,mBAAgB,IAAI;AACtC,QAAI,UAAW,QAAO,UAAU,OAAO;AAEvC,QAAI,SAAU,QAAO;AAErB,iBAAa,SAAS,OAAO;AAC7B,eAAW;AAEX,WAAO;AAAA,EACX;AAEA,SAAO;AACX;AA0BO,IAAM,SAAS,CAAI,aAAuC;AAC7D,QAAM,WAAwB,CAAC,YAAY;AA9G/C;AA+GQ,UAAM,aAAY,wCAAS,UAAT,mBAAgB,IAAI;AACtC,QAAI,UAAW,QAAO,UAAU,OAAO;AAEvC,QAAI,EAAC,mCAAS,OAAO,QAAO,SAAS,OAAO;AAE5C,UAAM,aAAa,QAAQ,MAAM,IAAI,QAAQ,IACvC,QAAQ,MAAM,IAAI,QAAQ,IAC1B,SAAS,OAAO;AACtB,YAAQ,MAAM,IAAI,UAAU,UAAU;AAEtC,WAAO;AAAA,EACX;AAEA,SAAO;AACX;;;ACnGO,IAAM,cAAc,MAAa,oBAAI,IAAI;;;ACYzC,IAAM,gBAAgB,MAAe,oBAAI,IAAI;;;ACmC7C,IAAM,cAAc,CACvB,WACA,YAGC;AACD,QAAM,cAAc,UAAU,IAAI,CAAC,aAAa,SAAS,OAAO,CAAC;AAEjE,QAAM,cAAc,YAAY;AAAA,IAC5B,CAAC,eAAe,sBAAsB;AAAA,EAC1C;AAEA,SAAQ,cAAc,QAAQ,IAAI,WAAW,IAAI;AACrD;AAqDO,IAAM,aAAa,CACtB,WACA,YAGC;AACD,QAAM,uBAAuB,OAAO,QAAQ,SAAS,EAAE;AAAA,IACnD,CAAC,CAAC,KAAK,QAAQ,MAAM,CAAC,KAAK,SAAS,OAAO,CAAC;AAAA,EAChD;AAEA,QAAM,cAAc,qBAAqB;AAAA,IACrC,CAAC,CAAC,EAAE,UAAU,MAAM,sBAAsB;AAAA,EAC9C;AAEA,MAAI,aAAa;AACb,YAAQ,YAAY;AAChB,YAAM,iBAAiB,MAAM,QAAQ;AAAA,QACjC,qBAAqB,IAAI,OAAO,CAAC,KAAK,UAAU,MAAM;AAAA,UAClD;AAAA,UACA,MAAM;AAAA,QACV,CAAC;AAAA,MACL;AACA,aAAO,OAAO,YAAY,cAAc;AAAA,IAC5C,GAAG;AAAA,EACP;AAEA,SAAO,OAAO,YAAY,oBAAoB;AAClD;","names":[]}