1 | (function() {
|
2 | var root;
|
3 | if (typeof window !== 'undefined' && window !== null) {
|
4 | root = window;
|
5 | } else {
|
6 | root = global;
|
7 | }
|
8 |
|
9 | root.$IMA = root.$IMA || {};
|
10 | var modules = {};
|
11 |
|
12 | root.$IMA.Loader = {
|
13 | modules: modules,
|
14 | register: function(moduleName, dependencies, moduleFactory) {
|
15 | this.modules[moduleName] = {
|
16 | dependencies: dependencies,
|
17 | dependencyOf: [],
|
18 | factory: moduleFactory,
|
19 | instance: null
|
20 | };
|
21 | },
|
22 | replaceModule: function(moduleName, dependencies, moduleFactory) {
|
23 | var moduleDescriptor = this.modules[moduleName];
|
24 | if (!moduleDescriptor) {
|
25 | throw new Error(
|
26 | 'You must register module "' + moduleName + '" at first.'
|
27 | );
|
28 | }
|
29 |
|
30 | Object.keys(this.modules).forEach(function(modulePath) {
|
31 | var module = root.$IMA.Loader.modules[modulePath];
|
32 | module.dependencies.forEach(function(dependency) {
|
33 | if (resolveModuleName(modulePath, dependency) === moduleName) {
|
34 | module.instance = null;
|
35 | }
|
36 | });
|
37 | });
|
38 |
|
39 | moduleDescriptor.dependencies = dependencies;
|
40 | moduleDescriptor.factory = moduleFactory;
|
41 | moduleDescriptor.dependencyOf = [];
|
42 | moduleDescriptor.instance = null;
|
43 |
|
44 | return resolveModule(moduleName);
|
45 | },
|
46 | import: function(moduleName) {
|
47 | return Promise.resolve(this.importSync(moduleName));
|
48 | },
|
49 | importSync: function(moduleName) {
|
50 | if (!this.modules[moduleName]) {
|
51 | throw new Error(
|
52 | '$IMA.Loader.importSync: Module name ' +
|
53 | moduleName +
|
54 | ' is not registered. Update your build.js.'
|
55 | );
|
56 | }
|
57 |
|
58 | return resolveModule(moduleName);
|
59 | },
|
60 | initAllModules: function() {
|
61 | Object.keys(modules).forEach(function(moduleName) {
|
62 | resolveModule(moduleName);
|
63 | });
|
64 |
|
65 | return Promise.resolve();
|
66 | }
|
67 | };
|
68 |
|
69 | function resolveModule(moduleName, dependencyOf, parentDependencySetter) {
|
70 | if (!modules[moduleName]) {
|
71 | throw new Error(
|
72 | '$IMA.Loader.import: Module name ' +
|
73 | moduleName +
|
74 | (dependencyOf ? ' (dependency of ' + dependencyOf + ')' : '') +
|
75 | ' is not registered. Update your build.js.'
|
76 | );
|
77 | }
|
78 |
|
79 | var module = modules[moduleName];
|
80 | if (
|
81 | parentDependencySetter &&
|
82 | module.dependencyOf.indexOf(parentDependencySetter) === -1
|
83 | ) {
|
84 |
|
85 | module.dependencyOf.push(parentDependencySetter);
|
86 | }
|
87 | if (module.instance) {
|
88 | return module.instance;
|
89 | }
|
90 |
|
91 | var moduleInstance = {};
|
92 | var moduleInitializer = module.factory(function _export(key, value) {
|
93 | moduleInstance[key] = value;
|
94 |
|
95 |
|
96 | module.dependencyOf.forEach(function(dependencySetter) {
|
97 | dependencySetter(moduleInstance);
|
98 | });
|
99 | });
|
100 | module.instance = moduleInstance;
|
101 |
|
102 | module.dependencies.forEach(function(dependencyName, index) {
|
103 | var resolvedName = resolveModuleName(moduleName, dependencyName);
|
104 | var setter = moduleInitializer.setters[index];
|
105 | var dependency = resolveModule(resolvedName, moduleName, setter);
|
106 | setter(dependency);
|
107 | });
|
108 |
|
109 | moduleInitializer.execute();
|
110 |
|
111 | return moduleInstance;
|
112 | }
|
113 |
|
114 | function resolveModuleName(currentModule, referencedModule) {
|
115 | var modulePath;
|
116 | if (referencedModule.substring(0, 2) === './') {
|
117 | if (currentModule.indexOf('/') > -1) {
|
118 | modulePath =
|
119 | currentModule.substring(0, currentModule.lastIndexOf('/')) +
|
120 | '/' +
|
121 | referencedModule.substring(2);
|
122 | } else {
|
123 |
|
124 | modulePath = referencedModule.substring(2);
|
125 | }
|
126 | } else if (referencedModule.substring(0, 3) === '../') {
|
127 | if (currentModule.indexOf('/') === -1) {
|
128 | throw new Error(
|
129 | 'The ' +
|
130 | currentModule +
|
131 | ' module imports from the ' +
|
132 | 'module ' +
|
133 | referencedModule +
|
134 | ' which may reside ' +
|
135 | 'outside of the application directory'
|
136 | );
|
137 | }
|
138 |
|
139 | modulePath = currentModule.substring(0, currentModule.lastIndexOf('/'));
|
140 | modulePath =
|
141 | modulePath.substring(0, modulePath.lastIndexOf('/')) +
|
142 | '/' +
|
143 | referencedModule.substring(3);
|
144 | } else {
|
145 | return referencedModule;
|
146 | }
|
147 |
|
148 | modulePath = modulePath.replace(/\/\/+/g, '/');
|
149 | while (modulePath.indexOf('/./') > -1) {
|
150 | modulePath = modulePath.replace(/\/[.][/]/g, '/');
|
151 | }
|
152 | while (modulePath.indexOf('../') > -1) {
|
153 | if (modulePath.substring(0, 3) === '../') {
|
154 | throw new Error(
|
155 | 'The ' +
|
156 | currentModule +
|
157 | ' module imports from the ' +
|
158 | 'module ' +
|
159 | referencedModule +
|
160 | ' which may reside ' +
|
161 | 'outside of the application directory'
|
162 | );
|
163 | }
|
164 | modulePath = modulePath.replace(/\/[^.][^/]*\/[.][.]\//g, '/');
|
165 | modulePath = modulePath.replace(/^[^.][^/]*\/[.][.]\//g, '');
|
166 | }
|
167 | modulePath = modulePath.replace(/^[.][/]/g, '');
|
168 |
|
169 | return modulePath;
|
170 | }
|
171 | })();
|