| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2012 Google Inc. All rights reserved. | 2 * Copyright (C) 2012 Google Inc. All rights reserved. |
| 3 * | 3 * |
| 4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
| 6 * met: | 6 * met: |
| 7 * | 7 * |
| 8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
| 9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
| 10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
| 11 * copyright notice, this list of conditions and the following disclaimer | 11 * copyright notice, this list of conditions and the following disclaimer |
| 12 * in the documentation and/or other materials provided with the | 12 * in the documentation and/or other materials provided with the |
| 13 * distribution. | 13 * distribution. |
| 14 * * Neither the name of Google Inc. nor the names of its | 14 * * Neither the name of Google Inc. nor the names of its |
| 15 * contributors may be used to endorse or promote products derived from | 15 * contributors may be used to endorse or promote products derived from |
| 16 * this software without specific prior written permission. | 16 * this software without specific prior written permission. |
| 17 * | 17 * |
| 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 29 */ | 29 */ |
| 30 | |
| 31 /** | 30 /** |
| 32 * @constructor | |
| 33 * @implements {WebInspector.DebuggerSourceMapping} | 31 * @implements {WebInspector.DebuggerSourceMapping} |
| 34 * @param {!WebInspector.DebuggerModel} debuggerModel | 32 * @unrestricted |
| 35 * @param {!WebInspector.Workspace} workspace | |
| 36 * @param {!WebInspector.NetworkMapping} networkMapping | |
| 37 * @param {!WebInspector.DebuggerWorkspaceBinding} debuggerWorkspaceBinding | |
| 38 */ | 33 */ |
| 39 WebInspector.ResourceScriptMapping = function(debuggerModel, workspace, networkM
apping, debuggerWorkspaceBinding) | 34 WebInspector.ResourceScriptMapping = class { |
| 40 { | 35 /** |
| 36 * @param {!WebInspector.DebuggerModel} debuggerModel |
| 37 * @param {!WebInspector.Workspace} workspace |
| 38 * @param {!WebInspector.NetworkMapping} networkMapping |
| 39 * @param {!WebInspector.DebuggerWorkspaceBinding} debuggerWorkspaceBinding |
| 40 */ |
| 41 constructor(debuggerModel, workspace, networkMapping, debuggerWorkspaceBinding
) { |
| 41 this._target = debuggerModel.target(); | 42 this._target = debuggerModel.target(); |
| 42 this._debuggerModel = debuggerModel; | 43 this._debuggerModel = debuggerModel; |
| 43 this._networkMapping = networkMapping; | 44 this._networkMapping = networkMapping; |
| 44 this._debuggerWorkspaceBinding = debuggerWorkspaceBinding; | 45 this._debuggerWorkspaceBinding = debuggerWorkspaceBinding; |
| 45 /** @type {!Set<!WebInspector.UISourceCode>} */ | 46 /** @type {!Set<!WebInspector.UISourceCode>} */ |
| 46 this._boundUISourceCodes = new Set(); | 47 this._boundUISourceCodes = new Set(); |
| 47 | 48 |
| 48 /** @type {!Map.<!WebInspector.UISourceCode, !WebInspector.ResourceScriptFil
e>} */ | 49 /** @type {!Map.<!WebInspector.UISourceCode, !WebInspector.ResourceScriptFil
e>} */ |
| 49 this._uiSourceCodeToScriptFile = new Map(); | 50 this._uiSourceCodeToScriptFile = new Map(); |
| 50 | 51 |
| 51 this._eventListeners = [ | 52 this._eventListeners = [ |
| 52 debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.GlobalO
bjectCleared, this._debuggerReset, this), | 53 debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.GlobalObj
ectCleared, this._debuggerReset, this), |
| 53 workspace.addEventListener(WebInspector.Workspace.Events.UISourceCodeAdd
ed, this._uiSourceCodeAdded, this), | 54 workspace.addEventListener(WebInspector.Workspace.Events.UISourceCodeAdded
, this._uiSourceCodeAdded, this), |
| 54 workspace.addEventListener(WebInspector.Workspace.Events.UISourceCodeRem
oved, this._uiSourceCodeRemoved, this) | 55 workspace.addEventListener(WebInspector.Workspace.Events.UISourceCodeRemov
ed, this._uiSourceCodeRemoved, this) |
| 55 ]; | 56 ]; |
| 57 } |
| 58 |
| 59 /** |
| 60 * @override |
| 61 * @param {!WebInspector.DebuggerModel.Location} rawLocation |
| 62 * @return {?WebInspector.UILocation} |
| 63 */ |
| 64 rawLocationToUILocation(rawLocation) { |
| 65 var debuggerModelLocation = /** @type {!WebInspector.DebuggerModel.Location}
*/ (rawLocation); |
| 66 var script = debuggerModelLocation.script(); |
| 67 if (!script) |
| 68 return null; |
| 69 var uiSourceCode = this._workspaceUISourceCodeForScript(script); |
| 70 if (!uiSourceCode) |
| 71 return null; |
| 72 var scriptFile = this.scriptFile(uiSourceCode); |
| 73 if (scriptFile && |
| 74 ((scriptFile.hasDivergedFromVM() && !scriptFile.isMergingToVM()) || scri
ptFile.isDivergingFromVM())) |
| 75 return null; |
| 76 var lineNumber = debuggerModelLocation.lineNumber - (script.isInlineScriptWi
thSourceURL() ? script.lineOffset : 0); |
| 77 var columnNumber = debuggerModelLocation.columnNumber || 0; |
| 78 if (script.isInlineScriptWithSourceURL() && !lineNumber && columnNumber) |
| 79 columnNumber -= script.columnOffset; |
| 80 return uiSourceCode.uiLocation(lineNumber, columnNumber); |
| 81 } |
| 82 |
| 83 /** |
| 84 * @override |
| 85 * @param {!WebInspector.UISourceCode} uiSourceCode |
| 86 * @param {number} lineNumber |
| 87 * @param {number} columnNumber |
| 88 * @return {?WebInspector.DebuggerModel.Location} |
| 89 */ |
| 90 uiLocationToRawLocation(uiSourceCode, lineNumber, columnNumber) { |
| 91 var scripts = this._scriptsForUISourceCode(uiSourceCode); |
| 92 console.assert(scripts.length); |
| 93 var script = scripts[scripts.length - 1]; |
| 94 if (script.isInlineScriptWithSourceURL()) |
| 95 return this._debuggerModel.createRawLocation( |
| 96 script, lineNumber + script.lineOffset, lineNumber ? columnNumber : co
lumnNumber + script.columnOffset); |
| 97 return this._debuggerModel.createRawLocation(script, lineNumber, columnNumbe
r); |
| 98 } |
| 99 |
| 100 /** |
| 101 * @param {!WebInspector.Script} script |
| 102 */ |
| 103 addScript(script) { |
| 104 if (script.isAnonymousScript()) |
| 105 return; |
| 106 this._debuggerWorkspaceBinding.pushSourceMapping(script, this); |
| 107 |
| 108 var uiSourceCode = this._workspaceUISourceCodeForScript(script); |
| 109 if (!uiSourceCode) |
| 110 return; |
| 111 |
| 112 this._bindUISourceCodeToScripts(uiSourceCode, [script]); |
| 113 } |
| 114 |
| 115 /** |
| 116 * @override |
| 117 * @return {boolean} |
| 118 */ |
| 119 isIdentity() { |
| 120 return true; |
| 121 } |
| 122 |
| 123 /** |
| 124 * @override |
| 125 * @param {!WebInspector.UISourceCode} uiSourceCode |
| 126 * @param {number} lineNumber |
| 127 * @return {boolean} |
| 128 */ |
| 129 uiLineHasMapping(uiSourceCode, lineNumber) { |
| 130 return true; |
| 131 } |
| 132 |
| 133 /** |
| 134 * @param {!WebInspector.UISourceCode} uiSourceCode |
| 135 * @return {?WebInspector.ResourceScriptFile} |
| 136 */ |
| 137 scriptFile(uiSourceCode) { |
| 138 return this._uiSourceCodeToScriptFile.get(uiSourceCode) || null; |
| 139 } |
| 140 |
| 141 /** |
| 142 * @param {!WebInspector.UISourceCode} uiSourceCode |
| 143 * @param {?WebInspector.ResourceScriptFile} scriptFile |
| 144 */ |
| 145 _setScriptFile(uiSourceCode, scriptFile) { |
| 146 if (scriptFile) |
| 147 this._uiSourceCodeToScriptFile.set(uiSourceCode, scriptFile); |
| 148 else |
| 149 this._uiSourceCodeToScriptFile.remove(uiSourceCode); |
| 150 } |
| 151 |
| 152 /** |
| 153 * @param {!WebInspector.Event} event |
| 154 */ |
| 155 _uiSourceCodeAdded(event) { |
| 156 var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.data); |
| 157 if (uiSourceCode.isFromServiceProject()) |
| 158 return; |
| 159 var scripts = this._scriptsForUISourceCode(uiSourceCode); |
| 160 if (!scripts.length) |
| 161 return; |
| 162 |
| 163 this._bindUISourceCodeToScripts(uiSourceCode, scripts); |
| 164 } |
| 165 |
| 166 /** |
| 167 * @param {!WebInspector.Event} event |
| 168 */ |
| 169 _uiSourceCodeRemoved(event) { |
| 170 var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.data); |
| 171 if (uiSourceCode.isFromServiceProject() || !this._boundUISourceCodes.has(uiS
ourceCode)) |
| 172 return; |
| 173 |
| 174 this._unbindUISourceCode(uiSourceCode); |
| 175 } |
| 176 |
| 177 /** |
| 178 * @param {!WebInspector.UISourceCode} uiSourceCode |
| 179 */ |
| 180 _updateLocations(uiSourceCode) { |
| 181 var scripts = this._scriptsForUISourceCode(uiSourceCode); |
| 182 if (!scripts.length) |
| 183 return; |
| 184 for (var i = 0; i < scripts.length; ++i) |
| 185 this._debuggerWorkspaceBinding.updateLocations(scripts[i]); |
| 186 } |
| 187 |
| 188 /** |
| 189 * @param {!WebInspector.Script} script |
| 190 * @return {?WebInspector.UISourceCode} |
| 191 */ |
| 192 _workspaceUISourceCodeForScript(script) { |
| 193 if (script.isAnonymousScript()) |
| 194 return null; |
| 195 return this._networkMapping.uiSourceCodeForScriptURL(script.sourceURL, scrip
t); |
| 196 } |
| 197 |
| 198 /** |
| 199 * @param {!WebInspector.UISourceCode} uiSourceCode |
| 200 * @return {!Array.<!WebInspector.Script>} |
| 201 */ |
| 202 _scriptsForUISourceCode(uiSourceCode) { |
| 203 var target = WebInspector.NetworkProject.targetForUISourceCode(uiSourceCode)
; |
| 204 if (target !== this._debuggerModel.target()) |
| 205 return []; |
| 206 return this._debuggerModel.scriptsForSourceURL(uiSourceCode.url()); |
| 207 } |
| 208 |
| 209 /** |
| 210 * @param {!WebInspector.UISourceCode} uiSourceCode |
| 211 * @param {!Array.<!WebInspector.Script>} scripts |
| 212 */ |
| 213 _bindUISourceCodeToScripts(uiSourceCode, scripts) { |
| 214 console.assert(scripts.length); |
| 215 // Due to different listeners order, a script file could be created just bef
ore uiSourceCode |
| 216 // for the corresponding script was created. Check that we don't create scri
ptFile twice. |
| 217 var boundScriptFile = this.scriptFile(uiSourceCode); |
| 218 if (boundScriptFile && boundScriptFile._hasScripts(scripts)) |
| 219 return; |
| 220 |
| 221 var scriptFile = new WebInspector.ResourceScriptFile(this, uiSourceCode, scr
ipts); |
| 222 this._setScriptFile(uiSourceCode, scriptFile); |
| 223 for (var i = 0; i < scripts.length; ++i) |
| 224 this._debuggerWorkspaceBinding.updateLocations(scripts[i]); |
| 225 this._debuggerWorkspaceBinding.setSourceMapping(this._target, uiSourceCode,
this); |
| 226 this._boundUISourceCodes.add(uiSourceCode); |
| 227 } |
| 228 |
| 229 /** |
| 230 * @param {!WebInspector.UISourceCode} uiSourceCode |
| 231 */ |
| 232 _unbindUISourceCode(uiSourceCode) { |
| 233 var scriptFile = this.scriptFile(uiSourceCode); |
| 234 if (scriptFile) { |
| 235 scriptFile.dispose(); |
| 236 this._setScriptFile(uiSourceCode, null); |
| 237 } |
| 238 this._debuggerWorkspaceBinding.setSourceMapping(this._target, uiSourceCode,
null); |
| 239 this._boundUISourceCodes.delete(uiSourceCode); |
| 240 } |
| 241 |
| 242 _debuggerReset() { |
| 243 for (var uiSourceCode of this._boundUISourceCodes.valuesArray()) |
| 244 this._unbindUISourceCode(uiSourceCode); |
| 245 this._boundUISourceCodes.clear(); |
| 246 console.assert(!this._uiSourceCodeToScriptFile.size); |
| 247 } |
| 248 |
| 249 dispose() { |
| 250 WebInspector.EventTarget.removeEventListeners(this._eventListeners); |
| 251 this._debuggerReset(); |
| 252 } |
| 56 }; | 253 }; |
| 57 | 254 |
| 58 WebInspector.ResourceScriptMapping.prototype = { | |
| 59 /** | |
| 60 * @override | |
| 61 * @param {!WebInspector.DebuggerModel.Location} rawLocation | |
| 62 * @return {?WebInspector.UILocation} | |
| 63 */ | |
| 64 rawLocationToUILocation: function(rawLocation) | |
| 65 { | |
| 66 var debuggerModelLocation = /** @type {!WebInspector.DebuggerModel.Locat
ion} */ (rawLocation); | |
| 67 var script = debuggerModelLocation.script(); | |
| 68 if (!script) | |
| 69 return null; | |
| 70 var uiSourceCode = this._workspaceUISourceCodeForScript(script); | |
| 71 if (!uiSourceCode) | |
| 72 return null; | |
| 73 var scriptFile = this.scriptFile(uiSourceCode); | |
| 74 if (scriptFile && ((scriptFile.hasDivergedFromVM() && !scriptFile.isMerg
ingToVM()) || scriptFile.isDivergingFromVM())) | |
| 75 return null; | |
| 76 var lineNumber = debuggerModelLocation.lineNumber - (script.isInlineScri
ptWithSourceURL() ? script.lineOffset : 0); | |
| 77 var columnNumber = debuggerModelLocation.columnNumber || 0; | |
| 78 if (script.isInlineScriptWithSourceURL() && !lineNumber && columnNumber) | |
| 79 columnNumber -= script.columnOffset; | |
| 80 return uiSourceCode.uiLocation(lineNumber, columnNumber); | |
| 81 }, | |
| 82 | |
| 83 /** | |
| 84 * @override | |
| 85 * @param {!WebInspector.UISourceCode} uiSourceCode | |
| 86 * @param {number} lineNumber | |
| 87 * @param {number} columnNumber | |
| 88 * @return {?WebInspector.DebuggerModel.Location} | |
| 89 */ | |
| 90 uiLocationToRawLocation: function(uiSourceCode, lineNumber, columnNumber) | |
| 91 { | |
| 92 var scripts = this._scriptsForUISourceCode(uiSourceCode); | |
| 93 console.assert(scripts.length); | |
| 94 var script = scripts[scripts.length - 1]; | |
| 95 if (script.isInlineScriptWithSourceURL()) | |
| 96 return this._debuggerModel.createRawLocation(script, lineNumber + sc
ript.lineOffset, lineNumber ? columnNumber : columnNumber + script.columnOffset)
; | |
| 97 return this._debuggerModel.createRawLocation(script, lineNumber, columnN
umber); | |
| 98 }, | |
| 99 | |
| 100 /** | |
| 101 * @param {!WebInspector.Script} script | |
| 102 */ | |
| 103 addScript: function(script) | |
| 104 { | |
| 105 if (script.isAnonymousScript()) | |
| 106 return; | |
| 107 this._debuggerWorkspaceBinding.pushSourceMapping(script, this); | |
| 108 | |
| 109 var uiSourceCode = this._workspaceUISourceCodeForScript(script); | |
| 110 if (!uiSourceCode) | |
| 111 return; | |
| 112 | |
| 113 this._bindUISourceCodeToScripts(uiSourceCode, [script]); | |
| 114 }, | |
| 115 | |
| 116 /** | |
| 117 * @override | |
| 118 * @return {boolean} | |
| 119 */ | |
| 120 isIdentity: function() | |
| 121 { | |
| 122 return true; | |
| 123 }, | |
| 124 | |
| 125 /** | |
| 126 * @override | |
| 127 * @param {!WebInspector.UISourceCode} uiSourceCode | |
| 128 * @param {number} lineNumber | |
| 129 * @return {boolean} | |
| 130 */ | |
| 131 uiLineHasMapping: function(uiSourceCode, lineNumber) | |
| 132 { | |
| 133 return true; | |
| 134 }, | |
| 135 | |
| 136 /** | |
| 137 * @param {!WebInspector.UISourceCode} uiSourceCode | |
| 138 * @return {?WebInspector.ResourceScriptFile} | |
| 139 */ | |
| 140 scriptFile: function(uiSourceCode) | |
| 141 { | |
| 142 return this._uiSourceCodeToScriptFile.get(uiSourceCode) || null; | |
| 143 }, | |
| 144 | |
| 145 /** | |
| 146 * @param {!WebInspector.UISourceCode} uiSourceCode | |
| 147 * @param {?WebInspector.ResourceScriptFile} scriptFile | |
| 148 */ | |
| 149 _setScriptFile: function(uiSourceCode, scriptFile) | |
| 150 { | |
| 151 if (scriptFile) | |
| 152 this._uiSourceCodeToScriptFile.set(uiSourceCode, scriptFile); | |
| 153 else | |
| 154 this._uiSourceCodeToScriptFile.remove(uiSourceCode); | |
| 155 }, | |
| 156 | |
| 157 /** | |
| 158 * @param {!WebInspector.Event} event | |
| 159 */ | |
| 160 _uiSourceCodeAdded: function(event) | |
| 161 { | |
| 162 var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.data
); | |
| 163 if (uiSourceCode.isFromServiceProject()) | |
| 164 return; | |
| 165 var scripts = this._scriptsForUISourceCode(uiSourceCode); | |
| 166 if (!scripts.length) | |
| 167 return; | |
| 168 | |
| 169 this._bindUISourceCodeToScripts(uiSourceCode, scripts); | |
| 170 }, | |
| 171 | |
| 172 /** | |
| 173 * @param {!WebInspector.Event} event | |
| 174 */ | |
| 175 _uiSourceCodeRemoved: function(event) | |
| 176 { | |
| 177 var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.data
); | |
| 178 if (uiSourceCode.isFromServiceProject() || !this._boundUISourceCodes.has
(uiSourceCode)) | |
| 179 return; | |
| 180 | |
| 181 this._unbindUISourceCode(uiSourceCode); | |
| 182 }, | |
| 183 | |
| 184 /** | |
| 185 * @param {!WebInspector.UISourceCode} uiSourceCode | |
| 186 */ | |
| 187 _updateLocations: function(uiSourceCode) | |
| 188 { | |
| 189 var scripts = this._scriptsForUISourceCode(uiSourceCode); | |
| 190 if (!scripts.length) | |
| 191 return; | |
| 192 for (var i = 0; i < scripts.length; ++i) | |
| 193 this._debuggerWorkspaceBinding.updateLocations(scripts[i]); | |
| 194 }, | |
| 195 | |
| 196 /** | |
| 197 * @param {!WebInspector.Script} script | |
| 198 * @return {?WebInspector.UISourceCode} | |
| 199 */ | |
| 200 _workspaceUISourceCodeForScript: function(script) | |
| 201 { | |
| 202 if (script.isAnonymousScript()) | |
| 203 return null; | |
| 204 return this._networkMapping.uiSourceCodeForScriptURL(script.sourceURL, s
cript); | |
| 205 }, | |
| 206 | |
| 207 /** | |
| 208 * @param {!WebInspector.UISourceCode} uiSourceCode | |
| 209 * @return {!Array.<!WebInspector.Script>} | |
| 210 */ | |
| 211 _scriptsForUISourceCode: function(uiSourceCode) | |
| 212 { | |
| 213 var target = WebInspector.NetworkProject.targetForUISourceCode(uiSourceC
ode); | |
| 214 if (target !== this._debuggerModel.target()) | |
| 215 return []; | |
| 216 return this._debuggerModel.scriptsForSourceURL(uiSourceCode.url()); | |
| 217 }, | |
| 218 | |
| 219 /** | |
| 220 * @param {!WebInspector.UISourceCode} uiSourceCode | |
| 221 * @param {!Array.<!WebInspector.Script>} scripts | |
| 222 */ | |
| 223 _bindUISourceCodeToScripts: function(uiSourceCode, scripts) | |
| 224 { | |
| 225 console.assert(scripts.length); | |
| 226 // Due to different listeners order, a script file could be created just
before uiSourceCode | |
| 227 // for the corresponding script was created. Check that we don't create
scriptFile twice. | |
| 228 var boundScriptFile = this.scriptFile(uiSourceCode); | |
| 229 if (boundScriptFile && boundScriptFile._hasScripts(scripts)) | |
| 230 return; | |
| 231 | |
| 232 var scriptFile = new WebInspector.ResourceScriptFile(this, uiSourceCode,
scripts); | |
| 233 this._setScriptFile(uiSourceCode, scriptFile); | |
| 234 for (var i = 0; i < scripts.length; ++i) | |
| 235 this._debuggerWorkspaceBinding.updateLocations(scripts[i]); | |
| 236 this._debuggerWorkspaceBinding.setSourceMapping(this._target, uiSourceCo
de, this); | |
| 237 this._boundUISourceCodes.add(uiSourceCode); | |
| 238 }, | |
| 239 | |
| 240 /** | |
| 241 * @param {!WebInspector.UISourceCode} uiSourceCode | |
| 242 */ | |
| 243 _unbindUISourceCode: function(uiSourceCode) | |
| 244 { | |
| 245 var scriptFile = this.scriptFile(uiSourceCode); | |
| 246 if (scriptFile) { | |
| 247 scriptFile.dispose(); | |
| 248 this._setScriptFile(uiSourceCode, null); | |
| 249 } | |
| 250 this._debuggerWorkspaceBinding.setSourceMapping(this._target, uiSourceCo
de, null); | |
| 251 this._boundUISourceCodes.delete(uiSourceCode); | |
| 252 }, | |
| 253 | |
| 254 _debuggerReset: function() | |
| 255 { | |
| 256 for (var uiSourceCode of this._boundUISourceCodes.valuesArray()) | |
| 257 this._unbindUISourceCode(uiSourceCode); | |
| 258 this._boundUISourceCodes.clear(); | |
| 259 console.assert(!this._uiSourceCodeToScriptFile.size); | |
| 260 }, | |
| 261 | |
| 262 dispose: function() | |
| 263 { | |
| 264 WebInspector.EventTarget.removeEventListeners(this._eventListeners); | |
| 265 this._debuggerReset(); | |
| 266 } | |
| 267 }; | |
| 268 | |
| 269 /** | 255 /** |
| 270 * @constructor | 256 * @unrestricted |
| 271 * @extends {WebInspector.Object} | |
| 272 * @param {!WebInspector.ResourceScriptMapping} resourceScriptMapping | |
| 273 * @param {!WebInspector.UISourceCode} uiSourceCode | |
| 274 * @param {!Array.<!WebInspector.Script>} scripts | |
| 275 */ | 257 */ |
| 276 WebInspector.ResourceScriptFile = function(resourceScriptMapping, uiSourceCode,
scripts) | 258 WebInspector.ResourceScriptFile = class extends WebInspector.Object { |
| 277 { | 259 /** |
| 260 * @param {!WebInspector.ResourceScriptMapping} resourceScriptMapping |
| 261 * @param {!WebInspector.UISourceCode} uiSourceCode |
| 262 * @param {!Array.<!WebInspector.Script>} scripts |
| 263 */ |
| 264 constructor(resourceScriptMapping, uiSourceCode, scripts) { |
| 265 super(); |
| 278 console.assert(scripts.length); | 266 console.assert(scripts.length); |
| 279 | 267 |
| 280 this._resourceScriptMapping = resourceScriptMapping; | 268 this._resourceScriptMapping = resourceScriptMapping; |
| 281 this._uiSourceCode = uiSourceCode; | 269 this._uiSourceCode = uiSourceCode; |
| 282 | 270 |
| 283 if (this._uiSourceCode.contentType().isScript()) | 271 if (this._uiSourceCode.contentType().isScript()) |
| 284 this._script = scripts[scripts.length - 1]; | 272 this._script = scripts[scripts.length - 1]; |
| 285 | 273 |
| 286 this._uiSourceCode.addEventListener(WebInspector.UISourceCode.Events.Working
CopyChanged, this._workingCopyChanged, this); | 274 this._uiSourceCode.addEventListener( |
| 287 this._uiSourceCode.addEventListener(WebInspector.UISourceCode.Events.Working
CopyCommitted, this._workingCopyCommitted, this); | 275 WebInspector.UISourceCode.Events.WorkingCopyChanged, this._workingCopyCh
anged, this); |
| 276 this._uiSourceCode.addEventListener( |
| 277 WebInspector.UISourceCode.Events.WorkingCopyCommitted, this._workingCopy
Committed, this); |
| 278 } |
| 279 |
| 280 /** |
| 281 * @param {!Array.<!WebInspector.Script>} scripts |
| 282 * @return {boolean} |
| 283 */ |
| 284 _hasScripts(scripts) { |
| 285 return this._script && this._script === scripts[0]; |
| 286 } |
| 287 |
| 288 /** |
| 289 * @return {boolean} |
| 290 */ |
| 291 _isDiverged() { |
| 292 if (this._uiSourceCode.isDirty()) |
| 293 return true; |
| 294 if (!this._script) |
| 295 return false; |
| 296 if (typeof this._scriptSource === 'undefined') |
| 297 return false; |
| 298 var workingCopy = this._uiSourceCode.workingCopy(); |
| 299 |
| 300 // Match ignoring sourceURL. |
| 301 if (!workingCopy.startsWith(this._scriptSource.trimRight())) |
| 302 return true; |
| 303 var suffix = this._uiSourceCode.workingCopy().substr(this._scriptSource.leng
th); |
| 304 return !!suffix.length && !suffix.match(WebInspector.Script.sourceURLRegex); |
| 305 } |
| 306 |
| 307 /** |
| 308 * @param {!WebInspector.Event} event |
| 309 */ |
| 310 _workingCopyChanged(event) { |
| 311 this._update(); |
| 312 } |
| 313 |
| 314 _workingCopyCommitted(event) { |
| 315 if (this._uiSourceCode.project().type() === WebInspector.projectTypes.Snippe
ts) |
| 316 return; |
| 317 if (!this._script) |
| 318 return; |
| 319 var debuggerModel = this._resourceScriptMapping._debuggerModel; |
| 320 var source = this._uiSourceCode.workingCopy(); |
| 321 debuggerModel.setScriptSource(this._script.scriptId, source, scriptSourceWas
Set.bind(this)); |
| 322 |
| 323 /** |
| 324 * @param {?string} error |
| 325 * @param {!RuntimeAgent.ExceptionDetails=} exceptionDetails |
| 326 * @this {WebInspector.ResourceScriptFile} |
| 327 */ |
| 328 function scriptSourceWasSet(error, exceptionDetails) { |
| 329 if (!error && !exceptionDetails) |
| 330 this._scriptSource = source; |
| 331 this._update(); |
| 332 |
| 333 if (!error && !exceptionDetails) |
| 334 return; |
| 335 if (!exceptionDetails) { |
| 336 WebInspector.console.addMessage( |
| 337 WebInspector.UIString('LiveEdit failed: %s', error), WebInspector.Co
nsole.MessageLevel.Warning); |
| 338 return; |
| 339 } |
| 340 var messageText = WebInspector.UIString('LiveEdit compile failed: %s', exc
eptionDetails.text); |
| 341 this._uiSourceCode.addLineMessage( |
| 342 WebInspector.UISourceCode.Message.Level.Error, messageText, exceptionD
etails.lineNumber, |
| 343 exceptionDetails.columnNumber); |
| 344 } |
| 345 } |
| 346 |
| 347 _update() { |
| 348 if (this._isDiverged() && !this._hasDivergedFromVM) |
| 349 this._divergeFromVM(); |
| 350 else if (!this._isDiverged() && this._hasDivergedFromVM) |
| 351 this._mergeToVM(); |
| 352 } |
| 353 |
| 354 _divergeFromVM() { |
| 355 this._isDivergingFromVM = true; |
| 356 this._resourceScriptMapping._updateLocations(this._uiSourceCode); |
| 357 delete this._isDivergingFromVM; |
| 358 this._hasDivergedFromVM = true; |
| 359 this.dispatchEventToListeners(WebInspector.ResourceScriptFile.Events.DidDive
rgeFromVM, this._uiSourceCode); |
| 360 } |
| 361 |
| 362 _mergeToVM() { |
| 363 delete this._hasDivergedFromVM; |
| 364 this._isMergingToVM = true; |
| 365 this._resourceScriptMapping._updateLocations(this._uiSourceCode); |
| 366 delete this._isMergingToVM; |
| 367 this.dispatchEventToListeners(WebInspector.ResourceScriptFile.Events.DidMerg
eToVM, this._uiSourceCode); |
| 368 } |
| 369 |
| 370 /** |
| 371 * @return {boolean} |
| 372 */ |
| 373 hasDivergedFromVM() { |
| 374 return this._hasDivergedFromVM; |
| 375 } |
| 376 |
| 377 /** |
| 378 * @return {boolean} |
| 379 */ |
| 380 isDivergingFromVM() { |
| 381 return this._isDivergingFromVM; |
| 382 } |
| 383 |
| 384 /** |
| 385 * @return {boolean} |
| 386 */ |
| 387 isMergingToVM() { |
| 388 return this._isMergingToVM; |
| 389 } |
| 390 |
| 391 checkMapping() { |
| 392 if (!this._script || typeof this._scriptSource !== 'undefined') { |
| 393 this._mappingCheckedForTest(); |
| 394 return; |
| 395 } |
| 396 this._script.requestContent().then(callback.bind(this)); |
| 397 |
| 398 /** |
| 399 * @param {?string} source |
| 400 * @this {WebInspector.ResourceScriptFile} |
| 401 */ |
| 402 function callback(source) { |
| 403 this._scriptSource = source; |
| 404 this._update(); |
| 405 this._mappingCheckedForTest(); |
| 406 } |
| 407 } |
| 408 |
| 409 _mappingCheckedForTest() { |
| 410 } |
| 411 |
| 412 /** |
| 413 * @return {?WebInspector.Target} |
| 414 */ |
| 415 target() { |
| 416 if (!this._script) |
| 417 return null; |
| 418 return this._script.target(); |
| 419 } |
| 420 |
| 421 dispose() { |
| 422 this._uiSourceCode.removeEventListener( |
| 423 WebInspector.UISourceCode.Events.WorkingCopyChanged, this._workingCopyCh
anged, this); |
| 424 this._uiSourceCode.removeEventListener( |
| 425 WebInspector.UISourceCode.Events.WorkingCopyCommitted, this._workingCopy
Committed, this); |
| 426 } |
| 427 |
| 428 /** |
| 429 * @param {string} sourceMapURL |
| 430 */ |
| 431 addSourceMapURL(sourceMapURL) { |
| 432 if (!this._script) |
| 433 return; |
| 434 this._script.addSourceMapURL(sourceMapURL); |
| 435 } |
| 436 |
| 437 /** |
| 438 * @return {boolean} |
| 439 */ |
| 440 hasSourceMapURL() { |
| 441 return this._script && !!this._script.sourceMapURL; |
| 442 } |
| 288 }; | 443 }; |
| 289 | 444 |
| 290 /** @enum {symbol} */ | 445 /** @enum {symbol} */ |
| 291 WebInspector.ResourceScriptFile.Events = { | 446 WebInspector.ResourceScriptFile.Events = { |
| 292 DidMergeToVM: Symbol("DidMergeToVM"), | 447 DidMergeToVM: Symbol('DidMergeToVM'), |
| 293 DidDivergeFromVM: Symbol("DidDivergeFromVM"), | 448 DidDivergeFromVM: Symbol('DidDivergeFromVM'), |
| 294 }; | 449 }; |
| 295 | |
| 296 WebInspector.ResourceScriptFile.prototype = { | |
| 297 /** | |
| 298 * @param {!Array.<!WebInspector.Script>} scripts | |
| 299 * @return {boolean} | |
| 300 */ | |
| 301 _hasScripts: function(scripts) | |
| 302 { | |
| 303 return this._script && this._script === scripts[0]; | |
| 304 }, | |
| 305 | |
| 306 /** | |
| 307 * @return {boolean} | |
| 308 */ | |
| 309 _isDiverged: function() | |
| 310 { | |
| 311 if (this._uiSourceCode.isDirty()) | |
| 312 return true; | |
| 313 if (!this._script) | |
| 314 return false; | |
| 315 if (typeof this._scriptSource === "undefined") | |
| 316 return false; | |
| 317 var workingCopy = this._uiSourceCode.workingCopy(); | |
| 318 | |
| 319 // Match ignoring sourceURL. | |
| 320 if (!workingCopy.startsWith(this._scriptSource.trimRight())) | |
| 321 return true; | |
| 322 var suffix = this._uiSourceCode.workingCopy().substr(this._scriptSource.
length); | |
| 323 return !!suffix.length && !suffix.match(WebInspector.Script.sourceURLReg
ex); | |
| 324 }, | |
| 325 | |
| 326 /** | |
| 327 * @param {!WebInspector.Event} event | |
| 328 */ | |
| 329 _workingCopyChanged: function(event) | |
| 330 { | |
| 331 this._update(); | |
| 332 }, | |
| 333 | |
| 334 _workingCopyCommitted: function(event) | |
| 335 { | |
| 336 if (this._uiSourceCode.project().type() === WebInspector.projectTypes.Sn
ippets) | |
| 337 return; | |
| 338 if (!this._script) | |
| 339 return; | |
| 340 var debuggerModel = this._resourceScriptMapping._debuggerModel; | |
| 341 var source = this._uiSourceCode.workingCopy(); | |
| 342 debuggerModel.setScriptSource(this._script.scriptId, source, scriptSourc
eWasSet.bind(this)); | |
| 343 | |
| 344 /** | |
| 345 * @param {?string} error | |
| 346 * @param {!RuntimeAgent.ExceptionDetails=} exceptionDetails | |
| 347 * @this {WebInspector.ResourceScriptFile} | |
| 348 */ | |
| 349 function scriptSourceWasSet(error, exceptionDetails) | |
| 350 { | |
| 351 if (!error && !exceptionDetails) | |
| 352 this._scriptSource = source; | |
| 353 this._update(); | |
| 354 | |
| 355 if (!error && !exceptionDetails) | |
| 356 return; | |
| 357 if (!exceptionDetails) { | |
| 358 WebInspector.console.addMessage(WebInspector.UIString("LiveEdit
failed: %s", error), WebInspector.Console.MessageLevel.Warning); | |
| 359 return; | |
| 360 } | |
| 361 var messageText = WebInspector.UIString("LiveEdit compile failed: %s
", exceptionDetails.text); | |
| 362 this._uiSourceCode.addLineMessage(WebInspector.UISourceCode.Message.
Level.Error, messageText, exceptionDetails.lineNumber, exceptionDetails.columnNu
mber); | |
| 363 } | |
| 364 }, | |
| 365 | |
| 366 _update: function() | |
| 367 { | |
| 368 if (this._isDiverged() && !this._hasDivergedFromVM) | |
| 369 this._divergeFromVM(); | |
| 370 else if (!this._isDiverged() && this._hasDivergedFromVM) | |
| 371 this._mergeToVM(); | |
| 372 }, | |
| 373 | |
| 374 _divergeFromVM: function() | |
| 375 { | |
| 376 this._isDivergingFromVM = true; | |
| 377 this._resourceScriptMapping._updateLocations(this._uiSourceCode); | |
| 378 delete this._isDivergingFromVM; | |
| 379 this._hasDivergedFromVM = true; | |
| 380 this.dispatchEventToListeners(WebInspector.ResourceScriptFile.Events.Did
DivergeFromVM, this._uiSourceCode); | |
| 381 }, | |
| 382 | |
| 383 _mergeToVM: function() | |
| 384 { | |
| 385 delete this._hasDivergedFromVM; | |
| 386 this._isMergingToVM = true; | |
| 387 this._resourceScriptMapping._updateLocations(this._uiSourceCode); | |
| 388 delete this._isMergingToVM; | |
| 389 this.dispatchEventToListeners(WebInspector.ResourceScriptFile.Events.Did
MergeToVM, this._uiSourceCode); | |
| 390 }, | |
| 391 | |
| 392 /** | |
| 393 * @return {boolean} | |
| 394 */ | |
| 395 hasDivergedFromVM: function() | |
| 396 { | |
| 397 return this._hasDivergedFromVM; | |
| 398 }, | |
| 399 | |
| 400 /** | |
| 401 * @return {boolean} | |
| 402 */ | |
| 403 isDivergingFromVM: function() | |
| 404 { | |
| 405 return this._isDivergingFromVM; | |
| 406 }, | |
| 407 | |
| 408 /** | |
| 409 * @return {boolean} | |
| 410 */ | |
| 411 isMergingToVM: function() | |
| 412 { | |
| 413 return this._isMergingToVM; | |
| 414 }, | |
| 415 | |
| 416 checkMapping: function() | |
| 417 { | |
| 418 if (!this._script || typeof this._scriptSource !== "undefined") { | |
| 419 this._mappingCheckedForTest(); | |
| 420 return; | |
| 421 } | |
| 422 this._script.requestContent().then(callback.bind(this)); | |
| 423 | |
| 424 /** | |
| 425 * @param {?string} source | |
| 426 * @this {WebInspector.ResourceScriptFile} | |
| 427 */ | |
| 428 function callback(source) | |
| 429 { | |
| 430 this._scriptSource = source; | |
| 431 this._update(); | |
| 432 this._mappingCheckedForTest(); | |
| 433 } | |
| 434 }, | |
| 435 | |
| 436 _mappingCheckedForTest: function() { }, | |
| 437 | |
| 438 /** | |
| 439 * @return {?WebInspector.Target} | |
| 440 */ | |
| 441 target: function() | |
| 442 { | |
| 443 if (!this._script) | |
| 444 return null; | |
| 445 return this._script.target(); | |
| 446 }, | |
| 447 | |
| 448 dispose: function() | |
| 449 { | |
| 450 this._uiSourceCode.removeEventListener(WebInspector.UISourceCode.Events.
WorkingCopyChanged, this._workingCopyChanged, this); | |
| 451 this._uiSourceCode.removeEventListener(WebInspector.UISourceCode.Events.
WorkingCopyCommitted, this._workingCopyCommitted, this); | |
| 452 }, | |
| 453 | |
| 454 /** | |
| 455 * @param {string} sourceMapURL | |
| 456 */ | |
| 457 addSourceMapURL: function(sourceMapURL) | |
| 458 { | |
| 459 if (!this._script) | |
| 460 return; | |
| 461 this._script.addSourceMapURL(sourceMapURL); | |
| 462 }, | |
| 463 | |
| 464 /** | |
| 465 * @return {boolean} | |
| 466 */ | |
| 467 hasSourceMapURL: function() | |
| 468 { | |
| 469 return this._script && !!this._script.sourceMapURL; | |
| 470 }, | |
| 471 | |
| 472 __proto__: WebInspector.Object.prototype | |
| 473 }; | |
| OLD | NEW |