Bug 1363925: Part 7b - Turn on valid-jsdoc rule for XPIProvider.jsm. r=me,npotb
authorKris Maglione <maglione.k@gmail.com>
Sat, 21 Apr 2018 20:51:52 -0700
changeset 415213 2132b4cf18db3a8c0ab9ffc4977be05ec58748b1
parent 415212 ee1bdb001079770b20899df675e6cd0640a2d5fe
child 415214 fde77a548f547094e5c06a30f927175c03ad23ae
push id33892
push userebalazs@mozilla.com
push dateTue, 24 Apr 2018 09:42:58 +0000
treeherdermozilla-central@26e53729a109 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersme, npotb
bugs1363925
milestone61.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1363925: Part 7b - Turn on valid-jsdoc rule for XPIProvider.jsm. r=me,npotb MozReview-Commit-ID: BQ6N84B2pC3
toolkit/mozapps/extensions/internal/XPIProvider.jsm
--- a/toolkit/mozapps/extensions/internal/XPIProvider.jsm
+++ b/toolkit/mozapps/extensions/internal/XPIProvider.jsm
@@ -1,14 +1,16 @@
  /* 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";
 
+/* eslint "valid-jsdoc": [2, {requireReturn: false, requireReturnDescription: false, prefer: {return: "returns"}}] */
+
 var EXPORTED_SYMBOLS = ["XPIProvider", "XPIInternal"];
 
 /* globals WebExtensionPolicy */
 
 ChromeUtils.import("resource://gre/modules/Services.jsm");
 ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
 ChromeUtils.import("resource://gre/modules/AddonManager.jsm");
 
@@ -425,43 +427,46 @@ function findMatchingStaticBlocklistItem
   }
   return null;
 }
 
 /**
  * Helper function that determines whether an addon of a certain type is a
  * WebExtension.
  *
- * @param  {String} type
- * @return {Boolean}
+ * @param {string} type
+ *        The add-on type to check.
+ * @returns {boolean}
  */
 function isWebExtension(type) {
   return type == "webextension" || type == "webextension-theme";
 }
 
 var gThemeAliases = null;
 /**
  * Helper function that determines whether an addon of a certain type is a
  * theme.
  *
- * @param  {String} type
- * @return {Boolean}
+ * @param {string} type
+ *        The add-on type to check.
+ * @returns {boolean}
  */
 function isTheme(type) {
   if (!gThemeAliases)
     gThemeAliases = getAllAliasesForTypes(["theme"]);
   return gThemeAliases.includes(type);
 }
 
 /**
  * Evaluates whether an add-on is allowed to run in safe mode.
  *
- * @param  aAddon
- *         The add-on to check
- * @return true if the add-on should run in safe mode
+ * @param {AddonInternal} aAddon
+ *        The add-on to check
+ * @returns {boolean}
+ *        True if the add-on should run in safe mode
  */
 function canRunInSafeMode(aAddon) {
   // Even though the updated system add-ons aren't generally run in safe mode we
   // include them here so their uninstall functions get called when switching
   // back to the default set.
 
   // TODO product should make the call about temporary add-ons running
   // in safe mode. assuming for now that they are.
@@ -497,19 +502,20 @@ function isDisabledLegacy(addon) {
 
           // Properly signed legacy extensions are allowed.
           addon.signedState !== AddonManager.SIGNEDSTATE_PRIVILEGED);
 }
 
 /**
  * Calculates whether an add-on should be appDisabled or not.
  *
- * @param  aAddon
- *         The add-on to check
- * @return true if the add-on should not be appDisabled
+ * @param {AddonInternal} aAddon
+ *        The add-on to check
+ * @returns {boolean}
+ *        True if the add-on should not be appDisabled
  */
 function isUsableAddon(aAddon) {
   if (mustSign(aAddon.type) && !aAddon.isCorrectlySigned) {
     logger.warn(`Add-on ${aAddon.id} is not correctly signed.`);
     if (Services.prefs.getBoolPref(PREF_XPI_SIGNATURES_DEV_ROOT, false)) {
       logger.warn(`Preference ${PREF_XPI_SIGNATURES_DEV_ROOT} is set.`);
     }
     return false;
@@ -565,19 +571,20 @@ function isUsableAddon(aAddon) {
   }
 
   return true;
 }
 
 /**
  * Converts an internal add-on type to the type presented through the API.
  *
- * @param  aType
- *         The internal add-on type
- * @return an external add-on type
+ * @param {string} aType
+ *        The internal add-on type
+ * @returns {string}
+ *        An external add-on type
  */
 function getExternalType(aType) {
   if (aType in TYPE_ALIASES)
     return TYPE_ALIASES[aType];
   return aType;
 }
 
 function getManifestFileForDir(aDir) {
@@ -589,19 +596,20 @@ function getManifestFileForDir(aDir) {
     return file;
   return null;
 }
 
 /**
  * Converts a list of API types to a list of API types and any aliases for those
  * types.
  *
- * @param  aTypes
- *         An array of types or null for all types
- * @return an array of types or null for all types
+ * @param {Array<string>?} aTypes
+ *        An array of types or null for all types
+ * @returns {Array<string>?}
+ *        An array of types or null for all types
  */
 function getAllAliasesForTypes(aTypes) {
   if (!aTypes)
     return null;
 
   // Build a set of all requested types and their aliases
   let typeset = new Set(aTypes);
 
@@ -617,59 +625,62 @@ function getAllAliasesForTypes(aTypes) {
   return [...typeset];
 }
 
 /**
  * Gets an nsIURI for a file within another file, either a directory or an XPI
  * file. If aFile is a directory then this will return a file: URI, if it is an
  * XPI file then it will return a jar: URI.
  *
- * @param  aFile
- *         The file containing the resources, must be either a directory or an
- *         XPI file
- * @param  aPath
- *         The path to find the resource at, "/" separated. If aPath is empty
- *         then the uri to the root of the contained files will be returned
- * @return an nsIURI pointing at the resource
+ * @param {nsIFile} aFile
+ *        The file containing the resources, must be either a directory or an
+ *        XPI file
+ * @param {string} aPath
+ *        The path to find the resource at, "/" separated. If aPath is empty
+ *        then the uri to the root of the contained files will be returned
+ * @returns {nsIURI}
+ *        An nsIURI pointing at the resource
  */
 function getURIForResourceInFile(aFile, aPath) {
   if (aFile.exists() && aFile.isDirectory()) {
     let resource = aFile.clone();
     if (aPath)
       aPath.split("/").forEach(part => resource.append(part));
 
     return Services.io.newFileURI(resource);
   }
 
   return buildJarURI(aFile, aPath);
 }
 
 /**
  * Creates a jar: URI for a file inside a ZIP file.
  *
- * @param  aJarfile
- *         The ZIP file as an nsIFile
- * @param  aPath
- *         The path inside the ZIP file
- * @return an nsIURI for the file
+ * @param {nsIFile} aJarfile
+ *        The ZIP file as an nsIFile
+ * @param {string} aPath
+ *        The path inside the ZIP file
+ * @returns {nsIURI}
+ *        An nsIURI for the file
  */
 function buildJarURI(aJarfile, aPath) {
   let uri = Services.io.newFileURI(aJarfile);
   uri = "jar:" + uri.spec + "!/" + aPath;
   return Services.io.newURI(uri);
 }
 
 /**
  * Gets a snapshot of directory entries.
  *
- * @param  aDir
- *         Directory to look at
- * @param  aSortEntries
- *         True to sort entries by filename
- * @return An array of nsIFile, or an empty array if aDir is not a readable directory
+ * @param {nsIURI} aDir
+ *        Directory to look at
+ * @param {boolean} aSortEntries
+ *        True to sort entries by filename
+ * @returns {Array<nsIFile>}
+ *        An array of nsIFile, or an empty array if aDir is not a readable directory
  */
 function getDirectoryEntries(aDir, aSortEntries) {
   let dirEnum;
   try {
     dirEnum = aDir.directoryEntries.QueryInterface(Ci.nsIDirectoryEnumerator);
     let entries = [];
     while (dirEnum.hasMoreElements())
       entries.push(dirEnum.nextFile);
@@ -689,18 +700,23 @@ function getDirectoryEntries(aDir, aSort
   } finally {
     if (dirEnum) {
       dirEnum.close();
     }
   }
 }
 
 /**
- * Record a bit of per-addon telemetry
- * @param aAddon the addon to record
+ * Record a bit of per-addon telemetry.
+ *
+ * Yes, this description is extremely helpful. How dare you question its
+ * utility?
+ *
+ * @param {AddonInternal} aAddon
+ *        The addon to record
  */
 function recordAddonTelemetry(aAddon) {
   let locale = aAddon.defaultLocale;
   if (locale) {
     if (locale.name)
       XPIProvider.setTelemetry(aAddon.id, "name", locale.name);
     if (locale.creator)
       XPIProvider.setTelemetry(aAddon.id, "creator", locale.creator);
@@ -758,21 +774,22 @@ class XPIState {
   /**
    * Migrates an add-on's data from xpiState and bootstrappedAddons
    * preferences, and returns an XPIState object for it.
    *
    * @param {XPIStateLocation} location
    *        The location of the add-on.
    * @param {string} id
    *        The ID of the add-on to migrate.
-   * @param {object} state
+   * @param {object} saved
    *        The add-on's data from the xpiState preference.
    * @param {object} [bootstrapped]
    *        The add-on's data from the bootstrappedAddons preference, if
    *        applicable.
+   * @returns {XPIState}
    */
   static migrate(location, id, saved, bootstrapped) {
     let data = {
       enabled: saved.e,
       path: descriptorToPath(saved.d, location.dir),
       lastModifiedTime: saved.mt || saved.st,
       version: saved.v,
     };
@@ -826,16 +843,18 @@ class XPIState {
       return path;
     }
     return this.path;
   }
 
   /**
    * Returns a JSON-compatible representation of this add-on's state
    * data, to be saved to addonStartup.json.
+   *
+   * @returns {Object}
    */
   toJSON() {
     let json = {
       enabled: this.enabled,
       lastModifiedTime: this.lastModifiedTime,
       path: this.relativePath,
       version: this.version,
     };
@@ -851,19 +870,23 @@ class XPIState {
     if (this.startupData) {
       json.startupData = this.startupData;
     }
     return json;
   }
 
   /**
    * Update the last modified time for an add-on on disk.
-   * @param aFile: nsIFile path of the add-on.
-   * @param aId: The add-on ID.
-   * @return True if the time stamp has changed.
+   *
+   * @param {nsIFile} aFile
+   *        The location of the add-on.
+   * @param {string} aId
+   *        The add-on ID.
+   * @returns {boolean}
+   *       True if the time stamp has changed.
    */
   getModTime(aFile, aId) {
     // Modified time is the install manifest time, if any. If no manifest
     // exists, we assume this is a packed .xpi and use the time stamp of
     // {path}
     let mtime = (tryGetMtime(getManifestFileForDir(aFile)) ||
                  tryGetMtime(aFile));
     if (!mtime) {
@@ -874,19 +897,23 @@ class XPIState {
     this.lastModifiedTime = mtime;
     return this.changed;
   }
 
   /**
    * Update the XPIState to match an XPIDatabase entry; if 'enabled' is changed to true,
    * update the last-modified time. This should probably be made async, but for now we
    * don't want to maintain parallel sync and async versions of the scan.
+   *
    * Caller is responsible for doing XPIStates.save() if necessary.
-   * @param aDBAddon The DBAddonInternal for this add-on.
-   * @param aUpdated The add-on was updated, so we must record new modified time.
+   *
+   * @param {DBAddonInternal} aDBAddon
+   *        The DBAddonInternal for this add-on.
+   * @param {boolean} [aUpdated = false]
+   *        The add-on was updated, so we must record new modified time.
    */
   syncWithDB(aDBAddon, aUpdated = false) {
     logger.debug("Updating XPIState for " + JSON.stringify(aDBAddon));
     // If the add-on changes from disabled to enabled, we should re-check the modified time.
     // If this is a newly found add-on, it won't have an 'enabled' field but we
     // did a full recursive scan in that case, so we don't need to do it again.
     // We don't use aDBAddon.active here because it's not updated until after restart.
     let mustGetMod = (aDBAddon.visible && !aDBAddon.disabled && !this.enabled);
@@ -944,16 +971,18 @@ class XPIStateLocation extends Map {
       // Make a note that this state was restored from saved data.
       xpiState.wasRestored = true;
     }
   }
 
   /**
    * Returns a JSON-compatible representation of this location's state
    * data, to be saved to addonStartup.json.
+   *
+   * @returns {Object}
    */
   toJSON() {
     let json = {
       addons: {},
       staged: this.staged,
     };
 
     if (this.path) {
@@ -1139,16 +1168,18 @@ var XPIStates = {
     logger.debug("Migrated data: ${}", data);
 
     return data;
   },
 
   /**
    * Load extension state data from addonStartup.json, or migrates it
    * from legacy state preferences, if they exist.
+   *
+   * @returns {Object}
    */
   loadExtensionState() {
     let state;
     try {
       state = aomStartup.readStartupData();
     } catch (e) {
       logger.warn("Error parsing extensions state: ${error}",
                   {error: e});
@@ -1167,21 +1198,22 @@ var XPIStates = {
     logger.debug("Loaded add-on state: ${}", state);
     return state || {};
   },
 
   /**
    * Walk through all install locations, highest priority first,
    * comparing the on-disk state of extensions to what is stored in prefs.
    *
-   * @param {bool} [ignoreSideloads = true]
+   * @param {boolean} [ignoreSideloads = true]
    *        If true, ignore changes in scopes where we don't accept
    *        side-loads.
    *
-   * @return true if anything has changed.
+   * @returns {boolean}
+   *        True if anything has changed.
    */
   getInstallState(ignoreSideloads = true) {
     if (!this.db) {
       this.db = new Map();
     }
 
     let oldState = this.initialStateData || this.loadExtensionState();
     this.initialStateData = oldState;
@@ -1247,18 +1279,27 @@ var XPIStates = {
 
     logger.debug("getInstallState changed: ${rv}, state: ${state}",
         {rv: changed, state: this.db});
     return changed;
   },
 
   /**
    * Get the Map of XPI states for a particular location.
-   * @param name The name of the install location.
-   * @return XPIStateLocation (id -> XPIState) or null if there are no add-ons in the location.
+   *
+   * @param {string} name
+   *        The name of the install location.
+   * @param {string?} [path]
+   *        The expected path of the location, if known.
+   * @param {Object?} [saved]
+   *        The saved data for the location, as read from the
+   *        addonStartup.json file.
+   *
+   * @returns {XPIStateLocation?}
+   *        (id -> XPIState) or null if there are no add-ons in the location.
    */
   getLocation(name, path, saved) {
     let location = this.db.get(name);
 
     if (path && location && location.path != path) {
       location = null;
       saved = null;
     }
@@ -1271,35 +1312,40 @@ var XPIStates = {
       }
     }
     return location;
   },
 
   /**
    * Get the XPI state for a specific add-on in a location.
    * If the state is not in our cache, return null.
-   * @param aLocation The name of the location where the add-on is installed.
-   * @param aId       The add-on ID
-   * @return The XPIState entry for the add-on, or null.
+   *
+   * @param {string} aLocation
+   *        The name of the location where the add-on is installed.
+   * @param {string} aId
+   *        The add-on ID
+   *
+   * @returns {XPIState?}
+   *        The XPIState entry for the add-on, or null.
    */
   getAddon(aLocation, aId) {
     let location = this.db.get(aLocation);
     return location && location.get(aId);
   },
 
   /**
    * Find the highest priority location of an add-on by ID and return the
    * XPIState.
    * @param {string} aId
    *        The add-on IDa
    * @param {function} aFilter
    *        An optional filter to apply to install locations.  If provided,
    *        addons in locations that do not match the filter are not considered.
    *
-   * @return {XPIState?}
+   * @returns {XPIState?}
    */
   findAddon(aId, aFilter = location => true) {
     // Fortunately the Map iterator returns in order of insertion, which is
     // also our highest -> lowest priority order.
     for (let location of this.db.values()) {
       if (!aFilter(location)) {
         continue;
       }
@@ -1343,17 +1389,19 @@ var XPIStates = {
       if (addon.bootstrapped) {
         yield addon;
       }
     }
   },
 
   /**
    * Add a new XPIState for an add-on and synchronize it with the DBAddonInternal.
-   * @param aAddon DBAddonInternal for the new add-on.
+   *
+   * @param {DBAddonInternal} aAddon
+   *        The add-on to add.
    */
   addAddon(aAddon) {
     let location = this.getLocation(aAddon._installLocation.name);
     location.addAddon(aAddon);
   },
 
   /**
    * Save the current state of installed add-ons.
@@ -1378,33 +1426,40 @@ var XPIStates = {
         data[key] = loc;
       }
     }
     return data;
   },
 
   /**
    * Remove the XPIState for an add-on and save the new state.
-   * @param aLocation  The name of the add-on location.
-   * @param aId        The ID of the add-on.
+   *
+   * @param {string} aLocation
+   *        The name of the add-on location.
+   * @param {string} aId
+   *        The ID of the add-on.
+   *
    */
   removeAddon(aLocation, aId) {
     logger.debug("Removing XPIState for " + aLocation + ":" + aId);
     let location = this.db.get(aLocation);
     if (location) {
       location.delete(aId);
       if (location.size == 0) {
         this.db.delete(aLocation);
       }
       this.save();
     }
   },
 
   /**
    * Disable the XPIState for an add-on.
+   *
+   * @param {string} aId
+   *        The ID of the add-on.
    */
   disableAddon(aId) {
     logger.debug(`Disabling XPIState for ${aId}`);
     let state = this.findAddon(aId);
     if (state) {
       state.enabled = false;
     }
   },
@@ -1545,28 +1600,28 @@ var XPIProvider = {
         logger.warn("Cancel failed", e);
       }
     }
   },
 
   /**
    * Starts the XPI provider initializes the install locations and prefs.
    *
-   * @param  aAppChanged
-   *         A tri-state value. Undefined means the current profile was created
-   *         for this session, true means the profile already existed but was
-   *         last used with an application with a different version number,
-   *         false means that the profile was last used by this version of the
-   *         application.
-   * @param  aOldAppVersion
-   *         The version of the application last run with this profile or null
-   *         if it is a new profile or the version is unknown
-   * @param  aOldPlatformVersion
-   *         The version of the platform last run with this profile or null
-   *         if it is a new profile or the version is unknown
+   * @param {boolean?} aAppChanged
+   *        A tri-state value. Undefined means the current profile was created
+   *        for this session, true means the profile already existed but was
+   *        last used with an application with a different version number,
+   *        false means that the profile was last used by this version of the
+   *        application.
+   * @param {string?} [aOldAppVersion]
+   *        The version of the application last run with this profile or null
+   *        if it is a new profile or the version is unknown
+   * @param {string?} [aOldPlatformVersion]
+   *        The version of the platform last run with this profile or null
+   *        if it is a new profile or the version is unknown
    */
   startup(aAppChanged, aOldAppVersion, aOldPlatformVersion) {
     function addDirectoryInstallLocation(aName, aKey, aPaths, aScope, aLocked) {
       try {
         var dir = FileUtils.getDir(aKey, aPaths);
       } catch (e) {
         // Some directories aren't defined on some platforms, ignore them
         logger.debug("Skipping unavailable install location " + aName);
@@ -2172,20 +2227,21 @@ var XPIProvider = {
       ChromeUtils.import("resource://gre/modules/TelemetrySession.jsm", {}).TelemetrySession;
     TelemetrySession.setAddOns(data);
   },
 
   /**
    * Check the staging directories of install locations for any add-ons to be
    * installed or add-ons to be uninstalled.
    *
-   * @param  aManifests
+   * @param {Object} aManifests
    *         A dictionary to add detected install manifests to for the purpose
    *         of passing through updated compatibility information
-   * @return true if an add-on was installed or uninstalled
+   * @returns {boolean}
+   *        True if an add-on was installed or uninstalled
    */
   processPendingFileChanges(aManifests) {
     let changed = false;
     for (let location of this.installLocations) {
       aManifests[location.name] = {};
       // We can't install or uninstall anything in locked locations
       if (location.locked) {
         continue;
@@ -2231,22 +2287,23 @@ var XPIProvider = {
   },
 
   /**
    * Installs any add-ons located in the extensions directory of the
    * application's distribution specific directory into the profile unless a
    * newer version already exists or the user has previously uninstalled the
    * distributed add-on.
    *
-   * @param  aManifests
-   *         A dictionary to add new install manifests to to save having to
-   *         reload them later
-   * @param  aAppChanged
-   *         See checkForChanges
-   * @return true if any new add-ons were installed
+   * @param {Object} aManifests
+   *        A dictionary to add new install manifests to to save having to
+   *        reload them later
+   * @param {string} [aAppChanged]
+   *        See checkForChanges
+   * @returns {boolean}
+   *        True if any new add-ons were installed
    */
   installDistributionAddons(aManifests, aAppChanged) {
     let distroDir;
     try {
       distroDir = FileUtils.getDir(KEY_APP_DISTRIBUTION, [DIR_EXTENSIONS]);
     } catch (e) {
       return false;
     }
@@ -2333,29 +2390,30 @@ var XPIProvider = {
     return Array.from(XPIDatabase.getAddons())
                 .filter(addon => addon.dependencies.includes(aAddon.id));
   },
 
   /**
    * Checks for any changes that have occurred since the last time the
    * application was launched.
    *
-   * @param  aAppChanged
-   *         A tri-state value. Undefined means the current profile was created
-   *         for this session, true means the profile already existed but was
-   *         last used with an application with a different version number,
-   *         false means that the profile was last used by this version of the
-   *         application.
-   * @param  aOldAppVersion
-   *         The version of the application last run with this profile or null
-   *         if it is a new profile or the version is unknown
-   * @param  aOldPlatformVersion
-   *         The version of the platform last run with this profile or null
-   *         if it is a new profile or the version is unknown
-   * @return true if a change requiring a restart was detected
+   * @param {boolean?} [aAppChanged]
+   *        A tri-state value. Undefined means the current profile was created
+   *        for this session, true means the profile already existed but was
+   *        last used with an application with a different version number,
+   *        false means that the profile was last used by this version of the
+   *        application.
+   * @param {string?} [aOldAppVersion]
+   *        The version of the application last run with this profile or null
+   *        if it is a new profile or the version is unknown
+   * @param {string?} [aOldPlatformVersion]
+   *        The version of the platform last run with this profile or null
+   *        if it is a new profile or the version is unknown
+   * @returns {boolean}
+   *        True if a change requiring a restart was detected
    */
   checkForChanges(aAppChanged, aOldAppVersion, aOldPlatformVersion) {
     logger.debug("checkForChanges");
 
     // Keep track of whether and why we need to open and update the database at
     // startup time.
     let updateReasons = [];
     if (aAppChanged) {
@@ -2476,19 +2534,20 @@ var XPIProvider = {
     return addons.filter(addon => (addon.seen === false &&
                                    addon.permissions & AddonManager.PERM_CAN_ENABLE));
   },
 
   /**
    * Called to test whether this provider supports installing a particular
    * mimetype.
    *
-   * @param  aMimetype
-   *         The mimetype to check for
-   * @return true if the mimetype is application/x-xpinstall
+   * @param {string} aMimetype
+   *        The mimetype to check for
+   * @returns {boolean}
+   *        True if the mimetype is application/x-xpinstall
    */
   supportsMimetype(aMimetype) {
     return aMimetype == "application/x-xpinstall";
   },
 
   // Identify temporary install IDs.
   isTemporaryInstallID(id) {
     return id.endsWith(TEMPORARY_ADDON_SUFFIX);
@@ -2508,22 +2567,23 @@ var XPIProvider = {
   setStartupData(aID, aData) {
     let state = XPIStates.findAddon(aID);
     state.startupData = aData;
     XPIStates.save();
   },
 
   /**
    * Returns an Addon corresponding to an instance ID.
-   * @param aInstanceID
+   *
+   * @param {Symbol} aInstanceID
    *        An Addon Instance ID
-   * @return {Promise}
-   * @resolves The found Addon or null if no such add-on exists.
-   * @rejects  Never
-   * @throws if the aInstanceID argument is not specified
+   *
+   * @returns {AddonInternal?}
+   *
+   * @throws if the aInstanceID argument is not valid.
    */
    getAddonByInstanceID(aInstanceID) {
      let id = this.getAddonIDByInstanceID(aInstanceID);
      if (id) {
        return this.syncGetAddonByID(id);
      }
 
      return null;
@@ -2541,28 +2601,29 @@ var XPIProvider = {
      }
 
      return null;
    },
 
   /**
    * Removes an AddonInstall from the list of active installs.
    *
-   * @param  install
-   *         The AddonInstall to remove
+   * @param {AddonInstall} aInstall
+   *        The AddonInstall to remove
    */
   removeActiveInstall(aInstall) {
     this.installs.delete(aInstall);
   },
 
   /**
    * Called to get an Addon with a particular ID.
    *
-   * @param  aId
-   *         The ID of the add-on to retrieve
+   * @param {string} aId
+   *        The ID of the add-on to retrieve
+   * @returns {Addon?}
    */
   async getAddonByID(aId) {
     let aAddon = await XPIDatabase.getVisibleAddonForID(aId);
     return aAddon ? aAddon.wrapper : null;
   },
 
   /**
    * Synchronously returns the Addon object for the add-on with the
@@ -2582,34 +2643,35 @@ var XPIProvider = {
   syncGetAddonByID(aId) {
     let aAddon = XPIDatabase.syncGetVisibleAddonForID(aId);
     return aAddon ? aAddon.wrapper : null;
   },
 
   /**
    * Called to get Addons of a particular type.
    *
-   * @param  aTypes
-   *         An array of types to fetch. Can be null to get all types.
+   * @param {Array<string>?} aTypes
+   *        An array of types to fetch. Can be null to get all types.
+   * @returns {Addon[]}
    */
   async getAddonsByTypes(aTypes) {
     let typesToGet = getAllAliasesForTypes(aTypes);
     if (typesToGet && !typesToGet.some(type => ALL_EXTERNAL_TYPES.has(type))) {
       return [];
     }
 
     let addons = await XPIDatabase.getVisibleAddons(typesToGet);
     return addons.map(a => a.wrapper);
   },
 
   /**
    * Called to get active Addons of a particular type
    *
-   * @param  aTypes
-   *         An array of types to fetch. Can be null to get all types.
+   * @param {Array<string>?} aTypes
+   *        An array of types to fetch. Can be null to get all types.
    * @returns {Promise<Array<Addon>>}
    */
   async getActiveAddons(aTypes) {
     // If we already have the database loaded, returning full info is fast.
     if (this.isDBLoaded) {
       let addons = await this.getAddonsByTypes(aTypes);
       return {
         addons: addons.filter(addon => addon.isActive),
@@ -2646,29 +2708,31 @@ var XPIProvider = {
 
     return {addons: result, fullData: false};
   },
 
 
   /**
    * Obtain an Addon having the specified Sync GUID.
    *
-   * @param  aGUID
-   *         String GUID of add-on to retrieve
+   * @param {string} aGUID
+   *        String GUID of add-on to retrieve
+   * @returns {Addon?}
    */
   async getAddonBySyncGUID(aGUID) {
     let addon = await XPIDatabase.getAddonBySyncGUID(aGUID);
     return addon ? addon.wrapper : null;
   },
 
   /**
    * Called to get Addons that have pending operations.
    *
-   * @param  aTypes
-   *         An array of types to fetch. Can be null to get all types
+   * @param {Array<string>?} aTypes
+   *        An array of types to fetch. Can be null to get all types
+   * @returns {Addon[]}
    */
   async getAddonsWithOperationsByTypes(aTypes) {
     let typesToGet = getAllAliasesForTypes(aTypes);
 
     let aAddons = await XPIDatabase.getVisibleAddonsWithPendingOperations(typesToGet);
     let results = aAddons.map(a => a.wrapper);
     for (let install of XPIProvider.installs) {
       if (install.state == AddonManager.STATE_INSTALLED &&
@@ -2677,38 +2741,39 @@ var XPIProvider = {
     }
     return results;
   },
 
   /**
    * Called to get the current AddonInstalls, optionally limiting to a list of
    * types.
    *
-   * @param  aTypes
-   *         An array of types or null to get all types
+   * @param {Array<string>?} aTypes
+   *        An array of types or null to get all types
+   * @returns {AddonInstall[]}
    */
   getInstallsByTypes(aTypes) {
     let results = [...this.installs];
     if (aTypes) {
       results = results.filter(install => {
         return aTypes.includes(getExternalType(install.type));
       });
     }
 
     return results.map(install => install.wrapper);
   },
 
   /**
    * Called when a new add-on has been enabled when only one add-on of that type
    * can be enabled.
    *
-   * @param  aId
-   *         The ID of the newly enabled add-on
-   * @param  aType
-   *         The type of the newly enabled add-on
+   * @param {string} aId
+   *        The ID of the newly enabled add-on
+   * @param {string} aType
+   *        The type of the newly enabled add-on
    */
   addonChanged(aId, aType) {
     // We only care about themes in this provider
     if (!isTheme(aType))
       return;
 
     let addons = XPIDatabase.getAddonsByType("webextension-theme");
     for (let theme of addons) {
@@ -2759,17 +2824,17 @@ var XPIProvider = {
       return;
 
     for (let [id, val] of this.activeAddons) {
       connection.setAddonOptions(
         id, { global: val.bootstrapScope });
     }
   },
 
-  /**
+  /*
    * Notified when a preference we're interested in has changed.
    *
    * @see nsIObserver
    */
   observe(aSubject, aTopic, aData) {
     if (aTopic == NOTIFICATION_FLUSH_PERMISSIONS) {
       if (!aData || aData == XPI_PERMISSION) {
         this.importPermissions();
@@ -2802,31 +2867,30 @@ var XPIProvider = {
   },
 
   /**
    * Loads a bootstrapped add-on's bootstrap.js into a sandbox and the reason
    * values as constants in the scope. This will also add information about the
    * add-on to the bootstrappedAddons dictionary and notify the crash reporter
    * that new add-ons have been loaded.
    *
-   * @param  aId
-   *         The add-on's ID
-   * @param  aFile
-   *         The nsIFile for the add-on
-   * @param  aVersion
-   *         The add-on's version
-   * @param  aType
-   *         The type for the add-on
-   * @param  aRunInSafeMode
-   *         Boolean indicating whether the add-on can run in safe mode.
-   * @param  aDependencies
-   *         An array of add-on IDs on which this add-on depends.
-   * @param  hasEmbeddedWebExtension
-   *         Boolean indicating whether the add-on has an embedded webextension.
-   * @return a JavaScript scope
+   * @param {string} aId
+   *        The add-on's ID
+   * @param {nsIFile} aFile
+   *        The nsIFile for the add-on
+   * @param {string} aVersion
+   *        The add-on's version
+   * @param {string} aType
+   *        The type for the add-on
+   * @param {boolean} aRunInSafeMode
+   *        Boolean indicating whether the add-on can run in safe mode.
+   * @param {string[]} aDependencies
+   *        An array of add-on IDs on which this add-on depends.
+   * @param {boolean} hasEmbeddedWebExtension
+   *        Boolean indicating whether the add-on has an embedded webextension.
    */
   loadBootstrapScope(aId, aFile, aVersion, aType, aRunInSafeMode, aDependencies,
                      hasEmbeddedWebExtension) {
     this.activeAddons.set(aId, {
       bootstrapScope: null,
       // a Symbol passed to this add-on, which it can use to identify itself
       instanceID: Symbol(aId),
       started: false,
@@ -2891,42 +2955,42 @@ var XPIProvider = {
     let wrappedJSObject = { id: aId, options: { global: activeAddon.bootstrapScope }};
     Services.obs.notifyObservers({ wrappedJSObject }, "toolbox-update-addon-options");
   },
 
   /**
    * Unloads a bootstrap scope by dropping all references to it and then
    * updating the list of active add-ons with the crash reporter.
    *
-   * @param  aId
-   *         The add-on's ID
+   * @param {string} aId
+   *        The add-on's ID
    */
   unloadBootstrapScope(aId) {
     this.activeAddons.delete(aId);
     this.addAddonsToCrashReporter();
 
     // Notify the BrowserToolboxProcess that an addon has been unloaded.
     let wrappedJSObject = { id: aId, options: { global: null }};
     Services.obs.notifyObservers({ wrappedJSObject }, "toolbox-update-addon-options");
   },
 
   /**
    * Calls a bootstrap method for an add-on.
    *
-   * @param  aAddon
-   *         An object representing the add-on, with `id`, `type` and `version`
-   * @param  aFile
-   *         The nsIFile for the add-on
-   * @param  aMethod
-   *         The name of the bootstrap method to call
-   * @param  aReason
-   *         The reason flag to pass to the bootstrap's startup method
-   * @param  aExtraParams
-   *         An object of additional key/value pairs to pass to the method in
-   *         the params argument
+   * @param {Object} aAddon
+   *        An object representing the add-on, with `id`, `type` and `version`
+   * @param {nsIFile} aFile
+   *        The nsIFile for the add-on
+   * @param {string} aMethod
+   *        The name of the bootstrap method to call
+   * @param {integer} aReason
+   *        The reason flag to pass to the bootstrap's startup method
+   * @param {Object?} [aExtraParams]
+   *        An object of additional key/value pairs to pass to the method in
+   *        the params argument
    */
   callBootstrapMethod(aAddon, aFile, aMethod, aReason, aExtraParams) {
     if (!aAddon.id || !aAddon.version || !aAddon.type) {
       throw new Error("aAddon must include an id, version, and type");
     }
 
     // Only run in safe mode if allowed to
     let runInSafeMode = "runInSafeMode" in aAddon ? aAddon.runInSafeMode : canRunInSafeMode(aAddon);
@@ -3048,28 +3112,29 @@ var XPIProvider = {
     }
   },
 
   /**
    * Updates the disabled state for an add-on. Its appDisabled property will be
    * calculated and if the add-on is changed the database will be saved and
    * appropriate notifications will be sent out to the registered AddonListeners.
    *
-   * @param  aAddon
-   *         The DBAddonInternal to update
-   * @param  aUserDisabled
-   *         Value for the userDisabled property. If undefined the value will
-   *         not change
-   * @param  aSoftDisabled
-   *         Value for the softDisabled property. If undefined the value will
-   *         not change. If true this will force userDisabled to be true
-   * @param {boolean} aBecauseSelecting
+   * @param {DBAddonInternal} aAddon
+   *        The DBAddonInternal to update
+   * @param {boolean?} [aUserDisabled]
+   *        Value for the userDisabled property. If undefined the value will
+   *        not change
+   * @param {boolean?} [aSoftDisabled]
+   *        Value for the softDisabled property. If undefined the value will
+   *        not change. If true this will force userDisabled to be true
+   * @param {boolean?} [aBecauseSelecting]
    *        True if we're disabling this add-on because we're selecting
    *        another.
-   * @return a tri-state indicating the action taken for the add-on:
+   * @returns {boolean?}
+   *       A tri-state indicating the action taken for the add-on:
    *           - undefined: The add-on did not change state
    *           - true: The add-on because disabled
    *           - false: The add-on became enabled
    * @throws if addon is not a DBAddonInternal
    */
   updateAddonDisabledState(aAddon, aUserDisabled, aSoftDisabled, aBecauseSelecting) {
     if (!(aAddon.inDatabase))
       throw new Error("Can only update addon states for installed addons.");
@@ -3505,24 +3570,21 @@ AddonInternal.prototype = {
   },
 
   /**
    * toJSON is called by JSON.stringify in order to create a filtered version
    * of this object to be serialized to a JSON file. A new object is returned
    * with copies of all non-private properties. Functions, getters and setters
    * are not copied.
    *
-   * @param  aKey
-   *         The key that this object is being serialized as in the JSON.
-   *         Unused here since this is always the main object serialized
-   *
-   * @return an object containing copies of the properties of this object
-   *         ignoring private properties, functions, getters and setters
+   * @returns {Object}
+   *       An object containing copies of the properties of this object
+   *       ignoring private properties, functions, getters and setters.
    */
-  toJSON(aKey) {
+  toJSON() {
     let obj = {};
     for (let prop in this) {
       // Ignore the wrapper property
       if (prop == "wrapper")
         continue;
 
       // Ignore private properties
       if (prop.substring(0, 1) == "_")
@@ -3546,18 +3608,18 @@ AddonInternal.prototype = {
     return obj;
   },
 
   /**
    * When an add-on install is pending its metadata will be cached in a file.
    * This method reads particular properties of that metadata that may be newer
    * than that in the install manifest, like compatibility information.
    *
-   * @param  aObj
-   *         A JS object containing the cached metadata
+   * @param {Object} aObj
+   *        A JS object containing the cached metadata
    */
   importMetadata(aObj) {
     for (let prop of PENDING_INSTALL_METADATA) {
       if (!(prop in aObj))
         continue;
 
       this[prop] = aObj[prop];
     }
@@ -3602,16 +3664,19 @@ AddonInternal.prototype = {
 
     return permissions;
   },
 };
 
 /**
  * The AddonWrapper wraps an Addon to provide the data visible to consumers of
  * the public API.
+ *
+ * @param {AddonInternal} aAddon
+ *        The add-on object to wrap.
  */
 function AddonWrapper(aAddon) {
   wrapperMap.set(this, aAddon);
 }
 
 AddonWrapper.prototype = {
   get __AddonInternal__() {
     return AppConstants.DEBUG ? addonFor(this) : undefined;
@@ -4019,17 +4084,17 @@ AddonWrapper.prototype = {
 
   /**
    * Reloads the add-on.
    *
    * For temporarily installed add-ons, this uninstalls and re-installs the
    * add-on. Otherwise, the addon is disabled and then re-enabled, and the cache
    * is flushed.
    *
-   * @return Promise
+   * @returns {Promise}
    */
   reload() {
     return new Promise((resolve) => {
       const addon = addonFor(this);
 
       logger.debug(`reloading add-on ${addon.id}`);
 
       if (!this.temporarilyInstalled) {
@@ -4046,20 +4111,20 @@ AddonWrapper.prototype = {
   },
 
   /**
    * Returns a URI to the selected resource or to the add-on bundle if aPath
    * is null. URIs to the bundle will always be file: URIs. URIs to resources
    * will be file: URIs if the add-on is unpacked or jar: URIs if the add-on is
    * still an XPI file.
    *
-   * @param  aPath
-   *         The path in the add-on to get the URI for or null to get a URI to
-   *         the file or directory the add-on is installed as.
-   * @return an nsIURI
+   * @param {string?} aPath
+   *        The path in the add-on to get the URI for or null to get a URI to
+   *        the file or directory the add-on is installed as.
+   * @returns {nsIURI}
    */
   getResourceURI(aPath) {
     let addon = addonFor(this);
     if (!aPath)
       return Services.io.newFileURI(addon._sourceBundle);
 
     return getURIForResourceInFile(addon._sourceBundle, aPath);
   }
@@ -4216,22 +4281,22 @@ function forwardInstallMethods(cls, meth
  */
 class DirectoryInstallLocation {
   /**
    * Each add-on installed in the location is either a directory containing the
    * add-on's files or a text file containing an absolute path to the directory
    * containing the add-ons files. The directory or text file must have the same
    * name as the add-on's ID.
    *
-   * @param  aName
-   *         The string identifier for the install location
-   * @param  aDirectory
-   *         The nsIFile directory for the install location
-   * @param  aScope
-   *         The scope of add-ons installed in this location
+   * @param {string} aName
+   *        The string identifier for the install location
+   * @param {nsIFile} aDirectory
+   *        The nsIFile directory for the install location
+   * @param {integer} aScope
+   *        The scope of add-ons installed in this location
   */
   constructor(aName, aDirectory, aScope) {
     this._name = aName;
     this.locked = true;
     this._directory = aDirectory;
     this._scope = aScope;
     this._IDToFileMap = {};
     this._linkedAddons = [];
@@ -4249,19 +4314,20 @@ class DirectoryInstallLocation {
 
   get path() {
     return this._directory && this._directory.path;
   }
 
   /**
    * Reads a directory linked to in a file.
    *
-   * @param   file
-   *          The file containing the directory path
-   * @return  An nsIFile object representing the linked directory.
+   * @param {nsIFile} aFile
+   *        The file containing the directory path
+   * @returns {nsIFile}
+   *        An nsIFile object representing the linked directory.
    */
   _readDirectoryFromFile(aFile) {
     let linkedDirectory;
     if (aFile.isSymlink()) {
       linkedDirectory = aFile.clone();
       try {
         linkedDirectory.normalize();
       } catch (e) {
@@ -4306,16 +4372,20 @@ class DirectoryInstallLocation {
     }
 
     logger.warn("File pointer " + aFile.path + " does not contain a path");
     return null;
   }
 
   /**
    * Finds all the add-ons installed in this location.
+   *
+   * @param {boolean} [rescan = false]
+   *        True if the directory should be re-scanned, even if it has
+   *        already been initialized.
    */
   _readAddons(rescan = false) {
     if ((this.initialized && !rescan) || !this._directory) {
       return;
     }
     this.initialized = true;
 
     // Use a snapshot of the directory contents to avoid possible issues with
@@ -4373,68 +4443,75 @@ class DirectoryInstallLocation {
    * Gets the scope of this install location.
    */
   get scope() {
     return this._scope;
   }
 
   /**
    * Gets an array of nsIFiles for add-ons installed in this location.
+   *
+   * @param {boolean} [rescan = false]
+   *        True if the directory should be re-scanned, even if it has
+   *        already been initialized.
+   *
+   * @returns {nsIFile[]}
    */
   getAddonLocations(rescan = false) {
     this._readAddons(rescan);
 
     let locations = new Map();
     for (let id in this._IDToFileMap) {
       locations.set(id, this._IDToFileMap[id].clone());
     }
     return locations;
   }
 
   /**
    * Gets the directory that the add-on with the given ID is installed in.
    *
-   * @param  aId
-   *         The ID of the add-on
-   * @return The nsIFile
+   * @param {string} aId
+   *        The ID of the add-on
+   * @returns {nsIFile}
    * @throws if the ID does not match any of the add-ons installed
    */
   getLocationForID(aId) {
     if (!(aId in this._IDToFileMap))
       this._readAddons();
 
     if (aId in this._IDToFileMap)
       return this._IDToFileMap[aId].clone();
     throw new Error("Unknown add-on ID " + aId);
   }
 
   /**
    * Returns true if the given addon was installed in this location by a text
    * file pointing to its real path.
    *
-   * @param aId
+   * @param {string} aId
    *        The ID of the addon
+   * @returns {boolean}
    */
   isLinkedAddon(aId) {
     return this._linkedAddons.includes(aId);
   }
 }
 
 /**
  * An extension of DirectoryInstallLocation which adds methods to installing
  * and removing add-ons from the directory at runtime.
  */
 class MutableDirectoryInstallLocation extends DirectoryInstallLocation {
   /**
-   * @param  aName
-   *         The string identifier for the install location
-   * @param  aDirectory
-   *         The nsIFile directory for the install location
-   * @param  aScope
-   *         The scope of add-ons installed in this location
+   * @param {string} aName
+   *        The string identifier for the install location
+   * @param {nsIFile} aDirectory
+   *        The nsIFile directory for the install location
+   * @param {integer} aScope
+   *        The scope of add-ons installed in this location
    */
   constructor(aName, aDirectory, aScope) {
     super(aName, aDirectory, aScope);
 
     this.locked = false;
     this._stagingDirLock = 0;
   }
 }
@@ -4488,24 +4565,24 @@ class BuiltInInstallLocation extends Dir
 /**
  * An object which identifies a directory install location for system add-ons
  * updates.
  */
 class SystemAddonInstallLocation extends MutableDirectoryInstallLocation {
   /**
     * The location consists of a directory which contains the add-ons installed.
     *
-    * @param  aName
-    *         The string identifier for the install location
-    * @param  aDirectory
-    *         The nsIFile directory for the install location
-    * @param  aScope
-    *         The scope of add-ons installed in this location
-    * @param  aResetSet
-    *         True to throw away the current add-on set
+    * @param {string} aName
+    *        The string identifier for the install location
+    * @param {nsIFile} aDirectory
+    *        The nsIFile directory for the install location
+    * @param {integer} aScope
+    *        The scope of add-ons installed in this location
+    * @param {boolean} aResetSet
+    *        True to throw away the current add-on set
     */
   constructor(aName, aDirectory, aScope, aResetSet) {
     let addonSet = SystemAddonInstallLocation._loadAddonSet();
     let directory = null;
 
     // The system add-on update directory is stored in a pref.
     // Therefore, this is looked up before calling the
     // constructor on the superclass.
@@ -4529,16 +4606,18 @@ class SystemAddonInstallLocation extends
       this.resetAddonSet();
     }
 
     this.locked = false;
   }
 
   /**
    * Reads the current set of system add-ons
+   *
+   * @returns {Object}
    */
   static _loadAddonSet() {
     try {
       let setStr = Services.prefs.getStringPref(PREF_SYSTEM_ADDON_SET, null);
       if (setStr) {
         let addonSet = JSON.parse(setStr);
         if ((typeof addonSet == "object") && addonSet.schema == 1) {
           return addonSet;
@@ -4566,16 +4645,18 @@ class SystemAddonInstallLocation extends
       }
     }
 
     return addons;
   }
 
   /**
    * Tests whether updated system add-ons are expected.
+   *
+   * @returns {boolean}
    */
   isActive() {
     return this._directory != null;
   }
 }
 
 forwardInstallMethods(SystemAddonInstallLocation,
                       ["cleanDirectories", "cleanStagingDir", "getStagingDir",
@@ -4596,22 +4677,22 @@ const TemporaryInstallLocation = { locke
 /**
  * An object that identifies a registry install location for add-ons. The location
  * consists of a registry key which contains string values mapping ID to the
  * path where an add-on is installed
  *
  */
 class WinRegInstallLocation extends DirectoryInstallLocation {
   /**
-    * @param  aName
-    *         The string identifier of this Install Location.
-    * @param  aRootKey
-    *         The root key (one of the ROOT_KEY_ values from nsIWindowsRegKey).
-    * @param  scope
-    *         The scope of add-ons installed in this location
+    * @param {string} aName
+    *        The string identifier of this Install Location.
+    * @param {integer} aRootKey
+    *        The root key (one of the ROOT_KEY_ values from nsIWindowsRegKey).
+    * @param {integer} aScope
+    *        The scope of add-ons installed in this location
     */
   constructor(aName, aRootKey, aScope) {
     super(aName, undefined, aScope);
 
     this.locked = true;
     this._name = aName;
     this._rootKey = aRootKey;
     this._scope = aScope;
@@ -4650,18 +4731,18 @@ class WinRegInstallLocation extends Dire
 
     return "SOFTWARE\\" + appVendor + appName;
   }
 
   /**
    * Read the registry and build a mapping between ID and path for each
    * installed add-on.
    *
-   * @param  key
-   *         The key that contains the ID to path mapping
+   * @param {nsIWindowsRegKey} aKey
+   *        The key that contains the ID to path mapping
    */
   _readAddons(aKey) {
     let count = aKey.valueCount;
     for (let i = 0; i < count; ++i) {
       let id = aKey.getValueName(i);
 
       let file = new nsIFile(aKey.readStringValue(id));
 
@@ -4676,17 +4757,17 @@ class WinRegInstallLocation extends Dire
 
   /**
    * Gets the name of this install location.
    */
   get name() {
     return this._name;
   }
 
-  /**
+  /*
    * @see DirectoryInstallLocation
    */
   isLinkedAddon(aId) {
     return true;
   }
 }
 
 var XPIInternal = {