@raubjo/architect 0.5.1

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 (68) hide show
  1. package/README.md +860 -0
  2. package/package.json +121 -0
  3. package/src/cache/cache.ts +46 -0
  4. package/src/cache/contract.ts +9 -0
  5. package/src/cache/manager.ts +110 -0
  6. package/src/cache/provider.ts +11 -0
  7. package/src/config/contract.ts +63 -0
  8. package/src/config/discovery.ts +99 -0
  9. package/src/config/env.global.d.ts +6 -0
  10. package/src/config/env.ts +68 -0
  11. package/src/config/index.ts +5 -0
  12. package/src/config/provider.ts +17 -0
  13. package/src/config/repository.ts +164 -0
  14. package/src/container/adapters/builtin.ts +323 -0
  15. package/src/container/contract.ts +43 -0
  16. package/src/container/runtime.ts +29 -0
  17. package/src/events/bus.ts +174 -0
  18. package/src/events/concerns/dispatchable.ts +10 -0
  19. package/src/events/provider.ts +9 -0
  20. package/src/events/types.ts +9 -0
  21. package/src/foundation/application.ts +136 -0
  22. package/src/foundation/current-application.ts +20 -0
  23. package/src/index.ts +58 -0
  24. package/src/log/contract.ts +21 -0
  25. package/src/log/drivers/console.ts +54 -0
  26. package/src/log/drivers/null.ts +23 -0
  27. package/src/log/drivers/stack.ts +46 -0
  28. package/src/log/manager.ts +76 -0
  29. package/src/log/provider.ts +11 -0
  30. package/src/react.ts +2 -0
  31. package/src/renderers/adapters/react.tsx +25 -0
  32. package/src/renderers/adapters/solid.tsx +26 -0
  33. package/src/renderers/adapters/svelte.ts +73 -0
  34. package/src/renderers/adapters/vue.ts +22 -0
  35. package/src/renderers/contract.ts +12 -0
  36. package/src/runtimes/react.tsx +81 -0
  37. package/src/runtimes/solid.tsx +47 -0
  38. package/src/runtimes/svelte.ts +17 -0
  39. package/src/runtimes/vue.ts +34 -0
  40. package/src/solid.ts +2 -0
  41. package/src/store/adapters/contract.ts +11 -0
  42. package/src/store/adapters/indexed-db.ts +187 -0
  43. package/src/store/adapters/local-storage.ts +48 -0
  44. package/src/store/adapters/memory.ts +35 -0
  45. package/src/store/manager.ts +68 -0
  46. package/src/store/provider.ts +10 -0
  47. package/src/store/store.ts +1 -0
  48. package/src/support/arr.ts +372 -0
  49. package/src/support/collection.ts +889 -0
  50. package/src/support/facades/cache.ts +6 -0
  51. package/src/support/facades/config.ts +6 -0
  52. package/src/support/facades/event.ts +6 -0
  53. package/src/support/facades/facade.ts +146 -0
  54. package/src/support/facades/index.ts +5 -0
  55. package/src/support/facades/log.ts +6 -0
  56. package/src/support/facades/store.ts +6 -0
  57. package/src/support/fluent.ts +56 -0
  58. package/src/support/globals.ts +8 -0
  59. package/src/support/lazy-collection.ts +341 -0
  60. package/src/support/manager.ts +53 -0
  61. package/src/support/num.ts +50 -0
  62. package/src/support/pipeline.ts +29 -0
  63. package/src/support/service-provider.ts +19 -0
  64. package/src/support/str.ts +682 -0
  65. package/src/svelte.ts +2 -0
  66. package/src/types/peer-deps.d.ts +10 -0
  67. package/src/vue.ts +2 -0
  68. package/tsconfig.json +15 -0
@@ -0,0 +1,6 @@
1
+ import type CacheManager from "../../cache/manager"
2
+ import { createFacade } from "./facade"
3
+
4
+ export const Cache = createFacade<CacheManager>("cache")
5
+
6
+ export default Cache
@@ -0,0 +1,6 @@
1
+ import type ConfigRepository from "../../config/repository"
2
+ import { createFacade } from "./facade"
3
+
4
+ export const Config = createFacade<ConfigRepository>("config")
5
+
6
+ export default Config
@@ -0,0 +1,6 @@
1
+ import type { Bus } from "../../events/bus"
2
+ import { createFacade } from "./facade"
3
+
4
+ export const Event = createFacade<Bus>("events")
5
+
6
+ export default Event
@@ -0,0 +1,146 @@
1
+ import { makeFromCurrentApplication } from "../../foundation/current-application"
2
+
3
+ // Module-level state shared by all facades.
4
+ const macroRegistry = new Map<string, Map<string, (...args: unknown[]) => unknown>>()
5
+ const resolvedInstances = new Map<string, unknown>()
6
+
7
+ export function clearFacadeCache(): void {
8
+ resolvedInstances.clear()
9
+ }
10
+
11
+ export function flushAllMacros(): void {
12
+ macroRegistry.clear()
13
+ }
14
+
15
+ function getMacros(accessor: string): Map<string, (...args: unknown[]) => unknown> {
16
+ let macros = macroRegistry.get(accessor)
17
+ if (!macros) {
18
+ macros = new Map()
19
+ macroRegistry.set(accessor, macros)
20
+ }
21
+ return macros
22
+ }
23
+
24
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
25
+ export interface FacadeInstance<T = unknown> {
26
+ getFacadeAccessor(): string
27
+ macro(name: string, fn: (instance: T, ...args: unknown[]) => unknown): void
28
+ hasMacro(name: string): boolean
29
+ flushMacros(): void
30
+ clearResolvedInstance(name: string): void
31
+ clearResolvedInstances(): void
32
+ callFacadeMethod(method: string, ...args: unknown[]): unknown
33
+ callFacadeMethod<R = unknown>(method: string, ...args: unknown[]): R
34
+ use(...args: unknown[]): unknown
35
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
36
+ [key: string]: any
37
+ }
38
+
39
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
40
+ export function createFacade<T = any>(accessor: string): FacadeInstance<T> {
41
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
42
+ let proxy: any
43
+
44
+ const facade: Record<string, unknown> = {
45
+ getFacadeAccessor(): string {
46
+ return accessor
47
+ },
48
+
49
+ macro(name: string, fn: (instance: T, ...args: unknown[]) => unknown): void {
50
+ getMacros(accessor).set(name, fn as (...args: unknown[]) => unknown)
51
+ },
52
+
53
+ hasMacro(name: string): boolean {
54
+ return getMacros(accessor).has(name)
55
+ },
56
+
57
+ flushMacros(): void {
58
+ getMacros(accessor).clear()
59
+ },
60
+
61
+ clearResolvedInstance(name: string): void {
62
+ resolvedInstances.delete(name)
63
+ },
64
+
65
+ clearResolvedInstances(): void {
66
+ resolvedInstances.clear()
67
+ },
68
+
69
+ callFacadeMethod<R = unknown>(method: string, ...args: unknown[]): R {
70
+ const macro = getMacros(accessor).get(method)
71
+ if (macro) {
72
+ const instance = resolveInstance<T>(accessor)
73
+ return macro(instance, ...args) as R
74
+ }
75
+
76
+ const instance = resolveInstance<Record<string, (...a: unknown[]) => unknown>>(accessor)
77
+ const callable = instance[method]
78
+ if (typeof callable !== "function") {
79
+ throw new Error(`Method [${method}] does not exist on resolved facade instance.`)
80
+ }
81
+
82
+ return callable.apply(instance, args) as R
83
+ },
84
+
85
+ // use() returns the proxy instead of the instance's return value so callers can chain.
86
+ use(...args: unknown[]): unknown {
87
+ const instance = resolveInstance<Record<string, (...a: unknown[]) => unknown>>(accessor)
88
+ if (typeof instance.use === "function") {
89
+ instance.use(...args)
90
+ }
91
+ return proxy
92
+ },
93
+ }
94
+
95
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
96
+ proxy = new Proxy(facade, {
97
+ get(target, prop) {
98
+ if (prop in target) {
99
+ return target[prop as string]
100
+ }
101
+
102
+ const name = String(prop)
103
+
104
+ // Macro check (takes precedence over instance methods).
105
+ const macros = getMacros(accessor)
106
+ const macro = macros.get(name)
107
+ if (macro) {
108
+ return (...args: unknown[]) => {
109
+ const instance = resolveInstance<T>(accessor)
110
+ return macro(instance, ...args)
111
+ }
112
+ }
113
+
114
+ const instance = resolveInstance<Record<string, unknown>>(accessor)
115
+ const value = instance[prop as keyof typeof instance]
116
+
117
+ if (typeof value === "function") {
118
+ return (...args: unknown[]) => {
119
+ return (value as (...a: unknown[]) => unknown).apply(instance, args)
120
+ }
121
+ }
122
+
123
+ return value
124
+ },
125
+
126
+ has(target, prop) {
127
+ if (prop in target) return true
128
+ const name = String(prop)
129
+ if (getMacros(accessor).has(name)) return true
130
+ const instance = resolveInstance<Record<string, unknown>>(accessor)
131
+ return name in instance
132
+ },
133
+ })
134
+
135
+ return proxy as FacadeInstance<T>
136
+ }
137
+
138
+ function resolveInstance<T>(accessor: string): T {
139
+ if (resolvedInstances.has(accessor)) {
140
+ return resolvedInstances.get(accessor) as T
141
+ }
142
+
143
+ const instance = makeFromCurrentApplication<T>(accessor)
144
+ resolvedInstances.set(accessor, instance)
145
+ return instance
146
+ }
@@ -0,0 +1,5 @@
1
+ export { Cache } from "./cache"
2
+ export { Config } from "./config"
3
+ export { Event } from "./event"
4
+ export { Log } from "./log"
5
+ export { Store } from "./store"
@@ -0,0 +1,6 @@
1
+ import type LogManager from "../../log/manager"
2
+ import { createFacade } from "./facade"
3
+
4
+ export const Log = createFacade<LogManager>("log")
5
+
6
+ export default Log
@@ -0,0 +1,6 @@
1
+ import type StoreManager from "../../store/manager"
2
+ import { createFacade } from "./facade"
3
+
4
+ export const Store = createFacade<StoreManager>("store")
5
+
6
+ export default Store
@@ -0,0 +1,56 @@
1
+ // biome-ignore lint/suspicious/noUnsafeDeclarationMerging: Proxy in constructor handles runtime property access; interface merging is intentional for typed T["key"] access
2
+ export class Fluent<T extends Record<string, unknown> = Record<string, unknown>> {
3
+ protected attributes: Record<string, unknown>
4
+
5
+ constructor(attributes: T = {} as T) {
6
+ this.attributes = { ...attributes }
7
+
8
+ // biome-ignore lint/correctness/noConstructorReturn: Creating a proxy for magic methods: `get()`
9
+ return new Proxy(this, {
10
+ get(target, prop, receiver) {
11
+ if (typeof prop === "string" && !(prop in target)) {
12
+ return target.attributes[prop]
13
+ }
14
+ return Reflect.get(target, prop, receiver)
15
+ },
16
+ }) as Fluent<T>
17
+ }
18
+
19
+ get(key: string): unknown
20
+ get<V>(key: string): V | null
21
+ get<V>(key: string, defaultValue: V): V
22
+ get<V>(key: string, defaultValue: V | null): V | null
23
+ get<V = unknown>(key: string, defaultValue?: V | null): unknown {
24
+ const fallback = defaultValue !== undefined ? defaultValue : null
25
+ const parts = key.split(".")
26
+ let current: unknown = this.attributes
27
+ for (const part of parts) {
28
+ if (current === null || current === undefined || typeof current !== "object") return fallback
29
+ current = (current as Record<string, unknown>)[part]
30
+ }
31
+ return current === undefined ? fallback : current
32
+ }
33
+
34
+ set(key: string, value: unknown): this {
35
+ const parts = key.split(".")
36
+ let current = this.attributes
37
+ for (let i = 0; i < parts.length - 1; i++) {
38
+ const part = parts[i]
39
+ if (typeof current[part] !== "object" || current[part] === null) current[part] = {}
40
+ current = current[part] as Record<string, unknown>
41
+ }
42
+ current[parts[parts.length - 1]] = value
43
+ return this
44
+ }
45
+
46
+ has(key: string): boolean {
47
+ return this.get(key) !== null
48
+ }
49
+
50
+ toArray(): T {
51
+ return { ...this.attributes } as T
52
+ }
53
+ }
54
+
55
+ // eslint-disable-next-line @typescript-eslint/no-empty-object-type
56
+ export interface Fluent<T extends Record<string, unknown> = Record<string, unknown>> extends T {}
@@ -0,0 +1,8 @@
1
+ export function registerGlobalHelpers(helpers: Record<string, unknown>): void {
2
+ const globalScope = globalThis as Record<string, unknown>
3
+ for (const [key, value] of Object.entries(helpers)) {
4
+ if (typeof globalScope[key] === "undefined") {
5
+ globalScope[key] = value
6
+ }
7
+ }
8
+ }
@@ -0,0 +1,341 @@
1
+ import { Collection } from "./collection"
2
+
3
+ export class LazyCollection<T> implements Iterable<T> {
4
+ protected constructor(protected readonly source: () => Iterable<T>) {}
5
+
6
+ static make<T>(source: (() => Iterable<T>) | Iterable<T>): LazyCollection<T> {
7
+ if (typeof source === "function") {
8
+ return new LazyCollection(source as () => Iterable<T>)
9
+ }
10
+ const captured = source
11
+ return new LazyCollection(() => captured)
12
+ }
13
+
14
+ static times<U>(count: number, callback: (n: number) => U): LazyCollection<U> {
15
+ return new LazyCollection(function* () {
16
+ for (let i = 1; i <= count; i++) {
17
+ yield callback(i)
18
+ }
19
+ })
20
+ }
21
+
22
+ [Symbol.iterator](): Iterator<T> {
23
+ return this.source()[Symbol.iterator]()
24
+ }
25
+
26
+ // ── Lazy (return LazyCollection) ──────────────────────────────────────────
27
+
28
+ map<U>(callback: (item: T, index: number) => U): LazyCollection<U> {
29
+ const self = this
30
+ return new LazyCollection(function* () {
31
+ let i = 0
32
+ for (const item of self) {
33
+ yield callback(item, i++)
34
+ }
35
+ })
36
+ }
37
+
38
+ filter(callback?: (item: T, index: number) => boolean): LazyCollection<T> {
39
+ const self = this
40
+ return new LazyCollection(function* () {
41
+ let i = 0
42
+ for (const item of self) {
43
+ if (callback ? callback(item, i++) : Boolean(item)) yield item
44
+ else i++
45
+ }
46
+ })
47
+ }
48
+
49
+ reject(callback: (item: T, index: number) => boolean): LazyCollection<T> {
50
+ return this.filter((item, i) => !callback(item, i))
51
+ }
52
+
53
+ flatMap<U>(callback: (item: T, index: number) => U[]): LazyCollection<U> {
54
+ const self = this
55
+ return new LazyCollection(function* () {
56
+ let i = 0
57
+ for (const item of self) {
58
+ yield* callback(item, i++)
59
+ }
60
+ })
61
+ }
62
+
63
+ take(count: number): LazyCollection<T> {
64
+ const self = this
65
+ return new LazyCollection(function* () {
66
+ if (count <= 0) return
67
+ let n = 0
68
+ const iter = self[Symbol.iterator]()
69
+ while (n < count) {
70
+ const { done, value } = iter.next()
71
+ if (done) break
72
+ yield value
73
+ n++
74
+ }
75
+ })
76
+ }
77
+
78
+ skip(count: number): LazyCollection<T> {
79
+ const self = this
80
+ return new LazyCollection(function* () {
81
+ let n = 0
82
+ for (const item of self) {
83
+ if (n++ < count) continue
84
+ yield item
85
+ }
86
+ })
87
+ }
88
+
89
+ takeUntil(valueOrCallback: T | ((item: T, index: number) => boolean)): LazyCollection<T> {
90
+ const self = this
91
+ return new LazyCollection(function* () {
92
+ let i = 0
93
+ const iter = self[Symbol.iterator]()
94
+ while (true) {
95
+ const { done, value } = iter.next()
96
+ if (done) break
97
+ const match =
98
+ typeof valueOrCallback === "function"
99
+ ? (valueOrCallback as (item: T, index: number) => boolean)(value, i++)
100
+ : value === valueOrCallback
101
+ if (match) break
102
+ yield value
103
+ }
104
+ })
105
+ }
106
+
107
+ takeWhile(callback: (item: T, index: number) => boolean): LazyCollection<T> {
108
+ return this.takeUntil((item, i) => !callback(item, i))
109
+ }
110
+
111
+ skipUntil(valueOrCallback: T | ((item: T, index: number) => boolean)): LazyCollection<T> {
112
+ if (typeof valueOrCallback === "function") {
113
+ return this.skipWhile((item, i) => !valueOrCallback(item, i))
114
+ }
115
+ return this.skipWhile((item) => item !== valueOrCallback)
116
+ }
117
+
118
+ skipWhile(callback: (item: T, index: number) => boolean): LazyCollection<T> {
119
+ const self = this
120
+ return new LazyCollection(function* () {
121
+ let skipping = true
122
+ let i = 0
123
+ for (const item of self) {
124
+ if (skipping && callback(item, i++)) continue
125
+ skipping = false
126
+ yield item
127
+ }
128
+ })
129
+ }
130
+
131
+ tap(callback: (item: T) => void): LazyCollection<T> {
132
+ const self = this
133
+ return new LazyCollection(function* () {
134
+ for (const item of self) {
135
+ callback(item)
136
+ yield item
137
+ }
138
+ })
139
+ }
140
+
141
+ chunk(size: number): LazyCollection<T[]> {
142
+ const self = this
143
+ return new LazyCollection(function* () {
144
+ let buf: T[] = []
145
+ for (const item of self) {
146
+ buf.push(item)
147
+ if (buf.length === size) {
148
+ yield buf
149
+ buf = []
150
+ }
151
+ }
152
+ if (buf.length > 0) yield buf
153
+ })
154
+ }
155
+
156
+ concat(other: Iterable<T>): LazyCollection<T> {
157
+ const self = this
158
+ return new LazyCollection(function* () {
159
+ yield* self
160
+ yield* other
161
+ })
162
+ }
163
+
164
+ values(): LazyCollection<T> {
165
+ return this
166
+ }
167
+
168
+ unique(key?: keyof T | ((item: T) => unknown)): LazyCollection<T> {
169
+ const self = this
170
+ return new LazyCollection(function* () {
171
+ const seen = new Set<unknown>()
172
+ for (const item of self) {
173
+ const v = self.extractValue(item, key)
174
+ if (!seen.has(v)) {
175
+ seen.add(v)
176
+ yield item
177
+ }
178
+ }
179
+ })
180
+ }
181
+
182
+ pluck<K extends keyof T>(key: K): LazyCollection<T[K]> {
183
+ return this.map((item) => item[key])
184
+ }
185
+
186
+ // ── Terminal (materialize) ─────────────────────────────────────────────────
187
+
188
+ collect(): Collection<T> {
189
+ return new Collection(this.all())
190
+ }
191
+
192
+ all(): T[] {
193
+ return [...this]
194
+ }
195
+
196
+ toArray(): T[] {
197
+ return this.all()
198
+ }
199
+
200
+ count(): number {
201
+ return this.all().length
202
+ }
203
+
204
+ first(callback?: (item: T, index: number) => boolean): T | null {
205
+ let i = 0
206
+ for (const item of this) {
207
+ if (!callback || callback(item, i++)) return item
208
+ }
209
+ return null
210
+ }
211
+
212
+ last(callback?: (item: T, index: number) => boolean): T | null {
213
+ let result: T | null = null
214
+ let i = 0
215
+ for (const item of this) {
216
+ if (!callback || callback(item, i++)) result = item
217
+ }
218
+ return result
219
+ }
220
+
221
+ each(callback: (item: T, index: number) => void): void {
222
+ let i = 0
223
+ for (const item of this) {
224
+ callback(item, i++)
225
+ }
226
+ }
227
+
228
+ reduce<U>(callback: (carry: U, item: T, index: number) => U, initial: U): U {
229
+ let acc = initial
230
+ let i = 0
231
+ for (const item of this) {
232
+ acc = callback(acc, item, i++)
233
+ }
234
+ return acc
235
+ }
236
+
237
+ sum(key?: keyof T | ((item: T) => number)): number {
238
+ let total = 0
239
+ for (const item of this) total += this.extractValue(item, key) as number
240
+ return total
241
+ }
242
+
243
+ min(key?: keyof T | ((item: T) => number)): T | null {
244
+ let result: T | null = null
245
+ let minVal: number | null = null
246
+ for (const item of this) {
247
+ const v = this.extractValue(item, key) as number
248
+ if (minVal === null || v < minVal) {
249
+ minVal = v
250
+ result = item
251
+ }
252
+ }
253
+ return result
254
+ }
255
+
256
+ max(key?: keyof T | ((item: T) => number)): T | null {
257
+ let result: T | null = null
258
+ let maxVal: number | null = null
259
+ for (const item of this) {
260
+ const v = this.extractValue(item, key) as number
261
+ if (maxVal === null || v > maxVal) {
262
+ maxVal = v
263
+ result = item
264
+ }
265
+ }
266
+ return result
267
+ }
268
+
269
+ avg(key?: keyof T | ((item: T) => number)): number {
270
+ let total = 0
271
+ let count = 0
272
+ for (const item of this) {
273
+ total += this.extractValue(item, key) as number
274
+ count++
275
+ }
276
+ return count === 0 ? 0 : total / count
277
+ }
278
+
279
+ average(key?: keyof T | ((item: T) => number)): number {
280
+ return this.avg(key)
281
+ }
282
+
283
+ contains(itemOrCallback: T | ((item: T) => boolean)): boolean {
284
+ const test =
285
+ typeof itemOrCallback === "function"
286
+ ? (itemOrCallback as (item: T) => boolean)
287
+ : (i: T) => i === itemOrCallback
288
+ for (const item of this) {
289
+ if (test(item)) return true
290
+ }
291
+ return false
292
+ }
293
+
294
+ every(callback: (item: T, index: number) => boolean): boolean {
295
+ let i = 0
296
+ for (const item of this) {
297
+ if (!callback(item, i++)) return false
298
+ }
299
+ return true
300
+ }
301
+
302
+ some(callback: (item: T, index: number) => boolean): boolean {
303
+ let i = 0
304
+ for (const item of this) {
305
+ if (callback(item, i++)) return true
306
+ }
307
+ return false
308
+ }
309
+
310
+ groupBy<K extends string>(key: keyof T | ((item: T) => K)): Record<string, LazyCollection<T>> {
311
+ const groups: Record<string, T[]> = {}
312
+ for (const item of this) {
313
+ const k = String(this.extractValue(item, key))
314
+ if (!groups[k]) groups[k] = []
315
+ groups[k].push(item)
316
+ }
317
+ return Object.fromEntries(Object.entries(groups).map(([k, v]) => [k, LazyCollection.make(v)]))
318
+ }
319
+
320
+ toJson(): string {
321
+ return JSON.stringify(this.all())
322
+ }
323
+
324
+ // ── protected helpers ───────────────────────────────────────────────────────
325
+
326
+ protected extractValue(item: T, key?: keyof T | ((item: T) => unknown)): unknown {
327
+ if (!key) return item
328
+ return typeof key === "function" ? key(item) : item[key]
329
+ }
330
+
331
+ // ─────────────────────────────────────────────────────────────────────────
332
+
333
+ isEmpty(): boolean {
334
+ for (const _ of this) return false
335
+ return true
336
+ }
337
+
338
+ isNotEmpty(): boolean {
339
+ return !this.isEmpty()
340
+ }
341
+ }
@@ -0,0 +1,53 @@
1
+ import ConfigRepository from "../config/repository"
2
+
3
+ export default abstract class Manager<TDriver, TFactory = TDriver> {
4
+ protected drivers: Record<string, TDriver>
5
+ protected customCreators: Record<string, (config: ConfigRepository) => TDriver>
6
+ protected active: string
7
+ protected config: ConfigRepository
8
+
9
+ constructor(
10
+ drivers: Record<string, TDriver>,
11
+ active = "default",
12
+ config: ConfigRepository = new ConfigRepository({}),
13
+ ) {
14
+ this.drivers = { ...drivers }
15
+ this.customCreators = {}
16
+ this.config = config
17
+ this.active = active in drivers ? active : this.defaultDriverName()
18
+ }
19
+
20
+ extend(name: string, factory: (config: ConfigRepository) => TFactory): this {
21
+ this.customCreators[name] = (cfg) => this.createDriver(factory(cfg), cfg)
22
+ return this
23
+ }
24
+
25
+ use(name: string): this {
26
+ this.active = this.resolve(name) ? name : this.active
27
+ return this
28
+ }
29
+
30
+ protected abstract createDriver(raw: TFactory, config: ConfigRepository): TDriver
31
+
32
+ protected defaultDriverName(): string {
33
+ return Object.keys(this.drivers)[0] ?? "default"
34
+ }
35
+
36
+ protected driverType(): string {
37
+ return "Driver"
38
+ }
39
+
40
+ protected resolve(name: string): TDriver {
41
+ if (name in this.drivers) {
42
+ return this.drivers[name]
43
+ }
44
+
45
+ if (name in this.customCreators) {
46
+ const driver = this.customCreators[name](this.config)
47
+ this.drivers[name] = driver
48
+ return driver
49
+ }
50
+
51
+ throw new Error(`${this.driverType()} [${name}] is not defined.`)
52
+ }
53
+ }