UNPKG

5.27 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 moduleInstance[key] = value;
94 // The exported values have been updated, notify the modules that
95 // depend on this one - this is required for circular dependencies.
96 module.dependencyOf.forEach(function(dependencySetter) {
97 dependencySetter(moduleInstance);
98 });
99 });
100 module.instance = moduleInstance; // allow lazy circular dependencies
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 // the current module is in the application's root
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})();