UNPKG

3.21 kBPlain TextView Raw
1import { Factory, FactoryDefinition } from './factory';
2import { RegistryReader, Injection } from './registry';
3import { Resolver } from './resolver';
4import { Dict } from './dict';
5
6interface Lookup {
7 factory: Factory<any>;
8 instance: any;
9}
10
11export 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}