UNPKG

5.54 kBJavaScriptView Raw
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 // This is required for circular dependencies
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 // when exporting only functions, all of them are packed as object and sent as a key
94 if (typeof key === 'object') {
95 Object.keys(key).forEach(function(innerKey) {
96 moduleInstance[innerKey] = key[innerKey];
97 });
98 } else {
99 moduleInstance[key] = value;
100 }
101 // The exported values have been updated, notify the modules that
102 // depend on this one - this is required for circular dependencies.
103 module.dependencyOf.forEach(function(dependencySetter) {
104 dependencySetter(moduleInstance);
105 });
106 });
107 module.instance = moduleInstance; // allow lazy circular dependencies
108
109 module.dependencies.forEach(function(dependencyName, index) {
110 var resolvedName = resolveModuleName(moduleName, dependencyName);
111 var setter = moduleInitializer.setters[index];
112 var dependency = resolveModule(resolvedName, moduleName, setter);
113 setter(dependency);
114 });
115
116 moduleInitializer.execute();
117
118 return moduleInstance;
119 }
120
121 function resolveModuleName(currentModule, referencedModule) {
122 var modulePath;
123 if (referencedModule.substring(0, 2) === './') {
124 if (currentModule.indexOf('/') > -1) {
125 modulePath =
126 currentModule.substring(0, currentModule.lastIndexOf('/')) +
127 '/' +
128 referencedModule.substring(2);
129 } else {
130 // the current module is in the application's root
131 modulePath = referencedModule.substring(2);
132 }
133 } else if (referencedModule.substring(0, 3) === '../') {
134 if (currentModule.indexOf('/') === -1) {
135 throw new Error(
136 'The ' +
137 currentModule +
138 ' module imports from the ' +
139 'module ' +
140 referencedModule +
141 ' which may reside ' +
142 'outside of the application directory'
143 );
144 }
145
146 modulePath = currentModule.substring(0, currentModule.lastIndexOf('/'));
147 modulePath =
148 modulePath.substring(0, modulePath.lastIndexOf('/')) +
149 '/' +
150 referencedModule.substring(3);
151 } else {
152 return referencedModule;
153 }
154
155 modulePath = modulePath.replace(/\/\/+/g, '/');
156 while (modulePath.indexOf('/./') > -1) {
157 modulePath = modulePath.replace(/\/[.][/]/g, '/');
158 }
159 while (modulePath.indexOf('../') > -1) {
160 if (modulePath.substring(0, 3) === '../') {
161 throw new Error(
162 'The ' +
163 currentModule +
164 ' module imports from the ' +
165 'module ' +
166 referencedModule +
167 ' which may reside ' +
168 'outside of the application directory'
169 );
170 }
171 modulePath = modulePath.replace(/\/[^.][^/]*\/[.][.]\//g, '/');
172 modulePath = modulePath.replace(/^[^.][^/]*\/[.][.]\//g, '');
173 }
174 modulePath = modulePath.replace(/^[.][/]/g, '');
175
176 return modulePath;
177 }
178})();