atomic-di 1.0.0-rc.2 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (2) hide show
  1. package/README.md +33 -33
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -13,7 +13,7 @@ This library implements lifetimes, scopes and mocking for pure dependency inject
13
13
  - [Scoped](#Scoped)
14
14
  - [Resolution context](#Resolution-context)
15
15
  - [Mocking](#Mocking)
16
- - [Scopes](#Scopes)
16
+ - [Scoping](#Scoping)
17
17
  - [Bulk resolutions](#Bulk-resolutions)
18
18
  - [List resolution](#List-resolution)
19
19
  - [Map resolution](#Map-resolution)
@@ -36,7 +36,7 @@ This library implements lifetimes, scopes and mocking for pure dependency inject
36
36
 
37
37
  Before reading, it's highly recommended that you familiarize yourself with the concepts of inversion of control (IoC) and dependency injection (DI), as well as DI techniques.
38
38
 
39
- If you need a container to build your application, or you are satisfied with pure dependency injection, you should definitely consider other solutions, or not use the framework at all.
39
+ If you need a container to build your application, or you are satisfied with pure dependency injection, you should definitely consider other solutions, or not use a framework at all.
40
40
 
41
41
  This library is an attempt to provide full-featured dependency injection **without containers**.
42
42
 
@@ -44,21 +44,21 @@ This library is an attempt to provide full-featured dependency injection **witho
44
44
 
45
45
  ### Lifetimes
46
46
 
47
- We can implement lifetime using static initializations together with factory functions that create instances on demand. However, this can introduce inconsistency into the composition code.
47
+ We can implement lifetime using static initializations together with factory functions that create instances on demand. However, this can introduce inconsistency into a composition code.
48
48
 
49
49
  This library solves this problem by allowing to resolve instances once using the same factory technique.
50
50
 
51
51
  ### Scopes
52
52
 
53
- Often in your application you may need to resolve instances separately for different "scopes" of the program, be it a request, a transaction or a worker thread. This behavior can be achieved by correctly distributing transient resolutions, but at scale the complexity of this approach will only increase.
53
+ Often in your application you may need to resolve instances separately for different "scopes" of a program, be it a request, a transaction or a worker thread. This behavior can be achieved by correctly distributing transient resolutions, but at scale the complexity of this approach will only increase.
54
54
 
55
- This library solves this problem by introducing into factories (hereinafter referred to as providers) the ability to work with a map of providers to their instances, which serves as a scope.
55
+ This library solves this problem by introducing into factories (hereinafter referred to as providers) an ability to work with a map of providers to their instances, which serves as a scope.
56
56
 
57
- ### Mocking
57
+ ### Testing
58
58
 
59
59
  Testability is an important part of every application. IoC handles this very well, but to perform a unit test we still need to resolve modules. To ensure testing without side effects, developers often use mocking - replacing implementations with others with the same behavior. We can rebuild modules manually for each unit test or group of unit tests, but at scale this approach can introduce a lot of extra manual work without any significant benefit.
60
60
 
61
- This library solves this problem by allowing you to use factories that have been defined for the main application build. It's enough to create a map of mock providers to providers with the same interface, and pass it to the provider call to replace the implementations in its dependencies.
61
+ This library solves this problem by allowing you to use factories that have been defined for a main application build. It's enough to create a map of mock providers to providers with the same interface, and pass it to a provider call to replace implementations in its dependencies.
62
62
 
63
63
  # Installation
64
64
 
@@ -80,7 +80,7 @@ npx jsr add @ensi/di
80
80
  - [Scoped](#Scoped)
81
81
  - [Resolution context](#Resolution-context)
82
82
  - [Mocking](#Mocking)
83
- - [Scopes](#Scopes)
83
+ - [Scoping](#Scoping)
84
84
  - [Bulk resolutions](#Bulk-resolutions)
85
85
  - [List resolution](#List-resolution)
86
86
  - [Map resolution](#Map-resolution)
@@ -91,54 +91,54 @@ The library provides functions that create providers with behavior typical of si
91
91
 
92
92
  ### Transient
93
93
 
94
- Transient providers are created using the `transient` function:
94
+ Transient providers are created using `transient` function:
95
95
  ```ts
96
96
  const getThing = transient(() => createThing())
97
97
  ```
98
98
 
99
- Transient providers are no different from regular factories except for additional logic required for scopes and mocks to work correctly. This logic is also present in the other two functions, you can read about it [here](#Resolution-context).
99
+ Transient providers are no different from regular factories except for additional logic required for scopes and mocks to work correctly. This logic is also present in other two functions, you can read about it [here](#Resolution-context).
100
100
 
101
101
  ### Singleton
102
102
 
103
- Singleton providers are created using the `singleton` function:
103
+ Singleton providers are created using `singleton` function:
104
104
  ```ts
105
105
  const getA = singleton(() => createA())
106
106
  const getB = transient((c) => createB(getA(c)))
107
107
  ```
108
108
 
109
- In this case, calling `getA` will always result in the same instance, and the passed factory will only be called once:
109
+ In this case, calling `getA` will always result in a same instance, and a passed factory will only be called once:
110
110
  ```ts
111
111
  getA() === getA() == getB().A === getB().A
112
112
  ```
113
113
 
114
- You may have noticed that the `getB` provider factory uses a certain `c` argument. This is a context that can optionally be passed when calling the provider, you can read about it [here](#Resolution-context).
114
+ You may have noticed that the `getB` provider factory uses a certain `c` argument. This is a context that can optionally be passed when calling a provider, you can read about it [here](#Resolution-context).
115
115
 
116
116
  ### Scoped
117
117
 
118
- Scoped providers are created using the `scoped` function:
118
+ Scoped providers are created using `scoped` function:
119
119
  ```ts
120
120
  const getThing = scoped(() => createThing())
121
121
  ```
122
122
 
123
- When calling this provider without passing a scope to the resolution context, it will create a new unique instance:
123
+ When calling this provider without passing a scope to a resolution context, it will create a new unique instance:
124
124
  ```ts
125
125
  getThing() !== getThing()
126
126
  ```
127
127
 
128
- To get resolutions within a scope, we need to pass it to the provider call in the resolution context object:
128
+ To get resolutions within a scope, we need to pass it to a provider call in a resolution context object:
129
129
  ```ts
130
130
  const scope = createScope()
131
131
 
132
132
  getThing({ scope }) === getThing({ scope })
133
133
  ```
134
134
 
135
- You can read more about scopes [here](#Scopes).
135
+ You can read more about scopes [here](#Scoping).
136
136
 
137
137
  ## Resolution context
138
138
 
139
- Each provider can accept a resolution context object. This is an object with optional `scope` and `mocks` fields that defines how the instance will be resolved.
139
+ Each provider can accept a resolution context object. This is an object with optional `scope` and `mocks` fields that defines how an instance will be resolved.
140
140
 
141
- In all provider factories that have dependencies, this context **must** be passed into all calls to other providers to ensure it is propagated up the call chain.
141
+ In all provider factories that have dependencies, this context **must** be passed into all calls to other providers to ensure it is propagated up a call chain.
142
142
 
143
143
  #### Incorrect
144
144
  ```ts
@@ -147,7 +147,7 @@ const getB = scoped(() => createB(getA()))
147
147
  const getC = scoped(() => createC(getB()))
148
148
  ```
149
149
 
150
- In this case, the context will not propagate beyond `getC` and other providers will not know about the current scope and mocks, and `getB` will return an instance that is not related to any scopes.
150
+ In this case, a context will not propagate beyond `getC` and other providers will not know about a current scope and mocks, and `getB` will return an instance that is not related to any scopes.
151
151
 
152
152
  #### Correct
153
153
  ```ts
@@ -156,23 +156,23 @@ const getB = scoped((c) => createB(getA(c)))
156
156
  const getC = scoped((c) => createC(getB(c)))
157
157
  ```
158
158
 
159
- In this case, `getC` will propagate the context, and `getB` and `getA` will be aware of the current mocks and scopes, resolving instances correctly.
159
+ In this case, `getC` will propagate a context, and `getB` and `getA` will be aware of a current mocks and scopes, resolving instances correctly.
160
160
 
161
- More details on how the provider behaves depending on the passed context can be found in the sections on [mocking](#Mocking) and [scopes](#Scopes).
161
+ More details on how provider behaves depending on a passed context can be found in sections about [mocking](#Mocking) and [scoping](#Scoping).
162
162
 
163
163
  ## Mocking
164
164
 
165
- To replace implementations inside factories, we can use a mock map. To create one, we can use the `createMockMap` function:
165
+ To replace implementations inside factories, we can use a mock map. To create one, we can use `createMockMap` function:
166
166
  ```ts
167
167
  const mockMap = createMockMap()
168
168
  ```
169
169
 
170
- To register a mock, you need to `set` an entry with the original provider in the key and its mock in the value:
170
+ To register a mock, you need to `set` an entry with an original provider in a key and its mock in a value:
171
171
  ```ts
172
172
  mockMap.set(getDatabase, getMockDatabase)
173
173
  ```
174
174
 
175
- Once all mocks have been registered, this map can be passed to the provider call. If the provider finds a mock in the resolution context, it checks whether it is among the keys, and in that case returns the mock call instead of itself.
175
+ Once all mocks have been registered, this map can be passed to a provider call. If a provider finds a mock in a resolution context, it checks whether it is among the keys, and in that case returns a mock call instead of itself.
176
176
 
177
177
  #### Direct replacement
178
178
  ```ts
@@ -203,16 +203,16 @@ const mocks = createMockMap().set(getC, getSea)
203
203
  getC({ mocks }) === "2sea"
204
204
  ```
205
205
 
206
- ## Scopes
206
+ ## Scoping
207
207
 
208
- In this library, a scope is a map of providers to their resolutions. To create one, you can use the `createScope` function:
208
+ In this library, a scope is a map of providers to their resolutions. To create one, you can use `createScope` function:
209
209
  ```ts
210
210
  const scope = createScope()
211
211
  ```
212
212
 
213
- It is passed to the scoped provider call or to the call of a provider that has the scoped provider among its transitive dependencies.
214
- - If the scoped provider finds a scope in the resolution context, it first tries to get its own resolution from it. If there is none, it creates a new resolution and places it in the scope below itself.
215
- - If a scope is not passed to the resolution context when calling the scoped provider, the provider will create a new instance, i.e. it will behave as a transient provider.
213
+ It is passed to a scoped provider call or to a call of a provider that has the scoped provider among its transitive dependencies.
214
+ - If a scoped provider finds a scope in a resolution context, it first tries to get its own resolution from it. If there is none, it creates a new resolution and places it in the scope below itself.
215
+ - If a scope is not passed to a resolution context when calling a scoped provider, the provider will create a new instance, i.e. it will behave as a transient provider.
216
216
 
217
217
  #### Direct scoped provider call
218
218
  ```ts
@@ -253,11 +253,11 @@ thing1.scopedDependency === thing2.scopedDependency
253
253
 
254
254
  ## Bulk resolutions
255
255
 
256
- It often happens that you need to resolve instances of a large number of entities, in our case providers, with the same context. Fortunately, the library provides functions for this.
256
+ It often happens that you need to resolve instances of a large number of entities, in our case providers, with a same context. Fortunately, the library provides functions for this.
257
257
 
258
258
  ### List resolution
259
259
 
260
- To resolve instances of a list of providers, you can use the `resolveList` function, which takes a list of providers and a common resolution context. If at least one provider in the passed list of providers returns a `Promise`, the function will return a `Promise` of the list of **awaited** resolutions.
260
+ To resolve instances of a list of providers, you can use `resolveList` function, which takes a list of providers and a common resolution context. If at least one provider in the passed list of providers returns a `Promise`, the function will return a `Promise` of a list of **awaited** resolutions.
261
261
 
262
262
  #### Only sync providers
263
263
  ```ts
@@ -301,7 +301,7 @@ resolutions == [
301
301
 
302
302
  ### Map resolution
303
303
 
304
- To resolve instances of a provider map, or an object with string keys and providers in the values, you can use the `resolveMap` function, which takes a provider map and a common resolution context. If at least one provider in the values of the passed provider map returns a `Promise`, the function will return a `Promise` of a map of **awaited** resolutions.
304
+ To resolve instances of a provider map, or an object with string keys and providers in a values, you can use `resolveMap` function, which takes a provider map and a common resolution context. If at least one provider in the values of the passed provider map returns a `Promise`, the function will return a `Promise` of a map of **awaited** resolutions.
305
305
 
306
306
  #### Only sync providers
307
307
  ```ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "atomic-di",
3
- "version": "1.0.0-rc.2",
3
+ "version": "1.0.0",
4
4
  "description": "This library implements lifetimes, scopes and mocking for pure dependency injection.",
5
5
  "repository": "https://github.com/ncor/atomic-di",
6
6
  "bugs": "https://github.com/ncor/atomic-di/issues",