@relax.js/core 1.0.2 → 1.0.4
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 +194 -188
- package/dist/DependencyInjection.d.ts +42 -24
- package/dist/collections/Index.d.ts +2 -0
- package/dist/collections/index.js +1 -1
- package/dist/collections/index.js.map +4 -4
- package/dist/collections/index.mjs +1 -1
- package/dist/collections/index.mjs.map +4 -4
- package/dist/di/index.js +1 -1
- package/dist/di/index.js.map +3 -3
- package/dist/di/index.mjs +1 -1
- package/dist/di/index.mjs.map +3 -3
- package/dist/errors.d.ts +20 -0
- package/dist/forms/FormValidator.d.ts +1 -20
- package/dist/forms/ValidationRules.d.ts +2 -0
- package/dist/forms/index.js +1 -1
- package/dist/forms/index.js.map +4 -4
- package/dist/forms/index.mjs +1 -1
- package/dist/forms/index.mjs.map +4 -4
- package/dist/html/TableRenderer.d.ts +1 -0
- package/dist/html/index.js.map +2 -2
- package/dist/html/index.mjs.map +2 -2
- package/dist/html/template.d.ts +4 -0
- package/dist/http/http.d.ts +1 -0
- package/dist/http/index.js.map +2 -2
- package/dist/http/index.mjs.map +2 -2
- package/dist/index.d.ts +0 -2
- package/dist/index.js +3 -3
- package/dist/index.js.map +4 -4
- package/dist/index.mjs +3 -3
- package/dist/index.mjs.map +4 -4
- package/dist/routing/index.js +3 -3
- package/dist/routing/index.js.map +3 -3
- package/dist/routing/index.mjs +3 -3
- package/dist/routing/index.mjs.map +3 -3
- package/dist/routing/routeTargetRegistry.d.ts +1 -0
- package/dist/routing/types.d.ts +2 -1
- package/dist/templates/NodeTemplate.d.ts +2 -0
- package/dist/utils/index.js +1 -1
- package/dist/utils/index.js.map +2 -2
- package/dist/utils/index.mjs +1 -1
- package/dist/utils/index.mjs.map +2 -2
- package/docs/Architecture.md +333 -333
- package/docs/DependencyInjection.md +277 -237
- package/docs/Errors.md +87 -87
- package/docs/GettingStarted.md +231 -231
- package/docs/Pipes.md +5 -5
- package/docs/Translations.md +167 -312
- package/docs/WhyRelaxjs.md +336 -336
- package/docs/api/.nojekyll +1 -0
- package/docs/api/assets/hierarchy.js +1 -0
- package/docs/api/assets/highlight.css +120 -0
- package/docs/api/assets/icons.js +18 -0
- package/docs/api/assets/icons.svg +1 -0
- package/docs/api/assets/main.js +60 -0
- package/docs/api/assets/navigation.js +1 -0
- package/docs/api/assets/search.js +1 -0
- package/docs/api/assets/style.css +1633 -0
- package/docs/api/classes/http.WebSocketClient.html +26 -0
- package/docs/api/classes/i18n.LocaleChangeEvent.html +66 -0
- package/docs/api/classes/index.Blueprint.html +3 -0
- package/docs/api/classes/index.BoundNode.html +3 -0
- package/docs/api/classes/index.DigitsValidation.html +10 -0
- package/docs/api/classes/index.FormValidator.html +32 -0
- package/docs/api/classes/index.HttpError.html +13 -0
- package/docs/api/classes/index.LinkedList.html +26 -0
- package/docs/api/classes/index.NavigateRouteEvent.html +76 -0
- package/docs/api/classes/index.Node.html +15 -0
- package/docs/api/classes/index.PageSelectedEvent.html +61 -0
- package/docs/api/classes/index.Pager.html +4 -0
- package/docs/api/classes/index.RangeValidation.html +15 -0
- package/docs/api/classes/index.RelaxError.html +17 -0
- package/docs/api/classes/index.RequiredValidation.html +10 -0
- package/docs/api/classes/index.RouteError.html +11 -0
- package/docs/api/classes/index.RouteGuardError.html +12 -0
- package/docs/api/classes/index.RouteLink.html +779 -0
- package/docs/api/classes/index.RouteTarget.html +788 -0
- package/docs/api/classes/index.SSEClient.html +13 -0
- package/docs/api/classes/index.SSEDataEvent.html +63 -0
- package/docs/api/classes/index.ServiceCollection.html +28 -0
- package/docs/api/classes/index.ServiceContainer.html +24 -0
- package/docs/api/classes/index.SortChangeEvent.html +61 -0
- package/docs/api/classes/index.TableRenderer.html +5 -0
- package/docs/api/classes/index.TableSorter.html +4 -0
- package/docs/api/enums/index.GuardResult.html +9 -0
- package/docs/api/functions/elements.formError.html +6 -0
- package/docs/api/functions/elements.selectOne.html +6 -0
- package/docs/api/functions/i18n.getCurrentLocale.html +3 -0
- package/docs/api/functions/i18n.loadNamespace.html +7 -0
- package/docs/api/functions/i18n.loadNamespaces.html +6 -0
- package/docs/api/functions/i18n.onMissingTranslation.html +7 -0
- package/docs/api/functions/i18n.setLocale.html +7 -0
- package/docs/api/functions/i18n.setMessageFormatter.html +7 -0
- package/docs/api/functions/i18n.t.html +9 -0
- package/docs/api/functions/index.BooleanConverter.html +6 -0
- package/docs/api/functions/index.ContainerService.html +13 -0
- package/docs/api/functions/index.DateConverter.html +11 -0
- package/docs/api/functions/index.Inject.html +16 -0
- package/docs/api/functions/index.NumberConverter.html +5 -0
- package/docs/api/functions/index.RegisterValidator.html +7 -0
- package/docs/api/functions/index.applyPipes.html +17 -0
- package/docs/api/functions/index.asyncHandler.html +11 -0
- package/docs/api/functions/index.capitalizePipe.html +4 -0
- package/docs/api/functions/index.clearPendingNavigations.html +1 -0
- package/docs/api/functions/index.compileTemplate.html +26 -0
- package/docs/api/functions/index.configure.html +5 -0
- package/docs/api/functions/index.createBluePrint.html +1 -0
- package/docs/api/functions/index.createConverterFromDataType.html +4 -0
- package/docs/api/functions/index.createConverterFromInputType.html +5 -0
- package/docs/api/functions/index.createPipeRegistry.html +12 -0
- package/docs/api/functions/index.currencyPipe.html +9 -0
- package/docs/api/functions/index.datePipe.html +9 -0
- package/docs/api/functions/index.daysAgoPipe.html +8 -0
- package/docs/api/functions/index.defaultPipe.html +5 -0
- package/docs/api/functions/index.defineRoutes.html +8 -0
- package/docs/api/functions/index.del.html +8 -0
- package/docs/api/functions/index.findRouteByName.html +5 -0
- package/docs/api/functions/index.findRouteByUrl.html +4 -0
- package/docs/api/functions/index.firstPipe.html +4 -0
- package/docs/api/functions/index.generateSequentialId.html +21 -0
- package/docs/api/functions/index.get.html +9 -0
- package/docs/api/functions/index.getDataConverter.html +11 -0
- package/docs/api/functions/index.getParentComponent.html +18 -0
- package/docs/api/functions/index.getValidator.html +4 -0
- package/docs/api/functions/index.html.html +19 -0
- package/docs/api/functions/index.joinPipe.html +5 -0
- package/docs/api/functions/index.keysPipe.html +4 -0
- package/docs/api/functions/index.lastPipe.html +4 -0
- package/docs/api/functions/index.lowercasePipe.html +4 -0
- package/docs/api/functions/index.mapFormToClass.html +17 -0
- package/docs/api/functions/index.matchRoute.html +5 -0
- package/docs/api/functions/index.navigate.html +8 -0
- package/docs/api/functions/index.onError.html +8 -0
- package/docs/api/functions/index.piecesPipe.html +8 -0
- package/docs/api/functions/index.post.html +9 -0
- package/docs/api/functions/index.printRoutes.html +2 -0
- package/docs/api/functions/index.put.html +9 -0
- package/docs/api/functions/index.readData.html +17 -0
- package/docs/api/functions/index.registerRouteTarget.html +9 -0
- package/docs/api/functions/index.reportError.html +10 -0
- package/docs/api/functions/index.request.html +8 -0
- package/docs/api/functions/index.resolveValue.html +18 -0
- package/docs/api/functions/index.setFetch.html +6 -0
- package/docs/api/functions/index.setFormData.html +17 -0
- package/docs/api/functions/index.shortenPipe.html +5 -0
- package/docs/api/functions/index.startRouting.html +6 -0
- package/docs/api/functions/index.ternaryPipe.html +6 -0
- package/docs/api/functions/index.trimPipe.html +4 -0
- package/docs/api/functions/index.unregisterRouteTarget.html +3 -0
- package/docs/api/functions/index.uppercasePipe.html +4 -0
- package/docs/api/hierarchy.html +1 -0
- package/docs/api/index.html +323 -0
- package/docs/api/interfaces/http.SimpleDataEvent.html +3 -0
- package/docs/api/interfaces/http.WebSocketAbstraction.html +9 -0
- package/docs/api/interfaces/http.WebSocketCodec.html +4 -0
- package/docs/api/interfaces/http.WebSocketOptions.html +20 -0
- package/docs/api/interfaces/index.CompiledTemplate.html +10 -0
- package/docs/api/interfaces/index.DataLoader.html +19 -0
- package/docs/api/interfaces/index.EngineConfig.html +11 -0
- package/docs/api/interfaces/index.ErrorContext.html +4 -0
- package/docs/api/interfaces/index.FormReaderOptions.html +8 -0
- package/docs/api/interfaces/index.HttpOptions.html +16 -0
- package/docs/api/interfaces/index.HttpResponse.html +17 -0
- package/docs/api/interfaces/index.LoadRoute.html +7 -0
- package/docs/api/interfaces/index.NavigateOptions.html +7 -0
- package/docs/api/interfaces/index.PipeRegistry.html +12 -0
- package/docs/api/interfaces/index.RegistrationOptions.html +22 -0
- package/docs/api/interfaces/index.RenderTemplate.html +7 -0
- package/docs/api/interfaces/index.RequestOptions.html +11 -0
- package/docs/api/interfaces/index.Routable.html +10 -0
- package/docs/api/interfaces/index.Route.html +13 -0
- package/docs/api/interfaces/index.RouteGuard.html +2 -0
- package/docs/api/interfaces/index.RouteValue.html +6 -0
- package/docs/api/interfaces/index.SSEOptions.html +24 -0
- package/docs/api/interfaces/index.ValidationContext.html +8 -0
- package/docs/api/interfaces/index.ValidatorOptions.html +14 -0
- package/docs/api/media/Architecture.md +333 -0
- package/docs/api/media/DependencyInjection.md +277 -0
- package/docs/api/media/GettingStarted.md +231 -0
- package/docs/api/media/HttpClient.md +459 -0
- package/docs/api/media/Pipes.md +211 -0
- package/docs/api/media/Routing.md +332 -0
- package/docs/api/media/WhyRelaxjs.md +336 -0
- package/docs/api/media/forms.md +99 -0
- package/docs/api/media/html.md +175 -0
- package/docs/api/media/i18n.md +354 -0
- package/docs/api/media/utilities.md +143 -0
- package/docs/api/media/validation.md +351 -0
- package/docs/api/modules/collections_Index.html +1 -0
- package/docs/api/modules/di.html +1 -0
- package/docs/api/modules/elements.html +1 -0
- package/docs/api/modules/forms.html +1 -0
- package/docs/api/modules/html.html +1 -0
- package/docs/api/modules/http.html +1 -0
- package/docs/api/modules/i18n.html +1 -0
- package/docs/api/modules/index.html +1 -0
- package/docs/api/modules/routing.html +1 -0
- package/docs/api/modules/utils.html +1 -0
- package/docs/api/modules.html +1 -0
- package/docs/api/types/http.WebSocketFactory.html +2 -0
- package/docs/api/types/i18n.MessageFormatter.html +3 -0
- package/docs/api/types/i18n.MissingTranslationHandler.html +1 -0
- package/docs/api/types/index.Constructor.html +7 -0
- package/docs/api/types/index.ConverterFunc.html +2 -0
- package/docs/api/types/index.DataType.html +2 -0
- package/docs/api/types/index.InputType.html +2 -0
- package/docs/api/types/index.PipeFunction.html +6 -0
- package/docs/api/types/index.RouteData.html +1 -0
- package/docs/api/types/index.RouteMatchResult.html +9 -0
- package/docs/api/types/index.RouteParamType.html +1 -0
- package/docs/api/types/index.RouteSegmentType.html +2 -0
- package/docs/api/types/index.SSEEventFactory.html +5 -0
- package/docs/api/types/index.ServiceScope.html +10 -0
- package/docs/api/types/index.SortColumn.html +3 -0
- package/docs/api/variables/i18n.formatICU.html +3 -0
- package/docs/api/variables/index.container.html +6 -0
- package/docs/api/variables/index.defaultPipes.html +6 -0
- package/docs/api/variables/index.internalRoutes.html +1 -0
- package/docs/api/variables/index.serviceCollection.html +6 -0
- package/docs/api.json +93171 -0
- package/docs/elements/dom.md +102 -102
- package/docs/forms/creating-form-components.md +924 -924
- package/docs/forms/form-api.md +94 -94
- package/docs/forms/forms.md +99 -99
- package/docs/forms/patterns.md +311 -311
- package/docs/forms/reading-writing.md +365 -365
- package/docs/forms/validation.md +351 -351
- package/docs/html/TableRenderer.md +291 -291
- package/docs/html/html.md +175 -175
- package/docs/html/index.md +54 -54
- package/docs/html/template.md +422 -422
- package/docs/http/HttpClient.md +459 -459
- package/docs/http/ServerSentEvents.md +184 -184
- package/docs/http/index.md +109 -109
- package/docs/i18n/i18n.md +49 -4
- package/docs/i18n/intl-standard.md +178 -178
- package/docs/routing/RouteLink.md +98 -98
- package/docs/routing/Routing.md +332 -332
- package/docs/routing/layouts.md +207 -207
- package/docs/utilities.md +143 -143
- package/package.json +4 -3
|
@@ -1,237 +1,277 @@
|
|
|
1
|
-
# Dependency Injection
|
|
2
|
-
|
|
3
|
-
A lightweight IoC container for managing service dependencies in your application.
|
|
4
|
-
|
|
5
|
-
## Overview
|
|
6
|
-
|
|
7
|
-
The DI system provides:
|
|
8
|
-
- Constructor injection
|
|
9
|
-
- Property injection
|
|
10
|
-
- Singleton and scoped lifetimes
|
|
11
|
-
- Decorator-based registration
|
|
12
|
-
|
|
13
|
-
## Quick Start
|
|
14
|
-
|
|
15
|
-
```typescript
|
|
16
|
-
import { ContainerService, container } from '
|
|
17
|
-
|
|
18
|
-
@ContainerService()
|
|
19
|
-
class LoggerService {
|
|
20
|
-
log(message: string) {
|
|
21
|
-
console.log(`[LOG] ${message}`);
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
// Resolve and use
|
|
26
|
-
const logger = container.resolve(LoggerService);
|
|
27
|
-
logger.log('Hello!');
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
## Registration
|
|
31
|
-
|
|
32
|
-
Use the `@ContainerService` decorator to register services:
|
|
33
|
-
|
|
34
|
-
```typescript
|
|
35
|
-
@ContainerService()
|
|
36
|
-
class ConfigService {
|
|
37
|
-
apiUrl = '/api/v1';
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
@ContainerService({ inject: [ConfigService] })
|
|
41
|
-
class ApiClient {
|
|
42
|
-
constructor(private config: ConfigService) {}
|
|
43
|
-
|
|
44
|
-
fetch(path: string) {
|
|
45
|
-
return fetch(this.config.apiUrl + path);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
### Manual Registration
|
|
51
|
-
|
|
52
|
-
For cases where you can't use decorators (e.g. registering an existing instance):
|
|
53
|
-
|
|
54
|
-
```typescript
|
|
55
|
-
import { serviceCollection } from '
|
|
56
|
-
|
|
57
|
-
// Register with existing instance
|
|
58
|
-
const config = { apiUrl: '/api' };
|
|
59
|
-
serviceCollection.register(ConfigService, {
|
|
60
|
-
inject: [],
|
|
61
|
-
instance: config
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
// Register with custom key
|
|
65
|
-
serviceCollection.register(CacheService, {
|
|
66
|
-
key: 'primaryCache',
|
|
67
|
-
scope: 'global',
|
|
68
|
-
inject: []
|
|
69
|
-
});
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
## Scopes
|
|
73
|
-
|
|
74
|
-
### Global (Singleton)
|
|
75
|
-
|
|
76
|
-
Same instance returned every time:
|
|
77
|
-
|
|
78
|
-
```typescript
|
|
79
|
-
@ContainerService({ scope: 'global' })
|
|
80
|
-
class DatabaseConnection {
|
|
81
|
-
// ...
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
const db1 = container.resolve(DatabaseConnection);
|
|
85
|
-
const db2 = container.resolve(DatabaseConnection);
|
|
86
|
-
// db1 === db2
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
### Closest (Scoped)
|
|
90
|
-
|
|
91
|
-
New instance for each container scope:
|
|
92
|
-
|
|
93
|
-
```typescript
|
|
94
|
-
@ContainerService({ scope: 'closest' })
|
|
95
|
-
class RequestContext {
|
|
96
|
-
// ...
|
|
97
|
-
}
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
## Constructor Injection
|
|
101
|
-
|
|
102
|
-
Dependencies are passed to the constructor in order:
|
|
103
|
-
|
|
104
|
-
```typescript
|
|
105
|
-
@ContainerService({
|
|
106
|
-
inject: [LoggerService, ConfigService, DatabaseConnection]
|
|
107
|
-
})
|
|
108
|
-
class UserRepository {
|
|
109
|
-
constructor(
|
|
110
|
-
private logger: LoggerService,
|
|
111
|
-
private config: ConfigService,
|
|
112
|
-
private db: DatabaseConnection
|
|
113
|
-
) {}
|
|
114
|
-
}
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
## Property Injection
|
|
118
|
-
|
|
119
|
-
### Using the `@Inject` Decorator
|
|
120
|
-
|
|
121
|
-
The `@Inject` decorator resolves a dependency and assigns it to a class field
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
### Using the `properties` Option
|
|
139
|
-
|
|
140
|
-
Alternatively, declare property injection in the registration options:
|
|
141
|
-
|
|
142
|
-
```typescript
|
|
143
|
-
@ContainerService({
|
|
144
|
-
inject: [],
|
|
145
|
-
properties: {
|
|
146
|
-
logger: LoggerService,
|
|
147
|
-
cache: 'primaryCache' // string key
|
|
148
|
-
}
|
|
149
|
-
})
|
|
150
|
-
class OrderService {
|
|
151
|
-
logger!: LoggerService;
|
|
152
|
-
cache!: CacheService;
|
|
153
|
-
}
|
|
154
|
-
```
|
|
155
|
-
|
|
156
|
-
##
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
```
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
1
|
+
# Dependency Injection
|
|
2
|
+
|
|
3
|
+
A lightweight IoC container for managing service dependencies in your application.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
The DI system provides:
|
|
8
|
+
- Constructor injection
|
|
9
|
+
- Property injection
|
|
10
|
+
- Singleton and scoped lifetimes
|
|
11
|
+
- Decorator-based registration
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
import { ContainerService, container } from '@relax.js/core/di';
|
|
17
|
+
|
|
18
|
+
@ContainerService()
|
|
19
|
+
class LoggerService {
|
|
20
|
+
log(message: string) {
|
|
21
|
+
console.log(`[LOG] ${message}`);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Resolve and use
|
|
26
|
+
const logger = container.resolve(LoggerService);
|
|
27
|
+
logger.log('Hello!');
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Registration
|
|
31
|
+
|
|
32
|
+
Use the `@ContainerService` decorator to register services:
|
|
33
|
+
|
|
34
|
+
```typescript
|
|
35
|
+
@ContainerService()
|
|
36
|
+
class ConfigService {
|
|
37
|
+
apiUrl = '/api/v1';
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
@ContainerService({ inject: [ConfigService] })
|
|
41
|
+
class ApiClient {
|
|
42
|
+
constructor(private config: ConfigService) {}
|
|
43
|
+
|
|
44
|
+
fetch(path: string) {
|
|
45
|
+
return fetch(this.config.apiUrl + path);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Manual Registration
|
|
51
|
+
|
|
52
|
+
For cases where you can't use decorators (e.g. registering an existing instance):
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
import { serviceCollection } from '@relax.js/core/di';
|
|
56
|
+
|
|
57
|
+
// Register with existing instance
|
|
58
|
+
const config = { apiUrl: '/api' };
|
|
59
|
+
serviceCollection.register(ConfigService, {
|
|
60
|
+
inject: [],
|
|
61
|
+
instance: config
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
// Register with custom key
|
|
65
|
+
serviceCollection.register(CacheService, {
|
|
66
|
+
key: 'primaryCache',
|
|
67
|
+
scope: 'global',
|
|
68
|
+
inject: []
|
|
69
|
+
});
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Scopes
|
|
73
|
+
|
|
74
|
+
### Global (Singleton)
|
|
75
|
+
|
|
76
|
+
Same instance returned every time:
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
@ContainerService({ scope: 'global' })
|
|
80
|
+
class DatabaseConnection {
|
|
81
|
+
// ...
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const db1 = container.resolve(DatabaseConnection);
|
|
85
|
+
const db2 = container.resolve(DatabaseConnection);
|
|
86
|
+
// db1 === db2
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Closest (Scoped)
|
|
90
|
+
|
|
91
|
+
New instance for each container scope:
|
|
92
|
+
|
|
93
|
+
```typescript
|
|
94
|
+
@ContainerService({ scope: 'closest' })
|
|
95
|
+
class RequestContext {
|
|
96
|
+
// ...
|
|
97
|
+
}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Constructor Injection
|
|
101
|
+
|
|
102
|
+
Dependencies are passed to the constructor in order:
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
@ContainerService({
|
|
106
|
+
inject: [LoggerService, ConfigService, DatabaseConnection]
|
|
107
|
+
})
|
|
108
|
+
class UserRepository {
|
|
109
|
+
constructor(
|
|
110
|
+
private logger: LoggerService,
|
|
111
|
+
private config: ConfigService,
|
|
112
|
+
private db: DatabaseConnection
|
|
113
|
+
) {}
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Property Injection
|
|
118
|
+
|
|
119
|
+
### Using the `@Inject` Decorator
|
|
120
|
+
|
|
121
|
+
The `@Inject` decorator resolves a dependency and assigns it to a class field.
|
|
122
|
+
The service is resolved when the instance is created, so the field is available
|
|
123
|
+
in all methods including `connectedCallback` for web components.
|
|
124
|
+
|
|
125
|
+
```typescript
|
|
126
|
+
import { ContainerService, Inject } from '@relax.js/core/di';
|
|
127
|
+
|
|
128
|
+
@ContainerService({ inject: [] })
|
|
129
|
+
class OrderService {
|
|
130
|
+
@Inject(LoggerService)
|
|
131
|
+
private logger!: LoggerService;
|
|
132
|
+
|
|
133
|
+
@Inject('primaryCache') // resolve by string key
|
|
134
|
+
private cache!: CacheService;
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### Using the `properties` Option
|
|
139
|
+
|
|
140
|
+
Alternatively, declare property injection in the registration options:
|
|
141
|
+
|
|
142
|
+
```typescript
|
|
143
|
+
@ContainerService({
|
|
144
|
+
inject: [],
|
|
145
|
+
properties: {
|
|
146
|
+
logger: LoggerService,
|
|
147
|
+
cache: 'primaryCache' // string key
|
|
148
|
+
}
|
|
149
|
+
})
|
|
150
|
+
class OrderService {
|
|
151
|
+
logger!: LoggerService;
|
|
152
|
+
cache!: CacheService;
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## Using Services in Web Components
|
|
157
|
+
|
|
158
|
+
Web components use `@Inject` to access services. Do not use `@ContainerService` on
|
|
159
|
+
components since the browser creates them with zero constructor arguments.
|
|
160
|
+
|
|
161
|
+
### Property Injection with @Inject
|
|
162
|
+
|
|
163
|
+
```typescript
|
|
164
|
+
import { Inject } from '@relax.js/core/di';
|
|
165
|
+
|
|
166
|
+
class UserPanel extends HTMLElement {
|
|
167
|
+
@Inject(UserService)
|
|
168
|
+
private userService!: UserService;
|
|
169
|
+
|
|
170
|
+
@Inject(LoggerService)
|
|
171
|
+
private logger!: LoggerService;
|
|
172
|
+
|
|
173
|
+
connectedCallback() {
|
|
174
|
+
// Injected fields are resolved and ready to use
|
|
175
|
+
const user = this.userService.getCurrentUser();
|
|
176
|
+
this.logger.log('UserPanel connected');
|
|
177
|
+
this.render(user);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
customElements.define('user-panel', UserPanel);
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
This works the same way regardless of how the component is created:
|
|
185
|
+
|
|
186
|
+
```typescript
|
|
187
|
+
// Created by application code
|
|
188
|
+
document.createElement('user-panel');
|
|
189
|
+
|
|
190
|
+
// Created by the browser from HTML
|
|
191
|
+
// <user-panel></user-panel>
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### Setup Order
|
|
195
|
+
|
|
196
|
+
Register all services before defining custom elements. Services
|
|
197
|
+
decorated with `@ContainerService` register themselves when imported,
|
|
198
|
+
so import those modules first.
|
|
199
|
+
|
|
200
|
+
```typescript
|
|
201
|
+
// main.ts - application entry point
|
|
202
|
+
|
|
203
|
+
// 1. Import services (registers them via @ContainerService)
|
|
204
|
+
import './services/ApiClient';
|
|
205
|
+
import './services/UserService';
|
|
206
|
+
|
|
207
|
+
// 2. Register any manual services
|
|
208
|
+
serviceCollection.register(ConfigService, {
|
|
209
|
+
inject: [],
|
|
210
|
+
instance: { apiUrl: '/api/v1' },
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
// 3. Define custom elements (components can now resolve services)
|
|
214
|
+
import { UserPanel } from './components/UserPanel';
|
|
215
|
+
customElements.define('user-panel', UserPanel);
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
## Resolving Dependencies
|
|
219
|
+
|
|
220
|
+
```typescript
|
|
221
|
+
// By class
|
|
222
|
+
const service = container.resolve(MyService);
|
|
223
|
+
|
|
224
|
+
// By string key
|
|
225
|
+
const cache = container.resolve<CacheService>('primaryCache');
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
## Error Handling
|
|
229
|
+
|
|
230
|
+
All DI errors go through the global [`onError`](Errors.md) handler, so you can log, display, or suppress them.
|
|
231
|
+
|
|
232
|
+
### Resolution Errors
|
|
233
|
+
|
|
234
|
+
Thrown when `resolve()` cannot find a registered service.
|
|
235
|
+
|
|
236
|
+
| Field | Description |
|
|
237
|
+
|-------|-------------|
|
|
238
|
+
| `service` | The class name or string key that was requested |
|
|
239
|
+
| `registeredTypes` | Array of all registered class names |
|
|
240
|
+
| `registeredKeys` | Array of all registered string keys |
|
|
241
|
+
|
|
242
|
+
```
|
|
243
|
+
RelaxError: Failed to resolve service 'MyService'
|
|
244
|
+
{ service: 'MyService', registeredTypes: ['LoggerService', 'ConfigService'], registeredKeys: ['primaryCache'] }
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
### Registration Errors
|
|
248
|
+
|
|
249
|
+
Thrown during `register()` or `registerByType()` to catch configuration mistakes early.
|
|
250
|
+
|
|
251
|
+
| Error | Context | Cause |
|
|
252
|
+
|-------|---------|-------|
|
|
253
|
+
| Service name collision | `{ service }` | Two different classes registered with the same class name |
|
|
254
|
+
| Service key already registered | `{ key, existingClass, newClass }` | A string key is reused for a different class |
|
|
255
|
+
| Instance and inject conflict | `{ service }` | Both `instance` and non-empty `inject` provided (`inject` is ignored) |
|
|
256
|
+
|
|
257
|
+
### Suppressing Errors
|
|
258
|
+
|
|
259
|
+
```typescript
|
|
260
|
+
import { onError } from '@relax.js/core/utils';
|
|
261
|
+
|
|
262
|
+
onError((error, ctx) => {
|
|
263
|
+
if (error.context.service === 'OptionalPlugin') {
|
|
264
|
+
ctx.suppress();
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
console.error(error.message, error.context);
|
|
268
|
+
});
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
## Best Practices
|
|
272
|
+
|
|
273
|
+
1. **Register early**: Register all services at application startup
|
|
274
|
+
2. **Prefer constructor injection**: More explicit than property injection
|
|
275
|
+
3. **Use global scope for stateless services**: Like loggers, config
|
|
276
|
+
4. **Use closest scope for request-specific data**: Like user context
|
|
277
|
+
5. **Avoid circular dependencies**: Restructure to use events or mediators
|