Merge inbound to mozilla-central a=merge

This commit is contained in:
Coroiu Cristina 2018-12-21 23:55:45 +02:00
commit bbc7fc4e7c
183 changed files with 1854 additions and 811 deletions

View File

@ -558,8 +558,8 @@ class SearchOneOffs {
// Make the top-level menu button.
let button = document.createXULElement("toolbarbutton");
list.appendChild(button);
button.classList.add("addengine-item", "badged-button");
button.setAttribute("class", "addengine-menu-button");
button.classList.add("addengine-menu-button", "addengine-item",
"badged-button");
button.setAttribute("type", "menu");
button.setAttribute("label",
this.bundle.GetStringFromName("cmd_addFoundEngineMenu"));

View File

@ -1,9 +1,9 @@
This is the debugger.html project output.
See https://github.com/devtools-html/debugger.html
Version 110
Version 111
Comparison: https://github.com/devtools-html/debugger.html/compare/release-109...release-110
Comparison: https://github.com/devtools-html/debugger.html/compare/release-110...release-111
Packages:
- babel-plugin-transform-es2015-modules-commonjs @6.26.2

View File

@ -1787,8 +1787,8 @@ html .toggle-button.end.vertical svg {
margin-right: 5px;
}
.sources-list .tree .focused img:not(.vue):not(.angular),
.sources-list .managed-tree .tree .node.focused img.blackBox {
.sources-list .tree .focused .img:not(.vue):not(.angular),
.sources-list .managed-tree .tree .node.focused .img.blackBox {
background: #ffffff;
}
@ -1919,10 +1919,6 @@ html .toggle-button.end.vertical svg {
margin-top: 2px;
}
.theme-dark .sources-list .managed-tree .tree .node:not(.focused) .img.blackBox {
background-color: var(--theme-comment);
}
.theme-dark .sources-list .managed-tree .tree .node .img.blackBox {
background-color: var(--theme-body-color);
}
@ -3700,6 +3696,10 @@ html[dir="rtl"] .breakpoints-list .breakpoint .breakpoint-line {
.worker-list .worker:hover {
background-color: var(--search-overlays-semitransparent);
}
.worker-list .worker.selected {
background-color: var(--tab-line-selected-color);
}
/* 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/>. */

View File

@ -1015,6 +1015,9 @@ exports.getMemberExpression = getMemberExpression;
exports.getVariables = getVariables;
exports.getPatternIdentifiers = getPatternIdentifiers;
exports.isTopLevel = isTopLevel;
exports.nodeHasSameLocation = nodeHasSameLocation;
exports.sameLocation = sameLocation;
exports.getFunctionParameterNames = getFunctionParameterNames;
var _types = __webpack_require__(2268);
@ -1057,7 +1060,7 @@ function getObjectExpressionValue(node) {
return value.name;
}
if (t.isCallExpression(value)) {
if (t.isCallExpression(value) || t.isFunctionExpression(value)) {
return "";
}
const code = (0, _generator2.default)(value).code;
@ -1178,6 +1181,38 @@ function isTopLevel(ancestors) {
return ancestors.filter(ancestor => ancestor.key == "body").length == 1;
}
function nodeHasSameLocation(a, b) {
return sameLocation(a.location, b.location);
}
function sameLocation(a, b) {
return a.start.line == b.start.line && a.start.column == b.start.column && a.end.line == b.end.line && a.end.column == b.end.column;
}
function getFunctionParameterNames(path) {
if (path.node.params != null) {
return path.node.params.map(param => {
if (param.type !== "AssignmentPattern") {
return param.name;
}
// Parameter with default value
if (param.left.type === "Identifier" && param.right.type === "Identifier") {
return `${param.left.name} = ${param.right.name}`;
} else if (param.left.type === "Identifier" && param.right.type === "StringLiteral") {
return `${param.left.name} = ${param.right.value}`;
} else if (param.left.type === "Identifier" && param.right.type === "ObjectExpression") {
return `${param.left.name} = {}`;
} else if (param.left.type === "Identifier" && param.right.type === "ArrayExpression") {
return `${param.left.name} = []`;
} else if (param.left.type === "Identifier" && param.right.type === "NullLiteral") {
return `${param.left.name} = null`;
}
});
}
return [];
}
/***/ }),
/***/ 1455:
@ -1313,28 +1348,15 @@ function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj;
let symbolDeclarations = new Map();
function getFunctionParameterNames(path) {
if (path.node.params != null) {
return path.node.params.map(param => {
if (param.type !== "AssignmentPattern") {
return param.name;
}
// Parameter with default value
if (param.left.type === "Identifier" && param.right.type === "Identifier") {
return `${param.left.name} = ${param.right.name}`;
} else if (param.left.type === "Identifier" && param.right.type === "StringLiteral") {
return `${param.left.name} = ${param.right.value}`;
} else if (param.left.type === "Identifier" && param.right.type === "ObjectExpression") {
return `${param.left.name} = {}`;
} else if (param.left.type === "Identifier" && param.right.type === "ArrayExpression") {
return `${param.left.name} = []`;
} else if (param.left.type === "Identifier" && param.right.type === "NullLiteral") {
return `${param.left.name} = null`;
}
});
function getUniqueIdentifiers(identifiers) {
const newIdentifiers = [];
for (const newId of identifiers) {
if (!newIdentifiers.find(id => (0, _helpers.nodeHasSameLocation)(id, newId))) {
newIdentifiers.push(newId);
}
}
return [];
return newIdentifiers;
}
/* eslint-disable complexity */
@ -1345,7 +1367,7 @@ function extractSymbol(path, symbols) {
name,
klass: (0, _inferClassName.inferClassName)(path),
location: path.node.loc,
parameterNames: getFunctionParameterNames(path),
parameterNames: (0, _helpers.getFunctionParameterNames)(path),
identifier: path.node.id,
// indicates the occurence of the function in a file
// e.g { name: foo, ... index: 4 } is the 4th foo function
@ -1442,7 +1464,7 @@ function extractSymbol(path, symbols) {
});
}
if (t.isIdentifier(path) && !t.isGenericTypeAnnotation(path.parent) && !t.isObjectProperty(path.parent) && !t.isArrayPattern(path.parent)) {
if (t.isIdentifier(path) && !t.isGenericTypeAnnotation(path.parent)) {
let { start, end } = path.node.loc;
// We want to include function params, but exclude the function name
@ -1520,6 +1542,7 @@ function extractSymbols(sourceId) {
// comments are extracted separately from the AST
symbols.comments = (0, _helpers.getComments)(ast);
symbols.identifiers = getUniqueIdentifiers(symbols.identifiers);
return symbols;
}
@ -23060,6 +23083,13 @@ function mapOriginalExpression(expression, mappings) {
return;
}
const ancestor = ancestors[ancestors.length - 1];
// Shorthand properties can have a key and value with `node.loc.start` value
// and we only want to replace the value.
if (t.isObjectProperty(ancestor.node) && ancestor.key !== "value") {
return;
}
const replacement = replacements.get(locationKey(node.loc.start));
if (replacement) {
replaceNode(ancestors, t.cloneNode(replacement));

View File

@ -12,7 +12,7 @@ import {
isPaused
} from "../selectors";
import { mapFrames, fetchExtra } from "./pause";
import { mapFrames } from "./pause";
import { updateTab } from "./tabs";
import { PROMISE } from "./utils/middleware/promise";
@ -67,7 +67,6 @@ export function setSymbols(sourceId: SourceId) {
});
if (isPaused(getState())) {
await dispatch(fetchExtra());
await dispatch(mapFrames());
}

View File

@ -7,7 +7,7 @@
import { getSourceFromId } from "../../selectors";
import * as parser from "../../workers/parser";
import { isGenerated } from "../../utils/source";
import { mapPausePoints } from "../../utils/pause/pausePoints";
import { convertToList } from "../../utils/pause/pausePoints";
import { features } from "../../utils/prefs";
import { getGeneratedLocation } from "../../utils/source-maps";
@ -28,20 +28,24 @@ function compressPausePoints(pausePoints) {
}
async function mapLocations(pausePoints, state, source, sourceMaps) {
const pausePointList = convertToList(pausePoints);
const sourceId = source.id;
return mapPausePoints(pausePoints, async ({ types, location }) => {
const generatedLocation = await getGeneratedLocation(
state,
source,
{
...location,
sourceId
},
sourceMaps
);
return { types, location, generatedLocation };
});
return Promise.all(
pausePointList.map(async ({ types, location }) => {
const generatedLocation = await getGeneratedLocation(
state,
source,
{
...location,
sourceId
},
sourceMaps
);
return { types, location, generatedLocation };
})
);
}
export function setPausePoints(sourceId: SourceId) {
return async ({ dispatch, getState, client, sourceMaps }: ThunkArgs) => {
@ -56,6 +60,11 @@ export function setPausePoints(sourceId: SourceId) {
let pausePoints = await parser.getPausePoints(sourceId);
if (isGenerated(source)) {
const compressed = compressPausePoints(pausePoints);
await client.setPausePoints(sourceId, compressed);
}
pausePoints = await mapLocations(
pausePoints,
getState(),
@ -63,11 +72,6 @@ export function setPausePoints(sourceId: SourceId) {
sourceMaps
);
if (isGenerated(source)) {
const compressed = compressPausePoints(pausePoints);
await client.setPausePoints(sourceId, compressed);
}
dispatch(
({
type: "SET_PAUSE_POINTS",

View File

@ -17,7 +17,8 @@ import {
getXHRBreakpoints,
getSelectedSource,
getBreakpointAtLocation,
getBreakpointsAtLine
getBreakpointsAtLine,
getBreakpointsForSource
} from "../../selectors";
import { assertBreakpoint, createXHRBreakpoint } from "../../utils/breakpoint";
import {
@ -32,7 +33,12 @@ import { isEmptyLineInSource } from "../../reducers/ast";
// this will need to be changed so that addCLientBreakpoint is removed
import type { ThunkArgs, Action } from "../types";
import type { Breakpoint, SourceLocation, XHRBreakpoint } from "../../types";
import type {
Breakpoint,
Source,
SourceLocation,
XHRBreakpoint
} from "../../types";
import { recordEvent } from "../../utils/telemetry";
@ -104,6 +110,40 @@ export function disableBreakpoint(location: SourceLocation) {
};
}
/**
* Disable all breakpoints in a source
*
* @memberof actions/breakpoints
* @static
*/
export function disableBreakpointsInSource(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.generatedLocation));
}
}
};
}
/**
* Enable all breakpoints in a source
*
* @memberof actions/breakpoints
* @static
*/
export function enableBreakpointsInSource(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.generatedLocation));
}
}
};
}
/**
* Toggle All Breakpoints
*
@ -196,6 +236,21 @@ export function removeBreakpoints(breakpoints: Breakpoint[]) {
};
}
/**
* Removes all breakpoints in a source
*
* @memberof actions/breakpoints
* @static
*/
export function removeBreakpointsInSource(source: Source) {
return async ({ dispatch, getState, client }: ThunkArgs) => {
const breakpoints = getBreakpointsForSource(getState(), source.id);
for (const breakpoint of breakpoints) {
dispatch(removeBreakpoint(breakpoint.generatedLocation));
}
};
}
export function remapBreakpoints(sourceId: string) {
return async ({ dispatch, getState, sourceMaps }: ThunkArgs) => {
const breakpoints = getBreakpointsList(getState());

View File

@ -5,6 +5,7 @@
// @flow
import {
getCurrentThread,
getExpression,
getExpressions,
getSelectedFrame,
@ -117,7 +118,11 @@ export function evaluateExpressions() {
const expressions = getExpressions(getState()).toJS();
const inputs = expressions.map(({ input }) => input);
const frameId = getSelectedFrameId(getState());
const results = await client.evaluateExpressions(inputs, frameId);
const thread = getCurrentThread(getState());
const results = await client.evaluateExpressions(inputs, {
frameId,
thread
});
dispatch({ type: "EVALUATE_EXPRESSIONS", inputs, results });
};
}
@ -147,11 +152,16 @@ function evaluateExpression(expression: Expression) {
}
const frameId = getSelectedFrameId(getState());
const thread = getCurrentThread(getState());
return dispatch({
type: "EVALUATE_EXPRESSION",
thread,
input: expression.input,
[PROMISE]: client.evaluateInFrame(wrapExpression(input), frameId)
[PROMISE]: client.evaluateInFrame(wrapExpression(input), {
frameId,
thread
})
});
};
}

View File

@ -54,10 +54,10 @@ export function navigate(url: string): Action {
};
}
export function connect(url: string, canRewind: boolean) {
export function connect(url: string, thread: string, canRewind: boolean) {
return async function({ dispatch }: ThunkArgs) {
await dispatch(updateWorkers());
dispatch(({ type: "CONNECT", url, canRewind }: Action));
dispatch(({ type: "CONNECT", url, thread, canRewind }: Action));
};
}

View File

@ -5,6 +5,7 @@
// @flow
import type { ThunkArgs } from "../types";
import { getCurrentThread } from "../../selectors";
/**
* Debugger breakOnNext command.
@ -15,8 +16,9 @@ import type { ThunkArgs } from "../types";
* @static
*/
export function breakOnNext() {
return async ({ dispatch, client }: ThunkArgs) => {
await client.breakOnNext();
return dispatch({ type: "BREAK_ON_NEXT" });
return async ({ dispatch, getState, client }: ThunkArgs) => {
const thread = getCurrentThread(getState());
await client.breakOnNext(thread);
return dispatch({ type: "BREAK_ON_NEXT", thread });
};
}

View File

@ -5,7 +5,12 @@
// @flow
import { isPaused, getSource, getTopFrame } from "../../selectors";
import {
isPaused,
getCurrentThread,
getSource,
getTopFrame
} from "../../selectors";
import { PROMISE } from "../utils/middleware/promise";
import { getNextStep } from "../../workers/parser";
import { addHiddenBreakpoint } from "../breakpoints";
@ -16,6 +21,15 @@ import type { Source } from "../../types";
import type { ThunkArgs } from "../types";
import type { Command } from "../../reducers/types";
export function selectThread(thread: string) {
return async ({ dispatch, client }: ThunkArgs) => {
return dispatch({
type: "SELECT_THREAD",
thread
});
};
}
/**
* Debugger commands like stepOver, stepIn, stepUp
*
@ -24,11 +38,13 @@ import type { Command } from "../../reducers/types";
* @static
*/
export function command(type: Command) {
return async ({ dispatch, client }: ThunkArgs) => {
return async ({ dispatch, getState, client }: ThunkArgs) => {
const thread = getCurrentThread(getState());
return dispatch({
type: "COMMAND",
command: type,
[PROMISE]: client[type]()
thread,
[PROMISE]: client[type](thread)
});
};
}

View File

@ -4,7 +4,12 @@
// @flow
import { inComponent, getSelectedFrame } from "../../selectors";
import {
getCurrentThread,
getSource,
inComponent,
getSelectedFrame
} from "../../selectors";
import { isImmutablePreview } from "../../utils/preview";
import type { ThunkArgs } from "../types";
@ -77,6 +82,7 @@ export function fetchExtra() {
const extra = await dispatch(getExtra("this;", frame.this));
dispatch({
type: "ADD_EXTRA",
thread: getCurrentThread(getState()),
extra: extra
});
};
@ -89,8 +95,16 @@ export function getExtra(expression: string, result: Object) {
return {};
}
const source = getSource(getState(), selectedFrame.location.sourceId);
if (!source) {
return {};
}
const extra = await getExtraProps(getState, expression, result, expr =>
client.evaluateInFrame(expr, selectedFrame.id)
client.evaluateInFrame(expr, {
frameId: selectedFrame.id,
thread: source.thread
})
);
return extra;

View File

@ -4,10 +4,13 @@
// @flow
import { getSelectedFrame, getGeneratedFrameScope } from "../../selectors";
import {
getCurrentThread,
getSelectedFrame,
getGeneratedFrameScope
} from "../../selectors";
import { mapScopes } from "./mapScopes";
import { PROMISE } from "../utils/middleware/promise";
import { fetchExtra } from "./extra";
import type { ThunkArgs } from "../types";
export function fetchScopes() {
@ -19,11 +22,11 @@ export function fetchScopes() {
const scopes = dispatch({
type: "ADD_SCOPES",
thread: getCurrentThread(getState()),
frame,
[PROMISE]: client.getFrameScopes(frame)
});
await dispatch(fetchExtra());
await dispatch(mapScopes(scopes, frame));
};
}

View File

@ -10,6 +10,7 @@
*/
export {
selectThread,
stepIn,
stepOver,
stepOut,
@ -25,7 +26,6 @@ export { resumed } from "./resumed";
export { continueToHere } from "./continueToHere";
export { breakOnNext } from "./breakOnNext";
export { mapFrames } from "./mapFrames";
export { fetchExtra, getExtra } from "./extra";
export { setPopupObjectProperties } from "./setPopupObjectProperties";
export { pauseOnExceptions } from "./pauseOnExceptions";
export { selectFrame } from "./selectFrame";

View File

@ -5,6 +5,7 @@
// @flow
import {
getCurrentThread,
getFrames,
getSymbols,
getSource,
@ -170,9 +171,11 @@ export function mapFrames() {
mappedFrames = await expandFrames(mappedFrames, sourceMaps, getState);
mappedFrames = mapDisplayNames(mappedFrames, getState);
const thread = getCurrentThread(getState());
const selectedFrameId = getSelectedFrameId(getState(), mappedFrames);
dispatch({
type: "MAP_FRAMES",
thread,
frames: mappedFrames,
selectedFrameId
});

View File

@ -4,7 +4,7 @@
// @flow
import { getSource } from "../../selectors";
import { getCurrentThread, getSource } from "../../selectors";
import { loadSourceText } from "../sources/loadSourceText";
import { PROMISE } from "../utils/middleware/promise";
@ -28,6 +28,7 @@ export function mapScopes(scopes: Promise<Scope>, frame: Frame) {
await dispatch({
type: "MAP_SCOPES",
thread: getCurrentThread(getState()),
frame,
[PROMISE]: (async function() {
if (

View File

@ -11,7 +11,6 @@ DebuggerModules(
'breakOnNext.js',
'commands.js',
'continueToHere.js',
'extra.js',
'fetchScopes.js',
'index.js',
'mapFrames.js',

View File

@ -7,6 +7,7 @@
import { PROMISE } from "../utils/middleware/promise";
import { recordEvent } from "../../utils/telemetry";
import type { ThunkArgs } from "../types";
import { getCurrentThread } from "../../selectors";
/**
*
@ -17,7 +18,7 @@ export function pauseOnExceptions(
shouldPauseOnExceptions: boolean,
shouldPauseOnCaughtExceptions: boolean
) {
return ({ dispatch, client }: ThunkArgs) => {
return ({ dispatch, getState, client }: ThunkArgs) => {
/* eslint-disable camelcase */
recordEvent("pause_on_exceptions", {
exceptions: shouldPauseOnExceptions,
@ -26,11 +27,14 @@ export function pauseOnExceptions(
});
/* eslint-enable camelcase */
const thread = getCurrentThread(getState());
return dispatch({
type: "PAUSE_ON_EXCEPTIONS",
thread,
shouldPauseOnExceptions,
shouldPauseOnCaughtExceptions,
[PROMISE]: client.pauseOnExceptions(
thread,
shouldPauseOnExceptions,
shouldPauseOnCaughtExceptions
)

View File

@ -38,7 +38,7 @@ async function getOriginalSourceForFrame(state, frame: Frame) {
*/
export function paused(pauseInfo: Pause) {
return async function({ dispatch, getState, client, sourceMaps }: ThunkArgs) {
const { frames, why, loadedObjects } = pauseInfo;
const { thread, frames, why, loadedObjects } = pauseInfo;
const topFrame = frames.length > 0 ? frames[0] : null;
// NOTE: do not step when leaving a frame or paused at a debugger statement
@ -57,6 +57,7 @@ export function paused(pauseInfo: Pause) {
dispatch({
type: "PAUSED",
thread,
why,
frames,
selectedFrameId: topFrame ? topFrame.id : undefined,

View File

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

View File

@ -7,6 +7,7 @@
import { selectLocation } from "../sources";
import { evaluateExpressions } from "../expressions";
import { fetchScopes } from "./fetchScopes";
import { getCurrentThread } from "../../selectors";
import type { Frame } from "../../types";
import type { ThunkArgs } from "../types";
@ -19,6 +20,7 @@ export function selectFrame(frame: Frame) {
return async ({ dispatch, client, getState, sourceMaps }: ThunkArgs) => {
dispatch({
type: "SELECT_FRAME",
thread: getCurrentThread(getState()),
frame
});

View File

@ -4,7 +4,7 @@
// @flow
import { getPopupObjectProperties } from "../../selectors";
import { getCurrentThread, getPopupObjectProperties } from "../../selectors";
import type { ThunkArgs } from "../types";
/**
@ -19,8 +19,10 @@ export function setPopupObjectProperties(object: any, properties: Object) {
return;
}
const thread = getCurrentThread(getState());
dispatch({
type: "SET_POPUP_OBJECT_PROPERTIES",
thread,
objectId,
properties
});

View File

@ -5,7 +5,7 @@
// @flow
import type { ThunkArgs } from "../types";
import { getSkipPausing } from "../../selectors";
import { getSkipPausing, getCurrentThread } from "../../selectors";
/**
* @memberof actions/pause
@ -13,8 +13,9 @@ import { getSkipPausing } from "../../selectors";
*/
export function toggleSkipPausing() {
return async ({ dispatch, client, getState, sourceMaps }: ThunkArgs) => {
const thread = getCurrentThread(getState());
const skipPausing = !getSkipPausing(getState());
await client.setSkipPausing(skipPausing);
dispatch({ type: "TOGGLE_SKIP_PAUSING", skipPausing });
await client.setSkipPausing(thread, skipPausing);
dispatch({ type: "TOGGLE_SKIP_PAUSING", thread, skipPausing });
};
}

View File

@ -19,7 +19,6 @@ import {
} from "../selectors";
import { getMappedExpression } from "./expressions";
import { getExtra } from "./pause";
import type { Action, ThunkArgs } from "./types";
import type { Position } from "../types";
@ -100,24 +99,21 @@ export function setPreview(
return;
}
const { result } = await client.evaluateInFrame(
expression,
selectedFrame.id
);
const { result } = await client.evaluateInFrame(expression, {
frameId: selectedFrame.id,
thread: source.thread
});
if (result === undefined) {
return;
}
const extra = await dispatch(getExtra(expression, result));
return {
expression,
result,
location,
tokenPos,
cursorPos,
extra
cursorPos
};
})()
});

View File

@ -40,6 +40,7 @@ function createOriginalSource(
url: originalUrl,
relativeUrl: originalUrl,
id: generatedToOriginalId(generatedSource.id, originalUrl),
thread: "",
isPrettyPrinted: false,
isWasm: false,
isBlackBoxed: false,

View File

@ -37,6 +37,7 @@ export function createPrettySource(sourceId: string) {
url,
relativeUrl: url,
id,
thread: "",
isBlackBoxed: false,
isPrettyPrinted: true,
isWasm: false,

View File

@ -42,6 +42,7 @@ export const setSelectedLocation = (
location: SourceLocation
) => ({
type: "SET_SELECTED_LOCATION",
thread: source.thread,
source,
location
});

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 { setupCommands, clientCommands } from "./chrome/commands";
import { setupEvents, clientEvents, pageEvents } from "./chrome/events";
export async function onConnect(connection: any, actions: Object): Object {
const {
tabConnection,
connTarget: { type }
} = connection;
const { Debugger, Runtime, Page } = tabConnection;
Debugger.enable();
Debugger.setPauseOnExceptions({ state: "none" });
Debugger.setAsyncCallStackDepth({ maxDepth: 0 });
if (type == "chrome") {
Page.frameNavigated(pageEvents.frameNavigated);
Page.frameStartedLoading(pageEvents.frameStartedLoading);
Page.frameStoppedLoading(pageEvents.frameStoppedLoading);
}
Debugger.scriptParsed(clientEvents.scriptParsed);
Debugger.scriptFailedToParse(clientEvents.scriptFailedToParse);
Debugger.paused(clientEvents.paused);
Debugger.resumed(clientEvents.resumed);
setupCommands({ Debugger, Runtime, Page });
setupEvents({ actions, Page, type, Runtime });
return {};
}
export { clientCommands, clientEvents };

View File

@ -0,0 +1,144 @@
/* 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 {
toServerLocation,
fromServerLocation,
createLoadedObject
} from "./create";
import type { SourceLocation } from "../../types";
import type { ServerLocation, Agents } from "./types";
type setBreakpointResponseType = {
breakpointId: string,
serverLocation?: ServerLocation
};
let debuggerAgent;
let runtimeAgent;
let pageAgent;
function setupCommands({ Debugger, Runtime, Page }: Agents) {
debuggerAgent = Debugger;
runtimeAgent = Runtime;
pageAgent = Page;
}
function resume() {
return debuggerAgent.resume();
}
function stepIn() {
return debuggerAgent.stepInto();
}
function stepOver() {
return debuggerAgent.stepOver();
}
function stepOut() {
return debuggerAgent.stepOut();
}
function pauseOnExceptions(
shouldPauseOnExceptions: boolean,
shouldIgnoreCaughtExceptions: boolean
) {
if (!shouldPauseOnExceptions) {
return debuggerAgent.setPauseOnExceptions({ state: "none" });
}
const state = shouldIgnoreCaughtExceptions ? "uncaught" : "all";
return debuggerAgent.setPauseOnExceptions({ state });
}
function breakOnNext() {
return debuggerAgent.pause();
}
function sourceContents(sourceId: string) {
return debuggerAgent
.getScriptSource({ scriptId: sourceId })
.then(({ scriptSource }) => ({
source: scriptSource,
contentType: null
}));
}
async function setBreakpoint(location: SourceLocation, condition: string) {
const {
breakpointId,
serverLocation
}: setBreakpointResponseType = await debuggerAgent.setBreakpoint({
location: toServerLocation(location),
columnNumber: location.column
});
const actualLocation = fromServerLocation(serverLocation) || location;
return {
id: breakpointId,
actualLocation: actualLocation
};
}
function removeBreakpoint(breakpointId: string) {
return debuggerAgent.removeBreakpoint({ breakpointId });
}
async function getProperties(object: any) {
const { result } = await runtimeAgent.getProperties({
objectId: object.objectId
});
const loadedObjects = result.map(createLoadedObject);
return { loadedObjects };
}
function evaluate(script: string) {
return runtimeAgent.evaluate({ expression: script });
}
function debuggeeCommand(script: string): Promise<void> {
evaluate(script);
return Promise.resolve();
}
function navigate(url: string) {
return pageAgent.navigate({ url });
}
function getBreakpointByLocation(location: SourceLocation) {}
function setPausePoints() {}
function getFrameScopes() {}
function evaluateInFrame() {}
function evaluateExpressions() {}
const clientCommands = {
resume,
stepIn,
stepOut,
stepOver,
pauseOnExceptions,
breakOnNext,
sourceContents,
setBreakpoint,
removeBreakpoint,
evaluate,
debuggeeCommand,
navigate,
getProperties,
getBreakpointByLocation,
setPausePoints,
getFrameScopes,
evaluateInFrame,
evaluateExpressions
};
export { setupCommands, clientCommands };

View File

@ -0,0 +1,52 @@
/* 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 type { SourceLocation, LoadedObject } from "../../types";
import type { ServerLocation } from "./types";
export function fromServerLocation(
serverLocation?: ServerLocation
): ?SourceLocation {
if (serverLocation) {
return {
sourceId: serverLocation.scriptId,
line: serverLocation.lineNumber + 1,
column: serverLocation.columnNumber,
sourceUrl: ""
};
}
}
export function toServerLocation(location: SourceLocation): ServerLocation {
return {
scriptId: location.sourceId,
lineNumber: location.line - 1
};
}
export function createFrame(frame: any) {
return {
id: frame.callFrameId,
displayName: frame.functionName,
scopeChain: frame.scopeChain,
generatedLocation: frame.location,
location: fromServerLocation(frame.location)
};
}
export function createLoadedObject(
serverObject: any,
parentId: string
): LoadedObject {
const { value, name } = serverObject;
return {
objectId: value.objectId,
parentId,
name,
value
};
}

View File

@ -0,0 +1,122 @@
/* 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 { createFrame, createLoadedObject } from "./create";
let actions;
let pageAgent;
let clientType;
let runtimeAgent;
function setupEvents(dependencies: any) {
actions = dependencies.actions;
pageAgent = dependencies.Page;
clientType = dependencies.clientType;
runtimeAgent = dependencies.Runtime;
}
// Debugger Events
function scriptParsed({
scriptId,
url,
startLine,
startColumn,
endLine,
endColumn,
executionContextId,
hash,
isContentScript,
isInternalScript,
isLiveEdit,
sourceMapURL,
hasSourceURL,
deprecatedCommentWasUsed
}: any) {
if (isContentScript) {
return;
}
if (clientType == "node") {
sourceMapURL = undefined;
}
actions.newSource({
id: scriptId,
url,
sourceMapURL,
isPrettyPrinted: false
});
}
function scriptFailedToParse() {}
async function paused({
callFrames,
reason,
data,
hitBreakpoints,
asyncStackTrace
}: any) {
const frames = callFrames.map(createFrame);
const frame = frames[0];
const why = { type: reason, ...data };
const objectId = frame.scopeChain[0].object.objectId;
const { result } = await runtimeAgent.getProperties({
objectId
});
const loadedObjects = result.map(createLoadedObject);
if (clientType == "chrome") {
pageAgent.configureOverlay({ message: "Paused in debugger.html" });
}
await actions.paused({ frame, why, frames, loadedObjects });
}
function resumed() {
if (clientType == "chrome") {
pageAgent.configureOverlay({ suspended: false });
}
actions.resumed();
}
function globalObjectCleared() {}
// Page Events
function frameNavigated(frame: any) {
actions.navigated();
}
function frameStartedLoading() {
actions.willNavigate();
}
function domContentEventFired() {}
function loadEventFired() {}
function frameStoppedLoading() {}
const clientEvents = {
scriptParsed,
scriptFailedToParse,
paused,
resumed,
globalObjectCleared
};
const pageEvents = {
frameNavigated,
frameStartedLoading,
domContentEventFired,
loadEventFired,
frameStoppedLoading
};
export { setupEvents, pageEvents, clientEvents };

View File

@ -0,0 +1,14 @@
# vim: set filetype=python:
# 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/.
DIRS += [
]
DebuggerModules(
'commands.js',
'create.js',
'events.js',
)

View File

@ -58,6 +58,7 @@ export async function onConnect(connection: any, actions: Object): Object {
const traits = tabTarget.activeTab ? tabTarget.activeTab.traits : null;
await actions.connect(
tabTarget.url,
threadClient.actor,
traits && traits.canRewind
);
await actions.newSources(sources);
@ -66,7 +67,7 @@ export async function onConnect(connection: any, actions: Object): Object {
// paused state.
const pausedPacket = threadClient.getLastPausePacket();
if (pausedPacket) {
clientEvents.paused("paused", pausedPacket);
clientEvents.paused(threadClient, "paused", pausedPacket);
}
return { bpClients };

View File

@ -25,15 +25,19 @@ import type {
BPClients
} from "./types";
import type { PausePoints } from "../../workers/parser";
import type { PausePointsMap } from "../../workers/parser";
import { makePendingLocationId } from "../../utils/breakpoint";
import { createSource, createBreakpointLocation } from "./create";
import { createSource, createBreakpointLocation, createWorker } from "./create";
import { originalToGeneratedId, isOriginalId } from "devtools-source-map";
import { supportsWorkers, updateWorkerClients } from "./workers";
import Services from "devtools-services";
import { features } from "../../utils/prefs";
let bpClients: BPClients;
let workerClients: Object;
let sourceThreads: Object;
let threadClient: ThreadClient;
let tabTarget: TabTarget;
let debuggerClient: DebuggerClient;
@ -52,6 +56,8 @@ function setupCommands(dependencies: Dependencies): { bpClients: BPClients } {
debuggerClient = dependencies.debuggerClient;
supportsWasm = dependencies.supportsWasm;
bpClients = {};
workerClients = {};
sourceThreads = {};
return { bpClients };
}
@ -72,60 +78,78 @@ function sendPacket(packet: Object, callback?: Function = r => r) {
return debuggerClient.request(packet).then(callback);
}
function resume(): Promise<*> {
function lookupThreadClient(thread: string) {
if (thread == threadClient.actor) {
return threadClient;
}
if (!workerClients[thread]) {
throw new Error(`Unknown thread client: ${thread}`);
}
return workerClients[thread].thread;
}
function lookupConsoleClient(thread: string) {
if (thread == threadClient.actor) {
return tabTarget.activeConsole;
}
return workerClients[thread].console;
}
function resume(thread: string): Promise<*> {
return new Promise(resolve => {
threadClient.resume(resolve);
lookupThreadClient(thread).resume(resolve);
});
}
function stepIn(): Promise<*> {
function stepIn(thread: string): Promise<*> {
return new Promise(resolve => {
threadClient.stepIn(resolve);
lookupThreadClient(thread).stepIn(resolve);
});
}
function stepOver(): Promise<*> {
function stepOver(thread: string): Promise<*> {
return new Promise(resolve => {
threadClient.stepOver(resolve);
lookupThreadClient(thread).stepOver(resolve);
});
}
function stepOut(): Promise<*> {
function stepOut(thread: string): Promise<*> {
return new Promise(resolve => {
threadClient.stepOut(resolve);
lookupThreadClient(thread).stepOut(resolve);
});
}
function rewind(): Promise<*> {
function rewind(thread: string): Promise<*> {
return new Promise(resolve => {
threadClient.rewind(resolve);
lookupThreadClient(thread).rewind(resolve);
});
}
function reverseStepIn(): Promise<*> {
function reverseStepIn(thread: string): Promise<*> {
return new Promise(resolve => {
threadClient.reverseStepIn(resolve);
lookupThreadClient(thread).reverseStepIn(resolve);
});
}
function reverseStepOver(): Promise<*> {
function reverseStepOver(thread: string): Promise<*> {
return new Promise(resolve => {
threadClient.reverseStepOver(resolve);
lookupThreadClient(thread).reverseStepOver(resolve);
});
}
function reverseStepOut(): Promise<*> {
function reverseStepOut(thread: string): Promise<*> {
return new Promise(resolve => {
threadClient.reverseStepOut(resolve);
lookupThreadClient(thread).reverseStepOut(resolve);
});
}
function breakOnNext(): Promise<*> {
return threadClient.breakOnNext();
function breakOnNext(thread: string): Promise<*> {
return lookupThreadClient(thread).breakOnNext();
}
function sourceContents(sourceId: SourceId): Source {
const sourceClient = threadClient.source({ actor: sourceId });
const sourceThreadClient = sourceThreads[sourceId];
const sourceClient = sourceThreadClient.source({ actor: sourceId });
return sourceClient.source();
}
@ -162,7 +186,8 @@ function setBreakpoint(
condition: boolean,
noSliding: boolean
): Promise<BreakpointResult> {
const sourceClient = threadClient.source({ actor: location.sourceId });
const sourceThreadClient = sourceThreads[location.sourceId];
const sourceClient = sourceThreadClient.source({ actor: location.sourceId });
return sourceClient
.setBreakpoint({
@ -209,39 +234,43 @@ function setBreakpointCondition(
const bpClient = bpClients[breakpointId];
delete bpClients[breakpointId];
const sourceThreadClient = sourceThreads[bpClient.source.actor];
return bpClient
.setCondition(threadClient, condition, noSliding)
.setCondition(sourceThreadClient, condition, noSliding)
.then(_bpClient => {
bpClients[breakpointId] = _bpClient;
return { id: breakpointId };
});
}
async function evaluateInFrame(script: Script, frameId: string) {
return evaluate(script, { frameId });
async function evaluateInFrame(script: Script, options: EvaluateParam) {
return evaluate(script, options);
}
async function evaluateExpressions(scripts: Script[], frameId?: string) {
return Promise.all(scripts.map(script => evaluate(script, { frameId })));
async function evaluateExpressions(scripts: Script[], options: EvaluateParam) {
return Promise.all(scripts.map(script => evaluate(script, options)));
}
type EvaluateParam = { frameId?: FrameId };
type EvaluateParam = { thread?: string, frameId?: FrameId };
function evaluate(
script: ?Script,
{ frameId }: EvaluateParam = {}
{ thread, frameId }: EvaluateParam = {}
): Promise<mixed> {
const params = frameId ? { frameActor: frameId } : {};
if (!tabTarget || !tabTarget.activeConsole || !script) {
const params = { thread, frameActor: frameId };
if (!tabTarget || !script) {
return Promise.resolve({});
}
const console = thread
? lookupConsoleClient(thread)
: tabTarget.activeConsole;
if (!console) {
return Promise.resolve({});
}
return new Promise(resolve => {
tabTarget.activeConsole.evaluateJSAsync(
script,
result => resolve(result),
params
);
console.evaluateJSAsync(script, result => resolve(result), params);
});
}
@ -271,8 +300,8 @@ function reload(): Promise<*> {
return tabTarget.activeTab.reload();
}
function getProperties(grip: Grip): Promise<*> {
const objClient = threadClient.pauseGrip(grip);
function getProperties(thread: string, grip: Grip): Promise<*> {
const objClient = lookupThreadClient(thread).pauseGrip(grip);
return objClient.getPrototypeAndProperties().then(resp => {
const { ownProperties, safeGetterValues } = resp;
@ -289,14 +318,21 @@ async function getFrameScopes(frame: Frame): Promise<*> {
return frame.scope;
}
return threadClient.getEnvironment(frame.id);
let sourceId = frame.location.sourceId;
if (isOriginalId(sourceId)) {
sourceId = originalToGeneratedId(sourceId);
}
const sourceThreadClient = sourceThreads[sourceId];
return sourceThreadClient.getEnvironment(frame.id);
}
function pauseOnExceptions(
thread: string,
shouldPauseOnExceptions: boolean,
shouldPauseOnCaughtExceptions: boolean
): Promise<*> {
return threadClient.pauseOnExceptions(
return lookupThreadClient(thread).pauseOnExceptions(
shouldPauseOnExceptions,
// Providing opposite value because server
// uses "shouldIgnoreCaughtExceptions"
@ -325,91 +361,97 @@ function disablePrettyPrint(sourceId: SourceId): Promise<*> {
return sourceClient.disablePrettyPrint();
}
async function setPausePoints(sourceId: SourceId, pausePoints: PausePoints) {
async function setPausePoints(sourceId: SourceId, pausePoints: PausePointsMap) {
return sendPacket({ to: sourceId, type: "setPausePoints", pausePoints });
}
async function setSkipPausing(shouldSkip: boolean) {
return threadClient.request({
async function setSkipPausing(thread: string, shouldSkip: boolean) {
const client = lookupThreadClient(thread);
return client.request({
skip: shouldSkip,
to: threadClient.actor,
to: client.actor,
type: "skipBreakpoints"
});
}
function interrupt(): Promise<*> {
return threadClient.interrupt();
function interrupt(thread: string): Promise<*> {
return lookupThreadClient(thread).interrupt();
}
function eventListeners(): Promise<*> {
return threadClient.eventListeners();
}
function pauseGrip(func: Function): ObjectClient {
return threadClient.pauseGrip(func);
function pauseGrip(thread: string, func: Function): ObjectClient {
return lookupThreadClient(thread).pauseGrip(func);
}
async function fetchSources() {
const { sources } = await threadClient.getSources();
function registerSource(source: Source) {
if (isOriginalId(source.id)) {
throw new Error("registerSource called with original ID");
}
sourceThreads[source.id] = lookupThreadClient(source.thread);
}
async function createSources(client: ThreadClient) {
const { sources } = await client.getSources();
return (
sources &&
sources.map(packet => createSource(client.actor, packet, { supportsWasm }))
);
}
async function fetchSources(): Promise<any[]> {
let sources = await createSources(threadClient);
// NOTE: this happens when we fetch sources and then immediately navigate
if (!sources) {
return;
return [];
}
return sources.map(source => createSource(source, { supportsWasm }));
}
if (features.windowlessWorkers) {
// Also fetch sources from any workers.
workerClients = await updateWorkerClients({
threadClient,
debuggerClient,
tabTarget,
workerClients
});
/**
* Temporary helper to check if the current server will support a call to
* listWorkers. On Fennec 60 or older, the call will silently crash and prevent
* the client from resuming.
* XXX: Remove when FF60 for Android is no longer used or available.
*
* See https://bugzilla.mozilla.org/show_bug.cgi?id=1443550 for more details.
*/
async function checkServerSupportsListWorkers() {
const root = await tabTarget.root;
// root is not available on all debug targets.
if (!root) {
return false;
const workerNames = Object.getOwnPropertyNames(workerClients);
workerNames.forEach(actor => {
const workerSources = createSources(workerClients[actor].thread);
if (workerSources) {
sources = sources.concat(workerSources);
}
});
}
const deviceFront = await debuggerClient.mainRoot.getFront("device");
const description = await deviceFront.getDescription();
const isFennec = description.apptype === "mobile/android";
if (!isFennec) {
// Explicitly return true early to avoid calling Services.vs.compare.
// This would force us to extent the Services shim provided by
// devtools-modules, used when this code runs in a tab.
return true;
}
// We are only interested in Fennec release versions here.
// We assume that the server fix for Bug 1443550 will land in FF61.
const version = description.platformversion;
return Services.vc.compare(version, "61.0") >= 0;
return sources;
}
async function fetchWorkers(): Promise<{ workers: Worker[] }> {
// Temporary workaround for Bug 1443550
// XXX: Remove when FF60 for Android is no longer used or available.
const supportsListWorkers = await checkServerSupportsListWorkers();
if (features.windowlessWorkers) {
workerClients = await updateWorkerClients({
tabTarget,
debuggerClient,
threadClient,
workerClients
});
// NOTE: The Worker and Browser Content toolboxes do not have a parent
// with a listWorkers function
// TODO: there is a listWorkers property, but it is not a function on the
// parent. Investigate what it is
if (
!threadClient._parent ||
typeof threadClient._parent.listWorkers != "function" ||
!supportsListWorkers
) {
const workerNames = Object.getOwnPropertyNames(workerClients);
return {
workers: workerNames.map(actor =>
createWorker(actor, workerClients[actor].url)
)
};
}
if (!supportsWorkers(tabTarget)) {
return Promise.resolve({ workers: [] });
}
return threadClient._parent.listWorkers();
return tabTarget.activeTab.listWorkers();
}
const clientCommands = {
@ -450,7 +492,8 @@ const clientCommands = {
fetchWorkers,
sendPacket,
setPausePoints,
setSkipPausing
setSkipPausing,
registerSource
};
export { setupCommands, clientCommands };

View File

@ -13,6 +13,8 @@ import type {
SourcePayload
} from "./types";
import { clientCommands } from "./commands";
export function createFrame(frame: FramePacket): ?Frame {
if (!frame) {
return null;
@ -41,11 +43,13 @@ export function createFrame(frame: FramePacket): ?Frame {
}
export function createSource(
thread: string,
source: SourcePayload,
{ supportsWasm }: { supportsWasm: boolean }
): Source {
const createdSource = {
id: source.actor,
thread,
url: source.url,
relativeUrl: source.url,
isPrettyPrinted: false,
@ -54,12 +58,14 @@ export function createSource(
isBlackBoxed: false,
loadedState: "unloaded"
};
clientCommands.registerSource(createdSource);
return Object.assign(createdSource, {
isWasm: supportsWasm && source.introductionType === "wasm"
});
}
export function createPause(
thread: string,
packet: PausedPacket,
response: FramesResponse
): any {
@ -68,6 +74,7 @@ export function createPause(
return {
...packet,
thread,
frame: createFrame(frame),
frames: response.frames.map(createFrame)
};
@ -92,3 +99,12 @@ export function createBreakpointLocation(
column: actualLocation.column
};
}
export function createWorker(actor: string, url: string) {
return {
actor,
url,
// Ci.nsIWorkerDebugger.TYPE_DEDICATED
type: 0
};
}

View File

@ -23,21 +23,24 @@ type Dependencies = {
supportsWasm: boolean
};
let threadClient: ThreadClient;
let actions: Actions;
let supportsWasm: boolean;
let isInterrupted: boolean;
function addThreadEventListeners(client: ThreadClient) {
Object.keys(clientEvents).forEach(eventName => {
client.addListener(eventName, clientEvents[eventName].bind(null, client));
});
}
function setupEvents(dependencies: Dependencies) {
threadClient = dependencies.threadClient;
const threadClient = dependencies.threadClient;
actions = dependencies.actions;
supportsWasm = dependencies.supportsWasm;
sourceQueue.initialize(actions);
if (threadClient) {
Object.keys(clientEvents).forEach(eventName => {
threadClient.addListener(eventName, clientEvents[eventName]);
});
addThreadEventListeners(threadClient);
if (threadClient._parent) {
// Parent may be BrowsingContextTargetFront/WorkerTargetFront and
@ -54,7 +57,11 @@ function setupEvents(dependencies: Dependencies) {
}
}
async function paused(_: "paused", packet: PausedPacket) {
async function paused(
threadClient: ThreadClient,
_: "paused",
packet: PausedPacket
) {
// If paused by an explicit interrupt, which are generated by the
// slow script dialog and internal events such as setting
// breakpoints, ignore the event.
@ -79,13 +86,17 @@ async function paused(_: "paused", packet: PausedPacket) {
}
if (why.type != "alreadyPaused") {
const pause = createPause(packet, response);
const pause = createPause(threadClient.actor, packet, response);
await sourceQueue.flush();
actions.paused(pause);
}
}
function resumed(_: "resumed", packet: ResumedPacket) {
function resumed(
threadClient: ThreadClient,
_: "resumed",
packet: ResumedPacket
) {
// NOTE: the client suppresses resumed events while interrupted
// to prevent unintentional behavior.
// see [client docs](../README.md#interrupted) for more information.
@ -97,8 +108,12 @@ function resumed(_: "resumed", packet: ResumedPacket) {
actions.resumed(packet);
}
function newSource(_: "newSource", { source }: SourcePacket) {
sourceQueue.queue(createSource(source, { supportsWasm }));
function newSource(
threadClient: ThreadClient,
_: "newSource",
{ source }: SourcePacket
) {
sourceQueue.queue(createSource(threadClient.actor, source, { supportsWasm }));
}
function workerListChanged() {
@ -111,4 +126,4 @@ const clientEvents = {
newSource
};
export { setupEvents, clientEvents };
export { setupEvents, clientEvents, addThreadEventListeners };

View File

@ -11,4 +11,5 @@ DebuggerModules(
'commands.js',
'create.js',
'events.js',
'workers.js',
)

View File

@ -0,0 +1,54 @@
/* 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 { addThreadEventListeners } from "./events";
import type { TabTarget } from "./types";
export function supportsWorkers(tabTarget: TabTarget) {
return tabTarget.isBrowsingContext || tabTarget.isContentProcess;
}
export async function updateWorkerClients({
tabTarget,
debuggerClient,
threadClient,
workerClients
}: Object) {
if (!supportsWorkers(tabTarget)) {
return {};
}
const newWorkerClients = {};
const { workers } = await tabTarget.activeTab.listWorkers();
for (const workerTargetFront of workers) {
await workerTargetFront.attach();
const [, workerThread] = await workerTargetFront.attachThread();
if (workerClients[workerThread.actor]) {
if (workerClients[workerThread.actor].thread != workerThread) {
throw new Error(`Multiple clients for actor ID: ${workerThread.actor}`);
}
newWorkerClients[workerThread.actor] = workerClients[workerThread.actor];
} else {
addThreadEventListeners(workerThread);
workerThread.resume();
const [, consoleClient] = await debuggerClient.attachConsole(
workerTargetFront.targetForm.consoleActor,
[]
);
newWorkerClients[workerThread.actor] = {
url: workerTargetFront.url,
thread: workerThread,
console: consoleClient
};
}
}
return newWorkerClients;
}

View File

@ -5,6 +5,7 @@
// @flow
import * as firefox from "./firefox";
import * as chrome from "./chrome";
import { prefs, asyncStore } from "../utils/prefs";
import { setupHelper } from "../utils/dbg";
@ -46,6 +47,13 @@ async function loadInitialState() {
return { pendingBreakpoints, tabs, breakpoints };
}
function getClient(connection: any) {
const {
tab: { clientType }
} = connection;
return clientType == "firefox" ? firefox : chrome;
}
export async function onConnect(
connection: Object,
{ services, toolboxActions }: Object
@ -55,8 +63,11 @@ export async function onConnect(
return;
}
const commands = firefox.clientCommands;
const client = getClient(connection);
const commands = client.clientCommands;
const initialState = await loadInitialState();
const { store, actions, selectors } = bootstrapStore(
commands,
{
@ -67,7 +78,8 @@ export async function onConnect(
);
const workers = bootstrapWorkers();
await firefox.onConnect(connection, actions);
await client.onConnect(connection, actions);
await loadFromPrefs(actions);
syncXHRBreakpoints();
setupHelper({
@ -76,7 +88,7 @@ export async function onConnect(
selectors,
workers: { ...workers, ...services },
connection,
client: firefox.clientCommands
client: client.clientCommands
});
bootstrapApp(store);

View File

@ -4,10 +4,12 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
DIRS += [
'chrome',
'firefox',
]
DebuggerModules(
'chrome.js',
'firefox.js',
'index.js',
)

View File

@ -4,10 +4,10 @@
// @flow
import React, { Component } from "react";
import { connect } from "react-redux";
import PropTypes from "prop-types";
import classnames from "classnames";
import { connect } from "../utils/connect";
import { prefs, features } from "../utils/prefs";
import actions from "../actions";
import A11yIntention from "./A11yIntention";
@ -44,6 +44,8 @@ import "./App.css";
// $FlowIgnore
import "devtools-launchpad/src/components/Root.css";
import type { ActiveSearchType } from "../selectors";
import "./shared/menu.css";
import "./shared/reps.css";
@ -61,7 +63,7 @@ type Props = {
orientation: OrientationType,
startPanelCollapsed: boolean,
endPanelCollapsed: boolean,
activeSearch: string,
activeSearch: ActiveSearchType,
quickOpenEnabled: boolean,
canRewind: boolean,
setActiveSearch: typeof actions.setActiveSearch,

View File

@ -3,13 +3,13 @@
* file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
// @flow
import { connect } from "react-redux";
import React, { Component } from "react";
import Breakpoint from "./Breakpoint";
import { getSelectedSource, getFirstVisibleBreakpoints } from "../../selectors";
import { makeLocationId } from "../../utils/breakpoint";
import { isLoaded } from "../../utils/source";
import { connect } from "../../utils/connect";
import type { Breakpoint as BreakpointType, Source } from "../../types";

View File

@ -3,12 +3,12 @@
* file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
import React, { Component } from "react";
import { connect } from "react-redux";
import ColumnBreakpoint from "./ColumnBreakpoint";
import "./ColumnBreakpoints.css";
import { getSelectedSource, visibleColumnBreakpoints } from "../../selectors";
import { connect } from "../../utils/connect";
import { makeLocationId } from "../../utils/breakpoint";
import actions from "../../actions";

View File

@ -5,7 +5,7 @@
// @flow
import React, { PureComponent } from "react";
import ReactDOM from "react-dom";
import { connect } from "react-redux";
import { connect } from "../../utils/connect";
import "./ConditionalPanel.css";
import { toEditorLine } from "../../utils/editor";
import actions from "../../actions";

View File

@ -14,7 +14,7 @@ import {
import { isLoaded } from "../../utils/source";
import { isException } from "../../utils/pause";
import { getIndentation } from "../../utils/indentation";
import { connect } from "react-redux";
import { connect } from "../../utils/connect";
import {
getVisibleSelectedFrame,
getPauseReason,

View File

@ -3,7 +3,7 @@
* file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
import { Component } from "react";
import { connect } from "react-redux";
import { connect } from "../../utils/connect";
import { showMenu } from "devtools-contextmenu";
import { isOriginalId } from "devtools-source-map";

View File

@ -2,7 +2,7 @@
* 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/>. */
import { connect } from "react-redux";
import { connect } from "../../utils/connect";
import { Component } from "react";
import { getSelectedSource, getEmptyLines } from "../../selectors";
import type { Source } from "../../types";

View File

@ -4,7 +4,7 @@
// @flow
import React, { PureComponent } from "react";
import { connect } from "react-redux";
import { connect } from "../../utils/connect";
import classnames from "classnames";
import Svg from "../shared/Svg";
import actions from "../../actions";

View File

@ -4,7 +4,7 @@
import { Component } from "react";
import { showMenu } from "devtools-contextmenu";
import { connect } from "react-redux";
import { connect } from "../../utils/connect";
import { lineAtHeight } from "../../utils/editor";
import {
getContextMenu,

View File

@ -8,7 +8,7 @@ import { toEditorLine, endOperation, startOperation } from "../../utils/editor";
import { getDocument, hasDocument } from "../../utils/editor/source-documents";
import { isLoaded } from "../../utils/source";
import { connect } from "react-redux";
import { connect } from "../../utils/connect";
import {
getVisibleSelectedFrame,
getSelectedLocation,

View File

@ -5,7 +5,7 @@
// @flow
import { Component } from "react";
import { range, isEmpty } from "lodash";
import { connect } from "react-redux";
import { connect } from "../../utils/connect";
import { getHighlightedLineRange } from "../../selectors";
type Props = {

View File

@ -5,7 +5,7 @@
// @flow
import React, { Component } from "react";
import { connect } from "react-redux";
import { connect } from "../../../utils/connect";
import Reps from "devtools-reps";
const {
@ -17,7 +17,7 @@ const {
const { ObjectInspector, utils } = objectInspector;
const {
node: { createNode, getChildren, getValue, nodeIsPrimitive, NODE_TYPES },
node: { createNode, getChildren, getValue, nodeIsPrimitive },
loadProperties: { loadItemProperties }
} = utils;
@ -25,7 +25,6 @@ import actions from "../../../actions";
import { getAllPopupObjectProperties } from "../../../selectors";
import Popover from "../../shared/Popover";
import PreviewFunction from "../../shared/PreviewFunction";
import { isReactComponent, isImmutablePreview } from "../../../utils/preview";
import Svg from "../../shared/Svg";
import { createObjectClient } from "../../../client/firefox";
@ -45,7 +44,6 @@ type Props = {
range: EditorRange,
editor: any,
editorRef: ?HTMLDivElement,
extra: Object,
setPopupObjectProperties: typeof actions.setPopupObjectProperties,
addExpression: typeof actions.addExpression,
selectSourceURL: typeof actions.selectSourceURL,
@ -129,17 +127,12 @@ export class Popup extends Component<Props, State> {
};
getRoot() {
const { expression, value, extra } = this.props;
let rootValue = value;
if (extra.immutable) {
rootValue = extra.immutable.entries;
}
const { expression, value } = this.props;
return createNode({
name: expression,
path: expression,
contents: { value: rootValue }
contents: { value }
});
}
@ -223,33 +216,22 @@ export class Popup extends Component<Props, State> {
}
renderObjectPreview() {
const { extra, value } = this.props;
const root = this.getRoot();
if (nodeIsPrimitive(root)) {
return null;
}
let roots = this.getChildren();
const roots = this.getChildren();
if (!Array.isArray(roots) || roots.length === 0) {
return null;
}
let header = null;
if (extra.immutable && isImmutablePreview(value)) {
header = this.renderImmutable(extra.immutable);
roots = roots.filter(r => r.type != NODE_TYPES.PROTOTYPE);
} else if (extra.react && isReactComponent(this.getObjectProperties())) {
header = this.renderReact(extra.react);
roots = roots.filter(r => ["state", "props"].includes(r.name));
}
return (
<div
className="preview-popup"
style={{ maxHeight: this.calculateMaxHeight() }}
>
{header}
{this.renderObjectInspector(roots)}
</div>
);

View File

@ -5,7 +5,7 @@
// @flow
import React, { PureComponent } from "react";
import { connect } from "react-redux";
import { connect } from "../../../utils/connect";
import Popup from "./Popup";
@ -22,7 +22,7 @@ type Props = {
editorRef: ?HTMLDivElement,
selectedSource: Source,
preview: PreviewType,
isPaused: Boolean,
isPaused: boolean,
clearPreview: typeof actions.clearPreview,
setPopupObjectProperties: typeof actions.setPopupObjectProperties,
addExpression: typeof actions.addExpression,
@ -148,7 +148,7 @@ class Preview extends PureComponent<Props, State> {
return null;
}
const { result, expression, location, cursorPos, extra } = preview;
const { result, expression, location, cursorPos } = preview;
const value = result;
if (typeof value == "undefined" || value.optimizedOut) {
return null;
@ -164,7 +164,6 @@ class Preview extends PureComponent<Props, State> {
range={editorRange}
expression={expression}
popoverPos={cursorPos}
extra={extra}
onClose={this.onClose}
/>
);

View File

@ -6,7 +6,7 @@
import PropTypes from "prop-types";
import React, { Component } from "react";
import { connect } from "react-redux";
import { connect } from "../../utils/connect";
import { CloseButton } from "../shared/Button";
import Svg from "../shared/Svg";
import actions from "../../actions";

View File

@ -5,7 +5,7 @@
// @flow
import React, { PureComponent } from "react";
import { connect } from "react-redux";
import { connect } from "../../utils/connect";
import { showMenu, buildMenu } from "devtools-contextmenu";
@ -35,6 +35,7 @@ import {
getSourcesForTabs,
getHasSiblingOfSameName
} from "../../selectors";
import type { ActiveSearchType } from "../../selectors";
import classnames from "classnames";
@ -44,7 +45,7 @@ type Props = {
tabSources: SourcesList,
selectedSource: Source,
source: Source,
activeSearch: string,
activeSearch: ActiveSearchType,
hasSiblingOfSameName: boolean,
selectSource: typeof actions.selectSource,
closeTab: typeof actions.closeTab,

View File

@ -5,7 +5,7 @@
// @flow
import React, { PureComponent } from "react";
import { connect } from "react-redux";
import { connect } from "../../utils/connect";
import { getSelectedSource, getSourcesForTabs } from "../../selectors";
import { isVisible } from "../../utils/ui";

View File

@ -7,7 +7,7 @@
import PropTypes from "prop-types";
import React, { PureComponent } from "react";
import ReactDOM from "react-dom";
import { connect } from "react-redux";
import { connect } from "../../utils/connect";
import classnames from "classnames";
import { debounce } from "lodash";

View File

@ -6,7 +6,7 @@
import React, { Component } from "react";
import { showMenu } from "devtools-contextmenu";
import { connect } from "react-redux";
import { connect } from "../../utils/connect";
import { score as fuzzaldrinScore } from "fuzzaldrin-plus";
import { copyToTheClipboard } from "../../utils/clipboard";

View File

@ -7,7 +7,7 @@
// Dependencies
import React, { Component } from "react";
import classnames from "classnames";
import { connect } from "react-redux";
import { connect } from "../../utils/connect";
// Selectors
import {

View File

@ -5,7 +5,7 @@
// @flow
import React, { Component } from "react";
import { connect } from "react-redux";
import { connect } from "../../utils/connect";
import classnames from "classnames";
import { showMenu } from "devtools-contextmenu";

View File

@ -5,7 +5,7 @@
// @flow
import React, { Component } from "react";
import { connect } from "react-redux";
import { connect } from "../../utils/connect";
import { Tab, Tabs, TabList, TabPanels } from "react-aria-components/src/tabs";
import { formatKeyShortcut } from "../../utils/text";
import actions from "../../actions";
@ -22,14 +22,14 @@ import Outline from "./Outline";
import SourcesTree from "./SourcesTree";
import type { SourcesMap } from "../../reducers/types";
import type { SelectedPrimaryPaneTabType } from "../../reducers/ui";
import type { SelectedPrimaryPaneTabType } from "../../selectors";
type State = {
alphabetizeOutline: boolean
};
type Props = {
selectedTab: string,
selectedTab: SelectedPrimaryPaneTabType,
sources: SourcesMap,
horizontal: boolean,
sourceSearchOn: boolean,

View File

@ -6,7 +6,7 @@
import PropTypes from "prop-types";
import React, { Component } from "react";
import { connect } from "react-redux";
import { connect } from "../utils/connect";
import classnames from "classnames";
import actions from "../actions";
@ -157,20 +157,8 @@ export class ProjectSearch extends Component<Props, State> {
);
};
getResults = (): Result[] => {
const { results } = this.props;
return results
.toJS()
.map(result => ({
type: "RESULT",
...result,
matches: result.matches.map(m => ({ type: "MATCH", ...m }))
}))
.filter(result => result.filepath && result.matches.length > 0);
};
getResultCount = () =>
this.getResults().reduce((count, file) => count + file.matches.length, 0);
this.props.results.reduce((count, file) => count + file.matches.length, 0);
onKeyDown = (e: SyntheticKeyboardEvent<HTMLInputElement>) => {
if (e.key === "Escape") {
@ -271,8 +259,7 @@ export class ProjectSearch extends Component<Props, State> {
};
renderResults = () => {
const results = this.getResults();
const { status } = this.props;
const { status, results } = this.props;
if (!this.props.query) {
return;
}

View File

@ -4,7 +4,7 @@
// @flow
import React, { Component } from "react";
import { connect } from "react-redux";
import { connect } from "../utils/connect";
import fuzzyAldrin from "fuzzaldrin-plus";
import { basename } from "../utils/path";

View File

@ -5,7 +5,7 @@
// @flow
import React, { PureComponent } from "react";
import { connect } from "react-redux";
import { connect } from "../../../utils/connect";
import { createSelector } from "reselect";
import classnames from "classnames";
@ -28,8 +28,7 @@ import type {
SourceLocation
} from "../../../types";
type FormattedFrame = {
...Frame,
type FormattedFrame = Frame & {
selectedLocation: SourceLocation
};
@ -43,7 +42,7 @@ type Props = {
breakpoint: FormattedBreakpoint,
breakpoints: BreakpointType[],
source: Source,
frame: ?FormattedFrame,
frame: FormattedFrame,
enableBreakpoint: typeof actions.enableBreakpoint,
removeBreakpoint: typeof actions.removeBreakpoint,
removeBreakpoints: typeof actions.removeBreakpoints,
@ -176,7 +175,7 @@ class Breakpoint extends PureComponent<Props> {
const getFormattedFrame = createSelector(
getSelectedSource,
getSelectedFrame,
(selectedSource: Source, frame: Frame) => {
(selectedSource: Source, frame: Frame): ?FormattedFrame => {
if (!frame) {
return null;
}

View File

@ -4,7 +4,7 @@
// @flow
import React, { PureComponent } from "react";
import { connect } from "react-redux";
import { connect } from "../../../utils/connect";
import actions from "../../../actions";
import {
getTruncatedFileName,
@ -12,20 +12,32 @@ import {
getSourceQueryString,
getFileURL
} from "../../../utils/source";
import { getHasSiblingOfSameName } from "../../../selectors";
import {
getHasSiblingOfSameName,
getBreakpointsForSource
} from "../../../selectors";
import SourceIcon from "../../shared/SourceIcon";
import type { Source } from "../../../types";
import type { Source, Breakpoint } from "../../../types";
import showContextMenu from "./BreakpointHeadingsContextMenu";
type Props = {
sources: Source[],
source: Source,
hasSiblingOfSameName: boolean,
breakpointsForSource: Breakpoint[],
disableBreakpointsInSource: typeof actions.disableBreakpointsInSource,
enableBreakpointsInSource: typeof actions.enableBreakpointsInSource,
removeBreakpointsInSource: typeof actions.removeBreakpointsInSource,
selectSource: typeof actions.selectSource
};
class BreakpointHeading extends PureComponent<Props> {
onContextMenu = e => {
showContextMenu({ ...this.props, contextMenuEvent: e });
};
render() {
const { sources, source, hasSiblingOfSameName, selectSource } = this.props;
@ -37,6 +49,7 @@ class BreakpointHeading extends PureComponent<Props> {
className="breakpoint-heading"
title={getFileURL(source, false)}
onClick={() => selectSource(source.id)}
onContextMenu={this.onContextMenu}
>
<SourceIcon
source={source}
@ -52,10 +65,16 @@ class BreakpointHeading extends PureComponent<Props> {
}
const mapStateToProps = (state, { source }) => ({
hasSiblingOfSameName: getHasSiblingOfSameName(state, source)
hasSiblingOfSameName: getHasSiblingOfSameName(state, source),
breakpointsForSource: getBreakpointsForSource(state, source.id)
});
export default connect(
mapStateToProps,
{ selectSource: actions.selectSource }
{
selectSource: actions.selectSource,
enableBreakpointsInSource: actions.enableBreakpointsInSource,
disableBreakpointsInSource: actions.disableBreakpointsInSource,
removeBreakpointsInSource: actions.removeBreakpointsInSource
}
)(BreakpointHeading);

View File

@ -0,0 +1,90 @@
/* 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 { buildMenu, showMenu } from "devtools-contextmenu";
import actions from "../../../actions";
import type { Breakpoint, Source } from "../../../types";
type Props = {
source: Source,
breakpointsForSource: Breakpoint[],
disableBreakpointsInSource: typeof actions.disableBreakpointsInSource,
enableBreakpointsInSource: typeof actions.enableBreakpointsInSource,
removeBreakpointsInSource: typeof actions.removeBreakpointsInSource,
contextMenuEvent: SyntheticEvent<HTMLElement>
};
export default function showContextMenu(props: Props) {
const {
source,
breakpointsForSource,
disableBreakpointsInSource,
enableBreakpointsInSource,
removeBreakpointsInSource,
contextMenuEvent
} = props;
contextMenuEvent.preventDefault();
const enableInSourceLabel = L10N.getStr(
"breakpointHeadingsMenuItem.enableInSource.label"
);
const disableInSourceLabel = L10N.getStr(
"breakpointHeadingsMenuItem.disableInSource.label"
);
const removeInSourceLabel = L10N.getStr(
"breakpointHeadingsMenuItem.removeInSource.label"
);
const enableInSourceKey = L10N.getStr(
"breakpointHeadingsMenuItem.enableInSource.accesskey"
);
const disableInSourceKey = L10N.getStr(
"breakpointHeadingsMenuItem.disableInSource.accesskey"
);
const removeInSourceKey = L10N.getStr(
"breakpointHeadingsMenuItem.removeInSource.accesskey"
);
const disableInSourceItem = {
id: "node-menu-disable-in-source",
label: disableInSourceLabel,
accesskey: disableInSourceKey,
disabled: false,
click: () => disableBreakpointsInSource(source)
};
const enableInSourceItem = {
id: "node-menu-enable-in-source",
label: enableInSourceLabel,
accesskey: enableInSourceKey,
disabled: false,
click: () => enableBreakpointsInSource(source)
};
const removeInSourceItem = {
id: "node-menu-enable-in-source",
label: removeInSourceLabel,
accesskey: removeInSourceKey,
disabled: false,
click: () => removeBreakpointsInSource(source)
};
const hideDisableInSourceItem = breakpointsForSource.every(
breakpoint => breakpoint.disabled
);
const hideEnableInSourceItem = breakpointsForSource.every(
breakpoint => !breakpoint.disabled
);
const items = [
{ item: disableInSourceItem, hidden: () => hideDisableInSourceItem },
{ item: enableInSourceItem, hidden: () => hideEnableInSourceItem },
{ item: removeInSourceItem, hidden: () => false }
];
showMenu(contextMenuEvent, buildMenu(items));
}

View File

@ -6,7 +6,7 @@
import React, { Component } from "react";
import classnames from "classnames";
import { connect } from "react-redux";
import { connect } from "../../../utils/connect";
import ExceptionOption from "./ExceptionOption";

View File

@ -10,6 +10,7 @@ DIRS += [
DebuggerModules(
'Breakpoint.js',
'BreakpointHeading.js',
'BreakpointHeadingsContextMenu.js',
'BreakpointsContextMenu.js',
'ExceptionOption.js',
'index.js',

View File

@ -8,7 +8,7 @@
import PropTypes from "prop-types";
import React, { Component } from "react";
import { connect } from "react-redux";
import { connect } from "../../utils/connect";
import classnames from "classnames";
import { features } from "../../utils/prefs";
import {

View File

@ -4,7 +4,7 @@
// @flow
import React, { Component } from "react";
import { connect } from "react-redux";
import { connect } from "../../utils/connect";
import classnames from "classnames";
import { features } from "../../utils/prefs";
import { objectInspector } from "devtools-reps";
@ -164,6 +164,7 @@ class Expressions extends Component<Props, State> {
hideInput = () => {
this.setState({ focused: false });
this.props.onExpressionAdded();
this.props.clearExpressionError();
};
onFocus = () => {

View File

@ -5,7 +5,7 @@
// @flow
import React, { Component } from "react";
import { connect } from "react-redux";
import { connect } from "../../../utils/connect";
import PropTypes from "prop-types";
import type { Frame, Why } from "../../../types";
@ -22,7 +22,6 @@ import { copyToTheClipboard } from "../../../utils/clipboard";
import {
getFrameworkGroupingState,
getSelectedFrame,
isPaused as getIsPaused,
getCallStackFrames,
getPauseReason
} from "../../../selectors";
@ -214,8 +213,7 @@ const mapStateToProps = state => ({
frames: getCallStackFrames(state),
why: getPauseReason(state),
frameworkGroupingOn: getFrameworkGroupingState(state),
selectedFrame: getSelectedFrame(state),
pause: getIsPaused(state)
selectedFrame: getSelectedFrame(state)
});
export default connect(

View File

@ -2,9 +2,8 @@
* 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 React, { PureComponent } from "react";
import { connect } from "react-redux";
import { connect } from "../../utils/connect";
import actions from "../../actions";
import { createObjectClient } from "../../client/firefox";
@ -13,7 +12,7 @@ import { getSelectedFrame, getAllPopupObjectProperties } from "../../selectors";
import { objectInspector } from "devtools-reps";
import { isReactComponent } from "../../utils/preview";
import type { Frame, Grip } from "../../types";
import type { Frame } from "../../types";
const {
component: ObjectInspector,
@ -28,7 +27,7 @@ type Props = {
selectedFrame: Frame,
popupObjectProperties: Object,
setPopupObjectProperties: typeof actions.setPopupObjectProperties,
openElementInInspector: (grip: Grip) => void
openElementInInspector: typeof actions.setPopupObjectProperties
};
class FrameworkComponent extends PureComponent<Props> {
@ -99,13 +98,13 @@ class FrameworkComponent extends PureComponent<Props> {
const mapStateToProps = state => ({
selectedFrame: getSelectedFrame(state),
popupObjectProperties: getAllPopupObjectProperties(state),
openElementInInspector: actions.openElementInInspectorCommand
popupObjectProperties: getAllPopupObjectProperties(state)
});
export default connect(
mapStateToProps,
{
setPopupObjectProperties: actions.setPopupObjectProperties
setPopupObjectProperties: actions.setPopupObjectProperties,
openElementInInspector: actions.openElementInInspectorCommand
}
)(FrameworkComponent);

View File

@ -4,7 +4,7 @@
// @flow
import React, { PureComponent } from "react";
import { connect } from "react-redux";
import { connect } from "../../utils/connect";
import actions from "../../actions";
import { createObjectClient } from "../../client/firefox";
@ -19,7 +19,8 @@ import {
import { getScopes } from "../../utils/pause/scopes";
import { objectInspector } from "devtools-reps";
import type { Pause, Why } from "../../types";
import type { Why } from "../../types";
import type { NamedValue } from "../../utils/pause/scopes/types";
import "./Scopes.css";
@ -27,7 +28,7 @@ import "./Scopes.css";
const { ObjectInspector } = objectInspector;
type Props = {
isPaused: Pause,
isPaused: boolean,
selectedFrame: Object,
generatedFrameScopes: Object,
originalFrameScopes: Object | null,

View File

@ -2,25 +2,54 @@
* 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/>. */
import React, { PureComponent } from "react";
import { connect } from "react-redux";
import React, { Component } from "react";
import { connect } from "../../utils/connect";
import type { List } from "immutable";
import "./Workers.css";
import actions from "../../actions";
import { getWorkers } from "../../selectors";
import {
getMainThread,
getCurrentThread,
threadIsPaused,
getWorkers
} from "../../selectors";
import { basename } from "../../utils/path";
import { features } from "../../utils/prefs";
import type { Worker } from "../../types";
import AccessibleImage from "../shared/AccessibleImage";
import classnames from "classnames";
export class Workers extends PureComponent {
type Props = {
selectThread: string => void
};
export class Workers extends Component<Props> {
props: {
workers: List<Worker>,
openWorkerToolbox: object => void
openWorkerToolbox: object => void,
mainThread: string,
currentThread: string
};
renderWorkers(workers) {
renderWorkers(workers, mainThread, currentThread) {
if (features.windowlessWorkers) {
return [{ actor: mainThread }, ...workers].map(worker => (
<div
className={classnames(
"worker",
worker.actor == currentThread && "selected"
)}
key={worker.actor}
onClick={() => this.props.selectThread(worker.actor)}
>
<img className="domain" />
{(worker.url ? basename(worker.url) : "Main Thread") +
(this.props.threadIsPaused(worker.actor) ? " PAUSED" : "")}
</div>
));
}
const { openWorkerToolbox } = this.props;
return workers.map(worker => (
<div
@ -39,11 +68,11 @@ export class Workers extends PureComponent {
}
render() {
const { workers } = this.props;
const { workers, mainThread, currentThread } = this.props;
return (
<div className="pane workers-list">
{workers && workers.size > 0
? this.renderWorkers(workers)
? this.renderWorkers(workers, mainThread, currentThread)
: this.renderNoWorkersPlaceholder()}
</div>
);
@ -51,10 +80,16 @@ export class Workers extends PureComponent {
}
const mapStateToProps = state => ({
workers: getWorkers(state)
workers: getWorkers(state),
mainThread: getMainThread(state),
currentThread: getCurrentThread(state),
threadIsPaused: thread => threadIsPaused(state, thread)
});
export default connect(
mapStateToProps,
actions
{
openWorkerToolbox: actions.openWorkerToolbox,
selectThread: actions.selectThread
}
)(Workers);

View File

@ -5,7 +5,7 @@
// @flow
import React, { Component } from "react";
import { connect } from "react-redux";
import { connect } from "../../utils/connect";
import classnames from "classnames";
import actions from "../../actions";

View File

@ -5,7 +5,7 @@
// @flow
import React, { Component } from "react";
import { connect } from "react-redux";
import { connect } from "../../utils/connect";
import { List } from "immutable";
import actions from "../../actions";
@ -18,8 +18,7 @@ import {
getIsWaitingOnBreak,
getShouldPauseOnExceptions,
getShouldPauseOnCaughtExceptions,
getWorkers,
getExtra
getWorkers
} from "../../selectors";
import Svg from "../shared/Svg";
@ -33,7 +32,6 @@ import Workers from "./Workers";
import Accordion from "../shared/Accordion";
import CommandBar from "./CommandBar";
import UtilsBar from "./UtilsBar";
import FrameworkComponent from "./FrameworkComponent";
import XHRBreakpoints from "./XHRBreakpoints";
import Scopes from "./Scopes";
@ -72,7 +70,6 @@ type State = {
type Props = {
expressions: List<Expression>,
extra: Object,
hasFrames: boolean,
horizontal: boolean,
breakpoints: Object,
@ -216,22 +213,6 @@ class SecondaryPanes extends Component<Props, State> {
};
}
getComponentItem() {
const {
extra: { react }
} = this.props;
return {
header: react.displayName,
className: "component-pane",
component: <FrameworkComponent />,
opened: prefs.componentVisible,
onToggle: opened => {
prefs.componentVisible = opened;
}
};
}
getWatchItem(): AccordionPaneItem {
return {
header: L10N.getStr("watchExpressions.header"),
@ -318,7 +299,7 @@ class SecondaryPanes extends Component<Props, State> {
}
getStartItems() {
const { extra, workers } = this.props;
const { workers } = this.props;
const items: Array<AccordionPaneItem> = [];
if (this.props.horizontal) {
@ -335,10 +316,6 @@ class SecondaryPanes extends Component<Props, State> {
items.push(this.getCallStackItem());
if (this.props.horizontal) {
if (features.componentPane && extra && extra.react) {
items.push(this.getComponentItem());
}
items.push(this.getScopeItem());
}
}
@ -355,7 +332,7 @@ class SecondaryPanes extends Component<Props, State> {
}
getEndItems() {
const { extra, workers } = this.props;
const { workers } = this.props;
let items: Array<AccordionPaneItem> = [];
@ -369,10 +346,6 @@ class SecondaryPanes extends Component<Props, State> {
items.push(this.getWatchItem());
if (features.componentPane && extra && extra.react) {
items.push(this.getComponentItem());
}
if (this.props.hasFrames) {
items = [...items, this.getScopeItem()];
}
@ -427,7 +400,6 @@ class SecondaryPanes extends Component<Props, State> {
const mapStateToProps = state => ({
expressions: getExpressions(state),
extra: getExtra(state),
hasFrames: !!getTopFrame(state),
breakpoints: getBreakpointsList(state),
breakpointsDisabled: getBreakpointsDisabled(state),

View File

@ -11,7 +11,6 @@ DIRS += [
DebuggerModules(
'CommandBar.js',
'Expressions.js',
'FrameworkComponent.js',
'index.js',
'Scopes.js',
'UtilsBar.js',

View File

@ -5,7 +5,7 @@
// @flow
import React, { Component } from "react";
import { connect } from "react-redux";
import { connect } from "../utils/connect";
import actions from "../actions";
import { getPaneCollapse } from "../selectors";

View File

@ -6,7 +6,7 @@
import React, { PureComponent } from "react";
import { connect } from "react-redux";
import { connect } from "../../utils/connect";
import AccessibleImage from "./AccessibleImage";

View File

@ -13,15 +13,10 @@ import * as I from "immutable";
import makeRecord from "../utils/makeRecord";
import { findEmptyLines } from "../utils/ast";
import type {
AstLocation,
SymbolDeclarations,
PausePoints,
PausePoint
} from "../workers/parser";
import type { AstLocation, SymbolDeclarations } from "../workers/parser";
import type { Map } from "immutable";
import type { SourceLocation, Source } from "../types";
import type { SourceLocation, Source, Position } from "../types";
import type { Action, DonePromiseAction } from "../actions/types";
import type { Record } from "../utils/makeRecord";
@ -36,7 +31,18 @@ export type SourceMetaDataType = {
};
export type SourceMetaDataMap = Map<string, SourceMetaDataType>;
export type PausePointsMap = Map<string, PausePoints>;
export type PausePoint = {
location: Position,
generatedLocation: SourceLocation,
types: { break: boolean, step: boolean }
};
export type PausePointsMap = {
[line: string]: { [column: string]: PausePoint }
};
export type PausePoints = PausePoint[];
export type PausePointsState = Map<string, PausePoint[]>;
export type Preview =
| {| updating: true |}
@ -47,8 +53,7 @@ export type Preview =
location: AstLocation,
cursorPos: any,
tokenPos: AstLocation,
result: Object,
extra: Object
result: Object
|};
export type ASTState = {
@ -57,22 +62,20 @@ export type ASTState = {
outOfScopeLocations: ?Array<AstLocation>,
inScopeLines: ?Array<Number>,
preview: Preview,
pausePoints: PausePointsMap,
pausePoints: PausePointsState,
sourceMetaData: SourceMetaDataMap
};
export function initialASTState() {
return makeRecord(
({
symbols: I.Map(),
emptyLines: I.Map(),
outOfScopeLocations: null,
inScopeLines: null,
preview: null,
pausePoints: I.Map(),
sourceMetaData: I.Map()
}: ASTState)
)();
export function initialASTState(): Record<ASTState> {
return makeRecord({
symbols: I.Map(),
emptyLines: I.Map(),
outOfScopeLocations: null,
inScopeLines: null,
preview: null,
pausePoints: I.Map(),
sourceMetaData: I.Map()
})();
}
function update(
@ -221,12 +224,35 @@ export function getPausePoint(
return;
}
const linePoints = pausePoints[String(line)];
if (linePoints && column) {
return linePoints[String(column)];
for (const point of pausePoints) {
const { location: pointLocation } = point;
if (pointLocation.line == line && pointLocation.column == column) {
return point;
}
}
}
export function getFirstPausePointLocation(
state: OuterState,
location: SourceLocation
): SourceLocation {
const { sourceId } = location;
const pausePoints = getPausePoints(state, location.sourceId);
if (!pausePoints) {
return location;
}
const pausesAtLine = pausePoints[location.line];
if (pausesAtLine) {
const values: PausePoint[] = (Object.values(pausesAtLine): any);
const firstPausePoint = values.find(pausePoint => pausePoint.types.break);
if (firstPausePoint) {
return { ...firstPausePoint.location, sourceId };
}
}
return location;
}
export function hasPausePoints(state: OuterState, sourceId: string): boolean {
const pausePoints = getPausePoints(state, sourceId);
return !!pausePoints;

View File

@ -21,11 +21,9 @@ type DebuggeeState = {
workers: WorkersList
};
export const createDebuggeeState = makeRecord(
({
workers: List()
}: DebuggeeState)
);
export const createDebuggeeState: () => Record<DebuggeeState> = makeRecord({
workers: List()
});
export default function debuggee(
state: Record<DebuggeeState> = createDebuggeeState(),

View File

@ -13,7 +13,7 @@ import makeRecord from "../utils/makeRecord";
import { List, Map } from "immutable";
import { omit, zip } from "lodash";
import { createSelector } from "reselect";
import { createSelector } from "../utils/createSelector";
import { prefs } from "../utils/prefs";
import type { Expression } from "../types";
@ -27,14 +27,12 @@ export type ExpressionState = {
currentAutocompleteInput: string | null
};
export const createExpressionState = makeRecord(
({
expressions: List(restoreExpressions()),
expressionError: false,
autocompleteMatches: Map({}),
currentAutocompleteInput: null
}: ExpressionState)
);
export const createExpressionState: () => Record<ExpressionState> = makeRecord({
expressions: List(restoreExpressions()),
expressionError: false,
autocompleteMatches: Map({}),
currentAutocompleteInput: null
});
function update(
state: Record<ExpressionState> = createExpressionState(),

View File

@ -46,17 +46,15 @@ const emptySearchResults = Object.freeze({
count: 0
});
export const createFileSearchState = makeRecord(
({
query: "",
searchResults: emptySearchResults,
modifiers: makeRecord({
caseSensitive: prefs.fileSearchCaseSensitive,
wholeWord: prefs.fileSearchWholeWord,
regexMatch: prefs.fileSearchRegexMatch
})()
}: FileSearchState)
);
export const createFileSearchState: () => Record<FileSearchState> = makeRecord({
query: "",
searchResults: emptySearchResults,
modifiers: makeRecord({
caseSensitive: prefs.fileSearchCaseSensitive,
wholeWord: prefs.fileSearchWholeWord,
regexMatch: prefs.fileSearchRegexMatch
})()
});
function update(
state: Record<FileSearchState> = createFileSearchState(),

View File

@ -10,7 +10,7 @@
* @module reducers/pause
*/
import { createSelector } from "reselect";
import { createSelector } from "../utils/createSelector";
import { isGeneratedId } from "devtools-source-map";
import { prefs } from "../utils/prefs";
import { getSelectedSource } from "./sources";
@ -32,8 +32,8 @@ export type Command =
| "reverseStepOut"
| "expression";
export type PauseState = {
extra: ?Object,
// Pause state associated with an individual thread.
type ThreadPauseState = {
why: ?Why,
isWaitingOnBreak: boolean,
frames: ?(any[]),
@ -60,27 +60,29 @@ export type PauseState = {
loadedObjects: Object,
shouldPauseOnExceptions: boolean,
shouldPauseOnCaughtExceptions: boolean,
canRewind: boolean,
debuggeeUrl: string,
command: Command,
previousLocation: ?MappedLocation,
skipPausing: boolean
};
// Pause state describing all threads.
export type PauseState = {
mainThread: string,
currentThread: string,
debuggeeUrl: string,
canRewind: boolean,
threads: { [string]: ThreadPauseState }
};
export const createPauseState = (): PauseState => ({
...emptyPauseState,
extra: {},
isWaitingOnBreak: false,
shouldPauseOnExceptions: prefs.pauseOnExceptions,
shouldPauseOnCaughtExceptions: prefs.pauseOnCaughtExceptions,
mainThread: "UnknownThread",
currentThread: "UnknownThread",
threads: {},
canRewind: false,
debuggeeUrl: "",
command: null,
previousLocation: null,
skipPausing: prefs.skipPausing
debuggeeUrl: ""
});
const emptyPauseState = {
const resumedPauseState = {
frames: null,
frameScopes: {
generated: {},
@ -92,13 +94,56 @@ const emptyPauseState = {
why: null
};
const createInitialPauseState = () => ({
...resumedPauseState,
isWaitingOnBreak: false,
shouldPauseOnExceptions: prefs.pauseOnExceptions,
shouldPauseOnCaughtExceptions: prefs.pauseOnCaughtExceptions,
canRewind: false,
debuggeeUrl: "",
command: null,
previousLocation: null,
skipPausing: prefs.skipPausing
});
function getThreadPauseState(state: PauseState, thread: string) {
// Thread state is lazily initialized so that we don't have to keep track of
// the current set of worker threads.
return state.threads[thread] || createInitialPauseState();
}
function update(
state: PauseState = createPauseState(),
action: Action
): PauseState {
// Actions need to specify any thread they are operating on. These helpers
// manage updating the pause state for that thread.
const threadState = () => {
if (!action.thread) {
throw new Error(`Missing thread in action ${action.type}`);
}
return getThreadPauseState(state, action.thread);
};
const updateThreadState = newThreadState => {
if (!action.thread) {
throw new Error(`Missing thread in action ${action.type}`);
}
return {
...state,
threads: {
...state.threads,
[action.thread]: { ...threadState(), ...newThreadState }
}
};
};
switch (action.type) {
case "SELECT_THREAD":
return { ...state, currentThread: action.thread };
case "PAUSED": {
const { selectedFrameId, frames, loadedObjects, why } = action;
const { thread, selectedFrameId, frames, loadedObjects, why } = action;
// turn this into an object keyed by object id
const objectMap = {};
@ -106,24 +151,20 @@ function update(
objectMap[obj.value.objectId] = obj;
});
return {
...state,
state = { ...state, currentThread: thread };
return updateThreadState({
isWaitingOnBreak: false,
selectedFrameId,
frames,
frameScopes: { ...emptyPauseState.frameScopes },
frameScopes: { ...resumedPauseState.frameScopes },
loadedObjects: objectMap,
why
};
});
}
case "MAP_FRAMES": {
const { selectedFrameId, frames } = action;
return { ...state, frames, selectedFrameId };
}
case "ADD_EXTRA": {
return { ...state, extra: action.extra };
return updateThreadState({ frames, selectedFrameId });
}
case "ADD_SCOPES": {
@ -131,33 +172,30 @@ function update(
const selectedFrameId = frame.id;
const generated = {
...state.frameScopes.generated,
...threadState().frameScopes.generated,
[selectedFrameId]: {
pending: status !== "done",
scope: value
}
};
return {
...state,
return updateThreadState({
frameScopes: {
...state.frameScopes,
...threadState().frameScopes,
generated
}
};
});
}
case "TRAVEL_TO":
return {
...state,
...action.data.paused
};
return updateThreadState({ ...action.data.paused });
case "MAP_SCOPES": {
const { frame, status, value } = action;
const selectedFrameId = frame.id;
const original = {
...state.frameScopes.original,
...threadState().frameScopes.original,
[selectedFrameId]: {
pending: status !== "done",
scope: value && value.scope
@ -165,49 +203,48 @@ function update(
};
const mappings = {
...state.frameScopes.mappings,
...threadState().frameScopes.mappings,
[selectedFrameId]: value && value.mappings
};
return {
...state,
return updateThreadState({
frameScopes: {
...state.frameScopes,
...threadState().frameScopes,
original,
mappings
}
};
});
}
case "BREAK_ON_NEXT":
return { ...state, isWaitingOnBreak: true };
return updateThreadState({ isWaitingOnBreak: true });
case "SELECT_FRAME":
return {
...state,
selectedFrameId: action.frame.id
};
return updateThreadState({ selectedFrameId: action.frame.id });
case "SET_POPUP_OBJECT_PROPERTIES":
case "SET_POPUP_OBJECT_PROPERTIES": {
if (!action.properties) {
return { ...state };
return state;
}
return {
...state,
return updateThreadState({
loadedObjects: {
...state.loadedObjects,
...threadState().loadedObjects,
[action.objectId]: action.properties
}
};
});
}
case "CONNECT":
return {
...createPauseState(),
mainThread: action.thread,
currentThread: action.thread,
debuggeeUrl: action.url,
canRewind: action.canRewind
};
case "PAUSE_ON_EXCEPTIONS":
case "PAUSE_ON_EXCEPTIONS": {
const { shouldPauseOnExceptions, shouldPauseOnCaughtExceptions } = action;
prefs.pauseOnExceptions = shouldPauseOnExceptions;
@ -216,40 +253,52 @@ function update(
// Preserving for the old debugger
prefs.ignoreCaughtExceptions = !shouldPauseOnCaughtExceptions;
return {
...state,
return updateThreadState({
shouldPauseOnExceptions,
shouldPauseOnCaughtExceptions
};
case "COMMAND": {
return action.status === "start"
? {
...state,
...emptyPauseState,
command: action.command,
previousLocation: getPauseLocation(state, action)
}
: { ...state, command: null };
});
}
case "COMMAND":
if (action.status === "start") {
return updateThreadState({
...resumedPauseState,
command: action.command,
previousLocation: getPauseLocation(threadState(), action)
});
}
return updateThreadState({ command: null });
case "RESUME":
return { ...state, ...emptyPauseState };
// Workaround for threads resuming before the initial connection.
if (!action.thread && !state.currentThread) {
return state;
}
return updateThreadState(resumedPauseState);
case "EVALUATE_EXPRESSION":
return {
...state,
return updateThreadState({
command: action.status === "start" ? "expression" : null
};
});
case "NAVIGATE":
return { ...state, ...emptyPauseState, debuggeeUrl: action.url };
return {
...state,
currentThread: state.mainThread,
threads: {
[state.mainThread]: {
...state.threads[state.mainThread],
...resumedPauseState
}
},
debuggeeUrl: action.url
};
case "TOGGLE_SKIP_PAUSING": {
const { skipPausing } = action;
prefs.skipPausing = skipPausing;
return { ...state, skipPausing };
return updateThreadState({ skipPausing });
}
}
@ -287,25 +336,39 @@ function getPauseLocation(state, action) {
// (right now) to type those wrapped functions.
type OuterState = State;
const getPauseState = state => state.pause;
function getCurrentPauseState(state: OuterState): ThreadPauseState {
return getThreadPauseState(state.pause, state.pause.currentThread);
}
export const getAllPopupObjectProperties = createSelector(
getPauseState,
getCurrentPauseState,
pauseWrapper => pauseWrapper.loadedObjects
);
export function getPauseReason(state: OuterState): ?Why {
return state.pause.why;
return getCurrentPauseState(state).why;
}
export function getPauseCommand(state: OuterState): Command {
return state.pause && state.pause.command;
return getCurrentPauseState(state).command;
}
export function isStepping(state: OuterState) {
return ["stepIn", "stepOver", "stepOut"].includes(getPauseCommand(state));
}
export function getMainThread(state: OuterState) {
return state.pause.mainThread;
}
export function getCurrentThread(state: OuterState) {
return state.pause.currentThread;
}
export function threadIsPaused(state: OuterState, thread: string) {
return !!getThreadPauseState(state.pause, thread).frames;
}
export function isPaused(state: OuterState) {
return !!getFrames(state);
}
@ -315,11 +378,11 @@ export function getIsPaused(state: OuterState) {
}
export function getPreviousPauseFrameLocation(state: OuterState) {
return state.pause.previousLocation;
return getCurrentPauseState(state).previousLocation;
}
export function isEvaluatingExpression(state: OuterState) {
return state.pause.command === "expression";
return getCurrentPauseState(state).command === "expression";
}
export function getPopupObjectProperties(state: OuterState, objectId: string) {
@ -327,27 +390,23 @@ export function getPopupObjectProperties(state: OuterState, objectId: string) {
}
export function getIsWaitingOnBreak(state: OuterState) {
return state.pause.isWaitingOnBreak;
return getCurrentPauseState(state).isWaitingOnBreak;
}
export function getShouldPauseOnExceptions(state: OuterState) {
return state.pause.shouldPauseOnExceptions;
return getCurrentPauseState(state).shouldPauseOnExceptions;
}
export function getShouldPauseOnCaughtExceptions(state: OuterState) {
return state.pause.shouldPauseOnCaughtExceptions;
return getCurrentPauseState(state).shouldPauseOnCaughtExceptions;
}
export function getCanRewind(state: OuterState) {
return state.pause.canRewind;
}
export function getExtra(state: OuterState) {
return state.pause.extra;
}
export function getFrames(state: OuterState) {
return state.pause.frames;
return getCurrentPauseState(state).frames;
}
function getGeneratedFrameId(frameId: string): string {
@ -389,7 +448,7 @@ export function getOriginalFrameScope(
}
export function getFrameScopes(state: OuterState) {
return state.pause.frameScopes;
return getCurrentPauseState(state).frameScopes;
}
export function getSelectedFrameBindings(state: OuterState) {
@ -467,7 +526,7 @@ export function getSelectedScopeMappings(
}
export function getSelectedFrameId(state: OuterState) {
return state.pause.selectedFrameId;
return getCurrentPauseState(state).selectedFrameId;
}
export function getTopFrame(state: OuterState) {
@ -492,7 +551,7 @@ export function getDebuggeeUrl(state: OuterState) {
}
export function getSkipPausing(state: OuterState) {
return state.pause.skipPausing;
return getCurrentPauseState(state).skipPausing;
}
// NOTE: currently only used for chrome

View File

@ -10,17 +10,12 @@
* @module reducers/project-text-search
*/
import * as I from "immutable";
import makeRecord from "../utils/makeRecord";
import type { Action } from "../actions/types";
import type { Record } from "../utils/makeRecord";
import type { List } from "immutable";
export type Search = {
id: string,
filepath: string,
matches: I.List<any>
+sourceId: string,
+filepath: string,
+matches: any[]
};
export type StatusType = "INITIAL" | "FETCHING" | "DONE" | "ERROR";
export const statusType = {
@ -30,77 +25,75 @@ export const statusType = {
error: "ERROR"
};
export type ResultRecord = Record<Search>;
export type ResultList = List<ResultRecord>;
export type ResultList = Search[];
export type ProjectTextSearchState = {
query: string,
results: ResultList,
status: string
+query: string,
+results: ResultList,
+status: string
};
export function initialProjectTextSearchState(): Record<
ProjectTextSearchState
> {
return makeRecord(
({
query: "",
results: I.List(),
status: statusType.initial
}: ProjectTextSearchState)
)();
export function initialProjectTextSearchState(): ProjectTextSearchState {
return {
query: "",
results: [],
status: statusType.initial
};
}
function update(
state: Record<ProjectTextSearchState> = initialProjectTextSearchState(),
state: ProjectTextSearchState = initialProjectTextSearchState(),
action: Action
): Record<ProjectTextSearchState> {
): ProjectTextSearchState {
switch (action.type) {
case "ADD_QUERY":
const actionCopy = action;
return state.update("query", value => actionCopy.query);
return { ...state, query: action.query };
case "CLEAR_QUERY":
return state.merge({
return {
...state,
query: "",
status: statusType.initial
});
};
case "ADD_SEARCH_RESULT":
const results = state.get("results");
return state.merge({ results: results.push(action.result) });
const results = state.results;
if (action.result.matches.length === 0) {
return state;
}
const result = {
type: "RESULT",
...action.result,
matches: action.result.matches.map(m => ({ type: "MATCH", ...m }))
};
return { ...state, results: [...results, result] };
case "UPDATE_STATUS":
return state.merge({ status: action.status });
return { ...state, status: action.status };
case "CLEAR_SEARCH_RESULTS":
return state.merge({
results: state.get("results").clear()
});
return { ...state, results: [] };
case "CLEAR_SEARCH":
case "CLOSE_PROJECT_SEARCH":
case "NAVIGATE":
return state.merge({
query: "",
results: state.get("results").clear(),
status: statusType.initial
});
return initialProjectTextSearchState();
}
return state;
}
type OuterState = { projectTextSearch: Record<ProjectTextSearchState> };
type OuterState = { projectTextSearch: ProjectTextSearchState };
export function getTextSearchResults(state: OuterState) {
return state.projectTextSearch.get("results");
return state.projectTextSearch.results;
}
export function getTextSearchStatus(state: OuterState) {
return state.projectTextSearch.get("status");
return state.projectTextSearch.status;
}
export function getTextSearchQuery(state: OuterState) {
return state.projectTextSearch.get("query");
return state.projectTextSearch.query;
}
export default update;

View File

@ -9,7 +9,7 @@
* @module reducers/sources
*/
import { createSelector } from "reselect";
import { createSelector } from "../utils/createSelector";
import {
getPrettySourceURL,
underRoot,

View File

@ -9,7 +9,7 @@
* @module reducers/tabs
*/
import { createSelector } from "reselect";
import { createSelector } from "../utils/createSelector";
import { isOriginalId } from "devtools-source-map";
import move from "lodash-move";

View File

@ -43,21 +43,19 @@ export type UIState = {
conditionalPanelLocation: null | SourceLocation
};
export const createUIState = makeRecord(
({
selectedPrimaryPaneTab: "sources",
activeSearch: null,
contextMenu: {},
shownSource: null,
startPanelCollapsed: prefs.startPanelCollapsed,
endPanelCollapsed: prefs.endPanelCollapsed,
frameworkGroupingOn: prefs.frameworkGroupingOn,
highlightedLineRange: undefined,
conditionalPanelLocation: null,
orientation: "horizontal",
viewport: null
}: UIState)
);
export const createUIState: () => Record<UIState> = makeRecord({
selectedPrimaryPaneTab: "sources",
activeSearch: null,
contextMenu: {},
shownSource: null,
startPanelCollapsed: prefs.startPanelCollapsed,
endPanelCollapsed: prefs.endPanelCollapsed,
frameworkGroupingOn: prefs.frameworkGroupingOn,
highlightedLineRange: undefined,
conditionalPanelLocation: null,
orientation: "horizontal",
viewport: null
});
function update(
state: Record<UIState> = createUIState(),
@ -186,7 +184,7 @@ export function getConditionalPanelLocation(
return state.ui.get("conditionalPanelLocation");
}
export function getOrientation(state: OuterState): boolean {
export function getOrientation(state: OuterState): OrientationType {
return state.ui.get("orientation");
}

View File

@ -5,7 +5,7 @@
// @flow
import { sortBy, uniq } from "lodash";
import { createSelector } from "reselect";
import { createSelector } from "../utils/createSelector";
import {
getSources,
getBreakpointsList,

View File

@ -4,7 +4,7 @@
// @flow
import { createSelector } from "reselect";
import { createSelector } from "../utils/createSelector";
import type {
BreakpointsState,

View File

@ -13,7 +13,7 @@ import { isOriginal } from "../utils/source";
import { get } from "lodash";
import type { Frame, Source } from "../types";
import type { SourcesMap } from "../reducers/sources";
import { createSelector } from "reselect";
import { createSelector } from "../utils/createSelector";
function getLocation(frame, isGeneratedSource) {
return isGeneratedSource

View File

@ -5,7 +5,7 @@
// @flow
import { isGeneratedId } from "devtools-source-map";
import { createSelector } from "reselect";
import { createSelector } from "../utils/createSelector";
import { uniqBy } from "lodash";
import { getBreakpointsList } from "../reducers/breakpoints";
@ -46,7 +46,7 @@ function isVisible(breakpoint, selectedSource) {
/*
* Finds the breakpoints, which appear in the selected source.
*/
*/
export const getVisibleBreakpoints = createSelector(
getSelectedSource,
getBreakpointsList,
@ -63,7 +63,7 @@ export const getVisibleBreakpoints = createSelector(
/*
* Finds the first breakpoint per line, which appear in the selected source.
*/
*/
export const getFirstVisibleBreakpoints = createSelector(
getVisibleBreakpoints,
breakpoints => {

View File

@ -3,7 +3,7 @@
* file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
import { groupBy, get, sortedUniqBy } from "lodash";
import { createSelector } from "reselect";
import { createSelector } from "../utils/createSelector";
import { getViewport } from "../selectors";
import { getVisibleBreakpoints } from "./visibleBreakpoints";

View File

@ -4,7 +4,6 @@
import { getSelectedSource } from "../reducers/sources";
import { getPausePoints } from "../reducers/ast";
import { convertToList } from "../utils/pause/pausePoints";
export function getVisiblePausePoints(state) {
const source = getSelectedSource(state);
@ -12,6 +11,5 @@ export function getVisiblePausePoints(state) {
return null;
}
const pausePoints = getPausePoints(state, source.id);
return convertToList(pausePoints);
return getPausePoints(state, source.id);
}

View File

@ -7,7 +7,7 @@
import { getSelectedLocation } from "../reducers/sources";
import { getSelectedFrame } from "../reducers/pause";
import { isOriginalId } from "devtools-source-map";
import { createSelector } from "reselect";
import { createSelector } from "../utils/createSelector";
import type { Frame, SourceLocation } from "../types";

View File

@ -5,18 +5,16 @@
// @flow
import { xor, range } from "lodash";
import { convertToList } from "./pause/pausePoints";
import type { SourceLocation, Position } from "../types";
import type { Symbols } from "../reducers/ast";
import type {
AstPosition,
AstLocation,
PausePoints,
FunctionDeclaration,
ClassDeclaration
} from "../workers/parser";
import type { PausePoints } from "../reducers/types";
export function findBestMatchExpression(symbols: Symbols, tokenPos: Position) {
if (symbols.loading) {
@ -43,14 +41,15 @@ export function findBestMatchExpression(symbols: Symbols, tokenPos: Position) {
}, null);
}
export function findEmptyLines(sourceText: string, pausePoints: PausePoints) {
export function findEmptyLines(
sourceText: string,
pausePoints: PausePoints
): number[] {
if (!pausePoints || !sourceText) {
return [];
}
const pausePointsList = convertToList(pausePoints);
const breakpoints = pausePointsList.filter(point => point.types.break);
const breakpoints = pausePoints.filter(point => point.types.break);
const breakpointLines = breakpoints.map(point => point.location.line);
if (!sourceText || breakpointLines.length == 0) {

View File

@ -198,12 +198,19 @@ export function sortBreakpoints(breakpoints: Breakpoint[]) {
return _sortBreakpoints(breakpoints, "location");
}
function _sortBreakpoints(breakpoints: Array<Object>, property: string) {
return sortBy(breakpoints, [
// Priority: line number, undefined column, column number
`${property}.line`,
bp => {
return bp[property].column === undefined || bp[property].column;
}
]);
function _sortBreakpoints(
breakpoints: Array<Object>,
property: string
): Array<Object> {
// prettier-ignore
return sortBy(
breakpoints,
[
// Priority: line number, undefined column, column number
`${property}.line`,
bp => {
return bp[property].column === undefined || bp[property].column;
}
]
);
}

View File

@ -0,0 +1,17 @@
/* 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 { connect as reduxConnect } from "react-redux";
import * as React from "react";
export function connect<Config, RSP: {}, MDP: {}>(
mapStateToProps: (state: any, props: any) => RSP,
mapDispatchToProps?: (() => MDP) | MDP
): (
Component: React.AbstractComponent<Config>
) => React.AbstractComponent<$Diff<Config, RSP & MDP>> {
// $FlowFixMe
return reduxConnect(mapStateToProps, mapDispatchToProps);
}

View File

@ -0,0 +1,12 @@
/* 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/>. */
import { createSelector as reselectCreateSelector } from "reselect";
function createSelector(...args) {
// $FlowFixMe
return reselectCreateSelector(...args);
}
export { createSelector };

View File

@ -18,7 +18,7 @@ import { isWasm, lineToWasmOffset, wasmOffsetToLine } from "../wasm";
import type { AstLocation } from "../../workers/parser";
import type { EditorPosition, EditorRange } from "../editor/types";
import type { SourceLocation } from "../../types";
import type { SearchModifiers, Source, SourceLocation } from "../../types";
type Editor = Object;
let editor: ?Editor;
@ -58,11 +58,11 @@ export function endOperation() {
codeMirror.endOperation();
}
export function shouldShowPrettyPrint(source) {
export function shouldShowPrettyPrint(source: Source) {
return shouldPrettyPrint(source);
}
export function shouldShowFooter(source, horizontal) {
export function shouldShowFooter(source: ?Source, horizontal: boolean) {
if (!horizontal) {
return true;
}
@ -72,7 +72,13 @@ export function shouldShowFooter(source, horizontal) {
return shouldShowPrettyPrint(source) || isOriginal(source);
}
export function traverseResults(e, ctx, query, dir, modifiers) {
export function traverseResults(
e: Event,
ctx: any,
query: string,
dir: string,
modifiers: SearchModifiers
) {
e.stopPropagation();
e.preventDefault();
@ -181,7 +187,7 @@ export function getLocationsInViewport({ codeMirror }: Object) {
export function markText(
{ codeMirror }: Object,
className,
className: String,
{ start, end }: EditorRange
) {
return codeMirror.markText(
@ -191,7 +197,11 @@ export function markText(
);
}
export function lineAtHeight({ codeMirror }, sourceId, event) {
export function lineAtHeight(
{ codeMirror }: Object,
sourceId: string,
event: MouseEvent
) {
const _editorLine = codeMirror.lineAtHeight(event.clientY);
return toSourceLine(sourceId, _editorLine);
}
@ -213,7 +223,7 @@ export function getSourceLocationFromMouseEvent(
};
}
export function forEachLine(codeMirror: Object, iter) {
export function forEachLine(codeMirror: Object, iter: Function) {
codeMirror.operation(() => {
codeMirror.doc.iter(0, codeMirror.lineCount(), iter);
});

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