Setup eslint and enforce rules
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
@@ -1,14 +1,14 @@
|
||||
import {DependencyKey, InstanceRef, Instantiable, isInstantiable, StaticClass} from "./types";
|
||||
import {AbstractFactory} from "./factory/AbstractFactory";
|
||||
import {collect, Collection, globalRegistry, logIfDebugging} from "../util";
|
||||
import {Factory} from "./factory/Factory";
|
||||
import {DuplicateFactoryKeyError} from "./error/DuplicateFactoryKeyError";
|
||||
import {ClosureFactory} from "./factory/ClosureFactory";
|
||||
import NamedFactory from "./factory/NamedFactory";
|
||||
import SingletonFactory from "./factory/SingletonFactory";
|
||||
import {InvalidDependencyKeyError} from "./error/InvalidDependencyKeyError";
|
||||
import {DependencyKey, InstanceRef, Instantiable, isInstantiable} from './types'
|
||||
import {AbstractFactory} from './factory/AbstractFactory'
|
||||
import {collect, Collection, globalRegistry, logIfDebugging} from '../util'
|
||||
import {Factory} from './factory/Factory'
|
||||
import {DuplicateFactoryKeyError} from './error/DuplicateFactoryKeyError'
|
||||
import {ClosureFactory} from './factory/ClosureFactory'
|
||||
import NamedFactory from './factory/NamedFactory'
|
||||
import SingletonFactory from './factory/SingletonFactory'
|
||||
import {InvalidDependencyKeyError} from './error/InvalidDependencyKeyError'
|
||||
|
||||
export type MaybeFactory = AbstractFactory | undefined
|
||||
export type MaybeFactory<T> = AbstractFactory<T> | undefined
|
||||
export type MaybeDependency = any | undefined
|
||||
export type ResolvedDependency = { paramIndex: number, key: DependencyKey, resolved: any }
|
||||
|
||||
@@ -34,7 +34,7 @@ export class Container {
|
||||
* Collection of factories registered with this container.
|
||||
* @type Collection<AbstractFactory>
|
||||
*/
|
||||
protected factories: Collection<AbstractFactory> = new Collection<AbstractFactory>()
|
||||
protected factories: Collection<AbstractFactory<unknown>> = new Collection<AbstractFactory<unknown>>()
|
||||
|
||||
/**
|
||||
* Collection of singleton instances produced by this container.
|
||||
@@ -51,12 +51,14 @@ export class Container {
|
||||
* Register a basic instantiable class as a standard Factory with this container.
|
||||
* @param {Instantiable} dependency
|
||||
*/
|
||||
register(dependency: Instantiable<any>) {
|
||||
if ( this.resolve(dependency) )
|
||||
register(dependency: Instantiable<any>): this {
|
||||
if ( this.resolve(dependency) ) {
|
||||
throw new DuplicateFactoryKeyError(dependency)
|
||||
}
|
||||
|
||||
const factory = new Factory(dependency)
|
||||
this.factories.push(factory)
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -64,12 +66,14 @@ export class Container {
|
||||
* @param {string} name - unique name to identify the factory in the container
|
||||
* @param {function} producer - factory to produce a value
|
||||
*/
|
||||
registerProducer(name: string | StaticClass<any, any>, producer: () => any) {
|
||||
if ( this.resolve(name) )
|
||||
registerProducer(name: DependencyKey, producer: () => any): this {
|
||||
if ( this.resolve(name) ) {
|
||||
throw new DuplicateFactoryKeyError(name)
|
||||
}
|
||||
|
||||
const factory = new ClosureFactory(name, producer)
|
||||
this.factories.push(factory)
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -78,12 +82,14 @@ export class Container {
|
||||
* @param {string} name - unique name to identify the factory in the container
|
||||
* @param {Instantiable} dependency
|
||||
*/
|
||||
registerNamed(name: string, dependency: Instantiable<any>) {
|
||||
if ( this.resolve(name) )
|
||||
registerNamed(name: string, dependency: Instantiable<any>): this {
|
||||
if ( this.resolve(name) ) {
|
||||
throw new DuplicateFactoryKeyError(name)
|
||||
}
|
||||
|
||||
const factory = new NamedFactory(name, dependency)
|
||||
this.factories.push(factory)
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -92,11 +98,13 @@ export class Container {
|
||||
* @param {string} key - unique name to identify the singleton in the container
|
||||
* @param value
|
||||
*/
|
||||
registerSingleton(key: string, value: any) {
|
||||
if ( this.resolve(key) )
|
||||
registerSingleton<T>(key: DependencyKey, value: T): this {
|
||||
if ( this.resolve(key) ) {
|
||||
throw new DuplicateFactoryKeyError(key)
|
||||
}
|
||||
|
||||
this.factories.push(new SingletonFactory(value, key))
|
||||
this.factories.push(new SingletonFactory(key, value))
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -105,24 +113,30 @@ export class Container {
|
||||
* @param staticClass
|
||||
* @param instance
|
||||
*/
|
||||
registerSingletonInstance<T>(staticClass: Instantiable<T>, instance: T) {
|
||||
if ( this.resolve(staticClass) )
|
||||
registerSingletonInstance<T>(staticClass: Instantiable<T>, instance: T): this {
|
||||
if ( this.resolve(staticClass) ) {
|
||||
throw new DuplicateFactoryKeyError(staticClass)
|
||||
}
|
||||
|
||||
this.register(staticClass)
|
||||
this.instances.push({
|
||||
key: staticClass,
|
||||
value: instance,
|
||||
})
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a given factory with the container.
|
||||
* @param {AbstractFactory} factory
|
||||
*/
|
||||
registerFactory(factory: AbstractFactory) {
|
||||
if ( !this.factories.includes(factory) )
|
||||
registerFactory(factory: AbstractFactory<unknown>): this {
|
||||
if ( !this.factories.includes(factory) ) {
|
||||
this.factories.push(factory)
|
||||
}
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -138,7 +152,7 @@ export class Container {
|
||||
* @param {DependencyKey} key
|
||||
*/
|
||||
hasKey(key: DependencyKey): boolean {
|
||||
return !!this.resolve(key)
|
||||
return Boolean(this.resolve(key))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -147,17 +161,22 @@ export class Container {
|
||||
*/
|
||||
getExistingInstance(key: DependencyKey): MaybeDependency {
|
||||
const instances = this.instances.where('key', '=', key)
|
||||
if ( instances.isNotEmpty() ) return instances.first()
|
||||
if ( instances.isNotEmpty() ) {
|
||||
return instances.first()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the factory for the given key, if one is registered with this container.
|
||||
* @param {DependencyKey} key
|
||||
*/
|
||||
resolve(key: DependencyKey): MaybeFactory {
|
||||
resolve(key: DependencyKey): MaybeFactory<unknown> {
|
||||
const factory = this.factories.firstWhere(item => item.match(key))
|
||||
if ( factory ) return factory
|
||||
else logIfDebugging('extollo.di.injector', 'unable to resolve factory', factory, this.factories)
|
||||
if ( factory ) {
|
||||
return factory
|
||||
} else {
|
||||
logIfDebugging('extollo.di.injector', 'unable to resolve factory', factory, this.factories)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -172,22 +191,25 @@ export class Container {
|
||||
// If we've already instantiated this, just return that
|
||||
const instance = this.getExistingInstance(key)
|
||||
logIfDebugging('extollo.di.injector', 'resolveAndCreate existing instance?', instance)
|
||||
if ( typeof instance !== 'undefined' ) return instance.value
|
||||
if ( typeof instance !== 'undefined' ) {
|
||||
return instance.value
|
||||
}
|
||||
|
||||
// Otherwise, attempt to create it
|
||||
const factory = this.resolve(key)
|
||||
logIfDebugging('extollo.di.injector', 'resolveAndCreate factory', factory)
|
||||
if ( !factory )
|
||||
if ( !factory ) {
|
||||
throw new InvalidDependencyKeyError(key)
|
||||
}
|
||||
|
||||
// Produce and store a new instance
|
||||
const new_instance = this.produceFactory(factory, parameters)
|
||||
const newInstance = this.produceFactory(factory, parameters)
|
||||
this.instances.push({
|
||||
key,
|
||||
value: new_instance,
|
||||
value: newInstance,
|
||||
})
|
||||
|
||||
return new_instance
|
||||
return newInstance
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -196,7 +218,7 @@ export class Container {
|
||||
* @param {AbstractFactory} factory
|
||||
* @param {array} parameters
|
||||
*/
|
||||
protected produceFactory(factory: AbstractFactory, parameters: any[]) {
|
||||
protected produceFactory<T>(factory: AbstractFactory<T>, parameters: any[]): T {
|
||||
// Create the dependencies for the factory
|
||||
const keys = factory.getDependencyKeys().filter(req => this.hasKey(req.key))
|
||||
const dependencies = keys.map<ResolvedDependency>(req => {
|
||||
@@ -210,20 +232,23 @@ export class Container {
|
||||
// Build the arguments for the factory, using dependencies in the
|
||||
// correct paramIndex positions, or parameters of we don't have
|
||||
// the dependency.
|
||||
const construction_args = []
|
||||
let params = collect(parameters).reverse()
|
||||
const constructorArguments = []
|
||||
const params = collect(parameters).reverse()
|
||||
for ( let i = 0; i <= dependencies.max('paramIndex'); i++ ) {
|
||||
const dep = dependencies.firstWhere('paramIndex', '=', i)
|
||||
if ( dep ) construction_args.push(dep.resolved)
|
||||
else construction_args.push(params.pop())
|
||||
if ( dep ) {
|
||||
constructorArguments.push(dep.resolved)
|
||||
} else {
|
||||
constructorArguments.push(params.pop())
|
||||
}
|
||||
}
|
||||
|
||||
// Produce a new instance
|
||||
const inst = factory.produce(construction_args, params.reverse().all())
|
||||
const inst = factory.produce(constructorArguments, params.reverse().all())
|
||||
|
||||
factory.getInjectedProperties().each(dependency => {
|
||||
if ( dependency.key && inst ) {
|
||||
inst[dependency.property] = this.resolveAndCreate(dependency.key)
|
||||
(inst as any)[dependency.property] = this.resolveAndCreate(dependency.key)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -240,12 +265,13 @@ export class Container {
|
||||
* @param {...any} parameters
|
||||
*/
|
||||
make<T>(target: DependencyKey, ...parameters: any[]): T {
|
||||
if ( this.hasKey(target) )
|
||||
if ( this.hasKey(target) ) {
|
||||
return this.resolveAndCreate(target, ...parameters)
|
||||
else if ( typeof target !== 'string' && isInstantiable(target) )
|
||||
} else if ( typeof target !== 'string' && isInstantiable(target) ) {
|
||||
return this.produceFactory(new Factory(target), parameters)
|
||||
else
|
||||
} else {
|
||||
throw new TypeError(`Invalid or unknown make target: ${target}`)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -255,8 +281,9 @@ export class Container {
|
||||
getDependencies(target: DependencyKey): Collection<DependencyKey> {
|
||||
const factory = this.resolve(target)
|
||||
|
||||
if ( !factory )
|
||||
if ( !factory ) {
|
||||
throw new InvalidDependencyKeyError(target)
|
||||
}
|
||||
|
||||
return factory.getDependencyKeys().pluck('key')
|
||||
}
|
||||
@@ -265,8 +292,9 @@ export class Container {
|
||||
* Given a different container, copy the factories and instances from this container over to it.
|
||||
* @param container
|
||||
*/
|
||||
cloneTo(container: Container) {
|
||||
cloneTo(container: Container): this {
|
||||
container.factories = this.factories.clone()
|
||||
container.instances = this.instances.clone()
|
||||
return this
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user