diff options
Diffstat (limited to 'devtools/client/debugger/src/reducers/sources-content.js')
-rw-r--r-- | devtools/client/debugger/src/reducers/sources-content.js | 139 |
1 files changed, 139 insertions, 0 deletions
diff --git a/devtools/client/debugger/src/reducers/sources-content.js b/devtools/client/debugger/src/reducers/sources-content.js new file mode 100644 index 0000000000..b60cb059b9 --- /dev/null +++ b/devtools/client/debugger/src/reducers/sources-content.js @@ -0,0 +1,139 @@ +/* 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/>. */ + +/** + * Sources content reducer. + * + * This store the textual content for each source. + */ + +import { pending, fulfilled, rejected } from "../utils/async-value"; + +export function initialSourcesContentState() { + return { + /** + * Text content of all the original sources. + * This is large data, so this is only fetched on-demand for a subset of sources. + * This state attribute is mutable in order to avoid cloning this possibly large map + * on each new source. But selectors are never based on the map. Instead they only + * query elements of the map. + * + * Map(source id => AsyncValue<String>) + */ + mutableOriginalSourceTextContentMapBySourceId: new Map(), + + /** + * Text content of all the generated sources. + * + * Map(source actor is => AsyncValue<String>) + */ + mutableGeneratedSourceTextContentMapBySourceActorId: new Map(), + + /** + * Incremental number that is bumped each time we navigate to a new page. + * + * This is used to better handle async race condition where we mix previous page data + * with the new page. As sources are keyed by URL we may easily conflate the two page loads data. + */ + epoch: 1, + }; +} + +function update(state = initialSourcesContentState(), action) { + switch (action.type) { + case "LOAD_ORIGINAL_SOURCE_TEXT": + if (!action.sourceId) { + throw new Error("No source id found."); + } + return updateSourceTextContent(state, action); + + case "LOAD_GENERATED_SOURCE_TEXT": + if (!action.sourceActorId) { + throw new Error("No source actor id found."); + } + return updateSourceTextContent(state, action); + + case "REMOVE_THREAD": + return removeThread(state, action); + } + + return state; +} + +/* + * Update a source's loaded text content. + */ +function updateSourceTextContent(state, action) { + // If there was a navigation between the time the action was started and + // completed, we don't want to update the store. + if (action.epoch !== state.epoch) { + return state; + } + + let content; + if (action.status === "start") { + content = pending(); + } else if (action.status === "error") { + content = rejected(action.error); + } else if (typeof action.value.text === "string") { + content = fulfilled({ + type: "text", + value: action.value.text, + contentType: action.value.contentType, + }); + } else { + content = fulfilled({ + type: "wasm", + value: action.value.text, + }); + } + + if (action.sourceId && action.sourceActorId) { + throw new Error( + "Both the source id and the source actor should not exist at the same time" + ); + } + + if (action.sourceId) { + state.mutableOriginalSourceTextContentMapBySourceId.set( + action.sourceId, + content + ); + } + + if (action.sourceActorId) { + state.mutableGeneratedSourceTextContentMapBySourceActorId.set( + action.sourceActorId, + content + ); + } + + return { + ...state, + }; +} + +function removeThread(state, action) { + const originalSizeBefore = + state.mutableOriginalSourceTextContentMapBySourceId.size; + for (const source of action.sources) { + state.mutableOriginalSourceTextContentMapBySourceId.delete(source.id); + } + const generatedSizeBefore = + state.mutableGeneratedSourceTextContentMapBySourceActorId.size; + for (const actor of action.actors) { + state.mutableGeneratedSourceTextContentMapBySourceActorId.delete(actor.id); + } + if ( + originalSizeBefore != + state.mutableOriginalSourceTextContentMapBySourceId.size || + generatedSizeBefore != + state.mutableGeneratedSourceTextContentMapBySourceActorId.size + ) { + return { ...state }; + } + return state; +} + +export default update; |