mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
248 lines
6.9 KiB
JavaScript
248 lines
6.9 KiB
JavaScript
/* 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 protocol = require("devtools/server/protocol");
|
|
const { method, RetVal, Arg, types } = protocol;
|
|
const { expectState, ActorPool } = require("devtools/server/actors/common");
|
|
const { ObjectActor,
|
|
createValueGrip } = require("devtools/server/actors/object");
|
|
const DevToolsUtils = require("devtools/shared/DevToolsUtils");
|
|
loader.lazyRequireGetter(this, "events", "sdk/event/core");
|
|
|
|
// Teach protocol.js how to deal with legacy actor types
|
|
types.addType("ObjectActor", {
|
|
write: actor => actor.grip(),
|
|
read: grip => grip
|
|
});
|
|
|
|
/**
|
|
* The Promises Actor provides support for getting the list of live promises and
|
|
* observing changes to their settlement state.
|
|
*/
|
|
var PromisesActor = protocol.ActorClass({
|
|
typeName: "promises",
|
|
|
|
events: {
|
|
// Event emitted for new promises allocated in debuggee and bufferred by
|
|
// sending the list of promise objects in a batch.
|
|
"new-promises": {
|
|
type: "new-promises",
|
|
data: Arg(0, "array:ObjectActor"),
|
|
},
|
|
// Event emitted for promise settlements.
|
|
"promises-settled": {
|
|
type: "promises-settled",
|
|
data: Arg(0, "array:ObjectActor")
|
|
}
|
|
},
|
|
|
|
/**
|
|
* @param conn DebuggerServerConnection.
|
|
* @param parent TabActor|RootActor
|
|
*/
|
|
initialize: function(conn, parent) {
|
|
protocol.Actor.prototype.initialize.call(this, conn);
|
|
|
|
this.conn = conn;
|
|
this.parent = parent;
|
|
this.state = "detached";
|
|
this._dbg = null;
|
|
this._gripDepth = 0;
|
|
this._navigationLifetimePool = null;
|
|
this._newPromises = null;
|
|
this._promisesSettled = null;
|
|
|
|
this.objectGrip = this.objectGrip.bind(this);
|
|
this._makePromiseEventHandler = this._makePromiseEventHandler.bind(this);
|
|
this._onWindowReady = this._onWindowReady.bind(this);
|
|
},
|
|
|
|
destroy: function() {
|
|
protocol.Actor.prototype.destroy.call(this, this.conn);
|
|
|
|
if (this.state === "attached") {
|
|
this.detach();
|
|
}
|
|
},
|
|
|
|
get dbg() {
|
|
if (!this._dbg) {
|
|
this._dbg = this.parent.makeDebugger();
|
|
}
|
|
return this._dbg;
|
|
},
|
|
|
|
/**
|
|
* Attach to the PromisesActor.
|
|
*/
|
|
attach: method(expectState("detached", function() {
|
|
this.dbg.addDebuggees();
|
|
|
|
this._navigationLifetimePool = this._createActorPool();
|
|
this.conn.addActorPool(this._navigationLifetimePool);
|
|
|
|
this._newPromises = [];
|
|
this._promisesSettled = [];
|
|
|
|
this.dbg.findScripts().forEach(s => {
|
|
this.parent.sources.createSourceActors(s.source);
|
|
});
|
|
|
|
this.dbg.onNewScript = s => {
|
|
this.parent.sources.createSourceActors(s.source);
|
|
};
|
|
|
|
events.on(this.parent, "window-ready", this._onWindowReady);
|
|
|
|
this.state = "attached";
|
|
}, `attaching to the PromisesActor`), {
|
|
request: {},
|
|
response: {}
|
|
}),
|
|
|
|
/**
|
|
* Detach from the PromisesActor upon Debugger closing.
|
|
*/
|
|
detach: method(expectState("attached", function() {
|
|
this.dbg.removeAllDebuggees();
|
|
this.dbg.enabled = false;
|
|
this._dbg = null;
|
|
this._newPromises = null;
|
|
this._promisesSettled = null;
|
|
|
|
if (this._navigationLifetimePool) {
|
|
this.conn.removeActorPool(this._navigationLifetimePool);
|
|
this._navigationLifetimePool = null;
|
|
}
|
|
|
|
events.off(this.parent, "window-ready", this._onWindowReady);
|
|
|
|
this.state = "detached";
|
|
}, `detaching from the PromisesActor`), {
|
|
request: {},
|
|
response: {}
|
|
}),
|
|
|
|
_createActorPool: function() {
|
|
let pool = new ActorPool(this.conn);
|
|
pool.objectActors = new WeakMap();
|
|
return pool;
|
|
},
|
|
|
|
/**
|
|
* Create an ObjectActor for the given Promise object.
|
|
*
|
|
* @param object promise
|
|
* The promise object
|
|
* @return object
|
|
* An ObjectActor object that wraps the given Promise object
|
|
*/
|
|
_createObjectActorForPromise: function(promise) {
|
|
if (this._navigationLifetimePool.objectActors.has(promise)) {
|
|
return this._navigationLifetimePool.objectActors.get(promise);
|
|
}
|
|
|
|
let actor = new ObjectActor(promise, {
|
|
getGripDepth: () => this._gripDepth,
|
|
incrementGripDepth: () => this._gripDepth++,
|
|
decrementGripDepth: () => this._gripDepth--,
|
|
createValueGrip: v =>
|
|
createValueGrip(v, this._navigationLifetimePool, this.objectGrip),
|
|
sources: () => this.parent.sources,
|
|
createEnvironmentActor: () => DevToolsUtils.reportException(
|
|
"PromisesActor", Error("createEnvironmentActor not yet implemented")),
|
|
getGlobalDebugObject: () => DevToolsUtils.reportException(
|
|
"PromisesActor", Error("getGlobalDebugObject not yet implemented")),
|
|
});
|
|
|
|
this._navigationLifetimePool.addActor(actor);
|
|
this._navigationLifetimePool.objectActors.set(promise, actor);
|
|
|
|
return actor;
|
|
},
|
|
|
|
/**
|
|
* Get a grip for the given Promise object.
|
|
*
|
|
* @param object value
|
|
* The Promise object
|
|
* @return object
|
|
* The grip for the given Promise object
|
|
*/
|
|
objectGrip: function(value) {
|
|
return this._createObjectActorForPromise(value).grip();
|
|
},
|
|
|
|
/**
|
|
* Get a list of ObjectActors for all live Promise Objects.
|
|
*/
|
|
listPromises: method(function() {
|
|
let promises = this.dbg.findObjects({ class: "Promise" });
|
|
|
|
this.dbg.onNewPromise = this._makePromiseEventHandler(this._newPromises,
|
|
"new-promises");
|
|
this.dbg.onPromiseSettled = this._makePromiseEventHandler(
|
|
this._promisesSettled, "promises-settled");
|
|
|
|
return promises.map(p => this._createObjectActorForPromise(p));
|
|
}, {
|
|
request: {
|
|
},
|
|
response: {
|
|
promises: RetVal("array:ObjectActor")
|
|
}
|
|
}),
|
|
|
|
/**
|
|
* Creates an event handler for onNewPromise that will add the new
|
|
* Promise ObjectActor to the array and schedule it to be emitted as a
|
|
* batch for the provided event.
|
|
*
|
|
* @param array array
|
|
* The list of Promise ObjectActors to emit
|
|
* @param string eventName
|
|
* The event name
|
|
*/
|
|
_makePromiseEventHandler: function(array, eventName) {
|
|
return promise => {
|
|
let actor = this._createObjectActorForPromise(promise);
|
|
let needsScheduling = array.length == 0;
|
|
|
|
array.push(actor);
|
|
|
|
if (needsScheduling) {
|
|
DevToolsUtils.executeSoon(() => {
|
|
events.emit(this, eventName, array.splice(0, array.length));
|
|
});
|
|
}
|
|
};
|
|
},
|
|
|
|
_onWindowReady: expectState("attached", function({ isTopLevel }) {
|
|
if (!isTopLevel) {
|
|
return;
|
|
}
|
|
|
|
this._navigationLifetimePool.cleanup();
|
|
this.dbg.removeAllDebuggees();
|
|
this.dbg.addDebuggees();
|
|
})
|
|
});
|
|
|
|
exports.PromisesActor = PromisesActor;
|
|
|
|
exports.PromisesFront = protocol.FrontClass(PromisesActor, {
|
|
initialize: function(client, form) {
|
|
protocol.Front.prototype.initialize.call(this, client, form);
|
|
this.actorID = form.promisesActor;
|
|
this.manage(this);
|
|
},
|
|
|
|
destroy: function() {
|
|
protocol.Front.prototype.destroy.call(this);
|
|
}
|
|
});
|