Merge inbound to mozilla-central. a=merge
authorOana Pop Rus <opoprus@mozilla.com>
Thu, 07 Feb 2019 11:47:46 +0200
changeset 457544 00432a450b3af67c4d5711810691b27093880c62
parent 457537 9f0d85143372f3c9aac39ba48b7e39866c040ae2 (current diff)
parent 457543 abd40252d1aeb1878fcc3f7dc3f5e11f5a77dff6 (diff)
child 457550 05869b5a4dc3fb9904983549a978c4199a3f64a6
child 457588 29e9a6507e6466ec0c2dbd813d172908d80116c0
push id35514
push useropoprus@mozilla.com
push dateThu, 07 Feb 2019 09:48:41 +0000
treeherdermozilla-central@00432a450b3a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone67.0a1
first release with
nightly linux32
00432a450b3a / 67.0a1 / 20190207094841 / files
nightly linux64
00432a450b3a / 67.0a1 / 20190207094841 / files
nightly mac
00432a450b3a / 67.0a1 / 20190207094841 / files
nightly win32
00432a450b3a / 67.0a1 / 20190207094841 / files
nightly win64
00432a450b3a / 67.0a1 / 20190207094841 / files
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Merge inbound to mozilla-central. a=merge
devtools/client/debugger/new/images/toggle-panes.svg
toolkit/mozapps/extensions/internal/RDFDataSource.jsm
toolkit/mozapps/extensions/internal/RDFManifestConverter.jsm
toolkit/mozapps/extensions/test/xpcshell/data/test_bug542391.rdf
toolkit/mozapps/extensions/test/xpcshell/data/test_install.rdf
toolkit/mozapps/extensions/test/xpcshell/data/test_temporary/bootstrap.js
toolkit/mozapps/extensions/test/xpcshell/data/test_update.rdf
toolkit/mozapps/extensions/test/xpcshell/data/test_update_rdf.json
toolkit/mozapps/extensions/test/xpcshell/data/test_updatecheck.rdf
toolkit/mozapps/extensions/test/xpcshell/data/test_updatecheck_rdf.json
toolkit/mozapps/extensions/test/xpcshell/data/test_updateid.rdf
toolkit/mozapps/extensions/test/xpcshell/test_update_rdf.js
--- a/browser/components/resistfingerprinting/test/browser/browser_navigator.js
+++ b/browser/components/resistfingerprinting/test/browser/browser_navigator.js
@@ -134,17 +134,17 @@ async function testWorkerNavigator() {
 }
 
 add_task(async function setup() {
   await SpecialPowers.pushPrefEnv({"set":
     [["privacy.resistFingerprinting", true]],
   });
 
   let appVersion = parseInt(Services.appinfo.version);
-  let spoofedVersion = appVersion - ((appVersion - 4) % 7);
+  let spoofedVersion = appVersion - ((appVersion - 4) % 8);
   spoofedUserAgentNavigator = `Mozilla/5.0 (${SPOOFED_UA_NAVIGATOR_OS[AppConstants.platform]}; rv:${spoofedVersion}.0) Gecko/20100101 Firefox/${spoofedVersion}.0`;
   spoofedUserAgentHeader = `Mozilla/5.0 (${SPOOFED_UA_HTTPHEADER_OS[AppConstants.platform]}; rv:${spoofedVersion}.0) Gecko/20100101 Firefox/${spoofedVersion}.0`;
 });
 
 add_task(async function runNavigatorTest() {
   await testNavigator();
 });
 
--- a/devtools/client/debugger/new/README.mozilla
+++ b/devtools/client/debugger/new/README.mozilla
@@ -1,13 +1,13 @@
 This is the debugger.html project output.
 See https://github.com/devtools-html/debugger.html
 
-Version 122
+Version 123
 
-Comparison: https://github.com/devtools-html/debugger.html/compare/release-121...release-122
+Comparison: https://github.com/devtools-html/debugger.html/compare/release-122...release-123
 
 Packages:
 - babel-plugin-transform-es2015-modules-commonjs @6.26.2
 - babel-preset-react @6.24.1
 - react @16.4.1
 - react-dom @16.4.1
 - webpack @3.12.0
--- a/devtools/client/debugger/new/dist/debugger.css
+++ b/devtools/client/debugger/new/dist/debugger.css
@@ -543,16 +543,25 @@ html[dir="rtl"] .tree-node button.arrow 
   .shortcuts-section {
     width: 100%;
   }
 }
 /* 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/>. */
 
+:root {
+  /* header height is 28px + 1px for its border */
+  --editor-header-height: 29px;
+  /* footer height is 24px + 1px for its border */
+  --editor-footer-height: 25px;
+  /* searchbar height is 24px + 2px for its top and bottom borders */
+  --editor-searchbar-height: 26px;
+}
+
 :root.theme-light,
 :root .theme-light {
   --search-overlays-semitransparent: rgba(221, 225, 228, 0.66);
   --popup-shadow-color: #d0d0d0;
 }
 
 :root.theme-dark,
 :root .theme-dark {
@@ -565,42 +574,45 @@ html[dir="rtl"] .tree-node button.arrow 
 
 * {
   box-sizing: border-box;
 }
 
 button {
   background: transparent;
   border: none;
+  font-family: inherit;
+  font-size: inherit;
 }
 
 button:hover,
 button:focus {
   background-color: var(--theme-toolbar-background-hover);
 }
 
+.theme-dark button:hover,
+.theme-dark button:focus {
+  background-color: var(--theme-toolbar-hover);
+}
+
 .debugger {
   display: flex;
   flex: 1;
   height: 100%;
 }
 
 .editor-pane {
   display: flex;
   position: relative;
   flex: 1;
-  background-color: var(--theme-tab-toolbar-background);
-  height: calc(100% - 1px);
+  background-color: var(--theme-body-background);
+  height: 100%;
   overflow: hidden;
 }
 
-.theme-dark .editor-pane {
-  background-color: var(--theme-toolbar-background);
-}
-
 .editor-container {
   width: 100%;
 }
 
 .search-container {
   position: absolute;
   top: 0;
   left: 0;
@@ -1055,17 +1067,17 @@ html[dir="rtl"] .managed-tree .tree .nod
   position: fixed;
 }
 .img {
   /* default height an width which will likely be overrode */
   width: 12px;
   height: 12px;
   /* makes span appear like an image */
   display: inline-block;
-  background: var(--theme-body-color);
+  background: var(--theme-icon-color);
   mask-size: 100%;
 }
 /* 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/>. */
 
 .close-btn {
   width: 14px;
@@ -1139,68 +1151,59 @@ img.close::before {
   opacity: 0.8;
   cursor: default;
 }
 
 .command-bar-button:not(.disabled):hover {
   background: var(--theme-toolbar-background-hover);
 }
 
+.theme-dark .command-bar-button:not(.disabled):hover {
+  background: var(--theme-toolbar-hover);
+}
+
 :root.theme-dark .command-bar-button {
   color: var(--theme-body-color);
 }
 
 .command-bar-button > * {
   width: 16px;
   height: 16px;
   display: inline-block;
   vertical-align: middle;
 }
 /* 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/>. */
 
 .toggle-button {
-  transform: translate(0, 0px);
-  transition: transform 0.25s ease-in-out;
-  padding: 5px;
-  height: inherit;
+  padding: 4px 6px;
 }
 
 .toggle-button .img {
-  fill: var(--theme-comment);
-  vertical-align: 0;
-}
-
-:root.theme-dark .toggle-button .img {
-  fill: var(--theme-comment-alt);
+  vertical-align: middle;
 }
 
 .toggle-button.end {
   margin-inline-end: 0px;
   margin-inline-start: auto;
 }
 
 .toggle-button.start {
   margin-inline-start: 0px;
 }
 
-html:not([dir="rtl"]) .toggle-button.end .img,
-html[dir="rtl"] .toggle-button.start .img {
-  transform: rotate(180deg);
-}
-
-html .toggle-button.end.vertical .img {
+html[dir="rtl"] .toggle-button.start .img,
+html[dir="ltr"] .toggle-button.end:not(.vertical) .img {
+  transform: scaleX(-1);
+}
+
+.toggle-button.end.vertical .img {
   transform: rotate(-90deg);
 }
-
-.toggle-button.start.collapsed,
-.toggle-button.end.collapsed {
-  transform: rotate(180deg);
-}
 /* 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/>. */
 
 .arrow,
 .worker,
 .refresh,
 .shortcut,
@@ -1401,18 +1404,23 @@ span.img.marko {
   mask-size: 100%;
 }
 
 .img.extension {
   mask: url("resource://devtools/client/debugger/new/images/extension.svg") no-repeat;
   mask-size: 100%;
 }
 
-.img.toggle-panes {
-  mask: url("resource://devtools/client/debugger/new/images/toggle-panes.svg") no-repeat;
+.img.pane-collapse {
+  mask: url("resource://devtools/client/debugger/new/images/pane-collapse.svg") no-repeat;
+  mask-size: 100%;
+}
+
+.img.pane-expand {
+  mask: url("resource://devtools/client/debugger/new/images/pane-expand.svg") no-repeat;
   mask-size: 100%;
 }
 
 .img.file {
   mask: url("resource://devtools/client/debugger/new/images/file.svg") no-repeat;
   mask-size: 100%;
   width: 13px;
   height: 13px;
@@ -2068,17 +2076,16 @@ menuseparator {
   margin: 0;
   padding: 0 0 4px 0;
   position: absolute;
   top: 38px;
   bottom: 25px;
   left: 0;
   right: 0;
   list-style-type: none;
-  font-family: var(--monospace-font-family);
   overflow: auto;
 }
 
 .outline-list__class-list {
   margin: 0;
   padding: 0;
   list-style: none;
 }
@@ -2369,68 +2376,68 @@ menuseparator {
 .tree-indent {
   border-inline-start: 0 none;
 }
 
 .source-outline-tabs {
   font-size: 12px;
   width: 100%;
   background: var(--theme-body-background);
-  border-top: 1px solid var(--theme-splitter-color);
   display: flex;
   -moz-user-select: none;
   user-select: none;
   box-sizing: border-box;
-  height: 29px;
+  height: var(--editor-header-height);
   margin: 0;
   padding: 0;
+  border-bottom: 1px solid var(--theme-splitter-color);
 }
 
 .source-outline-tabs .tab {
+  align-items: center;
   background-color: var(--theme-toolbar-background);
-  border-top: 2px solid transparent;
-  border-bottom: 1px solid var(--theme-splitter-color);
   color: var(--theme-toolbar-color);
   cursor: default;
   display: inline-flex;
   flex: 1;
   justify-content: center;
-  margin-bottom: 0px;
-  margin-top: -1px;
   overflow: hidden;
-  padding: 5px 8px 7px 8px;
+  padding: 5px;
   position: relative;
   transition: all 0.25s ease;
 }
 
+.source-outline-tabs .tab::before {
+  content: "";
+  position: absolute;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 2px;
+  background-color: var(--tab-line-color, transparent);
+  transition: transform 250ms var(--animation-curve), opacity 250ms var(--animation-curve);
+  opacity: 0;
+  transform: scaleX(0);
+}
+
+.source-outline-tabs .tab.active {
+  --tab-line-color: var(--tab-line-selected-color);
+  color: var(--theme-toolbar-selected-color);
+  border-bottom-color: transparent;
+}
+
 .source-outline-tabs .tab:not(.active):hover {
+  --tab-line-color: var(--tab-line-hover-color);
   background-color: var(--theme-toolbar-hover);
-  border-top: 2px solid rgba(0, 0, 0, 0.2);
-}
-
-.theme-dark .source-outline-tabs .tab:hover {
-  border-top: 2px solid var(--tab-line-hover-color);
-}
-
-.source-outline-tabs .tab.active {
-  border-top: 2px solid var(--tab-line-selected-color);
-  color: var(--theme-toolbar-selected-color);
-}
-
-.theme-dark .source-outline-tabs .tab.active {
-  color: var(--theme-toolbar-selected-color);
-}
-
-.theme-dark .source-outline-tabs .tab.active:hover {
-  border-top: 2px solid var(--tab-line-selected-color);
-}
-
-.source-outline-tabs .tab.active path,
-.source-outline-tabs .tab:hover path {
-  fill: var(--theme-body-color);
+}
+
+.source-outline-tabs .tab:hover::before,
+.source-outline-tabs .tab.active::before {
+  opacity: 1;
+  transform: scaleX(1);
 }
 
 .source-outline-panel {
   flex: 1;
   overflow: auto;
 }
 
 .source-outline-panel.has-root > div {
@@ -2528,17 +2535,17 @@ menuseparator {
 
 .source-footer > .commands > .action {
   display: flex;
   justify-content: center;
   align-items: center;
   transition: opacity 200ms;
   border: none;
   background: transparent;
-  padding: 6px;
+  padding: 4px 6px;
 }
 
 .source-footer > .commands > .action .img {
   height: 100%;
   display: flex;
   flex-direction: column;
   justify-content: center;
 }
@@ -2598,23 +2605,23 @@ menuseparator {
 }
 /* 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/>. */
 
 .search-bar {
   display: flex;
   border: 1px solid transparent;
-  border-top: 1px solid var(--theme-splitter-color);
+  border-top-color: var(--theme-splitter-color);
   height: var(--editor-searchbar-height);
+  transition: border-color 200ms var(--animation-curve);
 }
 
 .search-bar.search-bar-focused {
-  border: 1px solid var(--blue-50);
-  transition: border-color 0.2s ease-in-out;
+  border-color: var(--blue-50);
 }
 
 .search-bar .search-field {
   padding-left: 7px;
 }
 
 .search-bar .search-shadow {
   flex-grow: 1;
@@ -2956,17 +2963,17 @@ menuseparator {
 }
 /* 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/>. */
 
 .column-breakpoint {
   display: inline;
   padding: 0;
-  margin-inline-end: 4px;
+  padding-inline-end: 4px;
 }
 
 .column-breakpoint:hover {
   background-color: transparent;
 }
 
 .column-breakpoint svg {
   display: inline;
@@ -3037,30 +3044,32 @@ menuseparator {
   width: calc(100% - 4em);
   border: none;
   background: var(--theme-toolbar-background);
   font-size: 14px;
   color: var(--theme-conditional-breakpoint-color);
   line-height: 30px;
 }
 
+.conditional-breakpoint-panel input:not(:placeholder-shown) {
+  font-family: var(--monospace-font-family);
+}
+
 .conditional-breakpoint-panel input:focus {
   outline-width: 0;
 }
 /* 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/>. */
 
 .editor-wrapper {
   --debug-line-border: rgb(145, 188, 219);
   --debug-expression-background: rgba(202, 227, 255, 0.5);
-  --editor-searchbar-height: 27px;
   --debug-line-error-border: rgb(255, 0, 0);
   --debug-expression-error-background: rgba(231, 116, 113, 0.3);
-  --editor-header-height: 30px;
   --highlight-line-duration: 1500ms;
 }
 
 .theme-dark .editor-wrapper {
   --debug-expression-background: rgba(202, 227, 255, 0.3);
   --debug-line-border: #7786a2;
 }
 
@@ -3090,17 +3099,16 @@ menuseparator {
  * BUG https://github.com/devtools-html/debugger.html/issues/63
  */
 .editor-wrapper {
   position: absolute;
   height: calc(100% - var(--editor-header-height));
   width: calc(100% - 1px);
   top: var(--editor-header-height);
   left: 0px;
-  --editor-footer-height: 24px;
 }
 
 html[dir="rtl"] .editor-mount {
   direction: ltr;
 }
 
 .theme-light {
   --gutter-hover-background-color: #dde1e4;
@@ -3511,21 +3519,16 @@ html .breakpoints-list .breakpoint.pause
   color: var(--theme-comment);
   transition: color 0.15s linear;
 }
 
 .breakpoints-list .breakpoint:hover {
   background-color: var(--search-overlays-semitransparent);
 }
 
-.breakpoints-list .breakpoint .breakpoint-line,
-.breakpoints-list .breakpoint-label {
-  font-family: var(--monospace-font-family);
-}
-
 .breakpoints-list .breakpoint .breakpoint-line {
   font-size: 11px;
   color: var(--theme-comment);
   min-width: 16px;
   text-align: right;
 }
 
 html[dir="rtl"] .breakpoints-list .breakpoint .breakpoint-line {
@@ -3746,18 +3749,18 @@ html[dir="rtl"] .breakpoints-list .break
 .expression-content .tree-node {
   overflow-x: hidden;
 }
 
 .expression-content .tree-node[data-expandable="false"][aria-level="1"] {
   padding-inline-start: 10px;
 }
 
-.expression-input {
-  max-width: 50%;
+.input-expression:not(:placeholder-shown) {
+  font-family: var(--monospace-font-family);
 }
 /* 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/>. */
 
 .frames [role="list"] .frames-group .group,
 .frames [role="list"] .frames-group .group .location {
   font-weight: 500;
@@ -4229,17 +4232,18 @@ html[dir="rtl"] .command-bar {
 .command-bar .active .skipPausing {
   background-color: var(--theme-highlight-blue);
 }
 
 .bottom {
   border-bottom: none;
   background-color: var(--theme-body-background);
   border-top: 1px solid var(--theme-splitter-color);
-  flex: 0 0 25px;
+  flex: none;
+  height: var(--editor-footer-height);
 }
 
 .command-bar.bottom {
   justify-content: flex-end;
 }
 
 .command-bar.bottom > button {
   color: var(--theme-comment);
@@ -4512,26 +4516,23 @@ html[dir="rtl"] .object-node {
   width: 20em;
   overflow: auto;
 }
 /* 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/>. */
 
 .welcomebox {
+  position: absolute;
+  top: var(--editor-header-height);
+  left: 0;
+  bottom: 1px;
   width: calc(100% - 1px);
-
-  /* Offsetting it by 30px for the sources-header area */
-  height: calc(100% - 30px);
-  position: absolute;
-  top: 30px;
-  left: 0;
   padding: 50px 0 0 0;
   text-align: center;
-  font-size: 1.25em;
   background-color: var(--theme-toolbar-background);
   font-weight: lighter;
   z-index: 10;
   user-select: none;
 }
 
 .theme-dark .welcomebox {
   background-color: var(--theme-body-background);
@@ -4545,16 +4546,17 @@ html[dir="rtl"] .object-node {
   offset-inline-start: auto;
   inset-inline-start: auto;
   bottom: 0;
 }
 
 .alignlabel {
   display: flex;
   white-space: nowrap;
+  font-size: 1.25em;
 }
 
 .shortcutKeys {
   font-family: Courier;
 }
 
 .shortcutKey,
 .shortcutLabel {
@@ -4605,143 +4607,98 @@ html[dir="rtl"] .object-node {
 html .welcomebox .toggle-button-end.collapsed {
   bottom: 1px;
 }
 /* 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/>. */
 
 .source-header {
-  border-bottom: 1px solid var(--theme-splitter-color);
+  display: flex;
   width: 100%;
-  height: 29px;
-  display: flex;
+  height: var(--editor-header-height);
+  border-bottom: 1px solid var(--theme-splitter-color);
+  background-color: var(--theme-toolbar-background);
 }
 
 .source-header * {
   -moz-user-select: none;
   user-select: none;
 }
 
-.source-header .new-tab-btn {
-  padding: 4px;
-  margin-top: 4px;
-  margin-left: 2px;
-  fill: var(--theme-comment);
-  transition: 0.1s ease;
-  align-self: center;
-}
-
-.source-header .new-tab-btn:hover {
-  background-color: var(--theme-toolbar-background-hover);
-}
-
-.source-header .new-tab-btn svg {
-  width: 12px;
-  display: block;
-}
-
 .source-tabs {
   max-width: calc(100% - 80px);
   align-self: flex-start;
 }
 
 .source-tab {
   display: inline-flex;
   align-items: center;
   position: relative;
   min-width: 40px;
   max-width: 100%;
   overflow: hidden;
   padding: 5px;
   cursor: default;
-  height: 30px;
+  height: calc(var(--editor-header-height) - 1px);
   font-size: 12px;
   background-color: transparent;
+  vertical-align: bottom;
 }
 
 .source-tab::before {
   content: "";
   position: absolute;
   top: 0;
   left: 0;
   width: 100%;
   height: 2px;
-  background: transparent;
+  background-color: var(--tab-line-color, transparent);
   transition: transform 250ms var(--animation-curve), opacity 250ms var(--animation-curve);
   opacity: 0;
   transform: scaleX(0);
 }
 
-.source-tab:first-child {
-  margin-inline-start: 0;
+.source-tab.active {
+  --tab-line-color: var(--tab-line-selected-color);
+  color: var(--theme-toolbar-selected-color);
+  border-bottom-color: transparent;
 }
 
 .source-tab:not(.active):hover {
-  background: linear-gradient(var(--theme-toolbar-hover) 28px, transparent 1px);
-}
-
-.source-tab:not(.active):hover::before {
-  background: var(--tab-line-hover-color);
+  --tab-line-color: var(--tab-line-hover-color);
+  background-color: var(--theme-toolbar-hover);
+}
+
+.source-tab:hover::before,
+.source-tab.active::before {
   opacity: 1;
   transform: scaleX(1);
 }
 
-.source-tab.active {
-  color: var(--theme-toolbar-selected-color);
-  border-bottom-color: transparent;
-}
-
-.source-tab.active::before {
-  background: var(--tab-line-selected-color);
-  opacity: 1;
-  transform: scaleX(1);
-}
-
-.theme-dark .source-tab.active {
-  color: var(--theme-toolbar-selected-color);
-}
-
-.source-tab.active path,
-.source-tab:hover path {
-  fill: var(--theme-body-color);
-}
-
 .source-tab .source-icon {
   margin-inline-end: 0;
 }
 
 .source-tab .img.prettyPrint,
 .source-tab .source-icon.blackBox {
   height: 12px;
   width: 12px;
   align-self: center;
 }
 
-.source-tab .prettyPrint path {
-  fill: var(--theme-textbox-box-shadow);
-}
-
 .source-tab .img.react {
   mask: url("resource://devtools/client/debugger/new/images/react.svg") no-repeat;
   mask-size: 100%;
   height: 14px;
   width: 14px;
   background: var(--theme-highlight-bluegrey);
   top: 0;
 }
 
-.source-tab .blackBox path {
-  fill: var(--theme-textbox-box-shadow);
-}
-
-.theme-dark .source-tab .blackBox circle {
-  fill: var(--theme-body-color);
-}
-
 .source-tab .filename {
   white-space: nowrap;
   text-overflow: ellipsis;
   overflow: hidden;
   padding: 0 4px;
   align-self: center;
   margin-bottom: 1px;
 }
--- a/devtools/client/debugger/new/dist/parser-worker.js
+++ b/devtools/client/debugger/new/dist/parser-worker.js
@@ -878,17 +878,17 @@ function parseVueScript(code) {
     ast = parse(code, sourceOptions.original);
   }
   return ast;
 }
 
 function parseConsoleScript(text, opts) {
   try {
     return _parse(text, {
-      plugins: ["objectRestSpread"],
+      plugins: ["objectRestSpread", "dynamicImport"],
       ...opts,
       allowAwaitOutsideFunction: true
     });
   } catch (e) {
     return null;
   }
 }
 
@@ -23646,17 +23646,17 @@ function getAssignmentTarget(node, bindi
   }
 
   return node;
 }
 
 // translates new bindings `var a = 3` into `self.a = 3`
 // and existing bindings `var a = 3` into `a = 3` for re-assignments
 function globalizeDeclaration(node, bindings) {
-  return node.declarations.map(declaration => t.expressionStatement(t.assignmentExpression("=", getAssignmentTarget(declaration.id, bindings), declaration.init)));
+  return node.declarations.map(declaration => t.expressionStatement(t.assignmentExpression("=", getAssignmentTarget(declaration.id, bindings), declaration.init || t.unaryExpression("void", t.numericLiteral(0)))));
 }
 
 // translates new bindings `a = 3` into `self.a = 3`
 // and keeps assignments the same for existing bindings.
 function globalizeAssignment(node, bindings) {
   return t.assignmentExpression(node.operator, getAssignmentTarget(node.left, bindings), node.right);
 }
 
--- a/devtools/client/debugger/new/dist/search-worker.js
+++ b/devtools/client/debugger/new/dist/search-worker.js
@@ -579,16 +579,21 @@ function getMatches(query, text, modifie
     isGlobal: true
   });
   const matchedLocations = [];
   const lines = text.split("\n");
   for (let i = 0; i < lines.length; i++) {
     let singleMatch;
     const line = lines[i];
     while ((singleMatch = regexQuery.exec(line)) !== null) {
+      // Flow doesn't understand the test above.
+      if (!singleMatch) {
+        throw new Error("no singleMatch");
+      }
+
       matchedLocations.push({ line: i, ch: singleMatch.index });
 
       // When the match is an empty string the regexQuery.lastIndex will not
       // change resulting in an infinite loop so we need to check for this and
       // increment it manually in that case.  See issue #7023
       if (singleMatch[0] === "") {
         (0, _assert2.default)(!regexQuery.unicode, "lastIndex++ can cause issues in unicode mode");
         regexQuery.lastIndex++;
@@ -614,17 +619,17 @@ exports.findSourceMatches = findSourceMa
 var _getMatches = __webpack_require__(1632);
 
 var _getMatches2 = _interopRequireDefault(_getMatches);
 
 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
 
 function findSourceMatches(source, queryText) {
   const { id, loadedState, text } = source;
-  if (loadedState != "loaded" || !text || queryText == "") {
+  if (loadedState != "loaded" || typeof text != "string" || queryText == "") {
     return [];
   }
 
   const modifiers = {
     caseSensitive: false,
     regexMatch: false,
     wholeWord: false
   };
--- a/devtools/client/debugger/new/dist/vendors.css
+++ b/devtools/client/debugger/new/dist/vendors.css
@@ -380,18 +380,23 @@ span.img.marko {
   mask-size: 100%;
 }
 
 .img.extension {
   mask: url("resource://devtools/client/debugger/new/images/extension.svg") no-repeat;
   mask-size: 100%;
 }
 
-.img.toggle-panes {
-  mask: url("resource://devtools/client/debugger/new/images/toggle-panes.svg") no-repeat;
+.img.pane-collapse {
+  mask: url("resource://devtools/client/debugger/new/images/pane-collapse.svg") no-repeat;
+  mask-size: 100%;
+}
+
+.img.pane-expand {
+  mask: url("resource://devtools/client/debugger/new/images/pane-expand.svg") no-repeat;
   mask-size: 100%;
 }
 
 .img.file {
   mask: url("resource://devtools/client/debugger/new/images/file.svg") no-repeat;
   mask-size: 100%;
   width: 13px;
   height: 13px;
--- a/devtools/client/debugger/new/dist/vendors.js
+++ b/devtools/client/debugger/new/dist/vendors.js
@@ -947,23 +947,49 @@ module.exports = {
 /***/ }),
 
 /***/ 1464:
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
-/* 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/. */
-
-const { formatKeyShortcut } = __webpack_require__(3786);
+var _devtoolsServices = __webpack_require__(22);
+
+var _devtoolsServices2 = _interopRequireDefault(_devtoolsServices);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+const { appinfo } = _devtoolsServices2.default; /* 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/. */
+
+const isMacOS = appinfo.OS === "Darwin";
+
 const EventEmitter = __webpack_require__(1382);
 
+/**
+ * Formats key for use in tooltips
+ * For macOS we use the following unicode
+ *
+ * cmd ⌘ = \u2318
+ * shift ⇧ – \u21E7
+ * option (alt) ⌥ \u2325
+ *
+ * For Win/Lin this replaces CommandOrControl or CmdOrCtrl with Ctrl
+ *
+ * @static
+ */
+function formatKeyShortcut(shortcut) {
+  if (isMacOS) {
+    return shortcut.replace(/Shift\+/g, "\u21E7").replace(/Command\+|Cmd\+/g, "\u2318").replace(/CommandOrControl\+|CmdOrCtrl\+/g, "\u2318").replace(/Alt\+/g, "\u2325");
+  }
+  return shortcut.replace(/CommandOrControl\+|CmdOrCtrl\+/g, `${L10N.getStr("ctrl")}+`).replace(/Shift\+/g, "Shift+");
+}
+
 function inToolbox() {
   try {
     return window.parent.document.documentURI == "about:devtools-toolbox";
   } catch (e) {
     // If `window` is not available, it's very likely that we are in the toolbox.
     return true;
   }
 }
@@ -3865,17 +3891,17 @@ module.exports = {
 // should implement the similar functionalities on its own.
 //
 // Please keep in mind that if the feature in this file has changed, don't
 // forget to also change that accordingly in
 // devtools/client/shared/unicode-url.js in the mozilla-central repository.
 
 
 
-const punycode = __webpack_require__(916);
+const punycode = __webpack_require__(3641);
 
 /**
  * Gets a readble Unicode hostname from a hostname.
  *
  * If the `hostname` is a readable ASCII hostname, such as example.org, then
  * this function will simply return the original `hostname`.
  *
  * If the `hostname` is a Punycode hostname representing a Unicode domain name,
@@ -3964,16 +3990,556 @@ function getUnicodeUrl(url) {
 module.exports = {
   getUnicodeHostname,
   getUnicodeUrlPath,
   getUnicodeUrl
 };
 
 /***/ }),
 
+/***/ 3641:
+/***/ (function(module, exports, __webpack_require__) {
+
+/* WEBPACK VAR INJECTION */(function(module, global) {var __WEBPACK_AMD_DEFINE_RESULT__;/*! https://mths.be/punycode v1.4.1 by @mathias */
+;(function(root) {
+
+	/** Detect free variables */
+	var freeExports = typeof exports == 'object' && exports &&
+		!exports.nodeType && exports;
+	var freeModule = typeof module == 'object' && module &&
+		!module.nodeType && module;
+	var freeGlobal = typeof global == 'object' && global;
+	if (
+		freeGlobal.global === freeGlobal ||
+		freeGlobal.window === freeGlobal ||
+		freeGlobal.self === freeGlobal
+	) {
+		root = freeGlobal;
+	}
+
+	/**
+	 * The `punycode` object.
+	 * @name punycode
+	 * @type Object
+	 */
+	var punycode,
+
+	/** Highest positive signed 32-bit float value */
+	maxInt = 2147483647, // aka. 0x7FFFFFFF or 2^31-1
+
+	/** Bootstring parameters */
+	base = 36,
+	tMin = 1,
+	tMax = 26,
+	skew = 38,
+	damp = 700,
+	initialBias = 72,
+	initialN = 128, // 0x80
+	delimiter = '-', // '\x2D'
+
+	/** Regular expressions */
+	regexPunycode = /^xn--/,
+	regexNonASCII = /[^\x20-\x7E]/, // unprintable ASCII chars + non-ASCII chars
+	regexSeparators = /[\x2E\u3002\uFF0E\uFF61]/g, // RFC 3490 separators
+
+	/** Error messages */
+	errors = {
+		'overflow': 'Overflow: input needs wider integers to process',
+		'not-basic': 'Illegal input >= 0x80 (not a basic code point)',
+		'invalid-input': 'Invalid input'
+	},
+
+	/** Convenience shortcuts */
+	baseMinusTMin = base - tMin,
+	floor = Math.floor,
+	stringFromCharCode = String.fromCharCode,
+
+	/** Temporary variable */
+	key;
+
+	/*--------------------------------------------------------------------------*/
+
+	/**
+	 * A generic error utility function.
+	 * @private
+	 * @param {String} type The error type.
+	 * @returns {Error} Throws a `RangeError` with the applicable error message.
+	 */
+	function error(type) {
+		throw new RangeError(errors[type]);
+	}
+
+	/**
+	 * A generic `Array#map` utility function.
+	 * @private
+	 * @param {Array} array The array to iterate over.
+	 * @param {Function} callback The function that gets called for every array
+	 * item.
+	 * @returns {Array} A new array of values returned by the callback function.
+	 */
+	function map(array, fn) {
+		var length = array.length;
+		var result = [];
+		while (length--) {
+			result[length] = fn(array[length]);
+		}
+		return result;
+	}
+
+	/**
+	 * A simple `Array#map`-like wrapper to work with domain name strings or email
+	 * addresses.
+	 * @private
+	 * @param {String} domain The domain name or email address.
+	 * @param {Function} callback The function that gets called for every
+	 * character.
+	 * @returns {Array} A new string of characters returned by the callback
+	 * function.
+	 */
+	function mapDomain(string, fn) {
+		var parts = string.split('@');
+		var result = '';
+		if (parts.length > 1) {
+			// In email addresses, only the domain name should be punycoded. Leave
+			// the local part (i.e. everything up to `@`) intact.
+			result = parts[0] + '@';
+			string = parts[1];
+		}
+		// Avoid `split(regex)` for IE8 compatibility. See #17.
+		string = string.replace(regexSeparators, '\x2E');
+		var labels = string.split('.');
+		var encoded = map(labels, fn).join('.');
+		return result + encoded;
+	}
+
+	/**
+	 * Creates an array containing the numeric code points of each Unicode
+	 * character in the string. While JavaScript uses UCS-2 internally,
+	 * this function will convert a pair of surrogate halves (each of which
+	 * UCS-2 exposes as separate characters) into a single code point,
+	 * matching UTF-16.
+	 * @see `punycode.ucs2.encode`
+	 * @see <https://mathiasbynens.be/notes/javascript-encoding>
+	 * @memberOf punycode.ucs2
+	 * @name decode
+	 * @param {String} string The Unicode input string (UCS-2).
+	 * @returns {Array} The new array of code points.
+	 */
+	function ucs2decode(string) {
+		var output = [],
+		    counter = 0,
+		    length = string.length,
+		    value,
+		    extra;
+		while (counter < length) {
+			value = string.charCodeAt(counter++);
+			if (value >= 0xD800 && value <= 0xDBFF && counter < length) {
+				// high surrogate, and there is a next character
+				extra = string.charCodeAt(counter++);
+				if ((extra & 0xFC00) == 0xDC00) { // low surrogate
+					output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000);
+				} else {
+					// unmatched surrogate; only append this code unit, in case the next
+					// code unit is the high surrogate of a surrogate pair
+					output.push(value);
+					counter--;
+				}
+			} else {
+				output.push(value);
+			}
+		}
+		return output;
+	}
+
+	/**
+	 * Creates a string based on an array of numeric code points.
+	 * @see `punycode.ucs2.decode`
+	 * @memberOf punycode.ucs2
+	 * @name encode
+	 * @param {Array} codePoints The array of numeric code points.
+	 * @returns {String} The new Unicode string (UCS-2).
+	 */
+	function ucs2encode(array) {
+		return map(array, function(value) {
+			var output = '';
+			if (value > 0xFFFF) {
+				value -= 0x10000;
+				output += stringFromCharCode(value >>> 10 & 0x3FF | 0xD800);
+				value = 0xDC00 | value & 0x3FF;
+			}
+			output += stringFromCharCode(value);
+			return output;
+		}).join('');
+	}
+
+	/**
+	 * Converts a basic code point into a digit/integer.
+	 * @see `digitToBasic()`
+	 * @private
+	 * @param {Number} codePoint The basic numeric code point value.
+	 * @returns {Number} The numeric value of a basic code point (for use in
+	 * representing integers) in the range `0` to `base - 1`, or `base` if
+	 * the code point does not represent a value.
+	 */
+	function basicToDigit(codePoint) {
+		if (codePoint - 48 < 10) {
+			return codePoint - 22;
+		}
+		if (codePoint - 65 < 26) {
+			return codePoint - 65;
+		}
+		if (codePoint - 97 < 26) {
+			return codePoint - 97;
+		}
+		return base;
+	}
+
+	/**
+	 * Converts a digit/integer into a basic code point.
+	 * @see `basicToDigit()`
+	 * @private
+	 * @param {Number} digit The numeric value of a basic code point.
+	 * @returns {Number} The basic code point whose value (when used for
+	 * representing integers) is `digit`, which needs to be in the range
+	 * `0` to `base - 1`. If `flag` is non-zero, the uppercase form is
+	 * used; else, the lowercase form is used. The behavior is undefined
+	 * if `flag` is non-zero and `digit` has no uppercase form.
+	 */
+	function digitToBasic(digit, flag) {
+		//  0..25 map to ASCII a..z or A..Z
+		// 26..35 map to ASCII 0..9
+		return digit + 22 + 75 * (digit < 26) - ((flag != 0) << 5);
+	}
+
+	/**
+	 * Bias adaptation function as per section 3.4 of RFC 3492.
+	 * https://tools.ietf.org/html/rfc3492#section-3.4
+	 * @private
+	 */
+	function adapt(delta, numPoints, firstTime) {
+		var k = 0;
+		delta = firstTime ? floor(delta / damp) : delta >> 1;
+		delta += floor(delta / numPoints);
+		for (/* no initialization */; delta > baseMinusTMin * tMax >> 1; k += base) {
+			delta = floor(delta / baseMinusTMin);
+		}
+		return floor(k + (baseMinusTMin + 1) * delta / (delta + skew));
+	}
+
+	/**
+	 * Converts a Punycode string of ASCII-only symbols to a string of Unicode
+	 * symbols.
+	 * @memberOf punycode
+	 * @param {String} input The Punycode string of ASCII-only symbols.
+	 * @returns {String} The resulting string of Unicode symbols.
+	 */
+	function decode(input) {
+		// Don't use UCS-2
+		var output = [],
+		    inputLength = input.length,
+		    out,
+		    i = 0,
+		    n = initialN,
+		    bias = initialBias,
+		    basic,
+		    j,
+		    index,
+		    oldi,
+		    w,
+		    k,
+		    digit,
+		    t,
+		    /** Cached calculation results */
+		    baseMinusT;
+
+		// Handle the basic code points: let `basic` be the number of input code
+		// points before the last delimiter, or `0` if there is none, then copy
+		// the first basic code points to the output.
+
+		basic = input.lastIndexOf(delimiter);
+		if (basic < 0) {
+			basic = 0;
+		}
+
+		for (j = 0; j < basic; ++j) {
+			// if it's not a basic code point
+			if (input.charCodeAt(j) >= 0x80) {
+				error('not-basic');
+			}
+			output.push(input.charCodeAt(j));
+		}
+
+		// Main decoding loop: start just after the last delimiter if any basic code
+		// points were copied; start at the beginning otherwise.
+
+		for (index = basic > 0 ? basic + 1 : 0; index < inputLength; /* no final expression */) {
+
+			// `index` is the index of the next character to be consumed.
+			// Decode a generalized variable-length integer into `delta`,
+			// which gets added to `i`. The overflow checking is easier
+			// if we increase `i` as we go, then subtract off its starting
+			// value at the end to obtain `delta`.
+			for (oldi = i, w = 1, k = base; /* no condition */; k += base) {
+
+				if (index >= inputLength) {
+					error('invalid-input');
+				}
+
+				digit = basicToDigit(input.charCodeAt(index++));
+
+				if (digit >= base || digit > floor((maxInt - i) / w)) {
+					error('overflow');
+				}
+
+				i += digit * w;
+				t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);
+
+				if (digit < t) {
+					break;
+				}
+
+				baseMinusT = base - t;
+				if (w > floor(maxInt / baseMinusT)) {
+					error('overflow');
+				}
+
+				w *= baseMinusT;
+
+			}
+
+			out = output.length + 1;
+			bias = adapt(i - oldi, out, oldi == 0);
+
+			// `i` was supposed to wrap around from `out` to `0`,
+			// incrementing `n` each time, so we'll fix that now:
+			if (floor(i / out) > maxInt - n) {
+				error('overflow');
+			}
+
+			n += floor(i / out);
+			i %= out;
+
+			// Insert `n` at position `i` of the output
+			output.splice(i++, 0, n);
+
+		}
+
+		return ucs2encode(output);
+	}
+
+	/**
+	 * Converts a string of Unicode symbols (e.g. a domain name label) to a
+	 * Punycode string of ASCII-only symbols.
+	 * @memberOf punycode
+	 * @param {String} input The string of Unicode symbols.
+	 * @returns {String} The resulting Punycode string of ASCII-only symbols.
+	 */
+	function encode(input) {
+		var n,
+		    delta,
+		    handledCPCount,
+		    basicLength,
+		    bias,
+		    j,
+		    m,
+		    q,
+		    k,
+		    t,
+		    currentValue,
+		    output = [],
+		    /** `inputLength` will hold the number of code points in `input`. */
+		    inputLength,
+		    /** Cached calculation results */
+		    handledCPCountPlusOne,
+		    baseMinusT,
+		    qMinusT;
+
+		// Convert the input in UCS-2 to Unicode
+		input = ucs2decode(input);
+
+		// Cache the length
+		inputLength = input.length;
+
+		// Initialize the state
+		n = initialN;
+		delta = 0;
+		bias = initialBias;
+
+		// Handle the basic code points
+		for (j = 0; j < inputLength; ++j) {
+			currentValue = input[j];
+			if (currentValue < 0x80) {
+				output.push(stringFromCharCode(currentValue));
+			}
+		}
+
+		handledCPCount = basicLength = output.length;
+
+		// `handledCPCount` is the number of code points that have been handled;
+		// `basicLength` is the number of basic code points.
+
+		// Finish the basic string - if it is not empty - with a delimiter
+		if (basicLength) {
+			output.push(delimiter);
+		}
+
+		// Main encoding loop:
+		while (handledCPCount < inputLength) {
+
+			// All non-basic code points < n have been handled already. Find the next
+			// larger one:
+			for (m = maxInt, j = 0; j < inputLength; ++j) {
+				currentValue = input[j];
+				if (currentValue >= n && currentValue < m) {
+					m = currentValue;
+				}
+			}
+
+			// Increase `delta` enough to advance the decoder's <n,i> state to <m,0>,
+			// but guard against overflow
+			handledCPCountPlusOne = handledCPCount + 1;
+			if (m - n > floor((maxInt - delta) / handledCPCountPlusOne)) {
+				error('overflow');
+			}
+
+			delta += (m - n) * handledCPCountPlusOne;
+			n = m;
+
+			for (j = 0; j < inputLength; ++j) {
+				currentValue = input[j];
+
+				if (currentValue < n && ++delta > maxInt) {
+					error('overflow');
+				}
+
+				if (currentValue == n) {
+					// Represent delta as a generalized variable-length integer
+					for (q = delta, k = base; /* no condition */; k += base) {
+						t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);
+						if (q < t) {
+							break;
+						}
+						qMinusT = q - t;
+						baseMinusT = base - t;
+						output.push(
+							stringFromCharCode(digitToBasic(t + qMinusT % baseMinusT, 0))
+						);
+						q = floor(qMinusT / baseMinusT);
+					}
+
+					output.push(stringFromCharCode(digitToBasic(q, 0)));
+					bias = adapt(delta, handledCPCountPlusOne, handledCPCount == basicLength);
+					delta = 0;
+					++handledCPCount;
+				}
+			}
+
+			++delta;
+			++n;
+
+		}
+		return output.join('');
+	}
+
+	/**
+	 * Converts a Punycode string representing a domain name or an email address
+	 * to Unicode. Only the Punycoded parts of the input will be converted, i.e.
+	 * it doesn't matter if you call it on a string that has already been
+	 * converted to Unicode.
+	 * @memberOf punycode
+	 * @param {String} input The Punycoded domain name or email address to
+	 * convert to Unicode.
+	 * @returns {String} The Unicode representation of the given Punycode
+	 * string.
+	 */
+	function toUnicode(input) {
+		return mapDomain(input, function(string) {
+			return regexPunycode.test(string)
+				? decode(string.slice(4).toLowerCase())
+				: string;
+		});
+	}
+
+	/**
+	 * Converts a Unicode string representing a domain name or an email address to
+	 * Punycode. Only the non-ASCII parts of the domain name will be converted,
+	 * i.e. it doesn't matter if you call it with a domain that's already in
+	 * ASCII.
+	 * @memberOf punycode
+	 * @param {String} input The domain name or email address to convert, as a
+	 * Unicode string.
+	 * @returns {String} The Punycode representation of the given domain name or
+	 * email address.
+	 */
+	function toASCII(input) {
+		return mapDomain(input, function(string) {
+			return regexNonASCII.test(string)
+				? 'xn--' + encode(string)
+				: string;
+		});
+	}
+
+	/*--------------------------------------------------------------------------*/
+
+	/** Define the public API */
+	punycode = {
+		/**
+		 * A string representing the current Punycode.js version number.
+		 * @memberOf punycode
+		 * @type String
+		 */
+		'version': '1.4.1',
+		/**
+		 * An object of methods to convert from JavaScript's internal character
+		 * representation (UCS-2) to Unicode code points, and back.
+		 * @see <https://mathiasbynens.be/notes/javascript-encoding>
+		 * @memberOf punycode
+		 * @type Object
+		 */
+		'ucs2': {
+			'decode': ucs2decode,
+			'encode': ucs2encode
+		},
+		'decode': decode,
+		'encode': encode,
+		'toASCII': toASCII,
+		'toUnicode': toUnicode
+	};
+
+	/** Expose `punycode` */
+	// Some AMD build optimizers, like r.js, check for specific condition patterns
+	// like the following:
+	if (
+		true
+	) {
+		!(__WEBPACK_AMD_DEFINE_RESULT__ = (function() {
+			return punycode;
+		}).call(exports, __webpack_require__, exports, module),
+				__WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
+	} else if (freeExports && freeModule) {
+		if (module.exports == freeExports) {
+			// in Node.js, io.js, or RingoJS v0.8.0+
+			freeModule.exports = punycode;
+		} else {
+			// in Narwhal or RingoJS v0.7.0-
+			for (key in punycode) {
+				punycode.hasOwnProperty(key) && (freeExports[key] = punycode[key]);
+			}
+		}
+	} else {
+		// in Rhino or a web browser
+		root.punycode = punycode;
+	}
+
+}(this));
+
+/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(793)(module), __webpack_require__(792)))
+
+/***/ }),
+
 /***/ 3642:
 /***/ (function(module, exports) {
 
 module.exports = __WEBPACK_EXTERNAL_MODULE_3642__;
 
 /***/ }),
 
 /***/ 3643:
@@ -5233,16 +5799,17 @@ const vendored = exports.vendored = {
   "lodash-move": _lodashMove2.default,
   "react-aria-components/src/tabs": reactAriaComponentsTabs,
   "react-transition-group/Transition": transition,
   reselect,
   // Svg is required via relative paths, so the key is not imported path.
   // See .babel/transform-mc.js
   Svg: _Svg2.default
 };
+// $FlowIgnore
 
 /***/ }),
 
 /***/ 3750:
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
@@ -6475,67 +7042,16 @@ var _propTypes = __webpack_require__(364
 var _propTypes2 = _interopRequireDefault(_propTypes);
 
 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
 
 exports.default = _propTypes2.default.object;
 
 /***/ }),
 
-/***/ 3786:
-/***/ (function(module, exports, __webpack_require__) {
-
-"use strict";
-
-
-Object.defineProperty(exports, "__esModule", {
-  value: true
-});
-exports.formatKeyShortcut = formatKeyShortcut;
-
-var _devtoolsServices = __webpack_require__(22);
-
-var _devtoolsServices2 = _interopRequireDefault(_devtoolsServices);
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
-const { appinfo } = _devtoolsServices2.default; /* 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/>. */
-
-/**
- * Utils for keyboard command strings
- * @module utils/text
- */
-
-
-const isMacOS = appinfo.OS === "Darwin";
-
-/**
- * Formats key for use in tooltips
- * For macOS we use the following unicode
- *
- * cmd ⌘ = \u2318
- * shift ⇧ – \u21E7
- * option (alt) ⌥ \u2325
- *
- * For Win/Lin this replaces CommandOrControl or CmdOrCtrl with Ctrl
- *
- * @memberof utils/text
- * @static
- */
-function formatKeyShortcut(shortcut) {
-  if (isMacOS) {
-    return shortcut.replace(/Shift\+/g, "\u21E7").replace(/Command\+|Cmd\+/g, "\u2318").replace(/CommandOrControl\+|CmdOrCtrl\+/g, "\u2318").replace(/Alt\+/g, "\u2325");
-  }
-  return shortcut.replace(/CommandOrControl\+|CmdOrCtrl\+/g, "Ctrl").replace(/Shift\+/g, "Shift");
-}
-
-/***/ }),
-
 /***/ 3791:
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
 "use strict";
 Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
 /* harmony export (immutable) */ __webpack_exports__["defaultMemoize"] = defaultMemoize;
 /* harmony export (immutable) */ __webpack_exports__["createSelectorCreator"] = createSelectorCreator;
 /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "createSelector", function() { return createSelector; });
@@ -7148,552 +7664,12 @@ module.exports = function(module) {
 			}
 		});
 		module.webpackPolyfill = 1;
 	}
 	return module;
 };
 
 
-/***/ }),
-
-/***/ 916:
-/***/ (function(module, exports, __webpack_require__) {
-
-/* WEBPACK VAR INJECTION */(function(module, global) {var __WEBPACK_AMD_DEFINE_RESULT__;/*! https://mths.be/punycode v1.4.1 by @mathias */
-;(function(root) {
-
-	/** Detect free variables */
-	var freeExports = typeof exports == 'object' && exports &&
-		!exports.nodeType && exports;
-	var freeModule = typeof module == 'object' && module &&
-		!module.nodeType && module;
-	var freeGlobal = typeof global == 'object' && global;
-	if (
-		freeGlobal.global === freeGlobal ||
-		freeGlobal.window === freeGlobal ||
-		freeGlobal.self === freeGlobal
-	) {
-		root = freeGlobal;
-	}
-
-	/**
-	 * The `punycode` object.
-	 * @name punycode
-	 * @type Object
-	 */
-	var punycode,
-
-	/** Highest positive signed 32-bit float value */
-	maxInt = 2147483647, // aka. 0x7FFFFFFF or 2^31-1
-
-	/** Bootstring parameters */
-	base = 36,
-	tMin = 1,
-	tMax = 26,
-	skew = 38,
-	damp = 700,
-	initialBias = 72,
-	initialN = 128, // 0x80
-	delimiter = '-', // '\x2D'
-
-	/** Regular expressions */
-	regexPunycode = /^xn--/,
-	regexNonASCII = /[^\x20-\x7E]/, // unprintable ASCII chars + non-ASCII chars
-	regexSeparators = /[\x2E\u3002\uFF0E\uFF61]/g, // RFC 3490 separators
-
-	/** Error messages */
-	errors = {
-		'overflow': 'Overflow: input needs wider integers to process',
-		'not-basic': 'Illegal input >= 0x80 (not a basic code point)',
-		'invalid-input': 'Invalid input'
-	},
-
-	/** Convenience shortcuts */
-	baseMinusTMin = base - tMin,
-	floor = Math.floor,
-	stringFromCharCode = String.fromCharCode,
-
-	/** Temporary variable */
-	key;
-
-	/*--------------------------------------------------------------------------*/
-
-	/**
-	 * A generic error utility function.
-	 * @private
-	 * @param {String} type The error type.
-	 * @returns {Error} Throws a `RangeError` with the applicable error message.
-	 */
-	function error(type) {
-		throw new RangeError(errors[type]);
-	}
-
-	/**
-	 * A generic `Array#map` utility function.
-	 * @private
-	 * @param {Array} array The array to iterate over.
-	 * @param {Function} callback The function that gets called for every array
-	 * item.
-	 * @returns {Array} A new array of values returned by the callback function.
-	 */
-	function map(array, fn) {
-		var length = array.length;
-		var result = [];
-		while (length--) {
-			result[length] = fn(array[length]);
-		}
-		return result;
-	}
-
-	/**
-	 * A simple `Array#map`-like wrapper to work with domain name strings or email
-	 * addresses.
-	 * @private
-	 * @param {String} domain The domain name or email address.
-	 * @param {Function} callback The function that gets called for every
-	 * character.
-	 * @returns {Array} A new string of characters returned by the callback
-	 * function.
-	 */
-	function mapDomain(string, fn) {
-		var parts = string.split('@');
-		var result = '';
-		if (parts.length > 1) {
-			// In email addresses, only the domain name should be punycoded. Leave
-			// the local part (i.e. everything up to `@`) intact.
-			result = parts[0] + '@';
-			string = parts[1];
-		}
-		// Avoid `split(regex)` for IE8 compatibility. See #17.
-		string = string.replace(regexSeparators, '\x2E');
-		var labels = string.split('.');
-		var encoded = map(labels, fn).join('.');
-		return result + encoded;
-	}
-
-	/**
-	 * Creates an array containing the numeric code points of each Unicode
-	 * character in the string. While JavaScript uses UCS-2 internally,
-	 * this function will convert a pair of surrogate halves (each of which
-	 * UCS-2 exposes as separate characters) into a single code point,
-	 * matching UTF-16.
-	 * @see `punycode.ucs2.encode`
-	 * @see <https://mathiasbynens.be/notes/javascript-encoding>
-	 * @memberOf punycode.ucs2
-	 * @name decode
-	 * @param {String} string The Unicode input string (UCS-2).
-	 * @returns {Array} The new array of code points.
-	 */
-	function ucs2decode(string) {
-		var output = [],
-		    counter = 0,
-		    length = string.length,
-		    value,
-		    extra;
-		while (counter < length) {
-			value = string.charCodeAt(counter++);
-			if (value >= 0xD800 && value <= 0xDBFF && counter < length) {
-				// high surrogate, and there is a next character
-				extra = string.charCodeAt(counter++);
-				if ((extra & 0xFC00) == 0xDC00) { // low surrogate
-					output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000);
-				} else {
-					// unmatched surrogate; only append this code unit, in case the next
-					// code unit is the high surrogate of a surrogate pair
-					output.push(value);
-					counter--;
-				}
-			} else {
-				output.push(value);
-			}
-		}
-		return output;
-	}
-
-	/**
-	 * Creates a string based on an array of numeric code points.
-	 * @see `punycode.ucs2.decode`
-	 * @memberOf punycode.ucs2
-	 * @name encode
-	 * @param {Array} codePoints The array of numeric code points.
-	 * @returns {String} The new Unicode string (UCS-2).
-	 */
-	function ucs2encode(array) {
-		return map(array, function(value) {
-			var output = '';
-			if (value > 0xFFFF) {
-				value -= 0x10000;
-				output += stringFromCharCode(value >>> 10 & 0x3FF | 0xD800);
-				value = 0xDC00 | value & 0x3FF;
-			}
-			output += stringFromCharCode(value);
-			return output;
-		}).join('');
-	}
-
-	/**
-	 * Converts a basic code point into a digit/integer.
-	 * @see `digitToBasic()`
-	 * @private
-	 * @param {Number} codePoint The basic numeric code point value.
-	 * @returns {Number} The numeric value of a basic code point (for use in
-	 * representing integers) in the range `0` to `base - 1`, or `base` if
-	 * the code point does not represent a value.
-	 */
-	function basicToDigit(codePoint) {
-		if (codePoint - 48 < 10) {
-			return codePoint - 22;
-		}
-		if (codePoint - 65 < 26) {
-			return codePoint - 65;
-		}
-		if (codePoint - 97 < 26) {
-			return codePoint - 97;
-		}
-		return base;
-	}
-
-	/**
-	 * Converts a digit/integer into a basic code point.
-	 * @see `basicToDigit()`
-	 * @private
-	 * @param {Number} digit The numeric value of a basic code point.
-	 * @returns {Number} The basic code point whose value (when used for
-	 * representing integers) is `digit`, which needs to be in the range
-	 * `0` to `base - 1`. If `flag` is non-zero, the uppercase form is
-	 * used; else, the lowercase form is used. The behavior is undefined
-	 * if `flag` is non-zero and `digit` has no uppercase form.
-	 */
-	function digitToBasic(digit, flag) {
-		//  0..25 map to ASCII a..z or A..Z
-		// 26..35 map to ASCII 0..9
-		return digit + 22 + 75 * (digit < 26) - ((flag != 0) << 5);
-	}
-
-	/**
-	 * Bias adaptation function as per section 3.4 of RFC 3492.
-	 * https://tools.ietf.org/html/rfc3492#section-3.4
-	 * @private
-	 */
-	function adapt(delta, numPoints, firstTime) {
-		var k = 0;
-		delta = firstTime ? floor(delta / damp) : delta >> 1;
-		delta += floor(delta / numPoints);
-		for (/* no initialization */; delta > baseMinusTMin * tMax >> 1; k += base) {
-			delta = floor(delta / baseMinusTMin);
-		}
-		return floor(k + (baseMinusTMin + 1) * delta / (delta + skew));
-	}
-
-	/**
-	 * Converts a Punycode string of ASCII-only symbols to a string of Unicode
-	 * symbols.
-	 * @memberOf punycode
-	 * @param {String} input The Punycode string of ASCII-only symbols.
-	 * @returns {String} The resulting string of Unicode symbols.
-	 */
-	function decode(input) {
-		// Don't use UCS-2
-		var output = [],
-		    inputLength = input.length,
-		    out,
-		    i = 0,
-		    n = initialN,
-		    bias = initialBias,
-		    basic,
-		    j,
-		    index,
-		    oldi,
-		    w,
-		    k,
-		    digit,
-		    t,
-		    /** Cached calculation results */
-		    baseMinusT;
-
-		// Handle the basic code points: let `basic` be the number of input code
-		// points before the last delimiter, or `0` if there is none, then copy
-		// the first basic code points to the output.
-
-		basic = input.lastIndexOf(delimiter);
-		if (basic < 0) {
-			basic = 0;
-		}
-
-		for (j = 0; j < basic; ++j) {
-			// if it's not a basic code point
-			if (input.charCodeAt(j) >= 0x80) {
-				error('not-basic');
-			}
-			output.push(input.charCodeAt(j));
-		}
-
-		// Main decoding loop: start just after the last delimiter if any basic code
-		// points were copied; start at the beginning otherwise.
-
-		for (index = basic > 0 ? basic + 1 : 0; index < inputLength; /* no final expression */) {
-
-			// `index` is the index of the next character to be consumed.
-			// Decode a generalized variable-length integer into `delta`,
-			// which gets added to `i`. The overflow checking is easier
-			// if we increase `i` as we go, then subtract off its starting
-			// value at the end to obtain `delta`.
-			for (oldi = i, w = 1, k = base; /* no condition */; k += base) {
-
-				if (index >= inputLength) {
-					error('invalid-input');
-				}
-
-				digit = basicToDigit(input.charCodeAt(index++));
-
-				if (digit >= base || digit > floor((maxInt - i) / w)) {
-					error('overflow');
-				}
-
-				i += digit * w;
-				t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);
-
-				if (digit < t) {
-					break;
-				}
-
-				baseMinusT = base - t;
-				if (w > floor(maxInt / baseMinusT)) {
-					error('overflow');
-				}
-
-				w *= baseMinusT;
-
-			}
-
-			out = output.length + 1;
-			bias = adapt(i - oldi, out, oldi == 0);
-
-			// `i` was supposed to wrap around from `out` to `0`,
-			// incrementing `n` each time, so we'll fix that now:
-			if (floor(i / out) > maxInt - n) {
-				error('overflow');
-			}
-
-			n += floor(i / out);
-			i %= out;
-
-			// Insert `n` at position `i` of the output
-			output.splice(i++, 0, n);
-
-		}
-
-		return ucs2encode(output);
-	}
-
-	/**
-	 * Converts a string of Unicode symbols (e.g. a domain name label) to a
-	 * Punycode string of ASCII-only symbols.
-	 * @memberOf punycode
-	 * @param {String} input The string of Unicode symbols.
-	 * @returns {String} The resulting Punycode string of ASCII-only symbols.
-	 */
-	function encode(input) {
-		var n,
-		    delta,
-		    handledCPCount,
-		    basicLength,
-		    bias,
-		    j,
-		    m,
-		    q,
-		    k,
-		    t,
-		    currentValue,
-		    output = [],
-		    /** `inputLength` will hold the number of code points in `input`. */
-		    inputLength,
-		    /** Cached calculation results */
-		    handledCPCountPlusOne,
-		    baseMinusT,
-		    qMinusT;
-
-		// Convert the input in UCS-2 to Unicode
-		input = ucs2decode(input);
-
-		// Cache the length
-		inputLength = input.length;
-
-		// Initialize the state
-		n = initialN;
-		delta = 0;
-		bias = initialBias;
-
-		// Handle the basic code points
-		for (j = 0; j < inputLength; ++j) {
-			currentValue = input[j];
-			if (currentValue < 0x80) {
-				output.push(stringFromCharCode(currentValue));
-			}
-		}
-
-		handledCPCount = basicLength = output.length;
-
-		// `handledCPCount` is the number of code points that have been handled;
-		// `basicLength` is the number of basic code points.
-
-		// Finish the basic string - if it is not empty - with a delimiter
-		if (basicLength) {
-			output.push(delimiter);
-		}
-
-		// Main encoding loop:
-		while (handledCPCount < inputLength) {
-
-			// All non-basic code points < n have been handled already. Find the next
-			// larger one:
-			for (m = maxInt, j = 0; j < inputLength; ++j) {
-				currentValue = input[j];
-				if (currentValue >= n && currentValue < m) {
-					m = currentValue;
-				}
-			}
-
-			// Increase `delta` enough to advance the decoder's <n,i> state to <m,0>,
-			// but guard against overflow
-			handledCPCountPlusOne = handledCPCount + 1;
-			if (m - n > floor((maxInt - delta) / handledCPCountPlusOne)) {
-				error('overflow');
-			}
-
-			delta += (m - n) * handledCPCountPlusOne;
-			n = m;
-
-			for (j = 0; j < inputLength; ++j) {
-				currentValue = input[j];
-
-				if (currentValue < n && ++delta > maxInt) {
-					error('overflow');
-				}
-
-				if (currentValue == n) {
-					// Represent delta as a generalized variable-length integer
-					for (q = delta, k = base; /* no condition */; k += base) {
-						t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);
-						if (q < t) {
-							break;
-						}
-						qMinusT = q - t;
-						baseMinusT = base - t;
-						output.push(
-							stringFromCharCode(digitToBasic(t + qMinusT % baseMinusT, 0))
-						);
-						q = floor(qMinusT / baseMinusT);
-					}
-
-					output.push(stringFromCharCode(digitToBasic(q, 0)));
-					bias = adapt(delta, handledCPCountPlusOne, handledCPCount == basicLength);
-					delta = 0;
-					++handledCPCount;
-				}
-			}
-
-			++delta;
-			++n;
-
-		}
-		return output.join('');
-	}
-
-	/**
-	 * Converts a Punycode string representing a domain name or an email address
-	 * to Unicode. Only the Punycoded parts of the input will be converted, i.e.
-	 * it doesn't matter if you call it on a string that has already been
-	 * converted to Unicode.
-	 * @memberOf punycode
-	 * @param {String} input The Punycoded domain name or email address to
-	 * convert to Unicode.
-	 * @returns {String} The Unicode representation of the given Punycode
-	 * string.
-	 */
-	function toUnicode(input) {
-		return mapDomain(input, function(string) {
-			return regexPunycode.test(string)
-				? decode(string.slice(4).toLowerCase())
-				: string;
-		});
-	}
-
-	/**
-	 * Converts a Unicode string representing a domain name or an email address to
-	 * Punycode. Only the non-ASCII parts of the domain name will be converted,
-	 * i.e. it doesn't matter if you call it with a domain that's already in
-	 * ASCII.
-	 * @memberOf punycode
-	 * @param {String} input The domain name or email address to convert, as a
-	 * Unicode string.
-	 * @returns {String} The Punycode representation of the given domain name or
-	 * email address.
-	 */
-	function toASCII(input) {
-		return mapDomain(input, function(string) {
-			return regexNonASCII.test(string)
-				? 'xn--' + encode(string)
-				: string;
-		});
-	}
-
-	/*--------------------------------------------------------------------------*/
-
-	/** Define the public API */
-	punycode = {
-		/**
-		 * A string representing the current Punycode.js version number.
-		 * @memberOf punycode
-		 * @type String
-		 */
-		'version': '1.4.1',
-		/**
-		 * An object of methods to convert from JavaScript's internal character
-		 * representation (UCS-2) to Unicode code points, and back.
-		 * @see <https://mathiasbynens.be/notes/javascript-encoding>
-		 * @memberOf punycode
-		 * @type Object
-		 */
-		'ucs2': {
-			'decode': ucs2decode,
-			'encode': ucs2encode
-		},
-		'decode': decode,
-		'encode': encode,
-		'toASCII': toASCII,
-		'toUnicode': toUnicode
-	};
-
-	/** Expose `punycode` */
-	// Some AMD build optimizers, like r.js, check for specific condition patterns
-	// like the following:
-	if (
-		true
-	) {
-		!(__WEBPACK_AMD_DEFINE_RESULT__ = (function() {
-			return punycode;
-		}).call(exports, __webpack_require__, exports, module),
-				__WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
-	} else if (freeExports && freeModule) {
-		if (module.exports == freeExports) {
-			// in Node.js, io.js, or RingoJS v0.8.0+
-			freeModule.exports = punycode;
-		} else {
-			// in Narwhal or RingoJS v0.7.0-
-			for (key in punycode) {
-				punycode.hasOwnProperty(key) && (freeExports[key] = punycode[key]);
-			}
-		}
-	} else {
-		// in Rhino or a web browser
-		root.punycode = punycode;
-	}
-
-}(this));
-
-/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(793)(module), __webpack_require__(792)))
-
 /***/ })
 
 /******/ });
 });
\ No newline at end of file
--- a/devtools/client/debugger/new/images/moz.build
+++ b/devtools/client/debugger/new/images/moz.build
@@ -37,32 +37,33 @@ DevToolsModules(
     'lodash.svg',
     'magnifying-glass.svg',
     'marko.svg',
     'mobx.svg',
     'next-circle.svg',
     'next.svg',
     'nextjs.svg',
     'nuxtjs.svg',
+    'pane-collapse.svg',
+    'pane-expand.svg',
     'pause.svg',
     'plus.svg',
     'preact.svg',
     'prettyPrint.svg',
     'pug.svg',
     'react.svg',
     'redux.svg',
     'regex-match.svg',
     'reload.svg',
     'resume.svg',
     'rxjs.svg',
     'sencha-extjs.svg',
     'stepIn.svg',
     'stepOut.svg',
     'stepOver.svg',
     'tab.svg',
-    'toggle-panes.svg',
     'typescript.svg',
     'underscore.svg',
     'vuejs.svg',
     'webpack.svg',
     'whole-word-match.svg',
     'worker.svg',
 )
new file mode 100644
--- /dev/null
+++ b/devtools/client/debugger/new/images/pane-collapse.svg
@@ -0,0 +1,7 @@
+<!-- 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/. -->
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
+  <path d="M4 3H2v10h2V3zm7 7V6L8 8l3 2z" fill-opacity=".3"/>
+  <path d="M11.47 10.88A1 1 0 0 0 12 10V6a1 1 0 0 0-1.55-.83l-3 2a1 1 0 0 0 0 1.66l3 2c.3.2.7.23 1.02.05zM8 8l3-2v4L8 8zM2 2h12c.6 0 1 .4 1 1v10c0 .6-.4 1-1 1H2c-.6 0-1-.4-1-1V3c0-.6.4-1 1-1zm12 11V3H5v10h9zM2 13h2V3H2v10z"/>
+</svg>
new file mode 100644
--- /dev/null
+++ b/devtools/client/debugger/new/images/pane-expand.svg
@@ -0,0 +1,7 @@
+<!-- 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/. -->
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" width="16" height="16">
+  <path d="M4 3H2v10h2V3zM8 6v4l3-2-3-2z" fill-opacity=".3"/>
+  <path d="M7.53 10.88A1 1 0 0 1 7 10V6a1 1 0 0 1 1.55-.83l3 2a1 1 0 0 1 0 1.66l-3 2a1 1 0 0 1-1.02.05zM11 8L8 6v4l3-2zM2 2h12c.6 0 1 .4 1 1v10c0 .6-.4 1-1 1H2c-.6 0-1-.4-1-1V3c0-.6.4-1 1-1zm12 11V3H5v10h9zM2 13h2V3H2v10z"/>
+</svg>
deleted file mode 100644
--- a/devtools/client/debugger/new/images/toggle-panes.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-<!-- 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/. -->
-<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="#0b0b0b">
-  <path fill-opacity=".3" d="M12,3h2v10h-2V3z M5,9.9V6.1L8,8L5,9.9z"/>
-  <path d="M14,2H2C1.4,2,1,2.4,1,3v10c0,0.6,0.4,1,1,1h12c0.6,0,1-0.4,1-1V3C15,2.4,14.6,2,14,2z M2,13L2,13V3h0h9v10   H2L2,13z M14,13C14,13,14,13,14,13h-2V3h2c0,0,0,0,0,0V13z M8.5,7.2l-3-1.9C4.6,4.7,4,5,4,6.1v3.8c0,1.1,0.6,1.4,1.5,0.8l3-1.9   C9.5,8.3,9.5,7.8,8.5,7.2z M5,9.9V6.1L8,8L5,9.9z"/>
-</svg>
--- a/devtools/client/debugger/new/src/actions/ast/setInScopeLines.js
+++ b/devtools/client/debugger/new/src/actions/ast/setInScopeLines.js
@@ -1,18 +1,23 @@
 /* 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/>. */
 
+// @flow
+
 import { getOutOfScopeLocations, getSelectedSource } from "../../selectors";
 import { getSourceLineCount } from "../../utils/source";
 
 import { range, flatMap, uniq, without } from "lodash";
 
-function getOutOfScopeLines(outOfScopeLocations: AstLocation[]) {
+import type { ASTLocation } from "../../types";
+import type { ThunkArgs } from "../types";
+
+function getOutOfScopeLines(outOfScopeLocations: ASTLocation[]) {
   if (!outOfScopeLocations) {
     return null;
   }
 
   return uniq(
     flatMap(outOfScopeLocations, location =>
       range(location.start.line, location.end.line)
     )
--- a/devtools/client/debugger/new/src/actions/navigation.js
+++ b/devtools/client/debugger/new/src/actions/navigation.js
@@ -28,18 +28,18 @@ import type { Action, ThunkArgs } from "
  * @module actions/navigation
  */
 
 /**
  * @memberof actions/navigation
  * @static
  */
 export function willNavigate(event: Object) {
-  return async function({ dispatch, getState, client, sourceMaps }: ThunkArgs) {
-    await sourceMaps.clearSourceMaps();
+  return function({ dispatch, getState, client, sourceMaps }: ThunkArgs) {
+    sourceMaps.clearSourceMaps();
     clearWasmStates();
     clearDocuments();
     clearSymbols();
     clearASTs();
     clearScopes();
     clearSources();
     dispatch(navigate(event.url));
   };
--- a/devtools/client/debugger/new/src/actions/pause/mapFrames.js
+++ b/devtools/client/debugger/new/src/actions/pause/mapFrames.js
@@ -134,16 +134,17 @@ async function expandFrames(
       // Keep outer most frame with true actor ID, and generate uniquie
       // one for the nested frames.
       const id = j == 0 ? frame.id : `${frame.id}-originalFrame${j}`;
       result.push({
         id,
         thread: originalFrame.thread,
         displayName: originalFrame.displayName,
         location: originalFrame.location,
+        source: null,
         scope: frame.scope,
         this: frame.this,
         isOriginal: true,
         // More fields that will be added by the mapDisplayNames and
         // updateFrameLocation.
         generatedLocation: frame.generatedLocation,
         originalDisplayName: originalFrame.displayName
       });
--- a/devtools/client/debugger/new/src/actions/pause/tests/pause.spec.js
+++ b/devtools/client/debugger/new/src/actions/pause/tests/pause.spec.js
@@ -341,27 +341,31 @@ describe("pause", () => {
         {
           displayName: "fooBar",
           generatedLocation: { column: 0, line: 1, sourceId: "foo-wasm" },
           id: mockFrameId,
           isOriginal: true,
           location: originalLocation,
           originalDisplayName: "fooBar",
           scope: { bindings: { arguments: [], variables: {} } },
-          this: undefined
+          source: null,
+          this: undefined,
+          thread: undefined
         },
         {
           displayName: "barZoo",
           generatedLocation: { column: 0, line: 1, sourceId: "foo-wasm" },
           id: `${mockFrameId}-originalFrame1`,
           isOriginal: true,
           location: originalLocation2,
           originalDisplayName: "barZoo",
           scope: { bindings: { arguments: [], variables: {} } },
-          this: undefined
+          source: null,
+          this: undefined,
+          thread: undefined
         }
       ]);
     });
   });
 
   describe("resumed", () => {
     it("should not evaluate expression while stepping", async () => {
       const client = { evaluateExpressions: jest.fn() };
--- a/devtools/client/debugger/new/src/actions/tests/__snapshots__/pending-breakpoints.spec.js.snap
+++ b/devtools/client/debugger/new/src/actions/tests/__snapshots__/pending-breakpoints.spec.js.snap
@@ -16,41 +16,43 @@ Object {
       "column": undefined,
       "line": 5,
       "sourceUrl": "http://localhost:8000/examples/bar.js",
     },
     "hidden": false,
     "location": Object {
       "column": undefined,
       "line": 5,
+      "sourceId": "",
       "sourceUrl": "http://localhost:8000/examples/bar.js",
     },
   },
 }
 `;
 
 exports[`invalid breakpoint location a corrected corresponding pending breakpoint is added 1`] = `
 Object {
   "astLocation": Object {
     "index": 0,
     "name": undefined,
     "offset": Object {
+      "column": 0,
       "line": 7,
       "sourceId": "foo.js",
       "sourceUrl": "http://localhost:8000/examples/foo.js",
     },
   },
   "disabled": false,
   "generatedLocation": Object {
-    "column": undefined,
+    "column": 0,
     "line": 7,
     "sourceUrl": "http://localhost:8000/examples/foo.js",
   },
   "location": Object {
-    "column": undefined,
+    "column": 0,
     "line": 7,
     "sourceUrl": "http://localhost:8000/examples/foo.js",
   },
   "options": Object {
     "condition": null,
     "hidden": false,
     "logValue": null,
   },
--- a/devtools/client/debugger/new/src/actions/tests/helpers/breakpoints.js
+++ b/devtools/client/debugger/new/src/actions/tests/helpers/breakpoints.js
@@ -1,16 +1,19 @@
 /* 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/>. */
 
-export function mockPendingBreakpoint(overrides = {}) {
+// @flow
+
+export function mockPendingBreakpoint(overrides: Object = {}) {
   const { sourceUrl, line, column, condition, disabled, hidden } = overrides;
   return {
     location: {
+      sourceId: "",
       sourceUrl: sourceUrl || "http://localhost:8000/examples/bar.js",
       line: line || 5,
       column: column || undefined
     },
     generatedLocation: {
       sourceUrl: sourceUrl || "http://localhost:8000/examples/bar.js",
       line: line || 5,
       column: column || undefined
@@ -23,29 +26,38 @@ export function mockPendingBreakpoint(ov
       index: 0
     },
     condition: condition || null,
     disabled: disabled || false,
     hidden: hidden || false
   };
 }
 
-export function generateBreakpoint(filename, line = 5, column) {
+export function generateBreakpoint(
+  filename: string,
+  line: number = 5,
+  column: number = 0
+) {
   return {
+    id: "breakpoint",
+    loading: false,
+    originalText: "",
+    text: "",
     location: {
       sourceUrl: `http://localhost:8000/examples/${filename}`,
       sourceId: `${filename}/originalSource`,
       line,
       column
     },
     generatedLocation: {
       sourceUrl: `http://localhost:8000/examples/${filename}`,
       sourceId: filename,
       line,
       column
     },
+    astLocation: undefined,
     options: {
-      condition: null,
+      condition: "",
       hidden: false
     },
     disabled: false
   };
 }
--- a/devtools/client/debugger/new/src/actions/tests/helpers/readFixture.js
+++ b/devtools/client/debugger/new/src/actions/tests/helpers/readFixture.js
@@ -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/>. */
 
+// @flow
+
 import fs from "fs";
 import path from "path";
 
-export default function readFixture(name) {
+export default function readFixture(name: string) {
   const text = fs.readFileSync(
     path.join(__dirname, `../fixtures/${name}`),
     "utf8"
   );
   return text;
 }
--- a/devtools/client/debugger/new/src/actions/tests/helpers/threadClient.js
+++ b/devtools/client/debugger/new/src/actions/tests/helpers/threadClient.js
@@ -1,13 +1,22 @@
 /* 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/>. */
 
-import { makeBreakpointId } from "../../../utils/breakpoint";
+// @flow
+
+import { makeBreakpointActorId } from "../../../utils/breakpoint";
+
+import type {
+  SourceLocation,
+  SourceActor,
+  SourceActorLocation,
+  BreakpointOptions
+} from "../../../types";
 
 function createSource(name) {
   name = name.replace(/\..*$/, "");
   return {
     source: `function ${name}() {\n  return ${name} \n}`,
     contentType: "text/javascript"
   };
 }
@@ -26,67 +35,79 @@ const sources = [
   "foo.js",
   "bar.js",
   "base.js",
   "bazz.js",
   "jquery.js"
 ];
 
 export const simpleMockThreadClient = {
-  getBreakpointByLocation: jest.fn(),
-  setBreakpoint: (location, _condition) =>
+  getBreakpointByLocation: (jest.fn(): any),
+  setBreakpoint: (location: SourceActorLocation, _condition: string) =>
     Promise.resolve({ id: "hi", actualLocation: location }),
 
-  removeBreakpoint: _id => Promise.resolve(),
+  removeBreakpoint: (_id: string) => Promise.resolve(),
 
-  setBreakpointOptions: (_id, _location, _options, _noSliding) =>
-    Promise.resolve({ sourceId: "a", line: 5 }),
+  setBreakpointOptions: (
+    _id: string,
+    _location: SourceActorLocation,
+    _options: BreakpointOptions,
+    _noSliding: boolean
+  ) => Promise.resolve({ sourceId: "a", line: 5 }),
   setPausePoints: () => Promise.resolve({}),
-  sourceContents: ({ source }) =>
+  sourceContents: ({
+    source
+  }: SourceActor): Promise<{| source: any, contentType: ?string |}> =>
     new Promise((resolve, reject) => {
       if (sources.includes(source)) {
         resolve(createSource(source));
       }
 
       reject(`unknown source: ${source}`);
     })
 };
 
 // Breakpoint Sliding
 function generateCorrectingThreadClient(offset = 0) {
   return {
-    getBreakpointByLocation: jest.fn(),
-    setBreakpoint: (location, condition) => {
+    getBreakpointByLocation: (jest.fn(): any),
+    setBreakpoint: (location: SourceActorLocation, condition: string) => {
       const actualLocation = { ...location, line: location.line + offset };
 
       return Promise.resolve({
-        id: makeBreakpointId(location),
+        id: makeBreakpointActorId(location),
         actualLocation,
         condition
       });
     },
-    sourceContents: ({ source }) => Promise.resolve(createSource(source))
+    sourceContents: ({ source }: SourceActor) =>
+      Promise.resolve(createSource(source))
   };
 }
 
 /* in some cases, a breakpoint may be added, but the source will respond
  * with a different breakpoint location. This is due to the breakpoint being
  * added between functions, or somewhere that doesnt make sense. This function
  * simulates that behavior.
  * */
-export function simulateCorrectThreadClient(offset, location) {
+export function simulateCorrectThreadClient(
+  offset: number,
+  location: SourceLocation
+) {
   const correctedThreadClient = generateCorrectingThreadClient(offset);
   const offsetLine = { line: location.line + offset };
   const correctedLocation = { ...location, ...offsetLine };
   return { correctedThreadClient, correctedLocation };
 }
 
 // sources and tabs
 export const sourceThreadClient = {
-  sourceContents: function({ source }) {
+  sourceContents: function({
+    source
+  }: SourceActor): Promise<{| source: any, contentType: ?string |}> {
     return new Promise((resolve, reject) => {
       if (sources.includes(source)) {
         resolve(createSource(source));
       }
 
       reject(`unknown source: ${source}`);
     });
   },
--- a/devtools/client/debugger/new/src/actions/utils/middleware/log.js
+++ b/devtools/client/debugger/new/src/actions/utils/middleware/log.js
@@ -1,29 +1,32 @@
 /* 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/>. */
 /* global window */
 
+// @flow
+
 import { isTesting } from "devtools-environment";
+import type { ThunkArgs } from "../../types";
 
 const blacklist = [
   "SET_POPUP_OBJECT_PROPERTIES",
   "SET_PAUSE_POINTS",
   "SET_SYMBOLS",
   "OUT_OF_SCOPE_LOCATIONS",
   "MAP_SCOPES",
   "MAP_FRAMES",
   "ADD_SCOPES",
   "IN_SCOPE_LINES",
   "REMOVE_BREAKPOINT",
   "NODE_PROPERTIES_LOADED"
 ];
 
-function cloneAction(action) {
+function cloneAction(action: any) {
   action = action || {};
   action = { ...action };
 
   // ADD_TAB, ...
   if (action.source && action.source.text) {
     const source = { ...action.source, text: "" };
     action.source = source;
   }
@@ -74,28 +77,30 @@ function serializeAction(action) {
     if (action.type === "PAUSED") {
       action = formatPause(action);
     }
 
     // dump(`> ${action.type}...\n ${JSON.stringify(action)}\n`);
     return JSON.stringify(action);
   } catch (e) {
     console.error(e);
+    return "";
   }
 }
 
 /**
  * A middleware that logs all actions coming through the system
  * to the console.
  */
-export function log({ dispatch, getState }) {
-  return next => action => {
+export function log({ dispatch, getState }: ThunkArgs) {
+  return (next: any) => (action: any) => {
     const asyncMsg = !action.status ? "" : `[${action.status}]`;
 
     if (isTesting()) {
+      // $FlowIgnore
       dump(
         `[ACTION] ${action.type} ${asyncMsg} - ${serializeAction(action)}\n`
       );
     } else {
       console.log(action, asyncMsg);
     }
 
     next(action);
--- a/devtools/client/debugger/new/src/actions/utils/middleware/timing.js
+++ b/devtools/client/debugger/new/src/actions/utils/middleware/timing.js
@@ -1,30 +1,32 @@
 /* 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/>. */
 
+// @flow
+
 /* global window */
 
 /**
  * Redux middleware that sets performance markers for all actions such that they
  * will appear in performance tooling under the User Timing API
  */
 
 const mark =
   window.performance && window.performance.mark
     ? window.performance.mark.bind(window.performance)
-    : () => {};
+    : a => {};
 
 const measure =
   window.performance && window.performance.measure
     ? window.performance.measure.bind(window.performance)
-    : () => {};
+    : (a, b, c) => {};
 
-export function timing(store) {
-  return next => action => {
+export function timing(store: any) {
+  return (next: any) => (action: any) => {
     mark(`${action.type}_start`);
     const result = next(action);
     mark(`${action.type}_end`);
     measure(`${action.type}`, `${action.type}_start`, `${action.type}_end`);
     return result;
   };
 }
--- a/devtools/client/debugger/new/src/client/firefox/create.js
+++ b/devtools/client/debugger/new/src/client/firefox/create.js
@@ -41,16 +41,17 @@ export function createFrame(thread: Thre
 
   return {
     id: frame.actor,
     thread,
     displayName: title,
     location,
     generatedLocation: location,
     this: frame.this,
+    source: null,
     scope: frame.environment
   };
 }
 
 function makeSourceId(source) {
   return source.url ? `sourceURL-${source.url}` : `source-${source.actor}`;
 }
 
--- a/devtools/client/debugger/new/src/components/App.css
+++ b/devtools/client/debugger/new/src/components/App.css
@@ -4,42 +4,45 @@
 
 * {
   box-sizing: border-box;
 }
 
 button {
   background: transparent;
   border: none;
+  font-family: inherit;
+  font-size: inherit;
 }
 
 button:hover,
 button:focus {
   background-color: var(--theme-toolbar-background-hover);
 }
 
+.theme-dark button:hover,
+.theme-dark button:focus {
+  background-color: var(--theme-toolbar-hover);
+}
+
 .debugger {
   display: flex;
   flex: 1;
   height: 100%;
 }
 
 .editor-pane {
   display: flex;
   position: relative;
   flex: 1;
-  background-color: var(--theme-tab-toolbar-background);
-  height: calc(100% - 1px);
+  background-color: var(--theme-body-background);
+  height: 100%;
   overflow: hidden;
 }
 
-.theme-dark .editor-pane {
-  background-color: var(--theme-toolbar-background);
-}
-
 .editor-container {
   width: 100%;
 }
 
 .search-container {
   position: absolute;
   top: 0;
   left: 0;
--- a/devtools/client/debugger/new/src/components/Editor/ColumnBreakpoints.css
+++ b/devtools/client/debugger/new/src/components/Editor/ColumnBreakpoints.css
@@ -1,16 +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/>. */
 
 .column-breakpoint {
   display: inline;
   padding: 0;
-  margin-inline-end: 4px;
+  padding-inline-end: 4px;
 }
 
 .column-breakpoint:hover {
   background-color: transparent;
 }
 
 .column-breakpoint svg {
   display: inline;
--- a/devtools/client/debugger/new/src/components/Editor/ColumnBreakpoints.js
+++ b/devtools/client/debugger/new/src/components/Editor/ColumnBreakpoints.js
@@ -1,34 +1,38 @@
 /* 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/>. */
 
+// @flow
+
 import React, { Component } from "react";
 
 import ColumnBreakpoint from "./ColumnBreakpoint";
 import "./ColumnBreakpoints.css";
 
 import { getSelectedSource, visibleColumnBreakpoints } from "../../selectors";
 import { connect } from "../../utils/connect";
 import { makeBreakpointId } from "../../utils/breakpoint";
 import { breakpointItemActions } from "./menus/breakpoints";
 import type { BreakpointItemActions } from "./menus/breakpoints";
 
 import type { Source } from "../../types";
 // eslint-disable-next-line max-len
 import type { ColumnBreakpoint as ColumnBreakpointType } from "../../selectors/visibleColumnBreakpoints";
 
-class ColumnBreakpoints extends Component {
-  props: {
-    editor: Object,
-    selectedSource: Source,
-    columnBreakpoints: ColumnBreakpointType[],
-    breakpointActions: BreakpointItemActions
-  };
+type Props = {
+  editor: Object,
+  selectedSource: Source,
+  columnBreakpoints: ColumnBreakpointType[],
+  breakpointActions: BreakpointItemActions
+};
+
+class ColumnBreakpoints extends Component<Props> {
+  props: Props;
 
   render() {
     const {
       editor,
       columnBreakpoints,
       selectedSource,
       breakpointActions
     } = this.props;
--- a/devtools/client/debugger/new/src/components/Editor/ConditionalPanel.css
+++ b/devtools/client/debugger/new/src/components/Editor/ConditionalPanel.css
@@ -28,11 +28,15 @@
   width: calc(100% - 4em);
   border: none;
   background: var(--theme-toolbar-background);
   font-size: 14px;
   color: var(--theme-conditional-breakpoint-color);
   line-height: 30px;
 }
 
+.conditional-breakpoint-panel input:not(:placeholder-shown) {
+  font-family: var(--monospace-font-family);
+}
+
 .conditional-breakpoint-panel input:focus {
   outline-width: 0;
 }
--- a/devtools/client/debugger/new/src/components/Editor/Editor.css
+++ b/devtools/client/debugger/new/src/components/Editor/Editor.css
@@ -1,19 +1,17 @@
 /* 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/>. */
 
 .editor-wrapper {
   --debug-line-border: rgb(145, 188, 219);
   --debug-expression-background: rgba(202, 227, 255, 0.5);
-  --editor-searchbar-height: 27px;
   --debug-line-error-border: rgb(255, 0, 0);
   --debug-expression-error-background: rgba(231, 116, 113, 0.3);
-  --editor-header-height: 30px;
   --highlight-line-duration: 1500ms;
 }
 
 .theme-dark .editor-wrapper {
   --debug-expression-background: rgba(202, 227, 255, 0.3);
   --debug-line-border: #7786a2;
 }
 
@@ -43,17 +41,16 @@
  * BUG https://github.com/devtools-html/debugger.html/issues/63
  */
 .editor-wrapper {
   position: absolute;
   height: calc(100% - var(--editor-header-height));
   width: calc(100% - 1px);
   top: var(--editor-header-height);
   left: 0px;
-  --editor-footer-height: 24px;
 }
 
 html[dir="rtl"] .editor-mount {
   direction: ltr;
 }
 
 .theme-light {
   --gutter-hover-background-color: #dde1e4;
--- a/devtools/client/debugger/new/src/components/Editor/EditorMenu.js
+++ b/devtools/client/debugger/new/src/components/Editor/EditorMenu.js
@@ -1,32 +1,41 @@
 /* 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/>. */
 
+// @flow
+
 import { Component } from "react";
 import { connect } from "../../utils/connect";
 import { showMenu } from "devtools-contextmenu";
 
 import { getSourceLocationFromMouseEvent } from "../../utils/editor";
 import { getPrettySource, getIsPaused } from "../../selectors";
 
 import { editorMenuItems, editorItemActions } from "./menus/editor";
-import type { EditorMenuActions } from "./menus/editor";
+
+import type { Source } from "../../types";
+import type { EditorItemActions } from "./menus/editor";
+import type SourceEditor from "../../utils/editor/source-editor";
 
 type Props = {
   contextMenu: ?MouseEvent,
-  editorActions: EditorMenuActions,
-  clearContextMenu: () => {}
+  editorActions: EditorItemActions,
+  clearContextMenu: () => void,
+  editor: SourceEditor,
+  hasPrettySource: boolean,
+  isPaused: boolean,
+  selectedSource: Source
 };
 
-class EditorMenu extends Component {
+class EditorMenu extends Component<Props> {
   props: Props;
 
-  componentWillUpdate(nextProps) {
+  componentWillUpdate(nextProps: Props) {
     this.props.clearContextMenu();
     if (nextProps.contextMenu) {
       this.showMenu(nextProps);
     }
   }
 
   showMenu(props) {
     const {
@@ -36,17 +45,18 @@ class EditorMenu extends Component {
       hasPrettySource,
       isPaused,
       contextMenu: event
     } = props;
 
     const location = getSourceLocationFromMouseEvent(
       editor,
       selectedSource,
-      event
+      // Use a coercion, as contextMenu is optional
+      (event: any)
     );
 
     showMenu(
       event,
       editorMenuItems({
         editorActions,
         selectedSource,
         hasPrettySource,
--- a/devtools/client/debugger/new/src/components/Editor/EmptyLines.js
+++ b/devtools/client/debugger/new/src/components/Editor/EmptyLines.js
@@ -1,26 +1,28 @@
 /* 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/>. */
 
+// @flow
+
 import { connect } from "../../utils/connect";
 import { Component } from "react";
 import { getSelectedSource, getEmptyLines } from "../../selectors";
 import type { Source } from "../../types";
 import { toEditorLine } from "../../utils/editor";
 
-type props = {
+type Props = {
   selectedSource: Source,
   editor: Object,
   emptyLines: Object
 };
 
-class EmptyLines extends Component {
-  props: props;
+class EmptyLines extends Component<Props> {
+  props: Props;
 
   disableEmptyLines: Function;
 
   componentDidMount() {
     this.disableEmptyLines();
   }
 
   componentDidUpdate() {
@@ -58,16 +60,19 @@ class EmptyLines extends Component {
 
   render() {
     return null;
   }
 }
 
 const mapStateToProps = state => {
   const selectedSource = getSelectedSource(state);
+  if (!selectedSource) {
+    throw new Error("no selectedSource");
+  }
   const foundEmptyLines = getEmptyLines(state, selectedSource.id);
 
   return {
     selectedSource,
     emptyLines: selectedSource ? foundEmptyLines : []
   };
 };
 
--- a/devtools/client/debugger/new/src/components/Editor/Footer.css
+++ b/devtools/client/debugger/new/src/components/Editor/Footer.css
@@ -31,17 +31,17 @@
 
 .source-footer > .commands > .action {
   display: flex;
   justify-content: center;
   align-items: center;
   transition: opacity 200ms;
   border: none;
   background: transparent;
-  padding: 6px;
+  padding: 4px 6px;
 }
 
 .source-footer > .commands > .action .img {
   height: 100%;
   display: flex;
   flex-direction: column;
   justify-content: center;
 }
--- a/devtools/client/debugger/new/src/components/Editor/Footer.js
+++ b/devtools/client/debugger/new/src/components/Editor/Footer.js
@@ -151,19 +151,19 @@ class SourceFooter extends PureComponent
     if (this.props.horizontal) {
       return;
     }
 
     return (
       <PaneToggleButton
         position="end"
         key="toggle"
-        collapsed={!this.props.endPanelCollapsed}
+        collapsed={this.props.endPanelCollapsed}
         horizontal={this.props.horizontal}
-        handleClick={this.props.togglePaneCollapse}
+        handleClick={(this.props.togglePaneCollapse: any)}
       />
     );
   }
 
   renderCommands() {
     const commands = [
       this.prettyPrintButton(),
       this.blackBoxButton(),
--- a/devtools/client/debugger/new/src/components/Editor/SearchBar.css
+++ b/devtools/client/debugger/new/src/components/Editor/SearchBar.css
@@ -1,22 +1,22 @@
 /* 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/>. */
 
 .search-bar {
   display: flex;
   border: 1px solid transparent;
-  border-top: 1px solid var(--theme-splitter-color);
+  border-top-color: var(--theme-splitter-color);
   height: var(--editor-searchbar-height);
+  transition: border-color 200ms var(--animation-curve);
 }
 
 .search-bar.search-bar-focused {
-  border: 1px solid var(--blue-50);
-  transition: border-color 0.2s ease-in-out;
+  border-color: var(--blue-50);
 }
 
 .search-bar .search-field {
   padding-left: 7px;
 }
 
 .search-bar .search-shadow {
   flex-grow: 1;
--- a/devtools/client/debugger/new/src/components/Editor/Tabs.css
+++ b/devtools/client/debugger/new/src/components/Editor/Tabs.css
@@ -1,140 +1,95 @@
 /* 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/>. */
 
 .source-header {
-  border-bottom: 1px solid var(--theme-splitter-color);
+  display: flex;
   width: 100%;
-  height: 29px;
-  display: flex;
+  height: var(--editor-header-height);
+  border-bottom: 1px solid var(--theme-splitter-color);
+  background-color: var(--theme-toolbar-background);
 }
 
 .source-header * {
   -moz-user-select: none;
   user-select: none;
 }
 
-.source-header .new-tab-btn {
-  padding: 4px;
-  margin-top: 4px;
-  margin-left: 2px;
-  fill: var(--theme-comment);
-  transition: 0.1s ease;
-  align-self: center;
-}
-
-.source-header .new-tab-btn:hover {
-  background-color: var(--theme-toolbar-background-hover);
-}
-
-.source-header .new-tab-btn svg {
-  width: 12px;
-  display: block;
-}
-
 .source-tabs {
   max-width: calc(100% - 80px);
   align-self: flex-start;
 }
 
 .source-tab {
   display: inline-flex;
   align-items: center;
   position: relative;
   min-width: 40px;
   max-width: 100%;
   overflow: hidden;
   padding: 5px;
   cursor: default;
-  height: 30px;
+  height: calc(var(--editor-header-height) - 1px);
   font-size: 12px;
   background-color: transparent;
+  vertical-align: bottom;
 }
 
 .source-tab::before {
   content: "";
   position: absolute;
   top: 0;
   left: 0;
   width: 100%;
   height: 2px;
-  background: transparent;
+  background-color: var(--tab-line-color, transparent);
   transition: transform 250ms var(--animation-curve), opacity 250ms var(--animation-curve);
   opacity: 0;
   transform: scaleX(0);
 }
 
-.source-tab:first-child {
-  margin-inline-start: 0;
-}
-
-.source-tab:not(.active):hover {
-  background: linear-gradient(var(--theme-toolbar-hover) 28px, transparent 1px);
-}
-
-.source-tab:not(.active):hover::before {
-  background: var(--tab-line-hover-color);
-  opacity: 1;
-  transform: scaleX(1);
-}
-
 .source-tab.active {
+  --tab-line-color: var(--tab-line-selected-color);
   color: var(--theme-toolbar-selected-color);
   border-bottom-color: transparent;
 }
 
-.source-tab.active::before {
-  background: var(--tab-line-selected-color);
-  opacity: 1;
-  transform: scaleX(1);
+.source-tab:not(.active):hover {
+  --tab-line-color: var(--tab-line-hover-color);
+  background-color: var(--theme-toolbar-hover);
 }
 
-.theme-dark .source-tab.active {
-  color: var(--theme-toolbar-selected-color);
-}
-
-.source-tab.active path,
-.source-tab:hover path {
-  fill: var(--theme-body-color);
+.source-tab:hover::before,
+.source-tab.active::before {
+  opacity: 1;
+  transform: scaleX(1);
 }
 
 .source-tab .source-icon {
   margin-inline-end: 0;
 }
 
 .source-tab .img.prettyPrint,
 .source-tab .source-icon.blackBox {
   height: 12px;
   width: 12px;
   align-self: center;
 }
 
-.source-tab .prettyPrint path {
-  fill: var(--theme-textbox-box-shadow);
-}
-
 .source-tab .img.react {
   mask: url(/images/react.svg) no-repeat;
   mask-size: 100%;
   height: 14px;
   width: 14px;
   background: var(--theme-highlight-bluegrey);
   top: 0;
 }
 
-.source-tab .blackBox path {
-  fill: var(--theme-textbox-box-shadow);
-}
-
-.theme-dark .source-tab .blackBox circle {
-  fill: var(--theme-body-color);
-}
-
 .source-tab .filename {
   white-space: nowrap;
   text-overflow: ellipsis;
   overflow: hidden;
   padding: 0 4px;
   align-self: center;
   margin-bottom: 1px;
 }
--- a/devtools/client/debugger/new/src/components/Editor/Tabs.js
+++ b/devtools/client/debugger/new/src/components/Editor/Tabs.js
@@ -169,33 +169,33 @@ class Tabs extends PureComponent<Props, 
 
     return <Dropdown panel={Panel} icon={icon} />;
   }
 
   renderStartPanelToggleButton() {
     return (
       <PaneToggleButton
         position="start"
-        collapsed={!this.props.startPanelCollapsed}
-        handleClick={this.props.togglePaneCollapse}
+        collapsed={this.props.startPanelCollapsed}
+        handleClick={(this.props.togglePaneCollapse: any)}
       />
     );
   }
 
   renderEndPanelToggleButton() {
     const { horizontal, endPanelCollapsed, togglePaneCollapse } = this.props;
     if (!horizontal) {
       return;
     }
 
     return (
       <PaneToggleButton
         position="end"
-        collapsed={!endPanelCollapsed}
-        handleClick={togglePaneCollapse}
+        collapsed={endPanelCollapsed}
+        handleClick={(togglePaneCollapse: any)}
         horizontal={horizontal}
       />
     );
   }
 
   render() {
     return (
       <div className="source-header">
--- a/devtools/client/debugger/new/src/components/Editor/index.js
+++ b/devtools/client/debugger/new/src/components/Editor/index.js
@@ -119,17 +119,17 @@ type State = {
 
 class Editor extends PureComponent<Props, State> {
   $editorWrapper: ?HTMLDivElement;
   constructor(props: Props) {
     super(props);
 
     this.state = {
       highlightedLineRange: null,
-      editor: null,
+      editor: (null: any),
       contextMenu: null
     };
   }
 
   componentWillReceiveProps(nextProps) {
     if (!this.state.editor) {
       return;
     }
@@ -237,17 +237,17 @@ class Editor extends PureComponent<Props
       this.props.closeTab(selectedSource);
     }
   };
 
   componentWillUnmount() {
     if (this.state.editor) {
       this.state.editor.destroy();
       this.state.editor.codeMirror.off("scroll", this.onEditorScroll);
-      this.setState({ editor: null });
+      this.setState({ editor: (null: any) });
     }
 
     const searchAgainKey = L10N.getStr("sourceSearch.search.again.key2");
     const searchAgainPrevKey = L10N.getStr(
       "sourceSearch.search.againPrev.key2"
     );
     const shortcuts = this.context.shortcuts;
     shortcuts.off(L10N.getStr("sourceTabs.closeTab.key"));
@@ -601,17 +601,17 @@ class Editor extends PureComponent<Props
     }
 
     return (
       <div>
         <DebugLine editor={editor} />
         <HighlightLine />
         <EmptyLines editor={editor} />
         <Breakpoints editor={editor} />
-        <Preview editor={editor} editorRef={this.$editorWrapper} />;
+        <Preview editor={editor} editorRef={this.$editorWrapper} />
         <Footer editor={editor} horizontal={horizontal} />
         <HighlightLines editor={editor} />
         {
           <EditorMenu
             editor={editor}
             contextMenu={contextMenu}
             clearContextMenu={this.clearContextMenu}
             selectedSource={selectedSource}
--- a/devtools/client/debugger/new/src/components/Editor/menus/source.js
+++ b/devtools/client/debugger/new/src/components/Editor/menus/source.js
@@ -1,3 +1,5 @@
 /* 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/>. */
+
+// @flow
--- a/devtools/client/debugger/new/src/components/Editor/tests/Footer.spec.js
+++ b/devtools/client/debugger/new/src/components/Editor/tests/Footer.spec.js
@@ -23,16 +23,17 @@ function generateDefaults(overrides) {
   return {
     editor: {
       codeMirror: {
         doc: {},
         cursorActivity: jest.fn(),
         on: jest.fn()
       }
     },
+    endPanelCollapsed: false,
     selectedSource: makeSource("foo").source,
     ...overrides
   };
 }
 
 function render(overrides = {}, position = { line: 0, column: 0 }) {
   const clear = jest.fn();
   const props = generateDefaults(overrides);
--- a/devtools/client/debugger/new/src/components/Editor/tests/__snapshots__/Footer.spec.js.snap
+++ b/devtools/client/debugger/new/src/components/Editor/tests/__snapshots__/Footer.spec.js.snap
@@ -6,17 +6,17 @@ exports[`SourceFooter Component default 
 >
   <span
     className="cursor-position"
     title="(Line 2, column 2)"
   >
     (2, 2)
   </span>
   <PaneToggleButton
-    collapsed={true}
+    collapsed={false}
     horizontal={false}
     key="toggle"
     position="end"
   />
 </div>
 `;
 
 exports[`SourceFooter Component move cursor should render new cursor position 1`] = `
@@ -25,15 +25,15 @@ exports[`SourceFooter Component move cur
 >
   <span
     className="cursor-position"
     title="(Line 6, column 11)"
   >
     (6, 11)
   </span>
   <PaneToggleButton
-    collapsed={true}
+    collapsed={false}
     horizontal={false}
     key="toggle"
     position="end"
   />
 </div>
 `;
--- a/devtools/client/debugger/new/src/components/PrimaryPanes/Outline.css
+++ b/devtools/client/debugger/new/src/components/PrimaryPanes/Outline.css
@@ -25,17 +25,16 @@
   margin: 0;
   padding: 0 0 4px 0;
   position: absolute;
   top: 38px;
   bottom: 25px;
   left: 0;
   right: 0;
   list-style-type: none;
-  font-family: var(--monospace-font-family);
   overflow: auto;
 }
 
 .outline-list__class-list {
   margin: 0;
   padding: 0;
   list-style: none;
 }
--- a/devtools/client/debugger/new/src/components/PrimaryPanes/Outline.js
+++ b/devtools/client/debugger/new/src/components/PrimaryPanes/Outline.js
@@ -202,17 +202,17 @@ export class Outline extends Component<P
 
     if (this.props.alphabetizeOutline) {
       namedFunctions = sortBy(namedFunctions, "name");
       classes = sortBy(classes, "klass");
       classFunctions = sortBy(classFunctions, "name");
     }
 
     return (
-      <ul className="outline-list">
+      <ul className="outline-list devtools-monospace">
         {namedFunctions.map(func => this.renderFunction(func))}
         {classes.map(klass => this.renderClassFunctions(klass, classFunctions))}
       </ul>
     );
   }
 
   renderFooter() {
     return (
--- a/devtools/client/debugger/new/src/components/PrimaryPanes/Sources.css
+++ b/devtools/client/debugger/new/src/components/PrimaryPanes/Sources.css
@@ -144,68 +144,68 @@
 .tree-indent {
   border-inline-start: 0 none;
 }
 
 .source-outline-tabs {
   font-size: 12px;
   width: 100%;
   background: var(--theme-body-background);
-  border-top: 1px solid var(--theme-splitter-color);
   display: flex;
   -moz-user-select: none;
   user-select: none;
   box-sizing: border-box;
-  height: 29px;
+  height: var(--editor-header-height);
   margin: 0;
   padding: 0;
+  border-bottom: 1px solid var(--theme-splitter-color);
 }
 
 .source-outline-tabs .tab {
+  align-items: center;
   background-color: var(--theme-toolbar-background);
-  border-top: 2px solid transparent;
-  border-bottom: 1px solid var(--theme-splitter-color);
   color: var(--theme-toolbar-color);
   cursor: default;
   display: inline-flex;
   flex: 1;
   justify-content: center;
-  margin-bottom: 0px;
-  margin-top: -1px;
   overflow: hidden;
-  padding: 5px 8px 7px 8px;
+  padding: 5px;
   position: relative;
   transition: all 0.25s ease;
 }
 
-.source-outline-tabs .tab:not(.active):hover {
-  background-color: var(--theme-toolbar-hover);
-  border-top: 2px solid rgba(0, 0, 0, 0.2);
-}
-
-.theme-dark .source-outline-tabs .tab:hover {
-  border-top: 2px solid var(--tab-line-hover-color);
+.source-outline-tabs .tab::before {
+  content: "";
+  position: absolute;
+  top: 0;
+  left: 0;
+  width: 100%;
+  height: 2px;
+  background-color: var(--tab-line-color, transparent);
+  transition: transform 250ms var(--animation-curve), opacity 250ms var(--animation-curve);
+  opacity: 0;
+  transform: scaleX(0);
 }
 
 .source-outline-tabs .tab.active {
-  border-top: 2px solid var(--tab-line-selected-color);
+  --tab-line-color: var(--tab-line-selected-color);
   color: var(--theme-toolbar-selected-color);
-}
-
-.theme-dark .source-outline-tabs .tab.active {
-  color: var(--theme-toolbar-selected-color);
+  border-bottom-color: transparent;
 }
 
-.theme-dark .source-outline-tabs .tab.active:hover {
-  border-top: 2px solid var(--tab-line-selected-color);
+.source-outline-tabs .tab:not(.active):hover {
+  --tab-line-color: var(--tab-line-hover-color);
+  background-color: var(--theme-toolbar-hover);
 }
 
-.source-outline-tabs .tab.active path,
-.source-outline-tabs .tab:hover path {
-  fill: var(--theme-body-color);
+.source-outline-tabs .tab:hover::before,
+.source-outline-tabs .tab.active::before {
+  opacity: 1;
+  transform: scaleX(1);
 }
 
 .source-outline-panel {
   flex: 1;
   overflow: auto;
 }
 
 .source-outline-panel.has-root > div {
--- a/devtools/client/debugger/new/src/components/ProjectSearch.js
+++ b/devtools/client/debugger/new/src/components/ProjectSearch.js
@@ -49,17 +49,18 @@ type Result = {
   matches: Array<Match>,
   sourceId: string
 };
 
 type Item = Result | Match;
 
 type State = {
   inputValue: string,
-  inputFocused: boolean
+  inputFocused: boolean,
+  focusedItem: ?Item
 };
 
 type Props = {
   query: string,
   results: List<Result>,
   status: StatusType,
   activeSearch: ActiveSearchType,
   closeProjectSearch: typeof actions.closeProjectSearch,
@@ -76,33 +77,23 @@ function getFilePath(item: Item, index?:
     : `${item.sourceId}-${item.line}-${item.column}-${index || "$"}`;
 }
 
 function sanitizeQuery(query: string): string {
   // no '\' at end of query
   return query.replace(/\\$/, "");
 }
 
-type FileItem = {
-  setExpanded: (Result, boolean) => mixed,
-  file: Result,
-  expanded: boolean
-};
-type MatchItem = {
-  expanded: null,
-  match: Match
-};
-
 export class ProjectSearch extends Component<Props, State> {
-  focusedItem: ?(FileItem | MatchItem);
   constructor(props: Props) {
     super(props);
     this.state = {
       inputValue: this.props.query || "",
-      inputFocused: false
+      inputFocused: false,
+      focusedItem: null
     };
   }
 
   componentDidMount() {
     const { shortcuts } = this.context;
 
     shortcuts.on(
       L10N.getStr("projectTextSearch.key"),
@@ -168,60 +159,56 @@ export class ProjectSearch extends Compo
       return;
     }
 
     e.stopPropagation();
 
     if (e.key !== "Enter") {
       return;
     }
-    this.focusedItem = null;
+    this.setState({ focusedItem: null });
     const query = sanitizeQuery(this.state.inputValue);
     if (query) {
       this.doSearch(query);
     }
   };
 
   onHistoryScroll = (query: string) => {
     this.setState({ inputValue: query });
   };
 
   onEnterPress = () => {
-    if (!this.focusedItem || this.state.inputFocused) {
+    if (
+      !this.isProjectSearchEnabled() ||
+      !this.state.focusedItem ||
+      this.state.inputFocused
+    ) {
       return;
     }
-    if (this.focusedItem.expanded !== null) {
-      // expanded is not null implies this is a `FileItem`
-      const { setExpanded, file, expanded } = this.focusedItem;
-      setExpanded(file, !expanded);
-    } else {
-      const { match } = this.focusedItem;
-      this.selectMatchItem(match);
+    if (this.state.focusedItem.type === "MATCH") {
+      this.selectMatchItem(this.state.focusedItem);
+    }
+  };
+
+  onFocus = (item: Item) => {
+    if (this.state.focusedItem !== item) {
+      this.setState({ focusedItem: item });
     }
   };
 
   inputOnChange = (e: SyntheticInputEvent<HTMLInputElement>) => {
     const inputValue = e.target.value;
     const { clearSearch } = this.props;
     this.setState({ inputValue });
     if (inputValue === "") {
       clearSearch();
     }
   };
 
-  renderFile = (
-    file: Result,
-    focused: boolean,
-    expanded: boolean,
-    setExpanded: Function
-  ) => {
-    if (focused) {
-      this.focusedItem = { setExpanded, file, expanded };
-    }
-
+  renderFile = (file: Result, focused: boolean, expanded: boolean) => {
     const matchesLength = file.matches.length;
     const matches = ` (${matchesLength} match${matchesLength > 1 ? "es" : ""})`;
 
     return (
       <div
         className={classnames("file-result", { focused })}
         key={file.sourceId}
       >
@@ -229,19 +216,16 @@ export class ProjectSearch extends Compo
         <AccessibleImage className="file" />
         <span className="file-path">{getRelativePath(file.filepath)}</span>
         <span className="matches-summary">{matches}</span>
       </div>
     );
   };
 
   renderMatch = (match: Match, focused: boolean) => {
-    if (focused) {
-      this.focusedItem = { match, expanded: null };
-    }
     return (
       <div
         className={classnames("result", { focused })}
         onClick={() => setTimeout(() => this.selectMatchItem(match), 50)}
       >
         <span className="line-number" key={match.line}>
           {match.line}
         </span>
@@ -250,21 +234,20 @@ export class ProjectSearch extends Compo
     );
   };
 
   renderItem = (
     item: Item,
     depth: number,
     focused: boolean,
     _: any,
-    expanded: boolean,
-    { setExpanded }: { setExpanded: Function }
+    expanded: boolean
   ) => {
     if (item.type === "RESULT") {
-      return this.renderFile(item, focused, expanded, setExpanded);
+      return this.renderFile(item, focused, expanded);
     }
     return this.renderMatch(item, focused);
   };
 
   renderResults = () => {
     const { status, results } = this.props;
     if (!this.props.query) {
       return;
@@ -276,16 +259,18 @@ export class ProjectSearch extends Compo
           getChildren={file => file.matches || []}
           itemHeight={24}
           autoExpandAll={true}
           autoExpandDepth={1}
           autoExpandNodeChildrenLimit={100}
           getParent={item => null}
           getPath={getFilePath}
           renderItem={this.renderItem}
+          focused={this.state.focusedItem}
+          onFocus={this.onFocus}
         />
       );
     }
     const msg =
       status === statusType.fetching
         ? L10N.getStr("loadingText")
         : L10N.getStr("projectTextSearch.noResults");
     return <div className="no-result-msg absolute-center">{msg}</div>;
--- a/devtools/client/debugger/new/src/components/SecondaryPanes/Breakpoints/Breakpoint.js
+++ b/devtools/client/debugger/new/src/components/SecondaryPanes/Breakpoints/Breakpoint.js
@@ -165,24 +165,26 @@ class Breakpoint extends PureComponent<P
           type="checkbox"
           className="breakpoint-checkbox"
           checked={!breakpoint.disabled}
           onChange={this.handleBreakpointCheckbox}
           onClick={ev => ev.stopPropagation()}
         />
         <label
           htmlFor={breakpoint.id}
-          className="breakpoint-label cm-s-mozilla"
+          className="breakpoint-label cm-s-mozilla devtools-monospace"
           onClick={this.selectBreakpoint}
           title={text}
         >
           <span dangerouslySetInnerHTML={this.highlightText(text, editor)} />
         </label>
         <div className="breakpoint-line-close">
-          <div className="breakpoint-line">{this.getBreakpointLocation()}</div>
+          <div className="breakpoint-line devtools-monospace">
+            {this.getBreakpointLocation()}
+          </div>
           <CloseButton
             handleClick={e => this.removeBreakpoint(e)}
             tooltip={L10N.getStr("breakpoints.removeBreakpointTooltip")}
           />
         </div>
       </div>
     );
   }
--- a/devtools/client/debugger/new/src/components/SecondaryPanes/Breakpoints/Breakpoints.css
+++ b/devtools/client/debugger/new/src/components/SecondaryPanes/Breakpoints/Breakpoints.css
@@ -135,21 +135,16 @@ html .breakpoints-list .breakpoint.pause
   color: var(--theme-comment);
   transition: color 0.15s linear;
 }
 
 .breakpoints-list .breakpoint:hover {
   background-color: var(--search-overlays-semitransparent);
 }
 
-.breakpoints-list .breakpoint .breakpoint-line,
-.breakpoints-list .breakpoint-label {
-  font-family: var(--monospace-font-family);
-}
-
 .breakpoints-list .breakpoint .breakpoint-line {
   font-size: 11px;
   color: var(--theme-comment);
   min-width: 16px;
   text-align: right;
 }
 
 html[dir="rtl"] .breakpoints-list .breakpoint .breakpoint-line {
--- a/devtools/client/debugger/new/src/components/SecondaryPanes/Breakpoints/tests/__snapshots__/Breakpoint.spec.js.snap
+++ b/devtools/client/debugger/new/src/components/SecondaryPanes/Breakpoints/tests/__snapshots__/Breakpoint.spec.js.snap
@@ -10,32 +10,32 @@ exports[`Breakpoint disabled 1`] = `
   <input
     checked={false}
     className="breakpoint-checkbox"
     onChange={[Function]}
     onClick={[Function]}
     type="checkbox"
   />
   <label
-    className="breakpoint-label cm-s-mozilla"
+    className="breakpoint-label cm-s-mozilla devtools-monospace"
     onClick={[Function]}
   >
     <span
       dangerouslySetInnerHTML={
         Object {
           "__html": "",
         }
       }
     />
   </label>
   <div
     className="breakpoint-line-close"
   >
     <div
-      className="breakpoint-line"
+      className="breakpoint-line devtools-monospace"
     >
       53
     </div>
     <CloseButton
       handleClick={[Function]}
       tooltip="Remove breakpoint"
     />
   </div>
@@ -52,32 +52,32 @@ exports[`Breakpoint paused at a differen
   <input
     checked={true}
     className="breakpoint-checkbox"
     onChange={[Function]}
     onClick={[Function]}
     type="checkbox"
   />
   <label
-    className="breakpoint-label cm-s-mozilla"
+    className="breakpoint-label cm-s-mozilla devtools-monospace"
     onClick={[Function]}
   >
     <span
       dangerouslySetInnerHTML={
         Object {
           "__html": "",
         }
       }
     />
   </label>
   <div
     className="breakpoint-line-close"
   >
     <div
-      className="breakpoint-line"
+      className="breakpoint-line devtools-monospace"
     >
       53
     </div>
     <CloseButton
       handleClick={[Function]}
       tooltip="Remove breakpoint"
     />
   </div>
@@ -94,32 +94,32 @@ exports[`Breakpoint paused at a generate
   <input
     checked={true}
     className="breakpoint-checkbox"
     onChange={[Function]}
     onClick={[Function]}
     type="checkbox"
   />
   <label
-    className="breakpoint-label cm-s-mozilla"
+    className="breakpoint-label cm-s-mozilla devtools-monospace"
     onClick={[Function]}
   >
     <span
       dangerouslySetInnerHTML={
         Object {
           "__html": "",
         }
       }
     />
   </label>
   <div
     className="breakpoint-line-close"
   >
     <div
-      className="breakpoint-line"
+      className="breakpoint-line devtools-monospace"
     >
       53
     </div>
     <CloseButton
       handleClick={[Function]}
       tooltip="Remove breakpoint"
     />
   </div>
@@ -136,32 +136,32 @@ exports[`Breakpoint paused at an origina
   <input
     checked={true}
     className="breakpoint-checkbox"
     onChange={[Function]}
     onClick={[Function]}
     type="checkbox"
   />
   <label
-    className="breakpoint-label cm-s-mozilla"
+    className="breakpoint-label cm-s-mozilla devtools-monospace"
     onClick={[Function]}
   >
     <span
       dangerouslySetInnerHTML={
         Object {
           "__html": "",
         }
       }
     />
   </label>
   <div
     className="breakpoint-line-close"
   >
     <div
-      className="breakpoint-line"
+      className="breakpoint-line devtools-monospace"
     >
       5
     </div>
     <CloseButton
       handleClick={[Function]}
       tooltip="Remove breakpoint"
     />
   </div>
@@ -178,32 +178,32 @@ exports[`Breakpoint simple 1`] = `
   <input
     checked={true}
     className="breakpoint-checkbox"
     onChange={[Function]}
     onClick={[Function]}
     type="checkbox"
   />
   <label
-    className="breakpoint-label cm-s-mozilla"
+    className="breakpoint-label cm-s-mozilla devtools-monospace"
     onClick={[Function]}
   >
     <span
       dangerouslySetInnerHTML={
         Object {
           "__html": "",
         }
       }
     />
   </label>
   <div
     className="breakpoint-line-close"
   >
     <div
-      className="breakpoint-line"
+      className="breakpoint-line devtools-monospace"
     >
       53
     </div>
     <CloseButton
       handleClick={[Function]}
       tooltip="Remove breakpoint"
     />
   </div>
--- a/devtools/client/debugger/new/src/components/SecondaryPanes/CommandBar.css
+++ b/devtools/client/debugger/new/src/components/SecondaryPanes/CommandBar.css
@@ -111,17 +111,18 @@ html[dir="rtl"] .command-bar {
 .command-bar .active .skipPausing {
   background-color: var(--theme-highlight-blue);
 }
 
 .bottom {
   border-bottom: none;
   background-color: var(--theme-body-background);
   border-top: 1px solid var(--theme-splitter-color);
-  flex: 0 0 25px;
+  flex: none;
+  height: var(--editor-footer-height);
 }
 
 .command-bar.bottom {
   justify-content: flex-end;
 }
 
 .command-bar.bottom > button {
   color: var(--theme-comment);
--- a/devtools/client/debugger/new/src/components/SecondaryPanes/Expressions.css
+++ b/devtools/client/debugger/new/src/components/SecondaryPanes/Expressions.css
@@ -111,11 +111,11 @@
 .expression-content .tree-node {
   overflow-x: hidden;
 }
 
 .expression-content .tree-node[data-expandable="false"][aria-level="1"] {
   padding-inline-start: 10px;
 }
 
-.expression-input {
-  max-width: 50%;
+.input-expression:not(:placeholder-shown) {
+  font-family: var(--monospace-font-family);
 }
--- a/devtools/client/debugger/new/src/components/SecondaryPanes/Expressions.js
+++ b/devtools/client/debugger/new/src/components/SecondaryPanes/Expressions.js
@@ -66,20 +66,27 @@ class Expressions extends Component<Prop
       editing: false,
       editIndex: -1,
       inputValue: "",
       focused: false
     };
   }
 
   componentDidMount() {
-    const { expressions, evaluateExpressions } = this.props;
+    const { expressions, evaluateExpressions, showInput } = this.props;
+
     if (expressions.size > 0) {
       evaluateExpressions();
     }
+
+    // Ensures that the input is focused when the "+"
+    // is clicked while the panel is collapsed
+    if (showInput && this._input) {
+      this._input.focus();
+    }
   }
 
   clear = () => {
     this.setState(() => {
       this.props.clearExpressionError();
       return { editing: false, editIndex: -1, inputValue: "" };
     });
   };
--- a/devtools/client/debugger/new/src/components/SecondaryPanes/Frames/Frame.js
+++ b/devtools/client/debugger/new/src/components/SecondaryPanes/Frames/Frame.js
@@ -10,30 +10,29 @@ import classNames from "classnames";
 
 import AccessibleImage from "../../shared/AccessibleImage";
 import { formatDisplayName } from "../../../utils/pause/frames";
 import { getFilename, getFileURL } from "../../../utils/source";
 import FrameMenu from "./FrameMenu";
 import FrameIndent from "./FrameIndent";
 
 import type { Frame } from "../../../types";
-import type { LocalFrame } from "./types";
 
 type FrameTitleProps = {
   frame: Frame,
   options: Object,
   l10n: Object
 };
 
 function FrameTitle({ frame, options = {}, l10n }: FrameTitleProps) {
   const displayName = formatDisplayName(frame, options, l10n);
   return <span className="title">{displayName}</span>;
 }
 
-type FrameLocationProps = { frame: LocalFrame, displayFullUrl: boolean };
+type FrameLocationProps = { frame: Frame, displayFullUrl: boolean };
 
 function FrameLocation({ frame, displayFullUrl = false }: FrameLocationProps) {
   if (!frame.source) {
     return null;
   }
 
   if (frame.library) {
     return (
@@ -57,18 +56,18 @@ function FrameLocation({ frame, displayF
       <span className="line">{location.line}</span>
     </span>
   );
 }
 
 FrameLocation.displayName = "FrameLocation";
 
 type FrameComponentProps = {
-  frame: LocalFrame,
-  selectedFrame: LocalFrame,
+  frame: Frame,
+  selectedFrame: Frame,
   copyStackTrace: Function,
   toggleFrameworkGrouping: Function,
   selectFrame: Function,
   frameworkGroupingOn: boolean,
   hideLocation: boolean,
   shouldMapDisplayName: boolean,
   toggleBlackBox: Function,
   displayFullUrl: boolean,
@@ -134,16 +133,20 @@ export default class FrameComponent exte
       selectable
     } = this.props;
     const { l10n } = this.context;
 
     const className = classNames("frame", {
       selected: selectedFrame && selectedFrame.id === frame.id
     });
 
+    if (!frame.source) {
+      throw new Error("no frame source");
+    }
+
     const title = getFrameTitle
       ? getFrameTitle(
           `${getFileURL(frame.source, false)}:${frame.location.line}`
         )
       : undefined;
 
     return (
       <div
--- a/devtools/client/debugger/new/src/components/SecondaryPanes/Frames/FrameIndent.js
+++ b/devtools/client/debugger/new/src/components/SecondaryPanes/Frames/FrameIndent.js
@@ -1,12 +1,14 @@
 /* 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/>. */
 
+// @flow
+
 import React from "react";
 
 export default function FrameIndent() {
   return (
     <span className="frame-indent clipboard-only">
       &nbsp;&nbsp;&nbsp;&nbsp;
     </span>
   );
--- a/devtools/client/debugger/new/src/components/SecondaryPanes/Frames/FrameMenu.js
+++ b/devtools/client/debugger/new/src/components/SecondaryPanes/Frames/FrameMenu.js
@@ -1,17 +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/>. */
 
 // @flow
 import { showMenu } from "devtools-contextmenu";
 import { copyToTheClipboard } from "../../../utils/clipboard";
-import type { LocalFrame } from "./types";
-import type { ContextMenuItem } from "../../../types";
+import type { ContextMenuItem, Frame } from "../../../types";
 import { kebabCase } from "lodash";
 
 const blackboxString = "sourceFooter.blackbox";
 const unblackboxString = "sourceFooter.unblackbox";
 
 function formatMenuElement(
   labelString: string,
   click: Function,
@@ -52,17 +51,17 @@ function blackBoxSource(source, toggleBl
   const toggleBlackBoxString = source.isBlackBoxed
     ? unblackboxString
     : blackboxString;
 
   return formatMenuElement(toggleBlackBoxString, () => toggleBlackBox(source));
 }
 
 export default function FrameMenu(
-  frame: LocalFrame,
+  frame: Frame,
   frameworkGroupingOn: boolean,
   callbacks: Object,
   event: SyntheticMouseEvent<HTMLElement>
 ) {
   event.stopPropagation();
   event.preventDefault();
 
   const menuOptions = [];
--- a/devtools/client/debugger/new/src/components/SecondaryPanes/Frames/Group.js
+++ b/devtools/client/debugger/new/src/components/SecondaryPanes/Frames/Group.js
@@ -10,21 +10,21 @@ import classNames from "classnames";
 import { getLibraryFromUrl } from "../../../utils/pause/frames";
 
 import FrameMenu from "./FrameMenu";
 import AccessibleImage from "../../shared/AccessibleImage";
 import FrameComponent from "./Frame";
 
 import "./Group.css";
 
-import type { LocalFrame } from "./types";
+import type { Frame } from "../../../types";
 import Badge from "../../shared/Badge";
 import FrameIndent from "./FrameIndent";
 
-type FrameLocationProps = { frame: LocalFrame, expanded: boolean };
+type FrameLocationProps = { frame: Frame, expanded: boolean };
 function FrameLocation({ frame, expanded }: FrameLocationProps) {
   const library = frame.library || getLibraryFromUrl(frame);
   if (!library) {
     return null;
   }
 
   const arrowClassName = classNames("arrow", { expanded });
   return (
@@ -34,18 +34,18 @@ function FrameLocation({ frame, expanded
       <span className="group-description-name">{library}</span>
     </span>
   );
 }
 
 FrameLocation.displayName = "FrameLocation";
 
 type Props = {
-  group: LocalFrame[],
-  selectedFrame: LocalFrame,
+  group: Frame[],
+  selectedFrame: Frame,
   selectFrame: Function,
   toggleFrameworkGrouping: Function,
   copyStackTrace: Function,
   toggleBlackBox: Function,
   frameworkGroupingOn: boolean,
   displayFullUrl: boolean,
   getFrameTitle?: string => string,
   disableContextMenu: boolean,
--- a/devtools/client/debugger/new/src/components/SecondaryPanes/Frames/index.js
+++ b/devtools/client/debugger/new/src/components/SecondaryPanes/Frames/index.js
@@ -21,18 +21,16 @@ import { copyToTheClipboard } from "../.
 
 import {
   getFrameworkGroupingState,
   getSelectedFrame,
   getCallStackFrames,
   getPauseReason
 } from "../../../selectors";
 
-import type { LocalFrame } from "./types";
-
 import "./Frames.css";
 
 const NUM_FRAMES_SHOWN = 7;
 
 type Props = {
   frames: Array<Frame>,
   frameworkGroupingOn: boolean,
   selectedFrame: Object,
@@ -108,56 +106,56 @@ class Frames extends Component<Props, St
     copyToTheClipboard(framesToCopy);
   };
 
   toggleFrameworkGrouping = () => {
     const { toggleFrameworkGrouping, frameworkGroupingOn } = this.props;
     toggleFrameworkGrouping(!frameworkGroupingOn);
   };
 
-  renderFrames(frames: LocalFrame[]) {
+  renderFrames(frames: Frame[]) {
     const {
       selectFrame,
       selectedFrame,
       toggleBlackBox,
       frameworkGroupingOn,
       displayFullUrl,
       getFrameTitle,
       disableContextMenu,
       selectable = false
     } = this.props;
 
     const framesOrGroups = this.truncateFrames(this.collapseFrames(frames));
-    type FrameOrGroup = LocalFrame | LocalFrame[];
+    type FrameOrGroup = Frame | Frame[];
 
     // We're not using a <ul> because it adds new lines before and after when
     // the user copies the trace. Needed for the console which has several
     // places where we don't want to have those new lines.
     return (
       <div role="list">
         {framesOrGroups.map(
           (frameOrGroup: FrameOrGroup) =>
             frameOrGroup.id ? (
               <FrameComponent
-                frame={frameOrGroup}
+                frame={(frameOrGroup: any)}
                 toggleFrameworkGrouping={this.toggleFrameworkGrouping}
                 copyStackTrace={this.copyStackTrace}
                 frameworkGroupingOn={frameworkGroupingOn}
                 selectFrame={selectFrame}
                 selectedFrame={selectedFrame}
                 toggleBlackBox={toggleBlackBox}
                 key={String(frameOrGroup.id)}
                 displayFullUrl={displayFullUrl}
                 getFrameTitle={getFrameTitle}
                 disableContextMenu={disableContextMenu}
                 selectable={selectable}
               />
             ) : (
               <Group
-                group={frameOrGroup}
+                group={(frameOrGroup: any)}
                 toggleFrameworkGrouping={this.toggleFrameworkGrouping}
                 copyStackTrace={this.copyStackTrace}
                 frameworkGroupingOn={frameworkGroupingOn}
                 selectFrame={selectFrame}
                 selectedFrame={selectedFrame}
                 toggleBlackBox={toggleBlackBox}
                 key={frameOrGroup[0].id}
                 displayFullUrl={displayFullUrl}
@@ -166,23 +164,23 @@ class Frames extends Component<Props, St
                 selectable={selectable}
               />
             )
         )}
       </div>
     );
   }
 
-  renderToggleButton(frames: LocalFrame[]) {
+  renderToggleButton(frames: Frame[]) {
     const { l10n } = this.context;
     const buttonMessage = this.state.showAllFrames
       ? l10n.getStr("callStack.collapse")
       : l10n.getStr("callStack.expand");
 
-    frames = this.collapseFrames(frames);
+    frames = (this.collapseFrames(frames): any);
     if (frames.length <= NUM_FRAMES_SHOWN) {
       return null;
     }
 
     return (
       <div className="show-more-container">
         <button className="show-more" onClick={this.toggleFramesDisplay}>
           {buttonMessage}
--- a/devtools/client/debugger/new/src/components/SecondaryPanes/Frames/tests/Frame.spec.js
+++ b/devtools/client/debugger/new/src/components/SecondaryPanes/Frames/tests/Frame.spec.js
@@ -2,132 +2,96 @@
  * 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/>. */
 
 // @flow
 
 import React from "react";
 import { shallow, mount } from "enzyme";
 import Frame from "../Frame.js";
+import { makeMockFrame, makeMockSource } from "../../../../utils/test-mockup";
 
 import FrameMenu from "../FrameMenu";
 jest.mock("../FrameMenu", () => jest.fn());
 
-function frameProperties(frame, selectedFrame, overrides = {}) {
+function frameProperties(frame, selectedFrame: any, overrides = {}) {
   return {
     frame,
     selectedFrame,
     copyStackTrace: jest.fn(),
     contextTypes: {},
     selectFrame: jest.fn(),
     toggleBlackBox: jest.fn(),
     displayFullUrl: false,
     frameworkGroupingOn: false,
     selectable: true,
     toggleFrameworkGrouping: null,
     ...overrides
   };
 }
 
 function render(frameToSelect = {}, overrides = {}, propsOverrides = {}) {
-  const defaultFrame = {
-    id: 1,
-    source: {
-      url: "foo-view.js",
-      isBlackBoxed: false
-    },
-    displayName: "renderFoo",
-    frameworkGroupingOn: false,
-    toggleFrameworkGrouping: jest.fn(),
-    library: false,
-    location: {
-      line: 10
-    }
-  };
+  const source = makeMockSource("foo-view.js");
+  const defaultFrame = makeMockFrame("1", source, undefined, 10, "renderFoo");
+
   const frame = { ...defaultFrame, ...overrides };
   const selectedFrame = { ...frame, ...frameToSelect };
 
   const props = frameProperties(frame, selectedFrame, propsOverrides);
   const component = shallow(<Frame {...props} />);
   return { component, props };
 }
 
 describe("Frame", () => {
   it("user frame", () => {
     const { component } = render();
     expect(component).toMatchSnapshot();
   });
 
   it("user frame (not selected)", () => {
-    const { component } = render({ id: 2 });
+    const { component } = render({ id: "2" });
     expect(component).toMatchSnapshot();
   });
 
   it("library frame", () => {
+    const source = makeMockSource("backbone.js");
     const backboneFrame = {
-      id: 3,
-      source: { url: "backbone.js" },
-      displayName: "updateEvents",
-      library: "backbone",
-      location: {
-        line: 12
-      }
+      ...makeMockFrame("3", source, undefined, 12, "updateEvents"),
+      library: "backbone"
     };
 
-    const { component } = render({ id: 3 }, backboneFrame);
+    const { component } = render({ id: "3" }, backboneFrame);
     expect(component).toMatchSnapshot();
   });
 
-  fit("filename only", () => {
-    const frame = {
-      id: 1,
-      source: {
-        url: "https://firefox.com/assets/src/js/foo-view.js"
-      },
-      displayName: "renderFoo",
-      location: {
-        line: 10
-      }
-    };
+  it("filename only", () => {
+    const source = makeMockSource(
+      "https://firefox.com/assets/src/js/foo-view.js"
+    );
+    const frame = makeMockFrame("1", source, undefined, 10, "renderFoo");
 
     const props = frameProperties(frame, null);
     const component = mount(<Frame {...props} />);
     expect(component.text()).toBe("\trenderFoo foo-view.js:10\n");
   });
 
   it("full URL", () => {
     const url = `https://${"a".repeat(100)}.com/assets/src/js/foo-view.js`;
-    const frame = {
-      id: 1,
-      source: {
-        url
-      },
-      displayName: "renderFoo",
-      location: {
-        line: 10
-      }
-    };
+    const source = makeMockSource(url);
+    const frame = makeMockFrame("1", source, undefined, 10, "renderFoo");
 
     const props = frameProperties(frame, null, { displayFullUrl: true });
     const component = mount(<Frame {...props} />);
     expect(component.text()).toBe(`renderFoo ${url}:10`);
   });
 
   it("getFrameTitle", () => {
     const url = `https://${"a".repeat(100)}.com/assets/src/js/foo-view.js`;
-    const frame = {
-      id: 1,
-      source: {
-        url
-      },
-      displayName: "renderFoo",
-      location: {
-        line: 10
-      }
-    };
+    const source = makeMockSource(url);
+    const frame = makeMockFrame("1", source, undefined, 10, "renderFoo");
 
     const props = frameProperties(frame, null, {
       getFrameTitle: x => `Jump to ${x}`
     });
     const component = shallow(<Frame {...props} />);
     expect(component.prop("title")).toBe(`Jump to ${url}:10`);
     expect(component).toMatchSnapshot();
   });
--- a/devtools/client/debugger/new/src/components/SecondaryPanes/Frames/tests/FrameMenu.spec.js
+++ b/devtools/client/debugger/new/src/components/SecondaryPanes/Frames/tests/FrameMenu.spec.js
@@ -4,41 +4,38 @@
 
 // @flow
 
 import FrameMenu from "../FrameMenu";
 import { kebabCase } from "lodash";
 
 import { showMenu } from "devtools-contextmenu";
 import { copyToTheClipboard } from "../../../../utils/clipboard";
+import { makeMockFrame, makeMockSource } from "../../../../utils/test-mockup";
+
 jest.mock("devtools-contextmenu", () => ({ showMenu: jest.fn() }));
 jest.mock("../../../../utils/clipboard", () => ({
   copyToTheClipboard: jest.fn()
 }));
 
 function generateMockId(labelString) {
   const label = L10N.getStr(labelString);
   return `node-menu-${kebabCase(label)}`;
 }
 
 describe("FrameMenu", () => {
   let mockEvent: any;
   let mockFrame;
-  let emptyFrame;
+  let emptyFrame: any;
   let callbacks;
   let frameworkGroupingOn;
   let toggleFrameworkGrouping;
 
   beforeEach(() => {
-    mockFrame = {
-      source: {
-        url: "isFake",
-        isBlackBoxed: false
-      }
-    };
+    mockFrame = makeMockFrame(undefined, makeMockSource("isFake"));
     mockEvent = {
       stopPropagation: jest.fn(),
       preventDefault: jest.fn()
     };
     callbacks = {
       toggleFrameworkGrouping,
       toggleBlackbox: jest.fn(),
       copyToTheClipboard
--- a/devtools/client/debugger/new/src/components/SecondaryPanes/Frames/tests/Frames.spec.js
+++ b/devtools/client/debugger/new/src/components/SecondaryPanes/Frames/tests/Frames.spec.js
@@ -4,16 +4,17 @@
 
 // @flow
 
 import React from "react";
 import { mount, shallow } from "enzyme";
 import Frames from "../index.js";
 // eslint-disable-next-line
 import { formatCallStackFrames } from "../../../../selectors/getCallStackFrames";
+import { makeMockFrame, makeMockSource } from "../../../../utils/test-mockup";
 
 function render(overrides = {}) {
   const defaultProps = {
     frames: null,
     selectedFrame: null,
     frameworkGroupingOn: false,
     toggleFrameworkGrouping: jest.fn(),
     contextTypes: {},
@@ -186,33 +187,33 @@ describe("Frames", () => {
       });
 
       expect(component.find("Group").prop("getFrameTitle")).toBe(getFrameTitle);
     });
   });
 
   describe("Blackboxed Frames", () => {
     it("filters blackboxed frames", () => {
+      const source1 = makeMockSource(undefined, "1");
+      const source2 = makeMockSource(undefined, "2");
+      source2.isBlackBoxed = true;
+
       const frames = [
-        { id: 1, location: { sourceId: "1" } },
-        { id: 2, location: { sourceId: "2" } },
-        { id: 3, location: { sourceId: "1" } },
-        { id: 8, location: { sourceId: "2" } }
+        makeMockFrame("1", source1),
+        makeMockFrame("2", source2),
+        makeMockFrame("3", source1),
+        makeMockFrame("8", source2)
       ];
 
       const sources = {
-        "1": { id: "1" },
-        "2": { id: "2", isBlackBoxed: true }
+        "1": source1,
+        "2": source2
       };
 
-      const processedFrames = formatCallStackFrames(
-        frames,
-        sources,
-        sources["1"]
-      );
+      const processedFrames = formatCallStackFrames(frames, sources, source1);
       const selectedFrame = frames[0];
 
       const component = render({
         frames: processedFrames,
         frameworkGroupingOn: false,
         selectedFrame
       });
 
--- a/devtools/client/debugger/new/src/components/SecondaryPanes/Frames/tests/Group.spec.js
+++ b/devtools/client/debugger/new/src/components/SecondaryPanes/Frames/tests/Group.spec.js
@@ -2,24 +2,26 @@
  * 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/>. */
 
 // @flow
 
 import React from "react";
 import { shallow } from "enzyme";
 import Group from "../Group.js";
+import { makeMockFrame, makeMockSource } from "../../../../utils/test-mockup";
 
 import FrameMenu from "../FrameMenu";
 jest.mock("../FrameMenu", () => jest.fn());
 
 function render(overrides = {}) {
+  const frame = { ...makeMockFrame(), displayName: "foo", library: "Back" };
   const defaultProps = {
-    group: [{ displayName: "foo", library: "Back" }],
-    selectedFrame: {},
+    group: [frame],
+    selectedFrame: frame,
     frameworkGroupingOn: true,
     toggleFrameworkGrouping: jest.fn(),
     selectFrame: jest.fn(),
     copyStackTrace: jest.fn(),
     toggleBlackBox: jest.fn(),
     disableContextMenu: false,
     displayFullUrl: false,
     selectable: true
@@ -34,98 +36,60 @@ function render(overrides = {}) {
 
 describe("Group", () => {
   it("displays a group", () => {
     const { component } = render();
     expect(component).toMatchSnapshot();
   });
 
   it("passes the getFrameTitle prop to the Frame components", () => {
+    const mahscripts = makeMockSource("http://myfile.com/mahscripts.js");
+    const back = makeMockSource("http://myfile.com/back.js");
     const group = [
       {
-        id: 1,
-        library: "Back",
-        displayName: "renderFoo",
-        location: {
-          line: 55
-        },
-        source: {
-          url: "http://myfile.com/mahscripts.js"
-        }
+        ...makeMockFrame("1", mahscripts, undefined, 55, "renderFoo"),
+        library: "Back"
       },
       {
-        id: 2,
-        library: "Back",
-        displayName: "a",
-        location: {
-          line: 55
-        },
-        source: {
-          url: "http://myfile.com/back.js"
-        }
+        ...makeMockFrame("2", back, undefined, 55, "a"),
+        library: "Back"
       },
       {
-        id: 3,
-        library: "Back",
-        displayName: "b",
-        location: {
-          line: 55
-        },
-        source: {
-          url: "http://myfile.com/back.js"
-        }
+        ...makeMockFrame("3", back, undefined, 55, "b"),
+        library: "Back"
       }
     ];
     const getFrameTitle = () => {};
     const { component } = render({ group, getFrameTitle });
 
     component.setState({ expanded: true });
 
     const frameComponents = component.find("Frame");
     expect(frameComponents).toHaveLength(3);
     frameComponents.forEach(node => {
       expect(node.prop("getFrameTitle")).toBe(getFrameTitle);
     });
     expect(component).toMatchSnapshot();
   });
 
   it("renders group with anonymous functions", () => {
+    const mahscripts = makeMockSource("http://myfile.com/mahscripts.js");
+    const back = makeMockSource("http://myfile.com/back.js");
     const group = [
       {
-        id: 1,
-        library: "Back",
-        displayName: "",
-        location: {
-          line: 55
-        },
-        source: {
-          url: "http://myfile.com/mahscripts.js"
-        }
+        ...makeMockFrame("1", mahscripts, undefined, 55),
+        library: "Back"
       },
       {
-        id: 2,
-        library: "Back",
-        displayName: "",
-        location: {
-          line: 55
-        },
-        source: {
-          url: "http://myfile.com/back.js"
-        }
+        ...makeMockFrame("2", back, undefined, 55),
+        library: "Back"
       },
       {
-        id: 3,
-        library: "Back",
-        displayName: "",
-        location: {
-          line: 55
-        },
-        source: {
-          url: "http://myfile.com/back.js"
-        }
+        ...makeMockFrame("3", back, undefined, 55),
+        library: "Back"
       }
     ];
 
     const { component } = render({ group });
     expect(component).toMatchSnapshot();
     component.setState({ expanded: true });
     expect(component).toMatchSnapshot();
   });
--- a/devtools/client/debugger/new/src/components/SecondaryPanes/Frames/tests/__snapshots__/Frame.spec.js.snap
+++ b/devtools/client/debugger/new/src/components/SecondaryPanes/Frames/tests/__snapshots__/Frame.spec.js.snap
@@ -11,23 +11,50 @@ exports[`Frame getFrameTitle 1`] = `
   tabIndex={0}
   title="Jump to https://aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.com/assets/src/js/foo-view.js:10"
 >
   <FrameIndent />
   <FrameTitle
     frame={
       Object {
         "displayName": "renderFoo",
-        "id": 1,
+        "generatedLocation": Object {
+          "line": 10,
+          "sourceId": "source",
+        },
+        "id": "1",
         "location": Object {
           "line": 10,
+          "sourceId": "source",
+        },
+        "scope": Object {
+          "actor": "scope-actor",
+          "bindings": Object {
+            "arguments": Array [],
+            "variables": Object {},
+          },
+          "function": null,
+          "object": null,
+          "parent": null,
+          "type": "block",
         },
         "source": Object {
+          "contentType": "text/javascript",
+          "id": "source",
+          "introductionUrl": null,
+          "isBlackBoxed": false,
+          "isPrettyPrinted": false,
+          "isWasm": false,
+          "loadedState": "unloaded",
+          "relativeUrl": "https://aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.com/assets/src/js/foo-view.js",
+          "text": "",
           "url": "https://aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.com/assets/src/js/foo-view.js",
         },
+        "this": Object {},
+        "thread": "FakeThread",
       }
     }
     options={
       Object {
         "shouldMapDisplayName": true,
       }
     }
   />
@@ -36,23 +63,50 @@ exports[`Frame getFrameTitle 1`] = `
   >
      
   </span>
   <FrameLocation
     displayFullUrl={false}
     frame={
       Object {
         "displayName": "renderFoo",
-        "id": 1,
+        "generatedLocation": Object {
+          "line": 10,
+          "sourceId": "source",
+        },
+        "id": "1",
         "location": Object {
           "line": 10,
+          "sourceId": "source",
+        },
+        "scope": Object {
+          "actor": "scope-actor",
+          "bindings": Object {
+            "arguments": Array [],
+            "variables": Object {},
+          },
+          "function": null,
+          "object": null,
+          "parent": null,
+          "type": "block",
         },
         "source": Object {
+          "contentType": "text/javascript",
+          "id": "source",
+          "introductionUrl": null,
+          "isBlackBoxed": false,
+          "isPrettyPrinted": false,
+          "isWasm": false,
+          "loadedState": "unloaded",
+          "relativeUrl": "https://aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.com/assets/src/js/foo-view.js",
+          "text": "",
           "url": "https://aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.com/assets/src/js/foo-view.js",
         },
+        "this": Object {},
+        "thread": "FakeThread",
       }
     }
   />
   <br
     className="clipboard-only"
   />
 </div>
 `;
@@ -67,26 +121,51 @@ exports[`Frame library frame 1`] = `
   role="listitem"
   tabIndex={0}
 >
   <FrameIndent />
   <FrameTitle
     frame={
       Object {
         "displayName": "updateEvents",
-        "frameworkGroupingOn": false,
-        "id": 3,
+        "generatedLocation": Object {
+          "line": 12,
+          "sourceId": "source",
+        },
+        "id": "3",
         "library": "backbone",
         "location": Object {
           "line": 12,
+          "sourceId": "source",
+        },
+        "scope": Object {
+          "actor": "scope-actor",
+          "bindings": Object {
+            "arguments": Array [],
+            "variables": Object {},
+          },
+          "function": null,
+          "object": null,
+          "parent": null,
+          "type": "block",
         },
         "source": Object {
+          "contentType": "text/javascript",
+          "id": "source",
+          "introductionUrl": null,
+          "isBlackBoxed": false,
+          "isPrettyPrinted": false,
+          "isWasm": false,
+          "loadedState": "unloaded",
+          "relativeUrl": "backbone.js",
+          "text": "",
           "url": "backbone.js",
         },
-        "toggleFrameworkGrouping": [MockFunction],
+        "this": Object {},
+        "thread": "FakeThread",
       }
     }
     options={
       Object {
         "shouldMapDisplayName": true,
       }
     }
   />
@@ -95,26 +174,51 @@ exports[`Frame library frame 1`] = `
   >
      
   </span>
   <FrameLocation
     displayFullUrl={false}
     frame={
       Object {
         "displayName": "updateEvents",
-        "frameworkGroupingOn": false,
-        "id": 3,
+        "generatedLocation": Object {
+          "line": 12,
+          "sourceId": "source",
+        },
+        "id": "3",
         "library": "backbone",
         "location": Object {
           "line": 12,
+          "sourceId": "source",
+        },
+        "scope": Object {
+          "actor": "scope-actor",
+          "bindings": Object {
+            "arguments": Array [],
+            "variables": Object {},
+          },
+          "function": null,
+          "object": null,
+          "parent": null,
+          "type": "block",
         },
         "source": Object {
+          "contentType": "text/javascript",
+          "id": "source",
+          "introductionUrl": null,
+          "isBlackBoxed": false,
+          "isPrettyPrinted": false,
+          "isWasm": false,
+          "loadedState": "unloaded",
+          "relativeUrl": "backbone.js",
+          "text": "",
           "url": "backbone.js",
         },
-        "toggleFrameworkGrouping": [MockFunction],
+        "this": Object {},
+        "thread": "FakeThread",
       }
     }
   />
   <br
     className="clipboard-only"
   />
 </div>
 `;
@@ -129,27 +233,50 @@ exports[`Frame user frame (not selected)
   role="listitem"
   tabIndex={0}
 >
   <FrameIndent />
   <FrameTitle
     frame={
       Object {
         "displayName": "renderFoo",
-        "frameworkGroupingOn": false,
-        "id": 1,
-        "library": false,
+        "generatedLocation": Object {
+          "line": 10,
+          "sourceId": "source",
+        },
+        "id": "1",
         "location": Object {
           "line": 10,
+          "sourceId": "source",
+        },
+        "scope": Object {
+          "actor": "scope-actor",
+          "bindings": Object {
+            "arguments": Array [],
+            "variables": Object {},
+          },
+          "function": null,
+          "object": null,
+          "parent": null,
+          "type": "block",
         },
         "source": Object {
+          "contentType": "text/javascript",
+          "id": "source",
+          "introductionUrl": null,
           "isBlackBoxed": false,
+          "isPrettyPrinted": false,
+          "isWasm": false,
+          "loadedState": "unloaded",
+          "relativeUrl": "foo-view.js",
+          "text": "",
           "url": "foo-view.js",
         },
-        "toggleFrameworkGrouping": [MockFunction],
+        "this": Object {},
+        "thread": "FakeThread",
       }
     }
     options={
       Object {
         "shouldMapDisplayName": true,
       }
     }
   />
@@ -158,27 +285,50 @@ exports[`Frame user frame (not selected)
   >
      
   </span>
   <FrameLocation
     displayFullUrl={false}
     frame={
       Object {
         "displayName": "renderFoo",
-        "frameworkGroupingOn": false,
-        "id": 1,
-        "library": false,
+        "generatedLocation": Object {
+          "line": 10,
+          "sourceId": "source",
+        },
+        "id": "1",
         "location": Object {
           "line": 10,
+          "sourceId": "source",
+        },
+        "scope": Object {
+          "actor": "scope-actor",
+          "bindings": Object {
+            "arguments": Array [],
+            "variables": Object {},
+          },
+          "function": null,
+          "object": null,
+          "parent": null,
+          "type": "block",
         },
         "source": Object {
+          "contentType": "text/javascript",
+          "id": "source",
+          "introductionUrl": null,
           "isBlackBoxed": false,
+          "isPrettyPrinted": false,
+          "isWasm": false,
+          "loadedState": "unloaded",
+          "relativeUrl": "foo-view.js",
+          "text": "",
           "url": "foo-view.js",
         },
-        "toggleFrameworkGrouping": [MockFunction],
+        "this": Object {},
+        "thread": "FakeThread",
       }
     }
   />
   <br
     className="clipboard-only"
   />
 </div>
 `;
@@ -193,27 +343,50 @@ exports[`Frame user frame 1`] = `
   role="listitem"
   tabIndex={0}
 >
   <FrameIndent />
   <FrameTitle
     frame={
       Object {
         "displayName": "renderFoo",
-        "frameworkGroupingOn": false,
-        "id": 1,
-        "library": false,
+        "generatedLocation": Object {
+          "line": 10,
+          "sourceId": "source",
+        },
+        "id": "1",
         "location": Object {
           "line": 10,
+          "sourceId": "source",
+        },
+        "scope": Object {
+          "actor": "scope-actor",
+          "bindings": Object {
+            "arguments": Array [],
+            "variables": Object {},
+          },
+          "function": null,
+          "object": null,
+          "parent": null,
+          "type": "block",
         },
         "source": Object {
+          "contentType": "text/javascript",
+          "id": "source",
+          "introductionUrl": null,
           "isBlackBoxed": false,
+          "isPrettyPrinted": false,
+          "isWasm": false,
+          "loadedState": "unloaded",
+          "relativeUrl": "foo-view.js",
+          "text": "",
           "url": "foo-view.js",
         },
-        "toggleFrameworkGrouping": [MockFunction],
+        "this": Object {},
+        "thread": "FakeThread",
       }
     }
     options={
       Object {
         "shouldMapDisplayName": true,
       }
     }
   />
@@ -222,27 +395,50 @@ exports[`Frame user frame 1`] = `
   >
      
   </span>
   <FrameLocation
     displayFullUrl={false}
     frame={
       Object {
         "displayName": "renderFoo",
-        "frameworkGroupingOn": false,
-        "id": 1,
-        "library": false,
+        "generatedLocation": Object {
+          "line": 10,
+          "sourceId": "source",
+        },
+        "id": "1",
         "location": Object {
           "line": 10,
+          "sourceId": "source",
+        },
+        "scope": Object {
+          "actor": "scope-actor",
+          "bindings": Object {
+            "arguments": Array [],
+            "variables": Object {},
+          },
+          "function": null,
+          "object": null,
+          "parent": null,
+          "type": "block",
         },
         "source": Object {
+          "contentType": "text/javascript",
+          "id": "source",
+          "introductionUrl": null,
           "isBlackBoxed": false,
+          "isPrettyPrinted": false,
+          "isWasm": false,
+          "loadedState": "unloaded",
+          "relativeUrl": "foo-view.js",
+          "text": "",
           "url": "foo-view.js",
         },
-        "toggleFrameworkGrouping": [MockFunction],
+        "this": Object {},
+        "thread": "FakeThread",
       }
     }
   />
   <br
     className="clipboard-only"
   />
 </div>
 `;
--- a/devtools/client/debugger/new/src/components/SecondaryPanes/Frames/tests/__snapshots__/Frames.spec.js.snap
+++ b/devtools/client/debugger/new/src/components/SecondaryPanes/Frames/tests/__snapshots__/Frames.spec.js.snap
@@ -7,67 +7,185 @@ exports[`Frames Blackboxed Frames filter
   <div
     role="list"
   >
     <Frame
       copyStackTrace={[Function]}
       disableContextMenu={false}
       frame={
         Object {
-          "id": 1,
+          "displayName": "display-1",
+          "generatedLocation": Object {
+            "line": 4,
+            "sourceId": "1",
+          },
+          "id": "1",
           "location": Object {
+            "line": 4,
             "sourceId": "1",
           },
+          "scope": Object {
+            "actor": "scope-actor",
+            "bindings": Object {
+              "arguments": Array [],
+              "variables": Object {},
+            },
+            "function": null,
+            "object": null,
+            "parent": null,
+            "type": "block",
+          },
           "source": Object {
+            "contentType": "text/javascript",
             "id": "1",
+            "introductionUrl": null,
+            "isBlackBoxed": false,
+            "isPrettyPrinted": false,
+            "isWasm": false,
+            "loadedState": "unloaded",
+            "relativeUrl": "url",
+            "text": "",
+            "url": "url",
           },
+          "this": Object {},
+          "thread": "FakeThread",
         }
       }
       frameworkGroupingOn={false}
       hideLocation={false}
       key="1"
       selectFrame={[MockFunction]}
       selectable={false}
       selectedFrame={
         Object {
-          "id": 1,
+          "displayName": "display-1",
+          "generatedLocation": Object {
+            "line": 4,
+            "sourceId": "1",
+          },
+          "id": "1",
           "location": Object {
+            "line": 4,
             "sourceId": "1",
           },
+          "scope": Object {
+            "actor": "scope-actor",
+            "bindings": Object {
+              "arguments": Array [],
+              "variables": Object {},
+            },
+            "function": null,
+            "object": null,
+            "parent": null,
+            "type": "block",
+          },
+          "source": Object {
+            "contentType": "text/javascript",
+            "id": "1",
+            "introductionUrl": null,
+            "isBlackBoxed": false,
+            "isPrettyPrinted": false,
+            "isWasm": false,
+            "loadedState": "unloaded",
+            "relativeUrl": "url",
+            "text": "",
+            "url": "url",
+          },
+          "this": Object {},
+          "thread": "FakeThread",
         }
       }
       shouldMapDisplayName={true}
       toggleBlackBox={[MockFunction]}
       toggleFrameworkGrouping={[Function]}
     />
     <Frame
       copyStackTrace={[Function]}
       disableContextMenu={false}
       frame={
         Object {
-          "id": 3,
+          "displayName": "display-3",
+          "generatedLocation": Object {
+            "line": 4,
+            "sourceId": "1",
+          },
+          "id": "3",
           "location": Object {
+            "line": 4,
             "sourceId": "1",
           },
+          "scope": Object {
+            "actor": "scope-actor",
+            "bindings": Object {
+              "arguments": Array [],
+              "variables": Object {},
+            },
+            "function": null,
+            "object": null,
+            "parent": null,
+            "type": "block",
+          },
           "source": Object {
+            "contentType": "text/javascript",
             "id": "1",
+            "introductionUrl": null,
+            "isBlackBoxed": false,
+            "isPrettyPrinted": false,
+            "isWasm": false,
+            "loadedState": "unloaded",
+            "relativeUrl": "url",
+            "text": "",
+            "url": "url",
           },
+          "this": Object {},
+          "thread": "FakeThread",
         }
       }
       frameworkGroupingOn={false}
       hideLocation={false}
       key="3"
       selectFrame={[MockFunction]}
       selectable={false}
       selectedFrame={
         Object {
-          "id": 1,
+          "displayName": "display-1",
+          "generatedLocation": Object {
+            "line": 4,
+            "sourceId": "1",
+          },
+          "id": "1",
           "location": Object {
+            "line": 4,
             "sourceId": "1",
           },
+          "scope": Object {
+            "actor": "scope-actor",
+            "bindings": Object {
+              "arguments": Array [],
+              "variables": Object {},
+            },
+            "function": null,
+            "object": null,
+            "parent": null,
+            "type": "block",
+          },
+          "source": Object {
+            "contentType": "text/javascript",
+            "id": "1",
+            "introductionUrl": null,
+            "isBlackBoxed": false,
+            "isPrettyPrinted": false,
+            "isWasm": false,
+            "loadedState": "unloaded",
+            "relativeUrl": "url",
+            "text": "",
+            "url": "url",
+          },
+          "this": Object {},
+          "thread": "FakeThread",
         }
       }
       shouldMapDisplayName={true}
       toggleBlackBox={[MockFunction]}
       toggleFrameworkGrouping={[Function]}
     />
   </div>
 </div>
--- a/devtools/client/debugger/new/src/components/SecondaryPanes/Frames/tests/__snapshots__/Group.spec.js.snap
+++ b/devtools/client/debugger/new/src/components/SecondaryPanes/Frames/tests/__snapshots__/Group.spec.js.snap
@@ -2,28 +2,63 @@
 
 exports[`Group displays a group 1`] = `
 <div
   className="frames-group"
   onContextMenu={[Function]}
 >
   <div
     className="group"
+    key="frame"
     onClick={[Function]}
     role="listitem"
     tabIndex={0}
     title="Show Back frames"
   >
     <FrameIndent />
     <FrameLocation
       expanded={false}
       frame={
         Object {
           "displayName": "foo",
+          "generatedLocation": Object {
+            "line": 4,
+            "sourceId": "source",
+          },
+          "id": "frame",
           "library": "Back",
+          "location": Object {
+            "line": 4,
+            "sourceId": "source",
+          },
+          "scope": Object {
+            "actor": "scope-actor",
+            "bindings": Object {
+              "arguments": Array [],
+              "variables": Object {},
+            },
+            "function": null,
+            "object": null,
+            "parent": null,
+            "type": "block",
+          },
+          "source": Object {
+            "contentType": "text/javascript",
+            "id": "source",
+            "introductionUrl": null,
+            "isBlackBoxed": false,
+            "isPrettyPrinted": false,
+            "isWasm": false,
+            "loadedState": "unloaded",
+            "relativeUrl": "url",
+            "text": "",
+            "url": "url",
+          },
+          "this": Object {},
+          "thread": "FakeThread",
         }
       }
     />
     <span
       className="clipboard-only"
     >
        
     </span>
@@ -48,24 +83,51 @@ exports[`Group passes the getFrameTitle 
     title="Collapse Back frames"
   >
     <FrameIndent />
     <FrameLocation
       expanded={true}
       frame={
         Object {
           "displayName": "renderFoo",
-          "id": 1,
+          "generatedLocation": Object {
+            "line": 55,
+            "sourceId": "source",
+          },
+          "id": "1",
           "library": "Back",
           "location": Object {
             "line": 55,
+            "sourceId": "source",
+          },
+          "scope": Object {
+            "actor": "scope-actor",
+            "bindings": Object {
+              "arguments": Array [],
+              "variables": Object {},
+            },
+            "function": null,
+            "object": null,
+            "parent": null,
+            "type": "block",
           },
           "source": Object {
+            "contentType": "text/javascript",
+            "id": "source",
+            "introductionUrl": null,
+            "isBlackBoxed": false,
+            "isPrettyPrinted": false,
+            "isWasm": false,
+            "loadedState": "unloaded",
+            "relativeUrl": "http://myfile.com/mahscripts.js",
+            "text": "",
             "url": "http://myfile.com/mahscripts.js",
           },
+          "this": Object {},
+          "thread": "FakeThread",
         }
       }
     />
     <span
       className="clipboard-only"
     >
        
     </span>
@@ -79,91 +141,289 @@ exports[`Group passes the getFrameTitle 
     <FrameIndent />
     <Frame
       copyStackTrace={[MockFunction]}
       disableContextMenu={false}
       displayFullUrl={false}
       frame={
         Object {
           "displayName": "renderFoo",
-          "id": 1,
+          "generatedLocation": Object {
+            "line": 55,
+            "sourceId": "source",
+          },
+          "id": "1",
           "library": "Back",
           "location": Object {
             "line": 55,
+            "sourceId": "source",
+          },
+          "scope": Object {
+            "actor": "scope-actor",
+            "bindings": Object {
+              "arguments": Array [],
+              "variables": Object {},
+            },
+            "function": null,
+            "object": null,
+            "parent": null,
+            "type": "block",
           },
           "source": Object {
+            "contentType": "text/javascript",
+            "id": "source",
+            "introductionUrl": null,
+            "isBlackBoxed": false,
+            "isPrettyPrinted": false,
+            "isWasm": false,
+            "loadedState": "unloaded",
+            "relativeUrl": "http://myfile.com/mahscripts.js",
+            "text": "",
             "url": "http://myfile.com/mahscripts.js",
           },
+          "this": Object {},
+          "thread": "FakeThread",
         }
       }
       frameworkGroupingOn={true}
       getFrameTitle={[Function]}
       hideLocation={true}
       key="1"
       selectFrame={[MockFunction]}
       selectable={true}
-      selectedFrame={Object {}}
+      selectedFrame={
+        Object {
+          "displayName": "foo",
+          "generatedLocation": Object {
+            "line": 4,
+            "sourceId": "source",
+          },
+          "id": "frame",
+          "library": "Back",
+          "location": Object {
+            "line": 4,
+            "sourceId": "source",
+          },
+          "scope": Object {
+            "actor": "scope-actor",
+            "bindings": Object {
+              "arguments": Array [],
+              "variables": Object {},
+            },
+            "function": null,
+            "object": null,
+            "parent": null,
+            "type": "block",
+          },
+          "source": Object {
+            "contentType": "text/javascript",
+            "id": "source",
+            "introductionUrl": null,
+            "isBlackBoxed": false,
+            "isPrettyPrinted": false,
+            "isWasm": false,
+            "loadedState": "unloaded",
+            "relativeUrl": "url",
+            "text": "",
+            "url": "url",
+          },
+          "this": Object {},
+          "thread": "FakeThread",
+        }
+      }
       shouldMapDisplayName={false}
       toggleBlackBox={[MockFunction]}
       toggleFrameworkGrouping={[MockFunction]}
     />
     <FrameIndent />
     <Frame
       copyStackTrace={[MockFunction]}
       disableContextMenu={false}
       displayFullUrl={false}
       frame={
         Object {
           "displayName": "a",
-          "id": 2,
+          "generatedLocation": Object {
+            "line": 55,
+            "sourceId": "source",
+          },
+          "id": "2",
           "library": "Back",
           "location": Object {
             "line": 55,
+            "sourceId": "source",
+          },
+          "scope": Object {
+            "actor": "scope-actor",
+            "bindings": Object {
+              "arguments": Array [],
+              "variables": Object {},
+            },
+            "function": null,
+            "object": null,
+            "parent": null,
+            "type": "block",
           },
           "source": Object {
+            "contentType": "text/javascript",
+            "id": "source",
+            "introductionUrl": null,
+            "isBlackBoxed": false,
+            "isPrettyPrinted": false,
+            "isWasm": false,
+            "loadedState": "unloaded",
+            "relativeUrl": "http://myfile.com/back.js",
+            "text": "",
             "url": "http://myfile.com/back.js",
           },
+          "this": Object {},
+          "thread": "FakeThread",
         }
       }
       frameworkGroupingOn={true}
       getFrameTitle={[Function]}
       hideLocation={true}
       key="2"
       selectFrame={[MockFunction]}
       selectable={true}
-      selectedFrame={Object {}}
+      selectedFrame={
+        Object {
+          "displayName": "foo",
+          "generatedLocation": Object {
+            "line": 4,
+            "sourceId": "source",
+          },
+          "id": "frame",
+          "library": "Back",
+          "location": Object {
+            "line": 4,
+            "sourceId": "source",
+          },
+          "scope": Object {
+            "actor": "scope-actor",
+            "bindings": Object {
+              "arguments": Array [],
+              "variables": Object {},
+            },
+            "function": null,
+            "object": null,
+            "parent": null,
+            "type": "block",
+          },
+          "source": Object {
+            "contentType": "text/javascript",
+            "id": "source",
+            "introductionUrl": null,
+            "isBlackBoxed": false,
+            "isPrettyPrinted": false,
+            "isWasm": false,
+            "loadedState": "unloaded",
+            "relativeUrl": "url",
+            "text": "",
+            "url": "url",
+          },
+          "this": Object {},
+          "thread": "FakeThread",
+        }
+      }
       shouldMapDisplayName={false}
       toggleBlackBox={[MockFunction]}
       toggleFrameworkGrouping={[MockFunction]}
     />
     <FrameIndent />
     <Frame
       copyStackTrace={[MockFunction]}
       disableContextMenu={false}
       displayFullUrl={false}
       frame={
         Object {
           "displayName": "b",
-          "id": 3,
+          "generatedLocation": Object {
+            "line": 55,
+            "sourceId": "source",
+          },
+          "id": "3",
           "library": "Back",
           "location": Object {
             "line": 55,
+            "sourceId": "source",
+          },
+          "scope": Object {
+            "actor": "scope-actor",
+            "bindings": Object {
+              "arguments": Array [],
+              "variables": Object {},
+            },
+            "function": null,
+            "object": null,
+            "parent": null,
+            "type": "block",
           },
           "source": Object {
+            "contentType": "text/javascript",
+            "id": "source",
+            "introductionUrl": null,
+            "isBlackBoxed": false,
+            "isPrettyPrinted": false,
+            "isWasm": false,
+            "loadedState": "unloaded",
+            "relativeUrl": "http://myfile.com/back.js",
+            "text": "",
             "url": "http://myfile.com/back.js",
           },
+          "this": Object {},
+          "thread": "FakeThread",
         }
       }
       frameworkGroupingOn={true}
       getFrameTitle={[Function]}
       hideLocation={true}
       key="3"
       selectFrame={[MockFunction]}
       selectable={true}
-      selectedFrame={Object {}}
+      selectedFrame={
+        Object {
+          "displayName": "foo",
+          "generatedLocation": Object {
+            "line": 4,
+            "sourceId": "source",
+          },
+          "id": "frame",
+          "library": "Back",
+          "location": Object {
+            "line": 4,
+            "sourceId": "source",
+          },
+          "scope": Object {
+            "actor": "scope-actor",
+            "bindings": Object {
+              "arguments": Array [],
+              "variables": Object {},
+            },
+            "function": null,
+            "object": null,
+            "parent": null,
+            "type": "block",
+          },
+          "source": Object {
+            "contentType": "text/javascript",
+            "id": "source",
+            "introductionUrl": null,
+            "isBlackBoxed": false,
+            "isPrettyPrinted": false,
+            "isWasm": false,
+            "loadedState": "unloaded",
+            "relativeUrl": "url",
+            "text": "",
+            "url": "url",
+          },
+          "this": Object {},
+          "thread": "FakeThread",
+        }
+      }
       shouldMapDisplayName={false}
       toggleBlackBox={[MockFunction]}
       toggleFrameworkGrouping={[MockFunction]}
     />
   </div>
 </div>
 `;
 
@@ -180,25 +440,52 @@ exports[`Group renders group with anonym
     tabIndex={0}
     title="Show Back frames"
   >
     <FrameIndent />
     <FrameLocation
       expanded={false}
       frame={
         Object {
-          "displayName": "",
-          "id": 1,
+          "displayName": "display-1",
+          "generatedLocation": Object {
+            "line": 55,
+            "sourceId": "source",
+          },
+          "id": "1",
           "library": "Back",
           "location": Object {
             "line": 55,
+            "sourceId": "source",
+          },
+          "scope": Object {
+            "actor": "scope-actor",
+            "bindings": Object {
+              "arguments": Array [],
+              "variables": Object {},
+            },
+            "function": null,
+            "object": null,
+            "parent": null,
+            "type": "block",
           },
           "source": Object {
+            "contentType": "text/javascript",
+            "id": "source",
+            "introductionUrl": null,
+            "isBlackBoxed": false,
+            "isPrettyPrinted": false,
+            "isWasm": false,
+            "loadedState": "unloaded",
+            "relativeUrl": "http://myfile.com/mahscripts.js",
+            "text": "",
             "url": "http://myfile.com/mahscripts.js",
           },
+          "this": Object {},
+          "thread": "FakeThread",
         }
       }
     />
     <span
       className="clipboard-only"
     >
        
     </span>
@@ -222,25 +509,52 @@ exports[`Group renders group with anonym
     tabIndex={0}
     title="Collapse Back frames"
   >
     <FrameIndent />
     <FrameLocation
       expanded={true}
       frame={
         Object {
-          "displayName": "",
-          "id": 1,
+          "displayName": "display-1",
+          "generatedLocation": Object {
+            "line": 55,
+            "sourceId": "source",
+          },
+          "id": "1",
           "library": "Back",
           "location": Object {
             "line": 55,
+            "sourceId": "source",
+          },
+          "scope": Object {
+            "actor": "scope-actor",
+            "bindings": Object {
+              "arguments": Array [],
+              "variables": Object {},
+            },
+            "function": null,
+            "object": null,
+            "parent": null,
+            "type": "block",
           },
           "source": Object {
+            "contentType": "text/javascript",
+            "id": "source",
+            "introductionUrl": null,
+            "isBlackBoxed": false,
+            "isPrettyPrinted": false,
+            "isWasm": false,
+            "loadedState": "unloaded",
+            "relativeUrl": "http://myfile.com/mahscripts.js",
+            "text": "",
             "url": "http://myfile.com/mahscripts.js",
           },
+          "this": Object {},
+          "thread": "FakeThread",
         }
       }
     />
     <span
       className="clipboard-only"
     >
        
     </span>
@@ -253,88 +567,286 @@ exports[`Group renders group with anonym
   >
     <FrameIndent />
     <Frame
       copyStackTrace={[MockFunction]}
       disableContextMenu={false}
       displayFullUrl={false}
       frame={
         Object {
-          "displayName": "",
-          "id": 1,
+          "displayName": "display-1",
+          "generatedLocation": Object {
+            "line": 55,
+            "sourceId": "source",
+          },
+          "id": "1",
           "library": "Back",
           "location": Object {
             "line": 55,
+            "sourceId": "source",
+          },
+          "scope": Object {
+            "actor": "scope-actor",
+            "bindings": Object {
+              "arguments": Array [],
+              "variables": Object {},
+            },
+            "function": null,
+            "object": null,
+            "parent": null,
+            "type": "block",
           },
           "source": Object {
+            "contentType": "text/javascript",
+            "id": "source",
+            "introductionUrl": null,
+            "isBlackBoxed": false,
+            "isPrettyPrinted": false,
+            "isWasm": false,
+            "loadedState": "unloaded",
+            "relativeUrl": "http://myfile.com/mahscripts.js",
+            "text": "",
             "url": "http://myfile.com/mahscripts.js",
           },
+          "this": Object {},
+          "thread": "FakeThread",
         }
       }
       frameworkGroupingOn={true}
       hideLocation={true}
       key="1"
       selectFrame={[MockFunction]}
       selectable={true}
-      selectedFrame={Object {}}
+      selectedFrame={
+        Object {
+          "displayName": "foo",
+          "generatedLocation": Object {
+            "line": 4,
+            "sourceId": "source",
+          },
+          "id": "frame",
+          "library": "Back",
+          "location": Object {
+            "line": 4,
+            "sourceId": "source",
+          },
+          "scope": Object {
+            "actor": "scope-actor",
+            "bindings": Object {
+              "arguments": Array [],
+              "variables": Object {},
+            },
+            "function": null,
+            "object": null,
+            "parent": null,
+            "type": "block",
+          },
+          "source": Object {
+            "contentType": "text/javascript",
+            "id": "source",
+            "introductionUrl": null,
+            "isBlackBoxed": false,
+            "isPrettyPrinted": false,
+            "isWasm": false,
+            "loadedState": "unloaded",
+            "relativeUrl": "url",
+            "text": "",
+            "url": "url",
+          },
+          "this": Object {},
+          "thread": "FakeThread",
+        }
+      }
       shouldMapDisplayName={false}
       toggleBlackBox={[MockFunction]}
       toggleFrameworkGrouping={[MockFunction]}
     />
     <FrameIndent />
     <Frame
       copyStackTrace={[MockFunction]}
       disableContextMenu={false}
       displayFullUrl={false}
       frame={
         Object {
-          "displayName": "",
-          "id": 2,
+          "displayName": "display-2",
+          "generatedLocation": Object {
+            "line": 55,
+            "sourceId": "source",
+          },
+          "id": "2",
           "library": "Back",
           "location": Object {
             "line": 55,
+            "sourceId": "source",
+          },
+          "scope": Object {
+            "actor": "scope-actor",
+            "bindings": Object {
+              "arguments": Array [],
+              "variables": Object {},
+            },
+            "function": null,
+            "object": null,
+            "parent": null,
+            "type": "block",
           },
           "source": Object {
+            "contentType": "text/javascript",
+            "id": "source",
+            "introductionUrl": null,
+            "isBlackBoxed": false,
+            "isPrettyPrinted": false,
+            "isWasm": false,
+            "loadedState": "unloaded",
+            "relativeUrl": "http://myfile.com/back.js",
+            "text": "",
             "url": "http://myfile.com/back.js",
           },
+          "this": Object {},
+          "thread": "FakeThread",
         }
       }
       frameworkGroupingOn={true}
       hideLocation={true}
       key="2"
       selectFrame={[MockFunction]}
       selectable={true}
-      selectedFrame={Object {}}
+      selectedFrame={
+        Object {
+          "displayName": "foo",
+          "generatedLocation": Object {
+            "line": 4,
+            "sourceId": "source",
+          },
+          "id": "frame",
+          "library": "Back",
+          "location": Object {
+            "line": 4,
+            "sourceId": "source",
+          },
+          "scope": Object {
+            "actor": "scope-actor",
+            "bindings": Object {
+              "arguments": Array [],
+              "variables": Object {},
+            },
+            "function": null,
+            "object": null,
+            "parent": null,
+            "type": "block",
+          },
+          "source": Object {
+            "contentType": "text/javascript",
+            "id": "source",
+            "introductionUrl": null,
+            "isBlackBoxed": false,
+            "isPrettyPrinted": false,
+            "isWasm": false,
+            "loadedState": "unloaded",
+            "relativeUrl": "url",
+            "text": "",
+            "url": "url",
+          },
+          "this": Object {},
+          "thread": "FakeThread",
+        }
+      }
       shouldMapDisplayName={false}
       toggleBlackBox={[MockFunction]}
       toggleFrameworkGrouping={[MockFunction]}
     />
     <FrameIndent />
     <Frame
       copyStackTrace={[MockFunction]}
       disableContextMenu={false}
       displayFullUrl={false}
       frame={
         Object {
-          "displayName": "",
-          "id": 3,
+          "displayName": "display-3",
+          "generatedLocation": Object {
+            "line": 55,
+            "sourceId": "source",
+          },
+          "id": "3",
           "library": "Back",
           "location": Object {
             "line": 55,
+            "sourceId": "source",
+          },
+          "scope": Object {
+            "actor": "scope-actor",
+            "bindings": Object {
+              "arguments": Array [],
+              "variables": Object {},
+            },
+            "function": null,
+            "object": null,
+            "parent": null,
+            "type": "block",
           },
           "source": Object {
+            "contentType": "text/javascript",
+            "id": "source",
+            "introductionUrl": null,
+            "isBlackBoxed": false,
+            "isPrettyPrinted": false,
+            "isWasm": false,
+            "loadedState": "unloaded",
+            "relativeUrl": "http://myfile.com/back.js",
+            "text": "",
             "url": "http://myfile.com/back.js",
           },
+          "this": Object {},
+          "thread": "FakeThread",
         }
       }
       frameworkGroupingOn={true}
       hideLocation={true}
       key="3"
       selectFrame={[MockFunction]}
       selectable={true}
-      selectedFrame={Object {}}
+      selectedFrame={
+        Object {
+          "displayName": "foo",
+          "generatedLocation": Object {
+            "line": 4,
+            "sourceId": "source",
+          },
+          "id": "frame",
+          "library": "Back",
+          "location": Object {
+            "line": 4,
+            "sourceId": "source",
+          },
+          "scope": Object {
+            "actor": "scope-actor",
+            "bindings": Object {
+              "arguments": Array [],
+              "variables": Object {},
+            },
+            "function": null,
+            "object": null,
+            "parent": null,
+            "type": "block",
+          },
+          "source": Object {
+            "contentType": "text/javascript",
+            "id": "source",
+            "introductionUrl": null,
+            "isBlackBoxed": false,
+            "isPrettyPrinted": false,
+            "isWasm": false,
+            "loadedState": "unloaded",
+            "relativeUrl": "url",
+            "text": "",
+            "url": "url",
+          },
+          "this": Object {},
+          "thread": "FakeThread",
+        }
+      }
       shouldMapDisplayName={false}
       toggleBlackBox={[MockFunction]}
       toggleFrameworkGrouping={[MockFunction]}
     />
   </div>
 </div>
 `;
--- a/devtools/client/debugger/new/src/components/SecondaryPanes/XHRBreakpoints.js
+++ b/devtools/client/debugger/new/src/components/SecondaryPanes/XHRBreakpoints.js
@@ -54,16 +54,26 @@ class XHRBreakpoints extends Component<P
       editing: false,
       inputValue: "",
       inputMethod: "",
       focused: false,
       editIndex: -1
     };
   }
 
+  componentDidMount() {
+    const { showInput } = this.props;
+
+    // Ensures that the input is focused when the "+"
+    // is clicked while the panel is collapsed
+    if (this._input && showInput) {
+      this._input.focus();
+    }
+  }
+
   componentDidUpdate(prevProps, prevState) {
     const input = this._input;
 
     if (!input) {
       return;
     }
 
     if (!prevState.editing && this.state.editing) {
--- a/devtools/client/debugger/new/src/components/WelcomeBox.css
+++ b/devtools/client/debugger/new/src/components/WelcomeBox.css
@@ -1,23 +1,20 @@
 /* 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/>. */
 
 .welcomebox {
+  position: absolute;
+  top: var(--editor-header-height);
+  left: 0;
+  bottom: 1px;
   width: calc(100% - 1px);
-
-  /* Offsetting it by 30px for the sources-header area */
-  height: calc(100% - 30px);
-  position: absolute;
-  top: 30px;
-  left: 0;
   padding: 50px 0 0 0;
   text-align: center;
-  font-size: 1.25em;
   background-color: var(--theme-toolbar-background);
   font-weight: lighter;
   z-index: 10;
   user-select: none;
 }
 
 .theme-dark .welcomebox {
   background-color: var(--theme-body-background);
@@ -31,16 +28,17 @@
   offset-inline-start: auto;
   inset-inline-start: auto;
   bottom: 0;
 }
 
 .alignlabel {
   display: flex;
   white-space: nowrap;
+  font-size: 1.25em;
 }
 
 .shortcutKeys {
   font-family: Courier;
 }
 
 .shortcutKey,
 .shortcutLabel {
--- a/devtools/client/debugger/new/src/components/WelcomeBox.js
+++ b/devtools/client/debugger/new/src/components/WelcomeBox.js
@@ -30,17 +30,17 @@ export class WelcomeBox extends Componen
     const { horizontal, endPanelCollapsed, togglePaneCollapse } = this.props;
     if (horizontal) {
       return;
     }
 
     return (
       <PaneToggleButton
         position="end"
-        collapsed={!endPanelCollapsed}
+        collapsed={endPanelCollapsed}
         horizontal={horizontal}
         handleClick={togglePaneCollapse}
       />
     );
   }
 
   render() {
     const searchSourcesShortcut = formatKeyShortcut(
@@ -87,18 +87,18 @@ export class WelcomeBox extends Componen
               role="button"
               tabIndex="0"
               onClick={() => toggleShortcutsModal()}
             >
               <span className="shortcutKey">{allShortcutsShortcut}</span>
               <span className="shortcutLabel">{allShortcutsLabel}</span>
             </p>
           </div>
-          {this.renderToggleButton()}
         </div>
+        {this.renderToggleButton()}
       </div>
     );
   }
 }
 
 const mapStateToProps = state => ({
   endPanelCollapsed: getPaneCollapse(state, "end")
 });
--- a/devtools/client/debugger/new/src/components/shared/AccessibleImage.css
+++ b/devtools/client/debugger/new/src/components/shared/AccessibleImage.css
@@ -1,9 +1,9 @@
 .img {
   /* default height an width which will likely be overrode */
   width: 12px;
   height: 12px;
   /* makes span appear like an image */
   display: inline-block;
-  background: var(--theme-body-color);
+  background: var(--theme-icon-color);
   mask-size: 100%;
 }
--- a/devtools/client/debugger/new/src/components/shared/Button/PaneToggleButton.js
+++ b/devtools/client/debugger/new/src/components/shared/Button/PaneToggleButton.js
@@ -18,28 +18,30 @@ type Props = {
 
 class PaneToggleButton extends PureComponent<Props> {
   static defaultProps = {
     horizontal: false
   };
 
   render() {
     const { position, collapsed, horizontal, handleClick } = this.props;
-    const title = !collapsed
+    const title = collapsed
       ? L10N.getStr("expandPanes")
       : L10N.getStr("collapsePanes");
 
     return (
       <CommandBarButton
         className={classnames("toggle-button", position, {
           collapsed,
           vertical: !horizontal
         })}
-        onClick={() => handleClick(position, collapsed)}
+        onClick={() => handleClick(position, !collapsed)}
         title={title}
       >
-        <AccessibleImage className="toggle-panes" />
+        <AccessibleImage
+          className={collapsed ? "pane-expand" : "pane-collapse"}
+        />
       </CommandBarButton>
     );
   }
 }
 
 export default PaneToggleButton;
--- a/devtools/client/debugger/new/src/components/shared/Button/index.js
+++ b/devtools/client/debugger/new/src/components/shared/Button/index.js
@@ -1,9 +1,11 @@
 /* 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/>. */
 
+// @flow
+
 import CloseButton from "./CloseButton";
 import CommandBarButton, { debugBtn } from "./CommandBarButton";
 import PaneToggleButton from "./PaneToggleButton";
 
 export { CloseButton, CommandBarButton, debugBtn, PaneToggleButton };
--- a/devtools/client/debugger/new/src/components/shared/Button/styles/CommandBarButton.css
+++ b/devtools/client/debugger/new/src/components/shared/Button/styles/CommandBarButton.css
@@ -18,16 +18,20 @@
   opacity: 0.8;
   cursor: default;
 }
 
 .command-bar-button:not(.disabled):hover {
   background: var(--theme-toolbar-background-hover);
 }
 
+.theme-dark .command-bar-button:not(.disabled):hover {
+  background: var(--theme-toolbar-hover);
+}
+
 :root.theme-dark .command-bar-button {
   color: var(--theme-body-color);
 }
 
 .command-bar-button > * {
   width: 16px;
   height: 16px;
   display: inline-block;
--- a/devtools/client/debugger/new/src/components/shared/Button/styles/PaneToggleButton.css
+++ b/devtools/client/debugger/new/src/components/shared/Button/styles/PaneToggleButton.css
@@ -1,42 +1,29 @@
 /* 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/>. */
 
 .toggle-button {
-  transform: translate(0, 0px);
-  transition: transform 0.25s ease-in-out;
-  padding: 5px;
-  height: inherit;
+  padding: 4px 6px;
 }
 
 .toggle-button .img {
-  fill: var(--theme-comment);
-  vertical-align: 0;
-}
-
-:root.theme-dark .toggle-button .img {
-  fill: var(--theme-comment-alt);
+  vertical-align: middle;
 }
 
 .toggle-button.end {
   margin-inline-end: 0px;
   margin-inline-start: auto;
 }
 
 .toggle-button.start {
   margin-inline-start: 0px;
 }
 
-html:not([dir="rtl"]) .toggle-button.end .img,
-html[dir="rtl"] .toggle-button.start .img {
-  transform: rotate(180deg);
+html[dir="rtl"] .toggle-button.start .img,
+html[dir="ltr"] .toggle-button.end:not(.vertical) .img {
+  transform: scaleX(-1);
 }
 
-html .toggle-button.end.vertical .img {
+.toggle-button.end.vertical .img {
   transform: rotate(-90deg);
 }
-
-.toggle-button.start.collapsed,
-.toggle-button.end.collapsed {
-  transform: rotate(180deg);
-}
--- a/devtools/client/debugger/new/src/components/shared/Button/tests/CloseButton.spec.js
+++ b/devtools/client/debugger/new/src/components/shared/Button/tests/CloseButton.spec.js
@@ -6,17 +6,19 @@
 
 import React from "react";
 import { shallow } from "enzyme";
 import { CloseButton } from "../";
 
 describe("CloseButton", () => {
   it("renders with tooltip", () => {
     const tooltip = "testTooltip";
-    const wrapper = shallow(<CloseButton tooltip={tooltip} />);
+    const wrapper = shallow(
+      <CloseButton tooltip={tooltip} handleClick={() => {}} />
+    );
     expect(wrapper).toMatchSnapshot();
   });
 
   it("handles click event", () => {
     const handleClickSpy = jest.fn();
     const wrapper = shallow(<CloseButton handleClick={handleClickSpy} />);
     wrapper.simulate("click");
     expect(handleClickSpy).toBeCalled();
--- a/devtools/client/debugger/new/src/components/shared/Button/tests/CommandBarButton.spec.js
+++ b/devtools/client/debugger/new/src/components/shared/Button/tests/CommandBarButton.spec.js
@@ -5,23 +5,27 @@
 // @flow
 
 import React from "react";
 import { shallow } from "enzyme";
 import { CommandBarButton, debugBtn } from "../";
 
 describe("CommandBarButton", () => {
   it("renders", () => {
-    const wrapper = shallow(<CommandBarButton />);
+    const wrapper = shallow(
+      <CommandBarButton children={([]: any)} className={""} />
+    );
     expect(wrapper).toMatchSnapshot();
   });
 
   it("renders children", () => {
     const children = [1, 2, 3, 4];
-    const wrapper = shallow(<CommandBarButton children={children} />);
+    const wrapper = shallow(
+      <CommandBarButton children={(children: any)} className={""} />
+    );
     expect(wrapper.find("button").children()).toHaveLength(4);
   });
 });
 
 describe("debugBtn", () => {
   it("renders", () => {
     const wrapper = shallow(<debugBtn />);
     expect(wrapper).toMatchSnapshot();
--- a/devtools/client/debugger/new/src/components/shared/Button/tests/PaneToggleButton.spec.js
+++ b/devtools/client/debugger/new/src/components/shared/Button/tests/PaneToggleButton.spec.js
@@ -5,17 +5,23 @@
 // @flow
 
 import React from "react";
 import { shallow } from "enzyme";
 import { PaneToggleButton } from "../";
 
 describe("PaneToggleButton", () => {
   const handleClickSpy = jest.fn();
-  const wrapper = shallow(<PaneToggleButton handleClick={handleClickSpy} />);
+  const wrapper = shallow(
+    <PaneToggleButton
+      handleClick={handleClickSpy}
+      collapsed={false}
+      position={""}
+    />
+  );
 
   it("renders default", () => {
     expect(wrapper.hasClass("vertical")).toBe(true);
     expect(wrapper).toMatchSnapshot();
   });
 
   it("toggles horizontal class", () => {
     wrapper.setProps({ horizontal: true });
@@ -34,14 +40,14 @@ describe("PaneToggleButton", () => {
 
   it("toggles end position ", () => {
     wrapper.setProps({ position: "end" });
     expect(wrapper.hasClass("end")).toBe(true);
   });
 
   it("handleClick is called", () => {
     const position = "testPosition";
-    const collapsed = "testCollapsed";
+    const collapsed = false;
     wrapper.setProps({ position, collapsed });
     wrapper.simulate("click");
-    expect(handleClickSpy).toBeCalledWith(position, collapsed);
+    expect(handleClickSpy).toBeCalledWith(position, true);
   });
 });
--- a/devtools/client/debugger/new/src/components/shared/Button/tests/__snapshots__/CloseButton.spec.js.snap
+++ b/devtools/client/debugger/new/src/components/shared/Button/tests/__snapshots__/CloseButton.spec.js.snap
@@ -1,12 +1,13 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
 exports[`CloseButton renders with tooltip 1`] = `
 <button
   className="close-btn"
+  onClick={[Function]}
   title="testTooltip"
 >
   <AccessibleImage
     className="close"
   />
 </button>
 `;
--- a/devtools/client/debugger/new/src/components/shared/Button/tests/__snapshots__/PaneToggleButton.spec.js.snap
+++ b/devtools/client/debugger/new/src/components/shared/Button/tests/__snapshots__/PaneToggleButton.spec.js.snap
@@ -1,13 +1,13 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
 exports[`PaneToggleButton renders default 1`] = `
 <CommandBarButton
   className="toggle-button vertical"
   onClick={[Function]}
-  title="Expand panes"
+  title="Collapse panes"
 >
   <AccessibleImage
-    className="toggle-panes"
+    className="pane-collapse"
   />
 </CommandBarButton>
 `;
--- a/devtools/client/debugger/new/src/components/shared/ManagedTree.js
+++ b/devtools/client/debugger/new/src/components/shared/ManagedTree.js
@@ -35,18 +35,17 @@ type Props = {
 type State = {
   expanded: any
 };
 
 class ManagedTree extends Component<Props, State> {
   constructor(props: Props) {
     super(props);
     this.state = {
-      expanded: props.expanded || new Set(),
-      focusedItem: null
+      expanded: props.expanded || new Set()
     };
   }
 
   static defaultProps = {
     onFocus: () => {}
   };
 
   componentWillReceiveProps(nextProps: Props) {
--- a/devtools/client/debugger/new/src/components/shared/PreviewFunction.js
+++ b/devtools/client/debugger/new/src/components/shared/PreviewFunction.js
@@ -20,17 +20,17 @@ type FunctionType = {
   parameterNames?: string[]
 };
 
 type Props = { func: FunctionType };
 
 export default class PreviewFunction extends Component<Props> {
   renderFunctionName(func: FunctionType) {
     const { l10n } = this.context;
-    const name = formatDisplayName(func, undefined, l10n);
+    const name = formatDisplayName((func: any), undefined, l10n);
     return <span className="function-name">{name}</span>;
   }
 
   renderParams(func: FunctionType) {
     const { parameterNames = [] } = func;
     const params = parameterNames.filter(i => i).map(param => (
       <span className="param" key={param}>
         {param}
--- a/devtools/client/debugger/new/src/components/shared/Svg.css
+++ b/devtools/client/debugger/new/src/components/shared/Svg.css
@@ -203,18 +203,23 @@ span.img.marko {
   mask-size: 100%;
 }
 
 .img.extension {
   mask: url(/images/extension.svg) no-repeat;
   mask-size: 100%;
 }
 
-.img.toggle-panes {
-  mask: url(/images/toggle-panes.svg) no-repeat;
+.img.pane-collapse {
+  mask: url(/images/pane-collapse.svg) no-repeat;
+  mask-size: 100%;
+}
+
+.img.pane-expand {
+  mask: url(/images/pane-expand.svg) no-repeat;
   mask-size: 100%;
 }
 
 .img.file {
   mask: url(/images/file.svg) no-repeat;
   mask-size: 100%;
   width: 13px;
   height: 13px;
--- a/devtools/client/debugger/new/src/components/test/ProjectSearch.spec.js
+++ b/devtools/client/debugger/new/src/components/test/ProjectSearch.spec.js
@@ -60,16 +60,17 @@ const testResults = [
         type: "MATCH"
       },
       { match: "match5", value: "some thing match5", column: 40, type: "MATCH" }
     ]
   }
 ];
 
 const testMatch = {
+  type: "MATCH",
   match: "match1",
   value: "some thing match1",
   sourceId: "some-target/source42",
   line: 3,
   column: 30
 };
 
 function render(overrides = {}, mounted = false) {
@@ -193,62 +194,39 @@ describe("ProjectSearch", () => {
     const selectSpecificLocation = jest.fn();
     const component = render(
       {
         results: testResults,
         selectSpecificLocation
       },
       true
     );
-    component.instance().focusedItem = null;
+    component.instance().state.focusedItem = null;
     shortcuts.dispatch("Enter");
     expect(selectSpecificLocation).not.toHaveBeenCalled();
   });
 
   it("onEnterPress shortcut match", () => {
     const selectSpecificLocation = jest.fn();
     const component = render(
       {
         results: testResults,
         selectSpecificLocation
       },
       true
     );
-    component.instance().focusedItem = { match: testMatch, expanded: null };
+    component.instance().state.focusedItem = { ...testMatch };
     shortcuts.dispatch("Enter");
     expect(selectSpecificLocation).toHaveBeenCalledWith({
       sourceId: "some-target/source42",
       line: 3,
       column: 30
     });
   });
 
-  it("onEnterPress shortcut setExpanded", () => {
-    const selectSpecificLocation = jest.fn();
-    const component = render(
-      {
-        results: testResults,
-        selectSpecificLocation
-      },
-      true
-    );
-    const setExpanded = jest.fn();
-    const testFile = {
-      filepath: "testFilePath1",
-      matches: [testMatch]
-    };
-    component.instance().focusedItem = {
-      setExpanded,
-      file: testFile,
-      expanded: true
-    };
-    shortcuts.dispatch("Enter");
-    expect(setExpanded).toHaveBeenCalledWith(testFile, false);
-  });
-
   it("state.inputValue responds to prop.query changes", () => {
     const component = render({ query: "foo" });
     expect(component.state().inputValue).toEqual("foo");
     component.setProps({ query: "" });
     expect(component.state().inputValue).toEqual("");
   });
 
   describe("showErrorEmoji", () => {
--- a/devtools/client/debugger/new/src/components/test/__snapshots__/Outline.spec.js.snap
+++ b/devtools/client/debugger/new/src/components/test/__snapshots__/Outline.spec.js.snap
@@ -5,17 +5,17 @@ exports[`Outline renders a list of funct
   className="outline"
 >
   <div>
     <OutlineFilter
       filter=""
       updateFilter={[Function]}
     />
     <ul
-      className="outline-list"
+      className="outline-list devtools-monospace"
     >
       <li
         className="outline-list__element"
         key="my_example_function1:21:undefined"
         onClick={[Function]}
         onContextMenu={[Function]}
       >
         <span
@@ -72,17 +72,17 @@ exports[`Outline renders outline renders
   className="outline"
 >
   <div>
     <OutlineFilter
       filter=""
       updateFilter={[Function]}
     />
     <ul
-      className="outline-list"
+      className="outline-list devtools-monospace"
     >
       <div
         className="outline-list__class"
         key="x_klass"
       >
         <h2
           onClick={[Function]}
         >
@@ -199,17 +199,17 @@ exports[`Outline renders outline renders
   className="outline"
 >
   <div>
     <OutlineFilter
       filter=""
       updateFilter={[Function]}
     />
     <ul
-      className="outline-list"
+      className="outline-list devtools-monospace"
     >
       <div
         className="outline-list__class"
         key="x_klass"
       >
         <h2
           onClick={[Function]}
         >
@@ -326,17 +326,17 @@ exports[`Outline renders outline renders
   className="outline"
 >
   <div>
     <OutlineFilter
       filter=""
       updateFilter={[Function]}
     />
     <ul
-      className="outline-list"
+      className="outline-list devtools-monospace"
     >
       <li
         className="outline-list__element"
         key="my_example_function1:21:undefined"
         onClick={[Function]}
         onContextMenu={[Function]}
       >
         <span
@@ -413,17 +413,17 @@ exports[`Outline renders outline sorts f
   className="outline"
 >
   <div>
     <OutlineFilter
       filter=""
       updateFilter={[Function]}
     />
     <ul
-      className="outline-list"
+      className="outline-list devtools-monospace"
     >
       <li
         className="outline-list__element"
         key="a_function:70:undefined"
         onClick={[Function]}
         onContextMenu={[Function]}
       >
         <span
--- a/devtools/client/debugger/new/src/components/test/__snapshots__/ProjectSearch.spec.js.snap
+++ b/devtools/client/debugger/new/src/components/test/__snapshots__/ProjectSearch.spec.js.snap
@@ -195,44 +195,47 @@ exports[`ProjectSearch found search resu
             </div>
           </div>
         </SearchInput>
       </div>
       <ManagedTree
         autoExpandAll={true}
         autoExpandDepth={1}
         autoExpandNodeChildrenLimit={100}
+        focused={null}
         getChildren={[Function]}
         getParent={[Function]}
         getPath={[Function]}
         getRoots={[Function]}
         itemHeight={24}
         onFocus={[Function]}
         renderItem={[Function]}
       >
         <div
           className="managed-tree"
         >
           <Tree
             autoExpandAll={true}
             autoExpandDepth={1}
             autoExpandNodeChildrenLimit={100}
+            focused={null}
             getChildren={[Function]}
             getKey={[Function]}
             getParent={[Function]}
             getPath={[Function]}
             getRoots={[Function]}
             isExpanded={[Function]}
             itemHeight={24}
             onCollapse={[Function]}
             onExpand={[Function]}
             onFocus={[Function]}
             renderItem={[Function]}
           >
             <div
+              aria-activedescendant={null}
               className="tree "
               onBlur={[Function]}
               onFocus={[Function]}
               onKeyDown={[Function]}
               onKeyPress={[Function]}
               onKeyUp={[Function]}
               role="tree"
               style={Object {}}
@@ -832,16 +835,17 @@ exports[`ProjectSearch showErrorEmoji fa
         size="big"
         summaryMsg="5 results"
       />
     </div>
     <ManagedTree
       autoExpandAll={true}
       autoExpandDepth={1}
       autoExpandNodeChildrenLimit={100}
+      focused={null}
       getChildren={[Function]}
       getParent={[Function]}
       getPath={[Function]}
       getRoots={[Function]}
       itemHeight={24}
       onFocus={[Function]}
       renderItem={[Function]}
     />
--- a/devtools/client/debugger/new/src/components/test/__snapshots__/WelcomeBox.spec.js.snap
+++ b/devtools/client/debugger/new/src/components/test/__snapshots__/WelcomeBox.spec.js.snap
@@ -57,17 +57,17 @@ exports[`WelomeBox renders with default 
         </span>
         <span
           className="shortcutLabel"
         >
           Show all shortcuts
         </span>
       </p>
     </div>
-    <PaneToggleButton
-      collapsed={true}
-      handleClick={[MockFunction]}
-      horizontal={false}
-      position="end"
-    />
   </div>
+  <PaneToggleButton
+    collapsed={false}
+    handleClick={[MockFunction]}
+    horizontal={false}
+    position="end"
+  />
 </div>
 `;
--- a/devtools/client/debugger/new/src/components/variables.css
+++ b/devtools/client/debugger/new/src/components/variables.css
@@ -1,12 +1,21 @@
 /* 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/>. */
 
+:root {
+  /* header height is 28px + 1px for its border */
+  --editor-header-height: 29px;
+  /* footer height is 24px + 1px for its border */
+  --editor-footer-height: 25px;
+  /* searchbar height is 24px + 2px for its top and bottom borders */
+  --editor-searchbar-height: 26px;
+}
+
 :root.theme-light,
 :root .theme-light {
   --search-overlays-semitransparent: rgba(221, 225, 228, 0.66);
   --popup-shadow-color: #d0d0d0;
 }
 
 :root.theme-dark,
 :root .theme-dark {
--- a/devtools/client/debugger/new/src/reducers/async-requests.js
+++ b/devtools/client/debugger/new/src/reducers/async-requests.js
@@ -1,30 +1,32 @@
 /* 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/>. */
 
+// @flow
+
 /**
  * Async request reducer
  * @module reducers/async-request
  */
 
 const initialAsyncRequestState = [];
 
-function update(state = initialAsyncRequestState, action) {
+function update(state: string[] = initialAsyncRequestState, action: any) {
   const { seqId } = action;
 
   if (action.type === "NAVIGATE") {
     return initialAsyncRequestState;
   } else if (seqId) {
     let newState;
     if (action.status === "start") {
       newState = [...state, seqId];
     } else if (action.status === "error" || action.status === "done") {
-      newState = state.filter(id => id !== seqId);
+      newState = (state.filter(id => id !== seqId): string[]);
     }
 
     return newState;
   }
 
   return state;
 }
 
--- a/devtools/client/debugger/new/src/reducers/index.js
+++ b/devtools/client/debugger/new/src/reducers/index.js
@@ -1,12 +1,14 @@
 /* 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/>. */
 
+// @flow
+
 /**
  * Reducer index
  * @module reducers/index
  */
 
 import expressions from "./expressions";
 import sources from "./sources";
 import tabs from "./tabs";
--- a/devtools/client/debugger/new/src/reducers/quick-open.js
+++ b/devtools/client/debugger/new/src/reducers/quick-open.js
@@ -1,31 +1,33 @@
 /* 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/>. */
 
+// @flow
+
 /**
  * Quick Open reducer
  * @module reducers/quick-open
  */
 
 import makeRecord from "../utils/makeRecord";
 import { parseQuickOpenQuery } from "../utils/quick-open";
 import type { Action } from "../actions/types";
 import type { Record } from "../utils/makeRecord";
 
 export type QuickOpenType = "sources" | "functions" | "goto" | "gotoSource";
 
-type QuickOpenState = {
+export type QuickOpenState = {
   enabled: boolean,
   query: string,
   searchType: QuickOpenType
 };
 
-export const createQuickOpenState = makeRecord({
+export const createQuickOpenState: () => Record<QuickOpenState> = makeRecord({
   enabled: false,
   query: "",
   searchType: "sources"
 });
 
 export default function update(
   state: Record<QuickOpenState> = createQuickOpenState(),
   action: Action
--- a/devtools/client/debugger/new/src/reducers/tests/quick-open.spec.js
+++ b/devtools/client/debugger/new/src/reducers/tests/quick-open.spec.js
@@ -16,17 +16,17 @@ import update, {
 import {
   setQuickOpenQuery,
   openQuickOpen,
   closeQuickOpen
 } from "../../actions/quick-open";
 
 describe("quickOpen reducer", () => {
   test("initial state", () => {
-    const state = update(undefined, { type: "FAKE" });
+    const state = update(undefined, ({ type: "FAKE" }: any));
     expect(getQuickOpenQuery({ quickOpen: state })).toEqual("");
     expect(getQuickOpenType({ quickOpen: state })).toEqual("sources");
   });
 
   test("opens the quickOpen modal", () => {
     const state = update(createQuickOpenState(), openQuickOpen());
     expect(getQuickOpenEnabled({ quickOpen: state })).toEqual(true);
   });
--- a/devtools/client/debugger/new/src/reducers/types.js
+++ b/devtools/client/debugger/new/src/reducers/types.js
@@ -16,29 +16,31 @@ import type { DebuggeeState } from "./de
 import type { FileSearchState } from "./file-search";
 import type { PauseState } from "./pause";
 import type { PendingBreakpointsState } from "../selectors";
 import type { ProjectTextSearchState } from "./project-text-search";
 import type { Record } from "../utils/makeRecord";
 import type { SourcesState } from "./sources";
 import type { TabList } from "./tabs";
 import type { UIState } from "./ui";
+import type { QuickOpenState } from "./quick-open";
 
 export type State = {
   ast: Record<ASTState>,
   breakpoints: BreakpointsState,
   expressions: Record<ExpressionState>,
   debuggee: DebuggeeState,
   fileSearch: Record<FileSearchState>,
   pause: PauseState,
   pendingBreakpoints: PendingBreakpointsState,
   projectTextSearch: ProjectTextSearchState,
   sources: SourcesState,
   tabs: TabList,
-  ui: Record<UIState>
+  ui: Record<UIState>,
+  quickOpen: Record<QuickOpenState>
 };
 
 export type Selector<T> = State => T;
 
 export type PendingSelectedLocation = {
   url: string,
   line?: number,
   column?: number
--- a/devtools/client/debugger/new/src/selectors/breakpointAtLocation.js
+++ b/devtools/client/debugger/new/src/selectors/breakpointAtLocation.js
@@ -1,46 +1,50 @@
 /* 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/>. */
 
+// @flow
+
 import { getSelectedSource } from "../reducers/sources";
 import { getBreakpointsList } from "../reducers/breakpoints";
 import { isGenerated } from "../utils/source";
 
+import type { Breakpoint } from "../types";
+import type { State } from "../reducers/types";
+
 function getColumn(column, selectedSource) {
   if (column) {
     return column;
   }
 
   return isGenerated(selectedSource) ? undefined : 0;
 }
 
 function getLocation(bp, selectedSource) {
   return isGenerated(selectedSource)
     ? bp.generatedLocation || bp.location
     : bp.location;
 }
 
-function getBreakpointsForSource(
-  state: OuterState,
-  selectedSource: Source
-): Breakpoint[] {
+function getBreakpointsForSource(state: State, selectedSource): Breakpoint[] {
   const breakpoints = getBreakpointsList(state);
 
   return breakpoints.filter(bp => {
     const location = getLocation(bp, selectedSource);
     return location.sourceId === selectedSource.id;
   });
 }
 
+type LineColumn = { line: number, column: ?number };
+
 function findBreakpointAtLocation(
   breakpoints,
   selectedSource,
-  { line, column }
+  { line, column }: LineColumn
 ) {
   return breakpoints.find(breakpoint => {
     const location = getLocation(breakpoint, selectedSource);
     const sameLine = location.line === line;
     if (!sameLine) {
       return false;
     }
 
@@ -54,23 +58,29 @@ function findBreakpointAtLocation(
 
 /*
  * Finds a breakpoint at a location (line, column) of the
  * selected source.
  *
  * This is useful for finding a breakpoint when the
  * user clicks in the gutter or on a token.
  */
-export function getBreakpointAtLocation(state, location) {
+export function getBreakpointAtLocation(state: State, location: LineColumn) {
   const selectedSource = getSelectedSource(state);
+  if (!selectedSource) {
+    throw new Error("no selectedSource");
+  }
   const breakpoints = getBreakpointsForSource(state, selectedSource);
 
   return findBreakpointAtLocation(breakpoints, selectedSource, location);
 }
 
-export function getBreakpointsAtLine(state: OuterState, line: number) {
+export function getBreakpointsAtLine(state: State, line: number): Breakpoint[] {
   const selectedSource = getSelectedSource(state);
+  if (!selectedSource) {
+    throw new Error("no selectedSource");
+  }
   const breakpoints = getBreakpointsForSource(state, selectedSource);
 
   return breakpoints.filter(
     breakpoint => getLocation(breakpoint, selectedSource).line === line
   );
 }
--- a/devtools/client/debugger/new/src/selectors/getCallStackFrames.js
+++ b/devtools/client/debugger/new/src/selectors/getCallStackFrames.js
@@ -1,37 +1,48 @@
 /* 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/>. */
 
+// @flow
+
 import {
   getSources,
   getSelectedSource,
   getSourceInSources
 } from "../reducers/sources";
 import { getFrames } from "../reducers/pause";
 import { annotateFrames } from "../utils/pause/frames";
 import { isOriginal } from "../utils/source";
 import { get } from "lodash";
+import type { State } from "../reducers/types";
 import type { Frame, Source } from "../types";
 import type { SourcesMap } from "../reducers/sources";
 import { createSelector } from "reselect";
 
 function getLocation(frame, isGeneratedSource) {
   return isGeneratedSource
     ? frame.generatedLocation || frame.location
     : frame.location;
 }
 
-function getSourceForFrame(sources, frame, isGeneratedSource) {
+function getSourceForFrame(
+  sources: SourcesMap,
+  frame: Frame,
+  isGeneratedSource
+) {
   const sourceId = getLocation(frame, isGeneratedSource).sourceId;
   return getSourceInSources(sources, sourceId);
 }
 
-function appendSource(sources, frame, selectedSource) {
+function appendSource(
+  sources: SourcesMap,
+  frame: Frame,
+  selectedSource: ?Source
+): Frame {
   const isGeneratedSource = selectedSource && !isOriginal(selectedSource);
   return {
     ...frame,
     location: getLocation(frame, isGeneratedSource),
     source: getSourceForFrame(sources, frame, isGeneratedSource)
   };
 }
 
@@ -39,22 +50,22 @@ export function formatCallStackFrames(
   frames: Frame[],
   sources: SourcesMap,
   selectedSource: Source
 ) {
   if (!frames) {
     return null;
   }
 
-  const formattedFrames = frames
+  const formattedFrames: Frame[] = frames
     .filter(frame => getSourceForFrame(sources, frame))
     .map(frame => appendSource(sources, frame, selectedSource))
     .filter(frame => !get(frame, "source.isBlackBoxed"));
 
   return annotateFrames(formattedFrames);
 }
 
-export const getCallStackFrames = createSelector(
+export const getCallStackFrames: State => Frame[] = (createSelector: any)(
   getFrames,
   getSources,
   getSelectedSource,
   formatCallStackFrames
 );
--- a/devtools/client/debugger/new/src/selectors/isSelectedFrameVisible.js
+++ b/devtools/client/debugger/new/src/selectors/isSelectedFrameVisible.js
@@ -1,29 +1,32 @@
 /* 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/>. */
 
+// @flow
+
 import { originalToGeneratedId, isOriginalId } from "devtools-source-map";
 import { getSelectedFrame } from "../reducers/pause";
 import { getSelectedLocation } from "../reducers/sources";
+import type { State } from "../reducers/types";
 
 function getGeneratedId(sourceId) {
   if (isOriginalId(sourceId)) {
     return originalToGeneratedId(sourceId);
   }
 
   return sourceId;
 }
 
 /*
  * Checks to if the selected frame's source is currently
  * selected.
  */
-export function isSelectedFrameVisible(state) {
+export function isSelectedFrameVisible(state: State) {
   const selectedLocation = getSelectedLocation(state);
   const selectedFrame = getSelectedFrame(state);
 
   if (!selectedFrame || !selectedLocation) {
     return false;
   }
 
   if (isOriginalId(selectedLocation.sourceId)) {
--- a/devtools/client/debugger/new/src/selectors/visiblePausePoints.js
+++ b/devtools/client/debugger/new/src/selectors/visiblePausePoints.js
@@ -1,15 +1,19 @@
 /* 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/>. */
 
+// @flow
+
 import { getSelectedSource } from "../reducers/sources";
 import { getPausePoints } from "../reducers/ast";
 
-export function getVisiblePausePoints(state) {
+import type { State } from "../reducers/types";
+
+export function getVisiblePausePoints(state: State) {
   const source = getSelectedSource(state);
   if (!source) {
     return null;
   }
 
   return getPausePoints(state, source.id);
 }
--- a/devtools/client/debugger/new/src/test/__mocks__/request-animation-frame.js
+++ b/devtools/client/debugger/new/src/test/__mocks__/request-animation-frame.js
@@ -1,7 +1,10 @@
 /* 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/>. */
+
+// @flow
+
 global.requestAnimationFrame = function(cb) {
   cb();
   return null;
 };
--- a/devtools/client/debugger/new/src/test/__mocks__/styleMock.js
+++ b/devtools/client/debugger/new/src/test/__mocks__/styleMock.js
@@ -1,5 +1,7 @@
 /* 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/>. */
 
+// @flow
+
 module.exports = {};
--- a/devtools/client/debugger/new/src/test/__mocks__/svgMock.js
+++ b/devtools/client/debugger/new/src/test/__mocks__/svgMock.js
@@ -1,5 +1,7 @@
 /* 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/>. */
 
+// @flow
+
 module.exports = "<svg></svg>";
--- a/devtools/client/debugger/new/src/test/shim.js
+++ b/devtools/client/debugger/new/src/test/shim.js
@@ -1,5 +1,7 @@
 /* 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/>. */
 
+// @flow
+
 global.requestAnimationFrame = callback => setTimeout(callback, 0);
--- a/devtools/client/debugger/new/src/test/tests-setup.js
+++ b/devtools/client/debugger/new/src/test/tests-setup.js
@@ -1,18 +1,22 @@
 /* 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/>. */
 
+// @flow
+
+// $FlowIgnore
 global.Worker = require("workerjs");
 
 import path from "path";
 // import getConfig from "../../bin/getConfig";
 import { readFileSync } from "fs";
 import Enzyme from "enzyme";
+// $FlowIgnore
 import Adapter from "enzyme-adapter-react-16";
 import { setupHelper } from "../utils/dbg";
 import { prefs } from "../utils/prefs";
 
 import { startSourceMapWorker, stopSourceMapWorker } from "devtools-source-map";
 
 import {
   start as startPrettyPrintWorker,
@@ -60,17 +64,18 @@ global.indexedDB = mockIndexeddDB();
 Enzyme.configure({ adapter: new Adapter() });
 
 function formatException(reason, p) {
   console && console.log("Unhandled Rejection at:", p, "reason:", reason);
 }
 
 beforeAll(() => {
   startSourceMapWorker(
-    path.join(rootPath, "node_modules/devtools-source-map/src/worker.js")
+    path.join(rootPath, "node_modules/devtools-source-map/src/worker.js"),
+    ""
   );
   startPrettyPrintWorker(
     path.join(rootPath, "src/workers/pretty-print/worker.js")
   );
   startParserWorker(path.join(rootPath, "src/workers/parser/worker.js"));
   startSearchWorker(path.join(rootPath, "src/workers/search/worker.js"));
   process.on("unhandledRejection", formatException);
 });
--- a/devtools/client/debugger/new/src/test/utils/history.js
+++ b/devtools/client/debugger/new/src/test/utils/history.js
@@ -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/>. */
 
+// @flow
+
 let logs = [];
-export function getHistory(query: ?string = null) {
+export function getHistory(query: ?string = null): any {
   if (!query) {
     return logs;
   }
 
   return logs.filter(log => log.type === query);
 }
 
 export function clearHistory() {
--- a/devtools/client/debugger/new/src/types.js
+++ b/devtools/client/debugger/new/src/types.js
@@ -182,23 +182,24 @@ export type FrameId = string;
  * @static
  */
 export type Frame = {
   id: FrameId,
   thread: string,
   displayName: string,
   location: SourceLocation,
   generatedLocation: SourceLocation,
-  source?: Source,
+  source: ?Source,
   scope: Scope,
   // FIXME Define this type more clearly
   this: Object,
   framework?: string,
   isOriginal?: boolean,
-  originalDisplayName?: string
+  originalDisplayName?: string,
+  library?: string
 };
 
 export type ChromeFrame = {
   id: FrameId,
   displayName: string,
   scopeChain: any,
   generatedLocation: SourceLocation,
   location: ?SourceLocation
--- a/devtools/client/debugger/new/src/utils/editor/source-editor.js
+++ b/devtools/client/debugger/new/src/utils/editor/source-editor.js
@@ -1,19 +1,22 @@
 /* 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/>. */
 
+// @flow
+
 /**
  * CodeMirror source editor utils
  * @module utils/source-editor
  */
 
 const CodeMirror = require("codemirror");
 
+// $FlowIgnore
 require("codemirror/lib/codemirror.css");
 require("codemirror/mode/javascript/javascript");
 require("codemirror/mode/htmlmixed/htmlmixed");
 require("codemirror/mode/coffeescript/coffeescript");
 require("codemirror/mode/jsx/jsx");
 require("codemirror/mode/elm/elm");
 require("codemirror/mode/clojure/clojure");
 require("codemirror/mode/haxe/haxe");
--- a/devtools/client/debugger/new/src/utils/editor/token-events.js
+++ b/devtools/client/debugger/new/src/utils/editor/token-events.js
@@ -1,15 +1,17 @@
-import { getTokenLocation } from ".";
-import { isEqual } from "lodash";
-
 /* 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/>. */
 
+// @flow
+
+import { getTokenLocation } from ".";
+import { isEqual } from "lodash";
+
 function isInvalidTarget(target: HTMLElement) {
   if (!target || !target.innerText) {
     return true;
   }
 
   const tokenText = target.innerText.trim();
   const cursorPos = target.getBoundingClientRect();
 
@@ -45,17 +47,17 @@ function dispatch(codeMirror, eventName,
 function invalidLeaveTarget(target: ?HTMLElement) {
   if (!target || target.closest(".popover")) {
     return true;
   }
 
   return false;
 }
 
-export function onMouseOver(codeMirror) {
+export function onMouseOver(codeMirror: any) {
   let prevTokenPos = null;
 
   function onMouseLeave(event) {
     if (invalidLeaveTarget(event.relatedTarget)) {
       return addMouseLeave(event.target);
     }
 
     prevTokenPos = null;
@@ -64,17 +66,17 @@ export function onMouseOver(codeMirror) 
 
   function addMouseLeave(target) {
     target.addEventListener("mouseleave", onMouseLeave, {
       capture: true,
       once: true
     });
   }
 
-  return enterEvent => {
+  return (enterEvent: any) => {
     const { target } = enterEvent;
 
     if (isInvalidTarget(target)) {
       return;
     }
 
     const tokenPos = getTokenLocation(codeMirror, target);
 
--- a/devtools/client/debugger/new/src/utils/pause/frames/collapseFrames.js
+++ b/devtools/client/debugger/new/src/utils/pause/frames/collapseFrames.js
@@ -2,37 +2,37 @@
  * 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/>. */
 
 // @flow
 
 import { get, findIndex } from "lodash";
 
 // eslint-disable-next-line max-len
-import type { LocalFrame } from "../../../components/SecondaryPanes/Frames/types";
+import type { Frame } from "../../../types";
 import { getFrameUrl } from "./getFrameUrl";
 
 function collapseLastFrames(frames) {
   const index = findIndex(frames, frame =>
     getFrameUrl(frame).match(/webpack\/bootstrap/i)
   );
 
   if (index == -1) {
     return { newFrames: frames, lastGroup: [] };
   }
 
   const newFrames = frames.slice(0, index);
   const lastGroup = frames.slice(index);
   return { newFrames, lastGroup };
 }
 
-type FrameGroup = LocalFrame[];
-type GroupedFrames = Array<FrameGroup | LocalFrame>;
+type FrameGroup = Frame[];
+type GroupedFrames = Array<FrameGroup | Frame>;
 
-export function collapseFrames(frames: LocalFrame[]): GroupedFrames {
+export function collapseFrames(frames: Frame[]): GroupedFrames {
   // We collapse groups of one so that user frames
   // are not in a group of one
   function addGroupToList(group, list) {
     if (!group) {
       return list;
     }
 
     if (group.length > 1) {
--- a/devtools/client/debugger/new/src/utils/pause/frames/displayName.js
+++ b/devtools/client/debugger/new/src/utils/pause/frames/displayName.js
@@ -1,16 +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/>. */
 
 // @flow
 
 // eslint-disable-next-line max-len
-import type { LocalFrame } from "../../../components/SecondaryPanes/Frames/types";
+import type { Frame } from "../../../types";
 import { getFilename } from "../../source";
 
 // Decodes an anonymous naming scheme that
 // spider monkey implements based on "Naming Anonymous JavaScript Functions"
 // http://johnjbarton.github.io/nonymous/index.html
 const objectProperty = /([\w\d\$]+)$/;
 const arrayProperty = /\[(.*?)\]$/;
 const functionProperty = /([\w\d]+)[\/\.<]*?$/;
@@ -68,37 +68,45 @@ const displayNameMap = {
 function mapDisplayNames(frame, library) {
   const { displayName } = frame;
   return (
     (displayNameMap[library] && displayNameMap[library][displayName]) ||
     displayName
   );
 }
 
-function getFrameDisplayName(frame: LocalFrame): string {
-  const { displayName, originalDisplayName, userDisplayName, name } = frame;
+function getFrameDisplayName(frame: Frame): string {
+  const {
+    displayName,
+    originalDisplayName,
+    userDisplayName,
+    name
+  } = (frame: any);
   return originalDisplayName || userDisplayName || displayName || name;
 }
 
 type formatDisplayNameParams = {
   shouldMapDisplayName: boolean
 };
 export function formatDisplayName(
-  frame: LocalFrame,
+  frame: Frame,
   { shouldMapDisplayName = true }: formatDisplayNameParams = {},
   l10n: typeof L10N
 ): string {
   const { library } = frame;
   let displayName = getFrameDisplayName(frame);
   if (library && shouldMapDisplayName) {
     displayName = mapDisplayNames(frame, library);
   }
 
   return simplifyDisplayName(displayName) || l10n.getStr("anonymousFunction");
 }
 
-export function formatCopyName(frame: LocalFrame, l10n: typeof L10N): string {
+export function formatCopyName(frame: Frame, l10n: typeof L10N): string {
   const displayName = formatDisplayName(frame, undefined, l10n);
+  if (!frame.source) {
+    throw new Error("no frame source");
+  }
   const fileName = getFilename(frame.source);
   const frameLocation = frame.location.line;
 
   return `${displayName} (${fileName}#${frameLocation})`;
 }
--- a/devtools/client/debugger/new/src/utils/pause/frames/tests/displayName.spec.js
+++ b/devtools/client/debugger/new/src/utils/pause/frames/tests/displayName.spec.js
@@ -5,97 +5,89 @@
 // @flow
 
 import {
   formatCopyName,
   formatDisplayName,
   simplifyDisplayName
 } from "../displayName";
 
+import { makeMockFrame, makeMockSource } from "../../../test-mockup";
+
 describe("formatCopyName", () => {
   it("simple", () => {
-    const frame = {
-      displayName: "child",
-      location: {
-        line: 12
-      },
-      source: {
-        url: "todo-view.js"
-      }
-    };
+    const source = makeMockSource("todo-view.js");
+    const frame = makeMockFrame(undefined, source, undefined, 12, "child");
 
     expect(formatCopyName(frame, L10N)).toEqual("child (todo-view.js#12)");
   });
 });
 
 describe("formatting display names", () => {
   it("uses a library description", () => {
+    const source = makeMockSource("assets/backbone.js");
     const frame = {
-      library: "Backbone",
-      displayName: "extend/child",
-      source: {
-        url: "assets/backbone.js"
-      }
+      ...makeMockFrame(undefined, source, undefined, undefined, "extend/child"),
+      library: "Backbone"
     };
 
     expect(formatDisplayName(frame, undefined, L10N)).toEqual("Create Class");
   });
 
   it("shortens an anonymous function", () => {
-    const frame = {
-      displayName: "extend/child/bar/baz",
-      source: {
-        url: "assets/bar.js"
-      }
-    };
+    const source = makeMockSource("assets/bar.js");
+    const frame = makeMockFrame(
+      undefined,
+      source,
+      undefined,
+      undefined,
+      "extend/child/bar/baz"
+    );
 
     expect(formatDisplayName(frame, undefined, L10N)).toEqual("baz");
   });
 
   it("does not truncates long function names", () => {
-    const frame = {
-      displayName: "bazbazbazbazbazbazbazbazbazbazbazbazbaz",
-      source: {
-        url: "assets/bar.js"
-      }
-    };
+    const source = makeMockSource("extend/child/bar/baz");
+    const frame = makeMockFrame(
+      undefined,
+      source,
+      undefined,
+      undefined,
+      "bazbazbazbazbazbazbazbazbazbazbazbazbaz"
+    );
 
     expect(formatDisplayName(frame, undefined, L10N)).toEqual(
       "bazbazbazbazbazbazbazbazbazbazbazbazbaz"
     );
   });
 
   it("returns the original function name when present", () => {
+    const source = makeMockSource("entry.js");
     const frame = {
+      ...makeMockFrame(undefined, source),
       originalDisplayName: "originalFn",
-      displayName: "fn",
-      source: {
-        url: "entry.js"
-      }
+      displayName: "fn"
     };
 
     expect(formatDisplayName(frame, undefined, L10N)).toEqual("originalFn");
   });
 
   it("returns anonymous when displayName is undefined", () => {
-    const frame = {};
+    const frame = { ...makeMockFrame(), displayName: undefined };
     expect(formatDisplayName(frame, undefined, L10N)).toEqual("<anonymous>");
   });
 
   it("returns anonymous when displayName is null", () => {
-    const frame = {
-      displayName: null
-    };
+    const frame = { ...makeMockFrame(), displayName: (null: any) };
     expect(formatDisplayName(frame, undefined, L10N)).toEqual("<anonymous>");
   });
 
   it("returns anonymous when displayName is an empty string", () => {
-    const frame = {
-      displayName: ""
-    };
+    const frame = { ...makeMockFrame(), displayName: "" };
     expect(formatDisplayName(frame, undefined, L10N)).toEqual("<anonymous>");
   });
 });
 
 describe("simplifying display names", () => {
   const cases = {
     defaultCase: [["define", "define"]],
 
--- a/devtools/client/debugger/new/src/utils/sources-tree/sortTree.js
+++ b/devtools/client/debugger/new/src/utils/sources-tree/sortTree.js
@@ -1,38 +1,45 @@
 /* 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/>. */
 
+// @flow
+
 import { nodeHasChildren, isExactUrlMatch } from "./utils";
 
+import type { TreeDirectory } from "./types";
+
 /**
  * Look at the nodes in the source tree, and determine the index of where to
  * insert a new node. The ordering is index -> folder -> file.
  * @memberof utils/sources-tree
  * @static
  */
-export function sortEntireTree(tree, debuggeeUrl = "") {
+export function sortEntireTree(
+  tree: TreeDirectory,
+  debuggeeUrl: string = ""
+): TreeDirectory {
   if (nodeHasChildren(tree)) {
-    const contents = sortTree(tree, debuggeeUrl).map(subtree =>
+    const contents = sortTree(tree, debuggeeUrl).map((subtree: any) =>
       sortEntireTree(subtree)
     );
     return { ...tree, contents };
   }
   return tree;
 }
 
 /**
  * Look at the nodes in the source tree, and determine the index of where to
  * insert a new node. The ordering is index -> folder -> file.
  * @memberof utils/sources-tree
  * @static
  */
-export function sortTree(tree, debuggeeUrl = "") {
-  return tree.contents.sort((previousNode, currentNode) => {
+export function sortTree(tree: TreeDirectory, debuggeeUrl: string = "") {
+  return (tree.contents: any).sort((previousNode, currentNode) => {
     const currentNodeIsDir = nodeHasChildren(currentNode);
     const previousNodeIsDir = nodeHasChildren(previousNode);
     if (currentNode.name === "(index)") {
       return 1;
     } else if (previousNode.name === "(index)") {
       return -1;
     } else if (isExactUrlMatch(currentNode.name, debuggeeUrl)) {
       return 1;
--- a/devtools/client/debugger/new/src/utils/tabs.js
+++ b/devtools/client/debugger/new/src/utils/tabs.js
@@ -1,16 +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/>. */
 
 // @flow
 
 import type { Source } from "../types";
-import type { TabList } from "../reducers";
+import type { TabList } from "../reducers/tabs";
 
 type SourcesList = Source[];
 /*
  * Finds the hidden tabs by comparing the tabs' top offset.
  * hidden tabs will have a great top offset.
  *
  * @param sourceTabs Immutable.list
  * @param sourceTabEls HTMLCollection
@@ -36,17 +36,17 @@ export function getHiddenTabs(
   }
 
   return sourceTabs.filter((tab, index) => {
     const element = sourceTabEls[index];
     return element && hasTopOffset(element);
   });
 }
 
-export function getFramework(tabs: TabList[], url: string) {
+export function getFramework(tabs: TabList, url: string) {
   const tab = tabs.find(t => t.url === url);
 
   if (tab) {
     return tab.framework;
   }
 
   return "";
 }
--- a/devtools/client/debugger/new/src/utils/task.js
+++ b/devtools/client/debugger/new/src/utils/task.js
@@ -1,31 +1,33 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim: set ts=2 et sw=2 tw=80 filetype=javascript: */
 /* 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/>. */
 
+// @flow
+
 /**
  * This object provides the public module functions.
  */
 export const Task = {
   // XXX: Not sure if this works in all cases...
-  async: function(task) {
+  async: function(task: any) {
     return function() {
       return Task.spawn(task, this, arguments);
     };
   },
 
   /**
    * Creates and starts a new task.
    * @param task A generator function
    * @return A promise, resolved when the task terminates
    */
-  spawn: function(task, scope, args) {
+  spawn: function(task: any, scope: any, args: any): Promise<any> {
     return new Promise(function(resolve, reject) {
       const iterator = task.apply(scope, args);
 
       const callNext = lastValue => {
         const iteration = iterator.next(lastValue);
         Promise.resolve(iteration.value)
           .then(value => {
             if (iteration.done) {
--- a/devtools/client/debugger/new/src/utils/test-mockup.js
+++ b/devtools/client/debugger/new/src/utils/test-mockup.js
@@ -103,23 +103,25 @@ function makeMockBreakpoint(
     originalText: "text",
     options: {}
   };
 }
 
 function makeMockFrame(
   id: FrameId = "frame",
   source: Source = makeMockSource("url"),
-  scope: Scope = makeMockScope()
+  scope: Scope = makeMockScope(),
+  line: number = 4,
+  displayName: string = `display-${id}`
 ): Frame {
-  const location = { sourceId: source.id, line: 4 };
+  const location = { sourceId: source.id, line };
   return {
     id,
     thread: "FakeThread",
-    displayName: `display-${id}`,
+    displayName,
     location,
     generatedLocation: location,
     source,
     scope,
     this: {}
   };
 }
 
--- a/devtools/client/debugger/new/src/utils/url.js
+++ b/devtools/client/debugger/new/src/utils/url.js
@@ -1,12 +1,14 @@
 /* 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/>. */
 
+// @flow
+
 import { memoize } from "lodash";
 
 const defaultUrl = {
   hash: "",
   host: "",
   hostname: "",
   href: "",
   origin: "null",
@@ -16,20 +18,20 @@ const defaultUrl = {
   port: "",
   protocol: "",
   search: "",
   // This should be a "URLSearchParams" object
   searchParams: {},
   username: ""
 };
 
-export const parse = memoize(function parse(url: string) {
+export const parse = memoize(function parse(url: string): any {
   try {
     const urlObj = new URL(url);
-    urlObj.path = urlObj.pathname + urlObj.search;
+    (urlObj: any).path = urlObj.pathname + urlObj.search;
     return urlObj;
   } catch (err) {
     // If we're given simply a filename...
     if (url) {
       return { ...defaultUrl, path: url, pathname: url };
     }
 
     return defaultUrl;
--- a/devtools/client/debugger/new/src/utils/worker.js
+++ b/devtools/client/debugger/new/src/utils/worker.js
@@ -1,27 +1,29 @@
 /* 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/>. */
 
+// @flow
+
 export type Message = {
   data: {
     id: string,
     method: string,
     args: Array<any>
   }
 };
 
 let msgId = 1;
 /**
  * @memberof utils/utils
  * @static
  */
 function workerTask(worker: any, method: string) {
-  return function(...args: any) {
+  return function(...args: any): Promise<any> {
     return new Promise((resolve, reject) => {
       const id = msgId++;
       worker.postMessage({ id, method, args });
 
       const listener = ({ data: result }) => {
         if (result.id !== id) {
           return;
         }
@@ -34,17 +36,17 @@ function workerTask(worker: any, method:
         }
       };
 
       worker.addEventListener("message", listener);
     });
   };
 }
 
-function workerHandler(publicInterface) {
+function workerHandler(publicInterface: any) {
   return function onTask(msg: Message) {
     const { id, method, args } = msg.data;
     const response = publicInterface[method].apply(null, args);
 
     if (response instanceof Promise) {
       response
         .then(val => self.postMessage({ id, response: val }))
         .catch(error => self.postMessage({ id, error }));
--- a/devtools/client/debugger/new/src/vendors.js
+++ b/devtools/client/debugger/new/src/vendors.js
@@ -1,26 +1,29 @@
 /* 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/>. */
 
+// @flow
+
 /**
  * Vendors.js is a file used to bundle and expose all dependencies needed to run
  * the transpiled debugger modules when running in Firefox.
  *
  * To make transpilation easier, a vendored module should always be imported in
  * same way:
  * - always with destructuring (import { a } from "modA";)
  * - always without destructuring (import modB from "modB")
  *
  * Both are fine, but cannot be mixed for the same module.
  */
 
 // Modules imported with destructuring
 import * as devtoolsComponents from "devtools-components";
+// $FlowIgnore
 import * as devtoolsConfig from "devtools-config";
 import * as devtoolsContextmenu from "devtools-contextmenu";
 import * as devtoolsEnvironment from "devtools-environment";
 import * as devtoolsModules from "devtools-modules";
 import * as devtoolsUtils from "devtools-utils";
 import * as fuzzaldrinPlus from "fuzzaldrin-plus";
 import * as transition from "react-transition-group/Transition";
 import * as reactAriaComponentsTabs from "react-aria-components/src/tabs";
--- a/devtools/client/debugger/new/src/workers/parser/mapBindings.js
+++ b/devtools/client/debugger/new/src/workers/parser/mapBindings.js
@@ -55,17 +55,17 @@ function getAssignmentTarget(node, bindi
 // translates new bindings `var a = 3` into `self.a = 3`
 // and existing bindings `var a = 3` into `a = 3` for re-assignments
 function globalizeDeclaration(node, bindings) {
   return node.declarations.map(declaration =>
     t.expressionStatement(
       t.assignmentExpression(
         "=",
         getAssignmentTarget(declaration.id, bindings),
-        declaration.init
+        declaration.init || t.unaryExpression("void", t.numericLiteral(0))
       )
     )
   );
 }
 
 // translates new bindings `a = 3` into `self.a = 3`
 // and keeps assignments the same for existing bindings.
 function globalizeAssignment(node, bindings) {
--- a/devtools/client/debugger/new/src/workers/parser/tests/helpers/index.js
+++ b/devtools/client/debugger/new/src/workers/parser/tests/helpers/index.js
@@ -1,38 +1,38 @@
 /* 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/>. */
 
+// @flow
+
 import fs from "fs";
 import path from "path";
 
-export function getFixture(name, type = "js") {
+import { makeMockSource } from "../../../../utils/test-mockup";
+
+export function getFixture(name: string, type: string = "js") {
   return fs.readFileSync(
     path.join(__dirname, `../fixtures/${name}.${type}`),
     "utf8"
   );
 }
 
-export function getSource(name, type) {
+export function getSource(name: string, type: string = "js") {
   const text = getFixture(name, type);
   let contentType = "text/javascript";
   if (type === "html") {
     contentType = "text/html";
   } else if (type === "vue") {
     contentType = "text/vue";
   } else if (type === "ts") {
     contentType = "text/typescript";
   } else if (type === "tsx") {
     contentType = "text/typescript-jsx";
   }
 
-  return {
-    id: name,
-    text,
-    contentType
-  };
+  return makeMockSource(undefined, name, contentType, text);
 }
 
-export function getOriginalSource(name, type) {
+export function getOriginalSource(name: string, type: string = "js") {
   const source = getSource(name, type);
   return { ...source, id: `${name}/originalSource-1` };
 }
--- a/devtools/client/debugger/new/src/workers/parser/tests/mapBindings.spec.js
+++ b/devtools/client/debugger/new/src/workers/parser/tests/mapBindings.spec.js
@@ -40,16 +40,26 @@ describe("mapExpressionBindings", () => 
       newExpression: "self.a = 2; self.b = 3; self.c = 4;"
     },
     {
       name: "multiple declarations",
       expression: "const a = 2, b = 3",
       newExpression: "self.a = 2; self.b = 3"
     },
     {
+      name: "declaration with separate assignment",
+      expression: "let a; a = 2;",
+      newExpression: "self.a = void 0; self.a = 2;"
+    },
+    {
+      name: "multiple declarations with no assignment",
+      expression: "let a = 2, b;",
+      newExpression: "self.a = 2; self.b = void 0;"
+    },
+    {
       name: "local bindings become assignments",
       bindings: ["a"],
       expression: "var a = 2;",
       newExpression: "a = 2;"
     },
     {
       name: "assignments",
       expression: "a = 2;",
--- a/devtools/client/debugger/new/src/workers/parser/tests/mapExpression.spec.js
+++ b/devtools/client/debugger/new/src/workers/parser/tests/mapExpression.spec.js
@@ -500,16 +500,34 @@ describe("mapExpression", () => {
       shouldMapBindings: false,
       expectedMapped: {
         await: true,
         bindings: false,
         originalExpression: false
       }
     },
     {
+      name: "await (no bindings, dynamic import)",
+      expression: `
+        var {rainbowLog} = await import("./cool-module.js");
+        rainbowLog("dynamic");`,
+      newExpression: `var rainbowLog;
+
+        (async () => {
+          ({rainbowLog} = await import("./cool-module.js"));
+          return rainbowLog("dynamic");
+        })()`,
+      shouldMapBindings: false,
+      expectedMapped: {
+        await: true,
+        bindings: false,
+        originalExpression: false
+      }
+    },
+    {
       name: "simple",
       expression: "a",
       newExpression: "a",
       bindings: [],
       mappings: {},
       shouldMapBindings: true,
       expectedMapped: {
         await: false,
--- a/devtools/client/debugger/new/src/workers/parser/tests/pausePoints.spec.js
+++ b/devtools/client/debugger/new/src/workers/parser/tests/pausePoints.spec.js
@@ -22,17 +22,17 @@ cases(
       ? getOriginalSource(file, type)
       : getSource(file, type);
 
     setSource(source);
 
     // The coercion here is needed because getPausePoints and convertToList
     // operate on two incompatible definitions of PausePointsMap
     const nodes = convertToList((getPausePoints(source.id): any));
-    expect(formatPausePoints(source.text, nodes)).toMatchSnapshot();
+    expect(formatPausePoints(source.text || "", nodes)).toMatchSnapshot();
   },
   [
     { name: "control-flow", file: "control-flow" },
     { name: "flow", file: "flow", original: true },
     { name: "calls", file: "calls" },
     { name: "statements", file: "statements" },
     { name: "modules", file: "modules", original: true },
     { name: "jsx", file: "jsx", original: true },
--- a/devtools/client/debugger/new/src/workers/parser/utils/ast.js
+++ b/devtools/client/debugger/new/src/workers/parser/utils/ast.js
@@ -96,17 +96,17 @@ function parseVueScript(code) {
     ast = parse(code, sourceOptions.original);
   }
   return ast;
 }
 
 export function parseConsoleScript(text: string, opts?: Object): Object | null {
   try {
     return _parse(text, {
-      plugins: ["objectRestSpread"],
+      plugins: ["objectRestSpread", "dynamicImport"],
       ...opts,
       allowAwaitOutsideFunction: true
     });
   } catch (e) {
     return null;
   }
 }
 
--- a/devtools/client/debugger/new/src/workers/parser/utils/formatSymbols.js
+++ b/devtools/client/debugger/new/src/workers/parser/utils/formatSymbols.js
@@ -1,15 +1,19 @@
 /* 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/>. */
 
+// @flow
+
 import { getSymbols } from "../getSymbols";
 import { setSource } from "../sources";
 
+import type { Source } from "../../../types";
+
 function formatLocation(loc) {
   if (!loc) {
     return "";
   }
 
   const { start, end } = loc;
   const startLoc = `(${start.line}, ${start.column})`;
   const endLoc = `(${end.line}, ${end.column})`;
@@ -35,17 +39,17 @@ function summarize(symbol) {
 
   return `${loc} ${expression} ${name}${params} ${klass} ${names} ${values} ${index}`.trim(); // eslint-disable-line max-len
 }
 const bools = ["hasJsx", "hasTypes", "loading"];
 function formatBool(name, symbols) {
   return `${name}: ${symbols[name] ? "true" : "false"}`;
 }
 
-function formatKey(name, symbols) {
+function formatKey(name: string, symbols: any) {
   if (bools.includes(name)) {
     return formatBool(name, symbols);
   }
 
   return `${name}:\n${symbols[name].map(summarize).join("\n")}`;
 }
 
 export function formatSymbols(source: Source) {
--- a/devtools/client/debugger/new/src/workers/search/get-matches.js
+++ b/devtools/client/debugger/new/src/workers/search/get-matches.js
@@ -1,32 +1,41 @@
 /* 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/>. */
 
+// @flow
+
 import assert from "../../utils/assert";
 import buildQuery from "../../utils/build-query";
 
+import type { SearchModifiers } from "../../types";
+
 export default function getMatches(
   query: string,
   text: string,
   modifiers: SearchModifiers
-): number {
+): Object[] {
   if (!query || !text || !modifiers) {
     return [];
   }
   const regexQuery = buildQuery(query, modifiers, {
     isGlobal: true
   });
   const matchedLocations = [];
   const lines = text.split("\n");
   for (let i = 0; i < lines.length; i++) {
     let singleMatch;
     const line = lines[i];
     while ((singleMatch = regexQuery.exec(line)) !== null) {
+      // Flow doesn't understand the test above.
+      if (!singleMatch) {
+        throw new Error("no singleMatch");
+      }
+
       matchedLocations.push({ line: i, ch: singleMatch.index });
 
       // When the match is an empty string the regexQuery.lastIndex will not
       // change resulting in an infinite loop so we need to check for this and
       // increment it manually in that case.  See issue #7023
       if (singleMatch[0] === "") {
         assert(
           !regexQuery.unicode,
--- a/devtools/client/debugger/new/src/workers/search/index.js
+++ b/devtools/client/debugger/new/src/workers/search/index.js
@@ -1,12 +1,14 @@
 /* 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/>. */
 
+// @flow
+
 import { workerUtils } from "devtools-utils";
 const { WorkerDispatcher } = workerUtils;
 
 const dispatcher = new WorkerDispatcher();
 export const start = dispatcher.start.bind(dispatcher);
 export const stop = dispatcher.stop.bind(dispatcher);
 
 export const getMatches = dispatcher.task("getMatches");
--- a/devtools/client/debugger/new/src/workers/search/project-search.js
+++ b/devtools/client/debugger/new/src/workers/search/project-search.js
@@ -1,19 +1,23 @@
 /* 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/>. */
 
+// @flow
+
 // Maybe reuse file search's functions?
 
 import getMatches from "./get-matches";
 
-export function findSourceMatches(source, queryText) {
+import type { Source } from "../../types";
+
+export function findSourceMatches(source: Source, queryText: string): Object[] {
   const { id, loadedState, text } = source;
-  if (loadedState != "loaded" || !text || queryText == "") {
+  if (loadedState != "loaded" || typeof text != "string" || queryText == "") {
     return [];
   }
 
   const modifiers = {
     caseSensitive: false,
     regexMatch: false,
     wholeWord: false
   };
--- a/devtools/client/debugger/new/src/workers/search/tests/project-search.spec.js
+++ b/devtools/client/debugger/new/src/workers/search/tests/project-search.spec.js
@@ -12,44 +12,44 @@ const text = `
   }
 `;
 
 describe("project search", () => {
   const emptyResults = [];
 
   it("throws on lack of source", () => {
     const needle = "test";
-    const source = null;
+    const source: any = null;
     const matches = () => findSourceMatches(source, needle);
     expect(matches).toThrow(TypeError);
   });
 
   it("handles empty source object", () => {
     const needle = "test";
-    const source = {};
+    const source: any = {};
     const matches = findSourceMatches(source, needle);
     expect(matches).toEqual(emptyResults);
   });
 
   it("finds matches", () => {
     const needle = "foo";
-    const source = {
+    const source: any = {
       text,
       loadedState: "loaded",
       id: "bar.js",
       url: "http://example.com/foo/bar.js"
     };
 
     const matches = findSourceMatches(source, needle);
     expect(matches).toMatchSnapshot();
   });
 
   it("finds no matches in source", () => {
     const needle = "test";
-    const source = {
+    const source: any = {
       text,
       loadedState: "loaded",
       id: "bar.js",
       url: "http://example.com/foo/bar.js"
     };
     const matches = findSourceMatches(source, needle);
     expect(matches).toEqual(emptyResults);
   });
--- a/devtools/client/debugger/new/src/workers/search/worker.js
+++ b/devtools/client/debugger/new/src/workers/search/worker.js
@@ -1,10 +1,12 @@
 /* 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/>. */
 
+// @flow
+
 import getMatches from "./get-matches";
 import { findSourceMatches } from "./project-search";
 import { workerUtils } from "devtools-utils";
 const { workerHandler } = workerUtils;
 
 self.onmessage = workerHandler({ getMatches, findSourceMatches });
--- a/devtools/client/debugger/new/test/mochitest/browser.ini
+++ b/devtools/client/debugger/new/test/mochitest/browser.ini
@@ -695,16 +695,17 @@ skip-if = (verify && !debug && (os == 'l
 skip-if = (os == "win" && ccov) # Bug 1424154
 [browser_dbg-debugger-buttons.js]
 [browser_dbg-editor-gutter.js]
 [browser_dbg-editor-select.js]
 [browser_dbg-editor-highlight.js]
 [browser_dbg-ember-quickstart.js]
 [browser_dbg-expressions.js]
 [browser_dbg-expressions-error.js]
+[browser_dbg-expressions-focus.js]
 [browser_dbg-iframes.js]
 [browser_dbg-inline-cache.js]
 skip-if = ccov && os == 'win' # Bug 1443132
 [browser_dbg-inspector-integration.js]
 [browser_dbg-keyboard-navigation.js]
 [browser_dbg-keyboard-shortcuts.js]
 skip-if = os == "linux" # bug 1351952
 [browser_dbg-layout-changes.js]
new file mode 100644
--- /dev/null
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-expressions-focus.js
@@ -0,0 +1,19 @@
+/* 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/>. */
+
+// Ensures the input is displayed and focused when "+" is clicked
+add_task(async function() {
+  const dbg = await initDebugger("doc-script-switching.html");
+  // Close the panel
+  clickElementWithSelector(dbg, ".watch-expressions-pane ._header");
+  // Click + to add the new expression
+  clickElementWithSelector(dbg, ".watch-expressions-pane ._header .plus");
+  // Ensure element gets focused
+  await waitForElementWithSelector(dbg, ".expression-input-container.focused");
+  // Ensure the element is focused
+  is(
+    dbg.win.document.activeElement.classList.contains("input-expression"),
+    true
+  );
+});
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-expressions.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-expressions.js
@@ -1,10 +1,11 @@
-/* Any copyright is dedicated to the Public Domain.
- * http://creativecommons.org/publicdomain/zero/1.0/ */
+/* 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/>. */
 
 /**
  * tests the watch expressions component
  * 1. add watch expressions
  * 2. edit watch expressions
  * 3. delete watch expressions
  * 4. expanding properties when not paused
  */
--- a/devtools/client/shared/source-map/worker.js
+++ b/devtools/client/shared/source-map/worker.js
@@ -408,16 +408,556 @@ function isBuffer (obj) {
 // For Node v0.10 support. Remove this eventually.
 function isSlowBuffer (obj) {
   return typeof obj.readFloatLE === 'function' && typeof obj.slice === 'function' && isBuffer(obj.slice(0, 0))
 }
 
 
 /***/ }),
 
+/***/ 3641:
+/***/ (function(module, exports, __webpack_require__) {
+
+/* WEBPACK VAR INJECTION */(function(module, global) {var __WEBPACK_AMD_DEFINE_RESULT__;/*! https://mths.be/punycode v1.4.1 by @mathias */
+;(function(root) {
+
+	/** Detect free variables */
+	var freeExports = typeof exports == 'object' && exports &&
+		!exports.nodeType && exports;
+	var freeModule = typeof module == 'object' && module &&
+		!module.nodeType && module;
+	var freeGlobal = typeof global == 'object' && global;
+	if (
+		freeGlobal.global === freeGlobal ||
+		freeGlobal.window === freeGlobal ||
+		freeGlobal.self === freeGlobal
+	) {
+		root = freeGlobal;
+	}
+
+	/**
+	 * The `punycode` object.
+	 * @name punycode
+	 * @type Object
+	 */
+	var punycode,
+
+	/** Highest positive signed 32-bit float value */
+	maxInt = 2147483647, // aka. 0x7FFFFFFF or 2^31-1
+
+	/** Bootstring parameters */
+	base = 36,
+	tMin = 1,
+	tMax = 26,
+	skew = 38,
+	damp = 700,
+	initialBias = 72,
+	initialN = 128, // 0x80
+	delimiter = '-', // '\x2D'
+
+	/** Regular expressions */
+	regexPunycode = /^xn--/,
+	regexNonASCII = /[^\x20-\x7E]/, // unprintable ASCII chars + non-ASCII chars
+	regexSeparators = /[\x2E\u3002\uFF0E\uFF61]/g, // RFC 3490 separators
+
+	/** Error messages */
+	errors = {
+		'overflow': 'Overflow: input needs wider integers to process',
+		'not-basic': 'Illegal input >= 0x80 (not a basic code point)',
+		'invalid-input': 'Invalid input'
+	},
+
+	/** Convenience shortcuts */
+	baseMinusTMin = base - tMin,
+	floor = Math.floor,
+	stringFromCharCode = String.fromCharCode,
+
+	/** Temporary variable */
+	key;
+
+	/*--------------------------------------------------------------------------*/
+
+	/**
+	 * A generic error utility function.
+	 * @private
+	 * @param {String} type The error type.
+	 * @returns {Error} Throws a `RangeError` with the applicable error message.
+	 */
+	function error(type) {
+		throw new RangeError(errors[type]);
+	}
+
+	/**
+	 * A generic `Array#map` utility function.
+	 * @private
+	 * @param {Array} array The array to iterate over.
+	 * @param {Function} callback The function that gets called for every array
+	 * item.
+	 * @returns {Array} A new array of values returned by the callback function.
+	 */
+	function map(array, fn) {
+		var length = array.length;
+		var result = [];
+		while (length--) {
+			result[length] = fn(array[length]);
+		}
+		return result;
+	}
+
+	/**
+	 * A simple `Array#map`-like wrapper to work with domain name strings or email
+	 * addresses.
+	 * @private
+	 * @param {String} domain The domain name or email address.
+	 * @param {Function} callback The function that gets called for every
+	 * character.
+	 * @returns {Array} A new string of characters returned by the callback
+	 * function.
+	 */
+	function mapDomain(string, fn) {
+		var parts = string.split('@');
+		var result = '';
+		if (parts.length > 1) {
+			// In email addresses, only the domain name should be punycoded. Leave
+			// the local part (i.e. everything up to `@`) intact.
+			result = parts[0] + '@';
+			string = parts[1];
+		}
+		// Avoid `split(regex)` for IE8 compatibility. See #17.
+		string = string.replace(regexSeparators, '\x2E');
+		var labels = string.split('.');
+		var encoded = map(labels, fn).join('.');
+		return result + encoded;
+	}
+
+	/**
+	 * Creates an array containing the numeric code points of each Unicode
+	 * character in the string. While JavaScript uses UCS-2 internally,
+	 * this function will convert a pair of surrogate halves (each of which
+	 * UCS-2 exposes as separate characters) into a single code point,
+	 * matching UTF-16.
+	 * @see `punycode.ucs2.encode`
+	 * @see <https://mathiasbynens.be/notes/javascript-encoding>
+	 * @memberOf punycode.ucs2
+	 * @name decode
+	 * @param {String} string The Unicode input string (UCS-2).
+	 * @returns {Array} The new array of code points.
+	 */
+	function ucs2decode(string) {
+		var output = [],
+		    counter = 0,
+		    length = string.length,
+		    value,
+		    extra;
+		while (counter < length) {
+			value = string.charCodeAt(counter++);
+			if (value >= 0xD800 && value <= 0xDBFF && counter < length) {
+				// high surrogate, and there is a next character
+				extra = string.charCodeAt(counter++);
+				if ((extra & 0xFC00) == 0xDC00) { // low surrogate
+					output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000);
+				} else {
+					// unmatched surrogate; only append this code unit, in case the next
+					// code unit is the high surrogate of a surrogate pair
+					output.push(value);
+					counter--;
+				}
+			} else {
+				output.push(value);
+			}
+		}
+		return output;
+	}
+
+	/**
+	 * Creates a string based on an array of numeric code points.
+	 * @see `punycode.ucs2.decode`
+	 * @memberOf punycode.ucs2
+	 * @name encode
+	 * @param {Array} codePoints The array of numeric code points.
+	 * @returns {String} The new Unicode string (UCS-2).
+	 */
+	function ucs2encode(array) {
+		return map(array, function(value) {
+			var output = '';
+			if (value > 0xFFFF) {
+				value -= 0x10000;
+				output += stringFromCharCode(value >>> 10 & 0x3FF | 0xD800);
+				value = 0xDC00 | value & 0x3FF;
+			}
+			output += stringFromCharCode(value);
+			return output;
+		}).join('');
+	}
+
+	/**
+	 * Converts a basic code point into a digit/integer.
+	 * @see `digitToBasic()`
+	 * @private
+	 * @param {Number} codePoint The basic numeric code point value.
+	 * @returns {Number} The numeric value of a basic code point (for use in
+	 * representing integers) in the range `0` to `base - 1`, or `base` if
+	 * the code point does not represent a value.
+	 */
+	function basicToDigit(codePoint) {
+		if (codePoint - 48 < 10) {
+			return codePoint - 22;
+		}
+		if (codePoint - 65 < 26) {
+			return codePoint - 65;
+		}
+		if (codePoint - 97 < 26) {
+			return codePoint - 97;
+		}
+		return base;
+	}
+
+	/**
+	 * Converts a digit/integer into a basic code point.
+	 * @see `basicToDigit()`
+	 * @private
+	 * @param {Number} digit The numeric value of a basic code point.
+	 * @returns {Number} The basic code point whose value (when used for
+	 * representing integers) is `digit`, which needs to be in the range
+	 * `0` to `base - 1`. If `flag` is non-zero, the uppercase form is
+	 * used; else, the lowercase form is used. The behavior is undefined
+	 * if `flag` is non-zero and `digit` has no uppercase form.
+	 */
+	function digitToBasic(digit, flag) {
+		//  0..25 map to ASCII a..z or A..Z
+		// 26..35 map to ASCII 0..9
+		return digit + 22 + 75 * (digit < 26) - ((flag != 0) << 5);
+	}
+
+	/**
+	 * Bias adaptation function as per section 3.4 of RFC 3492.
+	 * https://tools.ietf.org/html/rfc3492#section-3.4
+	 * @private
+	 */
+	function adapt(delta, numPoints, firstTime) {
+		var k = 0;
+		delta = firstTime ? floor(delta / damp) : delta >> 1;
+		delta += floor(delta / numPoints);
+		for (/* no initialization */; delta > baseMinusTMin * tMax >> 1; k += base) {
+			delta = floor(delta / baseMinusTMin);
+		}
+		return floor(k + (baseMinusTMin + 1) * delta / (delta + skew));
+	}
+
+	/**
+	 * Converts a Punycode string of ASCII-only symbols to a string of Unicode
+	 * symbols.
+	 * @memberOf punycode
+	 * @param {String} input The Punycode string of ASCII-only symbols.
+	 * @returns {String} The resulting string of Unicode symbols.
+	 */
+	function decode(input) {
+		// Don't use UCS-2
+		var output = [],
+		    inputLength = input.length,
+		    out,
+		    i = 0,
+		    n = initialN,
+		    bias = initialBias,
+		    basic,
+		    j,
+		    index,
+		    oldi,
+		    w,
+		    k,
+		    digit,
+		    t,
+		    /** Cached calculation results */
+		    baseMinusT;
+
+		// Handle the basic code points: let `basic` be the number of input code
+		// points before the last delimiter, or `0` if there is none, then copy
+		// the first basic code points to the output.
+
+		basic = input.lastIndexOf(delimiter);
+		if (basic < 0) {
+			basic = 0;
+		}
+
+		for (j = 0; j < basic; ++j) {
+			// if it's not a basic code point
+			if (input.charCodeAt(j) >= 0x80) {
+				error('not-basic');
+			}
+			output.push(input.charCodeAt(j));
+		}
+
+		// Main decoding loop: start just after the last delimiter if any basic code
+		// points were copied; start at the beginning otherwise.
+
+		for (index = basic > 0 ? basic + 1 : 0; index < inputLength; /* no final expression */) {
+
+			// `index` is the index of the next character to be consumed.
+			// Decode a generalized variable-length integer into `delta`,
+			// which gets added to `i`. The overflow checking is easier
+			// if we increase `i` as we go, then subtract off its starting
+			// value at the end to obtain `delta`.
+			for (oldi = i, w = 1, k = base; /* no condition */; k += base) {
+
+				if (index >= inputLength) {
+					error('invalid-input');
+				}
+
+				digit = basicToDigit(input.charCodeAt(index++));
+
+				if (digit >= base || digit > floor((maxInt - i) / w)) {
+					error('overflow');
+				}
+
+				i += digit * w;
+				t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);
+
+				if (digit < t) {
+					break;
+				}
+
+				baseMinusT = base - t;
+				if (w > floor(maxInt / baseMinusT)) {
+					error('overflow');
+				}
+
+				w *= baseMinusT;
+
+			}
+
+			out = output.length + 1;
+			bias = adapt(i - oldi, out, oldi == 0);
+
+			// `i` was supposed to wrap around from `out` to `0`,
+			// incrementing `n` each time, so we'll fix that now:
+			if (floor(i / out) > maxInt - n) {
+				error('overflow');
+			}
+
+			n += floor(i / out);
+			i %= out;
+
+			// Insert `n` at position `i` of the output
+			output.splice(i++, 0, n);
+
+		}
+
+		return ucs2encode(output);
+	}
+
+	/**
+	 * Converts a string of Unicode symbols (e.g. a domain name label) to a
+	 * Punycode string of ASCII-only symbols.
+	 * @memberOf punycode
+	 * @param {String} input The string of Unicode symbols.
+	 * @returns {String} The resulting Punycode string of ASCII-only symbols.
+	 */
+	function encode(input) {
+		var n,
+		    delta,
+		    handledCPCount,
+		    basicLength,
+		    bias,
+		    j,
+		    m,
+		    q,
+		    k,
+		    t,
+		    currentValue,
+		    output = [],
+		    /** `inputLength` will hold the number of code points in `input`. */
+		    inputLength,
+		    /** Cached calculation results */
+		    handledCPCountPlusOne,
+		    baseMinusT,
+		    qMinusT;
+
+		// Convert the input in UCS-2 to Unicode
+		input = ucs2decode(input);
+
+		// Cache the length
+		inputLength = input.length;
+
+		// Initialize the state
+		n = initialN;
+		delta = 0;
+		bias = initialBias;
+
+		// Handle the basic code points
+		for (j = 0; j < inputLength; ++j) {
+			currentValue = input[j];
+			if (currentValue < 0x80) {
+				output.push(stringFromCharCode(currentValue));
+			}
+		}
+
+		handledCPCount = basicLength = output.length;
+
+		// `handledCPCount` is the number of code points that have been handled;
+		// `basicLength` is the number of basic code points.
+
+		// Finish the basic string - if it is not empty - with a delimiter
+		if (basicLength) {
+			output.push(delimiter);
+		}
+
+		// Main encoding loop:
+		while (handledCPCount < inputLength) {
+
+			// All non-basic code points < n have been handled already. Find the next
+			// larger one:
+			for (m = maxInt, j = 0; j < inputLength; ++j) {
+				currentValue = input[j];
+				if (currentValue >= n && currentValue < m) {
+					m = currentValue;
+				}
+			}
+
+			// Increase `delta` enough to advance the decoder's <n,i> state to <m,0>,
+			// but guard against overflow
+			handledCPCountPlusOne = handledCPCount + 1;
+			if (m - n > floor((maxInt - delta) / handledCPCountPlusOne)) {
+				error('overflow');
+			}
+
+			delta += (m - n) * handledCPCountPlusOne;
+			n = m;
+
+			for (j = 0; j < inputLength; ++j) {
+				currentValue = input[j];
+
+				if (currentValue < n && ++delta > maxInt) {
+					error('overflow');
+				}
+
+				if (currentValue == n) {
+					// Represent delta as a generalized variable-length integer
+					for (q = delta, k = base; /* no condition */; k += base) {
+						t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);
+						if (q < t) {
+							break;
+						}
+						qMinusT = q - t;
+						baseMinusT = base - t;
+						output.push(
+							stringFromCharCode(digitToBasic(t + qMinusT % baseMinusT, 0))
+						);
+						q = floor(qMinusT / baseMinusT);
+					}
+
+					output.push(stringFromCharCode(digitToBasic(q, 0)));
+					bias = adapt(delta, handledCPCountPlusOne, handledCPCount == basicLength);
+					delta = 0;
+					++handledCPCount;
+				}
+			}
+
+			++delta;
+			++n;
+
+		}
+		return output.join('');
+	}
+
+	/**
+	 * Converts a Punycode string representing a domain name or an email address
+	 * to Unicode. Only the Punycoded parts of the input will be converted, i.e.
+	 * it doesn't matter if you call it on a string that has already been
+	 * converted to Unicode.
+	 * @memberOf punycode
+	 * @param {String} input The Punycoded domain name or email address to
+	 * convert to Unicode.
+	 * @returns {String} The Unicode representation of the given Punycode
+	 * string.
+	 */
+	function toUnicode(input) {
+		return mapDomain(input, function(string) {
+			return regexPunycode.test(string)
+				? decode(string.slice(4).toLowerCase())
+				: string;
+		});
+	}
+
+	/**
+	 * Converts a Unicode string representing a domain name or an email address to
+	 * Punycode. Only the non-ASCII parts of the domain name will be converted,
+	 * i.e. it doesn't matter if you call it with a domain that's already in
+	 * ASCII.
+	 * @memberOf punycode
+	 * @param {String} input The domain name or email address to convert, as a
+	 * Unicode string.
+	 * @returns {String} The Punycode representation of the given domain name or
+	 * email address.
+	 */
+	function toASCII(input) {
+		return mapDomain(input, function(string) {
+			return regexNonASCII.test(string)
+				? 'xn--' + encode(string)
+				: string;
+		});
+	}
+
+	/*--------------------------------------------------------------------------*/
+
+	/** Define the public API */
+	punycode = {
+		/**
+		 * A string representing the current Punycode.js version number.
+		 * @memberOf punycode
+		 * @type String
+		 */
+		'version': '1.4.1',
+		/**
+		 * An object of methods to convert from JavaScript's internal character
+		 * representation (UCS-2) to Unicode code points, and back.
+		 * @see <https://mathiasbynens.be/notes/javascript-encoding>
+		 * @memberOf punycode
+		 * @type Object
+		 */
+		'ucs2': {
+			'decode': ucs2decode,
+			'encode': ucs2encode
+		},
+		'decode': decode,
+		'encode': encode,
+		'toASCII': toASCII,
+		'toUnicode': toUnicode
+	};
+
+	/** Expose `punycode` */
+	// Some AMD build optimizers, like r.js, check for specific condition patterns
+	// like the following:
+	if (
+		true
+	) {
+		!(__WEBPACK_AMD_DEFINE_RESULT__ = (function() {
+			return punycode;
+		}).call(exports, __webpack_require__, exports, module),
+				__WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
+	} else if (freeExports && freeModule) {
+		if (module.exports == freeExports) {
+			// in Node.js, io.js, or RingoJS v0.8.0+
+			freeModule.exports = punycode;
+		} else {
+			// in Narwhal or RingoJS v0.7.0-
+			for (key in punycode) {
+				punycode.hasOwnProperty(key) && (freeExports[key] = punycode[key]);
+			}
+		}
+	} else {
+		// in Rhino or a web browser
+		root.punycode = punycode;
+	}
+
+}(this));
+
+/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(793)(module), __webpack_require__(792)))
+
+/***/ }),
+
 /***/ 3651:
 /***/ (function(module, exports, __webpack_require__) {
 
 /* 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/. */
 
 const networkRequest = __webpack_require__(3653);
@@ -4612,17 +5152,17 @@ module.exports = function wasm() {
 
 /***/ }),
 
 /***/ 3807:
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 /* WEBPACK VAR INJECTION */(function(Buffer) {
-const punycode = __webpack_require__(916);
+const punycode = __webpack_require__(3641);
 const tr46 = __webpack_require__(3819);
 
 const infra = __webpack_require__(3811);
 const { percentEncode, percentDecode } = __webpack_require__(3808);
 
 const specialSchemes = {
   ftp: 21,
   file: null,
@@ -7672,17 +8212,17 @@ exports.implementation = class URLImpl {
 /***/ }),
 
 /***/ 3819:
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
-const punycode = __webpack_require__(916);
+const punycode = __webpack_require__(3641);
 const regexes = __webpack_require__(3820);
 const mappingTable = __webpack_require__(3821);
 
 function containsNonASCII(str) {
   return /[^\x00-\x7F]/.test(str);
 }
 
 function findStatus(val, { useSTD3ASCIIRules }) {
@@ -12888,552 +13428,12 @@ exports.write = function (buffer, value,
 
 var toString = {}.toString;
 
 module.exports = Array.isArray || function (arr) {
   return toString.call(arr) == '[object Array]';
 };
 
 
-/***/ }),
-
-/***/ 916:
-/***/ (function(module, exports, __webpack_require__) {
-
-/* WEBPACK VAR INJECTION */(function(module, global) {var __WEBPACK_AMD_DEFINE_RESULT__;/*! https://mths.be/punycode v1.4.1 by @mathias */
-;(function(root) {
-
-	/** Detect free variables */
-	var freeExports = typeof exports == 'object' && exports &&
-		!exports.nodeType && exports;
-	var freeModule = typeof module == 'object' && module &&
-		!module.nodeType && module;
-	var freeGlobal = typeof global == 'object' && global;
-	if (
-		freeGlobal.global === freeGlobal ||
-		freeGlobal.window === freeGlobal ||
-		freeGlobal.self === freeGlobal
-	) {
-		root = freeGlobal;
-	}
-
-	/**
-	 * The `punycode` object.
-	 * @name punycode
-	 * @type Object
-	 */
-	var punycode,
-
-	/** Highest positive signed 32-bit float value */
-	maxInt = 2147483647, // aka. 0x7FFFFFFF or 2^31-1
-
-	/** Bootstring parameters */
-	base = 36,
-	tMin = 1,
-	tMax = 26,
-	skew = 38,
-	damp = 700,
-	initialBias = 72,
-	initialN = 128, // 0x80
-	delimiter = '-', // '\x2D'
-
-	/** Regular expressions */
-	regexPunycode = /^xn--/,
-	regexNonASCII = /[^\x20-\x7E]/, // unprintable ASCII chars + non-ASCII chars
-	regexSeparators = /[\x2E\u3002\uFF0E\uFF61]/g, // RFC 3490 separators
-
-	/** Error messages */
-	errors = {
-		'overflow': 'Overflow: input needs wider integers to process',
-		'not-basic': 'Illegal input >= 0x80 (not a basic code point)',
-		'invalid-input': 'Invalid input'
-	},
-
-	/** Convenience shortcuts */
-	baseMinusTMin = base - tMin,
-	floor = Math.floor,
-	stringFromCharCode = String.fromCharCode,
-
-	/** Temporary variable */
-	key;
-
-	/*--------------------------------------------------------------------------*/
-
-	/**
-	 * A generic error utility function.
-	 * @private
-	 * @param {String} type The error type.
-	 * @returns {Error} Throws a `RangeError` with the applicable error message.
-	 */
-	function error(type) {
-		throw new RangeError(errors[type]);
-	}
-
-	/**
-	 * A generic `Array#map` utility function.
-	 * @private
-	 * @param {Array} array The array to iterate over.
-	 * @param {Function} callback The function that gets called for every array
-	 * item.
-	 * @returns {Array} A new array of values returned by the callback function.
-	 */
-	function map(array, fn) {
-		var length = array.length;
-		var result = [];
-		while (length--) {
-			result[length] = fn(array[length]);
-		}
-		return result;
-	}
-
-	/**
-	 * A simple `Array#map`-like wrapper to work with domain name strings or email
-	 * addresses.
-	 * @private
-	 * @param {String} domain The domain name or email address.
-	 * @param {Function} callback The function that gets called for every
-	 * character.
-	 * @returns {Array} A new string of characters returned by the callback
-	 * function.
-	 */
-	function mapDomain(string, fn) {
-		var parts = string.split('@');
-		var result = '';
-		if (parts.length > 1) {
-			// In email addresses, only the domain name should be punycoded. Leave
-			// the local part (i.e. everything up to `@`) intact.
-			result = parts[0] + '@';
-			string = parts[1];
-		}
-		// Avoid `split(regex)` for IE8 compatibility. See #17.
-		string = string.replace(regexSeparators, '\x2E');
-		var labels = string.split('.');
-		var encoded = map(labels, fn).join('.');
-		return result + encoded;
-	}
-
-	/**
-	 * Creates an array containing the numeric code points of each Unicode
-	 * character in the string. While JavaScript uses UCS-2 internally,
-	 * this function will convert a pair of surrogate halves (each of which
-	 * UCS-2 exposes as separate characters) into a single code point,
-	 * matching UTF-16.
-	 * @see `punycode.ucs2.encode`
-	 * @see <https://mathiasbynens.be/notes/javascript-encoding>
-	 * @memberOf punycode.ucs2
-	 * @name decode
-	 * @param {String} string The Unicode input string (UCS-2).
-	 * @returns {Array} The new array of code points.
-	 */
-	function ucs2decode(string) {
-		var output = [],
-		    counter = 0,
-		    length = string.length,
-		    value,
-		    extra;
-		while (counter < length) {
-			value = string.charCodeAt(counter++);
-			if (value >= 0xD800 && value <= 0xDBFF && counter < length) {
-				// high surrogate, and there is a next character
-				extra = string.charCodeAt(counter++);
-				if ((extra & 0xFC00) == 0xDC00) { // low surrogate
-					output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000);
-				} else {
-					// unmatched surrogate; only append this code unit, in case the next
-					// code unit is the high surrogate of a surrogate pair
-					output.push(value);
-					counter--;
-				}
-			} else {
-				output.push(value);
-			}
-		}
-		return output;
-	}
-
-	/**
-	 * Creates a string based on an array of numeric code points.
-	 * @see `punycode.ucs2.decode`
-	 * @memberOf punycode.ucs2
-	 * @name encode
-	 * @param {Array} codePoints The array of numeric code points.
-	 * @returns {String} The new Unicode string (UCS-2).
-	 */
-	function ucs2encode(array) {
-		return map(array, function(value) {
-			var output = '';
-			if (value > 0xFFFF) {
-				value -= 0x10000;
-				output += stringFromCharCode(value >>> 10 & 0x3FF | 0xD800);
-				value = 0xDC00 | value & 0x3FF;
-			}
-			output += stringFromCharCode(value);
-			return output;
-		}).join('');
-	}
-
-	/**
-	 * Converts a basic code point into a digit/integer.
-	 * @see `digitToBasic()`
-	 * @private
-	 * @param {Number} codePoint The basic numeric code point value.
-	 * @returns {Number} The numeric value of a basic code point (for use in
-	 * representing integers) in the range `0` to `base - 1`, or `base` if
-	 * the code point does not represent a value.
-	 */
-	function basicToDigit(codePoint) {
-		if (codePoint - 48 < 10) {
-			return codePoint - 22;
-		}
-		if (codePoint - 65 < 26) {
-			return codePoint - 65;
-		}
-		if (codePoint - 97 < 26) {
-			return codePoint - 97;
-		}
-		return base;
-	}
-
-	/**
-	 * Converts a digit/integer into a basic code point.
-	 * @see `basicToDigit()`
-	 * @private
-	 * @param {Number} digit The numeric value of a basic code point.
-	 * @returns {Number} The basic code point whose value (when used for
-	 * representing integers) is `digit`, which needs to be in the range
-	 * `0` to `base - 1`. If `flag` is non-zero, the uppercase form is
-	 * used; else, the lowercase form is used. The behavior is undefined
-	 * if `flag` is non-zero and `digit` has no uppercase form.
-	 */
-	function digitToBasic(digit, flag) {
-		//  0..25 map to ASCII a..z or A..Z
-		// 26..35 map to ASCII 0..9
-		return digit + 22 + 75 * (digit < 26) - ((flag != 0) << 5);
-	}
-
-	/**
-	 * Bias adaptation function as per section 3.4 of RFC 3492.
-	 * https://tools.ietf.org/html/rfc3492#section-3.4
-	 * @private
-	 */
-	function adapt(delta, numPoints, firstTime) {
-		var k = 0;
-		delta = firstTime ? floor(delta / damp) : delta >> 1;
-		delta += floor(delta / numPoints);
-		for (/* no initialization */; delta > baseMinusTMin * tMax >> 1; k += base) {
-			delta = floor(delta / baseMinusTMin);
-		}
-		return floor(k + (baseMinusTMin + 1) * delta / (delta + skew));
-	}
-
-	/**
-	 * Converts a Punycode string of ASCII-only symbols to a string of Unicode
-	 * symbols.
-	 * @memberOf punycode
-	 * @param {String} input The Punycode string of ASCII-only symbols.
-	 * @returns {String} The resulting string of Unicode symbols.
-	 */
-	function decode(input) {
-		// Don't use UCS-2
-		var output = [],
-		    inputLength = input.length,
-		    out,
-		    i = 0,
-		    n = initialN,
-		    bias = initialBias,
-		    basic,
-		    j,
-		    index,
-		    oldi,
-		    w,
-		    k,
-		    digit,
-		    t,
-		    /** Cached calculation results */
-		    baseMinusT;
-
-		// Handle the basic code points: let `basic` be the number of input code
-		// points before the last delimiter, or `0` if there is none, then copy
-		// the first basic code points to the output.
-
-		basic = input.lastIndexOf(delimiter);
-		if (basic < 0) {
-			basic = 0;
-		}
-
-		for (j = 0; j < basic; ++j) {
-			// if it's not a basic code point
-			if (input.charCodeAt(j) >= 0x80) {
-				error('not-basic');
-			}
-			output.push(input.charCodeAt(j));
-		}
-
-		// Main decoding loop: start just after the last delimiter if any basic code
-		// points were copied; start at the beginning otherwise.
-
-		for (index = basic > 0 ? basic + 1 : 0; index < inputLength; /* no final expression */) {
-
-			// `index` is the index of the next character to be consumed.
-			// Decode a generalized variable-length integer into `delta`,
-			// which gets added to `i`. The overflow checking is easier
-			// if we increase `i` as we go, then subtract off its starting
-			// value at the end to obtain `delta`.
-			for (oldi = i, w = 1, k = base; /* no condition */; k += base) {
-
-				if (index >= inputLength) {
-					error('invalid-input');
-				}
-
-				digit = basicToDigit(input.charCodeAt(index++));
-
-				if (digit >= base || digit > floor((maxInt - i) / w)) {
-					error('overflow');
-				}
-
-				i += digit * w;
-				t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);
-
-				if (digit < t) {
-					break;
-				}
-
-				baseMinusT = base - t;
-				if (w > floor(maxInt / baseMinusT)) {
-					error('overflow');
-				}
-
-				w *= baseMinusT;
-
-			}
-
-			out = output.length + 1;
-			bias = adapt(i - oldi, out, oldi == 0);
-
-			// `i` was supposed to wrap around from `out` to `0`,
-			// incrementing `n` each time, so we'll fix that now:
-			if (floor(i / out) > maxInt - n) {
-				error('overflow');
-			}
-
-			n += floor(i / out);
-			i %= out;
-
-			// Insert `n` at position `i` of the output
-			output.splice(i++, 0, n);
-
-		}
-
-		return ucs2encode(output);
-	}
-
-	/**
-	 * Converts a string of Unicode symbols (e.g. a domain name label) to a
-	 * Punycode string of ASCII-only symbols.
-	 * @memberOf punycode
-	 * @param {String} input The string of Unicode symbols.
-	 * @returns {String} The resulting Punycode string of ASCII-only symbols.
-	 */
-	function encode(input) {
-		var n,
-		    delta,
-		    handledCPCount,
-		    basicLength,
-		    bias,
-		    j,
-		    m,
-		    q,
-		    k,
-		    t,
-		    currentValue,
-		    output = [],
-		    /** `inputLength` will hold the number of code points in `input`. */
-		    inputLength,
-		    /** Cached calculation results */
-		    handledCPCountPlusOne,
-		    baseMinusT,
-		    qMinusT;
-
-		// Convert the input in UCS-2 to Unicode
-		input = ucs2decode(input);
-
-		// Cache the length
-		inputLength = input.length;
-
-		// Initialize the state
-		n = initialN;
-		delta = 0;
-		bias = initialBias;
-
-		// Handle the basic code points
-		for (j = 0; j < inputLength; ++j) {
-			currentValue = input[j];
-			if (currentValue < 0x80) {
-				output.push(stringFromCharCode(currentValue));
-			}
-		}
-
-		handledCPCount = basicLength = output.length;
-
-		// `handledCPCount` is the number of code points that have been handled;
-		// `basicLength` is the number of basic code points.
-
-		// Finish the basic string - if it is not empty - with a delimiter
-		if (basicLength) {
-			output.push(delimiter);
-		}
-
-		// Main encoding loop:
-		while (handledCPCount < inputLength) {
-
-			// All non-basic code points < n have been handled already. Find the next
-			// larger one:
-			for (m = maxInt, j = 0; j < inputLength; ++j) {
-				currentValue = input[j];
-				if (currentValue >= n && currentValue < m) {
-					m = currentValue;
-				}
-			}
-
-			// Increase `delta` enough to advance the decoder's <n,i> state to <m,0>,
-			// but guard against overflow
-			handledCPCountPlusOne = handledCPCount + 1;
-			if (m - n > floor((maxInt - delta) / handledCPCountPlusOne)) {
-				error('overflow');
-			}
-
-			delta += (m - n) * handledCPCountPlusOne;
-			n = m;
-
-			for (j = 0; j < inputLength; ++j) {
-				currentValue = input[j];
-
-				if (currentValue < n && ++delta > maxInt) {
-					error('overflow');
-				}
-
-				if (currentValue == n) {
-					// Represent delta as a generalized variable-length integer
-					for (q = delta, k = base; /* no condition */; k += base) {
-						t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);
-						if (q < t) {
-							break;
-						}
-						qMinusT = q - t;
-						baseMinusT = base - t;
-						output.push(
-							stringFromCharCode(digitToBasic(t + qMinusT % baseMinusT, 0))
-						);
-						q = floor(qMinusT / baseMinusT);
-					}
-
-					output.push(stringFromCharCode(digitToBasic(q, 0)));
-					bias = adapt(delta, handledCPCountPlusOne, handledCPCount == basicLength);
-					delta = 0;
-					++handledCPCount;
-				}
-			}
-
-			++delta;
-			++n;
-
-		}
-		return output.join('');
-	}
-
-	/**
-	 * Converts a Punycode string representing a domain name or an email address
-	 * to Unicode. Only the Punycoded parts of the input will be converted, i.e.
-	 * it doesn't matter if you call it on a string that has already been
-	 * converted to Unicode.
-	 * @memberOf punycode
-	 * @param {String} input The Punycoded domain name or email address to
-	 * convert to Unicode.
-	 * @returns {String} The Unicode representation of the given Punycode
-	 * string.
-	 */
-	function toUnicode(input) {
-		return mapDomain(input, function(string) {
-			return regexPunycode.test(string)
-				? decode(string.slice(4).toLowerCase())
-				: string;
-		});
-	}
-
-	/**
-	 * Converts a Unicode string representing a domain name or an email address to
-	 * Punycode. Only the non-ASCII parts of the domain name will be converted,
-	 * i.e. it doesn't matter if you call it with a domain that's already in
-	 * ASCII.
-	 * @memberOf punycode
-	 * @param {String} input The domain name or email address to convert, as a
-	 * Unicode string.
-	 * @returns {String} The Punycode representation of the given domain name or
-	 * email address.
-	 */
-	function toASCII(input) {
-		return mapDomain(input, function(string) {
-			return regexNonASCII.test(string)
-				? 'xn--' + encode(string)
-				: string;
-		});
-	}
-
-	/*--------------------------------------------------------------------------*/
-
-	/** Define the public API */
-	punycode = {
-		/**
-		 * A string representing the current Punycode.js version number.
-		 * @memberOf punycode
-		 * @type String
-		 */
-		'version': '1.4.1',
-		/**
-		 * An object of methods to convert from JavaScript's internal character
-		 * representation (UCS-2) to Unicode code points, and back.
-		 * @see <https://mathiasbynens.be/notes/javascript-encoding>
-		 * @memberOf punycode
-		 * @type Object
-		 */
-		'ucs2': {
-			'decode': ucs2decode,
-			'encode': ucs2encode
-		},
-		'decode': decode,
-		'encode': encode,
-		'toASCII': toASCII,
-		'toUnicode': toUnicode
-	};
-
-	/** Expose `punycode` */
-	// Some AMD build optimizers, like r.js, check for specific condition patterns
-	// like the following:
-	if (
-		true
-	) {
-		!(__WEBPACK_AMD_DEFINE_RESULT__ = (function() {
-			return punycode;
-		}).call(exports, __webpack_require__, exports, module),
-				__WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
-	} else if (freeExports && freeModule) {
-		if (module.exports == freeExports) {
-			// in Node.js, io.js, or RingoJS v0.8.0+
-			freeModule.exports = punycode;
-		} else {
-			// in Narwhal or RingoJS v0.7.0-
-			for (key in punycode) {
-				punycode.hasOwnProperty(key) && (freeExports[key] = punycode[key]);
-			}
-		}
-	} else {
-		// in Rhino or a web browser
-		root.punycode = punycode;
-	}
-
-}(this));
-
-/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(793)(module), __webpack_require__(792)))
-
 /***/ })
 
 /******/ });
 });
\ No newline at end of file
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -1683,20 +1683,17 @@ nsresult Navigator::GetUserAgent(nsPIDOM
     }
   }
 
   // When the caller is content and 'privacy.resistFingerprinting' is true,
   // return a spoofed userAgent which reveals the platform but not the
   // specific OS version, etc.
   if (!aIsCallerChrome && nsContentUtils::ShouldResistFingerprinting()) {
     nsAutoCString spoofedUA;
-    nsresult rv = nsRFPService::GetSpoofedUserAgent(spoofedUA, false);
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return rv;
-    }
+    nsRFPService::GetSpoofedUserAgent(spoofedUA, false);
     CopyASCIItoUTF16(spoofedUA, aUserAgent);
     return NS_OK;
   }
 
   nsresult rv;
   nsCOMPtr<nsIHttpProtocolHandler> service(
       do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &rv));
   if (NS_WARN_IF(NS_FAILED(rv))) {
--- a/gfx/layers/ipc/CompositorBridgeParent.cpp
+++ b/gfx/layers/ipc/CompositorBridgeParent.cpp
@@ -1727,16 +1727,22 @@ PWebRenderBridgeParent* CompositorBridge
   MOZ_RELEASE_ASSERT(false);
 #endif
   MOZ_ASSERT(wr::AsLayersId(aPipelineId) == mRootLayerTreeID);
   MOZ_ASSERT(!mWrBridge);
   MOZ_ASSERT(!mCompositor);
   MOZ_ASSERT(!mCompositorScheduler);
   MOZ_ASSERT(mWidget);
 
+#  ifdef XP_WIN
+  if (mWidget && DeviceManagerDx::Get()->CanUseDComp()) {
+    mWidget->AsWindows()->EnsureCompositorWindow();
+  }
+#  endif
+
   RefPtr<widget::CompositorWidget> widget = mWidget;
   wr::WrWindowId windowId = wr::NewWindowId();
   if (mApzUpdater) {
     // If APZ is enabled, we need to register the APZ updater with the window id
     // before the updater thread is created in WebRenderAPI::Create, so
     // that the callback from the updater thread can find the right APZUpdater.
     mApzUpdater->SetWebRenderWindowId(windowId);
   }
@@ -1929,22 +1935,16 @@ CompositorBridgeParent::AllocPCompositor
     // Should not create two widgets on the same compositor.
     return nullptr;
   }
 
   widget::CompositorWidgetParent* widget =
       new widget::CompositorWidgetParent(aInitData, mOptions);
   widget->AddRef();
 
-#  ifdef XP_WIN
-  if (mOptions.UseWebRender() && DeviceManagerDx::Get()->CanUseDComp()) {
-    widget->AsWindows()->EnsureCompositorWindow();
-  }
-#  endif
-
   // Sending the constructor acts as initialization as well.
   mWidget = widget;
   return widget;
 #else
   return nullptr;
 #endif
 }
 
--- a/netwerk/protocol/http/nsHttpHandler.cpp
+++ b/netwerk/protocol/http/nsHttpHandler.cpp
@@ -492,23 +492,18 @@ nsresult nsHttpHandler::Init() {
       appInfo->GetName(mAppName);
     }
     appInfo->GetVersion(mAppVersion);
     mAppName.StripChars(R"( ()<>@,;:\"/[]?={})");
   } else {
     mAppVersion.AssignLiteral(MOZ_APP_UA_VERSION);
   }
 
-  // Generating the spoofed User Agent for fingerprinting resistance.
-  rv = nsRFPService::GetSpoofedUserAgent(mSpoofedUserAgent, true);
-  if (NS_FAILED(rv)) {
-    // Empty mSpoofedUserAgent to make sure the unsuccessful spoofed UA string
-    // will not be used anywhere.
-    mSpoofedUserAgent.Truncate();
-  }
+  // Generate the spoofed User Agent for fingerprinting resistance.
+  nsRFPService::GetSpoofedUserAgent(mSpoofedUserAgent, true);
 
   mSessionStartTime = NowInSeconds();
   mHandlerActive = true;
 
   rv = InitConnectionMgr();
   if (NS_FAILED(rv)) return rv;
 
   mRequestContextService = RequestContextService::GetOrCreate();
--- a/toolkit/components/extensions/test/xpcshell/test_ext_contentscript_triggeringPrincipal.js
+++ b/toolkit/components/extensions/test/xpcshell/test_ext_contentscript_triggeringPrincipal.js
@@ -4,18 +4,16 @@
 
 /**
  * Tests that various types of inline content elements initiate requests
  * with the triggering pringipal of the caller that requested the load,
  * and that the correct security policies are applied to the resulting
  * loads.
  */
 
-const {escaped} = ChromeUtils.import("resource://testing-common/AddonTestUtils.jsm", null);
-
 const env = Cc["@mozilla.org/process/environment;1"].getService(Ci.nsIEnvironment);
 
 // Make sure media pre-loading is enabled on Android so that our <audio> and
 // <video> elements trigger the expected requests.
 Services.prefs.setIntPref("media.autoplay.default", Ci.nsIAutoplay.ALLOWED);
 Services.prefs.setIntPref("media.preload.default", 3);
 
 // Increase the length of the code samples included in CSP reports so that we
@@ -212,16 +210,54 @@ function createElement(test, opts) {
     return elem;
   }
   let elem = rec(getElementData(test, opts));
 
   return {elem, srcElem, src};
 }
 
 /**
+ * Escapes any occurrences of &, ", < or > with XML entities.
+ *
+ * @param {string} str
+ *        The string to escape.
+ * @returns {string} The escaped string.
+ */
+function escapeXML(str) {
+  let replacements = {"&": "&amp;", '"': "&quot;", "'": "&apos;", "<": "&lt;", ">": "&gt;"};
+  return String(str).replace(/[&"''<>]/g, m => replacements[m]);
+}
+
+/**
+ * A tagged template function which escapes any XML metacharacters in
+ * interpolated values.
+ *
+ * @param {Array<string>} strings
+ *        An array of literal strings extracted from the templates.
+ * @param {Array} values
+ *        An array of interpolated values extracted from the template.
+ * @returns {string}
+ *        The result of the escaped values interpolated with the literal
+ *        strings.
+ */
+function escaped(strings, ...values) {
+  let result = [];
+
+  for (let [i, string] of strings.entries()) {
+    result.push(string);
+    if (i < values.length) {
+      result.push(escapeXML(values[i]));
+    }
+  }
+
+  return result.join("");
+}
+
+
+/**
  * Converts the given test data, as accepted by {@see getElementData},
  * to an HTML representation.
  *
  * @param {ElementTestCase} test
  *        A test object, as passed to {@see getElementData}.
  * @param {ElementTestOptions} opts
  *        An options object, as passed to {@see getElementData}.
  * @returns {string}
--- a/toolkit/components/resistfingerprinting/nsRFPService.cpp
+++ b/toolkit/components/resistfingerprinting/nsRFPService.cpp
@@ -647,60 +647,66 @@ uint32_t nsRFPService::GetSpoofedPresent
   double time = floor(aTime / precision) * precision;
   // Bound the dropped ratio from 0 to 100.
   uint32_t boundedDroppedRatio = min(sVideoDroppedRatio, 100u);
 
   return NSToIntFloor(time * sVideoFramesPerSec *
                       ((100 - boundedDroppedRatio) / 100.0));
 }
 
+static uint32_t GetSpoofedVersion() {
+  // If we can't get the current Firefox version, use a hard-coded ESR version.
+  const uint32_t kKnownEsrVersion = 60;
+
+  nsresult rv;
+  nsCOMPtr<nsIXULAppInfo> appInfo =
+      do_GetService("@mozilla.org/xre/app-info;1", &rv);
+  NS_ENSURE_SUCCESS(rv, kKnownEsrVersion);
+
+  nsAutoCString appVersion;
+  rv = appInfo->GetVersion(appVersion);
+  NS_ENSURE_SUCCESS(rv, kKnownEsrVersion);
+
+  // The browser version will be spoofed as the last ESR version.
+  // By doing so, the anonymity group will cover more versions instead of one
+  // version.
+  uint32_t firefoxVersion = appVersion.ToInteger(&rv);
+  NS_ENSURE_SUCCESS(rv, kKnownEsrVersion);
+
+#ifdef DEBUG
+  // If we are running in Firefox ESR, determine whether the formula of ESR
+  // version has changed.  Once changed, we must update the formula in this
+  // function.
+  if (!strcmp(NS_STRINGIFY(MOZ_UPDATE_CHANNEL), "esr")) {
+    MOZ_ASSERT(((firefoxVersion % 8) == 4),
+               "Please update ESR version formula in nsRFPService.cpp");
+  }
+#endif  // DEBUG
+
+  // Starting with Firefox 52, a new ESR version will be released every
+  // eight Firefox versions: 52, 60, 68, ...
+  // We infer the last and closest ESR version based on this rule.
+  return firefoxVersion - ((firefoxVersion - 4) % 8);
+}
+
 /* static */
-nsresult nsRFPService::GetSpoofedUserAgent(nsACString& userAgent,
-                                           bool isForHTTPHeader) {
+void nsRFPService::GetSpoofedUserAgent(nsACString& userAgent,
+                                       bool isForHTTPHeader) {
   // This function generates the spoofed value of User Agent.
   // We spoof the values of the platform and Firefox version, which could be
   // used as fingerprinting sources to identify individuals.
   // Reference of the format of User Agent:
   // https://developer.mozilla.org/en-US/docs/Web/API/NavigatorID/userAgent
   // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/User-Agent
 
-  nsresult rv;
-  nsCOMPtr<nsIXULAppInfo> appInfo =
-      do_GetService("@mozilla.org/xre/app-info;1", &rv);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  nsAutoCString appVersion;
-  rv = appInfo->GetVersion(appVersion);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  // The browser version will be spoofed as the last ESR version.
-  // By doing so, the anonymity group will cover more versions instead of one
-  // version.
-  uint32_t firefoxVersion = appVersion.ToInteger(&rv);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  // If we are running in Firefox ESR, determine whether the formula of ESR
-  // version has changed.  Once changed, we must update the formula in this
-  // function.
-  if (!strcmp(NS_STRINGIFY(MOZ_UPDATE_CHANNEL), "esr")) {
-    MOZ_ASSERT(((firefoxVersion % 7) == 4),
-               "Please udpate ESR version formula in nsRFPService.cpp");
-  }
-
-  // Starting from Firefox 10, Firefox ESR was released once every seven
-  // Firefox releases, e.g. Firefox 10, 17, 24, 31, and so on.
-  // Except we used 60 as an ESR instead of 59.
-  // We infer the last and closest ESR version based on this rule.
-  uint32_t spoofedVersion = firefoxVersion - ((firefoxVersion - 4) % 7);
+  uint32_t spoofedVersion = GetSpoofedVersion();
   const char* spoofedOS = isForHTTPHeader ? SPOOFED_HTTP_UA_OS : SPOOFED_UA_OS;
   userAgent.Assign(nsPrintfCString(
       "Mozilla/5.0 (%s; rv:%d.0) Gecko/%s Firefox/%d.0", spoofedOS,
       spoofedVersion, LEGACY_UA_GECKO_TRAIL, spoofedVersion));
-
-  return rv;
 }
 
 static const char* gCallbackPrefs[] = {
     RESIST_FINGERPRINTING_PREF, RFP_TIMER_PREF, RFP_TIMER_VALUE_PREF,
     RFP_JITTER_VALUE_PREF,      nullptr,
 };
 
 nsresult nsRFPService::Init() {
--- a/toolkit/components/resistfingerprinting/nsRFPService.h
+++ b/toolkit/components/resistfingerprinting/nsRFPService.h
@@ -180,18 +180,17 @@ class nsRFPService final : public nsIObs
   // depend on the video resolution.
   static uint32_t GetSpoofedTotalFrames(double aTime);
   static uint32_t GetSpoofedDroppedFrames(double aTime, uint32_t aWidth,
                                           uint32_t aHeight);
   static uint32_t GetSpoofedPresentedFrames(double aTime, uint32_t aWidth,
                                             uint32_t aHeight);
 
   // This method generates the spoofed value of User Agent.
-  static nsresult GetSpoofedUserAgent(nsACString& userAgent,
-                                      bool isForHTTPHeader);
+  static void GetSpoofedUserAgent(nsACString& userAgent, bool isForHTTPHeader);
 
   /**
    * This method for getting spoofed modifier states for the given keyboard
    * event.
    *
    * @param aDoc           [in]  the owner's document for getting content
    *                             language.
    * @param aKeyboardEvent [in]  the keyboard event that needs to be spoofed.
--- a/toolkit/mozapps/extensions/internal/AddonTestUtils.jsm
+++ b/toolkit/mozapps/extensions/internal/AddonTestUtils.jsm
@@ -177,53 +177,16 @@ class MockBlocklist {
     await new Promise(r => setTimeout(r, 150));
     return Ci.nsIBlocklistService.STATE_NOT_BLOCKED;
   }
 }
 
 MockBlocklist.prototype.QueryInterface = ChromeUtils.generateQI(["nsIBlocklistService"]);
 
 
-/**
- * Escapes any occurrences of &, ", < or > with XML entities.
- *
- * @param {string} str
- *        The string to escape.
- * @return {string} The escaped string.
- */
-function escapeXML(str) {
-  let replacements = {"&": "&amp;", '"': "&quot;", "'": "&apos;", "<": "&lt;", ">": "&gt;"};
-  return String(str).replace(/[&"''<>]/g, m => replacements[m]);
-}
-
-/**
- * A tagged template function which escapes any XML metacharacters in
- * interpolated values.
- *
- * @param {Array<string>} strings
- *        An array of literal strings extracted from the templates.
- * @param {Array} values
- *        An array of interpolated values extracted from the template.
- * @returns {string}
- *        The result of the escaped values interpolated with the literal
- *        strings.
- */
-function escaped(strings, ...values) {
-  let result = [];
-
-  for (let [i, string] of strings.entries()) {
-    result.push(string);
-    if (i < values.length)
-      result.push(escapeXML(values[i]));
-  }
-
-  return result.join("");
-}
-
-
 class AddonsList {
   constructor(file) {
     this.extensions = [];
     this.themes = [];
     this.xpis = [];
 
     if (!file.exists()) {
       return;
@@ -862,81 +825,16 @@ var AddonTestUtils = {
       XPIScope.XPIStates.save();
       await XPIScope.XPIStates._jsonFile._save();
     }
 
     this.addonsList = new AddonsList(this.addonStartup);
   },
 
   /**
-   * Creates an update.rdf structure as a string using for the update data passed.
-   *
-   * @param {Object} data
-   *        The update data as a JS object. Each property name is an add-on ID,
-   *        the property value is an array of each version of the add-on. Each
-   *        array value is a JS object containing the data for the version, at
-   *        minimum a "version" and "targetApplications" property should be
-   *        included to create a functional update manifest.
-   * @return {string} The update.rdf structure as a string.
-   */
-  createUpdateRDF(data) {
-    var rdf = '<?xml version="1.0"?>\n';
-    rdf += '<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"\n' +
-           '     xmlns:em="http://www.mozilla.org/2004/em-rdf#">\n';
-
-    for (let addon in data) {
-      rdf += escaped`  <Description about="urn:mozilla:extension:${addon}"><em:updates><Seq>\n`;
-
-      for (let versionData of data[addon]) {
-        rdf += "    <li><Description>\n";
-        rdf += this._writeProps(versionData, ["version"],
-                                `      `);
-        for (let app of versionData.targetApplications || []) {
-          rdf += "      <em:targetApplication><Description>\n";
-          rdf += this._writeProps(app, ["id", "minVersion", "maxVersion", "updateLink", "updateHash"],
-                                  `        `);
-          rdf += "      </Description></em:targetApplication>\n";
-        }
-        rdf += "    </Description></li>\n";
-      }
-      rdf += "  </Seq></em:updates></Description>\n";
-    }
-    rdf += "</RDF>\n";
-
-    return rdf;
-  },
-
-  _writeProps(obj, props, indent = "  ") {
-    let items = [];
-    for (let prop of props) {
-      if (obj[prop] !== undefined)
-        items.push(escaped`${indent}<em:${prop}>${obj[prop]}</em:${prop}>\n`);
-    }
-    return items.join("");
-  },
-
-  _writeArrayProps(obj, props, indent = "  ") {
-    let items = [];
-    for (let prop of props) {
-      for (let val of obj[prop] || [])
-        items.push(escaped`${indent}<em:${prop}>${val}</em:${prop}>\n`);
-    }
-    return items.join("");
-  },
-
-  _writeLocaleStrings(data) {
-    let items = [];
-
-    items.push(this._writeProps(data, ["name", "description", "creator", "homepageURL"]));
-    items.push(this._writeArrayProps(data, ["developer", "translator", "contributor"]));
-
-    return items.join("");
-  },
-
-  /**
    * Recursively create all directories up to and including the given
    * path, if they do not exist.
    *
    * @param {string} path The path of the directory to create.
    * @returns {Promise} Resolves when all directories have been created.
    */
   recursiveMakeDir(path) {
     let paths = [];
--- a/toolkit/mozapps/extensions/internal/AddonUpdateChecker.jsm
+++ b/toolkit/mozapps/extensions/internal/AddonUpdateChecker.jsm
@@ -25,18 +25,16 @@ ChromeUtils.defineModuleGetter(this, "Ad
 ChromeUtils.defineModuleGetter(this, "AddonRepository",
                                "resource://gre/modules/addons/AddonRepository.jsm");
 ChromeUtils.defineModuleGetter(this, "Blocklist",
                                "resource://gre/modules/Blocklist.jsm");
 ChromeUtils.defineModuleGetter(this, "CertUtils",
                                "resource://gre/modules/CertUtils.jsm");
 ChromeUtils.defineModuleGetter(this, "ServiceRequest",
                                "resource://gre/modules/ServiceRequest.jsm");
-ChromeUtils.defineModuleGetter(this, "UpdateRDFConverter",
-                               "resource://gre/modules/addons/RDFManifestConverter.jsm");
 
 const {Log} = ChromeUtils.import("resource://gre/modules/Log.jsm");
 const LOGGER_ID = "addons.update-checker";
 
 // Create a new logger for use by the Addons Update Checker
 // (Requires AddonManager.jsm)
 var logger = Log.repository.getLogger(LOGGER_ID);
 
@@ -280,41 +278,21 @@ UpdateParser.prototype = {
     let channel = request.channel;
     if (channel instanceof Ci.nsIHttpChannel && !channel.requestSucceeded) {
       logger.warn("Request failed: " + this.url + " - " + channel.responseStatus +
            ": " + channel.responseStatusText);
       this.notifyError(AddonManager.ERROR_DOWNLOAD_ERROR);
       return;
     }
 
-    // Detect the manifest type by first attempting to parse it as
-    // JSON, and falling back to parsing it as XML if that fails.
-    let json;
-    try {
-      let data = request.responseText;
-      if (data.startsWith("<?xml")) {
-        logger.warn(`${this.url}: RDF update manifests are deprecated, ` +
-                    "and support will soon be removed");
-
-        json = UpdateRDFConverter.convertToJSON(request);
-        updateTypeHistogram.add("RDF");
-        Services.telemetry.keyedScalarAdd("extensions.updates.rdf", this.id, 1);
-      } else {
-        json = JSON.parse(data);
-        updateTypeHistogram.add("JSON");
-      }
-    } catch (e) {
-      logger.warn("onUpdateCheckComplete failed to determine manifest type");
-      this.notifyError(AddonManager.ERROR_UNKNOWN_FORMAT);
-      return;
-    }
-
     let results;
     try {
+      let json = JSON.parse(request.responseText);
       results = parseJSONManifest(this.id, request, json);
+      updateTypeHistogram.add("JSON");
     } catch (e) {
       logger.warn("onUpdateCheckComplete failed to parse update manifest", e);
       this.notifyError(AddonManager.ERROR_PARSE_ERROR);
       return;
     }
 
     if ("onUpdateCheckComplete" in this.observer) {
       try {
deleted file mode 100644
--- a/toolkit/mozapps/extensions/internal/RDFDataSource.jsm
+++ /dev/null
@@ -1,1517 +0,0 @@
- /* 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/. */
-
-/**
- * This module creates a new API for accessing and modifying RDF graphs. The
- * goal is to be able to serialise the graph in a human readable form. Also
- * if the graph was originally loaded from an RDF/XML the serialisation should
- * closely match the original with any new data closely following the existing
- * layout. The output should always be compatible with Mozilla's RDF parser.
- *
- * This is all achieved by using a DOM Document to hold the current state of the
- * graph in XML form. This can be initially loaded and parsed from disk or
- * a blank document used for an empty graph. As assertions are added to the
- * graph, appropriate DOM nodes are added to the document to represent them
- * along with any necessary whitespace to properly layout the XML.
- *
- * In general the order of adding assertions to the graph will impact the form
- * the serialisation takes. If a resource is first added as the object of an
- * assertion then it will eventually be serialised inside the assertion's
- * property element. If a resource is first added as the subject of an assertion
- * then it will be serialised at the top level of the XML.
- */
-
-const NS_XML = "http://www.w3.org/XML/1998/namespace";
-const NS_XMLNS = "http://www.w3.org/2000/xmlns/";
-const NS_RDF = "http://www.w3.org/1999/02/22-rdf-syntax-ns#";
-const NS_NC = "http://home.netscape.com/NC-rdf#";
-
-/* eslint prefer-template: 1 */
-
-function raw(strings) {
-  return strings.raw[0].replace(/\s+/, "");
-}
-
-// Copied from http://www.w3.org/TR/2000/REC-xml-20001006#CharClasses
-const XML_LETTER = raw`
-  \u0041-\u005A\u0061-\u007A\u00C0-\u00D6\u00D8-\u00F6
-  \u00F8-\u00FF\u0100-\u0131\u0134-\u013E\u0141-\u0148
-  \u014A-\u017E\u0180-\u01C3\u01CD-\u01F0\u01F4-\u01F5
-  \u01FA-\u0217\u0250-\u02A8\u02BB-\u02C1\u0386\u0388-\u038A
-  \u038C\u038E-\u03A1\u03A3-\u03CE\u03D0-\u03D6\u03DA\u03DC
-  \u03DE\u03E0\u03E2-\u03F3\u0401-\u040C\u040E-\u044F
-  \u0451-\u045C\u045E-\u0481\u0490-\u04C4\u04C7-\u04C8
-  \u04CB-\u04CC\u04D0-\u04EB\u04EE-\u04F5\u04F8-\u04F9
-  \u0531-\u0556\u0559\u0561-\u0586\u05D0-\u05EA\u05F0-\u05F2
-  \u0621-\u063A\u0641-\u064A\u0671-\u06B7\u06BA-\u06BE
-  \u06C0-\u06CE\u06D0-\u06D3\u06D5\u06E5-\u06E6\u0905-\u0939
-  \u093D\u0958-\u0961\u0985-\u098C\u098F-\u0990\u0993-\u09A8
-  \u09AA-\u09B0\u09B2\u09B6-\u09B9\u09DC-\u09DD\u09DF-\u09E1
-  \u09F0-\u09F1\u0A05-\u0A0A\u0A0F-\u0A10\u0A13-\u0A28
-  \u0A2A-\u0A30\u0A32-\u0A33\u0A35-\u0A36\u0A38-\u0A39
-  \u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8B\u0A8D
-  \u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2-\u0AB3
-  \u0AB5-\u0AB9\u0ABD\u0AE0\u0B05-\u0B0C\u0B0F-\u0B10
-  \u0B13-\u0B28\u0B2A-\u0B30\u0B32-\u0B33\u0B36-\u0B39
-  \u0B3D\u0B5C-\u0B5D\u0B5F-\u0B61\u0B85-\u0B8A\u0B8E-\u0B90
-  \u0B92-\u0B95\u0B99-\u0B9A\u0B9C\u0B9E-\u0B9F\u0BA3-\u0BA4
-  \u0BA8-\u0BAA\u0BAE-\u0BB5\u0BB7-\u0BB9\u0C05-\u0C0C
-  \u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C33\u0C35-\u0C39
-  \u0C60-\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8
-  \u0CAA-\u0CB3\u0CB5-\u0CB9\u0CDE\u0CE0-\u0CE1\u0D05-\u0D0C
-  \u0D0E-\u0D10\u0D12-\u0D28\u0D2A-\u0D39\u0D60-\u0D61
-  \u0E01-\u0E2E\u0E30\u0E32-\u0E33\u0E40-\u0E45\u0E81-\u0E82
-  \u0E84\u0E87-\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F
-  \u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA-\u0EAB\u0EAD-\u0EAE\u0EB0
-  \u0EB2-\u0EB3\u0EBD\u0EC0-\u0EC4\u0F40-\u0F47\u0F49-\u0F69
-  \u10A0-\u10C5\u10D0-\u10F6\u1100\u1102-\u1103\u1105-\u1107
-  \u1109\u110B-\u110C\u110E-\u1112\u113C\u113E\u1140\u114C
-  \u114E\u1150\u1154-\u1155\u1159\u115F-\u1161\u1163\u1165
-  \u1167\u1169\u116D-\u116E\u1172-\u1173\u1175\u119E\u11A8
-  \u11AB\u11AE-\u11AF\u11B7-\u11B8\u11BA\u11BC-\u11C2\u11EB
-  \u11F0\u11F9\u1E00-\u1E9B\u1EA0-\u1EF9\u1F00-\u1F15
-  \u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57
-  \u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC
-  \u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB
-  \u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2126\u212A-\u212B
-  \u212E\u2180-\u2182\u3041-\u3094\u30A1-\u30FA\u3105-\u312C
-  \uAC00-\uD7A3\u4E00-\u9FA5\u3007\u3021-\u3029
-`;
-const XML_DIGIT = raw`
-  \u0030-\u0039\u0660-\u0669\u06F0-\u06F9\u0966-\u096F
-  \u09E6-\u09EF\u0A66-\u0A6F\u0AE6-\u0AEF\u0B66-\u0B6F
-  \u0BE7-\u0BEF\u0C66-\u0C6F\u0CE6-\u0CEF\u0D66-\u0D6F
-  \u0E50-\u0E59\u0ED0-\u0ED9\u0F20-\u0F29
-`;
-const XML_COMBINING = raw`
-  \u0300-\u0345\u0360-\u0361\u0483-\u0486\u0591-\u05A1
-  \u05A3-\u05B9\u05BB-\u05BD\u05BF\u05C1-\u05C2\u05C4
-  \u064B-\u0652\u0670\u06D6-\u06DC\u06DD-\u06DF\u06E0-\u06E4
-  \u06E7-\u06E8\u06EA-\u06ED\u0901-\u0903\u093C\u093E-\u094C
-  \u094D\u0951-\u0954\u0962-\u0963\u0981-\u0983\u09BC\u09BE
-  \u09BF\u09C0-\u09C4\u09C7-\u09C8\u09CB-\u09CD\u09D7
-  \u09E2-\u09E3\u0A02\u0A3C\u0A3E\u0A3F\u0A40-\u0A42
-  \u0A47-\u0A48\u0A4B-\u0A4D\u0A70-\u0A71\u0A81-\u0A83
-  \u0ABC\u0ABE-\u0AC5\u0AC7-\u0AC9\u0ACB-\u0ACD\u0B01-\u0B03
-  \u0B3C\u0B3E-\u0B43\u0B47-\u0B48\u0B4B-\u0B4D\u0B56-\u0B57
-  \u0B82-\u0B83\u0BBE-\u0BC2\u0BC6-\u0BC8\u0BCA-\u0BCD\u0BD7
-  \u0C01-\u0C03\u0C3E-\u0C44\u0C46-\u0C48\u0C4A-\u0C4D
-  \u0C55-\u0C56\u0C82-\u0C83\u0CBE-\u0CC4\u0CC6-\u0CC8
-  \u0CCA-\u0CCD\u0CD5-\u0CD6\u0D02-\u0D03\u0D3E-\u0D43
-  \u0D46-\u0D48\u0D4A-\u0D4D\u0D57\u0E31\u0E34-\u0E3A
-  \u0E47-\u0E4E\u0EB1\u0EB4-\u0EB9\u0EBB-\u0EBC\u0EC8-\u0ECD
-  \u0F18-\u0F19\u0F35\u0F37\u0F39\u0F3E\u0F3F\u0F71-\u0F84
-  \u0F86-\u0F8B\u0F90-\u0F95\u0F97\u0F99-\u0FAD\u0FB1-\u0FB7
-  \u0FB9\u20D0-\u20DC\u20E1\u302A-\u302F\u3099\u309A
-`;
-const XML_EXTENDER = raw`
-  \u00B7\u02D0\u02D1\u0387\u0640\u0E46\u0EC6\u3005
-  \u3031-\u3035\u309D-\u309E\u30FC-\u30FE
-`;
-const XML_NCNAMECHAR = String.raw`${XML_LETTER}${XML_DIGIT}\.\-_${XML_COMBINING}${XML_EXTENDER}`;
-const XML_NCNAME = new RegExp(`^[${XML_LETTER}_][${XML_NCNAMECHAR}]*$`);
-
-const URI_SUFFIX = /[A-Za-z_][0-9A-Za-z\.\-_]*$/;
-const INDENT = /\n([ \t]*)$/;
-const RDF_LISTITEM = /^http:\/\/www.w3.org\/1999\/02\/22-rdf-syntax-ns#_\d+$/;
-
-const RDF_NODE_INVALID_TYPES =
-        ["RDF", "ID", "about", "bagID", "parseType", "resource", "nodeID",
-         "li", "aboutEach", "aboutEachPrefix"];
-const RDF_PROPERTY_INVALID_TYPES =
-        ["Description", "RDF", "ID", "about", "bagID", "parseType", "resource",
-         "nodeID", "aboutEach", "aboutEachPrefix"];
-
-/**
- * Whether to use properly namespaces attributes for rdf:about etc...
- * When on this produces poor output in the event that the rdf namespace is the
- * default namespace, and the parser recognises unnamespaced attributes and
- * most of our rdf examples are unnamespaced so leaving off for the time being.
- */
-const USE_RDFNS_ATTR = false;
-
-var EXPORTED_SYMBOLS = ["RDFLiteral", "RDFIntLiteral", "RDFDateLiteral",
-                        "RDFBlankNode", "RDFResource", "RDFDataSource"];
-
-const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
-
-XPCOMUtils.defineLazyGlobalGetters(this, ["DOMParser", "Element", "XMLSerializer", "fetch"]);
-
-ChromeUtils.defineModuleGetter(this, "OS",
-                               "resource://gre/modules/osfile.jsm");
-ChromeUtils.defineModuleGetter(this, "Services",
-                               "resource://gre/modules/Services.jsm");
-
-function isAttr(obj) {
-  return obj && typeof obj == "object" && ChromeUtils.getClassName(obj) == "Attr";
-}
-function isDocument(obj) {
-  return obj && typeof obj == "object" && obj.nodeType == Element.DOCUMENT_NODE;
-}
-function isElement(obj) {
-  return Element.isInstance(obj);
-}
-function isText(obj) {
-  return obj && typeof obj == "object" && ChromeUtils.getClassName(obj) == "Text";
-}
-
-/**
- * Logs an error message to the error console
- */
-function ERROR(str) {
-  Cu.reportError(str);
-}
-
-function RDF_R(name) {
-  return NS_RDF + name;
-}
-
-function renameNode(domnode, namespaceURI, qname) {
-  if (isElement(domnode)) {
-    var newdomnode = domnode.ownerDocument.createElementNS(namespaceURI, qname);
-    if ("listCounter" in domnode)
-      newdomnode.listCounter = domnode.listCounter;
-    domnode.replaceWith(newdomnode);
-    while (domnode.firstChild)
-      newdomnode.appendChild(domnode.firstChild);
-    for (let attr of domnode.attributes) {
-      domnode.removeAttributeNode(attr);
-      newdomnode.setAttributeNode(attr);
-    }
-    return newdomnode;
-  } else if (isAttr(domnode)) {
-    if (domnode.ownerElement.hasAttribute(namespaceURI, qname))
-      throw new Error("attribute already exists");
-    var attr = domnode.ownerDocument.createAttributeNS(namespaceURI, qname);
-    attr.value = domnode.value;
-    domnode.ownerElement.setAttributeNode(attr);
-    domnode.ownerElement.removeAttributeNode(domnode);
-    return attr;
-  }
-  throw new Error("cannot rename node of this type");
-}
-
-function predicateOrder(a, b) {
-  return a.getPredicate().localeCompare(b.getPredicate());
-}
-
-/**
- * Returns either an rdf namespaced attribute or an un-namespaced attribute
- * value. Returns null if neither exists,
- */
-function getRDFAttribute(element, name) {
-  if (element.hasAttributeNS(NS_RDF, name))
-    return element.getAttributeNS(NS_RDF, name);
-  if (element.hasAttribute(name))
-    return element.getAttribute(name);
-  return undefined;
-}
-
-/**
- * Represents an assertion in the datasource
- */
-class RDFAssertion {
-  constructor(subject, predicate, object) {
-    if (!(subject instanceof RDFSubject))
-      throw new Error("subject must be an RDFSubject");
-
-    if (typeof(predicate) != "string")
-      throw new Error("predicate must be a string URI");
-
-    if (!(object instanceof RDFLiteral) && !(object instanceof RDFSubject))
-      throw new Error("object must be a concrete RDFNode");
-
-    if (object instanceof RDFSubject && object._ds != subject._ds)
-      throw new Error("object must be from the same datasource as subject");
-
-    // The subject on this assertion, an RDFSubject
-    this._subject = subject;
-    // The predicate, a string
-    this._predicate = predicate;
-    // The object, an RDFNode
-    this._object = object;
-    // The datasource this assertion exists in
-    this._ds = this._subject._ds;
-    // Marks that _DOMnode is the subject's element
-    this._isSubjectElement = false;
-    // The DOM node that represents this assertion. Could be a property element,
-    // a property attribute or the subject's element for rdf:type
-    this._DOMNode = null;
-  }
-
-  /**
-   * Adds content to _DOMnode to store this assertion in the DOM document.
-   */
-  _applyToDOMNode() {
-    if (this._object instanceof RDFLiteral)
-      this._object._applyToDOMNode(this._ds, this._DOMnode);
-    else
-      this._object._addReferenceToElement(this._DOMnode);
-  }
-
-  /**
-   * Returns the DOM Element linked to the subject that this assertion is
-   * attached to.
-   */
-  _getSubjectElement() {
-    if (isAttr(this._DOMnode))
-      return this._DOMnode.ownerElement;
-    if (this._isSubjectElement)
-      return this._DOMnode;
-    return this._DOMnode.parentNode;
-  }
-
-  getSubject() {
-    return this._subject;
-  }
-
-  getPredicate() {
-    return this._predicate;
-  }
-
-  getObject() {
-    return this._object;
-  }
-}
-
-class RDFNode {
-  equals(rdfnode) {
-    return (rdfnode.constructor === this.constructor &&
-            rdfnode._value == this._value);
-  }
-}
-
-/**
- * A simple literal value
- */
-class RDFLiteral extends RDFNode {
-  constructor(value) {
-    super();
-    this._value = value;
-  }
-
-  /**
-   * This stores the value of the literal in the given DOM node
-   */
-  _applyToDOMNode(ds, domnode) {
-    if (isElement(domnode))
-      domnode.textContent = this._value;
-    else if (isAttr(domnode))
-      domnode.value = this._value;
-    else
-      throw new Error("cannot use this node for a literal");
-  }
-
-  getValue() {
-    return this._value;
-  }
-}
-
-/**
- * A literal that is integer typed.
- */
-class RDFIntLiteral extends RDFLiteral {
-  constructor(value) {
-    super(parseInt(value));
-  }
-
-  /**
-   * This stores the value of the literal in the given DOM node
-   */
-  _applyToDOMNode(ds, domnode) {
-    if (!isElement(domnode))
-      throw new Error("cannot use this node for a literal");
-
-    RDFLiteral.prototype._applyToDOMNode.call(this, ds, domnode);
-    var prefix = ds._resolvePrefix(domnode, `${NS_NC}parseType`);
-    domnode.setAttributeNS(prefix.namespaceURI, prefix.qname, "Integer");
-  }
-}
-
-/**
- * A literal that represents a date.
- */
-class RDFDateLiteral extends RDFLiteral {
-  constructor(value) {
-    if (!(value instanceof Date))
-      throw new Error("RDFDateLiteral must be constructed with a Date object");
-
-    super(value);
-  }
-
-  /**
-   * This stores the value of the literal in the given DOM node
-   */
-  _applyToDOMNode(ds, domnode) {
-    if (!isElement(domnode))
-      throw new Error("cannot use this node for a literal");
-
-    domnode.textContent = this._value.getTime();
-    var prefix = ds._resolvePrefix(domnode, `${NS_NC}parseType`);
-    domnode.setAttributeNS(prefix.namespaceURI, prefix.qname, "Date");
-  }
-}
-
-/**
- * This is an RDF node that can be a subject so a resource or a blank node
- */
-class RDFSubject extends RDFNode {
-  constructor(ds) {
-    super();
-    // A lookup of the assertions with this as the subject. Keyed on predicate
-    this._assertions = {};
-    // A lookup of the assertions with this as the object. Keyed on predicate
-    this._backwards = {};
-    // The datasource this subject belongs to
-    this._ds = ds;
-    // The DOM elements in the document that represent this subject. Array of Element
-    this._elements = [];
-  }
-
-  /**
-   * Creates a new Element in the document for holding assertions about this
-   * subject. The URI controls what tagname to use.
-   */
-  _createElement(uri) {
-    // Seek an appropriate reference to this node to add this node under
-    var parent = null;
-    for (var p in this._backwards) {
-      for (let back of this._backwards[p]) {
-        // Don't add under an rdf:type
-        if (back.getPredicate() == RDF_R("type"))
-          continue;
-        // The assertion already has a child node, probably one of ours
-        if (back._DOMnode.firstChild)
-          continue;
-        parent = back._DOMnode;
-        var element = this._ds._addElement(parent, uri);
-        this._removeReferenceFromElement(parent);
-        break;
-      }
-      if (parent)
-        break;
-    }
-
-    // No back assertions that are sensible to use
-    if (!parent)
-      element = this._ds._addElement(this._ds._document.documentElement, uri);
-
-    element.listCounter = 1;
-    this._applyToElement(element);
-    this._elements.push(element);
-    return element;
-  }
-
-  /**
-   * When a DOM node representing this subject is removed from the document
-   * we must remove the node and recreate any child assertions elsewhere.
-   */
-  _removeElement(element) {
-    var pos = this._elements.indexOf(element);
-    if (pos < 0)
-      throw new Error("invalid element");
-    this._elements.splice(pos, 1);
-    if (element.parentNode != element.ownerDocument.documentElement)
-      this._addReferenceToElement(element.parentNode);
-    this._ds._removeElement(element);
-
-    // Find all the assertions that are represented here and create new
-    // nodes for them.
-    for (var predicate in this._assertions) {
-      for (let assertion of this._assertions[predicate]) {
-        if (assertion._getSubjectElement() == element)
-          this._createDOMNodeForAssertion(assertion);
-      }
-    }
-  }
-
-  /**
-   * Creates a DOM node to represent the assertion in the document. If the
-   * assertion has rdf:type as the predicate then an attempt will be made to
-   * create a typed subject Element, otherwise a new property Element is
-   * created. For list items an attempt is made to find an appropriate container
-   * that an rdf:li element can be added to.
-   */
-  _createDOMNodeForAssertion(assertion) {
-    let elements;
-    if (RDF_LISTITEM.test(assertion.getPredicate())) {
-      // Find all the containers
-      elements = this._elements.filter(function(element) {
-        return (element.namespaceURI == NS_RDF && (element.localName == "Seq" ||
-                                                   element.localName == "Bag" ||
-                                                   element.localName == "Alt"));
-      });
-      if (elements.length > 0) {
-        // Look for one whose listCounter matches the item we want to add
-        var item = parseInt(assertion.getPredicate().substring(NS_RDF.length + 1));
-        for (let element of elements) {
-          if (element.listCounter == item) {
-            assertion._DOMnode = this._ds._addElement(element, RDF_R("li"));
-            assertion._applyToDOMNode();
-            element.listCounter++;
-            return;
-          }
-        }
-        // No good container to add to, shove in the first real container
-        assertion._DOMnode = this._ds._addElement(elements[0], assertion.getPredicate());
-        assertion._applyToDOMNode();
-        return;
-      }
-      // TODO No containers, this will end up in a non-container for now
-    } else if (assertion.getPredicate() == RDF_R("type")) {
-      // Try renaming an existing rdf:Description
-      for (let element of this.elements) {
-        if (element.namespaceURI == NS_RDF &&
-            element.localName == "Description") {
-          try {
-            var prefix = this._ds._resolvePrefix(element.parentNode, assertion.getObject().getURI());
-            element = renameNode(element, prefix.namespaceURI, prefix.qname);
-            assertion._DOMnode = element;
-            assertion._isSubjectElement = true;
-            return;
-          } catch (e) {
-            // If the type cannot be sensibly turned into a prefix then just set
-            // as a regular property
-          }
-        }
-      }
-    }
-
-    // Filter out all the containers
-    elements = this._elements.filter(function(element) {
-      return (element.namespaceURI != NS_RDF || (element.localName != "Seq" &&
-                                                 element.localName != "Bag" &&
-                                                 element.localName != "Alt"));
-    });
-    if (elements.length == 0) {
-      // Create a new node of the right type
-      if (assertion.getPredicate() == RDF_R("type")) {
-        try {
-          assertion._DOMnode = this._createElement(assertion.getObject().getURI());
-          assertion._isSubjectElement = true;
-          return;
-        } catch (e) {
-          // If the type cannot be sensibly turned into a prefix then just set
-          // as a regular property
-        }
-      }
-      elements[0] = this._createElement(RDF_R("Description"));
-    }
-    assertion._DOMnode = this._ds._addElement(elements[0], assertion.getPredicate());
-    assertion._applyToDOMNode();
-  }
-
-  /**
-   * Removes the DOM node representing the assertion.
-   */
-  _removeDOMNodeForAssertion(assertion) {
-    if (isAttr(assertion._DOMnode)) {
-      var parent = assertion._DOMnode.ownerElement;
-      parent.removeAttributeNode(assertion._DOMnode);
-    } else if (assertion._isSubjectElement) {
-      var domnode = renameNode(assertion._DOMnode, NS_RDF, "Description");
-      if (domnode != assertion._DOMnode) {
-        var pos = this._elements.indexOf(assertion._DOMnode);
-        this._elements.splice(pos, 1, domnode);
-      }
-      parent = domnode;
-    } else {
-      var object = assertion.getObject();
-      if (object instanceof RDFSubject && assertion._DOMnode.firstChild) {
-        // Object is a subject that has an Element inside this assertion's node.
-        for (let element of object._elements) {
-          if (element.parentNode == assertion._DOMnode) {
-            object._removeElement(element);
-            break;
-          }
-        }
-      }
-      parent = assertion._DOMnode.parentNode;
-      if (assertion._DOMnode.namespaceURI == NS_RDF &&
-          assertion._DOMnode.localName == "li")
-      parent.listCounter--;
-      this._ds._removeElement(assertion._DOMnode);
-    }
-
-    // If there are no assertions left using the assertion's containing dom node
-    // then remove it from the document.
-    // TODO could do with a quick lookup list for assertions attached to a node
-    for (var p in this._assertions) {
-      for (let assertion of this._assertions[p]) {
-        if (assertion._getSubjectElement() == parent)
-          return;
-      }
-    }
-    // No assertions left in this element.
-    this._removeElement(parent);
-  }
-
-  /**
-   * Parses the given Element from the DOM document
-   */
-  _parseElement(element) {
-    this._elements.push(element);
-
-    // There might be an inferred rdf:type assertion in the element name
-    if (element.namespaceURI != NS_RDF ||
-        element.localName != "Description") {
-      if (element.namespaceURI == NS_RDF && element.localName == "li")
-        throw new Error("rdf:li is not a valid type for a subject node");
-      var assertion = new RDFAssertion(this, RDF_R("type"),
-                                       this._ds.getResource(element.namespaceURI + element.localName));
-      assertion._DOMnode = element;
-      assertion._isSubjectElement = true;
-      this._addAssertion(assertion);
-    }
-
-    // Certain attributes can be literal properties
-    for (let attr of element.attributes) {
-      if (attr.namespaceURI == NS_XML || attr.namespaceURI == NS_XMLNS ||
-          attr.nodeName == "xmlns")
-        continue;
-      if ((attr.namespaceURI == NS_RDF || !attr.namespaceURI) &&
-          (["nodeID", "about", "resource", "ID", "parseType"].includes(attr.localName)))
-        continue;
-      var object = null;
-      if (attr.namespaceURI == NS_RDF) {
-        if (attr.localName == "type")
-          object = this._ds.getResource(attr.nodeValue);
-        else if (attr.localName == "li")
-          throw new Error("rdf:li is not allowed as a property attribute");
-        else if (attr.localName == "aboutEach")
-          throw new Error("rdf:aboutEach is deprecated");
-        else if (attr.localName == "aboutEachPrefix")
-          throw new Error("rdf:aboutEachPrefix is deprecated");
-        else if (attr.localName == "aboutEach")
-          throw new Error("rdf:aboutEach is deprecated");
-        else if (attr.localName == "bagID")
-          throw new Error("rdf:bagID is deprecated");
-      }
-      if (!object)
-        object = new RDFLiteral(attr.nodeValue);
-      assertion = new RDFAssertion(this, attr.namespaceURI + attr.localName, object);
-      assertion._DOMnode = attr;
-      this._addAssertion(assertion);
-    }
-
-    var child = element.firstChild;
-    element.listCounter = 1;
-    while (child) {
-      if (isText(child) && /\S/.test(child.nodeValue)) {
-        ERROR(`Text ${child.nodeValue} is not allowed in a subject node`);
-        throw new Error("subject nodes cannot contain text content");
-      } else if (isElement(child)) {
-        object = null;
-        var predicate = child.namespaceURI + child.localName;
-        if (child.namespaceURI == NS_RDF) {
-          if (RDF_PROPERTY_INVALID_TYPES.includes(child.localName) &&
-              !child.localName.match(/^_\d+$/))
-            throw new Error(`${child.nodeName} is an invalid property`);
-          if (child.localName == "li") {
-            predicate = RDF_R(`_${element.listCounter}`);
-            element.listCounter++;
-          }
-        }
-
-        // Check for and bail out on unknown attributes on the property element
-        for (let attr of child.attributes) {
-          // Ignore XML namespaced attributes
-          if (attr.namespaceURI == NS_XML)
-            continue;
-          // These are reserved by XML for future use
-          if (attr.localName.substring(0, 3).toLowerCase() == "xml")
-            continue;
-          // We can handle these RDF attributes
-          if ((!attr.namespaceURI || attr.namespaceURI == NS_RDF) &&
-              ["resource", "nodeID"].includes(attr.localName))
-            continue;
-          // This is a special attribute we handle for compatibility with Mozilla RDF
-          if (attr.namespaceURI == NS_NC &&
-              attr.localName == "parseType")
-            continue;
-          throw new Error(`Attribute ${attr.nodeName} is not supported`);
-        }
-
-        var parseType = child.getAttributeNS(NS_NC, "parseType");
-        if (parseType && parseType != "Date" && parseType != "Integer") {
-          ERROR(`parseType ${parseType} is not supported`);
-          throw new Error("unsupported parseType");
-        }
-
-        var resource = getRDFAttribute(child, "resource");
-        var nodeID = getRDFAttribute(child, "nodeID");
-        if ((resource && (nodeID || parseType)) ||
-            (nodeID && (resource || parseType))) {
-          ERROR("Cannot use more than one of parseType, resource and nodeID on a single node");
-          throw new Error("Invalid rdf assertion");
-        }
-
-        if (resource !== undefined) {
-          var base = Services.io.newURI(element.baseURI);
-          object = this._ds.getResource(base.resolve(resource));
-        } else if (nodeID !== undefined) {
-          if (!nodeID.match(XML_NCNAME))
-            throw new Error("rdf:nodeID must be a valid XML name");
-          object = this._ds.getBlankNode(nodeID);
-        } else {
-          var hasText = false;
-          var childElement = null;
-          var subchild = child.firstChild;
-          while (subchild) {
-            if (isText(subchild) && /\S/.test(subchild.nodeValue)) {
-              hasText = true;
-            } else if (isElement(subchild)) {
-              if (childElement) {
-                new Error(`Multiple object elements found in ${child.nodeName}`);
-              }
-              childElement = subchild;
-            }
-            subchild = subchild.nextSibling;
-          }
-
-          if ((resource || nodeID) && (hasText || childElement)) {
-            ERROR("Assertion references a resource so should not contain additional contents");
-            throw new Error("assertion cannot contain multiple objects");
-          }
-
-          if (hasText && childElement) {
-            ERROR(`Both literal and resource objects found in ${child.nodeName}`);
-            throw new Error("assertion cannot contain multiple objects");
-          }
-
-          if (childElement) {
-            if (parseType) {
-              ERROR("Cannot specify a parseType for an assertion with resource object");
-              throw new Error("parseType is not valid in this context");
-            }
-            object = this._ds._getSubjectForElement(childElement);
-            object._parseElement(childElement);
-          } else if (parseType == "Integer")
-            object = new RDFIntLiteral(child.textContent);
-          else if (parseType == "Date")
-            object = new RDFDateLiteral(new Date(child.textContent));
-          else
-            object = new RDFLiteral(child.textContent);
-        }
-
-        assertion = new RDFAssertion(this, predicate, object);
-        this._addAssertion(assertion);
-        assertion._DOMnode = child;
-      }
-      child = child.nextSibling;
-    }
-  }
-
-  /**
-   * Adds a new assertion to the internal hashes. Should be called for every
-   * new assertion parsed or created programmatically.
-   */
-  _addAssertion(assertion) {
-    var predicate = assertion.getPredicate();
-    if (predicate in this._assertions)
-      this._assertions[predicate].push(assertion);
-    else
-      this._assertions[predicate] = [ assertion ];
-
-    var object = assertion.getObject();
-    if (object instanceof RDFSubject) {
-      // Create reverse assertion
-      if (predicate in object._backwards)
-        object._backwards[predicate].push(assertion);
-      else
-        object._backwards[predicate] = [ assertion ];
-    }
-  }
-
-  /**
-   * Removes an assertion from the internal hashes. Should be called for all
-   * assertions that are programatically deleted.
-   */
-  _removeAssertion(assertion) {
-    var predicate = assertion.getPredicate();
-    if (predicate in this._assertions) {
-      var pos = this._assertions[predicate].indexOf(assertion);
-      if (pos >= 0)
-        this._assertions[predicate].splice(pos, 1);
-      if (this._assertions[predicate].length == 0)
-        delete this._assertions[predicate];
-    }
-
-    var object = assertion.getObject();
-    if (object instanceof RDFSubject) {
-      // Delete reverse assertion
-      if (predicate in object._backwards) {
-        pos = object._backwards[predicate].indexOf(assertion);
-        if (pos >= 0)
-          object._backwards[predicate].splice(pos, 1);
-        if (object._backwards[predicate].length == 0)
-          delete object._backwards[predicate];
-      }
-    }
-  }
-
-  /**
-   * Returns the ordinal assertions from this subject in order.
-   */
-  _getChildAssertions() {
-    var assertions = [];
-    for (var i in this._assertions) {
-      if (RDF_LISTITEM.test(i))
-        assertions.push(...this._assertions[i]);
-    }
-    assertions.sort(predicateOrder);
-    return assertions;
-  }