/* 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/>. */
/* eslint complexity: ["error", 36]*/
/** * Pause reducer * @module reducers/pause
*/
import { prefs } from "../utils/prefs";
// Pause state associated with an individual thread.
// Pause state describing all threads.
export function initialPauseState(thread = "UnknownThread") { return {
cx: {
navigateCounter: 0,
}, // This `threadcx` is the `cx` variable we pass around in components and actions. // This is pulled via getThreadContext(). // This stores information about the currently selected thread and its paused state.
threadcx: {
navigateCounter: 0, thread,
pauseCounter: 0,
},
threads: {},
skipPausing: prefs.skipPausing,
mapScopes: prefs.mapScopes,
shouldPauseOnDebuggerStatement: prefs.pauseOnDebuggerStatement,
shouldPauseOnExceptions: prefs.pauseOnExceptions,
shouldPauseOnCaughtExceptions: prefs.pauseOnCaughtExceptions,
};
}
export function getThreadPauseState(state, thread) { // Thread state is lazily initialized so that we don't have to keep track of // the current set of worker threads. return state.threads[thread] || createInitialPauseState();
}
function update(state = initialPauseState(), action) { // All the actions updating pause state must pass an object which designate // the related thread. const getActionThread = () => { constthread =
action.thread || action.selectedFrame?.thread || action.frame?.thread; if (!thread) { thrownew Error(`Missing thread in action ${action.type}`);
} returnthread;
};
// `threadState` and `updateThreadState` help easily get and update // the pause state for a given thread. const threadState = () => { return getThreadPauseState(state, getActionThread());
}; const updateThreadState = newThreadState => { return {
...state,
threads: {
...state.threads,
[getActionThread()]: { ...threadState(), ...newThreadState },
},
};
};
switch (action.type) { case"SELECT_THREAD": { // Ignore the action if the related thread doesn't exist. if (!state.threads[action.thread]) {
console.warn(
`Trying to select a destroyed or non-existent thread'${action.thread}'`
); return state;
}
case"INSERT_THREAD": { // When navigating to a new location, // we receive NAVIGATE early, which clear things // then we have REMOVE_THREAD of the previous thread. // INSERT_THREAD will be the very first event with the new thread actor ID. // Automatically select the new top level thread. if (action.newThread.isTopLevel) { return {
...state,
threadcx: {
...state.threadcx, thread: action.newThread.actor,
pauseCounter: state.threadcx.pauseCounter + 1,
},
threads: {
...state.threads,
[action.newThread.actor]: createInitialPauseState(),
},
};
}
case"REMOVE_THREAD": { if (
action.threadActorID in state.threads ||
action.threadActorID == state.threadcx.thread
) { // Remove the thread from the cached list const threads = { ...state.threads }; delete threads[action.threadActorID];
let threadcx = state.threadcx;
// And also switch to another thread if this was the currently selected one. // As we don't store thread objects in this reducer, and only store thread actor IDs, // we can't try to find the top level thread. So we pick the first available thread, // and hope that's the top level one. if (state.threadcx.thread == action.threadActorID) {
threadcx = {
...threadcx, thread: Object.keys(threads)[0],
pauseCounter: threadcx.pauseCounter + 1,
};
} return {
...state,
threadcx,
threads,
};
} break;
}
return updateThreadState({
isWaitingOnBreak: false,
selectedFrameId: topFrame.id,
isPaused: true, // On pause, we only receive the top frame, all subsequent ones // will be asynchronously populated via `fetchFrames` action
frames: [topFrame],
framesLoading: true,
frameScopes: { ...resumedPauseState.frameScopes },
why,
shouldBreakpointsPaneOpenOnPause: why.type === "breakpoint",
});
}
// We typically receive a PAUSED action before this one, // with only the first frame. Here, we avoid replacing it // with a copy of it in order to avoid triggerring selectors // uncessarily // (note that in jest, action's frames might be empty) // (and if we resume in between PAUSED and FETCHED_FRAMES // threadState().frames might be null) if (threadState().frames) { const previousFirstFrame = threadState().frames[0]; if (previousFirstFrame.id == frames[0]?.id) {
frames.splice(0, 1, previousFirstFrame);
}
} return updateThreadState({ frames, framesLoading: false });
}
// NOTE: We store the previous location so that we ensure that we // do not stop at the same location twice when we step over. if (action.command !== "stepOver") { returnnull;
}
const frame = frames?.[0]; if (!frame) { return previousLocation;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.