forked from mozilla/gecko-dev
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathRequire.jsm
195 lines (167 loc) · 5.52 KB
/
Require.jsm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
/* 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(function(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);
}.bind(this));
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);