@navios/di 0.1.7 → 0.1.9
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 +78 -0
- package/docs/README.md +81 -0
- package/lib/index.d.mts +435 -0
- package/lib/index.d.mts.map +1 -0
- package/lib/index.d.ts +435 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +795 -0
- package/lib/index.mjs +738 -0
- package/lib/index.mjs.map +1 -0
- package/package.json +9 -18
- package/project.json +50 -0
- package/src/__type-tests__/inject.spec-d.mts +99 -0
- package/src/__type-tests__/injectable.spec-d.mts +289 -0
- package/src/decorators/injectable.decorator.mts +58 -35
- package/src/injection-token.mts +19 -4
- package/src/interfaces/factory.interface.mts +3 -2
- package/src/resolve-service.mts +3 -5
- package/src/service-locator.mts +1 -1
- package/src/utils/get-injectors.mts +57 -11
- package/tsconfig.json +8 -0
- package/tsdown.config.mts +10 -0
- package/vitest.config.mts +9 -0
- package/dist/_tsup-dts-rollup.d.mts +0 -541
- package/dist/_tsup-dts-rollup.d.ts +0 -541
- package/dist/index.d.mts +0 -59
- package/dist/index.d.ts +0 -59
- package/dist/index.js +0 -1026
- package/dist/index.mjs +0 -967
|
@@ -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,13 +1,15 @@
|
|
|
1
|
-
import { NaviosException } from '@navios/common'
|
|
2
|
-
|
|
3
1
|
import { z } from 'zod'
|
|
4
2
|
|
|
5
3
|
import type {
|
|
4
|
+
BaseInjectionTokenSchemaType,
|
|
6
5
|
ClassType,
|
|
7
6
|
ClassTypeWithArgument,
|
|
8
7
|
ClassTypeWithInstance,
|
|
9
8
|
ClassTypeWithInstanceAndArgument,
|
|
9
|
+
ClassTypeWithInstanceAndOptionalArgument,
|
|
10
|
+
ClassTypeWithOptionalArgument,
|
|
10
11
|
InjectionTokenSchemaType,
|
|
12
|
+
OptionalInjectionTokenSchemaType,
|
|
11
13
|
} from '../injection-token.mjs'
|
|
12
14
|
import type { Factory, FactoryWithArgs } from '../interfaces/index.mjs'
|
|
13
15
|
import type { Registry } from '../registry.mjs'
|
|
@@ -24,11 +26,12 @@ export interface InjectableOptions {
|
|
|
24
26
|
token?: InjectionToken<any, any>
|
|
25
27
|
registry?: Registry
|
|
26
28
|
}
|
|
27
|
-
|
|
29
|
+
// #1 Simple constructorless class
|
|
28
30
|
export function Injectable(): <T extends ClassType>(
|
|
29
31
|
target: T,
|
|
30
32
|
context: ClassDecoratorContext,
|
|
31
33
|
) => T
|
|
34
|
+
// #2 Factory class without arguments
|
|
32
35
|
export function Injectable<R>(options: {
|
|
33
36
|
scope?: InjectableScope
|
|
34
37
|
type: InjectableType.Factory
|
|
@@ -36,42 +39,62 @@ export function Injectable<R>(options: {
|
|
|
36
39
|
target: T,
|
|
37
40
|
context: ClassDecoratorContext,
|
|
38
41
|
) => T
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
token: InjectionToken<undefined, S>
|
|
43
|
-
}): <T extends ClassTypeWithArgument<z.output<S>>>(
|
|
44
|
-
target: T,
|
|
45
|
-
context: ClassDecoratorContext,
|
|
46
|
-
) => T
|
|
47
|
-
export function Injectable<R, S extends InjectionTokenSchemaType>(options: {
|
|
42
|
+
|
|
43
|
+
// #3 Class with typeless token and schema
|
|
44
|
+
export function Injectable<Type, Schema>(options: {
|
|
48
45
|
scope?: InjectableScope
|
|
49
46
|
type?: InjectableType.Class
|
|
50
|
-
token: InjectionToken<
|
|
51
|
-
}):
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
47
|
+
token: InjectionToken<Type, Schema>
|
|
48
|
+
}): Schema extends BaseInjectionTokenSchemaType
|
|
49
|
+
? Type extends undefined
|
|
50
|
+
? <T extends ClassTypeWithArgument<z.output<Schema>>>(
|
|
51
|
+
target: T,
|
|
52
|
+
context: ClassDecoratorContext,
|
|
53
|
+
) => T
|
|
54
|
+
: <T extends ClassTypeWithInstanceAndArgument<Type, z.output<Schema>>>(
|
|
55
|
+
target: T,
|
|
56
|
+
context: ClassDecoratorContext,
|
|
57
|
+
) => T
|
|
58
|
+
: Schema extends OptionalInjectionTokenSchemaType
|
|
59
|
+
? Type extends undefined
|
|
60
|
+
? <T extends ClassTypeWithOptionalArgument<z.output<Schema>>>(
|
|
61
|
+
target: T,
|
|
62
|
+
context: ClassDecoratorContext,
|
|
63
|
+
) => T
|
|
64
|
+
: <
|
|
65
|
+
T extends ClassTypeWithInstanceAndOptionalArgument<
|
|
66
|
+
Type,
|
|
67
|
+
z.output<Schema>
|
|
68
|
+
>,
|
|
69
|
+
>(
|
|
70
|
+
target: T,
|
|
71
|
+
context: ClassDecoratorContext,
|
|
72
|
+
) => T
|
|
73
|
+
: Schema extends undefined
|
|
74
|
+
? <R extends ClassTypeWithInstance<Type>>(
|
|
75
|
+
target: R,
|
|
76
|
+
context: ClassDecoratorContext,
|
|
77
|
+
) => R
|
|
78
|
+
: never
|
|
79
|
+
|
|
80
|
+
// #4 Factory with typed token
|
|
81
|
+
export function Injectable<R, S>(options: {
|
|
60
82
|
scope?: InjectableScope
|
|
61
83
|
type: InjectableType.Factory
|
|
62
84
|
token: InjectionToken<R, S>
|
|
63
|
-
}):
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
) => T
|
|
85
|
+
}): R extends undefined
|
|
86
|
+
? never
|
|
87
|
+
: S extends InjectionTokenSchemaType
|
|
88
|
+
? <T extends ClassTypeWithInstance<FactoryWithArgs<R, S>>>(
|
|
89
|
+
target: T,
|
|
90
|
+
context: ClassDecoratorContext,
|
|
91
|
+
) => T
|
|
92
|
+
: S extends undefined
|
|
93
|
+
? <T extends ClassTypeWithInstance<Factory<R>>>(
|
|
94
|
+
target: T,
|
|
95
|
+
context: ClassDecoratorContext,
|
|
96
|
+
) => T
|
|
97
|
+
: never
|
|
75
98
|
export function Injectable({
|
|
76
99
|
scope = InjectableScope.Singleton,
|
|
77
100
|
type = InjectableType.Class,
|
|
@@ -101,7 +124,7 @@ export function Injectable({
|
|
|
101
124
|
async (ctx, args: any) => {
|
|
102
125
|
const builder = await resolveService(ctx, target)
|
|
103
126
|
if (typeof builder.create !== 'function') {
|
|
104
|
-
throw new
|
|
127
|
+
throw new Error(
|
|
105
128
|
`[ServiceLocator] Factory ${target.name} does not implement the create method.`,
|
|
106
129
|
)
|
|
107
130
|
}
|
package/src/injection-token.mts
CHANGED
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
import type { AnyZodObject } from 'zod'
|
|
2
2
|
|
|
3
|
-
import { randomUUID } from 'crypto'
|
|
4
|
-
|
|
5
3
|
import { z, ZodOptional, ZodRecord } from 'zod'
|
|
6
4
|
|
|
7
5
|
export type ClassType = new (...args: any[]) => any
|
|
8
6
|
export type ClassTypeWithArgument<Arg> = new (arg: Arg) => any
|
|
7
|
+
export type ClassTypeWithOptionalArgument<Arg> = new (arg?: Arg) => any
|
|
9
8
|
|
|
10
9
|
export type ClassTypeWithInstance<T> = new (...args: any[]) => T
|
|
11
10
|
export type ClassTypeWithInstanceAndArgument<T, Arg> = new (arg: Arg) => T
|
|
11
|
+
export type ClassTypeWithInstanceAndOptionalArgument<T, Arg> = new (
|
|
12
|
+
arg?: Arg,
|
|
13
|
+
) => T
|
|
12
14
|
|
|
15
|
+
export const Optional = Symbol('Optional')
|
|
16
|
+
export const Required = Symbol('Required')
|
|
13
17
|
export type BaseInjectionTokenSchemaType = AnyZodObject | ZodRecord
|
|
14
18
|
|
|
15
19
|
export type OptionalInjectionTokenSchemaType =
|
|
@@ -23,8 +27,17 @@ export type InjectionTokenSchemaType =
|
|
|
23
27
|
export class InjectionToken<
|
|
24
28
|
T,
|
|
25
29
|
S extends InjectionTokenSchemaType | unknown = unknown,
|
|
30
|
+
Required extends boolean = S extends ZodOptional<AnyZodObject>
|
|
31
|
+
? false
|
|
32
|
+
: S extends ZodOptional<ZodRecord>
|
|
33
|
+
? false
|
|
34
|
+
: S extends AnyZodObject
|
|
35
|
+
? true
|
|
36
|
+
: S extends ZodRecord
|
|
37
|
+
? true
|
|
38
|
+
: false,
|
|
26
39
|
> {
|
|
27
|
-
public id = randomUUID()
|
|
40
|
+
public id = globalThis.crypto.randomUUID()
|
|
28
41
|
private formattedName: string | null = null
|
|
29
42
|
|
|
30
43
|
constructor(
|
|
@@ -38,7 +51,9 @@ export class InjectionToken<
|
|
|
38
51
|
static create<T extends ClassType, Schema extends InjectionTokenSchemaType>(
|
|
39
52
|
name: T,
|
|
40
53
|
schema: Schema,
|
|
41
|
-
):
|
|
54
|
+
): Schema['_def']['typeName'] extends 'ZodOptional'
|
|
55
|
+
? InjectionToken<InstanceType<T>, Schema, false>
|
|
56
|
+
: InjectionToken<InstanceType<T>, Schema, true>
|
|
42
57
|
static create<T>(name: string | symbol): InjectionToken<T, undefined>
|
|
43
58
|
static create<T, Schema extends InjectionTokenSchemaType>(
|
|
44
59
|
name: string | any,
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { z } from 'zod'
|
|
2
2
|
|
|
3
|
+
import type { FactoryContext } from '../factory-context.mjs'
|
|
3
4
|
import type { InjectionTokenSchemaType } from '../injection-token.mjs'
|
|
4
5
|
|
|
5
6
|
export interface Factory<T> {
|
|
6
|
-
create(ctx?:
|
|
7
|
+
create(ctx?: FactoryContext): Promise<T> | T
|
|
7
8
|
}
|
|
8
9
|
|
|
9
10
|
export interface FactoryWithArgs<T, A extends InjectionTokenSchemaType> {
|
|
10
|
-
create(
|
|
11
|
+
create(...args: [FactoryContext, z.output<A>]): Promise<T> | T
|
|
11
12
|
}
|
package/src/resolve-service.mts
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { NaviosException } from '@navios/common'
|
|
2
|
-
|
|
3
1
|
import type { FactoryContext } from './factory-context.mjs'
|
|
4
2
|
import type { ClassType } from './injection-token.mjs'
|
|
5
3
|
|
|
@@ -30,11 +28,11 @@ export async function resolveService<T extends ClassType>(
|
|
|
30
28
|
}
|
|
31
29
|
if (promises.length > 0) {
|
|
32
30
|
console.error(`[ServiceLocator] ${target.name} has problem with it's definition.
|
|
33
|
-
|
|
31
|
+
|
|
34
32
|
One or more of the dependencies are registered as a InjectableScope.Instance and are used with syncInject.
|
|
35
|
-
|
|
33
|
+
|
|
36
34
|
Please use inject instead of syncInject to load those dependencies.`)
|
|
37
|
-
throw new
|
|
35
|
+
throw new Error(
|
|
38
36
|
`[ServiceLocator] Service ${target.name} cannot be instantiated.`,
|
|
39
37
|
)
|
|
40
38
|
}
|
package/src/service-locator.mts
CHANGED
|
@@ -450,7 +450,7 @@ export class ServiceLocator {
|
|
|
450
450
|
: undefined
|
|
451
451
|
const instanceName = self.makeInstanceName(token, validatedArgs)
|
|
452
452
|
dependencies.add(instanceName)
|
|
453
|
-
return self.getOrThrowInstance(injectionToken, args)
|
|
453
|
+
return self.getOrThrowInstance(injectionToken, args as any)
|
|
454
454
|
}
|
|
455
455
|
throw new Error(
|
|
456
456
|
`[ServiceLocator]#inject(): Invalid token type: ${typeof token}. Expected a class or an InjectionToken.`,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AnyZodObject, z } from 'zod'
|
|
1
|
+
import type { AnyZodObject, z, ZodType } from 'zod'
|
|
2
2
|
|
|
3
3
|
import type {
|
|
4
4
|
BaseInjectionTokenSchemaType,
|
|
@@ -6,6 +6,7 @@ import type {
|
|
|
6
6
|
ClassType,
|
|
7
7
|
FactoryInjectionToken,
|
|
8
8
|
InjectionToken,
|
|
9
|
+
InjectionTokenSchemaType,
|
|
9
10
|
OptionalInjectionTokenSchemaType,
|
|
10
11
|
} from '../injection-token.mjs'
|
|
11
12
|
import type { ServiceLocator } from '../service-locator.mjs'
|
|
@@ -15,30 +16,75 @@ import { InjectableTokenMeta } from '../symbols/index.mjs'
|
|
|
15
16
|
export interface CreateInjectorsOptions {
|
|
16
17
|
baseLocator: ServiceLocator
|
|
17
18
|
}
|
|
19
|
+
type Join<TElements, TSeparator extends string> =
|
|
20
|
+
TElements extends Readonly<[infer First, ...infer Rest]>
|
|
21
|
+
? Rest extends ReadonlyArray<string>
|
|
22
|
+
? First extends string
|
|
23
|
+
? `${First}${Rest extends [] ? '' : TSeparator}${Join<Rest, TSeparator>}`
|
|
24
|
+
: never
|
|
25
|
+
: never
|
|
26
|
+
: ''
|
|
27
|
+
// credits goes to https://stackoverflow.com/a/50375286
|
|
28
|
+
type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (
|
|
29
|
+
k: infer I,
|
|
30
|
+
) => void
|
|
31
|
+
? I
|
|
32
|
+
: never
|
|
33
|
+
|
|
34
|
+
// Converts union to overloaded function
|
|
35
|
+
type UnionToOvlds<U> = UnionToIntersection<
|
|
36
|
+
U extends any ? (f: U) => void : never
|
|
37
|
+
>
|
|
38
|
+
|
|
39
|
+
type PopUnion<U> = UnionToOvlds<U> extends (a: infer A) => void ? A : never
|
|
40
|
+
|
|
41
|
+
type IsUnion<T> = [T] extends [UnionToIntersection<T>] ? false : true
|
|
42
|
+
|
|
43
|
+
type UnionToArray<T, A extends unknown[] = []> =
|
|
44
|
+
IsUnion<T> extends true
|
|
45
|
+
? UnionToArray<Exclude<T, PopUnion<T>>, [PopUnion<T>, ...A]>
|
|
46
|
+
: [T, ...A]
|
|
18
47
|
|
|
19
48
|
export interface Injectors {
|
|
49
|
+
// #1 Simple class
|
|
20
50
|
inject<T extends ClassType>(token: T): Promise<InstanceType<T>>
|
|
21
|
-
|
|
51
|
+
// #2 Token with required Schema
|
|
52
|
+
inject<T, S extends InjectionTokenSchemaType>(
|
|
22
53
|
token: InjectionToken<T, S>,
|
|
23
54
|
args: z.input<S>,
|
|
24
55
|
): Promise<T>
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
):
|
|
56
|
+
// #3 Token with optional Schema
|
|
57
|
+
inject<T, S extends InjectionTokenSchemaType, R extends boolean>(
|
|
58
|
+
token: InjectionToken<T, S, R>,
|
|
59
|
+
): R extends false
|
|
60
|
+
? Promise<T>
|
|
61
|
+
: S extends ZodType<infer Type>
|
|
62
|
+
? `Error: Your token requires args: ${Join<
|
|
63
|
+
UnionToArray<keyof Type>,
|
|
64
|
+
', '
|
|
65
|
+
>}`
|
|
66
|
+
: 'Error: Your token requires args'
|
|
67
|
+
// #4 Token with no Schema
|
|
29
68
|
inject<T>(token: InjectionToken<T, undefined>): Promise<T>
|
|
30
69
|
inject<T>(token: BoundInjectionToken<T, any>): Promise<T>
|
|
31
70
|
inject<T>(token: FactoryInjectionToken<T, any>): Promise<T>
|
|
32
71
|
|
|
33
72
|
syncInject<T extends ClassType>(token: T): InstanceType<T>
|
|
34
|
-
syncInject<T, S extends
|
|
73
|
+
syncInject<T, S extends InjectionTokenSchemaType>(
|
|
35
74
|
token: InjectionToken<T, S>,
|
|
36
75
|
args: z.input<S>,
|
|
37
76
|
): T
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
):
|
|
77
|
+
// #3 Token with optional Schema
|
|
78
|
+
syncInject<T, S extends InjectionTokenSchemaType, R extends boolean>(
|
|
79
|
+
token: InjectionToken<T, S, R>,
|
|
80
|
+
): R extends false
|
|
81
|
+
? T
|
|
82
|
+
: S extends ZodType<infer Type>
|
|
83
|
+
? `Error: Your token requires args: ${Join<
|
|
84
|
+
UnionToArray<keyof Type>,
|
|
85
|
+
', '
|
|
86
|
+
>}`
|
|
87
|
+
: 'Error: Your token requires args'
|
|
42
88
|
syncInject<T>(token: InjectionToken<T, undefined>): T
|
|
43
89
|
syncInject<T>(token: BoundInjectionToken<T, any>): T
|
|
44
90
|
syncInject<T>(token: FactoryInjectionToken<T, any>): T
|
package/tsconfig.json
ADDED