Skip to content
This repository was archived by the owner on Apr 21, 2024. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 24 additions & 26 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,28 +33,6 @@ import { ... } from 'https://denopkg.com/Coder-Spirit/lambda-ioc@[VERSION]/lambd
import { ... } from 'https://deno.land/x/lambda_ioc@[VERSION]/lambda-ioc/deno/index.ts'
```

## Benefits

- 100% type safe:
- The type checker will complain if we try to resolve unregistered
dependencies.
- The type checker will complain if we try to register new dependencies that
depend on unregistered dependencies, or if there is any kind of type
mismatch.
- Purely functional
- Immutable
- Circular dependencies are impossible

## Drawbacks

- All dependencies must be declared "in order".
- This implies that this IoC container cannot be used in combination with some
auto-wiring solutions, such as IoC decorators.
- The involved types are a bit convoluted:
- They might cause the type checker to be slow.
- In some situations, the type checker might be unable to infer the involved
types due to excessive "nested types" depth.

## Example

```ts
Expand Down Expand Up @@ -105,13 +83,33 @@ container.resolveGroup('group2') // ~ [3, 4], not necessarily in the same order
```

It is also possible to register and resolve asynchronous factories and
dependencies. They are not documented yet because some "helpers" are missing,
and therefore it's a bit more annoying to take advantage of that feature.

If you are curious, just try out:
dependencies. If you are curious, just try out:
- `registerAsync`
- `registerAsyncConstructor`
- `resolveAsync`

## Benefits

- 100% type safe:
- The type checker will complain if we try to resolve unregistered
dependencies.
- The type checker will complain if we try to register new dependencies that
depend on unregistered dependencies, or if there is any kind of type
mismatch.
- Purely functional
- Immutable
- Circular dependencies are impossible

## Drawbacks

- All dependencies must be declared "in order".
- This implies that this IoC container cannot be used in combination with some
auto-wiring solutions, such as IoC decorators.
- The involved types are a bit convoluted:
- They might cause the type checker to be slow.
- In some situations, the type checker might be unable to infer the involved
types due to excessive "nested types" depth.

## Differences respect to Diddly

- First-class support for Deno.
Expand Down
50 changes: 24 additions & 26 deletions lambda-ioc/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,28 +33,6 @@ import { ... } from 'https://denopkg.com/Coder-Spirit/lambda-ioc@[VERSION]/lambd
import { ... } from 'https://deno.land/x/lambda_ioc@[VERSION]/lambda-ioc/deno/index.ts'
```

## Benefits

- 100% type safe:
- The type checker will complain if we try to resolve unregistered
dependencies.
- The type checker will complain if we try to register new dependencies that
depend on unregistered dependencies, or if there is any kind of type
mismatch.
- Purely functional
- Immutable
- Circular dependencies are impossible

## Drawbacks

- All dependencies must be declared "in order".
- This implies that this IoC container cannot be used in combination with some
auto-wiring solutions, such as IoC decorators.
- The involved types are a bit convoluted:
- They might cause the type checker to be slow.
- In some situations, the type checker might be unable to infer the involved
types due to excessive "nested types" depth.

## Example

```ts
Expand Down Expand Up @@ -105,13 +83,33 @@ container.resolveGroup('group2') // ~ [3, 4], not necessarily in the same order
```

It is also possible to register and resolve asynchronous factories and
dependencies. They are not documented yet because some "helpers" are missing,
and therefore it's a bit more annoying to take advantage of that feature.

If you are curious, just try out:
dependencies. If you are curious, just try out:
- `registerAsync`
- `registerAsyncConstructor`
- `resolveAsync`

## Benefits

- 100% type safe:
- The type checker will complain if we try to resolve unregistered
dependencies.
- The type checker will complain if we try to register new dependencies that
depend on unregistered dependencies, or if there is any kind of type
mismatch.
- Purely functional
- Immutable
- Circular dependencies are impossible

## Drawbacks

- All dependencies must be declared "in order".
- This implies that this IoC container cannot be used in combination with some
auto-wiring solutions, such as IoC decorators.
- The involved types are a bit convoluted:
- They might cause the type checker to be slow.
- In some situations, the type checker might be unable to infer the involved
types due to excessive "nested types" depth.

## Differences respect to Diddly

- First-class support for Deno.
Expand Down
59 changes: 43 additions & 16 deletions lambda-ioc/deno/combinators.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,24 @@
import {
ContainerKey,
AsyncDependencyFactory,
ReadableContainer,
ReadableSyncContainer,
SyncDependencyFactory,
} from './container.ts';
import { ParamsToResolverKeys, TupleO, Zip } from './util.ts';
import { ContainerKey, ParamsToResolverKeys, TupleO, Zip } from './util.ts';

/**
* Given a dependency factory, returns a new factory that will always resolve
* the same instance of the dependency.
*/
export function singleton<
TVal,
TDependencies extends Record<ContainerKey, unknown>,
TSyncDependencies extends Record<ContainerKey, unknown>,
>(
// eslint-disable-next-line @typescript-eslint/ban-types
factory: SyncDependencyFactory<TVal, ReadableContainer<TDependencies, {}>>,
// eslint-disable-next-line @typescript-eslint/ban-types
): SyncDependencyFactory<TVal, ReadableContainer<TDependencies, {}>> {
factory: SyncDependencyFactory<
TVal,
ReadableSyncContainer<TSyncDependencies>
>,
): SyncDependencyFactory<TVal, ReadableSyncContainer<TSyncDependencies>> {
let result: Awaited<TVal> | undefined

return (container) => {
Expand All @@ -27,6 +29,33 @@ export function singleton<
}
}

/**
* Given a dependency factory, returns a new asynchronous factory that will
* always resolve the same instance of the dependency.
*/
export function asyncSingleton<
TVal,
TSyncDependencies extends Record<ContainerKey, unknown>,
TAsyncDependencies extends Record<ContainerKey, unknown>,
>(
factory: AsyncDependencyFactory<
TVal,
ReadableContainer<TSyncDependencies, TAsyncDependencies>
>,
): AsyncDependencyFactory<
TVal,
ReadableContainer<TSyncDependencies, TAsyncDependencies>
> {
let result: TVal | undefined

return async (container) => {
if (!result) {
result = await factory(container)
}
return result
}
}

/**
* Given a function, and a list of named dependencies, creates a new dependency
* factory that will resolve a parameterless function wrapping the original
Expand All @@ -35,20 +64,20 @@ export function singleton<
export function func<
TParams extends readonly unknown[],
TReturn,
TDependencies extends ParamsToResolverKeys<TParams>,
TSyncDependencies extends ParamsToResolverKeys<TParams>,
>(
fn: (...args: TParams) => Awaited<TReturn>,
...args: TDependencies
...args: TSyncDependencies
): SyncDependencyFactory<
() => TReturn,
SyncFuncContainer<TParams, TDependencies>
SyncFuncContainer<TParams, TSyncDependencies>
> {
return (container: SyncFuncContainer<TParams, TDependencies>) => {
return (container: SyncFuncContainer<TParams, TSyncDependencies>) => {
const resolvedArgs = args.map((arg) =>
container.resolve(
// This is ugly as hell, but I did not want to apply ts-ignore
arg as Parameters<
SyncFuncContainer<TParams, TDependencies>['resolve']
SyncFuncContainer<TParams, TSyncDependencies>['resolve']
>[0],
),
) as unknown as TParams
Expand Down Expand Up @@ -89,11 +118,9 @@ export function constructor<
type SyncFuncContainer<
TParams extends readonly unknown[],
TSyncDependencies extends ParamsToResolverKeys<TParams>,
> = ReadableContainer<
> = ReadableSyncContainer<
TupleO<
// eslint-disable-next-line @typescript-eslint/no-explicit-any
Extract<Zip<TSyncDependencies, TParams>, readonly [ContainerKey, any][]>
>,
// eslint-disable-next-line @typescript-eslint/ban-types
{}
>
>
Loading