summaryrefslogtreecommitdiffstats
path: root/devtools/client/debugger/src/reducers/sources-content.js
diff options
context:
space:
mode:
Diffstat (limited to 'devtools/client/debugger/src/reducers/sources-content.js')
-rw-r--r--devtools/client/debugger/src/reducers/sources-content.js139
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;