@navios/di 0.7.1 → 0.9.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.
Files changed (263) hide show
  1. package/CHANGELOG.md +110 -0
  2. package/README.md +117 -17
  3. package/lib/browser/container/abstract-container.d.mts +112 -0
  4. package/lib/browser/container/abstract-container.d.mts.map +1 -0
  5. package/lib/browser/container/abstract-container.mjs +100 -0
  6. package/lib/browser/container/abstract-container.mjs.map +1 -0
  7. package/lib/browser/container/container.d.mts +100 -0
  8. package/lib/browser/container/container.d.mts.map +1 -0
  9. package/lib/browser/container/container.mjs +424 -0
  10. package/lib/browser/container/container.mjs.map +1 -0
  11. package/lib/browser/container/scoped-container.d.mts +93 -0
  12. package/lib/browser/container/scoped-container.d.mts.map +1 -0
  13. package/lib/browser/container/scoped-container.mjs +119 -0
  14. package/lib/browser/container/scoped-container.mjs.map +1 -0
  15. package/lib/browser/decorators/factory.decorator.d.mts +26 -0
  16. package/lib/browser/decorators/factory.decorator.d.mts.map +1 -0
  17. package/lib/browser/decorators/factory.decorator.mjs +20 -0
  18. package/lib/browser/decorators/factory.decorator.mjs.map +1 -0
  19. package/lib/browser/decorators/injectable.decorator.d.mts +38 -0
  20. package/lib/browser/decorators/injectable.decorator.d.mts.map +1 -0
  21. package/lib/browser/decorators/injectable.decorator.mjs +21 -0
  22. package/lib/browser/decorators/injectable.decorator.mjs.map +1 -0
  23. package/lib/browser/enums/injectable-scope.enum.d.mts +18 -0
  24. package/lib/browser/enums/injectable-scope.enum.d.mts.map +1 -0
  25. package/lib/browser/enums/injectable-scope.enum.mjs +20 -0
  26. package/lib/browser/enums/injectable-scope.enum.mjs.map +1 -0
  27. package/lib/browser/enums/injectable-type.enum.d.mts +8 -0
  28. package/lib/browser/enums/injectable-type.enum.d.mts.map +1 -0
  29. package/lib/browser/enums/injectable-type.enum.mjs +10 -0
  30. package/lib/browser/enums/injectable-type.enum.mjs.map +1 -0
  31. package/lib/browser/errors/di-error.d.mts +43 -0
  32. package/lib/browser/errors/di-error.d.mts.map +1 -0
  33. package/lib/browser/errors/di-error.mjs +98 -0
  34. package/lib/browser/errors/di-error.mjs.map +1 -0
  35. package/lib/browser/event-emitter.d.mts +16 -0
  36. package/lib/browser/event-emitter.d.mts.map +1 -0
  37. package/lib/browser/event-emitter.mjs +320 -0
  38. package/lib/browser/event-emitter.mjs.map +1 -0
  39. package/lib/browser/index.d.mts +37 -1508
  40. package/lib/browser/index.mjs +29 -2650
  41. package/lib/browser/interfaces/container.interface.d.mts +59 -0
  42. package/lib/browser/interfaces/container.interface.d.mts.map +1 -0
  43. package/lib/browser/interfaces/factory.interface.d.mts +14 -0
  44. package/lib/browser/interfaces/factory.interface.d.mts.map +1 -0
  45. package/lib/browser/interfaces/on-service-destroy.interface.d.mts +7 -0
  46. package/lib/browser/interfaces/on-service-destroy.interface.d.mts.map +1 -0
  47. package/lib/browser/interfaces/on-service-init.interface.d.mts +7 -0
  48. package/lib/browser/interfaces/on-service-init.interface.d.mts.map +1 -0
  49. package/lib/browser/internal/context/async-local-storage.browser.mjs +20 -0
  50. package/lib/browser/internal/context/async-local-storage.browser.mjs.map +1 -0
  51. package/lib/browser/internal/context/async-local-storage.d.mts +9 -0
  52. package/lib/browser/internal/context/async-local-storage.d.mts.map +1 -0
  53. package/lib/browser/internal/context/async-local-storage.types.d.mts +11 -0
  54. package/lib/browser/internal/context/async-local-storage.types.d.mts.map +1 -0
  55. package/lib/browser/internal/context/factory-context.d.mts +23 -0
  56. package/lib/browser/internal/context/factory-context.d.mts.map +1 -0
  57. package/lib/browser/internal/context/resolution-context.d.mts +43 -0
  58. package/lib/browser/internal/context/resolution-context.d.mts.map +1 -0
  59. package/lib/browser/internal/context/resolution-context.mjs +56 -0
  60. package/lib/browser/internal/context/resolution-context.mjs.map +1 -0
  61. package/lib/browser/internal/context/service-initialization-context.d.mts +48 -0
  62. package/lib/browser/internal/context/service-initialization-context.d.mts.map +1 -0
  63. package/lib/browser/internal/context/sync-local-storage.mjs +53 -0
  64. package/lib/browser/internal/context/sync-local-storage.mjs.map +1 -0
  65. package/lib/browser/internal/core/instance-resolver.d.mts +119 -0
  66. package/lib/browser/internal/core/instance-resolver.d.mts.map +1 -0
  67. package/lib/browser/internal/core/instance-resolver.mjs +306 -0
  68. package/lib/browser/internal/core/instance-resolver.mjs.map +1 -0
  69. package/lib/browser/internal/core/name-resolver.d.mts +52 -0
  70. package/lib/browser/internal/core/name-resolver.d.mts.map +1 -0
  71. package/lib/browser/internal/core/name-resolver.mjs +118 -0
  72. package/lib/browser/internal/core/name-resolver.mjs.map +1 -0
  73. package/lib/browser/internal/core/scope-tracker.d.mts +65 -0
  74. package/lib/browser/internal/core/scope-tracker.d.mts.map +1 -0
  75. package/lib/browser/internal/core/scope-tracker.mjs +120 -0
  76. package/lib/browser/internal/core/scope-tracker.mjs.map +1 -0
  77. package/lib/browser/internal/core/service-initializer.d.mts +44 -0
  78. package/lib/browser/internal/core/service-initializer.d.mts.map +1 -0
  79. package/lib/browser/internal/core/service-initializer.mjs +109 -0
  80. package/lib/browser/internal/core/service-initializer.mjs.map +1 -0
  81. package/lib/browser/internal/core/service-invalidator.d.mts +81 -0
  82. package/lib/browser/internal/core/service-invalidator.d.mts.map +1 -0
  83. package/lib/browser/internal/core/service-invalidator.mjs +142 -0
  84. package/lib/browser/internal/core/service-invalidator.mjs.map +1 -0
  85. package/lib/browser/internal/core/token-resolver.d.mts +54 -0
  86. package/lib/browser/internal/core/token-resolver.d.mts.map +1 -0
  87. package/lib/browser/internal/core/token-resolver.mjs +77 -0
  88. package/lib/browser/internal/core/token-resolver.mjs.map +1 -0
  89. package/lib/browser/internal/holder/holder-storage.interface.d.mts +99 -0
  90. package/lib/browser/internal/holder/holder-storage.interface.d.mts.map +1 -0
  91. package/lib/browser/internal/holder/instance-holder.d.mts +101 -0
  92. package/lib/browser/internal/holder/instance-holder.d.mts.map +1 -0
  93. package/lib/browser/internal/holder/instance-holder.mjs +19 -0
  94. package/lib/browser/internal/holder/instance-holder.mjs.map +1 -0
  95. package/lib/browser/internal/holder/unified-storage.d.mts +53 -0
  96. package/lib/browser/internal/holder/unified-storage.d.mts.map +1 -0
  97. package/lib/browser/internal/holder/unified-storage.mjs +144 -0
  98. package/lib/browser/internal/holder/unified-storage.mjs.map +1 -0
  99. package/lib/browser/internal/lifecycle/circular-detector.d.mts +39 -0
  100. package/lib/browser/internal/lifecycle/circular-detector.d.mts.map +1 -0
  101. package/lib/browser/internal/lifecycle/circular-detector.mjs +55 -0
  102. package/lib/browser/internal/lifecycle/circular-detector.mjs.map +1 -0
  103. package/lib/browser/internal/lifecycle/lifecycle-event-bus.d.mts +18 -0
  104. package/lib/browser/internal/lifecycle/lifecycle-event-bus.d.mts.map +1 -0
  105. package/lib/browser/internal/lifecycle/lifecycle-event-bus.mjs +43 -0
  106. package/lib/browser/internal/lifecycle/lifecycle-event-bus.mjs.map +1 -0
  107. package/lib/browser/internal/stub-factory-class.d.mts +14 -0
  108. package/lib/browser/internal/stub-factory-class.d.mts.map +1 -0
  109. package/lib/browser/internal/stub-factory-class.mjs +18 -0
  110. package/lib/browser/internal/stub-factory-class.mjs.map +1 -0
  111. package/lib/browser/symbols/injectable-token.d.mts +5 -0
  112. package/lib/browser/symbols/injectable-token.d.mts.map +1 -0
  113. package/lib/browser/symbols/injectable-token.mjs +6 -0
  114. package/lib/browser/symbols/injectable-token.mjs.map +1 -0
  115. package/lib/browser/token/injection-token.d.mts +55 -0
  116. package/lib/browser/token/injection-token.d.mts.map +1 -0
  117. package/lib/browser/token/injection-token.mjs +100 -0
  118. package/lib/browser/token/injection-token.mjs.map +1 -0
  119. package/lib/browser/token/registry.d.mts +37 -0
  120. package/lib/browser/token/registry.d.mts.map +1 -0
  121. package/lib/browser/token/registry.mjs +86 -0
  122. package/lib/browser/token/registry.mjs.map +1 -0
  123. package/lib/browser/utils/default-injectors.d.mts +12 -0
  124. package/lib/browser/utils/default-injectors.d.mts.map +1 -0
  125. package/lib/browser/utils/default-injectors.mjs +13 -0
  126. package/lib/browser/utils/default-injectors.mjs.map +1 -0
  127. package/lib/browser/utils/get-injectable-token.d.mts +9 -0
  128. package/lib/browser/utils/get-injectable-token.d.mts.map +1 -0
  129. package/lib/browser/utils/get-injectable-token.mjs +13 -0
  130. package/lib/browser/utils/get-injectable-token.mjs.map +1 -0
  131. package/lib/browser/utils/get-injectors.d.mts +55 -0
  132. package/lib/browser/utils/get-injectors.d.mts.map +1 -0
  133. package/lib/browser/utils/get-injectors.mjs +121 -0
  134. package/lib/browser/utils/get-injectors.mjs.map +1 -0
  135. package/lib/browser/utils/types.d.mts +23 -0
  136. package/lib/browser/utils/types.d.mts.map +1 -0
  137. package/lib/{container-Pb_Y4Z4x.mjs → container-8-z89TyQ.mjs} +1269 -1305
  138. package/lib/container-8-z89TyQ.mjs.map +1 -0
  139. package/lib/{container-BuAutHGg.d.mts → container-CNiqesCL.d.mts} +600 -569
  140. package/lib/container-CNiqesCL.d.mts.map +1 -0
  141. package/lib/{container-DnzgpfBe.cjs → container-CaY2fDuk.cjs} +1287 -1329
  142. package/lib/container-CaY2fDuk.cjs.map +1 -0
  143. package/lib/{container-oGTgX2iX.d.cts → container-D-0Ho3qL.d.cts} +601 -565
  144. package/lib/container-D-0Ho3qL.d.cts.map +1 -0
  145. package/lib/index.cjs +13 -15
  146. package/lib/index.cjs.map +1 -1
  147. package/lib/index.d.cts +58 -223
  148. package/lib/index.d.cts.map +1 -1
  149. package/lib/index.d.mts +62 -222
  150. package/lib/index.d.mts.map +1 -1
  151. package/lib/index.mjs +5 -6
  152. package/lib/index.mjs.map +1 -1
  153. package/lib/testing/index.cjs +569 -311
  154. package/lib/testing/index.cjs.map +1 -1
  155. package/lib/testing/index.d.cts +370 -41
  156. package/lib/testing/index.d.cts.map +1 -1
  157. package/lib/testing/index.d.mts +370 -41
  158. package/lib/testing/index.d.mts.map +1 -1
  159. package/lib/testing/index.mjs +568 -305
  160. package/lib/testing/index.mjs.map +1 -1
  161. package/package.json +2 -1
  162. package/src/__tests__/circular-detector.spec.mts +193 -0
  163. package/src/__tests__/concurrent.spec.mts +368 -0
  164. package/src/__tests__/container.spec.mts +32 -30
  165. package/src/__tests__/di-error.spec.mts +351 -0
  166. package/src/__tests__/e2e.browser.spec.mts +0 -4
  167. package/src/__tests__/e2e.spec.mts +10 -19
  168. package/src/__tests__/event-emitter.spec.mts +232 -109
  169. package/src/__tests__/get-injectors.spec.mts +250 -39
  170. package/src/__tests__/injection-token.spec.mts +293 -349
  171. package/src/__tests__/library-findings.spec.mts +8 -8
  172. package/src/__tests__/registry.spec.mts +358 -210
  173. package/src/__tests__/resolution-context.spec.mts +255 -0
  174. package/src/__tests__/scope-tracker.spec.mts +598 -0
  175. package/src/__tests__/scope-upgrade.spec.mts +808 -0
  176. package/src/__tests__/scoped-container.spec.mts +595 -0
  177. package/src/__tests__/test-container.spec.mts +293 -0
  178. package/src/__tests__/token-resolver.spec.mts +207 -0
  179. package/src/__tests__/unified-storage.spec.mts +535 -0
  180. package/src/__tests__/unit-test-container.spec.mts +405 -0
  181. package/src/__type-tests__/container.spec-d.mts +180 -0
  182. package/src/__type-tests__/factory.spec-d.mts +15 -3
  183. package/src/__type-tests__/inject.spec-d.mts +115 -20
  184. package/src/__type-tests__/injectable.spec-d.mts +69 -52
  185. package/src/__type-tests__/injection-token.spec-d.mts +176 -0
  186. package/src/__type-tests__/scoped-container.spec-d.mts +212 -0
  187. package/src/container/abstract-container.mts +327 -0
  188. package/src/container/container.mts +142 -170
  189. package/src/container/scoped-container.mts +126 -208
  190. package/src/decorators/factory.decorator.mts +16 -11
  191. package/src/decorators/injectable.decorator.mts +20 -16
  192. package/src/enums/index.mts +2 -2
  193. package/src/enums/injectable-scope.enum.mts +1 -0
  194. package/src/enums/injectable-type.enum.mts +1 -0
  195. package/src/errors/di-error.mts +96 -0
  196. package/src/event-emitter.mts +3 -27
  197. package/src/index.mts +6 -153
  198. package/src/interfaces/container.interface.mts +13 -0
  199. package/src/interfaces/factory.interface.mts +1 -1
  200. package/src/interfaces/index.mts +1 -1
  201. package/src/internal/context/async-local-storage.mts +3 -2
  202. package/src/internal/context/async-local-storage.types.mts +1 -0
  203. package/src/internal/context/factory-context.mts +1 -0
  204. package/src/internal/context/index.mts +3 -1
  205. package/src/internal/context/resolution-context.mts +1 -0
  206. package/src/internal/context/service-initialization-context.mts +43 -0
  207. package/src/internal/core/index.mts +5 -4
  208. package/src/internal/core/instance-resolver.mts +461 -292
  209. package/src/internal/core/name-resolver.mts +196 -0
  210. package/src/internal/core/scope-tracker.mts +242 -0
  211. package/src/internal/core/{instantiator.mts → service-initializer.mts} +51 -29
  212. package/src/internal/core/service-invalidator.mts +290 -0
  213. package/src/internal/core/{token-processor.mts → token-resolver.mts} +17 -88
  214. package/src/internal/holder/holder-storage.interface.mts +11 -5
  215. package/src/internal/holder/index.mts +2 -5
  216. package/src/internal/holder/instance-holder.mts +1 -3
  217. package/src/internal/holder/unified-storage.mts +245 -0
  218. package/src/internal/index.mts +2 -1
  219. package/src/internal/lifecycle/circular-detector.mts +1 -0
  220. package/src/internal/lifecycle/index.mts +1 -1
  221. package/src/internal/lifecycle/lifecycle-event-bus.mts +1 -0
  222. package/src/internal/stub-factory-class.mts +16 -0
  223. package/src/symbols/injectable-token.mts +3 -1
  224. package/src/testing/index.mts +2 -0
  225. package/src/testing/test-container.mts +546 -85
  226. package/src/testing/types.mts +117 -0
  227. package/src/testing/unit-test-container.mts +509 -0
  228. package/src/token/injection-token.mts +41 -4
  229. package/src/token/registry.mts +75 -9
  230. package/src/utils/default-injectors.mts +16 -0
  231. package/src/utils/get-injectable-token.mts +2 -3
  232. package/src/utils/get-injectors.mts +26 -15
  233. package/src/utils/index.mts +3 -1
  234. package/src/utils/types.mts +1 -0
  235. package/tsdown.config.mts +11 -1
  236. package/lib/browser/index.d.mts.map +0 -1
  237. package/lib/browser/index.mjs.map +0 -1
  238. package/lib/container-BuAutHGg.d.mts.map +0 -1
  239. package/lib/container-DnzgpfBe.cjs.map +0 -1
  240. package/lib/container-Pb_Y4Z4x.mjs.map +0 -1
  241. package/lib/container-oGTgX2iX.d.cts.map +0 -1
  242. package/src/__tests__/async-local-storage.browser.spec.mts +0 -166
  243. package/src/__tests__/async-local-storage.spec.mts +0 -333
  244. package/src/__tests__/errors.spec.mts +0 -87
  245. package/src/__tests__/factory.spec.mts +0 -137
  246. package/src/__tests__/injectable.spec.mts +0 -246
  247. package/src/__tests__/request-scope.spec.mts +0 -416
  248. package/src/__tests__/service-instantiator.spec.mts +0 -410
  249. package/src/__tests__/service-locator-event-bus.spec.mts +0 -242
  250. package/src/__tests__/service-locator-manager.spec.mts +0 -300
  251. package/src/__tests__/service-locator.spec.mts +0 -966
  252. package/src/__tests__/unified-api.spec.mts +0 -130
  253. package/src/browser.mts +0 -11
  254. package/src/injectors.mts +0 -18
  255. package/src/internal/context/request-context.mts +0 -214
  256. package/src/internal/core/invalidator.mts +0 -437
  257. package/src/internal/core/service-locator.mts +0 -202
  258. package/src/internal/holder/base-holder-manager.mts +0 -238
  259. package/src/internal/holder/holder-manager.mts +0 -85
  260. package/src/internal/holder/request-storage.mts +0 -134
  261. package/src/internal/holder/singleton-storage.mts +0 -105
  262. package/src/testing/README.md +0 -80
  263. package/src/testing/__tests__/test-container.spec.mts +0 -173
@@ -3,7 +3,7 @@ import { z } from 'zod/v4'
3
3
 
4
4
  import { Injectable } from '../decorators/index.mjs'
5
5
  import { InjectionToken } from '../token/injection-token.mjs'
6
- import { asyncInject } from '../injectors.mjs'
6
+ import { asyncInject, inject, optional } from '../utils/default-injectors.mjs'
7
7
 
8
8
  interface FooService {
9
9
  makeFoo(): string
@@ -17,8 +17,6 @@ const simpleOptionalObjectSchema = z
17
17
  foo: z.string(),
18
18
  })
19
19
  .optional()
20
- // const simpleRecordSchema = z.record(z.string(), z.string())
21
- // const simpleOptionalRecordSchema = z.record(z.string(), z.string()).optional()
22
20
 
23
21
  const typelessObjectToken = InjectionToken.create(
24
22
  Symbol.for('Typeless object token'),
@@ -28,14 +26,6 @@ const typelessOptionalObjectToken = InjectionToken.create(
28
26
  Symbol.for('Typeless optional object token'),
29
27
  simpleOptionalObjectSchema,
30
28
  )
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
29
 
40
30
  const typedObjectToken = InjectionToken.create<
41
31
  FooService,
@@ -45,18 +35,10 @@ const typedOptionalObjectToken = InjectionToken.create<
45
35
  FooService,
46
36
  typeof simpleOptionalObjectSchema
47
37
  >(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
38
 
57
39
  const typedToken = InjectionToken.create<FooService>(Symbol.for('Typed token'))
58
40
 
59
- describe('inject', () => {
41
+ describe('asyncInject', () => {
60
42
  describe('#1 Classes', () => {
61
43
  test('simple class', async () => {
62
44
  @Injectable()
@@ -68,6 +50,7 @@ describe('inject', () => {
68
50
 
69
51
  assertType<Foo>(await asyncInject(Foo))
70
52
  })
53
+
71
54
  test('class with required argument', async () => {
72
55
  @Injectable({
73
56
  schema: simpleObjectSchema,
@@ -78,6 +61,7 @@ describe('inject', () => {
78
61
 
79
62
  assertType<Foo>(await asyncInject(Foo, { foo: 'bar' }))
80
63
  })
64
+
81
65
  test('should fail if not compatible', async () => {
82
66
  @Injectable({
83
67
  schema: simpleObjectSchema,
@@ -90,6 +74,7 @@ describe('inject', () => {
90
74
  await asyncInject(Foo, { test: 'bar' })
91
75
  })
92
76
  })
77
+
93
78
  test('#2 Token with required Schema', async () => {
94
79
  const result = await asyncInject(typelessObjectToken, { foo: 'bar' })
95
80
  assertType<unknown>(result)
@@ -119,3 +104,113 @@ describe('inject', () => {
119
104
  assertType<FooService>(result)
120
105
  })
121
106
  })
107
+
108
+ describe('inject (synchronous)', () => {
109
+ describe('#1 Classes', () => {
110
+ test('simple class', () => {
111
+ @Injectable()
112
+ class Foo {
113
+ makeFoo() {
114
+ return 'foo'
115
+ }
116
+ }
117
+
118
+ assertType<Foo>(inject(Foo))
119
+ })
120
+
121
+ test('class with required argument', () => {
122
+ @Injectable({
123
+ schema: simpleObjectSchema,
124
+ })
125
+ class Foo {
126
+ constructor(public arg: z.infer<typeof simpleObjectSchema>) {}
127
+ }
128
+
129
+ assertType<Foo>(inject(Foo, { foo: 'bar' }))
130
+ })
131
+
132
+ test('should fail if not compatible', () => {
133
+ @Injectable({
134
+ schema: simpleObjectSchema,
135
+ })
136
+ class Foo {
137
+ constructor(public arg: z.infer<typeof simpleObjectSchema>) {}
138
+ }
139
+
140
+ // @ts-expect-error Should fail if not compatible
141
+ inject(Foo, { test: 'bar' })
142
+ })
143
+ })
144
+
145
+ test('#2 Token with required Schema', () => {
146
+ const result = inject(typelessObjectToken, { foo: 'bar' })
147
+ assertType<unknown>(result)
148
+
149
+ const result2 = inject(typedObjectToken, { foo: 'bar' })
150
+ assertType<FooService>(result2)
151
+
152
+ // @ts-expect-error We show error when we pass the wrong type
153
+ inject(typedObjectToken, undefined)
154
+ })
155
+
156
+ test('#3 Token with optional Schema', () => {
157
+ const result = inject(typelessOptionalObjectToken)
158
+ assertType<unknown>(result)
159
+
160
+ const result2 = inject(typedOptionalObjectToken)
161
+ assertType<FooService>(result2)
162
+
163
+ const result3 = inject(typedObjectToken)
164
+ // Special case when we pass the token without args
165
+ // We can only return an error string
166
+ assertType<'Error: Your token requires args: foo'>(result3)
167
+ })
168
+
169
+ test('#4 Token with no Schema', () => {
170
+ const result = inject(typedToken)
171
+ assertType<FooService>(result)
172
+ })
173
+ })
174
+
175
+ describe('optional', () => {
176
+ describe('#1 Classes', () => {
177
+ test('simple class returns nullable type', () => {
178
+ @Injectable()
179
+ class Foo {
180
+ makeFoo() {
181
+ return 'foo'
182
+ }
183
+ }
184
+
185
+ assertType<Foo | null>(optional(Foo))
186
+ })
187
+
188
+ // Note: optional() does not have a class + args overload
189
+ // Classes with required args should use tokens instead
190
+ })
191
+
192
+ test('#2 Token with required Schema', () => {
193
+ const result = optional(typelessObjectToken, { foo: 'bar' })
194
+ assertType<unknown>(result)
195
+
196
+ const result2 = optional(typedObjectToken, { foo: 'bar' })
197
+ assertType<FooService | null>(result2)
198
+ })
199
+
200
+ test('#3 Token with optional Schema', () => {
201
+ const result = optional(typelessOptionalObjectToken)
202
+ assertType<unknown>(result)
203
+
204
+ const result2 = optional(typedOptionalObjectToken)
205
+ assertType<FooService | null>(result2)
206
+
207
+ const result3 = optional(typedObjectToken)
208
+ // Special case when we pass the token without args
209
+ assertType<'Error: Your token requires args: foo'>(result3)
210
+ })
211
+
212
+ test('#4 Token with no Schema', () => {
213
+ const result = optional(typedToken)
214
+ assertType<FooService | null>(result)
215
+ })
216
+ })
@@ -3,7 +3,9 @@ import { expectTypeOf, test } from 'vitest'
3
3
  import { z } from 'zod/v4'
4
4
 
5
5
  import { Injectable } from '../decorators/index.mjs'
6
+ import { InjectableScope } from '../enums/index.mjs'
6
7
  import { InjectionToken } from '../token/injection-token.mjs'
8
+ import { Registry } from '../token/registry.mjs'
7
9
 
8
10
  interface FooService {
9
11
  makeFoo(): string
@@ -20,13 +22,6 @@ const simpleOptionalObjectSchema = z
20
22
  const otherObjectSchema = z.object({
21
23
  bar: z.string(),
22
24
  })
23
- const otherOptionalObjectSchema = z
24
- .object({
25
- bar: z.string(),
26
- })
27
- .optional()
28
- // const simpleRecordSchema = z.record(z.string(), z.string())
29
- // const simpleOptionalRecordSchema = z.record(z.string(), z.string()).optional()
30
25
 
31
26
  const typelessObjectToken = InjectionToken.create(
32
27
  Symbol.for('Typeless object token'),
@@ -36,14 +31,6 @@ const typelessOptionalObjectToken = InjectionToken.create(
36
31
  Symbol.for('Typeless optional object token'),
37
32
  simpleOptionalObjectSchema,
38
33
  )
39
- // const typelessRecordToken = InjectionToken.create(
40
- // Symbol.for('Typeless record token'),
41
- // simpleRecordSchema,
42
- // )
43
- // const typelessOptionalRecordToken = InjectionToken.create(
44
- // Symbol.for('Typeless optional record token'),
45
- // simpleOptionalRecordSchema,
46
- // )
47
34
 
48
35
  const typedObjectToken = InjectionToken.create<
49
36
  FooService,
@@ -53,23 +40,29 @@ const typedOptionalObjectToken = InjectionToken.create<
53
40
  FooService,
54
41
  typeof simpleOptionalObjectSchema
55
42
  >(Symbol.for('Typed optional object token'), simpleOptionalObjectSchema)
56
- // const typedRecordToken = InjectionToken.create<
57
- // FooService,
58
- // typeof simpleRecordSchema
59
- // >(Symbol.for('Typed record token'), simpleRecordSchema)
60
- // const typedOptionalRecordToken = InjectionToken.create<
61
- // FooService,
62
- // typeof simpleOptionalRecordSchema
63
- // >(Symbol.for('Typed optional record token'), simpleOptionalRecordSchema)
64
43
 
65
44
  const typedToken = InjectionToken.create<FooService>(Symbol.for('Typed token'))
66
45
 
67
46
  test('Injectable types', () => {
68
- // #1
47
+ // #1 Simple class without arguments
69
48
  expectTypeOf(
70
49
  @Injectable()
71
50
  class {},
72
51
  ).toBeConstructibleWith()
52
+
53
+ // #1 Injectable with scope
54
+ expectTypeOf(
55
+ @Injectable({ scope: InjectableScope.Transient })
56
+ class {},
57
+ ).toBeConstructibleWith()
58
+
59
+ // #1 Injectable with registry
60
+ const registry = new Registry()
61
+ expectTypeOf(
62
+ @Injectable({ registry })
63
+ class {},
64
+ ).toBeConstructibleWith()
65
+
73
66
  // #1 Injectable w/o decorators enabled in project
74
67
  expectTypeOf(
75
68
  Injectable({
@@ -84,7 +77,7 @@ test('Injectable types', () => {
84
77
  ),
85
78
  ).toBeConstructibleWith()
86
79
 
87
- // #2 required argument
80
+ // #2 Class with schema - required argument
88
81
  expectTypeOf(
89
82
  @Injectable({
90
83
  schema: simpleObjectSchema,
@@ -95,7 +88,8 @@ test('Injectable types', () => {
95
88
  ).toBeConstructibleWith({
96
89
  foo: 'something',
97
90
  })
98
- // #2 it's required in schema but optional in class allowed
91
+
92
+ // #2 It's required in schema but optional in class allowed
99
93
  expectTypeOf(
100
94
  @Injectable({
101
95
  schema: simpleObjectSchema,
@@ -106,7 +100,8 @@ test('Injectable types', () => {
106
100
  ).toBeConstructibleWith({
107
101
  foo: 'something',
108
102
  })
109
- // #2 should fail if not compatible
103
+
104
+ // #2 Should fail if not compatible
110
105
  // @ts-expect-error Should fail if not compatible
111
106
  @Injectable({
112
107
  schema: simpleObjectSchema,
@@ -115,7 +110,7 @@ test('Injectable types', () => {
115
110
  constructor(public arg: z.infer<typeof otherObjectSchema>) {}
116
111
  }
117
112
 
118
- // #3 required argument
113
+ // #3 Typeless token with required schema - required argument
119
114
  expectTypeOf(
120
115
  @Injectable({
121
116
  token: typelessObjectToken,
@@ -126,7 +121,8 @@ test('Injectable types', () => {
126
121
  ).toBeConstructibleWith({
127
122
  foo: 'something',
128
123
  })
129
- // #3 it's required in token but optional in class allowed
124
+
125
+ // #3 It's required in token but optional in class allowed
130
126
  expectTypeOf(
131
127
  @Injectable({
132
128
  token: typelessObjectToken,
@@ -137,7 +133,8 @@ test('Injectable types', () => {
137
133
  ).toBeConstructibleWith({
138
134
  foo: 'something',
139
135
  })
140
- // #3 optional value but class accepts it
136
+
137
+ // #3 Optional value but class accepts it
141
138
  expectTypeOf(
142
139
  @Injectable({
143
140
  token: typelessOptionalObjectToken,
@@ -148,7 +145,8 @@ test('Injectable types', () => {
148
145
  ).toBeConstructibleWith({
149
146
  foo: 'something',
150
147
  })
151
- // #3 optional value and class accepts it
148
+
149
+ // #3 Optional value and class accepts undefined
152
150
  expectTypeOf(
153
151
  @Injectable({
154
152
  token: typelessOptionalObjectToken,
@@ -157,7 +155,8 @@ test('Injectable types', () => {
157
155
  constructor(public arg: z.infer<typeof simpleOptionalObjectSchema>) {}
158
156
  },
159
157
  ).toBeConstructibleWith(undefined)
160
- // #3 compatible schemas
158
+
159
+ // #3 Compatible schemas
161
160
  expectTypeOf(
162
161
  @Injectable({
163
162
  token: typelessOptionalObjectToken,
@@ -166,7 +165,8 @@ test('Injectable types', () => {
166
165
  constructor(public arg?: z.infer<typeof simpleObjectSchema>) {}
167
166
  },
168
167
  ).toBeConstructibleWith(undefined)
169
- // #3 compatible schemas
168
+
169
+ // #3 Token has optional schema, but Class has required, should fail
170
170
  expectTypeOf(
171
171
  // @ts-expect-error token has optional schema, but Class has required, should fail
172
172
  @Injectable({
@@ -179,7 +179,7 @@ test('Injectable types', () => {
179
179
  foo: 'something',
180
180
  })
181
181
 
182
- // #3 typed token and required argument
182
+ // #3 Typed token with required schema - required argument
183
183
  expectTypeOf(
184
184
  @Injectable({
185
185
  token: typedObjectToken,
@@ -194,7 +194,8 @@ test('Injectable types', () => {
194
194
  ).toBeConstructibleWith({
195
195
  foo: 'something',
196
196
  })
197
- // #3 typed token and required argument
197
+
198
+ // #3 Typed token with optional schema
198
199
  expectTypeOf(
199
200
  @Injectable({
200
201
  token: typedOptionalObjectToken,
@@ -209,7 +210,8 @@ test('Injectable types', () => {
209
210
  ).toBeConstructibleWith({
210
211
  foo: 'something',
211
212
  })
212
- // #3 should fail if not compatible
213
+
214
+ // #3 Should fail if class doesn't implement token type
213
215
  expectTypeOf(
214
216
  // @ts-expect-error class doesn't implement the token type
215
217
  @Injectable({
@@ -221,9 +223,10 @@ test('Injectable types', () => {
221
223
  ).toBeConstructibleWith({
222
224
  foo: 'something',
223
225
  })
224
- // #3 should fail if not compatible
226
+
227
+ // #3 Should fail if return type doesn't match (returns undefined instead of string)
225
228
  expectTypeOf(
226
- // @ts-expect-error class doesn't implement the token type
229
+ // @ts-expect-error class doesn't implement the token type (wrong return type)
227
230
  @Injectable({
228
231
  token: typedOptionalObjectToken,
229
232
  })
@@ -237,7 +240,8 @@ test('Injectable types', () => {
237
240
  ).toBeConstructibleWith({
238
241
  foo: 'something',
239
242
  })
240
- // #3 typed token without schema
243
+
244
+ // #3 Typed token without schema
241
245
  expectTypeOf(
242
246
  @Injectable({
243
247
  token: typedToken,
@@ -249,7 +253,8 @@ test('Injectable types', () => {
249
253
  }
250
254
  },
251
255
  ).toBeConstructibleWith()
252
- // #3 typed token without schema fail if not compatible
256
+
257
+ // #3 Typed token without schema - fail if not compatible
253
258
  expectTypeOf(
254
259
  // @ts-expect-error class doesn't implement the token type
255
260
  @Injectable({
@@ -260,7 +265,9 @@ test('Injectable types', () => {
260
265
  },
261
266
  ).toBeConstructibleWith()
262
267
 
263
- // #3 required argument
268
+ // Function call syntax tests (without decorators)
269
+
270
+ // #3 Required argument
264
271
  expectTypeOf(
265
272
  Injectable({
266
273
  token: typelessObjectToken,
@@ -272,7 +279,8 @@ test('Injectable types', () => {
272
279
  ).toBeConstructibleWith({
273
280
  foo: 'something',
274
281
  })
275
- // #3 it's required in token but optional in class allowed
282
+
283
+ // #3 It's required in token but optional in class allowed
276
284
  expectTypeOf(
277
285
  Injectable({
278
286
  token: typelessObjectToken,
@@ -284,7 +292,8 @@ test('Injectable types', () => {
284
292
  ).toBeConstructibleWith({
285
293
  foo: 'something',
286
294
  })
287
- // #3 optional value but class accepts it
295
+
296
+ // #3 Optional value but class accepts it
288
297
  expectTypeOf(
289
298
  Injectable({
290
299
  token: typelessOptionalObjectToken,
@@ -296,7 +305,8 @@ test('Injectable types', () => {
296
305
  ).toBeConstructibleWith({
297
306
  foo: 'something',
298
307
  })
299
- // #3 optional value and class accepts it
308
+
309
+ // #3 Optional value and class accepts undefined
300
310
  expectTypeOf(
301
311
  Injectable({
302
312
  token: typelessOptionalObjectToken,
@@ -306,7 +316,8 @@ test('Injectable types', () => {
306
316
  },
307
317
  ),
308
318
  ).toBeConstructibleWith(undefined)
309
- // #3 compatible schemas
319
+
320
+ // #3 Compatible schemas
310
321
  expectTypeOf(
311
322
  Injectable({
312
323
  token: typelessOptionalObjectToken,
@@ -316,7 +327,8 @@ test('Injectable types', () => {
316
327
  },
317
328
  ),
318
329
  ).toBeConstructibleWith(undefined)
319
- // #3 compatible schemas
330
+
331
+ // #3 Token has optional schema, but Class has required, should fail
320
332
  expectTypeOf(
321
333
  Injectable({
322
334
  token: typelessOptionalObjectToken,
@@ -330,7 +342,7 @@ test('Injectable types', () => {
330
342
  foo: 'something',
331
343
  })
332
344
 
333
- // #3 typed token and required argument
345
+ // #3 Typed token with required schema - required argument
334
346
  expectTypeOf(
335
347
  Injectable({
336
348
  token: typedObjectToken,
@@ -346,7 +358,8 @@ test('Injectable types', () => {
346
358
  ).toBeConstructibleWith({
347
359
  foo: 'something',
348
360
  })
349
- // #3 typed token and required argument
361
+
362
+ // #3 Typed token with optional schema
350
363
  expectTypeOf(
351
364
  Injectable({
352
365
  token: typedOptionalObjectToken,
@@ -362,7 +375,8 @@ test('Injectable types', () => {
362
375
  ).toBeConstructibleWith({
363
376
  foo: 'something',
364
377
  })
365
- // #3 should fail if not compatible
378
+
379
+ // #3 Should fail if class doesn't implement token type
366
380
  expectTypeOf(
367
381
  Injectable({
368
382
  token: typedOptionalObjectToken,
@@ -375,7 +389,8 @@ test('Injectable types', () => {
375
389
  ).toBeConstructibleWith({
376
390
  foo: 'something',
377
391
  })
378
- // #3 should fail if not compatible
392
+
393
+ // #3 Should fail if return type doesn't match
379
394
  expectTypeOf(
380
395
  Injectable({
381
396
  token: typedOptionalObjectToken,
@@ -392,7 +407,8 @@ test('Injectable types', () => {
392
407
  ).toBeConstructibleWith({
393
408
  foo: 'something',
394
409
  })
395
- // #3 typed token without schema
410
+
411
+ // #3 Typed token without schema
396
412
  expectTypeOf(
397
413
  Injectable({
398
414
  token: typedToken,
@@ -405,7 +421,8 @@ test('Injectable types', () => {
405
421
  },
406
422
  ),
407
423
  ).toBeConstructibleWith()
408
- // #3 typed token without schema fail if not compatible
424
+
425
+ // #3 Typed token without schema - fail if not compatible
409
426
  expectTypeOf(
410
427
  Injectable({
411
428
  token: typedToken,
@@ -0,0 +1,176 @@
1
+ import { expectTypeOf, test } from 'vitest'
2
+ import { z } from 'zod/v4'
3
+
4
+ import {
5
+ BoundInjectionToken,
6
+ FactoryInjectionToken,
7
+ InjectionToken,
8
+ } from '../token/injection-token.mjs'
9
+
10
+ interface FooService {
11
+ makeFoo(): string
12
+ }
13
+
14
+ const simpleObjectSchema = z.object({
15
+ foo: z.string(),
16
+ })
17
+ const simpleOptionalObjectSchema = z
18
+ .object({
19
+ foo: z.string(),
20
+ })
21
+ .optional()
22
+
23
+ test('InjectionToken.create with class', () => {
24
+ class MyService {
25
+ getValue() {
26
+ return 42
27
+ }
28
+ }
29
+
30
+ const token = InjectionToken.create(MyService)
31
+ expectTypeOf(token).toMatchTypeOf<InjectionToken<MyService, undefined>>()
32
+ })
33
+
34
+ test('InjectionToken.create with class and schema', () => {
35
+ class MyService {
36
+ constructor(public config: z.infer<typeof simpleObjectSchema>) {}
37
+ getValue() {
38
+ return 42
39
+ }
40
+ }
41
+
42
+ const token = InjectionToken.create(MyService, simpleObjectSchema)
43
+ expectTypeOf(token).toMatchTypeOf<
44
+ InjectionToken<MyService, typeof simpleObjectSchema, true>
45
+ >()
46
+ })
47
+
48
+ test('InjectionToken.create with class and optional schema', () => {
49
+ class MyService {
50
+ constructor(public config?: z.infer<typeof simpleOptionalObjectSchema>) {}
51
+ getValue() {
52
+ return 42
53
+ }
54
+ }
55
+
56
+ const token = InjectionToken.create(MyService, simpleOptionalObjectSchema)
57
+ expectTypeOf(token).toMatchTypeOf<
58
+ InjectionToken<MyService, typeof simpleOptionalObjectSchema, false>
59
+ >()
60
+ })
61
+
62
+ test('InjectionToken.create with string name', () => {
63
+ const token = InjectionToken.create<FooService>('FooService')
64
+ expectTypeOf(token).toMatchTypeOf<InjectionToken<FooService, undefined>>()
65
+ })
66
+
67
+ test('InjectionToken.create with symbol name', () => {
68
+ const token = InjectionToken.create<FooService>(Symbol.for('FooService'))
69
+ expectTypeOf(token).toMatchTypeOf<InjectionToken<FooService, undefined>>()
70
+ })
71
+
72
+ test('InjectionToken.create with string name and schema', () => {
73
+ const token = InjectionToken.create<FooService, typeof simpleObjectSchema>(
74
+ 'FooService',
75
+ simpleObjectSchema,
76
+ )
77
+ expectTypeOf(token).toMatchTypeOf<
78
+ InjectionToken<FooService, typeof simpleObjectSchema>
79
+ >()
80
+ })
81
+
82
+ test('InjectionToken.bound creates BoundInjectionToken', () => {
83
+ const token = InjectionToken.create<FooService, typeof simpleObjectSchema>(
84
+ 'FooService',
85
+ simpleObjectSchema,
86
+ )
87
+ const boundToken = InjectionToken.bound(token, { foo: 'bar' })
88
+ expectTypeOf(boundToken).toMatchTypeOf<
89
+ BoundInjectionToken<FooService, typeof simpleObjectSchema>
90
+ >()
91
+ })
92
+
93
+ test('InjectionToken.bound requires correct argument type', () => {
94
+ const token = InjectionToken.create<FooService, typeof simpleObjectSchema>(
95
+ 'FooService',
96
+ simpleObjectSchema,
97
+ )
98
+
99
+ // @ts-expect-error Should fail with wrong argument type
100
+ InjectionToken.bound(token, { wrong: 'key' })
101
+
102
+ // @ts-expect-error Should fail with missing required property
103
+ InjectionToken.bound(token, {})
104
+ })
105
+
106
+ test('InjectionToken.factory creates FactoryInjectionToken', () => {
107
+ const token = InjectionToken.create<FooService, typeof simpleObjectSchema>(
108
+ 'FooService',
109
+ simpleObjectSchema,
110
+ )
111
+ const factoryToken = InjectionToken.factory(token, async () => ({
112
+ foo: 'bar',
113
+ }))
114
+ expectTypeOf(factoryToken).toMatchTypeOf<
115
+ FactoryInjectionToken<FooService, typeof simpleObjectSchema>
116
+ >()
117
+ })
118
+
119
+ test('InjectionToken.factory requires correct return type', () => {
120
+ const token = InjectionToken.create<FooService, typeof simpleObjectSchema>(
121
+ 'FooService',
122
+ simpleObjectSchema,
123
+ )
124
+
125
+ // @ts-expect-error Should fail with wrong return type
126
+ InjectionToken.factory(token, async () => ({ wrong: 'key' }))
127
+ })
128
+
129
+ test('InjectionToken.refineType changes BoundInjectionToken type', () => {
130
+ interface RefinedService {
131
+ doSomething(): void
132
+ }
133
+
134
+ const token = InjectionToken.create<unknown, typeof simpleObjectSchema>(
135
+ 'Service',
136
+ simpleObjectSchema,
137
+ )
138
+ const boundToken = InjectionToken.bound(token, { foo: 'bar' })
139
+ const refinedToken = InjectionToken.refineType<RefinedService>(boundToken)
140
+ expectTypeOf(refinedToken).toMatchTypeOf<
141
+ BoundInjectionToken<RefinedService, any>
142
+ >()
143
+ })
144
+
145
+ test('BoundInjectionToken has value property with correct type', () => {
146
+ const token = InjectionToken.create<FooService, typeof simpleObjectSchema>(
147
+ 'FooService',
148
+ simpleObjectSchema,
149
+ )
150
+ const boundToken = InjectionToken.bound(token, { foo: 'bar' })
151
+
152
+ expectTypeOf(boundToken.value).toMatchTypeOf<{ foo: string }>()
153
+ })
154
+
155
+ test('FactoryInjectionToken has factory property', () => {
156
+ const token = InjectionToken.create<FooService, typeof simpleObjectSchema>(
157
+ 'FooService',
158
+ simpleObjectSchema,
159
+ )
160
+ const factoryToken = InjectionToken.factory(token, async () => ({
161
+ foo: 'bar',
162
+ }))
163
+
164
+ expectTypeOf(factoryToken.factory).toBeFunction()
165
+ })
166
+
167
+ test('InjectionToken properties', () => {
168
+ const token = InjectionToken.create<FooService, typeof simpleObjectSchema>(
169
+ 'FooService',
170
+ simpleObjectSchema,
171
+ )
172
+
173
+ expectTypeOf(token.id).toBeString()
174
+ expectTypeOf(token.name).toMatchTypeOf<string | symbol | (new (...args: any[]) => any)>()
175
+ expectTypeOf(token.toString()).toBeString()
176
+ })