Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2016 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 */ | |
| 8 WebInspector.SourceMapNamesResolver = function() | |
| 9 { | |
| 10 this._resolvingPromises = new Map(); | |
| 11 } | |
| 12 | |
| 13 WebInspector.SourceMapNamesResolver._cacheSymbol = Symbol("cache"); | |
| 14 | |
| 15 WebInspector.SourceMapNamesResolver.prototype = { | |
| 16 /** | |
| 17 * @param {!WebInspector.DebuggerModel.Scope} scope | |
| 18 * @return {!Promise.<!Map<string, string>>} | |
| 19 */ | |
| 20 _resolveScope: function(scope) | |
| 21 { | |
| 22 var cachedMap = scope[WebInspector.SourceMapNamesResolver._cacheSymbol]; | |
| 23 if (cachedMap) | |
| 24 return Promise.resolve(cachedMap); | |
| 25 | |
| 26 var startLocation = scope.startLocation(); | |
| 27 var endLocation = scope.endLocation(); | |
| 28 var script = startLocation.script(); | |
| 29 | |
| 30 if (scope.type() === DebuggerAgent.ScopeType.Global || !startLocation || !endLocation || !script.sourceMapURL || script !== endLocation.script()) | |
| 31 return Promise.resolve(new Map()); | |
| 32 | |
| 33 var cachedPromise = this._resolvingPromises.get(scope); | |
|
dgozman
2016/02/22 17:24:56
Move this check before |var startLocation = ...|
sergeyv
2016/02/22 21:42:54
Done.
| |
| 34 if (cachedPromise) | |
| 35 return cachedPromise; | |
| 36 | |
| 37 var sourceMap = WebInspector.debuggerWorkspaceBinding.sourceMapForScript (script); | |
| 38 if (!sourceMap) | |
| 39 return Promise.resolve(new Map()); | |
| 40 | |
| 41 var promise = script.requestContent().then(onContent.bind(this)); | |
| 42 this._resolvingPromises.set(scope, promise); | |
| 43 return promise; | |
| 44 | |
| 45 /** | |
| 46 * @param {?string} content | |
| 47 * @return {!Map<string, string>} | |
| 48 * @this {WebInspector.SourceMapNamesResolver} | |
| 49 */ | |
| 50 function onContent(content) | |
| 51 { | |
| 52 if (!content) | |
| 53 return new Map(); | |
| 54 | |
| 55 var startLocation = scope.startLocation(); | |
| 56 var endLocation = scope.endLocation(); | |
| 57 var textRange = new WebInspector.TextRange(startLocation.lineNumber, startLocation.columnNumber, endLocation.lineNumber, endLocation.columnNumber); | |
| 58 | |
| 59 var scopeText = textRange.extract(content); | |
| 60 var scopeStart = textRange.toSourceRange(content).offset; | |
| 61 var prefix = "function fui"; | |
|
dgozman
2016/02/22 17:24:56
Maybe add () after function name for perfectly val
sergeyv
2016/02/22 21:42:54
usually scopes start with (); so we shouldn't add
| |
| 62 var root = acorn.parse(prefix + scopeText, {}); | |
| 63 var declarators = []; | |
| 64 var functionDeclarationCounter = 0; | |
| 65 var walker = new WebInspector.ESTreeWalker(beforeVisit, afterVisit); | |
| 66 | |
| 67 /** | |
| 68 * @param {!ESTree.Node} node | |
| 69 */ | |
| 70 function beforeVisit(node) | |
| 71 { | |
| 72 if (node.type === "FunctionDeclaration" || node.type === "Functi onExpression") | |
|
dgozman
2016/02/22 17:24:56
Does it support arrow functions?
sergeyv
2016/02/22 21:42:54
I will check this && support it in follow-ups
| |
| 73 functionDeclarationCounter++; | |
| 74 | |
| 75 if (node.type === "VariableDeclarator" && functionDeclarationCou nter === 1) | |
| 76 declarators.push(node) | |
|
dgozman
2016/02/22 17:24:56
missing semicolon
sergeyv
2016/02/22 21:42:54
Done.
| |
| 77 } | |
| 78 | |
| 79 /** | |
| 80 * @param {!ESTree.Node} node | |
| 81 */ | |
| 82 function afterVisit(node) | |
| 83 { | |
| 84 if (node.type === "FunctionDeclaration" || node.type === "Functi onExpression") | |
| 85 functionDeclarationCounter--; | |
| 86 } | |
| 87 | |
| 88 walker.walk(root); | |
| 89 | |
| 90 var namesMapping = new Map(); | |
| 91 | |
| 92 for (var i = 0; i < declarators.length; ++i) { | |
| 93 var id = declarators[i].id; | |
| 94 var start = scopeStart + id.start - prefix.length; | |
| 95 | |
| 96 var lineEndings = content.lineEndings(); | |
|
dgozman
2016/02/22 17:24:56
Move this call out of the loop.
sergeyv
2016/02/22 21:42:54
Done. But there was no real necessity in this: lin
| |
| 97 var lineNumber = lineEndings.lowerBound(start); | |
| 98 var columnNumber = start - (lineNumber === 0 ? 0 : (lineEndings[ lineNumber - 1] + 1)); | |
| 99 var entry = sourceMap.findEntry(lineNumber, columnNumber); | |
| 100 if (entry) | |
| 101 namesMapping.set(id.name, entry.name); | |
| 102 } | |
| 103 | |
| 104 this._resolvingPromises.remove(scope); | |
| 105 scope[WebInspector.SourceMapNamesResolver._cacheSymbol] = namesMappi ng; | |
| 106 return namesMapping; | |
| 107 } | |
| 108 }, | |
| 109 | |
| 110 /** | |
| 111 * @param {!WebInspector.DebuggerModel.Scope} scope | |
| 112 * @return {!WebInspector.RemoteObject} | |
| 113 */ | |
| 114 resolveScopeInObject: function(scope) | |
| 115 { | |
| 116 if (!Runtime.experiments.isEnabled("resolveVariableNames")) | |
| 117 return scope.object(); | |
| 118 | |
| 119 var startLocation = scope.startLocation(); | |
| 120 var endLocation = scope.endLocation(); | |
| 121 | |
| 122 if (scope.type() === DebuggerAgent.ScopeType.Global || !startLocation || !endLocation || !startLocation.script().sourceMapURL || startLocation.script() !== endLocation.script()) | |
| 123 return scope.object(); | |
| 124 | |
| 125 return new WebInspector.SourceMapNamesResolver.RemoteObject(scope); | |
| 126 } | |
| 127 } | |
| 128 | |
| 129 /** | |
| 130 * @constructor | |
| 131 * @extends {WebInspector.RemoteObject} | |
| 132 * @param {!WebInspector.DebuggerModel.Scope} scope | |
| 133 */ | |
| 134 WebInspector.SourceMapNamesResolver.RemoteObject = function(scope) | |
| 135 { | |
| 136 WebInspector.RemoteObject.call(this); | |
| 137 this._scope = scope; | |
| 138 this._object = scope.object(); | |
| 139 }; | |
| 140 | |
| 141 WebInspector.SourceMapNamesResolver.RemoteObject.prototype = { | |
| 142 /** | |
| 143 * @override | |
| 144 * @return {?RuntimeAgent.CustomPreview} | |
| 145 */ | |
| 146 customPreview: function() | |
| 147 { | |
| 148 return this._object.customPreview(); | |
| 149 }, | |
| 150 | |
| 151 /** | |
| 152 * @override | |
| 153 * @return {string} | |
| 154 */ | |
| 155 get type() | |
| 156 { | |
| 157 return this._object.type; | |
| 158 }, | |
| 159 | |
| 160 /** | |
| 161 * @override | |
| 162 * @return {string|undefined} | |
| 163 */ | |
| 164 get subtype() | |
| 165 { | |
| 166 return this._object.subtype; | |
| 167 }, | |
| 168 | |
| 169 /** | |
| 170 * @override | |
| 171 * @return {string|undefined} | |
| 172 */ | |
| 173 get description() | |
| 174 { | |
| 175 return this._object.description; | |
| 176 }, | |
| 177 | |
| 178 /** | |
| 179 * @override | |
| 180 * @return {boolean} | |
| 181 */ | |
| 182 get hasChildren() | |
| 183 { | |
| 184 return this._object.hasChildren; | |
| 185 }, | |
| 186 | |
| 187 /** | |
| 188 * @override | |
| 189 * @return {number} | |
| 190 */ | |
| 191 arrayLength: function() | |
| 192 { | |
| 193 return this._object.arrayLength(); | |
| 194 }, | |
| 195 | |
| 196 /** | |
| 197 * @override | |
| 198 * @param {function(?Array.<!WebInspector.RemoteObjectProperty>, ?Array.<!We bInspector.RemoteObjectProperty>)} callback | |
| 199 */ | |
| 200 getOwnProperties: function(callback) | |
| 201 { | |
| 202 this._object.getOwnProperties(callback); | |
| 203 }, | |
| 204 | |
| 205 /** | |
| 206 * @override | |
| 207 * @param {boolean} accessorPropertiesOnly | |
| 208 * @param {function(?Array<!WebInspector.RemoteObjectProperty>, ?Array<!WebI nspector.RemoteObjectProperty>)} callback | |
| 209 */ | |
| 210 getAllProperties: function(accessorPropertiesOnly, callback) | |
| 211 { | |
| 212 /** | |
| 213 * @param {?Array.<!WebInspector.RemoteObjectProperty>} properties | |
| 214 * @param {?Array.<!WebInspector.RemoteObjectProperty>} internalProperti es | |
| 215 * @this {WebInspector.SourceMapNamesResolver.RemoteObject} | |
| 216 */ | |
| 217 function wrappedCallback(properties, internalProperties) | |
| 218 { | |
| 219 WebInspector.sourceMapNamesResolver._resolveScope(this._scope).then( resolveNames.bind(null, properties, internalProperties)) | |
| 220 } | |
| 221 | |
| 222 /** | |
| 223 * @param {?Array.<!WebInspector.RemoteObjectProperty>} properties | |
| 224 * @param {?Array.<!WebInspector.RemoteObjectProperty>} internalProperti es | |
| 225 * @param {!Map<string, string>} namesMapping | |
| 226 */ | |
| 227 function resolveNames(properties, internalProperties, namesMapping) | |
| 228 { | |
| 229 var newProperties = []; | |
| 230 if (properties) { | |
| 231 for (var i = 0; i < properties.length; ++i) { | |
| 232 var property = properties[i]; | |
| 233 var name = namesMapping.get(property.name) || properties[i]. name; | |
| 234 newProperties.push(new WebInspector.RemoteObjectProperty(nam e, property.value, property.enumerable, property.writable, property.isOwn, prope rty.wasThrown, property.symbol, property.synthetic)); | |
| 235 } | |
| 236 } | |
| 237 | |
| 238 callback(newProperties, internalProperties); | |
| 239 } | |
| 240 | |
| 241 this._object.getAllProperties(accessorPropertiesOnly, wrappedCallback.bi nd(this)); | |
| 242 }, | |
| 243 | |
| 244 /** | |
| 245 * @override | |
| 246 * @param {string|!RuntimeAgent.CallArgument} argumentName | |
| 247 * @param {string} value | |
| 248 * @param {function(string=)} callback | |
| 249 */ | |
| 250 setPropertyValue: function(argumentName, value, callback) | |
| 251 { | |
| 252 WebInspector.sourceMapNamesResolver._resolveScope(this._scope).then(reso lveName.bind(this)); | |
| 253 | |
| 254 /** | |
| 255 * @param {!Map<string, string>} namesMapping | |
| 256 * @this {WebInspector.SourceMapNamesResolver.RemoteObject} | |
| 257 */ | |
| 258 function resolveName(namesMapping) | |
| 259 { | |
| 260 var name; | |
| 261 if (typeof argumentName === "string") | |
| 262 name = argumentName; | |
| 263 else | |
| 264 name = /** @type {string} */ (argumentName.value); | |
| 265 | |
| 266 var actualName = name; | |
| 267 for (var compiledName of namesMapping.keys()) { | |
|
dgozman
2016/02/22 17:24:56
Is this operation common enough to justify reverse
sergeyv
2016/02/22 21:42:54
It is used only when user changes a property value
| |
| 268 if (namesMapping.get(compiledName) === name) { | |
| 269 actualName = compiledName; | |
| 270 break; | |
| 271 } | |
| 272 } | |
| 273 this._object.setPropertyValue(actualName, value, callback); | |
| 274 } | |
| 275 }, | |
| 276 | |
| 277 /** | |
| 278 * @override | |
| 279 * @return {!Promise<?Array<!WebInspector.EventListener>>} | |
| 280 */ | |
| 281 eventListeners: function() | |
| 282 { | |
| 283 return this._object.eventListeners(); | |
| 284 }, | |
| 285 | |
| 286 /** | |
| 287 * @override | |
| 288 * @param {!RuntimeAgent.CallArgument} name | |
| 289 * @param {function(string=)} callback | |
| 290 */ | |
| 291 deleteProperty: function(name, callback) | |
| 292 { | |
| 293 this._object.deleteProperty(name, callback); | |
| 294 }, | |
| 295 | |
| 296 /** | |
| 297 * @override | |
| 298 * @param {function(this:Object, ...)} functionDeclaration | |
| 299 * @param {!Array<!RuntimeAgent.CallArgument>=} args | |
| 300 * @param {function(?WebInspector.RemoteObject, boolean=)=} callback | |
| 301 */ | |
| 302 callFunction: function(functionDeclaration, args, callback) | |
| 303 { | |
| 304 this._object.callFunction(functionDeclaration, args, callback); | |
| 305 }, | |
| 306 | |
| 307 /** | |
| 308 * @override | |
| 309 * @param {function(this:Object, ...)} functionDeclaration | |
| 310 * @param {!Array<!RuntimeAgent.CallArgument>|undefined} args | |
| 311 * @param {function(*)} callback | |
| 312 */ | |
| 313 callFunctionJSON: function(functionDeclaration, args, callback) | |
| 314 { | |
| 315 this._object.callFunctionJSON(functionDeclaration, args, callback); | |
| 316 }, | |
| 317 | |
| 318 /** | |
| 319 * @override | |
| 320 * @return {!WebInspector.Target} | |
| 321 */ | |
| 322 target: function() | |
| 323 { | |
| 324 return this._object.target(); | |
| 325 }, | |
| 326 | |
| 327 /** | |
| 328 * @override | |
| 329 * @return {?WebInspector.DebuggerModel} | |
| 330 */ | |
| 331 debuggerModel: function() | |
| 332 { | |
| 333 return this._object.debuggerModel(); | |
| 334 }, | |
| 335 | |
| 336 /** | |
| 337 * @override | |
| 338 * @return {boolean} | |
| 339 */ | |
| 340 isNode: function() | |
| 341 { | |
| 342 return this._object.isNode(); | |
| 343 }, | |
| 344 | |
| 345 /** | |
| 346 * @override | |
| 347 * @param {function(?WebInspector.DebuggerModel.FunctionDetails)} callback | |
| 348 */ | |
| 349 functionDetails: function(callback) | |
| 350 { | |
| 351 this._object.functionDetails(callback); | |
| 352 }, | |
| 353 | |
| 354 /** | |
| 355 * @override | |
| 356 * @param {function(?WebInspector.DebuggerModel.GeneratorObjectDetails)} cal lback | |
| 357 */ | |
| 358 generatorObjectDetails: function(callback) | |
| 359 { | |
| 360 this._object.generatorObjectDetails(callback); | |
| 361 }, | |
| 362 | |
| 363 /** | |
| 364 * @override | |
| 365 * @param {function(?Array<!DebuggerAgent.CollectionEntry>)} callback | |
| 366 */ | |
| 367 collectionEntries: function(callback) | |
| 368 { | |
| 369 this._object.collectionEntries(callback); | |
| 370 }, | |
| 371 | |
| 372 __proto__: WebInspector.RemoteObject.prototype | |
| 373 } | |
| 374 | |
| 375 WebInspector.sourceMapNamesResolver = new WebInspector.SourceMapNamesResolver(); | |
| OLD | NEW |