summaryrefslogtreecommitdiffstats
path: root/devtools/client/debugger/src/actions/sources/blackbox.js
diff options
context:
space:
mode:
Diffstat (limited to 'devtools/client/debugger/src/actions/sources/blackbox.js')
-rw-r--r--devtools/client/debugger/src/actions/sources/blackbox.js223
1 files changed, 223 insertions, 0 deletions
diff --git a/devtools/client/debugger/src/actions/sources/blackbox.js b/devtools/client/debugger/src/actions/sources/blackbox.js
new file mode 100644
index 0000000000..6821a0e140
--- /dev/null
+++ b/devtools/client/debugger/src/actions/sources/blackbox.js
@@ -0,0 +1,223 @@
+/* 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/>. */
+
+/**
+ * Redux actions for the sources state
+ * @module actions/sources
+ */
+
+import {
+ isOriginalId,
+ originalToGeneratedId,
+} from "devtools/client/shared/source-map-loader/index";
+import { recordEvent } from "../../utils/telemetry";
+import { toggleBreakpoints } from "../breakpoints";
+import {
+ getSourceActorsForSource,
+ isSourceBlackBoxed,
+ getBlackBoxRanges,
+ getBreakpointsForSource,
+} from "../../selectors";
+
+export async function blackboxSourceActorsForSource(
+ thunkArgs,
+ source,
+ shouldBlackBox,
+ ranges = []
+) {
+ const { getState, client, sourceMapLoader } = thunkArgs;
+ let sourceId = source.id;
+ // If the source is the original, then get the source id of its generated file
+ // and the range for where the original is represented in the generated file
+ // (which might be a bundle including other files).
+ if (isOriginalId(source.id)) {
+ sourceId = originalToGeneratedId(source.id);
+ const range = await sourceMapLoader.getFileGeneratedRange(source.id);
+ ranges = [];
+ if (range) {
+ ranges.push(range);
+ // TODO bug 1752108: Investigate blackboxing lines in original files,
+ // there is likely to be issues as the whole genrated file
+ // representing the original file will always be blackboxed.
+ console.warn(
+ "The might be unxpected issues when ignoring lines in an original file. " +
+ "The whole original source is being blackboxed."
+ );
+ } else {
+ throw new Error(
+ `Unable to retrieve generated ranges for original source ${source.url}`
+ );
+ }
+ }
+
+ for (const actor of getSourceActorsForSource(getState(), sourceId)) {
+ await client.blackBox(actor, shouldBlackBox, ranges);
+ }
+}
+
+/**
+ * Toggle blackboxing for the whole source or for specific lines in a source
+ *
+ * @param {Object} cx
+ * @param {Object} source - The source to be blackboxed/unblackboxed.
+ * @param {Boolean} [shouldBlackBox] - Specifies if the source should be blackboxed (true
+ * or unblackboxed (false). When this is not provided
+ * option is decided based on the blackboxed state
+ * of the source.
+ * @param {Array} [ranges] - List of line/column offsets to blackbox, these
+ * are provided only when blackboxing lines.
+ * The range structure:
+ * const range = {
+ * start: { line: 1, column: 5 },
+ * end: { line: 3, column: 4 },
+ * }
+ */
+export function toggleBlackBox(cx, source, shouldBlackBox, ranges = []) {
+ return async thunkArgs => {
+ const { dispatch, getState } = thunkArgs;
+
+ shouldBlackBox =
+ typeof shouldBlackBox == "boolean"
+ ? shouldBlackBox
+ : !isSourceBlackBoxed(getState(), source);
+
+ await blackboxSourceActorsForSource(
+ thunkArgs,
+ source,
+ shouldBlackBox,
+ ranges
+ );
+
+ if (shouldBlackBox) {
+ recordEvent("blackbox");
+ // If ranges is an empty array, it would mean we are blackboxing the whole
+ // source. To do that lets reset the content to an empty array.
+ if (!ranges.length) {
+ dispatch({ type: "BLACKBOX_WHOLE_SOURCES", sources: [source] });
+ await toggleBreakpointsInBlackboxedSources({
+ thunkArgs,
+ cx,
+ shouldDisable: true,
+ sources: [source],
+ });
+ } else {
+ const currentRanges = getBlackBoxRanges(getState())[source.url] || [];
+ ranges = ranges.filter(newRange => {
+ // To avoid adding duplicate ranges make sure
+ // no range already exists with same start and end lines.
+ const duplicate = currentRanges.findIndex(
+ r =>
+ r.start.line == newRange.start.line &&
+ r.end.line == newRange.end.line
+ );
+ return duplicate == -1;
+ });
+ dispatch({ type: "BLACKBOX_SOURCE_RANGES", source, ranges });
+ await toggleBreakpointsInRangesForBlackboxedSource({
+ thunkArgs,
+ cx,
+ shouldDisable: true,
+ source,
+ ranges,
+ });
+ }
+ } else {
+ // if there are no ranges to blackbox, then we are unblackboxing
+ // the whole source
+ // eslint-disable-next-line no-lonely-if
+ if (!ranges.length) {
+ dispatch({ type: "UNBLACKBOX_WHOLE_SOURCES", sources: [source] });
+ toggleBreakpointsInBlackboxedSources({
+ thunkArgs,
+ cx,
+ shouldDisable: false,
+ sources: [source],
+ });
+ } else {
+ dispatch({ type: "UNBLACKBOX_SOURCE_RANGES", source, ranges });
+ const blackboxRanges = getBlackBoxRanges(getState());
+ if (!blackboxRanges[source.url].length) {
+ dispatch({ type: "UNBLACKBOX_WHOLE_SOURCES", sources: [source] });
+ }
+ await toggleBreakpointsInRangesForBlackboxedSource({
+ thunkArgs,
+ cx,
+ shouldDisable: false,
+ source,
+ ranges,
+ });
+ }
+ }
+ };
+}
+
+async function toggleBreakpointsInRangesForBlackboxedSource({
+ thunkArgs,
+ cx,
+ shouldDisable,
+ source,
+ ranges,
+}) {
+ const { dispatch, getState } = thunkArgs;
+ for (const range of ranges) {
+ const breakpoints = getBreakpointsForSource(getState(), source.id, range);
+ await dispatch(toggleBreakpoints(cx, shouldDisable, breakpoints));
+ }
+}
+
+async function toggleBreakpointsInBlackboxedSources({
+ thunkArgs,
+ cx,
+ shouldDisable,
+ sources,
+}) {
+ const { dispatch, getState } = thunkArgs;
+ for (const source of sources) {
+ const breakpoints = getBreakpointsForSource(getState(), source.id);
+ await dispatch(toggleBreakpoints(cx, shouldDisable, breakpoints));
+ }
+}
+
+/*
+ * Blackboxes a group of sources together
+ *
+ * @param {Object} cx
+ * @param {Array} sourcesToBlackBox - The list of sources to blackbox
+ * @param {Boolean} shouldBlackbox - Specifies if the sources should blackboxed (true)
+ * or unblackboxed (false).
+ */
+export function blackBoxSources(cx, sourcesToBlackBox, shouldBlackBox) {
+ return async thunkArgs => {
+ const { dispatch, getState } = thunkArgs;
+
+ const sources = sourcesToBlackBox.filter(
+ source => isSourceBlackBoxed(getState(), source) !== shouldBlackBox
+ );
+
+ if (!sources.length) {
+ return;
+ }
+
+ for (const source of sources) {
+ await blackboxSourceActorsForSource(thunkArgs, source, shouldBlackBox);
+ }
+
+ if (shouldBlackBox) {
+ recordEvent("blackbox");
+ }
+
+ dispatch({
+ type: shouldBlackBox
+ ? "BLACKBOX_WHOLE_SOURCES"
+ : "UNBLACKBOX_WHOLE_SOURCES",
+ sources,
+ });
+ await toggleBreakpointsInBlackboxedSources({
+ thunkArgs,
+ cx,
+ shouldDisable: shouldBlackBox,
+ sources,
+ });
+ };
+}