Bug 1483646 - Update Debugger Frontend v82. r=dwalsh
authorJason Laster <jason.laster.11@gmail.com>
Wed, 15 Aug 2018 14:46:24 -0400
changeset 486907 598305280dc37b6b0136795508e4ff7c8ab7b480
parent 486906 da7e0c710c7d7a7ff3e124db32d4eae9ffebd2a1
child 486908 9b421c484e49a94345cbf82dd4efa8155a326e5c
push id9719
push userffxbld-merge
push dateFri, 24 Aug 2018 17:49:46 +0000
treeherdermozilla-beta@719ec98fba77 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdwalsh
bugs1483646
milestone63.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1483646 - Update Debugger Frontend v82. r=dwalsh
devtools/client/debugger/new/README.mozilla
devtools/client/debugger/new/dist/debugger.css
devtools/client/debugger/new/dist/parser-worker.js
devtools/client/debugger/new/panel.js
devtools/client/debugger/new/src/actions/ast.js
devtools/client/debugger/new/src/actions/breakpoints/addBreakpoint.js
devtools/client/debugger/new/src/actions/breakpoints/index.js
devtools/client/debugger/new/src/actions/breakpoints/syncBreakpoint.js
devtools/client/debugger/new/src/actions/pause/mapFrames.js
devtools/client/debugger/new/src/actions/pause/paused.js
devtools/client/debugger/new/src/actions/sources/newSources.js
devtools/client/debugger/new/src/actions/sources/prettyPrint.js
devtools/client/debugger/new/src/actions/sources/select.js
devtools/client/debugger/new/src/components/Editor/Preview/index.js
devtools/client/debugger/new/src/components/Editor/Tab.js
devtools/client/debugger/new/src/components/PrimaryPanes/SourcesTree.js
devtools/client/debugger/new/src/components/PrimaryPanes/SourcesTreeItem.js
devtools/client/debugger/new/src/components/PrimaryPanes/index.js
devtools/client/debugger/new/src/components/ProjectSearch.js
devtools/client/debugger/new/src/components/QuickOpenModal.js
devtools/client/debugger/new/src/reducers/pause.js
devtools/client/debugger/new/src/reducers/pending-breakpoints.js
devtools/client/debugger/new/src/reducers/sources.js
devtools/client/debugger/new/src/utils/pause/frames/getLibraryFromUrl.js
devtools/client/debugger/new/src/utils/source-maps.js
devtools/client/debugger/new/src/utils/source.js
devtools/client/debugger/new/src/utils/sources-tree/getURL.js
devtools/client/debugger/new/test/mochitest/browser_dbg-pause-points.js
devtools/client/debugger/new/test/mochitest/browser_dbg-preview-source-maps.js
devtools/client/debugger/new/test/mochitest/browser_dbg-sourcemaps.js
devtools/client/debugger/new/test/mochitest/browser_dbg-wasm-sourcemaps.js
devtools/client/debugger/new/test/mochitest/browser_dbg_rr_stepping-04.js
devtools/client/debugger/new/test/mochitest/helpers.js
devtools/client/shared/source-map/index.js
devtools/client/shared/source-map/worker.js
--- 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 81
+Version 82
 
-Comparison: https://github.com/devtools-html/debugger.html/compare/release-80...release-81
+Comparison: https://github.com/devtools-html/debugger.html/compare/release-81...release-82
 
 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
@@ -1372,16 +1372,17 @@ html .toggle-button.end.vertical svg {
 }
 
 .sources-pane {
   display: flex;
   flex: 1;
   overflow-x: auto;
   overflow-y: auto;
   height: 100%;
+  padding: 4px 0;
 }
 
 .sources-list {
   flex: 1;
   display: flex;
   overflow: hidden;
 }
 
@@ -1672,17 +1673,17 @@ menuseparator {
   padding: 0.5em;
   user-select: none;
   font-size: 12px;
   overflow: hidden;
 }
 
 .outline-list {
   list-style-type: none;
-  padding: 10px 0;
+  padding: 4px 0;
   margin: 0;
   font-family: var(--monospace-font-family);
   overflow: auto;
   position: absolute;
   top: 0;
   right: 0;
   left: 0;
   bottom: 25px;
--- a/devtools/client/debugger/new/dist/parser-worker.js
+++ b/devtools/client/debugger/new/dist/parser-worker.js
@@ -25332,33 +25332,34 @@ function onEnter(node, ancestors, state)
   const grandParentNode = grandParent && grandParent.node;
   const startLocation = node.loc.start;
 
   if (isImport(node) || t.isClassDeclaration(node) || isExport(node) || t.isDebuggerStatement(node) || t.isThrowStatement(node) || t.isBreakStatement(node) || t.isContinueStatement(node)) {
     return addStopPoint(state, startLocation);
   }
 
   if (isControlFlow(node)) {
-    addPoint(state, startLocation, isForStatement(node));
-
+    addStopPoint(state, startLocation);
+
+    // We want to pause at tests so that we can pause at each iteration
+    // e.g `while (i++ < 3) { }`
     const test = node.test || node.discriminant;
     if (test) {
       addStopPoint(state, test.loc.start);
     }
     return;
   }
 
   if (t.isBlockStatement(node) || t.isArrayExpression(node)) {
     return addEmptyPoint(state, startLocation);
   }
 
   if (isReturn(node)) {
     // We do not want to pause at the return if the
     // argument is a call on the same line e.g. return foo()
-
     return addPoint(state, startLocation, !isCall(node.argument) || getStartLine(node) != getStartLine(node.argument));
   }
 
   if (isAssignment(node)) {
     // step at assignments unless the right side is a call or default assignment
     // e.g. `var a = b()`,  `a = b(c = 2)`, `a = [ b() ]`
     const value = node.right || node.init;
     const defaultAssignment = t.isFunction(parentNode) && parent.key === "params";
@@ -25585,16 +25586,17 @@ const getAllGeneratedLocations = dispatc
   queue: true
 });
 const getOriginalLocation = dispatcher.task("getOriginalLocation");
 const getLocationScopes = dispatcher.task("getLocationScopes");
 const getOriginalSourceText = dispatcher.task("getOriginalSourceText");
 const applySourceMap = dispatcher.task("applySourceMap");
 const clearSourceMaps = dispatcher.task("clearSourceMaps");
 const hasMappedSource = dispatcher.task("hasMappedSource");
+const getOriginalStackFrames = dispatcher.task("getOriginalStackFrames");
 
 module.exports = {
   originalToGeneratedId,
   generatedToOriginalId,
   isGeneratedId,
   isOriginalId,
   hasMappedSource,
   getOriginalURLs,
@@ -25602,16 +25604,17 @@ module.exports = {
   getGeneratedRanges,
   getGeneratedLocation,
   getAllGeneratedLocations,
   getOriginalLocation,
   getLocationScopes,
   getOriginalSourceText,
   applySourceMap,
   clearSourceMaps,
+  getOriginalStackFrames,
   startSourceMapWorker: dispatcher.start.bind(dispatcher),
   stopSourceMapWorker: dispatcher.stop.bind(dispatcher)
 };
 
 /***/ }),
 
 /***/ 3651:
 /***/ (function(module, exports, __webpack_require__) {
--- a/devtools/client/debugger/new/panel.js
+++ b/devtools/client/debugger/new/panel.js
@@ -100,17 +100,17 @@ DebuggerPanel.prototype = {
     return this._actions.getMappedExpression(expression);
   },
 
   isPaused() {
     return this._selectors.isPaused(this._getState());
   },
 
   selectSource(url, line) {
-    this._actions.selectSourceURL(url, { location: { line } });
+    this._actions.selectSourceURL(url, { line });
   },
 
   getSource(sourceURL) {
     return this._selectors.getSourceByURL(this._getState(), sourceURL);
   },
 
   destroy: function() {
     this.panelWin.Debugger.destroy();
--- a/devtools/client/debugger/new/src/actions/ast.js
+++ b/devtools/client/debugger/new/src/actions/ast.js
@@ -85,17 +85,17 @@ function setOutOfScopeLocations() {
 
     if (!location) {
       return;
     }
 
     const source = (0, _selectors.getSourceFromId)(getState(), location.sourceId);
     let locations = null;
 
-    if (location.line && source && (0, _selectors.isPaused)(getState())) {
+    if (location.line && source && !source.isWasm && (0, _selectors.isPaused)(getState())) {
       locations = await (0, _parser.findOutOfScopeLocations)(source.id, location);
     }
 
     dispatch({
       type: "OUT_OF_SCOPE_LOCATIONS",
       locations
     });
     dispatch((0, _setInScopeLines.setInScopeLines)());
--- a/devtools/client/debugger/new/src/actions/breakpoints/addBreakpoint.js
+++ b/devtools/client/debugger/new/src/actions/breakpoints/addBreakpoint.js
@@ -2,16 +2,18 @@
 
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
 exports.addHiddenBreakpoint = addHiddenBreakpoint;
 exports.enableBreakpoint = enableBreakpoint;
 exports.addBreakpoint = addBreakpoint;
 
+var _devtoolsSourceMap = require("devtools/client/shared/source-map/index.js");
+
 var _breakpoint = require("../../utils/breakpoint/index");
 
 var _promise = require("../utils/middleware/promise");
 
 var _selectors = require("../../selectors/index");
 
 var _sourceMaps = require("../../utils/source-maps");
 
@@ -44,17 +46,17 @@ async function addBreakpointPromise(getS
       breakpoint: newBreakpoint
     };
   }
 
   const {
     id,
     hitCount,
     actualLocation
-  } = await client.setBreakpoint(generatedLocation, breakpoint.condition, sourceMaps.isOriginalId(location.sourceId));
+  } = await client.setBreakpoint(generatedLocation, breakpoint.condition, (0, _devtoolsSourceMap.isOriginalId)(location.sourceId));
   const newGeneratedLocation = actualLocation || generatedLocation;
   const newLocation = await sourceMaps.getOriginalLocation(newGeneratedLocation);
   const symbols = (0, _selectors.getSymbols)(getState(), source);
   const astLocation = await (0, _breakpoint.getASTLocation)(source, symbols, newLocation);
   const originalText = (0, _source.getTextAtPosition)(source, location);
   const text = (0, _source.getTextAtPosition)(generatedSource, actualLocation);
   const newBreakpoint = {
     id,
--- a/devtools/client/debugger/new/src/actions/breakpoints/index.js
+++ b/devtools/client/debugger/new/src/actions/breakpoints/index.js
@@ -12,16 +12,18 @@ exports.removeAllBreakpoints = removeAll
 exports.removeBreakpoints = removeBreakpoints;
 exports.remapBreakpoints = remapBreakpoints;
 exports.setBreakpointCondition = setBreakpointCondition;
 exports.toggleBreakpoint = toggleBreakpoint;
 exports.toggleBreakpointsAtLine = toggleBreakpointsAtLine;
 exports.addOrToggleDisabledBreakpoint = addOrToggleDisabledBreakpoint;
 exports.toggleDisabledBreakpoint = toggleDisabledBreakpoint;
 
+var _devtoolsSourceMap = require("devtools/client/shared/source-map/index.js");
+
 var _promise = require("../utils/middleware/promise");
 
 var _selectors = require("../../selectors/index");
 
 var _breakpoint = require("../../utils/breakpoint/index");
 
 var _addBreakpoint = require("./addBreakpoint");
 
@@ -258,17 +260,17 @@ function setBreakpointCondition(location
       return;
     }
 
     if (bp.disabled) {
       await dispatch((0, _addBreakpoint.enableBreakpoint)(location));
       bp.disabled = !bp.disabled;
     }
 
-    await client.setBreakpointCondition(bp.id, location, condition, sourceMaps.isOriginalId(bp.location.sourceId));
+    await client.setBreakpointCondition(bp.id, location, condition, (0, _devtoolsSourceMap.isOriginalId)(bp.location.sourceId));
     const newBreakpoint = { ...bp,
       condition
     };
     (0, _breakpoint.assertBreakpoint)(newBreakpoint);
     return dispatch({
       type: "SET_BREAKPOINT_CONDITION",
       breakpoint: newBreakpoint
     });
--- a/devtools/client/debugger/new/src/actions/breakpoints/syncBreakpoint.js
+++ b/devtools/client/debugger/new/src/actions/breakpoints/syncBreakpoint.js
@@ -51,17 +51,17 @@ function createSyncData(id, pendingBreak
   };
 } // we have three forms of syncing: disabled syncing, existing server syncing
 // and adding a new breakpoint
 
 
 async function syncBreakpointPromise(getState, client, sourceMaps, sourceId, pendingBreakpoint) {
   (0, _breakpoint.assertPendingBreakpoint)(pendingBreakpoint);
   const source = (0, _selectors.getSource)(getState(), sourceId);
-  const generatedSourceId = sourceMaps.isOriginalId(sourceId) ? (0, _devtoolsSourceMap.originalToGeneratedId)(sourceId) : sourceId;
+  const generatedSourceId = (0, _devtoolsSourceMap.isOriginalId)(sourceId) ? (0, _devtoolsSourceMap.originalToGeneratedId)(sourceId) : sourceId;
   const generatedSource = (0, _selectors.getSource)(getState(), generatedSourceId);
 
   if (!source) {
     return null;
   }
 
   const {
     location,
@@ -104,17 +104,17 @@ async function syncBreakpointPromise(get
       previousLocation,
       breakpoint: null
     };
   }
 
   const {
     id,
     actualLocation
-  } = await client.setBreakpoint(scopedGeneratedLocation, pendingBreakpoint.condition, sourceMaps.isOriginalId(sourceId)); // the breakpoint might have slid server side, so we want to get the location
+  } = await client.setBreakpoint(scopedGeneratedLocation, pendingBreakpoint.condition, (0, _devtoolsSourceMap.isOriginalId)(sourceId)); // the breakpoint might have slid server side, so we want to get the location
   // based on the server's return value
 
   const newGeneratedLocation = actualLocation;
   const newLocation = await sourceMaps.getOriginalLocation(newGeneratedLocation);
   const originalText = (0, _source.getTextAtPosition)(source, newLocation);
   const text = (0, _source.getTextAtPosition)(generatedSource, newGeneratedLocation);
   return createSyncData(id, pendingBreakpoint, newLocation, newGeneratedLocation, previousLocation, text, originalText);
 }
--- a/devtools/client/debugger/new/src/actions/pause/mapFrames.js
+++ b/devtools/client/debugger/new/src/actions/pause/mapFrames.js
@@ -4,38 +4,54 @@ Object.defineProperty(exports, "__esModu
   value: true
 });
 exports.updateFrameLocation = updateFrameLocation;
 exports.mapDisplayNames = mapDisplayNames;
 exports.mapFrames = mapFrames;
 
 var _selectors = require("../../selectors/index");
 
+var _assert = require("../../utils/assert");
+
+var _assert2 = _interopRequireDefault(_assert);
+
 var _ast = require("../../utils/ast");
 
+var _devtoolsSourceMap = require("devtools/client/shared/source-map/index.js");
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
 /* 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/>. */
 function updateFrameLocation(frame, sourceMaps) {
+  if (frame.isOriginal) {
+    return Promise.resolve(frame);
+  }
+
   return sourceMaps.getOriginalLocation(frame.location).then(loc => ({ ...frame,
     location: loc,
     generatedLocation: frame.generatedLocation || frame.location
   }));
 }
 
 function updateFrameLocations(frames, sourceMaps) {
   if (!frames || frames.length == 0) {
     return Promise.resolve(frames);
   }
 
   return Promise.all(frames.map(frame => updateFrameLocation(frame, sourceMaps)));
 }
 
 function mapDisplayNames(frames, getState) {
   return frames.map(frame => {
+    if (frame.isOriginal) {
+      return frame;
+    }
+
     const source = (0, _selectors.getSourceFromId)(getState(), frame.location.sourceId);
     const symbols = (0, _selectors.getSymbols)(getState(), source);
 
     if (!symbols || !symbols.functions) {
       return frame;
     }
 
     const originalFunction = (0, _ast.findClosestFunction)(symbols, frame.location);
@@ -45,16 +61,70 @@ function mapDisplayNames(frames, getStat
     }
 
     const originalDisplayName = originalFunction.name;
     return { ...frame,
       originalDisplayName
     };
   });
 }
+
+function isWasmOriginalSourceFrame(frame, getState) {
+  if ((0, _devtoolsSourceMap.isGeneratedId)(frame.location.sourceId)) {
+    return false;
+  }
+
+  const generatedSource = (0, _selectors.getSourceFromId)(getState(), frame.generatedLocation.sourceId);
+  return generatedSource.isWasm;
+}
+
+async function expandFrames(frames, sourceMaps, getState) {
+  const result = [];
+
+  for (let i = 0; i < frames.length; ++i) {
+    const frame = frames[i];
+
+    if (frame.isOriginal || !isWasmOriginalSourceFrame(frame, getState)) {
+      result.push(frame);
+      continue;
+    }
+
+    const originalFrames = await sourceMaps.getOriginalStackFrames(frame.generatedLocation);
+
+    if (!originalFrames) {
+      result.push(frame);
+      continue;
+    }
+
+    (0, _assert2.default)(originalFrames.length > 0, "Expected at least one original frame"); // First entry has not specific location -- use one from original frame.
+
+    originalFrames[0] = { ...originalFrames[0],
+      location: frame.location
+    };
+    originalFrames.forEach((originalFrame, j) => {
+      // 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,
+        displayName: originalFrame.displayName,
+        location: originalFrame.location,
+        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
+      });
+    });
+  }
+
+  return result;
+}
 /**
  * Map call stack frame locations and display names to originals.
  * e.g.
  * 1. When the debuggee pauses
  * 2. When a source is pretty printed
  * 3. When symbols are loaded
  * @memberof actions/pause
  * @static
@@ -69,15 +139,16 @@ function mapFrames() {
   }) {
     const frames = (0, _selectors.getFrames)(getState());
 
     if (!frames) {
       return;
     }
 
     let mappedFrames = await updateFrameLocations(frames, sourceMaps);
+    mappedFrames = await expandFrames(mappedFrames, sourceMaps, getState);
     mappedFrames = mapDisplayNames(mappedFrames, getState);
     dispatch({
       type: "MAP_FRAMES",
       frames: mappedFrames
     });
   };
 }
\ No newline at end of file
--- a/devtools/client/debugger/new/src/actions/pause/paused.js
+++ b/devtools/client/debugger/new/src/actions/pause/paused.js
@@ -1,17 +1,15 @@
 "use strict";
 
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
 exports.paused = paused;
 
-var _devtoolsSourceMap = require("devtools/client/shared/source-map/index.js");
-
 var _selectors = require("../../selectors/index");
 
 var _ = require("./index");
 
 var _breakpoints = require("../breakpoints/index");
 
 var _expressions = require("../expressions");
 
@@ -82,19 +80,17 @@ function paused(pauseInfo) {
     if (hiddenBreakpointLocation) {
       dispatch((0, _breakpoints.removeBreakpoint)(hiddenBreakpointLocation));
     }
 
     await dispatch((0, _.mapFrames)());
     const selectedFrame = (0, _selectors.getSelectedFrame)(getState());
 
     if (selectedFrame) {
-      const visibleFrame = (0, _selectors.getVisibleSelectedFrame)(getState());
-      const location = visibleFrame && (0, _devtoolsSourceMap.isGeneratedId)(visibleFrame.location.sourceId) ? selectedFrame.generatedLocation : selectedFrame.location;
-      await dispatch((0, _sources.selectLocation)(location));
+      await dispatch((0, _sources.selectLocation)(selectedFrame.location));
     }
 
     dispatch((0, _ui.togglePaneCollapse)("end", false));
     await dispatch((0, _fetchScopes.fetchScopes)()); // Run after fetching scoping data so that it may make use of the sourcemap
     // expression mappings for local variables.
 
     const atException = why.type == "exception";
 
--- a/devtools/client/debugger/new/src/actions/sources/newSources.js
+++ b/devtools/client/debugger/new/src/actions/sources/newSources.js
@@ -31,17 +31,17 @@ var _selectors = require("../../selector
 /**
  * Redux actions for the sources state
  * @module actions/sources
  */
 function createOriginalSource(originalUrl, generatedSource, sourceMaps) {
   return {
     url: originalUrl,
     relativeUrl: originalUrl,
-    id: sourceMaps.generatedToOriginalId(generatedSource.id, originalUrl),
+    id: (0, _devtoolsSourceMap.generatedToOriginalId)(generatedSource.id, originalUrl),
     isPrettyPrinted: false,
     isWasm: false,
     isBlackBoxed: false,
     loadedState: "unloaded"
   };
 }
 
 function loadSourceMaps(sources) {
@@ -137,17 +137,17 @@ function checkSelectedSource(sourceId) {
 
 function checkPendingBreakpoints(sourceId) {
   return async ({
     dispatch,
     getState
   }) => {
     // source may have been modified by selectLocation
     const source = (0, _selectors.getSourceFromId)(getState(), sourceId);
-    const pendingBreakpoints = (0, _selectors.getPendingBreakpointsForSource)(getState(), source.url);
+    const pendingBreakpoints = (0, _selectors.getPendingBreakpointsForSource)(getState(), source);
 
     if (pendingBreakpoints.length === 0) {
       return;
     } // load the source text if there is a pending breakpoint for it
 
 
     await dispatch((0, _loadSourceText.loadSourceText)(source));
     await Promise.all(pendingBreakpoints.map(bp => dispatch((0, _breakpoints.syncBreakpoint)(sourceId, bp))));
@@ -196,20 +196,20 @@ function newSources(sources) {
     if (sources.length == 0) {
       return;
     }
 
     dispatch({
       type: "ADD_SOURCES",
       sources: sources
     });
+    await dispatch(loadSourceMaps(sources));
 
     for (const source of sources) {
       dispatch(checkSelectedSource(source.id));
       dispatch(checkPendingBreakpoints(source.id));
-    }
+    } // We would like to restore the blackboxed state
+    // after loading all states to make sure the correctness.
 
-    await dispatch(loadSourceMaps(sources)); // We would like to restore the blackboxed state
-    // after loading all states to make sure the correctness.
 
     await dispatch(restoreBlackBoxedSources(sources));
   };
 }
\ No newline at end of file
--- a/devtools/client/debugger/new/src/actions/sources/prettyPrint.js
+++ b/devtools/client/debugger/new/src/actions/sources/prettyPrint.js
@@ -19,19 +19,19 @@ var _ast = require("../ast");
 var _prettyPrint = require("../../workers/pretty-print/index");
 
 var _parser = require("../../workers/parser/index");
 
 var _source = require("../../utils/source");
 
 var _loadSourceText = require("./loadSourceText");
 
-var _sources = require("../sources/index");
+var _pause = require("../pause/index");
 
-var _pause = require("../pause/index");
+var _sources = require("../sources/index");
 
 var _selectors = require("../../selectors/index");
 
 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
 
 /* 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/>. */
@@ -120,24 +120,24 @@ function togglePrettyPrint(sourceId) {
     const options = {};
 
     if (selectedLocation) {
       options.location = await sourceMaps.getOriginalLocation(selectedLocation);
     }
 
     if (prettySource) {
       const _sourceId = prettySource.id;
-      return dispatch((0, _sources.selectLocation)({ ...options.location,
+      return dispatch((0, _sources.selectSpecificLocation)({ ...options.location,
         sourceId: _sourceId
       }));
     }
 
     const newPrettySource = await dispatch(createPrettySource(sourceId));
     await dispatch((0, _breakpoints.remapBreakpoints)(sourceId));
     await dispatch((0, _pause.mapFrames)());
     await dispatch((0, _ast.setPausePoints)(newPrettySource.id));
     await dispatch((0, _ast.setSymbols)(newPrettySource.id));
-    dispatch((0, _sources.selectLocation)({ ...options.location,
+    dispatch((0, _sources.selectSpecificLocation)({ ...options.location,
       sourceId: newPrettySource.id
     }));
     return newPrettySource;
   };
 }
\ No newline at end of file
--- a/devtools/client/debugger/new/src/actions/sources/select.js
+++ b/devtools/client/debugger/new/src/actions/sources/select.js
@@ -9,16 +9,18 @@ exports.selectSource = selectSource;
 exports.selectLocation = selectLocation;
 exports.selectSpecificLocation = selectSpecificLocation;
 exports.selectSpecificSource = selectSpecificSource;
 exports.jumpToMappedLocation = jumpToMappedLocation;
 exports.jumpToMappedSelectedLocation = jumpToMappedSelectedLocation;
 
 var _devtoolsSourceMap = require("devtools/client/shared/source-map/index.js");
 
+var _sources = require("../../reducers/sources");
+
 var _ast = require("../ast");
 
 var _ui = require("../ui");
 
 var _prettyPrint = require("./prettyPrint");
 
 var _tabs = require("../tabs");
 
@@ -55,40 +57,45 @@ const setPendingSelectedLocation = expor
 });
 
 const clearSelectedLocation = exports.clearSelectedLocation = () => ({
   type: "CLEAR_SELECTED_LOCATION"
 });
 /**
  * Deterministically select a source that has a given URL. This will
  * work regardless of the connection status or if the source exists
- * yet. This exists mostly for external things to interact with the
+ * yet.
+ *
+ * This exists mostly for external things to interact with the
  * debugger.
  *
  * @memberof actions/sources
  * @static
  */
 
 
-function selectSourceURL(url, options = {}) {
+function selectSourceURL(url, options = {
+  line: 1
+}) {
   return async ({
     dispatch,
-    getState
+    getState,
+    sourceMaps
   }) => {
     const source = (0, _selectors.getSourceByURL)(getState(), url);
 
-    if (source) {
-      const sourceId = source.id;
-      const location = (0, _location.createLocation)({ ...options.location,
-        sourceId
-      });
-      await dispatch(selectLocation(location));
-    } else {
-      dispatch(setPendingSelectedLocation(url, options));
+    if (!source) {
+      return dispatch(setPendingSelectedLocation(url, options));
     }
+
+    const sourceId = source.id;
+    const location = (0, _location.createLocation)({ ...options,
+      sourceId
+    });
+    return dispatch(selectLocation(location));
   };
 }
 /**
  * @memberof actions/sources
  * @static
  */
 
 
@@ -104,55 +111,65 @@ function selectSource(sourceId) {
 }
 /**
  * @memberof actions/sources
  * @static
  */
 
 
 function selectLocation(location, {
-  checkPrettyPrint = true
+  keepContext = true
 } = {}) {
   return async ({
     dispatch,
     getState,
+    sourceMaps,
     client
   }) => {
     const currentSource = (0, _selectors.getSelectedSource)(getState());
 
     if (!client) {
       // No connection, do nothing. This happens when the debugger is
       // shut down too fast and it tries to display a default source.
       return;
     }
 
-    const source = (0, _selectors.getSource)(getState(), location.sourceId);
+    let source = (0, _selectors.getSource)(getState(), location.sourceId);
 
     if (!source) {
       // If there is no source we deselect the current selected source
       return dispatch(clearSelectedLocation());
     }
 
     const activeSearch = (0, _selectors.getActiveSearch)(getState());
 
     if (activeSearch !== "file") {
       dispatch((0, _ui.closeActiveSearch)());
+    } // Preserve the current source map context (original / generated)
+    // when navigting to a new location.
+
+
+    const selectedSource = (0, _selectors.getSelectedSource)(getState());
+
+    if (keepContext && selectedSource && (0, _devtoolsSourceMap.isOriginalId)(selectedSource.id) != (0, _devtoolsSourceMap.isOriginalId)(location.sourceId)) {
+      location = await (0, _sourceMaps.getMappedLocation)(getState(), sourceMaps, location);
+      source = (0, _sources.getSourceFromId)(getState(), location.sourceId);
     }
 
     dispatch((0, _tabs.addTab)(source.url, 0));
     dispatch(setSelectedLocation(source, location));
     await dispatch((0, _loadSourceText.loadSourceText)(source));
     const loadedSource = (0, _selectors.getSource)(getState(), source.id);
 
     if (!loadedSource) {
       // If there was a navigation while we were loading the loadedSource
       return;
     }
 
-    if (checkPrettyPrint && _prefs.prefs.autoPrettyPrint && !(0, _selectors.getPrettySource)(getState(), loadedSource.id) && (0, _source.shouldPrettyPrint)(loadedSource) && (0, _source.isMinified)(loadedSource)) {
+    if (keepContext && _prefs.prefs.autoPrettyPrint && !(0, _selectors.getPrettySource)(getState(), loadedSource.id) && (0, _source.shouldPrettyPrint)(loadedSource) && (0, _source.isMinified)(loadedSource)) {
       await dispatch((0, _prettyPrint.togglePrettyPrint)(loadedSource.id));
       dispatch((0, _tabs.closeTab)(loadedSource.url));
     }
 
     dispatch((0, _ast.setSymbols)(loadedSource.id));
     dispatch((0, _ast.setOutOfScopeLocations)()); // If a new source is selected update the file search results
 
     const newSource = (0, _selectors.getSelectedSource)(getState());
@@ -165,17 +182,17 @@ function selectLocation(location, {
 /**
  * @memberof actions/sources
  * @static
  */
 
 
 function selectSpecificLocation(location) {
   return selectLocation(location, {
-    checkPrettyPrint: false
+    keepContext: false
   });
 }
 /**
  * @memberof actions/sources
  * @static
  */
 
 
@@ -201,26 +218,18 @@ function jumpToMappedLocation(location) 
     getState,
     client,
     sourceMaps
   }) {
     if (!client) {
       return;
     }
 
-    const source = (0, _selectors.getSource)(getState(), location.sourceId);
-    let pairedLocation;
-
-    if ((0, _devtoolsSourceMap.isOriginalId)(location.sourceId)) {
-      pairedLocation = await (0, _sourceMaps.getGeneratedLocation)(getState(), source, location, sourceMaps);
-    } else {
-      pairedLocation = await sourceMaps.getOriginalLocation(location, source);
-    }
-
-    return dispatch(selectLocation({ ...pairedLocation
+    const pairedLocation = await (0, _sourceMaps.getMappedLocation)(getState(), sourceMaps, location);
+    return dispatch(selectSpecificLocation({ ...pairedLocation
     }));
   };
 }
 
 function jumpToMappedSelectedLocation() {
   return async function ({
     dispatch,
     getState
--- a/devtools/client/debugger/new/src/components/Editor/Preview/index.js
+++ b/devtools/client/debugger/new/src/components/Editor/Preview/index.js
@@ -31,17 +31,17 @@ function inPopup(e) {
   const {
     relatedTarget
   } = e;
 
   if (!relatedTarget) {
     return true;
   }
 
-  const pop = relatedTarget.closest(".popover") || relatedTarget.classList.contains("debug-expression");
+  const pop = relatedTarget.closest(".tooltip") || relatedTarget.closest(".popover") || relatedTarget.classList.contains("debug-expression");
   return pop;
 }
 
 function getElementFromPos(pos) {
   // $FlowIgnore
   return document.elementFromPoint(pos.x + pos.width / 2, pos.y + pos.height / 2);
 }
 
--- a/devtools/client/debugger/new/src/components/Editor/Tab.js
+++ b/devtools/client/debugger/new/src/components/Editor/Tab.js
@@ -143,34 +143,31 @@ class Tab extends _react.PureComponent {
 
     function onClickClose(e) {
       e.stopPropagation();
       closeTab(source.url);
     }
 
     function handleTabClick(e) {
       e.preventDefault();
-      e.stopPropagation(); // Accommodate middle click to close tab
-
-      if (e.button === 1) {
-        return closeTab(source.url);
-      }
-
+      e.stopPropagation();
       return selectSpecificSource(sourceId);
     }
 
     const className = (0, _classnames2.default)("source-tab", {
       active,
       pretty: isPrettyCode
     });
     const path = (0, _source.getDisplayPath)(source, tabSources);
     return _react2.default.createElement("div", {
       className: className,
       key: sourceId,
-      onClick: handleTabClick,
+      onClick: handleTabClick // Accommodate middle click to close tab
+      ,
+      onMouseUp: e => e.button === 1 && closeTab(source.url),
       onContextMenu: e => this.onTabContextMenu(e, sourceId),
       title: (0, _source.getFileURL)(source)
     }, _react2.default.createElement(_SourceIcon2.default, {
       source: source,
       shouldHide: icon => ["file", "javascript"].includes(icon)
     }), _react2.default.createElement("div", {
       className: "filename"
     }, (0, _source.getTruncatedFileName)(source), path && _react2.default.createElement("span", null, `../${path}/..`)), _react2.default.createElement(_Button.CloseButton, {
--- a/devtools/client/debugger/new/src/components/PrimaryPanes/SourcesTree.js
+++ b/devtools/client/debugger/new/src/components/PrimaryPanes/SourcesTree.js
@@ -307,24 +307,22 @@ var _initialiseProps = function () {
       debuggeeUrl,
       projectRoot
     } = this.props;
     return _react2.default.createElement(_SourcesTreeItem2.default, {
       item: item,
       depth: depth,
       focused: focused,
       expanded: expanded,
-      setExpanded: setExpanded,
       focusItem: this.focusItem,
       selectItem: this.selectItem,
       source: this.getSource(item),
       debuggeeUrl: debuggeeUrl,
       projectRoot: projectRoot,
-      clearProjectDirectoryRoot: this.props.clearProjectDirectoryRoot,
-      setProjectDirectoryRoot: this.props.setProjectDirectoryRoot
+      setExpanded: setExpanded
     });
   };
 };
 
 function getSourceForTree(state, source) {
   if (!source || !source.isPrettyPrinted) {
     return source;
   }
@@ -344,11 +342,10 @@ const mapStateToProps = state => {
     sources: (0, _selectors.getRelativeSources)(state),
     sourceCount: (0, _selectors.getSourceCount)(state)
   };
 };
 
 exports.default = (0, _reactRedux.connect)(mapStateToProps, {
   selectSource: _actions2.default.selectSource,
   setExpandedState: _actions2.default.setExpandedState,
-  setProjectDirectoryRoot: _actions2.default.setProjectDirectoryRoot,
   clearProjectDirectoryRoot: _actions2.default.clearProjectDirectoryRoot
 })(SourcesTree);
\ No newline at end of file
--- a/devtools/client/debugger/new/src/components/PrimaryPanes/SourcesTreeItem.js
+++ b/devtools/client/debugger/new/src/components/PrimaryPanes/SourcesTreeItem.js
@@ -1,32 +1,42 @@
 "use strict";
 
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
 
+var _devtoolsSourceMap = require("devtools/client/shared/source-map/index.js");
+
 var _react = require("devtools/client/shared/vendor/react");
 
 var _react2 = _interopRequireDefault(_react);
 
+var _reactRedux = require("devtools/client/shared/vendor/react-redux");
+
 var _classnames = require("devtools/client/debugger/new/dist/vendors").vendored["classnames"];
 
 var _classnames2 = _interopRequireDefault(_classnames);
 
 var _devtoolsContextmenu = require("devtools/client/debugger/new/dist/vendors").vendored["devtools-contextmenu"];
 
 var _SourceIcon = require("../shared/SourceIcon");
 
 var _SourceIcon2 = _interopRequireDefault(_SourceIcon);
 
 var _Svg = require("devtools/client/debugger/new/dist/vendors").vendored["Svg"];
 
 var _Svg2 = _interopRequireDefault(_Svg);
 
+var _selectors = require("../../selectors/index");
+
+var _actions = require("../../actions/index");
+
+var _actions2 = _interopRequireDefault(_actions);
+
 var _sourcesTree = require("../../utils/sources-tree/index");
 
 var _clipboard = require("../../utils/clipboard");
 
 var _prefs = require("../../utils/prefs");
 
 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
 
@@ -163,42 +173,71 @@ class SourceTreeItem extends _react.Comp
       className: (0, _classnames2.default)("arrow", {
         expanded
       })
     }) : _react2.default.createElement("i", {
       className: "no-arrow"
     });
   }
 
-  renderItemName(name) {
-    switch (name) {
+  renderItemName() {
+    const {
+      item
+    } = this.props;
+
+    switch (item.name) {
       case "ng://":
         return "Angular";
 
       case "webpack://":
         return "Webpack";
 
       default:
-        return name;
+        return `${item.name}`;
     }
   }
 
   render() {
     const {
       item,
       depth,
-      focused
+      focused,
+      hasMatchingGeneratedSource
     } = this.props;
+    const suffix = hasMatchingGeneratedSource ? _react2.default.createElement("span", {
+      className: "suffix"
+    }, "[sm]") : null;
     return _react2.default.createElement("div", {
       className: (0, _classnames2.default)("node", {
         focused
       }),
       key: item.path,
       onClick: this.onClick,
       onContextMenu: e => this.onContextMenu(e, item)
     }, this.renderItemArrow(), this.getIcon(item, depth), _react2.default.createElement("span", {
       className: "label"
-    }, " ", this.renderItemName(item.name), " "));
+    }, " ", this.renderItemName(), " ", suffix));
   }
 
 }
 
-exports.default = SourceTreeItem;
\ No newline at end of file
+function getHasMatchingGeneratedSource(state, source) {
+  if (!source) {
+    return false;
+  }
+
+  const sources = (0, _selectors.getSourcesByURL)(state, source.url);
+  return (0, _devtoolsSourceMap.isOriginalId)(source.id) && sources.length > 1;
+}
+
+const mapStateToProps = (state, props) => {
+  const {
+    source
+  } = props;
+  return {
+    hasMatchingGeneratedSource: getHasMatchingGeneratedSource(state, source)
+  };
+};
+
+exports.default = (0, _reactRedux.connect)(mapStateToProps, {
+  setProjectDirectoryRoot: _actions2.default.setProjectDirectoryRoot,
+  clearProjectDirectoryRoot: _actions2.default.clearProjectDirectoryRoot
+})(SourceTreeItem);
\ No newline at end of file
--- a/devtools/client/debugger/new/src/components/PrimaryPanes/index.js
+++ b/devtools/client/debugger/new/src/components/PrimaryPanes/index.js
@@ -115,12 +115,11 @@ class PrimaryPanes extends _react.Compon
 const mapStateToProps = state => ({
   selectedTab: (0, _selectors.getSelectedPrimaryPaneTab)(state),
   sources: (0, _selectors.getSources)(state),
   sourceSearchOn: (0, _selectors.getActiveSearch)(state) === "source"
 });
 
 exports.default = (0, _reactRedux.connect)(mapStateToProps, {
   setPrimaryPaneTab: _actions2.default.setPrimaryPaneTab,
-  selectLocation: _actions2.default.selectLocation,
   setActiveSearch: _actions2.default.setActiveSearch,
   closeActiveSearch: _actions2.default.closeActiveSearch
 })(PrimaryPanes);
\ No newline at end of file
--- a/devtools/client/debugger/new/src/components/ProjectSearch.js
+++ b/devtools/client/debugger/new/src/components/ProjectSearch.js
@@ -78,17 +78,17 @@ class ProjectSearch extends _react.Compo
       }
 
       return setActiveSearch("project");
     };
 
     this.isProjectSearchEnabled = () => this.props.activeSearch === "project";
 
     this.selectMatchItem = matchItem => {
-      this.props.selectLocation({ ...matchItem
+      this.props.selectSpecificLocation({ ...matchItem
       });
       this.props.doSearchForHighlight(this.state.inputValue, (0, _editor.getEditor)(), matchItem.line, matchItem.column);
     };
 
     this.getResults = () => {
       const {
         results
       } = this.props;
@@ -330,12 +330,12 @@ const mapStateToProps = state => ({
   query: (0, _selectors.getTextSearchQuery)(state),
   status: (0, _selectors.getTextSearchStatus)(state)
 });
 
 exports.default = (0, _reactRedux.connect)(mapStateToProps, {
   closeProjectSearch: _actions2.default.closeProjectSearch,
   searchSources: _actions2.default.searchSources,
   clearSearch: _actions2.default.clearSearch,
-  selectLocation: _actions2.default.selectLocation,
+  selectSpecificLocation: _actions2.default.selectSpecificLocation,
   setActiveSearch: _actions2.default.setActiveSearch,
   doSearchForHighlight: _actions2.default.doSearchForHighlight
 })(ProjectSearch);
\ No newline at end of file
--- a/devtools/client/debugger/new/src/components/QuickOpenModal.js
+++ b/devtools/client/debugger/new/src/components/QuickOpenModal.js
@@ -180,28 +180,28 @@ class QuickOpenModal extends _react.Comp
       this.gotoLocation({
         sourceId: item.id,
         line: 0
       });
     };
 
     this.onSelectResultItem = item => {
       const {
-        selectLocation,
+        selectSpecificLocation,
         selectedSource,
         highlightLineRange
       } = this.props;
 
       if (!this.isSymbolSearch() || selectedSource == null) {
         return;
       }
 
       if (this.isVariableQuery()) {
         const line = item.location && item.location.start ? item.location.start.line : 0;
-        return selectLocation({
+        return selectSpecificLocation({
           sourceId: selectedSource.id,
           line
         });
       }
 
       if (this.isFunctionQuery()) {
         return highlightLineRange({ ...(item.location != null ? {
             start: item.location.start.line,
@@ -227,24 +227,24 @@ class QuickOpenModal extends _react.Comp
 
       if (results != null) {
         this.onSelectResultItem(results[nextIndex]);
       }
     };
 
     this.gotoLocation = location => {
       const {
-        selectLocation,
+        selectSpecificLocation,
         selectedSource
       } = this.props;
       const selectedSourceId = selectedSource ? selectedSource.id : "";
 
       if (location != null) {
         const sourceId = location.sourceId ? location.sourceId : selectedSourceId;
-        selectLocation({
+        selectSpecificLocation({
           sourceId,
           line: location.line,
           column: location.column
         });
         this.closeModal();
       }
     };
 
@@ -477,14 +477,14 @@ function mapStateToProps(state) {
     tabs: (0, _selectors.getTabs)(state)
   };
 }
 /* istanbul ignore next: ignoring testing of redux connection stuff */
 
 
 exports.default = (0, _reactRedux.connect)(mapStateToProps, {
   shortcutsModalEnabled: _actions2.default.shortcutsModalEnabled,
-  selectLocation: _actions2.default.selectLocation,
+  selectSpecificLocation: _actions2.default.selectSpecificLocation,
   setQuickOpenQuery: _actions2.default.setQuickOpenQuery,
   highlightLineRange: _actions2.default.highlightLineRange,
   closeQuickOpen: _actions2.default.closeQuickOpen,
   toggleShortcutsModal: _actions2.default.toggleShortcutsModal
 })(QuickOpenModal);
\ No newline at end of file
--- a/devtools/client/debugger/new/src/reducers/pause.js
+++ b/devtools/client/debugger/new/src/reducers/pause.js
@@ -350,31 +350,40 @@ function getCanRewind(state) {
 function getExtra(state) {
   return state.pause.extra;
 }
 
 function getFrames(state) {
   return state.pause.frames;
 }
 
+function getGeneratedFrameId(frameId) {
+  if (frameId.includes("-originalFrame")) {
+    // The mapFrames can add original stack frames -- get generated frameId.
+    return frameId.substr(0, frameId.lastIndexOf("-originalFrame"));
+  }
+
+  return frameId;
+}
+
 function getGeneratedFrameScope(state, frameId) {
   if (!frameId) {
     return null;
   }
 
-  return getFrameScopes(state).generated[frameId];
+  return getFrameScopes(state).generated[getGeneratedFrameId(frameId)];
 }
 
 function getOriginalFrameScope(state, sourceId, frameId) {
   if (!frameId || !sourceId) {
     return null;
   }
 
   const isGenerated = (0, _devtoolsSourceMap.isGeneratedId)(sourceId);
-  const original = getFrameScopes(state).original[frameId];
+  const original = getFrameScopes(state).original[getGeneratedFrameId(frameId)];
 
   if (!isGenerated && original && (original.pending || original.scope)) {
     return original;
   }
 
   return null;
 }
 
--- a/devtools/client/debugger/new/src/reducers/pending-breakpoints.js
+++ b/devtools/client/debugger/new/src/reducers/pending-breakpoints.js
@@ -2,16 +2,20 @@
 
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
 exports.getPendingBreakpoints = getPendingBreakpoints;
 exports.getPendingBreakpointList = getPendingBreakpointList;
 exports.getPendingBreakpointsForSource = getPendingBreakpointsForSource;
 
+var _devtoolsSourceMap = require("devtools/client/shared/source-map/index.js");
+
+var _sources = require("./sources");
+
 var _breakpoint = require("../utils/breakpoint/index");
 
 /* 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/>. */
 
 /**
  * Pending breakpoints reducer
@@ -163,13 +167,20 @@ function deleteBreakpoint(state, locatio
 function getPendingBreakpoints(state) {
   return state.pendingBreakpoints;
 }
 
 function getPendingBreakpointList(state) {
   return Object.values(getPendingBreakpoints(state));
 }
 
-function getPendingBreakpointsForSource(state, sourceUrl) {
-  return getPendingBreakpointList(state).filter(pendingBreakpoint => pendingBreakpoint.location.sourceUrl === sourceUrl);
+function getPendingBreakpointsForSource(state, source) {
+  const sources = (0, _sources.getSourcesByURL)(state, source.url);
+
+  if (sources.length > 1 && (0, _devtoolsSourceMap.isGeneratedId)(source.id)) {
+    // Don't return pending breakpoints for duplicated generated sources
+    return [];
+  }
+
+  return getPendingBreakpointList(state).filter(pendingBreakpoint => pendingBreakpoint.location.sourceUrl === source.url);
 }
 
 exports.default = update;
\ No newline at end of file
--- a/devtools/client/debugger/new/src/reducers/sources.js
+++ b/devtools/client/debugger/new/src/reducers/sources.js
@@ -5,16 +5,17 @@ Object.defineProperty(exports, "__esModu
 });
 exports.getSelectedSource = exports.getSelectedLocation = exports.getSourceCount = undefined;
 exports.initialSourcesState = initialSourcesState;
 exports.createSource = createSource;
 exports.getBlackBoxList = getBlackBoxList;
 exports.getSource = getSource;
 exports.getSourceFromId = getSourceFromId;
 exports.getSourceByURL = getSourceByURL;
+exports.getSourcesByURL = getSourcesByURL;
 exports.getGeneratedSource = getGeneratedSource;
 exports.getPendingSelectedLocation = getPendingSelectedLocation;
 exports.getPrettySource = getPrettySource;
 exports.hasPrettySource = hasPrettySource;
 exports.getSourceByUrlInSources = getSourceByUrlInSources;
 exports.getSourceInSources = getSourceInSources;
 exports.getSources = getSources;
 exports.getUrls = getUrls;
@@ -244,16 +245,20 @@ function getSource(state, id) {
 function getSourceFromId(state, id) {
   return getSourcesState(state).sources[id];
 }
 
 function getSourceByURL(state, url) {
   return getSourceByUrlInSources(getSources(state), getUrls(state), url);
 }
 
+function getSourcesByURL(state, url) {
+  return getSourcesByUrlInSources(getSources(state), getUrls(state), url);
+}
+
 function getGeneratedSource(state, source) {
   if (!(0, _devtoolsSourceMap.isOriginalId)(source.id)) {
     return source;
   }
 
   return getSourceFromId(state, (0, _devtoolsSourceMap.originalToGeneratedId)(source.id));
 }
 
--- a/devtools/client/debugger/new/src/utils/pause/frames/getLibraryFromUrl.js
+++ b/devtools/client/debugger/new/src/utils/pause/frames/getLibraryFromUrl.js
@@ -52,17 +52,17 @@ const libraryMap = [{
 }, {
   label: "Ember",
   pattern: /ember/i
 }, {
   label: "Choo",
   pattern: /choo/i
 }, {
   label: "VueJS",
-  pattern: /vue\.js/i
+  pattern: /vue(?:\.[a-z]+)*\.js/i
 }, {
   label: "RxJS",
   pattern: /rxjs/i
 }, {
   label: "Angular",
   pattern: /angular/i
 }, {
   label: "Redux",
--- a/devtools/client/debugger/new/src/utils/source-maps.js
+++ b/devtools/client/debugger/new/src/utils/source-maps.js
@@ -1,22 +1,25 @@
 "use strict";
 
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
 exports.getGeneratedLocation = getGeneratedLocation;
+exports.getMappedLocation = getMappedLocation;
+
+var _devtoolsSourceMap = require("devtools/client/shared/source-map/index.js");
 
 var _selectors = require("../selectors/index");
 
 /* 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/>. */
 async function getGeneratedLocation(state, source, location, sourceMaps) {
-  if (!sourceMaps.isOriginalId(location.sourceId)) {
+  if (!(0, _devtoolsSourceMap.isOriginalId)(location.sourceId)) {
     return location;
   }
 
   const {
     line,
     sourceId,
     column
   } = await sourceMaps.getGeneratedLocation(location, source);
@@ -27,9 +30,19 @@ async function getGeneratedLocation(stat
   }
 
   return {
     line,
     sourceId,
     column: column === 0 ? undefined : column,
     sourceUrl: generatedSource.url
   };
+}
+
+async function getMappedLocation(state, sourceMaps, location) {
+  const source = (0, _selectors.getSource)(state, location.sourceId);
+
+  if ((0, _devtoolsSourceMap.isOriginalId)(location.sourceId)) {
+    return getGeneratedLocation(state, source, location, sourceMaps);
+  }
+
+  return sourceMaps.getOriginalLocation(location, source);
 }
\ No newline at end of file
--- a/devtools/client/debugger/new/src/utils/source.js
+++ b/devtools/client/debugger/new/src/utils/source.js
@@ -46,17 +46,18 @@ var _url = require("../utils/url");
 var _sourcesTree = require("./sources-tree/index");
 
 var _prefs = require("./prefs");
 
 const sourceTypes = exports.sourceTypes = {
   coffee: "coffeescript",
   js: "javascript",
   jsx: "react",
-  ts: "typescript"
+  ts: "typescript",
+  vue: "vue"
 };
 /**
  * Trims the query part or reference identifier of a url string, if necessary.
  *
  * @memberof utils/source
  * @static
  */
 
--- a/devtools/client/debugger/new/src/utils/sources-tree/getURL.js
+++ b/devtools/client/debugger/new/src/utils/sources-tree/getURL.js
@@ -43,38 +43,37 @@ function _getURL(source, defaultDomain) 
 
   if (!url) {
     return def;
   }
 
   const {
     pathname,
     protocol,
-    host,
-    path
+    host
   } = (0, _url.parse)(url);
   const filename = (0, _devtoolsModules.getUnicodeUrlPath)(getFilenameFromPath(pathname));
 
   switch (protocol) {
     case "javascript:":
       // Ignore `javascript:` URLs for now
       return def;
 
     case "moz-extension:":
     case "resource:":
       return { ...def,
-        path,
+        path: pathname,
         filename,
         group: `${protocol}//${host || ""}`
       };
 
     case "webpack:":
     case "ng:":
       return { ...def,
-        path: path,
+        path: pathname,
         filename,
         group: `${protocol}//`
       };
 
     case "about:":
       // An about page is a special case
       return { ...def,
         path: "/",
@@ -88,17 +87,17 @@ function _getURL(source, defaultDomain) 
         group: NoDomain,
         filename: url
       };
 
     case "":
       if (pathname && pathname.startsWith("/")) {
         // use file protocol for a URL like "/foo/bar.js"
         return { ...def,
-          path: path,
+          path: pathname,
           filename,
           group: "file://"
         };
       } else if (!host) {
         return { ...def,
           path: url,
           group: defaultDomain || "",
           filename
@@ -112,17 +111,17 @@ function _getURL(source, defaultDomain) 
       return { ...def,
         path: pathname,
         filename,
         group: (0, _devtoolsModules.getUnicodeHostname)(host)
       };
   }
 
   return { ...def,
-    path: path,
+    path: pathname,
     group: protocol ? `${protocol}//` : "",
     filename
   };
 }
 
 function getURL(source, debuggeeUrl) {
   if (urlMap.has(source)) {
     return urlMap.get(source) || def;
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-pause-points.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-pause-points.js
@@ -48,12 +48,11 @@ add_task(async function test() {
     name: "sequences",
     count: 4,
     steps: [[23,2], [25,8], [31,4], [34,2], [37,0]]
   });
 
   await testCase(dbg, {
     name: "flow",
     count: 8,
-    steps:
-      [[16,2], [17,12], [18,6], [19,8], [19,17], [19,8], [19,17], [19,8], [20,0]]
+    steps: [[16,2], [17,12], [18,6], [19,2], [19,8], [19,17], [19,8], [19,17], [19,8]]
   });
 });
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-preview-source-maps.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-preview-source-maps.js
@@ -55,12 +55,12 @@ add_task(async function() {
   info(`Test previewing in the generated location`);
   await dbg.actions.jumpToMappedSelectedLocation();
   await waitForSelectedSource(dbg, "bundle.js");
   await assertPreviews(dbg, [
     { line: 70, column: 11, result: 4, expression: "x" }
   ]);
 
   info(`Test that you can not preview in another original file`);
-  await selectSource(dbg, "output");
+  await selectSpecificSource(dbg, "output");
   await hoverAtPos(dbg, { line: 2, ch: 16 });
   await assertNoTooltip(dbg);
 });
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-sourcemaps.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-sourcemaps.js
@@ -44,29 +44,29 @@ add_task(async function() {
     selectors: { getBreakpoint, getBreakpoints },
     getState
   } = dbg;
 
   await waitForSources(dbg, "entry.js", "output.js", "times2.js", "opts.js");
   ok(true, "Original sources exist");
   const bundleSrc = findSource(dbg, "bundle.js");
 
-  await selectSource(dbg, bundleSrc);
+  await selectSpecificSource(dbg, bundleSrc);
 
   await clickGutter(dbg, 13);
   await waitForDispatch(dbg, "ADD_BREAKPOINT");
   assertEditorBreakpoint(dbg, 13, true);
 
   await clickGutter(dbg, 13);
   await waitForDispatch(dbg, "REMOVE_BREAKPOINT");
   is(getBreakpoints(getState()).size, 0, "No breakpoints exists");
 
   const entrySrc = findSource(dbg, "entry.js");
 
-  await selectSource(dbg, entrySrc);
+  await selectSpecificSource(dbg, entrySrc);
   ok(
     getCM(dbg)
       .getValue()
       .includes("window.keepMeAlive"),
     "Original source text loaded correctly"
   );
 
   // Test breaking on a breakpoint
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-wasm-sourcemaps.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-wasm-sourcemaps.js
@@ -19,17 +19,17 @@ add_task(async function() {
   await waitForLoadedSource(dbg, "doc-wasm-sourcemaps");
   assertPausedLocation(dbg);
 
   await waitForSource(dbg, "fib.c");
 
   ok(true, "Original sources exist");
   const mainSrc = findSource(dbg, "fib.c");
 
-  await selectSource(dbg, mainSrc);
+  await selectSpecificSource(dbg, mainSrc);
   await addBreakpoint(dbg, "fib.c", 10);
 
   resume(dbg);
 
   await waitForPaused(dbg, "fib.c");
 
   const frames = findAllElements(dbg, "frames");
   const firstFrameTitle = frames[0].querySelector(".title").textContent;
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg_rr_stepping-04.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg_rr_stepping-04.js
@@ -22,20 +22,17 @@ async function test() {
 
   // After reverse-stepping out of the topmost frame we should rewind to the
   // last breakpoint hit.
   await reverseStepOverToLine(client, 21);
   await checkEvaluateInTopFrame(client, "number", 9);
 
   await stepOverToLine(client, 22);
   await stepOverToLine(client, 23);
-  // Line 13 seems like it should be the next stepping point, but the column
-  // numbers reported by the JS engine and required by the pause points do not
-  // match, and we don't stop here.
-  //await stepOverToLine(client, 13);
+  await stepOverToLine(client, 13);
   await stepOverToLine(client, 17);
   await stepOverToLine(client, 18);
 
   // After forward-stepping out of the topmost frame we should run forward to
   // the next breakpoint hit.
   await stepOverToLine(client, 21);
   await checkEvaluateInTopFrame(client, "number", 10);
 
--- a/devtools/client/debugger/new/test/mochitest/helpers.js
+++ b/devtools/client/debugger/new/test/mochitest/helpers.js
@@ -597,16 +597,23 @@ function waitForLoadedSources(dbg) {
  * @static
  */
 async function selectSource(dbg, url, line) {
   const source = findSource(dbg, url);
   await dbg.actions.selectLocation({ sourceId: source.id, line });
   return waitForSelectedSource(dbg, url);
 }
 
+async function selectSpecificSource(dbg, url, line) {
+  const source = findSource(dbg, url);
+  await dbg.actions.selectLocation({ sourceId: source.id, line }, {keepContext: false});
+  return waitForSelectedSource(dbg, url);
+}
+
+
 function closeTab(dbg, url) {
   const source = findSource(dbg, url);
   return dbg.actions.closeTab(source.url);
 }
 
 /**
  * Steps over.
  *
--- a/devtools/client/shared/source-map/index.js
+++ b/devtools/client/shared/source-map/index.js
@@ -448,16 +448,17 @@ const getAllGeneratedLocations = dispatc
   queue: true
 });
 const getOriginalLocation = dispatcher.task("getOriginalLocation");
 const getLocationScopes = dispatcher.task("getLocationScopes");
 const getOriginalSourceText = dispatcher.task("getOriginalSourceText");
 const applySourceMap = dispatcher.task("applySourceMap");
 const clearSourceMaps = dispatcher.task("clearSourceMaps");
 const hasMappedSource = dispatcher.task("hasMappedSource");
+const getOriginalStackFrames = dispatcher.task("getOriginalStackFrames");
 
 module.exports = {
   originalToGeneratedId,
   generatedToOriginalId,
   isGeneratedId,
   isOriginalId,
   hasMappedSource,
   getOriginalURLs,
@@ -465,16 +466,17 @@ module.exports = {
   getGeneratedRanges,
   getGeneratedLocation,
   getAllGeneratedLocations,
   getOriginalLocation,
   getLocationScopes,
   getOriginalSourceText,
   applySourceMap,
   clearSourceMaps,
+  getOriginalStackFrames,
   startSourceMapWorker: dispatcher.start.bind(dispatcher),
   stopSourceMapWorker: dispatcher.stop.bind(dispatcher)
 };
 
 /***/ }),
 
 /***/ 3651:
 /***/ (function(module, exports, __webpack_require__) {
--- a/devtools/client/shared/source-map/worker.js
+++ b/devtools/client/shared/source-map/worker.js
@@ -1981,31 +1981,34 @@ const {
   getOriginalSourceText,
   getLocationScopes,
   hasMappedSource,
   applySourceMap
 } = __webpack_require__(3710);
 
 const { clearSourceMaps } = __webpack_require__(3704);
 
+const { getOriginalStackFrames } = __webpack_require__(3783);
+
 const {
   workerUtils: { workerHandler }
 } = __webpack_require__(3651);
 
 // The interface is implemented in source-map to be
 // easier to unit test.
 self.onmessage = workerHandler({
   getOriginalURLs,
   getOriginalRanges,
   getGeneratedRanges,
   getGeneratedLocation,
   getAllGeneratedLocations,
   getOriginalLocation,
   getLocationScopes,
   getOriginalSourceText,
+  getOriginalStackFrames,
   hasMappedSource,
   applySourceMap,
   clearSourceMaps
 });
 
 /***/ }),
 
 /***/ 3710:
@@ -4487,12 +4490,33 @@ exports.WasmRemap = WasmRemap;
 /***/ }),
 
 /***/ 3726:
 /***/ (function(module, exports, __webpack_require__) {
 
 module.exports = __webpack_require__(3709);
 
 
+/***/ }),
+
+/***/ 3783:
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+// Returns expanded stack frames details based on the generated location.
+// The function return null if not information was found.
+async function getOriginalStackFrames(generatedLocation) {
+  // Reserved for experemental source maps formats.
+  return null;
+} /* 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/>. */
+
+module.exports = {
+  getOriginalStackFrames
+};
+
 /***/ })
 
 /******/ });
 });
\ No newline at end of file