builtin-modules.js 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. /* This Source Code Form is subject to the terms of the Mozilla Public
  2. * License, v. 2.0. If a copy of the MPL was not distributed with this
  3. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  4. "use strict";
  5. /**
  6. * This module defines custom globals injected in all our modules and also
  7. * pseudo modules that aren't separate files but just dynamically set values.
  8. *
  9. * As it does so, the module itself doesn't have access to these globals,
  10. * nor the pseudo modules. Be careful to avoid loading any other js module as
  11. * they would also miss them.
  12. */
  13. const { Cu, CC, Cc, Ci } = require("chrome");
  14. const { Loader } = Cu.import("resource://gre/modules/commonjs/toolkit/loader.js", {});
  15. const promise = Cu.import("resource://gre/modules/Promise.jsm", {}).Promise;
  16. const jsmScope = Cu.import("resource://gre/modules/Services.jsm", {});
  17. const { Services } = jsmScope;
  18. // Steal various globals only available in JSM scope (and not Sandbox one)
  19. const { PromiseDebugging, ChromeUtils, ThreadSafeChromeUtils, HeapSnapshot,
  20. atob, btoa, Iterator } = jsmScope;
  21. const { URL } = Cu.Sandbox(CC("@mozilla.org/systemprincipal;1", "nsIPrincipal")(),
  22. {wantGlobalProperties: ["URL"]});
  23. /**
  24. * Defines a getter on a specified object that will be created upon first use.
  25. *
  26. * @param aObject
  27. * The object to define the lazy getter on.
  28. * @param aName
  29. * The name of the getter to define on aObject.
  30. * @param aLambda
  31. * A function that returns what the getter should return. This will
  32. * only ever be called once.
  33. */
  34. function defineLazyGetter(aObject, aName, aLambda)
  35. {
  36. Object.defineProperty(aObject, aName, {
  37. get: function () {
  38. // Redefine this accessor property as a data property.
  39. // Delete it first, to rule out "too much recursion" in case aObject is
  40. // a proxy whose defineProperty handler might unwittingly trigger this
  41. // getter again.
  42. delete aObject[aName];
  43. let value = aLambda.apply(aObject);
  44. Object.defineProperty(aObject, aName, {
  45. value,
  46. writable: true,
  47. configurable: true,
  48. enumerable: true
  49. });
  50. return value;
  51. },
  52. configurable: true,
  53. enumerable: true
  54. });
  55. }
  56. /**
  57. * Defines a getter on a specified object for a service. The service will not
  58. * be obtained until first use.
  59. *
  60. * @param aObject
  61. * The object to define the lazy getter on.
  62. * @param aName
  63. * The name of the getter to define on aObject for the service.
  64. * @param aContract
  65. * The contract used to obtain the service.
  66. * @param aInterfaceName
  67. * The name of the interface to query the service to.
  68. */
  69. function defineLazyServiceGetter(aObject, aName, aContract, aInterfaceName)
  70. {
  71. defineLazyGetter(aObject, aName, function XPCU_serviceLambda() {
  72. return Cc[aContract].getService(Ci[aInterfaceName]);
  73. });
  74. }
  75. /**
  76. * Defines a getter on a specified object for a module. The module will not
  77. * be imported until first use. The getter allows to execute setup and
  78. * teardown code (e.g. to register/unregister to services) and accepts
  79. * a proxy object which acts on behalf of the module until it is imported.
  80. *
  81. * @param aObject
  82. * The object to define the lazy getter on.
  83. * @param aName
  84. * The name of the getter to define on aObject for the module.
  85. * @param aResource
  86. * The URL used to obtain the module.
  87. * @param aSymbol
  88. * The name of the symbol exported by the module.
  89. * This parameter is optional and defaults to aName.
  90. * @param aPreLambda
  91. * A function that is executed when the proxy is set up.
  92. * This will only ever be called once.
  93. * @param aPostLambda
  94. * A function that is executed when the module has been imported to
  95. * run optional teardown procedures on the proxy object.
  96. * This will only ever be called once.
  97. * @param aProxy
  98. * An object which acts on behalf of the module to be imported until
  99. * the module has been imported.
  100. */
  101. function defineLazyModuleGetter(aObject, aName, aResource, aSymbol,
  102. aPreLambda, aPostLambda, aProxy)
  103. {
  104. let proxy = aProxy || {};
  105. if (typeof (aPreLambda) === "function") {
  106. aPreLambda.apply(proxy);
  107. }
  108. defineLazyGetter(aObject, aName, function XPCU_moduleLambda() {
  109. var temp = {};
  110. try {
  111. Cu.import(aResource, temp);
  112. if (typeof (aPostLambda) === "function") {
  113. aPostLambda.apply(proxy);
  114. }
  115. } catch (ex) {
  116. Cu.reportError("Failed to load module " + aResource + ".");
  117. throw ex;
  118. }
  119. return temp[aSymbol || aName];
  120. });
  121. }
  122. /**
  123. * Define a getter property on the given object that requires the given
  124. * module. This enables delaying importing modules until the module is
  125. * actually used.
  126. *
  127. * @param Object obj
  128. * The object to define the property on.
  129. * @param String property
  130. * The property name.
  131. * @param String module
  132. * The module path.
  133. * @param Boolean destructure
  134. * Pass true if the property name is a member of the module's exports.
  135. */
  136. function lazyRequireGetter(obj, property, module, destructure) {
  137. Object.defineProperty(obj, property, {
  138. get: () => {
  139. // Redefine this accessor property as a data property.
  140. // Delete it first, to rule out "too much recursion" in case obj is
  141. // a proxy whose defineProperty handler might unwittingly trigger this
  142. // getter again.
  143. delete obj[property];
  144. let value = destructure
  145. ? require(module)[property]
  146. : require(module || property);
  147. Object.defineProperty(obj, property, {
  148. value,
  149. writable: true,
  150. configurable: true,
  151. enumerable: true
  152. });
  153. return value;
  154. },
  155. configurable: true,
  156. enumerable: true
  157. });
  158. }
  159. // List of pseudo modules exposed to all devtools modules.
  160. exports.modules = {
  161. "Services": Object.create(Services),
  162. "toolkit/loader": Loader,
  163. promise,
  164. PromiseDebugging,
  165. ChromeUtils,
  166. ThreadSafeChromeUtils,
  167. HeapSnapshot,
  168. };
  169. defineLazyGetter(exports.modules, "Debugger", () => {
  170. // addDebuggerToGlobal only allows adding the Debugger object to a global. The
  171. // this object is not guaranteed to be a global (in particular on B2G, due to
  172. // compartment sharing), so add the Debugger object to a sandbox instead.
  173. let sandbox = Cu.Sandbox(CC("@mozilla.org/systemprincipal;1", "nsIPrincipal")());
  174. Cu.evalInSandbox(
  175. "Components.utils.import('resource://gre/modules/jsdebugger.jsm');" +
  176. "addDebuggerToGlobal(this);",
  177. sandbox
  178. );
  179. return sandbox.Debugger;
  180. });
  181. defineLazyGetter(exports.modules, "Timer", () => {
  182. let {setTimeout, clearTimeout} = Cu.import("resource://gre/modules/Timer.jsm", {});
  183. // Do not return Cu.import result, as SDK loader would freeze Timer.jsm globals...
  184. return {
  185. setTimeout,
  186. clearTimeout
  187. };
  188. });
  189. defineLazyGetter(exports.modules, "xpcInspector", () => {
  190. return Cc["@mozilla.org/jsinspector;1"].getService(Ci.nsIJSInspector);
  191. });
  192. defineLazyGetter(exports.modules, "FileReader", () => {
  193. let sandbox
  194. = Cu.Sandbox(CC("@mozilla.org/systemprincipal;1", "nsIPrincipal")(),
  195. {wantGlobalProperties: ["FileReader"]});
  196. return sandbox.FileReader;
  197. });
  198. // List of all custom globals exposed to devtools modules.
  199. // Changes here should be mirrored to devtools/.eslintrc.
  200. const globals = exports.globals = {
  201. isWorker: false,
  202. reportError: Cu.reportError,
  203. atob: atob,
  204. btoa: btoa,
  205. URL,
  206. loader: {
  207. lazyGetter: defineLazyGetter,
  208. lazyImporter: defineLazyModuleGetter,
  209. lazyServiceGetter: defineLazyServiceGetter,
  210. lazyRequireGetter: lazyRequireGetter,
  211. id: null // Defined by Loader.jsm
  212. },
  213. // Let new XMLHttpRequest do the right thing.
  214. XMLHttpRequest: function () {
  215. return Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
  216. .createInstance(Ci.nsIXMLHttpRequest);
  217. },
  218. Node: Ci.nsIDOMNode,
  219. Element: Ci.nsIDOMElement,
  220. DocumentFragment: Ci.nsIDOMDocumentFragment,
  221. // Make sure `define` function exists. This allows defining some modules
  222. // in AMD format while retaining CommonJS compatibility through this hook.
  223. // JSON Viewer needs modules in AMD format, as it currently uses RequireJS
  224. // from a content document and can't access our usual loaders. So, any
  225. // modules shared with the JSON Viewer should include a define wrapper:
  226. //
  227. // // Make this available to both AMD and CJS environments
  228. // define(function(require, exports, module) {
  229. // ... code ...
  230. // });
  231. //
  232. // Bug 1248830 will work out a better plan here for our content module
  233. // loading needs, especially as we head towards devtools.html.
  234. define(factory) {
  235. factory(this.require, this.exports, this.module);
  236. },
  237. };
  238. // Lazily define a few things so that the corresponding jsms are only loaded
  239. // when used.
  240. defineLazyGetter(globals, "console", () => {
  241. return Cu.import("resource://gre/modules/Console.jsm", {}).console;
  242. });
  243. defineLazyGetter(globals, "clearTimeout", () => {
  244. return Cu.import("resource://gre/modules/Timer.jsm", {}).clearTimeout;
  245. });
  246. defineLazyGetter(globals, "setTimeout", () => {
  247. return Cu.import("resource://gre/modules/Timer.jsm", {}).setTimeout;
  248. });
  249. defineLazyGetter(globals, "clearInterval", () => {
  250. return Cu.import("resource://gre/modules/Timer.jsm", {}).clearInterval;
  251. });
  252. defineLazyGetter(globals, "setInterval", () => {
  253. return Cu.import("resource://gre/modules/Timer.jsm", {}).setInterval;
  254. });
  255. defineLazyGetter(globals, "CSSRule", () => Ci.nsIDOMCSSRule);
  256. defineLazyGetter(globals, "DOMParser", () => {
  257. return CC("@mozilla.org/xmlextras/domparser;1", "nsIDOMParser");
  258. });
  259. defineLazyGetter(globals, "CSS", () => {
  260. let sandbox
  261. = Cu.Sandbox(CC("@mozilla.org/systemprincipal;1", "nsIPrincipal")(),
  262. {wantGlobalProperties: ["CSS"]});
  263. return sandbox.CSS;
  264. });
  265. defineLazyGetter(globals, "WebSocket", () => {
  266. return Services.appShell.hiddenDOMWindow.WebSocket;
  267. });
  268. lazyRequireGetter(globals, "indexedDB", "sdk/indexed-db", true);