diff options
Diffstat (limited to 'devtools/client/debugger/src/actions/sources/blackbox.js')
-rw-r--r-- | devtools/client/debugger/src/actions/sources/blackbox.js | 223 |
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, + }); + }; +} |