Merge mozilla-central to autoland. a=merge CLOSED TREE

This commit is contained in:
Noemi Erli 2019-04-07 00:47:23 +03:00
commit 18a982b872
126 changed files with 1729 additions and 973 deletions

View File

@ -149,11 +149,13 @@ DebuggerPanel.prototype = {
},
selectSourceURL(url, line, column) {
return this._actions.selectSourceURL(url, { line, column });
const cx = this._selectors.getContext(this._getState());
return this._actions.selectSourceURL(cx, url, { line, column });
},
selectSource(sourceId, line, column) {
return this._actions.selectSource(sourceId, { line, column });
const cx = this._selectors.getContext(this._getState());
return this._actions.selectSource(cx, sourceId, { line, column });
},
getSourceByActorId(sourceId) {

View File

@ -12,9 +12,10 @@ import * as parser from "../workers/parser";
import { isLoaded } from "../utils/source";
import type { Context } from "../types";
import type { ThunkArgs, Action } from "./types";
export function setOutOfScopeLocations() {
export function setOutOfScopeLocations(cx: Context) {
return async ({ dispatch, getState }: ThunkArgs) => {
const location = getSelectedLocation(getState());
if (!location) {
@ -38,9 +39,10 @@ export function setOutOfScopeLocations() {
dispatch(
({
type: "OUT_OF_SCOPE_LOCATIONS",
cx,
locations
}: Action)
);
dispatch(setInScopeLines());
dispatch(setInScopeLines(cx));
};
}

View File

@ -11,6 +11,7 @@ import { range, flatMap, uniq, without } from "lodash";
import type { AstLocation } from "../../workers/parser";
import type { ThunkArgs } from "../types";
import type { Context } from "../../types";
function getOutOfScopeLines(outOfScopeLocations: ?(AstLocation[])) {
if (!outOfScopeLocations) {
@ -24,7 +25,7 @@ function getOutOfScopeLines(outOfScopeLocations: ?(AstLocation[])) {
);
}
export function setInScopeLines() {
export function setInScopeLines(cx: Context) {
return ({ dispatch, getState }: ThunkArgs) => {
const source = getSelectedSource(getState());
const outOfScopeLocations = getOutOfScopeLocations(getState());
@ -44,6 +45,7 @@ export function setInScopeLines() {
dispatch({
type: "IN_SCOPE_LINES",
cx,
lines: inScopeLines
});
};

View File

@ -17,7 +17,8 @@ import {
import type {
MappedLocation,
SourceLocation,
BreakpointPositions
BreakpointPositions,
Context
} from "../../types";
import { makeBreakpointId } from "../../utils/breakpoint";
import {
@ -72,7 +73,7 @@ function convertToList(results, source) {
return positions;
}
async function _setBreakpointPositions(sourceId, thunkArgs) {
async function _setBreakpointPositions(cx, sourceId, thunkArgs) {
const { client, dispatch, getState, sourceMaps } = thunkArgs;
let generatedSource = getSource(getState(), sourceId);
if (!generatedSource) {
@ -124,6 +125,7 @@ async function _setBreakpointPositions(sourceId, thunkArgs) {
dispatch({
type: "ADD_BREAKPOINT_POSITIONS",
cx,
source: source,
positions
});
@ -132,7 +134,7 @@ async function _setBreakpointPositions(sourceId, thunkArgs) {
}
export const setBreakpointPositions: MemoizedAction<
{ sourceId: string },
{ cx: Context, sourceId: string },
?BreakpointPositions
> = memoizeableAction("setBreakpointPositions", {
hasValue: ({ sourceId }, { getState }) =>
@ -149,6 +151,6 @@ export const setBreakpointPositions: MemoizedAction<
: [];
return [sourceId, ...actors].join(":");
},
action: ({ sourceId }, thunkArgs) =>
_setBreakpointPositions(sourceId, thunkArgs)
action: ({ cx, sourceId }, thunkArgs) =>
_setBreakpointPositions(cx, sourceId, thunkArgs)
});

View File

@ -37,16 +37,17 @@ import type {
Breakpoint,
Source,
SourceLocation,
XHRBreakpoint
XHRBreakpoint,
Context
} from "../../types";
export * from "./breakpointPositions";
export * from "./modify";
export * from "./syncBreakpoint";
export function addHiddenBreakpoint(location: SourceLocation) {
export function addHiddenBreakpoint(cx: Context, location: SourceLocation) {
return ({ dispatch }: ThunkArgs) => {
return dispatch(addBreakpoint(location, { hidden: true }));
return dispatch(addBreakpoint(cx, location, { hidden: true }));
};
}
@ -56,12 +57,12 @@ export function addHiddenBreakpoint(location: SourceLocation) {
* @memberof actions/breakpoints
* @static
*/
export function disableBreakpointsInSource(source: Source) {
export function disableBreakpointsInSource(cx: Context, source: Source) {
return async ({ dispatch, getState, client }: ThunkArgs) => {
const breakpoints = getBreakpointsForSource(getState(), source.id);
for (const breakpoint of breakpoints) {
if (!breakpoint.disabled) {
dispatch(disableBreakpoint(breakpoint));
dispatch(disableBreakpoint(cx, breakpoint));
}
}
};
@ -73,12 +74,12 @@ export function disableBreakpointsInSource(source: Source) {
* @memberof actions/breakpoints
* @static
*/
export function enableBreakpointsInSource(source: Source) {
export function enableBreakpointsInSource(cx: Context, source: Source) {
return async ({ dispatch, getState, client }: ThunkArgs) => {
const breakpoints = getBreakpointsForSource(getState(), source.id);
for (const breakpoint of breakpoints) {
if (breakpoint.disabled) {
dispatch(enableBreakpoint(breakpoint));
dispatch(enableBreakpoint(cx, breakpoint));
}
}
};
@ -90,15 +91,18 @@ export function enableBreakpointsInSource(source: Source) {
* @memberof actions/breakpoints
* @static
*/
export function toggleAllBreakpoints(shouldDisableBreakpoints: boolean) {
export function toggleAllBreakpoints(
cx: Context,
shouldDisableBreakpoints: boolean
) {
return async ({ dispatch, getState, client }: ThunkArgs) => {
const breakpoints = getBreakpointsList(getState());
for (const breakpoint of breakpoints) {
if (shouldDisableBreakpoints) {
dispatch(disableBreakpoint(breakpoint));
dispatch(disableBreakpoint(cx, breakpoint));
} else {
dispatch(enableBreakpoint(breakpoint));
dispatch(enableBreakpoint(cx, breakpoint));
}
}
};
@ -111,6 +115,7 @@ export function toggleAllBreakpoints(shouldDisableBreakpoints: boolean) {
* @static
*/
export function toggleBreakpoints(
cx: Context,
shouldDisableBreakpoints: boolean,
breakpoints: Breakpoint[]
) {
@ -118,8 +123,8 @@ export function toggleBreakpoints(
const promises = breakpoints.map(
breakpoint =>
shouldDisableBreakpoints
? dispatch(disableBreakpoint(breakpoint))
: dispatch(enableBreakpoint(breakpoint))
? dispatch(disableBreakpoint(cx, breakpoint))
: dispatch(enableBreakpoint(cx, breakpoint))
);
await Promise.all(promises);
@ -127,12 +132,15 @@ export function toggleBreakpoints(
}
export function toggleBreakpointsAtLine(
cx: Context,
shouldDisableBreakpoints: boolean,
line: number
) {
return async ({ dispatch, getState }: ThunkArgs) => {
const breakpoints = await getBreakpointsAtLine(getState(), line);
return dispatch(toggleBreakpoints(shouldDisableBreakpoints, breakpoints));
const breakpoints = getBreakpointsAtLine(getState(), line);
return dispatch(
toggleBreakpoints(cx, shouldDisableBreakpoints, breakpoints)
);
};
}
@ -142,11 +150,11 @@ export function toggleBreakpointsAtLine(
* @memberof actions/breakpoints
* @static
*/
export function removeAllBreakpoints() {
export function removeAllBreakpoints(cx: Context) {
return async ({ dispatch, getState }: ThunkArgs) => {
const breakpointList = getBreakpointsList(getState());
return Promise.all(
breakpointList.map(bp => dispatch(removeBreakpoint(bp)))
breakpointList.map(bp => dispatch(removeBreakpoint(cx, bp)))
);
};
}
@ -157,9 +165,11 @@ export function removeAllBreakpoints() {
* @memberof actions/breakpoints
* @static
*/
export function removeBreakpoints(breakpoints: Breakpoint[]) {
export function removeBreakpoints(cx: Context, breakpoints: Breakpoint[]) {
return async ({ dispatch }: ThunkArgs) => {
return Promise.all(breakpoints.map(bp => dispatch(removeBreakpoint(bp))));
return Promise.all(
breakpoints.map(bp => dispatch(removeBreakpoint(cx, bp)))
);
};
}
@ -169,16 +179,16 @@ export function removeBreakpoints(breakpoints: Breakpoint[]) {
* @memberof actions/breakpoints
* @static
*/
export function removeBreakpointsInSource(source: Source) {
export function removeBreakpointsInSource(cx: Context, source: Source) {
return async ({ dispatch, getState, client }: ThunkArgs) => {
const breakpoints = getBreakpointsForSource(getState(), source.id);
for (const breakpoint of breakpoints) {
dispatch(removeBreakpoint(breakpoint));
dispatch(removeBreakpoint(cx, breakpoint));
}
};
}
export function remapBreakpoints(sourceId: string) {
export function remapBreakpoints(cx: Context, sourceId: string) {
return async ({ dispatch, getState, sourceMaps }: ThunkArgs) => {
const breakpoints = getBreakpointsForSource(getState(), sourceId);
const newBreakpoints = await remapLocations(
@ -192,16 +202,16 @@ export function remapBreakpoints(sourceId: string) {
// have different locations than the new ones. Manually remove the
// old breakpoints before adding the new ones.
for (const bp of breakpoints) {
dispatch(removeBreakpoint(bp));
dispatch(removeBreakpoint(cx, bp));
}
for (const bp of newBreakpoints) {
await dispatch(addBreakpoint(bp.location, bp.options, bp.disabled));
await dispatch(addBreakpoint(cx, bp.location, bp.options, bp.disabled));
}
};
}
export function toggleBreakpointAtLine(line: number) {
export function toggleBreakpointAtLine(cx: Context, line: number) {
return ({ dispatch, getState, client, sourceMaps }: ThunkArgs) => {
const state = getState();
const selectedSource = getSelectedSource(state);
@ -222,10 +232,10 @@ export function toggleBreakpointAtLine(line: number) {
}
if (bp) {
return dispatch(removeBreakpoint(bp));
return dispatch(removeBreakpoint(cx, bp));
}
return dispatch(
addBreakpoint({
addBreakpoint(cx, {
sourceId: selectedSource.id,
sourceUrl: selectedSource.url,
line: line
@ -234,7 +244,7 @@ export function toggleBreakpointAtLine(line: number) {
};
}
export function addBreakpointAtLine(line: number) {
export function addBreakpointAtLine(cx: Context, line: number) {
return ({ dispatch, getState, client, sourceMaps }: ThunkArgs) => {
const state = getState();
const source = getSelectedSource(state);
@ -244,7 +254,7 @@ export function addBreakpointAtLine(line: number) {
}
return dispatch(
addBreakpoint({
addBreakpoint(cx, {
sourceId: source.id,
sourceUrl: source.url,
column: undefined,
@ -254,45 +264,57 @@ export function addBreakpointAtLine(line: number) {
};
}
export function removeBreakpointsAtLine(sourceId: string, line: number) {
export function removeBreakpointsAtLine(
cx: Context,
sourceId: string,
line: number
) {
return ({ dispatch, getState, client, sourceMaps }: ThunkArgs) => {
const breakpointsAtLine = getBreakpointsForSource(
getState(),
sourceId,
line
);
return dispatch(removeBreakpoints(breakpointsAtLine));
return dispatch(removeBreakpoints(cx, breakpointsAtLine));
};
}
export function disableBreakpointsAtLine(sourceId: string, line: number) {
export function disableBreakpointsAtLine(
cx: Context,
sourceId: string,
line: number
) {
return ({ dispatch, getState, client, sourceMaps }: ThunkArgs) => {
const breakpointsAtLine = getBreakpointsForSource(
getState(),
sourceId,
line
);
return dispatch(toggleBreakpoints(true, breakpointsAtLine));
return dispatch(toggleBreakpoints(cx, true, breakpointsAtLine));
};
}
export function enableBreakpointsAtLine(sourceId: string, line: number) {
export function enableBreakpointsAtLine(
cx: Context,
sourceId: string,
line: number
) {
return ({ dispatch, getState, client, sourceMaps }: ThunkArgs) => {
const breakpointsAtLine = getBreakpointsForSource(
getState(),
sourceId,
line
);
return dispatch(toggleBreakpoints(false, breakpointsAtLine));
return dispatch(toggleBreakpoints(cx, false, breakpointsAtLine));
};
}
export function toggleDisabledBreakpoint(breakpoint: Breakpoint) {
export function toggleDisabledBreakpoint(cx: Context, breakpoint: Breakpoint) {
return ({ dispatch, getState, client, sourceMaps }: ThunkArgs) => {
if (!breakpoint.disabled) {
return dispatch(disableBreakpoint(breakpoint));
return dispatch(disableBreakpoint(cx, breakpoint));
}
return dispatch(enableBreakpoint(breakpoint));
return dispatch(enableBreakpoint(cx, breakpoint));
};
}

View File

@ -31,7 +31,8 @@ import type {
Breakpoint,
BreakpointOptions,
BreakpointPosition,
SourceLocation
SourceLocation,
Context
} from "../../types";
// This file has the primitive operations used to modify individual breakpoints
@ -78,7 +79,7 @@ function clientRemoveBreakpoint(generatedLocation: SourceLocation) {
};
}
export function enableBreakpoint(initialBreakpoint: Breakpoint) {
export function enableBreakpoint(cx: Context, initialBreakpoint: Breakpoint) {
return async ({ dispatch, getState, client, sourceMaps }: ThunkArgs) => {
const breakpoint = getBreakpoint(getState(), initialBreakpoint.location);
if (!breakpoint || !breakpoint.disabled) {
@ -87,6 +88,7 @@ export function enableBreakpoint(initialBreakpoint: Breakpoint) {
dispatch({
type: "SET_BREAKPOINT",
cx,
breakpoint: { ...breakpoint, disabled: false }
});
@ -95,6 +97,7 @@ export function enableBreakpoint(initialBreakpoint: Breakpoint) {
}
export function addBreakpoint(
cx: Context,
initialLocation: SourceLocation,
options: BreakpointOptions = {},
disabled: boolean = false,
@ -105,7 +108,7 @@ export function addBreakpoint(
const { sourceId, column } = initialLocation;
await dispatch(setBreakpointPositions({ sourceId }));
await dispatch(setBreakpointPositions({ cx, sourceId }));
const position: ?BreakpointPosition = column
? getBreakpointPositionsForLocation(getState(), initialLocation)
@ -146,7 +149,7 @@ export function addBreakpoint(
return;
}
dispatch({ type: "SET_BREAKPOINT", breakpoint });
dispatch({ type: "SET_BREAKPOINT", cx, breakpoint });
if (disabled) {
// If we just clobbered an enabled breakpoint with a disabled one, we need
@ -164,7 +167,7 @@ export function addBreakpoint(
* @memberof actions/breakpoints
* @static
*/
export function removeBreakpoint(initialBreakpoint: Breakpoint) {
export function removeBreakpoint(cx: Context, initialBreakpoint: Breakpoint) {
return ({ dispatch, getState, client }: ThunkArgs) => {
recordEvent("remove_breakpoint");
@ -175,6 +178,7 @@ export function removeBreakpoint(initialBreakpoint: Breakpoint) {
dispatch({
type: "REMOVE_BREAKPOINT",
cx,
location: breakpoint.location
});
@ -194,7 +198,10 @@ export function removeBreakpoint(initialBreakpoint: Breakpoint) {
* @memberof actions/breakpoints
* @static
*/
export function removeBreakpointAtGeneratedLocation(target: SourceLocation) {
export function removeBreakpointAtGeneratedLocation(
cx: Context,
target: SourceLocation
) {
return ({ dispatch, getState, client }: ThunkArgs) => {
// Remove any breakpoints matching the generated location.
const breakpoints = getBreakpointsList(getState());
@ -205,6 +212,7 @@ export function removeBreakpointAtGeneratedLocation(target: SourceLocation) {
) {
dispatch({
type: "REMOVE_BREAKPOINT",
cx,
location
});
}
@ -219,6 +227,7 @@ export function removeBreakpointAtGeneratedLocation(target: SourceLocation) {
) {
dispatch({
type: "REMOVE_PENDING_BREAKPOINT",
cx,
location
});
}
@ -235,7 +244,7 @@ export function removeBreakpointAtGeneratedLocation(target: SourceLocation) {
* @memberof actions/breakpoints
* @static
*/
export function disableBreakpoint(initialBreakpoint: Breakpoint) {
export function disableBreakpoint(cx: Context, initialBreakpoint: Breakpoint) {
return ({ dispatch, getState, client }: ThunkArgs) => {
const breakpoint = getBreakpoint(getState(), initialBreakpoint.location);
if (!breakpoint || breakpoint.disabled) {
@ -244,6 +253,7 @@ export function disableBreakpoint(initialBreakpoint: Breakpoint) {
dispatch({
type: "SET_BREAKPOINT",
cx,
breakpoint: { ...breakpoint, disabled: true }
});
@ -263,13 +273,14 @@ export function disableBreakpoint(initialBreakpoint: Breakpoint) {
* Any options to set on the breakpoint
*/
export function setBreakpointOptions(
cx: Context,
location: SourceLocation,
options: BreakpointOptions = {}
) {
return ({ dispatch, getState, client, sourceMaps }: ThunkArgs) => {
let breakpoint = getBreakpoint(getState(), location);
if (!breakpoint) {
return dispatch(addBreakpoint(location, options));
return dispatch(addBreakpoint(cx, location, options));
}
// Note: setting a breakpoint's options implicitly enables it.
@ -277,6 +288,7 @@ export function setBreakpointOptions(
dispatch({
type: "SET_BREAKPOINT",
cx,
breakpoint
});

View File

@ -27,15 +27,17 @@ import type {
ASTLocation,
PendingBreakpoint,
SourceId,
BreakpointPositions
BreakpointPositions,
Context
} from "../../types";
async function findBreakpointPosition(
cx: Context,
{ getState, dispatch },
location: SourceLocation
) {
const positions: BreakpointPositions = await dispatch(
setBreakpointPositions({ sourceId: location.sourceId })
setBreakpointPositions({ cx, sourceId: location.sourceId })
);
const position = findPosition(positions, location);
@ -43,13 +45,14 @@ async function findBreakpointPosition(
}
async function findNewLocation(
cx: Context,
{ name, offset, index }: ASTLocation,
location: SourceLocation,
source,
thunkArgs
) {
const symbols: LoadedSymbols = await thunkArgs.dispatch(
setSymbols({ source })
setSymbols({ cx, source })
);
const func = findFunctionByName(symbols, name, index);
@ -85,6 +88,7 @@ async function findNewLocation(
// to the reducer for the new location corresponding to the original location
// in the pending breakpoint.
export function syncBreakpoint(
cx: Context,
sourceId: SourceId,
pendingBreakpoint: PendingBreakpoint
) {
@ -124,6 +128,7 @@ export function syncBreakpoint(
);
return dispatch(
addBreakpoint(
cx,
sourceGeneratedLocation,
pendingBreakpoint.options,
pendingBreakpoint.disabled,
@ -135,6 +140,7 @@ export function syncBreakpoint(
const previousLocation = { ...location, sourceId };
const newLocation = await findNewLocation(
cx,
astLocation,
previousLocation,
source,
@ -142,6 +148,7 @@ export function syncBreakpoint(
);
const newGeneratedLocation = await findBreakpointPosition(
cx,
thunkArgs,
newLocation
);
@ -152,7 +159,9 @@ export function syncBreakpoint(
// breakpoint moved. If the old generated location still maps to an
// original location then we don't want to add a breakpoint for it.
if (location.sourceUrl != generatedLocation.sourceUrl) {
dispatch(removeBreakpointAtGeneratedLocation(sourceGeneratedLocation));
dispatch(
removeBreakpointAtGeneratedLocation(cx, sourceGeneratedLocation)
);
}
return;
}
@ -166,11 +175,14 @@ export function syncBreakpoint(
// breakpoint, remove any breakpoint associated with the old generated
// location.
if (!isSameLocation) {
dispatch(removeBreakpointAtGeneratedLocation(sourceGeneratedLocation));
dispatch(
removeBreakpointAtGeneratedLocation(cx, sourceGeneratedLocation)
);
}
return dispatch(
addBreakpoint(
cx,
newLocation,
pendingBreakpoint.options,
pendingBreakpoint.disabled

View File

@ -18,10 +18,10 @@ describe("breakpointPositions", () => {
getBreakpointPositions: async () => ({ "9": [1] })
});
const { dispatch, getState } = store;
const { dispatch, getState, cx } = store;
await dispatch(actions.newSource(makeSource("foo")));
dispatch(actions.setBreakpointPositions({ sourceId: "foo" }));
dispatch(actions.setBreakpointPositions({ cx, sourceId: "foo" }));
await waitForState(store, state =>
selectors.hasBreakpointPositions(state, "foo")
@ -58,11 +58,11 @@ describe("breakpointPositions", () => {
})
});
const { dispatch, getState } = store;
const { dispatch, getState, cx } = store;
await dispatch(actions.newSource(makeSource("foo")));
dispatch(actions.setBreakpointPositions({ sourceId: "foo" }));
dispatch(actions.setBreakpointPositions({ sourceId: "foo" }));
dispatch(actions.setBreakpointPositions({ cx, sourceId: "foo" }));
dispatch(actions.setBreakpointPositions({ cx, sourceId: "foo" }));
resolve({ "9": [1] });
await waitForState(store, state =>

View File

@ -23,7 +23,7 @@ function mockClient(positionsResponse = {}) {
describe("breakpoints", () => {
it("should add a breakpoint", async () => {
const { dispatch, getState } = createStore(mockClient({ "2": [1] }));
const { dispatch, getState, cx } = createStore(mockClient({ "2": [1] }));
const loc1 = {
sourceId: "a",
line: 2,
@ -33,16 +33,16 @@ describe("breakpoints", () => {
const source = makeSource("a");
await dispatch(actions.newSource(source));
await dispatch(actions.loadSourceText({ source }));
await dispatch(actions.loadSourceText({ cx, source }));
await dispatch(
actions.setSelectedLocation(source, {
actions.setSelectedLocation(cx, source, {
line: 1,
column: 1,
sourceId: source.id
})
);
await dispatch(actions.addBreakpoint(loc1));
await dispatch(actions.addBreakpoint(cx, loc1));
expect(selectors.getBreakpointCount(getState())).toEqual(1);
const bp = selectors.getBreakpoint(getState(), loc1);
@ -54,7 +54,7 @@ describe("breakpoints", () => {
});
it("should not show a breakpoint that does not have text", async () => {
const { dispatch, getState } = createStore(mockClient({ "5": [1] }));
const { dispatch, getState, cx } = createStore(mockClient({ "5": [1] }));
const loc1 = {
sourceId: "a",
line: 5,
@ -63,16 +63,16 @@ describe("breakpoints", () => {
};
const source = makeSource("a");
await dispatch(actions.newSource(source));
await dispatch(actions.loadSourceText({ source }));
await dispatch(actions.loadSourceText({ cx, source }));
await dispatch(
actions.setSelectedLocation(source, {
actions.setSelectedLocation(cx, source, {
line: 1,
column: 1,
sourceId: source.id
})
);
await dispatch(actions.addBreakpoint(loc1));
await dispatch(actions.addBreakpoint(cx, loc1));
expect(selectors.getBreakpointCount(getState())).toEqual(1);
const bp = selectors.getBreakpoint(getState(), loc1);
@ -81,7 +81,7 @@ describe("breakpoints", () => {
});
it("should show a disabled breakpoint that does not have text", async () => {
const { dispatch, getState } = createStore(mockClient({ "5": [1] }));
const { dispatch, getState, cx } = createStore(mockClient({ "5": [1] }));
const loc1 = {
sourceId: "a",
line: 5,
@ -90,22 +90,22 @@ describe("breakpoints", () => {
};
const source = makeSource("a");
await dispatch(actions.newSource(source));
await dispatch(actions.loadSourceText({ source }));
await dispatch(actions.loadSourceText({ cx, source }));
await dispatch(
actions.setSelectedLocation(source, {
actions.setSelectedLocation(cx, source, {
line: 1,
column: 1,
sourceId: source.id
})
);
await dispatch(actions.addBreakpoint(loc1));
await dispatch(actions.addBreakpoint(cx, loc1));
const breakpoint = selectors.getBreakpoint(getState(), loc1);
if (!breakpoint) {
throw new Error("no breakpoint");
}
await dispatch(actions.disableBreakpoint(breakpoint));
await dispatch(actions.disableBreakpoint(cx, breakpoint));
expect(selectors.getBreakpointCount(getState())).toEqual(1);
const bp = selectors.getBreakpoint(getState(), loc1);
@ -114,7 +114,7 @@ describe("breakpoints", () => {
});
it("should not re-add a breakpoint", async () => {
const { dispatch, getState } = createStore(mockClient({ "5": [1] }));
const { dispatch, getState, cx } = createStore(mockClient({ "5": [1] }));
const loc1 = {
sourceId: "a",
line: 5,
@ -124,26 +124,26 @@ describe("breakpoints", () => {
const source = makeSource("a");
await dispatch(actions.newSource(source));
await dispatch(actions.loadSourceText({ source }));
await dispatch(actions.loadSourceText({ cx, source }));
await dispatch(
actions.setSelectedLocation(source, {
actions.setSelectedLocation(cx, source, {
line: 1,
column: 1,
sourceId: source.id
})
);
await dispatch(actions.addBreakpoint(loc1));
await dispatch(actions.addBreakpoint(cx, loc1));
expect(selectors.getBreakpointCount(getState())).toEqual(1);
const bp = selectors.getBreakpoint(getState(), loc1);
expect(bp && bp.location).toEqual(loc1);
await dispatch(actions.addBreakpoint(loc1));
await dispatch(actions.addBreakpoint(cx, loc1));
expect(selectors.getBreakpointCount(getState())).toEqual(1);
});
it("should remove a breakpoint", async () => {
const { dispatch, getState } = createStore(
const { dispatch, getState, cx } = createStore(
mockClient({ "5": [1], "6": [2] })
);
@ -163,34 +163,34 @@ describe("breakpoints", () => {
const aSource = makeSource("a");
await dispatch(actions.newSource(aSource));
await dispatch(actions.loadSourceText({ source: aSource }));
await dispatch(actions.loadSourceText({ cx, source: aSource }));
const bSource = makeSource("b");
await dispatch(actions.newSource(bSource));
await dispatch(actions.loadSourceText({ source: bSource }));
await dispatch(actions.loadSourceText({ cx, source: bSource }));
await dispatch(
actions.setSelectedLocation(aSource, {
actions.setSelectedLocation(cx, aSource, {
line: 1,
column: 1,
sourceId: aSource.id
})
);
await dispatch(actions.addBreakpoint(loc1));
await dispatch(actions.addBreakpoint(loc2));
await dispatch(actions.addBreakpoint(cx, loc1));
await dispatch(actions.addBreakpoint(cx, loc2));
const bp = selectors.getBreakpoint(getState(), loc1);
if (!bp) {
throw new Error("no bp");
}
await dispatch(actions.removeBreakpoint(bp));
await dispatch(actions.removeBreakpoint(cx, bp));
expect(selectors.getBreakpointCount(getState())).toEqual(1);
});
it("should disable a breakpoint", async () => {
const { dispatch, getState } = createStore(
const { dispatch, getState, cx } = createStore(
mockClient({ "5": [1], "6": [2] })
);
@ -210,28 +210,28 @@ describe("breakpoints", () => {
const aSource = makeSource("a");
await dispatch(actions.newSource(aSource));
await dispatch(actions.loadSourceText({ source: aSource }));
await dispatch(actions.loadSourceText({ cx, source: aSource }));
const bSource = makeSource("b");
await dispatch(actions.newSource(bSource));
await dispatch(actions.loadSourceText({ source: bSource }));
await dispatch(actions.loadSourceText({ cx, source: bSource }));
await dispatch(actions.addBreakpoint(loc1));
await dispatch(actions.addBreakpoint(loc2));
await dispatch(actions.addBreakpoint(cx, loc1));
await dispatch(actions.addBreakpoint(cx, loc2));
const breakpoint = selectors.getBreakpoint(getState(), loc1);
if (!breakpoint) {
throw new Error("no breakpoint");
}
await dispatch(actions.disableBreakpoint(breakpoint));
await dispatch(actions.disableBreakpoint(cx, breakpoint));
const bp = selectors.getBreakpoint(getState(), loc1);
expect(bp && bp.disabled).toBe(true);
});
it("should enable breakpoint", async () => {
const { dispatch, getState } = createStore(
const { dispatch, getState, cx } = createStore(
mockClient({ "5": [1], "6": [2] })
);
const loc = {
@ -243,15 +243,15 @@ describe("breakpoints", () => {
const aSource = makeSource("a");
await dispatch(actions.newSource(aSource));
await dispatch(actions.loadSourceText({ source: aSource }));
await dispatch(actions.loadSourceText({ cx, source: aSource }));
await dispatch(actions.addBreakpoint(loc));
await dispatch(actions.addBreakpoint(cx, loc));
let bp = selectors.getBreakpoint(getState(), loc);
if (!bp) {
throw new Error("no breakpoint");
}
await dispatch(actions.disableBreakpoint(bp));
await dispatch(actions.disableBreakpoint(cx, bp));
bp = selectors.getBreakpoint(getState(), loc);
if (!bp) {
@ -260,14 +260,14 @@ describe("breakpoints", () => {
expect(bp && bp.disabled).toBe(true);
await dispatch(actions.enableBreakpoint(bp));
await dispatch(actions.enableBreakpoint(cx, bp));
bp = selectors.getBreakpoint(getState(), loc);
expect(bp && !bp.disabled).toBe(true);
});
it("should toggle all the breakpoints", async () => {
const { dispatch, getState } = createStore(
const { dispatch, getState, cx } = createStore(
mockClient({ "5": [1], "6": [2] })
);
@ -287,16 +287,16 @@ describe("breakpoints", () => {
const aSource = makeSource("a");
await dispatch(actions.newSource(aSource));
await dispatch(actions.loadSourceText({ source: aSource }));
await dispatch(actions.loadSourceText({ cx, source: aSource }));
const bSource = makeSource("b");
await dispatch(actions.newSource(bSource));
await dispatch(actions.loadSourceText({ source: bSource }));
await dispatch(actions.loadSourceText({ cx, source: bSource }));
await dispatch(actions.addBreakpoint(loc1));
await dispatch(actions.addBreakpoint(loc2));
await dispatch(actions.addBreakpoint(cx, loc1));
await dispatch(actions.addBreakpoint(cx, loc2));
await dispatch(actions.toggleAllBreakpoints(true));
await dispatch(actions.toggleAllBreakpoints(cx, true));
let bp1 = selectors.getBreakpoint(getState(), loc1);
let bp2 = selectors.getBreakpoint(getState(), loc2);
@ -304,7 +304,7 @@ describe("breakpoints", () => {
expect(bp1 && bp1.disabled).toBe(true);
expect(bp2 && bp2.disabled).toBe(true);
await dispatch(actions.toggleAllBreakpoints(false));
await dispatch(actions.toggleAllBreakpoints(cx, false));
bp1 = selectors.getBreakpoint(getState(), loc1);
bp2 = selectors.getBreakpoint(getState(), loc2);
@ -316,19 +316,19 @@ describe("breakpoints", () => {
const loc = { sourceId: "foo1", line: 5, column: 1 };
const getBp = () => selectors.getBreakpoint(getState(), loc);
const { dispatch, getState } = createStore(mockClient({ "5": [1] }));
const { dispatch, getState, cx } = createStore(mockClient({ "5": [1] }));
const source = makeSource("foo1");
await dispatch(actions.newSource(source));
await dispatch(actions.loadSourceText({ source }));
await dispatch(actions.loadSourceText({ cx, source }));
await dispatch(actions.selectLocation(loc));
await dispatch(actions.selectLocation(cx, loc));
await dispatch(actions.toggleBreakpointAtLine(5));
await dispatch(actions.toggleBreakpointAtLine(cx, 5));
const bp = getBp();
expect(bp && !bp.disabled).toBe(true);
await dispatch(actions.toggleBreakpointAtLine(5));
await dispatch(actions.toggleBreakpointAtLine(cx, 5));
expect(getBp()).toBe(undefined);
});
@ -336,28 +336,28 @@ describe("breakpoints", () => {
const location = { sourceId: "foo1", line: 5, column: 1 };
const getBp = () => selectors.getBreakpoint(getState(), location);
const { dispatch, getState } = createStore(mockClient({ "5": [1] }));
const { dispatch, getState, cx } = createStore(mockClient({ "5": [1] }));
const source = makeSource("foo1");
await dispatch(actions.newSource(source));
await dispatch(actions.loadSourceText({ source }));
await dispatch(actions.loadSourceText({ cx, source }));
await dispatch(actions.selectLocation({ sourceId: "foo1", line: 1 }));
await dispatch(actions.selectLocation(cx, { sourceId: "foo1", line: 1 }));
await dispatch(actions.toggleBreakpointAtLine(5));
await dispatch(actions.toggleBreakpointAtLine(cx, 5));
let bp = getBp();
expect(bp && !bp.disabled).toBe(true);
bp = getBp();
if (!bp) {
throw new Error("no bp");
}
await dispatch(actions.toggleDisabledBreakpoint(bp));
await dispatch(actions.toggleDisabledBreakpoint(cx, bp));
bp = getBp();
expect(bp && bp.disabled).toBe(true);
});
it("should set the breakpoint condition", async () => {
const { dispatch, getState } = createStore(mockClient({ "5": [1] }));
const { dispatch, getState, cx } = createStore(mockClient({ "5": [1] }));
const loc = {
sourceId: "a",
@ -368,15 +368,15 @@ describe("breakpoints", () => {
const source = makeSource("a");
await dispatch(actions.newSource(source));
await dispatch(actions.loadSourceText({ source }));
await dispatch(actions.loadSourceText({ cx, source }));
await dispatch(actions.addBreakpoint(loc));
await dispatch(actions.addBreakpoint(cx, loc));
let bp = selectors.getBreakpoint(getState(), loc);
expect(bp && bp.options.condition).toBe(undefined);
await dispatch(
actions.setBreakpointOptions(loc, {
actions.setBreakpointOptions(cx, loc, {
condition: "const foo = 0",
getTextForLine: () => {}
})
@ -387,7 +387,7 @@ describe("breakpoints", () => {
});
it("should set the condition and enable a breakpoint", async () => {
const { dispatch, getState } = createStore(mockClient({ "5": [1] }));
const { dispatch, getState, cx } = createStore(mockClient({ "5": [1] }));
const loc = {
sourceId: "a",
@ -398,21 +398,21 @@ describe("breakpoints", () => {
const source = makeSource("a");
await dispatch(actions.newSource(source));
await dispatch(actions.loadSourceText({ source }));
await dispatch(actions.loadSourceText({ cx, source }));
await dispatch(actions.addBreakpoint(loc));
await dispatch(actions.addBreakpoint(cx, loc));
let bp = selectors.getBreakpoint(getState(), loc);
if (!bp) {
throw new Error("no breakpoint");
}
await dispatch(actions.disableBreakpoint(bp));
await dispatch(actions.disableBreakpoint(cx, bp));
bp = selectors.getBreakpoint(getState(), loc);
expect(bp && bp.options.condition).toBe(undefined);
await dispatch(
actions.setBreakpointOptions(loc, {
actions.setBreakpointOptions(cx, loc, {
condition: "const foo = 0",
getTextForLine: () => {}
})
@ -425,7 +425,7 @@ describe("breakpoints", () => {
});
it("should remap breakpoints on pretty print", async () => {
const { dispatch, getState } = createStore(mockClient({ "1": [0] }));
const { dispatch, getState, cx } = createStore(mockClient({ "1": [0] }));
const loc = {
sourceId: "a.js",
@ -436,10 +436,10 @@ describe("breakpoints", () => {
const source = makeSource("a.js");
await dispatch(actions.newSource(source));
await dispatch(actions.loadSourceText({ source }));
await dispatch(actions.loadSourceText({ cx, source }));
await dispatch(actions.addBreakpoint(loc));
await dispatch(actions.togglePrettyPrint("a.js"));
await dispatch(actions.addBreakpoint(cx, loc));
await dispatch(actions.togglePrettyPrint(cx, "a.js"));
const breakpoint = selectors.getBreakpointsList(getState())[0];

View File

@ -6,10 +6,13 @@
import type { Action, ThunkArgs } from "./types";
import { getContext } from "../selectors";
export function updateWorkers() {
return async function({ dispatch, getState, client }: ThunkArgs) {
const cx = getContext(getState());
const workers = await client.fetchWorkers();
const mainThread = client.getMainThread();
dispatch(({ type: "SET_WORKERS", workers, mainThread }: Action));
dispatch(({ type: "SET_WORKERS", cx, workers, mainThread }: Action));
};
}

View File

@ -22,7 +22,7 @@ import { features } from "../utils/prefs";
import { isOriginal } from "../utils/source";
import * as parser from "../workers/parser";
import type { Expression } from "../types";
import type { Expression, ThreadContext } from "../types";
import type { ThunkArgs } from "./types";
/**
@ -33,7 +33,7 @@ import type { ThunkArgs } from "./types";
* @memberof actions/pause
* @static
*/
export function addExpression(input: string) {
export function addExpression(cx: ThreadContext, input: string) {
return async ({ dispatch, getState }: ThunkArgs) => {
if (!input) {
return;
@ -43,27 +43,26 @@ export function addExpression(input: string) {
const expression = getExpression(getState(), input);
if (expression) {
return dispatch(evaluateExpression(expression));
return dispatch(evaluateExpression(cx, expression));
}
dispatch({ type: "ADD_EXPRESSION", input, expressionError });
dispatch({ type: "ADD_EXPRESSION", cx, input, expressionError });
const newExpression = getExpression(getState(), input);
if (newExpression) {
return dispatch(evaluateExpression(newExpression));
return dispatch(evaluateExpression(cx, newExpression));
}
};
}
export function autocomplete(input: string, cursor: number) {
export function autocomplete(cx: ThreadContext, input: string, cursor: number) {
return async ({ dispatch, getState, client }: ThunkArgs) => {
if (!input) {
return;
}
const thread = getCurrentThread(getState());
const frameId = getSelectedFrameId(getState(), thread);
const frameId = getSelectedFrameId(getState(), cx.thread);
const result = await client.autocomplete(input, cursor, frameId);
await dispatch({ type: "AUTOCOMPLETE", input, result });
await dispatch({ type: "AUTOCOMPLETE", cx, input, result });
};
}
@ -75,7 +74,11 @@ export function clearExpressionError() {
return { type: "CLEAR_EXPRESSION_ERROR" };
}
export function updateExpression(input: string, expression: Expression) {
export function updateExpression(
cx: ThreadContext,
input: string,
expression: Expression
) {
return async ({ dispatch, getState }: ThunkArgs) => {
if (!input) {
return;
@ -84,12 +87,13 @@ export function updateExpression(input: string, expression: Expression) {
const expressionError = await parser.hasSyntaxError(input);
dispatch({
type: "UPDATE_EXPRESSION",
cx,
expression,
input: expressionError ? expression.input : input,
expressionError
});
dispatch(evaluateExpressions());
dispatch(evaluateExpressions(cx));
};
}
@ -115,21 +119,20 @@ export function deleteExpression(expression: Expression) {
* @param {number} selectedFrameId
* @static
*/
export function evaluateExpressions() {
export function evaluateExpressions(cx: ThreadContext) {
return async function({ dispatch, getState, client }: ThunkArgs) {
const expressions = getExpressions(getState()).toJS();
const inputs = expressions.map(({ input }) => input);
const thread = getCurrentThread(getState());
const frameId = getSelectedFrameId(getState(), thread);
const frameId = getSelectedFrameId(getState(), cx.thread);
const results = await client.evaluateExpressions(inputs, {
frameId,
thread
thread: cx.thread
});
dispatch({ type: "EVALUATE_EXPRESSIONS", inputs, results });
dispatch({ type: "EVALUATE_EXPRESSIONS", cx, inputs, results });
};
}
function evaluateExpression(expression: Expression) {
function evaluateExpression(cx: ThreadContext, expression: Expression) {
return async function({ dispatch, getState, client, sourceMaps }: ThunkArgs) {
if (!expression.input) {
console.warn("Expressions should not be empty");
@ -137,8 +140,7 @@ function evaluateExpression(expression: Expression) {
}
let input = expression.input;
const thread = getCurrentThread(getState());
const frame = getSelectedFrame(getState(), thread);
const frame = getSelectedFrame(getState(), cx.thread);
if (frame) {
const { location } = frame;
@ -154,15 +156,16 @@ function evaluateExpression(expression: Expression) {
}
}
const frameId = getSelectedFrameId(getState(), thread);
const frameId = getSelectedFrameId(getState(), cx.thread);
return dispatch({
type: "EVALUATE_EXPRESSION",
thread,
cx,
thread: cx.thread,
input: expression.input,
[PROMISE]: client.evaluateInFrame(wrapExpression(input), {
frameId,
thread
thread: cx.thread
})
});
};

View File

@ -15,7 +15,7 @@ import {
import { isWasm, renderWasmText } from "../utils/wasm";
import { getMatches } from "../workers/search";
import type { Action, FileTextSearchModifier, ThunkArgs } from "./types";
import type { WasmSource } from "../types";
import type { WasmSource, Context } from "../types";
import {
getSelectedSource,
@ -32,15 +32,15 @@ import {
type Editor = Object;
type Match = Object;
export function doSearch(query: string, editor: Editor) {
export function doSearch(cx: Context, query: string, editor: Editor) {
return ({ getState, dispatch }: ThunkArgs) => {
const selectedSource = getSelectedSource(getState());
if (!selectedSource || !selectedSource.text) {
return;
}
dispatch(setFileSearchQuery(query));
dispatch(searchContents(query, editor));
dispatch(setFileSearchQuery(cx, query));
dispatch(searchContents(cx, query, editor));
};
}
@ -59,20 +59,23 @@ export function doSearchForHighlight(
};
}
export function setFileSearchQuery(query: string): Action {
export function setFileSearchQuery(cx: Context, query: string): Action {
return {
type: "UPDATE_FILE_SEARCH_QUERY",
cx,
query
};
}
export function toggleFileSearchModifier(
cx: Context,
modifier: FileTextSearchModifier
): Action {
return { type: "TOGGLE_FILE_SEARCH_MODIFIER", modifier };
return { type: "TOGGLE_FILE_SEARCH_MODIFIER", cx, modifier };
}
export function updateSearchResults(
cx: Context,
characterIndex: number,
line: number,
matches: Match[]
@ -83,6 +86,7 @@ export function updateSearchResults(
return {
type: "UPDATE_SEARCH_RESULTS",
cx,
results: {
matches,
matchIndex,
@ -92,7 +96,7 @@ export function updateSearchResults(
};
}
export function searchContents(query: string, editor: Object) {
export function searchContents(cx: Context, query: string, editor: Object) {
return async ({ getState, dispatch }: ThunkArgs) => {
const modifiers = getFileSearchModifiers(getState());
const selectedSource = getSelectedSource(getState());
@ -124,7 +128,7 @@ export function searchContents(query: string, editor: Object) {
const { ch, line } = res;
dispatch(updateSearchResults(ch, line, matches));
dispatch(updateSearchResults(cx, ch, line, matches));
};
}
@ -155,7 +159,7 @@ export function searchContentsForHighlight(
};
}
export function traverseResults(rev: boolean, editor: Editor) {
export function traverseResults(cx: Context, rev: boolean, editor: Editor) {
return async ({ getState, dispatch }: ThunkArgs) => {
if (!editor) {
return;
@ -180,12 +184,12 @@ export function traverseResults(rev: boolean, editor: Editor) {
return;
}
const { ch, line } = results;
dispatch(updateSearchResults(ch, line, matchedLocations));
dispatch(updateSearchResults(cx, ch, line, matchedLocations));
}
};
}
export function closeFileSearch(editor: Editor) {
export function closeFileSearch(cx: Context, editor: Editor) {
return ({ getState, dispatch }: ThunkArgs) => {
if (editor) {
const query = getFileSearchQuery(getState());
@ -193,7 +197,7 @@ export function closeFileSearch(editor: Editor) {
removeOverlay(ctx, query);
}
dispatch(setFileSearchQuery(""));
dispatch(setFileSearchQuery(cx, ""));
dispatch(closeActiveSearch());
dispatch(clearHighlightLineRange());
};

View File

@ -4,8 +4,8 @@
// @flow
import { getCurrentThread } from "../../selectors";
import type { ThunkArgs } from "../types";
import type { ThreadContext } from "../../types";
/**
* Debugger breakOnNext command.
@ -15,10 +15,9 @@ import type { ThunkArgs } from "../types";
* @memberof actions/pause
* @static
*/
export function breakOnNext() {
export function breakOnNext(cx: ThreadContext) {
return async ({ dispatch, getState, client }: ThunkArgs) => {
const thread = getCurrentThread(getState());
await client.breakOnNext(thread);
return dispatch({ type: "BREAK_ON_NEXT", thread });
await client.breakOnNext(cx.thread);
return dispatch({ type: "BREAK_ON_NEXT", thread: cx.thread });
};
}

View File

@ -6,32 +6,39 @@
// @flow
import {
getIsPaused,
getCurrentThread,
getSource,
getTopFrame,
getSelectedFrame
getSelectedFrame,
getThreadContext
} from "../../selectors";
import { PROMISE } from "../utils/middleware/promise";
import { getNextStep } from "../../workers/parser";
import { addHiddenBreakpoint } from "../breakpoints";
import { evaluateExpressions } from "../expressions";
import { selectLocation } from "../sources";
import { fetchScopes } from "./fetchScopes";
import { features } from "../../utils/prefs";
import { recordEvent } from "../../utils/telemetry";
import assert from "../../utils/assert";
import type { Source, ThreadId } from "../../types";
import type { Source, ThreadId, Context, ThreadContext } from "../../types";
import type { ThunkArgs } from "../types";
import type { Command } from "../../reducers/types";
export function selectThread(thread: ThreadId) {
export function selectThread(cx: Context, thread: ThreadId) {
return async ({ dispatch, getState, client }: ThunkArgs) => {
await dispatch({ type: "SELECT_THREAD", thread });
dispatch(evaluateExpressions());
await dispatch({ cx, type: "SELECT_THREAD", thread });
// Get a new context now that the current thread has changed.
const threadcx = getThreadContext(getState());
assert(threadcx.thread == thread, "Thread mismatch");
dispatch(evaluateExpressions(threadcx));
const frame = getSelectedFrame(getState(), thread);
if (frame) {
dispatch(selectLocation(frame.location));
dispatch(selectLocation(threadcx, frame.location));
dispatch(fetchScopes(threadcx));
}
};
}
@ -43,14 +50,15 @@ export function selectThread(thread: ThreadId) {
* @memberof actions/pause
* @static
*/
export function command(thread: ThreadId, type: Command) {
export function command(cx: ThreadContext, type: Command) {
return async ({ dispatch, getState, client }: ThunkArgs) => {
if (type) {
return dispatch({
type: "COMMAND",
command: type,
thread,
[PROMISE]: client[type](thread)
cx,
thread: cx.thread,
[PROMISE]: client[type](cx.thread)
});
}
};
@ -62,11 +70,10 @@ export function command(thread: ThreadId, type: Command) {
* @static
* @returns {Function} {@link command}
*/
export function stepIn() {
export function stepIn(cx: ThreadContext) {
return ({ dispatch, getState }: ThunkArgs) => {
const thread = getCurrentThread(getState());
if (getIsPaused(getState(), thread)) {
return dispatch(command(thread, "stepIn"));
if (cx.isPaused) {
return dispatch(command(cx, "stepIn"));
}
};
}
@ -77,11 +84,10 @@ export function stepIn() {
* @static
* @returns {Function} {@link command}
*/
export function stepOver() {
export function stepOver(cx: ThreadContext) {
return ({ dispatch, getState }: ThunkArgs) => {
const thread = getCurrentThread(getState());
if (getIsPaused(getState(), thread)) {
return dispatch(astCommand(thread, "stepOver"));
if (cx.isPaused) {
return dispatch(astCommand(cx, "stepOver"));
}
};
}
@ -92,11 +98,10 @@ export function stepOver() {
* @static
* @returns {Function} {@link command}
*/
export function stepOut() {
export function stepOut(cx: ThreadContext) {
return ({ dispatch, getState }: ThunkArgs) => {
const thread = getCurrentThread(getState());
if (getIsPaused(getState(), thread)) {
return dispatch(command(thread, "stepOut"));
if (cx.isPaused) {
return dispatch(command(cx, "stepOut"));
}
};
}
@ -107,12 +112,11 @@ export function stepOut() {
* @static
* @returns {Function} {@link command}
*/
export function resume() {
export function resume(cx: ThreadContext) {
return ({ dispatch, getState }: ThunkArgs) => {
const thread = getCurrentThread(getState());
if (getIsPaused(getState(), thread)) {
if (cx.isPaused) {
recordEvent("continue");
return dispatch(command(thread, "resume"));
return dispatch(command(cx, "resume"));
}
};
}
@ -123,11 +127,10 @@ export function resume() {
* @static
* @returns {Function} {@link command}
*/
export function rewind() {
export function rewind(cx: ThreadContext) {
return ({ dispatch, getState }: ThunkArgs) => {
const thread = getCurrentThread(getState());
if (getIsPaused(getState(), thread)) {
return dispatch(command(thread, "rewind"));
if (cx.isPaused) {
return dispatch(command(cx, "rewind"));
}
};
}
@ -138,11 +141,10 @@ export function rewind() {
* @static
* @returns {Function} {@link command}
*/
export function reverseStepIn() {
export function reverseStepIn(cx: ThreadContext) {
return ({ dispatch, getState }: ThunkArgs) => {
const thread = getCurrentThread(getState());
if (getIsPaused(getState(), thread)) {
return dispatch(command(thread, "reverseStepIn"));
if (cx.isPaused) {
return dispatch(command(cx, "reverseStepIn"));
}
};
}
@ -153,11 +155,10 @@ export function reverseStepIn() {
* @static
* @returns {Function} {@link command}
*/
export function reverseStepOver() {
export function reverseStepOver(cx: ThreadContext) {
return ({ dispatch, getState }: ThunkArgs) => {
const thread = getCurrentThread(getState());
if (getIsPaused(getState(), thread)) {
return dispatch(astCommand(thread, "reverseStepOver"));
if (cx.isPaused) {
return dispatch(astCommand(cx, "reverseStepOver"));
}
};
}
@ -168,11 +169,10 @@ export function reverseStepOver() {
* @static
* @returns {Function} {@link command}
*/
export function reverseStepOut() {
export function reverseStepOut(cx: ThreadContext) {
return ({ dispatch, getState }: ThunkArgs) => {
const thread = getCurrentThread(getState());
if (getIsPaused(getState(), thread)) {
return dispatch(command(thread, "reverseStepOut"));
if (cx.isPaused) {
return dispatch(command(cx, "reverseStepOut"));
}
};
}
@ -205,26 +205,26 @@ function hasAwait(source: Source, pauseLocation) {
* @param stepType
* @returns {function(ThunkArgs)}
*/
export function astCommand(thread: ThreadId, stepType: Command) {
export function astCommand(cx: ThreadContext, stepType: Command) {
return async ({ dispatch, getState, sourceMaps }: ThunkArgs) => {
if (!features.asyncStepping) {
return dispatch(command(thread, stepType));
return dispatch(command(cx, stepType));
}
if (stepType == "stepOver") {
// This type definition is ambiguous:
const frame: any = getTopFrame(getState(), thread);
const frame: any = getTopFrame(getState(), cx.thread);
const source = getSource(getState(), frame.location.sourceId);
if (source && hasAwait(source, frame.location)) {
const nextLocation = await getNextStep(source.id, frame.location);
if (nextLocation) {
await dispatch(addHiddenBreakpoint(nextLocation));
return dispatch(command(thread, "resume"));
await dispatch(addHiddenBreakpoint(cx, nextLocation));
return dispatch(command(cx, "resume"));
}
}
}
return dispatch(command(thread, stepType));
return dispatch(command(cx, stepType));
};
}

View File

@ -5,7 +5,6 @@
// @flow
import {
getCurrentThread,
getSelectedSource,
getSelectedFrame,
getCanRewind
@ -14,12 +13,16 @@ import { addHiddenBreakpoint } from "../breakpoints";
import { resume, rewind } from "./commands";
import type { ThunkArgs } from "../types";
import type { ThreadContext } from "../../types";
export function continueToHere(line: number, column?: number) {
export function continueToHere(
cx: ThreadContext,
line: number,
column?: number
) {
return async function({ dispatch, getState }: ThunkArgs) {
const thread = getCurrentThread(getState());
const selectedSource = getSelectedSource(getState());
const selectedFrame = getSelectedFrame(getState(), thread);
const selectedFrame = getSelectedFrame(getState(), cx.thread);
if (!selectedFrame || !selectedSource) {
return;
@ -34,13 +37,13 @@ export function continueToHere(line: number, column?: number) {
getCanRewind(getState()) && line < debugLine ? rewind : resume;
await dispatch(
addHiddenBreakpoint({
addHiddenBreakpoint(cx, {
line,
column: column,
sourceId: selectedSource.id
})
);
dispatch(action());
dispatch(action(cx));
};
}

View File

@ -7,23 +7,24 @@
import { getSelectedFrame, getGeneratedFrameScope } from "../../selectors";
import { mapScopes } from "./mapScopes";
import { PROMISE } from "../utils/middleware/promise";
import type { ThreadId } from "../../types";
import type { ThreadContext } from "../../types";
import type { ThunkArgs } from "../types";
export function fetchScopes(thread: ThreadId) {
export function fetchScopes(cx: ThreadContext) {
return async function({ dispatch, getState, client, sourceMaps }: ThunkArgs) {
const frame = getSelectedFrame(getState(), thread);
const frame = getSelectedFrame(getState(), cx.thread);
if (!frame || getGeneratedFrameScope(getState(), frame.id)) {
return;
}
const scopes = dispatch({
type: "ADD_SCOPES",
thread,
cx,
thread: cx.thread,
frame,
[PROMISE]: client.getFrameScopes(frame)
});
await dispatch(mapScopes(scopes, frame));
await dispatch(mapScopes(cx, scopes, frame));
};
}

View File

@ -16,7 +16,7 @@ import assert from "../../utils/assert";
import { findClosestFunction } from "../../utils/ast";
import { setSymbols } from "../sources/symbols";
import type { Frame, ThreadId } from "../../types";
import type { Frame, ThreadContext } from "../../types";
import type { State } from "../../reducers/types";
import type { ThunkArgs } from "../types";
@ -155,11 +155,11 @@ async function expandFrames(
return result;
}
async function updateFrameSymbols(frames, { dispatch, getState }) {
async function updateFrameSymbols(cx, frames, { dispatch, getState }) {
await Promise.all(
frames.map(frame => {
const source = getSourceFromId(getState(), frame.location.sourceId);
return dispatch(setSymbols({ source }));
return dispatch(setSymbols({ cx, source }));
})
);
}
@ -173,28 +173,29 @@ async function updateFrameSymbols(frames, { dispatch, getState }) {
* @memberof actions/pause
* @static
*/
export function mapFrames(thread: ThreadId) {
export function mapFrames(cx: ThreadContext) {
return async function(thunkArgs: ThunkArgs) {
const { dispatch, getState, sourceMaps } = thunkArgs;
const frames = getFrames(getState(), thread);
const frames = getFrames(getState(), cx.thread);
if (!frames) {
return;
}
let mappedFrames = await updateFrameLocations(frames, sourceMaps);
await updateFrameSymbols(mappedFrames, thunkArgs);
await updateFrameSymbols(cx, mappedFrames, thunkArgs);
mappedFrames = await expandFrames(mappedFrames, sourceMaps, getState);
mappedFrames = mapDisplayNames(mappedFrames, getState);
const selectedFrameId = getSelectedFrameId(
getState(),
thread,
cx.thread,
mappedFrames
);
dispatch({
type: "MAP_FRAMES",
thread,
cx,
thread: cx.thread,
frames: mappedFrames,
selectedFrameId
});

View File

@ -10,15 +10,16 @@ import {
getSelectedFrame,
getSelectedGeneratedScope,
getSelectedOriginalScope,
getCurrentThread
getThreadContext
} from "../../selectors";
import { loadSourceText } from "../sources/loadSourceText";
import { PROMISE } from "../utils/middleware/promise";
import assert from "../../utils/assert";
import { features } from "../../utils/prefs";
import { log } from "../../utils/log";
import { isGenerated, isOriginal } from "../../utils/source";
import type { Frame, Scope } from "../../types";
import type { Frame, Scope, ThreadContext } from "../../types";
import type { ThunkArgs } from "../types";
@ -32,23 +33,30 @@ export function toggleMapScopes() {
dispatch({ type: "TOGGLE_MAP_SCOPES", mapScopes: true });
const thread = getCurrentThread(getState());
if (getSelectedOriginalScope(getState(), thread)) {
const cx = getThreadContext(getState());
if (getSelectedOriginalScope(getState(), cx.thread)) {
return;
}
const scopes = getSelectedGeneratedScope(getState(), thread);
const frame = getSelectedFrame(getState(), thread);
const scopes = getSelectedGeneratedScope(getState(), cx.thread);
const frame = getSelectedFrame(getState(), cx.thread);
if (!scopes || !frame) {
return;
}
dispatch(mapScopes(Promise.resolve(scopes.scope), frame));
dispatch(mapScopes(cx, Promise.resolve(scopes.scope), frame));
};
}
export function mapScopes(scopes: Promise<Scope>, frame: Frame) {
export function mapScopes(
cx: ThreadContext,
scopes: Promise<Scope>,
frame: Frame
) {
return async function({ dispatch, getState, client, sourceMaps }: ThunkArgs) {
assert(cx.thread == frame.thread, "Thread mismatch");
const generatedSource = getSource(
getState(),
frame.generatedLocation.sourceId
@ -58,7 +66,8 @@ export function mapScopes(scopes: Promise<Scope>, frame: Frame) {
await dispatch({
type: "MAP_SCOPES",
thread: frame.thread,
cx,
thread: cx.thread,
frame,
[PROMISE]: (async function() {
if (
@ -72,9 +81,9 @@ export function mapScopes(scopes: Promise<Scope>, frame: Frame) {
return null;
}
await dispatch(loadSourceText({ source }));
await dispatch(loadSourceText({ cx, source }));
if (isOriginal(source)) {
await dispatch(loadSourceText({ source: generatedSource }));
await dispatch(loadSourceText({ cx, source: generatedSource }));
}
try {

View File

@ -7,7 +7,8 @@ import {
getHiddenBreakpoint,
isEvaluatingExpression,
getSelectedFrame,
wasStepping
wasStepping,
getThreadContext
} from "../../selectors";
import { mapFrames } from ".";
@ -15,6 +16,7 @@ import { removeBreakpoint } from "../breakpoints";
import { evaluateExpressions } from "../expressions";
import { selectLocation } from "../sources";
import { togglePaneCollapse } from "../ui";
import assert from "../../utils/assert";
import { fetchScopes } from "./fetchScopes";
@ -42,29 +44,33 @@ export function paused(pauseInfo: Pause) {
loadedObjects: loadedObjects || []
});
// Get a context capturing the newly paused and selected thread.
const cx = getThreadContext(getState());
assert(cx.thread == thread, "Thread mismatch");
const hiddenBreakpoint = getHiddenBreakpoint(getState());
if (hiddenBreakpoint) {
dispatch(removeBreakpoint(hiddenBreakpoint));
dispatch(removeBreakpoint(cx, hiddenBreakpoint));
}
await dispatch(mapFrames(thread));
await dispatch(mapFrames(cx));
const selectedFrame = getSelectedFrame(getState(), thread);
if (selectedFrame) {
await dispatch(selectLocation(selectedFrame.location));
await dispatch(selectLocation(cx, selectedFrame.location));
}
if (!wasStepping(getState(), thread)) {
dispatch(togglePaneCollapse("end", false));
}
await dispatch(fetchScopes(thread));
await dispatch(fetchScopes(cx));
// Run after fetching scoping data so that it may make use of the sourcemap
// expression mappings for local variables.
const atException = why.type == "exception";
if (!atException || !isEvaluatingExpression(getState(), thread)) {
await dispatch(evaluateExpressions());
await dispatch(evaluateExpressions(cx));
}
};
}

View File

@ -4,7 +4,7 @@
// @flow
import { isStepping, getPauseReason } from "../../selectors";
import { isStepping, getPauseReason, getThreadContext } from "../../selectors";
import { evaluateExpressions } from "../expressions";
import { inDebuggerEval } from "../../utils/pause";
@ -26,8 +26,9 @@ export function resumed(packet: ResumedPacket) {
dispatch({ type: "RESUME", thread, wasStepping });
if (!wasStepping && !wasPausedInEval) {
await dispatch(evaluateExpressions());
const cx = getThreadContext(getState());
if (!wasStepping && !wasPausedInEval && cx.thread == thread) {
await dispatch(evaluateExpressions(cx));
}
};
}

View File

@ -7,25 +7,29 @@
import { selectLocation } from "../sources";
import { evaluateExpressions } from "../expressions";
import { fetchScopes } from "./fetchScopes";
import assert from "../../utils/assert";
import type { Frame } from "../../types";
import type { Frame, ThreadContext } from "../../types";
import type { ThunkArgs } from "../types";
/**
* @memberof actions/pause
* @static
*/
export function selectFrame(frame: Frame) {
export function selectFrame(cx: ThreadContext, frame: Frame) {
return async ({ dispatch, client, getState, sourceMaps }: ThunkArgs) => {
assert(cx.thread == frame.thread, "Thread mismatch");
dispatch({
type: "SELECT_FRAME",
thread: frame.thread,
cx,
thread: cx.thread,
frame
});
dispatch(selectLocation(frame.location));
dispatch(selectLocation(cx, frame.location));
dispatch(evaluateExpressions());
dispatch(fetchScopes(frame.thread));
dispatch(evaluateExpressions(cx));
dispatch(fetchScopes(cx));
};
}

View File

@ -4,25 +4,30 @@
// @flow
import { getPopupObjectProperties, getCurrentThread } from "../../selectors";
import { getPopupObjectProperties } from "../../selectors";
import type { ThunkArgs } from "../types";
import type { ThreadContext } from "../../types";
/**
* @memberof actions/pause
* @static
*/
export function setPopupObjectProperties(object: any, properties: Object) {
export function setPopupObjectProperties(
cx: ThreadContext,
object: any,
properties: Object
) {
return ({ dispatch, client, getState }: ThunkArgs) => {
const objectId = object.actor || object.objectId;
const thread = getCurrentThread(getState());
if (getPopupObjectProperties(getState(), thread, object.actor)) {
if (getPopupObjectProperties(getState(), cx.thread, object.actor)) {
return;
}
dispatch({
type: "SET_POPUP_OBJECT_PROPERTIES",
thread,
cx,
thread: cx.thread,
objectId,
properties
});

View File

@ -109,7 +109,8 @@ describe("pause", () => {
await dispatch(actions.newSource(makeSource("foo1")));
await dispatch(actions.paused(mockPauseInfo));
const stepped = dispatch(actions.stepIn());
const cx = selectors.getThreadContext(getState());
const stepped = dispatch(actions.stepIn(cx));
expect(isStepping(getState(), "FakeThread")).toBeTruthy();
if (!stepInResolve) {
throw new Error("no stepInResolve");
@ -121,9 +122,9 @@ describe("pause", () => {
it("should only step when paused", async () => {
const client = { stepIn: jest.fn() };
const { dispatch } = createStore(client);
const { dispatch, cx } = createStore(client);
dispatch(actions.stepIn());
dispatch(actions.stepIn(cx));
expect(client.stepIn.mock.calls).toHaveLength(0);
});
@ -133,7 +134,8 @@ describe("pause", () => {
await dispatch(actions.newSource(makeSource("foo1")));
await dispatch(actions.paused(mockPauseInfo));
dispatch(actions.stepIn());
const cx = selectors.getThreadContext(getState());
dispatch(actions.stepIn(cx));
expect(isStepping(getState(), "FakeThread")).toBeTruthy();
});
@ -144,15 +146,16 @@ describe("pause", () => {
await dispatch(actions.newSource(makeSource("foo1")));
await dispatch(actions.paused(mockPauseInfo));
const cx = selectors.getThreadContext(getState());
const getNextStepSpy = jest.spyOn(parser, "getNextStep");
dispatch(actions.stepOver());
dispatch(actions.stepOver(cx));
expect(getNextStepSpy).not.toBeCalled();
expect(isStepping(getState(), "FakeThread")).toBeTruthy();
});
it("should step over when paused before an await", async () => {
const store = createStore(mockThreadClient);
const { dispatch } = store;
const { dispatch, getState } = store;
const mockPauseInfo = createPauseInfo({
sourceId: "await",
line: 2,
@ -163,15 +166,16 @@ describe("pause", () => {
await dispatch(actions.newSource(source));
await dispatch(actions.paused(mockPauseInfo));
const cx = selectors.getThreadContext(getState());
const getNextStepSpy = jest.spyOn(parser, "getNextStep");
dispatch(actions.stepOver());
dispatch(actions.stepOver(cx));
expect(getNextStepSpy).toBeCalled();
getNextStepSpy.mockRestore();
});
it("should step over when paused after an await", async () => {
const store = createStore(mockThreadClient);
const { dispatch } = store;
const { dispatch, getState } = store;
const mockPauseInfo = createPauseInfo({
sourceId: "await",
line: 2,
@ -182,8 +186,9 @@ describe("pause", () => {
await dispatch(actions.newSource(source));
await dispatch(actions.paused(mockPauseInfo));
const cx = selectors.getThreadContext(getState());
const getNextStepSpy = jest.spyOn(parser, "getNextStep");
dispatch(actions.stepOver());
dispatch(actions.stepOver(cx));
expect(getNextStepSpy).toBeCalled();
getNextStepSpy.mockRestore();
});
@ -367,22 +372,27 @@ describe("pause", () => {
describe("resumed", () => {
it("should not evaluate expression while stepping", async () => {
const client = { evaluateExpressions: jest.fn() };
const { dispatch } = createStore(client);
const client = { ...mockThreadClient, evaluateExpressions: jest.fn() };
const { dispatch, getState } = createStore(client);
const mockPauseInfo = createPauseInfo();
dispatch(actions.stepIn());
await dispatch(actions.newSource(makeSource("foo1")));
await dispatch(actions.paused(mockPauseInfo));
const cx = selectors.getThreadContext(getState());
dispatch(actions.stepIn(cx));
await dispatch(actions.resumed(resumedPacket()));
expect(client.evaluateExpressions.mock.calls).toHaveLength(1);
});
it("resuming - will re-evaluate watch expressions", async () => {
const store = createStore(mockThreadClient);
const { dispatch, getState } = store;
const { dispatch, getState, cx } = store;
const mockPauseInfo = createPauseInfo();
await dispatch(actions.newSource(makeSource("foo1")));
await dispatch(actions.newSource(makeSource("foo")));
dispatch(actions.addExpression("foo"));
await dispatch(actions.addExpression(cx, "foo"));
await waitForState(store, state => selectors.getExpression(state, "foo"));
mockThreadClient.evaluateExpressions = () => new Promise(r => r(["YAY"]));

View File

@ -22,7 +22,7 @@ import {
import { getMappedExpression } from "./expressions";
import type { Action, ThunkArgs } from "./types";
import type { Position } from "../types";
import type { Position, Context } from "../types";
import type { AstLocation } from "../workers/parser";
function findExpressionMatch(state, codeMirror, tokenPos) {
@ -43,6 +43,7 @@ function findExpressionMatch(state, codeMirror, tokenPos) {
}
export function updatePreview(
cx: Context,
target: HTMLElement,
tokenPos: Object,
codeMirror: any
@ -68,11 +69,12 @@ export function updatePreview(
return;
}
dispatch(setPreview(expression, location, tokenPos, cursorPos));
dispatch(setPreview(cx, expression, location, tokenPos, cursorPos));
};
}
export function setPreview(
cx: Context,
expression: string,
location: AstLocation,
tokenPos: Position,
@ -81,6 +83,7 @@ export function setPreview(
return async ({ dispatch, getState, client, sourceMaps }: ThunkArgs) => {
await dispatch({
type: "SET_PREVIEW",
cx,
[PROMISE]: (async function() {
const source = getSelectedSource(getState());
if (!source) {
@ -126,7 +129,7 @@ export function setPreview(
};
}
export function clearPreview() {
export function clearPreview(cx: Context) {
return ({ dispatch, getState, client }: ThunkArgs) => {
const currentSelection = getPreview(getState());
if (!currentSelection) {
@ -135,7 +138,8 @@ export function clearPreview() {
return dispatch(
({
type: "CLEAR_SELECTION"
type: "CLEAR_SELECTION",
cx
}: Action)
);
};

View File

@ -20,67 +20,73 @@ import {
} from "../reducers/project-text-search";
import type { Action, ThunkArgs } from "./types";
import type { Context } from "../types";
import type { SearchOperation } from "../reducers/project-text-search";
export function addSearchQuery(query: string): Action {
return { type: "ADD_QUERY", query };
export function addSearchQuery(cx: Context, query: string): Action {
return { type: "ADD_QUERY", cx, query };
}
export function addOngoingSearch(ongoingSearch: SearchOperation): Action {
return { type: "ADD_ONGOING_SEARCH", ongoingSearch };
export function addOngoingSearch(
cx: Context,
ongoingSearch: SearchOperation
): Action {
return { type: "ADD_ONGOING_SEARCH", cx, ongoingSearch };
}
export function addSearchResult(
cx: Context,
sourceId: string,
filepath: string,
matches: Object[]
): Action {
return {
type: "ADD_SEARCH_RESULT",
cx,
result: { sourceId, filepath, matches }
};
}
export function clearSearchResults(): Action {
return { type: "CLEAR_SEARCH_RESULTS" };
export function clearSearchResults(cx: Context): Action {
return { type: "CLEAR_SEARCH_RESULTS", cx };
}
export function clearSearch(): Action {
return { type: "CLEAR_SEARCH" };
export function clearSearch(cx: Context): Action {
return { type: "CLEAR_SEARCH", cx };
}
export function updateSearchStatus(status: string): Action {
return { type: "UPDATE_STATUS", status };
export function updateSearchStatus(cx: Context, status: string): Action {
return { type: "UPDATE_STATUS", cx, status };
}
export function closeProjectSearch() {
export function closeProjectSearch(cx: Context) {
return ({ dispatch, getState }: ThunkArgs) => {
dispatch(stopOngoingSearch());
dispatch(stopOngoingSearch(cx));
dispatch({ type: "CLOSE_PROJECT_SEARCH" });
};
}
export function stopOngoingSearch() {
export function stopOngoingSearch(cx: Context) {
return ({ dispatch, getState }: ThunkArgs) => {
const state = getState();
const ongoingSearch = getTextSearchOperation(state);
const status = getTextSearchStatus(state);
if (ongoingSearch && status !== statusType.done) {
ongoingSearch.cancel();
dispatch(updateSearchStatus(statusType.cancelled));
dispatch(updateSearchStatus(cx, statusType.cancelled));
}
};
}
export function searchSources(query: string) {
export function searchSources(cx: Context, query: string) {
let cancelled = false;
const search = async ({ dispatch, getState }: ThunkArgs) => {
dispatch(stopOngoingSearch());
await dispatch(addOngoingSearch(search));
await dispatch(clearSearchResults());
await dispatch(addSearchQuery(query));
dispatch(updateSearchStatus(statusType.fetching));
dispatch(stopOngoingSearch(cx));
await dispatch(addOngoingSearch(cx, search));
await dispatch(clearSearchResults(cx));
await dispatch(addSearchQuery(cx, query));
dispatch(updateSearchStatus(cx, statusType.fetching));
const validSources = getSourceList(getState()).filter(
source => !hasPrettySource(getState(), source.id) && !isThirdParty(source)
);
@ -88,10 +94,10 @@ export function searchSources(query: string) {
if (cancelled) {
return;
}
await dispatch(loadSourceText({ source }));
await dispatch(searchSource(source.id, query));
await dispatch(loadSourceText({ cx, source }));
await dispatch(searchSource(cx, source.id, query));
}
dispatch(updateSearchStatus(statusType.done));
dispatch(updateSearchStatus(cx, statusType.done));
};
search.cancel = () => {
@ -101,7 +107,7 @@ export function searchSources(query: string) {
return search;
}
export function searchSource(sourceId: string, query: string) {
export function searchSource(cx: Context, sourceId: string, query: string) {
return async ({ dispatch, getState }: ThunkArgs) => {
const source = getSource(getState(), sourceId);
if (!source) {
@ -112,6 +118,6 @@ export function searchSource(sourceId: string, query: string) {
if (!matches.length) {
return;
}
dispatch(addSearchResult(source.id, source.url, matches));
dispatch(addSearchResult(cx, source.id, source.url, matches));
};
}

View File

@ -4,6 +4,7 @@
// @flow
import type { Action, FocusItem, ThunkArgs } from "./types";
import type { Context } from "../types";
export function setExpandedState(thread: string, expanded: Set<string>) {
return ({ dispatch, getState }: ThunkArgs) => {
@ -17,10 +18,11 @@ export function setExpandedState(thread: string, expanded: Set<string>) {
};
}
export function focusItem(item: FocusItem) {
export function focusItem(cx: Context, item: FocusItem) {
return ({ dispatch, getState }: ThunkArgs) => {
dispatch({
type: "SET_FOCUSED_SOURCE_ITEM",
cx,
item
});
};

View File

@ -16,7 +16,7 @@ import { getSourceFromId } from "../../selectors";
import { PROMISE } from "../utils/middleware/promise";
import type { Source } from "../../types";
import type { Source, Context } from "../../types";
import type { ThunkArgs } from "../types";
async function blackboxActors(state, client, sourceId, isBlackBoxed, range?) {
@ -27,7 +27,7 @@ async function blackboxActors(state, client, sourceId, isBlackBoxed, range?) {
return { isBlackBoxed: !isBlackBoxed };
}
export function toggleBlackBox(source: Source) {
export function toggleBlackBox(cx: Context, source: Source) {
return async ({ dispatch, getState, client, sourceMaps }: ThunkArgs) => {
const { isBlackBoxed } = source;
@ -45,6 +45,7 @@ export function toggleBlackBox(source: Source) {
return dispatch({
type: "BLACKBOX",
cx,
source,
[PROMISE]: blackboxActors(
getState(),

View File

@ -27,7 +27,7 @@ import { Telemetry } from "devtools-modules";
import type { ThunkArgs } from "../types";
import type { Source } from "../../types";
import type { Source, Context } from "../../types";
// Measures the time it takes for a source to load
const loadSourceHistogram = "DEVTOOLS_DEBUGGER_LOAD_SOURCE_MS";
@ -73,6 +73,7 @@ async function loadSource(
}
async function loadSourceTextPromise(
cx: Context,
source: Source,
{ dispatch, getState, client, sourceMaps }: ThunkArgs
): Promise<?Source> {
@ -92,27 +93,27 @@ async function loadSourceTextPromise(
if (!newSource.isWasm && isLoaded(newSource)) {
parser.setSource(newSource);
dispatch(setBreakpointPositions({ sourceId: newSource.id }));
dispatch(setBreakpointPositions({ cx, sourceId: newSource.id }));
// Update the text in any breakpoints for this source by re-adding them.
const breakpoints = getBreakpointsForSource(getState(), source.id);
for (const { location, options, disabled } of breakpoints) {
await dispatch(addBreakpoint(location, options, disabled));
await dispatch(addBreakpoint(cx, location, options, disabled));
}
}
return newSource;
}
export function loadSourceById(sourceId: string) {
export function loadSourceById(cx: Context, sourceId: string) {
return ({ getState, dispatch }: ThunkArgs) => {
const source = getSourceFromId(getState(), sourceId);
return dispatch(loadSourceText({ source }));
return dispatch(loadSourceText({ cx, source }));
};
}
export const loadSourceText: MemoizedAction<
{ source: Source },
{ cx: Context, source: Source },
?Source
> = memoizeableAction("loadSourceText", {
exitEarly: ({ source }) => !source,
@ -122,5 +123,6 @@ export const loadSourceText: MemoizedAction<
const epoch = getSourcesEpoch(getState());
return `${epoch}:${source.id}`;
},
action: ({ source }, thunkArgs) => loadSourceTextPromise(source, thunkArgs)
action: ({ cx, source }, thunkArgs) =>
loadSourceTextPromise(cx, source, thunkArgs)
});

View File

@ -28,13 +28,14 @@ import {
getSource,
getPendingSelectedLocation,
getPendingBreakpointsForSource,
hasBreakpointPositions
hasBreakpointPositions,
getContext
} from "../../selectors";
import { prefs } from "../../utils/prefs";
import sourceQueue from "../../utils/source-queue";
import type { Source, SourceId } from "../../types";
import type { Source, SourceId, Context } from "../../types";
import type { Action, ThunkArgs } from "../types";
function createOriginalSource(
@ -57,14 +58,14 @@ function createOriginalSource(
};
}
function loadSourceMaps(sources: Source[]) {
function loadSourceMaps(cx: Context, sources: Source[]) {
return async function({
dispatch,
sourceMaps
}: ThunkArgs): Promise<Promise<Source>[]> {
const sourceList = await Promise.all(
sources.map(async ({ id }) => {
const originalSources = await dispatch(loadSourceMap(id));
const originalSources = await dispatch(loadSourceMap(cx, id));
sourceQueue.queueSources(originalSources);
return originalSources;
})
@ -76,7 +77,7 @@ function loadSourceMaps(sources: Source[]) {
// loading source maps as sometimes generated and original
// files share the same paths.
for (const source of sources) {
dispatch(checkPendingBreakpoints(source.id));
dispatch(checkPendingBreakpoints(cx, source.id));
}
return flatten(sourceList);
@ -87,7 +88,7 @@ function loadSourceMaps(sources: Source[]) {
* @memberof actions/sources
* @static
*/
function loadSourceMap(sourceId: SourceId) {
function loadSourceMap(cx: Context, sourceId: SourceId) {
return async function({
dispatch,
getState,
@ -131,6 +132,7 @@ function loadSourceMap(sourceId: SourceId) {
dispatch(
({
type: "UPDATE_SOURCE",
cx,
// NOTE: Flow https://github.com/facebook/flow/issues/6342 issue
source: (({ ...currentSource, sourceMapURL: "" }: any): Source)
}: Action)
@ -144,7 +146,7 @@ function loadSourceMap(sourceId: SourceId) {
// If a request has been made to show this source, go ahead and
// select it.
function checkSelectedSource(sourceId: string) {
function checkSelectedSource(cx: Context, sourceId: string) {
return async ({ dispatch, getState }: ThunkArgs) => {
const source = getSource(getState(), sourceId);
const pendingLocation = getPendingSelectedLocation(getState());
@ -158,12 +160,12 @@ function checkSelectedSource(sourceId: string) {
if (rawPendingUrl === source.url) {
if (isPrettyURL(pendingUrl)) {
const prettySource = await dispatch(togglePrettyPrint(source.id));
return dispatch(checkPendingBreakpoints(prettySource.id));
const prettySource = await dispatch(togglePrettyPrint(cx, source.id));
return dispatch(checkPendingBreakpoints(cx, prettySource.id));
}
await dispatch(
selectLocation({
selectLocation(cx, {
sourceId: source.id,
line:
typeof pendingLocation.line === "number" ? pendingLocation.line : 0,
@ -174,7 +176,7 @@ function checkSelectedSource(sourceId: string) {
};
}
function checkPendingBreakpoints(sourceId: string) {
function checkPendingBreakpoints(cx: Context, sourceId: string) {
return async ({ dispatch, getState }: ThunkArgs) => {
// source may have been modified by selectLocation
const source = getSource(getState(), sourceId);
@ -192,17 +194,17 @@ function checkPendingBreakpoints(sourceId: string) {
}
// load the source text if there is a pending breakpoint for it
await dispatch(loadSourceText({ source }));
await dispatch(loadSourceText({ cx, source }));
await Promise.all(
pendingBreakpoints.map(bp => {
return dispatch(syncBreakpoint(sourceId, bp));
return dispatch(syncBreakpoint(cx, sourceId, bp));
})
);
};
}
function restoreBlackBoxedSources(sources: Source[]) {
function restoreBlackBoxedSources(cx: Context, sources: Source[]) {
return async ({ dispatch }: ThunkArgs) => {
const tabs = getBlackBoxList();
if (tabs.length == 0) {
@ -210,7 +212,7 @@ function restoreBlackBoxedSources(sources: Source[]) {
}
for (const source of sources) {
if (tabs.includes(source.url) && !source.isBlackBoxed) {
dispatch(toggleBlackBox(source));
dispatch(toggleBlackBox(cx, source));
}
}
};
@ -229,6 +231,8 @@ export function newSource(source: Source) {
export function newSources(sources: Source[]) {
return async ({ dispatch, getState }: ThunkArgs) => {
const cx = getContext(getState());
const _newSources = sources.filter(
source => !getSource(getState(), source.id) || isInlineScript(source)
);
@ -237,10 +241,10 @@ export function newSources(sources: Source[]) {
hasBreakpointPositions(getState(), source.id)
);
dispatch({ type: "ADD_SOURCES", sources });
dispatch({ type: "ADD_SOURCES", cx, sources });
for (const source of _newSources) {
dispatch(checkSelectedSource(source.id));
dispatch(checkSelectedSource(cx, source.id));
}
// Adding new sources may have cleared this file's breakpoint positions
@ -248,11 +252,11 @@ export function newSources(sources: Source[]) {
// re-request new breakpoint positions.
for (const source of sourcesNeedingPositions) {
if (!hasBreakpointPositions(getState(), source.id)) {
dispatch(setBreakpointPositions({ sourceId: source.id }));
dispatch(setBreakpointPositions({ cx, sourceId: source.id }));
}
}
dispatch(restoreBlackBoxedSources(_newSources));
dispatch(loadSourceMaps(_newSources));
dispatch(restoreBlackBoxedSources(cx, _newSources));
dispatch(loadSourceMaps(cx, _newSources));
};
}

View File

@ -18,14 +18,14 @@ import { selectSpecificLocation } from "../sources";
import {
getSource,
getSourceFromId,
getSourceThreads,
getSourceByURL,
getSelectedLocation
getSelectedLocation,
getThreadContext
} from "../../selectors";
import type { Action, ThunkArgs } from "../types";
import { selectSource } from "./select";
import type { JsSource, Source } from "../../types";
import type { JsSource, Source, Context } from "../../types";
export async function prettyPrintSource(
sourceMaps: any,
@ -51,7 +51,7 @@ export async function prettyPrintSource(
};
}
export function createPrettySource(sourceId: string) {
export function createPrettySource(cx: Context, sourceId: string) {
return async ({ dispatch, getState, sourceMaps }: ThunkArgs) => {
const source = getSourceFromId(getState(), sourceId);
const url = getPrettySourceURL(source.url);
@ -72,25 +72,25 @@ export function createPrettySource(sourceId: string) {
actors: []
};
dispatch(({ type: "ADD_SOURCE", source: prettySource }: Action));
await dispatch(selectSource(prettySource.id));
dispatch(({ type: "ADD_SOURCE", cx, source: prettySource }: Action));
await dispatch(selectSource(cx, prettySource.id));
return prettySource;
};
}
function selectPrettyLocation(prettySource: Source) {
function selectPrettyLocation(cx: Context, prettySource: Source) {
return async ({ dispatch, sourceMaps, getState }: ThunkArgs) => {
let location = getSelectedLocation(getState());
if (location) {
location = await sourceMaps.getOriginalLocation(location);
return dispatch(
selectSpecificLocation({ ...location, sourceId: prettySource.id })
selectSpecificLocation(cx, { ...location, sourceId: prettySource.id })
);
}
return dispatch(selectSource(prettySource.id));
return dispatch(selectSource(cx, prettySource.id));
};
}
@ -106,7 +106,7 @@ function selectPrettyLocation(prettySource: Source) {
* A promise that resolves to [aSource, prettyText] or rejects to
* [aSource, error].
*/
export function togglePrettyPrint(sourceId: string) {
export function togglePrettyPrint(cx: Context, sourceId: string) {
return async ({ dispatch, getState, client, sourceMaps }: ThunkArgs) => {
const source = getSource(getState(), sourceId);
if (!source) {
@ -118,7 +118,7 @@ export function togglePrettyPrint(sourceId: string) {
}
if (!isLoaded(source)) {
await dispatch(loadSourceText({ source }));
await dispatch(loadSourceText({ cx, source }));
}
assert(
@ -130,18 +130,18 @@ export function togglePrettyPrint(sourceId: string) {
const prettySource = getSourceByURL(getState(), url);
if (prettySource) {
return dispatch(selectPrettyLocation(prettySource));
return dispatch(selectPrettyLocation(cx, prettySource));
}
const newPrettySource = await dispatch(createPrettySource(sourceId));
await dispatch(selectPrettyLocation(newPrettySource));
const newPrettySource = await dispatch(createPrettySource(cx, sourceId));
await dispatch(selectPrettyLocation(cx, newPrettySource));
const threads = getSourceThreads(getState(), source);
await Promise.all(threads.map(thread => dispatch(mapFrames(thread))));
const threadcx = getThreadContext(getState());
await dispatch(mapFrames(threadcx));
await dispatch(setSymbols({ source: newPrettySource }));
await dispatch(setSymbols({ cx, source: newPrettySource }));
await dispatch(remapBreakpoints(sourceId));
await dispatch(remapBreakpoints(cx, sourceId));
return newPrettySource;
};

View File

@ -35,26 +35,39 @@ import {
getSelectedSource
} from "../../selectors";
import type { SourceLocation, PartialPosition, Source } from "../../types";
import type {
SourceLocation,
PartialPosition,
Source,
Context
} from "../../types";
import type { ThunkArgs } from "../types";
export const setSelectedLocation = (
cx: Context,
source: Source,
location: SourceLocation
) => ({
type: "SET_SELECTED_LOCATION",
cx,
source,
location
});
export const setPendingSelectedLocation = (url: string, options: Object) => ({
export const setPendingSelectedLocation = (
cx: Context,
url: string,
options: Object
) => ({
type: "SET_PENDING_SELECTED_LOCATION",
cx,
url: url,
line: options.location ? options.location.line : null
});
export const clearSelectedLocation = () => ({
type: "CLEAR_SELECTED_LOCATION"
export const clearSelectedLocation = (cx: Context) => ({
type: "CLEAR_SELECTED_LOCATION",
cx
});
/**
@ -69,18 +82,19 @@ export const clearSelectedLocation = () => ({
* @static
*/
export function selectSourceURL(
cx: Context,
url: string,
options: PartialPosition = { line: 1 }
) {
return async ({ dispatch, getState, sourceMaps }: ThunkArgs) => {
const source = getSourceByURL(getState(), url);
if (!source) {
return dispatch(setPendingSelectedLocation(url, options));
return dispatch(setPendingSelectedLocation(cx, url, options));
}
const sourceId = source.id;
const location = createLocation({ ...options, sourceId });
return dispatch(selectLocation(location));
return dispatch(selectLocation(cx, location));
};
}
@ -89,12 +103,13 @@ export function selectSourceURL(
* @static
*/
export function selectSource(
cx: Context,
sourceId: string,
options: PartialPosition = { line: 1 }
) {
return async ({ dispatch }: ThunkArgs) => {
const location = createLocation({ ...options, sourceId });
return dispatch(selectSpecificLocation(location));
return dispatch(selectSpecificLocation(cx, location));
};
}
@ -103,6 +118,7 @@ export function selectSource(
* @static
*/
export function selectLocation(
cx: Context,
location: SourceLocation,
{ keepContext = true }: Object = {}
) {
@ -118,7 +134,7 @@ export function selectLocation(
let source = getSource(getState(), location.sourceId);
if (!source) {
// If there is no source we deselect the current selected source
return dispatch(clearSelectedLocation());
return dispatch(clearSelectedLocation(cx));
}
const activeSearch = getActiveSearch(getState());
@ -143,9 +159,9 @@ export function selectLocation(
dispatch(addTab(source));
}
dispatch(setSelectedLocation(source, location));
dispatch(setSelectedLocation(cx, source, location));
await dispatch(loadSourceText({ source }));
await dispatch(loadSourceText({ cx, source }));
const loadedSource = getSource(getState(), source.id);
if (!loadedSource) {
@ -160,17 +176,17 @@ export function selectLocation(
shouldPrettyPrint(loadedSource) &&
isMinified(loadedSource)
) {
await dispatch(togglePrettyPrint(loadedSource.id));
dispatch(closeTab(loadedSource));
await dispatch(togglePrettyPrint(cx, loadedSource.id));
dispatch(closeTab(cx, loadedSource));
}
dispatch(setSymbols({ source: loadedSource }));
dispatch(setOutOfScopeLocations());
dispatch(setSymbols({ cx, source: loadedSource }));
dispatch(setOutOfScopeLocations(cx));
// If a new source is selected update the file search results
const newSource = getSelectedSource(getState());
if (currentSource && currentSource !== newSource) {
dispatch(updateActiveFileSearch());
dispatch(updateActiveFileSearch(cx));
}
};
}
@ -179,15 +195,15 @@ export function selectLocation(
* @memberof actions/sources
* @static
*/
export function selectSpecificLocation(location: SourceLocation) {
return selectLocation(location, { keepContext: false });
export function selectSpecificLocation(cx: Context, location: SourceLocation) {
return selectLocation(cx, location, { keepContext: false });
}
/**
* @memberof actions/sources
* @static
*/
export function jumpToMappedLocation(location: SourceLocation) {
export function jumpToMappedLocation(cx: Context, location: SourceLocation) {
return async function({ dispatch, getState, client, sourceMaps }: ThunkArgs) {
if (!client) {
return;
@ -195,17 +211,17 @@ export function jumpToMappedLocation(location: SourceLocation) {
const pairedLocation = await mapLocation(getState(), sourceMaps, location);
return dispatch(selectSpecificLocation({ ...pairedLocation }));
return dispatch(selectSpecificLocation(cx, { ...pairedLocation }));
};
}
export function jumpToMappedSelectedLocation() {
export function jumpToMappedSelectedLocation(cx: Context) {
return async function({ dispatch, getState }: ThunkArgs) {
const location = getSelectedLocation(getState());
if (!location) {
return;
}
await dispatch(jumpToMappedLocation(location));
await dispatch(jumpToMappedLocation(cx, location));
};
}

View File

@ -18,18 +18,19 @@ import {
type MemoizedAction
} from "../../utils/memoizableAction";
import type { Source } from "../../types";
import type { Source, Context } from "../../types";
import type { Symbols } from "../../reducers/types";
async function doSetSymbols(source, { dispatch, getState }) {
async function doSetSymbols(cx, source, { dispatch, getState }) {
const sourceId = source.id;
if (!isLoaded(source)) {
await dispatch(loadSourceText({ source }));
await dispatch(loadSourceText({ cx, source }));
}
await dispatch({
type: "SET_SYMBOLS",
cx,
sourceId,
[PROMISE]: parser.getSymbols(sourceId)
});
@ -42,7 +43,7 @@ async function doSetSymbols(source, { dispatch, getState }) {
return symbols;
}
type Args = { source: Source };
type Args = { cx: Context, source: Source };
export const setSymbols: MemoizedAction<Args, ?Symbols> = memoizeableAction(
"setSymbols",
@ -51,6 +52,6 @@ export const setSymbols: MemoizedAction<Args, ?Symbols> = memoizeableAction(
hasValue: ({ source }, { getState }) => hasSymbols(getState(), source),
getValue: ({ source }, { getState }) => getSymbols(getState(), source),
createKey: ({ source }) => source.id,
action: ({ source }, thunkArgs) => doSetSymbols(source, thunkArgs)
action: ({ cx, source }, thunkArgs) => doSetSymbols(cx, source, thunkArgs)
}
);

View File

@ -14,11 +14,11 @@ import {
describe("blackbox", () => {
it("should blackbox a source", async () => {
const store = createStore({ blackBox: async () => true });
const { dispatch, getState } = store;
const { dispatch, getState, cx } = store;
const foo1Source = makeSource("foo1");
await dispatch(actions.newSource(foo1Source));
await dispatch(actions.toggleBlackBox(foo1Source));
await dispatch(actions.toggleBlackBox(cx, foo1Source));
const fooSource = selectors.getSource(getState(), "foo1");

View File

@ -21,11 +21,11 @@ import { getBreakpointsList } from "../../../selectors";
describe("loadSourceText", () => {
it("should load source text", async () => {
const store = createStore(sourceThreadClient);
const { dispatch, getState } = store;
const { dispatch, getState, cx } = store;
const foo1Source = makeSource("foo1");
await dispatch(actions.newSource(foo1Source));
await dispatch(actions.loadSourceText({ source: foo1Source }));
await dispatch(actions.loadSourceText({ cx, source: foo1Source }));
const fooSource = selectors.getSource(getState(), "foo1");
if (!fooSource || typeof fooSource.text != "string") {
@ -35,7 +35,7 @@ describe("loadSourceText", () => {
const baseFoo2Source = makeSource("foo2");
await dispatch(actions.newSource(baseFoo2Source));
await dispatch(actions.loadSourceText({ source: baseFoo2Source }));
await dispatch(actions.loadSourceText({ cx, source: baseFoo2Source }));
const foo2Source = selectors.getSource(getState(), "foo2");
if (!foo2Source || typeof foo2Source.text != "string") {
@ -73,7 +73,7 @@ describe("loadSourceText", () => {
})
}
);
const { dispatch, getState } = store;
const { cx, dispatch, getState } = store;
await dispatch(actions.newSource(fooOrigSource));
await dispatch(actions.newSource(fooGenSource));
@ -83,20 +83,20 @@ describe("loadSourceText", () => {
line: 1,
column: 0
};
await dispatch(actions.addBreakpoint(location, {}));
await dispatch(actions.addBreakpoint(cx, location, {}));
const breakpoint = getBreakpointsList(getState())[0];
expect(breakpoint.text).toBe("");
expect(breakpoint.originalText).toBe("");
await dispatch(actions.loadSourceText({ source: fooOrigSource }));
await dispatch(actions.loadSourceText({ cx, source: fooOrigSource }));
const breakpoint1 = getBreakpointsList(getState())[0];
expect(breakpoint1.text).toBe("");
expect(breakpoint1.originalText).toBe("var fooOrig = 42;");
await dispatch(actions.loadSourceText({ source: fooGenSource }));
await dispatch(actions.loadSourceText({ cx, source: fooGenSource }));
const breakpoint2 = getBreakpointsList(getState())[0];
expect(breakpoint2.text).toBe("var fooGen = 42;");
@ -106,7 +106,7 @@ describe("loadSourceText", () => {
it("loads two sources w/ one request", async () => {
let resolve;
let count = 0;
const { dispatch, getState } = createStore({
const { dispatch, getState, cx } = createStore({
sourceContents: () =>
new Promise(r => {
count++;
@ -120,10 +120,10 @@ describe("loadSourceText", () => {
await dispatch(actions.newSource(baseSource));
let source = selectors.getSourceFromId(getState(), id);
dispatch(actions.loadSourceText({ source }));
dispatch(actions.loadSourceText({ cx, source }));
source = selectors.getSourceFromId(getState(), id);
const loading = dispatch(actions.loadSourceText({ source }));
const loading = dispatch(actions.loadSourceText({ cx, source }));
if (!resolve) {
throw new Error("no resolve");
@ -139,7 +139,7 @@ describe("loadSourceText", () => {
it("doesn't re-load loaded sources", async () => {
let resolve;
let count = 0;
const { dispatch, getState } = createStore({
const { dispatch, getState, cx } = createStore({
sourceContents: () =>
new Promise(r => {
count++;
@ -152,7 +152,7 @@ describe("loadSourceText", () => {
await dispatch(actions.newSource(baseSource));
let source = selectors.getSourceFromId(getState(), id);
const loading = dispatch(actions.loadSourceText({ source }));
const loading = dispatch(actions.loadSourceText({ cx, source }));
if (!resolve) {
throw new Error("no resolve");
@ -161,7 +161,7 @@ describe("loadSourceText", () => {
await loading;
source = selectors.getSourceFromId(getState(), id);
await dispatch(actions.loadSourceText({ source }));
await dispatch(actions.loadSourceText({ cx, source }));
expect(count).toEqual(1);
source = selectors.getSource(getState(), id);
@ -169,14 +169,14 @@ describe("loadSourceText", () => {
});
it("should cache subsequent source text loads", async () => {
const { dispatch, getState } = createStore(sourceThreadClient);
const { dispatch, getState, cx } = createStore(sourceThreadClient);
const source = makeSource("foo1");
dispatch(actions.newSource(source));
await dispatch(actions.loadSourceText({ source }));
await dispatch(actions.loadSourceText({ cx, source }));
const prevSource = selectors.getSourceFromId(getState(), "foo1");
await dispatch(actions.loadSourceText({ source: prevSource }));
await dispatch(actions.loadSourceText({ cx, source: prevSource }));
const curSource = selectors.getSource(getState(), "foo1");
expect(prevSource === curSource).toBeTruthy();
@ -184,7 +184,7 @@ describe("loadSourceText", () => {
it("should indicate a loading source", async () => {
const store = createStore(sourceThreadClient);
const { dispatch } = store;
const { dispatch, cx } = store;
const source = makeSource("foo2");
await dispatch(actions.newSource(source));
@ -194,17 +194,17 @@ describe("loadSourceText", () => {
return fooSource && fooSource.loadedState === "loading";
});
await dispatch(actions.loadSourceText({ source }));
await dispatch(actions.loadSourceText({ cx, source }));
expect(wasLoading()).toBe(true);
});
it("should indicate an errored source text", async () => {
const { dispatch, getState } = createStore(sourceThreadClient);
const { dispatch, getState, cx } = createStore(sourceThreadClient);
const source = makeSource("bad-id");
await dispatch(actions.newSource(source));
await dispatch(actions.loadSourceText({ source }));
await dispatch(actions.loadSourceText({ cx, source }));
const badSource = selectors.getSource(getState(), "bad-id");
if (!badSource || !badSource.error) {

View File

@ -45,9 +45,9 @@ describe("sources - new sources", () => {
});
it("should automatically select a pending source", async () => {
const { dispatch, getState } = createStore(threadClient);
const { dispatch, getState, cx } = createStore(threadClient);
const baseSource = makeSource("base.js");
await dispatch(actions.selectSourceURL(baseSource.url));
await dispatch(actions.selectSourceURL(cx, baseSource.url));
expect(getSelectedSource(getState())).toBe(undefined);
await dispatch(actions.newSource(baseSource));

View File

@ -14,13 +14,13 @@ import { createPrettySource } from "../prettyPrint";
import { sourceThreadClient } from "../../tests/helpers/threadClient.js";
describe("sources - pretty print", () => {
const { dispatch, getState } = createStore(sourceThreadClient);
const { dispatch, getState, cx } = createStore(sourceThreadClient);
it("returns a pretty source for a minified file", async () => {
const url = "base.js";
const source = makeSource(url);
await dispatch(actions.newSource(source));
await dispatch(createPrettySource(source.id));
await dispatch(createPrettySource(cx, source.id));
const prettyURL = `${source.url}:formatted`;
const pretty = selectors.getSourceByURL(getState(), prettyURL);
@ -31,15 +31,15 @@ describe("sources - pretty print", () => {
it("should create a source when first toggling pretty print", async () => {
const source = makeSource("foobar.js", { loadedState: "loaded" });
await dispatch(actions.togglePrettyPrint(source.id));
await dispatch(actions.togglePrettyPrint(cx, source.id));
expect(selectors.getSourceCount(getState())).toEqual(2);
});
it("should not make a second source when toggling pretty print", async () => {
const source = makeSource("foobar.js", { loadedState: "loaded" });
await dispatch(actions.togglePrettyPrint(source.id));
await dispatch(actions.togglePrettyPrint(cx, source.id));
expect(selectors.getSourceCount(getState())).toEqual(2);
await dispatch(actions.togglePrettyPrint(source.id));
await dispatch(actions.togglePrettyPrint(cx, source.id));
expect(selectors.getSourceCount(getState())).toEqual(2);
});
});

View File

@ -50,8 +50,9 @@ describe("sources", () => {
})
);
const cx = selectors.getThreadContext(getState());
await dispatch(
actions.selectLocation({ sourceId: "foo1", line: 1, column: 5 })
actions.selectLocation(cx, { sourceId: "foo1", line: 1, column: 5 })
);
const selectedSource = getSelectedSource(getState());
@ -72,7 +73,7 @@ describe("sources", () => {
});
it("should select next tab on tab closed if no previous tab", async () => {
const { dispatch, getState } = createStore(sourceThreadClient);
const { dispatch, getState, cx } = createStore(sourceThreadClient);
const fooSource = makeSource("foo.js");
@ -81,19 +82,19 @@ describe("sources", () => {
await dispatch(actions.newSource(makeSource("baz.js")));
// 3rd tab
await dispatch(actions.selectLocation(initialLocation("foo.js")));
await dispatch(actions.selectLocation(cx, initialLocation("foo.js")));
// 2nd tab
await dispatch(actions.selectLocation(initialLocation("bar.js")));
await dispatch(actions.selectLocation(cx, initialLocation("bar.js")));
// 1st tab
await dispatch(actions.selectLocation(initialLocation("baz.js")));
await dispatch(actions.selectLocation(cx, initialLocation("baz.js")));
// 3rd tab is reselected
await dispatch(actions.selectLocation(initialLocation("foo.js")));
await dispatch(actions.selectLocation(cx, initialLocation("foo.js")));
// closes the 1st tab, which should have no previous tab
await dispatch(actions.closeTab(fooSource));
await dispatch(actions.closeTab(cx, fooSource));
const selected = getSelectedSource(getState());
expect(selected && selected.id).toBe("bar.js");
@ -101,9 +102,9 @@ describe("sources", () => {
});
it("should open a tab for the source", async () => {
const { dispatch, getState } = createStore(sourceThreadClient);
const { dispatch, getState, cx } = createStore(sourceThreadClient);
await dispatch(actions.newSource(makeSource("foo.js")));
dispatch(actions.selectLocation(initialLocation("foo.js")));
dispatch(actions.selectLocation(cx, initialLocation("foo.js")));
const tabs = getSourceTabs(getState());
expect(tabs).toHaveLength(1);
@ -111,17 +112,17 @@ describe("sources", () => {
});
it("should select previous tab on tab closed", async () => {
const { dispatch, getState } = createStore(sourceThreadClient);
const { dispatch, getState, cx } = createStore(sourceThreadClient);
await dispatch(actions.newSource(makeSource("foo.js")));
await dispatch(actions.newSource(makeSource("bar.js")));
const bazSource = makeSource("baz.js");
await dispatch(actions.newSource(bazSource));
await dispatch(actions.selectLocation(initialLocation("foo.js")));
await dispatch(actions.selectLocation(initialLocation("bar.js")));
await dispatch(actions.selectLocation(initialLocation("baz.js")));
await dispatch(actions.closeTab(bazSource));
await dispatch(actions.selectLocation(cx, initialLocation("foo.js")));
await dispatch(actions.selectLocation(cx, initialLocation("bar.js")));
await dispatch(actions.selectLocation(cx, initialLocation("baz.js")));
await dispatch(actions.closeTab(cx, bazSource));
const selected = getSelectedSource(getState());
expect(selected && selected.id).toBe("bar.js");
@ -129,7 +130,7 @@ describe("sources", () => {
});
it("should keep the selected source when other tab closed", async () => {
const { dispatch, getState } = createStore(sourceThreadClient);
const { dispatch, getState, cx } = createStore(sourceThreadClient);
const bazSource = makeSource("baz.js");
@ -138,17 +139,17 @@ describe("sources", () => {
await dispatch(actions.newSource(bazSource));
// 3rd tab
await dispatch(actions.selectLocation(initialLocation("foo.js")));
await dispatch(actions.selectLocation(cx, initialLocation("foo.js")));
// 2nd tab
await dispatch(actions.selectLocation(initialLocation("bar.js")));
await dispatch(actions.selectLocation(cx, initialLocation("bar.js")));
// 1st tab
await dispatch(actions.selectLocation(initialLocation("baz.js")));
await dispatch(actions.selectLocation(cx, initialLocation("baz.js")));
// 3rd tab is reselected
await dispatch(actions.selectLocation(initialLocation("foo.js")));
await dispatch(actions.closeTab(bazSource));
await dispatch(actions.selectLocation(cx, initialLocation("foo.js")));
await dispatch(actions.closeTab(cx, bazSource));
const selected = getSelectedSource(getState());
expect(selected && selected.id).toBe("foo.js");
@ -168,29 +169,29 @@ describe("sources", () => {
});
it("sets and clears selected location correctly", () => {
const { dispatch, getState } = createStore(sourceThreadClient);
const { dispatch, getState, cx } = createStore(sourceThreadClient);
const source = makeSource("testSource");
const location = ({ test: "testLocation" }: any);
// set value
dispatch(actions.setSelectedLocation(source, location));
dispatch(actions.setSelectedLocation(cx, source, location));
expect(getSelectedLocation(getState())).toEqual({
sourceId: source.id,
...location
});
// clear value
dispatch(actions.clearSelectedLocation());
dispatch(actions.clearSelectedLocation(cx));
expect(getSelectedLocation(getState())).toEqual(null);
});
it("sets and clears pending selected location correctly", () => {
const { dispatch, getState } = createStore(sourceThreadClient);
const { dispatch, getState, cx } = createStore(sourceThreadClient);
const url = "testURL";
const options = { location: { line: "testLine" } };
// set value
dispatch(actions.setPendingSelectedLocation(url, options));
dispatch(actions.setPendingSelectedLocation(cx, url, options));
const setResult = getState().sources.pendingSelectedLocation;
expect(setResult).toEqual({
url,
@ -198,19 +199,19 @@ describe("sources", () => {
});
// clear value
dispatch(actions.clearSelectedLocation());
dispatch(actions.clearSelectedLocation(cx));
const clearResult = getState().sources.pendingSelectedLocation;
expect(clearResult).toEqual({ url: "" });
});
it("should keep the generated the viewing context", async () => {
const store = createStore(sourceThreadClient);
const { dispatch, getState } = store;
const { dispatch, getState, cx } = store;
const baseSource = makeSource("base.js");
await dispatch(actions.newSource(baseSource));
await dispatch(
actions.selectLocation({ sourceId: baseSource.id, line: 1 })
actions.selectLocation(cx, { sourceId: baseSource.id, line: 1 })
);
const selected = getSelectedSource(getState());
@ -219,7 +220,7 @@ describe("sources", () => {
});
it("should keep the original the viewing context", async () => {
const { dispatch, getState } = createStore(
const { dispatch, getState, cx } = createStore(
sourceThreadClient,
{},
{
@ -237,18 +238,20 @@ describe("sources", () => {
const originalBaseSource = makeOriginalSource("base.js");
await dispatch(actions.newSource(originalBaseSource));
await dispatch(actions.selectSource(originalBaseSource.id));
await dispatch(actions.selectSource(cx, originalBaseSource.id));
const fooSource = makeSource("foo.js");
await dispatch(actions.newSource(fooSource));
await dispatch(actions.selectLocation({ sourceId: fooSource.id, line: 1 }));
await dispatch(
actions.selectLocation(cx, { sourceId: fooSource.id, line: 1 })
);
const selected = getSelectedLocation(getState());
expect(selected && selected.line).toBe(12);
});
it("should change the original the viewing context", async () => {
const { dispatch, getState } = createStore(
const { dispatch, getState, cx } = createStore(
sourceThreadClient,
{},
{
@ -263,10 +266,10 @@ describe("sources", () => {
const baseSource = makeOriginalSource("base.js");
await dispatch(actions.newSource(baseSource));
await dispatch(actions.selectSource(baseSource.id));
await dispatch(actions.selectSource(cx, baseSource.id));
await dispatch(
actions.selectSpecificLocation({
actions.selectSpecificLocation(cx, {
sourceId: baseSource.id,
line: 1
})
@ -278,9 +281,9 @@ describe("sources", () => {
describe("selectSourceURL", () => {
it("should automatically select a pending source", async () => {
const { dispatch, getState } = createStore(sourceThreadClient);
const { dispatch, getState, cx } = createStore(sourceThreadClient);
const baseSource = makeSource("base.js");
await dispatch(actions.selectSourceURL(baseSource.url));
await dispatch(actions.selectSourceURL(cx, baseSource.url));
expect(getSelectedSource(getState())).toBe(undefined);
await dispatch(actions.newSource(baseSource));

View File

@ -23,7 +23,7 @@ import {
} from "../selectors";
import type { Action, ThunkArgs } from "./types";
import type { Source } from "../types";
import type { Source, Context } from "../types";
export function updateTab(source: Source, framework: string): Action {
const { url, id: sourceId } = source;
@ -62,7 +62,7 @@ export function moveTab(url: string, tabIndex: number): Action {
* @memberof actions/tabs
* @static
*/
export function closeTab(source: Source) {
export function closeTab(cx: Context, source: Source) {
return ({ dispatch, getState, client }: ThunkArgs) => {
const { id, url } = source;
@ -71,7 +71,7 @@ export function closeTab(source: Source) {
const tabs = removeSourceFromTabList(getSourceTabs(getState()), source);
const sourceId = getNewSelectedSourceId(getState(), tabs);
dispatch(({ type: "CLOSE_TAB", url, tabs }: Action));
dispatch(selectSource(sourceId));
dispatch(selectSource(cx, sourceId));
};
}
@ -79,7 +79,7 @@ export function closeTab(source: Source) {
* @memberof actions/tabs
* @static
*/
export function closeTabs(urls: string[]) {
export function closeTabs(cx: Context, urls: string[]) {
return ({ dispatch, getState, client }: ThunkArgs) => {
const sources = urls
.map(url => getSourceByURL(getState(), url))
@ -90,6 +90,6 @@ export function closeTabs(urls: string[]) {
dispatch(({ type: "CLOSE_TABS", sources, tabs }: Action));
const sourceId = getNewSelectedSourceId(getState(), tabs);
dispatch(selectSource(sourceId));
dispatch(selectSource(cx, sourceId));
};
}

View File

@ -66,13 +66,13 @@ describe("ast", () => {
describe("when the source is loaded", () => {
it("should be able to set symbols", async () => {
const store = createStore(threadClient);
const { dispatch, getState } = store;
const { dispatch, getState, cx } = store;
const base = makeSource("base.js");
await dispatch(actions.newSource(base));
await dispatch(actions.loadSourceText({ source: base }));
await dispatch(actions.loadSourceText({ cx, source: base }));
const loadedSource = selectors.getSourceFromId(getState(), base.id);
await dispatch(actions.setSymbols({ source: loadedSource }));
await dispatch(actions.setSymbols({ cx, source: loadedSource }));
await waitForState(store, state => !isSymbolsLoading(state, base));
const baseSymbols = getSymbols(getState(), base);
@ -102,27 +102,27 @@ describe("ast", () => {
describe("frameworks", () => {
it("should detect react components", async () => {
const store = createStore(threadClient, {}, sourceMaps);
const { dispatch, getState } = store;
const { cx, dispatch, getState } = store;
const source = makeOriginalSource("reactComponent.js");
await dispatch(actions.newSource(makeSource("reactComponent.js")));
await dispatch(actions.newSource(source));
await dispatch(actions.loadSourceText({ source }));
await dispatch(actions.loadSourceText({ cx, source }));
const loadedSource = selectors.getSourceFromId(getState(), source.id);
await dispatch(actions.setSymbols({ source: loadedSource }));
await dispatch(actions.setSymbols({ cx, source: loadedSource }));
expect(getFramework(getState(), source)).toBe("React");
});
it("should not give false positive on non react components", async () => {
const store = createStore(threadClient);
const { dispatch, getState } = store;
const { cx, dispatch, getState } = store;
const base = makeSource("base.js");
await dispatch(actions.newSource(base));
await dispatch(actions.loadSourceText({ source: base }));
await dispatch(actions.setSymbols({ source: base }));
await dispatch(actions.loadSourceText({ cx, source: base }));
await dispatch(actions.setSymbols({ cx, source: base }));
expect(getFramework(getState(), base)).toBe(undefined);
});
@ -136,14 +136,20 @@ describe("ast", () => {
it("with selected line", async () => {
const store = createStore(threadClient);
const { dispatch, getState } = store;
const { dispatch, getState, cx } = store;
const source = makeSource("scopes.js");
await dispatch(actions.newSource(source));
await dispatch(
actions.selectLocation({ sourceId: "scopes.js", line: 5 })
actions.selectLocation(cx, { sourceId: "scopes.js", line: 5 })
);
// Make sure the state has finished updating before pausing.
await waitForState(store, state => {
const symbols = getSymbols(state, source);
return symbols && !symbols.loading && getOutOfScopeLocations(state);
});
const frame = makeFrame({ id: "1", sourceId: "scopes.js" });
await dispatch(
actions.paused({
@ -154,7 +160,8 @@ describe("ast", () => {
})
);
await dispatch(actions.setOutOfScopeLocations());
const ncx = selectors.getThreadContext(getState());
await dispatch(actions.setOutOfScopeLocations(ncx));
await waitForState(store, state => getOutOfScopeLocations(state));
@ -166,10 +173,10 @@ describe("ast", () => {
});
it("without a selected line", async () => {
const { dispatch, getState } = createStore(threadClient);
const { dispatch, getState, cx } = createStore(threadClient);
const base = makeSource("base.js");
await dispatch(actions.newSource(base));
await dispatch(actions.selectSource("base.js"));
await dispatch(actions.selectSource(cx, "base.js"));
const locations = getOutOfScopeLocations(getState());
// const lines = getInScopeLines(getState());

View File

@ -51,52 +51,52 @@ const mockThreadClient = {
describe("expressions", () => {
it("should add an expression", async () => {
const { dispatch, getState } = createStore(mockThreadClient);
const { dispatch, getState, cx } = createStore(mockThreadClient);
await dispatch(actions.addExpression("foo"));
await dispatch(actions.addExpression(cx, "foo"));
expect(selectors.getExpressions(getState()).size).toBe(1);
});
it("should not add empty expressions", () => {
const { dispatch, getState } = createStore(mockThreadClient);
const { dispatch, getState, cx } = createStore(mockThreadClient);
dispatch(actions.addExpression((undefined: any)));
dispatch(actions.addExpression(""));
dispatch(actions.addExpression(cx, (undefined: any)));
dispatch(actions.addExpression(cx, ""));
expect(selectors.getExpressions(getState()).size).toBe(0);
});
it("should not add invalid expressions", async () => {
const { dispatch, getState } = createStore(mockThreadClient);
await dispatch(actions.addExpression("foo#"));
const { dispatch, getState, cx } = createStore(mockThreadClient);
await dispatch(actions.addExpression(cx, "foo#"));
const state = getState();
expect(selectors.getExpressions(state).size).toBe(0);
expect(selectors.getExpressionError(state)).toBe(true);
});
it("should update an expression", async () => {
const { dispatch, getState } = createStore(mockThreadClient);
const { dispatch, getState, cx } = createStore(mockThreadClient);
await dispatch(actions.addExpression("foo"));
await dispatch(actions.addExpression(cx, "foo"));
const expression = selectors.getExpression(getState(), "foo");
await dispatch(actions.updateExpression("bar", expression));
await dispatch(actions.updateExpression(cx, "bar", expression));
expect(selectors.getExpression(getState(), "bar").input).toBe("bar");
});
it("should not update an expression w/ invalid code", async () => {
const { dispatch, getState } = createStore(mockThreadClient);
const { dispatch, getState, cx } = createStore(mockThreadClient);
await dispatch(actions.addExpression("foo"));
await dispatch(actions.addExpression(cx, "foo"));
const expression = selectors.getExpression(getState(), "foo");
await dispatch(actions.updateExpression("#bar", expression));
await dispatch(actions.updateExpression(cx, "#bar", expression));
expect(selectors.getExpression(getState(), "bar")).toBeUndefined();
});
it("should delete an expression", async () => {
const { dispatch, getState } = createStore(mockThreadClient);
const { dispatch, getState, cx } = createStore(mockThreadClient);
await dispatch(actions.addExpression("foo"));
await dispatch(actions.addExpression("bar"));
await dispatch(actions.addExpression(cx, "foo"));
await dispatch(actions.addExpression(cx, "bar"));
expect(selectors.getExpressions(getState()).size).toBe(2);
const expression = selectors.getExpression(getState(), "foo");
@ -106,54 +106,57 @@ describe("expressions", () => {
});
it("should evaluate expressions global scope", async () => {
const { dispatch, getState } = createStore(mockThreadClient);
await dispatch(actions.addExpression("foo"));
await dispatch(actions.addExpression("bar"));
const { dispatch, getState, cx } = createStore(mockThreadClient);
await dispatch(actions.addExpression(cx, "foo"));
await dispatch(actions.addExpression(cx, "bar"));
expect(selectors.getExpression(getState(), "foo").value).toBe("bla");
expect(selectors.getExpression(getState(), "bar").value).toBe("bla");
await dispatch(actions.evaluateExpressions());
await dispatch(actions.evaluateExpressions(cx));
expect(selectors.getExpression(getState(), "foo").value).toBe("bla");
expect(selectors.getExpression(getState(), "bar").value).toBe("bla");
});
it("should evaluate expressions in specific scope", async () => {
const { dispatch, getState } = createStore(mockThreadClient);
await createFrames(dispatch);
await createFrames(getState, dispatch);
const cx = selectors.getThreadContext(getState());
await dispatch(actions.newSource(makeSource("source")));
await dispatch(actions.addExpression("foo"));
await dispatch(actions.addExpression("bar"));
await dispatch(actions.addExpression(cx, "foo"));
await dispatch(actions.addExpression(cx, "bar"));
expect(selectors.getExpression(getState(), "foo").value).toBe("boo");
expect(selectors.getExpression(getState(), "bar").value).toBe("boo");
await dispatch(actions.evaluateExpressions());
await dispatch(actions.evaluateExpressions(cx));
expect(selectors.getExpression(getState(), "foo").value).toBe("boo");
expect(selectors.getExpression(getState(), "bar").value).toBe("boo");
});
it("should get the autocomplete matches for the input", async () => {
const { dispatch, getState } = createStore(mockThreadClient);
await dispatch(actions.autocomplete("to", 2));
const { cx, dispatch, getState } = createStore(mockThreadClient);
await dispatch(actions.autocomplete(cx, "to", 2));
expect(selectors.getAutocompleteMatchset(getState())).toMatchSnapshot();
});
});
async function createFrames(dispatch) {
async function createFrames(getState, dispatch) {
const frame = makeMockFrame();
await dispatch(actions.newSource(makeSource("example.js")));
await dispatch(actions.newSource(makeSource("source")));
await dispatch(
actions.paused({
thread: "UnknownThread",
thread: "FakeThread",
frame,
frames: [frame],
why: { type: "just because" }
})
);
await dispatch(actions.selectFrame(frame));
await dispatch(
actions.selectFrame(selectors.getThreadContext(getState()), frame)
);
}

View File

@ -14,7 +14,7 @@ const {
describe("file text search", () => {
it("should update search results", () => {
const { dispatch, getState } = createStore();
const { dispatch, getState, cx } = createStore();
expect(getFileSearchResults(getState())).toEqual({
matches: [],
matchIndex: -1,
@ -23,7 +23,7 @@ describe("file text search", () => {
});
const matches = [{ line: 1, ch: 3 }, { line: 3, ch: 2 }];
dispatch(actions.updateSearchResults(2, 3, matches));
dispatch(actions.updateSearchResults(cx, 2, 3, matches));
expect(getFileSearchResults(getState())).toEqual({
count: 2,
@ -34,29 +34,29 @@ describe("file text search", () => {
});
it("should update the file search query", () => {
const { dispatch, getState } = createStore();
const { dispatch, getState, cx } = createStore();
let fileSearchQueryState = getFileSearchQuery(getState());
expect(fileSearchQueryState).toBe("");
dispatch(actions.setFileSearchQuery("foobar"));
dispatch(actions.setFileSearchQuery(cx, "foobar"));
fileSearchQueryState = getFileSearchQuery(getState());
expect(fileSearchQueryState).toBe("foobar");
});
it("should toggle a file search modifier", () => {
const { dispatch, getState } = createStore();
const { dispatch, getState, cx } = createStore();
let fileSearchModState = getFileSearchModifiers(getState());
expect(fileSearchModState.get("caseSensitive")).toBe(false);
dispatch(actions.toggleFileSearchModifier("caseSensitive"));
dispatch(actions.toggleFileSearchModifier(cx, "caseSensitive"));
fileSearchModState = getFileSearchModifiers(getState());
expect(fileSearchModState.get("caseSensitive")).toBe(true);
});
it("should toggle a file search query cleaning", () => {
const { dispatch, getState } = createStore();
dispatch(actions.setFileSearchQuery("foobar"));
const { dispatch, getState, cx } = createStore();
dispatch(actions.setFileSearchQuery(cx, "foobar"));
let fileSearchQueryState = getFileSearchQuery(getState());
expect(fileSearchQueryState).toBe("foobar");
dispatch(actions.setFileSearchQuery(""));
dispatch(actions.setFileSearchQuery(cx, ""));
fileSearchQueryState = getFileSearchQuery(getState());
expect(fileSearchQueryState).toBe("");
});

View File

@ -48,11 +48,11 @@ describe("navigation", () => {
});
it("navigation closes project-search", async () => {
const { dispatch, getState } = createStore(threadClient);
const { dispatch, getState, cx } = createStore(threadClient);
const mockQuery = "foo";
await dispatch(actions.newSource(makeSource("foo1")));
await dispatch(actions.searchSources(mockQuery));
await dispatch(actions.searchSources(cx, mockQuery));
let results = getTextSearchResults(getState());
expect(results).toHaveLength(1);
@ -77,9 +77,9 @@ describe("navigation", () => {
});
it("navigation clears the file-search query", async () => {
const { dispatch, getState } = createStore(threadClient);
const { dispatch, getState, cx } = createStore(threadClient);
dispatch(actions.setFileSearchQuery("foobar"));
dispatch(actions.setFileSearchQuery(cx, "foobar"));
expect(getFileSearchQuery(getState())).toBe("foobar");
await dispatch(actions.willNavigate("will-navigate"));
@ -88,10 +88,10 @@ describe("navigation", () => {
});
it("navigation clears the file-search results", async () => {
const { dispatch, getState } = createStore(threadClient);
const { dispatch, getState, cx } = createStore(threadClient);
const searchResults = [{ line: 1, ch: 3 }, { line: 3, ch: 2 }];
dispatch(actions.updateSearchResults(2, 3, searchResults));
dispatch(actions.updateSearchResults(cx, 2, 3, searchResults));
expect(getFileSearchResults(getState())).toEqual({
count: 2,
index: 2,

View File

@ -69,7 +69,7 @@ function mockSourceMaps() {
describe("when adding breakpoints", () => {
it("a corresponding pending breakpoint should be added", async () => {
const { dispatch, getState } = createStore(
const { dispatch, getState, cx } = createStore(
mockClient({ "5": [1] }),
loadInitialState(),
mockSourceMaps()
@ -78,12 +78,12 @@ describe("when adding breakpoints", () => {
const source = makeSource("foo.js");
await dispatch(actions.newSource(source));
await dispatch(actions.newSource(makeSource("foo.js")));
await dispatch(actions.loadSourceText({ source }));
await dispatch(actions.loadSourceText({ cx, source }));
const bp = generateBreakpoint("foo.js", 5, 1);
const id = makePendingLocationId(bp.location);
await dispatch(actions.addBreakpoint(bp.location));
await dispatch(actions.addBreakpoint(cx, bp.location));
const pendingBps = selectors.getPendingBreakpoints(getState());
expect(selectors.getPendingBreakpointList(getState())).toHaveLength(2);
@ -104,7 +104,7 @@ describe("when adding breakpoints", () => {
});
it("add a corresponding pendingBreakpoint for each addition", async () => {
const { dispatch, getState } = createStore(
const { dispatch, getState, cx } = createStore(
mockClient({ "5": [0] }),
loadInitialState(),
mockSourceMaps()
@ -119,11 +119,11 @@ describe("when adding breakpoints", () => {
await dispatch(actions.newSource(source1));
await dispatch(actions.newSource(source2));
await dispatch(actions.loadSourceText({ source: source1 }));
await dispatch(actions.loadSourceText({ source: source2 }));
await dispatch(actions.loadSourceText({ cx, source: source1 }));
await dispatch(actions.loadSourceText({ cx, source: source2 }));
await dispatch(actions.addBreakpoint(breakpoint1.location));
await dispatch(actions.addBreakpoint(breakpoint2.location));
await dispatch(actions.addBreakpoint(cx, breakpoint1.location));
await dispatch(actions.addBreakpoint(cx, breakpoint2.location));
const pendingBps = selectors.getPendingBreakpoints(getState());
@ -135,7 +135,7 @@ describe("when adding breakpoints", () => {
});
it("hidden breakponts do not create pending bps", async () => {
const { dispatch, getState } = createStore(
const { dispatch, getState, cx } = createStore(
mockClient({ "5": [0] }),
loadInitialState(),
mockSourceMaps()
@ -144,10 +144,10 @@ describe("when adding breakpoints", () => {
const source = makeSource("foo");
await dispatch(actions.newSource(makeSource("foo")));
await dispatch(actions.newSource(source));
await dispatch(actions.loadSourceText({ source }));
await dispatch(actions.loadSourceText({ cx, source }));
await dispatch(
actions.addBreakpoint(breakpoint1.location, { hidden: true })
actions.addBreakpoint(cx, breakpoint1.location, { hidden: true })
);
const pendingBps = selectors.getPendingBreakpoints(getState());
@ -155,7 +155,7 @@ describe("when adding breakpoints", () => {
});
it("remove a corresponding pending breakpoint when deleting", async () => {
const { dispatch, getState } = createStore(
const { dispatch, getState, cx } = createStore(
mockClient({ "5": [0] }),
loadInitialState(),
mockSourceMaps()
@ -170,12 +170,12 @@ describe("when adding breakpoints", () => {
await dispatch(actions.newSource(source1));
await dispatch(actions.newSource(source2));
await dispatch(actions.loadSourceText({ source: source1 }));
await dispatch(actions.loadSourceText({ source: source2 }));
await dispatch(actions.loadSourceText({ cx, source: source1 }));
await dispatch(actions.loadSourceText({ cx, source: source2 }));
await dispatch(actions.addBreakpoint(breakpoint1.location));
await dispatch(actions.addBreakpoint(breakpoint2.location));
await dispatch(actions.removeBreakpoint(breakpoint1));
await dispatch(actions.addBreakpoint(cx, breakpoint1.location));
await dispatch(actions.addBreakpoint(cx, breakpoint2.location));
await dispatch(actions.removeBreakpoint(cx, breakpoint1));
const pendingBps = selectors.getPendingBreakpoints(getState());
expect(pendingBps.hasOwnProperty(breakpointLocationId1)).toBe(false);
@ -186,7 +186,7 @@ describe("when adding breakpoints", () => {
describe("when changing an existing breakpoint", () => {
it("updates corresponding pendingBreakpoint", async () => {
const { dispatch, getState } = createStore(
const { dispatch, getState, cx } = createStore(
mockClient({ "5": [0] }),
loadInitialState(),
mockSourceMaps()
@ -197,11 +197,11 @@ describe("when changing an existing breakpoint", () => {
const source = makeSource("foo");
await dispatch(actions.newSource(source));
await dispatch(actions.newSource(makeSource("foo")));
await dispatch(actions.loadSourceText({ source }));
await dispatch(actions.loadSourceText({ cx, source }));
await dispatch(actions.addBreakpoint(bp.location));
await dispatch(actions.addBreakpoint(cx, bp.location));
await dispatch(
actions.setBreakpointOptions(bp.location, { condition: "2" })
actions.setBreakpointOptions(cx, bp.location, { condition: "2" })
);
const bps = selectors.getPendingBreakpoints(getState());
const breakpoint = bps[id];
@ -209,7 +209,7 @@ describe("when changing an existing breakpoint", () => {
});
it("if disabled, updates corresponding pendingBreakpoint", async () => {
const { dispatch, getState } = createStore(
const { dispatch, getState, cx } = createStore(
mockClient({ "5": [0] }),
loadInitialState(),
mockSourceMaps()
@ -221,17 +221,17 @@ describe("when changing an existing breakpoint", () => {
const source = makeSource("foo");
await dispatch(actions.newSource(source));
await dispatch(actions.loadSourceText({ source }));
await dispatch(actions.loadSourceText({ cx, source }));
await dispatch(actions.addBreakpoint(bp.location));
await dispatch(actions.disableBreakpoint(bp));
await dispatch(actions.addBreakpoint(cx, bp.location));
await dispatch(actions.disableBreakpoint(cx, bp));
const bps = selectors.getPendingBreakpoints(getState());
const breakpoint = bps[id];
expect(breakpoint.disabled).toBe(true);
});
it("does not delete the pre-existing pendingBreakpoint", async () => {
const { dispatch, getState } = createStore(
const { dispatch, getState, cx } = createStore(
mockClient({ "5": [0] }),
loadInitialState(),
mockSourceMaps()
@ -241,13 +241,13 @@ describe("when changing an existing breakpoint", () => {
const source = makeSource("foo.js");
await dispatch(actions.newSource(source));
await dispatch(actions.newSource(makeSource("foo.js")));
await dispatch(actions.loadSourceText({ source }));
await dispatch(actions.loadSourceText({ cx, source }));
const id = makePendingLocationId(bp.location);
await dispatch(actions.addBreakpoint(bp.location));
await dispatch(actions.addBreakpoint(cx, bp.location));
await dispatch(
actions.setBreakpointOptions(bp.location, { condition: "2" })
actions.setBreakpointOptions(cx, bp.location, { condition: "2" })
);
const bps = selectors.getPendingBreakpoints(getState());
const breakpoint = bps[id];
@ -267,7 +267,7 @@ describe("initializing when pending breakpoints exist in prefs", () => {
});
it("re-adding breakpoints update existing pending breakpoints", async () => {
const { dispatch, getState } = createStore(
const { dispatch, getState, cx } = createStore(
mockClient({ "5": [1, 2] }),
loadInitialState(),
mockSourceMaps()
@ -278,15 +278,15 @@ describe("initializing when pending breakpoints exist in prefs", () => {
const source = makeSource("bar.js");
await dispatch(actions.newSource(source));
await dispatch(actions.loadSourceText({ source }));
await dispatch(actions.addBreakpoint(bar.location));
await dispatch(actions.loadSourceText({ cx, source }));
await dispatch(actions.addBreakpoint(cx, bar.location));
const bps = selectors.getPendingBreakpointList(getState());
expect(bps).toHaveLength(2);
});
it("adding bps doesn't remove existing pending breakpoints", async () => {
const { dispatch, getState } = createStore(
const { dispatch, getState, cx } = createStore(
mockClient({ "5": [0] }),
loadInitialState(),
mockSourceMaps()
@ -296,9 +296,9 @@ describe("initializing when pending breakpoints exist in prefs", () => {
const source = makeSource("foo.js");
await dispatch(actions.newSource(source));
await dispatch(actions.newSource(makeSource("foo.js")));
await dispatch(actions.loadSourceText({ source }));
await dispatch(actions.loadSourceText({ cx, source }));
await dispatch(actions.addBreakpoint(bp.location));
await dispatch(actions.addBreakpoint(cx, bp.location));
const bps = selectors.getPendingBreakpointList(getState());
expect(bps).toHaveLength(2);
@ -313,12 +313,12 @@ describe("initializing with disabled pending breakpoints in prefs", () => {
mockSourceMaps()
);
const { getState, dispatch } = store;
const { getState, dispatch, cx } = store;
const source = makeSource("bar.js");
await dispatch(actions.newSource(makeSource("bar.js")));
await dispatch(actions.newSource(source));
await dispatch(actions.loadSourceText({ source }));
await dispatch(actions.loadSourceText({ cx, source }));
await waitForState(store, state => {
const bps = selectors.getBreakpointsForSource(state, source.id);
@ -346,7 +346,7 @@ describe("adding sources", () => {
loadInitialState({ disabled: true }),
mockSourceMaps()
);
const { getState, dispatch } = store;
const { getState, dispatch, cx } = store;
expect(selectors.getBreakpointCount(getState())).toEqual(0);
@ -354,7 +354,7 @@ describe("adding sources", () => {
await dispatch(actions.newSource(makeSource("bar.js")));
await dispatch(actions.newSource(source));
await dispatch(actions.loadSourceText({ source }));
await dispatch(actions.loadSourceText({ cx, source }));
await waitForState(store, state => selectors.getBreakpointCount(state) > 0);
@ -396,7 +396,7 @@ describe("adding sources", () => {
loadInitialState({ disabled: true }),
mockSourceMaps()
);
const { getState, dispatch } = store;
const { getState, dispatch, cx } = store;
expect(selectors.getBreakpointCount(getState())).toEqual(0);
@ -405,8 +405,8 @@ describe("adding sources", () => {
await dispatch(actions.newSource(makeSource("bar.js")));
await dispatch(actions.newSource(makeSource("foo.js")));
await dispatch(actions.newSources([source1, source2]));
await dispatch(actions.loadSourceText({ source: source1 }));
await dispatch(actions.loadSourceText({ source: source2 }));
await dispatch(actions.loadSourceText({ cx, source: source1 }));
await dispatch(actions.loadSourceText({ cx, source: source2 }));
await waitForState(store, state => selectors.getBreakpointCount(state) > 0);
expect(selectors.getBreakpointCount(getState())).toEqual(1);

View File

@ -44,16 +44,16 @@ const threadClient = {
describe("project text search", () => {
it("should add a project text search query", () => {
const { dispatch, getState } = createStore();
const { dispatch, getState, cx } = createStore();
const mockQuery = "foo";
dispatch(actions.addSearchQuery(mockQuery));
dispatch(actions.addSearchQuery(cx, mockQuery));
expect(getTextSearchQuery(getState())).toEqual(mockQuery);
});
it("should search all the loaded sources based on the query", async () => {
const { dispatch, getState } = createStore(threadClient);
const { dispatch, getState, cx } = createStore(threadClient);
const mockQuery = "foo";
const source1 = makeSource("foo1");
const source2 = makeSource("foo2");
@ -61,7 +61,7 @@ describe("project text search", () => {
await dispatch(actions.newSource(source1));
await dispatch(actions.newSource(source2));
await dispatch(actions.searchSources(mockQuery));
await dispatch(actions.searchSources(cx, mockQuery));
const results = getTextSearchResults(getState());
expect(results).toMatchSnapshot();
@ -87,26 +87,26 @@ describe("project text search", () => {
getOriginalLocations: async items => items
};
const { dispatch, getState } = createStore(threadClient, {}, mockMaps);
const { dispatch, getState, cx } = createStore(threadClient, {}, mockMaps);
const mockQuery = "bla";
await dispatch(actions.newSource(source1));
await dispatch(actions.newSource(source2));
await dispatch(actions.searchSources(mockQuery));
await dispatch(actions.searchSources(cx, mockQuery));
const results = getTextSearchResults(getState());
expect(results).toMatchSnapshot();
});
it("should search a specific source", async () => {
const { dispatch, getState } = createStore(threadClient);
const { dispatch, getState, cx } = createStore(threadClient);
const source = makeSource("bar");
await dispatch(actions.newSource(source));
await dispatch(actions.loadSourceText({ source }));
await dispatch(actions.loadSourceText({ cx, source }));
dispatch(actions.addSearchQuery("bla"));
dispatch(actions.addSearchQuery(cx, "bla"));
const barSource = getSource(getState(), "bar");
if (!barSource) {
@ -114,7 +114,7 @@ describe("project text search", () => {
}
const sourceId = barSource.id;
await dispatch(actions.searchSource(sourceId, "bla"), "bla");
await dispatch(actions.searchSource(cx, sourceId, "bla"), "bla");
const results = getTextSearchResults(getState());
@ -123,36 +123,36 @@ describe("project text search", () => {
});
it("should clear all the search results", async () => {
const { dispatch, getState } = createStore(threadClient);
const { dispatch, getState, cx } = createStore(threadClient);
const mockQuery = "foo";
await dispatch(actions.newSource(makeSource("foo1")));
await dispatch(actions.searchSources(mockQuery));
await dispatch(actions.searchSources(cx, mockQuery));
expect(getTextSearchResults(getState())).toMatchSnapshot();
await dispatch(actions.clearSearchResults());
await dispatch(actions.clearSearchResults(cx));
expect(getTextSearchResults(getState())).toMatchSnapshot();
});
it("should set the status properly", () => {
const { dispatch, getState } = createStore();
const { dispatch, getState, cx } = createStore();
const mockStatus = "Fetching";
dispatch(actions.updateSearchStatus(mockStatus));
dispatch(actions.updateSearchStatus(cx, mockStatus));
expect(getTextSearchStatus(getState())).toEqual(mockStatus);
});
it("should close project search", async () => {
const { dispatch, getState } = createStore(threadClient);
const { dispatch, getState, cx } = createStore(threadClient);
const mockQuery = "foo";
await dispatch(actions.newSource(makeSource("foo1")));
await dispatch(actions.searchSources(mockQuery));
await dispatch(actions.searchSources(cx, mockQuery));
expect(getTextSearchResults(getState())).toMatchSnapshot();
dispatch(actions.closeProjectSearch());
dispatch(actions.closeProjectSearch(cx));
expect(getTextSearchQuery(getState())).toEqual("");

View File

@ -17,39 +17,39 @@ const { getProjectDirectoryRoot, getDisplayedSources } = selectors;
describe("setProjectDirectoryRoot", () => {
it("should set domain directory as root", async () => {
const { dispatch, getState } = createStore();
dispatch(actions.setProjectDirectoryRoot("example.com"));
const { dispatch, getState, cx } = createStore();
dispatch(actions.setProjectDirectoryRoot(cx, "example.com"));
expect(getProjectDirectoryRoot(getState())).toBe("example.com");
});
it("should set a directory as root directory", async () => {
const { dispatch, getState } = createStore();
dispatch(actions.setProjectDirectoryRoot("/example.com/foo"));
const { dispatch, getState, cx } = createStore();
dispatch(actions.setProjectDirectoryRoot(cx, "/example.com/foo"));
expect(getProjectDirectoryRoot(getState())).toBe("/example.com/foo");
});
it("should add to the directory ", () => {
const { dispatch, getState } = createStore();
dispatch(actions.setProjectDirectoryRoot("/example.com/foo"));
dispatch(actions.setProjectDirectoryRoot("/foo/bar"));
const { dispatch, getState, cx } = createStore();
dispatch(actions.setProjectDirectoryRoot(cx, "/example.com/foo"));
dispatch(actions.setProjectDirectoryRoot(cx, "/foo/bar"));
expect(getProjectDirectoryRoot(getState())).toBe("/example.com/foo/bar");
});
it("should update the directory ", () => {
const { dispatch, getState } = createStore();
dispatch(actions.setProjectDirectoryRoot("/example.com/foo"));
dispatch(actions.clearProjectDirectoryRoot());
dispatch(actions.setProjectDirectoryRoot("/example.com/bar"));
const { dispatch, getState, cx } = createStore();
dispatch(actions.setProjectDirectoryRoot(cx, "/example.com/foo"));
dispatch(actions.clearProjectDirectoryRoot(cx));
dispatch(actions.setProjectDirectoryRoot(cx, "/example.com/bar"));
expect(getProjectDirectoryRoot(getState())).toBe("/example.com/bar");
});
it("should filter sources", async () => {
const store = createStore({});
const { dispatch, getState } = store;
const { dispatch, getState, cx } = store;
await dispatch(actions.newSource(makeSource("js/scopes.js")));
await dispatch(actions.newSource(makeSource("lib/vendor.js")));
dispatch(actions.setProjectDirectoryRoot("localhost:8000/examples/js"));
dispatch(actions.setProjectDirectoryRoot(cx, "localhost:8000/examples/js"));
const filteredSourcesByThread = getDisplayedSources(getState());
const filteredSources = Object.values(filteredSourcesByThread)[0];
@ -63,16 +63,16 @@ describe("setProjectDirectoryRoot", () => {
});
it("should update the child directory ", () => {
const { dispatch, getState } = createStore();
dispatch(actions.setProjectDirectoryRoot("example.com"));
dispatch(actions.setProjectDirectoryRoot("example.com/foo/bar"));
const { dispatch, getState, cx } = createStore();
dispatch(actions.setProjectDirectoryRoot(cx, "example.com"));
dispatch(actions.setProjectDirectoryRoot(cx, "example.com/foo/bar"));
expect(getProjectDirectoryRoot(getState())).toBe("example.com/foo/bar");
});
it("should update the child directory when domain name is Webpack://", () => {
const { dispatch, getState } = createStore();
dispatch(actions.setProjectDirectoryRoot("webpack://"));
dispatch(actions.setProjectDirectoryRoot("webpack:///app"));
const { dispatch, getState, cx } = createStore();
dispatch(actions.setProjectDirectoryRoot(cx, "webpack://"));
dispatch(actions.setProjectDirectoryRoot(cx, "webpack:///app"));
expect(getProjectDirectoryRoot(getState())).toBe("webpack:///app");
});
});

View File

@ -16,26 +16,26 @@ import { sourceThreadClient as threadClient } from "./helpers/threadClient.js";
describe("closing tabs", () => {
it("closing a tab", async () => {
const { dispatch, getState } = createStore(threadClient);
const { dispatch, getState, cx } = createStore(threadClient);
const fooSource = makeSource("foo.js");
await dispatch(actions.newSource(fooSource));
await dispatch(actions.selectLocation({ sourceId: "foo.js", line: 1 }));
dispatch(actions.closeTab(fooSource));
await dispatch(actions.selectLocation(cx, { sourceId: "foo.js", line: 1 }));
dispatch(actions.closeTab(cx, fooSource));
expect(getSelectedSource(getState())).toBe(undefined);
expect(getSourceTabs(getState())).toHaveLength(0);
});
it("closing the inactive tab", async () => {
const { dispatch, getState } = createStore(threadClient);
const { dispatch, getState, cx } = createStore(threadClient);
const fooSource = makeSource("foo.js");
await dispatch(actions.newSource(fooSource));
await dispatch(actions.newSource(makeSource("bar.js")));
await dispatch(actions.selectLocation({ sourceId: "foo.js", line: 1 }));
await dispatch(actions.selectLocation({ sourceId: "bar.js", line: 1 }));
dispatch(actions.closeTab(fooSource));
await dispatch(actions.selectLocation(cx, { sourceId: "foo.js", line: 1 }));
await dispatch(actions.selectLocation(cx, { sourceId: "bar.js", line: 1 }));
dispatch(actions.closeTab(cx, fooSource));
const selected = getSelectedSource(getState());
expect(selected && selected.id).toBe("bar.js");
@ -43,26 +43,26 @@ describe("closing tabs", () => {
});
it("closing the only tab", async () => {
const { dispatch, getState } = createStore(threadClient);
const { dispatch, getState, cx } = createStore(threadClient);
const fooSource = makeSource("foo.js");
await dispatch(actions.newSource(fooSource));
await dispatch(actions.selectLocation({ sourceId: "foo.js", line: 1 }));
dispatch(actions.closeTab(fooSource));
await dispatch(actions.selectLocation(cx, { sourceId: "foo.js", line: 1 }));
dispatch(actions.closeTab(cx, fooSource));
expect(getSelectedSource(getState())).toBe(undefined);
expect(getSourceTabs(getState())).toHaveLength(0);
});
it("closing the active tab", async () => {
const { dispatch, getState } = createStore(threadClient);
const { dispatch, getState, cx } = createStore(threadClient);
const barSource = makeSource("bar.js");
await dispatch(actions.newSource(makeSource("foo.js")));
await dispatch(actions.newSource(barSource));
await dispatch(actions.selectLocation({ sourceId: "foo.js", line: 1 }));
await dispatch(actions.selectLocation({ sourceId: "bar.js", line: 1 }));
await dispatch(actions.closeTab(barSource));
await dispatch(actions.selectLocation(cx, { sourceId: "foo.js", line: 1 }));
await dispatch(actions.selectLocation(cx, { sourceId: "bar.js", line: 1 }));
await dispatch(actions.closeTab(cx, barSource));
const selected = getSelectedSource(getState());
expect(selected && selected.id).toBe("foo.js");
@ -70,22 +70,24 @@ describe("closing tabs", () => {
});
it("closing many inactive tabs", async () => {
const { dispatch, getState } = createStore(threadClient);
const { dispatch, getState, cx } = createStore(threadClient);
const fooSource = makeSource("foo.js");
const barSource = makeSource("bar.js");
await dispatch(actions.newSource(fooSource));
await dispatch(actions.newSource(barSource));
await dispatch(actions.newSource(makeSource("bazz.js")));
await dispatch(actions.selectLocation({ sourceId: "foo.js", line: 1 }));
await dispatch(actions.selectLocation({ sourceId: "bar.js", line: 1 }));
await dispatch(actions.selectLocation({ sourceId: "bazz.js", line: 1 }));
await dispatch(actions.selectLocation(cx, { sourceId: "foo.js", line: 1 }));
await dispatch(actions.selectLocation(cx, { sourceId: "bar.js", line: 1 }));
await dispatch(
actions.selectLocation(cx, { sourceId: "bazz.js", line: 1 })
);
const tabs = [
"http://localhost:8000/examples/foo.js",
"http://localhost:8000/examples/bar.js"
];
dispatch(actions.closeTabs(tabs));
dispatch(actions.closeTabs(cx, tabs));
const selected = getSelectedSource(getState());
expect(selected && selected.id).toBe("bazz.js");
@ -93,19 +95,21 @@ describe("closing tabs", () => {
});
it("closing many tabs including the active tab", async () => {
const { dispatch, getState } = createStore(threadClient);
const { dispatch, getState, cx } = createStore(threadClient);
await dispatch(actions.newSource(makeSource("foo.js")));
await dispatch(actions.newSource(makeSource("bar.js")));
await dispatch(actions.newSource(makeSource("bazz.js")));
await dispatch(actions.selectLocation({ sourceId: "foo.js", line: 1 }));
await dispatch(actions.selectLocation({ sourceId: "bar.js", line: 1 }));
await dispatch(actions.selectLocation({ sourceId: "bazz.js", line: 1 }));
await dispatch(actions.selectLocation(cx, { sourceId: "foo.js", line: 1 }));
await dispatch(actions.selectLocation(cx, { sourceId: "bar.js", line: 1 }));
await dispatch(
actions.selectLocation(cx, { sourceId: "bazz.js", line: 1 })
);
const tabs = [
"http://localhost:8000/examples/bar.js",
"http://localhost:8000/examples/bazz.js"
];
await dispatch(actions.closeTabs(tabs));
await dispatch(actions.closeTabs(cx, tabs));
const selected = getSelectedSource(getState());
expect(selected && selected.id).toBe("foo.js");
@ -113,14 +117,14 @@ describe("closing tabs", () => {
});
it("closing all the tabs", async () => {
const { dispatch, getState } = createStore(threadClient);
const { dispatch, getState, cx } = createStore(threadClient);
await dispatch(actions.newSource(makeSource("foo.js")));
await dispatch(actions.newSource(makeSource("bar.js")));
await dispatch(actions.selectLocation({ sourceId: "foo.js", line: 1 }));
await dispatch(actions.selectLocation({ sourceId: "bar.js", line: 1 }));
await dispatch(actions.selectLocation(cx, { sourceId: "foo.js", line: 1 }));
await dispatch(actions.selectLocation(cx, { sourceId: "bar.js", line: 1 }));
await dispatch(
actions.closeTabs([
actions.closeTabs(cx, [
"http://localhost:8000/examples/foo.js",
"http://localhost:8000/examples/bar.js"
])

View File

@ -85,39 +85,39 @@ describe("ui", () => {
describe("setProjectDirectoryRoot", () => {
it("should set domain directory as root", () => {
const { dispatch, getState } = createStore();
dispatch(actions.setProjectDirectoryRoot("example.com"));
const { dispatch, getState, cx } = createStore();
dispatch(actions.setProjectDirectoryRoot(cx, "example.com"));
expect(getProjectDirectoryRoot(getState())).toBe("example.com");
});
it("should set a directory as root directory", () => {
const { dispatch, getState } = createStore();
dispatch(actions.setProjectDirectoryRoot("/example.com/foo"));
const { dispatch, getState, cx } = createStore();
dispatch(actions.setProjectDirectoryRoot(cx, "/example.com/foo"));
expect(getProjectDirectoryRoot(getState())).toBe("/example.com/foo");
});
it("should add to the directory ", () => {
const { dispatch, getState } = createStore();
dispatch(actions.setProjectDirectoryRoot("/example.com/foo"));
dispatch(actions.setProjectDirectoryRoot("/foo/bar"));
const { dispatch, getState, cx } = createStore();
dispatch(actions.setProjectDirectoryRoot(cx, "/example.com/foo"));
dispatch(actions.setProjectDirectoryRoot(cx, "/foo/bar"));
expect(getProjectDirectoryRoot(getState())).toBe("/example.com/foo/bar");
});
it("should update the directory ", () => {
const { dispatch, getState } = createStore();
dispatch(actions.setProjectDirectoryRoot("/example.com/foo"));
dispatch(actions.clearProjectDirectoryRoot());
dispatch(actions.setProjectDirectoryRoot("/example.com/bar"));
const { dispatch, getState, cx } = createStore();
dispatch(actions.setProjectDirectoryRoot(cx, "/example.com/foo"));
dispatch(actions.clearProjectDirectoryRoot(cx));
dispatch(actions.setProjectDirectoryRoot(cx, "/example.com/bar"));
expect(getProjectDirectoryRoot(getState())).toBe("/example.com/bar");
});
it("should filter sources", async () => {
const store = createStore({});
const { dispatch, getState } = store;
const { dispatch, getState, cx } = store;
await dispatch(actions.newSource(makeSource("js/scopes.js")));
await dispatch(actions.newSource(makeSource("lib/vendor.js")));
dispatch(actions.setProjectDirectoryRoot("localhost:8000/examples/js"));
dispatch(actions.setProjectDirectoryRoot(cx, "localhost:8000/examples/js"));
const filteredSourcesByThread = getDisplayedSources(getState());
const filteredSources = Object.values(filteredSourcesByThread)[0];
@ -131,16 +131,16 @@ describe("setProjectDirectoryRoot", () => {
});
it("should update the child directory ", () => {
const { dispatch, getState } = createStore();
dispatch(actions.setProjectDirectoryRoot("example.com"));
dispatch(actions.setProjectDirectoryRoot("example.com/foo/bar"));
const { dispatch, getState, cx } = createStore();
dispatch(actions.setProjectDirectoryRoot(cx, "example.com"));
dispatch(actions.setProjectDirectoryRoot(cx, "example.com/foo/bar"));
expect(getProjectDirectoryRoot(getState())).toBe("example.com/foo/bar");
});
it("should update the child directory when domain name is Webpack://", () => {
const { dispatch, getState } = createStore();
dispatch(actions.setProjectDirectoryRoot("webpack://"));
dispatch(actions.setProjectDirectoryRoot("webpack:///app"));
const { dispatch, getState, cx } = createStore();
dispatch(actions.setProjectDirectoryRoot(cx, "webpack://"));
dispatch(actions.setProjectDirectoryRoot(cx, "webpack:///app"));
expect(getProjectDirectoryRoot(getState())).toBe("webpack:///app");
});
});

View File

@ -6,26 +6,31 @@
import type { SymbolDeclarations, AstLocation } from "../../workers/parser";
import type { PromiseAction } from "../utils/middleware/promise";
import type { Context } from "../../types";
export type ASTAction =
| PromiseAction<
{|
+type: "SET_SYMBOLS",
+cx: Context,
+sourceId: string
|},
SymbolDeclarations
>
| {|
+type: "OUT_OF_SCOPE_LOCATIONS",
+cx: Context,
+locations: ?(AstLocation[])
|}
| {|
+type: "IN_SCOPE_LINES",
+cx: Context,
+lines: number[]
|}
| PromiseAction<
{|
+type: "SET_PREVIEW"
+type: "SET_PREVIEW",
+cx: Context
|},
{
expression: string,
@ -36,5 +41,6 @@ export type ASTAction =
}
>
| {|
+type: "CLEAR_SELECTION"
+type: "CLEAR_SELECTION",
+cx: Context
|};

View File

@ -10,7 +10,8 @@ import type {
XHRBreakpoint,
Source,
BreakpointPositions,
PendingLocation
PendingLocation,
Context
} from "../../types";
import type { PromiseAction } from "../utils/middleware/promise";
@ -42,18 +43,22 @@ export type BreakpointAction =
|}>
| {|
+type: "SET_BREAKPOINT",
+cx: Context,
+breakpoint: Breakpoint
|}
| {|
+type: "REMOVE_BREAKPOINT",
+cx: Context,
+location: SourceLocation
|}
| {|
+type: "REMOVE_PENDING_BREAKPOINT",
+cx: Context,
+location: PendingLocation
|}
| {|
type: "ADD_BREAKPOINT_POSITIONS",
+cx: Context,
positions: BreakpointPositions,
source: Source
|};

View File

@ -5,23 +5,33 @@
// @flow
import type { Command } from "../../reducers/types";
import type { Expression, LoadedObject, Frame, Scope, Why } from "../../types";
import type {
Expression,
LoadedObject,
Frame,
Scope,
Why,
ThreadContext
} from "../../types";
import type { PromiseAction } from "../utils/middleware/promise";
export type PauseAction =
| {|
+type: "BREAK_ON_NEXT",
+cx: ThreadContext,
+thread: string,
+value: boolean
|}
| {|
// Note: Do not include cx, as this action is triggered by the server.
+type: "RESUME",
+thread: string,
+value: void,
+wasStepping: boolean
|}
| {|
// Note: Do not include cx, as this action is triggered by the server.
+type: "PAUSED",
+thread: string,
+why: Why,
@ -37,11 +47,13 @@ export type PauseAction =
|}
| PromiseAction<{|
+type: "COMMAND",
+cx: ThreadContext,
+thread: string,
+command: Command
|}>
| {|
+type: "SELECT_FRAME",
+cx: ThreadContext,
+thread: string,
+frame: Frame
|}
@ -52,12 +64,14 @@ export type PauseAction =
|}
| {|
+type: "SET_POPUP_OBJECT_PROPERTIES",
+cx: ThreadContext,
+thread: string,
+objectId: string,
+properties: Object
|}
| {|
+type: "ADD_EXPRESSION",
+cx: ThreadContext,
+thread: string,
+id: number,
+input: string,
@ -67,6 +81,7 @@ export type PauseAction =
| PromiseAction<
{|
+type: "EVALUATE_EXPRESSION",
+cx: ThreadContext,
+thread: string,
+input: string
|},
@ -74,11 +89,13 @@ export type PauseAction =
>
| PromiseAction<{|
+type: "EVALUATE_EXPRESSIONS",
+cx: ThreadContext,
+results: Expression[],
+inputs: string[]
|}>
| {|
+type: "UPDATE_EXPRESSION",
+cx: ThreadContext,
+expression: Expression,
+input: string,
+expressionError: ?string
@ -95,12 +112,14 @@ export type PauseAction =
|}
| {|
+type: "AUTOCOMPLETE",
+cx: ThreadContext,
+input: string,
+result: Object
|}
| PromiseAction<
{|
+type: "MAP_SCOPES",
+cx: ThreadContext,
+thread: string,
+frame: Frame
|},
@ -113,6 +132,7 @@ export type PauseAction =
>
| {|
+type: "MAP_FRAMES",
+cx: ThreadContext,
+thread: string,
+frames: Frame[],
+selectedFrameId: string
@ -120,6 +140,7 @@ export type PauseAction =
| PromiseAction<
{|
+type: "ADD_SCOPES",
+cx: ThreadContext,
+thread: string,
+frame: Frame
|},

View File

@ -4,12 +4,13 @@
// @flow
import type { Source, SourceLocation } from "../../types";
import type { Source, SourceLocation, Context } from "../../types";
import type { PromiseAction } from "../utils/middleware/promise";
export type LoadSourceAction = PromiseAction<
{|
+type: "LOAD_SOURCE_TEXT",
+cx: Context,
+sourceId: string,
+epoch: number
|},
@ -19,31 +20,37 @@ export type SourceAction =
| LoadSourceAction
| {|
+type: "ADD_SOURCE",
+cx: Context,
+source: Source
|}
| {|
+type: "ADD_SOURCES",
+cx: Context,
+sources: Array<Source>
|}
| {|
+type: "UPDATE_SOURCE",
+cx: Context,
+source: Source
|}
| {|
+type: "SET_SELECTED_LOCATION",
+cx: Context,
+source: Source,
+location?: SourceLocation
|}
| {|
+type: "SET_PENDING_SELECTED_LOCATION",
+cx: Context,
+url: string,
+line?: number,
+column?: number
|}
| {| type: "CLEAR_SELECTED_LOCATION" |}
| {| type: "CLEAR_SELECTED_LOCATION", +cx: Context |}
| PromiseAction<
{|
+type: "BLACKBOX",
+cx: Context,
+source: Source
|},
{|

View File

@ -4,7 +4,12 @@
// @flow
import type { Source, PartialRange, SourceLocation } from "../../types";
import type {
Source,
PartialRange,
SourceLocation,
Context
} from "../../types";
import type {
ActiveSearchType,
@ -64,6 +69,7 @@ export type UIAction =
|}
| {|
+type: "SET_PROJECT_DIRECTORY_ROOT",
+cx: Context,
+url: string
|}
| {|

View File

@ -4,7 +4,7 @@
// @flow
import type { WorkerList, MainThread } from "../../types";
import type { WorkerList, MainThread, Context } from "../../types";
import type { State } from "../../reducers/types";
import type { MatchedLocations } from "../../reducers/file-search";
import type { TreeNode } from "../../utils/sources-tree/types";
@ -75,18 +75,23 @@ export type FocusItem = {
export type SourceTreeAction =
| {| +type: "SET_EXPANDED_STATE", +thread: string, +expanded: any |}
| {| +type: "SET_FOCUSED_SOURCE_ITEM", item: FocusItem |};
| {| +type: "SET_FOCUSED_SOURCE_ITEM", +cx: Context, item: FocusItem |};
export type ProjectTextSearchAction =
| {| +type: "ADD_QUERY", +query: string |}
| {| +type: "ADD_QUERY", +cx: Context, +query: string |}
| {|
+type: "ADD_SEARCH_RESULT",
+cx: Context,
+result: ProjectTextSearchResult
|}
| {| +type: "UPDATE_STATUS", +status: string |}
| {| +type: "CLEAR_SEARCH_RESULTS" |}
| {| +type: "ADD_ONGOING_SEARCH", +ongoingSearch: SearchOperation |}
| {| +type: "CLEAR_SEARCH" |};
| {| +type: "UPDATE_STATUS", +cx: Context, +status: string |}
| {| +type: "CLEAR_SEARCH_RESULTS", +cx: Context |}
| {|
+type: "ADD_ONGOING_SEARCH",
+cx: Context,
+ongoingSearch: SearchOperation
|}
| {| +type: "CLEAR_SEARCH", +cx: Context |};
export type FileTextSearchModifier =
| "caseSensitive"
@ -96,14 +101,17 @@ export type FileTextSearchModifier =
export type FileTextSearchAction =
| {|
+type: "TOGGLE_FILE_SEARCH_MODIFIER",
+cx: Context,
+modifier: FileTextSearchModifier
|}
| {|
+type: "UPDATE_FILE_SEARCH_QUERY",
+cx: Context,
+query: string
|}
| {|
+type: "UPDATE_SEARCH_RESULTS",
+cx: Context,
+results: {
matches: MatchedLocations[],
matchIndex: number,
@ -117,14 +125,16 @@ export type QuickOpenAction =
| {| +type: "OPEN_QUICK_OPEN", +query?: string |}
| {| +type: "CLOSE_QUICK_OPEN" |};
export type DebugeeAction =
export type DebuggeeAction =
| {|
+type: "SET_WORKERS",
+cx: Context,
+workers: WorkerList,
+mainThread: string
|}
| {|
+type: "SELECT_THREAD",
+cx: Context,
+thread: string
|};
@ -156,5 +166,5 @@ export type Action =
| QuickOpenAction
| FileTextSearchAction
| ProjectTextSearchAction
| DebugeeAction
| DebuggeeAction
| SourceTreeAction;

View File

@ -17,7 +17,7 @@ import type { ThunkArgs, panelPositionType } from "./types";
import { getEditor, getLocationsInViewport } from "../utils/editor";
import { searchContents } from "./file-search";
import type { SourceLocation } from "../types";
import type { SourceLocation, Context } from "../types";
import type {
ActiveSearchType,
OrientationType,
@ -53,13 +53,13 @@ export function setActiveSearch(activeSearch?: ActiveSearchType) {
};
}
export function updateActiveFileSearch() {
export function updateActiveFileSearch(cx: Context) {
return ({ dispatch, getState }: ThunkArgs) => {
const isFileSearchOpen = getActiveSearch(getState()) === "file";
const fileSearchQuery = getFileSearchQuery(getState());
if (isFileSearchOpen && fileSearchQuery) {
const editor = getEditor();
dispatch(searchContents(fileSearchQuery, editor));
dispatch(searchContents(cx, fileSearchQuery, editor));
}
};
}
@ -73,7 +73,7 @@ export function toggleFrameworkGrouping(toggleValue: boolean) {
};
}
export function showSource(sourceId: string) {
export function showSource(cx: Context, sourceId: string) {
return ({ dispatch, getState }: ThunkArgs) => {
const source = getSource(getState(), sourceId);
if (!source) {
@ -91,7 +91,7 @@ export function showSource(sourceId: string) {
dispatch(setPrimaryPaneTab("sources"));
dispatch({ type: "SHOW_SOURCE", source: null });
dispatch(selectSource(source.id));
dispatch(selectSource(cx, source.id));
dispatch({ type: "SHOW_SOURCE", source });
};
}
@ -171,14 +171,15 @@ export function closeConditionalPanel() {
};
}
export function clearProjectDirectoryRoot() {
export function clearProjectDirectoryRoot(cx: Context) {
return {
type: "SET_PROJECT_DIRECTORY_ROOT",
cx,
url: ""
};
}
export function setProjectDirectoryRoot(newRoot: string) {
export function setProjectDirectoryRoot(cx: Context, newRoot: string) {
return ({ dispatch, getState }: ThunkArgs) => {
const curRoot = getProjectDirectoryRoot(getState());
if (newRoot && curRoot) {
@ -195,6 +196,7 @@ export function setProjectDirectoryRoot(newRoot: string) {
dispatch({
type: "SET_PROJECT_DIRECTORY_ROOT",
cx,
url: newRoot
});
};

View File

@ -18,6 +18,7 @@ import { history } from "./middleware/history";
import { promise } from "./middleware/promise";
import { thunk } from "./middleware/thunk";
import { timing } from "./middleware/timing";
import { context } from "./middleware/context";
/**
* @memberof utils/create-store
@ -47,6 +48,7 @@ type ReduxStoreOptions = {
const configureStore = (opts: ReduxStoreOptions = {}) => {
const middleware = [
thunk(opts.makeThunkArgs),
context,
promise,
// Order is important: services must go last as they always

View File

@ -0,0 +1,37 @@
/* 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/>. */
// @flow
import {
validateNavigateContext,
validateContext
} from "../../../utils/context";
import type { ThunkArgs } from "../../types";
function validateActionContext(getState, action) {
if (action.type == "COMMAND" && action.status == "done") {
// The thread will have resumed execution since the action was initiated,
// so just make sure we haven't navigated.
validateNavigateContext(getState(), action.cx);
return;
}
// Validate using all available information in the context.
validateContext(getState(), action.cx);
}
// Middleware which looks for actions that have a cx property and ignores
// them if the context is no longer valid.
function context({ dispatch, getState }: ThunkArgs) {
return (next: Function) => (action: Object) => {
if ("cx" in action) {
validateActionContext(getState, action);
}
return next(action);
};
}
export { context };

View File

@ -8,6 +8,7 @@ DIRS += [
]
CompiledModules(
'context.js',
'history.js',
'log.js',
'promise.js',

View File

@ -15,13 +15,18 @@ import { breakpointItems } from "./menus/breakpoints";
import type { BreakpointItemActions } from "./menus/breakpoints";
import type { EditorItemActions } from "./menus/editor";
import type { Source, Breakpoint as BreakpointType } from "../../types";
import type {
Source,
Breakpoint as BreakpointType,
ThreadContext
} from "../../types";
const breakpointSvg = document.createElement("div");
breakpointSvg.innerHTML =
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 60 15" width="60" height="15"><path d="M53.07.5H1.5c-.54 0-1 .46-1 1v12c0 .54.46 1 1 1h51.57c.58 0 1.15-.26 1.53-.7l4.7-6.3-4.7-6.3c-.38-.44-.95-.7-1.53-.7z"/></svg>';
type Props = {
cx: ThreadContext,
breakpoint: BreakpointType,
selectedSource: Source,
editor: Object,
@ -61,6 +66,7 @@ class Breakpoint extends PureComponent<Props> {
onClick = (event: MouseEvent) => {
const {
cx,
breakpointActions,
editorActions,
breakpoint,
@ -77,31 +83,33 @@ class Breakpoint extends PureComponent<Props> {
const selectedLocation = getSelectedLocation(breakpoint, selectedSource);
if (event.metaKey) {
return editorActions.continueToHere(selectedLocation.line);
return editorActions.continueToHere(cx, selectedLocation.line);
}
if (event.shiftKey) {
if (features.columnBreakpoints) {
return breakpointActions.toggleBreakpointsAtLine(
cx,
!breakpoint.disabled,
selectedLocation.line
);
}
return breakpointActions.toggleDisabledBreakpoint(breakpoint);
return breakpointActions.toggleDisabledBreakpoint(cx, breakpoint);
}
return breakpointActions.removeBreakpointsAtLine(
cx,
selectedLocation.sourceId,
selectedLocation.line
);
};
onContextMenu = (event: MouseEvent) => {
const { breakpoint, breakpointActions } = this.props;
const { cx, breakpoint, breakpointActions } = this.props;
event.stopPropagation();
event.preventDefault();
showMenu(event, breakpointItems(breakpoint, breakpointActions));
showMenu(event, breakpointItems(cx, breakpoint, breakpointActions));
};
addBreakpoint(props: Props) {

View File

@ -14,9 +14,14 @@ import { editorItemActions } from "./menus/editor";
import type { BreakpointItemActions } from "./menus/breakpoints";
import type { EditorItemActions } from "./menus/editor";
import type { Breakpoint as BreakpointType, Source } from "../../types";
import type {
Breakpoint as BreakpointType,
Source,
ThreadContext
} from "../../types";
type Props = {
cx: ThreadContext,
selectedSource: Source,
breakpoints: BreakpointType[],
editor: Object,
@ -27,6 +32,7 @@ type Props = {
class Breakpoints extends Component<Props> {
render() {
const {
cx,
breakpoints,
selectedSource,
editor,
@ -43,6 +49,7 @@ class Breakpoints extends Component<Props> {
{breakpoints.map(bp => {
return (
<Breakpoint
cx={cx}
key={makeBreakpointId(bp.location)}
breakpoint={bp}
selectedSource={selectedSource}

View File

@ -13,13 +13,14 @@ import { breakpointItems, createBreakpointItems } from "./menus/breakpoints";
// eslint-disable-next-line max-len
import type { ColumnBreakpoint as ColumnBreakpointType } from "../../selectors/visibleColumnBreakpoints";
import type { BreakpointItemActions } from "./menus/breakpoints";
import type { Source } from "../../types";
import type { Source, Context } from "../../types";
type Bookmark = {
clear: Function
};
type Props = {
cx: Context,
editor: Object,
source: Source,
columnBreakpoint: ColumnBreakpointType,
@ -88,11 +89,11 @@ export default class ColumnBreakpoint extends PureComponent<Props> {
onClick = (event: MouseEvent) => {
event.stopPropagation();
event.preventDefault();
const { columnBreakpoint, breakpointActions } = this.props;
const { cx, columnBreakpoint, breakpointActions } = this.props;
if (columnBreakpoint.breakpoint) {
breakpointActions.removeBreakpoint(columnBreakpoint.breakpoint);
breakpointActions.removeBreakpoint(cx, columnBreakpoint.breakpoint);
} else {
breakpointActions.addBreakpoint(columnBreakpoint.location);
breakpointActions.addBreakpoint(cx, columnBreakpoint.location);
}
};
@ -100,13 +101,14 @@ export default class ColumnBreakpoint extends PureComponent<Props> {
event.stopPropagation();
event.preventDefault();
const {
cx,
columnBreakpoint: { breakpoint, location },
breakpointActions
} = this.props;
const items = breakpoint
? breakpointItems(breakpoint, breakpointActions)
: createBreakpointItems(location, breakpointActions);
? breakpointItems(cx, breakpoint, breakpointActions)
: createBreakpointItems(cx, location, breakpointActions);
showMenu(event, items);
};

View File

@ -8,17 +8,22 @@ import React, { Component } from "react";
import ColumnBreakpoint from "./ColumnBreakpoint";
import { getSelectedSource, visibleColumnBreakpoints } from "../../selectors";
import {
getSelectedSource,
visibleColumnBreakpoints,
getContext
} from "../../selectors";
import { connect } from "../../utils/connect";
import { makeBreakpointId } from "../../utils/breakpoint";
import { breakpointItemActions } from "./menus/breakpoints";
import type { BreakpointItemActions } from "./menus/breakpoints";
import type { Source } from "../../types";
import type { Source, Context } from "../../types";
// eslint-disable-next-line max-len
import type { ColumnBreakpoint as ColumnBreakpointType } from "../../selectors/visibleColumnBreakpoints";
type Props = {
cx: Context,
editor: Object,
selectedSource: Source,
columnBreakpoints: ColumnBreakpointType[],
@ -30,6 +35,7 @@ class ColumnBreakpoints extends Component<Props> {
render() {
const {
cx,
editor,
columnBreakpoints,
selectedSource,
@ -44,6 +50,7 @@ class ColumnBreakpoints extends Component<Props> {
editor.codeMirror.operation(() => {
breakpoints = columnBreakpoints.map(breakpoint => (
<ColumnBreakpoint
cx={cx}
key={makeBreakpointId(breakpoint.location)}
columnBreakpoint={breakpoint}
editor={editor}
@ -58,6 +65,7 @@ class ColumnBreakpoints extends Component<Props> {
const mapStateToProps = state => {
return {
cx: getContext(state),
selectedSource: getSelectedSource(state),
columnBreakpoints: visibleColumnBreakpoints(state)
};

View File

@ -14,14 +14,16 @@ import actions from "../../actions";
import {
getBreakpointForLocation,
getConditionalPanelLocation,
getLogPointStatus
getLogPointStatus,
getContext
} from "../../selectors";
import type { SourceLocation } from "../../types";
import type { SourceLocation, Context } from "../../types";
type Props = {
cx: Context,
breakpoint: ?Object,
setBreakpointOptions: Function,
setBreakpointOptions: typeof actions.setBreakpointOptions,
location: SourceLocation,
log: boolean,
editor: Object,
@ -63,10 +65,10 @@ export class ConditionalPanel extends PureComponent<Props> {
};
setBreakpoint(value: string) {
const { location, log, breakpoint } = this.props;
const { cx, location, log, breakpoint } = this.props;
const options = breakpoint ? breakpoint.options : {};
const type = log ? "logValue" : "condition";
return this.props.setBreakpointOptions(location, {
return this.props.setBreakpointOptions(cx, location, {
...options,
[type]: value
});
@ -199,6 +201,7 @@ const mapStateToProps = state => {
const location = getConditionalPanelLocation(state);
const log = getLogPointStatus(state);
return {
cx: getContext(state),
breakpoint: getBreakpointForLocation(state, location),
location,
log

View File

@ -12,16 +12,18 @@ import { getSourceLocationFromMouseEvent } from "../../utils/editor";
import {
getPrettySource,
getIsPaused,
getCurrentThread
getCurrentThread,
getThreadContext
} from "../../selectors";
import { editorMenuItems, editorItemActions } from "./menus/editor";
import type { Source } from "../../types";
import type { Source, ThreadContext } from "../../types";
import type { EditorItemActions } from "./menus/editor";
import type SourceEditor from "../../utils/editor/source-editor";
type Props = {
cx: ThreadContext,
contextMenu: ?MouseEvent,
editorActions: EditorItemActions,
clearContextMenu: () => void,
@ -43,6 +45,7 @@ class EditorMenu extends Component<Props> {
showMenu(props) {
const {
cx,
editor,
selectedSource,
editorActions,
@ -61,6 +64,7 @@ class EditorMenu extends Component<Props> {
showMenu(
event,
editorMenuItems({
cx,
editorActions,
selectedSource,
hasPrettySource,
@ -78,6 +82,7 @@ class EditorMenu extends Component<Props> {
}
const mapStateToProps = (state, props) => ({
cx: getThreadContext(state),
isPaused: getIsPaused(state, getCurrentThread(state)),
hasPrettySource: !!getPrettySource(state, props.selectedSource.id)
});

View File

@ -10,7 +10,8 @@ import actions from "../../actions";
import {
getSelectedSource,
getPrettySource,
getPaneCollapse
getPaneCollapse,
getContext
} from "../../selectors";
import {
@ -27,7 +28,7 @@ import { shouldShowPrettyPrint } from "../../utils/editor";
import { PaneToggleButton } from "../shared/Button";
import AccessibleImage from "../shared/AccessibleImage";
import type { Source } from "../../types";
import type { Source, Context } from "../../types";
import "./Footer.css";
@ -37,6 +38,7 @@ type CursorPosition = {
};
type Props = {
cx: Context,
selectedSource: Source,
mappedSource: Source,
endPanelCollapsed: boolean,
@ -83,7 +85,7 @@ class SourceFooter extends PureComponent<Props, State> {
}
prettyPrintButton() {
const { selectedSource, togglePrettyPrint } = this.props;
const { cx, selectedSource, togglePrettyPrint } = this.props;
if (!selectedSource) {
return;
@ -107,7 +109,7 @@ class SourceFooter extends PureComponent<Props, State> {
const type = "prettyPrint";
return (
<button
onClick={() => togglePrettyPrint(selectedSource.id)}
onClick={() => togglePrettyPrint(cx, selectedSource.id)}
className={classnames("action", type, {
active: sourceLoaded,
pretty: isPretty(selectedSource)
@ -122,7 +124,7 @@ class SourceFooter extends PureComponent<Props, State> {
}
blackBoxButton() {
const { selectedSource, toggleBlackBox } = this.props;
const { cx, selectedSource, toggleBlackBox } = this.props;
const sourceLoaded = selectedSource && isLoaded(selectedSource);
if (!selectedSource) {
@ -143,7 +145,7 @@ class SourceFooter extends PureComponent<Props, State> {
return (
<button
onClick={() => toggleBlackBox(selectedSource)}
onClick={() => toggleBlackBox(cx, selectedSource)}
className={classnames("action", type, {
active: sourceLoaded,
blackboxed: blackboxed
@ -182,7 +184,12 @@ class SourceFooter extends PureComponent<Props, State> {
}
renderSourceSummary() {
const { mappedSource, jumpToMappedLocation, selectedSource } = this.props;
const {
cx,
mappedSource,
jumpToMappedLocation,
selectedSource
} = this.props;
if (!mappedSource || !isOriginal(selectedSource)) {
return null;
@ -202,7 +209,7 @@ class SourceFooter extends PureComponent<Props, State> {
return (
<button
className="mapped-source"
onClick={() => jumpToMappedLocation(mappedSourceLocation)}
onClick={() => jumpToMappedLocation(cx, mappedSourceLocation)}
title={tooltip}
>
<span>{title}</span>
@ -255,6 +262,7 @@ const mapStateToProps = state => {
const selectedSource = getSelectedSource(state);
return {
cx: getContext(state),
selectedSource,
mappedSource: getGeneratedSource(state, selectedSource),
prettySource: getPrettySource(

View File

@ -24,7 +24,8 @@ const {
import actions from "../../../actions";
import {
getAllPopupObjectProperties,
getCurrentThread
getCurrentThread,
getThreadContext
} from "../../../selectors";
import Popover from "../../shared/Popover";
import PreviewFunction from "../../shared/PreviewFunction";
@ -36,9 +37,11 @@ import "./Popup.css";
import type { EditorRange } from "../../../utils/editor/types";
import type { Coords } from "../../shared/Popover";
import type { ThreadContext } from "../../../types";
type PopupValue = Object | null;
type Props = {
cx: ThreadContext,
popupObjectProperties: Object,
popoverPos: Object,
value: PopupValue,
@ -92,6 +95,7 @@ export class Popup extends Component<Props, State> {
async componentWillMount() {
const {
cx,
value,
setPopupObjectProperties,
popupObjectProperties
@ -108,7 +112,7 @@ export class Popup extends Component<Props, State> {
const onLoadItemProperties = loadItemProperties(root, createObjectClient);
if (onLoadItemProperties !== null) {
const properties = await onLoadItemProperties;
setPopupObjectProperties(root.contents.value, properties);
setPopupObjectProperties(cx, root.contents.value, properties);
}
}
}
@ -181,7 +185,7 @@ export class Popup extends Component<Props, State> {
};
renderFunctionPreview() {
const { selectSourceURL, value } = this.props;
const { cx, selectSourceURL, value } = this.props;
if (!value) {
return null;
@ -191,7 +195,9 @@ export class Popup extends Component<Props, State> {
return (
<div
className="preview-popup"
onClick={() => selectSourceURL(location.url, { line: location.line })}
onClick={() =>
selectSourceURL(cx, location.url, { line: location.line })
}
>
<PreviewFunction func={value} />
</div>
@ -330,6 +336,7 @@ export class Popup extends Component<Props, State> {
}
const mapStateToProps = state => ({
cx: getThreadContext(state),
popupObjectProperties: getAllPopupObjectProperties(
state,
getCurrentThread(state)

View File

@ -12,22 +12,21 @@ import Popup from "./Popup";
import {
getPreview,
getSelectedSource,
getIsPaused,
getCurrentThread
getThreadContext
} from "../../../selectors";
import actions from "../../../actions";
import { toEditorRange } from "../../../utils/editor";
import type { Source } from "../../../types";
import type { Source, ThreadContext } from "../../../types";
import type { Preview as PreviewType } from "../../../reducers/ast";
type Props = {
cx: ThreadContext,
editor: any,
editorRef: ?HTMLDivElement,
selectedSource: Source,
preview: PreviewType,
isPaused: boolean,
clearPreview: typeof actions.clearPreview,
setPopupObjectProperties: typeof actions.setPopupObjectProperties,
addExpression: typeof actions.addExpression,
@ -113,40 +112,41 @@ class Preview extends PureComponent<Props, State> {
}
onTokenEnter = ({ target, tokenPos }) => {
if (this.props.isPaused) {
this.props.updatePreview(target, tokenPos, this.props.editor.codeMirror);
const { cx, updatePreview, editor } = this.props;
if (cx.isPaused) {
updatePreview(cx, target, tokenPos, editor.codeMirror);
}
};
onTokenLeave = e => {
if (this.props.isPaused && !inPopup(e)) {
this.props.clearPreview();
if (this.props.cx.isPaused && !inPopup(e)) {
this.props.clearPreview(this.props.cx);
}
};
onMouseUp = () => {
if (this.props.isPaused) {
if (this.props.cx.isPaused) {
this.setState({ selecting: false });
return true;
}
};
onMouseDown = () => {
if (this.props.isPaused) {
if (this.props.cx.isPaused) {
this.setState({ selecting: true });
return true;
}
};
onScroll = () => {
if (this.props.isPaused) {
this.props.clearPreview();
if (this.props.cx.isPaused) {
this.props.clearPreview(this.props.cx);
}
};
onClose = e => {
if (this.props.isPaused) {
this.props.clearPreview();
if (this.props.cx.isPaused) {
this.props.clearPreview(this.props.cx);
}
};
@ -183,8 +183,8 @@ class Preview extends PureComponent<Props, State> {
}
const mapStateToProps = state => ({
cx: getThreadContext(state),
preview: getPreview(state),
isPaused: getIsPaused(state, getCurrentThread(state)),
selectedSource: getSelectedSource(state)
});

View File

@ -17,7 +17,8 @@ import {
getFileSearchQuery,
getFileSearchModifiers,
getFileSearchResults,
getHighlightedLineRange
getHighlightedLineRange,
getContext
} from "../../selectors";
import { removeOverlay } from "../../utils/editor";
@ -25,7 +26,7 @@ import { removeOverlay } from "../../utils/editor";
import { scrollList } from "../../utils/result-list";
import classnames from "classnames";
import type { Source } from "../../types";
import type { Source, Context } from "../../types";
import type { Modifiers, SearchResults } from "../../reducers/file-search";
import SearchInput from "../shared/SearchInput";
@ -55,6 +56,7 @@ type State = {
};
type Props = {
cx: Context,
editor: SourceEditor,
selectedSource?: Source,
searchOn: boolean,
@ -137,10 +139,10 @@ class SearchBar extends Component<Props, State> {
};
closeSearch = (e: SyntheticEvent<HTMLElement>) => {
const { closeFileSearch, editor, searchOn } = this.props;
const { cx, closeFileSearch, editor, searchOn } = this.props;
if (editor && searchOn) {
this.clearSearch();
closeFileSearch(editor);
closeFileSearch(cx, editor);
e.stopPropagation();
e.preventDefault();
}
@ -169,12 +171,12 @@ class SearchBar extends Component<Props, State> {
};
doSearch = (query: string) => {
const { selectedSource } = this.props;
const { cx, selectedSource } = this.props;
if (!selectedSource || !selectedSource.text) {
return;
}
this.props.doSearch(query, this.props.editor);
this.props.doSearch(cx, query, this.props.editor);
};
traverseResults = (e: SyntheticEvent<HTMLElement>, rev: boolean) => {
@ -185,7 +187,7 @@ class SearchBar extends Component<Props, State> {
if (!editor) {
return;
}
this.props.traverseResults(rev, editor);
this.props.traverseResults(this.props.cx, rev, editor);
};
// Handlers
@ -242,7 +244,7 @@ class SearchBar extends Component<Props, State> {
}
renderSearchModifiers = () => {
const { modifiers, toggleFileSearchModifier, query } = this.props;
const { cx, modifiers, toggleFileSearchModifier, query } = this.props;
const { doSearch } = this;
function SearchModBtn({ modVal, className, svgName, tooltip }) {
@ -253,12 +255,12 @@ class SearchBar extends Component<Props, State> {
<button
className={preppedClass}
onMouseDown={() => {
toggleFileSearchModifier(modVal);
toggleFileSearchModifier(cx, modVal);
doSearch(query);
}}
onKeyDown={(e: any) => {
if (e.key === "Enter") {
toggleFileSearchModifier(modVal);
toggleFileSearchModifier(cx, modVal);
doSearch(query);
}
}}
@ -357,6 +359,7 @@ SearchBar.contextTypes = {
};
const mapStateToProps = state => ({
cx: getContext(state),
searchOn: getActiveSearch(state) === "file",
selectedSource: getSelectedSource(state),
selectedLocation: getSelectedLocation(state),

View File

@ -13,7 +13,7 @@ import SourceIcon from "../shared/SourceIcon";
import { CloseButton } from "../shared/Button";
import type { List } from "immutable";
import type { Source } from "../../types";
import type { Source, Context } from "../../types";
import actions from "../../actions";
@ -33,7 +33,8 @@ import {
getSelectedSource,
getActiveSearch,
getSourcesForTabs,
getHasSiblingOfSameName
getHasSiblingOfSameName,
getContext
} from "../../selectors";
import type { ActiveSearchType } from "../../selectors";
@ -42,6 +43,7 @@ import classnames from "classnames";
type SourcesList = List<Source>;
type Props = {
cx: Context,
tabSources: SourcesList,
selectedSource: Source,
source: Source,
@ -63,6 +65,7 @@ class Tab extends PureComponent<Props> {
showContextMenu(e, tab: string) {
const {
cx,
closeTab,
closeTabs,
tabSources,
@ -88,13 +91,13 @@ class Tab extends PureComponent<Props> {
{
item: {
...tabMenuItems.closeTab,
click: () => closeTab(sourceTab)
click: () => closeTab(cx, sourceTab)
}
},
{
item: {
...tabMenuItems.closeOtherTabs,
click: () => closeTabs(otherTabURLs),
click: () => closeTabs(cx, otherTabURLs),
disabled: otherTabURLs.length === 0
}
},
@ -103,7 +106,7 @@ class Tab extends PureComponent<Props> {
...tabMenuItems.closeTabsToEnd,
click: () => {
const tabIndex = tabSources.findIndex(t => t.id == tab);
closeTabs(tabURLs.filter((t, i) => i > tabIndex));
closeTabs(cx, tabURLs.filter((t, i) => i > tabIndex));
},
disabled:
tabCount === 1 ||
@ -111,7 +114,10 @@ class Tab extends PureComponent<Props> {
}
},
{
item: { ...tabMenuItems.closeAllTabs, click: () => closeTabs(tabURLs) }
item: {
...tabMenuItems.closeAllTabs,
click: () => closeTabs(cx, tabURLs)
}
},
{ item: { type: "separator" } },
{
@ -132,7 +138,7 @@ class Tab extends PureComponent<Props> {
item: {
...tabMenuItems.showSource,
disabled: !selectedSource.url,
click: () => showSource(tab)
click: () => showSource(cx, tab)
}
},
{
@ -142,13 +148,13 @@ class Tab extends PureComponent<Props> {
? L10N.getStr("sourceFooter.unblackbox")
: L10N.getStr("sourceFooter.blackbox"),
disabled: !shouldBlackbox(source),
click: () => toggleBlackBox(source)
click: () => toggleBlackBox(cx, source)
}
},
{
item: {
...tabMenuItems.prettyPrint,
click: () => togglePrettyPrint(tab),
click: () => togglePrettyPrint(cx, tab),
disabled: isPretty(sourceTab)
}
}
@ -167,6 +173,7 @@ class Tab extends PureComponent<Props> {
render() {
const {
cx,
selectedSource,
selectSource,
closeTab,
@ -183,13 +190,13 @@ class Tab extends PureComponent<Props> {
function onClickClose(e) {
e.stopPropagation();
closeTab(source);
closeTab(cx, source);
}
function handleTabClick(e) {
e.preventDefault();
e.stopPropagation();
return selectSource(sourceId);
return selectSource(cx, sourceId);
}
const className = classnames("source-tab", {
@ -206,7 +213,7 @@ class Tab extends PureComponent<Props> {
key={sourceId}
onClick={handleTabClick}
// Accommodate middle click to close tab
onMouseUp={e => e.button === 1 && closeTab(source)}
onMouseUp={e => e.button === 1 && closeTab(cx, source)}
onContextMenu={e => this.onTabContextMenu(e, sourceId)}
title={getFileURL(source, false)}
>
@ -231,6 +238,7 @@ const mapStateToProps = (state, { source }) => {
const selectedSource = getSelectedSource(state);
return {
cx: getContext(state),
tabSources: getSourcesForTabs(state),
selectedSource: selectedSource,
activeSearch: getActiveSearch(state),

View File

@ -11,7 +11,8 @@ import {
getSelectedSource,
getSourcesForTabs,
getIsPaused,
getCurrentThread
getCurrentThread,
getContext
} from "../../selectors";
import { isVisible } from "../../utils/ui";
@ -28,11 +29,12 @@ import Dropdown from "../shared/Dropdown";
import AccessibleImage from "../shared/AccessibleImage";
import CommandBar from "../SecondaryPanes/CommandBar";
import type { Source } from "../../types";
import type { Source, Context } from "../../types";
type SourcesList = Source[];
type Props = {
cx: Context,
tabSources: SourcesList,
selectedSource: ?Source,
horizontal: boolean,
@ -136,10 +138,10 @@ class Tabs extends PureComponent<Props, State> {
}
renderDropdownSource = (source: Source) => {
const { selectSource } = this.props;
const { cx, selectSource } = this.props;
const filename = getFilename(source);
const onClick = () => selectSource(source.id);
const onClick = () => selectSource(cx, source.id);
return (
<li key={source.id} onClick={onClick}>
<AccessibleImage
@ -226,6 +228,7 @@ class Tabs extends PureComponent<Props, State> {
}
const mapStateToProps = state => ({
cx: getContext(state),
selectedSource: getSelectedSource(state),
tabSources: getSourcesForTabs(state),
isPaused: getIsPaused(state, getCurrentThread(state))

View File

@ -35,7 +35,8 @@ import {
getConditionalPanelLocation,
getSymbols,
getIsPaused,
getCurrentThread
getCurrentThread,
getThreadContext
} from "../../selectors";
// Redux actions
@ -79,13 +80,14 @@ import "./Highlight.css";
import type SourceEditor from "../../utils/editor/source-editor";
import type { SymbolDeclarations } from "../../workers/parser";
import type { SourceLocation, Source } from "../../types";
import type { SourceLocation, Source, ThreadContext } from "../../types";
const cssVars = {
searchbarHeight: "var(--editor-searchbar-height)"
};
export type Props = {
cx: ThreadContext,
selectedLocation: ?SourceLocation,
selectedSource: ?Source,
searchOn: boolean,
@ -224,11 +226,11 @@ class Editor extends PureComponent<Props, State> {
}
onClosePress = (key, e: KeyboardEvent) => {
const { selectedSource } = this.props;
const { cx, selectedSource } = this.props;
if (selectedSource) {
e.preventDefault();
e.stopPropagation();
this.props.closeTab(selectedSource);
this.props.closeTab(cx, selectedSource);
}
};
@ -272,7 +274,7 @@ class Editor extends PureComponent<Props, State> {
return;
}
this.props.toggleBreakpointAtLine(line);
this.props.toggleBreakpointAtLine(this.props.cx, line);
};
onToggleConditionalPanel = (key, e: KeyboardEvent) => {
@ -326,7 +328,7 @@ class Editor extends PureComponent<Props, State> {
};
onSearchAgain = (_, e: KeyboardEvent) => {
this.props.traverseResults(e.shiftKey, this.state.editor);
this.props.traverseResults(this.props.cx, e.shiftKey, this.state.editor);
};
openMenu(event: MouseEvent) {
@ -334,6 +336,7 @@ class Editor extends PureComponent<Props, State> {
event.preventDefault();
const {
cx,
selectedSource,
breakpointActions,
editorActions,
@ -356,9 +359,9 @@ class Editor extends PureComponent<Props, State> {
if (target.classList.contains("CodeMirror-linenumber")) {
return showMenu(event, [
...createBreakpointItems(location, breakpointActions),
...createBreakpointItems(cx, location, breakpointActions),
{ type: "separator" },
continueToHereItem(location, isPaused, editorActions)
continueToHereItem(cx, location, isPaused, editorActions)
]);
}
@ -380,6 +383,7 @@ class Editor extends PureComponent<Props, State> {
ev: MouseEvent
) => {
const {
cx,
selectedSource,
conditionalPanelLocation,
closeConditionalPanel,
@ -411,10 +415,10 @@ class Editor extends PureComponent<Props, State> {
}
if (ev.metaKey) {
return continueToHere(sourceLine);
return continueToHere(cx, sourceLine);
}
return addBreakpointAtLine(sourceLine);
return addBreakpointAtLine(cx, sourceLine);
};
onGutterContextMenu = (event: MouseEvent) => {
@ -422,7 +426,7 @@ class Editor extends PureComponent<Props, State> {
};
onClick(e: MouseEvent) {
const { selectedSource, jumpToMappedLocation } = this.props;
const { cx, selectedSource, jumpToMappedLocation } = this.props;
if (selectedSource && e.metaKey && e.altKey) {
const sourceLocation = getSourceLocationFromMouseEvent(
@ -430,7 +434,7 @@ class Editor extends PureComponent<Props, State> {
selectedSource,
e
);
jumpToMappedLocation(sourceLocation);
jumpToMappedLocation(cx, sourceLocation);
}
}
@ -568,7 +572,7 @@ class Editor extends PureComponent<Props, State> {
}
renderItems() {
const { selectedSource, conditionalPanelLocation } = this.props;
const { cx, selectedSource, conditionalPanelLocation } = this.props;
const { editor, contextMenu } = this.state;
if (!selectedSource || !editor || !getDocument(selectedSource.id)) {
@ -580,7 +584,7 @@ class Editor extends PureComponent<Props, State> {
<DebugLine editor={editor} />
<HighlightLine />
<EmptyLines editor={editor} />
<Breakpoints editor={editor} />
<Breakpoints editor={editor} cx={cx} />
<Preview editor={editor} editorRef={this.$editorWrapper} />
<HighlightLines editor={editor} />
{
@ -637,6 +641,7 @@ const mapStateToProps = state => {
const selectedSource = getSelectedSource(state);
return {
cx: getThreadContext(state),
selectedLocation: getSelectedLocation(state),
selectedSource,
searchOn: getActiveSearch(state) === "file",

View File

@ -6,10 +6,11 @@
import actions from "../../../actions";
import { bindActionCreators } from "redux";
import type { SourceLocation, Breakpoint } from "../../../types";
import type { SourceLocation, Breakpoint, Context } from "../../../types";
import { features } from "../../../utils/prefs";
export const addBreakpointItem = (
cx: Context,
location: SourceLocation,
breakpointActions: BreakpointItemActions
) => ({
@ -17,11 +18,12 @@ export const addBreakpointItem = (
label: L10N.getStr("editor.addBreakpoint"),
accesskey: L10N.getStr("shortcuts.toggleBreakpoint.accesskey"),
disabled: false,
click: () => breakpointActions.addBreakpoint(location),
click: () => breakpointActions.addBreakpoint(cx, location),
accelerator: L10N.getStr("toggleBreakpoint.key")
});
export const removeBreakpointItem = (
cx: Context,
breakpoint: Breakpoint,
breakpointActions: BreakpointItemActions
) => ({
@ -29,7 +31,7 @@ export const removeBreakpointItem = (
label: L10N.getStr("editor.removeBreakpoint"),
accesskey: L10N.getStr("shortcuts.toggleBreakpoint.accesskey"),
disabled: false,
click: () => breakpointActions.removeBreakpoint(breakpoint),
click: () => breakpointActions.removeBreakpoint(cx, breakpoint),
accelerator: L10N.getStr("toggleBreakpoint.key")
});
@ -108,13 +110,14 @@ export const logPointItem = (
};
export const toggleDisabledBreakpointItem = (
cx: Context,
breakpoint: Breakpoint,
breakpointActions: BreakpointItemActions
) => {
return {
accesskey: L10N.getStr("editor.disableBreakpoint.accesskey"),
disabled: false,
click: () => breakpointActions.toggleDisabledBreakpoint(breakpoint),
click: () => breakpointActions.toggleDisabledBreakpoint(cx, breakpoint),
...(breakpoint.disabled
? {
id: "node-menu-enable-breakpoint",
@ -128,21 +131,30 @@ export const toggleDisabledBreakpointItem = (
};
export function breakpointItems(
cx: Context,
breakpoint: Breakpoint,
breakpointActions: BreakpointItemActions
) {
const items = [
removeBreakpointItem(breakpoint, breakpointActions),
toggleDisabledBreakpointItem(breakpoint, breakpointActions)
removeBreakpointItem(cx, breakpoint, breakpointActions),
toggleDisabledBreakpointItem(cx, breakpoint, breakpointActions)
];
if (features.columnBreakpoints) {
items.push(
{ type: "separator" },
removeBreakpointsOnLineItem(breakpoint.location, breakpointActions),
removeBreakpointsOnLineItem(cx, breakpoint.location, breakpointActions),
breakpoint.disabled
? enableBreakpointsOnLineItem(breakpoint.location, breakpointActions)
: disableBreakpointsOnLineItem(breakpoint.location, breakpointActions),
? enableBreakpointsOnLineItem(
cx,
breakpoint.location,
breakpointActions
)
: disableBreakpointsOnLineItem(
cx,
breakpoint.location,
breakpointActions
),
{ type: "separator" }
);
}
@ -157,11 +169,12 @@ export function breakpointItems(
}
export function createBreakpointItems(
cx: Context,
location: SourceLocation,
breakpointActions: BreakpointItemActions
) {
const items = [
addBreakpointItem(location, breakpointActions),
addBreakpointItem(cx, location, breakpointActions),
addConditionalBreakpointItem(location, breakpointActions)
];
@ -173,6 +186,7 @@ export function createBreakpointItems(
// ToDo: Only enable if there are more than one breakpoints on a line?
export const removeBreakpointsOnLineItem = (
cx: Context,
location: SourceLocation,
breakpointActions: BreakpointItemActions
) => ({
@ -181,10 +195,15 @@ export const removeBreakpointsOnLineItem = (
accesskey: L10N.getStr("breakpointMenuItem.removeAllAtLine.accesskey"),
disabled: false,
click: () =>
breakpointActions.removeBreakpointsAtLine(location.sourceId, location.line)
breakpointActions.removeBreakpointsAtLine(
cx,
location.sourceId,
location.line
)
});
export const enableBreakpointsOnLineItem = (
cx: Context,
location: SourceLocation,
breakpointActions: BreakpointItemActions
) => ({
@ -193,10 +212,15 @@ export const enableBreakpointsOnLineItem = (
accesskey: L10N.getStr("breakpointMenuItem.enableAllAtLine.accesskey"),
disabled: false,
click: () =>
breakpointActions.enableBreakpointsAtLine(location.sourceId, location.line)
breakpointActions.enableBreakpointsAtLine(
cx,
location.sourceId,
location.line
)
});
export const disableBreakpointsOnLineItem = (
cx: Context,
location: SourceLocation,
breakpointActions: BreakpointItemActions
) => ({
@ -205,7 +229,11 @@ export const disableBreakpointsOnLineItem = (
accesskey: L10N.getStr("breakpointMenuItem.disableAllAtLine.accesskey"),
disabled: false,
click: () =>
breakpointActions.disableBreakpointsAtLine(location.sourceId, location.line)
breakpointActions.disableBreakpointsAtLine(
cx,
location.sourceId,
location.line
)
});
export type BreakpointItemActions = {

View File

@ -19,20 +19,26 @@ import { downloadFile } from "../../../utils/utils";
import actions from "../../../actions";
import type { Source, SourceLocation } from "../../../types";
import type {
Source,
SourceLocation,
Context,
ThreadContext
} from "../../../types";
function isMapped(selectedSource) {
return isOriginalId(selectedSource.id) || !!selectedSource.sourceMapURL;
}
export const continueToHereItem = (
cx: ThreadContext,
location: SourceLocation,
isPaused: boolean,
editorActions: EditorItemActions
) => ({
accesskey: L10N.getStr("editor.continueToHere.accesskey"),
disabled: !isPaused,
click: () => editorActions.continueToHere(location.line, location.column),
click: () => editorActions.continueToHere(cx, location.line, location.column),
id: "node-menu-continue-to-here",
label: L10N.getStr("editor.continueToHere.label")
});
@ -85,6 +91,7 @@ const copySourceUri2Item = (
});
const jumpToMappedLocationItem = (
cx: Context,
selectedSource: Source,
location: SourceLocation,
hasPrettySource: boolean,
@ -100,10 +107,11 @@ const jumpToMappedLocationItem = (
accesskey: L10N.getStr("editor.jumpToMappedLocation1.accesskey"),
disabled:
(!isMapped(selectedSource) && !isPretty(selectedSource)) || hasPrettySource,
click: () => editorActions.jumpToMappedLocation(location)
click: () => editorActions.jumpToMappedLocation(cx, location)
});
const showSourceMenuItem = (
cx: Context,
selectedSource: Source,
editorActions: EditorItemActions
) => ({
@ -111,10 +119,11 @@ const showSourceMenuItem = (
label: L10N.getStr("sourceTabs.revealInTree"),
accesskey: L10N.getStr("sourceTabs.revealInTree.accesskey"),
disabled: !selectedSource.url,
click: () => editorActions.showSource(selectedSource.id)
click: () => editorActions.showSource(cx, selectedSource.id)
});
const blackBoxMenuItem = (
cx: Context,
selectedSource: Source,
editorActions: EditorItemActions
) => ({
@ -124,10 +133,11 @@ const blackBoxMenuItem = (
: L10N.getStr("sourceFooter.blackbox"),
accesskey: L10N.getStr("sourceFooter.blackbox.accesskey"),
disabled: !shouldBlackbox(selectedSource),
click: () => editorActions.toggleBlackBox(selectedSource)
click: () => editorActions.toggleBlackBox(cx, selectedSource)
});
const watchExpressionItem = (
cx: ThreadContext,
selectedSource: Source,
selectionText: string,
editorActions: EditorItemActions
@ -135,7 +145,7 @@ const watchExpressionItem = (
id: "node-menu-add-watch-expression",
label: L10N.getStr("expressions.label"),
accesskey: L10N.getStr("expressions.accesskey"),
click: () => editorActions.addExpression(selectionText)
click: () => editorActions.addExpression(cx, selectionText)
});
const evaluateInConsoleItem = (
@ -161,6 +171,7 @@ const downloadFileItem = (
};
export function editorMenuItems({
cx,
editorActions,
selectedSource,
location,
@ -169,6 +180,7 @@ export function editorMenuItems({
isTextSelected,
isPaused
}: {
cx: ThreadContext,
editorActions: EditorItemActions,
selectedSource: Source,
location: SourceLocation,
@ -181,26 +193,27 @@ export function editorMenuItems({
items.push(
jumpToMappedLocationItem(
cx,
selectedSource,
location,
hasPrettySource,
editorActions
),
continueToHereItem(location, isPaused, editorActions),
continueToHereItem(cx, location, isPaused, editorActions),
{ type: "separator" },
copyToClipboardItem(selectedSource, editorActions),
copySourceItem(selectedSource, selectionText, editorActions),
copySourceUri2Item(selectedSource, editorActions),
downloadFileItem(selectedSource, editorActions),
{ type: "separator" },
showSourceMenuItem(selectedSource, editorActions),
blackBoxMenuItem(selectedSource, editorActions)
showSourceMenuItem(cx, selectedSource, editorActions),
blackBoxMenuItem(cx, selectedSource, editorActions)
);
if (isTextSelected) {
items.push(
{ type: "separator" },
watchExpressionItem(selectedSource, selectionText, editorActions),
watchExpressionItem(cx, selectedSource, selectionText, editorActions),
evaluateInConsoleItem(selectedSource, selectionText, editorActions)
);
}

View File

@ -67,7 +67,7 @@ describe("doSearch", () => {
.find("SearchInput")
.simulate("change", { target: { value: "query" } });
const doSearchArgs = props.doSearch.mock.calls[0][0];
const doSearchArgs = props.doSearch.mock.calls[0][1];
expect(doSearchArgs).toMatchSnapshot();
});
});

View File

@ -16,7 +16,8 @@ import actions from "../../actions";
import {
getSelectedSource,
getSymbols,
getSelectedLocation
getSelectedLocation,
getContext
} from "../../selectors";
import OutlineFilter from "./OutlineFilter";
@ -30,9 +31,10 @@ import type {
SymbolDeclaration,
FunctionDeclaration
} from "../../workers/parser";
import type { Source } from "../../types";
import type { Source, Context } from "../../types";
type Props = {
cx: Context,
symbols: SymbolDeclarations,
selectedSource: ?Source,
alphabetizeOutline: boolean,
@ -72,12 +74,12 @@ export class Outline extends Component<Props, State> {
}
selectItem(location: AstLocation) {
const { selectedSource, selectLocation } = this.props;
const { cx, selectedSource, selectLocation } = this.props;
if (!selectedSource) {
return;
}
selectLocation({
selectLocation(cx, {
sourceId: selectedSource.id,
line: location.start.line,
column: location.start.column
@ -264,6 +266,7 @@ const mapStateToProps = state => {
const symbols = selectedSource ? getSymbols(state, selectedSource) : null;
return {
cx: getContext(state),
symbols,
selectedSource,
selectedLocation: getSelectedLocation(state),

View File

@ -19,7 +19,8 @@ import {
getDisplayedSourcesForThread,
getFocusedSourceItem,
getWorkerByThread,
getWorkerCount
getWorkerCount,
getContext
} from "../../selectors";
import { getGeneratedSourceByURL } from "../../reducers/sources";
@ -51,11 +52,12 @@ import type {
TreeDirectory,
ParentMap
} from "../../utils/sources-tree/types";
import type { Worker, Source } from "../../types";
import type { Worker, Source, Context } from "../../types";
import type { SourcesMap, State as AppState } from "../../reducers/types";
import type { Item } from "../shared/ManagedTree";
type Props = {
cx: Context,
thread: string,
worker: Worker,
sources: SourcesMap,
@ -156,12 +158,12 @@ class SourcesTree extends Component<Props, State> {
selectItem = (item: TreeNode) => {
if (item.type == "source" && !Array.isArray(item.contents)) {
this.props.selectSource(item.contents.id);
this.props.selectSource(this.props.cx, item.contents.id);
}
};
onFocus = (item: TreeNode) => {
this.props.focusItem({ thread: this.props.thread, item });
this.props.focusItem(this.props.cx, { thread: this.props.thread, item });
};
onActivate = (item: TreeNode) => {
@ -371,6 +373,7 @@ const mapStateToProps = (state, props) => {
const displayedSources = getDisplayedSourcesForThread(state, thread);
return {
cx: getContext(state),
shownSource: getSourceForTree(state, displayedSources, shownSource, thread),
selectedSource: getSourceForTree(
state,

View File

@ -15,7 +15,8 @@ import AccessibleImage from "../shared/AccessibleImage";
import {
getGeneratedSourceByURL,
getHasSiblingOfSameName,
hasPrettySource as checkHasPrettySource
hasPrettySource as checkHasPrettySource,
getContext
} from "../../selectors";
import actions from "../../actions";
@ -30,9 +31,10 @@ import { copyToTheClipboard } from "../../utils/clipboard";
import { features } from "../../utils/prefs";
import type { TreeNode } from "../../utils/sources-tree/types";
import type { Source } from "../../types";
import type { Source, Context } from "../../types";
type Props = {
cx: Context,
debuggeeUrl: string,
projectRoot: string,
source: ?Source,
@ -134,7 +136,7 @@ class SourceTreeItem extends Component<Props, State> {
click: () => copyToTheClipboard(contents.url)
};
const { source } = this.props;
const { cx, source } = this.props;
if (source) {
const blackBoxMenuItem = {
id: "node-menu-blackbox",
@ -143,7 +145,7 @@ class SourceTreeItem extends Component<Props, State> {
: L10N.getStr("sourceFooter.blackbox"),
accesskey: L10N.getStr("sourceFooter.blackbox.accesskey"),
disabled: !shouldBlackbox(source),
click: () => this.props.toggleBlackBox(source)
click: () => this.props.toggleBlackBox(cx, source)
};
menuOptions.push(copySourceUri2, blackBoxMenuItem);
}
@ -155,14 +157,14 @@ class SourceTreeItem extends Component<Props, State> {
if (features.root) {
const { path } = item;
const { projectRoot } = this.props;
const { cx, projectRoot } = this.props;
if (projectRoot.endsWith(path)) {
menuOptions.push({
id: "node-remove-directory-root",
label: removeDirectoryRootLabel,
disabled: false,
click: () => this.props.clearProjectDirectoryRoot()
click: () => this.props.clearProjectDirectoryRoot(cx)
});
} else {
menuOptions.push({
@ -170,7 +172,7 @@ class SourceTreeItem extends Component<Props, State> {
label: setDirectoryRootLabel,
accesskey: setDirectoryRootKey,
disabled: false,
click: () => this.props.setProjectDirectoryRoot(path)
click: () => this.props.setProjectDirectoryRoot(cx, path)
});
}
}
@ -273,6 +275,7 @@ function getHasMatchingGeneratedSource(state, source: ?Source) {
const mapStateToProps = (state, props) => {
const { source } = props;
return {
cx: getContext(state),
hasMatchingGeneratedSource: getHasMatchingGeneratedSource(state, source),
hasSiblingOfSameName: getHasSiblingOfSameName(state, source),
hasPrettySource: source ? checkHasPrettySource(state, source.id) : false

View File

@ -14,7 +14,8 @@ import {
getActiveSearch,
getProjectDirectoryRoot,
getSelectedPrimaryPaneTab,
getThreads
getThreads,
getContext
} from "../../selectors";
import { features, prefs } from "../../utils/prefs";
import { connect } from "../../utils/connect";
@ -26,7 +27,7 @@ import AccessibleImage from "../shared/AccessibleImage";
import type { SourcesMapByThread } from "../../reducers/types";
import type { SelectedPrimaryPaneTabType } from "../../selectors";
import type { Thread } from "../../types";
import type { Thread, Context } from "../../types";
import "./Sources.css";
@ -35,6 +36,7 @@ type State = {
};
type Props = {
cx: Context,
selectedTab: SelectedPrimaryPaneTabType,
sources: SourcesMapByThread,
horizontal: boolean,
@ -101,7 +103,7 @@ class PrimaryPanes extends Component<Props, State> {
}
renderProjectRootHeader() {
const { projectRoot } = this.props;
const { cx, projectRoot } = this.props;
if (!projectRoot) {
return null;
@ -113,7 +115,7 @@ class PrimaryPanes extends Component<Props, State> {
<div key="root" className="sources-clear-root-container">
<button
className="sources-clear-root"
onClick={() => this.props.clearProjectDirectoryRoot()}
onClick={() => this.props.clearProjectDirectoryRoot(cx)}
title={L10N.getStr("removeDirectoryRoot.label")}
>
<AccessibleImage className="home" />
@ -164,6 +166,7 @@ class PrimaryPanes extends Component<Props, State> {
}
const mapStateToProps = state => ({
cx: getContext(state),
selectedTab: getSelectedPrimaryPaneTab(state),
sources: getDisplayedSources(state),
sourceSearchOn: getActiveSearch(state) === "source",

View File

@ -9,7 +9,7 @@ import { shallow } from "enzyme";
import { showMenu } from "devtools-contextmenu";
import SourcesTree from "../SourcesTree";
import { makeMockSource } from "../../../utils/test-mockup";
import { makeMockSource, mockcx } from "../../../utils/test-mockup";
import { copyToTheClipboard } from "../../../utils/clipboard";
jest.mock("devtools-contextmenu", () => ({ showMenu: jest.fn() }));
@ -194,6 +194,7 @@ describe("SourcesTree", () => {
instance.onActivate(item);
expect(spy).toHaveBeenCalledWith(item);
expect(props.selectSource).toHaveBeenCalledWith(
mockcx,
"server1.conn13.child1/39"
);
});
@ -204,6 +205,7 @@ describe("SourcesTree", () => {
const { instance, props } = render();
instance.selectItem(createMockItem());
expect(props.selectSource).toHaveBeenCalledWith(
mockcx,
"server1.conn13.child1/39"
);
});
@ -357,6 +359,7 @@ function generateDefaults(overrides: Object) {
)
};
return {
cx: mockcx,
thread: "FakeThread",
autoExpandAll: true,
selectSource: jest.fn(),

View File

@ -19,7 +19,8 @@ import {
getActiveSearch,
getTextSearchResults,
getTextSearchStatus,
getTextSearchQuery
getTextSearchQuery,
getContext
} from "../selectors";
import ManagedTree from "./shared/ManagedTree";
@ -29,6 +30,7 @@ import AccessibleImage from "./shared/AccessibleImage";
import type { List } from "immutable";
import type { ActiveSearchType } from "../reducers/types";
import type { StatusType } from "../reducers/project-text-search";
import type { Context } from "../types";
import "./ProjectSearch.css";
@ -59,6 +61,7 @@ type State = {
};
type Props = {
cx: Context,
query: string,
results: List<Result>,
status: StatusType,
@ -119,17 +122,17 @@ export class ProjectSearch extends Component<Props, State> {
}
doSearch(searchTerm: string) {
this.props.searchSources(searchTerm);
this.props.searchSources(this.props.cx, searchTerm);
}
toggleProjectTextSearch = (key: string, e: KeyboardEvent) => {
const { closeProjectSearch, setActiveSearch } = this.props;
const { cx, closeProjectSearch, setActiveSearch } = this.props;
if (e) {
e.preventDefault();
}
if (this.isProjectSearchEnabled()) {
return closeProjectSearch();
return closeProjectSearch(cx);
}
return setActiveSearch("project");
@ -138,7 +141,7 @@ export class ProjectSearch extends Component<Props, State> {
isProjectSearchEnabled = () => this.props.activeSearch === "project";
selectMatchItem = (matchItem: Match) => {
this.props.selectSpecificLocation({
this.props.selectSpecificLocation(this.props.cx, {
sourceId: matchItem.sourceId,
line: matchItem.line,
column: matchItem.column
@ -196,10 +199,10 @@ export class ProjectSearch extends Component<Props, State> {
inputOnChange = (e: SyntheticInputEvent<HTMLInputElement>) => {
const inputValue = e.target.value;
const { clearSearch } = this.props;
const { cx, clearSearch } = this.props;
this.setState({ inputValue });
if (inputValue === "") {
clearSearch();
clearSearch(cx);
}
};
@ -331,6 +334,7 @@ ProjectSearch.contextTypes = {
};
const mapStateToProps = state => ({
cx: getContext(state),
activeSearch: getActiveSearch(state),
results: getTextSearchResults(state),
query: getTextSearchQuery(state),

View File

@ -17,7 +17,8 @@ import {
getSelectedSource,
getSymbols,
getTabs,
isSymbolsLoading
isSymbolsLoading,
getContext
} from "../selectors";
import { scrollList } from "../utils/result-list";
import {
@ -35,13 +36,14 @@ import type {
QuickOpenResult
} from "../utils/quick-open";
import type { Source } from "../types";
import type { Source, Context } from "../types";
import type { QuickOpenType } from "../reducers/quick-open";
import type { Tab } from "../reducers/tabs";
import "./QuickOpenModal.css";
type Props = {
cx: Context,
enabled: boolean,
sources: Array<Object>,
selectedSource?: Source,
@ -245,11 +247,11 @@ export class QuickOpenModal extends Component<Props, State> {
};
gotoLocation = (location: ?GotoLocationType) => {
const { selectSpecificLocation, selectedSource } = this.props;
const { cx, selectSpecificLocation, selectedSource } = this.props;
const selectedSourceId = selectedSource ? selectedSource.id : "";
if (location != null) {
const sourceId = location.sourceId ? location.sourceId : selectedSourceId;
selectSpecificLocation({
selectSpecificLocation(cx, {
sourceId,
line: location.line,
column: location.column
@ -419,6 +421,7 @@ function mapStateToProps(state) {
const selectedSource = getSelectedSource(state);
return {
cx: getContext(state),
enabled: getQuickOpenEnabled(state),
sources: formatSources(getDisplayedSourcesList(state), getTabs(state)),
selectedSource,

View File

@ -27,7 +27,8 @@ import type {
Breakpoint as BreakpointType,
Frame,
Source,
SourceLocation
SourceLocation,
Context
} from "../../../types";
type FormattedFrame = Frame & {
@ -38,10 +39,12 @@ import {
getBreakpointsList,
getSelectedFrame,
getSelectedSource,
getCurrentThread
getCurrentThread,
getContext
} from "../../../selectors";
type Props = {
cx: Context,
breakpoint: BreakpointType,
breakpoints: BreakpointType[],
selectedSource: Source,
@ -79,22 +82,22 @@ class Breakpoint extends PureComponent<Props> {
selectBreakpoint = event => {
event.preventDefault();
const { selectSpecificLocation } = this.props;
selectSpecificLocation(this.selectedLocation);
const { cx, selectSpecificLocation } = this.props;
selectSpecificLocation(cx, this.selectedLocation);
};
removeBreakpoint = event => {
const { removeBreakpoint, breakpoint } = this.props;
const { cx, removeBreakpoint, breakpoint } = this.props;
event.stopPropagation();
removeBreakpoint(breakpoint);
removeBreakpoint(cx, breakpoint);
};
handleBreakpointCheckbox = () => {
const { breakpoint, enableBreakpoint, disableBreakpoint } = this.props;
const { cx, breakpoint, enableBreakpoint, disableBreakpoint } = this.props;
if (breakpoint.disabled) {
enableBreakpoint(breakpoint);
enableBreakpoint(cx, breakpoint);
} else {
disableBreakpoint(breakpoint);
disableBreakpoint(cx, breakpoint);
}
};
@ -211,6 +214,7 @@ const getFormattedFrame = createSelector(
);
const mapStateToProps = state => ({
cx: getContext(state),
breakpoints: getBreakpointsList(state),
frame: getFormattedFrame(state, getCurrentThread(state))
});

View File

@ -14,15 +14,17 @@ import {
} from "../../../utils/source";
import {
getHasSiblingOfSameName,
getBreakpointsForSource
getBreakpointsForSource,
getContext
} from "../../../selectors";
import SourceIcon from "../../shared/SourceIcon";
import type { Source, Breakpoint } from "../../../types";
import type { Source, Breakpoint, Context } from "../../../types";
import showContextMenu from "./BreakpointHeadingsContextMenu";
type Props = {
cx: Context,
sources: Source[],
source: Source,
hasSiblingOfSameName: boolean,
@ -39,7 +41,13 @@ class BreakpointHeading extends PureComponent<Props> {
};
render() {
const { sources, source, hasSiblingOfSameName, selectSource } = this.props;
const {
cx,
sources,
source,
hasSiblingOfSameName,
selectSource
} = this.props;
const path = getDisplayPath(source, sources);
const query = hasSiblingOfSameName ? getSourceQueryString(source) : "";
@ -48,7 +56,7 @@ class BreakpointHeading extends PureComponent<Props> {
<div
className="breakpoint-heading"
title={getFileURL(source, false)}
onClick={() => selectSource(source.id)}
onClick={() => selectSource(cx, source.id)}
onContextMenu={this.onContextMenu}
>
<SourceIcon
@ -65,6 +73,7 @@ class BreakpointHeading extends PureComponent<Props> {
}
const mapStateToProps = (state, { source }) => ({
cx: getContext(state),
hasSiblingOfSameName: getHasSiblingOfSameName(state, source),
breakpointsForSource: getBreakpointsForSource(state, source.id)
});

View File

@ -7,9 +7,10 @@
import { buildMenu, showMenu } from "devtools-contextmenu";
import actions from "../../../actions";
import type { Breakpoint, Source } from "../../../types";
import type { Breakpoint, Source, Context } from "../../../types";
type Props = {
cx: Context,
source: Source,
breakpointsForSource: Breakpoint[],
disableBreakpointsInSource: typeof actions.disableBreakpointsInSource,
@ -20,6 +21,7 @@ type Props = {
export default function showContextMenu(props: Props) {
const {
cx,
source,
breakpointsForSource,
disableBreakpointsInSource,
@ -54,7 +56,7 @@ export default function showContextMenu(props: Props) {
label: disableInSourceLabel,
accesskey: disableInSourceKey,
disabled: false,
click: () => disableBreakpointsInSource(source)
click: () => disableBreakpointsInSource(cx, source)
};
const enableInSourceItem = {
@ -62,7 +64,7 @@ export default function showContextMenu(props: Props) {
label: enableInSourceLabel,
accesskey: enableInSourceKey,
disabled: false,
click: () => enableBreakpointsInSource(source)
click: () => enableBreakpointsInSource(cx, source)
};
const removeInSourceItem = {
@ -70,7 +72,7 @@ export default function showContextMenu(props: Props) {
label: removeInSourceLabel,
accesskey: removeInSourceKey,
disabled: false,
click: () => removeBreakpointsInSource(source)
click: () => removeBreakpointsInSource(cx, source)
};
const hideDisableInSourceItem = breakpointsForSource.every(

View File

@ -9,9 +9,10 @@ import { getSelectedLocation } from "../../../utils/source-maps";
import actions from "../../../actions";
import { features } from "../../../utils/prefs";
import type { Breakpoint, Source } from "../../../types";
import type { Breakpoint, Source, Context } from "../../../types";
type Props = {
cx: Context,
breakpoint: Breakpoint,
breakpoints: Breakpoint[],
selectedSource: Source,
@ -29,6 +30,7 @@ type Props = {
export default function showContextMenu(props: Props) {
const {
cx,
breakpoint,
breakpoints,
selectedSource,
@ -115,7 +117,7 @@ export default function showContextMenu(props: Props) {
accesskey: deleteSelfKey,
disabled: false,
click: () => {
removeBreakpoint(breakpoint);
removeBreakpoint(cx, breakpoint);
}
};
@ -124,7 +126,7 @@ export default function showContextMenu(props: Props) {
label: deleteAllLabel,
accesskey: deleteAllKey,
disabled: false,
click: () => removeAllBreakpoints()
click: () => removeAllBreakpoints(cx)
};
const deleteOthersItem = {
@ -132,7 +134,7 @@ export default function showContextMenu(props: Props) {
label: deleteOthersLabel,
accesskey: deleteOthersKey,
disabled: false,
click: () => removeBreakpoints(otherBreakpoints)
click: () => removeBreakpoints(cx, otherBreakpoints)
};
const enableSelfItem = {
@ -141,7 +143,7 @@ export default function showContextMenu(props: Props) {
accesskey: enableSelfKey,
disabled: false,
click: () => {
toggleDisabledBreakpoint(breakpoint);
toggleDisabledBreakpoint(cx, breakpoint);
}
};
@ -150,7 +152,7 @@ export default function showContextMenu(props: Props) {
label: enableAllLabel,
accesskey: enableAllKey,
disabled: false,
click: () => toggleAllBreakpoints(false)
click: () => toggleAllBreakpoints(cx, false)
};
const enableOthersItem = {
@ -158,7 +160,7 @@ export default function showContextMenu(props: Props) {
label: enableOthersLabel,
accesskey: enableOthersKey,
disabled: false,
click: () => toggleBreakpoints(false, otherDisabledBreakpoints)
click: () => toggleBreakpoints(cx, false, otherDisabledBreakpoints)
};
const disableSelfItem = {
@ -167,7 +169,7 @@ export default function showContextMenu(props: Props) {
accesskey: disableSelfKey,
disabled: false,
click: () => {
toggleDisabledBreakpoint(breakpoint);
toggleDisabledBreakpoint(cx, breakpoint);
}
};
@ -176,14 +178,14 @@ export default function showContextMenu(props: Props) {
label: disableAllLabel,
accesskey: disableAllKey,
disabled: false,
click: () => toggleAllBreakpoints(true)
click: () => toggleAllBreakpoints(cx, true)
};
const disableOthersItem = {
id: "node-menu-disable-others",
label: disableOthersLabel,
accesskey: disableOthersKey,
click: () => toggleBreakpoints(true, otherEnabledBreakpoints)
click: () => toggleBreakpoints(cx, true, otherEnabledBreakpoints)
};
const removeConditionItem = {
@ -192,7 +194,7 @@ export default function showContextMenu(props: Props) {
accesskey: removeConditionKey,
disabled: false,
click: () =>
setBreakpointOptions(selectedLocation, {
setBreakpointOptions(cx, selectedLocation, {
...breakpoint.options,
condition: null
})
@ -203,7 +205,7 @@ export default function showContextMenu(props: Props) {
label: addConditionLabel,
accesskey: addConditionKey,
click: () => {
selectSpecificLocation(selectedLocation);
selectSpecificLocation(cx, selectedLocation);
openConditionalPanel(selectedLocation);
},
accelerator: L10N.getStr("toggleCondPanel.breakpoint.key")
@ -214,7 +216,7 @@ export default function showContextMenu(props: Props) {
label: editConditionLabel,
accesskey: editConditionKey,
click: () => {
selectSpecificLocation(selectedLocation);
selectSpecificLocation(cx, selectedLocation);
openConditionalPanel(selectedLocation);
},
accelerator: L10N.getStr("toggleCondPanel.breakpoint.key")
@ -244,7 +246,7 @@ export default function showContextMenu(props: Props) {
accesskey: L10N.getStr("editor.removeLogPoint.accesskey"),
disabled: false,
click: () =>
setBreakpointOptions(selectedLocation, {
setBreakpointOptions(cx, selectedLocation, {
...breakpoint.options,
logValue: null
})

View File

@ -12,7 +12,8 @@ import { buildMenu } from "devtools-contextmenu";
import {
makeMockBreakpoint,
makeMockSource
makeMockSource,
mockcx
} from "../../../../utils/test-mockup";
jest.mock("devtools-contextmenu");
@ -55,6 +56,7 @@ function generateDefaults(disabled) {
];
const props = {
cx: mockcx,
breakpoints,
breakpoint: breakpoints[0],
removeBreakpoint: jest.fn(),
@ -90,7 +92,7 @@ describe("BreakpointsContextMenu", () => {
expect(props.removeBreakpoints).toHaveBeenCalled();
const otherBreakpoints = [props.breakpoints[1], props.breakpoints[2]];
expect(props.removeBreakpoints.mock.calls[0][0]).toEqual(
expect(props.removeBreakpoints.mock.calls[0][1]).toEqual(
otherBreakpoints
);
});
@ -105,10 +107,10 @@ describe("BreakpointsContextMenu", () => {
expect(props.toggleBreakpoints).toHaveBeenCalled();
expect(props.toggleBreakpoints.mock.calls[0][0]).toBe(false);
expect(props.toggleBreakpoints.mock.calls[0][1]).toBe(false);
const otherBreakpoints = [props.breakpoints[1], props.breakpoints[2]];
expect(props.toggleBreakpoints.mock.calls[0][1]).toEqual(
expect(props.toggleBreakpoints.mock.calls[0][2]).toEqual(
otherBreakpoints
);
});
@ -122,10 +124,10 @@ describe("BreakpointsContextMenu", () => {
disableOthers.item.click();
expect(props.toggleBreakpoints).toHaveBeenCalled();
expect(props.toggleBreakpoints.mock.calls[0][0]).toBe(true);
expect(props.toggleBreakpoints.mock.calls[0][1]).toBe(true);
const otherBreakpoints = [props.breakpoints[1], props.breakpoints[2]];
expect(props.toggleBreakpoints.mock.calls[0][1]).toEqual(
expect(props.toggleBreakpoints.mock.calls[0][2]).toEqual(
otherBreakpoints
);
});

View File

@ -12,11 +12,11 @@ import { connect } from "../../utils/connect";
import classnames from "classnames";
import { features } from "../../utils/prefs";
import {
getIsPaused,
getIsWaitingOnBreak,
getCanRewind,
getSkipPausing,
getCurrentThread
getCurrentThread,
getThreadContext
} from "../../selectors";
import { formatKeyShortcut } from "../../utils/text";
import actions from "../../actions";
@ -25,6 +25,7 @@ import AccessibleImage from "../shared/AccessibleImage";
import "./CommandBar.css";
import { appinfo } from "devtools-services";
import type { ThreadContext } from "../../types";
const isMacOS = appinfo.OS === "Darwin";
@ -75,7 +76,7 @@ function formatKey(action) {
}
type Props = {
isPaused: boolean,
cx: ThreadContext,
isWaitingOnBreak: boolean,
horizontal: boolean,
canRewind: boolean,
@ -121,41 +122,44 @@ class CommandBar extends Component<Props> {
}
handleEvent(e, action) {
const { cx } = this.props;
e.preventDefault();
e.stopPropagation();
if (action === "resume") {
this.props.isPaused ? this.props.resume() : this.props.breakOnNext();
this.props.cx.isPaused
? this.props.resume(cx)
: this.props.breakOnNext(cx);
} else {
this.props[action]();
this.props[action](cx);
}
}
renderStepButtons() {
const { isPaused, canRewind } = this.props;
const className = isPaused ? "active" : "disabled";
const isDisabled = !isPaused;
const { cx, canRewind } = this.props;
const className = cx.isPaused ? "active" : "disabled";
const isDisabled = !cx.isPaused;
if (canRewind || (!isPaused && features.removeCommandBarOptions)) {
if (canRewind || (!cx.isPaused && features.removeCommandBarOptions)) {
return;
}
return [
debugBtn(
this.props.stepOver,
() => this.props.stepOver(cx),
"stepOver",
className,
L10N.getFormatStr("stepOverTooltip", formatKey("stepOver")),
isDisabled
),
debugBtn(
this.props.stepIn,
() => this.props.stepIn(cx),
"stepIn",
className,
L10N.getFormatStr("stepInTooltip", formatKey("stepIn")),
isDisabled
),
debugBtn(
this.props.stepOut,
() => this.props.stepOut(cx),
"stepOut",
className,
L10N.getFormatStr("stepOutTooltip", formatKey("stepOut")),
@ -165,13 +169,13 @@ class CommandBar extends Component<Props> {
}
resume() {
this.props.resume();
this.props.resume(this.props.cx);
}
renderPauseButton() {
const { isPaused, breakOnNext, isWaitingOnBreak, canRewind } = this.props;
const { cx, breakOnNext, isWaitingOnBreak, canRewind } = this.props;
if (isPaused) {
if (cx.isPaused) {
if (canRewind) {
return null;
}
@ -198,7 +202,7 @@ class CommandBar extends Component<Props> {
}
return debugBtn(
breakOnNext,
() => breakOnNext(cx),
"pause",
"active",
L10N.getFormatStr("pauseButtonTooltip", formatKey("resume"))
@ -206,32 +210,37 @@ class CommandBar extends Component<Props> {
}
renderTimeTravelButtons() {
const { isPaused, canRewind } = this.props;
const { cx, canRewind } = this.props;
if (!canRewind || !isPaused) {
if (!canRewind || !cx.isPaused) {
return null;
}
const isDisabled = !isPaused;
const isDisabled = !cx.isPaused;
return [
debugBtn(this.props.rewind, "rewind", "active", "Rewind Execution"),
debugBtn(
() => this.props.rewind(cx),
"rewind",
"active",
"Rewind Execution"
),
debugBtn(
this.props.resume,
() => this.props.resume(cx),
"resume",
"active",
L10N.getFormatStr("resumeButtonTooltip", formatKey("resume"))
),
<div key="divider-1" className="divider" />,
debugBtn(
this.props.reverseStepOver,
() => this.props.reverseStepOver(cx),
"reverseStepOver",
"active",
"Reverse step over"
),
debugBtn(
this.props.stepOver,
() => this.props.stepOver(cx),
"stepOver",
"active",
L10N.getFormatStr("stepOverTooltip", formatKey("stepOver")),
@ -239,7 +248,7 @@ class CommandBar extends Component<Props> {
),
<div key="divider-2" className="divider" />,
debugBtn(
this.props.stepOut,
() => this.props.stepOut(cx),
"stepOut",
"active",
L10N.getFormatStr("stepOutTooltip", formatKey("stepOut")),
@ -247,7 +256,7 @@ class CommandBar extends Component<Props> {
),
debugBtn(
this.props.stepIn,
() => this.props.stepIn(cx),
"stepIn",
"active",
L10N.getFormatStr("stepInTooltip", formatKey("stepIn")),
@ -303,7 +312,7 @@ CommandBar.contextTypes = {
};
const mapStateToProps = state => ({
isPaused: getIsPaused(state, getCurrentThread(state)),
cx: getThreadContext(state),
isWaitingOnBreak: getIsWaitingOnBreak(state, getCurrentThread(state)),
canRewind: getCanRewind(state),
skipPausing: getSkipPausing(state)

View File

@ -13,7 +13,8 @@ import actions from "../../actions";
import {
getExpressions,
getExpressionError,
getAutocompleteMatchset
getAutocompleteMatchset,
getThreadContext
} from "../../selectors";
import { getValue } from "../../utils/expressions";
import { createObjectClient } from "../../client/firefox";
@ -22,7 +23,7 @@ import { CloseButton } from "../shared/Button";
import { debounce } from "lodash";
import type { List } from "immutable";
import type { Expression } from "../../types";
import type { Expression, ThreadContext } from "../../types";
import "./Expressions.css";
@ -36,6 +37,7 @@ type State = {
};
type Props = {
cx: ThreadContext,
expressions: List<Expression>,
expressionError: boolean,
showInput: boolean,
@ -73,10 +75,10 @@ class Expressions extends Component<Props, State> {
}
componentDidMount() {
const { expressions, evaluateExpressions, showInput } = this.props;
const { cx, expressions, evaluateExpressions, showInput } = this.props;
if (expressions.size > 0) {
evaluateExpressions();
evaluateExpressions(cx);
}
// Ensures that the input is focused when the "+"
@ -161,7 +163,7 @@ class Expressions extends Component<Props, State> {
findAutocompleteMatches = debounce((value, selectionStart) => {
const { autocomplete } = this.props;
autocomplete(value, selectionStart);
autocomplete(this.props.cx, value, selectionStart);
}, 250);
handleKeyDown = (e: SyntheticKeyboardEvent<HTMLInputElement>) => {
@ -192,7 +194,11 @@ class Expressions extends Component<Props, State> {
e.preventDefault();
e.stopPropagation();
this.props.updateExpression(this.state.inputValue, expression);
this.props.updateExpression(
this.props.cx,
this.state.inputValue,
expression
);
this.hideInput();
};
@ -202,7 +208,7 @@ class Expressions extends Component<Props, State> {
e.stopPropagation();
this.props.clearExpressionError();
await this.props.addExpression(this.state.inputValue);
await this.props.addExpression(this.props.cx, this.state.inputValue);
this.setState({
editing: false,
editIndex: -1,
@ -377,6 +383,7 @@ class Expressions extends Component<Props, State> {
const mapStateToProps = state => {
return {
cx: getThreadContext(state),
autocompleteMatches: getAutocompleteMatchset(state),
expressions: getExpressions(state),
expressionError: getExpressionError(state)

View File

@ -13,8 +13,9 @@ import { formatDisplayName } from "../../../utils/pause/frames";
import { getFilename, getFileURL } from "../../../utils/source";
import FrameMenu from "./FrameMenu";
import FrameIndent from "./FrameIndent";
import actions from "../../../actions";
import type { Frame } from "../../../types";
import type { Frame, ThreadContext } from "../../../types";
type FrameTitleProps = {
frame: Frame,
@ -61,11 +62,12 @@ function FrameLocation({ frame, displayFullUrl = false }: FrameLocationProps) {
FrameLocation.displayName = "FrameLocation";
type FrameComponentProps = {
cx: ThreadContext,
frame: Frame,
selectedFrame: Frame,
copyStackTrace: Function,
toggleFrameworkGrouping: Function,
selectFrame: Function,
selectFrame: typeof actions.selectFrame,
frameworkGroupingOn: boolean,
hideLocation: boolean,
shouldMapDisplayName: boolean,
@ -107,7 +109,7 @@ export default class FrameComponent extends Component<FrameComponentProps> {
if (e.button !== 0) {
return;
}
this.props.selectFrame(frame);
this.props.selectFrame(this.props.cx, frame);
}
onKeyUp(
@ -118,7 +120,7 @@ export default class FrameComponent extends Component<FrameComponentProps> {
if (event.key != "Enter") {
return;
}
this.props.selectFrame(frame);
this.props.selectFrame(this.props.cx, frame);
}
render() {

View File

@ -15,7 +15,8 @@ import FrameComponent from "./Frame";
import "./Group.css";
import type { Frame } from "../../../types";
import actions from "../../../actions";
import type { Frame, ThreadContext } from "../../../types";
import Badge from "../../shared/Badge";
import FrameIndent from "./FrameIndent";
@ -39,9 +40,10 @@ function FrameLocation({ frame, expanded }: FrameLocationProps) {
FrameLocation.displayName = "FrameLocation";
type Props = {
cx: ThreadContext,
group: Frame[],
selectedFrame: Frame,
selectFrame: Function,
selectFrame: typeof actions.selectFrame,
toggleFrameworkGrouping: Function,
copyStackTrace: Function,
toggleBlackBox: Function,
@ -88,6 +90,7 @@ export default class Group extends Component<Props, State> {
renderFrames() {
const {
cx,
group,
selectFrame,
selectedFrame,
@ -114,6 +117,7 @@ export default class Group extends Component<Props, State> {
}
return acc.concat(
<FrameComponent
cx={cx}
copyStackTrace={copyStackTrace}
frame={frame}
frameworkGroupingOn={frameworkGroupingOn}

View File

@ -8,7 +8,7 @@ import React, { Component } from "react";
import { connect } from "../../../utils/connect";
import PropTypes from "prop-types";
import type { Frame, Why } from "../../../types";
import type { Frame, Why, ThreadContext } from "../../../types";
import FrameComponent from "./Frame";
import Group from "./Group";
@ -24,7 +24,8 @@ import {
getSelectedFrame,
getCallStackFrames,
getPauseReason,
getCurrentThread
getCurrentThread,
getThreadContext
} from "../../../selectors";
import "./Frames.css";
@ -32,11 +33,12 @@ import "./Frames.css";
const NUM_FRAMES_SHOWN = 7;
type Props = {
cx: ThreadContext,
frames: Array<Frame>,
frameworkGroupingOn: boolean,
selectedFrame: Object,
why: Why,
selectFrame: Function,
selectFrame: typeof actions.selectFrame,
toggleBlackBox: Function,
toggleFrameworkGrouping: Function,
disableFrameTruncate: boolean,
@ -114,6 +116,7 @@ class Frames extends Component<Props, State> {
renderFrames(frames: Frame[]) {
const {
cx,
selectFrame,
selectedFrame,
toggleBlackBox,
@ -136,6 +139,7 @@ class Frames extends Component<Props, State> {
(frameOrGroup: FrameOrGroup) =>
frameOrGroup.id ? (
<FrameComponent
cx={cx}
frame={(frameOrGroup: any)}
toggleFrameworkGrouping={this.toggleFrameworkGrouping}
copyStackTrace={this.copyStackTrace}
@ -151,6 +155,7 @@ class Frames extends Component<Props, State> {
/>
) : (
<Group
cx={cx}
group={(frameOrGroup: any)}
toggleFrameworkGrouping={this.toggleFrameworkGrouping}
copyStackTrace={this.copyStackTrace}
@ -216,6 +221,7 @@ class Frames extends Component<Props, State> {
Frames.contextTypes = { l10n: PropTypes.object };
const mapStateToProps = state => ({
cx: getThreadContext(state),
frames: getCallStackFrames(state),
why: getPauseReason(state, getCurrentThread(state)),
frameworkGroupingOn: getFrameworkGroupingState(state),

View File

@ -7,13 +7,18 @@
import React from "react";
import { shallow, mount } from "enzyme";
import Frame from "../Frame.js";
import { makeMockFrame, makeMockSource } from "../../../../utils/test-mockup";
import {
makeMockFrame,
makeMockSource,
mockthreadcx
} from "../../../../utils/test-mockup";
import FrameMenu from "../FrameMenu";
jest.mock("../FrameMenu", () => jest.fn());
function frameProperties(frame, selectedFrame: any, overrides = {}) {
return {
cx: mockthreadcx,
frame,
selectedFrame,
copyStackTrace: jest.fn(),

View File

@ -7,7 +7,11 @@
import React from "react";
import { shallow } from "enzyme";
import Group from "../Group.js";
import { makeMockFrame, makeMockSource } from "../../../../utils/test-mockup";
import {
makeMockFrame,
makeMockSource,
mockthreadcx
} from "../../../../utils/test-mockup";
import FrameMenu from "../FrameMenu";
jest.mock("../FrameMenu", () => jest.fn());
@ -15,6 +19,7 @@ jest.mock("../FrameMenu", () => jest.fn());
function render(overrides = {}) {
const frame = { ...makeMockFrame(), displayName: "foo", library: "Back" };
const defaultProps = {
cx: mockthreadcx,
group: [frame],
selectedFrame: frame,
frameworkGroupingOn: true,

View File

@ -155,6 +155,14 @@ exports[`Group passes the getFrameTitle prop to the Frame components 1`] = `
/>
<Frame
copyStackTrace={[MockFunction]}
cx={
Object {
"isPaused": false,
"navigateCounter": 0,
"pauseCounter": 0,
"thread": "FakeThread",
}
}
disableContextMenu={false}
displayFullUrl={false}
frame={
@ -258,6 +266,14 @@ exports[`Group passes the getFrameTitle prop to the Frame components 1`] = `
/>
<Frame
copyStackTrace={[MockFunction]}
cx={
Object {
"isPaused": false,
"navigateCounter": 0,
"pauseCounter": 0,
"thread": "FakeThread",
}
}
disableContextMenu={false}
displayFullUrl={false}
frame={
@ -361,6 +377,14 @@ exports[`Group passes the getFrameTitle prop to the Frame components 1`] = `
/>
<Frame
copyStackTrace={[MockFunction]}
cx={
Object {
"isPaused": false,
"navigateCounter": 0,
"pauseCounter": 0,
"thread": "FakeThread",
}
}
disableContextMenu={false}
displayFullUrl={false}
frame={
@ -618,6 +642,14 @@ exports[`Group renders group with anonymous functions 2`] = `
/>
<Frame
copyStackTrace={[MockFunction]}
cx={
Object {
"isPaused": false,
"navigateCounter": 0,
"pauseCounter": 0,
"thread": "FakeThread",
}
}
disableContextMenu={false}
displayFullUrl={false}
frame={
@ -720,6 +752,14 @@ exports[`Group renders group with anonymous functions 2`] = `
/>
<Frame
copyStackTrace={[MockFunction]}
cx={
Object {
"isPaused": false,
"navigateCounter": 0,
"pauseCounter": 0,
"thread": "FakeThread",
}
}
disableContextMenu={false}
displayFullUrl={false}
frame={
@ -822,6 +862,14 @@ exports[`Group renders group with anonymous functions 2`] = `
/>
<Frame
copyStackTrace={[MockFunction]}
cx={
Object {
"isPaused": false,
"navigateCounter": 0,
"pauseCounter": 0,
"thread": "FakeThread",
}
}
disableContextMenu={false}
displayFullUrl={false}
frame={

View File

@ -9,13 +9,14 @@ import { connect } from "../../utils/connect";
import classnames from "classnames";
import actions from "../../actions";
import { getCurrentThread, getIsPaused } from "../../selectors";
import { getCurrentThread, getIsPaused, getContext } from "../../selectors";
import { getDisplayName, isWorker } from "../../utils/workers";
import AccessibleImage from "../shared/AccessibleImage";
import type { Thread } from "../../types";
import type { Context, Thread } from "../../types";
type Props = {
cx: Context,
selectThread: typeof actions.selectThread,
isPaused: boolean,
thread: Thread,
@ -25,7 +26,7 @@ type Props = {
export class Worker extends Component<Props> {
onSelectThread = () => {
const { thread } = this.props;
this.props.selectThread(thread.actor);
this.props.selectThread(this.props.cx, thread.actor);
};
render() {
@ -57,6 +58,7 @@ export class Worker extends Component<Props> {
}
const mapStateToProps = (state, props: Props) => ({
cx: getContext(state),
currentThread: getCurrentThread(state),
isPaused: getIsPaused(state, props.thread.actor)
});

View File

@ -21,7 +21,8 @@ import {
getShouldPauseOnExceptions,
getShouldPauseOnCaughtExceptions,
getWorkers,
getCurrentThread
getCurrentThread,
getThreadContext
} from "../../selectors";
import AccessibleImage from "../shared/AccessibleImage";
@ -42,7 +43,7 @@ import Scopes from "./Scopes";
import "./SecondaryPanes.css";
import type { Expression, Frame, WorkerList } from "../../types";
import type { Expression, Frame, WorkerList, ThreadContext } from "../../types";
type AccordionPaneItem = {
header: string,
@ -72,6 +73,7 @@ type State = {
};
type Props = {
cx: ThreadContext,
expressions: List<Expression>,
hasFrames: boolean,
horizontal: boolean,
@ -114,6 +116,7 @@ class SecondaryPanes extends Component<Props, State> {
renderBreakpointsToggle() {
const {
cx,
toggleAllBreakpoints,
breakpoints,
breakpointsDisabled
@ -135,7 +138,7 @@ class SecondaryPanes extends Component<Props, State> {
key: "breakpoints-toggle",
onChange: e => {
e.stopPropagation();
toggleAllBreakpoints(!breakpointsDisabled);
toggleAllBreakpoints(cx, !breakpointsDisabled);
},
onClick: e => e.stopPropagation(),
checked: !breakpointsDisabled && !isIndeterminate,
@ -162,7 +165,7 @@ class SecondaryPanes extends Component<Props, State> {
debugBtn(
evt => {
evt.stopPropagation();
this.props.evaluateExpressions();
this.props.evaluateExpressions(this.props.cx);
},
"refresh",
"refresh",
@ -462,6 +465,7 @@ const mapStateToProps = state => {
const thread = getCurrentThread(state);
return {
cx: getThreadContext(state),
expressions: getExpressions(state),
hasFrames: !!getTopFrame(state, thread),
breakpoints: getBreakpointsList(state),

View File

@ -7,10 +7,12 @@
import React from "react";
import { shallow } from "enzyme";
import CommandBar from "../CommandBar";
import { mockthreadcx } from "../../../utils/test-mockup";
describe("CommandBar", () => {
it("f8 key command calls props.breakOnNext when not in paused state", () => {
const props = {
cx: mockthreadcx,
breakOnNext: jest.fn(),
resume: jest.fn(),
isPaused: false
@ -43,6 +45,7 @@ describe("CommandBar", () => {
it("f8 key command calls props.resume when in paused state", () => {
const props = {
cx: { ...mockthreadcx, isPaused: true },
breakOnNext: jest.fn(),
resume: jest.fn(),
isPaused: true

View File

@ -8,6 +8,7 @@ import React from "react";
import { shallow } from "enzyme";
import Outline from "../../components/PrimaryPanes/Outline";
import { makeSymbolDeclaration } from "../../utils/test-head";
import { mockcx } from "../../utils/test-mockup";
import { showMenu } from "devtools-contextmenu";
import { copyToTheClipboard } from "../../utils/clipboard";
@ -19,6 +20,7 @@ const mockFunctionText = "mock function text";
function generateDefaults(overrides) {
return {
cx: mockcx,
selectLocation: jest.fn(),
selectedSource: { id: sourceId },
getFunctionText: jest.fn().mockReturnValue(mockFunctionText),
@ -70,7 +72,10 @@ describe("Outline", () => {
const { selectLocation } = props;
const listItem = component.find("li").first();
listItem.simulate("click");
expect(selectLocation).toHaveBeenCalledWith({ line: startLine, sourceId });
expect(selectLocation).toHaveBeenCalledWith(mockcx, {
line: startLine,
sourceId
});
});
describe("renders outline", () => {
@ -210,7 +215,7 @@ describe("Outline", () => {
await component.find("h2").simulate("click", {});
expect(props.selectLocation).toHaveBeenCalledWith({
expect(props.selectLocation).toHaveBeenCalledWith(mockcx, {
line: 24,
sourceId: sourceId
});

View File

@ -8,6 +8,7 @@ import React from "react";
import { mount, shallow } from "enzyme";
import { ProjectSearch } from "../ProjectSearch";
import { statusType } from "../../reducers/project-text-search";
import { mockcx } from "../../utils/test-mockup";
const hooks = { on: [], off: [] };
const shortcuts = {
@ -75,6 +76,7 @@ const testMatch = {
function render(overrides = {}, mounted = false) {
const props = {
cx: mockcx,
status: "DONE",
sources: {},
results: [],
@ -187,7 +189,7 @@ describe("ProjectSearch", () => {
component
.find("SearchInput input")
.simulate("keydown", { key: "Enter", stopPropagation: jest.fn() });
expect(searchSources).toHaveBeenCalledWith("foo");
expect(searchSources).toHaveBeenCalledWith(mockcx, "foo");
});
it("onEnterPress shortcut no match or setExpanded", () => {
@ -215,7 +217,7 @@ describe("ProjectSearch", () => {
);
component.instance().state.focusedItem = { ...testMatch };
shortcuts.dispatch("Enter");
expect(selectSpecificLocation).toHaveBeenCalledWith({
expect(selectSpecificLocation).toHaveBeenCalledWith(mockcx, {
sourceId: "some-target/source42",
line: 3,
column: 30

View File

@ -8,6 +8,7 @@
import React from "react";
import { shallow, mount } from "enzyme";
import { QuickOpenModal } from "../QuickOpenModal";
import { mockcx } from "../../utils/test-mockup";
jest.mock("fuzzaldrin-plus");
@ -15,6 +16,7 @@ import { filter } from "fuzzaldrin-plus";
function generateModal(propOverrides, renderType = "shallow") {
const props = {
cx: mockcx,
enabled: false,
query: "",
searchType: "sources",
@ -314,7 +316,7 @@ describe("QuickOpenModal", () => {
key: "Enter"
};
wrapper.find("SearchInput").simulate("keydown", event);
expect(props.selectSpecificLocation).toHaveBeenCalledWith({
expect(props.selectSpecificLocation).toHaveBeenCalledWith(mockcx, {
column: 12,
line: 34,
sourceId: ""
@ -336,7 +338,7 @@ describe("QuickOpenModal", () => {
key: "Enter"
};
wrapper.find("SearchInput").simulate("keydown", event);
expect(props.selectSpecificLocation).toHaveBeenCalledWith({
expect(props.selectSpecificLocation).toHaveBeenCalledWith(mockcx, {
column: 12,
line: 34,
sourceId: sourceId
@ -447,7 +449,7 @@ describe("QuickOpenModal", () => {
key: "Enter"
};
wrapper.find("SearchInput").simulate("keydown", event);
expect(props.selectSpecificLocation).toHaveBeenCalledWith({
expect(props.selectSpecificLocation).toHaveBeenCalledWith(mockcx, {
column: undefined,
sourceId: id,
line: 0
@ -477,7 +479,7 @@ describe("QuickOpenModal", () => {
key: "Enter"
};
wrapper.find("SearchInput").simulate("keydown", event);
expect(props.selectSpecificLocation).toHaveBeenCalledWith({
expect(props.selectSpecificLocation).toHaveBeenCalledWith(mockcx, {
column: undefined,
line: 0,
sourceId: ""
@ -507,7 +509,7 @@ describe("QuickOpenModal", () => {
key: "Enter"
};
wrapper.find("SearchInput").simulate("keydown", event);
expect(props.selectSpecificLocation).toHaveBeenCalledWith({
expect(props.selectSpecificLocation).toHaveBeenCalledWith(mockcx, {
column: 4,
line: 3,
sourceId: id

View File

@ -44,6 +44,11 @@ exports[`ProjectSearch found search results 1`] = `
activeSearch="project"
clearSearch={[MockFunction]}
closeProjectSearch={[MockFunction]}
cx={
Object {
"navigateCounter": 0,
}
}
doSearchForHighlight={[MockFunction]}
query="match"
results={

Some files were not shown because too many files have changed in this diff Show More