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 |