lakutata
Version:
An IoC-based universal application framework.
290 lines (283 loc) • 8.49 kB
TypeScript
/**
* Injection mode type.
*/
type InjectionModeType = 'PROXY' | 'CLASSIC';
/**
* Lifetime type.
*/
type LifetimeType = 'APPLICATION_SINGLETON' | 'MODULE_SINGLETON' | 'SINGLETON' | 'TRANSIENT' | 'SCOPED';
/**
* Gets passed the container and is expected to return an object
* whose properties are accessible at construction time for the
* configured resolver.
*
* @type {Function}
*/
type InjectorFunction = <T extends object>(container: IDependencyInjectionContainer<T>) => object;
/**
* A resolver object returned by asClass(), asFunction() or asValue().
*/
interface Resolver<T> extends ResolverOptions<T> {
resolve<U extends object>(container: IDependencyInjectionContainer<U>): T;
}
/**
* Options for disposable resolvers.
*/
interface DisposableResolverOptions<T> extends ResolverOptions<T> {
dispose?: Disposer<T>;
}
/**
* Disposer function type.
*/
type Disposer<T> = (value: T) => any | Promise<any>;
/**
* The options when registering a class, function or value.
* @type RegistrationOptions
*/
interface ResolverOptions<T> {
/**
* Only used for inline configuration with `loadModules`.
*/
name?: string;
/**
* Lifetime setting.
*/
lifetime?: LifetimeType;
/**
* Registration function to use. Only used for inline configuration with `loadModules`.
*/
register?: (...args: any[]) => Resolver<T>;
/**
* True if this resolver should be excluded from lifetime leak checking. Used by resolvers that
* wish to uphold the anti-leakage contract themselves. Defaults to false.
*/
isLeakSafe?: boolean;
}
/**
* Builder resolver options.
*/
interface BuildResolverOptions<T> extends ResolverOptions<T>, DisposableResolverOptions<T> {
/**
* Resolution mode.
*/
injectionMode?: InjectionModeType;
/**
* Injector function to provide additional parameters.
*/
injector?: InjectorFunction;
}
/**
* A class constructor. For example:
*
* class MyClass {}
*
* container.registerClass('myClass', MyClass)
* ^^^^^^^
*/
type Constructor<T> = {
new (...args: any[]): T;
};
/**
* An object containing the module name and path (full path to module).
*
* @interface ModuleDescriptor
*/
interface ModuleDescriptor {
name: string;
path: string;
opts: any;
}
/**
* A glob pattern with associated registration options.
*/
type GlobWithOptions = [string] | [string, BuildResolverOptions<any> | LifetimeType];
/**
* Metadata of the module as well as the loaded module itself.
* @interface LoadedModuleDescriptor
*/
interface LoadedModuleDescriptor extends ModuleDescriptor {
value: unknown;
}
/**
* The options when invoking loadModules().
* @interface LoadModulesOptions
*/
interface LoadModulesOptions<ESM extends boolean = false> {
cwd?: string;
formatName?: NameFormatter | BuiltInNameFormatters;
resolverOptions?: BuildResolverOptions<any>;
esModules?: ESM;
}
/**
* Name formatting options when using loadModules().
* @type BuiltInNameFormatters
*/
type BuiltInNameFormatters = 'camelCase';
/**
* Takes in the filename of the module being loaded as well as the module descriptor,
* and returns a string which is used to register the module in the container.
*
* `descriptor.name` is the same as `name`.
*
* @type {NameFormatter}
*/
type NameFormatter = (name: string, descriptor: LoadedModuleDescriptor) => string;
/**
* The container returned from createContainer has some methods and properties.
* @interface IDependencyInjectionContainer
*/
interface IDependencyInjectionContainer<Cradle extends object = any> {
/**
* Options the container was configured with.
*/
options: ContainerOptions;
/**
* The proxy injected when using `PROXY` injection mode.
* Can be used as-is.
*/
readonly cradle: Cradle;
/**
* Getter for the rolled up registrations that merges the container family tree.
*/
readonly registrations: RegistrationHash;
/**
* Resolved modules cache.
*/
readonly cache: Map<string | symbol, CacheEntry>;
/**
* Creates a scoped container with this one as the parent.
*/
createScope<T extends object = object>(): IDependencyInjectionContainer<Cradle & T>;
/**
* Used by `util.inspect`.
*/
inspect(depth: number, opts?: any): string;
/**
* Binds `lib/loadModules` to this container, and provides
* real implementations of its dependencies.
*
* Additionally, any modules using the `dependsOn` API
* will be resolved.
*
* @see src/load-modules.ts documentation.
*/
loadModules<ESM extends boolean = false>(globPatterns: Array<string | GlobWithOptions>, options?: LoadModulesOptions<ESM>): ESM extends false ? this : Promise<this>;
/**
* Adds a single registration that using a pre-constructed resolver.
*/
register<T>(name: string | symbol, registration: Resolver<T>): this;
/**
* Pairs resolvers to registration names and registers them.
*/
register(nameAndRegistrationPair: NameAndRegistrationPair<Cradle>): this;
/**
* Resolves the registration with the given name.
*
* @param {string} name
* The name of the registration to resolve.
*
* @return {*}
* Whatever was resolved.
*/
resolve<K extends keyof Cradle>(name: K, resolveOptions?: ResolveOptions): Cradle[K];
/**
* Resolves the registration with the given name.
*
* @param {string} name
* The name of the registration to resolve.
*
* @return {*}
* Whatever was resolved.
*/
resolve<T>(name: string | symbol, resolveOptions?: ResolveOptions): T;
/**
* Checks if the registration with the given name exists.
*
* @param {string | symbol} name
* The name of the registration to resolve.
*
* @return {boolean}
* Whether or not the registration exists.
*/
hasRegistration(name: string | symbol): boolean;
/**
* Recursively gets a registration by name if it exists in the
* current container or any of its' parents.
*
* @param name {string | symbol} The registration name.
*/
getRegistration<K extends keyof Cradle>(name: K): Resolver<Cradle[K]> | null;
/**
* Recursively gets a registration by name if it exists in the
* current container or any of its' parents.
*
* @param name {string | symbol} The registration name.
*/
getRegistration<T = unknown>(name: string | symbol): Resolver<T> | null;
/**
* Given a resolver, class or function, builds it up and returns it.
* Does not cache it, this means that any lifetime configured in case of passing
* a resolver will not be used.
*
* @param {Resolver|Class|Function} targetOrResolver
* @param {ResolverOptions} opts
*/
build<T>(targetOrResolver: ClassOrFunctionReturning<T> | Resolver<T>, opts?: BuildResolverOptions<T>): T;
/**
* Disposes this container and it's children, calling the disposer
* on all disposable registrations and clearing the cache.
* Only applies to registrations with `SCOPED` or `SINGLETON` lifetime.
*/
dispose(): Promise<void>;
}
/**
* Optional resolve options.
*/
interface ResolveOptions {
/**
* If `true` and `resolve` cannot find the requested dependency,
* returns `undefined` rather than throwing an error.
*/
allowUnregistered?: boolean;
}
/**
* Cache entry.
*/
interface CacheEntry<T = any> {
/**
* The resolver that resolved the value.
*/
resolver: Resolver<T>;
/**
* The resolved value.
*/
value: T;
}
/**
* Register a Registration
* @interface NameAndRegistrationPair
*/
type NameAndRegistrationPair<T> = {
[U in keyof T]?: Resolver<T[U]>;
};
/**
* Function that returns T.
*/
type FunctionReturning<T> = (...args: Array<any>) => T;
/**
* A class or function returning T.
*/
type ClassOrFunctionReturning<T> = FunctionReturning<T> | Constructor<T>;
/**
* The options for the createContainer function.
*/
interface ContainerOptions {
require?: (id: string) => any;
injectionMode?: InjectionModeType;
strict?: boolean;
}
/**
* Contains a hash of registrations where the name is the key.
*/
type RegistrationHash = Record<string | symbol | number, Resolver<any>>;
export type { BuildResolverOptions, LifetimeType, NameAndRegistrationPair };