/* -*- 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);