1 | "use strict";
|
2 | let Enumerable = require('linq');
|
3 | const utils_1 = require('../core/metadata/utils');
|
4 | const constants_1 = require('../core/constants');
|
5 | const decorator_type_1 = require('../core/enums/decorator-type');
|
6 | const Utils = require('../core/utils');
|
7 | let _extSources = [];
|
8 | let _depInstMap = new Map();
|
9 | let _serviceMap = new Map();
|
10 | function extSources(extSources) {
|
11 | if (extSources !== undefined) {
|
12 | _extSources = extSources;
|
13 | }
|
14 | return _extSources;
|
15 | }
|
16 | exports.extSources = extSources;
|
17 | function serviceMap(serviceMap) {
|
18 | if (serviceMap !== undefined) {
|
19 | _serviceMap = serviceMap;
|
20 | }
|
21 | return _serviceMap;
|
22 | }
|
23 | exports.serviceMap = serviceMap;
|
24 |
|
25 |
|
26 | function generateToken(fn) {
|
27 | return fn.toString();
|
28 | }
|
29 | class DependencyNode {
|
30 | constructor(data) {
|
31 | this.parents = new Map();
|
32 | this.children = new Map();
|
33 | ;
|
34 | this.current = data;
|
35 | }
|
36 | }
|
37 | let dependencyRoot = new Map();
|
38 | let dependencyOrder;
|
39 | class DI {
|
40 | constructor() {
|
41 | this.stack = [];
|
42 | }
|
43 | resolveDependencies(cls) {
|
44 | if (_serviceMap.has(cls)) {
|
45 | return this.resolveServiceDependency(cls, _serviceMap.get(cls));
|
46 | }
|
47 | return this.getFromExtSources(cls);
|
48 | }
|
49 | getFromExtSources(cls) {
|
50 | let inst;
|
51 | _extSources.forEach(func => {
|
52 | if (!inst) {
|
53 | inst = func.apply(this, [cls]);
|
54 | }
|
55 | });
|
56 | return inst;
|
57 | }
|
58 | getDependencyOrderString(cls) {
|
59 | let arr = [];
|
60 | dependencyOrder.forEach((value, key) => {
|
61 | arr.push(key.name);
|
62 | });
|
63 | cls && arr.push(cls.name);
|
64 | return arr.join('=>');
|
65 | }
|
66 | resolveServiceDependency(cls, service) {
|
67 | let inst;
|
68 | if (!service.singleton) {
|
69 | inst = this.instantiateClass(cls);
|
70 | }
|
71 | inst = this.getInstance(cls);
|
72 | if (inst) {
|
73 | return inst;
|
74 | }
|
75 | else {
|
76 | inst = this.instantiateClass(cls);
|
77 | }
|
78 | return inst;
|
79 | }
|
80 | getInstance(cls) {
|
81 | return _depInstMap.get(cls);
|
82 | }
|
83 | getDependencies(cls) {
|
84 | return Enumerable.from(utils_1.MetaUtils.getMetaData(cls.prototype, constants_1.Decorators.INJECT));
|
85 | }
|
86 | publicDeps(deps) {
|
87 | return Enumerable.from(deps)
|
88 | .where((x) => x.decoratorType === decorator_type_1.DecoratorType.PROPERTY)
|
89 | .toArray();
|
90 | }
|
91 | constructorDeps(deps) {
|
92 | return Enumerable.from(deps)
|
93 | .where((x) => x.decoratorType === decorator_type_1.DecoratorType.PARAM)
|
94 | .toArray();
|
95 | }
|
96 | resolveConstructorDeps(deps) {
|
97 | let resolvedDeps = [];
|
98 | Enumerable.from(deps)
|
99 | .orderBy((x) => x.paramIndex)
|
100 | .forEach((x) => {
|
101 | let type = x.params.type;
|
102 | if (type.default) {
|
103 | type = type.default;
|
104 | }
|
105 | if (!type) {
|
106 | console.log(x);
|
107 | throw 'no type found';
|
108 | }
|
109 | resolvedDeps.push(this.resolveDependencies(type));
|
110 | });
|
111 | return resolvedDeps;
|
112 | }
|
113 | getType(params) {
|
114 | let type = params.type;
|
115 | if (type.__esModule) {
|
116 | type = type.default;
|
117 | }
|
118 | return type;
|
119 | }
|
120 | resolvePropDeps(inst, propDeps) {
|
121 | Enumerable.from(propDeps)
|
122 | .forEach((x) => {
|
123 | inst[x.propertyKey] = this.resolveDependencies(x.params.type);
|
124 | });
|
125 | }
|
126 |
|
127 | getCycle(parent, child) {
|
128 | let arr = Enumerable.from(this.stack)
|
129 | .select(x => x.parent.name)
|
130 | .toArray();
|
131 | arr.push(parent.name, child.name);
|
132 | return arr.join(" => ");
|
133 | }
|
134 |
|
135 | instantiateClass(cls) {
|
136 | console.log('get dependencies: ' + cls.name);
|
137 | let allDependencies = this.getDependencies(cls);
|
138 | let deps = this.constructorDeps(allDependencies);
|
139 | let str = Enumerable.from(deps)
|
140 | .select((x) => this.getType(x.params) ? this.getType(x.params).name : ' @ ')
|
141 | .toArray()
|
142 | .join(",");
|
143 | console.log(" " + str);
|
144 | if (!dependencyRoot.get(cls)) {
|
145 | dependencyRoot.set(cls, new DependencyNode(cls));
|
146 | }
|
147 | Enumerable.from(deps)
|
148 | .forEach((x) => {
|
149 | let type = this.getType(x.params);
|
150 | if (!dependencyRoot.get(type)) {
|
151 | dependencyRoot.set(type, new DependencyNode(type));
|
152 | }
|
153 | dependencyRoot.get(cls).children.set(type, true);
|
154 | if (dependencyRoot.get(type).children.get(cls)) {
|
155 | let cycleDepStr = this.getCycle(cls, type);
|
156 | throw Error('Cycle found: ' + cycleDepStr);
|
157 | }
|
158 | dependencyRoot.get(type).parents.set(cls, true);
|
159 | });
|
160 | this.stack.push({ parent: cls, children: deps });
|
161 | let injectedProps = this.publicDeps(allDependencies);
|
162 | let resolvedDeps = this.resolveConstructorDeps(deps);
|
163 | let inst = Utils.activator(cls, resolvedDeps);
|
164 | this.resolvePropDeps(inst, injectedProps);
|
165 | _depInstMap.set(cls, inst);
|
166 | this.stack.pop();
|
167 | return inst;
|
168 | }
|
169 | }
|
170 | class Container {
|
171 | |
172 |
|
173 |
|
174 |
|
175 |
|
176 |
|
177 | static addService(cls, params) {
|
178 | _serviceMap.set(cls, params);
|
179 | }
|
180 | |
181 |
|
182 |
|
183 |
|
184 | static resolve(key) {
|
185 | let srvKey = key;
|
186 | if (key.__esModule) {
|
187 | srvKey = key.default;
|
188 | }
|
189 | dependencyOrder = dependencyOrder || new Map();
|
190 | let di = new DI();
|
191 | return di.resolveDependencies(srvKey);
|
192 | }
|
193 | static addSource(source) {
|
194 | _extSources.push(source);
|
195 |
|
196 |
|
197 |
|
198 |
|
199 |
|
200 |
|
201 | }
|
202 | }
|
203 | exports.Container = Container;
|
204 |
|
205 |
|