pending-breakpoints.js (4107B)
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 * Pending breakpoints reducer. 7 * 8 * Pending breakpoints are a more lightweight version compared to regular breakpoints objects. 9 * They are meant to be persisted across Firefox restarts and stored into async-storage. 10 * This reducer data is saved into asyncStore from bootstrap.js and restored from main.js. 11 * 12 * The main difference with pending breakpoints is that we only save breakpoints 13 * against source with an URL as only them can be restored. (source IDs are different across reloads). 14 * The second difference is that we don't store the whole source object but only the source URL. 15 */ 16 17 import assert from "../utils/assert"; 18 19 function update(state = {}, action) { 20 switch (action.type) { 21 case "SET_BREAKPOINT": 22 if (action.status === "start") { 23 return setBreakpoint(state, action.breakpoint); 24 } 25 return state; 26 27 case "REMOVE_BREAKPOINT": 28 if (action.status === "start") { 29 return removeBreakpoint(state, action.breakpoint); 30 } 31 return state; 32 33 case "REMOVE_PENDING_BREAKPOINT": 34 return removePendingBreakpoint(state, action.pendingBreakpoint); 35 36 case "CLEAR_BREAKPOINTS": { 37 return {}; 38 } 39 } 40 41 return state; 42 } 43 44 function shouldBreakpointBePersisted(breakpoint) { 45 // We only save breakpoint for source with URL. 46 // Source without URL can only be identified via their source actor ID 47 // which isn't persisted across reloads. 48 return !breakpoint.options.hidden && breakpoint.location.source.url; 49 } 50 51 function setBreakpoint(state, breakpoint) { 52 if (!shouldBreakpointBePersisted(breakpoint)) { 53 return state; 54 } 55 56 const id = makeIdFromBreakpoint(breakpoint); 57 const pendingBreakpoint = createPendingBreakpoint(breakpoint); 58 59 return { ...state, [id]: pendingBreakpoint }; 60 } 61 62 function removeBreakpoint(state, breakpoint) { 63 if (!shouldBreakpointBePersisted(breakpoint)) { 64 return state; 65 } 66 67 const id = makeIdFromBreakpoint(breakpoint); 68 state = { ...state }; 69 70 delete state[id]; 71 return state; 72 } 73 74 function removePendingBreakpoint(state, pendingBreakpoint) { 75 const id = makeIdFromPendingBreakpoint(pendingBreakpoint); 76 state = { ...state }; 77 78 delete state[id]; 79 return state; 80 } 81 82 /** 83 * Return a unique identifier for a given breakpoint, 84 * using its original location, or for pretty-printed sources, 85 * its generated location. 86 * 87 * @param {object} breakpoint 88 */ 89 function makeIdFromBreakpoint(breakpoint) { 90 const location = breakpoint.location.source.isPrettyPrinted 91 ? breakpoint.generatedLocation 92 : breakpoint.location; 93 94 const { source, line, column } = location; 95 const sourceUrlString = source.url || ""; 96 const columnString = column || ""; 97 98 return `${sourceUrlString}:${line}:${columnString}`; 99 } 100 101 function makeIdFromPendingBreakpoint(pendingBreakpoint) { 102 const { sourceUrl, line, column } = pendingBreakpoint.location; 103 const sourceUrlString = sourceUrl || ""; 104 const columnString = column || ""; 105 106 return `${sourceUrlString}:${line}:${columnString}`; 107 } 108 109 /** 110 * Convert typical debugger frontend location (created via location.js:createLocation) 111 * to a more lightweight flavor of it which will be stored in async storage. 112 */ 113 function createPendingLocation(location) { 114 assert(location.hasOwnProperty("line"), "location must have a line"); 115 assert(location.hasOwnProperty("column"), "location must have a column"); 116 117 const { source, line, column } = location; 118 assert(source.url !== undefined, "pending location must have a source url"); 119 return { sourceUrl: source.url, line, column }; 120 } 121 122 /** 123 * Create a new pending breakpoint, which is a more lightweight version of the regular breakpoint object. 124 */ 125 function createPendingBreakpoint(bp) { 126 return { 127 options: bp.options, 128 disabled: bp.disabled, 129 location: createPendingLocation(bp.location), 130 generatedLocation: createPendingLocation(bp.generatedLocation), 131 }; 132 } 133 134 export default update;