<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[243727] trunk/Source/WebInspectorUI</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/243727">243727</a></dd>
<dt>Author</dt> <dd>drousso@apple.com</dd>
<dt>Date</dt> <dd>2019-04-01 17:20:11 -0700 (Mon, 01 Apr 2019)</dd>
</dl>

<h3>Log Message</h3>
<pre>Web Inspector: Debugger: modernize serialization of breakpoints and the maps that hold them
https://bugs.webkit.org/show_bug.cgi?id=196230
<rdar://problem/49236485>

Reviewed by Joseph Pecoraro.

* UserInterface/Controllers/DebuggerManager.js:
(WI.DebuggerManager):
(WI.DebuggerManager.prototype.breakpointsForSourceCode):
(WI.DebuggerManager.prototype.addBreakpoint):
(WI.DebuggerManager.prototype.removeBreakpoint):
(WI.DebuggerManager.prototype._setBreakpoint):
(WI.DebuggerManager.prototype._setBreakpoint.didSetBreakpoint):

* UserInterface/Models/Breakpoint.js:
(WI.Breakpoint):
(WI.Breakpoint.fromJSON): Added.
(WI.Breakpoint.prototype.toJSON):
(WI.Breakpoint.prototype.set resolved):
(WI.Breakpoint.prototype.recreateAction):
(WI.Breakpoint.prototype.saveIdentityToCookie):
(WI.Breakpoint.prototype._isSpecial): Added.
(WI.Breakpoint.set resolved.isSpecialBreakpoint): Deleted.
(WI.Breakpoint.serializeOptions): Deleted.

* UserInterface/Models/BreakpointAction.js:
(WI.BreakpointAction):
(WI.BreakpointAction.fromJSON): Added.
(WI.BreakpointAction.prototype.toProtocol): Added.

* UserInterface/Views/DebuggerSidebarPanel.js:
(WI.DebuggerSidebarPanel.prototype._addBreakpointsForSourceCode):

* UserInterface/Views/SourceCodeTextEditor.js:
(WI.SourceCodeTextEditor.prototype._prepareEditorForInitialContent):
(WI.SourceCodeTextEditor.prototype._breakpointsEnabledDidChange):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebInspectorUIChangeLog">trunk/Source/WebInspectorUI/ChangeLog</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceControllersDebuggerManagerjs">trunk/Source/WebInspectorUI/UserInterface/Controllers/DebuggerManager.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceModelsBreakpointjs">trunk/Source/WebInspectorUI/UserInterface/Models/Breakpoint.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceModelsBreakpointActionjs">trunk/Source/WebInspectorUI/UserInterface/Models/BreakpointAction.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceViewsDebuggerSidebarPaneljs">trunk/Source/WebInspectorUI/UserInterface/Views/DebuggerSidebarPanel.js</a></li>
<li><a href="#trunkSourceWebInspectorUIUserInterfaceViewsSourceCodeTextEditorjs">trunk/Source/WebInspectorUI/UserInterface/Views/SourceCodeTextEditor.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebInspectorUIChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/ChangeLog (243726 => 243727)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/ChangeLog    2019-04-02 00:01:05 UTC (rev 243726)
+++ trunk/Source/WebInspectorUI/ChangeLog       2019-04-02 00:20:11 UTC (rev 243727)
</span><span class="lines">@@ -1,5 +1,44 @@
</span><span class="cx"> 2019-04-01  Devin Rousso  <drousso@apple.com>
</span><span class="cx"> 
</span><ins>+        Web Inspector: Debugger: modernize serialization of breakpoints and the maps that hold them
+        https://bugs.webkit.org/show_bug.cgi?id=196230
+        <rdar://problem/49236485>
+
+        Reviewed by Joseph Pecoraro.
+
+        * UserInterface/Controllers/DebuggerManager.js:
+        (WI.DebuggerManager):
+        (WI.DebuggerManager.prototype.breakpointsForSourceCode):
+        (WI.DebuggerManager.prototype.addBreakpoint):
+        (WI.DebuggerManager.prototype.removeBreakpoint):
+        (WI.DebuggerManager.prototype._setBreakpoint):
+        (WI.DebuggerManager.prototype._setBreakpoint.didSetBreakpoint):
+
+        * UserInterface/Models/Breakpoint.js:
+        (WI.Breakpoint):
+        (WI.Breakpoint.fromJSON): Added.
+        (WI.Breakpoint.prototype.toJSON):
+        (WI.Breakpoint.prototype.set resolved):
+        (WI.Breakpoint.prototype.recreateAction):
+        (WI.Breakpoint.prototype.saveIdentityToCookie):
+        (WI.Breakpoint.prototype._isSpecial): Added.
+        (WI.Breakpoint.set resolved.isSpecialBreakpoint): Deleted.
+        (WI.Breakpoint.serializeOptions): Deleted.
+
+        * UserInterface/Models/BreakpointAction.js:
+        (WI.BreakpointAction):
+        (WI.BreakpointAction.fromJSON): Added.
+        (WI.BreakpointAction.prototype.toProtocol): Added.
+
+        * UserInterface/Views/DebuggerSidebarPanel.js:
+        (WI.DebuggerSidebarPanel.prototype._addBreakpointsForSourceCode):
+
+        * UserInterface/Views/SourceCodeTextEditor.js:
+        (WI.SourceCodeTextEditor.prototype._prepareEditorForInitialContent):
+        (WI.SourceCodeTextEditor.prototype._breakpointsEnabledDidChange):
+
+2019-04-01  Devin Rousso  <drousso@apple.com>
+
</ins><span class="cx">         Web Inspector: DOMDebugger: disabling a breakpoint for a specific event listener removes it from the UI
</span><span class="cx">         https://bugs.webkit.org/show_bug.cgi?id=196453
</span><span class="cx">         <rdar://problem/49489318>
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceControllersDebuggerManagerjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Controllers/DebuggerManager.js (243726 => 243727)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Controllers/DebuggerManager.js 2019-04-02 00:01:05 UTC (rev 243726)
+++ trunk/Source/WebInspectorUI/UserInterface/Controllers/DebuggerManager.js    2019-04-02 00:20:11 UTC (rev 243727)
</span><span class="lines">@@ -58,17 +58,24 @@
</span><span class="cx"> 
</span><span class="cx">         let specialBreakpointLocation = new WI.SourceCodeLocation(null, Infinity, Infinity);
</span><span class="cx"> 
</span><del>-        this._allExceptionsBreakpoint = new WI.Breakpoint(specialBreakpointLocation, !this._allExceptionsBreakpointEnabledSetting.value);
</del><ins>+        this._allExceptionsBreakpoint = new WI.Breakpoint(specialBreakpointLocation, {
+            disabled: !this._allExceptionsBreakpointEnabledSetting.value,
+        });
</ins><span class="cx">         this._allExceptionsBreakpoint.resolved = true;
</span><span class="cx"> 
</span><del>-        this._uncaughtExceptionsBreakpoint = new WI.Breakpoint(specialBreakpointLocation, !this._uncaughtExceptionsBreakpointEnabledSetting.value);
</del><ins>+        this._uncaughtExceptionsBreakpoint = new WI.Breakpoint(specialBreakpointLocation, {
+            disabled: !this._uncaughtExceptionsBreakpointEnabledSetting.value,
+        });
+        this._uncaughtExceptionsBreakpoint.resolved = true;
</ins><span class="cx"> 
</span><del>-        this._assertionFailuresBreakpoint = new WI.Breakpoint(specialBreakpointLocation, !this._assertionFailuresBreakpointEnabledSetting.value);
</del><ins>+        this._assertionFailuresBreakpoint = new WI.Breakpoint(specialBreakpointLocation, {
+            disabled: !this._assertionFailuresBreakpointEnabledSetting.value,
+        });
</ins><span class="cx">         this._assertionFailuresBreakpoint.resolved = true;
</span><span class="cx"> 
</span><span class="cx">         this._breakpoints = [];
</span><del>-        this._breakpointContentIdentifierMap = new Map;
-        this._breakpointScriptIdentifierMap = new Map;
</del><ins>+        this._breakpointContentIdentifierMap = new Multimap;
+        this._breakpointScriptIdentifierMap = new Multimap;
</ins><span class="cx">         this._breakpointIdMap = new Map;
</span><span class="cx"> 
</span><span class="cx">         this._breakOnExceptionsState = "none";
</span><span class="lines">@@ -103,7 +110,7 @@
</span><span class="cx">             let existingSerializedBreakpoints = WI.Setting.migrateValue("breakpoints");
</span><span class="cx">             if (existingSerializedBreakpoints) {
</span><span class="cx">                 for (let existingSerializedBreakpoint of existingSerializedBreakpoints)
</span><del>-                    await WI.objectStores.breakpoints.putObject(new WI.Breakpoint(existingSerializedBreakpoint));
</del><ins>+                    await WI.objectStores.breakpoints.putObject(WI.Breakpoint.fromJSON(existingSerializedBreakpoint));
</ins><span class="cx">             }
</span><span class="cx"> 
</span><span class="cx">             let serializedBreakpoints = await WI.objectStores.breakpoints.getAll();
</span><span class="lines">@@ -110,7 +117,7 @@
</span><span class="cx"> 
</span><span class="cx">             this._restoringBreakpoints = true;
</span><span class="cx">             for (let serializedBreakpoint of serializedBreakpoints) {
</span><del>-                let breakpoint = new WI.Breakpoint(serializedBreakpoint);
</del><ins>+                let breakpoint = WI.Breakpoint.fromJSON(serializedBreakpoint);
</ins><span class="cx"> 
</span><span class="cx">                 const key = null;
</span><span class="cx">                 WI.objectStores.breakpoints.associateObject(breakpoint, key, serializedBreakpoint);
</span><span class="lines">@@ -211,12 +218,8 @@
</span><span class="cx">     {
</span><span class="cx">         console.assert(sourceCode instanceof WI.Resource || sourceCode instanceof WI.Script);
</span><span class="cx"> 
</span><del>-        if (sourceCode instanceof WI.SourceMapResource) {
-            let originalSourceCodeBreakpoints = this.breakpointsForSourceCode(sourceCode.sourceMap.originalSourceCode);
-            return originalSourceCodeBreakpoints.filter(function(breakpoint) {
-                return breakpoint.sourceCodeLocation.displaySourceCode === sourceCode;
-            });
-        }
</del><ins>+        if (sourceCode instanceof WI.SourceMapResource)
+            return Array.from(this.breakpointsForSourceCode(sourceCode.sourceMap.originalSourceCode)).filter((breakpoint) => breakpoint.sourceCodeLocation.displaySourceCode === sourceCode);
</ins><span class="cx"> 
</span><span class="cx">         let contentIdentifierBreakpoints = this._breakpointContentIdentifierMap.get(sourceCode.contentIdentifier);
</span><span class="cx">         if (contentIdentifierBreakpoints) {
</span><span class="lines">@@ -480,23 +483,11 @@
</span><span class="cx">             return;
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        if (breakpoint.contentIdentifier) {
-            let contentIdentifierBreakpoints = this._breakpointContentIdentifierMap.get(breakpoint.contentIdentifier);
-            if (!contentIdentifierBreakpoints) {
-                contentIdentifierBreakpoints = [];
-                this._breakpointContentIdentifierMap.set(breakpoint.contentIdentifier, contentIdentifierBreakpoints);
-            }
-            contentIdentifierBreakpoints.push(breakpoint);
-        }
</del><ins>+        if (breakpoint.contentIdentifier)
+            this._breakpointContentIdentifierMap.add(breakpoint.contentIdentifier, breakpoint);
</ins><span class="cx"> 
</span><del>-        if (breakpoint.scriptIdentifier) {
-            let scriptIdentifierBreakpoints = this._breakpointScriptIdentifierMap.get(breakpoint.scriptIdentifier);
-            if (!scriptIdentifierBreakpoints) {
-                scriptIdentifierBreakpoints = [];
-                this._breakpointScriptIdentifierMap.set(breakpoint.scriptIdentifier, scriptIdentifierBreakpoints);
-            }
-            scriptIdentifierBreakpoints.push(breakpoint);
-        }
</del><ins>+        if (breakpoint.scriptIdentifier)
+            this._breakpointScriptIdentifierMap.add(breakpoint.scriptIdentifier, breakpoint);
</ins><span class="cx"> 
</span><span class="cx">         this._breakpoints.push(breakpoint);
</span><span class="cx"> 
</span><span class="lines">@@ -537,23 +528,11 @@
</span><span class="cx">         if (breakpoint.identifier)
</span><span class="cx">             this._removeBreakpoint(breakpoint);
</span><span class="cx"> 
</span><del>-        if (breakpoint.contentIdentifier) {
-            let contentIdentifierBreakpoints = this._breakpointContentIdentifierMap.get(breakpoint.contentIdentifier);
-            if (contentIdentifierBreakpoints) {
-                contentIdentifierBreakpoints.remove(breakpoint);
-                if (!contentIdentifierBreakpoints.length)
-                    this._breakpointContentIdentifierMap.delete(breakpoint.contentIdentifier);
-            }
-        }
</del><ins>+        if (breakpoint.contentIdentifier)
+            this._breakpointContentIdentifierMap.delete(breakpoint.contentIdentifier, breakpoint);
</ins><span class="cx"> 
</span><del>-        if (breakpoint.scriptIdentifier) {
-            let scriptIdentifierBreakpoints = this._breakpointScriptIdentifierMap.get(breakpoint.scriptIdentifier);
-            if (scriptIdentifierBreakpoints) {
-                scriptIdentifierBreakpoints.remove(breakpoint);
-                if (!scriptIdentifierBreakpoints.length)
-                    this._breakpointScriptIdentifierMap.delete(breakpoint.scriptIdentifier);
-            }
-        }
</del><ins>+        if (breakpoint.scriptIdentifier)
+            this._breakpointScriptIdentifierMap.delete(breakpoint.scriptIdentifier, breakpoint);
</ins><span class="cx"> 
</span><span class="cx">         // Disable the breakpoint first, so removing actions doesn't re-add the breakpoint.
</span><span class="cx">         breakpoint.disabled = true;
</span><span class="lines">@@ -903,14 +882,13 @@
</span><span class="cx"> 
</span><span class="cx">     _debuggerBreakpointOptions(breakpoint)
</span><span class="cx">     {
</span><del>-        const templatePlaceholderRegex = /\$\{.*?\}/;
-
-        let options = breakpoint.serializeOptions();
-        options.actions = options.actions.filter((action) => {
</del><ins>+        let actions = breakpoint.actions;
+        actions = actions.map((action) => action.toProtocol());
+        actions = actions.filter((action) => {
</ins><span class="cx">             if (action.type !== WI.BreakpointAction.Type.Log)
</span><span class="cx">                 return true;
</span><span class="cx"> 
</span><del>-            if (!templatePlaceholderRegex.test(action.data))
</del><ins>+            if (!/\$\{.*?\}/.test(action.data))
</ins><span class="cx">                 return true;
</span><span class="cx"> 
</span><span class="cx">             let lexer = new WI.BreakpointLogMessageLexer;
</span><span class="lines">@@ -930,7 +908,13 @@
</span><span class="cx">             action.type = WI.BreakpointAction.Type.Evaluate;
</span><span class="cx">             return true;
</span><span class="cx">         });
</span><del>-        return options;
</del><ins>+
+        return {
+            condition: breakpoint.condition,
+            ignoreCount: breakpoint.ignoreCount,
+            autoContinue: breakpoint.autoContinue,
+            actions,
+        };
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     _setBreakpoint(breakpoint, specificTarget, callback)
</span><span class="lines">@@ -946,10 +930,11 @@
</span><span class="cx">             this.breakpointsEnabled = true;
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        function didSetBreakpoint(target, error, breakpointIdentifier, locations)
-        {
-            if (error)
</del><ins>+        function didSetBreakpoint(target, error, breakpointIdentifier, locations) {
+            if (error) {
+                WI.reportInternalError(error);
</ins><span class="cx">                 return;
</span><ins>+            }
</ins><span class="cx"> 
</span><span class="cx">             this._breakpointIdMap.set(breakpointIdentifier, breakpoint);
</span><span class="cx"> 
</span><span class="lines">@@ -995,7 +980,8 @@
</span><span class="cx">                 location: {scriptId: breakpoint.scriptIdentifier, lineNumber: breakpoint.sourceCodeLocation.lineNumber, columnNumber: breakpoint.sourceCodeLocation.columnNumber},
</span><span class="cx">                 options
</span><span class="cx">             }, didSetBreakpoint.bind(this, target), target.DebuggerAgent);
</span><del>-        }
</del><ins>+        } else
+            WI.reportInternalError("Unknown source for breakpoint.");
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     _removeBreakpoint(breakpoint, callback)
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceModelsBreakpointjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Models/Breakpoint.js (243726 => 243727)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Models/Breakpoint.js   2019-04-02 00:01:05 UTC (rev 243726)
+++ trunk/Source/WebInspectorUI/UserInterface/Models/Breakpoint.js      2019-04-02 00:20:11 UTC (rev 243727)
</span><span class="lines">@@ -25,78 +25,91 @@
</span><span class="cx"> 
</span><span class="cx"> WI.Breakpoint = class Breakpoint extends WI.Object
</span><span class="cx"> {
</span><del>-    constructor(sourceCodeLocationOrInfo, disabled, condition)
</del><ins>+    constructor(sourceCodeLocation, {contentIdentifier, disabled, condition, ignoreCount, autoContinue} = {})
</ins><span class="cx">     {
</span><ins>+        console.assert(sourceCodeLocation instanceof WI.SourceCodeLocation);
+        console.assert(!contentIdentifier || typeof contentIdentifier === "string");
+        console.assert(!disabled || typeof disabled === "boolean");
+        console.assert(!condition || typeof condition === "string");
+        console.assert(!ignoreCount || !isNaN(ignoreCount));
+        console.assert(!autoContinue || typeof autoContinue === "boolean");
+
</ins><span class="cx">         super();
</span><span class="cx"> 
</span><del>-        if (sourceCodeLocationOrInfo instanceof WI.SourceCodeLocation) {
-            var sourceCode = sourceCodeLocationOrInfo.sourceCode;
-            var contentIdentifier = sourceCode ? sourceCode.contentIdentifier : null;
-            var scriptIdentifier = sourceCode instanceof WI.Script ? sourceCode.id : null;
-            var target = sourceCode instanceof WI.Script ? sourceCode.target : null;
-            var location = sourceCodeLocationOrInfo;
-        } else if (sourceCodeLocationOrInfo && typeof sourceCodeLocationOrInfo === "object") {
-            // The 'url' fallback is for transitioning from older frontends and should be removed.
-            var contentIdentifier = sourceCodeLocationOrInfo.contentIdentifier || sourceCodeLocationOrInfo.url;
-            var lineNumber = sourceCodeLocationOrInfo.lineNumber || 0;
-            var columnNumber = sourceCodeLocationOrInfo.columnNumber || 0;
-            var location = new WI.SourceCodeLocation(null, lineNumber, columnNumber);
-            var ignoreCount = sourceCodeLocationOrInfo.ignoreCount || 0;
-            var autoContinue = sourceCodeLocationOrInfo.autoContinue || false;
-            var actions = sourceCodeLocationOrInfo.actions || [];
-            for (var i = 0; i < actions.length; ++i)
-                actions[i] = new WI.BreakpointAction(this, actions[i]);
-            disabled = sourceCodeLocationOrInfo.disabled;
-            condition = sourceCodeLocationOrInfo.condition;
</del><ins>+        this._id = null;
+        this._sourceCodeLocation = sourceCodeLocation;
+
+        let sourceCode = this._sourceCodeLocation.sourceCode;
+        if (sourceCode) {
+            this._contentIdentifier = sourceCode.contentIdentifier;
+            console.assert(!contentIdentifier || contentIdentifier === this._contentIdentifier, "The content identifier from the source code should match the given value.");
</ins><span class="cx">         } else
</span><del>-            console.error("Unexpected type passed to WI.Breakpoint", sourceCodeLocationOrInfo);
</del><ins>+            this._contentIdentifier = contentIdentifier || null;
+        console.assert(this._contentIdentifier || this._isSpecial(), "There should always be a content identifier for a breakpoint.");
</ins><span class="cx"> 
</span><del>-        this._id = null;
-        this._contentIdentifier = contentIdentifier || null;
-        this._scriptIdentifier = scriptIdentifier || null;
-        this._target = target || null;
</del><ins>+        this._scriptIdentifier = sourceCode instanceof WI.Script ? sourceCode.id : null;
+        this._target = sourceCode instanceof WI.Script ? sourceCode.target : null;
</ins><span class="cx">         this._disabled = disabled || false;
</span><span class="cx">         this._condition = condition || "";
</span><span class="cx">         this._ignoreCount = ignoreCount || 0;
</span><span class="cx">         this._autoContinue = autoContinue || false;
</span><del>-        this._actions = actions || [];
</del><ins>+        this._actions = [];
</ins><span class="cx">         this._resolved = false;
</span><span class="cx"> 
</span><del>-        this._sourceCodeLocation = location;
</del><span class="cx">         this._sourceCodeLocation.addEventListener(WI.SourceCodeLocation.Event.LocationChanged, this._sourceCodeLocationLocationChanged, this);
</span><span class="cx">         this._sourceCodeLocation.addEventListener(WI.SourceCodeLocation.Event.DisplayLocationChanged, this._sourceCodeLocationDisplayLocationChanged, this);
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    // Public
</del><ins>+    // Import / Export
</ins><span class="cx"> 
</span><del>-    get identifier()
</del><ins>+    static fromJSON(json)
</ins><span class="cx">     {
</span><del>-        return this._id;
</del><ins>+        const sourceCode = null;
+        let breakpoint = new Breakpoint(new WI.SourceCodeLocation(sourceCode, json.lineNumber || 0, json.columnNumber || 0), {
+            // The 'url' fallback is for transitioning from older frontends and should be removed.
+            contentIdentifier: json.contentIdentifier || json.url,
+            disabled: json.disabled,
+            condition: json.condition,
+            ignoreCount: json.ignoreCount,
+            autoContinue: json.autoContinue,
+        });
+        breakpoint._actions = json.actions.map((actionJSON) => WI.BreakpointAction.fromJSON(actionJSON, breakpoint));
+        return breakpoint;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    set identifier(id)
</del><ins>+    toJSON(key)
</ins><span class="cx">     {
</span><del>-        this._id = id || null;
</del><ins>+        // The id, scriptIdentifier, target, and resolved state are tied to the current session, so don't include them for serialization.
+        let json = {
+            contentIdentifier: this._contentIdentifier,
+            lineNumber: this._sourceCodeLocation.lineNumber,
+            columnNumber: this._sourceCodeLocation.columnNumber,
+            disabled: this._disabled,
+            condition: this._condition,
+            ignoreCount: this._ignoreCount,
+            actions: this._actions.map((action) => action.toJSON()),
+            autoContinue: this._autoContinue,
+        };
+        if (key === WI.ObjectStore.toJSONSymbol)
+            json[WI.objectStores.breakpoints.keyPath] = this._contentIdentifier + ":" + this._sourceCodeLocation.lineNumber + ":" + this._sourceCodeLocation.columnNumber;
+        return json;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    get contentIdentifier()
-    {
-        return this._contentIdentifier;
-    }
</del><ins>+    // Public
</ins><span class="cx"> 
</span><del>-    get scriptIdentifier()
-    {
-        return this._scriptIdentifier;
-    }
</del><ins>+    get sourceCodeLocation() { return this._sourceCodeLocation; }
+    get contentIdentifier() { return this._contentIdentifier; }
+    get scriptIdentifier() { return this._scriptIdentifier; }
+    get target() { return this._target; }
</ins><span class="cx"> 
</span><del>-    get target()
</del><ins>+    get identifier()
</ins><span class="cx">     {
</span><del>-        return this._target;
</del><ins>+        return this._id;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    get sourceCodeLocation()
</del><ins>+    set identifier(id)
</ins><span class="cx">     {
</span><del>-        return this._sourceCodeLocation;
</del><ins>+        this._id = id || null;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     get resolved()
</span><span class="lines">@@ -109,13 +122,8 @@
</span><span class="cx">         if (this._resolved === resolved)
</span><span class="cx">             return;
</span><span class="cx"> 
</span><del>-        function isSpecialBreakpoint()
-        {
-            return this._sourceCodeLocation.isEqual(new WI.SourceCodeLocation(null, Infinity, Infinity));
-        }
</del><ins>+        console.assert(!resolved || this._sourceCodeLocation.sourceCode || this._isSpecial(), "Breakpoints must have a SourceCode to be resolved.", this);
</ins><span class="cx"> 
</span><del>-        console.assert(!resolved || this._sourceCodeLocation.sourceCode || isSpecialBreakpoint.call(this), "Breakpoints must have a SourceCode to be resolved.", this);
-
</del><span class="cx">         this._resolved = resolved || false;
</span><span class="cx"> 
</span><span class="cx">         this.dispatchEventToListeners(WI.Breakpoint.Event.ResolvedStateDidChange);
</span><span class="lines">@@ -241,18 +249,18 @@
</span><span class="cx"> 
</span><span class="cx">     recreateAction(type, actionToReplace)
</span><span class="cx">     {
</span><del>-        var newAction = new WI.BreakpointAction(this, type, null);
-
-        var index = this._actions.indexOf(actionToReplace);
</del><ins>+        let index = this._actions.indexOf(actionToReplace);
</ins><span class="cx">         console.assert(index !== -1);
</span><span class="cx">         if (index === -1)
</span><span class="cx">             return null;
</span><span class="cx"> 
</span><del>-        this._actions[index] = newAction;
</del><ins>+        const data = null;
+        let action = new WI.BreakpointAction(this, type, data);
+        this._actions[index] = action;
</ins><span class="cx"> 
</span><span class="cx">         this.dispatchEventToListeners(WI.Breakpoint.Event.ActionsDidChange);
</span><span class="cx"> 
</span><del>-        return newAction;
</del><ins>+        return action;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     removeAction(action)
</span><span class="lines">@@ -282,36 +290,11 @@
</span><span class="cx"> 
</span><span class="cx">     saveIdentityToCookie(cookie)
</span><span class="cx">     {
</span><del>-        cookie["breakpoint-content-identifier"] = this.contentIdentifier;
-        cookie["breakpoint-line-number"] = this.sourceCodeLocation.lineNumber;
-        cookie["breakpoint-column-number"] = this.sourceCodeLocation.columnNumber;
</del><ins>+        cookie["breakpoint-content-identifier"] = this._contentIdentifier;
+        cookie["breakpoint-line-number"] = this._sourceCodeLocation.lineNumber;
+        cookie["breakpoint-column-number"] = this._sourceCodeLocation.columnNumber;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    serializeOptions()
-    {
-        return {
-            condition: this._condition,
-            ignoreCount: this._ignoreCount,
-            actions: this._actions.map((action) => action.toJSON()),
-            autoContinue: this._autoContinue,
-        };
-    }
-
-    toJSON(key)
-    {
-        // The id, scriptIdentifier, target, and resolved state are tied to the current session, so don't include them for serialization.
-        let json = {
-            contentIdentifier: this._contentIdentifier,
-            lineNumber: this._sourceCodeLocation.lineNumber,
-            columnNumber: this._sourceCodeLocation.columnNumber,
-            disabled: this._disabled,
-            ...this.serializeOptions(),
-        };
-        if (key === WI.ObjectStore.toJSONSymbol)
-            json[WI.objectStores.breakpoints.keyPath] = this._contentIdentifier + ":" + this._sourceCodeLocation.lineNumber + ":" + this._sourceCodeLocation.columnNumber;
-        return json;
-    }
-
</del><span class="cx">     // Protected (Called by BreakpointAction)
</span><span class="cx"> 
</span><span class="cx">     breakpointActionDidChange(action)
</span><span class="lines">@@ -326,6 +309,11 @@
</span><span class="cx"> 
</span><span class="cx">     // Private
</span><span class="cx"> 
</span><ins>+    _isSpecial()
+    {
+        return this._sourceCodeLocation.isEqual(new WI.SourceCodeLocation(null, Infinity, Infinity));
+    }
+
</ins><span class="cx">     _sourceCodeLocationLocationChanged(event)
</span><span class="cx">     {
</span><span class="cx">         this.dispatchEventToListeners(WI.Breakpoint.Event.LocationDidChange, event.data);
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceModelsBreakpointActionjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Models/BreakpointAction.js (243726 => 243727)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Models/BreakpointAction.js     2019-04-02 00:01:05 UTC (rev 243726)
+++ trunk/Source/WebInspectorUI/UserInterface/Models/BreakpointAction.js        2019-04-02 00:20:11 UTC (rev 243727)
</span><span class="lines">@@ -25,26 +25,34 @@
</span><span class="cx"> 
</span><span class="cx"> WI.BreakpointAction = class BreakpointAction
</span><span class="cx"> {
</span><del>-    constructor(breakpoint, typeOrInfo, data)
</del><ins>+    constructor(breakpoint, type, data)
</ins><span class="cx">     {
</span><del>-        console.assert(breakpoint);
-        console.assert(typeOrInfo);
</del><ins>+        console.assert(breakpoint instanceof WI.Breakpoint);
+        console.assert(Object.values(WI.BreakpointAction.Type).includes(type));
</ins><span class="cx"> 
</span><span class="cx">         this._breakpoint = breakpoint;
</span><ins>+        this._type = type;
+        this._data = data || null;
+        this._id = WI.debuggerManager.nextBreakpointActionIdentifier();
+    }
</ins><span class="cx"> 
</span><del>-        if (typeof typeOrInfo === "string") {
-            this._type = typeOrInfo;
-            this._data = data || null;
-        } else if (typeof typeOrInfo === "object") {
-            this._type = typeOrInfo.type;
-            this._data = typeOrInfo.data || null;
-        } else
-            console.error("Unexpected type passed to WI.BreakpointAction");
</del><ins>+    // Import / Export
</ins><span class="cx"> 
</span><del>-        console.assert(typeof this._type === "string");
-        this._id = WI.debuggerManager.nextBreakpointActionIdentifier();
</del><ins>+    static fromJSON(json, breakpoint)
+    {
+        return new BreakpointAction(breakpoint, json.type, json.data);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    toJSON()
+    {
+        let json = {
+            type: this._type,
+        };
+        if (this._data)
+            json.data = this._data;
+        return json;
+    }
+
</ins><span class="cx">     // Public
</span><span class="cx"> 
</span><span class="cx">     get breakpoint() { return this._breakpoint; }
</span><span class="lines">@@ -66,14 +74,10 @@
</span><span class="cx">         this._breakpoint.breakpointActionDidChange(this);
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    toJSON()
</del><ins>+    toProtocol()
</ins><span class="cx">     {
</span><del>-        let json = {
-            type: this._type,
-            id: this._id,
-        };
-        if (this._data)
-            json.data = this._data;
</del><ins>+        let json = this.toJSON();
+        json.id = this._id;
</ins><span class="cx">         return json;
</span><span class="cx">     }
</span><span class="cx"> };
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceViewsDebuggerSidebarPaneljs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Views/DebuggerSidebarPanel.js (243726 => 243727)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Views/DebuggerSidebarPanel.js  2019-04-02 00:01:05 UTC (rev 243726)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/DebuggerSidebarPanel.js     2019-04-02 00:20:11 UTC (rev 243727)
</span><span class="lines">@@ -560,9 +560,8 @@
</span><span class="cx"> 
</span><span class="cx">     _addBreakpointsForSourceCode(sourceCode)
</span><span class="cx">     {
</span><del>-        var breakpoints = WI.debuggerManager.breakpointsForSourceCode(sourceCode);
-        for (var i = 0; i < breakpoints.length; ++i)
-            this._addBreakpoint(breakpoints[i], sourceCode);
</del><ins>+        for (let breakpoint of WI.debuggerManager.breakpointsForSourceCode(sourceCode))
+            this._addBreakpoint(breakpoint, sourceCode);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     _addIssuesForSourceCode(sourceCode)
</span></span></pre></div>
<a id="trunkSourceWebInspectorUIUserInterfaceViewsSourceCodeTextEditorjs"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebInspectorUI/UserInterface/Views/SourceCodeTextEditor.js (243726 => 243727)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebInspectorUI/UserInterface/Views/SourceCodeTextEditor.js  2019-04-02 00:01:05 UTC (rev 243726)
+++ trunk/Source/WebInspectorUI/UserInterface/Views/SourceCodeTextEditor.js     2019-04-02 00:20:11 UTC (rev 243727)
</span><span class="lines">@@ -499,9 +499,7 @@
</span><span class="cx">         if (this._supportsDebugging) {
</span><span class="cx">             this._breakpointMap = {};
</span><span class="cx"> 
</span><del>-            var breakpoints = WI.debuggerManager.breakpointsForSourceCode(this._sourceCode);
-            for (var i = 0; i < breakpoints.length; ++i) {
-                var breakpoint = breakpoints[i];
</del><ins>+            for (let breakpoint of WI.debuggerManager.breakpointsForSourceCode(this._sourceCode)) {
</ins><span class="cx">                 console.assert(this._matchesBreakpoint(breakpoint));
</span><span class="cx">                 var lineInfo = this._editorLineInfoForSourceCodeLocation(breakpoint.sourceCodeLocation);
</span><span class="cx">                 this._addBreakpointWithEditorLineInfo(breakpoint, lineInfo);
</span><span class="lines">@@ -562,8 +560,7 @@
</span><span class="cx">     {
</span><span class="cx">         console.assert(this._supportsDebugging);
</span><span class="cx"> 
</span><del>-        var breakpoints = WI.debuggerManager.breakpointsForSourceCode(this._sourceCode);
-        for (var breakpoint of breakpoints)
</del><ins>+        for (let breakpoint of WI.debuggerManager.breakpointsForSourceCode(this._sourceCode))
</ins><span class="cx">             this._updateBreakpointStatus(breakpoint);
</span><span class="cx">     }
</span><span class="cx"> 
</span></span></pre>
</div>
</div>

</body>
</html>