Bug 1520957 - [release 119] Replace formatted breakpoint with generic Breakpoint type (#7730). r=dwalsh
☠☠ backed out by 5b1c54cbac38 ☠ ☠
authorJason Laster <jason.laster.11@gmail.com>
Fri, 18 Jan 2019 12:20:35 -0500
changeset 511685 452045302b9f13c72ebf6eef8a62bbb3ffe8bcc1
parent 511684 38d601fa5c4e02da82c567c309482b380f7c68f9
child 511686 d3c9d833d45a8ad506100245f401567899fdf302
push id10547
push userffxbld-merge
push dateMon, 21 Jan 2019 13:03:58 +0000
treeherdermozilla-beta@24ec1916bffe [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdwalsh
bugs1520957
milestone66.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 1520957 - [release 119] Replace formatted breakpoint with generic Breakpoint type (#7730). r=dwalsh
devtools/client/debugger/new/src/actions/breakpoints/tests/__snapshots__/breakpoints.spec.js.snap
devtools/client/debugger/new/src/components/SecondaryPanes/Breakpoints/Breakpoint.js
devtools/client/debugger/new/src/components/SecondaryPanes/Breakpoints/BreakpointsContextMenu.js
devtools/client/debugger/new/src/components/SecondaryPanes/Breakpoints/index.js
devtools/client/debugger/new/src/components/SecondaryPanes/Breakpoints/tests/Breakpoint.spec.js
devtools/client/debugger/new/src/components/SecondaryPanes/Breakpoints/tests/__snapshots__/Breakpoint.spec.js.snap
devtools/client/debugger/new/src/selectors/breakpointSources.js
devtools/client/debugger/new/src/utils/breakpoint/index.js
devtools/client/debugger/new/src/utils/breakpoint/tests/index.spec.js
--- a/devtools/client/debugger/new/src/actions/breakpoints/tests/__snapshots__/breakpoints.spec.js.snap
+++ b/devtools/client/debugger/new/src/actions/breakpoints/tests/__snapshots__/breakpoints.spec.js.snap
@@ -32,25 +32,42 @@ Object {
 }
 `;
 
 exports[`breakpoints should add a breakpoint 1`] = `
 Array [
   Object {
     "breakpoints": Array [
       Object {
+        "astLocation": Object {
+          "index": 0,
+          "name": undefined,
+          "offset": Object {
+            "line": 2,
+            "sourceId": "a",
+            "sourceUrl": "http://localhost:8000/examples/a",
+          },
+        },
         "condition": null,
         "disabled": false,
-        "id": "hi",
-        "log": false,
-        "selectedLocation": Object {
+        "generatedLocation": Object {
           "line": 2,
           "sourceId": "a",
           "sourceUrl": "http://localhost:8000/examples/a",
         },
+        "hidden": false,
+        "id": "hi",
+        "loading": false,
+        "location": Object {
+          "line": 2,
+          "sourceId": "a",
+          "sourceUrl": "http://localhost:8000/examples/a",
+        },
+        "log": false,
+        "originalText": "return a",
         "text": "return a",
       },
     ],
     "source": Object {
       "contentType": "text/javascript",
       "error": undefined,
       "id": "a",
       "isBlackBoxed": false,
@@ -102,25 +119,42 @@ Object {
 }
 `;
 
 exports[`breakpoints should show a disabled breakpoint that does not have text 1`] = `
 Array [
   Object {
     "breakpoints": Array [
       Object {
+        "astLocation": Object {
+          "index": 0,
+          "name": undefined,
+          "offset": Object {
+            "line": 5,
+            "sourceId": "a",
+            "sourceUrl": "http://localhost:8000/examples/a",
+          },
+        },
         "condition": null,
         "disabled": true,
-        "id": "hi",
-        "log": false,
-        "selectedLocation": Object {
+        "generatedLocation": Object {
           "line": 5,
           "sourceId": "a",
           "sourceUrl": "http://localhost:8000/examples/a",
         },
+        "hidden": false,
+        "id": "hi",
+        "loading": false,
+        "location": Object {
+          "line": 5,
+          "sourceId": "a",
+          "sourceUrl": "http://localhost:8000/examples/a",
+        },
+        "log": false,
+        "originalText": "",
         "text": "",
       },
     ],
     "source": Object {
       "contentType": "text/javascript",
       "error": undefined,
       "id": "a",
       "isBlackBoxed": false,
--- a/devtools/client/debugger/new/src/components/SecondaryPanes/Breakpoints/Breakpoint.js
+++ b/devtools/client/debugger/new/src/components/SecondaryPanes/Breakpoints/Breakpoint.js
@@ -3,29 +3,29 @@
  * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
 
 // @flow
 
 import React, { PureComponent } from "react";
 import { connect } from "../../../utils/connect";
 import { createSelector } from "reselect";
 import classnames from "classnames";
-
 import actions from "../../../actions";
 
 import showContextMenu from "./BreakpointsContextMenu";
 import { CloseButton } from "../../shared/Button";
 
-import { getLocationWithoutColumn } from "../../../utils/breakpoint";
+import {
+  getLocationWithoutColumn,
+  getSelectedText
+} from "../../../utils/breakpoint";
 import { getSelectedLocation } from "../../../utils/source-maps";
 import { features } from "../../../utils/prefs";
 import { getEditor } from "../../../utils/editor";
 
-import type { FormattedBreakpoint } from "../../../selectors/breakpointSources";
-
 import type {
   Breakpoint as BreakpointType,
   Frame,
   Source,
   SourceLocation
 } from "../../../types";
 
 type FormattedFrame = Frame & {
@@ -34,18 +34,19 @@ type FormattedFrame = Frame & {
 
 import {
   getBreakpointsList,
   getSelectedFrame,
   getSelectedSource
 } from "../../../selectors";
 
 type Props = {
-  breakpoint: FormattedBreakpoint,
+  breakpoint: BreakpointType,
   breakpoints: BreakpointType[],
+  selectedSource: Source,
   source: Source,
   frame: FormattedFrame,
   enableBreakpoint: typeof actions.enableBreakpoint,
   removeBreakpoint: typeof actions.removeBreakpoint,
   removeBreakpoints: typeof actions.removeBreakpoints,
   removeAllBreakpoints: typeof actions.removeAllBreakpoints,
   disableBreakpoint: typeof actions.disableBreakpoint,
   setBreakpointCondition: typeof actions.setBreakpointCondition,
@@ -56,74 +57,75 @@ type Props = {
   selectSpecificLocation: typeof actions.selectSpecificLocation
 };
 
 class Breakpoint extends PureComponent<Props> {
   onContextMenu = e => {
     showContextMenu({ ...this.props, contextMenuEvent: e });
   };
 
+  get selectedLocation() {
+    const { breakpoint, selectedSource } = this.props;
+    return getSelectedLocation(breakpoint, selectedSource);
+  }
+
   onDoubleClick = () => {
     const { breakpoint, openConditionalPanel } = this.props;
     if (breakpoint.condition) {
-      openConditionalPanel(breakpoint.selectedLocation);
+      openConditionalPanel(this.selectedLocation);
     }
   };
 
-  selectBreakpoint = event => {
-    const { breakpoint, selectSpecificLocation } = this.props;
-
-    event.preventDefault();
-    selectSpecificLocation(breakpoint.selectedLocation);
+  selectBreakpoint = () => {
+    const { selectSpecificLocation } = this.props;
+    selectSpecificLocation(this.selectedLocation);
   };
 
   removeBreakpoint = event => {
-    const { breakpoint, removeBreakpoint } = this.props;
-
+    const { removeBreakpoint } = this.props;
     event.stopPropagation();
-    removeBreakpoint(breakpoint.selectedLocation);
+    removeBreakpoint(this.selectedLocation);
   };
 
   handleBreakpointCheckbox = () => {
     const { breakpoint, enableBreakpoint, disableBreakpoint } = this.props;
     if (breakpoint.disabled) {
-      enableBreakpoint(breakpoint.selectedLocation);
+      enableBreakpoint(this.selectedLocation);
     } else {
-      disableBreakpoint(breakpoint.selectedLocation);
+      disableBreakpoint(this.selectedLocation);
     }
   };
 
   isCurrentlyPausedAtBreakpoint() {
-    const { frame, breakpoint } = this.props;
+    const { frame } = this.props;
     if (!frame) {
       return false;
     }
 
-    const bpId = getLocationWithoutColumn(breakpoint.selectedLocation);
+    const bpId = getLocationWithoutColumn(this.selectedLocation);
     const frameId = getLocationWithoutColumn(frame.selectedLocation);
-
     return bpId == frameId;
   }
 
   getBreakpointLocation() {
-    const { breakpoint, source } = this.props;
-    const { column, line } = breakpoint.selectedLocation;
+    const { source } = this.props;
+    const { column, line } = this.selectedLocation;
 
     const isWasm = source && source.isWasm;
     const columnVal = features.columnBreakpoints && column ? `:${column}` : "";
     const bpLocation = isWasm
       ? `0x${line.toString(16).toUpperCase()}`
       : `${line}${columnVal}`;
 
     return bpLocation;
   }
 
   getBreakpointText() {
-    const { breakpoint } = this.props;
-    return breakpoint.condition || breakpoint.text;
+    const { breakpoint, selectedSource } = this.props;
+    return breakpoint.condition || getSelectedText(breakpoint, selectedSource);
   }
 
   highlightText() {
     const text = this.getBreakpointText() || "";
     const editor = getEditor();
 
     if (!editor.CodeMirror) {
       return { __html: text };
@@ -156,17 +158,16 @@ class Breakpoint extends PureComponent<P
           className="breakpoint-checkbox"
           checked={!breakpoint.disabled}
           onChange={this.handleBreakpointCheckbox}
           onClick={ev => ev.stopPropagation()}
         />
         <label
           htmlFor={breakpoint.id}
           className="breakpoint-label cm-s-mozilla"
-          onClick={this.selectBreakpoint}
           title={this.getBreakpointText()}
         >
           <span dangerouslySetInnerHTML={this.highlightText()} />
         </label>
         <div className="breakpoint-line-close">
           <div className="breakpoint-line">{this.getBreakpointLocation()}</div>
           <CloseButton
             handleClick={e => this.removeBreakpoint(e)}
--- a/devtools/client/debugger/new/src/components/SecondaryPanes/Breakpoints/BreakpointsContextMenu.js
+++ b/devtools/client/debugger/new/src/components/SecondaryPanes/Breakpoints/BreakpointsContextMenu.js
@@ -1,39 +1,41 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
 
 // @flow
 
 import { buildMenu, showMenu } from "devtools-contextmenu";
 
+import { getSelectedLocation } from "../../../utils/source-maps";
 import actions from "../../../actions";
-import type { Breakpoint } from "../../../types";
-import type { FormattedBreakpoint } from "../../../selectors/breakpointSources";
+import type { Breakpoint, Source } from "../../../types";
 
 type Props = {
-  breakpoint: FormattedBreakpoint,
+  breakpoint: Breakpoint,
   breakpoints: Breakpoint[],
+  selectedSource: Source,
   removeBreakpoint: typeof actions.removeBreakpoint,
   removeBreakpoints: typeof actions.removeBreakpoints,
   removeAllBreakpoints: typeof actions.removeAllBreakpoints,
   toggleBreakpoints: typeof actions.toggleBreakpoints,
   toggleAllBreakpoints: typeof actions.toggleAllBreakpoints,
   toggleDisabledBreakpoint: typeof actions.toggleDisabledBreakpoint,
   selectSpecificLocation: typeof actions.selectSpecificLocation,
   setBreakpointCondition: typeof actions.setBreakpointCondition,
   openConditionalPanel: typeof actions.openConditionalPanel,
   contextMenuEvent: SyntheticEvent<HTMLElement>
 };
 
 export default function showContextMenu(props: Props) {
   const {
     breakpoint,
     breakpoints,
+    selectedSource,
     removeBreakpoint,
     removeBreakpoints,
     removeAllBreakpoints,
     toggleBreakpoints,
     toggleAllBreakpoints,
     toggleDisabledBreakpoint,
     selectSpecificLocation,
     setBreakpointCondition,
@@ -90,32 +92,33 @@ export default function showContextMenu(
   );
   const editConditionKey = L10N.getStr(
     "breakpointMenuItem.editCondition2.accesskey"
   );
   const addConditionKey = L10N.getStr(
     "breakpointMenuItem.addCondition2.accesskey"
   );
 
+  const selectedLocation = getSelectedLocation(breakpoint, selectedSource);
   const otherBreakpoints = breakpoints.filter(b => b.id !== breakpoint.id);
   const enabledBreakpoints = breakpoints.filter(b => !b.disabled);
   const disabledBreakpoints = breakpoints.filter(b => b.disabled);
   const otherEnabledBreakpoints = breakpoints.filter(
     b => !b.disabled && b.id !== breakpoint.id
   );
   const otherDisabledBreakpoints = breakpoints.filter(
     b => b.disabled && b.id !== breakpoint.id
   );
 
   const deleteSelfItem = {
     id: "node-menu-delete-self",
     label: deleteSelfLabel,
     accesskey: deleteSelfKey,
     disabled: false,
-    click: () => removeBreakpoint(breakpoint.selectedLocation)
+    click: () => removeBreakpoint(selectedLocation)
   };
 
   const deleteAllItem = {
     id: "node-menu-delete-all",
     label: deleteAllLabel,
     accesskey: deleteAllKey,
     disabled: false,
     click: () => removeAllBreakpoints()
@@ -129,17 +132,17 @@ export default function showContextMenu(
     click: () => removeBreakpoints(otherBreakpoints)
   };
 
   const enableSelfItem = {
     id: "node-menu-enable-self",
     label: enableSelfLabel,
     accesskey: enableSelfKey,
     disabled: false,
-    click: () => toggleDisabledBreakpoint(breakpoint.selectedLocation.line)
+    click: () => toggleDisabledBreakpoint(selectedLocation.line)
   };
 
   const enableAllItem = {
     id: "node-menu-enable-all",
     label: enableAllLabel,
     accesskey: enableAllKey,
     disabled: false,
     click: () => toggleAllBreakpoints(false)
@@ -153,17 +156,17 @@ export default function showContextMenu(
     click: () => toggleBreakpoints(false, otherDisabledBreakpoints)
   };
 
   const disableSelfItem = {
     id: "node-menu-disable-self",
     label: disableSelfLabel,
     accesskey: disableSelfKey,
     disabled: false,
-    click: () => toggleDisabledBreakpoint(breakpoint.selectedLocation.line)
+    click: () => toggleDisabledBreakpoint(selectedLocation.line)
   };
 
   const disableAllItem = {
     id: "node-menu-disable-all",
     label: disableAllLabel,
     accesskey: disableAllKey,
     disabled: false,
     click: () => toggleAllBreakpoints(true)
@@ -176,36 +179,36 @@ export default function showContextMenu(
     click: () => toggleBreakpoints(true, otherEnabledBreakpoints)
   };
 
   const removeConditionItem = {
     id: "node-menu-remove-condition",
     label: removeConditionLabel,
     accesskey: removeConditionKey,
     disabled: false,
-    click: () => setBreakpointCondition(breakpoint.selectedLocation)
+    click: () => setBreakpointCondition(selectedLocation)
   };
 
   const addConditionItem = {
     id: "node-menu-add-condition",
     label: addConditionLabel,
     accesskey: addConditionKey,
     click: () => {
-      selectSpecificLocation(breakpoint.selectedLocation);
-      openConditionalPanel(breakpoint.selectedLocation);
+      selectSpecificLocation(selectedLocation);
+      openConditionalPanel(selectedLocation);
     }
   };
 
   const editConditionItem = {
     id: "node-menu-edit-condition",
     label: editConditionLabel,
     accesskey: editConditionKey,
     click: () => {
-      selectSpecificLocation(breakpoint.selectedLocation);
-      openConditionalPanel(breakpoint.selectedLocation);
+      selectSpecificLocation(selectedLocation);
+      openConditionalPanel(selectedLocation);
     }
   };
 
   const hideEnableSelfItem = !breakpoint.disabled;
   const hideEnableAllItem = disabledBreakpoints.length === 0;
   const hideEnableOthersItem = otherDisabledBreakpoints.length === 0;
   const hideDisableAllItem = enabledBreakpoints.length === 0;
   const hideDisableOthersItem = otherEnabledBreakpoints.length === 0;
--- a/devtools/client/debugger/new/src/components/SecondaryPanes/Breakpoints/index.js
+++ b/devtools/client/debugger/new/src/components/SecondaryPanes/Breakpoints/index.js
@@ -10,19 +10,21 @@ import { connect } from "../../../utils/
 
 import ExceptionOption from "./ExceptionOption";
 
 import Breakpoint from "./Breakpoint";
 import BreakpointHeading from "./BreakpointHeading";
 
 import actions from "../../../actions";
 import { getDisplayPath } from "../../../utils/source";
+import { getSelectedLocation } from "../../../utils/source-maps";
+
 import {
   makeLocationId,
-  sortFormattedBreakpoints
+  sortSelectedBreakpoints
 } from "../../../utils/breakpoint";
 
 import { getSelectedSource, getBreakpointSources } from "../../../selectors";
 
 import type { Source } from "../../../types";
 import type { BreakpointSources } from "../../../selectors/breakpointSources";
 
 import "./Breakpoints.css";
@@ -69,38 +71,44 @@ class Breakpoints extends Component<Prop
             }
           />
         )}
       </div>
     );
   }
 
   renderBreakpoints() {
-    const { breakpointSources } = this.props;
+    const { breakpointSources, selectedSource } = this.props;
     const sources = [
       ...breakpointSources.map(({ source, breakpoints }) => source)
     ];
 
     return [
       ...breakpointSources.map(({ source, breakpoints, i }) => {
         const path = getDisplayPath(source, sources);
-        const sortedBreakpoints = sortFormattedBreakpoints(breakpoints);
+        const sortedBreakpoints = sortSelectedBreakpoints(
+          breakpoints,
+          selectedSource
+        );
 
         return [
           <BreakpointHeading
             source={source}
             sources={sources}
             path={path}
             key={source.url}
           />,
           ...sortedBreakpoints.map(breakpoint => (
             <Breakpoint
               breakpoint={breakpoint}
               source={source}
-              key={makeLocationId(breakpoint.selectedLocation)}
+              selectedSource={selectedSource}
+              key={makeLocationId(
+                getSelectedLocation(breakpoint, selectedSource)
+              )}
             />
           ))
         ];
       })
     ];
   }
 
   render() {
--- a/devtools/client/debugger/new/src/components/SecondaryPanes/Breakpoints/tests/Breakpoint.spec.js
+++ b/devtools/client/debugger/new/src/components/SecondaryPanes/Breakpoints/tests/Breakpoint.spec.js
@@ -1,17 +1,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
 
 import React from "react";
 import { shallow } from "enzyme";
 
 import Breakpoint from "../Breakpoint";
-import { makeSource } from "../../../../utils/test-head";
+import { makeSource, makeOriginalSource } from "../../../../utils/test-head";
 
 describe("Breakpoint", () => {
   it("simple", () => {
     const { component } = render();
     expect(component).toMatchSnapshot();
   });
 
   it("disabled", () => {
@@ -26,46 +26,47 @@ describe("Breakpoint", () => {
       frame: { selectedLocation: generatedLocation }
     });
     expect(component).toMatchSnapshot();
   });
 
   it("paused at an original location", () => {
     const { component } = render({
       frame: { selectedLocation: location },
-      breakpoint: { selectedLocation: location }
+      breakpoint: { location },
+      selectedSource: makeOriginalSource("foo")
     });
 
     expect(component).toMatchSnapshot();
   });
 
   it("paused at a different", () => {
     const { component } = render({
       frame: { selectedLocation: { ...generatedLocation, line: 14 } }
     });
     expect(component).toMatchSnapshot();
   });
 });
 
 const generatedLocation = { sourceId: "foo", line: 53, column: 73 };
 const location = { sourceId: "foo/original", line: 5, column: 7 };
-const selectedLocation = generatedLocation;
 
 function render(overrides = {}) {
   const props = generateDefaults(overrides);
   const component = shallow(<Breakpoint.WrappedComponent {...props} />);
   const defaultState = component.state();
   const instance = component.instance();
 
   return { component, props, defaultState, instance };
 }
 
 function makeBreakpoint(overrides = {}) {
   return {
-    selectedLocation,
+    location,
+    generatedLocation,
     disabled: false,
     ...overrides
   };
 }
 
 function generateDefaults(overrides = { ...overrides, breakpoint: {} }) {
   const source = makeSource("foo");
   const breakpoint = makeBreakpoint(overrides.breakpoint);
--- a/devtools/client/debugger/new/src/components/SecondaryPanes/Breakpoints/tests/__snapshots__/Breakpoint.spec.js.snap
+++ b/devtools/client/debugger/new/src/components/SecondaryPanes/Breakpoints/tests/__snapshots__/Breakpoint.spec.js.snap
@@ -11,17 +11,16 @@ exports[`Breakpoint disabled 1`] = `
     checked={false}
     className="breakpoint-checkbox"
     onChange={[Function]}
     onClick={[Function]}
     type="checkbox"
   />
   <label
     className="breakpoint-label cm-s-mozilla"
-    onClick={[Function]}
   >
     <span
       dangerouslySetInnerHTML={
         Object {
           "__html": "",
         }
       }
     />
@@ -53,17 +52,16 @@ exports[`Breakpoint paused at a differen
     checked={true}
     className="breakpoint-checkbox"
     onChange={[Function]}
     onClick={[Function]}
     type="checkbox"
   />
   <label
     className="breakpoint-label cm-s-mozilla"
-    onClick={[Function]}
   >
     <span
       dangerouslySetInnerHTML={
         Object {
           "__html": "",
         }
       }
     />
@@ -95,17 +93,16 @@ exports[`Breakpoint paused at a generate
     checked={true}
     className="breakpoint-checkbox"
     onChange={[Function]}
     onClick={[Function]}
     type="checkbox"
   />
   <label
     className="breakpoint-label cm-s-mozilla"
-    onClick={[Function]}
   >
     <span
       dangerouslySetInnerHTML={
         Object {
           "__html": "",
         }
       }
     />
@@ -137,17 +134,16 @@ exports[`Breakpoint paused at an origina
     checked={true}
     className="breakpoint-checkbox"
     onChange={[Function]}
     onClick={[Function]}
     type="checkbox"
   />
   <label
     className="breakpoint-label cm-s-mozilla"
-    onClick={[Function]}
   >
     <span
       dangerouslySetInnerHTML={
         Object {
           "__html": "",
         }
       }
     />
@@ -179,17 +175,16 @@ exports[`Breakpoint simple 1`] = `
     checked={true}
     className="breakpoint-checkbox"
     onChange={[Function]}
     onClick={[Function]}
     type="checkbox"
   />
   <label
     className="breakpoint-label cm-s-mozilla"
-    onClick={[Function]}
   >
     <span
       dangerouslySetInnerHTML={
         Object {
           "__html": "",
         }
       }
     />
--- a/devtools/client/debugger/new/src/selectors/breakpointSources.js
+++ b/devtools/client/debugger/new/src/selectors/breakpointSources.js
@@ -6,75 +6,43 @@
 
 import { sortBy, uniq } from "lodash";
 import { createSelector } from "reselect";
 import {
   getSources,
   getBreakpointsList,
   getSelectedSource
 } from "../selectors";
-import { isGenerated, getFilename } from "../utils/source";
+import { getFilename } from "../utils/source";
 import { getSelectedLocation } from "../utils/source-maps";
 
-import type {
-  Source,
-  Breakpoint,
-  BreakpointId,
-  SourceLocation
-} from "../types";
+import type { Source, Breakpoint } from "../types";
 import type { Selector, SourcesMap } from "../reducers/types";
 
 export type BreakpointSources = Array<{
   source: Source,
-  breakpoints: FormattedBreakpoint[]
+  breakpoints: Breakpoint[]
 }>;
 
-export type FormattedBreakpoint = {|
-  id: BreakpointId,
-  condition: ?string,
-  log: boolean,
-  disabled: boolean,
-  text: string,
-  selectedLocation: SourceLocation
-|};
-
-function formatBreakpoint(
-  breakpoint: Breakpoint,
-  selectedSource: ?Source
-): FormattedBreakpoint {
-  const { id, condition, disabled, log } = breakpoint;
-
-  return {
-    id,
-    condition,
-    disabled,
-    log,
-    text:
-      selectedSource && isGenerated(selectedSource)
-        ? breakpoint.text
-        : breakpoint.originalText,
-    selectedLocation: getSelectedLocation(breakpoint, selectedSource)
-  };
-}
-
 function getBreakpointsForSource(
   source: Source,
   selectedSource: ?Source,
   breakpoints: Breakpoint[]
 ) {
   return breakpoints
     .sort((a, b) => a.location.line - b.location.line)
     .filter(
       bp =>
         !bp.hidden &&
         !bp.loading &&
         (bp.text || bp.originalText || bp.condition || bp.disabled)
     )
-    .map(bp => formatBreakpoint(bp, selectedSource))
-    .filter(bp => bp.selectedLocation.sourceId == source.id);
+    .filter(
+      bp => getSelectedLocation(bp, selectedSource).sourceId == source.id
+    );
 }
 
 function findBreakpointSources(
   sources: SourcesMap,
   breakpoints: Breakpoint[]
 ): Source[] {
   const sourceIds: string[] = uniq(breakpoints.map(bp => bp.location.sourceId));
 
--- a/devtools/client/debugger/new/src/utils/breakpoint/index.js
+++ b/devtools/client/debugger/new/src/utils/breakpoint/index.js
@@ -4,21 +4,23 @@
 
 // @flow
 
 import { sortBy } from "lodash";
 
 import { getBreakpoint } from "../../selectors";
 import assert from "../assert";
 import { features } from "../prefs";
+import { getSelectedLocation } from "../source-maps";
+import { isGenerated } from "../source";
 
 export { getASTLocation, findScopeByName } from "./astBreakpointLocation";
 
-import type { FormattedBreakpoint } from "../../selectors/breakpointSources";
 import type {
+  Source,
   SourceLocation,
   PendingLocation,
   Breakpoint,
   PendingBreakpoint
 } from "../../types";
 
 import type { State } from "../../reducers/types";
 
@@ -188,18 +190,37 @@ export function createPendingBreakpoint(
     log: bp.log,
     disabled: bp.disabled,
     location: pendingLocation,
     astLocation: bp.astLocation,
     generatedLocation: pendingGeneratedLocation
   };
 }
 
-export function sortFormattedBreakpoints(breakpoints: FormattedBreakpoint[]) {
-  return _sortBreakpoints(breakpoints, "selectedLocation");
+export function getSelectedText(
+  breakpoint: Breakpoint,
+  selectedSource: Source
+) {
+  return selectedSource && isGenerated(selectedSource)
+    ? breakpoint.text
+    : breakpoint.originalText;
+}
+
+export function sortSelectedBreakpoints(
+  breakpoints: Breakpoint[],
+  selectedSource: Source
+): Breakpoint[] {
+  return sortBy(breakpoints, [
+    // Priority: line number, undefined column, column number
+    bp => getSelectedLocation(bp, selectedSource).line,
+    bp => {
+      const location = getSelectedLocation(bp, selectedSource);
+      return location.column === undefined || location.column;
+    }
+  ]);
 }
 
 export function sortBreakpoints(breakpoints: Breakpoint[]) {
   return _sortBreakpoints(breakpoints, "location");
 }
 
 function _sortBreakpoints(
   breakpoints: Array<Object>,
--- a/devtools/client/debugger/new/src/utils/breakpoint/tests/index.spec.js
+++ b/devtools/client/debugger/new/src/utils/breakpoint/tests/index.spec.js
@@ -1,29 +1,32 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
 
-import { sortBreakpoints, sortFormattedBreakpoints } from "../index";
+import { sortBreakpoints, sortSelectedBreakpoints } from "../index";
 
 describe("breakpoint sorting", () => {
-  it("sortFormattedBreakpoints should sort by line number and column ", () => {
-    const sorted = sortFormattedBreakpoints([
-      { selectedLocation: { line: 100, column: 2 } },
-      { selectedLocation: { line: 9, column: 2 } },
-      { selectedLocation: { line: 2, column: undefined } },
-      { selectedLocation: { line: 2, column: 7 } }
-    ]);
+  it("sortSelectedBreakpoints should sort by line number and column ", () => {
+    const sorted = sortSelectedBreakpoints(
+      [
+        { location: { line: 100, column: 2 } },
+        { location: { line: 9, column: 2 } },
+        { location: { line: 2, column: undefined } },
+        { location: { line: 2, column: 7 } }
+      ],
+      { id: "foo/originalSource-1" }
+    );
 
-    expect(sorted[0].selectedLocation.line).toBe(2);
-    expect(sorted[0].selectedLocation.column).toBe(undefined);
-    expect(sorted[1].selectedLocation.line).toBe(2);
-    expect(sorted[1].selectedLocation.column).toBe(7);
-    expect(sorted[2].selectedLocation.line).toBe(9);
-    expect(sorted[3].selectedLocation.line).toBe(100);
+    expect(sorted[0].location.line).toBe(2);
+    expect(sorted[0].location.column).toBe(undefined);
+    expect(sorted[1].location.line).toBe(2);
+    expect(sorted[1].location.column).toBe(7);
+    expect(sorted[2].location.line).toBe(9);
+    expect(sorted[3].location.line).toBe(100);
   });
 
   it("sortBreakpoints should sort by line number and column ", () => {
     const sorted = sortBreakpoints([
       { location: { line: 100, column: 2 } },
       { location: { line: 9, column: 2 } },
       { location: { line: 2, column: undefined } },
       { location: { line: 2, column: 7 } }