Bug 1483877 - Update Debugger Frontend v83. r=dwalsh
authorJason Laster <jason.laster.11@gmail.com>
Fri, 17 Aug 2018 07:28:00 -0400
changeset 487309 c06cdaa3d0aa7b339542d8c20fe77d4b9fca0574
parent 487308 22cb98ed738bcc1de2c1d04ee8837df80c05a193
child 487310 127d6ad1af5483d9f90e865d49c2ea11418196ae
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
bugs1483877
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 1483877 - Update Debugger Frontend v83. 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/src/actions/ui.js
devtools/client/debugger/new/src/components/PrimaryPanes/SourcesTreeItem.js
devtools/client/debugger/new/src/components/shared/ResultList.js
devtools/client/debugger/new/src/reducers/sources.js
devtools/client/debugger/new/src/reducers/ui.js
devtools/client/debugger/new/src/selectors/getRelativeSources.js
devtools/client/debugger/new/src/selectors/index.js
devtools/client/debugger/new/src/selectors/moz.build
devtools/client/debugger/new/src/utils/source.js
devtools/client/debugger/new/test/mochitest/browser_dbg-pause-points.js
devtools/client/locales/en-US/debugger.properties
devtools/client/shared/components/reps/reps.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 82
+Version 83
 
-Comparison: https://github.com/devtools-html/debugger.html/compare/release-81...release-82
+Comparison: https://github.com/devtools-html/debugger.html/compare/release-82...release-83
 
 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
@@ -1401,16 +1401,22 @@ html .toggle-button.end.vertical svg {
 .sources-list .tree img.arrow {
   margin-right: 5px;
 }
 
 .sources-list .tree .focused img.arrow {
   background-color: white;
 }
 
+.sources-list .tree .label .suffix {
+  font-style: italic;
+  font-size: 0.9em;
+  color: var(--theme-comment);
+}
+
 .sources-list .tree img.arrow.expanded {
   transform: rotate(0deg);
 }
 
 .theme-dark .source-list .tree .node.focused {
   background-color: var(--theme-tab-toolbar-background);
 }
 
--- a/devtools/client/debugger/new/dist/parser-worker.js
+++ b/devtools/client/debugger/new/dist/parser-worker.js
@@ -25254,29 +25254,24 @@ const isForStatement = node => t.isForSt
                                                                                     * 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 isControlFlow = node => isForStatement(node) || t.isWhileStatement(node) || t.isIfStatement(node) || t.isSwitchCase(node) || t.isSwitchStatement(node) || t.isTryStatement(node) || t.isWithStatement(node);
 
 const isAssignment = node => t.isVariableDeclarator(node) || t.isAssignmentExpression(node) || t.isAssignmentPattern(node);
 
 const isImport = node => t.isImport(node) || t.isImportDeclaration(node);
-const isReturn = node => t.isReturnStatement(node);
 const isCall = node => t.isCallExpression(node) || t.isJSXElement(node);
 
 const inStepExpression = parent => t.isArrayExpression(parent) || t.isObjectProperty(parent) || t.isCallExpression(parent) || t.isJSXElement(parent) || t.isSequenceExpression(parent);
 
 const inExpression = (parent, grandParent) => inStepExpression(parent) || t.isJSXAttribute(grandParent) || t.isTemplateLiteral(parent);
 
 const isExport = node => t.isExportNamedDeclaration(node) || t.isExportDefaultDeclaration(node);
 
-function getStartLine(node) {
-  return node.loc.start.line;
-}
-
 // Finds the first call item in a step expression so that we can step
 // to the beginning of the list and either step in or over. e.g. [], x(), { }
 function isFirstCall(node, parentNode, grandParentNode) {
   let children = [];
   if (t.isArrayExpression(parentNode)) {
     children = parentNode.elements;
   }
 
@@ -25290,54 +25285,31 @@ function isFirstCall(node, parentNode, g
 
   if (t.isCallExpression(parentNode)) {
     children = parentNode.arguments;
   }
 
   return children.find(child => isCall(child)) === node;
 }
 
-// Check to see if the node is a step expression and if any of its children
-// expressions include calls. e.g. [ a() ], { a: a() }
-function hasCall(node) {
-  let children = [];
-  if (t.isArrayExpression(node)) {
-    children = node.elements;
-  }
-
-  if (t.isObjectExpression(node)) {
-    children = node.properties.map(({ value }) => value);
-  }
-
-  if (t.isSequenceExpression(node)) {
-    children = node.expressions;
-  }
-
-  if (t.isCallExpression(node)) {
-    children = node.arguments;
-  }
-
-  return children.find(child => isCall(child));
-}
-
 function getPausePoints(sourceId) {
   const state = {};
   (0, _ast.traverseAst)(sourceId, { enter: onEnter }, state);
   return state;
 }
 
 /* eslint-disable complexity */
 function onEnter(node, ancestors, state) {
   const parent = ancestors[ancestors.length - 1];
   const parentNode = parent && parent.node;
   const grandParent = ancestors[ancestors.length - 2];
   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)) {
+  if (isImport(node) || t.isClassDeclaration(node) || isExport(node) || t.isDebuggerStatement(node) || t.isThrowStatement(node) || t.isBreakStatement(node) || t.isContinueStatement(node) || t.isReturnStatement(node)) {
     return addStopPoint(state, startLocation);
   }
 
   if (isControlFlow(node)) {
     addStopPoint(state, startLocation);
 
     // We want to pause at tests so that we can pause at each iteration
     // e.g `while (i++ < 3) { }`
@@ -25347,30 +25319,22 @@ function onEnter(node, ancestors, state)
     }
     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;
+    // step at assignments unless the right side is a default assignment
+    // e.g. `( b = 2 ) => {}`
     const defaultAssignment = t.isFunction(parentNode) && parent.key === "params";
-    const includesCall = isCall(value) || hasCall(value);
-
-    return addPoint(state, startLocation, !includesCall && !defaultAssignment);
+
+    return addPoint(state, startLocation, !defaultAssignment);
   }
 
   if (isCall(node)) {
     let location = startLocation;
 
     // When functions are chained, we want to use the property location
     // e.g `foo().bar()`
     if (t.isMemberExpression(node.callee)) {
--- a/devtools/client/debugger/new/src/actions/ui.js
+++ b/devtools/client/debugger/new/src/actions/ui.js
@@ -19,18 +19,16 @@ exports.closeConditionalPanel = closeCon
 exports.clearProjectDirectoryRoot = clearProjectDirectoryRoot;
 exports.setProjectDirectoryRoot = setProjectDirectoryRoot;
 exports.setOrientation = setOrientation;
 
 var _selectors = require("../selectors/index");
 
 var _select = require("../actions/sources/select");
 
-var _ui = require("../reducers/ui");
-
 var _editor = require("../utils/editor/index");
 
 var _fileSearch = require("./file-search");
 
 /* 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 setContextMenu(type, event) {
@@ -219,17 +217,17 @@ function clearProjectDirectoryRoot() {
   };
 }
 
 function setProjectDirectoryRoot(newRoot) {
   return ({
     dispatch,
     getState
   }) => {
-    const curRoot = (0, _ui.getProjectDirectoryRoot)(getState());
+    const curRoot = (0, _selectors.getProjectDirectoryRoot)(getState());
 
     if (newRoot && curRoot) {
       const newRootArr = newRoot.replace(/\/+/g, "/").split("/");
       const curRootArr = curRoot.replace(/^\//, "").replace(/\/+/g, "/").split("/");
 
       if (newRootArr[0] !== curRootArr[0]) {
         newRootArr.splice(0, 2);
         newRoot = `${curRoot}/${newRootArr.join("/")}`;
--- a/devtools/client/debugger/new/src/components/PrimaryPanes/SourcesTreeItem.js
+++ b/devtools/client/debugger/new/src/components/PrimaryPanes/SourcesTreeItem.js
@@ -199,17 +199,17 @@ class SourceTreeItem extends _react.Comp
     const {
       item,
       depth,
       focused,
       hasMatchingGeneratedSource
     } = this.props;
     const suffix = hasMatchingGeneratedSource ? _react2.default.createElement("span", {
       className: "suffix"
-    }, "[sm]") : null;
+    }, L10N.getStr("sourceFooter.mappedSuffix")) : 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", {
--- a/devtools/client/debugger/new/src/components/shared/ResultList.js
+++ b/devtools/client/debugger/new/src/components/shared/ResultList.js
@@ -68,14 +68,14 @@ var _initialiseProps = function () {
         selected: index === selected
       })
     };
     return _react2.default.createElement("li", props, item.icon && _react2.default.createElement("div", null, _react2.default.createElement("img", {
       className: item.icon
     })), _react2.default.createElement("div", {
       id: `${item.id}-title`,
       className: "title"
-    }, item.title), _react2.default.createElement("div", {
+    }, item.title), item.subtitle != item.title ? _react2.default.createElement("div", {
       id: `${item.id}-subtitle`,
       className: "subtitle"
-    }, item.subtitle));
+    }, item.subtitle) : null);
   };
 };
\ No newline at end of file
--- a/devtools/client/debugger/new/src/reducers/sources.js
+++ b/devtools/client/debugger/new/src/reducers/sources.js
@@ -15,16 +15,18 @@ exports.getGeneratedSource = getGenerate
 exports.getPendingSelectedLocation = getPendingSelectedLocation;
 exports.getPrettySource = getPrettySource;
 exports.hasPrettySource = hasPrettySource;
 exports.getSourceByUrlInSources = getSourceByUrlInSources;
 exports.getSourceInSources = getSourceInSources;
 exports.getSources = getSources;
 exports.getUrls = getUrls;
 exports.getSourceList = getSourceList;
+exports.getProjectDirectoryRoot = getProjectDirectoryRoot;
+exports.getRelativeSources = getRelativeSources;
 
 var _reselect = require("devtools/client/debugger/new/dist/vendors").vendored["reselect"];
 
 var _source = require("../utils/source");
 
 var _devtoolsSourceMap = require("devtools/client/shared/source-map/index.js");
 
 var _prefs = require("../utils/prefs");
@@ -36,18 +38,20 @@ var _prefs = require("../utils/prefs");
 /**
  * Sources reducer
  * @module reducers/sources
  */
 function initialSourcesState() {
   return {
     sources: {},
     urls: {},
+    relativeSources: {},
     selectedLocation: undefined,
-    pendingSelectedLocation: _prefs.prefs.pendingSelectedLocation
+    pendingSelectedLocation: _prefs.prefs.pendingSelectedLocation,
+    projectDirectoryRoot: _prefs.prefs.projectDirectoryRoot
   };
 }
 
 function createSource(source) {
   return {
     id: undefined,
     url: undefined,
     sourceMapURL: undefined,
@@ -132,16 +136,19 @@ function update(state = initialSourcesSt
         return updateSource(state, {
           id,
           isBlackBoxed
         });
       }
 
       break;
 
+    case "SET_PROJECT_DIRECTORY_ROOT":
+      return recalculateRelativeSources(state, action.url);
+
     case "NAVIGATE":
       const source = state.selectedLocation && state.sources[state.selectedLocation.sourceId];
       const url = source && source.url;
 
       if (!url) {
         return initialSourcesState();
       }
 
@@ -195,25 +202,48 @@ function updateSource(state, source) {
 
   const existingSource = state.sources[source.id];
   const updatedSource = existingSource ? { ...existingSource,
     ...source
   } : createSource(source);
   const existingUrls = state.urls[source.url];
   const urls = existingUrls ? [...existingUrls, source.id] : [source.id];
   return { ...state,
+    relativeSources: updateRelativeSource({ ...state.relativeSources
+    }, updatedSource, state.projectDirectoryRoot),
     sources: { ...state.sources,
       [source.id]: updatedSource
     },
     urls: { ...state.urls,
       [source.url]: urls
     }
   };
 }
 
+function updateRelativeSource(relativeSources, source, root) {
+  if (!(0, _source.underRoot)(source, root)) {
+    return relativeSources;
+  }
+
+  const relativeSource = { ...source,
+    relativeUrl: (0, _source.getRelativeUrl)(source, root)
+  };
+  relativeSources[source.id] = relativeSource;
+  return relativeSources;
+}
+
+function recalculateRelativeSources(state, root) {
+  _prefs.prefs.projectDirectoryRoot = root;
+  const relativeSources = Object.values(state.sources).reduce((sources, source) => updateRelativeSource(sources, source, root), {});
+  return { ...state,
+    projectDirectoryRoot: root,
+    relativeSources
+  };
+}
+
 function updateBlackBoxList(url, isBlackBoxed) {
   const tabs = getBlackBoxList();
   const i = tabs.indexOf(url);
 
   if (i >= 0) {
     if (!isBlackBoxed) {
       tabs.splice(i, 1);
     }
@@ -318,9 +348,18 @@ const getSourceCount = exports.getSource
 const getSelectedLocation = exports.getSelectedLocation = (0, _reselect.createSelector)(getSourcesState, sources => sources.selectedLocation);
 const getSelectedSource = exports.getSelectedSource = (0, _reselect.createSelector)(getSelectedLocation, getSources, (selectedLocation, sources) => {
   if (!selectedLocation) {
     return;
   }
 
   return sources[selectedLocation.sourceId];
 });
+
+function getProjectDirectoryRoot(state) {
+  return state.sources.projectDirectoryRoot;
+}
+
+function getRelativeSources(state) {
+  return state.sources.relativeSources;
+}
+
 exports.default = update;
\ No newline at end of file
--- a/devtools/client/debugger/new/src/reducers/ui.js
+++ b/devtools/client/debugger/new/src/reducers/ui.js
@@ -7,17 +7,16 @@ exports.createUIState = undefined;
 exports.getSelectedPrimaryPaneTab = getSelectedPrimaryPaneTab;
 exports.getActiveSearch = getActiveSearch;
 exports.getContextMenu = getContextMenu;
 exports.getFrameworkGroupingState = getFrameworkGroupingState;
 exports.getShownSource = getShownSource;
 exports.getPaneCollapse = getPaneCollapse;
 exports.getHighlightedLineRange = getHighlightedLineRange;
 exports.getConditionalPanelLine = getConditionalPanelLine;
-exports.getProjectDirectoryRoot = getProjectDirectoryRoot;
 exports.getOrientation = getOrientation;
 
 var _makeRecord = require("../utils/makeRecord");
 
 var _makeRecord2 = _interopRequireDefault(_makeRecord);
 
 var _prefs = require("../utils/prefs");
 
@@ -31,17 +30,16 @@ function _interopRequireDefault(obj) { r
  * UI reducer
  * @module reducers/ui
  */
 const createUIState = exports.createUIState = (0, _makeRecord2.default)({
   selectedPrimaryPaneTab: "sources",
   activeSearch: null,
   contextMenu: {},
   shownSource: null,
-  projectDirectoryRoot: _prefs.prefs.projectDirectoryRoot,
   startPanelCollapsed: _prefs.prefs.startPanelCollapsed,
   endPanelCollapsed: _prefs.prefs.endPanelCollapsed,
   frameworkGroupingOn: _prefs.prefs.frameworkGroupingOn,
   highlightedLineRange: undefined,
   conditionalPanelLine: null,
   orientation: "horizontal"
 });
 
@@ -107,20 +105,16 @@ function update(state = createUIState(),
       return state.set("highlightedLineRange", {});
 
     case "OPEN_CONDITIONAL_PANEL":
       return state.set("conditionalPanelLine", action.line);
 
     case "CLOSE_CONDITIONAL_PANEL":
       return state.set("conditionalPanelLine", null);
 
-    case "SET_PROJECT_DIRECTORY_ROOT":
-      _prefs.prefs.projectDirectoryRoot = action.url;
-      return state.set("projectDirectoryRoot", action.url);
-
     case "SET_PRIMARY_PANE_TAB":
       return state.set("selectedPrimaryPaneTab", action.tabName);
 
     case "CLOSE_PROJECT_SEARCH":
       {
         if (state.get("activeSearch") === "project") {
           return state.set("activeSearch", null);
         }
@@ -173,17 +167,13 @@ function getPaneCollapse(state, position
 function getHighlightedLineRange(state) {
   return state.ui.get("highlightedLineRange");
 }
 
 function getConditionalPanelLine(state) {
   return state.ui.get("conditionalPanelLine");
 }
 
-function getProjectDirectoryRoot(state) {
-  return state.ui.get("projectDirectoryRoot");
-}
-
 function getOrientation(state) {
   return state.ui.get("orientation");
 }
 
 exports.default = update;
\ No newline at end of file
deleted file mode 100644
--- a/devtools/client/debugger/new/src/selectors/getRelativeSources.js
+++ /dev/null
@@ -1,52 +0,0 @@
-"use strict";
-
-Object.defineProperty(exports, "__esModule", {
-  value: true
-});
-exports.getRelativeSources = undefined;
-
-var _selectors = require("../selectors/index");
-
-var _lodash = require("devtools/client/shared/vendor/lodash");
-
-var _sourcesTree = require("../utils/sources-tree/index");
-
-var _reselect = require("devtools/client/debugger/new/dist/vendors").vendored["reselect"];
-
-/* 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 getRelativeUrl(source, root) {
-  const {
-    group,
-    path
-  } = (0, _sourcesTree.getURL)(source);
-
-  if (!root) {
-    return path;
-  } // + 1 removes the leading "/"
-
-
-  const url = group + path;
-  return url.slice(url.indexOf(root) + root.length + 1);
-}
-
-function formatSource(source, root) {
-  // NOTE: Flow https://github.com/facebook/flow/issues/6342 issue
-  return { ...source,
-    relativeUrl: getRelativeUrl(source, root)
-  };
-}
-
-function underRoot(source, root) {
-  return source.url && source.url.includes(root);
-}
-/*
- * Gets the sources that are below a project root
- */
-
-
-const getRelativeSources = exports.getRelativeSources = (0, _reselect.createSelector)(_selectors.getSources, _selectors.getProjectDirectoryRoot, (sources, root) => {
-  const relativeSources = (0, _lodash.chain)(sources).pickBy(source => underRoot(source, root)).mapValues(source => formatSource(source, root)).value();
-  return relativeSources;
-});
\ No newline at end of file
--- a/devtools/client/debugger/new/src/selectors/index.js
+++ b/devtools/client/debugger/new/src/selectors/index.js
@@ -257,25 +257,16 @@ var _visibleSelectedFrame = require("./v
 
 Object.defineProperty(exports, "getVisibleSelectedFrame", {
   enumerable: true,
   get: function () {
     return _visibleSelectedFrame.getVisibleSelectedFrame;
   }
 });
 
-var _getRelativeSources = require("./getRelativeSources");
-
-Object.defineProperty(exports, "getRelativeSources", {
-  enumerable: true,
-  get: function () {
-    return _getRelativeSources.getRelativeSources;
-  }
-});
-
 var _breakpointSources = require("./breakpointSources");
 
 Object.defineProperty(exports, "getBreakpointSources", {
   enumerable: true,
   get: function () {
     return _breakpointSources.getBreakpointSources;
   }
 });
\ No newline at end of file
--- a/devtools/client/debugger/new/src/selectors/moz.build
+++ b/devtools/client/debugger/new/src/selectors/moz.build
@@ -6,15 +6,14 @@
 DIRS += [
 
 ]
 
 DevToolsModules(
     'breakpointAtLocation.js',
     'breakpointSources.js',
     'getCallStackFrames.js',
-    'getRelativeSources.js',
     'inComponent.js',
     'index.js',
     'isSelectedFrameVisible.js',
     'visibleBreakpoints.js',
     'visibleSelectedFrame.js',
 )
--- a/devtools/client/debugger/new/src/utils/source.js
+++ b/devtools/client/debugger/new/src/utils/source.js
@@ -27,16 +27,18 @@ exports.getDisplayPath = getDisplayPath;
 exports.getFileURL = getFileURL;
 exports.getSourcePath = getSourcePath;
 exports.getSourceLineCount = getSourceLineCount;
 exports.getMode = getMode;
 exports.isLoaded = isLoaded;
 exports.isLoading = isLoading;
 exports.getTextAtPosition = getTextAtPosition;
 exports.getSourceClassnames = getSourceClassnames;
+exports.getRelativeUrl = getRelativeUrl;
+exports.underRoot = underRoot;
 
 var _devtoolsSourceMap = require("devtools/client/shared/source-map/index.js");
 
 var _devtoolsModules = require("devtools/client/debugger/new/dist/vendors").vendored["devtools-modules"];
 
 var _utils = require("./utils");
 
 var _text = require("../utils/text");
@@ -492,9 +494,28 @@ function getSourceClassnames(source, sou
     return "prettyPrint";
   }
 
   if (source.isBlackBoxed) {
     return "blackBox";
   }
 
   return sourceTypes[(0, _sourcesTree.getFileExtension)(source)] || defaultClassName;
+}
+
+function getRelativeUrl(source, root) {
+  const {
+    group,
+    path
+  } = (0, _sourcesTree.getURL)(source);
+
+  if (!root) {
+    return path;
+  } // + 1 removes the leading "/"
+
+
+  const url = group + path;
+  return url.slice(url.indexOf(root) + root.length + 1);
+}
+
+function underRoot(source, root) {
+  return source.url && source.url.includes(root);
 }
\ No newline at end of file
--- a/devtools/client/debugger/new/test/mochitest/browser_dbg-pause-points.js
+++ b/devtools/client/debugger/new/test/mochitest/browser_dbg-pause-points.js
@@ -41,18 +41,19 @@ add_task(async function test() {
   await testCase(dbg, {
     name: "expressions",
     count: 4,
     steps: [[40,2], [41,2], [41,8], [42,8], [43,0]]
   });
 
   await testCase(dbg, {
     name: "sequences",
-    count: 4,
-    steps: [[23,2], [25,8], [31,4], [34,2], [37,0]]
+    count: 5,
+    steps: [[23,2], [25,8], [29,8], [31,4], [34,2], [37,0]]
+
   });
 
   await testCase(dbg, {
     name: "flow",
     count: 8,
     steps: [[16,2], [17,12], [18,6], [19,2], [19,8], [19,17], [19,8], [19,17], [19,8]]
   });
 });
--- a/devtools/client/locales/en-US/debugger.properties
+++ b/devtools/client/locales/en-US/debugger.properties
@@ -544,16 +544,20 @@ sourceFooter.blackboxed=Blackboxed sourc
 # LOCALIZATION NOTE (sourceFooter.mappedSource): Text associated
 # with a mapped source. %S is replaced by the source map origin.
 sourceFooter.mappedSource=(From %S)
 
 # LOCALIZATION NOTE (sourceFooter.mappedSourceTooltip): Tooltip text associated
 # with a mapped source. %S is replaced by the source map origin.
 sourceFooter.mappedSourceTooltip=(Source mapped from %S)
 
+# LOCALIZATION NOTE (sourceFooter.mappedSuffix): Text associated
+# with a mapped source.  Displays next to URLs in tree and tabs.
+sourceFooter.mappedSuffix=(mapped)
+
 # LOCALIZATION NOTE (sourceFooter.codeCoverage): Text associated
 # with a code coverage button
 sourceFooter.codeCoverage=Code coverage
 
 # LOCALIZATION NOTE (sourceTabs.closeTabButtonTooltip): The tooltip that is displayed
 # for close tab button in source tabs.
 sourceTabs.closeTabButtonTooltip=Close tab
 
--- a/devtools/client/shared/components/reps/reps.js
+++ b/devtools/client/shared/components/reps/reps.js
@@ -2908,21 +2908,21 @@ if (typeof window === "object") {
   WINDOW_PROPERTIES = Object.getOwnPropertyNames(window);
 }
 
 function getType(item) {
   return item.type;
 }
 
 function getValue(item) {
-  if (item && item.contents && item.contents.hasOwnProperty("value")) {
+  if (nodeHasValue(item)) {
     return item.contents.value;
   }
 
-  if (item && item.contents && item.contents.hasOwnProperty("getterValue")) {
+  if (nodeHasGetterValue(item)) {
     return item.contents.getterValue;
   }
 
   if (nodeHasAccessors(item)) {
     return item.contents;
   }
 
   return undefined;
@@ -2939,16 +2939,24 @@ function nodeIsEntries(item) {
 function nodeIsMapEntry(item) {
   return GripMapEntryRep.supportsObject(getValue(item));
 }
 
 function nodeHasChildren(item) {
   return Array.isArray(item.contents);
 }
 
+function nodeHasValue(item) {
+  return item && item.contents && item.contents.hasOwnProperty("value");
+}
+
+function nodeHasGetterValue(item) {
+  return item && item.contents && item.contents.hasOwnProperty("getterValue");
+}
+
 function nodeIsObject(item) {
   const value = getValue(item);
   return value && value.type === "object";
 }
 
 function nodeIsArrayLike(item) {
   const value = getValue(item);
   return GripArrayRep.supportsObject(value) || ArrayRep.supportsObject(value);
@@ -3386,28 +3394,25 @@ function makeNodesForProperties(objProps
   if (prototype && prototype.type !== "null") {
     nodes.push(makeNodeForPrototype(objProps, parent));
   }
 
   return nodes;
 }
 
 function setNodeFullText(loadedProps, node) {
-  if (nodeHasFullText(node)) {
+  if (nodeHasFullText(node) || !nodeIsLongString(node)) {
     return node;
   }
 
-  if (nodeIsLongString(node)) {
-    const {fullText} = loadedProps;
-
-    if (node.contents.value) {
-      node.contents.value.fullText = fullText;
-    } else if (node.contents.getterValue) {
-      node.contents.getterValue.fullText = fullText;
-    }
+  const { fullText } = loadedProps;
+  if (nodeHasValue(node)) {
+    node.contents.value.fullText = fullText;
+  } else if (nodeHasGetterValue(node)) {
+    node.contents.getterValue.fullText = fullText;
   }
 
   return node;
 }
 
 function makeNodeForPrototype(objProps, parent) {
   const { prototype } = objProps || {};