mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-29 21:25:35 +00:00
196 lines
5.5 KiB
JavaScript
196 lines
5.5 KiB
JavaScript
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
"use strict";
|
|
|
|
/**
|
|
* Require.jsm is a small module loader that loads JavaScript modules as
|
|
* defined by AMD/RequireJS and CommonJS, or specifically as used by:
|
|
* GCLI, Orion, Firebug, CCDump, NetPanel/HTTPMonitor and others.
|
|
*
|
|
* To date, no attempt has been made to ensure that Require.jsm closely follows
|
|
* either the AMD or CommonJS specs. It is hoped that a more formal JavaScript
|
|
* module standard will arrive before this is necessary. In the mean time it
|
|
* serves the projects it loads.
|
|
*/
|
|
|
|
this.EXPORTED_SYMBOLS = [ "define", "require" ];
|
|
|
|
const console = (function() {
|
|
const tempScope = {};
|
|
Components.utils.import("resource://gre/modules/devtools/Console.jsm", tempScope);
|
|
return tempScope.console;
|
|
})();
|
|
|
|
/**
|
|
* Define a module along with a payload.
|
|
* @param moduleName Name for the payload
|
|
* @param deps Ignored. For compatibility with CommonJS AMD Spec
|
|
* @param payload Function with (require, exports, module) params
|
|
*/
|
|
this.define = function define(moduleName, deps, payload) {
|
|
if (typeof moduleName != "string") {
|
|
throw new Error("Error: Module name is not a string");
|
|
}
|
|
|
|
if (arguments.length == 2) {
|
|
payload = deps;
|
|
}
|
|
else {
|
|
payload.deps = deps;
|
|
}
|
|
|
|
if (define.debugDependencies) {
|
|
console.log("define: " + moduleName + " -> " + payload.toString()
|
|
.slice(0, 40).replace(/\n/, '\\n').replace(/\r/, '\\r') + "...");
|
|
}
|
|
|
|
if (moduleName in define.modules) {
|
|
throw new Error("Error: Redefining module: " + moduleName);
|
|
}
|
|
|
|
// Mark the payload so we know we need to call it to get the real module
|
|
payload.__uncompiled = true;
|
|
define.modules[moduleName] = payload;
|
|
}
|
|
|
|
/**
|
|
* The global store of un-instantiated modules
|
|
*/
|
|
define.modules = {};
|
|
|
|
/**
|
|
* Should we console.log on module definition/instantiation/requirement?
|
|
*/
|
|
define.debugDependencies = false;
|
|
|
|
|
|
/**
|
|
* 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 = {};
|
|
|
|
if (define.debugDependencies) {
|
|
this.depth = "";
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 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 deps A name, or array of names for the payload
|
|
* @param callback Function to call when the dependencies are resolved
|
|
* @return The module required or undefined for array/callback method
|
|
*/
|
|
Domain.prototype.require = function(config, deps, callback) {
|
|
if (arguments.length <= 2) {
|
|
callback = deps;
|
|
deps = config;
|
|
config = undefined;
|
|
}
|
|
|
|
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);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Lookup module names and resolve them by calling the definition function if
|
|
* needed.
|
|
* @param moduleName A name for the payload to lookup
|
|
* @return The module specified by aModuleName or null if not found
|
|
*/
|
|
Domain.prototype.lookup = function(moduleName) {
|
|
if (moduleName in this.modules) {
|
|
var module = this.modules[moduleName];
|
|
if (define.debugDependencies) {
|
|
console.log(this.depth + " Using module: " + moduleName);
|
|
}
|
|
return module;
|
|
}
|
|
|
|
if (!(moduleName in define.modules)) {
|
|
throw new Error("Missing module: " + moduleName);
|
|
}
|
|
|
|
var module = define.modules[moduleName];
|
|
|
|
if (define.debugDependencies) {
|
|
console.log(this.depth + " Compiling module: " + moduleName);
|
|
}
|
|
|
|
if (module.__uncompiled) {
|
|
if (define.debugDependencies) {
|
|
this.depth += ".";
|
|
}
|
|
|
|
var exports = {};
|
|
try {
|
|
var params = module.deps.map((dep) => {
|
|
if (dep === "require") {
|
|
return this.require.bind(this);
|
|
}
|
|
if (dep === "exports") {
|
|
return exports;
|
|
}
|
|
if (dep === "module") {
|
|
return { id: moduleName, uri: "" };
|
|
}
|
|
return this.lookup(dep);
|
|
});
|
|
|
|
var reply = module.apply(null, params);
|
|
module = (reply !== undefined) ? reply : exports;
|
|
}
|
|
catch (ex) {
|
|
dump("Error using module '" + moduleName + "' - " + ex + "\n");
|
|
throw ex;
|
|
}
|
|
|
|
if (define.debugDependencies) {
|
|
this.depth = this.depth.slice(0, -1);
|
|
}
|
|
}
|
|
|
|
// cache the resulting module object for next time
|
|
this.modules[moduleName] = module;
|
|
|
|
return module;
|
|
};
|
|
|
|
/**
|
|
* Expose the Domain constructor and a global domain (on the define function
|
|
* to avoid exporting more than we need. This is a common pattern with
|
|
* require systems)
|
|
*/
|
|
define.Domain = Domain;
|
|
define.globalDomain = new Domain();
|
|
|
|
/**
|
|
* Expose a default require function which is the require of the global
|
|
* sandbox to make it easy to use.
|
|
*/
|
|
this.require = define.globalDomain.require.bind(define.globalDomain);
|