Begin abstracting global container into injector

This commit is contained in:
Garrett Mills 2021-06-17 19:34:32 -05:00
parent f00233d49a
commit 9796a7277e
Signed by: garrettmills
GPG Key ID: D2BF5FBA8298F246
6 changed files with 67 additions and 9 deletions

View File

@ -7,6 +7,7 @@ import {ClosureFactory} from './factory/ClosureFactory'
import NamedFactory from './factory/NamedFactory' import NamedFactory from './factory/NamedFactory'
import SingletonFactory from './factory/SingletonFactory' import SingletonFactory from './factory/SingletonFactory'
import {InvalidDependencyKeyError} from './error/InvalidDependencyKeyError' import {InvalidDependencyKeyError} from './error/InvalidDependencyKeyError'
import {ContainerBlueprint} from './ContainerBlueprint'
export type MaybeFactory<T> = AbstractFactory<T> | undefined export type MaybeFactory<T> = AbstractFactory<T> | undefined
export type MaybeDependency = any | undefined export type MaybeDependency = any | undefined
@ -23,6 +24,11 @@ export class Container {
const existing = <Container | undefined> globalRegistry.getGlobal('extollo/injector') const existing = <Container | undefined> globalRegistry.getGlobal('extollo/injector')
if ( !existing ) { if ( !existing ) {
const container = new Container() const container = new Container()
ContainerBlueprint.getContainerBlueprint()
.resolve()
.map(factory => container.registerFactory(factory))
globalRegistry.setGlobal('extollo/injector', container) globalRegistry.setGlobal('extollo/injector', container)
return container return container
} }

View File

@ -0,0 +1,42 @@
import {Instantiable} from './types'
import NamedFactory from './factory/NamedFactory'
import {AbstractFactory} from './factory/AbstractFactory'
import {Factory} from './factory/Factory'
export class ContainerBlueprint {
private static instance?: ContainerBlueprint
public static getContainerBlueprint(): ContainerBlueprint {
if ( !this.instance ) {
this.instance = new ContainerBlueprint()
}
return this.instance
}
protected factories: (() => AbstractFactory<any>)[] = []
/**
* Register a basic instantiable class as a standard Factory with this container,
* identified by a string name rather than static class.
* @param {string} name - unique name to identify the factory in the container
* @param {Instantiable} dependency
*/
registerNamed(name: string, dependency: Instantiable<any>): this {
this.factories.push(() => new NamedFactory(name, dependency))
return this
}
/**
* Register a basic instantiable class as a standard Factory with this container.
* @param {Instantiable} dependency
*/
register(dependency: Instantiable<any>): this {
this.factories.push(() => new Factory(dependency))
return this
}
resolve(): AbstractFactory<any>[] {
return this.factories.map(x => x())
}
}

View File

@ -10,7 +10,7 @@ import {
DEPENDENCY_KEYS_SERVICE_TYPE_KEY, DEPENDENCY_KEYS_SERVICE_TYPE_KEY,
PropertyDependency, PropertyDependency,
} from '../types' } from '../types'
import {Container} from '../Container' import {ContainerBlueprint} from '../ContainerBlueprint'
/** /**
* Get a collection of dependency requirements for the given target object. * Get a collection of dependency requirements for the given target object.
@ -145,9 +145,9 @@ export const Singleton = (name?: string): ClassDecorator => {
Injectable()(target) Injectable()(target)
if ( name ) { if ( name ) {
Container.getContainer().registerNamed(name, target) ContainerBlueprint.getContainerBlueprint().registerNamed(name, target)
} else { } else {
Container.getContainer().register(target) ContainerBlueprint.getContainerBlueprint().register(target)
} }
} }
} }

View File

@ -7,6 +7,7 @@ export * from './factory/Factory'
export * from './factory/NamedFactory' export * from './factory/NamedFactory'
export * from './factory/SingletonFactory' export * from './factory/SingletonFactory'
export * from './ContainerBlueprint'
export * from './Container' export * from './Container'
export * from './ScopedContainer' export * from './ScopedContainer'
export * from './types' export * from './types'

View File

@ -1,5 +1,5 @@
import {Application} from './Application' import {Application} from './Application'
import {Container, DependencyKey} from '../di' import {Container, DependencyKey, Injectable} from '../di'
/** /**
* Base type for a class that supports binding methods by string. * Base type for a class that supports binding methods by string.
@ -25,12 +25,11 @@ export function isBindable(what: unknown): what is Bindable {
/** /**
* Base for classes that gives access to the global application and container. * Base for classes that gives access to the global application and container.
*/ */
@Injectable()
export class AppClass { export class AppClass {
/** The global application instance. */ /** The global application instance. */
private readonly appClassApplication!: Application; private get appClassApplication(): Application {
return Application.getApplication()
constructor() {
this.appClassApplication = Application.getApplication()
} }
/** Get the global Application. */ /** Get the global Application. */

View File

@ -1,4 +1,4 @@
import {Container} from '../di' import {Container, ContainerBlueprint} from '../di'
import { import {
ErrorWithContext, ErrorWithContext,
globalRegistry, globalRegistry,
@ -52,6 +52,11 @@ export class Application extends Container {
const existing = <Container | undefined> globalRegistry.getGlobal('extollo/injector') const existing = <Container | undefined> globalRegistry.getGlobal('extollo/injector')
if ( !existing ) { if ( !existing ) {
const container = new Application() const container = new Application()
ContainerBlueprint.getContainerBlueprint()
.resolve()
.map(factory => container.registerFactory(factory))
globalRegistry.setGlobal('extollo/injector', container) globalRegistry.setGlobal('extollo/injector', container)
return container return container
} }
@ -74,6 +79,11 @@ export class Application extends Container {
return app return app
} else { } else {
const app = new Application() const app = new Application()
ContainerBlueprint.getContainerBlueprint()
.resolve()
.map(factory => app.registerFactory(factory))
globalRegistry.setGlobal('extollo/injector', app) globalRegistry.setGlobal('extollo/injector', app)
return app return app
} }