From 9796a7277e08d85e476ecb0086b1f6a6d1fb1b29 Mon Sep 17 00:00:00 2001 From: garrettmills Date: Thu, 17 Jun 2021 19:34:32 -0500 Subject: [PATCH] Begin abstracting global container into injector --- src/di/Container.ts | 6 +++++ src/di/ContainerBlueprint.ts | 42 +++++++++++++++++++++++++++++++++++ src/di/decorator/injection.ts | 6 ++--- src/di/index.ts | 1 + src/lifecycle/AppClass.ts | 9 ++++---- src/lifecycle/Application.ts | 12 +++++++++- 6 files changed, 67 insertions(+), 9 deletions(-) create mode 100644 src/di/ContainerBlueprint.ts diff --git a/src/di/Container.ts b/src/di/Container.ts index 34efd19..5580c51 100644 --- a/src/di/Container.ts +++ b/src/di/Container.ts @@ -7,6 +7,7 @@ import {ClosureFactory} from './factory/ClosureFactory' import NamedFactory from './factory/NamedFactory' import SingletonFactory from './factory/SingletonFactory' import {InvalidDependencyKeyError} from './error/InvalidDependencyKeyError' +import {ContainerBlueprint} from './ContainerBlueprint' export type MaybeFactory = AbstractFactory | undefined export type MaybeDependency = any | undefined @@ -23,6 +24,11 @@ export class Container { const existing = globalRegistry.getGlobal('extollo/injector') if ( !existing ) { const container = new Container() + + ContainerBlueprint.getContainerBlueprint() + .resolve() + .map(factory => container.registerFactory(factory)) + globalRegistry.setGlobal('extollo/injector', container) return container } diff --git a/src/di/ContainerBlueprint.ts b/src/di/ContainerBlueprint.ts new file mode 100644 index 0000000..3b78d75 --- /dev/null +++ b/src/di/ContainerBlueprint.ts @@ -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)[] = [] + + /** + * 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): 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): this { + this.factories.push(() => new Factory(dependency)) + return this + } + + resolve(): AbstractFactory[] { + return this.factories.map(x => x()) + } +} diff --git a/src/di/decorator/injection.ts b/src/di/decorator/injection.ts index 2f4cfa5..b42ab23 100644 --- a/src/di/decorator/injection.ts +++ b/src/di/decorator/injection.ts @@ -10,7 +10,7 @@ import { DEPENDENCY_KEYS_SERVICE_TYPE_KEY, PropertyDependency, } from '../types' -import {Container} from '../Container' +import {ContainerBlueprint} from '../ContainerBlueprint' /** * Get a collection of dependency requirements for the given target object. @@ -145,9 +145,9 @@ export const Singleton = (name?: string): ClassDecorator => { Injectable()(target) if ( name ) { - Container.getContainer().registerNamed(name, target) + ContainerBlueprint.getContainerBlueprint().registerNamed(name, target) } else { - Container.getContainer().register(target) + ContainerBlueprint.getContainerBlueprint().register(target) } } } diff --git a/src/di/index.ts b/src/di/index.ts index ce299c5..acfa927 100644 --- a/src/di/index.ts +++ b/src/di/index.ts @@ -7,6 +7,7 @@ export * from './factory/Factory' export * from './factory/NamedFactory' export * from './factory/SingletonFactory' +export * from './ContainerBlueprint' export * from './Container' export * from './ScopedContainer' export * from './types' diff --git a/src/lifecycle/AppClass.ts b/src/lifecycle/AppClass.ts index f569cc4..e551dce 100644 --- a/src/lifecycle/AppClass.ts +++ b/src/lifecycle/AppClass.ts @@ -1,5 +1,5 @@ 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. @@ -25,12 +25,11 @@ export function isBindable(what: unknown): what is Bindable { /** * Base for classes that gives access to the global application and container. */ +@Injectable() export class AppClass { /** The global application instance. */ - private readonly appClassApplication!: Application; - - constructor() { - this.appClassApplication = Application.getApplication() + private get appClassApplication(): Application { + return Application.getApplication() } /** Get the global Application. */ diff --git a/src/lifecycle/Application.ts b/src/lifecycle/Application.ts index fe0565d..3b6ca75 100644 --- a/src/lifecycle/Application.ts +++ b/src/lifecycle/Application.ts @@ -1,4 +1,4 @@ -import {Container} from '../di' +import {Container, ContainerBlueprint} from '../di' import { ErrorWithContext, globalRegistry, @@ -52,6 +52,11 @@ export class Application extends Container { const existing = globalRegistry.getGlobal('extollo/injector') if ( !existing ) { const container = new Application() + + ContainerBlueprint.getContainerBlueprint() + .resolve() + .map(factory => container.registerFactory(factory)) + globalRegistry.setGlobal('extollo/injector', container) return container } @@ -74,6 +79,11 @@ export class Application extends Container { return app } else { const app = new Application() + + ContainerBlueprint.getContainerBlueprint() + .resolve() + .map(factory => app.registerFactory(factory)) + globalRegistry.setGlobal('extollo/injector', app) return app }