| /* -*- Mode: js; js-indent-level: 2; -*- */ |
| /* |
| * Copyright 2011 Mozilla Foundation and contributors |
| * Licensed under the New BSD license. See LICENSE or: |
| * http://opensource.org/licenses/BSD-3-Clause |
| */ |
| |
| /** |
| * Define a module along with a payload. |
| * @param {string} moduleName Name for the payload |
| * @param {ignored} deps Ignored. For compatibility with CommonJS AMD Spec |
| * @param {function} payload Function with (require, exports, module) params |
| */ |
| function define(moduleName, deps, payload) { |
| if (typeof moduleName != "string") { |
| throw new TypeError('Expected string, got: ' + moduleName); |
| } |
| |
| if (arguments.length == 2) { |
| payload = deps; |
| } |
| |
| if (moduleName in define.modules) { |
| throw new Error("Module already defined: " + moduleName); |
| } |
| define.modules[moduleName] = payload; |
| }; |
| |
| /** |
| * The global store of un-instantiated modules |
| */ |
| define.modules = {}; |
| |
| |
| /** |
| * We invoke require() in the context of a Domain so we can have multiple |
| * sets of modules running separate from each other. |
| * This contrasts with JSMs which are singletons, Domains allows us to |
| * optionally load a CommonJS module twice with separate data each time. |
| * Perhaps you want 2 command lines with a different set of commands in each, |
| * for example. |
| */ |
| function Domain() { |
| this.modules = {}; |
| this._currentModule = null; |
| } |
| |
| (function () { |
| |
| /** |
| * Lookup module names and resolve them by calling the definition function if |
| * needed. |
| * There are 2 ways to call this, either with an array of dependencies and a |
| * callback to call when the dependencies are found (which can happen |
| * asynchronously in an in-page context) or with a single string an no callback |
| * where the dependency is resolved synchronously and returned. |
| * The API is designed to be compatible with the CommonJS AMD spec and |
| * RequireJS. |
| * @param {string[]|string} deps A name, or names for the payload |
| * @param {function|undefined} callback Function to call when the dependencies |
| * are resolved |
| * @return {undefined|object} The module required or undefined for |
| * array/callback method |
| */ |
| Domain.prototype.require = function(deps, callback) { |
| if (Array.isArray(deps)) { |
| var params = deps.map(function(dep) { |
| return this.lookup(dep); |
| }, this); |
| if (callback) { |
| callback.apply(null, params); |
| } |
| return undefined; |
| } |
| else { |
| return this.lookup(deps); |
| } |
| }; |
| |
| function normalize(path) { |
| var bits = path.split('/'); |
| var i = 1; |
| while (i < bits.length) { |
| if (bits[i] === '..') { |
| bits.splice(i-1, 1); |
| } else if (bits[i] === '.') { |
| bits.splice(i, 1); |
| } else { |
| i++; |
| } |
| } |
| return bits.join('/'); |
| } |
| |
| function join(a, b) { |
| a = a.trim(); |
| b = b.trim(); |
| if (/^\//.test(b)) { |
| return b; |
| } else { |
| return a.replace(/\/*$/, '/') + b; |
| } |
| } |
| |
| function dirname(path) { |
| var bits = path.split('/'); |
| bits.pop(); |
| return bits.join('/'); |
| } |
| |
| /** |
| * Lookup module names and resolve them by calling the definition function if |
| * needed. |
| * @param {string} moduleName A name for the payload to lookup |
| * @return {object} The module specified by aModuleName or null if not found. |
| */ |
| Domain.prototype.lookup = function(moduleName) { |
| if (/^\./.test(moduleName)) { |
| moduleName = normalize(join(dirname(this._currentModule), moduleName)); |
| } |
| |
| if (moduleName in this.modules) { |
| var module = this.modules[moduleName]; |
| return module; |
| } |
| |
| if (!(moduleName in define.modules)) { |
| throw new Error("Module not defined: " + moduleName); |
| } |
| |
| var module = define.modules[moduleName]; |
| |
| if (typeof module == "function") { |
| var exports = {}; |
| var previousModule = this._currentModule; |
| this._currentModule = moduleName; |
| module(this.require.bind(this), exports, { id: moduleName, uri: "" }); |
| this._currentModule = previousModule; |
| module = exports; |
| } |
| |
| // cache the resulting module object for next time |
| this.modules[moduleName] = module; |
| |
| return module; |
| }; |
| |
| }()); |
| |
| define.Domain = Domain; |
| define.globalDomain = new Domain(); |
| var require = define.globalDomain.require.bind(define.globalDomain); |