1 jls.loader.provide('jls.lang.ModuleLoader'); 2 3 /* 4 * for /f %d in ('dir /b ..\res\cjsunit') do jls -Djls.enableCommonJSModule -sp ..\res\cjsunit\%d program.js 5 */ 6 7 /** 8 * @class A module loader is an object that is responsible for loading Common JS modules. 9 * The ModuleLoader class implements the CommonJS Modules 1.0 specification. 10 */ 11 jls.lang.ModuleLoader = jls.lang.Class.create(/** @lends jls.lang.ModuleLoader.prototype */ 12 { 13 // private 14 initialize : function() { 15 this._cache = {}; 16 this._path = '.'; 17 this._commonJSEnabled = ('jls.enableCommonJSModule' in _native.core.properties); 18 }, 19 /** 20 * Returns the exported API of the foreign module. 21 * 22 * @param {String} path The path of the module to load. 23 */ 24 require : function(path) { 25 // Find out the absolute path that is used as unique id 26 var pathItems = path.split('/'); 27 if ((this._path != '.') && ((pathItems[0] == '.') || (pathItems[0] == '..'))) { 28 pathItems = this._path.split('/').concat(pathItems); 29 } 30 for (var i = 0; i < pathItems.length; i++) { 31 if (pathItems[i] == '.') { 32 pathItems.splice(i, 1); 33 i--; 34 continue; 35 } 36 if (pathItems[i] == '..') { 37 if (i == 0) { 38 throw new jls.lang.Exception('Invalid path'); 39 } 40 pathItems.splice(i - 1, 1); 41 i -= 2; 42 continue; 43 } 44 } 45 var absPath = pathItems.join('/'); 46 if (absPath in this._cache) { 47 return this._cache[absPath]; 48 } 49 // We have to create the object before evaluating the module in case of cyclic dependency. 50 var exports = {}; 51 // We have to keep our path for relative requires 52 var previousPath = this._path; 53 try { 54 if (pathItems.length > 1) { 55 pathItems.splice(pathItems.length - 1, 1); 56 this._path = pathItems.join('/'); 57 } else { 58 this._path = '.'; 59 } 60 // TODO Remove 61 //jls.logger.warn('require("' + path + '") previousPath: ' + previousPath + ', path: ' + this._path + ', absPath: ' + absPath); 62 this._cache[absPath] = exports; 63 var rsrcStr = _native.core.getResourceAsString(absPath + '.js'); 64 var evalSrc = 'function (exports) { '; 65 if (! this._commonJSEnabled) { 66 // Add require in the scope 67 evalSrc += 'var require = jls.lang.ModuleLoader.getInstance().require.bind(jls.lang.ModuleLoader.getInstance()); '; 68 } 69 evalSrc += rsrcStr; 70 evalSrc += ' }'; 71 var fn = eval(evalSrc); 72 fn(exports); 73 } 74 catch (e) { 75 // remove entry as something goes wrong 76 delete this._cache[absPath]; 77 throw e; // rethrow 78 } 79 finally { 80 // Restore previous path 81 this._path = previousPath; 82 } 83 return exports; 84 } 85 }); 86 87 Object.extend(jls.lang.ModuleLoader, /** @lends jls.lang.ModuleLoader */ 88 { 89 _instance : null, 90 /** 91 * Gets the current module loader instance. 92 * 93 * @returns {jls.lang.ModuleLoader} The module loader instance. 94 */ 95 getInstance : function() { 96 if (jls.lang.ModuleLoader._instance == null) { 97 jls.lang.ModuleLoader._instance = new jls.lang.ModuleLoader(); 98 } 99 return jls.lang.ModuleLoader._instance; 100 } 101 }); 102 103