atomic-di 0.8.1-beta.1 → 0.9.1-beta.2
Sign up to get free protection for your applications and to get access to all the features.
- package/README.md +14 -1
- package/dist/index.d.mts +36 -42
- package/dist/index.d.ts +36 -42
- package/dist/index.js +1 -32
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -32
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -10
package/README.md
CHANGED
@@ -1 +1,14 @@
|
|
1
|
-
|
1
|
+
# Installation
|
2
|
+
|
3
|
+
You can use any package manager.
|
4
|
+
|
5
|
+
```bash
|
6
|
+
npm add atomic-di
|
7
|
+
```
|
8
|
+
```bash
|
9
|
+
npx jsr add @ensi/di
|
10
|
+
```
|
11
|
+
|
12
|
+
# Contribution
|
13
|
+
|
14
|
+
This is free and open source project licensed under the [MIT License](LICENSE). You could help its development by contributing via [pull requests](https://github.com/ncor/atomic-di/fork) or [submitting an issue](https://github.com/ncor/atomic-di/issues).
|
package/dist/index.d.mts
CHANGED
@@ -1,60 +1,54 @@
|
|
1
|
-
type Entry<K, V> = [K, V];
|
2
|
-
type Entries<K, V> = Entry<K, V>[];
|
3
1
|
/**
|
4
|
-
*
|
5
|
-
*
|
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
|
7
|
+
* 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
|
+
* ```
|
6
19
|
*/
|
7
|
-
type
|
8
|
-
/**
|
9
|
-
* Map's entries.
|
10
|
-
*/
|
11
|
-
readonly entries: Entries<K, V>;
|
20
|
+
type MockMap = Omit<Map<Provider<any>, Provider<any>>, "set" | "get"> & {
|
12
21
|
/**
|
13
|
-
*
|
22
|
+
* Sets a mock for a provider.
|
14
23
|
*
|
15
|
-
* @param
|
16
|
-
*
|
17
|
-
* @returns The value or undefined.
|
24
|
+
* @param provider - The original provider.
|
25
|
+
* @param mock - The mock provider.
|
18
26
|
*/
|
19
|
-
|
27
|
+
set<T>(provider: Provider<T>, mock: Provider<T>): MockMap;
|
20
28
|
/**
|
21
|
-
*
|
22
|
-
*
|
23
|
-
* @param key - The key that will be associated with the value.
|
24
|
-
* @param value - The value to set.
|
29
|
+
* Retrieves a mock of a provider. Returns undefined if there's none.
|
25
30
|
*
|
26
|
-
* @
|
31
|
+
* @param provider - The provider.
|
27
32
|
*/
|
28
|
-
|
29
|
-
/**
|
30
|
-
* Merges two immutable maps. If there're any matching keys,
|
31
|
-
* values from the second map will override values from the first map.
|
32
|
-
*
|
33
|
-
* @param other The second immutable map.
|
34
|
-
*
|
35
|
-
* @returns A new immutable map as a result of merging two maps.
|
36
|
-
*/
|
37
|
-
merge(other: ImmutableMap<K, V>): ImmutableMap<K, V>;
|
33
|
+
get<T>(provider: Provider<T>): Provider<T> | undefined;
|
38
34
|
};
|
39
|
-
|
40
35
|
/**
|
41
|
-
*
|
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.
|
42
40
|
*
|
43
41
|
* Passed to a provider call in a resolution context object
|
44
42
|
* in order to replace providers with their mocks.
|
45
43
|
* ```ts
|
46
|
-
* const
|
47
|
-
*
|
48
|
-
*
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
*
|
44
|
+
* const otherProvider =
|
45
|
+
* transitive(() => ...)
|
46
|
+
* const otherProviderMock: typeof otherProvider =
|
47
|
+
* scoped(() => ...)
|
48
|
+
*
|
49
|
+
* const mocks = createMockMap()
|
50
|
+
* mocks.set(otherProvider, otherProviderMock)
|
53
51
|
*
|
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
52
|
* provider({ mocks })
|
59
53
|
* ```
|
60
54
|
*
|
package/dist/index.d.ts
CHANGED
@@ -1,60 +1,54 @@
|
|
1
|
-
type Entry<K, V> = [K, V];
|
2
|
-
type Entries<K, V> = Entry<K, V>[];
|
3
1
|
/**
|
4
|
-
*
|
5
|
-
*
|
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
|
7
|
+
* 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
|
+
* ```
|
6
19
|
*/
|
7
|
-
type
|
8
|
-
/**
|
9
|
-
* Map's entries.
|
10
|
-
*/
|
11
|
-
readonly entries: Entries<K, V>;
|
20
|
+
type MockMap = Omit<Map<Provider<any>, Provider<any>>, "set" | "get"> & {
|
12
21
|
/**
|
13
|
-
*
|
22
|
+
* Sets a mock for a provider.
|
14
23
|
*
|
15
|
-
* @param
|
16
|
-
*
|
17
|
-
* @returns The value or undefined.
|
24
|
+
* @param provider - The original provider.
|
25
|
+
* @param mock - The mock provider.
|
18
26
|
*/
|
19
|
-
|
27
|
+
set<T>(provider: Provider<T>, mock: Provider<T>): MockMap;
|
20
28
|
/**
|
21
|
-
*
|
22
|
-
*
|
23
|
-
* @param key - The key that will be associated with the value.
|
24
|
-
* @param value - The value to set.
|
29
|
+
* Retrieves a mock of a provider. Returns undefined if there's none.
|
25
30
|
*
|
26
|
-
* @
|
31
|
+
* @param provider - The provider.
|
27
32
|
*/
|
28
|
-
|
29
|
-
/**
|
30
|
-
* Merges two immutable maps. If there're any matching keys,
|
31
|
-
* values from the second map will override values from the first map.
|
32
|
-
*
|
33
|
-
* @param other The second immutable map.
|
34
|
-
*
|
35
|
-
* @returns A new immutable map as a result of merging two maps.
|
36
|
-
*/
|
37
|
-
merge(other: ImmutableMap<K, V>): ImmutableMap<K, V>;
|
33
|
+
get<T>(provider: Provider<T>): Provider<T> | undefined;
|
38
34
|
};
|
39
|
-
|
40
35
|
/**
|
41
|
-
*
|
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.
|
42
40
|
*
|
43
41
|
* Passed to a provider call in a resolution context object
|
44
42
|
* in order to replace providers with their mocks.
|
45
43
|
* ```ts
|
46
|
-
* const
|
47
|
-
*
|
48
|
-
*
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
*
|
44
|
+
* const otherProvider =
|
45
|
+
* transitive(() => ...)
|
46
|
+
* const otherProviderMock: typeof otherProvider =
|
47
|
+
* scoped(() => ...)
|
48
|
+
*
|
49
|
+
* const mocks = createMockMap()
|
50
|
+
* mocks.set(otherProvider, otherProviderMock)
|
53
51
|
*
|
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
52
|
* provider({ mocks })
|
59
53
|
* ```
|
60
54
|
*
|
package/dist/index.js
CHANGED
@@ -63,39 +63,8 @@ var scoped = (resolver) => provide("scoped", resolver);
|
|
63
63
|
// src/scope.ts
|
64
64
|
var createScope = () => /* @__PURE__ */ new Map();
|
65
65
|
|
66
|
-
// src/immutable-map.ts
|
67
|
-
var createImmutableMap = (entries = []) => {
|
68
|
-
const get = (key) => {
|
69
|
-
var _a;
|
70
|
-
return (_a = entries.find((entry) => entry[0] === key)) == null ? void 0 : _a[1];
|
71
|
-
};
|
72
|
-
const set = (key, value) => {
|
73
|
-
if (get(key) !== void 0) {
|
74
|
-
const newEntries2 = entries.map(
|
75
|
-
(entry) => entry[0] === key ? [entry[0], value] : entry
|
76
|
-
);
|
77
|
-
return createImmutableMap(newEntries2);
|
78
|
-
}
|
79
|
-
const newEntries = [...entries, [key, value]];
|
80
|
-
return createImmutableMap(newEntries);
|
81
|
-
};
|
82
|
-
const merge = (other) => {
|
83
|
-
const newEntries = [
|
84
|
-
...entries.filter((entry) => other.get(entry[0]) === void 0),
|
85
|
-
...other.entries
|
86
|
-
];
|
87
|
-
return createImmutableMap(newEntries);
|
88
|
-
};
|
89
|
-
return Object.freeze({
|
90
|
-
entries,
|
91
|
-
get,
|
92
|
-
set,
|
93
|
-
merge
|
94
|
-
});
|
95
|
-
};
|
96
|
-
|
97
66
|
// src/mock-map.ts
|
98
|
-
var createMockMap = () =>
|
67
|
+
var createMockMap = () => /* @__PURE__ */ new Map();
|
99
68
|
|
100
69
|
// src/collection-resolution.ts
|
101
70
|
var resolveList = (providers, context) => {
|
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/immutable-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(factory) 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(factory) 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 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 * 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 *\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(factory) 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(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 *\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 \"./immutable-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"]}
|
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 * @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(factory) 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(factory) 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 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 * 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 *\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(factory) 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(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 *\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","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 *\n * @param providers - The list of providers.\n * @param context - The resolution context.\n *\n * @returns The list of resolutions.\n */\nexport const resolveList = <const Providers extends ProviderList>(\n providers: Providers,\n context?: ResolutionContext,\n): AwaitAllValuesInCollection<\n InferProviderCollectionResolutions<Providers>\n> => {\n const resolutions = providers.map((provider) => provider(context));\n\n return (\n resolutions.some((resolution) => resolution instanceof Promise)\n ? Promise.all(resolutions)\n : resolutions\n ) as any;\n};\n\n/**\n * Calls every provider in a map with a provided resolution context\n * and returns a map with identical keys but with resolutions in values instead.\n * Returns a promise of a map of awaited resolutions if there's at least one\n * promise in the resolutions.\n *\n * @param providers - The map of providers.\n * @param context - The resolution context.\n *\n * @returns The map of resolutions.\n */\nexport const resolveMap = <const Providers extends ProviderRecord>(\n providers: Providers,\n context?: ResolutionContext,\n): AwaitAllValuesInCollection<\n InferProviderCollectionResolutions<Providers>\n> => {\n let resolutionMapEntries = Object.entries(providers).map(\n ([key, provider]) => [key, provider(context)],\n );\n\n if (\n resolutionMapEntries.some(\n ([, resolution]) => resolution instanceof Promise,\n )\n ) {\n return (async () => {\n resolutionMapEntries = await Promise.all(\n resolutionMapEntries.map(async ([key, resolution]) => [\n key,\n await resolution,\n ]),\n );\n\n return Object.fromEntries(resolutionMapEntries);\n })() as any;\n }\n\n return Object.fromEntries(resolutionMapEntries);\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACMO,IAAM,OAAO,CAIhB,OACC;AACD,MAAI,WAAW;AACf,MAAI;AAEJ,SAAO,OAAO,OAAO,IAAI,SAAe;AACpC,QAAI,SAAU,QAAO;AAErB,aAAS,GAAG,GAAG,IAAI;AACnB,eAAW;AAEX,WAAO;AAAA,EACX,GAAG,EAAE;AACT;;;ACkDO,IAAM,UAAU,CACnB,UACA,aACc;AACd,aAAW,aAAa,cAAc,KAAK,QAAQ,IAAI;AAEvD,QAAM,UAAuB,CAAC,YAAY;AA/E9C;AAgFQ,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;AAYO,IAAM,YAAY,CAAI,aACzB,QAAQ,aAAa,QAAQ;AAY1B,IAAM,YAAY,CAAI,aACzB,QAAQ,aAAa,QAAQ;AAc1B,IAAM,SAAS,CAAI,aAA0B,QAAQ,UAAU,QAAQ;;;AC5GvE,IAAM,cAAc,MAAa,oBAAI,IAAI;;;ACiCzC,IAAM,gBAAgB,MAAe,oBAAI,IAAI;;;AC1B7C,IAAM,cAAc,CACvB,WACA,YAGC;AACD,QAAM,cAAc,UAAU,IAAI,CAAC,aAAa,SAAS,OAAO,CAAC;AAEjE,SACI,YAAY,KAAK,CAAC,eAAe,sBAAsB,OAAO,IACxD,QAAQ,IAAI,WAAW,IACvB;AAEd;AAaO,IAAM,aAAa,CACtB,WACA,YAGC;AACD,MAAI,uBAAuB,OAAO,QAAQ,SAAS,EAAE;AAAA,IACjD,CAAC,CAAC,KAAK,QAAQ,MAAM,CAAC,KAAK,SAAS,OAAO,CAAC;AAAA,EAChD;AAEA,MACI,qBAAqB;AAAA,IACjB,CAAC,CAAC,EAAE,UAAU,MAAM,sBAAsB;AAAA,EAC9C,GACF;AACE,YAAQ,YAAY;AAChB,6BAAuB,MAAM,QAAQ;AAAA,QACjC,qBAAqB,IAAI,OAAO,CAAC,KAAK,UAAU,MAAM;AAAA,UAClD;AAAA,UACA,MAAM;AAAA,QACV,CAAC;AAAA,MACL;AAEA,aAAO,OAAO,YAAY,oBAAoB;AAAA,IAClD,GAAG;AAAA,EACP;AAEA,SAAO,OAAO,YAAY,oBAAoB;AAClD;","names":[]}
|
package/dist/index.mjs
CHANGED
@@ -31,39 +31,8 @@ var scoped = (resolver) => provide("scoped", resolver);
|
|
31
31
|
// src/scope.ts
|
32
32
|
var createScope = () => /* @__PURE__ */ new Map();
|
33
33
|
|
34
|
-
// src/immutable-map.ts
|
35
|
-
var createImmutableMap = (entries = []) => {
|
36
|
-
const get = (key) => {
|
37
|
-
var _a;
|
38
|
-
return (_a = entries.find((entry) => entry[0] === key)) == null ? void 0 : _a[1];
|
39
|
-
};
|
40
|
-
const set = (key, value) => {
|
41
|
-
if (get(key) !== void 0) {
|
42
|
-
const newEntries2 = entries.map(
|
43
|
-
(entry) => entry[0] === key ? [entry[0], value] : entry
|
44
|
-
);
|
45
|
-
return createImmutableMap(newEntries2);
|
46
|
-
}
|
47
|
-
const newEntries = [...entries, [key, value]];
|
48
|
-
return createImmutableMap(newEntries);
|
49
|
-
};
|
50
|
-
const merge = (other) => {
|
51
|
-
const newEntries = [
|
52
|
-
...entries.filter((entry) => other.get(entry[0]) === void 0),
|
53
|
-
...other.entries
|
54
|
-
];
|
55
|
-
return createImmutableMap(newEntries);
|
56
|
-
};
|
57
|
-
return Object.freeze({
|
58
|
-
entries,
|
59
|
-
get,
|
60
|
-
set,
|
61
|
-
merge
|
62
|
-
});
|
63
|
-
};
|
64
|
-
|
65
34
|
// src/mock-map.ts
|
66
|
-
var createMockMap = () =>
|
35
|
+
var createMockMap = () => /* @__PURE__ */ new Map();
|
67
36
|
|
68
37
|
// src/collection-resolution.ts
|
69
38
|
var resolveList = (providers, context) => {
|
package/dist/index.mjs.map
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"sources":["../src/helpers.ts","../src/provider.ts","../src/scope.ts","../src/immutable-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(factory) 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(factory) 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 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 * 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 *\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(factory) 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(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 *\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 \"./immutable-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"]}
|
1
|
+
{"version":3,"sources":["../src/helpers.ts","../src/provider.ts","../src/scope.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(factory) 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(factory) 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 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 * 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 *\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(factory) 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(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 *\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","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 *\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":";AAMO,IAAM,OAAO,CAIhB,OACC;AACD,MAAI,WAAW;AACf,MAAI;AAEJ,SAAO,OAAO,OAAO,IAAI,SAAe;AACpC,QAAI,SAAU,QAAO;AAErB,aAAS,GAAG,GAAG,IAAI;AACnB,eAAW;AAEX,WAAO;AAAA,EACX,GAAG,EAAE;AACT;;;ACkDO,IAAM,UAAU,CACnB,UACA,aACc;AACd,aAAW,aAAa,cAAc,KAAK,QAAQ,IAAI;AAEvD,QAAM,UAAuB,CAAC,YAAY;AA/E9C;AAgFQ,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;AAYO,IAAM,YAAY,CAAI,aACzB,QAAQ,aAAa,QAAQ;AAY1B,IAAM,YAAY,CAAI,aACzB,QAAQ,aAAa,QAAQ;AAc1B,IAAM,SAAS,CAAI,aAA0B,QAAQ,UAAU,QAAQ;;;AC5GvE,IAAM,cAAc,MAAa,oBAAI,IAAI;;;ACiCzC,IAAM,gBAAgB,MAAe,oBAAI,IAAI;;;AC1B7C,IAAM,cAAc,CACvB,WACA,YAGC;AACD,QAAM,cAAc,UAAU,IAAI,CAAC,aAAa,SAAS,OAAO,CAAC;AAEjE,SACI,YAAY,KAAK,CAAC,eAAe,sBAAsB,OAAO,IACxD,QAAQ,IAAI,WAAW,IACvB;AAEd;AAaO,IAAM,aAAa,CACtB,WACA,YAGC;AACD,MAAI,uBAAuB,OAAO,QAAQ,SAAS,EAAE;AAAA,IACjD,CAAC,CAAC,KAAK,QAAQ,MAAM,CAAC,KAAK,SAAS,OAAO,CAAC;AAAA,EAChD;AAEA,MACI,qBAAqB;AAAA,IACjB,CAAC,CAAC,EAAE,UAAU,MAAM,sBAAsB;AAAA,EAC9C,GACF;AACE,YAAQ,YAAY;AAChB,6BAAuB,MAAM,QAAQ;AAAA,QACjC,qBAAqB,IAAI,OAAO,CAAC,KAAK,UAAU,MAAM;AAAA,UAClD;AAAA,UACA,MAAM;AAAA,QACV,CAAC;AAAA,MACL;AAEA,aAAO,OAAO,YAAY,oBAAoB;AAAA,IAClD,GAAG;AAAA,EACP;AAEA,SAAO,OAAO,YAAY,oBAAoB;AAClD;","names":[]}
|
package/package.json
CHANGED
@@ -1,14 +1,9 @@
|
|
1
1
|
{
|
2
2
|
"name": "atomic-di",
|
3
|
-
"version": "0.
|
3
|
+
"version": "0.9.1-beta.2",
|
4
4
|
"description": "A toolset for containerless dependency injection.",
|
5
|
-
"repository":
|
6
|
-
|
7
|
-
"url": "https://github.com/ncor/atomic-di.git"
|
8
|
-
},
|
9
|
-
"bugs": {
|
10
|
-
"url": "https://github.com/ncor/atomic-di/issues"
|
11
|
-
},
|
5
|
+
"repository": "https://github.com/ncor/atomic-di",
|
6
|
+
"bugs": "https://github.com/ncor/atomic-di/issues",
|
12
7
|
"homepage": "https://github.com/ncor/atomic-di#readme",
|
13
8
|
"exports": {
|
14
9
|
".": {
|
@@ -32,7 +27,6 @@
|
|
32
27
|
},
|
33
28
|
"scripts": {
|
34
29
|
"build": "npx tsup",
|
35
|
-
"test": "pnpx vitest coverage --coverage"
|
36
|
-
"benchmark": "pnpx vitest benchmark"
|
30
|
+
"test": "pnpx vitest coverage --coverage"
|
37
31
|
}
|
38
32
|
}
|