Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(11)

Side by Side Diff: third_party/WebKit/Source/devtools/front_end/sources/SourceMapNamesResolver.js

Issue 1770263002: Devtools: resolve expressions in minified scripts with sourcemaps (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « third_party/WebKit/Source/devtools/front_end/sources/JavaScriptSourceFrame.js ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 WebInspector.SourceMapNamesResolver = {}; 5 WebInspector.SourceMapNamesResolver = {};
6 6
7 WebInspector.SourceMapNamesResolver._cachedMapSymbol = Symbol("cache"); 7 WebInspector.SourceMapNamesResolver._cachedMapSymbol = Symbol("cache");
8 WebInspector.SourceMapNamesResolver._cachedPromiseSymbol = Symbol("cache"); 8 WebInspector.SourceMapNamesResolver._cachedPromiseSymbol = Symbol("cachePromise" );
9 9
10 /** 10 /**
11 * @param {!WebInspector.DebuggerModel.Scope} scope 11 * @param {!WebInspector.DebuggerModel.Scope} scope
12 * @return {!Promise.<!Map<string, string>>} 12 * @return {!Promise.<!Map<string, string>>}
13 */ 13 */
14 WebInspector.SourceMapNamesResolver._resolveScope = function(scope) 14 WebInspector.SourceMapNamesResolver._resolveScope = function(scope)
15 { 15 {
16 var cachedMap = scope[WebInspector.SourceMapNamesResolver._cachedMapSymbol]; 16 var cachedMap = scope[WebInspector.SourceMapNamesResolver._cachedMapSymbol];
17 if (cachedMap) 17 if (cachedMap)
18 return Promise.resolve(cachedMap); 18 return Promise.resolve(cachedMap);
19 19
20 var cachedPromise = scope[WebInspector.SourceMapNamesResolver._cachedPromise Symbol]; 20 var cachedPromise = scope[WebInspector.SourceMapNamesResolver._cachedPromise Symbol];
21 if (cachedPromise) 21 if (cachedPromise)
22 return cachedPromise; 22 return cachedPromise;
23 23
24 var startLocation = scope.startLocation(); 24 var startLocation = scope.startLocation();
25 var endLocation = scope.endLocation(); 25 var endLocation = scope.endLocation();
26 var script = startLocation.script();
27 26
28 if (scope.type() === DebuggerAgent.ScopeType.Global || !startLocation || !en dLocation || !script.sourceMapURL || script !== endLocation.script()) 27 if (scope.type() === DebuggerAgent.ScopeType.Global || !startLocation || !en dLocation || !startLocation.script().sourceMapURL || (startLocation.script() !== endLocation.script()))
29 return Promise.resolve(new Map()); 28 return Promise.resolve(new Map());
30 29
30 var script = startLocation.script();
31 var sourceMap = WebInspector.debuggerWorkspaceBinding.sourceMapForScript(scr ipt); 31 var sourceMap = WebInspector.debuggerWorkspaceBinding.sourceMapForScript(scr ipt);
32 if (!sourceMap) 32 if (!sourceMap)
33 return Promise.resolve(new Map()); 33 return Promise.resolve(new Map());
34 34
35 var promise = script.requestContent().then(onContent); 35 var promise = script.requestContent().then(onContent);
36 scope[WebInspector.SourceMapNamesResolver._cachedPromiseSymbol] = promise; 36 scope[WebInspector.SourceMapNamesResolver._cachedPromiseSymbol] = promise;
37 return promise; 37 return promise;
38 38
39 /** 39 /**
40 * @param {?string} content 40 * @param {?string} content
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
110 namesMapping.set(id.name, entry.name); 110 namesMapping.set(id.name, entry.name);
111 } 111 }
112 112
113 scope[WebInspector.SourceMapNamesResolver._cachedMapSymbol] = namesMappi ng; 113 scope[WebInspector.SourceMapNamesResolver._cachedMapSymbol] = namesMappi ng;
114 delete scope[WebInspector.SourceMapNamesResolver._cachedPromiseSymbol]; 114 delete scope[WebInspector.SourceMapNamesResolver._cachedPromiseSymbol];
115 return namesMapping; 115 return namesMapping;
116 } 116 }
117 } 117 }
118 118
119 /** 119 /**
120 * @param {!WebInspector.DebuggerModel.CallFrame} callFrame
121 * @return {!Promise.<!Map<string, string>>}
122 */
123 WebInspector.SourceMapNamesResolver._allVariablesInCallFrame = function(callFram e)
124 {
125 var cached = callFrame[WebInspector.SourceMapNamesResolver._cachedMapSymbol] ;
126 if (cached)
127 return Promise.resolve(cached);
128
129 var promises = [];
130 var scopeChain = callFrame.scopeChain();
131 for (var i = 0; i < scopeChain.length; ++i)
132 promises.push(WebInspector.SourceMapNamesResolver._resolveScope(scopeCha in[i]));
133
134 return Promise.all(promises).then(mergeVariables);
135
136 /**
137 * @param {!Array<!Map<string, string>>} nameMappings
138 * @return {!Map<string, string>}
139 */
140 function mergeVariables(nameMappings)
141 {
142 var reverseMapping = new Map();
143 for (var map of nameMappings) {
144 for (var compiledName of map.keys()) {
145 var originalName = map.get(compiledName);
146 if (!reverseMapping.has(originalName))
147 reverseMapping.set(originalName, compiledName);
148 }
149 }
150 callFrame[WebInspector.SourceMapNamesResolver._cachedMapSymbol] = revers eMapping;
151 return reverseMapping;
152 }
153 }
154
155 /**
156 * @param {!WebInspector.DebuggerModel.CallFrame} callFrame
157 * @param {string} originalText
158 * @param {!WebInspector.UISourceCode} uiSourceCode
159 * @param {number} lineNumber
160 * @param {number} startColumnNumber
161 * @param {number} endColumnNumber
162 * @return {!Promise<string>}
163 */
164 WebInspector.SourceMapNamesResolver.resolveExpression = function(callFrame, orig inalText, uiSourceCode, lineNumber, startColumnNumber, endColumnNumber)
165 {
166 if (!Runtime.experiments.isEnabled("resolveVariableNames"))
167 return Promise.resolve("");
168
169 return WebInspector.SourceMapNamesResolver._allVariablesInCallFrame(callFram e).then(findCompiledName);
170
171 /**
172 * @param {!Map<string, string>} reverseMapping
173 * @return {!Promise<string>}
174 */
175 function findCompiledName(reverseMapping)
176 {
177 if (reverseMapping.has(originalText))
178 return Promise.resolve(reverseMapping.get(originalText) || "");
179
180 return WebInspector.SourceMapNamesResolver._resolveExpression(callFrame, uiSourceCode, lineNumber, startColumnNumber, endColumnNumber)
181 }
182 }
183
184 /**
185 * @param {!WebInspector.DebuggerModel.CallFrame} callFrame
186 * @param {!WebInspector.UISourceCode} uiSourceCode
187 * @param {number} lineNumber
188 * @param {number} startColumnNumber
189 * @param {number} endColumnNumber
190 * @return {!Promise<string>}
191 */
192 WebInspector.SourceMapNamesResolver._resolveExpression = function(callFrame, uiS ourceCode, lineNumber, startColumnNumber, endColumnNumber)
193 {
194 var target = callFrame.target();
195 var rawLocation = WebInspector.debuggerWorkspaceBinding.uiLocationToRawLocat ion(target, uiSourceCode, lineNumber, startColumnNumber);
196 if (!rawLocation)
197 return Promise.resolve("");
198
199 var script = rawLocation.script();
200 var sourceMap = WebInspector.debuggerWorkspaceBinding.sourceMapForScript(scr ipt);
201 if (!sourceMap)
202 return Promise.resolve("");
203
204 /**
205 * @param {!{lineNumber: number, columnNumber: number}} position
206 * @param {!WebInspector.SourceMap.Entry} mapping
207 * @return {number}
208 */
209 function comparator(position, mapping)
210 {
211 if (position.lineNumber !== mapping.sourceLineNumber)
212 return position.lineNumber - mapping.sourceLineNumber;
213
214 return position.columnNumber - mapping.sourceColumnNumber;
215 }
216
217 var mappings = sourceMap.reversedMappings(uiSourceCode.url());
218 var startIndex = mappings.lowerBound({lineNumber: lineNumber, columnNumber: startColumnNumber}, comparator);
dgozman 2016/03/08 18:26:42 Let's move this to SourceMap.reverseMapTextRange.
sergeyv 2016/03/08 22:53:04 Done.
219 var endIndex = mappings.upperBound({lineNumber: lineNumber, columnNumber: en dColumnNumber}, comparator);
220
221 var startMapping = mappings[startIndex];
222 var endMapping = mappings[endIndex];
223
224 if (startMapping === endMapping)
225 return Promise.resolve("");
226
227 return script.requestContent().then(onContent);
228
229 /**
230 * @param {?string} content
231 * @return {string}
232 */
233 function onContent(content)
234 {
235 if (!content)
236 return "";
237
238 var textRange = new WebInspector.TextRange(startMapping.lineNumber, star tMapping.columnNumber, endMapping.lineNumber, endMapping.columnNumber);
239 var originalText = textRange.extract(content);
240 var tokenizer = acorn.tokenizer(originalText, {ecmaVersion: 6});
241 try {
242 var token = tokenizer.getToken();
243 while (token.type !== acorn.tokTypes.eof && WebInspector.AcornTokeni zer.punctuator(token))
244 token = tokenizer.getToken();
245
246 var startIndex = token.start;
247 var endIndex = token.end;
248 while (token.type !== acorn.tokTypes.eof) {
249 var isIdentifier = WebInspector.AcornTokenizer.identifier(token) ;
250 var isThis = WebInspector.AcornTokenizer.keyword(token, "this");
251 var isString = token.type === acorn.tokTypes.string;
252 if (!isThis && !isIdentifier && !isString)
253 break;
254
255 endIndex = token.end;
256 token = tokenizer.getToken();
257 while (WebInspector.AcornTokenizer.punctuator(token, ".[]")) {
258 if (WebInspector.AcornTokenizer.punctuator(token, "]"))
259 endIndex = token.end;
dgozman 2016/03/08 18:26:42 Let's not do this if current balance of [] is zero
sergeyv 2016/03/08 22:53:04 Done.
260
261 token = tokenizer.getToken();
262 }
263 }
264 return originalText.substring(startIndex, endIndex);
265 } catch (e) {
266 return "";
267 }
268 }
269 }
270
271 /**
120 * @param {!WebInspector.DebuggerModel.Scope} scope 272 * @param {!WebInspector.DebuggerModel.Scope} scope
121 * @return {!WebInspector.RemoteObject} 273 * @return {!WebInspector.RemoteObject}
122 */ 274 */
123 WebInspector.SourceMapNamesResolver.resolveScopeInObject = function(scope) 275 WebInspector.SourceMapNamesResolver.resolveScopeInObject = function(scope)
124 { 276 {
125 if (!Runtime.experiments.isEnabled("resolveVariableNames")) 277 if (!Runtime.experiments.isEnabled("resolveVariableNames"))
126 return scope.object(); 278 return scope.object();
127 279
128 var startLocation = scope.startLocation(); 280 var startLocation = scope.startLocation();
129 var endLocation = scope.endLocation(); 281 var endLocation = scope.endLocation();
(...skipping 242 matching lines...) Expand 10 before | Expand all | Expand 10 after
372 * @override 524 * @override
373 * @param {function(?Array<!DebuggerAgent.CollectionEntry>)} callback 525 * @param {function(?Array<!DebuggerAgent.CollectionEntry>)} callback
374 */ 526 */
375 collectionEntries: function(callback) 527 collectionEntries: function(callback)
376 { 528 {
377 this._object.collectionEntries(callback); 529 this._object.collectionEntries(callback);
378 }, 530 },
379 531
380 __proto__: WebInspector.RemoteObject.prototype 532 __proto__: WebInspector.RemoteObject.prototype
381 } 533 }
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/devtools/front_end/sources/JavaScriptSourceFrame.js ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698