Bug 1607801 - Pre-define ChromeUtils.import paths; r=julienw
authorGreg Tatum <gtatum@mozilla.com>
Tue, 28 Apr 2020 17:49:59 +0000
changeset 526537 8dfe8cb5a8311dc6062c8d9a421dbbf65bc5050e
parent 526536 79e01e02fa5ebaa2bd4cf7c98043fdf687651555
child 526538 de5aad1dc90e32d9483d5324fd808bfa92086410
push id37358
push useropoprus@mozilla.com
push dateWed, 29 Apr 2020 03:05:14 +0000
treeherdermozilla-central@6bb8423186c1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjulienw
bugs1607801
milestone77.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 1607801 - Pre-define ChromeUtils.import paths; r=julienw This patch takes the approach from mossop on pre-defining ChromeUtils.import paths, so that they don't need to be defined where they are used. Perhaps in the future we could automate this more, but for now this will make the current approach more ergonomic for consumers of the types. Differential Revision: https://phabricator.services.mozilla.com/D59206
devtools/client/performance-new/@types/gecko.d.ts
devtools/client/performance-new/initializer.js
devtools/client/performance-new/popup/background.jsm.js
devtools/client/performance-new/popup/menu-button.jsm.js
devtools/client/performance-new/popup/panel.jsm.js
--- a/devtools/client/performance-new/@types/gecko.d.ts
+++ b/devtools/client/performance-new/@types/gecko.d.ts
@@ -12,21 +12,61 @@
 /**
  * Namespace anything that has its types mocked out here. These definitions are
  * only "good enough" to get the type checking to pass in this directory.
  * Eventually some more structured solution should be found. This namespace is
  * global and makes sure that all the definitions inside do not clash with
  * naming.
  */
 declare namespace MockedExports {
+
+  /**
+   * This interface teaches ChromeUtils.import how to find modules.
+   */
+  interface KnownModules {
+    "resource://gre/modules/Services.jsm":
+      typeof import("resource://gre/modules/Services.jsm");
+    "Services":
+      typeof import("Services");
+    "chrome":
+      typeof import("chrome");
+    "resource://gre/modules/osfile.jsm":
+      typeof import("resource://gre/modules/osfile.jsm");
+    "resource://gre/modules/AppConstants.jsm":
+      typeof import("resource://gre/modules/AppConstants.jsm");
+    "resource://gre/modules/ProfilerGetSymbols.jsm":
+      typeof import("resource://gre/modules/ProfilerGetSymbols.jsm");
+    "resource:///modules/CustomizableUI.jsm":
+      typeof import("resource:///modules/CustomizableUI.jsm")
+    "resource:///modules/CustomizableWidgets.jsm":
+      typeof import("resource:///modules/CustomizableWidgets.jsm");
+    "resource://devtools/shared/Loader.jsm":
+      typeof import("resource://devtools/shared/Loader.jsm");
+    "resource://devtools/client/performance-new/popup/background.jsm.js":
+      typeof import("resource://devtools/client/performance-new/popup/background.jsm.js");
+    "resource://devtools/client/shared/browser-loader.js": any;
+    "resource://devtools/client/performance-new/popup/menu-button.jsm.js":
+      typeof import("devtools/client/performance-new/popup/menu-button.jsm.js");
+    "resource://devtools/client/performance-new/popup/panel.jsm.js":
+      typeof import("devtools/client/performance-new/popup/panel.jsm.js");
+    "resource:///modules/PanelMultiView.jsm":
+      typeof import("resource:///modules/PanelMultiView.jsm");
+  }
+
   interface ChromeUtils {
     /**
-     * Use a JSDoc import declaration to pull in the correct type.
+     * This function reads the KnownModules and resolves which import to use.
+     * If you are getting the TS2345 error:
+     *
+     *  Argument of type '"resource:///.../file.jsm"' is not assignable to parameter
+     *  of type
+     *
+     * Then add the file path to the KnownModules above.
      */
-    import: (path: string) => any;
+    import: <S extends keyof KnownModules>(module: S) => KnownModules[S];
     createObjectIn: (content: ContentWindow) => object;
     exportFunction: (fn: Function, scope: object, options?: object) => void;
     cloneInto: (value: any, scope: object, options?: object) => void;
   }
 
   interface MessageManager {
     loadFrameScript(url: string, flag: boolean): void;
     sendAsyncMessage: (event: string, data: any) => void;
@@ -155,16 +195,20 @@ declare namespace MockedExports {
 
   const WebChannelJSM: any;
 
   // TS-TODO
   const CustomizableUIJSM: any;
   const CustomizableWidgetsJSM: any;
   const PanelMultiViewJSM: any;
 
+  const LoaderJSM: {
+    require: (path: string) => any;
+  };
+
   const Services: Services;
 
   // This class is needed by the Cc importing mechanism. e.g.
   // Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
   class nsIFilePicker {}
 
   interface FilePicker {
     init: (window: Window, title: string, mode: number) => void;
@@ -267,16 +311,20 @@ declare module "resource:///modules/Cust
 declare module "resource:///modules/CustomizableWidgets.jsm" {
   export = MockedExports.CustomizableWidgetsJSM;
 }
 
 declare module "resource:///modules/PanelMultiView.jsm" {
   export = MockedExports.PanelMultiViewJSM;
 }
 
+declare module "resource://devtools/shared/Loader.jsm" {
+  export = MockedExports.LoaderJSM;
+}
+
 declare var ChromeUtils: MockedExports.ChromeUtils;
 declare var Cu: MockedExports.ChromeUtils;
 
 /**
  * This is a variant on the normal Document, as it contains chrome-specific properties.
  */
 declare interface ChromeDocument extends Document {
   /**
--- a/devtools/client/performance-new/initializer.js
+++ b/devtools/client/performance-new/initializer.js
@@ -54,19 +54,19 @@ const {
   receiveProfile,
   createMultiModalGetSymbolTableFn,
 } = require("devtools/client/performance-new/browser");
 
 const {
   setRecordingPreferences,
   presets,
   getRecordingPreferences,
-} = /** @type {import("resource://devtools/client/performance-new/popup/background.jsm.js")} */ (ChromeUtils.import(
+} = ChromeUtils.import(
   "resource://devtools/client/performance-new/popup/background.jsm.js"
-));
+);
 
 /**
  * This file initializes the DevTools Panel UI. It is in charge of initializing
  * the DevTools specific environment, and then passing those requirements into
  * the UI.
  */
 
 /**
--- a/devtools/client/performance-new/popup/background.jsm.js
+++ b/devtools/client/performance-new/popup/background.jsm.js
@@ -8,22 +8,22 @@
  * This file contains all of the background logic for controlling the state and
  * configuration of the profiler. It is in a JSM so that the logic can be shared
  * with both the popup client, and the keyboard shortcuts. The shortcuts don't need
  * access to any UI, and need to be loaded independent of the popup.
  */
 
 // The following are not lazily loaded as they are needed during initialization.
 
-/** @type {import("resource://gre/modules/Services.jsm")} */
 const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
-/** @type {import("resource://gre/modules/AppConstants.jsm")} */
-const { AppConstants } = ChromeUtils.import(
+// For some reason TypeScript was giving me an error when de-structuring AppConstants. I
+// suspect a bug in TypeScript was at play.
+const AppConstants = ChromeUtils.import(
   "resource://gre/modules/AppConstants.jsm"
-);
+).AppConstants;
 
 /**
  * @typedef {import("../@types/perf").RecordingStateFromPreferences} RecordingStateFromPreferences
  * @typedef {import("../@types/perf").PopupBackgroundFeatures} PopupBackgroundFeatures
  * @typedef {import("../@types/perf").SymbolTableAsTuple} SymbolTableAsTuple
  * @typedef {import("../@types/perf").PerformancePref} PerformancePref
  * @typedef {import("../@types/perf").ProfilerWebChannel} ProfilerWebChannel
  * @typedef {import("../@types/perf").MessageFromFrontend} MessageFromFrontend
@@ -68,73 +68,65 @@ function requireLazy(callback) {
     if (cache === undefined) {
       cache = callback();
     }
     return cache;
   };
 }
 
 const lazyOS = requireLazy(() =>
-  /** @type {import("resource://gre/modules/osfile.jsm")} */
-  (ChromeUtils.import("resource://gre/modules/osfile.jsm"))
+  ChromeUtils.import("resource://gre/modules/osfile.jsm")
 );
 
 const lazyProfilerGetSymbols = requireLazy(() =>
-  /** @type {import("resource://gre/modules/ProfilerGetSymbols.jsm")} */
-  (ChromeUtils.import("resource://gre/modules/ProfilerGetSymbols.jsm"))
+  ChromeUtils.import("resource://gre/modules/ProfilerGetSymbols.jsm")
 );
 
 const lazyBrowserModule = requireLazy(() => {
   const { require } = ChromeUtils.import(
     "resource://devtools/shared/Loader.jsm"
   );
-  /** @type {import("devtools/client/performance-new/browser")} */
   const browserModule = require("devtools/client/performance-new/browser");
   return browserModule;
 });
 
 const lazyPreferenceManagement = requireLazy(() => {
   const { require } = ChromeUtils.import(
     "resource://devtools/shared/Loader.jsm"
   );
 
-  /** @type {import("devtools/client/performance-new/preference-management")} */
   const preferenceManagementModule = require("devtools/client/performance-new/preference-management");
   return preferenceManagementModule;
 });
 
 const lazyRecordingUtils = requireLazy(() => {
   const { require } = ChromeUtils.import(
     "resource://devtools/shared/Loader.jsm"
   );
 
-  /** @type {import("devtools/shared/performance-new/recording-utils")} */
   const recordingUtils = require("devtools/shared/performance-new/recording-utils");
   return recordingUtils;
 });
 
 const lazyUtils = requireLazy(() => {
   const { require } = ChromeUtils.import(
     "resource://devtools/shared/Loader.jsm"
   );
-  /** @type {import("devtools/client/performance-new/utils")} */
   const recordingUtils = require("devtools/client/performance-new/utils");
   return recordingUtils;
 });
 
 const lazyProfilerMenuButton = requireLazy(() =>
-  /** @type {import("devtools/client/performance-new/popup/menu-button.jsm.js")} */
-  (ChromeUtils.import(
+  ChromeUtils.import(
     "resource://devtools/client/performance-new/popup/menu-button.jsm.js"
-  ))
+  )
 );
 
 const lazyCustomizableUI = requireLazy(() =>
-  /** @type {import("resource:///modules/CustomizableUI.jsm")} */
-  (ChromeUtils.import("resource:///modules/CustomizableUI.jsm"))
+  ChromeUtils.import("resource:///modules/CustomizableUI.jsm")
 );
 
 /** @type {Presets} */
 const presets = {
   "web-developer": {
     label: "Web Developer",
     description:
       "Recommended preset for most web app debugging, with low overhead.",
--- a/devtools/client/performance-new/popup/menu-button.jsm.js
+++ b/devtools/client/performance-new/popup/menu-button.jsm.js
@@ -32,32 +32,28 @@ function requireLazy(callback) {
     return cache;
   };
 }
 
 // Provide an exports object for the JSM to be properly read by TypeScript.
 /** @type {any} */ (this).exports = {};
 
 const lazyServices = requireLazy(() =>
-  /** @type {import("resource://gre/modules/Services.jsm")} */
-  (ChromeUtils.import("resource://gre/modules/Services.jsm"))
+  ChromeUtils.import("resource://gre/modules/Services.jsm")
 );
 const lazyCustomizableUI = requireLazy(() =>
-  /** @type {import("resource:///modules/CustomizableUI.jsm")} */
-  (ChromeUtils.import("resource:///modules/CustomizableUI.jsm"))
+  ChromeUtils.import("resource:///modules/CustomizableUI.jsm")
 );
 const lazyCustomizableWidgets = requireLazy(() =>
-  /** @type {import("resource:///modules/CustomizableWidgets.jsm")} */
-  (ChromeUtils.import("resource:///modules/CustomizableWidgets.jsm"))
+  ChromeUtils.import("resource:///modules/CustomizableWidgets.jsm")
 );
 const lazyPopupPanel = requireLazy(() =>
-  /** @type {import("devtools/client/performance-new/popup/panel.jsm.js")} */
-  (ChromeUtils.import(
+  ChromeUtils.import(
     "resource://devtools/client/performance-new/popup/panel.jsm.js"
-  ))
+  )
 );
 
 const WIDGET_ID = "profiler-button";
 
 /**
  * Add the profiler button to the navbar.
  *
  * @param {ChromeDocument} document  The browser's document.
--- a/devtools/client/performance-new/popup/panel.jsm.js
+++ b/devtools/client/performance-new/popup/panel.jsm.js
@@ -38,28 +38,25 @@ function requireLazy(callback) {
     return cache;
   };
 }
 
 // Provide an exports object for the JSM to be properly read by TypeScript.
 /** @type {any} */ (this).module = {};
 
 const lazyServices = requireLazy(() =>
-  /** @type {import("resource://gre/modules/Services.jsm")} */
-  (ChromeUtils.import("resource://gre/modules/Services.jsm"))
+  ChromeUtils.import("resource://gre/modules/Services.jsm")
 );
 const lazyPanelMultiView = requireLazy(() =>
-  /** @type {import("resource:///modules/PanelMultiView.jsm")} */
-  (ChromeUtils.import("resource:///modules/PanelMultiView.jsm"))
+  ChromeUtils.import("resource:///modules/PanelMultiView.jsm")
 );
 const lazyBackground = requireLazy(() =>
-  /** @type {import("resource://devtools/client/performance-new/popup/background.jsm.js")} */
-  (ChromeUtils.import(
+  ChromeUtils.import(
     "resource://devtools/client/performance-new/popup/background.jsm.js"
-  ))
+  )
 );
 
 /**
  * This function collects all of the selection of the elements inside of the panel.
  *
  * @param {XULElement} panelview
  */
 function selectElementsInPanelview(panelview) {