153 lines
4.2 KiB
JavaScript
153 lines
4.2 KiB
JavaScript
|
/* -*- 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);
|