2 * Copyright (C) 2012 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
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.
33 * @implements {WebInspector.DebuggerSourceMapping}
34 * @param {!WebInspector.DebuggerModel} debuggerModel
35 * @param {!WebInspector.Workspace} workspace
36 * @param {!WebInspector.NetworkMapping} networkMapping
37 * @param {!WebInspector.NetworkProject} networkProject
38 * @param {!WebInspector.DebuggerWorkspaceBinding} debuggerWorkspaceBinding
40 WebInspector
.CompilerScriptMapping = function(debuggerModel
, workspace
, networkMapping
, networkProject
, debuggerWorkspaceBinding
)
42 this._target
= debuggerModel
.target();
43 this._debuggerModel
= debuggerModel
;
44 this._workspace
= workspace
;
45 this._workspace
.addEventListener(WebInspector
.Workspace
.Events
.UISourceCodeAdded
, this._uiSourceCodeAddedToWorkspace
, this);
46 this._networkMapping
= networkMapping
;
47 this._networkProject
= networkProject
;
48 this._debuggerWorkspaceBinding
= debuggerWorkspaceBinding
;
50 /** @type {!Object.<string, !WebInspector.SourceMap>} */
51 this._sourceMapForSourceMapURL
= {};
52 /** @type {!Object.<string, !Array.<function(?WebInspector.SourceMap)>>} */
53 this._pendingSourceMapLoadingCallbacks
= {};
54 /** @type {!Object.<string, !WebInspector.SourceMap>} */
55 this._sourceMapForScriptId
= {};
56 /** @type {!Map.<!WebInspector.SourceMap, !WebInspector.Script>} */
57 this._scriptForSourceMap
= new Map();
58 /** @type {!Map.<string, !WebInspector.SourceMap>} */
59 this._sourceMapForURL
= new Map();
60 /** @type {!Map.<string, !WebInspector.UISourceCode>} */
61 this._stubUISourceCodes
= new Map();
63 this._stubProjectID
= "compiler-script-project";
64 this._stubProjectDelegate
= new WebInspector
.ContentProviderBasedProjectDelegate(this._workspace
, this._stubProjectID
, WebInspector
.projectTypes
.Service
);
65 debuggerModel
.addEventListener(WebInspector
.DebuggerModel
.Events
.GlobalObjectCleared
, this._debuggerReset
, this);
68 WebInspector
.CompilerScriptMapping
.StubProjectID
= "compiler-script-project";
70 WebInspector
.CompilerScriptMapping
.prototype = {
72 * @param {!WebInspector.DebuggerModel.Location} rawLocation
75 mapsToSourceCode: function (rawLocation
) {
76 var sourceMap
= this._sourceMapForScriptId
[rawLocation
.scriptId
];
80 return !!sourceMap
.findEntry(rawLocation
.lineNumber
, rawLocation
.columnNumber
);
85 * @param {!WebInspector.DebuggerModel.Location} rawLocation
86 * @return {?WebInspector.UILocation}
88 rawLocationToUILocation: function(rawLocation
)
90 var debuggerModelLocation
= /** @type {!WebInspector.DebuggerModel.Location} */ (rawLocation
);
92 var stubUISourceCode
= this._stubUISourceCodes
.get(debuggerModelLocation
.scriptId
);
94 return new WebInspector
.UILocation(stubUISourceCode
, rawLocation
.lineNumber
, rawLocation
.columnNumber
);
96 var sourceMap
= this._sourceMapForScriptId
[debuggerModelLocation
.scriptId
];
99 var lineNumber
= debuggerModelLocation
.lineNumber
;
100 var columnNumber
= debuggerModelLocation
.columnNumber
|| 0;
101 var entry
= sourceMap
.findEntry(lineNumber
, columnNumber
);
102 if (!entry
|| !entry
.sourceURL
)
104 var uiSourceCode
= this._networkMapping
.uiSourceCodeForURL(/** @type {string} */ (entry
.sourceURL
), this._target
);
107 return uiSourceCode
.uiLocation(/** @type {number} */ (entry
.sourceLineNumber
), /** @type {number} */ (entry
.sourceColumnNumber
));
112 * @param {!WebInspector.UISourceCode} uiSourceCode
113 * @param {number} lineNumber
114 * @param {number} columnNumber
115 * @return {?WebInspector.DebuggerModel.Location}
117 uiLocationToRawLocation: function(uiSourceCode
, lineNumber
, columnNumber
)
119 if (uiSourceCode
.project().type() === WebInspector
.projectTypes
.Service
)
121 var networkURL
= this._networkMapping
.networkURL(uiSourceCode
);
124 var sourceMap
= this._sourceMapForURL
.get(networkURL
);
127 var script
= /** @type {!WebInspector.Script} */ (this._scriptForSourceMap
.get(sourceMap
));
128 console
.assert(script
);
129 var entry
= sourceMap
.firstSourceLineMapping(networkURL
, lineNumber
);
132 return this._debuggerModel
.createRawLocation(script
, entry
.lineNumber
, entry
.columnNumber
);
136 * @param {!WebInspector.Script} script
138 addScript: function(script
)
140 if (!script
.sourceMapURL
) {
141 script
.addEventListener(WebInspector
.Script
.Events
.SourceMapURLAdded
, this._sourceMapURLAdded
.bind(this));
145 this._processScript(script
);
149 * @param {!WebInspector.Event} event
151 _sourceMapURLAdded: function(event
)
153 var script
= /** @type {!WebInspector.Script} */ (event
.target
);
154 if (!script
.sourceMapURL
)
156 this._processScript(script
);
160 * @param {!WebInspector.Script} script
162 _processScript: function(script
)
164 // Create stub UISourceCode for the time source mapping is being loaded.
165 var url
= script
.sourceURL
;
166 var splitURL
= WebInspector
.ParsedURL
.splitURLIntoPathComponents(url
);
167 var parentPath
= splitURL
.slice(1, -1).join("/");
168 var name
= splitURL
.peekLast() || "";
169 var uiSourceCodePath
= this._stubProjectDelegate
.addContentProvider(parentPath
, name
, url
, url
, new WebInspector
.StaticContentProvider(WebInspector
.resourceTypes
.Script
, "\n\n\n\n\n// Please wait a bit.\n// Compiled script is not shown while source map is being loaded!", url
));
170 var stubUISourceCode
= /** @type {!WebInspector.UISourceCode} */ (this._workspace
.uiSourceCode(this._stubProjectID
, uiSourceCodePath
));
171 this._stubUISourceCodes
.set(script
.scriptId
, stubUISourceCode
);
173 this._debuggerWorkspaceBinding
.pushSourceMapping(script
, this);
174 this._loadSourceMapForScript(script
, this._sourceMapLoaded
.bind(this, script
, uiSourceCodePath
));
178 * @param {!WebInspector.Script} script
179 * @param {string} uiSourceCodePath
180 * @param {?WebInspector.SourceMap} sourceMap
182 _sourceMapLoaded: function(script
, uiSourceCodePath
, sourceMap
)
184 this._stubUISourceCodes
.delete(script
.scriptId
);
185 this._stubProjectDelegate
.removeFile(uiSourceCodePath
);
188 this._debuggerWorkspaceBinding
.updateLocations(script
);
192 if (this._scriptForSourceMap
.get(sourceMap
)) {
193 this._sourceMapForScriptId
[script
.scriptId
] = sourceMap
;
194 this._debuggerWorkspaceBinding
.updateLocations(script
);
198 this._sourceMapForScriptId
[script
.scriptId
] = sourceMap
;
199 this._scriptForSourceMap
.set(sourceMap
, script
);
201 var sourceURLs
= sourceMap
.sources();
202 var missingSources
= [];
203 for (var i
= 0; i
< sourceURLs
.length
; ++i
) {
204 var sourceURL
= sourceURLs
[i
];
205 if (this._sourceMapForURL
.get(sourceURL
))
207 this._sourceMapForURL
.set(sourceURL
, sourceMap
);
208 if (!this._networkMapping
.hasMappingForURL(sourceURL
) && !this._networkMapping
.uiSourceCodeForURL(sourceURL
, script
.target())) {
209 var contentProvider
= sourceMap
.sourceContentProvider(sourceURL
, WebInspector
.resourceTypes
.Script
);
210 this._networkProject
.addFileForURL(sourceURL
, contentProvider
, script
.isContentScript());
212 var uiSourceCode
= this._networkMapping
.uiSourceCodeForURL(sourceURL
, this._target
);
214 this._bindUISourceCode(uiSourceCode
);
216 if (missingSources
.length
< 3)
217 missingSources
.push(sourceURL
);
218 else if (missingSources
.peekLast() !== "\u2026")
219 missingSources
.push("\u2026");
222 if (missingSources
.length
) {
223 WebInspector
.console
.warn(
224 WebInspector
.UIString("Source map %s points to the files missing from the workspace: [%s]",
225 sourceMap
.url(), missingSources
.join(", ")));
228 this._debuggerWorkspaceBinding
.updateLocations(script
);
235 isIdentity: function()
242 * @param {!WebInspector.UISourceCode} uiSourceCode
243 * @param {number} lineNumber
246 uiLineHasMapping: function(uiSourceCode
, lineNumber
)
248 var networkURL
= this._networkMapping
.networkURL(uiSourceCode
);
251 var sourceMap
= this._sourceMapForURL
.get(networkURL
);
254 return !!sourceMap
.firstSourceLineMapping(networkURL
, lineNumber
);
258 * @param {!WebInspector.UISourceCode} uiSourceCode
260 _bindUISourceCode: function(uiSourceCode
)
262 this._debuggerWorkspaceBinding
.setSourceMapping(this._target
, uiSourceCode
, this);
266 * @param {!WebInspector.UISourceCode} uiSourceCode
268 _unbindUISourceCode: function(uiSourceCode
)
270 this._debuggerWorkspaceBinding
.setSourceMapping(this._target
, uiSourceCode
, null);
274 * @param {!WebInspector.Event} event
276 _uiSourceCodeAddedToWorkspace: function(event
)
278 var uiSourceCode
= /** @type {!WebInspector.UISourceCode} */ (event
.data
);
279 var networkURL
= this._networkMapping
.networkURL(uiSourceCode
);
280 if (!networkURL
|| !this._sourceMapForURL
.get(networkURL
))
282 this._bindUISourceCode(uiSourceCode
);
286 * @param {!WebInspector.Script} script
287 * @param {function(?WebInspector.SourceMap)} callback
289 _loadSourceMapForScript: function(script
, callback
)
291 // script.sourceURL can be a random string, but is generally an absolute path -> complete it to inspected page url for
293 var scriptURL
= WebInspector
.ParsedURL
.completeURL(this._target
.resourceTreeModel
.inspectedPageURL(), script
.sourceURL
);
299 console
.assert(script
.sourceMapURL
);
300 var scriptSourceMapURL
= /** @type {string} */ (script
.sourceMapURL
);
302 var sourceMapURL
= WebInspector
.ParsedURL
.completeURL(scriptURL
, scriptSourceMapURL
);
308 var sourceMap
= this._sourceMapForSourceMapURL
[sourceMapURL
];
314 var pendingCallbacks
= this._pendingSourceMapLoadingCallbacks
[sourceMapURL
];
315 if (pendingCallbacks
) {
316 pendingCallbacks
.push(callback
);
320 pendingCallbacks
= [callback
];
321 this._pendingSourceMapLoadingCallbacks
[sourceMapURL
] = pendingCallbacks
;
323 WebInspector
.SourceMap
.load(sourceMapURL
, scriptURL
, sourceMapLoaded
.bind(this));
326 * @param {?WebInspector.SourceMap} sourceMap
327 * @this {WebInspector.CompilerScriptMapping}
329 function sourceMapLoaded(sourceMap
)
331 var url
= /** @type {string} */ (sourceMapURL
);
332 var callbacks
= this._pendingSourceMapLoadingCallbacks
[url
];
333 delete this._pendingSourceMapLoadingCallbacks
[url
];
337 this._sourceMapForSourceMapURL
[url
] = sourceMap
;
338 for (var i
= 0; i
< callbacks
.length
; ++i
)
339 callbacks
[i
](sourceMap
);
343 _debuggerReset: function()
346 * @param {string} sourceURL
347 * @this {WebInspector.CompilerScriptMapping}
349 function unbindUISourceCodeForURL(sourceURL
)
351 var uiSourceCode
= this._networkMapping
.uiSourceCodeForURL(sourceURL
, this._target
);
354 this._unbindUISourceCode(uiSourceCode
);
357 this._sourceMapForURL
.keysArray().forEach(unbindUISourceCodeForURL
.bind(this));
359 this._sourceMapForSourceMapURL
= {};
360 this._pendingSourceMapLoadingCallbacks
= {};
361 this._sourceMapForScriptId
= {};
362 this._scriptForSourceMap
.clear();
363 this._sourceMapForURL
.clear();
368 this._workspace
.removeEventListener(WebInspector
.Workspace
.Events
.UISourceCodeAdded
, this._uiSourceCodeAddedToWorkspace
, this);