@navios/di 0.1.6 → 0.1.8

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,2 +1,80 @@
1
1
  # Navios DI
2
2
 
3
+ Navios DI is a library that implements the Dependency Injection pattern. It provides you with basic tools to create and manage your services
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @navios/di
9
+ # or
10
+ yarn add @navios/di
11
+ ```
12
+
13
+ ## Simple Usage example
14
+
15
+ ```ts
16
+ import { Injectable, inject, syncInject } from '@navios/di';
17
+
18
+ @Injectable()
19
+ class GreeterService {
20
+ getFoo(user: string): string {
21
+ return `Hello ${user}`;
22
+ }
23
+ }
24
+
25
+ @Injectable()
26
+ class UserService {
27
+ private readonly greeterService = syncInject(GreeterService);
28
+
29
+ greet(user: string): string {
30
+ return this.greeterService.getFoo(user);
31
+ }
32
+ }
33
+
34
+ const userService = await inject(UserService);
35
+
36
+ console.log(userService.greet('World')); // Hello World
37
+ ```
38
+
39
+ ## Usage with Injection Token
40
+
41
+ ```ts
42
+ import { Injectable, inject, syncInject, InjectionToken } from '@navios/di';
43
+ import { z } from 'zod';
44
+
45
+ const schema = z.object({
46
+ user: z.string(),
47
+ })
48
+
49
+ interface GreeterInterface {
50
+ getFoo(): string;
51
+ }
52
+
53
+ const token = new InjectionToken.create<GreeterInterface, typeof schema>(
54
+ Symbol.for('user'),
55
+ schema,
56
+ )
57
+
58
+ @Injectable({
59
+ token,
60
+ })
61
+ class GreeterService {
62
+ constructor(private readonly config: z.infer<typeof schema>) {}
63
+
64
+ getFoo(): string {
65
+ return `Hello ${this.config.user}`;
66
+ }
67
+ }
68
+
69
+ const greetWorld = await inject(token, {
70
+ user: 'World'
71
+ })
72
+ const BoundGreeterService = InjectionToken.bound(token, {
73
+ user: 'Earth'
74
+ })
75
+
76
+ const greetEarth = await inject(BoundGreeterService);
77
+
78
+ console.log(greetWorld.getFoo()); // Hello World
79
+ console.log(greetEarth.getFoo()); // Hello Earth
80
+ ```
@@ -1,13 +1,18 @@
1
1
  import type { AnyZodObject } from 'zod';
2
2
  import { z } from 'zod';
3
3
  import { ZodOptional } from 'zod';
4
+ import { ZodRecord } from 'zod';
4
5
 
5
- declare class BoundInjectionToken<T, S extends AnyZodObject | ZodOptional<AnyZodObject>> {
6
+ declare type BaseInjectionTokenSchemaType = AnyZodObject | ZodRecord;
7
+ export { BaseInjectionTokenSchemaType }
8
+ export { BaseInjectionTokenSchemaType as BaseInjectionTokenSchemaType_alias_1 }
9
+
10
+ declare class BoundInjectionToken<T, S extends InjectionTokenSchemaType> {
6
11
  readonly token: InjectionToken<T, S>;
7
12
  readonly value: z.input<S>;
8
13
  id: string;
9
14
  name: string | symbol | ClassType;
10
- schema: AnyZodObject | ZodOptional<AnyZodObject>;
15
+ schema: InjectionTokenSchemaType;
11
16
  constructor(token: InjectionToken<T, S>, value: z.input<S>);
12
17
  toString(): string;
13
18
  }
@@ -36,6 +41,14 @@ declare type ClassTypeWithInstanceAndArgument<T, Arg> = new (arg: Arg) => T;
36
41
  export { ClassTypeWithInstanceAndArgument }
37
42
  export { ClassTypeWithInstanceAndArgument as ClassTypeWithInstanceAndArgument_alias_1 }
38
43
 
44
+ declare type ClassTypeWithInstanceAndOptionalArgument<T, Arg> = new (arg?: Arg) => T;
45
+ export { ClassTypeWithInstanceAndOptionalArgument }
46
+ export { ClassTypeWithInstanceAndOptionalArgument as ClassTypeWithInstanceAndOptionalArgument_alias_1 }
47
+
48
+ declare type ClassTypeWithOptionalArgument<Arg> = new (arg?: Arg) => any;
49
+ export { ClassTypeWithOptionalArgument }
50
+ export { ClassTypeWithOptionalArgument as ClassTypeWithOptionalArgument_alias_1 }
51
+
39
52
  declare interface CreateInjectorsOptions {
40
53
  baseLocator: ServiceLocator;
41
54
  }
@@ -89,7 +102,7 @@ export { EventsNames }
89
102
  export { EventsNames as EventsNames_alias_1 }
90
103
 
91
104
  declare interface Factory<T> {
92
- create(ctx?: any): Promise<T> | T;
105
+ create(ctx?: FactoryContext): Promise<T> | T;
93
106
  }
94
107
  export { Factory }
95
108
  export { Factory as Factory_alias_1 }
@@ -109,14 +122,14 @@ declare interface FactoryContext {
109
122
  export { FactoryContext }
110
123
  export { FactoryContext as FactoryContext_alias_1 }
111
124
 
112
- declare class FactoryInjectionToken<T, S extends AnyZodObject | ZodOptional<AnyZodObject>> {
125
+ declare class FactoryInjectionToken<T, S extends InjectionTokenSchemaType> {
113
126
  readonly token: InjectionToken<T, S>;
114
127
  readonly factory: () => Promise<z.input<S>>;
115
128
  value?: z.input<S>;
116
129
  resolved: boolean;
117
130
  id: string;
118
131
  name: string | symbol | ClassType;
119
- schema: AnyZodObject | ZodOptional<AnyZodObject>;
132
+ schema: InjectionTokenSchemaType;
120
133
  constructor(token: InjectionToken<T, S>, factory: () => Promise<z.input<S>>);
121
134
  resolve(): Promise<z.input<S>>;
122
135
  toString(): string;
@@ -149,8 +162,8 @@ export { FactoryTokenNotResolved }
149
162
  export { FactoryTokenNotResolved as FactoryTokenNotResolved_alias_1 }
150
163
  export { FactoryTokenNotResolved as FactoryTokenNotResolved_alias_2 }
151
164
 
152
- declare interface FactoryWithArgs<T, A extends AnyZodObject> {
153
- create(ctx: any, args: z.output<A>): Promise<T> | T;
165
+ declare interface FactoryWithArgs<T, A extends InjectionTokenSchemaType> {
166
+ create(...args: [FactoryContext, z.output<A>]): Promise<T> | T;
154
167
  }
155
168
  export { FactoryWithArgs }
156
169
  export { FactoryWithArgs as FactoryWithArgs_alias_1 }
@@ -187,38 +200,17 @@ declare function Injectable<R>(options: {
187
200
  type: InjectableType.Factory;
188
201
  }): <T extends ClassTypeWithInstance<Factory<R>>>(target: T, context: ClassDecoratorContext) => T;
189
202
 
190
- declare function Injectable<S extends AnyZodObject>(options: {
191
- scope?: InjectableScope;
192
- type?: InjectableType.Class;
193
- token: InjectionToken<undefined, S>;
194
- }): <T extends ClassTypeWithArgument<z.output<S>>>(target: T, context: ClassDecoratorContext) => T;
195
-
196
- declare function Injectable<R, S extends AnyZodObject>(options: {
203
+ declare function Injectable<Type, Schema>(options: {
197
204
  scope?: InjectableScope;
198
205
  type?: InjectableType.Class;
199
- token: InjectionToken<R, S>;
200
- }): <T extends ClassTypeWithInstanceAndArgument<R, z.output<S>>>(target: T, context: ClassDecoratorContext) => T;
206
+ token: InjectionToken<Type, Schema>;
207
+ }): Schema extends BaseInjectionTokenSchemaType ? Type extends undefined ? <T extends ClassTypeWithArgument<z.output<Schema>>>(target: T, context: ClassDecoratorContext) => T : <T extends ClassTypeWithInstanceAndArgument<Type, z.output<Schema>>>(target: T, context: ClassDecoratorContext) => T : Schema extends OptionalInjectionTokenSchemaType ? Type extends undefined ? <T extends ClassTypeWithOptionalArgument<z.output<Schema>>>(target: T, context: ClassDecoratorContext) => T : <T extends ClassTypeWithInstanceAndOptionalArgument<Type, z.output<Schema>>>(target: T, context: ClassDecoratorContext) => T : Schema extends undefined ? <R extends ClassTypeWithInstance<Type>>(target: R, context: ClassDecoratorContext) => R : never;
201
208
 
202
- declare function Injectable<T extends ClassType>(options: {
203
- scope?: InjectableScope;
204
- token: InjectionToken<T, undefined>;
205
- }): (target: T, context: ClassDecoratorContext) => T;
206
-
207
- declare function Injectable<R, S extends AnyZodObject>(options: {
209
+ declare function Injectable<R, S>(options: {
208
210
  scope?: InjectableScope;
209
211
  type: InjectableType.Factory;
210
212
  token: InjectionToken<R, S>;
211
- }): <T extends ClassTypeWithInstance<FactoryWithArgs<R, S>>>(target: T, context: ClassDecoratorContext) => T & {
212
- [InjectableTokenMeta]: InjectionToken<R, S>;
213
- };
214
-
215
- declare function Injectable<R>(options: {
216
- scope?: InjectableScope;
217
- type: InjectableType.Factory;
218
- token: InjectionToken<R, undefined>;
219
- }): <T extends ClassTypeWithInstance<Factory<R>>>(target: T, context: ClassDecoratorContext) => T & {
220
- [InjectableTokenMeta]: InjectionToken<R, undefined>;
221
- };
213
+ }): R extends undefined ? never : S extends InjectionTokenSchemaType ? <T extends ClassTypeWithInstance<FactoryWithArgs<R, S>>>(target: T, context: ClassDecoratorContext) => T : S extends undefined ? <T extends ClassTypeWithInstance<Factory<R>>>(target: T, context: ClassDecoratorContext) => T : never;
222
214
  export { Injectable }
223
215
  export { Injectable as Injectable_alias_1 }
224
216
  export { Injectable as Injectable_alias_2 }
@@ -264,34 +256,38 @@ declare type InjectionFactory<T = unknown, Args = unknown> = (ctx: FactoryContex
264
256
  export { InjectionFactory }
265
257
  export { InjectionFactory as InjectionFactory_alias_1 }
266
258
 
267
- declare class InjectionToken<T, S extends AnyZodObject | ZodOptional<AnyZodObject> | unknown = unknown> {
259
+ declare class InjectionToken<T, S extends InjectionTokenSchemaType | unknown = unknown> {
268
260
  readonly name: string | symbol | ClassType;
269
261
  readonly schema: AnyZodObject | undefined;
270
262
  id: `${string}-${string}-${string}-${string}-${string}`;
271
263
  private formattedName;
272
264
  constructor(name: string | symbol | ClassType, schema: AnyZodObject | undefined);
273
265
  static create<T extends ClassType>(name: T): InjectionToken<InstanceType<T>, undefined>;
274
- static create<T extends ClassType, Schema extends AnyZodObject | ZodOptional<AnyZodObject>>(name: T, schema: Schema): InjectionToken<InstanceType<T>, Schema>;
266
+ static create<T extends ClassType, Schema extends InjectionTokenSchemaType>(name: T, schema: Schema): InjectionToken<InstanceType<T>, Schema>;
275
267
  static create<T>(name: string | symbol): InjectionToken<T, undefined>;
276
- static create<T, Schema extends AnyZodObject | ZodOptional<AnyZodObject>>(name: string | any, schema: Schema): InjectionToken<T, Schema>;
277
- static bound<T, S extends AnyZodObject | ZodOptional<AnyZodObject>>(token: InjectionToken<T, S>, value: z.input<S>): BoundInjectionToken<T, S>;
278
- static factory<T, S extends AnyZodObject | ZodOptional<AnyZodObject>>(token: InjectionToken<T, S>, factory: () => Promise<z.input<S>>): FactoryInjectionToken<T, S>;
268
+ static create<T, Schema extends InjectionTokenSchemaType>(name: string | any, schema: Schema): InjectionToken<T, Schema>;
269
+ static bound<T, S extends InjectionTokenSchemaType>(token: InjectionToken<T, S>, value: z.input<S>): BoundInjectionToken<T, S>;
270
+ static factory<T, S extends InjectionTokenSchemaType>(token: InjectionToken<T, S>, factory: () => Promise<z.input<S>>): FactoryInjectionToken<T, S>;
279
271
  static refineType<T>(token: BoundInjectionToken<any, any>): BoundInjectionToken<T, any>;
280
272
  toString(): string;
281
273
  }
282
274
  export { InjectionToken }
283
275
  export { InjectionToken as InjectionToken_alias_1 }
284
276
 
277
+ declare type InjectionTokenSchemaType = BaseInjectionTokenSchemaType | OptionalInjectionTokenSchemaType;
278
+ export { InjectionTokenSchemaType }
279
+ export { InjectionTokenSchemaType as InjectionTokenSchemaType_alias_1 }
280
+
285
281
  declare interface Injectors {
286
282
  inject<T extends ClassType>(token: T): Promise<InstanceType<T>>;
287
- inject<T, S extends AnyZodObject>(token: InjectionToken<T, S>, args: z.input<S>): Promise<T>;
288
- inject<T, S extends ZodOptional<AnyZodObject>>(token: InjectionToken<T, S>, args?: z.input<S>): Promise<T>;
283
+ inject<T, S extends BaseInjectionTokenSchemaType>(token: InjectionToken<T, S>, args: z.input<S>): Promise<T>;
284
+ inject<T, S extends OptionalInjectionTokenSchemaType>(token: InjectionToken<T, S>, args?: z.input<S>): Promise<T>;
289
285
  inject<T>(token: InjectionToken<T, undefined>): Promise<T>;
290
286
  inject<T>(token: BoundInjectionToken<T, any>): Promise<T>;
291
287
  inject<T>(token: FactoryInjectionToken<T, any>): Promise<T>;
292
288
  syncInject<T extends ClassType>(token: T): InstanceType<T>;
293
- syncInject<T, S extends AnyZodObject>(token: InjectionToken<T, S>, args: z.input<S>): T;
294
- syncInject<T, S extends ZodOptional<AnyZodObject>>(token: InjectionToken<T, S>, args?: z.input<S>): T;
289
+ syncInject<T, S extends BaseInjectionTokenSchemaType>(token: InjectionToken<T, S>, args: z.input<S>): T;
290
+ syncInject<T, S extends OptionalInjectionTokenSchemaType>(token: InjectionToken<T, S>, args?: z.input<S>): T;
295
291
  syncInject<T>(token: InjectionToken<T, undefined>): T;
296
292
  syncInject<T>(token: BoundInjectionToken<T, any>): T;
297
293
  syncInject<T>(token: FactoryInjectionToken<T, any>): T;
@@ -338,6 +334,10 @@ declare function makeProxyServiceLocator(serviceLocator: ServiceLocator, ctx: Fa
338
334
  export { makeProxyServiceLocator }
339
335
  export { makeProxyServiceLocator as makeProxyServiceLocator_alias_1 }
340
336
 
337
+ declare type OptionalInjectionTokenSchemaType = ZodOptional<AnyZodObject> | ZodOptional<ZodRecord>;
338
+ export { OptionalInjectionTokenSchemaType }
339
+ export { OptionalInjectionTokenSchemaType as OptionalInjectionTokenSchemaType_alias_1 }
340
+
341
341
  declare const provideServiceLocator: Injectors['provideServiceLocator'];
342
342
  export { provideServiceLocator }
343
343
  export { provideServiceLocator as provideServiceLocator_alias_1 }
@@ -387,24 +387,25 @@ declare class ServiceLocator {
387
387
  removeInstance<Instance>(token: BoundInjectionToken<Instance, any>): void;
388
388
  removeInstance<Instance>(token: FactoryInjectionToken<Instance, any>): void;
389
389
  removeInstance<Instance>(token: InjectionToken<Instance, undefined>): void;
390
- removeInstance<Instance, Schema extends AnyZodObject | ZodOptional<AnyZodObject>>(token: InjectionToken<Instance, Schema>, args: z.input<Schema>): void;
390
+ removeInstance<Instance, Schema extends BaseInjectionTokenSchemaType>(token: InjectionToken<Instance, Schema>, args: z.input<Schema>): void;
391
+ removeInstance<Instance, Schema extends OptionalInjectionTokenSchemaType>(token: InjectionToken<Instance, Schema>, args?: z.input<Schema>): void;
391
392
  private resolveTokenArgs;
392
- getInstanceIdentifier<Instance, Schema extends AnyZodObject>(token: InjectionToken<Instance, Schema>, args: z.input<Schema>): string;
393
- getInstanceIdentifier<Instance, Schema extends ZodOptional<AnyZodObject>>(token: InjectionToken<Instance, Schema>, args?: z.input<Schema>): string;
393
+ getInstanceIdentifier<Instance, Schema extends BaseInjectionTokenSchemaType>(token: InjectionToken<Instance, Schema>, args: z.input<Schema>): string;
394
+ getInstanceIdentifier<Instance, Schema extends OptionalInjectionTokenSchemaType>(token: InjectionToken<Instance, Schema>, args?: z.input<Schema>): string;
394
395
  getInstanceIdentifier<Instance>(token: InjectionToken<Instance, undefined>): string;
395
396
  getInstanceIdentifier<Instance>(token: BoundInjectionToken<Instance, any>): string;
396
397
  getInstanceIdentifier<Instance>(token: FactoryInjectionToken<Instance, any>): string;
397
- getInstance<Instance, Schema extends AnyZodObject>(token: InjectionToken<Instance, Schema>, args: z.input<Schema>): Promise<[undefined, Instance] | [UnknownError | FactoryNotFound]>;
398
- getInstance<Instance, Schema extends ZodOptional<AnyZodObject>>(token: InjectionToken<Instance, Schema>, args?: z.input<Schema>): Promise<[undefined, Instance] | [UnknownError | FactoryNotFound]>;
398
+ getInstance<Instance, Schema extends BaseInjectionTokenSchemaType>(token: InjectionToken<Instance, Schema>, args: z.input<Schema>): Promise<[undefined, Instance] | [UnknownError | FactoryNotFound]>;
399
+ getInstance<Instance, Schema extends OptionalInjectionTokenSchemaType>(token: InjectionToken<Instance, Schema>, args?: z.input<Schema>): Promise<[undefined, Instance] | [UnknownError | FactoryNotFound]>;
399
400
  getInstance<Instance>(token: InjectionToken<Instance, undefined>): Promise<[undefined, Instance] | [UnknownError | FactoryNotFound]>;
400
401
  getInstance<Instance>(token: BoundInjectionToken<Instance, any>): Promise<[undefined, Instance] | [UnknownError | FactoryNotFound]>;
401
402
  getInstance<Instance>(token: FactoryInjectionToken<Instance, any>): Promise<[undefined, Instance] | [UnknownError | FactoryNotFound]>;
402
- getOrThrowInstance<Instance, Schema extends AnyZodObject | ZodOptional<AnyZodObject> | undefined>(token: InjectionToken<Instance, Schema>, args: Schema extends AnyZodObject ? z.input<Schema> : Schema extends ZodOptional<AnyZodObject> ? z.input<Schema> | undefined : undefined): Promise<Instance>;
403
+ getOrThrowInstance<Instance, Schema extends InjectionTokenSchemaType | undefined>(token: InjectionToken<Instance, Schema>, args: Schema extends AnyZodObject ? z.input<Schema> : Schema extends ZodOptional<AnyZodObject> ? z.input<Schema> | undefined : undefined): Promise<Instance>;
403
404
  private notifyListeners;
404
405
  private createInstance;
405
406
  private resolveInstance;
406
407
  private createFactoryContext;
407
- getSyncInstance<Instance, Schema extends AnyZodObject | ZodOptional<AnyZodObject> | undefined>(token: InjectionToken<Instance, Schema>, args: Schema extends AnyZodObject ? z.input<Schema> : Schema extends ZodOptional<AnyZodObject> ? z.input<Schema> | undefined : undefined): Instance | null;
408
+ getSyncInstance<Instance, Schema extends InjectionTokenSchemaType | undefined>(token: InjectionToken<Instance, Schema>, args: Schema extends AnyZodObject ? z.input<Schema> : Schema extends ZodOptional<AnyZodObject> ? z.input<Schema> | undefined : undefined): Instance | null;
408
409
  invalidate(service: string, round?: number): Promise<any>;
409
410
  ready(): Promise<null>;
410
411
  makeInstanceName(token: InjectionToken<any, any> | BoundInjectionToken<any, any> | FactoryInjectionToken<any, any>, args: any): string;
@@ -1,13 +1,18 @@
1
1
  import type { AnyZodObject } from 'zod';
2
2
  import { z } from 'zod';
3
3
  import { ZodOptional } from 'zod';
4
+ import { ZodRecord } from 'zod';
4
5
 
5
- declare class BoundInjectionToken<T, S extends AnyZodObject | ZodOptional<AnyZodObject>> {
6
+ declare type BaseInjectionTokenSchemaType = AnyZodObject | ZodRecord;
7
+ export { BaseInjectionTokenSchemaType }
8
+ export { BaseInjectionTokenSchemaType as BaseInjectionTokenSchemaType_alias_1 }
9
+
10
+ declare class BoundInjectionToken<T, S extends InjectionTokenSchemaType> {
6
11
  readonly token: InjectionToken<T, S>;
7
12
  readonly value: z.input<S>;
8
13
  id: string;
9
14
  name: string | symbol | ClassType;
10
- schema: AnyZodObject | ZodOptional<AnyZodObject>;
15
+ schema: InjectionTokenSchemaType;
11
16
  constructor(token: InjectionToken<T, S>, value: z.input<S>);
12
17
  toString(): string;
13
18
  }
@@ -36,6 +41,14 @@ declare type ClassTypeWithInstanceAndArgument<T, Arg> = new (arg: Arg) => T;
36
41
  export { ClassTypeWithInstanceAndArgument }
37
42
  export { ClassTypeWithInstanceAndArgument as ClassTypeWithInstanceAndArgument_alias_1 }
38
43
 
44
+ declare type ClassTypeWithInstanceAndOptionalArgument<T, Arg> = new (arg?: Arg) => T;
45
+ export { ClassTypeWithInstanceAndOptionalArgument }
46
+ export { ClassTypeWithInstanceAndOptionalArgument as ClassTypeWithInstanceAndOptionalArgument_alias_1 }
47
+
48
+ declare type ClassTypeWithOptionalArgument<Arg> = new (arg?: Arg) => any;
49
+ export { ClassTypeWithOptionalArgument }
50
+ export { ClassTypeWithOptionalArgument as ClassTypeWithOptionalArgument_alias_1 }
51
+
39
52
  declare interface CreateInjectorsOptions {
40
53
  baseLocator: ServiceLocator;
41
54
  }
@@ -89,7 +102,7 @@ export { EventsNames }
89
102
  export { EventsNames as EventsNames_alias_1 }
90
103
 
91
104
  declare interface Factory<T> {
92
- create(ctx?: any): Promise<T> | T;
105
+ create(ctx?: FactoryContext): Promise<T> | T;
93
106
  }
94
107
  export { Factory }
95
108
  export { Factory as Factory_alias_1 }
@@ -109,14 +122,14 @@ declare interface FactoryContext {
109
122
  export { FactoryContext }
110
123
  export { FactoryContext as FactoryContext_alias_1 }
111
124
 
112
- declare class FactoryInjectionToken<T, S extends AnyZodObject | ZodOptional<AnyZodObject>> {
125
+ declare class FactoryInjectionToken<T, S extends InjectionTokenSchemaType> {
113
126
  readonly token: InjectionToken<T, S>;
114
127
  readonly factory: () => Promise<z.input<S>>;
115
128
  value?: z.input<S>;
116
129
  resolved: boolean;
117
130
  id: string;
118
131
  name: string | symbol | ClassType;
119
- schema: AnyZodObject | ZodOptional<AnyZodObject>;
132
+ schema: InjectionTokenSchemaType;
120
133
  constructor(token: InjectionToken<T, S>, factory: () => Promise<z.input<S>>);
121
134
  resolve(): Promise<z.input<S>>;
122
135
  toString(): string;
@@ -149,8 +162,8 @@ export { FactoryTokenNotResolved }
149
162
  export { FactoryTokenNotResolved as FactoryTokenNotResolved_alias_1 }
150
163
  export { FactoryTokenNotResolved as FactoryTokenNotResolved_alias_2 }
151
164
 
152
- declare interface FactoryWithArgs<T, A extends AnyZodObject> {
153
- create(ctx: any, args: z.output<A>): Promise<T> | T;
165
+ declare interface FactoryWithArgs<T, A extends InjectionTokenSchemaType> {
166
+ create(...args: [FactoryContext, z.output<A>]): Promise<T> | T;
154
167
  }
155
168
  export { FactoryWithArgs }
156
169
  export { FactoryWithArgs as FactoryWithArgs_alias_1 }
@@ -187,38 +200,17 @@ declare function Injectable<R>(options: {
187
200
  type: InjectableType.Factory;
188
201
  }): <T extends ClassTypeWithInstance<Factory<R>>>(target: T, context: ClassDecoratorContext) => T;
189
202
 
190
- declare function Injectable<S extends AnyZodObject>(options: {
191
- scope?: InjectableScope;
192
- type?: InjectableType.Class;
193
- token: InjectionToken<undefined, S>;
194
- }): <T extends ClassTypeWithArgument<z.output<S>>>(target: T, context: ClassDecoratorContext) => T;
195
-
196
- declare function Injectable<R, S extends AnyZodObject>(options: {
203
+ declare function Injectable<Type, Schema>(options: {
197
204
  scope?: InjectableScope;
198
205
  type?: InjectableType.Class;
199
- token: InjectionToken<R, S>;
200
- }): <T extends ClassTypeWithInstanceAndArgument<R, z.output<S>>>(target: T, context: ClassDecoratorContext) => T;
206
+ token: InjectionToken<Type, Schema>;
207
+ }): Schema extends BaseInjectionTokenSchemaType ? Type extends undefined ? <T extends ClassTypeWithArgument<z.output<Schema>>>(target: T, context: ClassDecoratorContext) => T : <T extends ClassTypeWithInstanceAndArgument<Type, z.output<Schema>>>(target: T, context: ClassDecoratorContext) => T : Schema extends OptionalInjectionTokenSchemaType ? Type extends undefined ? <T extends ClassTypeWithOptionalArgument<z.output<Schema>>>(target: T, context: ClassDecoratorContext) => T : <T extends ClassTypeWithInstanceAndOptionalArgument<Type, z.output<Schema>>>(target: T, context: ClassDecoratorContext) => T : Schema extends undefined ? <R extends ClassTypeWithInstance<Type>>(target: R, context: ClassDecoratorContext) => R : never;
201
208
 
202
- declare function Injectable<T extends ClassType>(options: {
203
- scope?: InjectableScope;
204
- token: InjectionToken<T, undefined>;
205
- }): (target: T, context: ClassDecoratorContext) => T;
206
-
207
- declare function Injectable<R, S extends AnyZodObject>(options: {
209
+ declare function Injectable<R, S>(options: {
208
210
  scope?: InjectableScope;
209
211
  type: InjectableType.Factory;
210
212
  token: InjectionToken<R, S>;
211
- }): <T extends ClassTypeWithInstance<FactoryWithArgs<R, S>>>(target: T, context: ClassDecoratorContext) => T & {
212
- [InjectableTokenMeta]: InjectionToken<R, S>;
213
- };
214
-
215
- declare function Injectable<R>(options: {
216
- scope?: InjectableScope;
217
- type: InjectableType.Factory;
218
- token: InjectionToken<R, undefined>;
219
- }): <T extends ClassTypeWithInstance<Factory<R>>>(target: T, context: ClassDecoratorContext) => T & {
220
- [InjectableTokenMeta]: InjectionToken<R, undefined>;
221
- };
213
+ }): R extends undefined ? never : S extends InjectionTokenSchemaType ? <T extends ClassTypeWithInstance<FactoryWithArgs<R, S>>>(target: T, context: ClassDecoratorContext) => T : S extends undefined ? <T extends ClassTypeWithInstance<Factory<R>>>(target: T, context: ClassDecoratorContext) => T : never;
222
214
  export { Injectable }
223
215
  export { Injectable as Injectable_alias_1 }
224
216
  export { Injectable as Injectable_alias_2 }
@@ -264,34 +256,38 @@ declare type InjectionFactory<T = unknown, Args = unknown> = (ctx: FactoryContex
264
256
  export { InjectionFactory }
265
257
  export { InjectionFactory as InjectionFactory_alias_1 }
266
258
 
267
- declare class InjectionToken<T, S extends AnyZodObject | ZodOptional<AnyZodObject> | unknown = unknown> {
259
+ declare class InjectionToken<T, S extends InjectionTokenSchemaType | unknown = unknown> {
268
260
  readonly name: string | symbol | ClassType;
269
261
  readonly schema: AnyZodObject | undefined;
270
262
  id: `${string}-${string}-${string}-${string}-${string}`;
271
263
  private formattedName;
272
264
  constructor(name: string | symbol | ClassType, schema: AnyZodObject | undefined);
273
265
  static create<T extends ClassType>(name: T): InjectionToken<InstanceType<T>, undefined>;
274
- static create<T extends ClassType, Schema extends AnyZodObject | ZodOptional<AnyZodObject>>(name: T, schema: Schema): InjectionToken<InstanceType<T>, Schema>;
266
+ static create<T extends ClassType, Schema extends InjectionTokenSchemaType>(name: T, schema: Schema): InjectionToken<InstanceType<T>, Schema>;
275
267
  static create<T>(name: string | symbol): InjectionToken<T, undefined>;
276
- static create<T, Schema extends AnyZodObject | ZodOptional<AnyZodObject>>(name: string | any, schema: Schema): InjectionToken<T, Schema>;
277
- static bound<T, S extends AnyZodObject | ZodOptional<AnyZodObject>>(token: InjectionToken<T, S>, value: z.input<S>): BoundInjectionToken<T, S>;
278
- static factory<T, S extends AnyZodObject | ZodOptional<AnyZodObject>>(token: InjectionToken<T, S>, factory: () => Promise<z.input<S>>): FactoryInjectionToken<T, S>;
268
+ static create<T, Schema extends InjectionTokenSchemaType>(name: string | any, schema: Schema): InjectionToken<T, Schema>;
269
+ static bound<T, S extends InjectionTokenSchemaType>(token: InjectionToken<T, S>, value: z.input<S>): BoundInjectionToken<T, S>;
270
+ static factory<T, S extends InjectionTokenSchemaType>(token: InjectionToken<T, S>, factory: () => Promise<z.input<S>>): FactoryInjectionToken<T, S>;
279
271
  static refineType<T>(token: BoundInjectionToken<any, any>): BoundInjectionToken<T, any>;
280
272
  toString(): string;
281
273
  }
282
274
  export { InjectionToken }
283
275
  export { InjectionToken as InjectionToken_alias_1 }
284
276
 
277
+ declare type InjectionTokenSchemaType = BaseInjectionTokenSchemaType | OptionalInjectionTokenSchemaType;
278
+ export { InjectionTokenSchemaType }
279
+ export { InjectionTokenSchemaType as InjectionTokenSchemaType_alias_1 }
280
+
285
281
  declare interface Injectors {
286
282
  inject<T extends ClassType>(token: T): Promise<InstanceType<T>>;
287
- inject<T, S extends AnyZodObject>(token: InjectionToken<T, S>, args: z.input<S>): Promise<T>;
288
- inject<T, S extends ZodOptional<AnyZodObject>>(token: InjectionToken<T, S>, args?: z.input<S>): Promise<T>;
283
+ inject<T, S extends BaseInjectionTokenSchemaType>(token: InjectionToken<T, S>, args: z.input<S>): Promise<T>;
284
+ inject<T, S extends OptionalInjectionTokenSchemaType>(token: InjectionToken<T, S>, args?: z.input<S>): Promise<T>;
289
285
  inject<T>(token: InjectionToken<T, undefined>): Promise<T>;
290
286
  inject<T>(token: BoundInjectionToken<T, any>): Promise<T>;
291
287
  inject<T>(token: FactoryInjectionToken<T, any>): Promise<T>;
292
288
  syncInject<T extends ClassType>(token: T): InstanceType<T>;
293
- syncInject<T, S extends AnyZodObject>(token: InjectionToken<T, S>, args: z.input<S>): T;
294
- syncInject<T, S extends ZodOptional<AnyZodObject>>(token: InjectionToken<T, S>, args?: z.input<S>): T;
289
+ syncInject<T, S extends BaseInjectionTokenSchemaType>(token: InjectionToken<T, S>, args: z.input<S>): T;
290
+ syncInject<T, S extends OptionalInjectionTokenSchemaType>(token: InjectionToken<T, S>, args?: z.input<S>): T;
295
291
  syncInject<T>(token: InjectionToken<T, undefined>): T;
296
292
  syncInject<T>(token: BoundInjectionToken<T, any>): T;
297
293
  syncInject<T>(token: FactoryInjectionToken<T, any>): T;
@@ -338,6 +334,10 @@ declare function makeProxyServiceLocator(serviceLocator: ServiceLocator, ctx: Fa
338
334
  export { makeProxyServiceLocator }
339
335
  export { makeProxyServiceLocator as makeProxyServiceLocator_alias_1 }
340
336
 
337
+ declare type OptionalInjectionTokenSchemaType = ZodOptional<AnyZodObject> | ZodOptional<ZodRecord>;
338
+ export { OptionalInjectionTokenSchemaType }
339
+ export { OptionalInjectionTokenSchemaType as OptionalInjectionTokenSchemaType_alias_1 }
340
+
341
341
  declare const provideServiceLocator: Injectors['provideServiceLocator'];
342
342
  export { provideServiceLocator }
343
343
  export { provideServiceLocator as provideServiceLocator_alias_1 }
@@ -387,24 +387,25 @@ declare class ServiceLocator {
387
387
  removeInstance<Instance>(token: BoundInjectionToken<Instance, any>): void;
388
388
  removeInstance<Instance>(token: FactoryInjectionToken<Instance, any>): void;
389
389
  removeInstance<Instance>(token: InjectionToken<Instance, undefined>): void;
390
- removeInstance<Instance, Schema extends AnyZodObject | ZodOptional<AnyZodObject>>(token: InjectionToken<Instance, Schema>, args: z.input<Schema>): void;
390
+ removeInstance<Instance, Schema extends BaseInjectionTokenSchemaType>(token: InjectionToken<Instance, Schema>, args: z.input<Schema>): void;
391
+ removeInstance<Instance, Schema extends OptionalInjectionTokenSchemaType>(token: InjectionToken<Instance, Schema>, args?: z.input<Schema>): void;
391
392
  private resolveTokenArgs;
392
- getInstanceIdentifier<Instance, Schema extends AnyZodObject>(token: InjectionToken<Instance, Schema>, args: z.input<Schema>): string;
393
- getInstanceIdentifier<Instance, Schema extends ZodOptional<AnyZodObject>>(token: InjectionToken<Instance, Schema>, args?: z.input<Schema>): string;
393
+ getInstanceIdentifier<Instance, Schema extends BaseInjectionTokenSchemaType>(token: InjectionToken<Instance, Schema>, args: z.input<Schema>): string;
394
+ getInstanceIdentifier<Instance, Schema extends OptionalInjectionTokenSchemaType>(token: InjectionToken<Instance, Schema>, args?: z.input<Schema>): string;
394
395
  getInstanceIdentifier<Instance>(token: InjectionToken<Instance, undefined>): string;
395
396
  getInstanceIdentifier<Instance>(token: BoundInjectionToken<Instance, any>): string;
396
397
  getInstanceIdentifier<Instance>(token: FactoryInjectionToken<Instance, any>): string;
397
- getInstance<Instance, Schema extends AnyZodObject>(token: InjectionToken<Instance, Schema>, args: z.input<Schema>): Promise<[undefined, Instance] | [UnknownError | FactoryNotFound]>;
398
- getInstance<Instance, Schema extends ZodOptional<AnyZodObject>>(token: InjectionToken<Instance, Schema>, args?: z.input<Schema>): Promise<[undefined, Instance] | [UnknownError | FactoryNotFound]>;
398
+ getInstance<Instance, Schema extends BaseInjectionTokenSchemaType>(token: InjectionToken<Instance, Schema>, args: z.input<Schema>): Promise<[undefined, Instance] | [UnknownError | FactoryNotFound]>;
399
+ getInstance<Instance, Schema extends OptionalInjectionTokenSchemaType>(token: InjectionToken<Instance, Schema>, args?: z.input<Schema>): Promise<[undefined, Instance] | [UnknownError | FactoryNotFound]>;
399
400
  getInstance<Instance>(token: InjectionToken<Instance, undefined>): Promise<[undefined, Instance] | [UnknownError | FactoryNotFound]>;
400
401
  getInstance<Instance>(token: BoundInjectionToken<Instance, any>): Promise<[undefined, Instance] | [UnknownError | FactoryNotFound]>;
401
402
  getInstance<Instance>(token: FactoryInjectionToken<Instance, any>): Promise<[undefined, Instance] | [UnknownError | FactoryNotFound]>;
402
- getOrThrowInstance<Instance, Schema extends AnyZodObject | ZodOptional<AnyZodObject> | undefined>(token: InjectionToken<Instance, Schema>, args: Schema extends AnyZodObject ? z.input<Schema> : Schema extends ZodOptional<AnyZodObject> ? z.input<Schema> | undefined : undefined): Promise<Instance>;
403
+ getOrThrowInstance<Instance, Schema extends InjectionTokenSchemaType | undefined>(token: InjectionToken<Instance, Schema>, args: Schema extends AnyZodObject ? z.input<Schema> : Schema extends ZodOptional<AnyZodObject> ? z.input<Schema> | undefined : undefined): Promise<Instance>;
403
404
  private notifyListeners;
404
405
  private createInstance;
405
406
  private resolveInstance;
406
407
  private createFactoryContext;
407
- getSyncInstance<Instance, Schema extends AnyZodObject | ZodOptional<AnyZodObject> | undefined>(token: InjectionToken<Instance, Schema>, args: Schema extends AnyZodObject ? z.input<Schema> : Schema extends ZodOptional<AnyZodObject> ? z.input<Schema> | undefined : undefined): Instance | null;
408
+ getSyncInstance<Instance, Schema extends InjectionTokenSchemaType | undefined>(token: InjectionToken<Instance, Schema>, args: Schema extends AnyZodObject ? z.input<Schema> : Schema extends ZodOptional<AnyZodObject> ? z.input<Schema> | undefined : undefined): Instance | null;
408
409
  invalidate(service: string, round?: number): Promise<any>;
409
410
  ready(): Promise<null>;
410
411
  makeInstanceName(token: InjectionToken<any, any> | BoundInjectionToken<any, any> | FactoryInjectionToken<any, any>, args: any): string;
package/dist/index.d.mts CHANGED
@@ -25,8 +25,13 @@ export { EventEmitter_alias_1 as EventEmitter } from './_tsup-dts-rollup.mjs';
25
25
  export { FactoryContext_alias_1 as FactoryContext } from './_tsup-dts-rollup.mjs';
26
26
  export { ClassType } from './_tsup-dts-rollup.mjs';
27
27
  export { ClassTypeWithArgument } from './_tsup-dts-rollup.mjs';
28
+ export { ClassTypeWithOptionalArgument } from './_tsup-dts-rollup.mjs';
28
29
  export { ClassTypeWithInstance } from './_tsup-dts-rollup.mjs';
29
30
  export { ClassTypeWithInstanceAndArgument } from './_tsup-dts-rollup.mjs';
31
+ export { ClassTypeWithInstanceAndOptionalArgument } from './_tsup-dts-rollup.mjs';
32
+ export { BaseInjectionTokenSchemaType } from './_tsup-dts-rollup.mjs';
33
+ export { OptionalInjectionTokenSchemaType } from './_tsup-dts-rollup.mjs';
34
+ export { InjectionTokenSchemaType } from './_tsup-dts-rollup.mjs';
30
35
  export { InjectionToken } from './_tsup-dts-rollup.mjs';
31
36
  export { BoundInjectionToken } from './_tsup-dts-rollup.mjs';
32
37
  export { FactoryInjectionToken } from './_tsup-dts-rollup.mjs';
package/dist/index.d.ts CHANGED
@@ -25,8 +25,13 @@ export { EventEmitter_alias_1 as EventEmitter } from './_tsup-dts-rollup.js';
25
25
  export { FactoryContext_alias_1 as FactoryContext } from './_tsup-dts-rollup.js';
26
26
  export { ClassType } from './_tsup-dts-rollup.js';
27
27
  export { ClassTypeWithArgument } from './_tsup-dts-rollup.js';
28
+ export { ClassTypeWithOptionalArgument } from './_tsup-dts-rollup.js';
28
29
  export { ClassTypeWithInstance } from './_tsup-dts-rollup.js';
29
30
  export { ClassTypeWithInstanceAndArgument } from './_tsup-dts-rollup.js';
31
+ export { ClassTypeWithInstanceAndOptionalArgument } from './_tsup-dts-rollup.js';
32
+ export { BaseInjectionTokenSchemaType } from './_tsup-dts-rollup.js';
33
+ export { OptionalInjectionTokenSchemaType } from './_tsup-dts-rollup.js';
34
+ export { InjectionTokenSchemaType } from './_tsup-dts-rollup.js';
30
35
  export { InjectionToken } from './_tsup-dts-rollup.js';
31
36
  export { BoundInjectionToken } from './_tsup-dts-rollup.js';
32
37
  export { FactoryInjectionToken } from './_tsup-dts-rollup.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@navios/di",
3
- "version": "0.1.6",
3
+ "version": "0.1.8",
4
4
  "author": {
5
5
  "name": "Oleksandr Hanzha",
6
6
  "email": "alex@granted.name"
@@ -0,0 +1,289 @@
1
+ import { expectTypeOf, test } from 'vitest'
2
+ import { z } from 'zod'
3
+
4
+ import { Injectable } from '../decorators/index.mjs'
5
+ import { InjectableType } from '../enums/index.mjs'
6
+ import { InjectionToken } from '../injection-token.mjs'
7
+
8
+ interface FooService {
9
+ makeFoo(): string
10
+ }
11
+
12
+ const simpleObjectSchema = z.object({
13
+ foo: z.string(),
14
+ })
15
+ const simpleOptionalObjectSchema = z
16
+ .object({
17
+ foo: z.string(),
18
+ })
19
+ .optional()
20
+ const simpleRecordSchema = z.record(z.string())
21
+ const simpleOptionalRecordSchema = z.record(z.string()).optional()
22
+
23
+ const typelessObjectToken = InjectionToken.create(
24
+ Symbol.for('Typeless object token'),
25
+ simpleObjectSchema,
26
+ )
27
+ const typelessOptionalObjectToken = InjectionToken.create(
28
+ Symbol.for('Typeless optional object token'),
29
+ simpleOptionalObjectSchema,
30
+ )
31
+ const typelessRecordToken = InjectionToken.create(
32
+ Symbol.for('Typeless record token'),
33
+ simpleRecordSchema,
34
+ )
35
+ const typelessOptionalRecordToken = InjectionToken.create(
36
+ Symbol.for('Typeless optional record token'),
37
+ simpleOptionalRecordSchema,
38
+ )
39
+
40
+ const typedObjectToken = InjectionToken.create<
41
+ FooService,
42
+ typeof simpleObjectSchema
43
+ >(Symbol.for('Typed object token'), simpleObjectSchema)
44
+ const typedOptionalObjectToken = InjectionToken.create<
45
+ FooService,
46
+ typeof simpleOptionalObjectSchema
47
+ >(Symbol.for('Typed optional object token'), simpleOptionalObjectSchema)
48
+ const typedRecordToken = InjectionToken.create<
49
+ FooService,
50
+ typeof simpleRecordSchema
51
+ >(Symbol.for('Typed record token'), simpleRecordSchema)
52
+ const typedOptionalRecordToken = InjectionToken.create<
53
+ FooService,
54
+ typeof simpleOptionalRecordSchema
55
+ >(Symbol.for('Typed optional record token'), simpleOptionalRecordSchema)
56
+
57
+ const typedToken = InjectionToken.create<FooService>(Symbol.for('Typed token'))
58
+
59
+ test('Injectable types', () => {
60
+ // #1
61
+ expectTypeOf(
62
+ @Injectable()
63
+ class {},
64
+ ).toBeConstructibleWith()
65
+ // #2
66
+ expectTypeOf(
67
+ @Injectable({
68
+ type: InjectableType.Factory,
69
+ })
70
+ class {
71
+ create() {}
72
+ },
73
+ ).toBeConstructibleWith()
74
+ expectTypeOf(
75
+ // @ts-expect-error should check that the class implements the factory
76
+ @Injectable({
77
+ type: InjectableType.Factory,
78
+ })
79
+ class {},
80
+ ).toBeConstructibleWith()
81
+
82
+ // #3 required argument
83
+ expectTypeOf(
84
+ @Injectable({
85
+ token: typelessObjectToken,
86
+ })
87
+ class {
88
+ constructor(public arg: z.infer<typeof simpleObjectSchema>) {}
89
+ },
90
+ ).toBeConstructibleWith({
91
+ foo: 'something',
92
+ })
93
+ // #3 it's required in token but optional in class allowed
94
+ expectTypeOf(
95
+ @Injectable({
96
+ token: typelessObjectToken,
97
+ })
98
+ class {
99
+ constructor(public arg?: z.infer<typeof simpleObjectSchema>) {}
100
+ },
101
+ ).toBeConstructibleWith({
102
+ foo: 'something',
103
+ })
104
+ // #3 optional value but class accepts it
105
+ expectTypeOf(
106
+ @Injectable({
107
+ token: typelessOptionalObjectToken,
108
+ })
109
+ class {
110
+ constructor(public arg: z.infer<typeof simpleOptionalObjectSchema>) {}
111
+ },
112
+ ).toBeConstructibleWith({
113
+ foo: 'something',
114
+ })
115
+ // #3 optional value and class accepts it
116
+ expectTypeOf(
117
+ @Injectable({
118
+ token: typelessOptionalObjectToken,
119
+ })
120
+ class {
121
+ constructor(public arg: z.infer<typeof simpleOptionalObjectSchema>) {}
122
+ },
123
+ ).toBeConstructibleWith(undefined)
124
+ // #3 compatible schemas
125
+ expectTypeOf(
126
+ @Injectable({
127
+ token: typelessOptionalObjectToken,
128
+ })
129
+ class {
130
+ constructor(public arg?: z.infer<typeof simpleObjectSchema>) {}
131
+ },
132
+ ).toBeConstructibleWith(undefined)
133
+ // #3 compatible schemas
134
+ expectTypeOf(
135
+ // @ts-expect-error token has optional schema, but Class has required, should fail
136
+ @Injectable({
137
+ token: typelessOptionalObjectToken,
138
+ })
139
+ class {
140
+ constructor(public arg: z.infer<typeof simpleObjectSchema>) {}
141
+ },
142
+ ).toBeConstructibleWith({
143
+ foo: 'something',
144
+ })
145
+
146
+ // #3 typed token and required argument
147
+ expectTypeOf(
148
+ @Injectable({
149
+ token: typedObjectToken,
150
+ })
151
+ class {
152
+ constructor(public arg: z.infer<typeof simpleObjectSchema>) {}
153
+
154
+ makeFoo() {
155
+ return this.arg.foo
156
+ }
157
+ },
158
+ ).toBeConstructibleWith({
159
+ foo: 'something',
160
+ })
161
+ // #3 typed token and required argument
162
+ expectTypeOf(
163
+ @Injectable({
164
+ token: typedOptionalObjectToken,
165
+ })
166
+ class {
167
+ constructor(public arg?: z.infer<typeof simpleObjectSchema>) {}
168
+
169
+ makeFoo() {
170
+ return this.arg?.foo ?? 'default'
171
+ }
172
+ },
173
+ ).toBeConstructibleWith({
174
+ foo: 'something',
175
+ })
176
+ // #3 should fail if not compatible
177
+ expectTypeOf(
178
+ // @ts-expect-error class doesn't implement the token type
179
+ @Injectable({
180
+ token: typedOptionalObjectToken,
181
+ })
182
+ class {
183
+ constructor(public arg?: z.infer<typeof simpleObjectSchema>) {}
184
+ },
185
+ ).toBeConstructibleWith({
186
+ foo: 'something',
187
+ })
188
+ // #3 should fail if not compatible
189
+ expectTypeOf(
190
+ // @ts-expect-error class doesn't implement the token type
191
+ @Injectable({
192
+ token: typedOptionalObjectToken,
193
+ })
194
+ class {
195
+ constructor(public arg?: z.infer<typeof simpleObjectSchema>) {}
196
+
197
+ makeFoo() {
198
+ return this.arg?.foo
199
+ }
200
+ },
201
+ ).toBeConstructibleWith({
202
+ foo: 'something',
203
+ })
204
+ // #3 typed token without schema
205
+ expectTypeOf(
206
+ @Injectable({
207
+ token: typedToken,
208
+ })
209
+ class {
210
+ constructor() {}
211
+ makeFoo() {
212
+ return 'foo'
213
+ }
214
+ },
215
+ ).toBeConstructibleWith()
216
+ // #3 typed token without schema fail if not compatible
217
+ expectTypeOf(
218
+ // @ts-expect-error class doesn't implement the token type
219
+ @Injectable({
220
+ token: typedToken,
221
+ })
222
+ class {
223
+ constructor() {}
224
+ },
225
+ ).toBeConstructibleWith()
226
+
227
+ // #4 factory with typed token
228
+ expectTypeOf(
229
+ @Injectable({
230
+ type: InjectableType.Factory,
231
+ token: typedToken,
232
+ })
233
+ class {
234
+ constructor() {}
235
+ create() {
236
+ return {
237
+ makeFoo: () => 'foo',
238
+ }
239
+ }
240
+ },
241
+ ).toBeConstructibleWith()
242
+ // #4 factory with typed token without schema should fail if not compatible
243
+ expectTypeOf(
244
+ // @ts-expect-error factory doesn't implement the token type
245
+ @Injectable({
246
+ type: InjectableType.Factory,
247
+ token: typedToken,
248
+ })
249
+ class {
250
+ constructor() {}
251
+ create(ctx: any, arg: z.infer<typeof simpleObjectSchema>) {
252
+ return {
253
+ makeFoo: () => 'foo',
254
+ }
255
+ }
256
+ },
257
+ ).toBeConstructibleWith()
258
+ // #4 factory with typed token fail if not compatible
259
+ expectTypeOf(
260
+ // @ts-expect-error class doesn't implement the token type
261
+ @Injectable({
262
+ type: InjectableType.Factory,
263
+ token: typedToken,
264
+ })
265
+ class {
266
+ constructor() {}
267
+ create() {
268
+ return {
269
+ // makeFoo: () => 'foo',
270
+ }
271
+ }
272
+ },
273
+ ).toBeConstructibleWith()
274
+ // #4 factory with typed token and schema
275
+ expectTypeOf(
276
+ @Injectable({
277
+ type: InjectableType.Factory,
278
+ token: typedObjectToken,
279
+ })
280
+ class {
281
+ constructor() {}
282
+ create(ctx: any, arg: z.infer<typeof simpleObjectSchema>) {
283
+ return {
284
+ makeFoo: () => 'foo',
285
+ }
286
+ }
287
+ },
288
+ )
289
+ })
@@ -1,14 +1,17 @@
1
- import type { AnyZodObject } from 'zod'
2
-
3
1
  import { NaviosException } from '@navios/common'
4
2
 
5
3
  import { z } from 'zod'
6
4
 
7
5
  import type {
6
+ BaseInjectionTokenSchemaType,
8
7
  ClassType,
9
8
  ClassTypeWithArgument,
10
9
  ClassTypeWithInstance,
11
10
  ClassTypeWithInstanceAndArgument,
11
+ ClassTypeWithInstanceAndOptionalArgument,
12
+ ClassTypeWithOptionalArgument,
13
+ InjectionTokenSchemaType,
14
+ OptionalInjectionTokenSchemaType,
12
15
  } from '../injection-token.mjs'
13
16
  import type { Factory, FactoryWithArgs } from '../interfaces/index.mjs'
14
17
  import type { Registry } from '../registry.mjs'
@@ -25,11 +28,12 @@ export interface InjectableOptions {
25
28
  token?: InjectionToken<any, any>
26
29
  registry?: Registry
27
30
  }
28
-
31
+ // #1 Simple constructorless class
29
32
  export function Injectable(): <T extends ClassType>(
30
33
  target: T,
31
34
  context: ClassDecoratorContext,
32
35
  ) => T
36
+ // #2 Factory class without arguments
33
37
  export function Injectable<R>(options: {
34
38
  scope?: InjectableScope
35
39
  type: InjectableType.Factory
@@ -37,43 +41,62 @@ export function Injectable<R>(options: {
37
41
  target: T,
38
42
  context: ClassDecoratorContext,
39
43
  ) => T
40
- export function Injectable<S extends AnyZodObject>(options: {
41
- scope?: InjectableScope
42
- type?: InjectableType.Class
43
- token: InjectionToken<undefined, S>
44
- }): <T extends ClassTypeWithArgument<z.output<S>>>(
45
- target: T,
46
- context: ClassDecoratorContext,
47
- ) => T
48
- export function Injectable<R, S extends AnyZodObject>(options: {
44
+
45
+ // #3 Class with typeless token and schema
46
+ export function Injectable<Type, Schema>(options: {
49
47
  scope?: InjectableScope
50
48
  type?: InjectableType.Class
51
- token: InjectionToken<R, S>
52
- }): <T extends ClassTypeWithInstanceAndArgument<R, z.output<S>>>(
53
- target: T,
54
- context: ClassDecoratorContext,
55
- ) => T
56
- export function Injectable<T extends ClassType>(options: {
57
- scope?: InjectableScope
58
- token: InjectionToken<T, undefined>
59
- }): (target: T, context: ClassDecoratorContext) => T
49
+ token: InjectionToken<Type, Schema>
50
+ }): Schema extends BaseInjectionTokenSchemaType
51
+ ? Type extends undefined
52
+ ? <T extends ClassTypeWithArgument<z.output<Schema>>>(
53
+ target: T,
54
+ context: ClassDecoratorContext,
55
+ ) => T
56
+ : <T extends ClassTypeWithInstanceAndArgument<Type, z.output<Schema>>>(
57
+ target: T,
58
+ context: ClassDecoratorContext,
59
+ ) => T
60
+ : Schema extends OptionalInjectionTokenSchemaType
61
+ ? Type extends undefined
62
+ ? <T extends ClassTypeWithOptionalArgument<z.output<Schema>>>(
63
+ target: T,
64
+ context: ClassDecoratorContext,
65
+ ) => T
66
+ : <
67
+ T extends ClassTypeWithInstanceAndOptionalArgument<
68
+ Type,
69
+ z.output<Schema>
70
+ >,
71
+ >(
72
+ target: T,
73
+ context: ClassDecoratorContext,
74
+ ) => T
75
+ : Schema extends undefined
76
+ ? <R extends ClassTypeWithInstance<Type>>(
77
+ target: R,
78
+ context: ClassDecoratorContext,
79
+ ) => R
80
+ : never
60
81
 
61
- export function Injectable<R, S extends AnyZodObject>(options: {
82
+ // #4 Factory with typed token
83
+ export function Injectable<R, S>(options: {
62
84
  scope?: InjectableScope
63
85
  type: InjectableType.Factory
64
86
  token: InjectionToken<R, S>
65
- }): <T extends ClassTypeWithInstance<FactoryWithArgs<R, S>>>(
66
- target: T,
67
- context: ClassDecoratorContext,
68
- ) => T & { [InjectableTokenMeta]: InjectionToken<R, S> }
69
- export function Injectable<R>(options: {
70
- scope?: InjectableScope
71
- type: InjectableType.Factory
72
- token: InjectionToken<R, undefined>
73
- }): <T extends ClassTypeWithInstance<Factory<R>>>(
74
- target: T,
75
- context: ClassDecoratorContext,
76
- ) => T & { [InjectableTokenMeta]: InjectionToken<R, undefined> }
87
+ }): R extends undefined
88
+ ? never
89
+ : S extends InjectionTokenSchemaType
90
+ ? <T extends ClassTypeWithInstance<FactoryWithArgs<R, S>>>(
91
+ target: T,
92
+ context: ClassDecoratorContext,
93
+ ) => T
94
+ : S extends undefined
95
+ ? <T extends ClassTypeWithInstance<Factory<R>>>(
96
+ target: T,
97
+ context: ClassDecoratorContext,
98
+ ) => T
99
+ : never
77
100
  export function Injectable({
78
101
  scope = InjectableScope.Singleton,
79
102
  type = InjectableType.Class,
@@ -2,17 +2,31 @@ import type { AnyZodObject } from 'zod'
2
2
 
3
3
  import { randomUUID } from 'crypto'
4
4
 
5
- import { z, ZodOptional } from 'zod'
5
+ import { z, ZodOptional, ZodRecord } from 'zod'
6
6
 
7
7
  export type ClassType = new (...args: any[]) => any
8
8
  export type ClassTypeWithArgument<Arg> = new (arg: Arg) => any
9
+ export type ClassTypeWithOptionalArgument<Arg> = new (arg?: Arg) => any
9
10
 
10
11
  export type ClassTypeWithInstance<T> = new (...args: any[]) => T
11
12
  export type ClassTypeWithInstanceAndArgument<T, Arg> = new (arg: Arg) => T
13
+ export type ClassTypeWithInstanceAndOptionalArgument<T, Arg> = new (
14
+ arg?: Arg,
15
+ ) => T
16
+
17
+ export type BaseInjectionTokenSchemaType = AnyZodObject | ZodRecord
18
+
19
+ export type OptionalInjectionTokenSchemaType =
20
+ | ZodOptional<AnyZodObject>
21
+ | ZodOptional<ZodRecord>
22
+
23
+ export type InjectionTokenSchemaType =
24
+ | BaseInjectionTokenSchemaType
25
+ | OptionalInjectionTokenSchemaType
12
26
 
13
27
  export class InjectionToken<
14
28
  T,
15
- S extends AnyZodObject | ZodOptional<AnyZodObject> | unknown = unknown,
29
+ S extends InjectionTokenSchemaType | unknown = unknown,
16
30
  > {
17
31
  public id = randomUUID()
18
32
  private formattedName: string | null = null
@@ -25,12 +39,12 @@ export class InjectionToken<
25
39
  static create<T extends ClassType>(
26
40
  name: T,
27
41
  ): InjectionToken<InstanceType<T>, undefined>
28
- static create<
29
- T extends ClassType,
30
- Schema extends AnyZodObject | ZodOptional<AnyZodObject>,
31
- >(name: T, schema: Schema): InjectionToken<InstanceType<T>, Schema>
42
+ static create<T extends ClassType, Schema extends InjectionTokenSchemaType>(
43
+ name: T,
44
+ schema: Schema,
45
+ ): InjectionToken<InstanceType<T>, Schema>
32
46
  static create<T>(name: string | symbol): InjectionToken<T, undefined>
33
- static create<T, Schema extends AnyZodObject | ZodOptional<AnyZodObject>>(
47
+ static create<T, Schema extends InjectionTokenSchemaType>(
34
48
  name: string | any,
35
49
  schema: Schema,
36
50
  ): InjectionToken<T, Schema>
@@ -39,14 +53,14 @@ export class InjectionToken<
39
53
  return new InjectionToken(name, schema)
40
54
  }
41
55
 
42
- static bound<T, S extends AnyZodObject | ZodOptional<AnyZodObject>>(
56
+ static bound<T, S extends InjectionTokenSchemaType>(
43
57
  token: InjectionToken<T, S>,
44
58
  value: z.input<S>,
45
59
  ): BoundInjectionToken<T, S> {
46
60
  return new BoundInjectionToken(token, value)
47
61
  }
48
62
 
49
- static factory<T, S extends AnyZodObject | ZodOptional<AnyZodObject>>(
63
+ static factory<T, S extends InjectionTokenSchemaType>(
50
64
  token: InjectionToken<T, S>,
51
65
  factory: () => Promise<z.input<S>>,
52
66
  ): FactoryInjectionToken<T, S> {
@@ -77,13 +91,10 @@ export class InjectionToken<
77
91
  }
78
92
  }
79
93
 
80
- export class BoundInjectionToken<
81
- T,
82
- S extends AnyZodObject | ZodOptional<AnyZodObject>,
83
- > {
94
+ export class BoundInjectionToken<T, S extends InjectionTokenSchemaType> {
84
95
  public id: string
85
96
  public name: string | symbol | ClassType
86
- public schema: AnyZodObject | ZodOptional<AnyZodObject>
97
+ public schema: InjectionTokenSchemaType
87
98
 
88
99
  constructor(
89
100
  public readonly token: InjectionToken<T, S>,
@@ -91,7 +102,7 @@ export class BoundInjectionToken<
91
102
  ) {
92
103
  this.name = token.name
93
104
  this.id = token.id
94
- this.schema = token.schema as AnyZodObject | ZodOptional<AnyZodObject>
105
+ this.schema = token.schema as InjectionTokenSchemaType
95
106
  }
96
107
 
97
108
  toString() {
@@ -99,15 +110,12 @@ export class BoundInjectionToken<
99
110
  }
100
111
  }
101
112
 
102
- export class FactoryInjectionToken<
103
- T,
104
- S extends AnyZodObject | ZodOptional<AnyZodObject>,
105
- > {
113
+ export class FactoryInjectionToken<T, S extends InjectionTokenSchemaType> {
106
114
  public value?: z.input<S>
107
115
  public resolved = false
108
116
  public id: string
109
117
  public name: string | symbol | ClassType
110
- public schema: AnyZodObject | ZodOptional<AnyZodObject>
118
+ public schema: InjectionTokenSchemaType
111
119
 
112
120
  constructor(
113
121
  public readonly token: InjectionToken<T, S>,
@@ -115,7 +123,7 @@ export class FactoryInjectionToken<
115
123
  ) {
116
124
  this.name = token.name
117
125
  this.id = token.id
118
- this.schema = token.schema as AnyZodObject | ZodOptional<AnyZodObject>
126
+ this.schema = token.schema as InjectionTokenSchemaType
119
127
  }
120
128
 
121
129
  async resolve(): Promise<z.input<S>> {
@@ -1,11 +1,12 @@
1
- import type { AnyZodObject } from 'zod'
2
-
3
1
  import { z } from 'zod'
4
2
 
3
+ import type { FactoryContext } from '../factory-context.mjs'
4
+ import type { InjectionTokenSchemaType } from '../injection-token.mjs'
5
+
5
6
  export interface Factory<T> {
6
- create(ctx?: any): Promise<T> | T
7
+ create(ctx?: FactoryContext): Promise<T> | T
7
8
  }
8
9
 
9
- export interface FactoryWithArgs<T, A extends AnyZodObject> {
10
- create(ctx: any, args: z.output<A>): Promise<T> | T
10
+ export interface FactoryWithArgs<T, A extends InjectionTokenSchemaType> {
11
+ create(...args: [FactoryContext, z.output<A>]): Promise<T> | T
11
12
  }
@@ -3,6 +3,11 @@
3
3
  import type { AnyZodObject, z, ZodOptional } from 'zod'
4
4
 
5
5
  import type { FactoryContext } from './factory-context.mjs'
6
+ import type {
7
+ BaseInjectionTokenSchemaType,
8
+ InjectionTokenSchemaType,
9
+ OptionalInjectionTokenSchemaType,
10
+ } from './injection-token.mjs'
6
11
  import type { Registry } from './registry.mjs'
7
12
  import type { ServiceLocatorInstanceHolder } from './service-locator-instance-holder.mjs'
8
13
 
@@ -98,13 +103,15 @@ export class ServiceLocator {
98
103
  public removeInstance<Instance>(
99
104
  token: InjectionToken<Instance, undefined>,
100
105
  ): void
101
- public removeInstance<
102
- Instance,
103
- Schema extends AnyZodObject | ZodOptional<AnyZodObject>,
104
- >(
106
+ public removeInstance<Instance, Schema extends BaseInjectionTokenSchemaType>(
105
107
  token: InjectionToken<Instance, Schema>,
106
108
  args: z.input<Schema>,
107
109
  ): void
110
+ public removeInstance<
111
+ Instance,
112
+ Schema extends OptionalInjectionTokenSchemaType,
113
+ >(token: InjectionToken<Instance, Schema>, args?: z.input<Schema>): void
114
+
108
115
  public removeInstance(
109
116
  token:
110
117
  | InjectionToken<any, any>
@@ -116,18 +123,25 @@ export class ServiceLocator {
116
123
  const instanceName = this.getInstanceIdentifier(token, args)
117
124
  return this.invalidate(instanceName)
118
125
  }
119
- private resolveTokenArgs<Instance, Schema extends AnyZodObject>(
126
+
127
+ private resolveTokenArgs<
128
+ Instance,
129
+ Schema extends BaseInjectionTokenSchemaType,
130
+ >(
120
131
  token: InjectionToken<Instance, Schema>,
121
132
  args: z.input<Schema>,
122
133
  ): [undefined, z.output<Schema>] | [UnknownError]
123
- private resolveTokenArgs<Instance, Schema extends ZodOptional<AnyZodObject>>(
134
+ private resolveTokenArgs<
135
+ Instance,
136
+ Schema extends OptionalInjectionTokenSchemaType,
137
+ >(
124
138
  token: InjectionToken<Instance, Schema>,
125
139
  args?: z.input<Schema>,
126
140
  ): [undefined, z.output<Schema>] | [UnknownError]
127
- private resolveTokenArgs<Instance, Schema extends AnyZodObject>(
141
+ private resolveTokenArgs<Instance, Schema extends InjectionTokenSchemaType>(
128
142
  token: BoundInjectionToken<Instance, Schema>,
129
143
  ): [undefined, z.output<Schema>] | [UnknownError]
130
- private resolveTokenArgs<Instance, Schema extends AnyZodObject>(
144
+ private resolveTokenArgs<Instance, Schema extends InjectionTokenSchemaType>(
131
145
  token: FactoryInjectionToken<Instance, Schema>,
132
146
  ): [undefined, z.output<Schema>] | [FactoryTokenNotResolved | UnknownError]
133
147
  private resolveTokenArgs(
@@ -161,13 +175,13 @@ export class ServiceLocator {
161
175
  return [undefined, validatedArgs?.data]
162
176
  }
163
177
 
164
- public getInstanceIdentifier<Instance, Schema extends AnyZodObject>(
165
- token: InjectionToken<Instance, Schema>,
166
- args: z.input<Schema>,
167
- ): string
168
178
  public getInstanceIdentifier<
169
179
  Instance,
170
- Schema extends ZodOptional<AnyZodObject>,
180
+ Schema extends BaseInjectionTokenSchemaType,
181
+ >(token: InjectionToken<Instance, Schema>, args: z.input<Schema>): string
182
+ public getInstanceIdentifier<
183
+ Instance,
184
+ Schema extends OptionalInjectionTokenSchemaType,
171
185
  >(token: InjectionToken<Instance, Schema>, args?: z.input<Schema>): string
172
186
  public getInstanceIdentifier<Instance>(
173
187
  token: InjectionToken<Instance, undefined>,
@@ -195,11 +209,11 @@ export class ServiceLocator {
195
209
  return this.makeInstanceName(token as InjectionToken<any>, realArgs)
196
210
  }
197
211
 
198
- public getInstance<Instance, Schema extends AnyZodObject>(
212
+ public getInstance<Instance, Schema extends BaseInjectionTokenSchemaType>(
199
213
  token: InjectionToken<Instance, Schema>,
200
214
  args: z.input<Schema>,
201
215
  ): Promise<[undefined, Instance] | [UnknownError | FactoryNotFound]>
202
- public getInstance<Instance, Schema extends ZodOptional<AnyZodObject>>(
216
+ public getInstance<Instance, Schema extends OptionalInjectionTokenSchemaType>(
203
217
  token: InjectionToken<Instance, Schema>,
204
218
  args?: z.input<Schema>,
205
219
  ): Promise<[undefined, Instance] | [UnknownError | FactoryNotFound]>
@@ -273,7 +287,7 @@ export class ServiceLocator {
273
287
 
274
288
  public async getOrThrowInstance<
275
289
  Instance,
276
- Schema extends AnyZodObject | ZodOptional<AnyZodObject> | undefined,
290
+ Schema extends InjectionTokenSchemaType | undefined,
277
291
  >(
278
292
  token: InjectionToken<Instance, Schema>,
279
293
  args: Schema extends AnyZodObject
@@ -301,7 +315,7 @@ export class ServiceLocator {
301
315
 
302
316
  private async createInstance<
303
317
  Instance,
304
- Schema extends AnyZodObject | ZodOptional<AnyZodObject> | undefined,
318
+ Schema extends InjectionTokenSchemaType | undefined,
305
319
  >(
306
320
  instanceName: string,
307
321
  token: InjectionToken<Instance, Schema>,
@@ -328,10 +342,10 @@ export class ServiceLocator {
328
342
 
329
343
  private async resolveInstance<
330
344
  Instance,
331
- Schema extends AnyZodObject | ZodOptional<AnyZodObject> | undefined,
332
- Args extends Schema extends AnyZodObject
345
+ Schema extends InjectionTokenSchemaType | undefined,
346
+ Args extends Schema extends BaseInjectionTokenSchemaType
333
347
  ? z.input<Schema>
334
- : Schema extends ZodOptional<AnyZodObject>
348
+ : Schema extends OptionalInjectionTokenSchemaType
335
349
  ? z.input<Schema> | undefined
336
350
  : undefined,
337
351
  >(
@@ -455,7 +469,7 @@ export class ServiceLocator {
455
469
 
456
470
  public getSyncInstance<
457
471
  Instance,
458
- Schema extends AnyZodObject | ZodOptional<AnyZodObject> | undefined,
472
+ Schema extends InjectionTokenSchemaType | undefined,
459
473
  >(
460
474
  token: InjectionToken<Instance, Schema>,
461
475
  args: Schema extends AnyZodObject
@@ -1,10 +1,12 @@
1
- import type { AnyZodObject, z, ZodOptional } from 'zod'
1
+ import type { AnyZodObject, z } from 'zod'
2
2
 
3
3
  import type {
4
+ BaseInjectionTokenSchemaType,
4
5
  BoundInjectionToken,
5
6
  ClassType,
6
7
  FactoryInjectionToken,
7
8
  InjectionToken,
9
+ OptionalInjectionTokenSchemaType,
8
10
  } from '../injection-token.mjs'
9
11
  import type { ServiceLocator } from '../service-locator.mjs'
10
12
 
@@ -16,11 +18,11 @@ export interface CreateInjectorsOptions {
16
18
 
17
19
  export interface Injectors {
18
20
  inject<T extends ClassType>(token: T): Promise<InstanceType<T>>
19
- inject<T, S extends AnyZodObject>(
21
+ inject<T, S extends BaseInjectionTokenSchemaType>(
20
22
  token: InjectionToken<T, S>,
21
23
  args: z.input<S>,
22
24
  ): Promise<T>
23
- inject<T, S extends ZodOptional<AnyZodObject>>(
25
+ inject<T, S extends OptionalInjectionTokenSchemaType>(
24
26
  token: InjectionToken<T, S>,
25
27
  args?: z.input<S>,
26
28
  ): Promise<T>
@@ -29,11 +31,11 @@ export interface Injectors {
29
31
  inject<T>(token: FactoryInjectionToken<T, any>): Promise<T>
30
32
 
31
33
  syncInject<T extends ClassType>(token: T): InstanceType<T>
32
- syncInject<T, S extends AnyZodObject>(
34
+ syncInject<T, S extends BaseInjectionTokenSchemaType>(
33
35
  token: InjectionToken<T, S>,
34
36
  args: z.input<S>,
35
37
  ): T
36
- syncInject<T, S extends ZodOptional<AnyZodObject>>(
38
+ syncInject<T, S extends OptionalInjectionTokenSchemaType>(
37
39
  token: InjectionToken<T, S>,
38
40
  args?: z.input<S>,
39
41
  ): T