Bug 1423425 Make some extensions comments jsdoc-compatible draft
authorAndrew Swan <aswan@mozilla.com>
Tue, 05 Dec 2017 18:53:15 -0800
changeset 712813 e9cb757a18f1c97667c2717e5d0f1cb91ec28964
parent 712812 2aa1650c3e80a0334448bf8278be9c60e89bdab8
child 712814 d054c53fa16a78ca5c55ea6db380659546a25952
push id93447
push useraswan@mozilla.com
push dateMon, 18 Dec 2017 20:54:53 +0000
bugs1423425
milestone59.0a1
Bug 1423425 Make some extensions comments jsdoc-compatible MozReview-Commit-ID: 3mUKR9IuEKA
toolkit/components/extensions/Extension.jsm
toolkit/components/extensions/ExtensionCommon.jsm
--- a/toolkit/components/extensions/Extension.jsm
+++ b/toolkit/components/extensions/Extension.jsm
@@ -274,25 +274,27 @@ var UninstallObserver = {
       // Clear the entry in the UUID map
       UUIDMap.remove(addon.id);
     }
   },
 };
 
 UninstallObserver.init();
 
-// Represents the data contained in an extension, contained either
-// in a directory or a zip file, which may or may not be installed.
-// This class implements the functionality of the Extension class,
-// primarily related to manifest parsing and localization, which is
-// useful prior to extension installation or initialization.
-//
-// No functionality of this class is guaranteed to work before
-// |loadManifest| has been called, and completed.
-this.ExtensionData = class {
+/**
+ * Represents the data contained in an extension, contained either
+ * in a directory or a zip file, which may or may not be installed.
+ * This class implements the functionality of the Extension class,
+ * primarily related to manifest parsing and localization, which is
+ * useful prior to extension installation or initialization.
+ *
+ * No functionality of this class is guaranteed to work before
+ * `loadManifest` has been called, and completed.
+ */
+class ExtensionData {
   constructor(rootURI) {
     this.rootURI = rootURI;
     this.resourceURL = rootURI.spec;
 
     this.manifest = null;
     this.type = null;
     this.id = null;
     this.uuid = null;
@@ -313,21 +315,28 @@ this.ExtensionData = class {
     return null;
   }
 
   get logger() {
     let id = this.id || "<unknown>";
     return Log.repository.getLogger(LOGGER_ID_BASE + id);
   }
 
-  // Report an error about the extension's manifest file.
+  /**
+   * Report an error about the extension's manifest file.
+   * @param {string} message The error message
+   */
   manifestError(message) {
     this.packagingError(`Reading manifest: ${message}`);
   }
 
+  /**
+   * Report a warning about the extension's manifest file.
+   * @param {string} message The warning message
+   */
   manifestWarning(message) {
     this.packagingWarning(`Reading manifest: ${message}`);
   }
 
   // Report an error about the extension's general packaging.
   packagingError(message) {
     this.errors.push(message);
     this.logError(message);
@@ -955,33 +964,34 @@ this.ExtensionData = class {
       if (haveAccessKeys) {
         result.acceptKey = bundle.GetStringFromName("webextPerms.optionalPermsAllow.accessKey");
         result.cancelKey = bundle.GetStringFromName("webextPerms.optionalPermsDeny.accessKey");
       }
     }
 
     return result;
   }
-};
+}
 
 const PROXIED_EVENTS = new Set(["test-harness-message", "add-permissions", "remove-permissions"]);
 
 const shutdownPromises = new Map();
 
 class BootstrapScope {
   install(data, reason) {}
   uninstall(data, reason) {
     Management.emit("uninstall", {id: data.id});
   }
 
   update(data, reason) {
     Management.emit("update", {id: data.id, resourceURI: data.resourceURI});
   }
 
   startup(data, reason) {
+    // eslint-disable-next-line no-use-before-define
     this.extension = new Extension(data, this.BOOTSTRAP_REASON_TO_STRING_MAP[reason]);
     return this.extension.startup();
   }
 
   shutdown(data, reason) {
     this.extension.shutdown(this.BOOTSTRAP_REASON_TO_STRING_MAP[reason]);
     this.extension = null;
   }
@@ -1002,29 +1012,33 @@ XPCOMUtils.defineLazyGetter(BootstrapSco
   });
 });
 
 class LangpackBootstrapScope {
   install(data, reason) {}
   uninstall(data, reason) {}
 
   startup(data, reason) {
+    // eslint-disable-next-line no-use-before-define
     this.langpack = new Langpack(data);
     return this.langpack.startup();
   }
 
   shutdown(data, reason) {
     this.langpack.shutdown();
     this.langpack = null;
   }
 }
 
-// We create one instance of this class per extension. |addonData|
-// comes directly from bootstrap.js when initializing.
-this.Extension = class extends ExtensionData {
+/**
+ * This class is the main representation of an active WebExtension
+ * in the main process.
+ * @extends ExtensionData
+ */
+class Extension extends ExtensionData {
   constructor(addonData, startupReason) {
     super(addonData.resourceURI);
 
     this.uuid = UUIDMap.get(addonData.id);
     this.instanceId = getUniqueId();
 
     this.MESSAGE_EMIT_EVENT = `Extension:EmitEvent:${this.instanceId}`;
     Services.ppmm.addMessageListener(this.MESSAGE_EMIT_EVENT, this);
@@ -1107,16 +1121,23 @@ this.Extension = class extends Extension
       this.policy.permissions = Array.from(this.permissions);
       this.policy.allowedOrigins = this.whiteListedHosts;
 
       this.cachePermissions();
     });
     /* eslint-enable mozilla/balanced-listeners */
   }
 
+  // Some helpful properties added elsewhere:
+  /**
+   * An object used to map between extension-visible tab ids and
+   * native Tab object
+   * @property {TabManager} tabManager
+   */
+
   static getBootstrapScope(id, file) {
     return new BootstrapScope();
   }
 
   get groupFrameLoader() {
     let frameLoader = this._backgroundPageFrameLoader;
     for (let view of this.views) {
       if (view.viewType === "background" && view.xulBrowser) {
@@ -1346,16 +1367,25 @@ this.Extension = class extends Extension
 
     data["Extension:Extensions"].push(serial);
 
     return this.broadcast("Extension:Startup", serial).then(() => {
       return Promise.all(promises);
     });
   }
 
+  /**
+   * Call the close() method on the given object when this extension
+   * is shut down.  This can happen during browser shutdown, or when
+   * an extension is manually disabled or uninstalled.
+   *
+   * @param {object} obj
+   *        An object on which to call the close() method when this
+   *        extension is shut down.
+   */
   callOnClose(obj) {
     this.onShutdown.add(obj);
   }
 
   forgetOnClose(obj) {
     this.onShutdown.delete(obj);
   }
 
@@ -1645,19 +1675,19 @@ this.Extension = class extends Extension
 
   get optionalOrigins() {
     if (this._optionalOrigins == null) {
       let origins = this.manifest.optional_permissions.filter(perm => classifyPermission(perm).origin);
       this._optionalOrigins = new MatchPatternSet(origins, {ignorePath: true});
     }
     return this._optionalOrigins;
   }
-};
+}
 
-this.Langpack = class extends ExtensionData {
+class Langpack extends ExtensionData {
   constructor(addonData, startupReason) {
     super(addonData.resourceURI);
     this.startupData = addonData.startupData;
     this.manifestCacheKey = [addonData.id, addonData.version];
   }
 
   static getBootstrapScope(id, file) {
     return new LangpackBootstrapScope();
@@ -1748,9 +1778,9 @@ this.Langpack = class extends ExtensionD
     }
     if (this.chromeRegistryHandle) {
       this.chromeRegistryHandle.destruct();
       this.chromeRegistryHandle = null;
     }
 
     resourceProtocol.setSubstitution(this.langpackId, null);
   }
-};
+}
--- a/toolkit/components/extensions/ExtensionCommon.jsm
+++ b/toolkit/components/extensions/ExtensionCommon.jsm
@@ -78,16 +78,21 @@ class NoCloneSpreadArgs {
     this.unwrappedValues = args;
   }
 
   [Symbol.iterator]() {
     return this.unwrappedValues[Symbol.iterator]();
   }
 }
 
+/**
+ * Base class for WebExtension APIs.  Each API creates a new class
+ * that inherits from this class, the derived class is instantiated
+ * once for each extension that uses the API.
+ */
 class ExtensionAPI extends ExtensionUtils.EventEmitter {
   constructor(extension) {
     super();
 
     this.extension = extension;
 
     extension.once("shutdown", () => {
       if (this.onShutdown) {
@@ -170,16 +175,23 @@ var ExtensionAPIs = {
     if (!this.apis.has(namespace)) {
       throw new Error(`API namespace does not exist: ${namespace}`);
     }
 
     this.apis.delete(namespace);
   },
 };
 
+/**
+ * This class contains the information we have about an individual
+ * extension.  It is never instantiated directly, instead subclasses
+ * for each type of process extend this class and add members that are
+ * relevant for that process.
+ * @abstract
+ */
 class BaseContext {
   constructor(envType, extension) {
     this.envType = envType;
     this.onClose = new Set();
     this.checkedLastError = false;
     this._lastError = null;
     this.contextId = getUniqueId();
     this.unloaded = false;
@@ -1513,37 +1525,48 @@ LocaleData.prototype = {
   },
 };
 
 defineLazyGetter(LocaleData.prototype, "availableLocales", function() {
   return new Set([this.BUILTIN, this.selectedLocale, this.defaultLocale]
                  .filter(locale => this.messages.has(locale)));
 });
 
-// This is a generic class for managing event listeners. Example usage:
-//
-// new EventManager(context, "api.subAPI", fire => {
-//   let listener = (...) => {
-//     // Fire any listeners registered with addListener.
-//     fire.async(arg1, arg2);
-//   };
-//   // Register the listener.
-//   SomehowRegisterListener(listener);
-//   return () => {
-//     // Return a way to unregister the listener.
-//     SomehowUnregisterListener(listener);
-//   };
-// }).api()
-//
-// The result is an object with addListener, removeListener, and
-// hasListener methods. |context| is an add-on scope (either an
-// ExtensionContext in the chrome process or ExtensionContext in a
-// content process). |name| is for debugging. |register| is a function
-// to register the listener. |register| should return an
-// unregister function that will unregister the listener.
+/**
+* This is a generic class for managing event listeners.
+ *
+ * @example
+ * new EventManager(context, "api.subAPI", fire => {
+ *   let listener = (...) => {
+ *     // Fire any listeners registered with addListener.
+ *     fire.async(arg1, arg2);
+ *   };
+ *   // Register the listener.
+ *   SomehowRegisterListener(listener);
+ *   return () => {
+ *     // Return a way to unregister the listener.
+ *     SomehowUnregisterListener(listener);
+ *   };
+ * }).api()
+ *
+ * The result is an object with addListener, removeListener, and
+ * hasListener methods. `context` is an add-on scope (either an
+ * ExtensionContext in the chrome process or ExtensionContext in a
+ * content process). `name` is for debugging. `register` is a function
+ * to register the listener. `register` should return an
+ * unregister function that will unregister the listener.
+ * @constructor
+ *
+ * @param {BaseContext} context
+ *        An object representing the extension instance using this event.
+ * @param {string} name
+ *        A name used only for debugging.
+ * @param {functon} register
+ *        A function called whenever a new listener is added.
+ */
 function EventManager(context, name, register) {
   this.context = context;
   this.name = name;
   this.register = register;
   this.unregister = new Map();
   this.inputHandling = false;
 }