UNPKG

10.5 kBJavaScriptView Raw
1var helpers = {};
2
3var nucleoAMD = function(options){
4
5 this.registry = {};
6 this.Mocked = options && options.isMocked ? null : nucleoAMD.create({isMocked:true});
7 this.seen = {};
8 this._config = {};
9 this.UID = helpers.get_uid({append: this.Mocked ? 'AMD':'MOCK'});
10 this.defaultConfig = {
11 relativePaths: true,
12 defaultFile: 'main',
13 paths: null
14 };
15
16 this.config({});
17
18};
19
20nucleoAMD.create = function(options){
21 return new nucleoAMD(options);
22};
23
24var extend = function(moduleName, definition){
25 nucleoAMD.prototype[moduleName] = definition;
26};
27
28var _extend = function(moduleName, definition){
29 helpers[moduleName] = definition;
30};
31extend("config", function(data) {
32
33 if(data === undefined){
34
35 return helpers.cloneObject(this._config);
36
37 } else if(helpers.isString(data)) {
38
39 return helpers.cloneObject(this._config[data]);
40
41 } else if(helpers.isObject(data)){
42
43 this._config = helpers.extend(this.defaultConfig, data);
44
45 }
46
47});
48extend("define", function(name, deps, callback) {
49
50 var value = {};
51
52 if (!callback) {
53
54 value.deps = [];
55 value.callback = deps;
56
57 } else {
58
59 value.deps = deps;
60 value.callback = callback;
61
62 }
63
64 if(this.registry[name]){
65 helpers.throwError('duplicatedModule ' + name);
66 }
67
68 this.registry[name] = value;
69
70});
71extend("has_entries", function(){
72
73 var hasModules = false;
74
75 for (var moduleName in this.registry) {
76
77 hasModules = true;
78 break;
79
80 }
81
82 return hasModules;
83
84});
85extend("list_entries", function(options){
86
87 var names = [];
88 var moduleName;
89 var regex = options && options.regex ? options.regex : '';
90 var shouldAddModule;
91
92 for (moduleName in this.registry) {
93
94 shouldAddModule = (regex && moduleName.match(regex)) || !regex;
95
96 if(shouldAddModule){
97
98 names.push(moduleName);
99
100 }
101
102 };
103
104 return names;
105
106});
107extend("markAsUnseen", function(moduleName){
108 this.seen[moduleName] = undefined;
109});
110extend("mock", function(name, deps, callback){
111
112 this.Mocked.define(name, deps, callback);
113
114});
115extend("require", function(name, submodule) {
116
117 var module = helpers.internalRequire.call(this, name, null);
118 var sub_module = module.isMock ? module.mocked : module[submodule || 'default'];
119 var result = helpers.cloneObject(sub_module);
120
121 return result;
122
123});
124extend("reset", function() {
125
126 this.registry = {};
127 this.Mocked = nucleoAMD.create({isMocked:true});
128 this.seen = {};
129 this._config = {};
130 this.UID = helpers.get_uid({append: this.Mocked ? 'AMD':'MOCK'});
131 this.defaultConfig = {
132 relativePaths: true,
133 defaultFile: 'main',
134 paths: null
135 };
136
137 this.config({});
138
139});
140_extend("cloneObject", function(source) {
141
142 var name, s, empty = {}, dest = {};
143 var isNotObject = !helpers.isObject(source);
144
145 if(isNotObject){
146 return source;
147 }
148
149 for(name in source){
150 /*jshint -W089 */
151 // the (!(name in empty) || empty[name] !== s) condition avoids copying properties in "source"
152 // inherited from Object.prototype. For example, if dest has a custom toString() method,
153 // don't overwrite it with the toString() method that source inherited from Object.prototype
154 s = source[name];
155 if(!(name in dest) || (dest[name] !== s && (!(name in empty) || empty[name] !== s))){
156 dest[name] = helpers.cloneObject ? helpers.cloneObject(s) : s;
157 }
158 }
159
160 return dest;
161
162});
163_extend("extend", function(obj1, obj2) {
164
165 var obj3 = {};
166 var isObject = helpers.isObject;
167 var cloneObject = helpers.cloneObject;
168 var extend = helpers.extend;
169
170 if (isObject(obj1)) {
171
172 for (var attrname in obj1) {
173
174 obj3[attrname] = cloneObject(obj1[attrname]);
175
176 }
177
178 }
179
180 if (isObject(obj2)) {
181
182 for (var attrname in obj2) {
183
184 if (isObject(obj1) && isObject(obj1[attrname]) && isObject(obj2[attrname])) {
185
186 obj3[attrname] = cloneObject(extend(obj1[attrname], obj2[attrname]));
187
188 } else {
189
190 obj3[attrname] = obj2[attrname];
191
192 }
193
194 }
195
196 }
197
198 return cloneObject(obj3);
199
200});
201_extend("getIgnoredPatterns", function() {
202
203 var prefixExitsOnConfig = this._config && this._config.paths && typeof this._config.paths.prefix === 'string';
204 var hasIgnore = prefixExitsOnConfig && this._config.paths.ignore;
205 var ignoreIsString = hasIgnore && typeof this._config.paths.ignore === 'string';
206 var ignorePatterns = [];
207
208 if (hasIgnore) {
209
210 if (ignoreIsString) {
211
212 ignorePatterns.push(this._config.paths.ignore);
213
214 } else if (helpers.isArray(this._config.paths.ignore)) {
215
216 ignorePatterns = this._config.paths.ignore;
217
218 }
219
220 }
221
222 return ignorePatterns;
223
224});
225_extend("getNameWithPrefix", function(path) {
226
227 var prefixExitsOnConfig = this._config && this._config.paths && typeof this._config.paths.prefix === 'string';
228 var prefix = prefixExitsOnConfig ? this._config.paths.prefix : '';
229 var ignorePatterns = helpers.getIgnoredPatterns.call(this);
230 var shouldIgnore = helpers.shouldIgnorePrefix(path, ignorePatterns);
231 var shouldAddPrefix = prefixExitsOnConfig && !shouldIgnore;
232
233 prefix = prefix.length && prefix.slice(-1) !== '/' ? prefix + '/' : prefix;
234
235 var name = shouldAddPrefix ? prefix + path : path;
236
237 return name;
238
239});
240_extend("get_dependencies_values", function(exports, name) {
241
242 var mod = this.registry[name];
243 var deps = mod.deps;
244 var callback = mod.callback;
245 var reified = [];
246 var length = deps.length;
247 var dep_name, dep;
248
249 for (var i = 0; i < length; i++) {
250
251 if (deps[i] === 'exports') {
252
253 reified.push(exports);
254
255 } else {
256
257 dep_name = helpers.resolve.call(this, deps[i], name);
258 dep = helpers.internalRequire.call(this, dep_name, name);
259
260 reified.push(dep);
261
262 }
263
264 }
265
266 return reified;
267
268});
269_extend("get_mocked_module", function(name) {
270
271 var hasMocks = this.Mocked && this.Mocked.has_entries();
272 var mocked_module;
273
274 if (hasMocks) {
275
276 try {
277
278 mocked_module = this.Mocked.require(name);
279
280 } catch (err) {}
281
282 }
283
284 if (mocked_module !== undefined) {
285
286 // TODO make tests for non-default exported in the module. don't assume that module is 'default'
287 var result = {
288 'default': mocked_module
289 };
290
291 return result;
292
293 }
294
295 return undefined;
296
297});
298_extend("get_uid", function(options){
299
300 // for the moment, it's purpose is not to be a real UID generator
301 var now = new Date();
302 var appended = options && options.append ? options.append : '';
303 var uid = helpers.random() + '.' +
304 now.getMinutes() + '.' +
305 now.getSeconds() + '.' +
306 now.getMilliseconds() + '/' +
307 appended;
308
309 return uid;
310
311});
312_extend("handle_default_filename", function(name, referrerName){
313
314 if (!this.registry[name]) {
315
316 var hasEndingSlash = name.slice(-1) === '/';
317 var slash = hasEndingSlash ? '' : '/';
318 var indexFileName = name + slash + this._config.defaultFile;
319
320 if (this.registry[indexFileName]) {
321
322 name = indexFileName;
323
324 } else if (referrerName) {
325
326 helpers.throwError('Could not find module ' + name + ' required by: ' + referrerName);
327
328 } else {
329
330 helpers.throwError('Could not find module ' + name);
331
332 }
333
334 }
335
336 return name;
337
338});
339_extend("internalRequire", function(name, referrerName) {
340
341 name = helpers.getNameWithPrefix.call(this, name);
342
343 var mocked_module = helpers.get_mocked_module.call(this, name);
344
345 if(mocked_module){
346
347 return mocked_module;
348
349 }
350
351 var exports = this.seen[name];
352 var oldName = name;
353
354 if (exports !== undefined) {
355 return exports;
356 }
357
358 name = helpers.handle_default_filename.call(this, name, referrerName);
359
360 exports = this.seen[name] = this.seen[oldName] = {};
361
362 var reified = helpers.get_dependencies_values.call(this, exports, name);
363
364 // test "instances of objects: should export method" exposes global variable
365 // "this" sent as context in callback.apply is the cause of the pollution of globalnamespace
366 // TODO fix the pollution or find a way to restrict that kind of methods by throwing errors
367 this.registry[name].callback.apply(this, reified);
368
369 return exports;
370
371});
372_extend("isArray", function(myArray) {
373 return Object.prototype.toString.call(myArray).indexOf("Array") > -1;
374});
375_extend("isFunction", function(func){
376 return Object.prototype.toString.call(func) === '[object Function]';
377});
378_extend("isObject", function(obj){
379 return Object.prototype.toString.call(obj) === '[object Object]';
380});
381_extend("isString", function(string){
382 return Object.prototype.toString.call(string) === '[object String]';
383});
384_extend("random", function() {
385
386 var random = Math.round(Math.random() * 100, 2);
387
388 return random;
389
390});
391_extend("reset_amd", function() {
392
393 AMD = nucleoAMD.create();
394
395});
396_extend("resolve", function(child, name) {
397
398 if (child.charAt(0) === '.') {
399
400 if (!this._config.relativePaths) {
401
402 helpers.throwError('Relative paths are not allowed: ' + child + ' required by ' + name);
403
404 }
405
406 } else {
407
408 return child;
409
410 }
411
412 var parts = child.split('/');
413 var parentBase = name.split('/').slice(0, -1);
414
415 for (var i = 0, l = parts.length; i < l; i++) {
416
417 var part = parts[i];
418
419 if (part === '..') {
420
421 parentBase.pop();
422
423 } else if (part === '.') {
424
425 continue;
426
427 } else {
428
429 parentBase.push(part);
430
431 }
432
433 }
434
435 return parentBase.join('/');
436
437});
438_extend("shouldIgnorePrefix", function(path, ignorePatterns) {
439
440 var shouldIgnore = false;
441
442 for (var i = 0; i < ignorePatterns.length; i++) {
443
444 var containsInvalidChars = /[^\w\d/_-]/.test(ignorePatterns[i]);
445
446 if (containsInvalidChars) {
447
448 helpers.throwError('Ignored prefixes contains invalid chars');
449
450 }
451
452 var ignorePattern = new RegExp('^' + ignorePatterns[i] + '(\/)?(\w+)*');
453
454 if (shouldIgnore === false && ignorePattern.test(path)) {
455
456 shouldIgnore = true;
457
458 }
459
460 };
461
462 return shouldIgnore;
463
464});
465_extend("throwError", function(msg) {
466
467 throw new Error(msg);
468
469});
470var AMD = nucleoAMD.create();
471 module.exports = AMD;
\No newline at end of file