Bug 1541629 - Part 3: Adopt new SourceActor types/actions throughout codebase. r=jlast

Differential Revision: https://phabricator.services.mozilla.com/D27958

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Logan Smyth 2019-04-19 16:07:39 +00:00
Родитель 59376adc13
Коммит cde6e6feaa
31 изменённых файлов: 463 добавлений и 331 удалений

Просмотреть файл

@ -14,10 +14,12 @@ import {
getSource,
getSourceFromId,
hasBreakpointPositions,
getBreakpointPositionsForSource
getBreakpointPositionsForSource,
getSourceActorsForSource
} from "../../selectors";
import type {
SourceId,
MappedLocation,
Range,
SourceLocation,
@ -30,8 +32,6 @@ import {
type MemoizedAction
} from "../../utils/memoizableAction";
// const requests = new Map();
async function mapLocations(
generatedLocations: SourceLocation[],
{ sourceMaps }: { sourceMaps: typeof SourceMaps }
@ -108,13 +108,18 @@ async function _setBreakpointPositions(cx, sourceId, thunkArgs) {
};
}
const bps = await client.getBreakpointPositions(generatedSource, range);
const bps = await client.getBreakpointPositions(
getSourceActorsForSource(getState(), generatedSource.id),
range
);
for (const line in bps) {
results[line] = (results[line] || []).concat(bps[line]);
}
}
} else {
results = await client.getBreakpointPositions(generatedSource);
results = await client.getBreakpointPositions(
getSourceActorsForSource(getState(), generatedSource.id)
);
}
let positions = convertToList(results, generatedSource);
@ -139,6 +144,11 @@ async function _setBreakpointPositions(cx, sourceId, thunkArgs) {
return positions;
}
const runningFetches = {};
export function isFetchingBreakpoints(id: SourceId) {
return id in runningFetches;
}
export const setBreakpointPositions: MemoizedAction<
{ cx: Context, sourceId: string },
?BreakpointPositions
@ -153,10 +163,21 @@ export const setBreakpointPositions: MemoizedAction<
isOriginalId(sourceId) ? originalToGeneratedId(sourceId) : sourceId
);
const actors = generatedSource
? generatedSource.actors.map(({ actor }) => actor)
? getSourceActorsForSource(getState(), generatedSource.id).map(
({ actor }) => actor
)
: [];
return [sourceId, ...actors].join(":");
},
action: ({ cx, sourceId }, thunkArgs) =>
_setBreakpointPositions(cx, sourceId, thunkArgs)
action: async ({ cx, sourceId }, thunkArgs) => {
runningFetches[sourceId] = (runningFetches[sourceId] | 0) + 1;
try {
return await _setBreakpointPositions(cx, sourceId, thunkArgs);
} finally {
runningFetches[sourceId] -= 0;
if (runningFetches[sourceId] === 0) {
delete runningFetches[sourceId];
}
}
}
});

Просмотреть файл

@ -35,13 +35,6 @@ Array [
},
],
"source": Object {
"actors": Array [
Object {
"actor": "a-1-actor",
"source": "a",
"thread": "FakeThread",
},
],
"contentType": "text/javascript",
"id": "a",
"introductionType": null,
@ -129,13 +122,6 @@ Array [
},
],
"source": Object {
"actors": Array [
Object {
"actor": "a-1-actor",
"source": "a",
"thread": "FakeThread",
},
],
"contentType": "text/javascript",
"id": "a",
"introductionType": null,

Просмотреть файл

@ -11,15 +11,22 @@ import {
makeSource,
waitForState
} from "../../../utils/test-head";
import { createSource } from "../../tests/helpers/threadClient";
describe("breakpointPositions", () => {
it("fetches positions", async () => {
const fooContent = createSource("foo", "");
const store = createStore({
getBreakpointPositions: async () => ({ "9": [1] })
getBreakpointPositions: async () => ({ "9": [1] }),
sourceContents: async () => fooContent
});
const { dispatch, getState, cx } = store;
await dispatch(actions.newGeneratedSource(makeSource("foo")));
const source = await dispatch(
actions.newGeneratedSource(makeSource("foo"))
);
await dispatch(actions.loadSourceById(cx, source.id));
dispatch(actions.setBreakpointPositions({ cx, sourceId: "foo" }));
@ -48,6 +55,8 @@ describe("breakpointPositions", () => {
});
it("doesn't re-fetch positions", async () => {
const fooContent = createSource("foo", "");
let resolve = _ => {};
let count = 0;
const store = createStore({
@ -55,11 +64,15 @@ describe("breakpointPositions", () => {
new Promise(r => {
count++;
resolve = r;
})
}),
sourceContents: async () => fooContent
});
const { dispatch, getState, cx } = store;
await dispatch(actions.newGeneratedSource(makeSource("foo")));
const source = await dispatch(
actions.newGeneratedSource(makeSource("foo"))
);
await dispatch(actions.loadSourceById(cx, source.id));
dispatch(actions.setBreakpointPositions({ cx, sourceId: "foo" }));
dispatch(actions.setBreakpointPositions({ cx, sourceId: "foo" }));

Просмотреть файл

@ -6,8 +6,9 @@
import { differenceBy } from "lodash";
import type { Action, ThunkArgs } from "./types";
import { removeSourceActors } from "./source-actors";
import { getContext, getWorkers } from "../selectors";
import { getContext, getWorkers, getSourceActorsForThread } from "../selectors";
export function updateWorkers() {
return async function({ dispatch, getState, client }: ThunkArgs) {
@ -19,6 +20,11 @@ export function updateWorkers() {
const addedWorkers = differenceBy(workers, currentWorkers, w => w.actor);
const removedWorkers = differenceBy(currentWorkers, workers, w => w.actor);
if (removedWorkers.length > 0) {
const sourceActors = getSourceActorsForThread(
getState(),
removedWorkers.map(w => w.actor)
);
dispatch(removeSourceActors(sourceActors));
dispatch(
({
type: "REMOVE_WORKERS",

Просмотреть файл

@ -12,7 +12,7 @@
import { isOriginalId, originalToGeneratedId } from "devtools-source-map";
import { recordEvent } from "../../utils/telemetry";
import { features } from "../../utils/prefs";
import { getSourceFromId } from "../../selectors";
import { getSourceActorsForSource } from "../../selectors";
import { PROMISE } from "../utils/middleware/promise";
@ -20,9 +20,8 @@ import type { Source, Context } from "../../types";
import type { ThunkArgs } from "../types";
async function blackboxActors(state, client, sourceId, isBlackBoxed, range?) {
const source = getSourceFromId(state, sourceId);
for (const sourceActor of source.actors) {
await client.blackBox(sourceActor, isBlackBoxed, range);
for (const actor of getSourceActorsForSource(state, sourceId)) {
await client.blackBox(actor, isBlackBoxed, range);
}
return { isBlackBoxed: !isBlackBoxed };
}

Просмотреть файл

@ -10,7 +10,8 @@ import {
getSourceFromId,
getGeneratedSource,
getSourcesEpoch,
getBreakpointsForSource
getBreakpointsForSource,
getSourceActorsForSource
} from "../../selectors";
import { setBreakpointPositions, addBreakpoint } from "../breakpoints";
@ -36,14 +37,23 @@ const telemetry = new Telemetry();
async function loadSource(
state,
source: Source,
{ sourceMaps, client }
{ sourceMaps, client, getState }
): Promise<?{
text: string,
contentType: string
}> {
if (isPretty(source) && isOriginal(source)) {
const generatedSource = getGeneratedSource(state, source);
return prettyPrintSource(sourceMaps, source, generatedSource);
if (!generatedSource) {
throw new Error("Unable to find minified original.");
}
return prettyPrintSource(
sourceMaps,
source,
generatedSource,
getSourceActorsForSource(state, generatedSource.id)
);
}
if (isOriginal(source)) {
@ -58,12 +68,13 @@ async function loadSource(
return result;
}
if (!source.actors.length) {
const actors = getSourceActorsForSource(state, source.id);
if (!actors.length) {
throw new Error("No source actor for loadSource");
}
telemetry.start(loadSourceHistogram, source);
const response = await client.sourceContents(source.actors[0]);
const response = await client.sourceContents(actors[0]);
telemetry.finish(loadSourceHistogram, source);
return {
@ -82,7 +93,7 @@ async function loadSourceTextPromise(
type: "LOAD_SOURCE_TEXT",
sourceId: source.id,
epoch,
[PROMISE]: loadSource(getState(), source, { sourceMaps, client })
[PROMISE]: loadSource(getState(), source, { sourceMaps, client, getState })
});
const newSource = getSource(getState(), source.id);

Просмотреть файл

@ -12,25 +12,32 @@
import { generatedToOriginalId } from "devtools-source-map";
import { flatten } from "lodash";
import {
stringToSourceActorId,
type SourceActor
} from "../../reducers/source-actors";
import { insertSourceActors } from "../../actions/source-actors";
import { makeSourceId } from "../../client/firefox/create";
import { toggleBlackBox } from "./blackbox";
import { syncBreakpoint, setBreakpointPositions } from "../breakpoints";
import { loadSourceText } from "./loadSourceText";
import { isFetchingBreakpoints } from "../breakpoints/breakpointPositions";
import { togglePrettyPrint } from "./prettyPrint";
import { selectLocation } from "../sources";
import {
getRawSourceURL,
isPrettyURL,
isOriginal,
isInlineScript,
isUrlExtension
isUrlExtension,
isInlineScript
} from "../../utils/source";
import {
getBlackBoxList,
getSource,
getSourceFromId,
hasSourceActor,
getPendingSelectedLocation,
getPendingBreakpointsForSource,
hasBreakpointPositions,
getContext
} from "../../selectors";
@ -245,8 +252,8 @@ export function newOriginalSource(sourceInfo: OriginalSourceData) {
};
}
export function newOriginalSources(sourceInfo: Array<OriginalSourceData>) {
return async ({ dispatch }: ThunkArgs) => {
const sources = sourceInfo.map(({ id, url }) => ({
return async ({ dispatch, getState }: ThunkArgs) => {
const sources: Array<Source> = sourceInfo.map(({ id, url }) => ({
id,
url,
relativeUrl: url,
@ -256,11 +263,15 @@ export function newOriginalSources(sourceInfo: Array<OriginalSourceData>) {
loadedState: "unloaded",
introductionUrl: null,
introductionType: undefined,
isExtension: false,
actors: []
isExtension: false
}));
return dispatch(newInnerSources(sources));
const cx = getContext(getState());
dispatch(addSources(cx, sources));
await dispatch(checkNewSources(cx, sources));
return sources;
};
}
@ -271,65 +282,101 @@ export function newGeneratedSource(sourceInfo: GeneratedSourceData) {
};
}
export function newGeneratedSources(sourceInfo: Array<GeneratedSourceData>) {
return async ({ dispatch, client }: ThunkArgs) => {
return async ({
dispatch,
getState,
client
}: ThunkArgs): Promise<Array<Source>> => {
const supportsWasm = client.hasWasmSupport();
const sources: Array<Source> = sourceInfo.map(({ thread, source, id }) => {
id = id || makeSourceId(source);
const sourceActor = {
actor: source.actor,
source: id,
thread
};
const createdSource: any = {
id,
url: source.url,
relativeUrl: source.url,
isPrettyPrinted: false,
sourceMapURL: source.sourceMapURL,
introductionUrl: source.introductionUrl,
introductionType: source.introductionType,
isBlackBoxed: false,
loadedState: "unloaded",
isWasm: !!supportsWasm && source.introductionType === "wasm",
isExtension: (source.url && isUrlExtension(source.url)) || false,
actors: [sourceActor]
};
return createdSource;
});
return dispatch(newInnerSources(sources));
};
}
const resultIds = [];
const newSources: Array<Source> = [];
const newSourceActors: Array<SourceActor> = [];
function newInnerSources(sources: Source[]) {
return async ({ dispatch, getState }: ThunkArgs) => {
const cx = getContext(getState());
for (const { thread, source, id } of sourceInfo) {
const newId = id || makeSourceId(source);
const _newSources = sources.filter(
source => !getSource(getState(), source.id) || isInlineScript(source)
);
if (!getSource(getState(), newId)) {
newSources.push(
({
id: newId,
url: source.url,
relativeUrl: source.url,
isPrettyPrinted: false,
sourceMapURL: source.sourceMapURL,
introductionUrl: source.introductionUrl,
introductionType: source.introductionType,
isBlackBoxed: false,
loadedState: "unloaded",
isWasm: !!supportsWasm && source.introductionType === "wasm",
isExtension: (source.url && isUrlExtension(source.url)) || false
}: any)
);
}
const sourcesNeedingPositions = _newSources.filter(source =>
hasBreakpointPositions(getState(), source.id)
);
const actorId = stringToSourceActorId(source.actor);
dispatch({ type: "ADD_SOURCES", cx, sources });
// We are sometimes notified about a new source multiple times if we
// request a new source list and also get a source event from the server.
if (!hasSourceActor(getState(), actorId)) {
newSourceActors.push({
id: actorId,
actor: source.actor,
thread,
source: newId,
for (const source of _newSources) {
dispatch(checkSelectedSource(cx, source.id));
isBlackBoxed: source.isBlackBoxed,
sourceMapURL: source.sourceMapURL,
url: source.url,
introductionUrl: source.introductionUrl,
introductionType: source.introductionType
});
}
resultIds.push(newId);
}
const cx = getContext(getState());
dispatch(addSources(cx, newSources));
const sourceIDsNeedingPositions = newSourceActors
.map(actor => actor.source)
.filter(sourceId => {
const source = getSource(getState(), sourceId);
return (
source && isInlineScript(source) && isFetchingBreakpoints(sourceId)
);
});
dispatch(insertSourceActors(newSourceActors));
// Adding new sources may have cleared this file's breakpoint positions
// in cases where a new <script> loaded in the HTML, so we manually
// re-request new breakpoint positions.
for (const source of sourcesNeedingPositions) {
if (!hasBreakpointPositions(getState(), source.id)) {
dispatch(setBreakpointPositions({ cx, sourceId: source.id }));
}
for (const sourceId of sourceIDsNeedingPositions) {
dispatch(setBreakpointPositions({ cx, sourceId }));
}
dispatch(restoreBlackBoxedSources(cx, _newSources));
dispatch(loadSourceMaps(cx, _newSources));
await dispatch(checkNewSources(cx, newSources));
return resultIds.map(id => getSourceFromId(getState(), id));
};
}
function addSources(cx, sources: Array<Source>) {
return ({ dispatch, getState }: ThunkArgs) => {
dispatch({ type: "ADD_SOURCES", cx, sources });
};
}
function checkNewSources(cx, sources: Source[]) {
return async ({ dispatch, getState }: ThunkArgs) => {
for (const source of sources) {
dispatch(checkSelectedSource(cx, source.id));
}
dispatch(restoreBlackBoxedSources(cx, sources));
dispatch(loadSourceMaps(cx, sources));
return sources;
};

Просмотреть файл

@ -26,12 +26,13 @@ import {
import type { Action, ThunkArgs } from "../types";
import { selectSource } from "./select";
import type { JsSource, Source, Context } from "../../types";
import type { JsSource, Source, SourceActor, Context } from "../../types";
export async function prettyPrintSource(
sourceMaps: typeof SourceMaps,
prettySource: Source,
generatedSource: any
generatedSource: Source,
actors: Array<SourceActor>
) {
const url = getPrettySourceURL(generatedSource.url);
const { code, mappings } = await prettyPrint({
@ -42,8 +43,8 @@ export async function prettyPrintSource(
// The source map URL service used by other devtools listens to changes to
// sources based on their actor IDs, so apply the mapping there too.
for (const sourceActor of generatedSource.actors) {
await sourceMaps.applySourceMap(sourceActor.actor, url, code, mappings);
for (const { actor } of actors) {
await sourceMaps.applySourceMap(actor, url, code, mappings);
}
return {
id: prettySource.id,
@ -69,8 +70,7 @@ export function createPrettySource(cx: Context, sourceId: string) {
loadedState: "loading",
introductionUrl: null,
introductionType: undefined,
isExtension: false,
actors: []
isExtension: false
};
dispatch(({ type: "ADD_SOURCE", cx, source: prettySource }: Action));

Просмотреть файл

@ -2,7 +2,6 @@
exports[`sources - pretty print returns a pretty source for a minified file 1`] = `
Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "base.js/originalSource-36c718d4bde9a75edb388ff7733efe7f",
"introductionType": undefined,

Просмотреть файл

@ -27,7 +27,10 @@ describe("blackbox", () => {
throw new Error("foo should exist");
}
const thread = foo1Source.actors[0].thread;
const { thread } = selectors.getSourceActorsForSource(
getState(),
foo1Source.id
)[0];
const displayedSources = selectors.getDisplayedSourcesForThread(
getState(),
thread

Просмотреть файл

@ -64,7 +64,10 @@ describe("loadSourceText", () => {
getOriginalLocations: async items =>
items.map(item => ({
...item,
sourceId: fooOrigSource.id
sourceId:
item.sourceId === fooGenSource1.id
? fooOrigSource1.id
: fooOrigSource2.id
})),
getOriginalSourceText: async s => ({
text: fooOrigContent.source,
@ -74,36 +77,66 @@ describe("loadSourceText", () => {
);
const { cx, dispatch, getState } = store;
const fooGenSource = await dispatch(
actions.newGeneratedSource(makeSource("fooGen"))
const fooGenSource1 = await dispatch(
actions.newGeneratedSource(makeSource("fooGen1"))
);
const fooOrigSource = await dispatch(
actions.newOriginalSource(makeOriginalSource(fooGenSource))
const fooOrigSource1 = await dispatch(
actions.newOriginalSource(makeOriginalSource(fooGenSource1))
);
const fooGenSource2 = await dispatch(
actions.newGeneratedSource(makeSource("fooGen2"))
);
const fooOrigSource2 = await dispatch(
actions.newOriginalSource(makeOriginalSource(fooGenSource2))
);
const location = {
sourceId: fooOrigSource.id,
line: 1,
column: 0
};
await dispatch(actions.addBreakpoint(cx, location, {}));
await dispatch(actions.loadSourceText({ cx, source: fooOrigSource1 }));
const breakpoint = getBreakpointsList(getState())[0];
expect(breakpoint.text).toBe("");
expect(breakpoint.originalText).toBe("");
await dispatch(actions.loadSourceText({ cx, source: fooOrigSource }));
await dispatch(
actions.addBreakpoint(
cx,
{
sourceId: fooOrigSource1.id,
line: 1,
column: 0
},
{}
)
);
const breakpoint1 = getBreakpointsList(getState())[0];
expect(breakpoint1.text).toBe("");
expect(breakpoint1.originalText).toBe("var fooOrig = 42;");
await dispatch(actions.loadSourceText({ cx, source: fooGenSource }));
await dispatch(actions.loadSourceText({ cx, source: fooGenSource1 }));
const breakpoint2 = getBreakpointsList(getState())[0];
expect(breakpoint2.text).toBe("var fooGen = 42;");
expect(breakpoint2.originalText).toBe("var fooOrig = 42;");
await dispatch(actions.loadSourceText({ cx, source: fooGenSource2 }));
await dispatch(
actions.addBreakpoint(
cx,
{
sourceId: fooGenSource2.id,
line: 1,
column: 0
},
{}
)
);
const breakpoint3 = getBreakpointsList(getState())[1];
expect(breakpoint3.text).toBe("var fooGen = 42;");
expect(breakpoint3.originalText).toBe("");
await dispatch(actions.loadSourceText({ cx, source: fooOrigSource2 }));
const breakpoint4 = getBreakpointsList(getState())[1];
expect(breakpoint4.text).toBe("var fooGen = 42;");
expect(breakpoint4.originalText).toBe("var fooOrig = 42;");
});
it("loads two sources w/ one request", async () => {

Просмотреть файл

@ -20,7 +20,6 @@ import type {
Script,
SourceId,
SourceActor,
Source,
Worker,
Range
} from "../../types";
@ -188,7 +187,7 @@ function removeXHRBreakpoint(path: string, method: string) {
function locationKey(location: BreakpointLocation) {
const { sourceUrl, line, column } = location;
const sourceId = location.sourceId || "";
return `${(sourceUrl: any)}:${sourceId}:${line}:${(column: any)}`;
return `${(sourceUrl: any)}:${(sourceId: any)}:${line}:${(column: any)}`;
}
function waitForWorkers(shouldWait: boolean) {
@ -446,12 +445,12 @@ function getMainThread() {
}
async function getBreakpointPositions(
source: Source,
actors: Array<SourceActor>,
range: ?Range
): Promise<{ [string]: number[] }> {
const sourcePositions = {};
for (const { thread, actor } of source.actors) {
for (const { thread, actor } of actors) {
const sourceThreadClient = lookupThreadClient(thread);
const sourceClient = sourceThreadClient.source({ actor });
const { positions } = await sourceClient.getBreakpointPositionsCompressed(

Просмотреть файл

@ -200,7 +200,6 @@ exports[`SourcesTree on receiving new props updates highlighted items updates hi
Array [
Object {
"contents": Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "server1.conn13.child1/41",
"introductionType": undefined,
@ -223,7 +222,6 @@ exports[`SourcesTree on receiving new props updates highlighted items updates hi
"contents": Array [
Object {
"contents": Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "server1.conn13.child1/42",
"introductionType": undefined,
@ -244,7 +242,6 @@ exports[`SourcesTree on receiving new props updates highlighted items updates hi
},
Object {
"contents": Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "server1.conn13.child1/42/originalSource-sha",
"introductionType": undefined,
@ -265,7 +262,6 @@ exports[`SourcesTree on receiving new props updates highlighted items updates hi
},
Object {
"contents": Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "server1.conn13.child1/39",
"introductionType": undefined,
@ -286,7 +282,6 @@ exports[`SourcesTree on receiving new props updates highlighted items updates hi
},
Object {
"contents": Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "server1.conn13.child1/41",
"introductionType": undefined,
@ -307,7 +302,6 @@ exports[`SourcesTree on receiving new props updates highlighted items updates hi
},
Object {
"contents": Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "server1.conn13.child1/40",
"introductionType": undefined,

Просмотреть файл

@ -14,7 +14,6 @@ Object {
<Connect(SourceIcon)
source={
Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "server1.conn13.child1/39",
"introductionType": undefined,
@ -51,7 +50,6 @@ Object {
"focusItem": [MockFunction],
"item": Object {
"contents": Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "server1.conn13.child1/39",
"introductionType": undefined,
@ -73,7 +71,6 @@ Object {
"setExpanded": [MockFunction],
"setProjectDirectoryRoot": [MockFunction],
"source": Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "server1.conn13.child1/39",
"introductionType": undefined,
@ -103,7 +100,6 @@ Object {
item={
Object {
"contents": Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "server1.conn13.child1/39",
"introductionType": undefined,
@ -127,7 +123,6 @@ Object {
setProjectDirectoryRoot={[MockFunction]}
source={
Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "server1.conn13.child1/39",
"introductionType": undefined,
@ -158,7 +153,6 @@ Object {
<Connect(SourceIcon)
source={
Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "server1.conn13.child1/39",
"introductionType": undefined,
@ -194,7 +188,6 @@ Object {
"focusItem": [MockFunction],
"item": Object {
"contents": Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "server1.conn13.child1/39",
"introductionType": undefined,
@ -216,7 +209,6 @@ Object {
"setExpanded": [MockFunction],
"setProjectDirectoryRoot": [MockFunction],
"source": Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "server1.conn13.child1/39",
"introductionType": undefined,
@ -249,7 +241,6 @@ Object {
<Connect(SourceIcon)
source={
Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "server1.conn13.child1/39",
"introductionType": undefined,
@ -292,7 +283,6 @@ Object {
"hasMatchingGeneratedSource": true,
"item": Object {
"contents": Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "server1.conn13.child1/39",
"introductionType": undefined,
@ -315,7 +305,6 @@ Object {
"setExpanded": [MockFunction],
"setProjectDirectoryRoot": [MockFunction],
"source": Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "server1.conn13.child1/39",
"introductionType": undefined,
@ -346,7 +335,6 @@ Object {
item={
Object {
"contents": Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "server1.conn13.child1/39",
"introductionType": undefined,
@ -371,7 +359,6 @@ Object {
setProjectDirectoryRoot={[MockFunction]}
source={
Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "server1.conn13.child1/39",
"introductionType": undefined,
@ -402,7 +389,6 @@ Object {
<Connect(SourceIcon)
source={
Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "server1.conn13.child1/39",
"introductionType": undefined,
@ -444,7 +430,6 @@ Object {
"hasMatchingGeneratedSource": true,
"item": Object {
"contents": Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "server1.conn13.child1/39",
"introductionType": undefined,
@ -467,7 +452,6 @@ Object {
"setExpanded": [MockFunction],
"setProjectDirectoryRoot": [MockFunction],
"source": Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "server1.conn13.child1/39",
"introductionType": undefined,
@ -522,7 +506,6 @@ Object {
"focusItem": [MockFunction],
"item": Object {
"contents": Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "server1.conn13.child1/39",
"introductionType": undefined,
@ -545,7 +528,6 @@ Object {
"setExpanded": [MockFunction],
"setProjectDirectoryRoot": [MockFunction],
"source": Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "server1.conn13.child1/39",
"introductionType": undefined,
@ -576,7 +558,6 @@ Object {
item={
Object {
"contents": Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "server1.conn13.child1/39",
"introductionType": undefined,
@ -601,7 +582,6 @@ Object {
setProjectDirectoryRoot={[MockFunction]}
source={
Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "server1.conn13.child1/39",
"introductionType": undefined,
@ -653,7 +633,6 @@ Object {
"focusItem": [MockFunction],
"item": Object {
"contents": Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "server1.conn13.child1/39",
"introductionType": undefined,
@ -676,7 +655,6 @@ Object {
"setExpanded": [MockFunction],
"setProjectDirectoryRoot": [MockFunction],
"source": Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "server1.conn13.child1/39",
"introductionType": undefined,
@ -740,7 +718,6 @@ Object {
"setExpanded": [MockFunction],
"setProjectDirectoryRoot": [MockFunction],
"source": Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "server1.conn13.child1/39",
"introductionType": undefined,
@ -782,7 +759,6 @@ Object {
setProjectDirectoryRoot={[MockFunction]}
source={
Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "server1.conn13.child1/39",
"introductionType": undefined,
@ -843,7 +819,6 @@ Object {
"setExpanded": [MockFunction],
"setProjectDirectoryRoot": [MockFunction],
"source": Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "server1.conn13.child1/39",
"introductionType": undefined,
@ -908,7 +883,6 @@ Object {
"setExpanded": [MockFunction],
"setProjectDirectoryRoot": [MockFunction],
"source": Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "server1.conn13.child1/39",
"introductionType": undefined,
@ -951,7 +925,6 @@ Object {
setProjectDirectoryRoot={[MockFunction]}
source={
Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "server1.conn13.child1/39",
"introductionType": undefined,
@ -1013,7 +986,6 @@ Object {
"setExpanded": [MockFunction],
"setProjectDirectoryRoot": [MockFunction],
"source": Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "server1.conn13.child1/39",
"introductionType": undefined,
@ -1202,7 +1174,6 @@ Object {
"setExpanded": [MockFunction],
"setProjectDirectoryRoot": [MockFunction],
"source": Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "server1.conn13.child1/39",
"introductionType": undefined,
@ -1243,7 +1214,6 @@ Object {
setProjectDirectoryRoot={[MockFunction]}
source={
Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "server1.conn13.child1/39",
"introductionType": undefined,
@ -1303,7 +1273,6 @@ Object {
"setExpanded": [MockFunction],
"setProjectDirectoryRoot": [MockFunction],
"source": Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "server1.conn13.child1/39",
"introductionType": undefined,
@ -1613,7 +1582,6 @@ Object {
"setExpanded": [MockFunction],
"setProjectDirectoryRoot": [MockFunction],
"source": Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "server1.conn13.child1/39",
"introductionType": undefined,
@ -1655,7 +1623,6 @@ Object {
setProjectDirectoryRoot={[MockFunction]}
source={
Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "server1.conn13.child1/39",
"introductionType": undefined,
@ -1716,7 +1683,6 @@ Object {
"setExpanded": [MockFunction],
"setProjectDirectoryRoot": [MockFunction],
"source": Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "server1.conn13.child1/39",
"introductionType": undefined,
@ -1779,7 +1745,6 @@ Object {
"setExpanded": [MockFunction],
"setProjectDirectoryRoot": [MockFunction],
"source": Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "server1.conn13.child1/39",
"introductionType": undefined,
@ -1820,7 +1785,6 @@ Object {
setProjectDirectoryRoot={[MockFunction]}
source={
Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "server1.conn13.child1/39",
"introductionType": undefined,
@ -1880,7 +1844,6 @@ Object {
"setExpanded": [MockFunction],
"setProjectDirectoryRoot": [MockFunction],
"source": Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "server1.conn13.child1/39",
"introductionType": undefined,
@ -1913,7 +1876,6 @@ Object {
<Connect(SourceIcon)
source={
Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "server1.conn13.child1/39",
"introductionType": undefined,
@ -1950,7 +1912,6 @@ Object {
"focusItem": [MockFunction],
"item": Object {
"contents": Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "server1.conn13.child1/39",
"introductionType": undefined,
@ -1973,7 +1934,6 @@ Object {
"setExpanded": [MockFunction],
"setProjectDirectoryRoot": [MockFunction],
"source": Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "server1.conn13.child1/39",
"introductionType": undefined,
@ -2003,7 +1963,6 @@ Object {
item={
Object {
"contents": Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "server1.conn13.child1/39",
"introductionType": undefined,
@ -2028,7 +1987,6 @@ Object {
setProjectDirectoryRoot={[MockFunction]}
source={
Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "server1.conn13.child1/39",
"introductionType": undefined,
@ -2059,7 +2017,6 @@ Object {
<Connect(SourceIcon)
source={
Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "server1.conn13.child1/39",
"introductionType": undefined,
@ -2095,7 +2052,6 @@ Object {
"focusItem": [MockFunction],
"item": Object {
"contents": Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "server1.conn13.child1/39",
"introductionType": undefined,
@ -2118,7 +2074,6 @@ Object {
"setExpanded": [MockFunction],
"setProjectDirectoryRoot": [MockFunction],
"source": Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "server1.conn13.child1/39",
"introductionType": undefined,
@ -2151,7 +2106,6 @@ Object {
<Connect(SourceIcon)
source={
Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "server1.conn13.child1/39",
"introductionType": undefined,
@ -2190,7 +2144,6 @@ Object {
"focused": true,
"item": Object {
"contents": Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "server1.conn13.child1/39",
"introductionType": undefined,
@ -2212,7 +2165,6 @@ Object {
"setExpanded": [MockFunction],
"setProjectDirectoryRoot": [MockFunction],
"source": Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "server1.conn13.child1/39",
"introductionType": undefined,
@ -2244,7 +2196,6 @@ Object {
item={
Object {
"contents": Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "server1.conn13.child1/39",
"introductionType": undefined,
@ -2268,7 +2219,6 @@ Object {
setProjectDirectoryRoot={[MockFunction]}
source={
Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "server1.conn13.child1/39",
"introductionType": undefined,
@ -2299,7 +2249,6 @@ Object {
<Connect(SourceIcon)
source={
Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "server1.conn13.child1/39",
"introductionType": undefined,
@ -2337,7 +2286,6 @@ Object {
"focused": true,
"item": Object {
"contents": Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "server1.conn13.child1/39",
"introductionType": undefined,
@ -2359,7 +2307,6 @@ Object {
"setExpanded": [MockFunction],
"setProjectDirectoryRoot": [MockFunction],
"source": Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "server1.conn13.child1/39",
"introductionType": undefined,
@ -2392,7 +2339,6 @@ Object {
<Connect(SourceIcon)
source={
Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "server1.conn13.child1/39",
"introductionType": undefined,
@ -2429,7 +2375,6 @@ Object {
"focusItem": [MockFunction],
"item": Object {
"contents": Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "server1.conn13.child1/39",
"introductionType": undefined,
@ -2452,7 +2397,6 @@ Object {
"setExpanded": [MockFunction],
"setProjectDirectoryRoot": [MockFunction],
"source": Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "server1.conn13.child1/39",
"introductionType": undefined,
@ -2482,7 +2426,6 @@ Object {
item={
Object {
"contents": Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "server1.conn13.child1/39",
"introductionType": undefined,
@ -2507,7 +2450,6 @@ Object {
setProjectDirectoryRoot={[MockFunction]}
source={
Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "server1.conn13.child1/39",
"introductionType": undefined,
@ -2538,7 +2480,6 @@ Object {
<Connect(SourceIcon)
source={
Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "server1.conn13.child1/39",
"introductionType": undefined,
@ -2574,7 +2515,6 @@ Object {
"focusItem": [MockFunction],
"item": Object {
"contents": Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "server1.conn13.child1/39",
"introductionType": undefined,
@ -2597,7 +2537,6 @@ Object {
"setExpanded": [MockFunction],
"setProjectDirectoryRoot": [MockFunction],
"source": Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "server1.conn13.child1/39",
"introductionType": undefined,

Просмотреть файл

@ -37,7 +37,6 @@ exports[`Frame getFrameTitle 1`] = `
"type": "block",
},
"source": Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "source",
"introductionType": undefined,
@ -92,7 +91,6 @@ exports[`Frame getFrameTitle 1`] = `
"type": "block",
},
"source": Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "source",
"introductionType": undefined,
@ -154,7 +152,6 @@ exports[`Frame library frame 1`] = `
"type": "block",
},
"source": Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "source",
"introductionType": undefined,
@ -210,7 +207,6 @@ exports[`Frame library frame 1`] = `
"type": "block",
},
"source": Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "source",
"introductionType": undefined,
@ -271,7 +267,6 @@ exports[`Frame user frame (not selected) 1`] = `
"type": "block",
},
"source": Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "source",
"introductionType": undefined,
@ -326,7 +321,6 @@ exports[`Frame user frame (not selected) 1`] = `
"type": "block",
},
"source": Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "source",
"introductionType": undefined,
@ -387,7 +381,6 @@ exports[`Frame user frame 1`] = `
"type": "block",
},
"source": Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "source",
"introductionType": undefined,
@ -442,7 +435,6 @@ exports[`Frame user frame 1`] = `
"type": "block",
},
"source": Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "source",
"introductionType": undefined,

Просмотреть файл

@ -34,7 +34,6 @@ exports[`Frames Blackboxed Frames filters blackboxed frames 1`] = `
"type": "block",
},
"source": Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "1",
"introductionType": undefined,
@ -81,7 +80,6 @@ exports[`Frames Blackboxed Frames filters blackboxed frames 1`] = `
"type": "block",
},
"source": Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "1",
"introductionType": undefined,
@ -130,7 +128,6 @@ exports[`Frames Blackboxed Frames filters blackboxed frames 1`] = `
"type": "block",
},
"source": Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "1",
"introductionType": undefined,
@ -177,7 +174,6 @@ exports[`Frames Blackboxed Frames filters blackboxed frames 1`] = `
"type": "block",
},
"source": Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "1",
"introductionType": undefined,

Просмотреть файл

@ -41,7 +41,6 @@ exports[`Group displays a group 1`] = `
"type": "block",
},
"source": Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "source",
"introductionType": undefined,
@ -116,7 +115,6 @@ exports[`Group passes the getFrameTitle prop to the Frame components 1`] = `
"type": "block",
},
"source": Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "source",
"introductionType": undefined,
@ -190,7 +188,6 @@ exports[`Group passes the getFrameTitle prop to the Frame components 1`] = `
"type": "block",
},
"source": Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "source",
"introductionType": undefined,
@ -239,7 +236,6 @@ exports[`Group passes the getFrameTitle prop to the Frame components 1`] = `
"type": "block",
},
"source": Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "source",
"introductionType": undefined,
@ -301,7 +297,6 @@ exports[`Group passes the getFrameTitle prop to the Frame components 1`] = `
"type": "block",
},
"source": Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "source",
"introductionType": undefined,
@ -350,7 +345,6 @@ exports[`Group passes the getFrameTitle prop to the Frame components 1`] = `
"type": "block",
},
"source": Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "source",
"introductionType": undefined,
@ -412,7 +406,6 @@ exports[`Group passes the getFrameTitle prop to the Frame components 1`] = `
"type": "block",
},
"source": Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "source",
"introductionType": undefined,
@ -461,7 +454,6 @@ exports[`Group passes the getFrameTitle prop to the Frame components 1`] = `
"type": "block",
},
"source": Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "source",
"introductionType": undefined,
@ -528,7 +520,6 @@ exports[`Group renders group with anonymous functions 1`] = `
"type": "block",
},
"source": Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "source",
"introductionType": undefined,
@ -603,7 +594,6 @@ exports[`Group renders group with anonymous functions 2`] = `
"type": "block",
},
"source": Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "source",
"introductionType": undefined,
@ -677,7 +667,6 @@ exports[`Group renders group with anonymous functions 2`] = `
"type": "block",
},
"source": Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "source",
"introductionType": undefined,
@ -725,7 +714,6 @@ exports[`Group renders group with anonymous functions 2`] = `
"type": "block",
},
"source": Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "source",
"introductionType": undefined,
@ -787,7 +775,6 @@ exports[`Group renders group with anonymous functions 2`] = `
"type": "block",
},
"source": Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "source",
"introductionType": undefined,
@ -835,7 +822,6 @@ exports[`Group renders group with anonymous functions 2`] = `
"type": "block",
},
"source": Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "source",
"introductionType": undefined,
@ -897,7 +883,6 @@ exports[`Group renders group with anonymous functions 2`] = `
"type": "block",
},
"source": Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "source",
"introductionType": undefined,
@ -945,7 +930,6 @@ exports[`Group renders group with anonymous functions 2`] = `
"type": "block",
},
"source": Object {
"actors": Array [],
"contentType": "text/javascript",
"id": "source",
"introductionType": undefined,

Просмотреть файл

@ -122,7 +122,7 @@ class Scopes extends PureComponent<Props, State> {
const scopes =
(showOriginal && mapScopesEnabled && originalScopes) || generatedScopes;
if (scopes && !isLoading) {
if (scopes && scopes.length > 0 && !isLoading) {
return (
<div className="pane scopes-list">
<ObjectInspector

Просмотреть файл

@ -14,7 +14,6 @@ import { isEqual } from "lodash";
import { makeBreakpointId, findPosition } from "../utils/breakpoint";
import { findBreakableLines } from "../utils/breakable-lines";
import { isInlineScript } from "../utils/source";
// eslint-disable-next-line max-len
import { getBreakpointsList as getBreakpointsListSelector } from "../selectors/breakpoints";
@ -107,18 +106,20 @@ function update(
};
}
case "ADD_SOURCES": {
const { sources } = action;
case "INSERT_SOURCE_ACTORS": {
const { items } = action;
const scriptSources = sources.filter(source => isInlineScript(source));
const scriptActors = items.filter(
item => item.introductionType === "scriptElement"
);
if (scriptSources.length > 0) {
if (scriptActors.length > 0) {
const { ...breakpointPositions } = state.breakpointPositions;
// If new HTML sources are being added, we need to clear the breakpoint
// positions since the new source is a <script> with new breakpoints.
for (const source of scriptSources) {
delete breakpointPositions[source.id];
for (const { source } of scriptActors) {
delete breakpointPositions[source];
}
state = { ...state, breakpointPositions };

Просмотреть файл

@ -69,6 +69,11 @@ export default function update(
state = removeResources(state, items);
break;
}
case "NAVIGATE": {
state = initial;
break;
}
}
return state;

Просмотреть файл

@ -23,18 +23,32 @@ import {
import { originalToGeneratedId } from "devtools-source-map";
import { prefs } from "../utils/prefs";
import type { Source, SourceId, SourceLocation, ThreadId } from "../types";
import {
hasSourceActor,
getSourceActor,
getSourceActors,
getThreadsBySource,
type SourceActorId,
type SourceActorOuterState
} from "./source-actors";
import type {
Source,
SourceId,
SourceActor,
SourceLocation,
ThreadId
} from "../types";
import type { PendingSelectedLocation, Selector } from "./types";
import type { Action, DonePromiseAction, FocusItem } from "../actions/types";
import type { LoadSourceAction } from "../actions/types/SourceAction";
import { mapValues, uniqBy } from "lodash";
import { uniq } from "lodash";
export type SourcesMap = { [SourceId]: Source };
export type SourcesMapByThread = { [ThreadId]: SourcesMap };
type SourceActorMap = { [SourceId]: Array<SourceActorId> };
type UrlsMap = { [string]: SourceId[] };
type DisplayedSources = { [ThreadId]: { [SourceId]: boolean } };
type GetDisplayedSourcesSelector = OuterState => { [ThreadId]: SourcesMap };
type DisplayedSources = Set<SourceId>;
type PlainUrlsMap = { [string]: string[] };
export type SourcesState = {
@ -43,6 +57,9 @@ export type SourcesState = {
// All known sources.
sources: SourcesMap,
// A link between each source object and the source actor they wrap over.
actors: SourceActorMap,
// All sources associated with a given URL. When using source maps, multiple
// sources can have the same URL.
urls: UrlsMap,
@ -65,14 +82,15 @@ export type SourcesState = {
const emptySources = {
sources: {},
displayed: new Set(),
urls: {},
plainUrls: {},
displayed: {}
plainUrls: {}
};
export function initialSourcesState(): SourcesState {
return {
...emptySources,
actors: {},
epoch: 1,
selectedLocation: undefined,
pendingSelectedLocation: prefs.pendingSelectedLocation,
@ -97,7 +115,6 @@ export function createSource(state: SourcesState, source: Object): Source {
error: undefined,
loadedState: "unloaded",
relativeUrl: getRelativeUrl(source, root),
actors: [],
...source
};
}
@ -118,8 +135,11 @@ function update(
case "ADD_SOURCES":
return addSources(state, action.sources);
case "REMOVE_WORKERS":
return removeWorkers(state, action);
case "INSERT_SOURCE_ACTORS":
return insertSourceActors(state, action);
case "REMOVE_SOURCE_ACTORS":
return removeSourceActors(state, action);
case "SET_SELECTED_LOCATION":
location = {
@ -228,33 +248,19 @@ function updateAllSources(state: SourcesState, callback: any) {
* Add sources to the sources store
* - Add the source to the sources store
* - Add the source URL to the urls map
* - Add the source ID to the thread displayed map
*/
function addSources(state: SourcesState, sources: Source[]) {
function addSources(state: SourcesState, sources: Source[]): SourcesState {
state = {
...state,
sources: { ...state.sources },
displayed: new Set(state.displayed),
urls: { ...state.urls },
plainUrls: { ...state.plainUrls },
displayed: { ...state.displayed }
plainUrls: { ...state.plainUrls }
};
for (const source of sources) {
const existingSource = state.sources[source.id];
let updatedSource = existingSource || source;
// Merge the source actor list
if (existingSource && source.actors) {
const actors = uniqBy(
[...existingSource.actors, ...source.actors],
({ actor }) => actor
);
updatedSource = (({ ...updatedSource, actors }: any): Source);
}
// 1. Add the source to the sources map
state.sources[source.id] = updatedSource;
state.sources[source.id] = state.sources[source.id] || source;
// 2. Update the source url map
const existing = state.urls[source.url] || [];
@ -277,29 +283,51 @@ function addSources(state: SourcesState, sources: Source[]) {
(!source.isExtension ||
getChromeAndExtenstionsEnabled({ sources: state }))
) {
for (const actor of getSourceActors(state, source)) {
if (!state.displayed[actor.thread]) {
state.displayed[actor.thread] = {};
}
state.displayed[actor.thread][source.id] = true;
}
state.displayed.add(source.id);
}
}
return state;
}
function insertSourceActors(state: SourcesState, action): SourcesState {
const { items } = action;
state = {
...state,
actors: { ...state.actors }
};
for (const sourceActor of items) {
state.actors[sourceActor.source] = [
...(state.actors[sourceActor.source] || []),
sourceActor.id
];
}
return state;
}
/*
* Update sources when the worker list changes.
* - filter source actor lists so that missing threads no longer appear
* - NOTE: we do not remove sources for destroyed threads
*/
function removeWorkers(state: SourcesState, action: Object) {
const { workers } = action;
function removeSourceActors(state: SourcesState, action) {
const { items } = action;
return updateAllSources(state, source => ({
actors: source.actors.filter(({ thread }) => !workers.includes(thread))
}));
const actors = new Set(items.map(item => item.id));
const sources = new Set(items.map(item => item.source));
state = {
...state,
actors: { ...state.actors }
};
for (const source of sources) {
state.actors[source] = state.actors[source].filter(id => !actors.has(id));
}
return state;
}
/*
@ -376,14 +404,15 @@ type OuterState = { sources: SourcesState };
const getSourcesState = (state: OuterState) => state.sources;
function getSourceActors(state, source) {
if (isGenerated(source)) {
return source.actors;
}
// Original sources do not have actors, so use the generated source.
const generatedSource = state.sources[originalToGeneratedId(source.id)];
return generatedSource ? generatedSource.actors : [];
export function getSourceThreads(
state: OuterState & SourceActorOuterState,
source: Source
): ThreadId[] {
return uniq(
getSourceActors(state, state.sources.actors[source.id]).map(
actor => actor.thread
)
);
}
export function getSourceInSources(sources: SourcesMap, id: string): ?Source {
@ -403,17 +432,14 @@ export function getSourceFromId(state: OuterState, id: string): Source {
}
export function getSourceByActorId(
state: OuterState,
actorId: string
state: OuterState & SourceActorOuterState,
actorId: SourceActorId
): ?Source {
// We don't index the sources by actor IDs, so this method should be used
// sparingly.
for (const source of getSourceList(state)) {
if (source.actors.some(({ actor }) => actor == actorId)) {
return source;
}
if (!hasSourceActor(state, actorId)) {
return null;
}
return null;
return getSource(state, getSourceActor(state, actorId).source);
}
export function getSourcesByURLInSources(
@ -560,7 +586,9 @@ export function getSourceList(state: OuterState): Source[] {
return (Object.values(getSources(state)): any);
}
export function getDisplayedSourcesList(state: OuterState): Source[] {
export function getDisplayedSourcesList(
state: OuterState & SourceActorOuterState
): Source[] {
return ((Object.values(getDisplayedSources(state)): any).flatMap(
Object.values
): any);
@ -596,7 +624,7 @@ export function getProjectDirectoryRoot(state: OuterState): string {
return state.sources.projectDirectoryRoot;
}
function getAllDisplayedSources(state: OuterState) {
function getAllDisplayedSources(state: OuterState): DisplayedSources {
return state.sources.displayed;
}
@ -604,19 +632,55 @@ function getChromeAndExtenstionsEnabled(state: OuterState) {
return state.sources.chromeAndExtenstionsEnabled;
}
export const getDisplayedSources: GetDisplayedSourcesSelector = createSelector(
getSources,
getChromeAndExtenstionsEnabled,
type GetDisplayedSourceIDsSelector = (
OuterState & SourceActorOuterState
) => { [ThreadId]: Set<SourceId> };
const getDisplayedSourceIDs: GetDisplayedSourceIDsSelector = createSelector(
getThreadsBySource,
getAllDisplayedSources,
(sources, chromeAndExtenstionsEnabled, displayed) => {
return mapValues(displayed, threadSourceIds =>
mapValues(threadSourceIds, (_, id) => sources[id])
);
(threadsBySource, displayedSources) => {
const sourceIDsByThread = {};
for (const sourceId of displayedSources) {
const threads =
threadsBySource[sourceId] ||
threadsBySource[originalToGeneratedId(sourceId)] ||
[];
for (const thread of threads) {
if (!sourceIDsByThread[thread]) {
sourceIDsByThread[thread] = new Set();
}
sourceIDsByThread[thread].add(sourceId);
}
}
return sourceIDsByThread;
}
);
type GetDisplayedSourcesSelector = (
OuterState & SourceActorOuterState
) => { [ThreadId]: { [SourceId]: Source } };
export const getDisplayedSources: GetDisplayedSourcesSelector = createSelector(
state => state.sources.sources,
getDisplayedSourceIDs,
(sources, idsByThread) => {
const result = {};
for (const thread of Object.keys(idsByThread)) {
for (const id of idsByThread[thread]) {
if (!result[thread]) {
result[thread] = {};
}
result[thread][id] = sources[id];
}
}
return result;
}
);
export function getDisplayedSourcesForThread(
state: OuterState,
state: OuterState & SourceActorOuterState,
thread: string
): SourcesMap {
return getDisplayedSources(state)[thread] || {};
@ -626,4 +690,16 @@ export function getFocusedSourceItem(state: OuterState): ?FocusItem {
return state.sources.focusedItem;
}
export function getSourceActorsForSource(
state: OuterState & SourceActorOuterState,
id: SourceId
): Array<SourceActor> {
const actors = state.sources.actors[id];
if (!actors) {
return [];
}
return getSourceActors(state, actors);
}
export default update;

Просмотреть файл

@ -8,39 +8,29 @@ declare var it: (desc: string, func: () => void) => void;
declare var expect: (value: any) => any;
import update, { initialSourcesState, getDisplayedSources } from "../sources";
import type { Source } from "../../types";
import updateSourceActors from "../source-actors";
import type { Source, SourceActor } from "../../types";
import { prefs } from "../../utils/prefs";
import { makeMockSource, mockcx } from "../../utils/test-mockup";
const extensionSource = {
...makeMockSource(),
id: "extensionId",
url: "http://example.com/script.js",
actors: [{ actor: "extensionId-actor", source: "extensionId", thread: "foo" }]
url: "http://example.com/script.js"
};
const firefoxExtensionSource = {
...makeMockSource(),
id: "firefoxExtension",
url: "moz-extension://id/js/content.js",
isExtension: true,
actors: [
{
actor: "firefoxExtension-actor",
source: "firefoxExtension",
thread: "foo"
}
]
isExtension: true
};
const chromeExtensionSource = {
...makeMockSource(),
id: "chromeExtension",
isExtension: true,
url: "chrome-extension://id/js/content.js",
actors: [
{ actor: "chromeExtension-actor", source: "chromeExtension", thread: "foo" }
]
url: "chrome-extension://id/js/content.js"
};
const mockedSources = [
@ -49,6 +39,27 @@ const mockedSources = [
chromeExtensionSource
];
const mockSourceActors: Array<SourceActor> = ([
{
id: "extensionId-actor",
actor: "extensionId-actor",
source: "extensionId",
thread: "foo"
},
{
id: "firefoxExtension-actor",
actor: "firefoxExtension-actor",
source: "firefoxExtension",
thread: "foo"
},
{
id: "chromeExtension-actor",
actor: "chromeExtension-actor",
source: "chromeExtension",
thread: "foo"
}
]: any);
describe("sources reducer", () => {
it("should work", () => {
let state = initialSourcesState();
@ -71,7 +82,16 @@ describe("sources selectors", () => {
cx: mockcx,
// coercing to a Source for the purpose of this test
sources: ((mockedSources: any): Source[])
})
}),
sourceActors: undefined
};
const insertAction = {
type: "INSERT_SOURCE_ACTORS",
items: mockSourceActors
};
state = {
sources: update(state.sources, insertAction),
sourceActors: updateSourceActors(state.sourceActors, insertAction)
};
const selectedDisplayedSources = getDisplayedSources(state);
const threadSources = selectedDisplayedSources.foo;
@ -87,7 +107,18 @@ describe("sources selectors", () => {
cx: mockcx,
// coercing to a Source for the purpose of this test
sources: ((mockedSources: any): Source[])
})
}),
sourceActors: undefined
};
const insertAction = {
type: "INSERT_SOURCE_ACTORS",
items: mockSourceActors
};
state = {
sources: update(state.sources, insertAction),
sourceActors: updateSourceActors(state.sourceActors, insertAction)
};
const selectedDisplayedSources = getDisplayedSources(state);
const threadSources = selectedDisplayedSources.foo;

Просмотреть файл

@ -19,6 +19,7 @@ import type { PendingBreakpointsState } from "../selectors";
import type { ProjectTextSearchState } from "./project-text-search";
import type { Record } from "../utils/makeRecord";
import type { SourcesState } from "./sources";
import type { SourceActorsState } from "./source-actors";
import type { TabList } from "./tabs";
import type { UIState } from "./ui";
import type { QuickOpenState } from "./quick-open";
@ -33,6 +34,7 @@ export type State = {
pendingBreakpoints: PendingBreakpointsState,
projectTextSearch: ProjectTextSearchState,
sources: SourcesState,
sourceActors: SourceActorsState,
tabs: TabList,
ui: Record<UIState>,
quickOpen: Record<QuickOpenState>

Просмотреть файл

@ -20,7 +20,9 @@ export * from "../reducers/source-tree";
export {
getSourceActor,
getSourceActorsForThread,
hasSourceActor,
getSourceActors,
getSourceActorsForThread
} from "../reducers/source-actors";
export {

Просмотреть файл

@ -5,6 +5,9 @@
// @flow
import type { SourcePayload } from "./client/firefox/types";
import type { SourceActorId, SourceActor } from "./reducers/source-actors";
export type { SourceActorId, SourceActor };
export type SearchModifiers = {
caseSensitive: boolean,
@ -68,7 +71,7 @@ export type GeneratedSourceData = {
};
export type SourceActorLocation = {|
+sourceActor: SourceActor,
+sourceActor: SourceActorId,
+line: number,
+column?: number
|};
@ -118,7 +121,7 @@ export type BreakpointLocation = {
+line: number,
+column?: number,
+sourceUrl?: string,
+sourceId?: SourceId
+sourceId?: SourceActorId
};
export type ASTLocation = {|
@ -352,12 +355,6 @@ export type Grip = {
name?: string
};
export type SourceActor = {|
+actor: ActorId,
+source: SourceId,
+thread: ThreadId
|};
/**
* BaseSource
*
@ -377,8 +374,7 @@ type BaseSource = {|
+relativeUrl: string,
+introductionUrl: ?string,
+introductionType: ?string,
+isExtension: boolean,
+actors: SourceActor[]
+isExtension: boolean
|};
/**

Просмотреть файл

@ -4,7 +4,11 @@
// @flow
import { getBreakpoint, getSource } from "../../selectors";
import {
getBreakpoint,
getSource,
getSourceActorsForSource
} from "../../selectors";
import { isGenerated } from "../source";
import { sortSelectedLocations } from "../location";
import assert from "../assert";
@ -75,7 +79,10 @@ export function makeBreakpointLocation(
if (source.url) {
breakpointLocation.sourceUrl = source.url;
} else {
breakpointLocation.sourceId = source.actors[0].actor;
breakpointLocation.sourceId = getSourceActorsForSource(
state,
source.id
)[0].id;
}
return breakpointLocation;
}
@ -95,7 +102,7 @@ export function makeSourceActorLocation(
export function makeBreakpointActorId(location: SourceActorLocation) {
const { sourceActor, line, column } = location;
const columnString = column || "";
return `${sourceActor.actor}:${line}:${columnString}`;
return `${(sourceActor: any)}:${line}:${columnString}`;
}
export function assertBreakpoint(breakpoint: Breakpoint) {

Просмотреть файл

@ -23,7 +23,6 @@ exports[`calls updateTree.js adds one source 1`] = `
\\"loadedState\\": \\"unloaded\\",
\\"relativeUrl\\": \\"https://davidwalsh.name/\\",
\\"introductionUrl\\": null,
\\"actors\\": [],
\\"isWasm\\": false,
\\"contentType\\": \\"text/javascript\\",
\\"isExtension\\": false,
@ -42,7 +41,6 @@ exports[`calls updateTree.js adds one source 1`] = `
\\"loadedState\\": \\"unloaded\\",
\\"relativeUrl\\": \\"https://davidwalsh.name/source1.js\\",
\\"introductionUrl\\": null,
\\"actors\\": [],
\\"isWasm\\": false,
\\"contentType\\": \\"text/javascript\\",
\\"isExtension\\": false,
@ -78,7 +76,6 @@ exports[`calls updateTree.js adds two sources 1`] = `
\\"loadedState\\": \\"unloaded\\",
\\"relativeUrl\\": \\"https://davidwalsh.name/\\",
\\"introductionUrl\\": null,
\\"actors\\": [],
\\"isWasm\\": false,
\\"contentType\\": \\"text/javascript\\",
\\"isExtension\\": false,
@ -97,7 +94,6 @@ exports[`calls updateTree.js adds two sources 1`] = `
\\"loadedState\\": \\"unloaded\\",
\\"relativeUrl\\": \\"https://davidwalsh.name/source1.js\\",
\\"introductionUrl\\": null,
\\"actors\\": [],
\\"isWasm\\": false,
\\"contentType\\": \\"text/javascript\\",
\\"isExtension\\": false,
@ -116,7 +112,6 @@ exports[`calls updateTree.js adds two sources 1`] = `
\\"loadedState\\": \\"unloaded\\",
\\"relativeUrl\\": \\"https://davidwalsh.name/source2.js\\",
\\"introductionUrl\\": null,
\\"actors\\": [],
\\"isWasm\\": false,
\\"contentType\\": \\"text/javascript\\",
\\"isExtension\\": false,
@ -152,7 +147,6 @@ exports[`calls updateTree.js shows all the sources 1`] = `
\\"loadedState\\": \\"unloaded\\",
\\"relativeUrl\\": \\"https://davidwalsh.name/\\",
\\"introductionUrl\\": null,
\\"actors\\": [],
\\"isWasm\\": false,
\\"contentType\\": \\"text/javascript\\",
\\"isExtension\\": false,
@ -171,7 +165,6 @@ exports[`calls updateTree.js shows all the sources 1`] = `
\\"loadedState\\": \\"unloaded\\",
\\"relativeUrl\\": \\"https://davidwalsh.name/source1.js\\",
\\"introductionUrl\\": null,
\\"actors\\": [],
\\"isWasm\\": false,
\\"contentType\\": \\"text/javascript\\",
\\"isExtension\\": false,

Просмотреть файл

@ -103,7 +103,6 @@ function createSourceObject(
introductionUrl: props.introductionUrl || null,
introductionType: props.introductionType || null,
isExtension: false,
actors: [],
...(typeof props.text === "string"
? {
text: props.text || "",

Просмотреть файл

@ -40,7 +40,6 @@ function makeMockSource(
relativeUrl: url,
introductionUrl: null,
introductionType: undefined,
actors: [],
isWasm: false,
contentType,
isExtension: false,
@ -58,7 +57,6 @@ function makeMockWasmSource(text: {| binary: Object |}): WasmSource {
relativeUrl: "url",
introductionUrl: null,
introductionType: undefined,
actors: [],
isWasm: true,
isExtension: false,
text

Просмотреть файл

@ -21,8 +21,7 @@ describe("sources", () => {
isPrettyPrinted: false,
isWasm: false,
loadedState: "loaded",
isExtension: false,
actors: []
isExtension: false
};
expect(hasSource(sourceId)).toEqual(false);

Просмотреть файл

@ -12,6 +12,7 @@ add_task(async function() {
// about new actors being created in the page content.
await reload(dbg, "doc-html-breakpoints.html");
await waitForBreakableLine(dbg, "doc-html-breakpoints.html", 8);
await addBreakpoint(dbg, "doc-html-breakpoints.html", 8);
// Ensure that the breakpoints get added once the later scripts load.