Bug 1607801 - Upgrade TypeScript to v3.8.3; r=julienw
authorGreg Tatum <gtatum@mozilla.com>
Tue, 28 Apr 2020 17:48:53 +0000
changeset 526536 79e01e02fa5ebaa2bd4cf7c98043fdf687651555
parent 526535 20630fb87f8254888ad16a1a176749edde388729
child 526537 8dfe8cb5a8311dc6062c8d9a421dbbf65bc5050e
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 - Upgrade TypeScript to v3.8.3; r=julienw Differential Revision: https://phabricator.services.mozilla.com/D70439
devtools/client/performance-new/@types/gecko.d.ts
devtools/client/performance-new/@types/perf.d.ts
devtools/client/performance-new/browser.js
devtools/client/performance-new/components/RecordingButton.js
devtools/client/performance-new/frame-script.js
devtools/client/performance-new/initializer.js
devtools/client/performance-new/package.json
devtools/client/performance-new/popup/menu-button.jsm.js
devtools/client/performance-new/store/actions.js
devtools/client/performance-new/store/selectors.js
devtools/client/performance-new/yarn.lock
--- a/devtools/client/performance-new/@types/gecko.d.ts
+++ b/devtools/client/performance-new/@types/gecko.d.ts
@@ -43,16 +43,17 @@ declare namespace MockedExports {
   }
 
   interface BrowserTab {
     linkedBrowser: Browser;
   }
 
   interface ChromeWindow {
     gBrowser: Browser;
+    focus: () => void;
   }
 
   interface ChromeBrowser {
     browsingContext?: BrowsingContext;
   }
 
   interface BrowsingContext {
     id: number;
--- a/devtools/client/performance-new/@types/perf.d.ts
+++ b/devtools/client/performance-new/@types/perf.d.ts
@@ -145,27 +145,32 @@ export interface Library {
   name: string;
   path: string;
   debugName: string;
   debugPath: string;
   breakpadId: string;
   arch: string;
 }
 
-export interface GeckoProfile {
-  // Only type properties that we rely on.
+/**
+ * Only provide types for the GeckoProfile as much as we need it. There is no
+ * reason to maintain a full type definition here.
+ */
+export interface MinimallyTypedGeckoProfile {
+  libs: Array<{ debugName: string, breakpadId: string }>;
+  processes: Array<MinimallyTypedGeckoProfile>;
 }
 
 export type GetSymbolTableCallback = (
   debugName: string,
   breakpadId: string
 ) => Promise<SymbolTableAsTuple>;
 
 export type ReceiveProfile = (
-  geckoProfile: GeckoProfile,
+  geckoProfile: MinimallyTypedGeckoProfile,
   getSymbolTableCallback: GetSymbolTableCallback
 ) => void;
 
 export type SetRecordingPreferences = (settings: RecordingStateFromPreferences) => void;
 
 /**
  * This is the type signature for a function to restart the browser with a given
  * environment variable. Currently only implemented for the popup.
@@ -184,17 +189,17 @@ export type GetEnvironmentVariable = (en
  * ID of BrowsingContext of active tab.
  */
 export type GetActiveBrowsingContextID = () => number;
 
 /**
  * This interface is injected into profiler.firefox.com
  */
 interface GeckoProfilerFrameScriptInterface {
-  getProfile: () => Promise<object>;
+  getProfile: () => Promise<MinimallyTypedGeckoProfile>;
   getSymbolTable: GetSymbolTableCallback;
 }
 
 export interface RecordingStateFromPreferences {
   presetName: string;
   entries: number;
   interval: number;
   features: string[];
@@ -216,17 +221,17 @@ export interface InitializedValues {
   receiveProfile: ReceiveProfile;
   // A function to set the recording settings.
   setRecordingPreferences: SetRecordingPreferences;
   // The current list of presets, loaded in from a JSM.
   presets: Presets;
   // Determine the current page context.
   pageContext: PageContext;
   // The popup and devtools panel use different codepaths for getting symbol tables.
-  getSymbolTableGetter: (profile: object) => GetSymbolTableCallback;
+  getSymbolTableGetter: (profile: MinimallyTypedGeckoProfile) => GetSymbolTableCallback;
   // The list of profiler features that the current target supports. Note that
   // this value is only null to support older Firefox browsers that are targeted
   // by the actor system. This compatibility can be required when the ESR version
   // is running at least Firefox 72.
   supportedFeatures: string[] | null
   // Allow different devtools contexts to open about:profiling with different methods.
   // e.g. via a new tab, or page navigation.
   openAboutProfiling?: () => void,
@@ -277,34 +282,34 @@ export type Action =
       perfFront: PerfFront;
       receiveProfile: ReceiveProfile;
       setRecordingPreferences: SetRecordingPreferences;
       presets: Presets;
       pageContext: PageContext;
       openAboutProfiling?: () => void,
       openRemoteDevTools?: () => void,
       recordingSettingsFromPreferences: RecordingStateFromPreferences;
-      getSymbolTableGetter: (profile: object) => GetSymbolTableCallback;
+      getSymbolTableGetter: (profile: MinimallyTypedGeckoProfile) => GetSymbolTableCallback;
       supportedFeatures: string[] | null;
     }
   | {
       type: "CHANGE_PRESET";
       presetName: string;
       preset: PresetDefinition | undefined;
     };
 
 export interface InitializeStoreValues {
   perfFront: PerfFront;
   receiveProfile: ReceiveProfile;
   setRecordingPreferences: SetRecordingPreferences;
   presets: Presets;
   pageContext: PageContext;
   recordingPreferences: RecordingStateFromPreferences;
   supportedFeatures: string[] | null;
-  getSymbolTableGetter: (profile: object) => GetSymbolTableCallback;
+  getSymbolTableGetter: (profile: MinimallyTypedGeckoProfile) => GetSymbolTableCallback;
   openAboutProfiling?: () => void;
   openRemoteDevTools?: () => void;
 }
 
 export type PopupBackgroundFeatures = { [feature: string]: boolean };
 
 /**
  * The state of the profiler popup.
--- a/devtools/client/performance-new/browser.js
+++ b/devtools/client/performance-new/browser.js
@@ -12,16 +12,17 @@
  * @typedef {import("./@types/perf").RecordingState} RecordingState
  * @typedef {import("./@types/perf").GetSymbolTableCallback} GetSymbolTableCallback
  * @typedef {import("./@types/perf").PreferenceFront} PreferenceFront
  * @typedef {import("./@types/perf").PerformancePref} PerformancePref
  * @typedef {import("./@types/perf").RecordingStateFromPreferences} RecordingStateFromPreferences
  * @typedef {import("./@types/perf").RestartBrowserWithEnvironmentVariable} RestartBrowserWithEnvironmentVariable
  * @typedef {import("./@types/perf").GetEnvironmentVariable} GetEnvironmentVariable
  * @typedef {import("./@types/perf").GetActiveBrowsingContextID} GetActiveBrowsingContextID
+ * @typedef {import("./@types/perf").MinimallyTypedGeckoProfile} MinimallyTypedGeckoProfile
  */
 
 /**
  * TS-TODO
  *
  * This function replaces lazyRequireGetter, and TypeScript can understand it. It's
  * currently duplicated until we have consensus that TypeScript is a good idea.
  *
@@ -70,17 +71,17 @@ const UI_BASE_URL_PATH_DEFAULT = "/from-
  * worrying about polluting the browser environment.
  */
 
 /**
  * Once a profile is received from the actor, it needs to be opened up in
  * profiler.firefox.com to be analyzed. This function opens up profiler.firefox.com
  * into a new browser tab, and injects the profile via a frame script.
  *
- * @param {object} profile - The Gecko profile.
+ * @param {MinimallyTypedGeckoProfile} profile - The Gecko profile.
  * @param {GetSymbolTableCallback} getSymbolTableCallback - A callback function with the signature
  *   (debugName, breakpadId) => Promise<SymbolTableAsTuple>, which will be invoked
  *   when profiler.firefox.com sends SYMBOL_TABLE_REQUEST_EVENT messages to us. This
  *   function should obtain a symbol table for the requested binary and resolve the
  *   returned promise with it.
  */
 function receiveProfile(profile, getSymbolTableCallback) {
   const { Services } = lazyServices();
@@ -163,24 +164,24 @@ function receiveProfile(profile, getSymb
  *    absolute paths.
  *  - We get the "trusted" paths from the "libs" sections of the profile. We
  *    trust these paths because we just obtained the profile directly from
  *    Gecko.
  *  - This function builds the (debugName, breakpadId) => Library mapping and
  *    retains it on the returned closure so that it can be consulted after the
  *    profile has been passed to the UI.
  *
- * @param {object} profile - The profile JSON object
+ * @param {MinimallyTypedGeckoProfile} profile - The profile JSON object
  * @returns {(debugName: string, breakpadId: string) => Library | undefined}
  */
 function createLibraryMap(profile) {
   const map = new Map();
 
   /**
-   * @param {object} processProfile
+   * @param {MinimallyTypedGeckoProfile} processProfile
    */
   function fillMapForProcessRecursive(processProfile) {
     for (const lib of processProfile.libs) {
       const { debugName, breakpadId } = lib;
       const key = [debugName, breakpadId].join(":");
       map.set(key, lib);
     }
     for (const subprocess of processProfile.processes) {
@@ -288,17 +289,17 @@ async function getSymbolTableFromLocalBi
  *
  *   1) Profiling the same browser on the same machine.
  *   2) Profiling a remote browser on the same machine.
  *   3) Profiling a remote browser on a different device.
  *
  * The profiler popup uses a more simplified version of this function as
  * it's dealing with a simpler situation.
  *
- * @param {object} profile - The raw profie (not gzipped).
+ * @param {MinimallyTypedGeckoProfile} profile - The raw profie (not gzipped).
  * @param {() => string[]} getObjdirs - A function that returns an array of objdir paths
  *   on the host machine that should be searched for relevant build artifacts.
  * @param {PerfFront} perfFront
  * @return {GetSymbolTableCallback}
  */
 function createMultiModalGetSymbolTableFn(profile, getObjdirs, perfFront) {
   const libraryGetter = createLibraryMap(profile);
 
--- a/devtools/client/performance-new/components/RecordingButton.js
+++ b/devtools/client/performance-new/components/RecordingButton.js
@@ -48,30 +48,24 @@ const selectors = require("devtools/clie
 /**
  * This component is not responsible for the full life cycle of recording a profile. It
  * is only responsible for the actual act of stopping and starting recordings. It
  * also reacts to the changes of the recording state from external changes.
  *
  * @extends {React.PureComponent<Props>}
  */
 class RecordingButton extends PureComponent {
-  /** @param {Props} props */
-  constructor(props) {
-    super(props);
-    this._getProfileAndStopProfiler = () =>
-      this.props.getProfileAndStopProfiler(window);
-  }
-
   render() {
     const {
       startRecording,
       stopProfilerAndDiscardProfile,
       recordingState,
       isSupportedPlatform,
       recordingUnexpectedlyStopped,
+      getProfileAndStopProfiler,
     } = this.props;
 
     if (!isSupportedPlatform) {
       return renderButton({
         label: startRecordingLabel(),
         isPrimary: true,
         disabled: true,
         additionalMessage:
@@ -116,17 +110,17 @@ class RecordingButton extends PureCompon
             img({
               className: "perf-button-image",
               alt: "",
               /* This icon is actually the "open in new page" icon. */
               src: "chrome://devtools/skin/images/dock-undock.svg",
             })
           ),
           isPrimary: true,
-          onClick: this._getProfileAndStopProfiler,
+          onClick: getProfileAndStopProfiler,
           disabled: recordingState === "request-to-start-recording",
           additionalButton: {
             label: "Cancel recording",
             onClick: stopProfilerAndDiscardProfile,
           },
         });
 
       case "locked-by-private-browsing":
--- a/devtools/client/performance-new/frame-script.js
+++ b/devtools/client/performance-new/frame-script.js
@@ -4,28 +4,29 @@
 // @ts-check
 /// <reference path="./@types/frame-script.d.ts" />
 /* global content */
 "use strict";
 
 /**
  * @typedef {import("./@types/perf").GetSymbolTableCallback} GetSymbolTableCallback
  * @typedef {import("./@types/perf").ContentFrameMessageManager} ContentFrameMessageManager
+ * @typedef {import("./@types/perf").MinimallyTypedGeckoProfile} MinimallyTypedGeckoProfile
  */
 
 /**
  * This frame script injects itself into profiler.firefox.com and injects the profile
  * into the page. It is mostly taken from the Gecko Profiler Addon implementation.
  */
 
 const TRANSFER_EVENT = "devtools:perf-html-transfer-profile";
 const SYMBOL_TABLE_REQUEST_EVENT = "devtools:perf-html-request-symbol-table";
 const SYMBOL_TABLE_RESPONSE_EVENT = "devtools:perf-html-reply-symbol-table";
 
-/** @type {null | Object} */
+/** @type {null | MinimallyTypedGeckoProfile} */
 let gProfile = null;
 const symbolReplyPromiseMap = new Map();
 
 /**
  * TypeScript wants to use the DOM library definition, which conflicts with our
  * own definitions for the frame message manager. Instead, coerce the `this`
  * variable into the proper interface.
  *
@@ -61,17 +62,22 @@ frameScript.addMessageListener(SYMBOL_TA
 });
 
 function connectToPage() {
   const unsafeWindow = content.wrappedJSObject;
   if (unsafeWindow.connectToGeckoProfiler) {
     unsafeWindow.connectToGeckoProfiler(
       makeAccessibleToPage(
         {
-          getProfile: () => Promise.resolve(gProfile),
+          getProfile: () =>
+            gProfile
+              ? Promise.resolve(gProfile)
+              : Promise.reject(
+                  new Error("No profile was available to inject into the page.")
+                ),
           getSymbolTable: (debugName, breakpadId) =>
             getSymbolTable(debugName, breakpadId),
         },
         unsafeWindow
       )
     );
   }
 }
@@ -95,17 +101,17 @@ function getSymbolTable(debugName, break
 // compatibility with the existing profile importing mechanism:
 // See: https://github.com/firefox-devtools/Gecko-Profiler-Addon/blob/78138190b42565f54ce4022a5b28583406489ed2/data/tab-framescript.js
 
 /**
  * Create a promise that can be used in the page.
  *
  * @template T
  * @param {(resolve: Function, reject: Function) => Promise<T>} fun
- * @param {object} contentGlobal
+ * @param {any} contentGlobal
  * @returns Promise<T>
  */
 function createPromiseInPage(fun, contentGlobal) {
   /**
    * Use the any type here, as this is pretty dynamic, and probably not worth typing.
    * @param {any} resolve
    * @param {any} reject
    */
@@ -136,17 +142,17 @@ function createPromiseInPage(fun, conten
     Cu.exportFunction(funThatClonesObjects, contentGlobal)
   );
 }
 
 /**
  * Returns a function that calls the original function and tries to make the
  * return value available to the page.
  * @param {Function} fun
- * @param {object} contentGlobal
+ * @param {any} contentGlobal
  * @return {Function}
  */
 function wrapFunction(fun, contentGlobal) {
   return function() {
     // @ts-ignore - Ignore the use of `this`.
     const result = fun.apply(this, arguments);
     if (typeof result === "object") {
       if ("then" in result && typeof result.then === "function") {
@@ -163,17 +169,17 @@ function wrapFunction(fun, contentGlobal
 }
 
 /**
  * Pass a simple object containing values that are objects or functions.
  * The objects or functions are wrapped in such a way that they can be
  * consumed by the page.
  * @template T
  * @param {T} obj
- * @param {object} contentGlobal
+ * @param {any} contentGlobal
  * @return {T}
  */
 function makeAccessibleToPage(obj, contentGlobal) {
   /** @type {any} - This value is probably too dynamic to type. */
   const result = Cu.createObjectIn(contentGlobal);
   for (const field in obj) {
     switch (typeof obj[field]) {
       case "function":
--- a/devtools/client/performance-new/initializer.js
+++ b/devtools/client/performance-new/initializer.js
@@ -6,16 +6,17 @@
 
 /**
  * @typedef {import("./@types/perf").PerfFront} PerfFront
  * @typedef {import("./@types/perf").PreferenceFront} PreferenceFront
  * @typedef {import("./@types/perf").RecordingStateFromPreferences} RecordingStateFromPreferences
  * @typedef {import("./@types/perf").PageContext} PageContext
  * @typedef {import("./@types/perf").PanelWindow} PanelWindow
  * @typedef {import("./@types/perf").Store} Store
+ * @typedef {import("./@types/perf").MinimallyTypedGeckoProfile} MinimallyTypedGeckoProfile
  */
 "use strict";
 
 {
   // Create the browser loader, but take care not to conflict with
   // TypeScript. See devtools/client/performance-new/typescript.md and
   // the section on "Do not overload require" for more information.
 
@@ -117,17 +118,17 @@ async function gInit(perfFront, pageCont
        * @param {RecordingStateFromPreferences} newRecordingPreferences
        */
       setRecordingPreferences: newRecordingPreferences =>
         setRecordingPreferences(pageContext, newRecordingPreferences),
 
       // Configure the getSymbolTable function for the DevTools workflow.
       // See createMultiModalGetSymbolTableFn for more information.
       getSymbolTableGetter:
-        /** @type {(profile: Object) => GetSymbolTableCallback} */
+        /** @type {(profile: MinimallyTypedGeckoProfile) => GetSymbolTableCallback} */
         profile =>
           createMultiModalGetSymbolTableFn(
             profile,
             () => selectors.getObjdirs(store.getState()),
             selectors.getPerfFront(store.getState())
           ),
     })
   );
--- a/devtools/client/performance-new/package.json
+++ b/devtools/client/performance-new/package.json
@@ -6,11 +6,11 @@
     "test-ci": "tsc"
   },
   "license": "MPL-2.0",
   "devDependencies": {
     "@types/react": "^16.9.10",
     "@types/react-dom-factories": "^1.0.2",
     "@types/react-redux": "^7.1.5",
     "@types/redux": "^3.6.0",
-    "typescript": "^3.6.3"
+    "typescript": "^3.8.3"
   }
 }
--- a/devtools/client/performance-new/popup/menu-button.jsm.js
+++ b/devtools/client/performance-new/popup/menu-button.jsm.js
@@ -243,17 +243,23 @@ function initialize(toggleProfilerKeySho
 
     /**
      * This method is used when we need to operate upon the button element itself.
      * This is called once per browser window.
      *
      * @type {(buttonElement: HTMLElement) => void}
      */
     onCreated: buttonElement => {
-      const window = buttonElement.ownerDocument.defaultView;
+      const window = buttonElement?.ownerDocument?.defaultView;
+      if (!window) {
+        console.error(
+          "Unable to find the window of the profiler button element."
+        );
+        return;
+      }
 
       function updateButtonColor() {
         // Use photon blue-60 when active.
         buttonElement.style.fill = Services.profiler.IsActive()
           ? "#0060df"
           : "";
       }
 
--- a/devtools/client/performance-new/store/actions.js
+++ b/devtools/client/performance-new/store/actions.js
@@ -98,17 +98,17 @@ exports.changeInterval = interval =>
 exports.changeEntries = entries =>
   _dispatchAndUpdatePreferences({
     type: "CHANGE_ENTRIES",
     entries,
   });
 
 /**
  * Updates the recording settings for the features.
- * @param {object} features
+ * @param {string[]} features
  * @return {ThunkAction<void>}
  */
 exports.changeFeatures = features => {
   return (dispatch, getState) => {
     let promptEnvRestart = null;
     if (selectors.getPageContext(getState()) === "aboutprofiling") {
       // TODO Bug 1615431 - The popup supported restarting the browser, but
       // this hasn't been updated yet for the about:profiling workflow.
@@ -197,30 +197,24 @@ exports.startRecording = () => {
     // make sure and change the recording state first, then start the profiler.
     dispatch(changeRecordingState("request-to-start-recording"));
     perfFront.startProfiler(recordingSettings);
   };
 };
 
 /**
  * Stops the profiler, and opens the profile in a new window.
- * @param {object} window - The current window for the page.
  * @return {ThunkAction<void>}
  */
-exports.getProfileAndStopProfiler = window => {
+exports.getProfileAndStopProfiler = () => {
   return async (dispatch, getState) => {
     const perfFront = selectors.getPerfFront(getState());
     dispatch(changeRecordingState("request-to-get-profile-and-stop-profiler"));
     const profile = await perfFront.getProfileAndStopProfiler();
 
-    if (window.gClosePopup) {
-      // The close popup function only exists when we are in the popup.
-      window.gClosePopup();
-    }
-
     const getSymbolTable = selectors.getSymbolTableGetter(getState())(profile);
     const receiveProfile = selectors.getReceiveProfileFn(getState());
     receiveProfile(profile, getSymbolTable);
     dispatch(changeRecordingState("available-to-record"));
   };
 };
 
 /**
--- a/devtools/client/performance-new/store/selectors.js
+++ b/devtools/client/performance-new/store/selectors.js
@@ -132,17 +132,17 @@ const getReceiveProfileFn = state => get
 
 /** @type {Selector<SetRecordingPreferences>} */
 const getSetRecordingPreferencesFn = state =>
   getInitializedValues(state).setRecordingPreferences;
 
 /** @type {Selector<PageContext>} */
 const getPageContext = state => getInitializedValues(state).pageContext;
 
-/** @type {Selector<(profile: Object) => GetSymbolTableCallback>} */
+/** @type {Selector<(profile: MinimallyTypedGeckoProfile) => GetSymbolTableCallback>} */
 const getSymbolTableGetter = state =>
   getInitializedValues(state).getSymbolTableGetter;
 
 /** @type {Selector<string[] | null>} */
 const getSupportedFeatures = state =>
   getInitializedValues(state).supportedFeatures;
 
 /** @type {Selector<string | null>} */
--- a/devtools/client/performance-new/yarn.lock
+++ b/devtools/client/performance-new/yarn.lock
@@ -84,12 +84,12 @@ redux@*, redux@^4.0.0:
     loose-envify "^1.4.0"
     symbol-observable "^1.2.0"
 
 symbol-observable@^1.2.0:
   version "1.2.0"
   resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804"
   integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==
 
-typescript@^3.6.3:
-  version "3.6.3"
-  resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.6.3.tgz#fea942fabb20f7e1ca7164ff626f1a9f3f70b4da"
-  integrity sha512-N7bceJL1CtRQ2RiG0AQME13ksR7DiuQh/QehubYcghzv20tnh+MQnQIuJddTmsbqYj+dztchykemz0zFzlvdQw==
+typescript@^3.8.3:
+  version "3.8.3"
+  resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.8.3.tgz#409eb8544ea0335711205869ec458ab109ee1061"
+  integrity sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w==