summaryrefslogtreecommitdiffstats
path: root/devtools/shared/builtin-modules.js
diff options
context:
space:
mode:
Diffstat (limited to 'devtools/shared/builtin-modules.js')
-rw-r--r--devtools/shared/builtin-modules.js288
1 files changed, 288 insertions, 0 deletions
diff --git a/devtools/shared/builtin-modules.js b/devtools/shared/builtin-modules.js
new file mode 100644
index 000000000..64fae6da7
--- /dev/null
+++ b/devtools/shared/builtin-modules.js
@@ -0,0 +1,288 @@
+/* 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";
+
+/**
+ * This module defines custom globals injected in all our modules and also
+ * pseudo modules that aren't separate files but just dynamically set values.
+ *
+ * As it does so, the module itself doesn't have access to these globals,
+ * nor the pseudo modules. Be careful to avoid loading any other js module as
+ * they would also miss them.
+ */
+
+const { Cu, CC, Cc, Ci } = require("chrome");
+const { Loader } = Cu.import("resource://gre/modules/commonjs/toolkit/loader.js", {});
+const promise = Cu.import("resource://gre/modules/Promise.jsm", {}).Promise;
+const jsmScope = Cu.import("resource://gre/modules/Services.jsm", {});
+const { Services } = jsmScope;
+// Steal various globals only available in JSM scope (and not Sandbox one)
+const { PromiseDebugging, ChromeUtils, ThreadSafeChromeUtils, HeapSnapshot,
+ atob, btoa, Iterator } = jsmScope;
+const { URL } = Cu.Sandbox(CC("@mozilla.org/systemprincipal;1", "nsIPrincipal")(),
+ {wantGlobalProperties: ["URL"]});
+
+/**
+ * Defines a getter on a specified object that will be created upon first use.
+ *
+ * @param aObject
+ * The object to define the lazy getter on.
+ * @param aName
+ * The name of the getter to define on aObject.
+ * @param aLambda
+ * A function that returns what the getter should return. This will
+ * only ever be called once.
+ */
+function defineLazyGetter(aObject, aName, aLambda)
+{
+ Object.defineProperty(aObject, aName, {
+ get: function () {
+ // Redefine this accessor property as a data property.
+ // Delete it first, to rule out "too much recursion" in case aObject is
+ // a proxy whose defineProperty handler might unwittingly trigger this
+ // getter again.
+ delete aObject[aName];
+ let value = aLambda.apply(aObject);
+ Object.defineProperty(aObject, aName, {
+ value,
+ writable: true,
+ configurable: true,
+ enumerable: true
+ });
+ return value;
+ },
+ configurable: true,
+ enumerable: true
+ });
+}
+
+/**
+ * Defines a getter on a specified object for a service. The service will not
+ * be obtained until first use.
+ *
+ * @param aObject
+ * The object to define the lazy getter on.
+ * @param aName
+ * The name of the getter to define on aObject for the service.
+ * @param aContract
+ * The contract used to obtain the service.
+ * @param aInterfaceName
+ * The name of the interface to query the service to.
+ */
+function defineLazyServiceGetter(aObject, aName, aContract, aInterfaceName)
+{
+ defineLazyGetter(aObject, aName, function XPCU_serviceLambda() {
+ return Cc[aContract].getService(Ci[aInterfaceName]);
+ });
+}
+
+/**
+ * Defines a getter on a specified object for a module. The module will not
+ * be imported until first use. The getter allows to execute setup and
+ * teardown code (e.g. to register/unregister to services) and accepts
+ * a proxy object which acts on behalf of the module until it is imported.
+ *
+ * @param aObject
+ * The object to define the lazy getter on.
+ * @param aName
+ * The name of the getter to define on aObject for the module.
+ * @param aResource
+ * The URL used to obtain the module.
+ * @param aSymbol
+ * The name of the symbol exported by the module.
+ * This parameter is optional and defaults to aName.
+ * @param aPreLambda
+ * A function that is executed when the proxy is set up.
+ * This will only ever be called once.
+ * @param aPostLambda
+ * A function that is executed when the module has been imported to
+ * run optional teardown procedures on the proxy object.
+ * This will only ever be called once.
+ * @param aProxy
+ * An object which acts on behalf of the module to be imported until
+ * the module has been imported.
+ */
+function defineLazyModuleGetter(aObject, aName, aResource, aSymbol,
+ aPreLambda, aPostLambda, aProxy)
+{
+ let proxy = aProxy || {};
+
+ if (typeof (aPreLambda) === "function") {
+ aPreLambda.apply(proxy);
+ }
+
+ defineLazyGetter(aObject, aName, function XPCU_moduleLambda() {
+ var temp = {};
+ try {
+ Cu.import(aResource, temp);
+
+ if (typeof (aPostLambda) === "function") {
+ aPostLambda.apply(proxy);
+ }
+ } catch (ex) {
+ Cu.reportError("Failed to load module " + aResource + ".");
+ throw ex;
+ }
+ return temp[aSymbol || aName];
+ });
+}
+
+/**
+ * Define a getter property on the given object that requires the given
+ * module. This enables delaying importing modules until the module is
+ * actually used.
+ *
+ * @param Object obj
+ * The object to define the property on.
+ * @param String property
+ * The property name.
+ * @param String module
+ * The module path.
+ * @param Boolean destructure
+ * Pass true if the property name is a member of the module's exports.
+ */
+function lazyRequireGetter(obj, property, module, destructure) {
+ Object.defineProperty(obj, property, {
+ get: () => {
+ // Redefine this accessor property as a data property.
+ // Delete it first, to rule out "too much recursion" in case obj is
+ // a proxy whose defineProperty handler might unwittingly trigger this
+ // getter again.
+ delete obj[property];
+ let value = destructure
+ ? require(module)[property]
+ : require(module || property);
+ Object.defineProperty(obj, property, {
+ value,
+ writable: true,
+ configurable: true,
+ enumerable: true
+ });
+ return value;
+ },
+ configurable: true,
+ enumerable: true
+ });
+}
+
+// List of pseudo modules exposed to all devtools modules.
+exports.modules = {
+ "Services": Object.create(Services),
+ "toolkit/loader": Loader,
+ promise,
+ PromiseDebugging,
+ ChromeUtils,
+ ThreadSafeChromeUtils,
+ HeapSnapshot,
+};
+
+defineLazyGetter(exports.modules, "Debugger", () => {
+ // addDebuggerToGlobal only allows adding the Debugger object to a global. The
+ // this object is not guaranteed to be a global (in particular on B2G, due to
+ // compartment sharing), so add the Debugger object to a sandbox instead.
+ let sandbox = Cu.Sandbox(CC("@mozilla.org/systemprincipal;1", "nsIPrincipal")());
+ Cu.evalInSandbox(
+ "Components.utils.import('resource://gre/modules/jsdebugger.jsm');" +
+ "addDebuggerToGlobal(this);",
+ sandbox
+ );
+ return sandbox.Debugger;
+});
+
+defineLazyGetter(exports.modules, "Timer", () => {
+ let {setTimeout, clearTimeout} = Cu.import("resource://gre/modules/Timer.jsm", {});
+ // Do not return Cu.import result, as SDK loader would freeze Timer.jsm globals...
+ return {
+ setTimeout,
+ clearTimeout
+ };
+});
+
+defineLazyGetter(exports.modules, "xpcInspector", () => {
+ return Cc["@mozilla.org/jsinspector;1"].getService(Ci.nsIJSInspector);
+});
+
+defineLazyGetter(exports.modules, "FileReader", () => {
+ let sandbox
+ = Cu.Sandbox(CC("@mozilla.org/systemprincipal;1", "nsIPrincipal")(),
+ {wantGlobalProperties: ["FileReader"]});
+ return sandbox.FileReader;
+});
+
+// List of all custom globals exposed to devtools modules.
+// Changes here should be mirrored to devtools/.eslintrc.
+const globals = exports.globals = {
+ isWorker: false,
+ reportError: Cu.reportError,
+ atob: atob,
+ btoa: btoa,
+ URL,
+ loader: {
+ lazyGetter: defineLazyGetter,
+ lazyImporter: defineLazyModuleGetter,
+ lazyServiceGetter: defineLazyServiceGetter,
+ lazyRequireGetter: lazyRequireGetter,
+ id: null // Defined by Loader.jsm
+ },
+
+ // Let new XMLHttpRequest do the right thing.
+ XMLHttpRequest: function () {
+ return Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
+ .createInstance(Ci.nsIXMLHttpRequest);
+ },
+
+ Node: Ci.nsIDOMNode,
+ Element: Ci.nsIDOMElement,
+ DocumentFragment: Ci.nsIDOMDocumentFragment,
+
+ // Make sure `define` function exists. This allows defining some modules
+ // in AMD format while retaining CommonJS compatibility through this hook.
+ // JSON Viewer needs modules in AMD format, as it currently uses RequireJS
+ // from a content document and can't access our usual loaders. So, any
+ // modules shared with the JSON Viewer should include a define wrapper:
+ //
+ // // Make this available to both AMD and CJS environments
+ // define(function(require, exports, module) {
+ // ... code ...
+ // });
+ //
+ // Bug 1248830 will work out a better plan here for our content module
+ // loading needs, especially as we head towards devtools.html.
+ define(factory) {
+ factory(this.require, this.exports, this.module);
+ },
+};
+
+// Lazily define a few things so that the corresponding jsms are only loaded
+// when used.
+defineLazyGetter(globals, "console", () => {
+ return Cu.import("resource://gre/modules/Console.jsm", {}).console;
+});
+defineLazyGetter(globals, "clearTimeout", () => {
+ return Cu.import("resource://gre/modules/Timer.jsm", {}).clearTimeout;
+});
+defineLazyGetter(globals, "setTimeout", () => {
+ return Cu.import("resource://gre/modules/Timer.jsm", {}).setTimeout;
+});
+defineLazyGetter(globals, "clearInterval", () => {
+ return Cu.import("resource://gre/modules/Timer.jsm", {}).clearInterval;
+});
+defineLazyGetter(globals, "setInterval", () => {
+ return Cu.import("resource://gre/modules/Timer.jsm", {}).setInterval;
+});
+defineLazyGetter(globals, "CSSRule", () => Ci.nsIDOMCSSRule);
+defineLazyGetter(globals, "DOMParser", () => {
+ return CC("@mozilla.org/xmlextras/domparser;1", "nsIDOMParser");
+});
+defineLazyGetter(globals, "CSS", () => {
+ let sandbox
+ = Cu.Sandbox(CC("@mozilla.org/systemprincipal;1", "nsIPrincipal")(),
+ {wantGlobalProperties: ["CSS"]});
+ return sandbox.CSS;
+});
+defineLazyGetter(globals, "WebSocket", () => {
+ return Services.appShell.hiddenDOMWindow.WebSocket;
+});
+lazyRequireGetter(globals, "indexedDB", "sdk/indexed-db", true);