-
Notifications
You must be signed in to change notification settings - Fork 0
/
ioc.js
140 lines (119 loc) · 4.01 KB
/
ioc.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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
/*******************************************************************************************
* @ Name : IOC Container
* @ Author : Abbas Hosseini
* @ Description : A simple library that support dependency injection
* @ Version : 1.0.0
* @ Last update : Thursday - 2018 08 February
******************************************************************************************/
var core = (() =>{
/**
* IoC container symbol
*
* @type {Symbol}
* @private
* @description : Symbols is a good replacement for
* strings or integers as class/module constants
*/
const _container = Symbol('container');
/**
* Cache symbol
* @type {Symbol}
* @private
*/
const _cache = Symbol('cache');
/**
* IoC container class
*
* @class {IOC}
* @description : IoC container (or DI) is a design pattern that
* creates objects based on request and inject them when required
*/
class IOC {
constructor() {
this[_container] = new Map();
this[_cache] = new Map();
}
/**
* Get the shared container
*
* @returns {Map<string, object>}
*/
get container() {
return this[_container];
}
/**
* Get the shared container
*
* @returns {Map<string, object>}
*/
get cache() {
return this[_cache];
}
/**
* Register a module to IoC container
*
* @param {String} name is the module name
* @param {Function} factory is a factory function
* @returns return true when defining a module that was not previously defined
*/
register(name, factory) {
if (this.container.has(name))
throw new Error(`adding ${name} to container failed, because its already exists.`)
this.container.set(name, {
factory: factory,
dependencies: this.extractArgs(factory) || [],
});
}
/**
* Resolve a injected module
*
* @param {String} name is the name of requested module
* @returns {Object}
*/
resolve(name) {
if (this.cache.has(name))
return this.cache.get(name);
if (!this.container.has(name)) return undefined;
let self = this,
factory = this.container.get(name).factory,
dependencies = this.container.get(name).dependencies;
if (dependencies.length == 0) {
var instance = factory();
this.cache.set(name, instance);
}
var parameters = [];
dependencies.forEach(dependency => parameters.push(self.resolve(dependency)));
var instance = factory.apply(null, parameters);
this.cache.set(name, instance);
return instance;
}
/**
* Extract arguments of function
*
* @param {Function} fn is a factory function
* @returns {Array} args is list of function arguments
*/
extractArgs(fn) {
let ARROW_ARG = /^\s*[^\(]*\(\s*([^\)=>]*)\)/,
FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m,
fnText = fn.toString(),
regResult = fnText.match(FN_ARGS) || fnText.match(ARROW_ARG),
args = regResult[1].split(',').map((item) => {
return item.trim();
})
//fix split string ''
args = (args[0] == '') ? [] : args;
return args;
}
}
var ioc = new IOC();
//Public Interface
return {
define : (moduleName, fn) =>{
ioc.register(moduleName, fn)
},
require: (moduleName) => {
return ioc.resolve(moduleName)
},
}
})()