Bug 1450112 - Update Debugger Frontend v31. r=jdescottes
authorJason Laster <jason.laster.11@gmail.com>
Thu, 29 Mar 2018 16:58:17 -0400
changeset 410753 7fdb14ac881161d8dc429460d0aa373f4bbd9f39
parent 410752 8eec06866ec979e059f8e95a0f9d6fae46ad9159
child 410754 223010e3a593311128b4faa732362d69c801d57b
push id33736
push usershindli@mozilla.com
push dateFri, 30 Mar 2018 09:56:41 +0000
treeherdermozilla-central@b7fa9d95150e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjdescottes
bugs1450112
milestone61.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 1450112 - Update Debugger Frontend v31. r=jdescottes
devtools/client/debugger/new/README.mozilla
devtools/client/debugger/new/debugger.js
devtools/client/debugger/new/panel.js
devtools/client/debugger/new/parser-worker.js
devtools/client/debugger/new/test/mochitest/browser_dbg-babel-preview.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 30.0
+Version 31.0
 
-Comparison: https://github.com/devtools-html/debugger.html/compare/release-29...release-30
+Comparison: https://github.com/devtools-html/debugger.html/compare/release-30...release-31
 
 Packages:
 - babel-plugin-transform-es2015-modules-commonjs @6.26.0
 - babel-preset-react @6.24.1
 - react @16.2.0
 - react-dom @16.2.0
 - webpack @3.11.0
--- a/devtools/client/debugger/new/debugger.js
+++ b/devtools/client/debugger/new/debugger.js
@@ -2888,31 +2888,33 @@ const {
 } = __webpack_require__(1389);
 
 const { workerUtils: { WorkerDispatcher } } = __webpack_require__(1363);
 
 const dispatcher = new WorkerDispatcher();
 
 const getOriginalURLs = dispatcher.task("getOriginalURLs");
 const getGeneratedLocation = dispatcher.task("getGeneratedLocation");
+const getAllGeneratedLocations = dispatcher.task("getAllGeneratedLocations");
 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");
 
 module.exports = {
   originalToGeneratedId,
   generatedToOriginalId,
   isGeneratedId,
   isOriginalId,
   hasMappedSource,
   getOriginalURLs,
   getGeneratedLocation,
+  getAllGeneratedLocations,
   getOriginalLocation,
   getLocationScopes,
   getOriginalSourceText,
   applySourceMap,
   clearSourceMaps,
   startSourceMapWorker: dispatcher.start.bind(dispatcher),
   stopSourceMapWorker: dispatcher.stop.bind(dispatcher)
 };
@@ -3619,17 +3621,17 @@ function setSourceTextProps(state, actio
   return updateSource(state, text);
 }
 
 function updateSource(state, source) {
   if (!source.id) {
     return state;
   }
 
-  const existingSource = state.getIn(["sources", source.id]);
+  const existingSource = state.sources.get(source.id);
 
   if (existingSource) {
     const updatedSource = existingSource.merge(source);
     return state.setIn(["sources", source.id], updatedSource);
   }
 
   return state.setIn(["sources", source.id], new SourceRecordClass(source));
 }
@@ -4896,17 +4898,17 @@ function update(state = initialASTState(
 
 // NOTE: we'd like to have the app state fully typed
 // https://github.com/devtools-html/debugger.html/blob/master/src/reducers/sources.js#L179-L185
 function getSymbols(state, source) {
   if (!source) {
     return null;
   }
 
-  return state.ast.getIn(["symbols", source.id]) || null;
+  return state.ast.symbols.get(source.id) || null;
 }
 
 function hasSymbols(state, source) {
   const symbols = getSymbols(state, source);
 
   if (!symbols) {
     return false;
   }
@@ -4928,21 +4930,21 @@ function isEmptyLineInSource(state, line
   return emptyLines && emptyLines.includes(line);
 }
 
 function getEmptyLines(state, source) {
   if (!source) {
     return null;
   }
 
-  return state.ast.getIn(["emptyLines", source.id]);
+  return state.ast.emptyLines.get(source.id);
 }
 
 function getPausePoints(state, sourceId) {
-  return state.ast.getIn(["pausePoints", sourceId]);
+  return state.ast.pausePoints.get(sourceId);
 }
 
 function hasPausePoints(state, sourceId) {
   const pausePoints = getPausePoints(state, sourceId);
   return !!pausePoints;
 }
 
 function getOutOfScopeLocations(state) {
@@ -4950,17 +4952,17 @@ function getOutOfScopeLocations(state) {
 }
 
 function getPreview(state) {
   return state.ast.get("preview");
 }
 
 const emptySourceMetaData = {};
 function getSourceMetaData(state, sourceId) {
-  return state.ast.getIn(["sourceMetaData", sourceId]) || emptySourceMetaData;
+  return state.ast.sourceMetaData.get(sourceId) || emptySourceMetaData;
 }
 
 function hasSourceMetaData(state, sourceId) {
   return state.ast.hasIn(["sourceMetaData", sourceId]);
 }
 
 function getInScopeLines(state) {
   return state.ast.get("inScopeLines");
@@ -5299,16 +5301,17 @@ function trimUrlQuery(url) {
 
   return url.slice(0, q);
 }
 
 // Map suffix to content type.
 const contentMap = {
   "js": "text/javascript",
   "jsm": "text/javascript",
+  "mjs": "text/javascript",
   "ts": "text/typescript",
   "tsx": "text/typescript-jsx",
   "jsx": "text/jsx",
   "coffee": "text/coffeescript",
   "elm": "text/elm",
   "cljs": "text/x-clojure"
 };
 
@@ -6345,24 +6348,24 @@ function evaluateExpression(expression) 
       console.warn("Expressions should not be empty");
       return;
     }
 
     let input = expression.input;
     const frame = (0, _selectors.getSelectedFrame)(getState());
 
     if (frame) {
-      const { location, generatedLocation } = frame;
+      const { location } = frame;
       const source = (0, _selectors.getSource)(getState(), location.sourceId);
       const sourceId = source.get("id");
 
       const selectedSource = (0, _selectors.getSelectedSource)(getState());
 
       if (selectedSource && !(0, _devtoolsSourceMap.isGeneratedId)(sourceId) && !(0, _devtoolsSourceMap.isGeneratedId)(selectedSource.get("id"))) {
-        input = await getMappedExpression({ getState, sourceMaps }, generatedLocation, input);
+        input = await dispatch(getMappedExpression(input));
       }
     }
 
     const frameId = (0, _selectors.getSelectedFrameId)(getState());
 
     return dispatch({
       type: "EVALUATE_EXPRESSION",
       input: expression.input,
@@ -6370,23 +6373,28 @@ function evaluateExpression(expression) 
     });
   };
 }
 
 /**
  * Gets information about original variable names from the source map
  * and replaces all posible generated names.
  */
-async function getMappedExpression({ getState, sourceMaps }, generatedLocation, expression) {
-  const mappings = (0, _selectors.getSelectedScopeMappings)(getState());
-  if (!mappings) {
-    return expression;
-  }
-
-  return await parser.mapOriginalExpression(expression, mappings);
+function getMappedExpression(expression) {
+  return async function ({ dispatch, getState, client, sourceMaps }) {
+    const mappings = (0, _selectors.getSelectedScopeMappings)(getState());
+    if (!mappings) {
+      return expression;
+    }
+
+    return await dispatch({
+      type: "MAP_EXPRESSION_RESULT",
+      [_promise.PROMISE]: parser.mapOriginalExpression(expression, mappings)
+    });
+  };
 }
 
 /***/ }),
 
 /***/ 1399:
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
@@ -7816,30 +7824,30 @@ const createExpressionState = exports.cr
  */
 
 function update(state = createExpressionState(), action) {
   switch (action.type) {
     case "ADD_EXPRESSION":
       if (action.expressionError) {
         return state.set("expressionError", !!action.expressionError);
       }
-      return appendToList(state, ["expressions"], {
+      return appendExpressionToList(state, {
         input: action.input,
         value: null,
         updating: true
       });
     case "UPDATE_EXPRESSION":
       const key = action.expression.input;
-      return updateItemInList(state, ["expressions"], key, {
+      return updateExpressionInList(state, key, {
         input: action.input,
         value: null,
         updating: true
       }).set("expressionError", !!action.expressionError);
     case "EVALUATE_EXPRESSION":
-      return updateItemInList(state, ["expressions"], action.input, {
+      return updateExpressionInList(state, action.input, {
         input: action.input,
         value: action.value,
         updating: false
       });
     case "DELETE_EXPRESSION":
       return deleteExpression(state, action.input);
     case "CLEAR_EXPRESSION_ERROR":
       return state.set("expressionError", false);
@@ -7854,71 +7862,71 @@ function update(state = createExpression
   return state;
 }
 
 function travelTo(state, action) {
   const { expressions } = action.data;
   if (!expressions) {
     return state;
   }
-  return expressions.reduce((finalState, previousState) => updateItemInList(finalState, ["expressions"], previousState.input, {
+  return expressions.reduce((finalState, previousState) => updateExpressionInList(finalState, previousState.input, {
     input: previousState.input,
     value: previousState.value,
     updating: false
   }), state);
 }
 
 function restoreExpressions() {
   const exprs = _prefs.prefs.expressions;
   if (exprs.length == 0) {
     return;
   }
   return exprs;
 }
 
-function storeExpressions(state) {
-  const expressions = state.getIn(["expressions"]).map(expression => (0, _lodash.omit)(expression, "value")).toJS();
-
-  _prefs.prefs.expressions = expressions;
-}
-
-function appendToList(state, path, value) {
-  const newState = state.updateIn(path, () => {
-    return state.getIn(path).push(value);
-  });
+function storeExpressions({ expressions }) {
+  _prefs.prefs.expressions = expressions.map(expression => (0, _lodash.omit)(expression, "value")).toJS();
+}
+
+function appendExpressionToList(state, value) {
+  const newState = state.update("expressions", () => {
+    return state.expressions.push(value);
+  });
+
   storeExpressions(newState);
   return newState;
 }
 
-function updateItemInList(state, path, key, value) {
-  const newState = state.updateIn(path, () => {
-    const list = state.getIn(path);
+function updateExpressionInList(state, key, value) {
+  const newState = state.update("expressions", () => {
+    const list = state.expressions;
     const index = list.findIndex(e => e.input == key);
     return list.update(index, () => value);
   });
+
   storeExpressions(newState);
   return newState;
 }
 
 function deleteExpression(state, input) {
   const index = getExpressions({ expressions: state }).findIndex(e => e.input == input);
   const newState = state.deleteIn(["expressions", index]);
   storeExpressions(newState);
   return newState;
 }
 
 const getExpressionsWrapper = state => state.expressions;
 
-const getExpressions = exports.getExpressions = (0, _reselect.createSelector)(getExpressionsWrapper, expressions => expressions.get("expressions"));
+const getExpressions = exports.getExpressions = (0, _reselect.createSelector)(getExpressionsWrapper, expressions => expressions.expressions);
 
 function getExpression(state, input) {
   return getExpressions(state).find(exp => exp.input == input);
 }
 
-const getExpressionError = exports.getExpressionError = (0, _reselect.createSelector)(getExpressionsWrapper, expressions => expressions.get("expressionError"));
+const getExpressionError = exports.getExpressionError = (0, _reselect.createSelector)(getExpressionsWrapper, expressions => expressions.expressionError);
 
 exports.default = update;
 
 /***/ }),
 
 /***/ 1418:
 /***/ (function(module, exports, __webpack_require__) {
 
@@ -8113,17 +8121,17 @@ function updateAllBreakpoints(state, act
   });
   return state;
 }
 
 function removeBreakpoint(state, action) {
   const { breakpoint } = action;
 
   const locationId = (0, _breakpoint.makePendingLocationId)(breakpoint.location);
-  const pendingBp = state.getIn(["pendingBreakpoints", locationId]);
+  const pendingBp = state.pendingBreakpoints.get(locationId);
 
   if (!pendingBp && action.status == "start") {
     return state.set("pendingBreakpoints", I.Map());
   }
 
   return state.deleteIn(["pendingBreakpoints", locationId]);
 }
 
@@ -8439,17 +8447,17 @@ function update(state = createFileSearch
 
     case "UPDATE_SEARCH_RESULTS":
       {
         return state.set("searchResults", action.results);
       }
 
     case "TOGGLE_FILE_SEARCH_MODIFIER":
       {
-        const actionVal = !state.getIn(["modifiers", action.modifier]);
+        const actionVal = !state.modifiers[action.modifier];
 
         if (action.modifier == "caseSensitive") {
           _prefs.prefs.fileSearchCaseSensitive = actionVal;
         }
 
         if (action.modifier == "wholeWord") {
           _prefs.prefs.fileSearchWholeWord = actionVal;
         }
@@ -8466,25 +8474,25 @@ function update(state = createFileSearch
         return state;
       }
   }
 }
 
 // NOTE: we'd like to have the app state fully typed
 // https://github.com/devtools-html/debugger.html/blob/master/src/reducers/sources.js#L179-L185
 function getFileSearchQuery(state) {
-  return state.fileSearch.get("query");
+  return state.fileSearch.query;
 }
 
 function getFileSearchModifiers(state) {
-  return state.fileSearch.get("modifiers");
+  return state.fileSearch.modifiers;
 }
 
 function getFileSearchResults(state) {
-  return state.fileSearch.get("searchResults");
+  return state.fileSearch.searchResults;
 }
 
 exports.default = update;
 
 /***/ }),
 
 /***/ 1423:
 /***/ (function(module, exports, __webpack_require__) {
@@ -10042,16 +10050,20 @@ exports.default = ResultList; /* This So
 
 ResultList.defaultProps = {
   size: "small",
   role: "listbox"
 };
 
 var _initialiseProps = function () {
   this.renderListItem = (item, index) => {
+    if (item.value === "/" && item.title === "") {
+      item.title = "(index)";
+    }
+
     const { selectItem, selected } = this.props;
     const props = {
       onClick: event => selectItem(event, item, index),
       key: `${item.id}${item.value}${index}`,
       ref: String(index),
       title: item.value,
       "aria-labelledby": `${item.id}-title`,
       "aria-describedby": `${item.id}-subtitle`,
@@ -25013,17 +25025,17 @@ function _interopRequireDefault(obj) { r
  * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
 
 class Tabs extends _react.PureComponent {
 
   constructor(props) {
     super(props);
 
     this.renderDropdownSource = source => {
-      const { selectSource } = this.props;
+      const { selectSpecificSource } = this.props;
       const filename = (0, _source.getFilename)(source.toJS());
 
       const onClick = () => selectSpecificSource(source.id);
       return _react2.default.createElement(
         "li",
         { key: source.id, onClick: onClick },
         _react2.default.createElement("img", { className: `dropdown-icon ${this.getIconClass(source)}` }),
         filename
@@ -30226,21 +30238,16 @@ function createLocation({
 /***/ (function(module, exports, __webpack_require__) {
 
 "use strict";
 
 
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
-
-var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; /* 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/>. */
-
 exports.getExtra = getExtra;
 exports.updatePreview = updatePreview;
 exports.setPreview = setPreview;
 exports.clearPreview = clearPreview;
 
 var _ast = __webpack_require__(1638);
 
 var _editor = __webpack_require__(1358);
@@ -30260,17 +30267,19 @@ var _expressions = __webpack_require__(1
 var _lodash = __webpack_require__(2);
 
 async function getReactProps(evaluate) {
   const reactDisplayName = await evaluate("this.hasOwnProperty('_reactInternalFiber') ? " + "this._reactInternalFiber.type.name : " + "this._reactInternalInstance.getName()");
 
   return {
     displayName: reactDisplayName.result
   };
-}
+} /* 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 getImmutableProps(expression, evaluate) {
   const immutableEntries = await evaluate((exp => `${exp}.toJS()`)(expression));
 
   const immutableType = await evaluate((exp => `${exp}.constructor.name`)(expression));
 
   return {
     type: immutableType.result,
@@ -30378,19 +30387,17 @@ function setPreview(expression, location
   return async ({ dispatch, getState, client, sourceMaps }) => {
     await dispatch({
       type: "SET_PREVIEW",
       [_promise.PROMISE]: async function () {
         const source = (0, _selectors.getSelectedSource)(getState());
 
         const sourceId = source.get("id");
         if (location && !(0, _devtoolsSourceMap.isGeneratedId)(sourceId)) {
-          const generatedLocation = await sourceMaps.getGeneratedLocation(_extends({}, location.start, { sourceId }), source.toJS());
-
-          expression = await (0, _expressions.getMappedExpression)({ sourceMaps, getState }, generatedLocation, expression);
+          expression = await dispatch((0, _expressions.getMappedExpression)(expression));
         }
 
         const selectedFrame = (0, _selectors.getSelectedFrame)(getState());
         if (!selectedFrame) {
           return;
         }
 
         const { result } = await client.evaluateInFrame(selectedFrame.id, expression);
@@ -31528,16 +31535,18 @@ var _extends = Object.assign || function
 /**
  * Redux actions for the sources state
  * @module actions/sources
  */
 
 exports.selectSourceURL = selectSourceURL;
 exports.selectSource = selectSource;
 exports.selectLocation = selectLocation;
+exports.selectSpecificLocation = selectSpecificLocation;
+exports.selectSpecificSource = selectSpecificSource;
 exports.jumpToMappedLocation = jumpToMappedLocation;
 exports.jumpToMappedSelectedLocation = jumpToMappedSelectedLocation;
 
 var _devtoolsSourceMap = __webpack_require__(1360);
 
 var _ast = __webpack_require__(1399);
 
 var _ui = __webpack_require__(1385);
@@ -31608,56 +31617,113 @@ function selectSource(sourceId) {
 function selectLocation(location) {
   return async ({ dispatch, getState, client }) => {
     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);
-    if (!source) {
+    const sourceRecord = (0, _selectors.getSource)(getState(), location.sourceId);
+    if (!sourceRecord) {
       // If there is no source we deselect the current selected source
       return dispatch({ type: "CLEAR_SELECTED_SOURCE" });
     }
 
     const activeSearch = (0, _selectors.getActiveSearch)(getState());
     if (activeSearch !== "file") {
       dispatch((0, _ui.closeActiveSearch)());
     }
 
-    dispatch((0, _tabs.addTab)(source.toJS(), 0));
-
+    const source = sourceRecord.toJS();
+
+    dispatch((0, _tabs.addTab)(source, 0));
     dispatch({
       type: "SELECT_SOURCE",
-      source: source.toJS(),
+      source,
       location
     });
 
-    await dispatch((0, _loadSourceText.loadSourceText)(source));
+    await dispatch((0, _loadSourceText.loadSourceText)(sourceRecord));
     const selectedSource = (0, _selectors.getSelectedSource)(getState());
     if (!selectedSource) {
       return;
     }
 
-    const sourceId = selectedSource.get("id");
+    const sourceId = selectedSource.id;
+
     if (_prefs.prefs.autoPrettyPrint && !(0, _selectors.getPrettySource)(getState(), sourceId) && (0, _source.shouldPrettyPrint)(selectedSource) && (0, _source.isMinified)(selectedSource)) {
       await dispatch((0, _prettyPrint.togglePrettyPrint)(sourceId));
       dispatch((0, _tabs.closeTab)(source.url));
     }
 
     dispatch((0, _ast.setSymbols)(sourceId));
     dispatch((0, _ast.setOutOfScopeLocations)());
   };
 }
 
 /**
  * @memberof actions/sources
  * @static
  */
+function selectSpecificLocation(location) {
+  return async ({ dispatch, getState, client }) => {
+    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 sourceRecord = (0, _selectors.getSource)(getState(), location.sourceId);
+    if (!sourceRecord) {
+      // If there is no source we deselect the current selected source
+      return dispatch({ type: "CLEAR_SELECTED_SOURCE" });
+    }
+
+    const activeSearch = (0, _selectors.getActiveSearch)(getState());
+    if (activeSearch !== "file") {
+      dispatch((0, _ui.closeActiveSearch)());
+    }
+
+    const source = sourceRecord.toJS();
+
+    dispatch((0, _tabs.addTab)(source, 0));
+    dispatch({
+      type: "SELECT_SOURCE",
+      source,
+      location
+    });
+
+    await dispatch((0, _loadSourceText.loadSourceText)(sourceRecord));
+    const selectedSource = (0, _selectors.getSelectedSource)(getState());
+    if (!selectedSource) {
+      return;
+    }
+
+    const sourceId = selectedSource.id;
+    dispatch((0, _ast.setSymbols)(sourceId));
+    dispatch((0, _ast.setOutOfScopeLocations)());
+  };
+}
+
+/**
+ * @memberof actions/sources
+ * @static
+ */
+function selectSpecificSource(sourceId) {
+  return async ({ dispatch }) => {
+    const location = (0, _location.createLocation)({ sourceId });
+    return await dispatch(selectSpecificLocation(location));
+  };
+}
+
+/**
+ * @memberof actions/sources
+ * @static
+ */
 function jumpToMappedLocation(location) {
   return async function ({ dispatch, getState, client, sourceMaps }) {
     if (!client) {
       return;
     }
 
     const source = (0, _selectors.getSource)(getState(), location.sourceId);
     let pairedLocation;
@@ -33687,17 +33753,17 @@ class Tab extends _react.PureComponent {
 
   isSourceSearchEnabled() {
     return this.props.activeSearch === "source";
   }
 
   render() {
     const {
       selectedSource,
-      selectSource,
+      selectSpecificSource,
       closeTab,
       source,
       sourceMetaData
     } = this.props;
     const src = source.toJS();
     const filename = (0, _source.getFilename)(src);
     const sourceId = source.id;
     const active = selectedSource && sourceId == selectedSource.get("id") && !this.isProjectSearchEnabled() && !this.isSourceSearchEnabled();
@@ -33713,17 +33779,17 @@ class Tab extends _react.PureComponent {
       e.preventDefault();
       e.stopPropagation();
 
       // Accommodate middle click to close tab
       if (e.button === 1) {
         return closeTab(source.url);
       }
 
-      return selectSource(sourceId);
+      return selectSpecificSource(sourceId);
     }
 
     const className = (0, _classnames2.default)("source-tab", {
       active,
       pretty: isPrettyCode
     });
 
     return _react2.default.createElement(
@@ -33855,18 +33921,16 @@ function updateTree({
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
 
 var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
 
 exports.setupHelper = setupHelper;
 
-var _redux = __webpack_require__(3593);
-
 var _timings = __webpack_require__(1657);
 
 var timings = _interopRequireWildcard(_timings);
 
 var _prefs = __webpack_require__(226);
 
 var _devtoolsConfig = __webpack_require__(1355);
 
@@ -33912,20 +33976,18 @@ function getCM() {
 function _formatPausePoints(dbg, url) {
   const source = dbg.helpers.findSource(url);
   const pausePoints = dbg.selectors.getPausePoints(source);
   console.log((0, _pausePoints.formatPausePoints)(source.text, pausePoints));
 }
 
 function setupHelper(obj) {
   const selectors = bindSelectors(obj);
-  const actions = (0, _redux.bindActionCreators)(obj.actions, obj.store.dispatch);
   const dbg = _extends({}, obj, {
     selectors,
-    actions,
     prefs: _prefs.prefs,
     features: _prefs.features,
     timings,
     getCM,
     helpers: {
       findSource: url => findSource(dbg, url),
       evaluate: (expression, cbk) => evaluate(dbg, expression, cbk),
       sendPacketToThread: (packet, cbk) => sendPacketToThread(dbg, packet, cbk),
--- a/devtools/client/debugger/new/panel.js
+++ b/devtools/client/debugger/new/panel.js
@@ -111,16 +111,20 @@ DebuggerPanel.prototype = {
 
     frames.forEach(frame => {
       frame.actor = frame.id;
     });
 
     return { frames, selected };
   },
 
+  getMappedExpression(expression) {
+    return this._actions.getMappedExpression(expression);
+  },
+
   isPaused() {
     return this._selectors.isPaused(this._getState());
   },
 
   selectSource(url, line) {
     this._actions.selectSourceURL(url, { location: { line } });
   },
 
--- a/devtools/client/debugger/new/parser-worker.js
+++ b/devtools/client/debugger/new/parser-worker.js
@@ -779,31 +779,33 @@ const {
 } = __webpack_require__(1389);
 
 const { workerUtils: { WorkerDispatcher } } = __webpack_require__(1363);
 
 const dispatcher = new WorkerDispatcher();
 
 const getOriginalURLs = dispatcher.task("getOriginalURLs");
 const getGeneratedLocation = dispatcher.task("getGeneratedLocation");
+const getAllGeneratedLocations = dispatcher.task("getAllGeneratedLocations");
 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");
 
 module.exports = {
   originalToGeneratedId,
   generatedToOriginalId,
   isGeneratedId,
   isOriginalId,
   hasMappedSource,
   getOriginalURLs,
   getGeneratedLocation,
+  getAllGeneratedLocations,
   getOriginalLocation,
   getLocationScopes,
   getOriginalSourceText,
   applySourceMap,
   clearSourceMaps,
   startSourceMapWorker: dispatcher.start.bind(dispatcher),
   stopSourceMapWorker: dispatcher.stop.bind(dispatcher)
 };
@@ -1155,16 +1157,17 @@ function trimUrlQuery(url) {
 
   return url.slice(0, q);
 }
 
 // Map suffix to content type.
 const contentMap = {
   "js": "text/javascript",
   "jsm": "text/javascript",
+  "mjs": "text/javascript",
   "ts": "text/typescript",
   "tsx": "text/typescript-jsx",
   "jsx": "text/jsx",
   "coffee": "text/coffeescript",
   "elm": "text/elm",
   "cljs": "text/x-clojure"
 };
 
@@ -21281,37 +21284,46 @@ function getFirstExpression(ast) {
   if (statements.length == 0) {
     return null;
   }
 
   return statements[0].expression;
 }
 
 function mapOriginalExpression(expression, mappings) {
+  let didReplace = false;
+
   const ast = (0, _ast.parseScript)(expression);
   t.traverse(ast, (node, ancestors) => {
     const parent = ancestors[ancestors.length - 1];
     if (!parent) {
       return;
     }
 
     const parentNode = parent.node;
     if (t.isIdentifier(node) && t.isReferenced(node, parentNode)) {
       if (mappings.hasOwnProperty(node.name)) {
         const mapping = mappings[node.name];
-        if (mapping) {
+        if (mapping && mapping !== node.name) {
           const mappingNode = getFirstExpression((0, _ast.parseScript)(mapping));
-
           replaceNode(ancestors, mappingNode);
+
+          didReplace = true;
         }
       }
     }
   });
 
-  return (0, _generator2.default)(ast, { concise: true }).code;
+  if (!didReplace) {
+    // Avoid the extra code generation work and also avoid potentially
+    // reformatting the user's code unnecessarily.
+    return expression;
+  }
+
+  return (0, _generator2.default)(ast).code;
 }
 
 /***/ }),
 
 /***/ 3624:
 /***/ (function(module, exports, __webpack_require__) {
 
 var baseIteratee = __webpack_require__(814),
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-babel-preview.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-babel-preview.js
@@ -80,42 +80,42 @@ add_task(async function() {
   await pushPref("devtools.debugger.features.map-scopes", true);
 
   const dbg = await initDebugger("doc-babel.html");
 
   await breakpointPreviews(dbg, "for-of", { line: 5, column: 4 }, [
     {
       line: 5,
       column: 7,
-      expression: "doThing;",
+      expression: "doThing",
       result: "doThing(arg)",
     },
     {
       line: 5,
       column: 12,
-      expression: "x;",
+      expression: "x",
       result: "1",
     },
     {
       line: 8,
       column: 16,
-      expression: "doThing;",
+      expression: "doThing",
       result: "doThing(arg)",
     },
   ]);
 
   await breakpointPreviews(dbg, "shadowed-vars", { line: 18, column: 6 }, [
     // These aren't what the user would expect, but we test them anyway since
     // they reflect what this actually returns. These shadowed bindings read
     // the binding closest to the current frame's scope even though their
     // actual value is different.
     {
       line: 2,
       column: 9,
-      expression: "aVar;",
+      expression: "aVar",
       result: '"var3"',
     },
     {
       line: 3,
       column: 9,
       expression: "_aLet2;",
       result: '"let3"',
     },
@@ -123,17 +123,17 @@ add_task(async function() {
       line: 4,
       column: 11,
       expression: "_aConst2;",
       result: '"const3"',
     },
     {
       line: 10,
       column: 11,
-      expression: "aVar;",
+      expression: "aVar",
       result: '"var3"',
     },
     {
       line: 11,
       column: 11,
       expression: "_aLet2;",
       result: '"let3"',
     },
@@ -143,17 +143,17 @@ add_task(async function() {
       expression: "_aConst2;",
       result: '"const3"',
     },
 
     // These actually result in the values the user would expect.
     {
       line: 14,
       column: 13,
-      expression: "aVar;",
+      expression: "aVar",
       result: '"var3"',
     },
     {
       line: 15,
       column: 13,
       expression: "_aLet2;",
       result: '"let3"',
     },
@@ -188,17 +188,17 @@ add_task(async function() {
       line: 25,
       column: 16,
       expression: "_mod4.original;",
       result: '"an-original"',
     },
     {
       line: 26,
       column: 16,
-      expression: "aNamespace;",
+      expression: "aNamespace",
       fields: [
         ['aNamed', 'a-named'],
         ['default', 'a-default'],
       ],
     },
     {
       line: 31,
       column: 20,
@@ -221,16 +221,16 @@ add_task(async function() {
       line: 34,
       column: 20,
       expression: "_mod9.original;",
       result: '"an-original2"',
     },
     {
       line: 35,
       column: 20,
-      expression: "aNamespace2;",
+      expression: "aNamespace2",
       fields: [
         ['aNamed', 'a-named2'],
         ['default', 'a-default2'],
       ],
     },
   ]);
 });