atomic-di 0.8.1-beta.1 → 0.9.1-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1 +1,14 @@
1
- Not documented yet.
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
- * An immutable map. It's similar to `Map`,
5
- * but with reduced functionality and readonly builder behavior.
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 ImmutableMap<K, V> = {
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
- * Retrieves a possibly existing value under a key.
22
+ * Sets a mock for a provider.
14
23
  *
15
- * @param key - The key associated with the value.
16
- *
17
- * @returns The value or undefined.
24
+ * @param provider - The original provider.
25
+ * @param mock - The mock provider.
18
26
  */
19
- get(key: K): V | undefined;
27
+ set<T>(provider: Provider<T>, mock: Provider<T>): MockMap;
20
28
  /**
21
- * Sets a value under a key.
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
- * @returns A modified immutable map with the value being set in it.
31
+ * @param provider - The provider.
27
32
  */
28
- set(key: K, value: V): ImmutableMap<K, V>;
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
- * A map of providers to their compatible versions.
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 mocks = createMockMap().set(otherProvider, otherProviderMock)
47
- * provider({ mocks })
48
- * ```
49
- */
50
- type MockMap = ImmutableMap<Provider<any>, Provider<any>>;
51
- /**
52
- * Creates a mock map instance.
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
- * An immutable map. It's similar to `Map`,
5
- * but with reduced functionality and readonly builder behavior.
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 ImmutableMap<K, V> = {
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
- * Retrieves a possibly existing value under a key.
22
+ * Sets a mock for a provider.
14
23
  *
15
- * @param key - The key associated with the value.
16
- *
17
- * @returns The value or undefined.
24
+ * @param provider - The original provider.
25
+ * @param mock - The mock provider.
18
26
  */
19
- get(key: K): V | undefined;
27
+ set<T>(provider: Provider<T>, mock: Provider<T>): MockMap;
20
28
  /**
21
- * Sets a value under a key.
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
- * @returns A modified immutable map with the value being set in it.
31
+ * @param provider - The provider.
27
32
  */
28
- set(key: K, value: V): ImmutableMap<K, V>;
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
- * A map of providers to their compatible versions.
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 mocks = createMockMap().set(otherProvider, otherProviderMock)
47
- * provider({ mocks })
48
- * ```
49
- */
50
- type MockMap = ImmutableMap<Provider<any>, Provider<any>>;
51
- /**
52
- * Creates a mock map instance.
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 = () => createImmutableMap();
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":";;;;;;;;;;;;;;;;;;;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;;;ACyBzC,IAAM,qBAAqB,CAC9B,UAAyB,CAAC,MACL;AACrB,QAAM,MAAM,CAAC,QAAQ;AAtDzB;AAsD4B,yBAAQ,KAAK,CAAC,UAAU,MAAM,CAAC,MAAM,GAAG,MAAxC,mBAA4C;AAAA;AAEpE,QAAM,MAAM,CAAC,KAAQ,UAAa;AAC9B,QAAI,IAAI,GAAG,MAAM,QAAW;AACxB,YAAMA,cAA4B,QAAQ;AAAA,QAAI,CAAC,UAC3C,MAAM,CAAC,MAAM,MAAM,CAAC,MAAM,CAAC,GAAG,KAAK,IAAI;AAAA,MAC3C;AAEA,aAAO,mBAAmBA,WAAU;AAAA,IACxC;AAEA,UAAM,aAA4B,CAAC,GAAG,SAAS,CAAC,KAAK,KAAK,CAAC;AAE3D,WAAO,mBAAmB,UAAU;AAAA,EACxC;AAEA,QAAM,QAAQ,CAAC,UAA8B;AACzC,UAAM,aAA4B;AAAA,MAC9B,GAAG,QAAQ,OAAO,CAAC,UAAU,MAAM,IAAI,MAAM,CAAC,CAAC,MAAM,MAAS;AAAA,MAC9D,GAAG,MAAM;AAAA,IACb;AAEA,WAAO,mBAAmB,UAAU;AAAA,EACxC;AAEA,SAAO,OAAO,OAAO;AAAA,IACjB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACJ,CAAC;AACL;;;AC1DO,IAAM,gBAAgB,MAAe,mBAAmB;;;ACMxD,IAAM,cAAc,CACvB,WACA,YAGC;AACD,QAAM,cAAc,UAAU,IAAI,CAAC,aAAa,SAAS,OAAO,CAAC;AAEjE,SACI,YAAY,KAAK,CAAC,eAAe,sBAAsB,OAAO,IACxD,QAAQ,IAAI,WAAW,IACvB;AAEd;AAaO,IAAM,aAAa,CACtB,WACA,YAGC;AACD,MAAI,uBAAuB,OAAO,QAAQ,SAAS,EAAE;AAAA,IACjD,CAAC,CAAC,KAAK,QAAQ,MAAM,CAAC,KAAK,SAAS,OAAO,CAAC;AAAA,EAChD;AAEA,MACI,qBAAqB;AAAA,IACjB,CAAC,CAAC,EAAE,UAAU,MAAM,sBAAsB;AAAA,EAC9C,GACF;AACE,YAAQ,YAAY;AAChB,6BAAuB,MAAM,QAAQ;AAAA,QACjC,qBAAqB,IAAI,OAAO,CAAC,KAAK,UAAU,MAAM;AAAA,UAClD;AAAA,UACA,MAAM;AAAA,QACV,CAAC;AAAA,MACL;AAEA,aAAO,OAAO,YAAY,oBAAoB;AAAA,IAClD,GAAG;AAAA,EACP;AAEA,SAAO,OAAO,YAAY,oBAAoB;AAClD;","names":["newEntries"]}
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 = () => createImmutableMap();
35
+ var createMockMap = () => /* @__PURE__ */ new Map();
67
36
 
68
37
  // src/collection-resolution.ts
69
38
  var resolveList = (providers, context) => {
@@ -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.8.1-beta.1",
3
+ "version": "0.9.1-beta.2",
4
4
  "description": "A toolset for containerless dependency injection.",
5
- "repository": {
6
- "type": "git",
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
  }