1 | import { Factory, FactoryDefinition } from './factory';
|
2 | import { RegistryReader, Injection } from './registry';
|
3 | import { Resolver } from './resolver';
|
4 | import { Dict } from './dict';
|
5 |
|
6 | interface Lookup {
|
7 | factory: Factory<any>;
|
8 | instance: any;
|
9 | }
|
10 |
|
11 | export default class Container {
|
12 | private _registry: RegistryReader;
|
13 | private _resolver: Resolver;
|
14 | private _lookups: Dict<Lookup>;
|
15 | private _factoryDefinitionLookups: Dict<FactoryDefinition<any>>;
|
16 |
|
17 | constructor(registry: RegistryReader, resolver: Resolver = null) {
|
18 | this._registry = registry;
|
19 | this._resolver = resolver;
|
20 | this._lookups = {};
|
21 | this._factoryDefinitionLookups = {};
|
22 | }
|
23 |
|
24 | factoryFor(specifier: string): Factory<any> {
|
25 | let factoryDefinition: FactoryDefinition<any> = this._factoryDefinitionLookups[specifier];
|
26 |
|
27 | if (!factoryDefinition) {
|
28 | if (this._resolver) {
|
29 | factoryDefinition = this._resolver.retrieve(specifier);
|
30 | }
|
31 |
|
32 | if (!factoryDefinition) {
|
33 | factoryDefinition = this._registry.registration(specifier);
|
34 | }
|
35 |
|
36 | if (factoryDefinition) {
|
37 | this._factoryDefinitionLookups[specifier] = factoryDefinition;
|
38 | }
|
39 | }
|
40 |
|
41 | if (!factoryDefinition) {
|
42 | return;
|
43 | }
|
44 |
|
45 | return this.buildFactory(specifier, factoryDefinition);
|
46 | }
|
47 |
|
48 | lookup(specifier: string): any {
|
49 | let singleton = (this._registry.registeredOption(specifier, 'singleton') !== false);
|
50 |
|
51 | if (singleton) {
|
52 | let lookup = this._lookups[specifier];
|
53 | if (lookup) {
|
54 | return lookup.instance;
|
55 | }
|
56 | }
|
57 |
|
58 | let factory = this.factoryFor(specifier);
|
59 | if (!factory) { return; }
|
60 |
|
61 | if (this._registry.registeredOption(specifier, 'instantiate') === false) {
|
62 | return factory.class;
|
63 | }
|
64 |
|
65 | let instance = factory.create();
|
66 |
|
67 | if (singleton && instance) {
|
68 | this._lookups[specifier] = { factory, instance };
|
69 | }
|
70 |
|
71 | return instance;
|
72 | }
|
73 |
|
74 | defaultInjections(specifier: string): object {
|
75 | return {};
|
76 | }
|
77 |
|
78 | teardown(): void {
|
79 | let specifiers = Object.keys(this._lookups);
|
80 |
|
81 | for (let i=0;i<specifiers.length;i++) {
|
82 | let specifier = specifiers[i];
|
83 | let { factory, instance } = this._lookups[specifier];
|
84 | factory.teardown(instance);
|
85 | }
|
86 | }
|
87 |
|
88 | defaultTeardown(instance): void {
|
89 | }
|
90 |
|
91 | private buildInjections(specifier: string): object {
|
92 | let hash = this.defaultInjections(specifier);
|
93 | let injections: Injection[] = this._registry.registeredInjections(specifier);
|
94 | let injection: Injection;
|
95 |
|
96 | for (let i = 0; i < injections.length; i++) {
|
97 | injection = injections[i];
|
98 | hash[injection.property] = this.lookup(injection.source);
|
99 | }
|
100 |
|
101 | return hash;
|
102 | }
|
103 |
|
104 | private buildFactory(specifier: string, factoryDefinition: FactoryDefinition<any>): Factory<any> {
|
105 | let injections = this.buildInjections(specifier);
|
106 |
|
107 | return {
|
108 | class: factoryDefinition,
|
109 | teardown: (instance) => {
|
110 | if (factoryDefinition.teardown) {
|
111 | factoryDefinition.teardown(instance);
|
112 | } else {
|
113 | this.defaultTeardown(instance);
|
114 | }
|
115 | },
|
116 | create(options) {
|
117 | let mergedOptions = Object.assign({}, injections, options);
|
118 |
|
119 | return factoryDefinition.create(mergedOptions);
|
120 | }
|
121 | }
|
122 | }
|
123 | }
|