@illuma/core 1.0.0
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/CHANGELOG.md +46 -0
- package/README.md +164 -0
- package/dist/index.cjs +1089 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +378 -0
- package/dist/index.d.ts +378 -0
- package/dist/index.js +1045 -0
- package/dist/index.js.map +1 -0
- package/dist/injection-CSxu56ds.d.cts +57 -0
- package/dist/injection-Y_bVmBSk.d.ts +57 -0
- package/dist/plugin-container-CwkVlVS4.d.ts +136 -0
- package/dist/plugin-container-D8Zwpigq.d.cts +136 -0
- package/dist/plugins.cjs +80 -0
- package/dist/plugins.cjs.map +1 -0
- package/dist/plugins.d.cts +9 -0
- package/dist/plugins.d.ts +9 -0
- package/dist/plugins.js +54 -0
- package/dist/plugins.js.map +1 -0
- package/dist/providers-D9YA8L_g.d.cts +153 -0
- package/dist/providers-D9YA8L_g.d.ts +153 -0
- package/dist/testkit.cjs +995 -0
- package/dist/testkit.cjs.map +1 -0
- package/dist/testkit.d.cts +44 -0
- package/dist/testkit.d.ts +44 -0
- package/dist/testkit.js +970 -0
- package/dist/testkit.js.map +1 -0
- package/package.json +74 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,378 @@
|
|
|
1
|
+
import { N as NodeBase, P as Provider, T as Token, M as MultiNodeToken, a as NodeToken, C as Ctor } from './providers-D9YA8L_g.js';
|
|
2
|
+
export { e as extractToken, g as iNodeAliasProvider, f as iNodeClassProvider, d as iNodeFactoryProvider, h as iNodeProvider, b as iNodeTokenBaseOptions, c as iNodeValueProvider, i as isNodeBase } from './providers-D9YA8L_g.js';
|
|
3
|
+
export { E as ExtractInjectedType, N as NodeInjectFn, i as iNodeInjectorOptions, n as nodeInject } from './injection-Y_bVmBSk.js';
|
|
4
|
+
import { i as iInjectionNode, T as TreeNode, I as Illuma } from './plugin-container-CwkVlVS4.js';
|
|
5
|
+
|
|
6
|
+
/** @internal */
|
|
7
|
+
type InjectorFn = (token: NodeBase<any>, optional?: boolean) => any;
|
|
8
|
+
/**
|
|
9
|
+
* Internal context manager for tracking dependency injections during factory execution.
|
|
10
|
+
* This class manages the injection context lifecycle and tracks all injection calls.
|
|
11
|
+
*
|
|
12
|
+
* @internal
|
|
13
|
+
*/
|
|
14
|
+
declare abstract class InjectionContext {
|
|
15
|
+
static contextOpen: boolean;
|
|
16
|
+
static readonly _calls: Set<iInjectionNode<any>>;
|
|
17
|
+
static injector: InjectorFn | null;
|
|
18
|
+
private static readonly _scanners;
|
|
19
|
+
/**
|
|
20
|
+
* Adds a dependency to the current injection context.
|
|
21
|
+
* Called by `nodeInject` when a dependency is requested.
|
|
22
|
+
*
|
|
23
|
+
* @param node - The injection node representing the dependency
|
|
24
|
+
* @throws {InjectionError} If called outside of an active injection context
|
|
25
|
+
*/
|
|
26
|
+
static addDep(node: iInjectionNode<any>): void;
|
|
27
|
+
/**
|
|
28
|
+
* Opens a new injection context.
|
|
29
|
+
* Resets the calls set and sets the injector if provided.
|
|
30
|
+
*
|
|
31
|
+
* @param injector - Optional injector function to use for resolving dependencies
|
|
32
|
+
*/
|
|
33
|
+
/**
|
|
34
|
+
* Scans a factory function for dependencies.
|
|
35
|
+
* Executes the factory in a dry-run mode to capture `nodeInject` calls.
|
|
36
|
+
* Also runs registered context scanners.
|
|
37
|
+
*
|
|
38
|
+
* @param factory - The factory function to scan
|
|
39
|
+
* @returns A set of detected injection nodes
|
|
40
|
+
*/
|
|
41
|
+
static open(injector?: InjectorFn): void;
|
|
42
|
+
static scan(factory: any): Set<iInjectionNode<any>>;
|
|
43
|
+
static instantiate<T>(factory: () => T, injector: InjectorFn): T;
|
|
44
|
+
static closeAndReport(): Set<iInjectionNode<any>>;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Interface for dependency injection containers.
|
|
49
|
+
* Defines the core methods that all DI containers must implement.
|
|
50
|
+
*/
|
|
51
|
+
interface iDIContainer {
|
|
52
|
+
/**
|
|
53
|
+
* Registers a provider in the container.
|
|
54
|
+
* @template T - The type of value being provided
|
|
55
|
+
* @param provider - The provider configuration
|
|
56
|
+
*/
|
|
57
|
+
provide<T>(provider: Provider<T>): void;
|
|
58
|
+
/**
|
|
59
|
+
* @internal Finds the tree node associated with the given token.
|
|
60
|
+
* @template T - The type of value being searched
|
|
61
|
+
* @param token - The token or constructor to find
|
|
62
|
+
* @returns The associated tree node, or null if not found
|
|
63
|
+
*/
|
|
64
|
+
findNode<T>(token: Token<T>): TreeNode<T> | null;
|
|
65
|
+
/**
|
|
66
|
+
* Retrieves an instance for the given token.
|
|
67
|
+
* @template T - The type of value being retrieved
|
|
68
|
+
* @param token - The token or constructor to retrieve
|
|
69
|
+
* @returns The resolved instance
|
|
70
|
+
*/
|
|
71
|
+
get<T>(token: MultiNodeToken<T>): T[];
|
|
72
|
+
get<T>(token: NodeToken<T>): T;
|
|
73
|
+
get<T>(token: Ctor<T>): T;
|
|
74
|
+
produce<T>(fn: Ctor<T> | (() => T)): T;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Symbol used to mark classes as injectable and store their associated token.
|
|
79
|
+
* @internal
|
|
80
|
+
*/
|
|
81
|
+
declare const INJECTION_SYMBOL: unique symbol;
|
|
82
|
+
/**
|
|
83
|
+
* Decorator that marks a class as injectable in the dependency injection system.
|
|
84
|
+
* Automatically creates and associates a NodeToken with the class.
|
|
85
|
+
*
|
|
86
|
+
* @template T - The type of the class being decorated
|
|
87
|
+
* @returns A class decorator function
|
|
88
|
+
*
|
|
89
|
+
* @example
|
|
90
|
+
* ```typescript
|
|
91
|
+
* @NodeInjectable()
|
|
92
|
+
* class UserService {
|
|
93
|
+
* public getUser() {
|
|
94
|
+
* return { id: 1, name: 'John' };
|
|
95
|
+
* }
|
|
96
|
+
* }
|
|
97
|
+
*
|
|
98
|
+
* container.provide(UserService);
|
|
99
|
+
* container.bootstrap();
|
|
100
|
+
* const service = container.get(UserService);
|
|
101
|
+
* ```
|
|
102
|
+
*/
|
|
103
|
+
declare function NodeInjectable<T>(): (ctor: Ctor<T>) => Ctor<T>;
|
|
104
|
+
/**
|
|
105
|
+
* Alternative function to mark a class as injectable in the dependency injection system for environments
|
|
106
|
+
* that do not support decorators.
|
|
107
|
+
* @param ctor
|
|
108
|
+
* @returns
|
|
109
|
+
*
|
|
110
|
+
* @example
|
|
111
|
+
* ```typescript
|
|
112
|
+
* import { makeInjectable } from '@illuma/core';
|
|
113
|
+
*
|
|
114
|
+
* class _UserService {
|
|
115
|
+
* public getUser() {
|
|
116
|
+
* return { id: 1, name: "John Doe" };
|
|
117
|
+
* }
|
|
118
|
+
* }
|
|
119
|
+
*
|
|
120
|
+
* export type UserService = _UserService;
|
|
121
|
+
* export const UserService = makeInjectable(_UserService);
|
|
122
|
+
* ```
|
|
123
|
+
*/
|
|
124
|
+
declare function makeInjectable<T>(ctor: Ctor<T>): Ctor<T>;
|
|
125
|
+
/** @internal */
|
|
126
|
+
declare function isInjectable<T>(ctor: unknown): ctor is Ctor<T> & {
|
|
127
|
+
[INJECTION_SYMBOL]: NodeToken<T>;
|
|
128
|
+
};
|
|
129
|
+
/** @internal */
|
|
130
|
+
declare function getInjectableToken<T>(ctor: Ctor<T> & {
|
|
131
|
+
[INJECTION_SYMBOL]: NodeToken<T>;
|
|
132
|
+
}): NodeToken<T>;
|
|
133
|
+
declare function isConstructor(fn: unknown): fn is Ctor<any>;
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Configuration options for the NodeContainer.
|
|
137
|
+
*/
|
|
138
|
+
interface iContainerOptions {
|
|
139
|
+
/**
|
|
140
|
+
* When true, logs the bootstrap time to the console based on performance.now()
|
|
141
|
+
* difference before and after bootstrap.
|
|
142
|
+
* @default false
|
|
143
|
+
*/
|
|
144
|
+
measurePerformance?: boolean;
|
|
145
|
+
diagnostics?: boolean;
|
|
146
|
+
parent?: iDIContainer;
|
|
147
|
+
}
|
|
148
|
+
declare class NodeContainer extends Illuma implements iDIContainer {
|
|
149
|
+
private readonly _opts?;
|
|
150
|
+
private _bootstrapped;
|
|
151
|
+
private _rootNode?;
|
|
152
|
+
private readonly _parent?;
|
|
153
|
+
private readonly _protoNodes;
|
|
154
|
+
private readonly _multiProtoNodes;
|
|
155
|
+
constructor(_opts?: iContainerOptions | undefined);
|
|
156
|
+
/**
|
|
157
|
+
* Registers a provider in the container.
|
|
158
|
+
* Must be called before {@link bootstrap}.
|
|
159
|
+
*
|
|
160
|
+
* @template T - The type of value being provided
|
|
161
|
+
* @param provider - The provider configuration (token, class, or provider object)
|
|
162
|
+
* @throws {InjectionError} If called after bootstrap or if a duplicate provider is detected
|
|
163
|
+
*
|
|
164
|
+
* @example
|
|
165
|
+
* ```typescript
|
|
166
|
+
* // Provide a value
|
|
167
|
+
* container.provide({ provide: CONFIG_TOKEN, value: { apiKey: '123' } });
|
|
168
|
+
*
|
|
169
|
+
* // Provide a factory
|
|
170
|
+
* container.provide({ provide: LOGGER_TOKEN, factory: () => new ConsoleLogger() });
|
|
171
|
+
*
|
|
172
|
+
* // Provide an injectable class directly
|
|
173
|
+
* container.provide(UserService);
|
|
174
|
+
*
|
|
175
|
+
* // Provide a class override
|
|
176
|
+
* container.provide({ provide: ServiceClass, useClass: ServiceOverride });
|
|
177
|
+
* ```
|
|
178
|
+
*/
|
|
179
|
+
provide<T>(provider: Provider<T>): void;
|
|
180
|
+
findNode<T>(token: Token<T>): TreeNode<T> | null;
|
|
181
|
+
private _getFromParent;
|
|
182
|
+
private _buildInjectionTree;
|
|
183
|
+
/**
|
|
184
|
+
* Bootstraps the container by resolving the dependency trees and instantiating all providers.
|
|
185
|
+
* This must be called after all providers are registered and before calling {@link get}.
|
|
186
|
+
*
|
|
187
|
+
* The bootstrap process:
|
|
188
|
+
* 1. Validates all provider registrations
|
|
189
|
+
* 2. Builds dependency injection trees
|
|
190
|
+
* 3. Detects circular dependencies in each tree
|
|
191
|
+
* 4. Instantiates all dependencies in the correct order
|
|
192
|
+
*
|
|
193
|
+
* @throws {InjectionError} If the container is already bootstrapped or if circular dependencies are detected
|
|
194
|
+
*
|
|
195
|
+
* @example
|
|
196
|
+
* ```typescript
|
|
197
|
+
* const container = new NodeContainer();
|
|
198
|
+
* container.provide(UserService);
|
|
199
|
+
* container.provide(LoggerService);
|
|
200
|
+
* container.bootstrap(); // Resolves and instantiates all dependencies
|
|
201
|
+
* ```
|
|
202
|
+
*/
|
|
203
|
+
bootstrap(): void;
|
|
204
|
+
/**
|
|
205
|
+
* Retrieves an instance from the container.
|
|
206
|
+
* Must be called after {@link bootstrap}.
|
|
207
|
+
*
|
|
208
|
+
* @template T - The type of value being retrieved (typically inferred)
|
|
209
|
+
* @param token - The token or class to retrieve
|
|
210
|
+
* @returns For NodeToken: a single instance. For MultiNodeToken: an array of instances.
|
|
211
|
+
* @throws {InjectionError} If called before bootstrap or if the token is not found
|
|
212
|
+
*
|
|
213
|
+
* @example
|
|
214
|
+
* ```typescript
|
|
215
|
+
* // Get a single provider
|
|
216
|
+
* const logger = container.get(LoggerToken);
|
|
217
|
+
*
|
|
218
|
+
* // Get a decorated class
|
|
219
|
+
* const service = container.get(UserService);
|
|
220
|
+
*
|
|
221
|
+
* // Get multiple providers
|
|
222
|
+
* const plugins = container.get(PluginToken); // Returns array
|
|
223
|
+
* ```
|
|
224
|
+
*/
|
|
225
|
+
get<T>(token: MultiNodeToken<T>): T[];
|
|
226
|
+
get<T>(token: NodeToken<T>): T;
|
|
227
|
+
get<T>(token: Ctor<T>): T;
|
|
228
|
+
/**
|
|
229
|
+
* Instantiates a class outside injection context. Primarily used to create instances via Injector.
|
|
230
|
+
* Class does not get registered in the container and cannot be retrieved via {@link get} or {@link nodeInject}.
|
|
231
|
+
* Must be called after {@link bootstrap}.
|
|
232
|
+
*
|
|
233
|
+
* @template T - The type of the class being instantiated
|
|
234
|
+
* @param factory - Factory or class constructor to instantiate
|
|
235
|
+
* @returns A new instance of the class with dependencies injected
|
|
236
|
+
* @throws {InjectionError} If called before bootstrap or if the constructor is invalid
|
|
237
|
+
*/
|
|
238
|
+
produce<T>(fn: Ctor<T> | (() => T)): T;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
declare class InjectionError extends Error {
|
|
242
|
+
readonly code: number;
|
|
243
|
+
constructor(code: number, message: string);
|
|
244
|
+
static duplicate(token: NodeBase<unknown>): InjectionError;
|
|
245
|
+
static duplicateFactory(token: NodeBase<unknown>): InjectionError;
|
|
246
|
+
static invalidCtor(ctor: Ctor<unknown>): InjectionError;
|
|
247
|
+
static invalidProvider(provider: string): InjectionError;
|
|
248
|
+
static invalidAlias(alias: unknown): InjectionError;
|
|
249
|
+
static loopAlias(alias: NodeBase<unknown>): InjectionError;
|
|
250
|
+
static notBootstrapped(): InjectionError;
|
|
251
|
+
static bootstrapped(): InjectionError;
|
|
252
|
+
static doubleBootstrap(): InjectionError;
|
|
253
|
+
static notFound(token: NodeBase<unknown>): InjectionError;
|
|
254
|
+
static circularDependency(provider: NodeBase<unknown> | Ctor<unknown>, path: (NodeBase<unknown> | Ctor<unknown>)[]): InjectionError;
|
|
255
|
+
static untracked(token: NodeBase<unknown> | Ctor<unknown>, parent: NodeBase<unknown> | Ctor<unknown>): InjectionError;
|
|
256
|
+
static outsideContext(token: NodeBase<unknown> | Ctor<unknown>): InjectionError;
|
|
257
|
+
static calledUtilsOutsideContext(): InjectionError;
|
|
258
|
+
static instanceAccessFailed(token: NodeBase<unknown>): InjectionError;
|
|
259
|
+
static accessFailed(): InjectionError;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
interface iInjector {
|
|
263
|
+
/** The DI container associated with this injector */
|
|
264
|
+
readonly container: iDIContainer;
|
|
265
|
+
/**
|
|
266
|
+
* Retrieves an instance for the given token.
|
|
267
|
+
* @template T - The type of value being retrieved
|
|
268
|
+
* @param token - The token or constructor to retrieve
|
|
269
|
+
* @returns The resolved instance
|
|
270
|
+
*/
|
|
271
|
+
get<T>(token: MultiNodeToken<T>): T[];
|
|
272
|
+
get<T>(token: NodeToken<T>): T;
|
|
273
|
+
get<T>(token: Ctor<T>): T;
|
|
274
|
+
/**
|
|
275
|
+
* Instantiates a class with injections in runtime using current context.
|
|
276
|
+
* Useful when creating an object that requires injections in runtime.
|
|
277
|
+
* Class does not get registered in the container and cannot be retrieved via {@link get} or {@link nodeInject}.
|
|
278
|
+
*
|
|
279
|
+
* @template T - The type of the class being instantiated
|
|
280
|
+
* @param ctor - The constructor of the class to instantiate
|
|
281
|
+
* @returns A new instance of the class with dependencies injected
|
|
282
|
+
* @throws {InjectionError} If called before bootstrap or if the constructor is invalid
|
|
283
|
+
* Must be called after {@link bootstrap}.
|
|
284
|
+
*/
|
|
285
|
+
produce<T>(fn: Ctor<T> | (() => T)): T;
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* Injector implementation that allows retrieving instances from the parent DI container.
|
|
289
|
+
*/
|
|
290
|
+
declare class InjectorImpl implements iInjector {
|
|
291
|
+
readonly container: iDIContainer;
|
|
292
|
+
constructor(container: iDIContainer);
|
|
293
|
+
get<T>(token: MultiNodeToken<T>): T[];
|
|
294
|
+
get<T>(token: NodeToken<T>): T;
|
|
295
|
+
get<T>(token: Ctor<T>): T;
|
|
296
|
+
produce<T>(fn: Ctor<T> | (() => T)): T;
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* Injector node that is used to access provider outside of injection context.
|
|
300
|
+
* @example
|
|
301
|
+
* ```typescript
|
|
302
|
+
* import { Injector, nodeInject, NodeInjectable, NodeContainer } from "@illuma/core";
|
|
303
|
+
*
|
|
304
|
+
* @NodeInjectable()
|
|
305
|
+
* class MyService {
|
|
306
|
+
* private readonly _injector = nodeInject(Injector);
|
|
307
|
+
* public doSomething() {
|
|
308
|
+
* const otherService = this._injector.get(OtherService);
|
|
309
|
+
* // Use otherService...
|
|
310
|
+
* }
|
|
311
|
+
* }
|
|
312
|
+
* ```
|
|
313
|
+
*/
|
|
314
|
+
declare const Injector: NodeToken<iInjector>;
|
|
315
|
+
|
|
316
|
+
type MaybeAsyncFactory<T> = () => T | Promise<T>;
|
|
317
|
+
interface iInjectionOptions {
|
|
318
|
+
/**
|
|
319
|
+
* Whether to cache the result of the injection function
|
|
320
|
+
* Prevents multiple invocations from creating multiple sub-containers or injections
|
|
321
|
+
* @default true
|
|
322
|
+
*/
|
|
323
|
+
withCache?: boolean;
|
|
324
|
+
/**
|
|
325
|
+
* Overrides to provide to the sub-container
|
|
326
|
+
* These will be provided in addition to the main injection
|
|
327
|
+
* @default []
|
|
328
|
+
*/
|
|
329
|
+
overrides?: Provider[];
|
|
330
|
+
}
|
|
331
|
+
/**
|
|
332
|
+
* Creates an async function that injects a group of dependencies as a sub-container.
|
|
333
|
+
* The returned function, when called, will create a new sub-container, provide the given dependencies,
|
|
334
|
+
* bootstrap it, and return its injector.
|
|
335
|
+
*
|
|
336
|
+
* @note
|
|
337
|
+
* `injectGroupAsync` should be called within an injection context where the parent container is accessible.
|
|
338
|
+
*
|
|
339
|
+
* @param fn - A function that returns an array of providers or a promise resolving to one
|
|
340
|
+
* @returns A function that returns a promise resolving to the injector of the sub-container
|
|
341
|
+
*/
|
|
342
|
+
declare function injectGroupAsync(fn: MaybeAsyncFactory<Provider[]>, opts?: iInjectionOptions): () => Promise<iInjector>;
|
|
343
|
+
/**
|
|
344
|
+
* Creates an async function that injects a dependency for the given token or constructor.
|
|
345
|
+
* The returned function, when called, will create a new sub-container,
|
|
346
|
+
* provide the token or constructor, bootstrap it, and return the resolved instance(s).
|
|
347
|
+
*
|
|
348
|
+
* @note
|
|
349
|
+
* `injectAsync` should be called within an injection context where the parent container is accessible.
|
|
350
|
+
*
|
|
351
|
+
* @template T - The type of value being injected
|
|
352
|
+
* @param fn - A function that returns a token, constructor, or a promise resolving to one
|
|
353
|
+
* @returns A function that returns a promise resolving to the injected instance(s)
|
|
354
|
+
*/
|
|
355
|
+
declare function injectAsync<T>(fn: MaybeAsyncFactory<MultiNodeToken<T>>, opts?: iInjectionOptions): () => Promise<T[]>;
|
|
356
|
+
declare function injectAsync<T>(fn: MaybeAsyncFactory<NodeToken<T>>, opts?: iInjectionOptions): () => Promise<T>;
|
|
357
|
+
declare function injectAsync<T>(fn: MaybeAsyncFactory<Ctor<T>>, opts?: iInjectionOptions): () => Promise<T>;
|
|
358
|
+
interface iEntrypointConfig<T extends Token<any>> {
|
|
359
|
+
readonly entrypoint: T;
|
|
360
|
+
readonly providers: Provider[];
|
|
361
|
+
}
|
|
362
|
+
/**
|
|
363
|
+
* Creates an async function that injects a sub-container with a specific entrypoint.
|
|
364
|
+
* The returned function, when called, will create a new sub-container,
|
|
365
|
+
* provide the given providers, bootstrap it, and return the resolved instance(s) of the entrypoint.
|
|
366
|
+
*
|
|
367
|
+
* @note
|
|
368
|
+
* `injectEntryAsync` should be called within an injection context where the parent container is accessible.
|
|
369
|
+
*
|
|
370
|
+
* @template T - The type of the entrypoint token
|
|
371
|
+
* @param fn - A function that returns an entrypoint configuration or a promise resolving to one
|
|
372
|
+
* @returns A function that returns a promise resolving to the injected instance(s) of the entrypoint
|
|
373
|
+
*/
|
|
374
|
+
declare function injectEntryAsync<T>(fn: MaybeAsyncFactory<iEntrypointConfig<NodeToken<T>>>, opts?: iInjectionOptions): () => Promise<T[]>;
|
|
375
|
+
declare function injectEntryAsync<T>(fn: MaybeAsyncFactory<iEntrypointConfig<Ctor<T>>>, opts?: iInjectionOptions): () => Promise<T>;
|
|
376
|
+
declare function injectEntryAsync<T>(fn: MaybeAsyncFactory<iEntrypointConfig<MultiNodeToken<T>>>, opts?: iInjectionOptions): () => Promise<T>;
|
|
377
|
+
|
|
378
|
+
export { Ctor, INJECTION_SYMBOL, InjectionContext, InjectionError, Injector, type InjectorFn, InjectorImpl, MultiNodeToken, NodeBase, NodeContainer, NodeInjectable, NodeToken, Provider, Token, getInjectableToken, type iDIContainer, type iEntrypointConfig, iInjectionNode, type iInjector, injectAsync, injectEntryAsync, injectGroupAsync, isConstructor, isInjectable, makeInjectable };
|