 Chromium Code Reviews
 Chromium Code Reviews Issue 1663723002:
  [DevTools] Add sourceMap support for blackboxing  (Closed) 
  Base URL: https://chromium.googlesource.com/chromium/src.git@call-set-blackboxed-ranges-on-script-parsed
    
  
    Issue 1663723002:
  [DevTools] Add sourceMap support for blackboxing  (Closed) 
  Base URL: https://chromium.googlesource.com/chromium/src.git@call-set-blackboxed-ranges-on-script-parsed| OLD | NEW | 
|---|---|
| (Empty) | |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 /** | |
| 6 * @constructor | |
| 7 * @param {!WebInspector.DebuggerWorkspaceBinding} debuggerWorkspaceBinding | |
| 8 * @param {!WebInspector.NetworkMapping} networkMapping | |
| 9 */ | |
| 10 WebInspector.BlackboxManager = function(debuggerWorkspaceBinding, networkMapping ) | |
| 11 { | |
| 12 this._debuggerWorkspaceBinding = debuggerWorkspaceBinding; | |
| 13 this._networkMapping = networkMapping; | |
| 14 | |
| 15 WebInspector.targetManager.addModelListener(WebInspector.DebuggerModel, WebI nspector.DebuggerModel.Events.ParsedScriptSource, this._parsedScriptSource, this ); | |
| 16 WebInspector.targetManager.addModelListener(WebInspector.DebuggerModel, WebI nspector.DebuggerModel.Events.GlobalObjectCleared, this._globalObjectCleared, th is); | |
| 17 WebInspector.moduleSetting("skipStackFramesPattern").addChangeListener(this. _patternChanged.bind(this)); | |
| 18 WebInspector.moduleSetting("skipContentScripts").addChangeListener(this._pat ternChanged.bind(this)); | |
| 19 | |
| 20 /** @type {!Map<string, !Array<!DebuggerAgent.ScriptPosition>>} */ | |
| 21 this._scripts = new Map(); | |
| 
dgozman
2016/02/17 01:34:44
this._scriptIdToPositions
 
kozy
2016/02/17 03:40:42
Done.
 | |
| 22 /** @type {!Map<string, boolean>} */ | |
| 23 this._isBlackboxedURLCache = new Map(); | |
| 24 } | |
| 25 | |
| 26 WebInspector.BlackboxManager.prototype = { | |
| 27 | |
| 28 /** | |
| 29 * @param {function(!WebInspector.Event)} listener | |
| 30 * @param {!Object=} thisObject | |
| 31 */ | |
| 32 addChangeListener: function(listener, thisObject) | |
| 33 { | |
| 34 WebInspector.moduleSetting("skipStackFramesPattern").addChangeListener(l istener, thisObject); | |
| 35 }, | |
| 36 | |
| 37 /** | |
| 38 * @param {function(!WebInspector.Event)} listener | |
| 39 * @param {!Object=} thisObject | |
| 40 */ | |
| 41 removeChangeListener: function(listener, thisObject) | |
| 42 { | |
| 43 WebInspector.moduleSetting("skipStackFramesPattern").removeChangeListene r(listener, thisObject); | |
| 44 }, | |
| 45 | |
| 46 /** | |
| 47 * @param {!WebInspector.DebuggerModel.Location} location | |
| 48 * @return {boolean} | |
| 49 */ | |
| 50 isBlackboxedRawLocation: function(location) | |
| 51 { | |
| 52 if (!this._scripts.has(location.scriptId)) | |
| 53 return false; | |
| 54 var positions = this._scripts.get(location.scriptId); | |
| 55 var index = positions.lowerBound(location, comparator); | |
| 56 return !!(index % 2); | |
| 57 | |
| 58 function comparator(a, b) | |
| 
dgozman
2016/02/17 01:34:44
JSDoc plesae.
 
kozy
2016/02/17 03:40:43
Done.
 | |
| 59 { | |
| 60 if (a.lineNumber !== b.line) | |
| 61 return a.lineNumber - b.line; | |
| 62 return a.columnNumber - b.column; | |
| 63 } | |
| 64 }, | |
| 65 | |
| 66 /** | |
| 67 * @param {!WebInspector.UISourceCode} uiSourceCode | |
| 68 * @return {boolean} | |
| 69 */ | |
| 70 isBlackboxedUISourceCode: function(uiSourceCode) | |
| 71 { | |
| 72 var projectType = uiSourceCode.project().type(); | |
| 73 var isContentScript = projectType === WebInspector.projectTypes.ContentS cripts; | |
| 74 if (isContentScript && WebInspector.moduleSetting("skipContentScripts"). get()) | |
| 75 return true; | |
| 76 var networkURL = this._networkMapping.networkURL(uiSourceCode); | |
| 77 var url = projectType === WebInspector.projectTypes.Formatter ? uiSource Code.url() : networkURL; | |
| 78 return this.isBlackboxedURL(url); | |
| 79 }, | |
| 80 | |
| 81 /** | |
| 82 * @param {string} url | |
| 83 * @return {boolean} | |
| 84 */ | |
| 85 isBlackboxedURL: function(url) | |
| 86 { | |
| 87 if (this._isBlackboxedURLCache.has(url)) | |
| 88 return !!this._isBlackboxedURLCache.get(url); | |
| 89 var regex = WebInspector.moduleSetting("skipStackFramesPattern").asRegEx p(); | |
| 90 var isBlackboxed = regex && regex.test(url); | |
| 91 this._isBlackboxedURLCache.set(url, isBlackboxed); | |
| 92 return isBlackboxed; | |
| 93 }, | |
| 94 | |
| 95 /** | |
| 96 * @param {!WebInspector.Script} script | |
| 97 * @param {?WebInspector.SourceMap} sourceMap | |
| 98 */ | |
| 99 sourceMapLoaded: function(script, sourceMap) | |
| 100 { | |
| 101 if (!sourceMap) | |
| 102 return; | |
| 103 if (!this._scripts.has(script.scriptId)) | |
| 104 return; | |
| 105 | |
| 106 var mappings = sourceMap.mappings().slice(); | |
| 107 mappings.sort(mappingComparator); | |
| 108 | |
| 109 var previousScriptState = this._scripts.get(script.scriptId); | |
| 110 if (!mappings.length) { | |
| 111 if (previousScriptState.length > 0) | |
| 112 script.setBlackboxedRanges([]).then(this._setScriptState.bind(th is, script)); | |
| 113 return; | |
| 114 } | |
| 115 | |
| 116 var currentBlackboxed = false; | |
| 117 var isBlackboxed = false; | |
| 118 var positions = []; | |
| 119 if (mappings[0].lineNumber !== 0 || mappings[0].columnNumber !== 0) { | |
| 
dgozman
2016/02/17 01:34:44
Let's add a comment.
 
kozy
2016/02/17 03:40:43
Done.
 | |
| 120 positions.push({ line: 0, column: 0}); | |
| 121 currentBlackboxed = true; | |
| 122 } | |
| 123 for (var mapping of sourceMap.mappings()) { | |
| 124 if (currentBlackboxed !== this.isBlackboxedURL(mapping.sourceURL)) { | |
| 125 positions.push({ line: mapping.lineNumber, column: mapping.colum nNumber }); | |
| 126 currentBlackboxed = !currentBlackboxed; | |
| 127 } | |
| 128 if (currentBlackboxed) | |
| 129 isBlackboxed = true; | |
| 130 } | |
| 131 | |
| 132 var isChanged = previousScriptState.length !== positions.length; | |
| 133 for (var i = 0; !isChanged && i < positions.length; ++i) | |
| 134 isChanged = positions[i].line !== previousScriptState[i].line || pos itions[i].column !== previousScriptState[i].column; | |
| 135 if (!isChanged) | |
| 
dgozman
2016/02/17 01:34:44
hasChanged
 
kozy
2016/02/17 03:40:42
Done.
 | |
| 136 return; | |
| 137 | |
| 138 if (isBlackboxed) | |
| 
dgozman
2016/02/17 01:34:44
Can we get rid of this flag?
 
kozy
2016/02/17 03:40:42
We can't rid of this because when positions.length
 | |
| 139 script.setBlackboxedRanges(positions).then(this._setScriptState.bind (this, script)); | |
| 140 else | |
| 141 script.setBlackboxedRanges([]).then(this._setScriptState.bind(this, script)); | |
| 142 /** | |
| 143 * @param {!WebInspector.SourceMap.Entry} a | |
| 144 * @param {!WebInspector.SourceMap.Entry} b | |
| 
dgozman
2016/02/17 01:34:44
@return {number}
 
kozy
2016/02/17 03:40:43
Done.
 | |
| 145 */ | |
| 146 function mappingComparator(a, b) | |
| 147 { | |
| 148 if (a.lineNumber !== b.lineNumber) | |
| 149 return a.lineNumber - b.lineNumber; | |
| 150 return a.columnNumber - b.columnNumber; | |
| 151 } | |
| 152 }, | |
| 153 | |
| 154 /** | |
| 155 * @param {string} url | |
| 156 * @return {boolean} | |
| 157 */ | |
| 158 canBlackboxURL: function(url) | |
| 159 { | |
| 160 return !!this._urlToRegExpString(url); | |
| 161 }, | |
| 162 | |
| 163 /** | |
| 164 * @param {string} url | |
| 165 */ | |
| 166 blackboxURL: function(url) | |
| 167 { | |
| 168 var regexPatterns = WebInspector.moduleSetting("skipStackFramesPattern") .getAsArray(); | |
| 169 var regexValue = this._urlToRegExpString(url); | |
| 170 if (!regexValue) | |
| 171 return; | |
| 172 var found = false; | |
| 173 for (var i = 0; i < regexPatterns.length; ++i) { | |
| 174 var item = regexPatterns[i]; | |
| 175 if (item.pattern === regexValue) { | |
| 176 item.disabled = false; | |
| 177 found = true; | |
| 178 break; | |
| 179 } | |
| 180 } | |
| 181 if (!found) | |
| 182 regexPatterns.push({ pattern: regexValue }); | |
| 183 WebInspector.moduleSetting("skipStackFramesPattern").setAsArray(regexPat terns); | |
| 184 }, | |
| 185 | |
| 186 /** | |
| 187 * @param {string} url | |
| 188 * @param {boolean} isContentScript | |
| 189 */ | |
| 190 unblackbox: function(url, isContentScript) | |
| 191 { | |
| 192 if (isContentScript) | |
| 193 WebInspector.moduleSetting("skipContentScripts").set(false); | |
| 194 | |
| 195 var regexPatterns = WebInspector.moduleSetting("skipStackFramesPattern") .getAsArray(); | |
| 196 var regexValue = WebInspector.blackboxManager._urlToRegExpString(url); | |
| 197 if (!regexValue) | |
| 198 return; | |
| 199 regexPatterns = regexPatterns.filter(function(item) { | |
| 200 return item.pattern !== regexValue; | |
| 201 }); | |
| 202 for (var i = 0; i < regexPatterns.length; ++i) { | |
| 203 var item = regexPatterns[i]; | |
| 204 if (item.disabled) | |
| 205 continue; | |
| 206 try { | |
| 207 var regex = new RegExp(item.pattern); | |
| 208 if (regex.test(url)) | |
| 209 item.disabled = true; | |
| 210 } catch (e) { | |
| 211 } | |
| 212 } | |
| 213 WebInspector.moduleSetting("skipStackFramesPattern").setAsArray(regexPat terns); | |
| 214 }, | |
| 215 | |
| 216 _patternChanged: function() | |
| 217 { | |
| 218 this._isBlackboxedURLCache.clear(); | |
| 219 this._scripts.clear(); | |
| 220 | |
| 221 var promises = []; | |
| 222 for (var debuggerModel of WebInspector.DebuggerModel.instances()) { | |
| 223 for (var scriptId in debuggerModel.scripts) { | |
| 224 var script = debuggerModel.scripts[scriptId]; | |
| 225 promises.push(this._addScript(script).then(loadSourceMap.bind(th is, script))); | |
| 
dgozman
2016/02/17 01:34:44
this._addScript(script)
    .then(() => this._sour
 
kozy
2016/02/17 03:40:42
Done.
 | |
| 226 } | |
| 227 } | |
| 228 Promise.all(promises).then(this._patternChangeFinishedForTests); | |
| 229 | |
| 230 /** | |
| 231 * @param {!WebInspector.Script} script | |
| 232 * @this {!WebInspector.BlackboxManager} | |
| 233 */ | |
| 234 function loadSourceMap(script) | |
| 235 { | |
| 236 this.sourceMapLoaded(script, this._sourceMapForScript(script)); | |
| 237 } | |
| 238 }, | |
| 239 | |
| 240 // This method is sniffed in tests. | |
| 241 _patternChangeFinishedForTests: function() | |
| 242 { | |
| 243 }, | |
| 244 | |
| 245 _globalObjectCleared: function() | |
| 246 { | |
| 247 this._scripts.clear(); | |
| 248 this._isBlackboxedURLCache.clear(); | |
| 249 }, | |
| 250 | |
| 251 /** | |
| 252 * @param {!WebInspector.Event} event | |
| 253 */ | |
| 254 _parsedScriptSource: function(event) | |
| 255 { | |
| 256 var script = /** @type {!WebInspector.Script} */ (event.data); | |
| 257 this._addScript(script); | |
| 258 }, | |
| 259 | |
| 260 /** | |
| 261 * @param {!WebInspector.Script} script | |
| 262 * @return {!Promise<undefined>} | |
| 263 */ | |
| 264 _addScript: function(script) | |
| 265 { | |
| 266 var blackboxed = this._isBlackboxedScript(script); | |
| 267 if (!blackboxed) | |
| 268 return Promise.resolve(this._setScriptState(script, [])); | |
| 269 return script.setBlackboxedRanges([ { line: 0, column: 0 } ]).then(this. _setScriptState.bind(this, script)); | |
| 270 }, | |
| 271 | |
| 272 /** | |
| 273 * @param {!WebInspector.Script} script | |
| 274 * @return {boolean} | |
| 275 */ | |
| 276 _isBlackboxedScript: function(script) | |
| 277 { | |
| 278 if (script.isContentScript() && WebInspector.moduleSetting("skipContentS cripts").get()) | |
| 279 return true; | |
| 280 return this.isBlackboxedURL(script.sourceURL); | |
| 281 }, | |
| 282 | |
| 283 /** | |
| 284 * @param {!WebInspector.Script} script | |
| 285 * @return {?WebInspector.SourceMap} | |
| 286 */ | |
| 287 _sourceMapForScript: function(script) | |
| 288 { | |
| 289 return this._debuggerWorkspaceBinding.sourceMapForScript(script); | |
| 
dgozman
2016/02/17 01:34:44
Inline it!
 
kozy
2016/02/17 03:40:43
Done.
 | |
| 290 }, | |
| 291 | |
| 292 /** | |
| 293 * @param {!WebInspector.Script} script | |
| 294 * @param {?Array<!DebuggerAgent.ScriptPosition>} positions | |
| 295 */ | |
| 296 _setScriptState: function(script, positions) | |
| 297 { | |
| 298 if (positions) | |
| 299 this._scripts.set(script.scriptId, positions); | |
| 300 else if (!this._scripts.has(script.scriptId)) | |
| 301 this._scripts.set(script.scriptId, []); | |
| 302 }, | |
| 303 | |
| 304 /** | |
| 305 * @param {string} url | |
| 306 * @return {string} | |
| 307 */ | |
| 308 _urlToRegExpString: function(url) | |
| 309 { | |
| 310 var parsedURL = new WebInspector.ParsedURL(url); | |
| 311 if (parsedURL.isAboutBlank() || parsedURL.isDataURL()) | |
| 312 return ""; | |
| 313 if (!parsedURL.isValid) | |
| 314 return "^" + url.escapeForRegExp() + "$"; | |
| 315 var name = parsedURL.lastPathComponent; | |
| 316 if (name) | |
| 317 name = "/" + name; | |
| 318 else if (parsedURL.folderPathComponents) | |
| 319 name = parsedURL.folderPathComponents + "/"; | |
| 320 if (!name) | |
| 321 name = parsedURL.host; | |
| 322 if (!name) | |
| 323 return ""; | |
| 324 var scheme = parsedURL.scheme; | |
| 325 var prefix = ""; | |
| 326 if (scheme && scheme !== "http" && scheme !== "https") { | |
| 327 prefix = "^" + scheme + "://"; | |
| 328 if (scheme === "chrome-extension") | |
| 329 prefix += parsedURL.host + "\\b"; | |
| 330 prefix += ".*"; | |
| 331 } | |
| 332 return prefix + name.escapeForRegExp() + (url.endsWith(name) ? "$" : "\\ b"); | |
| 333 } | |
| 334 } | |
| 335 | |
| 336 /** @type {!WebInspector.BlackboxManager} */ | |
| 337 WebInspector.blackboxManager; | |
| OLD | NEW |