blackbox.js (6849B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */ 4 5 /** 6 * Redux actions for the sources state 7 * 8 * @module actions/sources 9 */ 10 11 import { recordEvent } from "../../utils/telemetry"; 12 import { toggleBreakpoints } from "../breakpoints/index"; 13 import { 14 getSourceActorsForSource, 15 isSourceBlackBoxed, 16 getBlackBoxRanges, 17 getBreakpointsForSource, 18 } from "../../selectors/index"; 19 20 export async function blackboxSourceActorsForSource( 21 thunkArgs, 22 source, 23 shouldBlackBox, 24 ranges = [] 25 ) { 26 const { getState, client, sourceMapLoader } = thunkArgs; 27 let sourceId = source.id; 28 // If the source is the original, then get the source id of its generated file 29 // and the range for where the original is represented in the generated file 30 // (which might be a bundle including other files). 31 if (source.isOriginal) { 32 sourceId = source.generatedSource.id; 33 const range = await sourceMapLoader.getFileGeneratedRange(source.id); 34 ranges = []; 35 if (range) { 36 ranges.push(range); 37 // TODO bug 1752108: Investigate blackboxing lines in original files, 38 // there is likely to be issues as the whole genrated file 39 // representing the original file will always be blackboxed. 40 console.warn( 41 "The might be unxpected issues when ignoring lines in an original file. " + 42 "The whole original source is being blackboxed." 43 ); 44 } else { 45 throw new Error( 46 `Unable to retrieve generated ranges for original source ${source.url}` 47 ); 48 } 49 } 50 51 for (const actor of getSourceActorsForSource(getState(), sourceId)) { 52 await client.blackBox(actor, shouldBlackBox, ranges); 53 } 54 } 55 56 /** 57 * Toggle blackboxing for the whole source or for specific lines in a source 58 * 59 * @param {object} source - The source to be blackboxed/unblackboxed. 60 * @param {boolean} [shouldBlackBox] - Specifies if the source should be blackboxed (true 61 * or unblackboxed (false). When this is not provided 62 * option is decided based on the blackboxed state 63 * of the source. 64 * @param {Array} [ranges] - List of line/column offsets to blackbox, these 65 * are provided only when blackboxing lines. 66 * The range structure: 67 * const range = { 68 * start: { line: 1, column: 5 }, 69 * end: { line: 3, column: 4 }, 70 * } 71 */ 72 export function toggleBlackBox(source, shouldBlackBox, ranges = []) { 73 return async thunkArgs => { 74 const { dispatch, getState } = thunkArgs; 75 76 shouldBlackBox = 77 typeof shouldBlackBox == "boolean" 78 ? shouldBlackBox 79 : !isSourceBlackBoxed(getState(), source); 80 81 await blackboxSourceActorsForSource( 82 thunkArgs, 83 source, 84 shouldBlackBox, 85 ranges 86 ); 87 88 if (shouldBlackBox) { 89 recordEvent("blackbox"); 90 // If ranges is an empty array, it would mean we are blackboxing the whole 91 // source. To do that lets reset the content to an empty array. 92 if (!ranges.length) { 93 dispatch({ type: "BLACKBOX_WHOLE_SOURCES", sources: [source] }); 94 await toggleBreakpointsInBlackboxedSources({ 95 thunkArgs, 96 shouldDisable: true, 97 sources: [source], 98 }); 99 } else { 100 const currentRanges = getBlackBoxRanges(getState())[source.url] || []; 101 ranges = ranges.filter(newRange => { 102 // To avoid adding duplicate ranges make sure 103 // no range already exists with same start and end lines. 104 const duplicate = currentRanges.findIndex( 105 r => 106 r.start.line == newRange.start.line && 107 r.end.line == newRange.end.line 108 ); 109 return duplicate == -1; 110 }); 111 dispatch({ type: "BLACKBOX_SOURCE_RANGES", source, ranges }); 112 await toggleBreakpointsInRangesForBlackboxedSource({ 113 thunkArgs, 114 shouldDisable: true, 115 source, 116 ranges, 117 }); 118 } 119 } else { 120 // if there are no ranges to blackbox, then we are unblackboxing 121 // the whole source 122 // eslint-disable-next-line no-lonely-if 123 if (!ranges.length) { 124 dispatch({ type: "UNBLACKBOX_WHOLE_SOURCES", sources: [source] }); 125 toggleBreakpointsInBlackboxedSources({ 126 thunkArgs, 127 shouldDisable: false, 128 sources: [source], 129 }); 130 } else { 131 dispatch({ type: "UNBLACKBOX_SOURCE_RANGES", source, ranges }); 132 const blackboxRanges = getBlackBoxRanges(getState()); 133 if (!blackboxRanges[source.url].length) { 134 dispatch({ type: "UNBLACKBOX_WHOLE_SOURCES", sources: [source] }); 135 } 136 await toggleBreakpointsInRangesForBlackboxedSource({ 137 thunkArgs, 138 shouldDisable: false, 139 source, 140 ranges, 141 }); 142 } 143 } 144 }; 145 } 146 147 async function toggleBreakpointsInRangesForBlackboxedSource({ 148 thunkArgs, 149 shouldDisable, 150 source, 151 ranges, 152 }) { 153 const { dispatch, getState } = thunkArgs; 154 for (const range of ranges) { 155 const breakpoints = getBreakpointsForSource(getState(), source, range); 156 await dispatch(toggleBreakpoints(shouldDisable, breakpoints)); 157 } 158 } 159 160 async function toggleBreakpointsInBlackboxedSources({ 161 thunkArgs, 162 shouldDisable, 163 sources, 164 }) { 165 const { dispatch, getState } = thunkArgs; 166 for (const source of sources) { 167 const breakpoints = getBreakpointsForSource(getState(), source); 168 await dispatch(toggleBreakpoints(shouldDisable, breakpoints)); 169 } 170 } 171 172 /** 173 * Blackboxes a group of sources together 174 * 175 * @param {Array} sourcesToBlackBox - The list of sources to blackbox 176 * @param {boolean} shouldBlackbox - Specifies if the sources should blackboxed (true) 177 * or unblackboxed (false). 178 */ 179 export function blackBoxSources(sourcesToBlackBox, shouldBlackBox) { 180 return async thunkArgs => { 181 const { dispatch, getState } = thunkArgs; 182 183 const sources = sourcesToBlackBox.filter( 184 source => isSourceBlackBoxed(getState(), source) !== shouldBlackBox 185 ); 186 187 if (!sources.length) { 188 return; 189 } 190 191 for (const source of sources) { 192 await blackboxSourceActorsForSource(thunkArgs, source, shouldBlackBox); 193 } 194 195 if (shouldBlackBox) { 196 recordEvent("blackbox"); 197 } 198 199 dispatch({ 200 type: shouldBlackBox 201 ? "BLACKBOX_WHOLE_SOURCES" 202 : "UNBLACKBOX_WHOLE_SOURCES", 203 sources, 204 }); 205 await toggleBreakpointsInBlackboxedSources({ 206 thunkArgs, 207 shouldDisable: shouldBlackBox, 208 sources, 209 }); 210 }; 211 }