Skip to content

Commit

Permalink
resolves #5: add beforInject and beforeConstruct hooks
Browse files Browse the repository at this point in the history
  • Loading branch information
zheksoon committed Apr 12, 2024
1 parent 3bb326b commit 070b9e1
Show file tree
Hide file tree
Showing 4 changed files with 307 additions and 22 deletions.
30 changes: 21 additions & 9 deletions src/container.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,19 +44,31 @@ export class Container {
return new Container(this, name);
};

public $getInstance(cls: any, args: any[] = []) {
public $getInstance(
descriptor: TokenClassDescriptor<any>,
args: any[] = [],
cache = true
) {
let instance = null;
let container: Container | null = this;

const cls = descriptor.class;

while (!instance && container) {
instance = container.instances.get(cls);
container = container.parentContainer;
}

if (!instance) {
if (descriptor.beforeConstruct) {
descriptor.beforeConstruct(this, descriptor, args);
}

instance = new cls(...args);

this.instances.set(cls, instance);
if (cache) {
this.instances.set(cls, instance);
}
}

return instance;
Expand Down Expand Up @@ -94,7 +106,7 @@ export class Container {

let container: Container = this;

const descriptor = this.getTokenDescriptor(clsOrToken);
let descriptor = this.getTokenDescriptor(clsOrToken);

this.resolutionSet.add(clsOrToken);

Expand All @@ -104,16 +116,17 @@ export class Container {
}

cls = clsOrToken;

scope = cls.scope || Scopes.Transient();

container = this;
descriptor = { class: cls, container: this };
} else {
if (descriptor.beforeInject) {
descriptor.beforeInject(container, descriptor, args);
}

if ("class" in descriptor) {
cls = descriptor.class as ScopedClass;

scope = descriptor.scope || cls.scope || Scopes.Transient();

container = descriptor.container;
} else if ("value" in descriptor) {
return descriptor.value;
Expand All @@ -125,10 +138,9 @@ export class Container {
}
}

return scope(cls, args, container, this.resolutionContainer);
return scope(descriptor, args, container, this.resolutionContainer);
} finally {
this.resolutionSet.delete(clsOrToken);

this.resolutionContainer = resolutionContainer;

if (!resolutionContainer) {
Expand Down
20 changes: 10 additions & 10 deletions src/scopes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,34 +4,34 @@ import type { ScopeHandler } from "./types";

export class Scopes {
public static Singleton(): ScopeHandler {
return function SingletonScope(cls, args) {
return function SingletonScope(descriptor, args) {
if (args.length > 0) {
throw new ArgumentsError(SingletonScope.name, cls.name);
throw new ArgumentsError(SingletonScope.name, descriptor.class.name);
}

return globalContainer.$getInstance(cls);
return globalContainer.$getInstance(descriptor);
};
}

public static Transient(): ScopeHandler {
return function TransientScope(cls, args) {
return new cls(...args);
return function TransientScope(descriptor, args, container) {
return container.$getInstance(descriptor, args, false);
};
}

public static Container(): ScopeHandler {
return function ContainerScope(cls, args, container) {
return function ContainerScope(descriptor, args, container) {
if (args.length > 0) {
throw new ArgumentsError(ContainerScope.name, cls.name);
throw new ArgumentsError(ContainerScope.name, descriptor.class.name);
}

return container.$getInstance(cls);
return container.$getInstance(descriptor);
};
}

public static Resolution(): ScopeHandler {
return function ResolutionScope(cls, args, _, resolutionContainer) {
return resolutionContainer.$getInstance(cls, args);
return function ResolutionScope(descriptor, args, _, resolutionContainer) {
return resolutionContainer.$getInstance(descriptor, args);
};
}

Expand Down
11 changes: 8 additions & 3 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,22 @@ type OptionalArgs<T, R = Required<T>> = R extends readonly [...infer Rest, infer

type TokenType<T, R = any> = T extends Token<infer U> ? U : R;

export type TokenValueDescriptor<T extends Token<any>> = {
type BaseDescriptor = {
beforeInject?: (container: Container, descriptor: AnyDescriptor, args: any[]) => any;
beforeConstruct?: (container: Container, descriptor: AnyDescriptor, args: any[]) => any;
};

export type TokenValueDescriptor<T extends Token<any>> = BaseDescriptor & {
token: T;
value: TokenType<T>;
};

export type TokenFactoryDescriptor<T extends Token<any>> = {
export type TokenFactoryDescriptor<T extends Token<any>> = BaseDescriptor & {
token: T;
factory: (container: Container, ...args: any[]) => TokenType<T>;
};

export type TokenClassDescriptor<T extends Token<any>> = {
export type TokenClassDescriptor<T extends Token<any>> = BaseDescriptor & {
token?: T;
class: Newable<TokenType<T>>;
scope?: ScopeHandler;
Expand Down
Loading

0 comments on commit 070b9e1

Please sign in to comment.