Skip to content
This repository was archived by the owner on Apr 21, 2024. It is now read-only.

Commit 87dbd96

Browse files
committed
feat: implement resolveGroup
1 parent 116c674 commit 87dbd96

File tree

3 files changed

+135
-14
lines changed

3 files changed

+135
-14
lines changed

lambda-ioc/deno/container.ts

Lines changed: 46 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,14 @@
22

33
export type ContainerKey = string | symbol
44

5-
/**
6-
* Represents a dependency factory: a function that, given an IoC container, it
7-
* is able to instantiate a specific dependency.
8-
*/
5+
type ExtractPrefix<S extends ContainerKey> =
6+
S extends `${infer Prefix}:${string}` ? Prefix : never
7+
8+
type ExtractPrefixedValues<
9+
Prefix extends string,
10+
Struct extends Record<ContainerKey, unknown>,
11+
BaseKeys extends keyof Struct = keyof Struct,
12+
> = BaseKeys extends `${Prefix}:${infer U}` ? Struct[`${Prefix}:${U}`] : never
913

1014
export interface SyncDependencyFactory<
1115
T,
@@ -21,12 +25,13 @@ export interface AsyncDependencyFactory<
2125
Record<ContainerKey, unknown>
2226
>,
2327
> {
24-
// It might seem counterintuitive that we allow T as return type, but the
25-
// factory might also "become async" because of its dependencies, not just
26-
// because of its return type.
2728
(container: TContainer): Promise<T>
2829
}
2930

31+
/**
32+
* Represents a dependency factory: a function that, given an IoC container, it
33+
* is able to instantiate a specific dependency.
34+
*/
3035
export interface DependencyFactory<
3136
T,
3237
TContainer extends ReadableContainer<
@@ -63,6 +68,20 @@ export interface ReadableContainer<
6368
): Promise<TAsyncDependencies[TName]>
6469
}
6570

71+
export interface RedableGroupContainer<
72+
TSyncDependencies extends Record<ContainerKey, unknown>,
73+
> {
74+
resolveGroup<
75+
GroupName extends keyof TSyncDependencies extends ContainerKey
76+
? ExtractPrefix<keyof TSyncDependencies>
77+
: never,
78+
>(
79+
groupName: GroupName,
80+
): (keyof TSyncDependencies extends ContainerKey
81+
? ExtractPrefixedValues<GroupName, TSyncDependencies>
82+
: never)[]
83+
}
84+
6685
/**
6786
* Represents a write-only version of a type-safe IoC container with
6887
* "auto-wired" dependencies resolution.
@@ -173,6 +192,7 @@ export interface Container<
173192
TSyncDependencies extends Record<ContainerKey, unknown>,
174193
TAsyncDependencies extends Record<ContainerKey, unknown>,
175194
> extends ReadableContainer<TSyncDependencies, TAsyncDependencies>,
195+
RedableGroupContainer<TSyncDependencies>,
176196
WritableContainer<TSyncDependencies, TAsyncDependencies> {}
177197

178198
/**
@@ -365,5 +385,24 @@ function __createContainer<
365385
] as AsyncDependencyFactory<TAsyncDependencies[TName], typeof this>
366386
)(this)
367387
},
388+
389+
resolveGroup<GroupName extends string>(
390+
groupName: GroupName,
391+
): (keyof TSyncDependencies extends ContainerKey
392+
? ExtractPrefixedValues<GroupName, TSyncDependencies>
393+
: never)[] {
394+
return (
395+
Object.entries(syncDependencies)
396+
.filter(([key]) => {
397+
return key.startsWith(`${groupName}:`)
398+
})
399+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
400+
.map(([_key, value]) => {
401+
return value(this)
402+
}) as (keyof TSyncDependencies extends ContainerKey
403+
? ExtractPrefixedValues<GroupName, TSyncDependencies>
404+
: never)[]
405+
)
406+
},
368407
}
369408
}

lambda-ioc/src/__tests__/container.test.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,26 @@ describe('container', () => {
7979
expect(await c1.resolveAsync('ab')).toBe(15)
8080
expect(await c2.resolveAsync('ab')).toBe(21)
8181
})
82+
83+
it('can register groups by relying on prefixes', () => {
84+
const container = createContainer()
85+
.register('a', () => 10)
86+
.register('b', () => 20)
87+
.register('g1:a', () => 30)
88+
.register('g1:b', () => 40)
89+
.register('g2:a', () => 50)
90+
.register('g2:b', () => 60)
91+
92+
const g1 = container.resolveGroup('g1')
93+
expect(g1).toHaveLength(2)
94+
expect(g1).toContain(30)
95+
expect(g1).toContain(40)
96+
97+
const g2 = container.resolveGroup('g2')
98+
expect(g2).toHaveLength(2)
99+
expect(g2).toContain(50)
100+
expect(g2).toContain(60)
101+
})
82102
})
83103

84104
// Type tests
@@ -195,4 +215,27 @@ describe('@types/container', () => {
195215
const c_can_only_resolve_b: C_resolveAsync_Parameters_is_b = true
196216
expect(c_can_only_resolve_b).toBe(true)
197217
})
218+
219+
it('only resolves the sync registered groups', () => {
220+
type C = Container<
221+
{
222+
a: number
223+
b: number
224+
'g1:a': number
225+
'g1:b': string
226+
'g2:a': string
227+
'g2:b': boolean
228+
},
229+
{}
230+
>
231+
232+
type C_resolveGroup_Parameters = Parameters<C['resolveGroup']>
233+
type C_resolve_Parameters_is_g1g2 = C_resolveGroup_Parameters extends [
234+
'g1' | 'g2',
235+
]
236+
? true
237+
: false
238+
const c_can_only_resolveGroup_g1g2: C_resolve_Parameters_is_g1g2 = true
239+
expect(c_can_only_resolveGroup_g1g2).toBe(true)
240+
})
198241
})

lambda-ioc/src/container.ts

Lines changed: 46 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,14 @@
22

33
export type ContainerKey = string | symbol
44

5-
/**
6-
* Represents a dependency factory: a function that, given an IoC container, it
7-
* is able to instantiate a specific dependency.
8-
*/
5+
type ExtractPrefix<S extends ContainerKey> =
6+
S extends `${infer Prefix}:${string}` ? Prefix : never
7+
8+
type ExtractPrefixedValues<
9+
Prefix extends string,
10+
Struct extends Record<ContainerKey, unknown>,
11+
BaseKeys extends keyof Struct = keyof Struct,
12+
> = BaseKeys extends `${Prefix}:${infer U}` ? Struct[`${Prefix}:${U}`] : never
913

1014
export interface SyncDependencyFactory<
1115
T,
@@ -21,12 +25,13 @@ export interface AsyncDependencyFactory<
2125
Record<ContainerKey, unknown>
2226
>,
2327
> {
24-
// It might seem counterintuitive that we allow T as return type, but the
25-
// factory might also "become async" because of its dependencies, not just
26-
// because of its return type.
2728
(container: TContainer): Promise<T>
2829
}
2930

31+
/**
32+
* Represents a dependency factory: a function that, given an IoC container, it
33+
* is able to instantiate a specific dependency.
34+
*/
3035
export interface DependencyFactory<
3136
T,
3237
TContainer extends ReadableContainer<
@@ -63,6 +68,20 @@ export interface ReadableContainer<
6368
): Promise<TAsyncDependencies[TName]>
6469
}
6570

71+
export interface RedableGroupContainer<
72+
TSyncDependencies extends Record<ContainerKey, unknown>,
73+
> {
74+
resolveGroup<
75+
GroupName extends keyof TSyncDependencies extends ContainerKey
76+
? ExtractPrefix<keyof TSyncDependencies>
77+
: never,
78+
>(
79+
groupName: GroupName,
80+
): (keyof TSyncDependencies extends ContainerKey
81+
? ExtractPrefixedValues<GroupName, TSyncDependencies>
82+
: never)[]
83+
}
84+
6685
/**
6786
* Represents a write-only version of a type-safe IoC container with
6887
* "auto-wired" dependencies resolution.
@@ -173,6 +192,7 @@ export interface Container<
173192
TSyncDependencies extends Record<ContainerKey, unknown>,
174193
TAsyncDependencies extends Record<ContainerKey, unknown>,
175194
> extends ReadableContainer<TSyncDependencies, TAsyncDependencies>,
195+
RedableGroupContainer<TSyncDependencies>,
176196
WritableContainer<TSyncDependencies, TAsyncDependencies> {}
177197

178198
/**
@@ -365,5 +385,24 @@ function __createContainer<
365385
] as AsyncDependencyFactory<TAsyncDependencies[TName], typeof this>
366386
)(this)
367387
},
388+
389+
resolveGroup<GroupName extends string>(
390+
groupName: GroupName,
391+
): (keyof TSyncDependencies extends ContainerKey
392+
? ExtractPrefixedValues<GroupName, TSyncDependencies>
393+
: never)[] {
394+
return (
395+
Object.entries(syncDependencies)
396+
.filter(([key]) => {
397+
return key.startsWith(`${groupName}:`)
398+
})
399+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
400+
.map(([_key, value]) => {
401+
return value(this)
402+
}) as (keyof TSyncDependencies extends ContainerKey
403+
? ExtractPrefixedValues<GroupName, TSyncDependencies>
404+
: never)[]
405+
)
406+
},
368407
}
369408
}

0 commit comments

Comments
 (0)