mirror of
https://github.com/react/react-native-devtools-frontend.git
synced 2026-09-29 16:57:00 +08:00
[bindings] Fix location translation for inline script with #sourceURL=
Translation between source locations of inline scripts with #sourceURL= did not work correctly, because the SourceFormatter handled them like inline scripts. DevTools opens them in its own window, and then continues to refer to locations in the file by the original positions in the containing document; however, the line endings used for formatting are line endings for the script only (in contrast to line endings for other inline scripts, which just reuse the line endings of the containing document). This CL adds a hack to handle inline scripts with #sourceURL= separately which entails that the SourceFormatter now also needs to know that such scripts are displayed in their own frame (as it is supposed to produce valid uiLocations). A redesign at some point in the future must clean this up; at the moment only fragmental knowledge about how this is supposed to work exists. Bug: chromium:1003497, chromium:1005789 Fixes: chromium:1017738 Change-Id: I3e13c6bc76b8692ce6badc09880c41d1a7e444c4 Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/1875713 Commit-Queue: Sigurd Schneider <sigurds@chromium.org> Reviewed-by: Benedikt Meurer <bmeurer@chromium.org>
This commit is contained in:
committed by
Commit Bot
parent
821269c8f7
commit
d3ddd33257
+18
-2
@@ -245,10 +245,26 @@ export default class Script {
|
||||
/**
|
||||
* @param {number} lineNumber
|
||||
* @param {number=} columnNumber
|
||||
* @return {!SDK.DebuggerModel.Location}
|
||||
* @return {?SDK.DebuggerModel.Location}
|
||||
*/
|
||||
rawLocation(lineNumber, columnNumber) {
|
||||
return new SDK.DebuggerModel.Location(this.debuggerModel, this.scriptId, lineNumber, columnNumber || 0);
|
||||
if (this.containsLocation(lineNumber, columnNumber)) {
|
||||
return new SDK.DebuggerModel.Location(this.debuggerModel, this.scriptId, lineNumber, columnNumber);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {!SDK.DebuggerModel.Location} location
|
||||
* @return {!Array.<number>}
|
||||
*/
|
||||
toRelativeLocation(location) {
|
||||
console.assert(
|
||||
location.scriptId === this.scriptId, '`toRelativeLocation` must be used with location of the same script');
|
||||
const relativeLineNumber = location.lineNumber - this.lineOffset;
|
||||
const relativeColumnNumber = (location.columnNumber || 0) - (relativeLineNumber === 0 ? this.columnOffset : 0);
|
||||
return [relativeLineNumber, relativeColumnNumber];
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -170,10 +170,24 @@ Sources.SourceFormatter.ScriptMapping = class {
|
||||
if (!formatData) {
|
||||
return null;
|
||||
}
|
||||
const lineNumber = rawLocation.lineNumber;
|
||||
const columnNumber = rawLocation.columnNumber || 0;
|
||||
const formattedLocation = formatData.mapping.originalToFormatted(lineNumber, columnNumber);
|
||||
return formatData.formattedSourceCode.uiLocation(formattedLocation[0], formattedLocation[1]);
|
||||
if (script.isInlineScriptWithSourceURL()) {
|
||||
// Inline scripts with #sourceURL= have lineEndings wrt. the inline script (and not wrt. the containing document),
|
||||
// but `rawLocation` will always use locations wrt. the containing document, because that is what the back-end is
|
||||
// sending. This is a hack, because what we are really doing here is deciding the location based on /how/ the
|
||||
// script is displayed, which is really something this layer cannot and should not have to decide: The
|
||||
// SourceFormatter should not have to know wether a script is displayed inline (in its containing document) or
|
||||
// stand-alone.
|
||||
const [relativeLineNumber, relativeColumnNumber] = script.toRelativeLocation(rawLocation);
|
||||
const [formattedLineNumber, formattedColumnNumber] =
|
||||
formatData.mapping.originalToFormatted(relativeLineNumber, relativeColumnNumber);
|
||||
return formatData.formattedSourceCode.uiLocation(formattedLineNumber, formattedColumnNumber);
|
||||
}
|
||||
// Here we either have an inline script without a #sourceURL= or a stand-alone script. For stand-alone scripts, no
|
||||
// translation must be applied. For inline scripts, also no translation must be applied, because the line-endings
|
||||
// tables in the mapping are the same as in the containing document.
|
||||
const [lineNumber, columnNumber] =
|
||||
formatData.mapping.originalToFormatted(rawLocation.lineNumber, rawLocation.columnNumber || 0);
|
||||
return formatData.formattedSourceCode.uiLocation(lineNumber, columnNumber);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -189,9 +203,29 @@ Sources.SourceFormatter.ScriptMapping = class {
|
||||
return [];
|
||||
}
|
||||
const [originalLine, originalColumn] = formatData.mapping.formattedToOriginal(lineNumber, columnNumber);
|
||||
const scripts = this._scriptsForUISourceCode(formatData.originalSourceCode)
|
||||
.filter(script => script.containsLocation(originalLine, originalColumn));
|
||||
return scripts.map(script => script.debuggerModel.createRawLocation(script, originalLine, originalColumn));
|
||||
if (formatData.originalSourceCode.contentType().isScript()) {
|
||||
// Here we have a script that is displayed on its own (i.e. it has a dedicated uiSourceCode). This means it is
|
||||
// either a stand-alone script or an inline script with a #sourceURL= and in both cases we can just forward the
|
||||
// question to the original (unformatted) source code.
|
||||
const rawLocations = Bindings.debuggerWorkspaceBinding.uiLocationToRawLocations(
|
||||
formatData.originalSourceCode, originalLine, originalColumn);
|
||||
console.assert(rawLocations.every(l => l && !!l.script()));
|
||||
return rawLocations;
|
||||
}
|
||||
if (formatData.originalSourceCode.contentType() === Common.resourceTypes.Document) {
|
||||
const target = Bindings.NetworkProject.targetForUISourceCode(formatData.originalSourceCode);
|
||||
const debuggerModel = target && target.model(SDK.DebuggerModel);
|
||||
if (debuggerModel) {
|
||||
const scripts = debuggerModel.scriptsForSourceURL(formatData.originalSourceCode.url())
|
||||
.filter(script => script.isInlineScript() && !script.hasSourceURL);
|
||||
// Here we have an inline script, which was formatted together with the containing document, so we must not
|
||||
// translate locations as they are relative to the start of the document.
|
||||
const locations = scripts.map(script => script.rawLocation(originalLine, originalColumn)).filter(l => !!l);
|
||||
console.assert(locations.every(l => l && !!l.script()));
|
||||
return locations;
|
||||
}
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user