initial commit
This commit is contained in:
44
dependency-manager.ts
Normal file
44
dependency-manager.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
type Provider<T> = (manager: DependencyManager) => Promise<T> | T;
|
||||
|
||||
type Modules = Map<string, {
|
||||
provider: Provider<any>;
|
||||
instance?: any;
|
||||
}>;
|
||||
|
||||
export class DependencyManager {
|
||||
private modules: Modules = new Map();
|
||||
private resolving: Set<string> = new Set();
|
||||
|
||||
// Enregistrer un module avec son initialisateur
|
||||
register<T>(name: string, provider: Provider<T>): void {
|
||||
if (this.modules.has(name)) {
|
||||
throw new Error(`Module ${name} is already registered.`);
|
||||
}
|
||||
this.modules.set(name, { provider });
|
||||
}
|
||||
|
||||
// Résoudre un module et ses dépendances
|
||||
async resolve<T>(name: string): Promise<T> {
|
||||
const module = this.modules.get(name);
|
||||
if (!module) {
|
||||
throw new Error(`Module ${name} is not registered.`);
|
||||
}
|
||||
|
||||
if (module.instance) {
|
||||
return module.instance;
|
||||
}
|
||||
|
||||
if (this.resolving.has(name)) {
|
||||
throw new Error(`Circular dependency detected for module ${name}.`);
|
||||
}
|
||||
|
||||
this.resolving.add(name);
|
||||
|
||||
try {
|
||||
module.instance = await module.provider(this);
|
||||
return module.instance;
|
||||
} finally {
|
||||
this.resolving.delete(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
69
readme.md
Normal file
69
readme.md
Normal file
@@ -0,0 +1,69 @@
|
||||
# Dependency manager
|
||||
|
||||
This lib provides a simplistic dependency manager.
|
||||
|
||||
## Features and limitations
|
||||
|
||||
- It resolves dependencies only when they are needed
|
||||
- It detect circular dependency
|
||||
|
||||
## Usage
|
||||
|
||||
Create a manager:
|
||||
|
||||
```typescript
|
||||
import { DependencyManager } from 'dependency-manager/mod.ts'
|
||||
|
||||
const manager = new DependencyManager()
|
||||
```
|
||||
|
||||
Create providers for your dependencies.
|
||||
A provider is a function that is called when attempting to retrieve the dependency for the first time.
|
||||
It receive the dependency manager, and return the dependency value, or a promise that resolves to it.
|
||||
|
||||
```typescript
|
||||
// dependency-free provider
|
||||
function loggerProvider() {
|
||||
return console.log
|
||||
}
|
||||
type Logger = ReturnType<typeof loggerProvider>;
|
||||
|
||||
// provider that need the 'logger' dependency
|
||||
async function fooProvider(manager: DependencyManager) {
|
||||
const logger = await manager.resolve<Logger>('logger');
|
||||
|
||||
return {
|
||||
bar: () => logger('bar'),
|
||||
baz: () => logger('baz'),
|
||||
}
|
||||
}
|
||||
type Foo = Awaited<ReturnType<typeof fooProvider>>;
|
||||
```
|
||||
|
||||
Register the dependency by passing the `register` method its name and provider:
|
||||
|
||||
```typescript
|
||||
manager.register('logger', loggerProvider);
|
||||
manager.register('foo', fooProvider);
|
||||
```
|
||||
|
||||
Retrieve dependencies by resolving them (always asynchrone, even if the provider was synchrone):
|
||||
|
||||
```typescript
|
||||
const foo = await manager.resolve<Foo>('foo');
|
||||
foo.bar();
|
||||
foo.baz();
|
||||
```
|
||||
|
||||
## Typing
|
||||
|
||||
Types should be explicitly defined when resolving a dependency.
|
||||
|
||||
## Errors
|
||||
|
||||
The `register` method throw an error if:
|
||||
- the name is already used.
|
||||
|
||||
The `resolve` method throw an error if:
|
||||
- the name doesn't exist (if no module has been registred with the given name).
|
||||
- a circular dependency is detected
|
||||
Reference in New Issue
Block a user