зеркало из https://github.com/mozilla/gecko-dev.git
Backed out 9 changesets (bug 1620280) for failure at browser_ext_devtools_inspectedWindow_targetSwitch.js. CLOSED TREE
Backed out changeset 8dda1f048067 (bug 1620280) Backed out changeset 309c0be48745 (bug 1620280) Backed out changeset 78a06cd336c6 (bug 1620280) Backed out changeset 74aba83895ce (bug 1620280) Backed out changeset 6a8126ded6ec (bug 1620280) Backed out changeset 47a2d6b77270 (bug 1620280) Backed out changeset 526c067da0c1 (bug 1620280) Backed out changeset 488f645884ba (bug 1620280) Backed out changeset 9cffe1c5fb6d (bug 1620280)
This commit is contained in:
Родитель
4f41db1dfa
Коммит
d89b519adc
|
@ -42,10 +42,5 @@ add_task(async function() {
|
||||||
const markupViewElement = inspector.panelDoc.getElementById("markup-box");
|
const markupViewElement = inspector.panelDoc.getElementById("markup-box");
|
||||||
ok(markupViewElement, "Inspector is still rendered");
|
ok(markupViewElement, "Inspector is still rendered");
|
||||||
|
|
||||||
// We explicitely destroy the toolbox in order to ensure waiting for its full destruction
|
|
||||||
// and avoid leak / pending requests
|
|
||||||
info("Destroy the opened toolbox");
|
|
||||||
await toolbox.destroy();
|
|
||||||
|
|
||||||
await removeTab(tab);
|
await removeTab(tab);
|
||||||
});
|
});
|
||||||
|
|
|
@ -51,7 +51,6 @@ class DebuggerPanel {
|
||||||
client,
|
client,
|
||||||
} = await this.panelWin.Debugger.bootstrap({
|
} = await this.panelWin.Debugger.bootstrap({
|
||||||
targetList: this.toolbox.targetList,
|
targetList: this.toolbox.targetList,
|
||||||
resourceWatcher: this.toolbox.resourceWatcher,
|
|
||||||
devToolsClient: this.toolbox.target.client,
|
devToolsClient: this.toolbox.target.client,
|
||||||
workers: {
|
workers: {
|
||||||
sourceMaps: this.toolbox.sourceMapService,
|
sourceMaps: this.toolbox.sourceMapService,
|
||||||
|
|
|
@ -47,7 +47,9 @@ import { validateNavigateContext, ContextError } from "../../utils/context";
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
Source,
|
Source,
|
||||||
|
SourceActorId,
|
||||||
SourceId,
|
SourceId,
|
||||||
|
ThreadId,
|
||||||
Context,
|
Context,
|
||||||
OriginalSourceData,
|
OriginalSourceData,
|
||||||
GeneratedSourceData,
|
GeneratedSourceData,
|
||||||
|
@ -398,3 +400,18 @@ function checkNewSources(cx: Context, sources: Source[]) {
|
||||||
return sources;
|
return sources;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function ensureSourceActor(
|
||||||
|
thread: ThreadId,
|
||||||
|
sourceActor: SourceActorId
|
||||||
|
) {
|
||||||
|
return async function({ dispatch, getState, client }: ThunkArgs) {
|
||||||
|
await sourceQueue.flush();
|
||||||
|
if (hasSourceActor(getState(), sourceActor)) {
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
|
||||||
|
const sources = await client.fetchThreadSources(thread);
|
||||||
|
await dispatch(newGeneratedSources(sources));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
import type { Target } from "../client/firefox/types";
|
import type { Target } from "../client/firefox/types";
|
||||||
import type { Action, ThunkArgs } from "./types";
|
import type { Action, ThunkArgs } from "./types";
|
||||||
import { removeSourceActors } from "./source-actors";
|
import { removeSourceActors } from "./source-actors";
|
||||||
|
import { newGeneratedSources } from "./sources";
|
||||||
import { validateContext } from "../utils/context";
|
import { validateContext } from "../utils/context";
|
||||||
|
|
||||||
import { getContext, getThread, getSourceActorsForThread } from "../selectors";
|
import { getContext, getThread, getSourceActorsForThread } from "../selectors";
|
||||||
|
@ -19,6 +20,19 @@ export function addTarget(targetFront: Target) {
|
||||||
validateContext(getState(), cx);
|
validateContext(getState(), cx);
|
||||||
|
|
||||||
dispatch(({ type: "INSERT_THREAD", cx, newThread: thread }: Action));
|
dispatch(({ type: "INSERT_THREAD", cx, newThread: thread }: Action));
|
||||||
|
|
||||||
|
// Fetch the sources and install breakpoints on any new workers.
|
||||||
|
try {
|
||||||
|
const sources = await client.fetchThreadSources(thread.actor);
|
||||||
|
validateContext(getState(), cx);
|
||||||
|
|
||||||
|
await dispatch(newGeneratedSources(sources));
|
||||||
|
} catch (e) {
|
||||||
|
// NOTE: This fails quietly because it is pretty easy for sources to
|
||||||
|
// throw during the fetch if their thread shuts down,
|
||||||
|
// which would cause test failures.
|
||||||
|
console.error(e);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,28 +7,20 @@
|
||||||
import { setupCommands, clientCommands } from "./firefox/commands";
|
import { setupCommands, clientCommands } from "./firefox/commands";
|
||||||
import { setupEvents, clientEvents } from "./firefox/events";
|
import { setupEvents, clientEvents } from "./firefox/events";
|
||||||
import { features, prefs } from "../utils/prefs";
|
import { features, prefs } from "../utils/prefs";
|
||||||
import { prepareSourcePayload } from "./firefox/create";
|
|
||||||
|
|
||||||
let actions;
|
let actions;
|
||||||
let targetList;
|
let targetList;
|
||||||
let resourceWatcher;
|
|
||||||
|
|
||||||
export async function onConnect(
|
export async function onConnect(
|
||||||
connection: any,
|
connection: any,
|
||||||
_actions: Object,
|
_actions: Object
|
||||||
store: any
|
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const {
|
const { devToolsClient, targetList: _targetList } = connection;
|
||||||
devToolsClient,
|
|
||||||
targetList: _targetList,
|
|
||||||
resourceWatcher: _resourceWatcher,
|
|
||||||
} = connection;
|
|
||||||
actions = _actions;
|
actions = _actions;
|
||||||
targetList = _targetList;
|
targetList = _targetList;
|
||||||
resourceWatcher = _resourceWatcher;
|
|
||||||
|
|
||||||
setupCommands({ devToolsClient, targetList });
|
setupCommands({ devToolsClient, targetList });
|
||||||
setupEvents({ actions, devToolsClient, store, resourceWatcher });
|
setupEvents({ actions, devToolsClient });
|
||||||
const { targetFront } = targetList;
|
const { targetFront } = targetList;
|
||||||
if (targetFront.isBrowsingContext || targetFront.isParentProcess) {
|
if (targetFront.isBrowsingContext || targetFront.isParentProcess) {
|
||||||
targetList.listenForWorkers = true;
|
targetList.listenForWorkers = true;
|
||||||
|
@ -44,21 +36,6 @@ export async function onConnect(
|
||||||
onTargetAvailable,
|
onTargetAvailable,
|
||||||
onTargetDestroyed
|
onTargetDestroyed
|
||||||
);
|
);
|
||||||
|
|
||||||
await resourceWatcher.watchResources([resourceWatcher.TYPES.SOURCE], {
|
|
||||||
onAvailable: onSourceAvailable,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function onDisconnect() {
|
|
||||||
targetList.unwatchTargets(
|
|
||||||
targetList.ALL_TYPES,
|
|
||||||
onTargetAvailable,
|
|
||||||
onTargetDestroyed
|
|
||||||
);
|
|
||||||
resourceWatcher.unwatchResources([resourceWatcher.TYPES.SOURCE], {
|
|
||||||
onAvailable: onSourceAvailable,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function onTargetAvailable({
|
async function onTargetAvailable({
|
||||||
|
@ -135,15 +112,4 @@ function onTargetDestroyed({ targetFront }): void {
|
||||||
actions.removeTarget(targetFront);
|
actions.removeTarget(targetFront);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function onSourceAvailable(sources) {
|
|
||||||
const frontendSources = await Promise.all(
|
|
||||||
sources.map(async source => {
|
|
||||||
const threadFront = await source.targetFront.getFront("thread");
|
|
||||||
const frontendSource = prepareSourcePayload(threadFront, source);
|
|
||||||
return frontendSource;
|
|
||||||
})
|
|
||||||
);
|
|
||||||
await actions.newGeneratedSources(frontendSources);
|
|
||||||
}
|
|
||||||
|
|
||||||
export { clientCommands, clientEvents };
|
export { clientCommands, clientEvents };
|
||||||
|
|
|
@ -4,12 +4,11 @@
|
||||||
|
|
||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
import { createThread, createFrame } from "./create";
|
import { prepareSourcePayload, createThread, createFrame } from "./create";
|
||||||
import {
|
import {
|
||||||
addThreadEventListeners,
|
addThreadEventListeners,
|
||||||
clientEvents,
|
clientEvents,
|
||||||
removeThreadEventListeners,
|
removeThreadEventListeners,
|
||||||
ensureSourceActor,
|
|
||||||
} from "./events";
|
} from "./events";
|
||||||
import { makePendingLocationId } from "../../utils/breakpoint";
|
import { makePendingLocationId } from "../../utils/breakpoint";
|
||||||
|
|
||||||
|
@ -23,6 +22,7 @@ import type {
|
||||||
PendingLocation,
|
PendingLocation,
|
||||||
Frame,
|
Frame,
|
||||||
FrameId,
|
FrameId,
|
||||||
|
GeneratedSourceData,
|
||||||
Script,
|
Script,
|
||||||
SourceId,
|
SourceId,
|
||||||
SourceActor,
|
SourceActor,
|
||||||
|
@ -39,6 +39,7 @@ import type {
|
||||||
ThreadFront,
|
ThreadFront,
|
||||||
ObjectFront,
|
ObjectFront,
|
||||||
ExpressionResult,
|
ExpressionResult,
|
||||||
|
SourcesPacket,
|
||||||
} from "./types";
|
} from "./types";
|
||||||
|
|
||||||
import type { EventListenerCategoryList } from "../../actions/types";
|
import type { EventListenerCategoryList } from "../../actions/types";
|
||||||
|
@ -317,13 +318,6 @@ function getProperties(thread: string, grip: Grip): Promise<*> {
|
||||||
async function getFrames(thread: string) {
|
async function getFrames(thread: string) {
|
||||||
const threadFront = lookupThreadFront(thread);
|
const threadFront = lookupThreadFront(thread);
|
||||||
const response = await threadFront.getFrames(0, CALL_STACK_PAGE_SIZE);
|
const response = await threadFront.getFrames(0, CALL_STACK_PAGE_SIZE);
|
||||||
|
|
||||||
// Ensure that each frame has its source already available.
|
|
||||||
// Because of throttling, the source may be available a bit late.
|
|
||||||
await Promise.all(
|
|
||||||
response.frames.map(frame => ensureSourceActor(frame.where.actor))
|
|
||||||
);
|
|
||||||
|
|
||||||
return response.frames.map<?Frame>((frame, i) =>
|
return response.frames.map<?Frame>((frame, i) =>
|
||||||
createFrame(thread, frame, i)
|
createFrame(thread, frame, i)
|
||||||
);
|
);
|
||||||
|
@ -402,6 +396,14 @@ function registerSourceActor(sourceActorId: string, sourceId: SourceId) {
|
||||||
sourceActors[sourceActorId] = sourceId;
|
sourceActors[sourceActorId] = sourceId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function getSources(
|
||||||
|
client: ThreadFront
|
||||||
|
): Promise<Array<GeneratedSourceData>> {
|
||||||
|
const { sources }: SourcesPacket = await client.getSources();
|
||||||
|
|
||||||
|
return sources.map(source => prepareSourcePayload(client, source));
|
||||||
|
}
|
||||||
|
|
||||||
async function toggleEventLogging(logEventBreakpoints: boolean) {
|
async function toggleEventLogging(logEventBreakpoints: boolean) {
|
||||||
return forEachThread(thread =>
|
return forEachThread(thread =>
|
||||||
thread.toggleEventLogging(logEventBreakpoints)
|
thread.toggleEventLogging(logEventBreakpoints)
|
||||||
|
@ -416,6 +418,21 @@ function getAllThreadFronts(): ThreadFront[] {
|
||||||
return fronts;
|
return fronts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fetch the sources for all the targets
|
||||||
|
async function fetchSources(): Promise<Array<GeneratedSourceData>> {
|
||||||
|
let sources = [];
|
||||||
|
for (const threadFront of getAllThreadFronts()) {
|
||||||
|
sources = sources.concat(await getSources(threadFront));
|
||||||
|
}
|
||||||
|
return sources;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fetchThreadSources(
|
||||||
|
thread: string
|
||||||
|
): Promise<Array<GeneratedSourceData>> {
|
||||||
|
return getSources(lookupThreadFront(thread));
|
||||||
|
}
|
||||||
|
|
||||||
// Check if any of the targets were paused before we opened
|
// Check if any of the targets were paused before we opened
|
||||||
// the debugger. If one is paused. Fake a `pause` RDP event
|
// the debugger. If one is paused. Fake a `pause` RDP event
|
||||||
// by directly calling the client event listener.
|
// by directly calling the client event listener.
|
||||||
|
@ -538,6 +555,8 @@ const clientCommands = {
|
||||||
getFrames,
|
getFrames,
|
||||||
pauseOnExceptions,
|
pauseOnExceptions,
|
||||||
toggleEventLogging,
|
toggleEventLogging,
|
||||||
|
fetchSources,
|
||||||
|
fetchThreadSources,
|
||||||
checkIfAlreadyPaused,
|
checkIfAlreadyPaused,
|
||||||
registerSourceActor,
|
registerSourceActor,
|
||||||
addThread,
|
addThread,
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
|
SourcePacket,
|
||||||
PausedPacket,
|
PausedPacket,
|
||||||
ThreadFront,
|
ThreadFront,
|
||||||
Target,
|
Target,
|
||||||
|
@ -13,23 +14,19 @@ import type {
|
||||||
|
|
||||||
import Actions from "../../actions";
|
import Actions from "../../actions";
|
||||||
|
|
||||||
import { createPause } from "./create";
|
import { createPause, prepareSourcePayload } from "./create";
|
||||||
import sourceQueue from "../../utils/source-queue";
|
import sourceQueue from "../../utils/source-queue";
|
||||||
import { recordEvent } from "../../utils/telemetry";
|
import { recordEvent } from "../../utils/telemetry";
|
||||||
import { prefs } from "../../utils/prefs";
|
import { prefs } from "../../utils/prefs";
|
||||||
import { hasSourceActor } from "../../selectors";
|
|
||||||
import { stringToSourceActorId } from "../../reducers/source-actors";
|
|
||||||
|
|
||||||
type Dependencies = {
|
type Dependencies = {
|
||||||
actions: typeof Actions,
|
actions: typeof Actions,
|
||||||
devToolsClient: DevToolsClient,
|
devToolsClient: DevToolsClient,
|
||||||
store: any,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let actions: typeof Actions;
|
let actions: typeof Actions;
|
||||||
let isInterrupted: boolean;
|
let isInterrupted: boolean;
|
||||||
let threadFrontListeners: WeakMap<ThreadFront, Array<Function>>;
|
let threadFrontListeners: WeakMap<ThreadFront, Array<Function>>;
|
||||||
let store: any;
|
|
||||||
|
|
||||||
function addThreadEventListeners(thread: ThreadFront): void {
|
function addThreadEventListeners(thread: ThreadFront): void {
|
||||||
const removeListeners = [];
|
const removeListeners = [];
|
||||||
|
@ -56,7 +53,6 @@ function attachAllTargets(currentTarget: Target): boolean {
|
||||||
function setupEvents(dependencies: Dependencies): void {
|
function setupEvents(dependencies: Dependencies): void {
|
||||||
actions = dependencies.actions;
|
actions = dependencies.actions;
|
||||||
sourceQueue.initialize(actions);
|
sourceQueue.initialize(actions);
|
||||||
store = dependencies.store;
|
|
||||||
|
|
||||||
threadFrontListeners = new WeakMap();
|
threadFrontListeners = new WeakMap();
|
||||||
}
|
}
|
||||||
|
@ -82,7 +78,10 @@ async function paused(
|
||||||
if (packet.frame) {
|
if (packet.frame) {
|
||||||
// When reloading we might receive a pause event before the
|
// When reloading we might receive a pause event before the
|
||||||
// top frame's source has arrived.
|
// top frame's source has arrived.
|
||||||
await ensureSourceActor(packet.frame.where.actor);
|
await actions.ensureSourceActor(
|
||||||
|
threadFront.actorID,
|
||||||
|
packet.frame.where.actor
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const pause = createPause(threadFront.actor, packet);
|
const pause = createPause(threadFront.actor, packet);
|
||||||
|
@ -103,36 +102,17 @@ function resumed(threadFront: ThreadFront): void {
|
||||||
actions.resumed(threadFront.actorID);
|
actions.resumed(threadFront.actorID);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
function newSource(threadFront: ThreadFront, { source }: SourcePacket): void {
|
||||||
* This method wait for the given source is registered in Redux store.
|
sourceQueue.queue({
|
||||||
*
|
type: "generated",
|
||||||
* @param {String} sourceActor
|
data: prepareSourcePayload(threadFront, source),
|
||||||
* Actor ID of the source to be waiting for.
|
|
||||||
*/
|
|
||||||
async function ensureSourceActor(sourceActor: string) {
|
|
||||||
const sourceActorId = stringToSourceActorId(sourceActor);
|
|
||||||
if (!hasSourceActor(store.getState(), sourceActorId)) {
|
|
||||||
await new Promise(resolve => {
|
|
||||||
const unsubscribe = store.subscribe(check);
|
|
||||||
let currentState = null;
|
|
||||||
function check() {
|
|
||||||
const previousState = currentState;
|
|
||||||
currentState = store.getState().sourceActors.values;
|
|
||||||
if (previousState == currentState) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (hasSourceActor(store.getState(), sourceActorId)) {
|
|
||||||
unsubscribe();
|
|
||||||
resolve();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const clientEvents = {
|
const clientEvents = {
|
||||||
paused,
|
paused,
|
||||||
resumed,
|
resumed,
|
||||||
|
newSource,
|
||||||
};
|
};
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
@ -141,5 +121,4 @@ export {
|
||||||
addThreadEventListeners,
|
addThreadEventListeners,
|
||||||
removeThreadEventListeners,
|
removeThreadEventListeners,
|
||||||
attachAllTargets,
|
attachAllTargets,
|
||||||
ensureSourceActor,
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -58,6 +58,10 @@ async function loadInitialState() {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getClient(connection: any) {
|
||||||
|
return firefox;
|
||||||
|
}
|
||||||
|
|
||||||
export async function onConnect(
|
export async function onConnect(
|
||||||
connection: Object,
|
connection: Object,
|
||||||
panelWorkers: Object,
|
panelWorkers: Object,
|
||||||
|
@ -70,7 +74,8 @@ export async function onConnect(
|
||||||
|
|
||||||
verifyPrefSchema();
|
verifyPrefSchema();
|
||||||
|
|
||||||
const commands = firefox.clientCommands;
|
const client = getClient(connection);
|
||||||
|
const commands = client.clientCommands;
|
||||||
|
|
||||||
const initialState = await loadInitialState();
|
const initialState = await loadInitialState();
|
||||||
const workers = bootstrapWorkers(panelWorkers);
|
const workers = bootstrapWorkers(panelWorkers);
|
||||||
|
@ -82,7 +87,7 @@ export async function onConnect(
|
||||||
initialState
|
initialState
|
||||||
);
|
);
|
||||||
|
|
||||||
const connected = firefox.onConnect(connection, actions, store);
|
const connected = client.onConnect(connection, actions);
|
||||||
|
|
||||||
await syncBreakpoints();
|
await syncBreakpoints();
|
||||||
syncXHRBreakpoints();
|
syncXHRBreakpoints();
|
||||||
|
@ -92,14 +97,10 @@ export async function onConnect(
|
||||||
selectors,
|
selectors,
|
||||||
workers,
|
workers,
|
||||||
connection,
|
connection,
|
||||||
client: firefox.clientCommands,
|
client: client.clientCommands,
|
||||||
});
|
});
|
||||||
|
|
||||||
bootstrapApp(store, panel);
|
bootstrapApp(store, panel);
|
||||||
await connected;
|
await connected;
|
||||||
return { store, actions, selectors, client: commands };
|
return { store, actions, selectors, client: commands };
|
||||||
}
|
}
|
||||||
|
|
||||||
export function onDisconnect() {
|
|
||||||
return firefox.onDisconnect();
|
|
||||||
}
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
import ReactDOM from "react-dom";
|
import ReactDOM from "react-dom";
|
||||||
import { onConnect, onDisconnect } from "./client";
|
import { onConnect } from "./client";
|
||||||
import { teardownWorkers } from "./utils/bootstrap";
|
import { teardownWorkers } from "./utils/bootstrap";
|
||||||
import sourceQueue from "./utils/source-queue";
|
import sourceQueue from "./utils/source-queue";
|
||||||
|
|
||||||
|
@ -15,25 +15,17 @@ function unmountRoot() {
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
bootstrap: ({
|
bootstrap: ({ targetList, devToolsClient, workers, panel }: any) =>
|
||||||
targetList,
|
|
||||||
resourceWatcher,
|
|
||||||
devToolsClient,
|
|
||||||
workers,
|
|
||||||
panel,
|
|
||||||
}: any) =>
|
|
||||||
onConnect(
|
onConnect(
|
||||||
{
|
{
|
||||||
tab: { clientType: "firefox" },
|
tab: { clientType: "firefox" },
|
||||||
targetList,
|
targetList,
|
||||||
resourceWatcher,
|
|
||||||
devToolsClient,
|
devToolsClient,
|
||||||
},
|
},
|
||||||
workers,
|
workers,
|
||||||
panel
|
panel
|
||||||
),
|
),
|
||||||
destroy: () => {
|
destroy: () => {
|
||||||
onDisconnect();
|
|
||||||
unmountRoot();
|
unmountRoot();
|
||||||
sourceQueue.clear();
|
sourceQueue.clear();
|
||||||
teardownWorkers();
|
teardownWorkers();
|
||||||
|
|
|
@ -25,10 +25,7 @@ export type PendingBreakpointsState = { [string]: PendingBreakpoint };
|
||||||
function update(state: PendingBreakpointsState = {}, action: Action) {
|
function update(state: PendingBreakpointsState = {}, action: Action) {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case "SET_BREAKPOINT":
|
case "SET_BREAKPOINT":
|
||||||
if (action.status === "start") {
|
|
||||||
return setBreakpoint(state, action);
|
return setBreakpoint(state, action);
|
||||||
}
|
|
||||||
return state;
|
|
||||||
|
|
||||||
case "REMOVE_BREAKPOINT":
|
case "REMOVE_BREAKPOINT":
|
||||||
if (action.status === "start") {
|
if (action.status === "start") {
|
||||||
|
|
|
@ -47,11 +47,7 @@ export function insertResources<R: ResourceBound>(
|
||||||
for (const resource of resources) {
|
for (const resource of resources) {
|
||||||
const { id } = resource;
|
const { id } = resource;
|
||||||
if (state.identity[id]) {
|
if (state.identity[id]) {
|
||||||
throw new Error(
|
throw new Error(`Resource "${id}" already exists, cannot insert`);
|
||||||
`Resource "${id}" already exists, cannot insert ${JSON.stringify(
|
|
||||||
resource
|
|
||||||
)}`
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
if (state.values[id]) {
|
if (state.values[id]) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
import { throttle } from "lodash";
|
import { throttle } from "lodash";
|
||||||
import type { QueuedSourceData } from "../types";
|
import type { QueuedSourceData } from "../types";
|
||||||
|
|
||||||
// This SourceQueue module is now only used for source mapped sources
|
|
||||||
let newQueuedSources;
|
let newQueuedSources;
|
||||||
let queuedSources;
|
let queuedSources;
|
||||||
let currentWork;
|
let currentWork;
|
||||||
|
|
|
@ -15,8 +15,6 @@ add_task(async function() {
|
||||||
|
|
||||||
// Navigate to a content process URL and check that the sources tree updates
|
// Navigate to a content process URL and check that the sources tree updates
|
||||||
await navigate(dbg, EXAMPLE_URL + "doc-scripts.html", "simple1.js");
|
await navigate(dbg, EXAMPLE_URL + "doc-scripts.html", "simple1.js");
|
||||||
info("Wait for all sources to be in the store");
|
|
||||||
await waitFor(() => dbg.selectors.getSourceCount() == 5);
|
|
||||||
is(dbg.selectors.getSourceCount(), 5, "5 sources are loaded.");
|
is(dbg.selectors.getSourceCount(), 5, "5 sources are loaded.");
|
||||||
|
|
||||||
// Check that you can still break after target switching.
|
// Check that you can still break after target switching.
|
||||||
|
|
|
@ -28,14 +28,15 @@ class SourceMapURLService {
|
||||||
this._urlToIDMap = new Map();
|
this._urlToIDMap = new Map();
|
||||||
this._mapsById = new Map();
|
this._mapsById = new Map();
|
||||||
this._sourcesLoading = null;
|
this._sourcesLoading = null;
|
||||||
this._onResourceAvailable = this._onResourceAvailable.bind(this);
|
|
||||||
this._runningCallback = false;
|
this._runningCallback = false;
|
||||||
|
|
||||||
this._syncPrevValue = this._syncPrevValue.bind(this);
|
this._syncPrevValue = this._syncPrevValue.bind(this);
|
||||||
|
this._onSourceUpdatedEvent = this._onSourceUpdatedEvent.bind(this);
|
||||||
this._clearAllState = this._clearAllState.bind(this);
|
this._clearAllState = this._clearAllState.bind(this);
|
||||||
|
this._onNewStyleSheet = this._onNewStyleSheet.bind(this);
|
||||||
|
|
||||||
this._target.on("will-navigate", this._clearAllState);
|
this._target.on("will-navigate", this._clearAllState);
|
||||||
|
this._target.on("source-updated", this._onSourceUpdatedEvent);
|
||||||
Services.prefs.addObserver(SOURCE_MAP_PREF, this._syncPrevValue);
|
Services.prefs.addObserver(SOURCE_MAP_PREF, this._syncPrevValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,6 +47,7 @@ class SourceMapURLService {
|
||||||
destroy() {
|
destroy() {
|
||||||
this._clearAllState();
|
this._clearAllState();
|
||||||
this._target.off("will-navigate", this._clearAllState);
|
this._target.off("will-navigate", this._clearAllState);
|
||||||
|
this._target.off("source-updated", this._onSourceUpdatedEvent);
|
||||||
Services.prefs.removeObserver(SOURCE_MAP_PREF, this._syncPrevValue);
|
Services.prefs.removeObserver(SOURCE_MAP_PREF, this._syncPrevValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -202,10 +204,9 @@ class SourceMapURLService {
|
||||||
this._pendingURLSubscriptions.clear();
|
this._pendingURLSubscriptions.clear();
|
||||||
this._urlToIDMap.clear();
|
this._urlToIDMap.clear();
|
||||||
|
|
||||||
const { resourceWatcher } = this._toolbox;
|
|
||||||
try {
|
try {
|
||||||
resourceWatcher.unwatchResources(
|
this._toolbox.resourceWatcher.unwatchResources(
|
||||||
[resourceWatcher.TYPES.STYLESHEET, resourceWatcher.TYPES.SOURCE],
|
[this._toolbox.resourceWatcher.TYPES.STYLESHEET],
|
||||||
{ onAvailable: this._onResourceAvailable }
|
{ onAvailable: this._onResourceAvailable }
|
||||||
);
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
@ -216,6 +217,10 @@ class SourceMapURLService {
|
||||||
this._sourcesLoading = null;
|
this._sourcesLoading = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_onSourceUpdatedEvent(sourceEvent) {
|
||||||
|
this._onNewJavascript(sourceEvent.source);
|
||||||
|
}
|
||||||
|
|
||||||
_onNewJavascript(source) {
|
_onNewJavascript(source) {
|
||||||
const { url, actor: id, sourceMapBaseURL, sourceMapURL } = source;
|
const { url, actor: id, sourceMapBaseURL, sourceMapURL } = source;
|
||||||
|
|
||||||
|
@ -416,42 +421,54 @@ class SourceMapURLService {
|
||||||
if (!this._prefValue) {
|
if (!this._prefValue) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!this._sourcesLoading) {
|
||||||
|
const sourcesLoading = (async () => {
|
||||||
if (this._target.isWorkerTarget) {
|
if (this._target.isWorkerTarget) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this._sourcesLoading) {
|
this._onResourceAvailable = async resources => {
|
||||||
const { resourceWatcher } = this._toolbox;
|
if (this._sourcesLoading === sourcesLoading) {
|
||||||
const { STYLESHEET, SOURCE } = resourceWatcher.TYPES;
|
|
||||||
|
|
||||||
this._sourcesLoading = resourceWatcher.watchResources(
|
|
||||||
[STYLESHEET, SOURCE],
|
|
||||||
{
|
|
||||||
onAvailable: this._onResourceAvailable,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return this._sourcesLoading;
|
|
||||||
}
|
|
||||||
|
|
||||||
waitForSourcesLoading() {
|
|
||||||
if (this._sourcesLoading) {
|
|
||||||
return this._sourcesLoading;
|
|
||||||
}
|
|
||||||
return Promise.resolve();
|
|
||||||
}
|
|
||||||
|
|
||||||
_onResourceAvailable(resources) {
|
|
||||||
const { resourceWatcher } = this._toolbox;
|
|
||||||
const { STYLESHEET, SOURCE } = resourceWatcher.TYPES;
|
|
||||||
for (const resource of resources) {
|
for (const resource of resources) {
|
||||||
if (resource.resourceType == STYLESHEET) {
|
|
||||||
this._onNewStyleSheet(resource);
|
this._onNewStyleSheet(resource);
|
||||||
} else if (resource.resourceType == SOURCE) {
|
|
||||||
this._onNewJavascript(resource);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
await Promise.all([
|
||||||
|
this._toolbox.resourceWatcher.watchResources(
|
||||||
|
[this._toolbox.resourceWatcher.TYPES.STYLESHEET],
|
||||||
|
{ onAvailable: this._onResourceAvailable }
|
||||||
|
),
|
||||||
|
(async () => {
|
||||||
|
const { threadFront } = this._toolbox;
|
||||||
|
if (!threadFront) {
|
||||||
|
console.warn(
|
||||||
|
"sourcemap url service cannot query for sources, no threadFront found"
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const { sources } = await threadFront.getSources();
|
||||||
|
if (this._sourcesLoading === sourcesLoading) {
|
||||||
|
// If we've cleared the state since starting this request,
|
||||||
|
// we don't want to populate these.
|
||||||
|
for (const source of sources) {
|
||||||
|
this._onNewJavascript(source);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
// Also ignore any protocol-based errors.
|
||||||
|
}
|
||||||
|
})(),
|
||||||
|
]);
|
||||||
|
})();
|
||||||
|
this._sourcesLoading = sourcesLoading;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this._sourcesLoading;
|
||||||
}
|
}
|
||||||
|
|
||||||
_convertPendingURLSubscriptionsToID(url, id) {
|
_convertPendingURLSubscriptionsToID(url, id) {
|
||||||
|
|
|
@ -119,21 +119,16 @@ function createScript(url) {
|
||||||
function waitForSourceLoad(toolbox, url) {
|
function waitForSourceLoad(toolbox, url) {
|
||||||
info(`Waiting for source ${url} to be available...`);
|
info(`Waiting for source ${url} to be available...`);
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
const { resourceWatcher } = toolbox;
|
const target = toolbox.target;
|
||||||
|
|
||||||
function onAvailable(sources) {
|
function sourceHandler(sourceEvent) {
|
||||||
for (const source of sources) {
|
if (sourceEvent && sourceEvent.source && sourceEvent.source.url === url) {
|
||||||
if (source.url === url) {
|
|
||||||
resourceWatcher.unwatchResources([resourceWatcher.TYPES.SOURCE], {
|
|
||||||
onAvailable,
|
|
||||||
});
|
|
||||||
resolve();
|
resolve();
|
||||||
|
target.off("source-updated", sourceHandler);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
resourceWatcher.watchResources([resourceWatcher.TYPES.SOURCE], {
|
target.on("source-updated", sourceHandler);
|
||||||
onAvailable,
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3586,6 +3586,11 @@ Toolbox.prototype = {
|
||||||
this._lastFocusedElement = null;
|
this._lastFocusedElement = null;
|
||||||
this._pausedThreads = null;
|
this._pausedThreads = null;
|
||||||
|
|
||||||
|
if (this._sourceMapURLService) {
|
||||||
|
this._sourceMapURLService.destroy();
|
||||||
|
this._sourceMapURLService = null;
|
||||||
|
}
|
||||||
|
|
||||||
if (this._sourceMapService) {
|
if (this._sourceMapService) {
|
||||||
this._sourceMapService.stopSourceMapWorker();
|
this._sourceMapService.stopSourceMapWorker();
|
||||||
this._sourceMapService = null;
|
this._sourceMapService = null;
|
||||||
|
@ -3690,12 +3695,6 @@ Toolbox.prototype = {
|
||||||
this._netMonitorAPI = null;
|
this._netMonitorAPI = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this._sourceMapURLService) {
|
|
||||||
await this._sourceMapURLService.waitForSourcesLoading();
|
|
||||||
this._sourceMapURLService.destroy();
|
|
||||||
this._sourceMapURLService = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._removeWindowListeners();
|
this._removeWindowListeners();
|
||||||
this._removeChromeEventHandlerEvents();
|
this._removeChromeEventHandlerEvents();
|
||||||
|
|
||||||
|
|
|
@ -42,6 +42,7 @@ function TargetMixin(parentClass) {
|
||||||
this._forceChrome = false;
|
this._forceChrome = false;
|
||||||
|
|
||||||
this.destroy = this.destroy.bind(this);
|
this.destroy = this.destroy.bind(this);
|
||||||
|
this._onNewSource = this._onNewSource.bind(this);
|
||||||
|
|
||||||
this.threadFront = null;
|
this.threadFront = null;
|
||||||
|
|
||||||
|
@ -565,9 +566,16 @@ function TargetMixin(parentClass) {
|
||||||
|
|
||||||
await this.threadFront.attach(options);
|
await this.threadFront.attach(options);
|
||||||
|
|
||||||
|
this.threadFront.on("newSource", this._onNewSource);
|
||||||
|
|
||||||
return this.threadFront;
|
return this.threadFront;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Listener for "newSource" event fired by the thread actor
|
||||||
|
_onNewSource(packet) {
|
||||||
|
this.emit("source-updated", packet);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Setup listeners for remote debugging, updating existing ones as necessary.
|
* Setup listeners for remote debugging, updating existing ones as necessary.
|
||||||
*/
|
*/
|
||||||
|
@ -587,6 +595,11 @@ function TargetMixin(parentClass) {
|
||||||
}
|
}
|
||||||
this.off("tabDetached", this.destroy);
|
this.off("tabDetached", this.destroy);
|
||||||
|
|
||||||
|
// Remove listeners set in attachThread
|
||||||
|
if (this.threadFront) {
|
||||||
|
this.threadFront.off("newSource", this._onNewSource);
|
||||||
|
}
|
||||||
|
|
||||||
// Remove listeners set in attachConsole
|
// Remove listeners set in attachConsole
|
||||||
if (this.removeOnInspectObjectListener) {
|
if (this.removeOnInspectObjectListener) {
|
||||||
this.removeOnInspectObjectListener();
|
this.removeOnInspectObjectListener();
|
||||||
|
|
|
@ -233,11 +233,6 @@ BoxModel.prototype = {
|
||||||
* Hides the box-model highlighter on the currently selected element.
|
* Hides the box-model highlighter on the currently selected element.
|
||||||
*/
|
*/
|
||||||
onHideBoxModelHighlighter() {
|
onHideBoxModelHighlighter() {
|
||||||
// As React components aren't destroyed when the panel closes,
|
|
||||||
// this function may still be called and throw because of destroyed fronts.
|
|
||||||
if (!this.inspector) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.inspector.highlighters.hideHighlighterType(
|
this.inspector.highlighters.hideHighlighterType(
|
||||||
this.inspector.highlighters.TYPES.BOXMODEL
|
this.inspector.highlighters.TYPES.BOXMODEL
|
||||||
);
|
);
|
||||||
|
|
|
@ -1927,11 +1927,6 @@ Inspector.prototype = {
|
||||||
* Options passed to the highlighter actor.
|
* Options passed to the highlighter actor.
|
||||||
*/
|
*/
|
||||||
onShowBoxModelHighlighterForNode(nodeFront, options) {
|
onShowBoxModelHighlighterForNode(nodeFront, options) {
|
||||||
// As React components aren't destroyed when the panel closes,
|
|
||||||
// this function may still be called and throw because of destroyed fronts.
|
|
||||||
if (this._destroyed) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.highlighters.showHighlighterTypeForNode(
|
this.highlighters.showHighlighterTypeForNode(
|
||||||
this.highlighters.TYPES.BOXMODEL,
|
this.highlighters.TYPES.BOXMODEL,
|
||||||
nodeFront,
|
nodeFront,
|
||||||
|
|
|
@ -94,9 +94,6 @@ add_task(async function testForeignCookieBlockedMessage() {
|
||||||
message,
|
message,
|
||||||
getStorageErrorUrl("CookieBlockedForeign")
|
getStorageErrorUrl("CookieBlockedForeign")
|
||||||
);
|
);
|
||||||
// We explicitely destroy the toolbox in order to ensure waiting for its full destruction
|
|
||||||
// and avoid leak / pending requests
|
|
||||||
await hud.toolbox.destroy();
|
|
||||||
win.close();
|
win.close();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -127,9 +124,6 @@ add_task(async function testLimitForeignCookieBlockedMessage() {
|
||||||
message,
|
message,
|
||||||
getStorageErrorUrl("CookieBlockedForeign")
|
getStorageErrorUrl("CookieBlockedForeign")
|
||||||
);
|
);
|
||||||
// We explicitely destroy the toolbox in order to ensure waiting for its full destruction
|
|
||||||
// and avoid leak / pending requests
|
|
||||||
await hud.toolbox.destroy();
|
|
||||||
win.close();
|
win.close();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -150,9 +144,6 @@ add_task(async function testAllCookieBlockedMessage() {
|
||||||
message,
|
message,
|
||||||
getStorageErrorUrl("CookieBlockedAll")
|
getStorageErrorUrl("CookieBlockedAll")
|
||||||
);
|
);
|
||||||
// We explicitely destroy the toolbox in order to ensure waiting for its full destruction
|
|
||||||
// and avoid leak / pending requests
|
|
||||||
await hud.toolbox.destroy();
|
|
||||||
win.close();
|
win.close();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -173,9 +164,6 @@ add_task(async function testTrackerCookieBlockedMessage() {
|
||||||
message,
|
message,
|
||||||
getStorageErrorUrl("CookieBlockedTracker")
|
getStorageErrorUrl("CookieBlockedTracker")
|
||||||
);
|
);
|
||||||
// We explicitely destroy the toolbox in order to ensure waiting for its full destruction
|
|
||||||
// and avoid leak / pending requests
|
|
||||||
await hud.toolbox.destroy();
|
|
||||||
win.close();
|
win.close();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -196,9 +184,6 @@ add_task(async function testForeignCookiePartitionedMessage() {
|
||||||
message,
|
message,
|
||||||
getStorageErrorUrl("CookiePartitionedForeign")
|
getStorageErrorUrl("CookiePartitionedForeign")
|
||||||
);
|
);
|
||||||
// We explicitely destroy the toolbox in order to ensure waiting for its full destruction
|
|
||||||
// and avoid leak / pending requests
|
|
||||||
await hud.toolbox.destroy();
|
|
||||||
win.close();
|
win.close();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -227,9 +212,6 @@ add_task(async function testCookieBlockedByPermissionMessage() {
|
||||||
message,
|
message,
|
||||||
getStorageErrorUrl("CookieBlockedByPermission")
|
getStorageErrorUrl("CookieBlockedByPermission")
|
||||||
);
|
);
|
||||||
// We explicitely destroy the toolbox in order to ensure waiting for its full destruction
|
|
||||||
// and avoid leak / pending requests
|
|
||||||
await hud.toolbox.destroy();
|
|
||||||
win.close();
|
win.close();
|
||||||
|
|
||||||
// Remove the custom permission.
|
// Remove the custom permission.
|
||||||
|
|
|
@ -144,11 +144,6 @@ add_task(async function testInvalidSameSiteMessage() {
|
||||||
`| ${message2}`,
|
`| ${message2}`,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Source map are being resolved in background and we might have
|
|
||||||
// pending request related to this service if we close the window
|
|
||||||
// immeditely. So just wait for these request to finish before proceeding.
|
|
||||||
await hud.toolbox.sourceMapURLService.waitForSourcesLoading();
|
|
||||||
|
|
||||||
await win.close();
|
await win.close();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -144,11 +144,8 @@ class Front extends Pool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call listeners registered via `watchFronts` method
|
// Call listeners registered via `watchFronts` method
|
||||||
// (ignore if this front has been destroyed)
|
|
||||||
if (this._frontCreationListeners) {
|
|
||||||
this._frontCreationListeners.emit(front.typeName, front);
|
this._frontCreationListeners.emit(front.typeName, front);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
async unmanage(front) {
|
async unmanage(front) {
|
||||||
super.unmanage(front);
|
super.unmanage(front);
|
||||||
|
|
|
@ -11,7 +11,6 @@ DevToolsModules(
|
||||||
'network-events.js',
|
'network-events.js',
|
||||||
'platform-messages.js',
|
'platform-messages.js',
|
||||||
'root-node.js',
|
'root-node.js',
|
||||||
'source.js',
|
|
||||||
'stylesheet.js',
|
'stylesheet.js',
|
||||||
'websocket.js',
|
'websocket.js',
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,81 +0,0 @@
|
||||||
/* 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/. */
|
|
||||||
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
const {
|
|
||||||
ResourceWatcher,
|
|
||||||
} = require("devtools/shared/resources/resource-watcher");
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Emit SOURCE resources, which represents a Javascript source and has the following attributes set on "available":
|
|
||||||
*
|
|
||||||
* - introductionType {null|String}: A string indicating how this source code was introduced into the system.
|
|
||||||
* This will typically be set to "scriptElement", "eval", ...
|
|
||||||
* But this may have many other values:
|
|
||||||
* https://searchfox.org/mozilla-central/rev/ac142717cc067d875e83e4b1316f004f6e063a46/dom/script/ScriptLoader.cpp#2628-2639
|
|
||||||
* https://searchfox.org/mozilla-central/search?q=symbol:_ZN2JS14CompileOptions19setIntroductionTypeEPKc&redirect=false
|
|
||||||
* https://searchfox.org/mozilla-central/rev/ac142717cc067d875e83e4b1316f004f6e063a46/devtools/server/actors/source.js#160-169
|
|
||||||
* - sourceMapBaseURL {String}: Base URL where to look for a source map.
|
|
||||||
* This isn't the source map URL.
|
|
||||||
* - sourceMapURL {null|String}: URL of the source map, if there is one.
|
|
||||||
* - url {null|String}: URL of the source, if it relates to a particular URL.
|
|
||||||
* Evaled sources won't have any related URL.
|
|
||||||
* - isBlackBoxed {Boolean}: Specifying whether the source actor's 'black-boxed' flag is set.
|
|
||||||
* - extensionName {null|String}: If the source comes from an add-on, the add-on name.
|
|
||||||
*/
|
|
||||||
module.exports = async function({
|
|
||||||
targetList,
|
|
||||||
targetFront,
|
|
||||||
isFissionEnabledOnContentToolbox,
|
|
||||||
onAvailable,
|
|
||||||
}) {
|
|
||||||
const isBrowserToolbox = targetList.targetFront.isParentProcess;
|
|
||||||
const isNonTopLevelFrameTarget =
|
|
||||||
!targetFront.isTopLevel &&
|
|
||||||
targetFront.targetType === targetList.TYPES.FRAME;
|
|
||||||
|
|
||||||
if (isBrowserToolbox && isNonTopLevelFrameTarget) {
|
|
||||||
// In the BrowserToolbox, non-top-level frame targets are already
|
|
||||||
// debugged via content-process targets.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const threadFront = await targetFront.getFront("thread");
|
|
||||||
|
|
||||||
// Use a list of all notified SourceFront as we don't have a newSource event for all sources
|
|
||||||
// but we sometime get sources notified both via newSource event *and* sources() method...
|
|
||||||
// We store actor ID instead of SourceFront as it appears that multiple SourceFront for the same
|
|
||||||
// actor are created...
|
|
||||||
const sourcesActorIDCache = new Set();
|
|
||||||
|
|
||||||
// Forward new sources (but also existing ones, see next comment)
|
|
||||||
threadFront.on("newSource", ({ source }) => {
|
|
||||||
if (sourcesActorIDCache.has(source.actor)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
sourcesActorIDCache.add(source.actor);
|
|
||||||
// source is a SourceActor's form, add the resourceType attribute on it
|
|
||||||
source.resourceType = ResourceWatcher.TYPES.SOURCE;
|
|
||||||
onAvailable([source]);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Forward already existing sources
|
|
||||||
// Note that calling `sources()` will end up emitting `newSource` event for all existing sources.
|
|
||||||
// But not in some cases, for example, when the thread is already paused.
|
|
||||||
// (And yes, it means that already existing sources can be transfered twice over the wire)
|
|
||||||
let { sources } = await threadFront.sources();
|
|
||||||
|
|
||||||
// Note that `sources()` doesn't encapsulate SourceFront into a `source` attribute
|
|
||||||
// while `newSource` event does.
|
|
||||||
sources = sources.filter(source => {
|
|
||||||
return !sourcesActorIDCache.has(source.actor);
|
|
||||||
});
|
|
||||||
for (const source of sources) {
|
|
||||||
sourcesActorIDCache.add(source.actor);
|
|
||||||
// source is a SourceActor's form, add the resourceType attribute on it
|
|
||||||
source.resourceType = ResourceWatcher.TYPES.SOURCE;
|
|
||||||
}
|
|
||||||
onAvailable(sources);
|
|
||||||
};
|
|
|
@ -666,9 +666,6 @@ class ResourceWatcher {
|
||||||
const onAvailable = this._onResourceAvailable.bind(this, { targetFront });
|
const onAvailable = this._onResourceAvailable.bind(this, { targetFront });
|
||||||
const onDestroyed = this._onResourceDestroyed.bind(this, { targetFront });
|
const onDestroyed = this._onResourceDestroyed.bind(this, { targetFront });
|
||||||
const onUpdated = this._onResourceUpdated.bind(this, { targetFront });
|
const onUpdated = this._onResourceUpdated.bind(this, { targetFront });
|
||||||
if (!(resourceType in LegacyListeners)) {
|
|
||||||
throw new Error(`Missing legacy listener for ${resourceType}`);
|
|
||||||
}
|
|
||||||
return LegacyListeners[resourceType]({
|
return LegacyListeners[resourceType]({
|
||||||
targetList: this.targetList,
|
targetList: this.targetList,
|
||||||
targetFront,
|
targetFront,
|
||||||
|
@ -750,7 +747,6 @@ ResourceWatcher.TYPES = ResourceWatcher.prototype.TYPES = {
|
||||||
NETWORK_EVENT: "network-event",
|
NETWORK_EVENT: "network-event",
|
||||||
WEBSOCKET: "websocket",
|
WEBSOCKET: "websocket",
|
||||||
NETWORK_EVENT_STACKTRACE: "network-event-stacktrace",
|
NETWORK_EVENT_STACKTRACE: "network-event-stacktrace",
|
||||||
SOURCE: "source",
|
|
||||||
};
|
};
|
||||||
module.exports = { ResourceWatcher };
|
module.exports = { ResourceWatcher };
|
||||||
|
|
||||||
|
@ -795,8 +791,6 @@ const LegacyListeners = {
|
||||||
.WEBSOCKET]: require("devtools/shared/resources/legacy-listeners/websocket"),
|
.WEBSOCKET]: require("devtools/shared/resources/legacy-listeners/websocket"),
|
||||||
[ResourceWatcher.TYPES
|
[ResourceWatcher.TYPES
|
||||||
.NETWORK_EVENT_STACKTRACE]: require("devtools/shared/resources/legacy-listeners/network-event-stacktraces"),
|
.NETWORK_EVENT_STACKTRACE]: require("devtools/shared/resources/legacy-listeners/network-event-stacktraces"),
|
||||||
[ResourceWatcher.TYPES
|
|
||||||
.SOURCE]: require("devtools/shared/resources/legacy-listeners/source"),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Optional transformers for each type of resource.
|
// Optional transformers for each type of resource.
|
||||||
|
|
|
@ -9,8 +9,6 @@ support-files =
|
||||||
network_document.html
|
network_document.html
|
||||||
fission_document.html
|
fission_document.html
|
||||||
fission_iframe.html
|
fission_iframe.html
|
||||||
sources.html
|
|
||||||
sources.js
|
|
||||||
style_document.css
|
style_document.css
|
||||||
style_document.html
|
style_document.html
|
||||||
style_iframe.css
|
style_iframe.css
|
||||||
|
@ -21,7 +19,6 @@ support-files =
|
||||||
test_worker.js
|
test_worker.js
|
||||||
websocket_backend_wsh.py
|
websocket_backend_wsh.py
|
||||||
websocket_frontend.html
|
websocket_frontend.html
|
||||||
worker-sources.js
|
|
||||||
|
|
||||||
[browser_resources_client_caching.js]
|
[browser_resources_client_caching.js]
|
||||||
[browser_resources_console_messages.js]
|
[browser_resources_console_messages.js]
|
||||||
|
@ -36,7 +33,6 @@ skip-if = os == "linux" #Bug 1655183
|
||||||
[browser_resources_platform_messages.js]
|
[browser_resources_platform_messages.js]
|
||||||
[browser_resources_root_node.js]
|
[browser_resources_root_node.js]
|
||||||
[browser_resources_several_resources.js]
|
[browser_resources_several_resources.js]
|
||||||
[browser_resources_sources.js]
|
|
||||||
[browser_resources_stylesheets.js]
|
[browser_resources_stylesheets.js]
|
||||||
[browser_resources_target_destroy.js]
|
[browser_resources_target_destroy.js]
|
||||||
[browser_resources_target_resources_race.js]
|
[browser_resources_target_resources_race.js]
|
||||||
|
|
|
@ -1,176 +0,0 @@
|
||||||
/* Any copyright is dedicated to the Public Domain.
|
|
||||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
|
||||||
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
// Test the ResourceWatcher API around SOURCE.
|
|
||||||
|
|
||||||
const {
|
|
||||||
ResourceWatcher,
|
|
||||||
} = require("devtools/shared/resources/resource-watcher");
|
|
||||||
|
|
||||||
const TEST_URL = URL_ROOT + "sources.html";
|
|
||||||
|
|
||||||
add_task(async function() {
|
|
||||||
const tab = await addTab(TEST_URL);
|
|
||||||
|
|
||||||
const htmlRequest = await fetch(TEST_URL);
|
|
||||||
const htmlContent = await htmlRequest.text();
|
|
||||||
|
|
||||||
const {
|
|
||||||
client,
|
|
||||||
resourceWatcher,
|
|
||||||
targetList,
|
|
||||||
} = await initResourceWatcherAndTarget(tab);
|
|
||||||
|
|
||||||
// Force the target list to cover workers
|
|
||||||
targetList.listenForWorkers = true;
|
|
||||||
await targetList.startListening();
|
|
||||||
|
|
||||||
const targets = [];
|
|
||||||
await targetList.watchTargets(targetList.ALL_TYPES, async function({
|
|
||||||
targetFront,
|
|
||||||
}) {
|
|
||||||
targets.push(targetFront);
|
|
||||||
});
|
|
||||||
is(targets.length, 2, "Got expected number of targets");
|
|
||||||
|
|
||||||
info("Check already available resources");
|
|
||||||
const availableResources = [];
|
|
||||||
await resourceWatcher.watchResources([ResourceWatcher.TYPES.SOURCE], {
|
|
||||||
onAvailable: resources => availableResources.push(...resources),
|
|
||||||
});
|
|
||||||
|
|
||||||
const expectedExistingResources = [
|
|
||||||
{
|
|
||||||
description: "independent js file",
|
|
||||||
sourceForm: {
|
|
||||||
introductionType: "scriptElement",
|
|
||||||
sourceMapBaseURL:
|
|
||||||
"http://example.com/browser/devtools/shared/resources/tests/sources.js",
|
|
||||||
url:
|
|
||||||
"http://example.com/browser/devtools/shared/resources/tests/sources.js",
|
|
||||||
isBlackBoxed: false,
|
|
||||||
sourceMapURL: null,
|
|
||||||
extensionName: null,
|
|
||||||
},
|
|
||||||
sourceContent: {
|
|
||||||
contentType: "text/javascript",
|
|
||||||
source: "/* eslint-disable */\nfunction scriptSource() {}\n",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
description: "eval",
|
|
||||||
sourceForm: {
|
|
||||||
introductionType: "eval",
|
|
||||||
sourceMapBaseURL:
|
|
||||||
"http://example.com/browser/devtools/shared/resources/tests/sources.html",
|
|
||||||
url: null,
|
|
||||||
isBlackBoxed: false,
|
|
||||||
sourceMapURL: null,
|
|
||||||
extensionName: null,
|
|
||||||
},
|
|
||||||
sourceContent: {
|
|
||||||
contentType: "text/javascript",
|
|
||||||
source: "this.global = function evalFunction() {}",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
description: "inline JS",
|
|
||||||
sourceForm: {
|
|
||||||
introductionType: "scriptElement",
|
|
||||||
sourceMapBaseURL:
|
|
||||||
"http://example.com/browser/devtools/shared/resources/tests/sources.html",
|
|
||||||
url:
|
|
||||||
"http://example.com/browser/devtools/shared/resources/tests/sources.html",
|
|
||||||
isBlackBoxed: false,
|
|
||||||
sourceMapURL: null,
|
|
||||||
extensionName: null,
|
|
||||||
},
|
|
||||||
sourceContent: {
|
|
||||||
contentType: "text/html",
|
|
||||||
source: htmlContent,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
description: "worker script",
|
|
||||||
sourceForm: {
|
|
||||||
introductionType: undefined,
|
|
||||||
sourceMapBaseURL:
|
|
||||||
"http://example.com/browser/devtools/shared/resources/tests/worker-sources.js",
|
|
||||||
url:
|
|
||||||
"http://example.com/browser/devtools/shared/resources/tests/worker-sources.js",
|
|
||||||
isBlackBoxed: false,
|
|
||||||
sourceMapURL: null,
|
|
||||||
extensionName: null,
|
|
||||||
},
|
|
||||||
sourceContent: {
|
|
||||||
contentType: "text/javascript",
|
|
||||||
source: "/* eslint-disable */\nfunction workerSource() {}\n",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
||||||
await assertResources(availableResources, expectedExistingResources);
|
|
||||||
|
|
||||||
await targetList.stopListening();
|
|
||||||
await client.close();
|
|
||||||
});
|
|
||||||
|
|
||||||
async function assertResources(resources, expected) {
|
|
||||||
is(
|
|
||||||
resources.length,
|
|
||||||
expected.length,
|
|
||||||
"Length of existing resources is correct at initial"
|
|
||||||
);
|
|
||||||
for (let i = 0; i < resources.length; i++) {
|
|
||||||
await assertResource(resources[i], expected);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function assertResource(source, expected) {
|
|
||||||
info(`Checking resource "#${expected.description}"`);
|
|
||||||
|
|
||||||
is(
|
|
||||||
source.resourceType,
|
|
||||||
ResourceWatcher.TYPES.SOURCE,
|
|
||||||
"Resource type is correct"
|
|
||||||
);
|
|
||||||
|
|
||||||
const threadFront = await source.targetFront.getFront("thread");
|
|
||||||
// `source` is SourceActor's form()
|
|
||||||
// so try to instantiate the related SourceFront:
|
|
||||||
const sourceFront = threadFront.source(source);
|
|
||||||
// then fetch source content
|
|
||||||
const sourceContent = await sourceFront.source();
|
|
||||||
|
|
||||||
// Order of sources is random, so we have to find the best expected resource.
|
|
||||||
// The only unique attribute is the JS Source text content.
|
|
||||||
const matchingExpected = expected.find(res => {
|
|
||||||
return res.sourceContent.source == sourceContent.source;
|
|
||||||
});
|
|
||||||
ok(
|
|
||||||
matchingExpected,
|
|
||||||
`This source was expected with source content being "${sourceContent.source}"`
|
|
||||||
);
|
|
||||||
assertObject(
|
|
||||||
sourceContent,
|
|
||||||
matchingExpected.sourceContent,
|
|
||||||
matchingExpected.description
|
|
||||||
);
|
|
||||||
|
|
||||||
assertObject(
|
|
||||||
source,
|
|
||||||
matchingExpected.sourceForm,
|
|
||||||
matchingExpected.description
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function assertObject(object, expected, description) {
|
|
||||||
for (const field in expected) {
|
|
||||||
is(
|
|
||||||
object[field],
|
|
||||||
expected[field],
|
|
||||||
`The value of ${field} is correct for "#${description}"`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,21 +0,0 @@
|
||||||
<!-- Any copyright is dedicated to the Public Domain.
|
|
||||||
http://creativecommons.org/publicdomain/zero/1.0/ -->
|
|
||||||
<!doctype HTML>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8"/>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<script type="text/javascript">
|
|
||||||
"use strict";
|
|
||||||
/* eslint-disable */
|
|
||||||
function inlineSource() {}
|
|
||||||
// Assign it to a global in order to avoid it being GCed
|
|
||||||
eval("this.global = function evalFunction() {}");
|
|
||||||
// Assign the worker to a global variable in order to avoid
|
|
||||||
// having it be GCed.
|
|
||||||
this.worker = new Worker("worker-sources.js");
|
|
||||||
</script>
|
|
||||||
<script src="sources.js"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -1,2 +0,0 @@
|
||||||
/* eslint-disable */
|
|
||||||
function scriptSource() {}
|
|
|
@ -1,2 +0,0 @@
|
||||||
/* eslint-disable */
|
|
||||||
function workerSource() {}
|
|
Загрузка…
Ссылка в новой задаче