/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
// This module converts Firefox specific types to the generic types
import {
hasSource,
hasSourceActor,
getSourceActor,
getSourceCount,
} from "../../selectors/index"; import { features } from "../../utils/prefs"; import {
isUrlExtension,
getRawSourceURL,
getFormattedSourceId,
} from "../../utils/source"; import { createLocation } from "../../utils/location"; import { getDisplayURL } from "../../utils/sources-tree/getURL";
let store;
/** * This function is to be called first before any other * and allow having access to any instances of classes that are * useful for this module * * @param {Object} dependencies * @param {Object} dependencies.store * The redux store object of the debugger frontend.
*/
export function setupCreate(dependencies) {
store = dependencies.store;
}
export async function createFrame(thread, frame, index = 0) { // Because of throttling, the source related to the top frame may be available a bit late. const sourceActor = await waitForSourceActorToBeRegisteredInStore(
frame.where.actor
);
/** * Create an original frame object. Similar to the frame objects generated by createFrame. * But with additional information related to SourceMap processing. * For example, location and generatedLocation will be different. * * @param {Function} getState * @param {Object} frame * The frame for the generated location, i.e. WASM binary code. * @param {String} id * The new ID to use for the new frame object. * @param {Object} originalFrame * An object crafted by the SourceMap Worker with additional information * about the original source code. i.e. the Rust, C++, whatever original source code. * See XScope.search() for definition of this object.
*/
export function createWasmOriginalFrame(
generatedFrame,
id,
originalFrame,
originalFrameLocation
) { return {
id, thread: generatedFrame.thread,
displayName: originalFrame.displayName,
location: originalFrameLocation,
generatedLocation: generatedFrame.generatedLocation, this: generatedFrame.this,
index: generatedFrame.index,
asyncCause: generatedFrame.asyncCause,
state: generatedFrame.state,
type: generatedFrame.type,
// All additional fields only available for WASM original frames
isOriginal: true,
originalDisplayName: originalFrame.displayName,
originalVariables: originalFrame.variables,
};
}
/** * This method wait for the given source actor to be registered in Redux store. * * @param {String} sourceActorId * Actor ID of the source to be waiting for.
*/
async function waitForSourceActorToBeRegisteredInStore(sourceActorId) { if (!hasSourceActor(store.getState(), sourceActorId)) {
await new Promise(resolve => { const unsubscribe = store.subscribe(check);
let currentSize = null; function check() { const previousSize = currentSize;
currentSize = store.getState().sourceActors.mutableSourceActors.size; // For perf reason, avoid any extra computation if sources did not change if (previousSize == currentSize) { return;
} if (hasSourceActor(store.getState(), sourceActorId)) {
unsubscribe();
resolve();
}
}
});
} return getSourceActor(store.getState(), sourceActorId);
}
/** * This method wait for the given source to be registered in Redux store. * * @param {String} sourceId * The id of the source to be waiting for.
*/
export async function waitForSourceToBeRegisteredInStore(sourceId) { returnnew Promise(resolve => { if (hasSource(store.getState(), sourceId)) {
resolve(); return;
} const unsubscribe = store.subscribe(check);
let currentSize = null; function check() { const previousSize = currentSize;
currentSize = getSourceCount(store.getState()); // For perf reason, avoid any extra computation if sources did not change if (previousSize == currentSize) { return;
} if (hasSource(store.getState(), sourceId)) {
unsubscribe();
resolve();
}
}
});
}
// Compute the reducer's source ID for a given source front/resource. // // We have four kind of "sources": // * "sources" in sources.js reducer, which map to 1 or many: // * "source actors" in source-actors.js reducer, which map 1 for 1 with: // * "SOURCE" resources coming from ResourceCommand API // * SourceFront, which are retrieved via `ThreadFront.source(sourceResource)` // // Note that SOURCE resources are actually the "form" of the SourceActor, // with the addition of `resourceType` and `targetFront` attributes. // // Unfortunately, the debugger frontend interacts with these 4 type of objects. // The last three actually try to represent the exact same thing. // // Here this method received a SOURCE resource (the 3rd bullet point)
export function makeSourceId(sourceResource) { // Allows Jest to use custom, simplier IDs if ("mockedJestID" in sourceResource) { return sourceResource.mockedJestID;
} // By default, within a given target, all sources will be grouped by URL. // You will be having a unique Source object in sources.js reducer, // while you might have many Source Actor objects in source-actors.js reducer. // // There is two distinct usecases here: // * HTML pages, which will have one source object which represents the whole HTML page // and it will relate to many source actors. One for each inline <script> tag. // Each script tag's source actor will actually return the whole content of the html page // and not only this one script tag content. // * Scripts with the same URL injected many times. // For example, two <script src=""> with the same location // Or by using eval("...// # SourceURL=") // All the scripts will be grouped under a unique Source object, while having dedicated // Source Actor objects. // An important point this time is that each actor may have a different source text content. // For now, the debugger arbitrarily picks the first source actor's text content and never // updates it. (See bug 1751063) if (sourceResource.url) { return `source-url-${sourceResource.url}`;
}
// Otherwise, we are processing a source without URL. // This is typically evals, console evaluations, setTimeout/setInterval strings, // DOM event handler strings (i.e. `<div onclick="foo">`), ... // The main way to interact with them is to use a debugger statement from them, // or have other panels ask the debugger to open them (like DOM event handlers from the inspector). // We can register transient breakpoints against them (i.e. they will only apply to the current source actor instance) return `source-actor-${sourceResource.actor}`;
}
/** * Create the source object for a generated source that is stored in sources.js reducer. * These generated sources relate to JS code which run in the * debugged runtime (as oppose to original sources * which are only available in debugger's environment). * * @param {SOURCE} sourceResource * SOURCE resource coming from the ResourceCommand API. * This represents the `SourceActor` from the server codebase.
*/
export function createGeneratedSource(sourceResource) { return createSourceObject({
id: makeSourceId(sourceResource),
url: sourceResource.url,
extensionName: sourceResource.extensionName,
isWasm: !!features.wasm && sourceResource.introductionType === "wasm",
isExtension:
(sourceResource.url && isUrlExtension(sourceResource.url)) || false,
isHTML: !!sourceResource.isInlineSource,
});
}
/** * Create the source object that is stored in sources.js reducer. * * This is an internal helper to this module to ensure all sources have the same shape. * Do not use it outside of this module!
*/ function createSourceObject({
id,
url,
extensionName = null,
isWasm = false,
isExtension = false,
isPrettyPrinted = false,
isOriginal = false,
isHTML = false,
}) { const displayURL = getDisplayURL(url, extensionName); return { // The ID, computed by: // * `makeSourceId` for generated, // * `generatedToOriginalId` for both source map and pretty printed original,
id,
// Absolute URL for the source. This may be a fake URL for pretty printed sources
url,
// A (slightly tweaked) URL object to represent the source URL. // The URL object is augmented of a "group" attribute and some other standard attributes // are modified from their typical value. See getDisplayURL implementation.
displayURL,
// Short label for this source. // // * For inlined/eval sources without a URL, the name will refer to the internal source ID, // * For pretty printed source, we take care to ignore the internal ":formatted" suffix used in the URL, // * For index files, i.e. sources loaded without a filename, they will be named "(index)". // * Special characters are decoded from the URL string. // (most of this is done by getDisplayURL)
shortName: url
? getRawSourceURL(displayURL.filename)
: getFormattedSourceId(id),
// Same as short name, but with the query parameters.
longName: url
? getRawSourceURL(displayURL.filename + displayURL.search)
: getFormattedSourceId(id),
// Only set for generated sources that are WebExtension sources. // This is especially useful to display the extension name for content scripts // that executes against the page we are debugging.
extensionName,
// Will be true if the source URL starts with moz-extension://, // which most likely means the source is a content script. // (Note that when debugging an add-on all generated sources will most likely have this flag set to true)
isExtension,
// True if WASM is enabled *and* the generated source is a WASM source
isWasm,
// True if this source is an HTML and relates to many sources actors, // one for each of its inline <script>
isHTML,
// True, if this is an original pretty printed source
isPrettyPrinted,
// True for source map original files, as well as pretty printed sources
isOriginal,
};
}
/** * Create the source object for a source mapped original source that is stored in sources.js reducer. * These original sources referred to by source maps. * This isn't code that runs in the runtime, so it isn't associated with anything * on the server side. It is associated with a generated source for the related bundle file * which itself relates to an actual code that runs in the runtime. * * @param {String} id * The ID of the source, computed by source map codebase. * @param {String} url * The URL of the original source file.
*/
export function createSourceMapOriginalSource(id, url) { return createSourceObject({
id,
url,
isOriginal: true,
});
}
/** * Create the source object for a pretty printed original source that is stored in sources.js reducer. * These original pretty printed sources aren't code that run in the runtime, * so it isn't associated with anything on the server side. * It is associated with a generated source for the non-pretty-printed file * which itself relates to an actual code that runs in the runtime. * * @param {String} id * The ID of the source, computed by pretty print. * @param {String} url * The URL of the pretty-printed source file. * This URL doesn't work. It is the URL of the non-pretty-printed file with ":formated" suffix.
*/
export function createPrettyPrintOriginalSource(id, url) { return createSourceObject({
id,
url,
isOriginal: true,
isPrettyPrinted: true,
});
}
/** * Create the "source actor" object that is stored in source-actor.js reducer. * This will represent server's source actor in the reducer universe. * * @param {SOURCE} sourceResource * SOURCE resource coming from the ResourceCommand API. * This represents the `SourceActor` from the server codebase. * @param {Object} sourceObject * Source object stored in redux, i.e. created via createSourceObject.
*/
export function createSourceActor(sourceResource, sourceObject) { const actorId = sourceResource.actor;
return {
id: actorId,
actor: actorId, // As sourceResource is only SourceActor's form and not the SourceFront, // we have to go through the target to retrieve the related ThreadActor's ID. thread: sourceResource.targetFront.getCachedFront("thread").actorID, // `source` is the reducer source ID
source: makeSourceId(sourceResource),
sourceObject,
sourceMapBaseURL: sourceResource.sourceMapBaseURL,
sourceMapURL: sourceResource.sourceMapURL,
url: sourceResource.url,
introductionType: sourceResource.introductionType,
sourceStartLine: sourceResource.sourceStartLine,
sourceStartColumn: sourceResource.sourceStartColumn,
sourceLength: sourceResource.sourceLength,
};
}
/** * Create a pause info object passed to paused action from * the THREAD_STATE "paused" resource.
*/
export async function createPause(threadActorID, pausedThreadState) { const frame = await createFrame(threadActorID, pausedThreadState.frame); return { thread: threadActorID,
frame,
why: pausedThreadState.why,
};
}
export function createThread(targetFront) { // When debugging a Web Extension, the top level target is always the fallback document. // It isn't really a top level document as it won't be the parent of any other. // So only print its name. const name =
targetFront.isTopLevel &&
!targetFront.commands.descriptorFront.isWebExtension
? L10N.getStr("mainThread")
: targetFront.name;
/** * Defines the shape of a breakpoint
*/
export function createBreakpoint({
id, thread,
disabled = false,
options = {},
location,
generatedLocation,
text,
originalText,
}) { return { // The unique identifier (string) for the breakpoint, for details on its format and creation See `makeBreakpointId`
id,
// The thread actor id (string) which the source this breakpoint is created in belongs to thread,
// This (boolean) specifies if the breakpoint is disabled or not
disabled,
// This (object) stores extra information about the breakpoint, which defines the type of the breakpoint (i.e conditional breakpoints, log points) // { // condition: <Boolean>, // logValue: <String>, // hidden: <Boolean> // }
options,
// The location (object) information for the original source, for details on its format and structure See `createLocation`
location,
// The location (object) information for the generated source, for details on its format and structure See `createLocation`
generatedLocation,
// The text (string) on the line which the brekpoint is set in the generated source
text,
// The text (string) on the line which the breakpoint is set in the original source
originalText,
};
}
¤ Dauer der Verarbeitung: 0.15 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.