Extract Lighthouse ReportRender types into proper exports

These types are used by Closure to typecheck numerous LightHouse integrations,
where the LightHouse bundle puts these classes on the global scope.
To make these typecheckable with TypeScript, move these into
proper exported classes/typedefs.

R=jacktfranklin@chromium.org

Bug: 1011811
Change-Id: Iab9b1e3391ddcfcbafa0ebac23ba81af674d1f75
Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/2509586
Commit-Queue: Tim van der Lippe <tvanderlippe@chromium.org>
Reviewed-by: Jack Franklin <jacktfranklin@chromium.org>
diff --git a/front_end/externs.js b/front_end/externs.js
index 9c0a546..e9b21c5 100644
--- a/front_end/externs.js
+++ b/front_end/externs.js
@@ -894,213 +894,12 @@
  */
 const unescapeCssString = function(input) {};
 
-
-// Lighthouse Report Renderer
-
 /**
  * @constructor
  * @param {!Document} document
  */
 const DOM = function(document) {};
 
-/**
- * @constructor
- * @param {!DOM} dom
- */
-const ReportRenderer = function(dom) {};
-
-ReportRenderer.prototype = {
-  /**
-   * @param {!ReportRenderer.ReportJSON} report
-   * @param {!Element} container Parent element to render the report into.
-   */
-  renderReport: function(report, container) {},
-
-  /**
-   * @param {!Document|!Element} context
-   */
-  setTemplateContext: function(context) {},
-
-};
-
-/**
- * @constructor
- * @param {!DOM} dom
- */
-const ReportUIFeatures = function(dom) {
-  /** @type {!ReportRenderer.ReportJSON} */
-  this.json;
-
-  /** @type {!Document} */
-  this._document;
-};
-
-ReportUIFeatures.prototype = {
-  /**
-   * @param {!Document|!Element} context
-   */
-  setTemplateContext: function(context) {},
-
-  /**
-   * @param {!ReportRenderer.ReportJSON} report
-   */
-  initFeatures: function(report) {},
-
-  _resetUIState: function() {},
-};
-
-/**
- * @typedef {{
- *     rawValue: (number|boolean|undefined),
- *     id: string,
- *     title: string,
- *     description: string,
- *     explanation: (string|undefined),
- *     errorMessage: (string|undefined),
- *     displayValue: (string|Array<string|number>|undefined),
- *     scoreDisplayMode: string,
- *     error: boolean,
- *     score: (number|null),
- *     details: (!DetailsRenderer.DetailsJSON|undefined),
- * }}
- */
-ReportRenderer.AuditResultJSON;
-
-/**
- * @typedef {{
- *     id: string,
- *     score: (number|null),
- *     weight: number,
- *     group: (string|undefined),
- *     result: ReportRenderer.AuditResultJSON
- * }}
- */
-ReportRenderer.AuditJSON;
-
-/**
- * @typedef {{
- *     title: string,
- *     id: string,
- *     score: (number|null),
- *     description: (string|undefined),
- *     manualDescription: string,
- *     auditRefs: !Array<!ReportRenderer.AuditJSON>
- * }}
- */
-ReportRenderer.CategoryJSON;
-
-/**
- * @typedef {{
- *     title: string,
- *     description: (string|undefined),
- * }}
- */
-ReportRenderer.GroupJSON;
-
-/**
- * @typedef {{
- *     lighthouseVersion: string,
- *     userAgent: string,
- *     fetchTime: string,
- *     timing: {total: number},
- *     requestedUrl: string,
- *     finalUrl: string,
- *     runWarnings: (!Array<string>|undefined),
- *     artifacts: {traces: {defaultPass: {traceEvents: !Array}}},
- *     audits: !Object<string, !ReportRenderer.AuditResultJSON>,
- *     categories: !Object<string, !ReportRenderer.CategoryJSON>,
- *     categoryGroups: !Object<string, !ReportRenderer.GroupJSON>,
- * }}
- */
-ReportRenderer.ReportJSON;
-
-/**
- * @typedef {{
- *     traces: {defaultPass: {traceEvents: !Array}},
- * }}
- */
-ReportRenderer.RunnerResultArtifacts;
-
-/**
- * @typedef {{
- *     lhr: !ReportRenderer.ReportJSON,
- *     artifacts: ReportRenderer.RunnerResultArtifacts,
- *     report: string,
- *     stack: string
- * }}
- */
-ReportRenderer.RunnerResult;
-
-
-/**
- * @constructor
- * @param {!DOM} dom
- * @param {!DetailsRenderer} detailsRenderer
- */
-const CategoryRenderer = function(dom, detailsRenderer) {};
-
-
-/**
- * @constructor
- * @param {!DOM} dom
- */
-const DetailsRenderer = function(dom) {};
-
-DetailsRenderer.prototype = {
-  /**
-   * @param {!DetailsRenderer.NodeDetailsJSON} item
-   * @return {!Element}
-   */
-  renderNode: function(item) {},
-};
-
-/**
- * @typedef {{
- *     type: string,
- *     value: (string|number|undefined),
- *     summary: (DetailsRenderer.OpportunitySummary|undefined),
- *     granularity: (number|undefined),
- *     displayUnit: (string|undefined)
- * }}
- */
-DetailsRenderer.DetailsJSON;
-
-/**
- * @typedef {{
- *     type: string,
- *     path: (string|undefined),
- *     selector: (string|undefined),
- *     snippet:(string|undefined)
- * }}
- */
-DetailsRenderer.NodeDetailsJSON;
-
-/**
- * @typedef {{
- *     sourceUrl: (string|undefined),
- *     sourceLine: (string|undefined),
- *     sourceColumn: (string|undefined),
- * }}
- */
-DetailsRenderer.SourceLocationDetailsJSON;
-
-/** @typedef {{
- *     wastedMs: (number|undefined),
- *     wastedBytes: (number|undefined),
- * }}
- */
-DetailsRenderer.OpportunitySummary;
-
-const LighthouseReportGenerator = class {
-  /**
-   * @param {!ReportRenderer.ReportJSON} lhr
-   * @return {string}
-   */
-  generateReportHtml(lhr) {
-    return '';
-  }
-};
-
 /** @interface */
 class InspectorFrontendHostAPI {
   /**
diff --git a/front_end/legacy/legacy-defs.d.ts b/front_end/legacy/legacy-defs.d.ts
index 59e1069..b18038a 100644
--- a/front_end/legacy/legacy-defs.d.ts
+++ b/front_end/legacy/legacy-defs.d.ts
@@ -11,6 +11,10 @@
   UI: {themeSupport: unknown}
 }
 
+declare class DOM {
+  constructor(doc: Document);
+}
+
 interface Array<T> {
   peekLast(): T | undefined;
   intersectOrdered(array: T[], comparator: (a: T, b: T) => number): T[];
diff --git a/front_end/lighthouse/BUILD.gn b/front_end/lighthouse/BUILD.gn
index e0477a0..1832030 100644
--- a/front_end/lighthouse/BUILD.gn
+++ b/front_end/lighthouse/BUILD.gn
@@ -12,6 +12,7 @@
     "LighthouseProtocolService.js",
     "LighthouseReportRenderer.js",
     "LighthouseReportSelector.js",
+    "LighthouseReporterTypes.js",
     "LighthouseStartView.js",
     "LighthouseStatusView.js",
     "RadioSetting.js",
diff --git a/front_end/lighthouse/LighthousePanel.js b/front_end/lighthouse/LighthousePanel.js
index b6d3e33..47d6507 100644
--- a/front_end/lighthouse/LighthousePanel.js
+++ b/front_end/lighthouse/LighthousePanel.js
@@ -14,6 +14,7 @@
 
 import {Events, LighthouseController} from './LighthouseController.js';
 import {ProtocolService} from './LighthouseProtocolService.js';
+import * as ReportRenderer from './LighthouseReporterTypes.js';  // eslint-disable-line no-unused-vars
 import {LighthouseReportRenderer, LighthouseReportUIFeatures} from './LighthouseReportRenderer.js';
 import {Item, ReportSelector} from './LighthouseReportSelector.js';
 import {StartView} from './LighthouseStartView.js';
diff --git a/front_end/lighthouse/LighthouseProtocolService.js b/front_end/lighthouse/LighthouseProtocolService.js
index 6d6b377..a0feca1 100644
--- a/front_end/lighthouse/LighthouseProtocolService.js
+++ b/front_end/lighthouse/LighthouseProtocolService.js
@@ -9,6 +9,8 @@
 import * as ProtocolClient from '../protocol_client/protocol_client.js';  // eslint-disable-line no-unused-vars
 import * as SDK from '../sdk/sdk.js';
 
+import * as ReportRenderer from './LighthouseReporterTypes.js';  // eslint-disable-line no-unused-vars
+
 export class ProtocolService extends Common.ObjectWrapper.ObjectWrapper {
   constructor() {
     super();
diff --git a/front_end/lighthouse/LighthouseReportRenderer.js b/front_end/lighthouse/LighthouseReportRenderer.js
index 62a53a7..e90f956 100644
--- a/front_end/lighthouse/LighthouseReportRenderer.js
+++ b/front_end/lighthouse/LighthouseReportRenderer.js
@@ -16,12 +16,14 @@
 import * as UI from '../ui/ui.js';
 import * as Workspace from '../workspace/workspace.js';
 
+import * as ReportRenderer from './LighthouseReporterTypes.js';  // eslint-disable-line no-unused-vars
+
 const MaxLengthForLinks = 40;
 
 /**
  * @override
  */
-export class LighthouseReportRenderer extends ReportRenderer {
+export class LighthouseReportRenderer extends self.ReportRenderer {
   /**
    * @param {!Element} el Parent element to render the report into.
    * @param {!ReportRenderer.RunnerResultArtifacts=} artifacts
@@ -63,7 +65,7 @@
     const domModel = mainTarget.model(SDK.DOMModel.DOMModel);
 
     for (const origElement of el.getElementsByClassName('lh-node')) {
-      /** @type {!DetailsRenderer.NodeDetailsJSON} */
+      /** @type {!ReportRenderer.NodeDetailsJSON} */
       const detailsItem = origElement.dataset;
       if (!detailsItem.path) {
         continue;
@@ -91,7 +93,7 @@
    */
   static async linkifySourceLocationDetails(el) {
     for (const origElement of el.getElementsByClassName('lh-source-location')) {
-      /** @type {!DetailsRenderer.SourceLocationDetailsJSON} */
+      /** @type {!ReportRenderer.SourceLocationDetailsJSON} */
       const detailsItem = origElement.dataset;
       if (!detailsItem.sourceUrl || !detailsItem.sourceLine || !detailsItem.sourceColumn) {
         continue;
@@ -120,7 +122,7 @@
 /**
  * @override
  */
-export class LighthouseReportUIFeatures extends ReportUIFeatures {
+export class LighthouseReportUIFeatures extends self.ReportUIFeatures {
   /**
    * @param {!DOM} dom
    */
diff --git a/front_end/lighthouse/LighthouseReportSelector.js b/front_end/lighthouse/LighthouseReportSelector.js
index 6b688f5..20dd074 100644
--- a/front_end/lighthouse/LighthouseReportSelector.js
+++ b/front_end/lighthouse/LighthouseReportSelector.js
@@ -8,6 +8,8 @@
 import * as Common from '../common/common.js';
 import * as UI from '../ui/ui.js';
 
+import * as ReportRenderer from './LighthouseReporterTypes.js';  // eslint-disable-line no-unused-vars
+
 export class ReportSelector {
   constructor(renderNewLighthouseView) {
     this._renderNewLighthouseView = renderNewLighthouseView;
diff --git a/front_end/lighthouse/LighthouseReporterTypes.js b/front_end/lighthouse/LighthouseReporterTypes.js
new file mode 100644
index 0000000..af4d11b
--- /dev/null
+++ b/front_end/lighthouse/LighthouseReporterTypes.js
@@ -0,0 +1,226 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+export class ReportRenderer {
+  /**
+   * @param {!DOM} dom
+   */
+  constructor(dom) {
+  }
+
+  /**
+   * @param {!ReportJSON} report
+   * @param {!Element} container Parent element to render the report into.
+   * @return {!Element}
+   */
+  renderReport(report, container) {
+    throw new Error('Not implemented yet!');
+  }
+
+  /**
+   * @param {!Document|!Element} context
+   */
+  setTemplateContext(context) {
+  }
+}
+
+/** @type {function(new:ReportRenderer, !DOM)} */
+// @ts-ignore
+self.ReportRenderer;
+
+export class ReportUIFeatures {
+  /**
+   * @param {!DOM} dom
+   */
+  constructor(dom) {
+    /** @type {!ReportJSON} */
+    this.json;
+    /** @type {!Document} */
+    this._document;
+  }
+
+  /**
+   * @param {!Document|!Element} context
+   */
+  setTemplateContext(context) {
+  }
+
+  /**
+   * @param {!ReportJSON} report
+   */
+  initFeatures(report) {
+  }
+
+  _resetUIState() {
+  }
+}
+
+/** @type {function(new:ReportUIFeatures)} */
+// @ts-ignore
+self.ReportUIFeatures;
+
+export class CategoryRenderer {
+  /**
+   * @param {!DOM} dom
+   * @param {!DetailsRenderer} detailsRenderer
+   */
+  constructor(dom, detailsRenderer) {
+  }
+}
+
+export class DetailsRenderer {
+  /**
+   * @param {!DOM} dom
+   */
+  constructor(dom) {
+  }
+
+  /**
+   * @param {!NodeDetailsJSON} item
+   * @return {!Element}
+   */
+  renderNode(item) {
+    throw new Error('Not implemented yet!');
+  }
+}
+
+export class LighthouseReportGenerator {
+  /**
+   * @param {!ReportJSON} lhr
+   * @return {string}
+   */
+  generateReportHtml(lhr) {
+    return '';
+  }
+}
+
+/**
+ * @typedef {{
+ *     rawValue: (number|boolean|undefined),
+ *     id: string,
+ *     title: string,
+ *     description: string,
+ *     explanation: (string|undefined),
+ *     errorMessage: (string|undefined),
+ *     displayValue: (string|Array<string|number>|undefined),
+ *     scoreDisplayMode: string,
+ *     error: boolean,
+ *     score: (number|null),
+ *     details: (!DetailsJSON|undefined),
+ * }}
+ */
+// @ts-ignore typedef
+export let AuditResultJSON;
+
+/**
+ * @typedef {{
+ *     id: string,
+ *     score: (number|null),
+ *     weight: number,
+ *     group: (string|undefined),
+ *     result: !AuditResultJSON
+ * }}
+ */
+// @ts-ignore typedef
+export let AuditJSON;
+
+/**
+ * @typedef {{
+ *     title: string,
+ *     id: string,
+ *     score: (number|null),
+ *     description: (string|undefined),
+ *     manualDescription: string,
+ *     auditRefs: !Array<!AuditJSON>
+ * }}
+ */
+// @ts-ignore typedef
+export let CategoryJSON;
+
+/**
+ * @typedef {{
+ *     title: string,
+ *     description: (string|undefined),
+ * }}
+ */
+// @ts-ignore typedef
+export let GroupJSON;
+
+/**
+ * @typedef {{
+ *     lighthouseVersion: string,
+ *     userAgent: string,
+ *     fetchTime: string,
+ *     timing: {total: number},
+ *     requestedUrl: string,
+ *     finalUrl: string,
+ *     runWarnings: (!Array<string>|undefined),
+ *     artifacts: {traces: {defaultPass: {traceEvents: !Array<?>}}},
+ *     audits: !Object<string, !AuditResultJSON>,
+ *     categories: !Object<string, !CategoryJSON>,
+ *     categoryGroups: !Object<string, !GroupJSON>,
+ * }}
+ */
+// @ts-ignore typedef
+export let ReportJSON;
+
+/**
+ * @typedef {{
+ *     type: string,
+ *     value: (string|number|undefined),
+ *     summary: (!OpportunitySummary|undefined),
+ *     granularity: (number|undefined),
+ *     displayUnit: (string|undefined)
+ * }}
+ */
+// @ts-ignore typedef
+export let DetailsJSON;
+
+/**
+ * @typedef {{
+ *     traces: {defaultPass: {traceEvents: !Array<?>}},
+ * }}
+ */
+// @ts-ignore typedef
+export let RunnerResultArtifacts;
+
+/**
+ * @typedef {{
+ *     lhr: !ReportJSON,
+ *     artifacts: RunnerResultArtifacts,
+ *     report: string,
+ *     stack: string
+ * }}
+ */
+// @ts-ignore typedef
+export let RunnerResult;
+
+/**
+ * @typedef {{
+ *     type: string,
+ *     path: (string|undefined),
+ *     selector: (string|undefined),
+ *     snippet:(string|undefined)
+ * }}
+ */
+// @ts-ignore typedef
+export let NodeDetailsJSON;
+
+/**
+ * @typedef {{
+ *     sourceUrl: (string|undefined),
+ *     sourceLine: (string|undefined),
+ *     sourceColumn: (string|undefined),
+ * }}
+ */
+// @ts-ignore typedef
+export let SourceLocationDetailsJSON;
+
+/** @typedef {{
+ *     wastedMs: (number|undefined),
+ *     wastedBytes: (number|undefined),
+ * }}
+*/
+// @ts-ignore typedef
+export let OpportunitySummary;
diff --git a/front_end/lighthouse/lighthouse-legacy.js b/front_end/lighthouse/lighthouse-legacy.js
index ff1dafd..8f9359f 100644
--- a/front_end/lighthouse/lighthouse-legacy.js
+++ b/front_end/lighthouse/lighthouse-legacy.js
@@ -9,7 +9,7 @@
 self.Lighthouse = self.Lighthouse || {};
 Lighthouse = Lighthouse || {};
 
-/** @type {!LighthouseReportGenerator} */
+/** @type {!LighthouseModule.LighthouseReporterTypes.LighthouseReportGenerator} */
 Lighthouse.ReportGenerator;
 
 /**
diff --git a/front_end/lighthouse/lighthouse.js b/front_end/lighthouse/lighthouse.js
index 862c1a9..03e4abb 100644
--- a/front_end/lighthouse/lighthouse.js
+++ b/front_end/lighthouse/lighthouse.js
@@ -8,6 +8,7 @@
 import * as LighthouseController from './LighthouseController.js';
 import * as LighthousePanel from './LighthousePanel.js';
 import * as LighthouseProtocolService from './LighthouseProtocolService.js';
+import * as LighthouseReporterTypes from './LighthouseReporterTypes.js';
 import * as LighthouseReportRenderer from './LighthouseReportRenderer.js';
 import * as LighthouseReportSelector from './LighthouseReportSelector.js';
 import * as LighthouseStartView from './LighthouseStartView.js';
@@ -18,6 +19,7 @@
   LighthouseController,
   LighthousePanel,
   LighthouseProtocolService,
+  LighthouseReporterTypes,
   LighthouseReportRenderer,
   LighthouseReportSelector,
   LighthouseStartView,
diff --git a/front_end/lighthouse/module.json b/front_end/lighthouse/module.json
index fcc9f2c..91f420a 100644
--- a/front_end/lighthouse/module.json
+++ b/front_end/lighthouse/module.json
@@ -32,7 +32,8 @@
     "LighthouseReportRenderer.js",
     "LighthouseStartView.js",
     "LighthouseStatusView.js",
-    "LighthouseProtocolService.js"
+    "LighthouseProtocolService.js",
+    "LighthouseReporterTypes.js"
   ],
   "resources": [
     "../third_party/lighthouse/report-assets/template.html",