-
Notifications
You must be signed in to change notification settings - Fork 1
/
di.js
102 lines (80 loc) · 2.21 KB
/
di.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
const sha1 = require('sha1');
const Immutable = require('immutable');
const ExtendableError = require('es6-error');
const {plan} = require('./plan');
const {lint} = require('./plan-lint');
class PlanLintError extends ExtendableError {
constructor(linterErrors) {
super();
this._linterErrors = linterErrors;
const errorsMessage = JSON.stringify(linterErrors, null, 2);
this.message = `Linter found following errors: ${errorsMessage}`;
}
get linterErrors() {
return this._linterErrors;
}
}
class DoesNotComputeError extends ExtendableError {}
class DependencyInjector {
constructor() {
this._idToPlanItem = new Immutable.Map();
this._idToFactory = new Immutable.Map();
}
define(...args) {
const [planItem, factory] = (() => {
if (args.length === 3) {
const [interface_, dependencies, factory] = args;
return [{interface: interface_, dependencies}, factory];
}
if (args.length === 2) {
if (typeof args[0] === 'object') {
return args;
}
const [interface_, factory] = args;
return [{interface: interface_}, factory];
}
})();
const id = (() => {
if (planItem.id) {
return planItem.id;
}
const hash = sha1(factory.toString());
return (new Immutable.Range())
.map(i => hash + '.' + i)
.find(id => !this._idToPlanItem.has(id));
})();
planItem.id = id;
this._idToPlanItem = this._idToPlanItem.set(id, planItem);
this._idToFactory = this._idToFactory.set(id, factory);
}
_lint(items, options) {
const errors = lint(items, options);
if (errors.length === 0) {
return;
}
throw new PlanLintError(errors);
}
require(interface_) {
const items = Array.from(this._idToPlanItem.values());
this._lint(items, {
target: interface_
});
const planned = plan(items, interface_);
if (!planned) {
throw new DoesNotComputeError();
}
const factory = planItem => this._idToFactory.get(planItem.id);
const instantiate = planItem => {
const depInstances = planItem.dependencies.map(instantiate);
return factory(planItem).apply(null, depInstances);
};
return instantiate(planned);
}
}
function makedi() {
return new DependencyInjector();
}
module.exports = Object.assign(makedi, {
DependencyInjector,
PlanLintError
});