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 |