Bug 1561435 - Format remaining devtools/, a=automatic-formatting, CLOSED TREE

# ignore-this-changeset

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

--HG--
extra : source : 4722b924e08478f5337ab509718bd66906bf472f
extra : amend_source : a5baa1aab21639fdba44537e3a10b179b0073cb4
This commit is contained in:
Victor Porof 2019-07-05 11:29:32 +02:00
parent 66e8f7440d
commit b8157dfaaf
304 changed files with 7063 additions and 4270 deletions

View file

@ -39,12 +39,6 @@ testing/marionette/prefs/marionette.js
toolkit/components/telemetry/datareporting-prefs.js toolkit/components/telemetry/datareporting-prefs.js
toolkit/components/telemetry/healthreport-prefs.js toolkit/components/telemetry/healthreport-prefs.js
# Ignore all devtools directories for now, except the debugger.
devtools/docs/**
devtools/platform/**
devtools/shared/**
devtools/startup/**
# Ignore testing pref files which aren't parsed normally. # Ignore testing pref files which aren't parsed normally.
testing/profiles/**/user.js testing/profiles/**/user.js

View file

@ -7,11 +7,11 @@
var gCount = 0; var gCount = 0;
const MAX = 10; const MAX = 10;
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm"); const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
var inspector = Cc["@mozilla.org/jsinspector;1"].getService(Ci.nsIJSInspector); var inspector = Cc["@mozilla.org/jsinspector;1"].getService(Ci.nsIJSInspector);
// Emulate 10 simultaneously-debugged windows from 3 separate client connections. // Emulate 10 simultaneously-debugged windows from 3 separate client connections.
var requestor = (count) => ({ var requestor = count => ({
url: "http://foo/bar/" + count, url: "http://foo/bar/" + count,
connection: "conn" + (count % 3), connection: "conn" + (count % 3),
}); });
@ -23,7 +23,7 @@ function run_test() {
function test_nesting() { function test_nesting() {
Assert.equal(inspector.eventLoopNestLevel, 0); Assert.equal(inspector.eventLoopNestLevel, 0);
Services.tm.dispatchToMainThread({ run: enterEventLoop}); Services.tm.dispatchToMainThread({ run: enterEventLoop });
Assert.equal(inspector.enterNestedEventLoop(requestor(gCount)), 0); Assert.equal(inspector.enterNestedEventLoop(requestor(gCount)), 0);
Assert.equal(inspector.eventLoopNestLevel, 0); Assert.equal(inspector.eventLoopNestLevel, 0);
@ -32,28 +32,32 @@ function test_nesting() {
function enterEventLoop() { function enterEventLoop() {
if (gCount++ < MAX) { if (gCount++ < MAX) {
Services.tm.dispatchToMainThread({ run: enterEventLoop}); Services.tm.dispatchToMainThread({ run: enterEventLoop });
Object.create(requestor(gCount)); Object.create(requestor(gCount));
Assert.equal(inspector.eventLoopNestLevel, gCount); Assert.equal(inspector.eventLoopNestLevel, gCount);
Assert.equal(inspector.lastNestRequestor.url, requestor(gCount - 1).url); Assert.equal(inspector.lastNestRequestor.url, requestor(gCount - 1).url);
Assert.equal(inspector.lastNestRequestor.connection, Assert.equal(
requestor(gCount - 1).connection); inspector.lastNestRequestor.connection,
requestor(gCount - 1).connection
);
Assert.equal(inspector.enterNestedEventLoop(requestor(gCount)), gCount); Assert.equal(inspector.enterNestedEventLoop(requestor(gCount)), gCount);
} else { } else {
Assert.equal(gCount, MAX + 1); Assert.equal(gCount, MAX + 1);
Services.tm.dispatchToMainThread({ run: exitEventLoop}); Services.tm.dispatchToMainThread({ run: exitEventLoop });
} }
} }
function exitEventLoop() { function exitEventLoop() {
if (inspector.lastNestRequestor != null) { if (inspector.lastNestRequestor != null) {
Assert.equal(inspector.lastNestRequestor.url, requestor(gCount - 1).url); Assert.equal(inspector.lastNestRequestor.url, requestor(gCount - 1).url);
Assert.equal(inspector.lastNestRequestor.connection, Assert.equal(
requestor(gCount - 1).connection); inspector.lastNestRequestor.connection,
requestor(gCount - 1).connection
);
if (gCount-- > 1) { if (gCount-- > 1) {
Services.tm.dispatchToMainThread({ run: exitEventLoop}); Services.tm.dispatchToMainThread({ run: exitEventLoop });
} }
Assert.equal(inspector.exitNestedEventLoop(), gCount); Assert.equal(inspector.exitNestedEventLoop(), gCount);

View file

@ -11,10 +11,17 @@
var { Ci, Cc, Cu, components } = require("chrome"); var { Ci, Cc, Cu, components } = require("chrome");
var Services = require("Services"); var Services = require("Services");
var flags = require("./flags"); var flags = require("./flags");
var {getStack, callFunctionWithAsyncStack} = require("devtools/shared/platform/stack"); var {
getStack,
callFunctionWithAsyncStack,
} = require("devtools/shared/platform/stack");
loader.lazyRequireGetter(this, "FileUtils", loader.lazyRequireGetter(
"resource://gre/modules/FileUtils.jsm", true); this,
"FileUtils",
"resource://gre/modules/FileUtils.jsm",
true
);
// Using this name lets the eslint plugin know about lazy defines in // Using this name lets the eslint plugin know about lazy defines in
// this file. // this file.
@ -37,7 +44,7 @@ for (const key of Object.keys(ThreadSafeDevToolsUtils)) {
exports.isCPOW = function(debuggerObject) { exports.isCPOW = function(debuggerObject) {
try { try {
return Cu.isCrossProcessWrapper(debuggerObject.unsafeDereference()); return Cu.isCrossProcessWrapper(debuggerObject.unsafeDereference());
} catch (e) { } } catch (e) {}
return false; return false;
}; };
@ -310,8 +317,9 @@ exports.isSafeJSObject = function(obj) {
return false; return false;
} }
if (Cu.getGlobalForObject(obj) == if (
Cu.getGlobalForObject(exports.isSafeJSObject)) { Cu.getGlobalForObject(obj) == Cu.getGlobalForObject(exports.isSafeJSObject)
) {
// obj is not a cross-compartment wrapper. // obj is not a cross-compartment wrapper.
return true; return true;
} }
@ -399,7 +407,7 @@ DevToolsUtils.defineLazyGetter(this, "AppConstants", () => {
/** /**
* No operation. The empty function. * No operation. The empty function.
*/ */
exports.noop = function() { }; exports.noop = function() {};
let assertionFailureCount = 0; let assertionFailureCount = 0;
@ -434,9 +442,10 @@ function reallyAssert(condition, message) {
* If assertions are not enabled, then this function is a no-op. * If assertions are not enabled, then this function is a no-op.
*/ */
Object.defineProperty(exports, "assert", { Object.defineProperty(exports, "assert", {
get: () => (AppConstants.DEBUG_JS_MODULES || flags.testing) get: () =>
? reallyAssert AppConstants.DEBUG_JS_MODULES || flags.testing
: exports.noop, ? reallyAssert
: exports.noop,
}); });
/** /**
@ -503,13 +512,18 @@ DevToolsUtils.defineLazyGetter(this, "NetworkHelper", () => {
* without relying on caching when we can (not for eval, etc.): * without relying on caching when we can (not for eval, etc.):
* http://www.softwareishard.com/blog/firebug/nsitraceablechannel-intercept-http-traffic/ * http://www.softwareishard.com/blog/firebug/nsitraceablechannel-intercept-http-traffic/
*/ */
function mainThreadFetch(urlIn, aOptions = { loadFromCache: true, function mainThreadFetch(
policy: Ci.nsIContentPolicy.TYPE_OTHER, urlIn,
window: null, aOptions = {
charset: null, loadFromCache: true,
principal: null, policy: Ci.nsIContentPolicy.TYPE_OTHER,
cacheKey: 0 }) { window: null,
return new Promise((resolve, reject) =>{ charset: null,
principal: null,
cacheKey: 0,
}
) {
return new Promise((resolve, reject) => {
// Create a channel. // Create a channel.
const url = urlIn.split(" -> ").pop(); const url = urlIn.split(" -> ").pop();
let channel; let channel;
@ -527,16 +541,19 @@ function mainThreadFetch(urlIn, aOptions = { loadFromCache: true,
// When loading from cache, the cacheKey allows us to target a specific // When loading from cache, the cacheKey allows us to target a specific
// SHEntry and offer ways to restore POST requests from cache. // SHEntry and offer ways to restore POST requests from cache.
if (aOptions.loadFromCache && if (
aOptions.cacheKey != 0 && channel instanceof Ci.nsICacheInfoChannel) { aOptions.loadFromCache &&
aOptions.cacheKey != 0 &&
channel instanceof Ci.nsICacheInfoChannel
) {
channel.cacheKey = aOptions.cacheKey; channel.cacheKey = aOptions.cacheKey;
} }
if (aOptions.window) { if (aOptions.window) {
// Respect private browsing. // Respect private browsing.
channel.loadGroup = aOptions.window.docShell channel.loadGroup = aOptions.window.docShell.QueryInterface(
.QueryInterface(Ci.nsIDocumentLoader) Ci.nsIDocumentLoader
.loadGroup; ).loadGroup;
} }
const onResponse = (stream, status, request) => { const onResponse = (stream, status, request) => {
@ -560,16 +577,26 @@ function mainThreadFetch(urlIn, aOptions = { loadFromCache: true,
// implementation of the "decode" algorithm // implementation of the "decode" algorithm
// (https://encoding.spec.whatwg.org/#decode) exposed to JS. // (https://encoding.spec.whatwg.org/#decode) exposed to JS.
let bomCharset = null; let bomCharset = null;
if (available >= 3 && source.codePointAt(0) == 0xef && if (
source.codePointAt(1) == 0xbb && source.codePointAt(2) == 0xbf) { available >= 3 &&
source.codePointAt(0) == 0xef &&
source.codePointAt(1) == 0xbb &&
source.codePointAt(2) == 0xbf
) {
bomCharset = "UTF-8"; bomCharset = "UTF-8";
source = source.slice(3); source = source.slice(3);
} else if (available >= 2 && source.codePointAt(0) == 0xfe && } else if (
source.codePointAt(1) == 0xff) { available >= 2 &&
source.codePointAt(0) == 0xfe &&
source.codePointAt(1) == 0xff
) {
bomCharset = "UTF-16BE"; bomCharset = "UTF-16BE";
source = source.slice(2); source = source.slice(2);
} else if (available >= 2 && source.codePointAt(0) == 0xff && } else if (
source.codePointAt(1) == 0xfe) { available >= 2 &&
source.codePointAt(0) == 0xff &&
source.codePointAt(1) == 0xfe
) {
bomCharset = "UTF-16LE"; bomCharset = "UTF-16LE";
source = source.slice(2); source = source.slice(2);
} }
@ -600,7 +627,10 @@ function mainThreadFetch(urlIn, aOptions = { loadFromCache: true,
}); });
} catch (ex) { } catch (ex) {
const uri = request.originalURI; const uri = request.originalURI;
if (ex.name === "NS_BASE_STREAM_CLOSED" && uri instanceof Ci.nsIFileURL) { if (
ex.name === "NS_BASE_STREAM_CLOSED" &&
uri instanceof Ci.nsIFileURL
) {
// Empty files cause NS_BASE_STREAM_CLOSED exception. Use OS.File to // Empty files cause NS_BASE_STREAM_CLOSED exception. Use OS.File to
// differentiate between empty files and other errors (bug 1170864). // differentiate between empty files and other errors (bug 1170864).
// This can be removed when bug 982654 is fixed. // This can be removed when bug 982654 is fixed.
@ -642,7 +672,11 @@ function mainThreadFetch(urlIn, aOptions = { loadFromCache: true,
* @param {Object} options - The options object passed to @method fetch. * @param {Object} options - The options object passed to @method fetch.
* @return {nsIChannel} - The newly created channel. Throws on failure. * @return {nsIChannel} - The newly created channel. Throws on failure.
*/ */
function newChannelForURL(url, { policy, window, principal }, recursing = false) { function newChannelForURL(
url,
{ policy, window, principal },
recursing = false
) {
const securityFlags = Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL; const securityFlags = Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL;
let uri; let uri;
@ -679,8 +713,7 @@ function newChannelForURL(url, { policy, window, principal }, recursing = false)
// and it may not be correct. // and it may not be correct.
let prin = principal; let prin = principal;
if (!prin) { if (!prin) {
prin = Services.scriptSecurityManager prin = Services.scriptSecurityManager.createCodebasePrincipal(uri, {});
.createCodebasePrincipal(uri, {});
} }
channelOptions.loadingPrincipal = prin; channelOptions.loadingPrincipal = prin;
@ -698,8 +731,11 @@ function newChannelForURL(url, { policy, window, principal }, recursing = false)
// can throw NS_ERROR_UNKNOWN_PROTOCOL if the external protocol isn't // can throw NS_ERROR_UNKNOWN_PROTOCOL if the external protocol isn't
// supported by Windows, so we also need to handle the exception here if // supported by Windows, so we also need to handle the exception here if
// parsing the URL above doesn't throw. // parsing the URL above doesn't throw.
return newChannelForURL("file://" + url, { policy, window, principal }, return newChannelForURL(
/* recursing */ true); "file://" + url,
{ policy, window, principal },
/* recursing */ true
);
} }
} }
@ -748,7 +784,7 @@ exports.openFileStream = function(filePath) {
exports.saveFileStream = function(filePath, istream) { exports.saveFileStream = function(filePath, istream) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const ostream = FileUtils.openSafeFileOutputStream(filePath); const ostream = FileUtils.openSafeFileOutputStream(filePath);
NetUtil.asyncCopy(istream, ostream, (status) => { NetUtil.asyncCopy(istream, ostream, status => {
if (!components.isSuccessCode(status)) { if (!components.isSuccessCode(status)) {
reject(new Error(`Could not save "${filePath}"`)); reject(new Error(`Could not save "${filePath}"`));
return; return;
@ -782,7 +818,7 @@ exports.showSaveFileDialog = function(parentWindow, suggestedFilename) {
fp.appendFilters(fp.filterAll); fp.appendFilters(fp.filterAll);
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
fp.open((result) => { fp.open(result => {
if (result == Ci.nsIFilePicker.returnCancel) { if (result == Ci.nsIFilePicker.returnCancel) {
reject(); reject();
} else { } else {
@ -800,14 +836,16 @@ exports.showSaveFileDialog = function(parentWindow, suggestedFilename) {
function errorOnFlag(exports, name) { function errorOnFlag(exports, name) {
Object.defineProperty(exports, name, { Object.defineProperty(exports, name, {
get: () => { get: () => {
const msg = `Cannot get the flag ${name}. ` + const msg =
`Use the "devtools/shared/flags" module instead`; `Cannot get the flag ${name}. ` +
`Use the "devtools/shared/flags" module instead`;
console.error(msg); console.error(msg);
throw new Error(msg); throw new Error(msg);
}, },
set: () => { set: () => {
const msg = `Cannot set the flag ${name}. ` + const msg =
`Use the "devtools/shared/flags" module instead`; `Cannot set the flag ${name}. ` +
`Use the "devtools/shared/flags" module instead`;
console.error(msg); console.error(msg);
throw new Error(msg); throw new Error(msg);
}, },

View file

@ -9,14 +9,22 @@
*/ */
var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm"); var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
var { Loader, Require, resolveURI, unload } = var { Loader, Require, resolveURI, unload } = ChromeUtils.import(
ChromeUtils.import("resource://devtools/shared/base-loader.js"); "resource://devtools/shared/base-loader.js"
var { requireRawId } = ChromeUtils.import("resource://devtools/shared/loader-plugin-raw.jsm"); );
var { requireRawId } = ChromeUtils.import(
"resource://devtools/shared/loader-plugin-raw.jsm"
);
this.EXPORTED_SYMBOLS = ["DevToolsLoader", "devtools", "BuiltinProvider", this.EXPORTED_SYMBOLS = [
"require", "loader", "DevToolsLoader",
// Export StructuredCloneHolder for its use from builtin-modules "devtools",
"StructuredCloneHolder"]; "BuiltinProvider",
"require",
"loader",
// Export StructuredCloneHolder for its use from builtin-modules
"StructuredCloneHolder",
];
/** /**
* Providers are different strategies for loading the devtools. * Providers are different strategies for loading the devtools.
@ -31,9 +39,9 @@ BuiltinProvider.prototype = {
load: function() { load: function() {
const paths = { const paths = {
// ⚠ DISCUSSION ON DEV-DEVELOPER-TOOLS REQUIRED BEFORE MODIFYING ⚠ // ⚠ DISCUSSION ON DEV-DEVELOPER-TOOLS REQUIRED BEFORE MODIFYING ⚠
"devtools": "resource://devtools", devtools: "resource://devtools",
// ⚠ DISCUSSION ON DEV-DEVELOPER-TOOLS REQUIRED BEFORE MODIFYING ⚠ // ⚠ DISCUSSION ON DEV-DEVELOPER-TOOLS REQUIRED BEFORE MODIFYING ⚠
"acorn": "resource://devtools/shared/acorn", acorn: "resource://devtools/shared/acorn",
// ⚠ DISCUSSION ON DEV-DEVELOPER-TOOLS REQUIRED BEFORE MODIFYING ⚠ // ⚠ DISCUSSION ON DEV-DEVELOPER-TOOLS REQUIRED BEFORE MODIFYING ⚠
"acorn/util/walk": "resource://devtools/shared/acorn/walk.js", "acorn/util/walk": "resource://devtools/shared/acorn/walk.js",
// ⚠ DISCUSSION ON DEV-DEVELOPER-TOOLS REQUIRED BEFORE MODIFYING ⚠ // ⚠ DISCUSSION ON DEV-DEVELOPER-TOOLS REQUIRED BEFORE MODIFYING ⚠
@ -171,7 +179,9 @@ DevToolsLoader.prototype = {
this.require = Require(this._provider.loader, { id: "devtools" }); this.require = Require(this._provider.loader, { id: "devtools" });
// Fetch custom pseudo modules and globals // Fetch custom pseudo modules and globals
const { modules, globals } = this.require("devtools/shared/builtin-modules"); const { modules, globals } = this.require(
"devtools/shared/builtin-modules"
);
// When creating a Loader for the browser toolbox, we have to use // When creating a Loader for the browser toolbox, we have to use
// Promise-backend.js, as a Loader module. Instead of Promise.jsm which // Promise-backend.js, as a Loader module. Instead of Promise.jsm which
@ -193,7 +203,10 @@ DevToolsLoader.prototype = {
// Register custom globals to the current loader instance // Register custom globals to the current loader instance
globals.loader.id = this.id; globals.loader.id = this.id;
Object.defineProperties(loader.globals, Object.getOwnPropertyDescriptors(globals)); Object.defineProperties(
loader.globals,
Object.getOwnPropertyDescriptors(globals)
);
// Expose lazy helpers on loader // Expose lazy helpers on loader
this.lazyGetter = globals.loader.lazyGetter; this.lazyGetter = globals.loader.lazyGetter;
@ -206,8 +219,12 @@ DevToolsLoader.prototype = {
// created for objects in the recording/replaying process. // created for objects in the recording/replaying process.
if (globals.isReplaying) { if (globals.isReplaying) {
const oldHook = this._provider.loader.requireHook; const oldHook = this._provider.loader.requireHook;
const ReplayInspector = this.require("devtools/server/actors/replay/inspector"); const ReplayInspector = this.require(
this._provider.loader.requireHook = ReplayInspector.wrapRequireHook(oldHook); "devtools/server/actors/replay/inspector"
);
this._provider.loader.requireHook = ReplayInspector.wrapRequireHook(
oldHook
);
} }
}, },

View file

@ -9,8 +9,11 @@ const { require } = ChromeUtils.import("resource://devtools/shared/Loader.jsm");
const { XPCOMUtils } = require("resource://gre/modules/XPCOMUtils.jsm"); const { XPCOMUtils } = require("resource://gre/modules/XPCOMUtils.jsm");
const DevToolsUtils = require("devtools/shared/DevToolsUtils"); const DevToolsUtils = require("devtools/shared/DevToolsUtils");
ChromeUtils.defineModuleGetter(this, ChromeUtils.defineModuleGetter(
"Reflect", "resource://gre/modules/reflect.jsm"); this,
"Reflect",
"resource://gre/modules/reflect.jsm"
);
this.EXPORTED_SYMBOLS = ["Parser", "ParserHelpers", "SyntaxTreeVisitor"]; this.EXPORTED_SYMBOLS = ["Parser", "ParserHelpers", "SyntaxTreeVisitor"];
@ -141,8 +144,13 @@ SyntaxTreesPool.prototype = {
* @see SyntaxTree.prototype.getIdentifierAt * @see SyntaxTree.prototype.getIdentifierAt
*/ */
getIdentifierAt({ line, column, scriptIndex, ignoreLiterals }) { getIdentifierAt({ line, column, scriptIndex, ignoreLiterals }) {
return this._call("getIdentifierAt", return this._call(
scriptIndex, line, column, ignoreLiterals)[0]; "getIdentifierAt",
scriptIndex,
line,
column,
ignoreLiterals
)[0];
}, },
/** /**
@ -232,7 +240,9 @@ SyntaxTreesPool.prototype = {
// Language features may be added, in which case the recursive methods // Language features may be added, in which case the recursive methods
// need to be updated. If an exception is thrown here, file a bug. // need to be updated. If an exception is thrown here, file a bug.
DevToolsUtils.reportException( DevToolsUtils.reportException(
`Syntax tree visitor for ${this._url}`, e); `Syntax tree visitor for ${this._url}`,
e
);
} }
} }
this._cache.set(requestId, results); this._cache.set(requestId, results);
@ -442,8 +452,10 @@ var ParserHelpers = {
const { loc: parentLocation, type: parentType } = node._parent; const { loc: parentLocation, type: parentType } = node._parent;
const { loc: nodeLocation } = node; const { loc: nodeLocation } = node;
if (!nodeLocation) { if (!nodeLocation) {
if (parentType == "FunctionDeclaration" || if (
parentType == "FunctionExpression") { parentType == "FunctionDeclaration" ||
parentType == "FunctionExpression"
) {
// e.g. "function foo() {}" or "{ bar: function foo() {} }" // e.g. "function foo() {}" or "{ bar: function foo() {} }"
// The location is unavailable for the identifier node "foo". // The location is unavailable for the identifier node "foo".
const loc = Cu.cloneInto(parentLocation, {}); const loc = Cu.cloneInto(parentLocation, {});
@ -516,8 +528,12 @@ var ParserHelpers = {
*/ */
nodeContainsPoint(node, line, column) { nodeContainsPoint(node, line, column) {
const { start: s, end: e } = this.getNodeLocation(node); const { start: s, end: e } = this.getNodeLocation(node);
return s.line == line && e.line == line && return (
s.column <= column && e.column >= column; s.line == line &&
e.line == line &&
s.column <= column &&
e.column >= column
);
}, },
/** /**
@ -708,8 +724,9 @@ var ParserHelpers = {
// directly as an evaluation string. Otherwise, construct the property // directly as an evaluation string. Otherwise, construct the property
// access chain, since the value might have changed. // access chain, since the value might have changed.
if (!this._getObjectExpressionPropertyKeyForValue(node)) { if (!this._getObjectExpressionPropertyKeyForValue(node)) {
const propertyChain = const propertyChain = this._getObjectExpressionPropertyChain(
this._getObjectExpressionPropertyChain(node._parent); node._parent
);
const propertyLeaf = node.name; const propertyLeaf = node.name;
return [...propertyChain, propertyLeaf].join("."); return [...propertyChain, propertyLeaf].join(".");
} }

View file

@ -81,7 +81,9 @@ exports.isCPOW = function() {
* Report that |who| threw an exception, |exception|. * Report that |who| threw an exception, |exception|.
*/ */
exports.reportException = function reportException(who, exception) { exports.reportException = function reportException(who, exception) {
const msg = `${who} threw an exception: ${exports.safeErrorString(exception)}`; const msg = `${who} threw an exception: ${exports.safeErrorString(
exception
)}`;
dump(msg + "\n"); dump(msg + "\n");
if (typeof console !== "undefined" && console && console.error) { if (typeof console !== "undefined" && console && console.error) {
@ -142,8 +144,12 @@ exports.safeErrorString = function(error) {
// Append additional line and column number information to the output, // Append additional line and column number information to the output,
// since it might not be part of the stringified error. // since it might not be part of the stringified error.
if (typeof error.lineNumber == "number" && typeof error.columnNumber == "number") { if (
errorString += "Line: " + error.lineNumber + ", column: " + error.columnNumber; typeof error.lineNumber == "number" &&
typeof error.columnNumber == "number"
) {
errorString +=
"Line: " + error.lineNumber + ", column: " + error.columnNumber;
} }
return errorString; return errorString;
@ -174,9 +180,11 @@ exports.zip = function(a, b) {
return b; return b;
} }
const pairs = []; const pairs = [];
for (let i = 0, aLength = a.length, bLength = b.length; for (
i < aLength || i < bLength; let i = 0, aLength = a.length, bLength = b.length;
i++) { i < aLength || i < bLength;
i++
) {
pairs.push([a[i], b[i]]); pairs.push([a[i], b[i]]);
} }
return pairs; return pairs;
@ -219,8 +227,7 @@ exports.compose = function compose(...funcs) {
return (...args) => { return (...args) => {
const initialValue = funcs[funcs.length - 1](...args); const initialValue = funcs[funcs.length - 1](...args);
const leftFuncs = funcs.slice(0, -1); const leftFuncs = funcs.slice(0, -1);
return leftFuncs.reduceRight((composed, f) => f(composed), return leftFuncs.reduceRight((composed, f) => f(composed), initialValue);
initialValue);
}; };
}; };
@ -311,7 +318,7 @@ exports.flatten = function(lists) {
* promise in the list of given promises to be rejected. * promise in the list of given promises to be rejected.
*/ */
exports.settleAll = values => { exports.settleAll = values => {
if (values === null || typeof (values[Symbol.iterator]) != "function") { if (values === null || typeof values[Symbol.iterator] != "function") {
throw new Error("settleAll() expects an iterable."); throw new Error("settleAll() expects an iterable.");
} }
@ -353,7 +360,7 @@ exports.settleAll = values => {
checkForCompletion(); checkForCompletion();
}; };
if (value && typeof (value.then) == "function") { if (value && typeof value.then == "function") {
value.then(resolver, rejecter); value.then(resolver, rejecter);
} else { } else {
// Given value is not a promise, forward it as a resolution value. // Given value is not a promise, forward it as a resolution value.

View file

@ -4,7 +4,7 @@
"use strict"; "use strict";
const {AddonManager} = require("resource://gre/modules/AddonManager.jsm"); const { AddonManager } = require("resource://gre/modules/AddonManager.jsm");
const Services = require("Services"); const Services = require("Services");
const EventEmitter = require("devtools/shared/event-emitter"); const EventEmitter = require("devtools/shared/event-emitter");
@ -44,10 +44,8 @@ class ADBAddon extends EventEmitter {
this._status = ADB_ADDON_STATES.UNKNOWN; this._status = ADB_ADDON_STATES.UNKNOWN;
const addonsListener = {}; const addonsListener = {};
addonsListener.onEnabled = addonsListener.onEnabled = addonsListener.onDisabled = addonsListener.onInstalled = addonsListener.onUninstalled = () =>
addonsListener.onDisabled = this.updateInstallStatus();
addonsListener.onInstalled =
addonsListener.onUninstalled = () => this.updateInstallStatus();
AddonManager.addAddonListener(addonsListener); AddonManager.addAddonListener(addonsListener);
this.updateInstallStatus(); this.updateInstallStatus();
@ -109,7 +107,9 @@ class ADBAddon extends EventEmitter {
*/ */
async install(source) { async install(source) {
if (!source) { if (!source) {
throw new Error("Missing mandatory `source` parameter for adb-addon.install"); throw new Error(
"Missing mandatory `source` parameter for adb-addon.install"
);
} }
const addon = await this._getAddon(); const addon = await this._getAddon();
@ -121,10 +121,9 @@ class ADBAddon extends EventEmitter {
if (addon && addon.userDisabled) { if (addon && addon.userDisabled) {
await addon.enable(); await addon.enable();
} else { } else {
const install = await AddonManager.getInstallForURL( const install = await AddonManager.getInstallForURL(this._getXpiLink(), {
this._getXpiLink(), telemetryInfo: { source },
{telemetryInfo: {source}} });
);
install.addListener(this); install.addListener(this);
install.install(); install.install();
} }
@ -199,7 +198,7 @@ class ADBAddon extends EventEmitter {
} }
// Expected AddonManager install listener. // Expected AddonManager install listener.
onInstallEnded({addon}) { onInstallEnded({ addon }) {
addon.enable(); addon.enable();
} }
} }

View file

@ -7,12 +7,24 @@
const { dumpn } = require("devtools/shared/DevToolsUtils"); const { dumpn } = require("devtools/shared/DevToolsUtils");
loader.lazyImporter(this, "OS", "resource://gre/modules/osfile.jsm"); loader.lazyImporter(this, "OS", "resource://gre/modules/osfile.jsm");
loader.lazyImporter(this, "ExtensionParent", "resource://gre/modules/ExtensionParent.jsm"); loader.lazyImporter(
this,
"ExtensionParent",
"resource://gre/modules/ExtensionParent.jsm"
);
loader.lazyRequireGetter(this, "Services"); loader.lazyRequireGetter(this, "Services");
loader.lazyRequireGetter(this, "FileUtils", loader.lazyRequireGetter(
"resource://gre/modules/FileUtils.jsm", true); this,
loader.lazyRequireGetter(this, "NetUtil", "FileUtils",
"resource://gre/modules/NetUtil.jsm", true); "resource://gre/modules/FileUtils.jsm",
true
);
loader.lazyRequireGetter(
this,
"NetUtil",
"resource://gre/modules/NetUtil.jsm",
true
);
loader.lazyGetter(this, "UNPACKED_ROOT_PATH", () => { loader.lazyGetter(this, "UNPACKED_ROOT_PATH", () => {
return OS.Path.join(OS.Constants.Path.localProfileDir, "adb"); return OS.Path.join(OS.Constants.Path.localProfileDir, "adb");
}); });
@ -35,18 +47,24 @@ const MANIFEST = "manifest.json";
*/ */
async function readFromExtension(fileUri) { async function readFromExtension(fileUri) {
return new Promise(resolve => { return new Promise(resolve => {
NetUtil.asyncFetch({ NetUtil.asyncFetch(
uri: fileUri, {
loadUsingSystemPrincipal: true, uri: fileUri,
}, (input) => { loadUsingSystemPrincipal: true,
try { },
const string = NetUtil.readInputStreamToString(input, input.available()); input => {
resolve(JSON.parse(string)); try {
} catch (e) { const string = NetUtil.readInputStreamToString(
dumpn(`Could not read ${fileUri} in the extension: ${e}`); input,
resolve(null); input.available()
);
resolve(JSON.parse(string));
} catch (e) {
dumpn(`Could not read ${fileUri} in the extension: ${e}`);
resolve(null);
}
} }
}); );
}); });
} }
@ -67,21 +85,24 @@ async function unpackFile(file) {
const basePath = file.substring(file.lastIndexOf("/") + 1); const basePath = file.substring(file.lastIndexOf("/") + 1);
const filePath = OS.Path.join(UNPACKED_ROOT_PATH, basePath); const filePath = OS.Path.join(UNPACKED_ROOT_PATH, basePath);
await new Promise((resolve, reject) => { await new Promise((resolve, reject) => {
NetUtil.asyncFetch({ NetUtil.asyncFetch(
uri: policy.getURL(file), {
loadUsingSystemPrincipal: true, uri: policy.getURL(file),
}, (input) => { loadUsingSystemPrincipal: true,
try { },
// Since we have to use NetUtil to read, probably it's okay to use for input => {
// writing, rather than bouncing to OS.File...? try {
const outputFile = new FileUtils.File(filePath); // Since we have to use NetUtil to read, probably it's okay to use for
const output = FileUtils.openAtomicFileOutputStream(outputFile); // writing, rather than bouncing to OS.File...?
NetUtil.asyncCopy(input, output, resolve); const outputFile = new FileUtils.File(filePath);
} catch (e) { const output = FileUtils.openAtomicFileOutputStream(outputFile);
dumpn(`Could not unpack file ${file} in the extension: ${e}`); NetUtil.asyncCopy(input, output, resolve);
reject(e); } catch (e) {
dumpn(`Could not unpack file ${file} in the extension: ${e}`);
reject(e);
}
} }
}); );
}); });
// Mark binaries as executable. // Mark binaries as executable.
await OS.File.setPermissions(filePath, { unixMode: 0o744 }); await OS.File.setPermissions(filePath, { unixMode: 0o744 });
@ -172,7 +193,7 @@ async function isManifestUnpacked() {
* Uses OS.File since this is a local file. * Uses OS.File since this is a local file.
*/ */
async function getManifestFromUnpacked() { async function getManifestFromUnpacked() {
if (!await isManifestUnpacked()) { if (!(await isManifestUnpacked())) {
throw new Error("Manifest doesn't exist at unpacked path"); throw new Error("Manifest doesn't exist at unpacked path");
} }
@ -182,8 +203,7 @@ async function getManifestFromUnpacked() {
let data; let data;
try { try {
data = JSON.parse(json); data = JSON.parse(json);
} catch (e) { } catch (e) {}
}
return data; return data;
} }
@ -191,7 +211,7 @@ async function getManifestFromUnpacked() {
* Check state of binary unpacking, including the location and manifest. * Check state of binary unpacking, including the location and manifest.
*/ */
async function isUnpacked() { async function isUnpacked() {
if (!await isManifestUnpacked()) { if (!(await isManifestUnpacked())) {
dumpn("Needs unpacking, no manifest found"); dumpn("Needs unpacking, no manifest found");
return false; return false;
} }
@ -201,7 +221,7 @@ async function isUnpacked() {
if (manifestInExtension.version != unpackedManifest.version) { if (manifestInExtension.version != unpackedManifest.version) {
dumpn( dumpn(
`Needs unpacking, extension version ${manifestInExtension.version} != ` + `Needs unpacking, extension version ${manifestInExtension.version} != ` +
`unpacked version ${unpackedManifest.version}` `unpacked version ${unpackedManifest.version}`
); );
return false; return false;
} }
@ -217,8 +237,7 @@ async function isUnpacked() {
* File object for the binary. * File object for the binary.
*/ */
async function getFileForBinary() { async function getFileForBinary() {
if (!await isUnpacked() && if (!(await isUnpacked()) && !(await extractFiles())) {
!await extractFiles()) {
return null; return null;
} }

View file

@ -33,7 +33,9 @@ class AdbDevice {
// Filter to lines with "firefox-debugger-socket" // Filter to lines with "firefox-debugger-socket"
let socketInfos = rawSocketInfo.split(/\r?\n/); let socketInfos = rawSocketInfo.split(/\r?\n/);
socketInfos = socketInfos.filter(l => l.includes("firefox-debugger-socket")); socketInfos = socketInfos.filter(l =>
l.includes("firefox-debugger-socket")
);
// It's possible to have multiple lines with the same path, so de-dupe them // It's possible to have multiple lines with the same path, so de-dupe them
const socketPaths = new Set(); const socketPaths = new Set();

View file

@ -10,8 +10,18 @@ const EventEmitter = require("devtools/shared/event-emitter");
const { getFileForBinary } = require("./adb-binary"); const { getFileForBinary } = require("./adb-binary");
const { setTimeout } = require("resource://gre/modules/Timer.jsm"); const { setTimeout } = require("resource://gre/modules/Timer.jsm");
loader.lazyRequireGetter(this, "runCommand", "devtools/shared/adb/commands/index", true); loader.lazyRequireGetter(
loader.lazyRequireGetter(this, "check", "devtools/shared/adb/adb-running-checker", true); this,
"runCommand",
"devtools/shared/adb/commands/index",
true
);
loader.lazyRequireGetter(
this,
"check",
"devtools/shared/adb/adb-running-checker",
true
);
// Waits until a predicate returns true or re-tries the predicate calls // Waits until a predicate returns true or re-tries the predicate calls
// |retry| times, we wait for 100ms between each calls. // |retry| times, we wait for 100ms between each calls.
@ -51,18 +61,23 @@ class AdbProcess extends EventEmitter {
async _runProcess(process, params) { async _runProcess(process, params) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
process.runAsync(params, params.length, { process.runAsync(
observe(subject, topic, data) { params,
switch (topic) { params.length,
case "process-finished": {
resolve(); observe(subject, topic, data) {
break; switch (topic) {
case "process-failed": case "process-finished":
reject(); resolve();
break; break;
} case "process-failed":
reject();
break;
}
},
}, },
}, false); false
);
}); });
} }
@ -85,7 +100,9 @@ class AdbProcess extends EventEmitter {
dumpn("Didn't find ADB process running, restarting"); dumpn("Didn't find ADB process running, restarting");
this._didRunInitially = true; this._didRunInitially = true;
const process = Cc["@mozilla.org/process/util;1"].createInstance(Ci.nsIProcess); const process = Cc["@mozilla.org/process/util;1"].createInstance(
Ci.nsIProcess
);
// FIXME: Bug 1481691 - We should avoid extracting files every time. // FIXME: Bug 1481691 - We should avoid extracting files every time.
const adbFile = await this._getAdbFile(); const adbFile = await this._getAdbFile();
@ -98,8 +115,7 @@ class AdbProcess extends EventEmitter {
try { try {
await this._runProcess(process, params); await this._runProcess(process, params);
isStarted = await waitUntil(check); isStarted = await waitUntil(check);
} catch (e) { } catch (e) {}
}
if (isStarted) { if (isStarted) {
onSuccessfulStart(); onSuccessfulStart();

View file

@ -4,7 +4,9 @@
"use strict"; "use strict";
const { RuntimeTypes } = require("devtools/client/webide/modules/runtime-types"); const {
RuntimeTypes,
} = require("devtools/client/webide/modules/runtime-types");
const { prepareTCPConnection } = require("devtools/shared/adb/commands/index"); const { prepareTCPConnection } = require("devtools/shared/adb/commands/index");
const { shell } = require("devtools/shared/adb/commands/index"); const { shell } = require("devtools/shared/adb/commands/index");
@ -94,9 +96,9 @@ class AdbRuntime {
// If using path base socket, it is "/data/data/<package>..."" // If using path base socket, it is "/data/data/<package>...""
// Until Fennec 62 only supports path based UNIX domain socket, but // Until Fennec 62 only supports path based UNIX domain socket, but
// Fennec 63+ supports both path based and abstract socket. // Fennec 63+ supports both path based and abstract socket.
return this._socketPath.startsWith("@") ? return this._socketPath.startsWith("@")
this._socketPath.substr(1).split("/")[0] : ? this._socketPath.substr(1).split("/")[0]
this._socketPath.split("/")[3]; : this._socketPath.split("/")[3];
} }
} }
exports.AdbRuntime = AdbRuntime; exports.AdbRuntime = AdbRuntime;

View file

@ -8,8 +8,9 @@ const { Cu } = require("chrome");
const { dumpn } = require("devtools/shared/DevToolsUtils"); const { dumpn } = require("devtools/shared/DevToolsUtils");
function createTCPSocket(location, port, options) { function createTCPSocket(location, port, options) {
const { TCPSocket } = const { TCPSocket } = Cu.getGlobalForObject(
Cu.getGlobalForObject(Cu.import("resource://gre/modules/Services.jsm", {})); Cu.import("resource://gre/modules/Services.jsm", {})
);
return new TCPSocket(location, port, options); return new TCPSocket(location, port, options);
} }
@ -63,8 +64,7 @@ class AdbSocket {
} }
close() { close() {
if (this.s.readyState === "open" || if (this.s.readyState === "open" || this.s.readyState === "connecting") {
this.s.readyState === "connecting") {
this.s.close(); this.s.close();
} }
} }

View file

@ -4,15 +4,25 @@
"use strict"; "use strict";
const { clearInterval, setInterval } = require("resource://gre/modules/Timer.jsm"); const {
clearInterval,
setInterval,
} = require("resource://gre/modules/Timer.jsm");
const EventEmitter = require("devtools/shared/event-emitter"); const EventEmitter = require("devtools/shared/event-emitter");
const { adbProcess } = require("devtools/shared/adb/adb-process"); const { adbProcess } = require("devtools/shared/adb/adb-process");
const { adbAddon } = require("devtools/shared/adb/adb-addon"); const { adbAddon } = require("devtools/shared/adb/adb-addon");
const AdbDevice = require("devtools/shared/adb/adb-device"); const AdbDevice = require("devtools/shared/adb/adb-device");
const { AdbRuntime } = require("devtools/shared/adb/adb-runtime"); const { AdbRuntime } = require("devtools/shared/adb/adb-runtime");
const { TrackDevicesCommand } = require("devtools/shared/adb/commands/track-devices"); const {
loader.lazyRequireGetter(this, "check", "devtools/shared/adb/adb-running-checker", true); TrackDevicesCommand,
} = require("devtools/shared/adb/commands/track-devices");
loader.lazyRequireGetter(
this,
"check",
"devtools/shared/adb/adb-running-checker",
true
);
// Duration in milliseconds of the runtime polling. We resort to polling here because we // Duration in milliseconds of the runtime polling. We resort to polling here because we
// have no event to know when a runtime started on an already discovered ADB device. // have no event to know when a runtime started on an already discovered ADB device.
@ -37,8 +47,14 @@ class Adb extends EventEmitter {
this._onNoDevicesDetected = this._onNoDevicesDetected.bind(this); this._onNoDevicesDetected = this._onNoDevicesDetected.bind(this);
this._trackDevicesCommand.on("device-connected", this._onDeviceConnected); this._trackDevicesCommand.on("device-connected", this._onDeviceConnected);
this._trackDevicesCommand.on("device-disconnected", this._onDeviceDisconnected); this._trackDevicesCommand.on(
this._trackDevicesCommand.on("no-devices-detected", this._onNoDevicesDetected); "device-disconnected",
this._onDeviceDisconnected
);
this._trackDevicesCommand.on(
"no-devices-detected",
this._onNoDevicesDetected
);
adbAddon.on("update", this._updateAdbProcess); adbAddon.on("update", this._updateAdbProcess);
} }
@ -87,7 +103,10 @@ class Adb extends EventEmitter {
// Device runtimes are detected by running a shell command and checking for // Device runtimes are detected by running a shell command and checking for
// "firefox-debugger-socket" in the list of currently running processes. // "firefox-debugger-socket" in the list of currently running processes.
this._timer = setInterval(this.updateRuntimes.bind(this), UPDATE_RUNTIMES_INTERVAL); this._timer = setInterval(
this.updateRuntimes.bind(this),
UPDATE_RUNTIMES_INTERVAL
);
} }
async _stopTracking() { async _stopTracking() {
@ -138,7 +157,7 @@ class Adb extends EventEmitter {
} }
async _getDeviceRuntimes(device) { async _getDeviceRuntimes(device) {
const socketPaths = [...await device.getRuntimeSocketPaths()]; const socketPaths = [...(await device.getRuntimeSocketPaths())];
const runtimes = []; const runtimes = [];
for (const socketPath of socketPaths) { for (const socketPath of socketPaths) {
const runtime = new AdbRuntime(device, socketPath); const runtime = new AdbRuntime(device, socketPath);

View file

@ -13,19 +13,17 @@ const { dumpn } = require("devtools/shared/DevToolsUtils");
const listDevices = function() { const listDevices = function() {
dumpn("listDevices"); dumpn("listDevices");
return this.runCommand("host:devices").then( return this.runCommand("host:devices").then(function onSuccess(data) {
function onSuccess(data) { const lines = data.split("\n");
const lines = data.split("\n"); const res = [];
const res = []; lines.forEach(function(line) {
lines.forEach(function(line) { if (line.length == 0) {
if (line.length == 0) { return;
return; }
} const [device] = line.split("\t");
const [ device ] = line.split("\t"); res.push(device);
res.push(device); });
}); return res;
return res; });
}
);
}; };
exports.listDevices = listDevices; exports.listDevices = listDevices;

View file

@ -5,7 +5,9 @@
"use strict"; "use strict";
const { dumpn } = require("devtools/shared/DevToolsUtils"); const { dumpn } = require("devtools/shared/DevToolsUtils");
const { ConnectionManager } = require("devtools/shared/client/connection-manager"); const {
ConnectionManager,
} = require("devtools/shared/client/connection-manager");
const { runCommand } = require("./run-command"); const { runCommand } = require("./run-command");
// sends adb forward deviceId, localPort and devicePort // sends adb forward deviceId, localPort and devicePort
@ -14,20 +16,21 @@ const forwardPort = function(deviceId, localPort, devicePort) {
// Send "host-serial:<serial-number>:<request>", // Send "host-serial:<serial-number>:<request>",
// with <request> set to "forward:<local>;<remote>" // with <request> set to "forward:<local>;<remote>"
// See https://android.googlesource.com/platform/system/core/+/jb-dev/adb/SERVICES.TXT // See https://android.googlesource.com/platform/system/core/+/jb-dev/adb/SERVICES.TXT
return runCommand(`host-serial:${ deviceId }:forward:${ localPort };${ devicePort }`) return runCommand(
.then(function onSuccess(data) { `host-serial:${deviceId}:forward:${localPort};${devicePort}`
return data; ).then(function onSuccess(data) {
}); return data;
});
}; };
// Prepare TCP connection for provided device id and socket path. // Prepare TCP connection for provided device id and socket path.
// The returned value is a port number of localhost for the connection. // The returned value is a port number of localhost for the connection.
const prepareTCPConnection = async function(deviceId, socketPath) { const prepareTCPConnection = async function(deviceId, socketPath) {
const port = ConnectionManager.getFreeTCPPort(); const port = ConnectionManager.getFreeTCPPort();
const local = `tcp:${ port }`; const local = `tcp:${port}`;
const remote = socketPath.startsWith("@") const remote = socketPath.startsWith("@")
? `localabstract:${ socketPath.substring(1) }` ? `localabstract:${socketPath.substring(1)}`
: `localfilesystem:${ socketPath }`; : `localfilesystem:${socketPath}`;
await forwardPort(deviceId, local, remote); await forwardPort(deviceId, local, remote);
return port; return port;
}; };

View file

@ -65,11 +65,13 @@ const shell = async function(deviceId, command) {
break; break;
} }
ignoreResponseCode = true; ignoreResponseCode = true;
// eslint-disable-next-lined no-fallthrough // eslint-disable-next-lined no-fallthrough
case "decode-shell": case "decode-shell":
const decoder = new TextDecoder(); const decoder = new TextDecoder();
const text = new Uint8Array(client.getBuffer(data), const text = new Uint8Array(
ignoreResponseCode ? 4 : 0); client.getBuffer(data),
ignoreResponseCode ? 4 : 0
);
stdout += decoder.decode(text); stdout += decoder.decode(text);
break; break;
default: default:

View file

@ -110,7 +110,10 @@ class TrackDevicesCommand extends EventEmitter {
}); });
// Fire events if needed. // Fire events if needed.
const deviceIds = new Set([...this._devices.keys(), ...newDevices.keys()]); const deviceIds = new Set([
...this._devices.keys(),
...newDevices.keys(),
]);
for (const deviceId of deviceIds) { for (const deviceId of deviceIds) {
const currentStatus = this._devices.get(deviceId); const currentStatus = this._devices.get(deviceId);
const newStatus = newDevices.get(deviceId); const newStatus = newDevices.get(deviceId);
@ -137,7 +140,9 @@ class TrackDevicesCommand extends EventEmitter {
} }
_fireConnectionEventIfNeeded(deviceId, currentStatus, newStatus) { _fireConnectionEventIfNeeded(deviceId, currentStatus, newStatus) {
const isCurrentOnline = !!(currentStatus && currentStatus !== ADB_STATUS_OFFLINE); const isCurrentOnline = !!(
currentStatus && currentStatus !== ADB_STATUS_OFFLINE
);
const isNewOnline = !!(newStatus && newStatus !== ADB_STATUS_OFFLINE); const isNewOnline = !!(newStatus && newStatus !== ADB_STATUS_OFFLINE);
if (isCurrentOnline === isNewOnline) { if (isCurrentOnline === isNewOnline) {

View file

@ -3,7 +3,9 @@
"use strict"; "use strict";
const { ExtensionTestUtils } = ChromeUtils.import("resource://testing-common/ExtensionXPCShellUtils.jsm"); const { ExtensionTestUtils } = ChromeUtils.import(
"resource://testing-common/ExtensionXPCShellUtils.jsm"
);
const { NetUtil } = require("resource://gre/modules/NetUtil.jsm"); const { NetUtil } = require("resource://gre/modules/NetUtil.jsm");
const { getFileForBinary } = require("devtools/shared/adb/adb-binary"); const { getFileForBinary } = require("devtools/shared/adb/adb-binary");
const { check } = require("devtools/shared/adb/adb-running-checker"); const { check } = require("devtools/shared/adb/adb-running-checker");
@ -11,30 +13,16 @@ const { adbProcess } = require("devtools/shared/adb/adb-process");
const { TrackDevicesCommand } = require("devtools/shared/adb/commands/index"); const { TrackDevicesCommand } = require("devtools/shared/adb/commands/index");
const ADB_JSON = { const ADB_JSON = {
"Linux": { Linux: {
"x86": [ x86: ["linux/adb"],
"linux/adb", x86_64: ["linux64/adb"],
],
"x86_64": [
"linux64/adb",
],
}, },
"Darwin": { Darwin: {
"x86_64": [ x86_64: ["mac64/adb"],
"mac64/adb",
],
}, },
"WINNT": { WINNT: {
"x86": [ x86: ["win32/adb.exe", "win32/AdbWinApi.dll", "win32/AdbWinUsbApi.dll"],
"win32/adb.exe", x86_64: ["win32/adb.exe", "win32/AdbWinApi.dll", "win32/AdbWinUsbApi.dll"],
"win32/AdbWinApi.dll",
"win32/AdbWinUsbApi.dll",
],
"x86_64": [
"win32/adb.exe",
"win32/AdbWinApi.dll",
"win32/AdbWinUsbApi.dll",
],
}, },
}; };
let extension_version = 1.0; let extension_version = 1.0;
@ -43,8 +31,9 @@ ExtensionTestUtils.init(this);
function readAdbMockContent() { function readAdbMockContent() {
const adbMockFile = do_get_file("adb.py", false); const adbMockFile = do_get_file("adb.py", false);
const s = Cc["@mozilla.org/network/file-input-stream;1"] const s = Cc["@mozilla.org/network/file-input-stream;1"].createInstance(
.createInstance(Ci.nsIFileInputStream); Ci.nsIFileInputStream
);
s.init(adbMockFile, -1, -1, false); s.init(adbMockFile, -1, -1, false);
try { try {
return NetUtil.readInputStreamToString(s, s.available()); return NetUtil.readInputStreamToString(s, s.available());
@ -152,92 +141,97 @@ add_task(async function testExtract() {
await extension.unload(); await extension.unload();
}); });
add_task({ add_task(
skip_if: () => mozinfo.os == "win", // bug 1482008 {
}, async function testStartAndStop() { skip_if: () => mozinfo.os == "win", // bug 1482008
const extension = ExtensionTestUtils.loadExtension({ },
manifest: { async function testStartAndStop() {
version: (extension_version++).toString(), const extension = ExtensionTestUtils.loadExtension({
applications: { manifest: {
gecko: { id: "adb@mozilla.org" }, version: (extension_version++).toString(),
applications: {
gecko: { id: "adb@mozilla.org" },
},
}, },
}, files: {
files: { "adb.json": JSON.stringify(ADB_JSON),
"adb.json": JSON.stringify(ADB_JSON), "linux/adb": adbMock,
"linux/adb": adbMock, "linux64/adb": adbMock,
"linux64/adb": adbMock, "mac64/adb": adbMock,
"mac64/adb": adbMock, "win32/adb.exe": adbMock,
"win32/adb.exe": adbMock, "win32/AdbWinApi.dll": "dummy",
"win32/AdbWinApi.dll": "dummy", "win32/AdbWinUsbApi.dll": "dummy",
"win32/AdbWinUsbApi.dll": "dummy",
},
});
await extension.startup();
// Call start() once and call stop() afterwards.
await adbProcess.start();
ok(adbProcess.ready);
ok(await check(), "adb is now running");
await adbProcess.stop();
ok(!adbProcess.ready);
ok(!(await check()), "adb is no longer running");
// Call start() twice and call stop() afterwards.
await adbProcess.start();
await adbProcess.start();
ok(adbProcess.ready);
ok(await check(), "adb is now running");
await adbProcess.stop();
ok(!adbProcess.ready);
ok(!(await check()), "adb is no longer running");
await extension.unload();
});
add_task({
skip_if: () => mozinfo.os == "win", // bug 1482008
}, async function testTrackDevices() {
const extension = ExtensionTestUtils.loadExtension({
manifest: {
version: (extension_version++).toString(),
applications: {
gecko: { id: "adb@mozilla.org" },
}, },
},
files: {
"adb.json": JSON.stringify(ADB_JSON),
"linux/adb": adbMock,
"linux64/adb": adbMock,
"mac64/adb": adbMock,
"win32/adb.exe": adbMock,
"win32/AdbWinApi.dll": "dummy",
"win32/AdbWinUsbApi.dll": "dummy",
},
});
await extension.startup();
await adbProcess.start();
ok(adbProcess.ready);
ok(await check(), "adb is now running");
const receivedDeviceId = await new Promise(resolve => {
const trackDevicesCommand = new TrackDevicesCommand();
trackDevicesCommand.on("device-connected", deviceId => {
resolve(deviceId);
}); });
trackDevicesCommand.run();
});
equal(receivedDeviceId, "1234567890"); await extension.startup();
await adbProcess.stop(); // Call start() once and call stop() afterwards.
ok(!adbProcess.ready); await adbProcess.start();
ok(adbProcess.ready);
ok(await check(), "adb is now running");
await extension.unload(); await adbProcess.stop();
}); ok(!adbProcess.ready);
ok(!(await check()), "adb is no longer running");
// Call start() twice and call stop() afterwards.
await adbProcess.start();
await adbProcess.start();
ok(adbProcess.ready);
ok(await check(), "adb is now running");
await adbProcess.stop();
ok(!adbProcess.ready);
ok(!(await check()), "adb is no longer running");
await extension.unload();
}
);
add_task(
{
skip_if: () => mozinfo.os == "win", // bug 1482008
},
async function testTrackDevices() {
const extension = ExtensionTestUtils.loadExtension({
manifest: {
version: (extension_version++).toString(),
applications: {
gecko: { id: "adb@mozilla.org" },
},
},
files: {
"adb.json": JSON.stringify(ADB_JSON),
"linux/adb": adbMock,
"linux64/adb": adbMock,
"mac64/adb": adbMock,
"win32/adb.exe": adbMock,
"win32/AdbWinApi.dll": "dummy",
"win32/AdbWinUsbApi.dll": "dummy",
},
});
await extension.startup();
await adbProcess.start();
ok(adbProcess.ready);
ok(await check(), "adb is now running");
const receivedDeviceId = await new Promise(resolve => {
const trackDevicesCommand = new TrackDevicesCommand();
trackDevicesCommand.on("device-connected", deviceId => {
resolve(deviceId);
});
trackDevicesCommand.run();
});
equal(receivedDeviceId, "1234567890");
await adbProcess.stop();
ok(!adbProcess.ready);
await extension.unload();
}
);

View file

@ -73,70 +73,90 @@ function withStore(type, onsuccess, onerror) {
function getItem(itemKey) { function getItem(itemKey) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let req; let req;
withStore("readonly", (store) => { withStore(
store.transaction.oncomplete = function onComplete() { "readonly",
let value = req.result; store => {
if (value === undefined) { store.transaction.oncomplete = function onComplete() {
value = null; let value = req.result;
} if (value === undefined) {
resolve(value); value = null;
}; }
req = store.get(itemKey); resolve(value);
req.onerror = function getItemOnError() { };
reject("Error in asyncStorage.getItem(): ", req.error.name); req = store.get(itemKey);
}; req.onerror = function getItemOnError() {
}, reject); reject("Error in asyncStorage.getItem(): ", req.error.name);
};
},
reject
);
}); });
} }
function setItem(itemKey, value) { function setItem(itemKey, value) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
withStore("readwrite", (store) => { withStore(
store.transaction.oncomplete = resolve; "readwrite",
const req = store.put(value, itemKey); store => {
req.onerror = function setItemOnError() { store.transaction.oncomplete = resolve;
reject("Error in asyncStorage.setItem(): ", req.error.name); const req = store.put(value, itemKey);
}; req.onerror = function setItemOnError() {
}, reject); reject("Error in asyncStorage.setItem(): ", req.error.name);
};
},
reject
);
}); });
} }
function removeItem(itemKey) { function removeItem(itemKey) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
withStore("readwrite", (store) => { withStore(
store.transaction.oncomplete = resolve; "readwrite",
const req = store.delete(itemKey); store => {
req.onerror = function removeItemOnError() { store.transaction.oncomplete = resolve;
reject("Error in asyncStorage.removeItem(): ", req.error.name); const req = store.delete(itemKey);
}; req.onerror = function removeItemOnError() {
}, reject); reject("Error in asyncStorage.removeItem(): ", req.error.name);
};
},
reject
);
}); });
} }
function clear() { function clear() {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
withStore("readwrite", (store) => { withStore(
store.transaction.oncomplete = resolve; "readwrite",
const req = store.clear(); store => {
req.onerror = function clearOnError() { store.transaction.oncomplete = resolve;
reject("Error in asyncStorage.clear(): ", req.error.name); const req = store.clear();
}; req.onerror = function clearOnError() {
}, reject); reject("Error in asyncStorage.clear(): ", req.error.name);
};
},
reject
);
}); });
} }
function length() { function length() {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let req; let req;
withStore("readonly", (store) => { withStore(
store.transaction.oncomplete = function onComplete() { "readonly",
resolve(req.result); store => {
}; store.transaction.oncomplete = function onComplete() {
req = store.count(); resolve(req.result);
req.onerror = function lengthOnError() { };
reject("Error in asyncStorage.length(): ", req.error.name); req = store.count();
}; req.onerror = function lengthOnError() {
}, reject); reject("Error in asyncStorage.length(): ", req.error.name);
};
},
reject
);
}); });
} }
@ -148,33 +168,37 @@ function key(n) {
} }
let req; let req;
withStore("readonly", (store) => { withStore(
store.transaction.oncomplete = function onComplete() { "readonly",
const cursor = req.result; store => {
resolve(cursor ? cursor.key : null); store.transaction.oncomplete = function onComplete() {
}; const cursor = req.result;
let advanced = false; resolve(cursor ? cursor.key : null);
req = store.openCursor(); };
req.onsuccess = function keyOnSuccess() { let advanced = false;
const cursor = req.result; req = store.openCursor();
if (!cursor) { req.onsuccess = function keyOnSuccess() {
// this means there weren"t enough keys const cursor = req.result;
return; if (!cursor) {
} // this means there weren"t enough keys
if (n === 0 || advanced) { return;
// Either 1) we have the first key, return it if that's what they }
// wanted, or 2) we"ve got the nth key. if (n === 0 || advanced) {
return; // Either 1) we have the first key, return it if that's what they
} // wanted, or 2) we"ve got the nth key.
return;
}
// Otherwise, ask the cursor to skip ahead n records // Otherwise, ask the cursor to skip ahead n records
advanced = true; advanced = true;
cursor.advance(n); cursor.advance(n);
}; };
req.onerror = function keyOnError() { req.onerror = function keyOnError() {
reject("Error in asyncStorage.key(): ", req.error.name); reject("Error in asyncStorage.key(): ", req.error.name);
}; };
}, reject); },
reject
);
}); });
} }

View file

@ -13,14 +13,25 @@ const { Constructor: CC, manager: Cm } = Components;
const systemPrincipal = CC("@mozilla.org/systemprincipal;1", "nsIPrincipal")(); const systemPrincipal = CC("@mozilla.org/systemprincipal;1", "nsIPrincipal")();
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm"); const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
const { XPCOMUtils } = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm"); const { XPCOMUtils } = ChromeUtils.import(
const { normalize, dirname } = ChromeUtils.import("resource://gre/modules/osfile/ospath_unix.jsm"); "resource://gre/modules/XPCOMUtils.jsm"
);
const { normalize, dirname } = ChromeUtils.import(
"resource://gre/modules/osfile/ospath_unix.jsm"
);
XPCOMUtils.defineLazyServiceGetter(this, "resProto", XPCOMUtils.defineLazyServiceGetter(
"@mozilla.org/network/protocol;1?name=resource", this,
"nsIResProtocolHandler"); "resProto",
"@mozilla.org/network/protocol;1?name=resource",
"nsIResProtocolHandler"
);
ChromeUtils.defineModuleGetter(this, "NetUtil", "resource://gre/modules/NetUtil.jsm"); ChromeUtils.defineModuleGetter(
this,
"NetUtil",
"resource://gre/modules/NetUtil.jsm"
);
const { defineLazyGetter } = XPCOMUtils; const { defineLazyGetter } = XPCOMUtils;
@ -58,8 +69,8 @@ function readURI(uri) {
const stream = NetUtil.newChannel({ const stream = NetUtil.newChannel({
uri: NetUtil.newURI(uri, "UTF-8"), uri: NetUtil.newURI(uri, "UTF-8"),
loadUsingSystemPrincipal: true} loadUsingSystemPrincipal: true,
).open(); }).open();
const count = stream.available(); const count = stream.available();
const data = NetUtil.readInputStreamToString(stream, count, { const data = NetUtil.readInputStreamToString(stream, count, {
charset: "UTF-8", charset: "UTF-8",
@ -74,7 +85,9 @@ function readURI(uri) {
function join(base, ...paths) { function join(base, ...paths) {
// If this is an absolute URL, we need to normalize only the path portion, // If this is an absolute URL, we need to normalize only the path portion,
// or we wind up stripping too many slashes and producing invalid URLs. // or we wind up stripping too many slashes and producing invalid URLs.
const match = /^((?:resource|file|chrome)\:\/\/[^\/]*|jar:[^!]+!)(.*)/.exec(base); const match = /^((?:resource|file|chrome)\:\/\/[^\/]*|jar:[^!]+!)(.*)/.exec(
base
);
if (match) { if (match) {
return match[1] + normalize([match[2], ...paths].join("/")); return match[1] + normalize([match[2], ...paths].join("/"));
} }
@ -100,8 +113,8 @@ function Sandbox(options) {
wantComponents: false, wantComponents: false,
sandboxName: options.name, sandboxName: options.name,
sandboxPrototype: "prototype" in options ? options.prototype : {}, sandboxPrototype: "prototype" in options ? options.prototype : {},
invisibleToDebugger: "invisibleToDebugger" in options ? invisibleToDebugger:
options.invisibleToDebugger : false, "invisibleToDebugger" in options ? options.invisibleToDebugger : false,
freshCompartment: options.freshCompartment || false, freshCompartment: options.freshCompartment || false,
}; };
@ -169,7 +182,10 @@ function load(loader, module) {
descriptors.define = define; descriptors.define = define;
} }
if ("DOMParser" in globals) { if ("DOMParser" in globals) {
descriptors.DOMParser = Object.getOwnPropertyDescriptor(globals, "DOMParser"); descriptors.DOMParser = Object.getOwnPropertyDescriptor(
globals,
"DOMParser"
);
} }
Object.defineProperties(sandbox, descriptors); Object.defineProperties(sandbox, descriptors);
} else { } else {
@ -188,12 +204,19 @@ function load(loader, module) {
// loadSubScript sometime throws string errors, which includes no stack. // loadSubScript sometime throws string errors, which includes no stack.
// At least provide the current stack by re-throwing a real Error object. // At least provide the current stack by re-throwing a real Error object.
if (typeof error == "string") { if (typeof error == "string") {
if (error.startsWith("Error creating URI") || if (
error.startsWith("Error opening input stream (invalid filename?)")) { error.startsWith("Error creating URI") ||
throw new Error(`Module \`${module.id}\` is not found at ${module.uri}`); error.startsWith("Error opening input stream (invalid filename?)")
) {
throw new Error(
`Module \`${module.id}\` is not found at ${module.uri}`
);
} }
throw new Error(`Error while loading module \`${module.id}\` at ${module.uri}:` + throw new Error(
"\n" + error); `Error while loading module \`${module.id}\` at ${module.uri}:` +
"\n" +
error
);
} }
// Otherwise just re-throw everything else which should have a stack // Otherwise just re-throw everything else which should have a stack
throw error; throw error;
@ -246,8 +269,8 @@ function resolve(id, base) {
function compileMapping(paths) { function compileMapping(paths) {
// Make mapping array that is sorted from longest path to shortest path. // Make mapping array that is sorted from longest path to shortest path.
const mapping = Object.keys(paths) const mapping = Object.keys(paths)
.sort((a, b) => b.length - a.length) .sort((a, b) => b.length - a.length)
.map(path => [path, paths[path]]); .map(path => [path, paths[path]]);
const PATTERN = /([.\\?+*(){}[\]^$])/g; const PATTERN = /([.\\?+*(){}[\]^$])/g;
const escapeMeta = str => str.replace(PATTERN, "\\$1"); const escapeMeta = str => str.replace(PATTERN, "\\$1");
@ -326,7 +349,7 @@ function lazyRequire(obj, moduleId, ...args) {
for (let props of args) { for (let props of args) {
if (typeof props !== "object") { if (typeof props !== "object") {
props = {[props]: props}; props = { [props]: props };
} }
for (const [fromName, toName] of Object.entries(props)) { for (const [fromName, toName] of Object.entries(props)) {
@ -355,15 +378,16 @@ function lazyRequireModule(obj, moduleId, prop = moduleId) {
// of `require` that is allowed to load only a modules that are associated // of `require` that is allowed to load only a modules that are associated
// with it during link time. // with it during link time.
function Require(loader, requirer) { function Require(loader, requirer) {
const { const { modules, mapping, mappingCache, requireHook } = loader;
modules, mapping, mappingCache, requireHook,
} = loader;
function require(id) { function require(id) {
if (!id) { if (!id) {
// Throw if `id` is not passed. // Throw if `id` is not passed.
throw Error("You must provide a module name when calling require() from " throw Error(
+ requirer.id, requirer.uri); "You must provide a module name when calling require() from " +
requirer.id,
requirer.uri
);
} }
if (requireHook) { if (requireHook) {
@ -432,8 +456,11 @@ function Require(loader, requirer) {
function getRequirements(id) { function getRequirements(id) {
if (!id) { if (!id) {
// Throw if `id` is not passed. // Throw if `id` is not passed.
throw Error("you must provide a module name when calling require() from " throw Error(
+ requirer.id, requirer.uri); "you must provide a module name when calling require() from " +
requirer.id,
requirer.uri
);
} }
let requirement, uri; let requirement, uri;
@ -459,8 +486,15 @@ function Require(loader, requirer) {
// Throw if `uri` can not be resolved. // Throw if `uri` can not be resolved.
if (!uri) { if (!uri) {
throw Error("Module: Can not resolve '" + id + "' module required by " + throw Error(
requirer.id + " located at " + requirer.uri, requirer.uri); "Module: Can not resolve '" +
id +
"' module required by " +
requirer.id +
" located at " +
requirer.uri,
requirer.uri
);
} }
return { uri: uri, requirement: requirement }; return { uri: uri, requirement: requirement };
@ -488,8 +522,12 @@ function Require(loader, requirer) {
function Module(id, uri) { function Module(id, uri) {
return Object.create(null, { return Object.create(null, {
id: { enumerable: true, value: id }, id: { enumerable: true, value: id },
exports: { enumerable: true, writable: true, value: Object.create(null), exports: {
configurable: true }, enumerable: true,
writable: true,
value: Object.create(null),
configurable: true,
},
uri: { value: uri }, uri: { value: uri },
}); });
} }
@ -545,9 +583,15 @@ function Loader(options) {
let modules = { let modules = {
"@loader/unload": destructor, "@loader/unload": destructor,
"@loader/options": options, "@loader/options": options,
"chrome": { Cc, Ci, Cu, Cr, Cm, chrome: {
CC: bind(CC, Components), components: Components, Cc,
ChromeWorker, Ci,
Cu,
Cr,
Cm,
CC: bind(CC, Components),
components: Components,
ChromeWorker,
}, },
}; };
@ -586,8 +630,11 @@ function Loader(options) {
// the sandbox directly. Note that this will not work for callers who // the sandbox directly. Note that this will not work for callers who
// depend on being able to add globals after the loader was created. // depend on being able to add globals after the loader was created.
for (const name of getOwnIdentifiers(globals)) { for (const name of getOwnIdentifiers(globals)) {
Object.defineProperty(sharedGlobalSandbox, name, Object.defineProperty(
Object.getOwnPropertyDescriptor(globals, name)); sharedGlobalSandbox,
name,
Object.getOwnPropertyDescriptor(globals, name)
);
} }
} }
@ -606,9 +653,15 @@ function Loader(options) {
// Map of module sandboxes indexed by module URIs. // Map of module sandboxes indexed by module URIs.
sandboxes: { enumerable: false, value: {} }, sandboxes: { enumerable: false, value: {} },
// Whether the modules loaded should be ignored by the debugger // Whether the modules loaded should be ignored by the debugger
invisibleToDebugger: { enumerable: false, invisibleToDebugger: {
value: options.invisibleToDebugger || false }, enumerable: false,
requireHook: { enumerable: false, writable: true, value: options.requireHook }, value: options.invisibleToDebugger || false,
},
requireHook: {
enumerable: false,
writable: true,
value: options.requireHook,
},
}; };
return Object.create(null, returnObj); return Object.create(null, returnObj);

View file

@ -165,11 +165,18 @@ function defineLazyServiceGetter(object, name, contract, interfaceName) {
* An object which acts on behalf of the module to be imported until * An object which acts on behalf of the module to be imported until
* the module has been imported. * the module has been imported.
*/ */
function defineLazyModuleGetter(object, name, resource, symbol, function defineLazyModuleGetter(
preLambda, postLambda, proxy) { object,
name,
resource,
symbol,
preLambda,
postLambda,
proxy
) {
proxy = proxy || {}; proxy = proxy || {};
if (typeof (preLambda) === "function") { if (typeof preLambda === "function") {
preLambda.apply(proxy); preLambda.apply(proxy);
} }
@ -178,7 +185,7 @@ function defineLazyModuleGetter(object, name, resource, symbol,
try { try {
ChromeUtils.import(resource, temp); ChromeUtils.import(resource, temp);
if (typeof (postLambda) === "function") { if (typeof postLambda === "function") {
postLambda.apply(proxy); postLambda.apply(proxy);
} }
} catch (ex) { } catch (ex) {
@ -247,13 +254,17 @@ defineLazyGetter(exports.modules, "Debugger", () => {
if (global.Debugger) { if (global.Debugger) {
return global.Debugger; return global.Debugger;
} }
const { addDebuggerToGlobal } = ChromeUtils.import("resource://gre/modules/jsdebugger.jsm"); const { addDebuggerToGlobal } = ChromeUtils.import(
"resource://gre/modules/jsdebugger.jsm"
);
addDebuggerToGlobal(global); addDebuggerToGlobal(global);
return global.Debugger; return global.Debugger;
}); });
defineLazyGetter(exports.modules, "ChromeDebugger", () => { defineLazyGetter(exports.modules, "ChromeDebugger", () => {
const { addDebuggerToGlobal } = ChromeUtils.import("resource://gre/modules/jsdebugger.jsm"); const { addDebuggerToGlobal } = ChromeUtils.import(
"resource://gre/modules/jsdebugger.jsm"
);
addDebuggerToGlobal(debuggerSandbox); addDebuggerToGlobal(debuggerSandbox);
return debuggerSandbox.Debugger; return debuggerSandbox.Debugger;
}); });
@ -265,7 +276,9 @@ defineLazyGetter(exports.modules, "RecordReplayControl", () => {
if (global.RecordReplayControl) { if (global.RecordReplayControl) {
return global.RecordReplayControl; return global.RecordReplayControl;
} }
const { addDebuggerToGlobal } = ChromeUtils.import("resource://gre/modules/jsdebugger.jsm"); const { addDebuggerToGlobal } = ChromeUtils.import(
"resource://gre/modules/jsdebugger.jsm"
);
addDebuggerToGlobal(global); addDebuggerToGlobal(global);
return global.RecordReplayControl; return global.RecordReplayControl;
}); });
@ -279,7 +292,10 @@ defineLazyGetter(exports.modules, "InspectorUtils", () => {
}); });
defineLazyGetter(exports.modules, "Timer", () => { defineLazyGetter(exports.modules, "Timer", () => {
const {setTimeout, clearTimeout} = require("resource://gre/modules/Timer.jsm"); const {
setTimeout,
clearTimeout,
} = require("resource://gre/modules/Timer.jsm");
// Do not return Cu.import result, as DevTools loader would freeze Timer.jsm globals... // Do not return Cu.import result, as DevTools loader would freeze Timer.jsm globals...
return { return {
setTimeout, setTimeout,
@ -377,7 +393,9 @@ lazyGlobal("WebSocket", () => {
return Services.appShell.hiddenDOMWindow.WebSocket; return Services.appShell.hiddenDOMWindow.WebSocket;
}); });
lazyGlobal("indexedDB", () => { lazyGlobal("indexedDB", () => {
return require("devtools/shared/indexed-db").createDevToolsIndexedDB(indexedDB); return require("devtools/shared/indexed-db").createDevToolsIndexedDB(
indexedDB
);
}); });
lazyGlobal("isReplaying", () => { lazyGlobal("isReplaying", () => {
return exports.modules.Debugger.recordReplayProcessKind() == "Middleman"; return exports.modules.Debugger.recordReplayProcessKind() == "Middleman";

View file

@ -6,7 +6,7 @@
"use strict"; "use strict";
const {Cc, Ci, Cr} = require("chrome"); const { Cc, Ci, Cr } = require("chrome");
const EventEmitter = require("devtools/shared/event-emitter"); const EventEmitter = require("devtools/shared/event-emitter");
const { DebuggerServer } = require("devtools/server/main"); const { DebuggerServer } = require("devtools/server/main");
const { DebuggerClient } = require("devtools/shared/client/debugger-client"); const { DebuggerClient } = require("devtools/shared/client/debugger-client");
@ -100,8 +100,9 @@ var ConnectionManager = {
return [...this._connections]; return [...this._connections];
}, },
getFreeTCPPort: function() { getFreeTCPPort: function() {
const serv = Cc["@mozilla.org/network/server-socket;1"] const serv = Cc["@mozilla.org/network/server-socket;1"].createInstance(
.createInstance(Ci.nsIServerSocket); Ci.nsIServerSocket
);
serv.init(-1, true, -1); serv.init(-1, true, -1);
const port = serv.port; const port = serv.port;
serv.close(); serv.close();
@ -251,8 +252,10 @@ Connection.prototype = {
return; return;
} }
clearTimeout(this._timeoutID); clearTimeout(this._timeoutID);
if (this.status == Connection.Status.CONNECTED || if (
this.status == Connection.Status.CONNECTING) { this.status == Connection.Status.CONNECTED ||
this.status == Connection.Status.CONNECTING
) {
this.log("disconnecting"); this.log("disconnecting");
this._setStatus(Connection.Status.DISCONNECTING); this._setStatus(Connection.Status.DISCONNECTING);
if (this._client) { if (this._client) {
@ -309,26 +312,32 @@ Connection.prototype = {
}, },
_clientConnect: function() { _clientConnect: function() {
this._getTransport().then(transport => { this._getTransport().then(
if (!transport) { transport => {
return; if (!transport) {
return;
}
this._client = new DebuggerClient(transport);
this._client.once("closed", this._onDisconnected);
this._client.connect().then(this._onConnected);
},
e => {
// If we're continuously trying to connect, we expect the connection to be
// rejected a couple times, so don't log these.
if (
!this.keepConnecting ||
e.result !== Cr.NS_ERROR_CONNECTION_REFUSED
) {
console.error(e);
}
// In some cases, especially on Mac, the openOutputStream call in
// DebuggerClient.socketConnect may throw NS_ERROR_NOT_INITIALIZED.
// It occurs when we connect agressively to the simulator,
// and keep trying to open a socket to the server being started in
// the simulator.
this._onDisconnected();
} }
this._client = new DebuggerClient(transport); );
this._client.once("closed", this._onDisconnected);
this._client.connect().then(this._onConnected);
}, e => {
// If we're continuously trying to connect, we expect the connection to be
// rejected a couple times, so don't log these.
if (!this.keepConnecting || e.result !== Cr.NS_ERROR_CONNECTION_REFUSED) {
console.error(e);
}
// In some cases, especially on Mac, the openOutputStream call in
// DebuggerClient.socketConnect may throw NS_ERROR_NOT_INITIALIZED.
// It occurs when we connect agressively to the simulator,
// and keep trying to open a socket to the server being started in
// the simulator.
this._onDisconnected();
});
}, },
get status() { get status() {
@ -360,9 +369,11 @@ Connection.prototype = {
this.log("disconnected (unexpected)"); this.log("disconnected (unexpected)");
break; break;
case Connection.Status.CONNECTING: case Connection.Status.CONNECTING:
this.log("connection error. Possible causes: USB port not connected, port not " + this.log(
"forwarded (adb forward), wrong host or port, remote debugging not " + "connection error. Possible causes: USB port not connected, port not " +
"enabled on the device."); "forwarded (adb forward), wrong host or port, remote debugging not " +
"enabled on the device."
);
break; break;
default: default:
this.log("disconnected"); this.log("disconnected");
@ -377,7 +388,9 @@ Connection.prototype = {
}, },
_onTimeout: function() { _onTimeout: function() {
this.log("connection timeout. Possible causes: didn't click on 'accept' (prompt)."); this.log(
"connection timeout. Possible causes: didn't click on 'accept' (prompt)."
);
this.emit(Connection.Events.TIMEOUT); this.emit(Connection.Events.TIMEOUT);
this.disconnect(); this.disconnect();
}, },

View file

@ -7,7 +7,10 @@
const promise = require("devtools/shared/deprecated-sync-thenables"); const promise = require("devtools/shared/deprecated-sync-thenables");
const DevToolsUtils = require("devtools/shared/DevToolsUtils"); const DevToolsUtils = require("devtools/shared/DevToolsUtils");
const { getStack, callFunctionWithAsyncStack } = require("devtools/shared/platform/stack"); const {
getStack,
callFunctionWithAsyncStack,
} = require("devtools/shared/platform/stack");
const EventEmitter = require("devtools/shared/event-emitter"); const EventEmitter = require("devtools/shared/event-emitter");
const { const {
ThreadStateTypes, ThreadStateTypes,
@ -15,12 +18,30 @@ const {
UnsolicitedPauses, UnsolicitedPauses,
} = require("./constants"); } = require("./constants");
loader.lazyRequireGetter(this, "Authentication", "devtools/shared/security/auth"); loader.lazyRequireGetter(
loader.lazyRequireGetter(this, "DebuggerSocket", "devtools/shared/security/socket", true); this,
"Authentication",
"devtools/shared/security/auth"
);
loader.lazyRequireGetter(
this,
"DebuggerSocket",
"devtools/shared/security/socket",
true
);
loader.lazyRequireGetter(this, "EventEmitter", "devtools/shared/event-emitter"); loader.lazyRequireGetter(this, "EventEmitter", "devtools/shared/event-emitter");
loader.lazyRequireGetter(this, "RootFront", "devtools/shared/fronts/root", true); loader.lazyRequireGetter(
loader.lazyRequireGetter(this, "ObjectClient", "devtools/shared/client/object-client"); this,
"RootFront",
"devtools/shared/fronts/root",
true
);
loader.lazyRequireGetter(
this,
"ObjectClient",
"devtools/shared/client/object-client"
);
loader.lazyRequireGetter(this, "Front", "devtools/shared/protocol", true); loader.lazyRequireGetter(this, "Front", "devtools/shared/protocol", true);
/** /**
@ -46,7 +67,7 @@ function DebuggerClient(transport) {
* the connection's root actor. * the connection's root actor.
*/ */
this.mainRoot = null; this.mainRoot = null;
this.expectReply("root", (packet) => { this.expectReply("root", packet => {
this.mainRoot = new RootFront(this, packet); this.mainRoot = new RootFront(this, packet);
// Root Front is a special case, managing itself as it doesn't have any parent. // Root Front is a special case, managing itself as it doesn't have any parent.
@ -98,22 +119,25 @@ DebuggerClient.requester = function(packetSkeleton, config = {}) {
outgoingPacket = before.call(this, outgoingPacket); outgoingPacket = before.call(this, outgoingPacket);
} }
return this.request(outgoingPacket, DevToolsUtils.makeInfallible((response) => { return this.request(
if (after) { outgoingPacket,
const { from } = response; DevToolsUtils.makeInfallible(response => {
response = after.call(this, response); if (after) {
if (!response.from) { const { from } = response;
response.from = from; response = after.call(this, response);
if (!response.from) {
response.from = from;
}
} }
}
// The callback is always the last parameter. // The callback is always the last parameter.
const thisCallback = args[maxPosition + 1]; const thisCallback = args[maxPosition + 1];
if (thisCallback) { if (thisCallback) {
thisCallback(response); thisCallback(response);
} }
return response; return response;
}, "DebuggerClient.requester request callback")); }, "DebuggerClient.requester request callback")
);
}, "DebuggerClient.requester"); }, "DebuggerClient.requester");
}; };
@ -294,9 +318,14 @@ DebuggerClient.prototype = {
}; };
if (this._closed) { if (this._closed) {
const msg = "'" + type + "' request packet to " + const msg =
"'" + packet.to + "' " + "'" +
"can't be sent as the connection is closed."; type +
"' request packet to " +
"'" +
packet.to +
"' " +
"can't be sent as the connection is closed.";
const resp = { error: "connectionClosed", message: msg }; const resp = { error: "connectionClosed", message: msg };
return promise.reject(safeOnResponse(resp)); return promise.reject(safeOnResponse(resp));
} }
@ -531,24 +560,28 @@ DebuggerClient.prototype = {
if (!packet.from) { if (!packet.from) {
DevToolsUtils.reportException( DevToolsUtils.reportException(
"onPacket", "onPacket",
new Error("Server did not specify an actor, dropping packet: " + new Error(
JSON.stringify(packet))); "Server did not specify an actor, dropping packet: " +
JSON.stringify(packet)
)
);
return; return;
} }
// Check for "forwardingCancelled" here instead of using a front to handle it. // Check for "forwardingCancelled" here instead of using a front to handle it.
// This is necessary because we might receive this event while the client is closing, // This is necessary because we might receive this event while the client is closing,
// and the fronts have already been removed by that point. // and the fronts have already been removed by that point.
if (this.mainRoot && if (
packet.from == this.mainRoot.actorID && this.mainRoot &&
packet.type == "forwardingCancelled") { packet.from == this.mainRoot.actorID &&
packet.type == "forwardingCancelled"
) {
this.purgeRequests(packet.prefix); this.purgeRequests(packet.prefix);
return; return;
} }
// support older browsers for Fx69+ for using the old thread client // support older browsers for Fx69+ for using the old thread client
if (!this.traits.hasThreadFront && if (!this.traits.hasThreadFront && packet.from.includes("context")) {
packet.from.includes("context")) {
this.sendToDeprecatedThreadClient(packet); this.sendToDeprecatedThreadClient(packet);
return; return;
} }
@ -565,8 +598,10 @@ DebuggerClient.prototype = {
// See if we have a handler function waiting for a reply from this // See if we have a handler function waiting for a reply from this
// actor. (Don't count unsolicited notifications or pauses as // actor. (Don't count unsolicited notifications or pauses as
// replies.) // replies.)
if (this._activeRequests.has(packet.from) && if (
!(packet.type in UnsolicitedNotifications)) { this._activeRequests.has(packet.from) &&
!(packet.type in UnsolicitedNotifications)
) {
activeRequest = this._activeRequests.get(packet.from); activeRequest = this._activeRequests.get(packet.from);
this._activeRequests.delete(packet.from); this._activeRequests.delete(packet.from);
} }
@ -585,8 +620,11 @@ DebuggerClient.prototype = {
if (activeRequest) { if (activeRequest) {
const emitReply = () => activeRequest.emit("json-reply", packet); const emitReply = () => activeRequest.emit("json-reply", packet);
if (activeRequest.stack) { if (activeRequest.stack) {
callFunctionWithAsyncStack(emitReply, activeRequest.stack, callFunctionWithAsyncStack(
"DevTools RDP"); emitReply,
activeRequest.stack,
"DevTools RDP"
);
} else { } else {
emitReply(); emitReply();
} }
@ -611,9 +649,13 @@ DebuggerClient.prototype = {
// See if we have a handler function waiting for a reply from this // See if we have a handler function waiting for a reply from this
// actor. (Don't count unsolicited notifications or pauses as // actor. (Don't count unsolicited notifications or pauses as
// replies.) // replies.)
if (this._activeRequests.has(packet.from) && if (
!(packet.type == ThreadStateTypes.paused && this._activeRequests.has(packet.from) &&
packet.why.type in UnsolicitedPauses)) { !(
packet.type == ThreadStateTypes.paused &&
packet.why.type in UnsolicitedPauses
)
) {
activeRequest = this._activeRequests.get(packet.from); activeRequest = this._activeRequests.get(packet.from);
this._activeRequests.delete(packet.from); this._activeRequests.delete(packet.from);
} }
@ -624,9 +666,11 @@ DebuggerClient.prototype = {
this._attemptNextRequest(packet.from); this._attemptNextRequest(packet.from);
// Packets that indicate thread state changes get special treatment. // Packets that indicate thread state changes get special treatment.
if (packet.type in ThreadStateTypes && if (
deprecatedThreadClient && packet.type in ThreadStateTypes &&
typeof deprecatedThreadClient._onThreadState == "function") { deprecatedThreadClient &&
typeof deprecatedThreadClient._onThreadState == "function"
) {
deprecatedThreadClient._onThreadState(packet); deprecatedThreadClient._onThreadState(packet);
} }
@ -677,8 +721,11 @@ DebuggerClient.prototype = {
if (!actor) { if (!actor) {
DevToolsUtils.reportException( DevToolsUtils.reportException(
"onBulkPacket", "onBulkPacket",
new Error("Server did not specify an actor, dropping bulk packet: " + new Error(
JSON.stringify(packet))); "Server did not specify an actor, dropping bulk packet: " +
JSON.stringify(packet)
)
);
return; return;
} }
@ -751,11 +798,19 @@ DebuggerClient.prototype = {
// to expectReply, so that there is no request object. // to expectReply, so that there is no request object.
let msg; let msg;
if (request.request) { if (request.request) {
msg = "'" + request.request.type + "' " + type + " request packet" + msg =
" to '" + request.actor + "' " + "'" +
"can't be sent as the connection just closed."; request.request.type +
"' " +
type +
" request packet" +
" to '" +
request.actor +
"' " +
"can't be sent as the connection just closed.";
} else { } else {
msg = "server side packet can't be received as the connection just closed."; msg =
"server side packet can't be received as the connection just closed.";
} }
const packet = { error: "connectionClosed", message: msg }; const packet = { error: "connectionClosed", message: msg };
request.emit("json-reply", packet); request.emit("json-reply", packet);
@ -838,14 +893,16 @@ DebuggerClient.prototype = {
return Promise.resolve(); return Promise.resolve();
} }
return DevToolsUtils.settleAll(requests).catch(() => { return DevToolsUtils.settleAll(requests)
// One of the requests might have failed, but ignore that situation here and pipe .catch(() => {
// both success and failure through the same path. The important part is just that // One of the requests might have failed, but ignore that situation here and pipe
// we waited. // both success and failure through the same path. The important part is just that
}).then(() => { // we waited.
// Repeat, more requests may have started in response to those we just waited for })
return this.waitForRequestsToSettle(); .then(() => {
}); // Repeat, more requests may have started in response to those we just waited for
return this.waitForRequestsToSettle();
});
}, },
/** /**

View file

@ -5,9 +5,12 @@
"use strict"; "use strict";
const {arg, DebuggerClient} = require("devtools/shared/client/debugger-client"); const {
arg,
DebuggerClient,
} = require("devtools/shared/client/debugger-client");
const EventEmitter = require("devtools/shared/event-emitter"); const EventEmitter = require("devtools/shared/event-emitter");
const {ThreadStateTypes} = require("devtools/shared/client/constants"); const { ThreadStateTypes } = require("devtools/shared/client/constants");
loader.lazyRequireGetter( loader.lazyRequireGetter(
this, this,
@ -78,36 +81,39 @@ ThreadClient.prototype = {
* than proceeding forwards. This parameter has no effect if the * than proceeding forwards. This parameter has no effect if the
* server does not support rewinding. * server does not support rewinding.
*/ */
_doResume: DebuggerClient.requester({ _doResume: DebuggerClient.requester(
type: "resume", {
resumeLimit: arg(0), type: "resume",
rewind: arg(1), resumeLimit: arg(0),
}, { rewind: arg(1),
before: function(packet) {
this._assertPaused("resume");
// Put the client in a tentative "resuming" state so we can prevent
// further requests that should only be sent in the paused state.
this._previousState = this._state;
this._state = "resuming";
return packet;
}, },
after: function(response) { {
if (response.error && this._state == "resuming") { before: function(packet) {
// There was an error resuming, update the state to the new one this._assertPaused("resume");
// reported by the server, if given (only on wrongState), otherwise
// reset back to the previous state. // Put the client in a tentative "resuming" state so we can prevent
if (response.state) { // further requests that should only be sent in the paused state.
this._state = ThreadStateTypes[response.state]; this._previousState = this._state;
} else { this._state = "resuming";
this._state = this._previousState;
return packet;
},
after: function(response) {
if (response.error && this._state == "resuming") {
// There was an error resuming, update the state to the new one
// reported by the server, if given (only on wrongState), otherwise
// reset back to the previous state.
if (response.state) {
this._state = ThreadStateTypes[response.state];
} else {
this._state = this._previousState;
}
} }
} delete this._previousState;
delete this._previousState; return response;
return response; },
}, }
}), ),
/** /**
* Reconfigure the thread actor. * Reconfigure the thread actor.

View file

@ -4,7 +4,10 @@
"use strict"; "use strict";
const {arg, DebuggerClient} = require("devtools/shared/client/debugger-client"); const {
arg,
DebuggerClient,
} = require("devtools/shared/client/debugger-client");
/** /**
* Environment clients are used to manipulate the lexical environment actors. * Environment clients are used to manipulate the lexical environment actors.
@ -22,7 +25,6 @@ function EnvironmentClient(client, form) {
exports.EnvironmentClient = EnvironmentClient; exports.EnvironmentClient = EnvironmentClient;
EnvironmentClient.prototype = { EnvironmentClient.prototype = {
get actor() { get actor() {
return this._form.actor; return this._form.actor;
}, },

View file

@ -86,8 +86,9 @@ function eventSource(proto) {
if (!listener) { if (!listener) {
this._listeners[name] = []; this._listeners[name] = [];
} else { } else {
this._listeners[name] = this._listeners[name] = this._listeners[name].filter(
this._listeners[name].filter(l => l.key != listener); l => l.key != listener
);
} }
}; };

View file

@ -4,7 +4,10 @@
"use strict"; "use strict";
const {arg, DebuggerClient} = require("devtools/shared/client/debugger-client"); const {
arg,
DebuggerClient,
} = require("devtools/shared/client/debugger-client");
/** /**
* A LongStringClient provides a way to access "very long" strings from the * A LongStringClient provides a way to access "very long" strings from the
* debugger server. * debugger server.

View file

@ -4,9 +4,20 @@
"use strict"; "use strict";
const {arg, DebuggerClient} = require("devtools/shared/client/debugger-client"); const {
loader.lazyRequireGetter(this, "PropertyIteratorClient", "devtools/shared/client/property-iterator-client"); arg,
loader.lazyRequireGetter(this, "SymbolIteratorClient", "devtools/shared/client/symbol-iterator-client"); DebuggerClient,
} = require("devtools/shared/client/debugger-client");
loader.lazyRequireGetter(
this,
"PropertyIteratorClient",
"devtools/shared/client/property-iterator-client"
);
loader.lazyRequireGetter(
this,
"SymbolIteratorClient",
"devtools/shared/client/symbol-iterator-client"
);
/** /**
* Grip clients are used to retrieve information about the relevant object. * Grip clients are used to retrieve information about the relevant object.
@ -46,16 +57,21 @@ ObjectClient.prototype = {
type: "threadGrip", type: "threadGrip",
}), }),
getDefinitionSite: DebuggerClient.requester({ getDefinitionSite: DebuggerClient.requester(
type: "definitionSite", {
}, { type: "definitionSite",
before: function(packet) {
if (this._grip.class != "Function") {
throw new Error("getDefinitionSite is only valid for function grips.");
}
return packet;
}, },
}), {
before: function(packet) {
if (this._grip.class != "Function") {
throw new Error(
"getDefinitionSite is only valid for function grips."
);
}
return packet;
},
}
),
/** /**
* Request the names of a function's formal parameters. * Request the names of a function's formal parameters.
@ -65,16 +81,21 @@ ObjectClient.prototype = {
* { parameterNames:[<parameterName>, ...] } * { parameterNames:[<parameterName>, ...] }
* where each <parameterName> is the name of a parameter. * where each <parameterName> is the name of a parameter.
*/ */
getParameterNames: DebuggerClient.requester({ getParameterNames: DebuggerClient.requester(
type: "parameterNames", {
}, { type: "parameterNames",
before: function(packet) {
if (this._grip.class !== "Function") {
throw new Error("getParameterNames is only valid for function grips.");
}
return packet;
}, },
}), {
before: function(packet) {
if (this._grip.class !== "Function") {
throw new Error(
"getParameterNames is only valid for function grips."
);
}
return packet;
},
}
),
/** /**
* Request the names of the properties defined on the object and not its * Request the names of the properties defined on the object and not its
@ -113,17 +134,25 @@ ObjectClient.prototype = {
* before dispatching them. * before dispatching them.
* @param onResponse function Called with the client instance. * @param onResponse function Called with the client instance.
*/ */
enumProperties: DebuggerClient.requester({ enumProperties: DebuggerClient.requester(
type: "enumProperties", {
options: arg(0), type: "enumProperties",
}, { options: arg(0),
after: function(response) {
if (response.iterator) {
return { iterator: new PropertyIteratorClient(this._client, response.iterator) };
}
return response;
}, },
}), {
after: function(response) {
if (response.iterator) {
return {
iterator: new PropertyIteratorClient(
this._client,
response.iterator
),
};
}
return response;
},
}
),
/** /**
* Request a PropertyIteratorClient instance to enumerate entries in a * Request a PropertyIteratorClient instance to enumerate entries in a
@ -131,48 +160,63 @@ ObjectClient.prototype = {
* *
* @param onResponse function Called with the request's response. * @param onResponse function Called with the request's response.
*/ */
enumEntries: DebuggerClient.requester({ enumEntries: DebuggerClient.requester(
type: "enumEntries", {
}, { type: "enumEntries",
before: function(packet) {
if (!["Map", "WeakMap", "Set", "WeakSet", "Storage"].includes(this._grip.class)) {
throw new Error("enumEntries is only valid for Map/Set/Storage-like grips.");
}
return packet;
}, },
after: function(response) { {
if (response.iterator) { before: function(packet) {
return { if (
iterator: new PropertyIteratorClient(this._client, response.iterator), !["Map", "WeakMap", "Set", "WeakSet", "Storage"].includes(
}; this._grip.class
} )
return response; ) {
}, throw new Error(
}), "enumEntries is only valid for Map/Set/Storage-like grips."
);
}
return packet;
},
after: function(response) {
if (response.iterator) {
return {
iterator: new PropertyIteratorClient(
this._client,
response.iterator
),
};
}
return response;
},
}
),
/** /**
* Request a SymbolIteratorClient instance to enumerate symbols in an object. * Request a SymbolIteratorClient instance to enumerate symbols in an object.
* *
* @param onResponse function Called with the request's response. * @param onResponse function Called with the request's response.
*/ */
enumSymbols: DebuggerClient.requester({ enumSymbols: DebuggerClient.requester(
type: "enumSymbols", {
}, { type: "enumSymbols",
before: function(packet) {
if (this._grip.type !== "object") {
throw new Error("enumSymbols is only valid for objects grips.");
}
return packet;
}, },
after: function(response) { {
if (response.iterator) { before: function(packet) {
return { if (this._grip.type !== "object") {
iterator: new SymbolIteratorClient(this._client, response.iterator), throw new Error("enumSymbols is only valid for objects grips.");
}; }
} return packet;
return response; },
}, after: function(response) {
}), if (response.iterator) {
return {
iterator: new SymbolIteratorClient(this._client, response.iterator),
};
}
return response;
},
}
),
/** /**
* Request the property descriptor of the object's specified property. * Request the property descriptor of the object's specified property.
@ -234,98 +278,121 @@ ObjectClient.prototype = {
* *
* @param onResponse function Called with the request's response. * @param onResponse function Called with the request's response.
*/ */
getScope: DebuggerClient.requester({ getScope: DebuggerClient.requester(
type: "scope", {
}, { type: "scope",
before: function(packet) {
if (this._grip.class !== "Function") {
throw new Error("scope is only valid for function grips.");
}
return packet;
}, },
}), {
before: function(packet) {
if (this._grip.class !== "Function") {
throw new Error("scope is only valid for function grips.");
}
return packet;
},
}
),
/** /**
* Request the promises directly depending on the current promise. * Request the promises directly depending on the current promise.
*/ */
getDependentPromises: DebuggerClient.requester({ getDependentPromises: DebuggerClient.requester(
type: "dependentPromises", {
}, { type: "dependentPromises",
before: function(packet) {
if (this._grip.class !== "Promise") {
throw new Error("getDependentPromises is only valid for promise " +
"grips.");
}
return packet;
}, },
}), {
before: function(packet) {
if (this._grip.class !== "Promise") {
throw new Error(
"getDependentPromises is only valid for promise " + "grips."
);
}
return packet;
},
}
),
/** /**
* Request the stack to the promise's allocation point. * Request the stack to the promise's allocation point.
*/ */
getPromiseAllocationStack: DebuggerClient.requester({ getPromiseAllocationStack: DebuggerClient.requester(
type: "allocationStack", {
}, { type: "allocationStack",
before: function(packet) {
if (this._grip.class !== "Promise") {
throw new Error("getAllocationStack is only valid for promise grips.");
}
return packet;
}, },
}), {
before: function(packet) {
if (this._grip.class !== "Promise") {
throw new Error(
"getAllocationStack is only valid for promise grips."
);
}
return packet;
},
}
),
/** /**
* Request the stack to the promise's fulfillment point. * Request the stack to the promise's fulfillment point.
*/ */
getPromiseFulfillmentStack: DebuggerClient.requester({ getPromiseFulfillmentStack: DebuggerClient.requester(
type: "fulfillmentStack", {
}, { type: "fulfillmentStack",
before: function(packet) {
if (this._grip.class !== "Promise") {
throw new Error("getPromiseFulfillmentStack is only valid for " +
"promise grips.");
}
return packet;
}, },
}), {
before: function(packet) {
if (this._grip.class !== "Promise") {
throw new Error(
"getPromiseFulfillmentStack is only valid for " + "promise grips."
);
}
return packet;
},
}
),
/** /**
* Request the stack to the promise's rejection point. * Request the stack to the promise's rejection point.
*/ */
getPromiseRejectionStack: DebuggerClient.requester({ getPromiseRejectionStack: DebuggerClient.requester(
type: "rejectionStack", {
}, { type: "rejectionStack",
before: function(packet) {
if (this._grip.class !== "Promise") {
throw new Error("getPromiseRejectionStack is only valid for " +
"promise grips.");
}
return packet;
}, },
}), {
before: function(packet) {
if (this._grip.class !== "Promise") {
throw new Error(
"getPromiseRejectionStack is only valid for " + "promise grips."
);
}
return packet;
},
}
),
/** /**
* Request the target and handler internal slots of a proxy. * Request the target and handler internal slots of a proxy.
*/ */
getProxySlots: DebuggerClient.requester({ getProxySlots: DebuggerClient.requester(
type: "proxySlots", {
}, { type: "proxySlots",
before: function(packet) {
if (this._grip.class !== "Proxy") {
throw new Error("getProxySlots is only valid for proxy grips.");
}
return packet;
}, },
after: function(response) { {
// Before Firefox 68 (bug 1392760), the proxySlots request didn't exist. before: function(packet) {
// The proxy target and handler were directly included in the grip. if (this._grip.class !== "Proxy") {
if (response.error === "unrecognizedPacketType") { throw new Error("getProxySlots is only valid for proxy grips.");
const {proxyTarget, proxyHandler} = this._grip; }
return {proxyTarget, proxyHandler}; return packet;
} },
return response; after: function(response) {
}, // Before Firefox 68 (bug 1392760), the proxySlots request didn't exist.
}), // The proxy target and handler were directly included in the grip.
if (response.error === "unrecognizedPacketType") {
const { proxyTarget, proxyHandler } = this._grip;
return { proxyTarget, proxyHandler };
}
return response;
},
}
),
}; };
module.exports = ObjectClient; module.exports = ObjectClient;

View file

@ -4,7 +4,10 @@
"use strict"; "use strict";
const {arg, DebuggerClient} = require("devtools/shared/client/debugger-client"); const {
arg,
DebuggerClient,
} = require("devtools/shared/client/debugger-client");
/** /**
* A PropertyIteratorClient provides a way to access to property names and * A PropertyIteratorClient provides a way to access to property names and
@ -46,10 +49,13 @@ PropertyIteratorClient.prototype = {
* @param callback Function * @param callback Function
* The function called when we receive the property names. * The function called when we receive the property names.
*/ */
names: DebuggerClient.requester({ names: DebuggerClient.requester(
type: "names", {
indexes: arg(0), type: "names",
}, {}), indexes: arg(0),
},
{}
),
/** /**
* Get a set of following property value(s). * Get a set of following property value(s).
@ -61,11 +67,14 @@ PropertyIteratorClient.prototype = {
* @param callback Function * @param callback Function
* The function called when we receive the property values. * The function called when we receive the property values.
*/ */
slice: DebuggerClient.requester({ slice: DebuggerClient.requester(
type: "slice", {
start: arg(0), type: "slice",
count: arg(1), start: arg(0),
}, {}), count: arg(1),
},
{}
),
/** /**
* Get all the property values. * Get all the property values.
@ -73,9 +82,12 @@ PropertyIteratorClient.prototype = {
* @param callback Function * @param callback Function
* The function called when we receive the property values. * The function called when we receive the property values.
*/ */
all: DebuggerClient.requester({ all: DebuggerClient.requester(
type: "all", {
}, {}), type: "all",
},
{}
),
}; };
module.exports = PropertyIteratorClient; module.exports = PropertyIteratorClient;

View file

@ -4,7 +4,10 @@
"use strict"; "use strict";
const {arg, DebuggerClient} = require("devtools/shared/client/debugger-client"); const {
arg,
DebuggerClient,
} = require("devtools/shared/client/debugger-client");
/** /**
* A SymbolIteratorClient provides a way to access to symbols * A SymbolIteratorClient provides a way to access to symbols
@ -44,11 +47,14 @@ SymbolIteratorClient.prototype = {
* @param callback Function * @param callback Function
* The function called when we receive the symbols. * The function called when we receive the symbols.
*/ */
slice: DebuggerClient.requester({ slice: DebuggerClient.requester(
type: "slice", {
start: arg(0), type: "slice",
count: arg(1), start: arg(0),
}, {}), count: arg(1),
},
{}
),
/** /**
* Get all the symbols. * Get all the symbols.
@ -56,9 +62,12 @@ SymbolIteratorClient.prototype = {
* @param callback Function * @param callback Function
* The function called when we receive the symbols. * The function called when we receive the symbols.
*/ */
all: DebuggerClient.requester({ all: DebuggerClient.requester(
type: "all", {
}, {}), type: "all",
},
{}
),
}; };
module.exports = SymbolIteratorClient; module.exports = SymbolIteratorClient;

View file

@ -6,7 +6,10 @@
"use strict"; "use strict";
const { ThreadStateTypes } = require("devtools/shared/client/constants"); const { ThreadStateTypes } = require("devtools/shared/client/constants");
const { FrontClassWithSpec, registerFront } = require("devtools/shared/protocol"); const {
FrontClassWithSpec,
registerFront,
} = require("devtools/shared/protocol");
const { threadSpec } = require("devtools/shared/specs/thread"); const { threadSpec } = require("devtools/shared/specs/thread");
loader.lazyRequireGetter( loader.lazyRequireGetter(
@ -198,7 +201,7 @@ class ThreadClient extends FrontClassWithSpec(threadSpec) {
async getSources() { async getSources() {
let sources = []; let sources = [];
try { try {
({sources} = await super.sources()); ({ sources } = await super.sources());
} catch (e) { } catch (e) {
// we may have closed the connection // we may have closed the connection
console.log(`getSources failed. Connection may have closed: ${e}`); console.log(`getSources failed. Connection may have closed: ${e}`);

View file

@ -3,7 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict"; "use strict";
const {Ci} = require("chrome"); const { Ci } = require("chrome");
const Services = require("Services"); const Services = require("Services");
const EventEmitter = require("devtools/shared/event-emitter"); const EventEmitter = require("devtools/shared/event-emitter");
@ -28,9 +28,13 @@ ContentObserver.prototype = {
*/ */
startListening: function() { startListening: function() {
Services.obs.addObserver( Services.obs.addObserver(
this._onContentGlobalCreated, "content-document-global-created"); this._onContentGlobalCreated,
"content-document-global-created"
);
Services.obs.addObserver( Services.obs.addObserver(
this._onInnerWindowDestroyed, "inner-window-destroyed"); this._onInnerWindowDestroyed,
"inner-window-destroyed"
);
}, },
/** /**
@ -38,9 +42,13 @@ ContentObserver.prototype = {
*/ */
stopListening: function() { stopListening: function() {
Services.obs.removeObserver( Services.obs.removeObserver(
this._onContentGlobalCreated, "content-document-global-created"); this._onContentGlobalCreated,
"content-document-global-created"
);
Services.obs.removeObserver( Services.obs.removeObserver(
this._onInnerWindowDestroyed, "inner-window-destroyed"); this._onInnerWindowDestroyed,
"inner-window-destroyed"
);
}, },
/** /**

View file

@ -5,11 +5,21 @@
"use strict"; "use strict";
const Services = require("Services"); const Services = require("Services");
const {getCSSLexer} = require("devtools/shared/css/lexer"); const { getCSSLexer } = require("devtools/shared/css/lexer");
const {cssColors} = require("devtools/shared/css/color-db"); const { cssColors } = require("devtools/shared/css/color-db");
loader.lazyRequireGetter(this, "CSS_ANGLEUNIT", "devtools/shared/css/constants", true); loader.lazyRequireGetter(
loader.lazyRequireGetter(this, "getAngleValueInDegrees", "devtools/shared/css/parsing-utils", true); this,
"CSS_ANGLEUNIT",
"devtools/shared/css/constants",
true
);
loader.lazyRequireGetter(
this,
"getAngleValueInDegrees",
"devtools/shared/css/parsing-utils",
true
);
const COLOR_UNIT_PREF = "devtools.defaultColorUnit"; const COLOR_UNIT_PREF = "devtools.defaultColorUnit";
@ -83,11 +93,11 @@ module.exports.colorUtils = {
* Values used in COLOR_UNIT_PREF * Values used in COLOR_UNIT_PREF
*/ */
CssColor.COLORUNIT = { CssColor.COLORUNIT = {
"authored": "authored", authored: "authored",
"hex": "hex", hex: "hex",
"name": "name", name: "name",
"rgb": "rgb", rgb: "rgb",
"hsl": "hsl", hsl: "hsl",
}; };
CssColor.prototype = { CssColor.prototype = {
@ -106,8 +116,8 @@ CssColor.prototype = {
// Specifically exclude the case where the color is // Specifically exclude the case where the color is
// case-insensitive. This makes it so that "#000" isn't // case-insensitive. This makes it so that "#000" isn't
// considered "upper case" for the purposes of color cycling. // considered "upper case" for the purposes of color cycling.
this._colorUnitUppercase = (color === color.toUpperCase()) && this._colorUnitUppercase =
(color !== color.toLowerCase()); color === color.toUpperCase() && color !== color.toLowerCase();
}, },
get colorUnit() { get colorUnit() {
@ -131,8 +141,10 @@ CssColor.prototype = {
* @param {String} color The color to use * @param {String} color The color to use
*/ */
setAuthoredUnitFromColor: function(color) { setAuthoredUnitFromColor: function(color) {
if (Services.prefs.getCharPref(COLOR_UNIT_PREF) === if (
CssColor.COLORUNIT.authored) { Services.prefs.getCharPref(COLOR_UNIT_PREF) ===
CssColor.COLORUNIT.authored
) {
this._colorUnit = classifyColor(color); this._colorUnit = classifyColor(color);
this._setColorUnitUppercase(color); this._setColorUnitUppercase(color);
} }
@ -195,7 +207,7 @@ CssColor.prototype = {
if (tuple.a !== 1) { if (tuple.a !== 1) {
return this.hex; return this.hex;
} }
const {r, g, b} = tuple; const { r, g, b } = tuple;
return rgbToColorName(r, g, b) || this.hex; return rgbToColorName(r, g, b) || this.hex;
}, },
@ -209,9 +221,11 @@ CssColor.prototype = {
} }
let hex = this.longHex; let hex = this.longHex;
if (hex.charAt(1) == hex.charAt(2) && if (
hex.charAt(3) == hex.charAt(4) && hex.charAt(1) == hex.charAt(2) &&
hex.charAt(5) == hex.charAt(6)) { hex.charAt(3) == hex.charAt(4) &&
hex.charAt(5) == hex.charAt(6)
) {
hex = "#" + hex.charAt(1) + hex.charAt(3) + hex.charAt(5); hex = "#" + hex.charAt(1) + hex.charAt(3) + hex.charAt(5);
} }
return hex; return hex;
@ -224,12 +238,18 @@ CssColor.prototype = {
} }
let alphaHex = this.longAlphaHex; let alphaHex = this.longAlphaHex;
if (alphaHex.charAt(1) == alphaHex.charAt(2) && if (
alphaHex.charAt(3) == alphaHex.charAt(4) && alphaHex.charAt(1) == alphaHex.charAt(2) &&
alphaHex.charAt(5) == alphaHex.charAt(6) && alphaHex.charAt(3) == alphaHex.charAt(4) &&
alphaHex.charAt(7) == alphaHex.charAt(8)) { alphaHex.charAt(5) == alphaHex.charAt(6) &&
alphaHex = "#" + alphaHex.charAt(1) + alphaHex.charAt(3) + alphaHex.charAt(7) == alphaHex.charAt(8)
alphaHex.charAt(5) + alphaHex.charAt(7); ) {
alphaHex =
"#" +
alphaHex.charAt(1) +
alphaHex.charAt(3) +
alphaHex.charAt(5) +
alphaHex.charAt(7);
} }
return alphaHex; return alphaHex;
}, },
@ -244,8 +264,12 @@ CssColor.prototype = {
} }
const tuple = this.getRGBATuple(); const tuple = this.getRGBATuple();
return "#" + ((1 << 24) + (tuple.r << 16) + (tuple.g << 8) + return (
(tuple.b << 0)).toString(16).substr(-6); "#" +
((1 << 24) + (tuple.r << 16) + (tuple.g << 8) + (tuple.b << 0))
.toString(16)
.substr(-6)
);
}, },
get longAlphaHex() { get longAlphaHex() {
@ -256,9 +280,15 @@ CssColor.prototype = {
const tuple = this.highResTuple; const tuple = this.highResTuple;
return "#" + ((1 << 24) + (tuple.r << 16) + (tuple.g << 8) + return (
(tuple.b << 0)).toString(16).substr(-6) + "#" +
Math.round(tuple.a).toString(16).padStart(2, "0"); ((1 << 24) + (tuple.r << 16) + (tuple.g << 8) + (tuple.b << 0))
.toString(16)
.substr(-6) +
Math.round(tuple.a)
.toString(16)
.padStart(2, "0")
);
}, },
get rgb() { get rgb() {
@ -287,10 +317,17 @@ CssColor.prototype = {
return this.authored; return this.authored;
} }
const components = this.getRGBATuple(); const components = this.getRGBATuple();
return "rgba(" + components.r + ", " + return (
components.g + ", " + "rgba(" +
components.b + ", " + components.r +
components.a + ")"; ", " +
components.g +
", " +
components.b +
", " +
components.a +
")"
);
}, },
get hsl() { get hsl() {
@ -407,8 +444,10 @@ CssColor.prototype = {
color = this.rgb; color = this.rgb;
} }
if (this._colorUnitUppercase && if (
this.colorUnit != CssColor.COLORUNIT.authored) { this._colorUnitUppercase &&
this.colorUnit != CssColor.COLORUNIT.authored
) {
color = color.toUpperCase(); color = color.toUpperCase();
} }
@ -432,7 +471,7 @@ CssColor.prototype = {
* appropriate. * appropriate.
*/ */
_getHSLATuple: function() { _getHSLATuple: function() {
const {r, g, b, a} = colorToRGBA(this.authored, this.cssColor4); const { r, g, b, a } = colorToRGBA(this.authored, this.cssColor4);
const [h, s, l] = rgbToHsl([r, g, b]); const [h, s, l] = rgbToHsl([r, g, b]);
@ -450,7 +489,7 @@ CssColor.prototype = {
return this.authored; return this.authored;
} }
const {r, g, b} = this.getRGBATuple(); const { r, g, b } = this.getRGBATuple();
const [h, s, l] = rgbToHsl([r, g, b]); const [h, s, l] = rgbToHsl([r, g, b]);
if (maybeAlpha !== undefined) { if (maybeAlpha !== undefined) {
return "hsla(" + h + ", " + s + "%, " + l + "%, " + maybeAlpha + ")"; return "hsla(" + h + ", " + s + "%, " + l + "%, " + maybeAlpha + ")";
@ -647,7 +686,10 @@ function hslToRGB([h, s, l]) {
* name was not a valid color * name was not a valid color
*/ */
function hexToRGBA(name, highResolution) { function hexToRGBA(name, highResolution) {
let r, g, b, a = 1; let r,
g,
b,
a = 1;
if (name.length === 3) { if (name.length === 3) {
// short hex string (e.g. F0C) // short hex string (e.g. F0C)
@ -685,7 +727,7 @@ function hexToRGBA(name, highResolution) {
if (!highResolution) { if (!highResolution) {
a = Math.round(a * 10) / 10; a = Math.round(a * 10) / 10;
} }
return {r, g, b, a}; return { r, g, b, a };
} }
/** /**
@ -722,8 +764,10 @@ function getToken(lexer) {
while (true) { while (true) {
const token = lexer.nextToken(); const token = lexer.nextToken();
if (!token || (token.tokenType !== "comment" && if (
token.tokenType !== "whitespace")) { !token ||
(token.tokenType !== "comment" && token.tokenType !== "whitespace")
) {
lexer._currentToken = token; lexer._currentToken = token;
return token; return token;
} }
@ -767,9 +811,9 @@ function expectSymbol(lexer, symbol) {
} }
const COLOR_COMPONENT_TYPE = { const COLOR_COMPONENT_TYPE = {
"integer": "integer", integer: "integer",
"number": "number", number: "number",
"percentage": "percentage", percentage: "percentage",
}; };
/** /**
@ -935,10 +979,16 @@ function parseHsl(lexer) {
// version of parseColorComponent function for them. No need to check the // version of parseColorComponent function for them. No need to check the
// separator after 'lightness'. It will be checked in opacity value parsing. // separator after 'lightness'. It will be checked in opacity value parsing.
const separatorBeforeAlpha = hasComma ? commaSeparator : "/"; const separatorBeforeAlpha = hasComma ? commaSeparator : "/";
if (parseColorComponent(lexer, COLOR_COMPONENT_TYPE.percentage, if (
hasComma ? commaSeparator : "", hsl) && parseColorComponent(
parseColorComponent(lexer, COLOR_COMPONENT_TYPE.percentage, "", hsl) && lexer,
parseColorOpacityAndCloseParen(lexer, separatorBeforeAlpha, a)) { COLOR_COMPONENT_TYPE.percentage,
hasComma ? commaSeparator : "",
hsl
) &&
parseColorComponent(lexer, COLOR_COMPONENT_TYPE.percentage, "", hsl) &&
parseColorOpacityAndCloseParen(lexer, separatorBeforeAlpha, a)
) {
return [...hslToRGB(hsl), ...a]; return [...hslToRGB(hsl), ...a];
} }
@ -980,18 +1030,32 @@ function parseOldStyleHsl(lexer, hasAlpha) {
// The saturation and lightness are <percentage>, so reuse the <percentage> // The saturation and lightness are <percentage>, so reuse the <percentage>
// version of parseColorComponent function for them. The opacity is <number> // version of parseColorComponent function for them. The opacity is <number>
if (hasAlpha) { if (hasAlpha) {
if (parseColorComponent(lexer, COLOR_COMPONENT_TYPE.percentage, if (
commaSeparator, hsl) && parseColorComponent(
parseColorComponent(lexer, COLOR_COMPONENT_TYPE.percentage, lexer,
commaSeparator, hsl) && COLOR_COMPONENT_TYPE.percentage,
parseColorComponent(lexer, COLOR_COMPONENT_TYPE.number, commaSeparator,
closeParen, a)) { hsl
) &&
parseColorComponent(
lexer,
COLOR_COMPONENT_TYPE.percentage,
commaSeparator,
hsl
) &&
parseColorComponent(lexer, COLOR_COMPONENT_TYPE.number, closeParen, a)
) {
return [...hslToRGB(hsl), ...a]; return [...hslToRGB(hsl), ...a];
} }
} else if (parseColorComponent(lexer, COLOR_COMPONENT_TYPE.percentage, } else if (
commaSeparator, hsl) && parseColorComponent(
parseColorComponent(lexer, COLOR_COMPONENT_TYPE.percentage, lexer,
closeParen, hsl)) { COLOR_COMPONENT_TYPE.percentage,
commaSeparator,
hsl
) &&
parseColorComponent(lexer, COLOR_COMPONENT_TYPE.percentage, closeParen, hsl)
) {
return [...hslToRGB(hsl), 1]; return [...hslToRGB(hsl), 1];
} }
@ -1022,9 +1086,10 @@ function parseRgb(lexer) {
return null; return null;
} }
unGetToken(lexer); unGetToken(lexer);
const type = (token.tokenType === "percentage") ? const type =
COLOR_COMPONENT_TYPE.percentage : token.tokenType === "percentage"
COLOR_COMPONENT_TYPE.number; ? COLOR_COMPONENT_TYPE.percentage
: COLOR_COMPONENT_TYPE.number;
// Parse R. // Parse R.
if (!parseColorComponent(lexer, type, "", rgba)) { if (!parseColorComponent(lexer, type, "", rgba)) {
@ -1036,9 +1101,11 @@ function parseRgb(lexer) {
// No need to check the separator after 'B'. It will be checked in 'A' values // No need to check the separator after 'B'. It will be checked in 'A' values
// parsing. // parsing.
const separatorBeforeAlpha = hasComma ? commaSeparator : "/"; const separatorBeforeAlpha = hasComma ? commaSeparator : "/";
if (parseColorComponent(lexer, type, hasComma ? commaSeparator : "", rgba) && if (
parseColorComponent(lexer, type, "", rgba) && parseColorComponent(lexer, type, hasComma ? commaSeparator : "", rgba) &&
parseColorOpacityAndCloseParen(lexer, separatorBeforeAlpha, rgba)) { parseColorComponent(lexer, type, "", rgba) &&
parseColorOpacityAndCloseParen(lexer, separatorBeforeAlpha, rgba)
) {
if (type === COLOR_COMPONENT_TYPE.percentage) { if (type === COLOR_COMPONENT_TYPE.percentage) {
rgba[0] = Math.round(255 * rgba[0]); rgba[0] = Math.round(255 * rgba[0]);
rgba[1] = Math.round(255 * rgba[1]); rgba[1] = Math.round(255 * rgba[1]);
@ -1070,27 +1137,33 @@ function parseOldStyleRgb(lexer, hasAlpha) {
const rgba = []; const rgba = [];
const token = getToken(lexer); const token = getToken(lexer);
if (token.tokenType !== "percentage" && if (
(token.tokenType !== "number" || !token.isInteger)) { token.tokenType !== "percentage" &&
(token.tokenType !== "number" || !token.isInteger)
) {
return null; return null;
} }
unGetToken(lexer); unGetToken(lexer);
const type = (token.tokenType === "percentage") ? const type =
COLOR_COMPONENT_TYPE.percentage : token.tokenType === "percentage"
COLOR_COMPONENT_TYPE.integer; ? COLOR_COMPONENT_TYPE.percentage
: COLOR_COMPONENT_TYPE.integer;
// Parse R. G, B and A. // Parse R. G, B and A.
if (hasAlpha) { if (hasAlpha) {
if (!parseColorComponent(lexer, type, commaSeparator, rgba) || if (
!parseColorComponent(lexer, type, commaSeparator, rgba) || !parseColorComponent(lexer, type, commaSeparator, rgba) ||
!parseColorComponent(lexer, type, commaSeparator, rgba) || !parseColorComponent(lexer, type, commaSeparator, rgba) ||
!parseColorComponent(lexer, COLOR_COMPONENT_TYPE.number, !parseColorComponent(lexer, type, commaSeparator, rgba) ||
closeParen, rgba)) { !parseColorComponent(lexer, COLOR_COMPONENT_TYPE.number, closeParen, rgba)
) {
return null; return null;
} }
} else if (!parseColorComponent(lexer, type, commaSeparator, rgba) || } else if (
!parseColorComponent(lexer, type, commaSeparator, rgba) || !parseColorComponent(lexer, type, commaSeparator, rgba) ||
!parseColorComponent(lexer, type, closeParen, rgba)) { !parseColorComponent(lexer, type, commaSeparator, rgba) ||
!parseColorComponent(lexer, type, closeParen, rgba)
) {
return null; return null;
} }
@ -1120,11 +1193,11 @@ function colorToRGBA(name, useCssColor4ColorFunction = false) {
if (name in cssColors) { if (name in cssColors) {
const result = cssColors[name]; const result = cssColors[name];
return {r: result[0], g: result[1], b: result[2], a: result[3]}; return { r: result[0], g: result[1], b: result[2], a: result[3] };
} else if (name === "transparent") { } else if (name === "transparent") {
return {r: 0, g: 0, b: 0, a: 0}; return { r: 0, g: 0, b: 0, a: 0 };
} else if (name === "currentcolor") { } else if (name === "currentcolor") {
return {r: 0, g: 0, b: 0, a: 1}; return { r: 0, g: 0, b: 0, a: 1 };
} }
const lexer = getCSSLexer(name); const lexer = getCSSLexer(name);
@ -1142,8 +1215,11 @@ function colorToRGBA(name, useCssColor4ColorFunction = false) {
} }
const expectedFunctions = ["rgba", "rgb", "hsla", "hsl"]; const expectedFunctions = ["rgba", "rgb", "hsla", "hsl"];
if (!func || func.tokenType !== "function" || if (
!expectedFunctions.includes(func.text)) { !func ||
func.tokenType !== "function" ||
!expectedFunctions.includes(func.text)
) {
return null; return null;
} }
@ -1151,8 +1227,10 @@ function colorToRGBA(name, useCssColor4ColorFunction = false) {
let vals; let vals;
if (!useCssColor4ColorFunction) { if (!useCssColor4ColorFunction) {
const hasAlpha = (func.text === "rgba" || func.text === "hsla"); const hasAlpha = func.text === "rgba" || func.text === "hsla";
vals = hsl ? parseOldStyleHsl(lexer, hasAlpha) : parseOldStyleRgb(lexer, hasAlpha); vals = hsl
? parseOldStyleHsl(lexer, hasAlpha)
: parseOldStyleRgb(lexer, hasAlpha);
} else { } else {
vals = hsl ? parseHsl(lexer) : parseRgb(lexer); vals = hsl ? parseHsl(lexer) : parseRgb(lexer);
} }
@ -1164,7 +1242,7 @@ function colorToRGBA(name, useCssColor4ColorFunction = false) {
return null; return null;
} }
return {r: vals[0], g: vals[1], b: vals[2], a: vals[3]}; return { r: vals[0], g: vals[1], b: vals[2], a: vals[3] };
} }
/** /**
@ -1188,8 +1266,10 @@ function isValidCSSColor(name, useCssColor4ColorFunction = false) {
function calculateLuminance(rgba) { function calculateLuminance(rgba) {
for (let i = 0; i < 3; i++) { for (let i = 0; i < 3; i++) {
rgba[i] /= 255; rgba[i] /= 255;
rgba[i] = (rgba[i] < 0.03928) ? (rgba[i] / 12.92) : rgba[i] =
Math.pow(((rgba[i] + 0.055) / 1.055), 2.4); rgba[i] < 0.03928
? rgba[i] / 12.92
: Math.pow((rgba[i] + 0.055) / 1.055, 2.4);
} }
return 0.2126 * rgba[0] + 0.7152 * rgba[1] + 0.0722 * rgba[2]; return 0.2126 * rgba[0] + 0.7152 * rgba[1] + 0.0722 * rgba[2];
} }
@ -1204,9 +1284,9 @@ function calculateLuminance(rgba) {
* @return {Array} * @return {Array}
* An array with combined [r,g,b,a] colors. * An array with combined [r,g,b,a] colors.
*/ */
function blendColors(foregroundColor, backgroundColor = [ 255, 255, 255, 1 ]) { function blendColors(foregroundColor, backgroundColor = [255, 255, 255, 1]) {
const [ fgR, fgG, fgB, fgA ] = foregroundColor; const [fgR, fgG, fgB, fgA] = foregroundColor;
const [ bgR, bgG, bgB, bgA ] = backgroundColor; const [bgR, bgG, bgB, bgA] = backgroundColor;
if (fgA === 1) { if (fgA === 1) {
return foregroundColor; return foregroundColor;
} }
@ -1241,5 +1321,5 @@ function calculateContrastRatio(backgroundColor, textColor) {
const textLuminance = calculateLuminance(textColor); const textLuminance = calculateLuminance(textColor);
const ratio = (textLuminance + 0.05) / (backgroundLuminance + 0.05); const ratio = (textLuminance + 0.05) / (backgroundLuminance + 0.05);
return (ratio > 1.0) ? ratio : (1 / ratio); return ratio > 1.0 ? ratio : 1 / ratio;
} }

View file

@ -8,10 +8,10 @@
* All CSS <angle> types that properties can support. * All CSS <angle> types that properties can support.
*/ */
exports.CSS_ANGLEUNIT = { exports.CSS_ANGLEUNIT = {
"deg": "deg", deg: "deg",
"rad": "rad", rad: "rad",
"grad": "grad", grad: "grad",
"turn": "turn", turn: "turn",
}; };
/** /**
@ -19,9 +19,9 @@ exports.CSS_ANGLEUNIT = {
* Kept for backwards compatibility. Remove after Firefox 70. * Kept for backwards compatibility. Remove after Firefox 70.
*/ */
exports.CSS_TYPES = { exports.CSS_TYPES = {
"color": 2, color: 2,
"gradient": 4, gradient: 4,
"timing-function": 10, "timing-function": 10,
}; };
/** /**

View file

@ -9,8 +9,10 @@
* as known by the platform. It is run from ./mach_commands.py by running * as known by the platform. It is run from ./mach_commands.py by running
* `mach devtools-css-db`. * `mach devtools-css-db`.
*/ */
var {require} = ChromeUtils.import("resource://devtools/shared/Loader.jsm"); var { require } = ChromeUtils.import("resource://devtools/shared/Loader.jsm");
var {generateCssProperties} = require("devtools/server/actors/css-properties"); var {
generateCssProperties,
} = require("devtools/server/actors/css-properties");
const InspectorUtils = require("InspectorUtils"); const InspectorUtils = require("InspectorUtils");
// xpcshell can output extra information, so place some delimiter text between // xpcshell can output extra information, so place some delimiter text between
@ -18,11 +20,13 @@ const InspectorUtils = require("InspectorUtils");
dump("DEVTOOLS_CSS_DB_DELIMITER"); dump("DEVTOOLS_CSS_DB_DELIMITER");
// Output JSON // Output JSON
dump(JSON.stringify({ dump(
cssProperties: cssProperties(), JSON.stringify({
preferences: preferences(), cssProperties: cssProperties(),
pseudoElements: pseudoElements(), preferences: preferences(),
})); pseudoElements: pseudoElements(),
})
);
dump("DEVTOOLS_CSS_DB_DELIMITER"); dump("DEVTOOLS_CSS_DB_DELIMITER");
@ -53,7 +57,7 @@ function cssProperties() {
function preferences() { function preferences() {
const prefs = InspectorUtils.getCSSPropertyPrefs(); const prefs = InspectorUtils.getCSSPropertyPrefs();
const result = []; const result = [];
for (const {name, pref} of prefs) { for (const { name, pref } of prefs) {
result.push([name, pref]); result.push([name, pref]);
} }
return result; return result;

View file

@ -133,14 +133,14 @@ const NUMBER_SIGN = "#".charCodeAt(0);
const PERCENT_SIGN = "%".charCodeAt(0); const PERCENT_SIGN = "%".charCodeAt(0);
const PLUS_SIGN = "+".charCodeAt(0); const PLUS_SIGN = "+".charCodeAt(0);
const QUESTION_MARK = "?".charCodeAt(0); const QUESTION_MARK = "?".charCodeAt(0);
const QUOTATION_MARK = "\"".charCodeAt(0); const QUOTATION_MARK = '"'.charCodeAt(0);
const REVERSE_SOLIDUS = "\\".charCodeAt(0); const REVERSE_SOLIDUS = "\\".charCodeAt(0);
const RIGHT_PARENTHESIS = ")".charCodeAt(0); const RIGHT_PARENTHESIS = ")".charCodeAt(0);
const SOLIDUS = "/".charCodeAt(0); const SOLIDUS = "/".charCodeAt(0);
const TILDE = "~".charCodeAt(0); const TILDE = "~".charCodeAt(0);
const VERTICAL_LINE = "|".charCodeAt(0); const VERTICAL_LINE = "|".charCodeAt(0);
const UCS2_REPLACEMENT_CHAR = 0xFFFD; const UCS2_REPLACEMENT_CHAR = 0xfffd;
const kImpliedEOFCharacters = [ const kImpliedEOFCharacters = [
UCS2_REPLACEMENT_CHAR, UCS2_REPLACEMENT_CHAR,
@ -160,7 +160,7 @@ const kImpliedEOFCharacters = [
* @return {Number} the character or its replacement * @return {Number} the character or its replacement
*/ */
function ensureValidChar(c) { function ensureValidChar(c) {
if (c >= 0x00110000 || (c & 0xFFF800) == 0xD800) { if (c >= 0x00110000 || (c & 0xfff800) == 0xd800) {
// Out of range or a surrogate. // Out of range or a surrogate.
return UCS2_REPLACEMENT_CHAR; return UCS2_REPLACEMENT_CHAR;
} }
@ -175,7 +175,7 @@ function ensureValidChar(c) {
* the input string. * the input string.
*/ */
function stringToCodes(str) { function stringToCodes(str) {
return Array.prototype.map.call(str, (c) => c.charCodeAt(0)); return Array.prototype.map.call(str, c => c.charCodeAt(0));
} }
const IS_HEX_DIGIT = 0x01; const IS_HEX_DIGIT = 0x01;
@ -204,38 +204,150 @@ const SUIJX = S | U | I | J | X;
/* eslint-disable indent, indent-legacy, no-multi-spaces, comma-spacing, spaced-comment */ /* eslint-disable indent, indent-legacy, no-multi-spaces, comma-spacing, spaced-comment */
const gLexTable = [ const gLexTable = [
// 00 01 02 03 04 05 06 07 // 00 01 02 03 04 05 06 07
0, S, S, S, S, S, S, S, 0,
// 08 TAB LF 0B FF CR 0E 0F S,
S, SH, V, S, V, V, S, S, S,
// 10 11 12 13 14 15 16 17 S,
S, S, S, S, S, S, S, S, S,
// 18 19 1A 1B 1C 1D 1E 1F S,
S, S, S, S, S, S, S, S, S,
//SPC ! " # $ % & ' S,
SH, SU, 0, SU, SU, SU, SU, 0, // 08 TAB LF 0B FF CR 0E 0F
// ( ) * + , - . / S,
S, S, SU, SU, SU, SUI, SU, SU, SH,
// 0 1 2 3 4 5 6 7 V,
SUIX, SUIX, SUIX, SUIX, SUIX, SUIX, SUIX, SUIX, S,
// 8 9 : ; < = > ? V,
SUIX, SUIX, SU, SU, SU, SU, SU, SU, V,
// @ A B C D E F G S,
SU,SUIJX,SUIJX,SUIJX,SUIJX,SUIJX,SUIJX, SUIJ, S,
// H I J K L M N O // 10 11 12 13 14 15 16 17
SUIJ, SUIJ, SUIJ, SUIJ, SUIJ, SUIJ, SUIJ, SUIJ, S,
// P Q R S T U V W S,
SUIJ, SUIJ, SUIJ, SUIJ, SUIJ, SUIJ, SUIJ, SUIJ, S,
// X Y Z [ \ ] ^ _ S,
SUIJ, SUIJ, SUIJ, SU, J, SU, SU, SUIJ, S,
// ` a b c d e f g S,
SU,SUIJX,SUIJX,SUIJX,SUIJX,SUIJX,SUIJX, SUIJ, S,
// h i j k l m n o S,
SUIJ, SUIJ, SUIJ, SUIJ, SUIJ, SUIJ, SUIJ, SUIJ, // 18 19 1A 1B 1C 1D 1E 1F
// p q r s t u v w S,
SUIJ, SUIJ, SUIJ, SUIJ, SUIJ, SUIJ, SUIJ, SUIJ, S,
// x y z { | } ~ 7F S,
SUIJ, SUIJ, SUIJ, SU, SU, SU, SU, S, S,
S,
S,
S,
S,
//SPC ! " # $ % & '
SH,
SU,
0,
SU,
SU,
SU,
SU,
0,
// ( ) * + , - . /
S,
S,
SU,
SU,
SU,
SUI,
SU,
SU,
// 0 1 2 3 4 5 6 7
SUIX,
SUIX,
SUIX,
SUIX,
SUIX,
SUIX,
SUIX,
SUIX,
// 8 9 : ; < = > ?
SUIX,
SUIX,
SU,
SU,
SU,
SU,
SU,
SU,
// @ A B C D E F G
SU,
SUIJX,
SUIJX,
SUIJX,
SUIJX,
SUIJX,
SUIJX,
SUIJ,
// H I J K L M N O
SUIJ,
SUIJ,
SUIJ,
SUIJ,
SUIJ,
SUIJ,
SUIJ,
SUIJ,
// P Q R S T U V W
SUIJ,
SUIJ,
SUIJ,
SUIJ,
SUIJ,
SUIJ,
SUIJ,
SUIJ,
// X Y Z [ \ ] ^ _
SUIJ,
SUIJ,
SUIJ,
SU,
J,
SU,
SU,
SUIJ,
// ` a b c d e f g
SU,
SUIJX,
SUIJX,
SUIJX,
SUIJX,
SUIJX,
SUIJX,
SUIJ,
// h i j k l m n o
SUIJ,
SUIJ,
SUIJ,
SUIJ,
SUIJ,
SUIJ,
SUIJ,
SUIJ,
// p q r s t u v w
SUIJ,
SUIJ,
SUIJ,
SUIJ,
SUIJ,
SUIJ,
SUIJ,
SUIJ,
// x y z { | } ~ 7F
SUIJ,
SUIJ,
SUIJ,
SU,
SU,
SU,
SU,
S,
]; ];
/* eslint-enable indent, indent-legacy, no-multi-spaces, comma-spacing, spaced-comment */ /* eslint-enable indent, indent-legacy, no-multi-spaces, comma-spacing, spaced-comment */
@ -304,16 +416,18 @@ function IsIdentStart(ch) {
* identifier. * identifier.
*/ */
function StartsIdent(aFirstChar, aSecondChar) { function StartsIdent(aFirstChar, aSecondChar) {
return IsIdentStart(aFirstChar) || return (
(aFirstChar == HYPHEN_MINUS && (aSecondChar == HYPHEN_MINUS || IsIdentStart(aFirstChar) ||
IsIdentStart(aSecondChar))); (aFirstChar == HYPHEN_MINUS &&
(aSecondChar == HYPHEN_MINUS || IsIdentStart(aSecondChar)))
);
} }
/** /**
* True if 'ch' is a decimal digit. * True if 'ch' is a decimal digit.
*/ */
function IsDigit(ch) { function IsDigit(ch) {
return (ch >= DIGIT_ZERO) && (ch <= DIGIT_NINE); return ch >= DIGIT_ZERO && ch <= DIGIT_NINE;
} }
/** /**
@ -351,12 +465,18 @@ function HexDigitValue(ch) {
*/ */
function MatchOperatorType(ch) { function MatchOperatorType(ch) {
switch (ch) { switch (ch) {
case TILDE: return eCSSToken_Includes; case TILDE:
case VERTICAL_LINE: return eCSSToken_Dashmatch; return eCSSToken_Includes;
case CIRCUMFLEX_ACCENT: return eCSSToken_Beginsmatch; case VERTICAL_LINE:
case DOLLAR_SIGN: return eCSSToken_Endsmatch; return eCSSToken_Dashmatch;
case ASTERISK: return eCSSToken_Containsmatch; case CIRCUMFLEX_ACCENT:
default: return eCSSToken_Symbol; return eCSSToken_Beginsmatch;
case DOLLAR_SIGN:
return eCSSToken_Endsmatch;
case ASTERISK:
return eCSSToken_Containsmatch;
default:
return eCSSToken_Symbol;
} }
} }
@ -428,16 +548,23 @@ Scanner.prototype = {
let eofChars = this.mEOFCharacters; let eofChars = this.mEOFCharacters;
if (aPreserveBackslash && if (
(eofChars & (eEOFCharacters_DropBackslash | aPreserveBackslash &&
eEOFCharacters_ReplacementChar)) != 0) { (eofChars &
eofChars &= ~(eEOFCharacters_DropBackslash | (eEOFCharacters_DropBackslash | eEOFCharacters_ReplacementChar)) !=
eEOFCharacters_ReplacementChar); 0
) {
eofChars &= ~(
eEOFCharacters_DropBackslash | eEOFCharacters_ReplacementChar
);
result += "\\"; result += "\\";
} }
if ((eofChars & eEOFCharacters_DropBackslash) != 0 && if (
result.length > 0 && result.endsWith("\\")) { (eofChars & eEOFCharacters_DropBackslash) != 0 &&
result.length > 0 &&
result.endsWith("\\")
) {
result = result.slice(0, -1); result = result.slice(0, -1);
} }
@ -525,7 +652,7 @@ Scanner.prototype = {
case eCSSToken_Dimension: case eCSSToken_Dimension:
resultToken.text = constructText(); resultToken.text = constructText();
/* Fall through. */ /* Fall through. */
case eCSSToken_Number: case eCSSToken_Number:
case eCSSToken_Percentage: case eCSSToken_Percentage:
resultToken.number = token.mNumber; resultToken.number = token.mNumber;
@ -595,9 +722,11 @@ Scanner.prototype = {
*/ */
AdvanceLine: function() { AdvanceLine: function() {
// Advance over \r\n as a unit. // Advance over \r\n as a unit.
if (this.mBuffer.charCodeAt(this.mOffset) == CARRIAGE_RETURN && if (
this.mOffset + 1 < this.mCount && this.mBuffer.charCodeAt(this.mOffset) == CARRIAGE_RETURN &&
this.mBuffer.charCodeAt(this.mOffset + 1) == LINE_FEED) { this.mOffset + 1 < this.mCount &&
this.mBuffer.charCodeAt(this.mOffset + 1) == LINE_FEED
) {
this.mOffset += 2; this.mOffset += 2;
} else { } else {
this.mOffset += 1; this.mOffset += 1;
@ -616,7 +745,8 @@ Scanner.prototype = {
SkipWhitespace: function() { SkipWhitespace: function() {
for (;;) { for (;;) {
const ch = this.Peek(); const ch = this.Peek();
if (!IsWhitespace(ch)) { // EOF counts as non-whitespace if (!IsWhitespace(ch)) {
// EOF counts as non-whitespace
break; break;
} }
if (IsVertSpace(ch)) { if (IsVertSpace(ch)) {
@ -760,8 +890,10 @@ Scanner.prototype = {
for (;;) { for (;;) {
// Consume runs of unescaped characters in one go. // Consume runs of unescaped characters in one go.
let n = this.mOffset; let n = this.mOffset;
while (n < this.mCount && IsOpenCharClass(this.mBuffer.charCodeAt(n), while (
aClass)) { n < this.mCount &&
IsOpenCharClass(this.mBuffer.charCodeAt(n), aClass)
) {
n++; n++;
} }
if (n > this.mOffset) { if (n > this.mOffset) {
@ -849,8 +981,9 @@ Scanner.prototype = {
const ch = this.Peek(); const ch = this.Peek();
if (IsIdentChar(ch) || ch == REVERSE_SOLIDUS) { if (IsIdentChar(ch) || ch == REVERSE_SOLIDUS) {
const type = const type = StartsIdent(ch, this.Peek(1))
StartsIdent(ch, this.Peek(1)) ? eCSSToken_ID : eCSSToken_Hash; ? eCSSToken_ID
: eCSSToken_Hash;
aToken.mIdent.length = 0; aToken.mIdent.length = 0;
if (this.GatherText(IS_IDCHAR, aToken.mIdent)) { if (this.GatherText(IS_IDCHAR, aToken.mIdent)) {
aToken.mType = type; aToken.mType = type;
@ -891,13 +1024,13 @@ Scanner.prototype = {
// Sign of the exponent. // Sign of the exponent.
let expSign = 1; let expSign = 1;
aToken.mHasSign = (c == PLUS_SIGN || c == HYPHEN_MINUS); aToken.mHasSign = c == PLUS_SIGN || c == HYPHEN_MINUS;
if (aToken.mHasSign) { if (aToken.mHasSign) {
this.Advance(); this.Advance();
c = this.Peek(); c = this.Peek();
} }
let gotDot = (c == FULL_STOP); let gotDot = c == FULL_STOP;
if (!gotDot) { if (!gotDot) {
// Scan the integer part of the mantissa. // Scan the integer part of the mantissa.
@ -907,7 +1040,7 @@ Scanner.prototype = {
c = this.Peek(); c = this.Peek();
} while (IsDigit(c)); } while (IsDigit(c));
gotDot = (c == FULL_STOP) && IsDigit(this.Peek(1)); gotDot = c == FULL_STOP && IsDigit(this.Peek(1));
} }
if (gotDot) { if (gotDot) {
@ -928,9 +1061,11 @@ Scanner.prototype = {
if (c == LATIN_SMALL_LETTER_E || c == LATIN_CAPITAL_LETTER_E) { if (c == LATIN_SMALL_LETTER_E || c == LATIN_CAPITAL_LETTER_E) {
const expSignChar = this.Peek(1); const expSignChar = this.Peek(1);
const nextChar = this.Peek(2); const nextChar = this.Peek(2);
if (IsDigit(expSignChar) || if (
((expSignChar == HYPHEN_MINUS || expSignChar == PLUS_SIGN) && IsDigit(expSignChar) ||
IsDigit(nextChar))) { ((expSignChar == HYPHEN_MINUS || expSignChar == PLUS_SIGN) &&
IsDigit(nextChar))
) {
gotE = true; gotE = true;
if (expSignChar == HYPHEN_MINUS) { if (expSignChar == HYPHEN_MINUS) {
expSign = -1; expSign = -1;
@ -1009,9 +1144,11 @@ Scanner.prototype = {
const ch = this.Peek(); const ch = this.Peek();
if (ch == -1) { if (ch == -1) {
this.AddEOFCharacters(aStop == QUOTATION_MARK ? this.AddEOFCharacters(
eEOFCharacters_DoubleQuote : aStop == QUOTATION_MARK
eEOFCharacters_SingleQuote); ? eEOFCharacters_DoubleQuote
: eEOFCharacters_SingleQuote
);
break; // EOF ends a string token with no error. break; // EOF ends a string token with no error.
} }
if (ch == aStop) { if (ch == aStop) {
@ -1073,7 +1210,7 @@ Scanner.prototype = {
} else { } else {
haveQues = true; haveQues = true;
low = low * 16 + 0x0; low = low * 16 + 0x0;
high = high * 16 + 0xF; high = high * 16 + 0xf;
} }
i++; i++;
@ -1219,8 +1356,10 @@ Scanner.prototype = {
aToken.mType = eCSSToken_Whitespace; aToken.mType = eCSSToken_Whitespace;
return true; return true;
} }
if (ch == SOLIDUS && // !IsSVGMode() && if (
this.Peek(1) == ASTERISK) { ch == SOLIDUS && // !IsSVGMode() &&
this.Peek(1) == ASTERISK
) {
this.SkipComment(); this.SkipComment();
aToken.mType = eCSSToken_Comment; aToken.mType = eCSSToken_Comment;
return true; return true;
@ -1282,10 +1421,12 @@ Scanner.prototype = {
} }
// the other HTML-comment token // the other HTML-comment token
if (ch == LESS_THAN_SIGN && if (
this.Peek(1) == EXCLAMATION_MARK && ch == LESS_THAN_SIGN &&
this.Peek(2) == HYPHEN_MINUS && this.Peek(1) == EXCLAMATION_MARK &&
this.Peek(3) == HYPHEN_MINUS) { this.Peek(2) == HYPHEN_MINUS &&
this.Peek(3) == HYPHEN_MINUS
) {
this.Advance(4); this.Advance(4);
aToken.mType = eCSSToken_HTMLComment; aToken.mType = eCSSToken_HTMLComment;
aToken.mIdent = stringToCodes("<!--"); aToken.mIdent = stringToCodes("<!--");

View file

@ -13,20 +13,25 @@
"use strict"; "use strict";
const {getCSSLexer} = require("devtools/shared/css/lexer"); const { getCSSLexer } = require("devtools/shared/css/lexer");
loader.lazyRequireGetter(this, "CSS_ANGLEUNIT", "devtools/shared/css/constants", true); loader.lazyRequireGetter(
this,
"CSS_ANGLEUNIT",
"devtools/shared/css/constants",
true
);
const SELECTOR_ATTRIBUTE = exports.SELECTOR_ATTRIBUTE = 1; const SELECTOR_ATTRIBUTE = (exports.SELECTOR_ATTRIBUTE = 1);
const SELECTOR_ELEMENT = exports.SELECTOR_ELEMENT = 2; const SELECTOR_ELEMENT = (exports.SELECTOR_ELEMENT = 2);
const SELECTOR_PSEUDO_CLASS = exports.SELECTOR_PSEUDO_CLASS = 3; const SELECTOR_PSEUDO_CLASS = (exports.SELECTOR_PSEUDO_CLASS = 3);
const CSS_BLOCKS = { "(": ")", "[": "]", "{": "}" }; const CSS_BLOCKS = { "(": ")", "[": "]", "{": "}" };
// When commenting out a declaration, we put this character into the // When commenting out a declaration, we put this character into the
// comment opener so that future parses of the commented text know to // comment opener so that future parses of the commented text know to
// bypass the property name validity heuristic. // bypass the property name validity heuristic.
const COMMENT_PARSING_HEURISTIC_BYPASS_CHAR = const COMMENT_PARSING_HEURISTIC_BYPASS_CHAR = (exports.COMMENT_PARSING_HEURISTIC_BYPASS_CHAR =
exports.COMMENT_PARSING_HEURISTIC_BYPASS_CHAR = "!"; "!");
/** /**
* A generator function that lexes a CSS source string, yielding the * A generator function that lexes a CSS source string, yielding the
@ -97,7 +102,7 @@ function cssTokenizerWithLineColumn(string) {
line: lineNumber, line: lineNumber,
column: columnNumber, column: columnNumber,
}; };
token.loc = {start: startLoc}; token.loc = { start: startLoc };
result.push(token); result.push(token);
prevToken = token; prevToken = token;
@ -153,8 +158,12 @@ function unescapeCSSComment(inputString) {
* @return {array} Array of declarations of the same form as returned * @return {array} Array of declarations of the same form as returned
* by parseDeclarations. * by parseDeclarations.
*/ */
function parseCommentDeclarations(isCssPropertyKnown, commentText, startOffset, function parseCommentDeclarations(
endOffset) { isCssPropertyKnown,
commentText,
startOffset,
endOffset
) {
let commentOverride = false; let commentOverride = false;
if (commentText === "") { if (commentText === "") {
return []; return [];
@ -210,8 +219,13 @@ function parseCommentDeclarations(isCssPropertyKnown, commentText, startOffset,
// seem worthwhile to support declarations in comments-in-comments // seem worthwhile to support declarations in comments-in-comments
// here, as there's no way to generate those using the tools, and // here, as there's no way to generate those using the tools, and
// users would be crazy to write such things. // users would be crazy to write such things.
const newDecls = parseDeclarationsInternal(isCssPropertyKnown, rewrittenText, const newDecls = parseDeclarationsInternal(
false, true, commentOverride); isCssPropertyKnown,
rewrittenText,
false,
true,
commentOverride
);
for (const decl of newDecls) { for (const decl of newDecls) {
decl.offsets[0] = rewrites[decl.offsets[0]]; decl.offsets[0] = rewrites[decl.offsets[0]];
decl.offsets[1] = rewrites[decl.offsets[1]]; decl.offsets[1] = rewrites[decl.offsets[1]];
@ -230,10 +244,14 @@ function parseCommentDeclarations(isCssPropertyKnown, commentText, startOffset,
* parseDeclarations * parseDeclarations
*/ */
function getEmptyDeclaration() { function getEmptyDeclaration() {
return {name: "", value: "", priority: "", return {
terminator: "", name: "",
offsets: [undefined, undefined], value: "",
colonOffsets: false}; priority: "",
terminator: "",
offsets: [undefined, undefined],
colonOffsets: false,
};
} }
/** /**
@ -269,8 +287,13 @@ function cssTrim(str) {
* heuristic. * heuristic.
*/ */
/* eslint-disable complexity */ /* eslint-disable complexity */
function parseDeclarationsInternal(isCssPropertyKnown, inputString, function parseDeclarationsInternal(
parseComments, inComment, commentOverride) { isCssPropertyKnown,
inputString,
parseComments,
inComment,
commentOverride
) {
if (inputString === null || inputString === undefined) { if (inputString === null || inputString === undefined) {
throw new Error("empty input string"); throw new Error("empty input string");
} }
@ -309,16 +332,23 @@ function parseDeclarationsInternal(isCssPropertyKnown, inputString,
lastProp.offsets[0] = token.startOffset; lastProp.offsets[0] = token.startOffset;
} }
lastProp.offsets[1] = token.endOffset; lastProp.offsets[1] = token.endOffset;
} else if (lastProp.name && !current && !importantState && } else if (
!lastProp.priority && lastProp.colonOffsets[1]) { lastProp.name &&
!current &&
!importantState &&
!lastProp.priority &&
lastProp.colonOffsets[1]
) {
// Whitespace appearing after the ":" is attributed to it. // Whitespace appearing after the ":" is attributed to it.
lastProp.colonOffsets[1] = token.endOffset; lastProp.colonOffsets[1] = token.endOffset;
} else if (importantState === 1) { } else if (importantState === 1) {
importantWS = true; importantWS = true;
} }
if (token.tokenType === "symbol" && if (
currentBlocks[currentBlocks.length - 1] === token.text) { token.tokenType === "symbol" &&
currentBlocks[currentBlocks.length - 1] === token.text
) {
// Closing the last block that was opened. // Closing the last block that was opened.
currentBlocks.pop(); currentBlocks.pop();
current += token.text; current += token.text;
@ -343,8 +373,11 @@ function parseDeclarationsInternal(isCssPropertyKnown, inputString,
// When parsing a comment body, if the left-hand-side is not a // When parsing a comment body, if the left-hand-side is not a
// valid property name, then drop it and stop parsing. // valid property name, then drop it and stop parsing.
if (inComment && !commentOverride && if (
!isCssPropertyKnown(lastProp.name)) { inComment &&
!commentOverride &&
!isCssPropertyKnown(lastProp.name)
) {
lastProp.name = null; lastProp.name = null;
break; break;
} }
@ -353,8 +386,11 @@ function parseDeclarationsInternal(isCssPropertyKnown, inputString,
// with colons) // with colons)
current += ":"; current += ":";
} }
} else if (token.tokenType === "symbol" && token.text === ";" && } else if (
!currentBlocks.length) { token.tokenType === "symbol" &&
token.text === ";" &&
!currentBlocks.length
) {
lastProp.terminator = ""; lastProp.terminator = "";
// When parsing a comment, if the name hasn't been set, then we // When parsing a comment, if the name hasn't been set, then we
// have probably just seen an ordinary semicolon used in text, // have probably just seen an ordinary semicolon used in text,
@ -406,11 +442,16 @@ function parseDeclarationsInternal(isCssPropertyKnown, inputString,
} }
} else if (token.tokenType === "comment") { } else if (token.tokenType === "comment") {
if (parseComments && !lastProp.name && !lastProp.value) { if (parseComments && !lastProp.name && !lastProp.value) {
const commentText = inputString.substring(token.startOffset + 2, const commentText = inputString.substring(
token.endOffset - 2); token.startOffset + 2,
const newDecls = parseCommentDeclarations(isCssPropertyKnown, commentText, token.endOffset - 2
token.startOffset, );
token.endOffset); const newDecls = parseCommentDeclarations(
isCssPropertyKnown,
commentText,
token.startOffset,
token.endOffset
);
// Insert the new declarations just before the final element. // Insert the new declarations just before the final element.
const lastDecl = declarations.pop(); const lastDecl = declarations.pop();
@ -505,20 +546,34 @@ function parseDeclarationsInternal(isCssPropertyKnown, inputString,
* on the object, which will hold the offsets of the start * on the object, which will hold the offsets of the start
* and end of the enclosing comment. * and end of the enclosing comment.
*/ */
function parseDeclarations(isCssPropertyKnown, inputString, function parseDeclarations(
parseComments = false) { isCssPropertyKnown,
return parseDeclarationsInternal(isCssPropertyKnown, inputString, inputString,
parseComments, false, false); parseComments = false
) {
return parseDeclarationsInternal(
isCssPropertyKnown,
inputString,
parseComments,
false,
false
);
} }
/** /**
* Like @see parseDeclarations, but removes properties that do not * Like @see parseDeclarations, but removes properties that do not
* have a name. * have a name.
*/ */
function parseNamedDeclarations(isCssPropertyKnown, inputString, function parseNamedDeclarations(
parseComments = false) { isCssPropertyKnown,
return parseDeclarations(isCssPropertyKnown, inputString, parseComments) inputString,
.filter(item => !!item.name); parseComments = false
) {
return parseDeclarations(
isCssPropertyKnown,
inputString,
parseComments
).filter(item => !!item.name);
} }
/** /**
@ -640,8 +695,10 @@ function parsePseudoClassesAndAttributes(value) {
* @return {Object} an object with 'value' and 'priority' properties. * @return {Object} an object with 'value' and 'priority' properties.
*/ */
function parseSingleValue(isCssPropertyKnown, value) { function parseSingleValue(isCssPropertyKnown, value) {
const declaration = parseDeclarations(isCssPropertyKnown, const declaration = parseDeclarations(
"a: " + value + ";")[0]; isCssPropertyKnown,
"a: " + value + ";"
)[0];
return { return {
value: declaration ? declaration.value : "", value: declaration ? declaration.value : "",
priority: declaration ? declaration.priority : "", priority: declaration ? declaration.priority : "",
@ -662,7 +719,7 @@ function getAngleValueInDegrees(angleValue, angleUnit) {
case CSS_ANGLEUNIT.grad: case CSS_ANGLEUNIT.grad:
return angleValue * 0.9; return angleValue * 0.9;
case CSS_ANGLEUNIT.rad: case CSS_ANGLEUNIT.rad:
return angleValue * 180 / Math.PI; return (angleValue * 180) / Math.PI;
case CSS_ANGLEUNIT.turn: case CSS_ANGLEUNIT.turn:
return angleValue * 360; return angleValue * 360;
default: default:

View file

@ -17,8 +17,11 @@ let db;
try { try {
db = require("devtools/shared/css/generated/properties-db"); db = require("devtools/shared/css/generated/properties-db");
} catch (error) { } catch (error) {
console.error(`If this error is being displayed and "mach devtools-css-db" is not ` + console.error(
`being run, then it needs to be fixed.`, error); `If this error is being displayed and "mach devtools-css-db" is not ` +
`being run, then it needs to be fixed.`,
error
);
db = { db = {
CSS_PROPERTIES: {}, CSS_PROPERTIES: {},
PSEUDO_ELEMENTS: [], PSEUDO_ELEMENTS: [],

View file

@ -35,9 +35,11 @@ const { Cu, CC, Cc, Ci } = require("chrome");
const EventEmitter = require("devtools/shared/event-emitter"); const EventEmitter = require("devtools/shared/event-emitter");
const Services = require("Services"); const Services = require("Services");
const UDPSocket = CC("@mozilla.org/network/udp-socket;1", const UDPSocket = CC(
"nsIUDPSocket", "@mozilla.org/network/udp-socket;1",
"init"); "nsIUDPSocket",
"init"
);
const SCAN_PORT = 50624; const SCAN_PORT = 50624;
const UPDATE_PORT = 50625; const UPDATE_PORT = 50625;
@ -47,8 +49,9 @@ const REPLY_TIMEOUT = 5000;
const { XPCOMUtils } = require("resource://gre/modules/XPCOMUtils.jsm"); const { XPCOMUtils } = require("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyGetter(this, "converter", () => { XPCOMUtils.defineLazyGetter(this, "converter", () => {
const conv = Cc["@mozilla.org/intl/scriptableunicodeconverter"] const conv = Cc[
.createInstance(Ci.nsIScriptableUnicodeConverter); "@mozilla.org/intl/scriptableunicodeconverter"
].createInstance(Ci.nsIScriptableUnicodeConverter);
conv.charset = "utf8"; conv.charset = "utf8";
return conv; return conv;
}); });
@ -72,8 +75,11 @@ function log(msg) {
function Transport(port) { function Transport(port) {
EventEmitter.decorate(this); EventEmitter.decorate(this);
try { try {
this.socket = new UDPSocket(port, false, this.socket = new UDPSocket(
Services.scriptSecurityManager.getSystemPrincipal()); port,
false,
Services.scriptSecurityManager.getSystemPrincipal()
);
this.socket.joinMulticast(ADDRESS); this.socket.joinMulticast(ADDRESS);
this.socket.asyncListen(this); this.socket.asyncListen(this);
} catch (e) { } catch (e) {
@ -82,7 +88,6 @@ function Transport(port) {
} }
Transport.prototype = { Transport.prototype = {
/** /**
* Send a object to some UDP port. * Send a object to some UDP port.
* @param object object * @param object object
@ -119,14 +124,14 @@ Transport.prototype = {
return; return;
} }
if (logging) { if (logging) {
log("Recv on " + this.socket.port + ":\n" + log(
JSON.stringify(object, null, 2)); "Recv on " + this.socket.port + ":\n" + JSON.stringify(object, null, 2)
);
} }
this.emit("message", object); this.emit("message", object);
}, },
onStopListening: function() {}, onStopListening: function() {},
}; };
/** /**
@ -143,7 +148,6 @@ function LocalDevice() {
LocalDevice.UNKNOWN = "unknown"; LocalDevice.UNKNOWN = "unknown";
LocalDevice.prototype = { LocalDevice.prototype = {
_get: function() { _get: function() {
// Without Settings API, just generate a name and stop, since the value // Without Settings API, just generate a name and stop, since the value
// can't be persisted. // can't be persisted.
@ -160,8 +164,9 @@ LocalDevice.prototype = {
// TODO: Bug 1180997: Find the right way to expose an editable name // TODO: Bug 1180997: Find the right way to expose an editable name
this.name = sysInfo.get("device"); this.name = sysInfo.get("device");
} else { } else {
this.name = Cc["@mozilla.org/network/dns-service;1"].getService(Ci.nsIDNSService) this.name = Cc["@mozilla.org/network/dns-service;1"].getService(
.myHostName; Ci.nsIDNSService
).myHostName;
} }
}, },
@ -173,7 +178,6 @@ LocalDevice.prototype = {
this._name = name; this._name = name;
log("Device: " + this._name); log("Device: " + this._name);
}, },
}; };
function Discovery() { function Discovery() {
@ -201,7 +205,6 @@ function Discovery() {
} }
Discovery.prototype = { Discovery.prototype = {
/** /**
* Add a new service offered by this device. * Add a new service offered by this device.
* @param service string * @param service string
@ -272,8 +275,10 @@ Discovery.prototype = {
_waitForReplies: function() { _waitForReplies: function() {
clearTimeout(this._expectingReplies.timer); clearTimeout(this._expectingReplies.timer);
this._expectingReplies.from = new Set(this.getRemoteDevices()); this._expectingReplies.from = new Set(this.getRemoteDevices());
this._expectingReplies.timer = this._expectingReplies.timer = setTimeout(
setTimeout(this._purgeMissingDevices, this.replyTimeout); this._purgeMissingDevices,
this.replyTimeout
);
}, },
get Transport() { get Transport() {
@ -385,8 +390,9 @@ Discovery.prototype = {
// Second, loop over the services in the received update // Second, loop over the services in the received update
for (const service in update.services) { for (const service in update.services) {
// Detect if this is a new device for this service // Detect if this is a new device for this service
const newDevice = !this.remoteServices[service] || const newDevice =
!this.remoteServices[service][remoteDevice]; !this.remoteServices[service] ||
!this.remoteServices[service][remoteDevice];
// Look up the service info we may have received previously from the same // Look up the service info we may have received previously from the same
// remote device // remote device
@ -407,8 +413,10 @@ Discovery.prototype = {
// If we've seen this service from the remote device, but the details have // If we've seen this service from the remote device, but the details have
// changed, announce the update // changed, announce the update
if (!newDevice && if (
JSON.stringify(oldDeviceInfo) != JSON.stringify(newDeviceInfo)) { !newDevice &&
JSON.stringify(oldDeviceInfo) != JSON.stringify(newDeviceInfo)
) {
log("UPDATED " + service + ", DEVICE " + remoteDevice); log("UPDATED " + service + ", DEVICE " + remoteDevice);
this.emit(service + "-device-updated", remoteDevice, newDeviceInfo); this.emit(service + "-device-updated", remoteDevice, newDeviceInfo);
} }
@ -430,7 +438,6 @@ Discovery.prototype = {
} }
} }
}, },
}; };
var discovery = new Discovery(); var discovery = new Discovery();

View file

@ -4,13 +4,14 @@
"use strict"; "use strict";
const { require } = const { require } = ChromeUtils.import("resource://devtools/shared/Loader.jsm");
ChromeUtils.import("resource://devtools/shared/Loader.jsm");
const Services = require("Services"); const Services = require("Services");
const defer = require("devtools/shared/defer"); const defer = require("devtools/shared/defer");
const EventEmitter = require("devtools/shared/event-emitter"); const EventEmitter = require("devtools/shared/event-emitter");
const discovery = require("devtools/shared/discovery/discovery"); const discovery = require("devtools/shared/discovery/discovery");
const { setTimeout, clearTimeout } = ChromeUtils.import("resource://gre/modules/Timer.jsm"); const { setTimeout, clearTimeout } = ChromeUtils.import(
"resource://gre/modules/Timer.jsm"
);
Services.prefs.setBoolPref("devtools.discovery.log", true); Services.prefs.setBoolPref("devtools.discovery.log", true);
@ -36,7 +37,6 @@ function TestTransport(port) {
} }
TestTransport.prototype = { TestTransport.prototype = {
send: function(object, port) { send: function(object, port) {
log("Send to " + port + ":\n" + JSON.stringify(object, null, 2)); log("Send to " + port + ":\n" + JSON.stringify(object, null, 2));
if (!gTestTransports[port]) { if (!gTestTransports[port]) {
@ -61,7 +61,6 @@ TestTransport.prototype = {
}, },
onStopListening: function(socket, status) {}, onStopListening: function(socket, status) {},
}; };
// Use TestTransport instead of the usual Transport // Use TestTransport instead of the usual Transport
@ -104,10 +103,14 @@ add_task(async function() {
deepEqual(discovery.getRemoteDevicesWithService("penguins"), ["test-device"]); deepEqual(discovery.getRemoteDevicesWithService("penguins"), ["test-device"]);
deepEqual(discovery.getRemoteDevices(), ["test-device"]); deepEqual(discovery.getRemoteDevices(), ["test-device"]);
deepEqual(discovery.getRemoteService("devtools", "test-device"), deepEqual(discovery.getRemoteService("devtools", "test-device"), {
{ port: 1234, host: "localhost" }); port: 1234,
deepEqual(discovery.getRemoteService("penguins", "test-device"), host: "localhost",
{ tux: true, host: "localhost" }); });
deepEqual(discovery.getRemoteService("penguins", "test-device"), {
tux: true,
host: "localhost",
});
discovery.removeService("devtools"); discovery.removeService("devtools");
await scanForChange("devtools", "removed"); await scanForChange("devtools", "removed");

View file

@ -5,7 +5,7 @@ module.exports = {
FILTER_REJECT: 2, FILTER_REJECT: 2,
FILTER_SKIP: 3, FILTER_SKIP: 3,
SHOW_ALL: 0xFFFFFFFF, SHOW_ALL: 0xffffffff,
SHOW_ELEMENT: 0x00000001, SHOW_ELEMENT: 0x00000001,
SHOW_ATTRIBUTE: 0x00000002, SHOW_ATTRIBUTE: 0x00000002,
SHOW_TEXT: 0x00000004, SHOW_TEXT: 0x00000004,

View file

@ -4,8 +4,9 @@
"use strict"; "use strict";
const BAD_LISTENER = "The event listener must be a function, or an object that has " + const BAD_LISTENER =
"`EventEmitter.handler` Symbol."; "The event listener must be a function, or an object that has " +
"`EventEmitter.handler` Symbol.";
const eventListeners = Symbol("EventEmitter/listeners"); const eventListeners = Symbol("EventEmitter/listeners");
const onceOriginalListener = Symbol("EventEmitter/once-original-listener"); const onceOriginalListener = Symbol("EventEmitter/once-original-listener");
@ -85,7 +86,10 @@ class EventEmitter {
// So we iterate all the listeners to check if any of them is a wrapper to // So we iterate all the listeners to check if any of them is a wrapper to
// the `listener` given. // the `listener` given.
for (const value of listenersForType.values()) { for (const value of listenersForType.values()) {
if (onceOriginalListener in value && value[onceOriginalListener] === listener) { if (
onceOriginalListener in value &&
value[onceOriginalListener] === listener
) {
listenersForType.delete(value); listenersForType.delete(value);
break; break;
} }
@ -270,7 +274,7 @@ class EventEmitter {
module.exports = EventEmitter; module.exports = EventEmitter;
const isEventHandler = (listener) => const isEventHandler = listener =>
listener && handler in listener && typeof listener[handler] === "function"; listener && handler in listener && typeof listener[handler] === "function";
const Services = require("Services"); const Services = require("Services");
@ -299,8 +303,7 @@ function serialize(target) {
} }
// Number / String // Number / String
if (typeof target === "string" || if (typeof target === "string" || typeof target === "number") {
typeof target === "number") {
return truncate(target, MAXLEN); return truncate(target, MAXLEN);
} }
@ -329,9 +332,11 @@ function serialize(target) {
} }
// Window // Window
if (target.constructor && if (
target.constructor.name && target.constructor &&
target.constructor.name === "Window") { target.constructor.name &&
target.constructor.name === "Window"
) {
return `window (${target.location.origin})`; return `window (${target.location.origin})`;
} }

View file

@ -110,10 +110,12 @@ function pointEquals(pointA, pointB) {
// Return whether two breakpoint positions are the same. // Return whether two breakpoint positions are the same.
function positionEquals(posA, posB) { function positionEquals(posA, posB) {
return posA.kind == posB.kind return (
&& posA.script == posB.script posA.kind == posB.kind &&
&& posA.offset == posB.offset posA.script == posB.script &&
&& posA.frameIndex == posB.frameIndex; posA.offset == posB.offset &&
posA.frameIndex == posB.frameIndex
);
} }
// Return whether an execution point matching posB also matches posA. // Return whether an execution point matching posB also matches posA.
@ -123,8 +125,12 @@ function positionSubsumes(posA, posB) {
return true; return true;
} }
if (posA.kind == "Break" && posB.kind == "OnStep" && if (
posA.script == posB.script && posA.offset == posB.offset) { posA.kind == "Break" &&
posB.kind == "OnStep" &&
posA.script == posB.script &&
posA.offset == posB.offset
) {
return true; return true;
} }

View file

@ -5,13 +5,18 @@
const { components } = require("chrome"); const { components } = require("chrome");
const Services = require("Services"); const Services = require("Services");
const { actorActorSpec, actorRegistrySpec } = require("devtools/shared/specs/actor-registry"); const {
const { FrontClassWithSpec, registerFront } = require("devtools/shared/protocol"); actorActorSpec,
actorRegistrySpec,
} = require("devtools/shared/specs/actor-registry");
const {
FrontClassWithSpec,
registerFront,
} = require("devtools/shared/protocol");
loader.lazyImporter(this, "NetUtil", "resource://gre/modules/NetUtil.jsm"); loader.lazyImporter(this, "NetUtil", "resource://gre/modules/NetUtil.jsm");
class ActorActorFront extends FrontClassWithSpec(actorActorSpec) { class ActorActorFront extends FrontClassWithSpec(actorActorSpec) {}
}
exports.ActorActorFront = ActorActorFront; exports.ActorActorFront = ActorActorFront;
registerFront(ActorActorFront); registerFront(ActorActorFront);
@ -24,22 +29,32 @@ function request(uri) {
reject(e); reject(e);
} }
NetUtil.asyncFetch({ NetUtil.asyncFetch(
uri, {
loadUsingSystemPrincipal: true, uri,
}, (stream, status, req) => { loadUsingSystemPrincipal: true,
if (!components.isSuccessCode(status)) { },
reject(new Error("Request failed with status code = " (stream, status, req) => {
+ status if (!components.isSuccessCode(status)) {
+ " after NetUtil.asyncFetch for url = " reject(
+ uri)); new Error(
return; "Request failed with status code = " +
} status +
" after NetUtil.asyncFetch for url = " +
uri
)
);
return;
}
const source = NetUtil.readInputStreamToString(stream, stream.available()); const source = NetUtil.readInputStreamToString(
stream.close(); stream,
resolve(source); stream.available()
}); );
stream.close();
resolve(source);
}
);
}); });
} }
@ -52,10 +67,9 @@ class ActorRegistryFront extends FrontClassWithSpec(actorRegistrySpec) {
} }
registerActor(uri, options) { registerActor(uri, options) {
return request(uri, options) return request(uri, options).then(sourceText => {
.then(sourceText => { return super.registerActor(sourceText, uri, options);
return super.registerActor(sourceText, uri, options); });
});
} }
} }

View file

@ -3,8 +3,11 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict"; "use strict";
const {addonsSpec} = require("devtools/shared/specs/addon/addons"); const { addonsSpec } = require("devtools/shared/specs/addon/addons");
const { FrontClassWithSpec, registerFront } = require("devtools/shared/protocol"); const {
FrontClassWithSpec,
registerFront,
} = require("devtools/shared/protocol");
class AddonsFront extends FrontClassWithSpec(addonsSpec) { class AddonsFront extends FrontClassWithSpec(addonsSpec) {
constructor(client) { constructor(client) {

View file

@ -7,13 +7,17 @@ const {
webExtensionInspectedWindowSpec, webExtensionInspectedWindowSpec,
} = require("devtools/shared/specs/addon/webextension-inspected-window"); } = require("devtools/shared/specs/addon/webextension-inspected-window");
const { FrontClassWithSpec, registerFront } = require("devtools/shared/protocol"); const {
FrontClassWithSpec,
registerFront,
} = require("devtools/shared/protocol");
/** /**
* The corresponding Front object for the WebExtensionInspectedWindowActor. * The corresponding Front object for the WebExtensionInspectedWindowActor.
*/ */
class WebExtensionInspectedWindowFront extends class WebExtensionInspectedWindowFront extends FrontClassWithSpec(
FrontClassWithSpec(webExtensionInspectedWindowSpec) { webExtensionInspectedWindowSpec
) {
constructor(client) { constructor(client) {
super(client); super(client);

View file

@ -72,7 +72,7 @@ class AnimationPlayerFront extends FrontClassWithSpec(animationPlayerSpec) {
* update the local knowledge of the state. * update the local knowledge of the state.
*/ */
onChanged(partialState) { onChanged(partialState) {
const {state} = this.reconstructState(partialState); const { state } = this.reconstructState(partialState);
this.state = state; this.state = state;
} }
@ -94,7 +94,7 @@ class AnimationPlayerFront extends FrontClassWithSpec(animationPlayerSpec) {
getCurrentState() { getCurrentState() {
this.currentStateHasChanged = false; this.currentStateHasChanged = false;
return super.getCurrentState().then(partialData => { return super.getCurrentState().then(partialData => {
const {state, hasChanged} = this.reconstructState(partialData); const { state, hasChanged } = this.reconstructState(partialData);
this.currentStateHasChanged = hasChanged; this.currentStateHasChanged = hasChanged;
return state; return state;
}); });
@ -112,7 +112,7 @@ class AnimationPlayerFront extends FrontClassWithSpec(animationPlayerSpec) {
} }
data.absoluteValues = this.calculateAbsoluteValues(data); data.absoluteValues = this.calculateAbsoluteValues(data);
return {state: data, hasChanged}; return { state: data, hasChanged };
} }
calculateAbsoluteValues(data) { calculateAbsoluteValues(data) {
@ -155,22 +155,28 @@ class AnimationPlayerFront extends FrontClassWithSpec(animationPlayerSpec) {
// the graph duration as double of the delay amount. In case of no delay, handle // the graph duration as double of the delay amount. In case of no delay, handle
// the duration as 1ms which is short enough so as to make the scrubber movable // the duration as 1ms which is short enough so as to make the scrubber movable
// and the limited duration is prioritized. // and the limited duration is prioritized.
endTime = (absoluteDelay > 0 ? absoluteDelay * 2 : 1); endTime = absoluteDelay > 0 ? absoluteDelay * 2 : 1;
} else { } else {
endTime = absoluteDelay + endTime =
toRate(duration * (iterationCount || 1)) + absoluteDelay +
absoluteEndDelay; toRate(duration * (iterationCount || 1)) +
absoluteEndDelay;
} }
const absoluteCreatedTime = const absoluteCreatedTime = isPositivePlaybackRate
isPositivePlaybackRate ? createdTime : createdTime - endTime; ? createdTime
const absoluteCurrentTimeAtCreated = : createdTime - endTime;
isPositivePlaybackRate ? currentTimeAtCreated : endTime - currentTimeAtCreated; const absoluteCurrentTimeAtCreated = isPositivePlaybackRate
const animationCurrentTime = ? currentTimeAtCreated
isPositivePlaybackRate ? currentTime : endTime - currentTime; : endTime - currentTimeAtCreated;
const absoluteCurrentTime = absoluteCreatedTime + toRate(animationCurrentTime); const animationCurrentTime = isPositivePlaybackRate
? currentTime
: endTime - currentTime;
const absoluteCurrentTime =
absoluteCreatedTime + toRate(animationCurrentTime);
const absoluteStartTime = absoluteCreatedTime + Math.min(absoluteDelay, 0); const absoluteStartTime = absoluteCreatedTime + Math.min(absoluteDelay, 0);
const absoluteStartTimeAtCreated = absoluteCreatedTime + absoluteCurrentTimeAtCreated; const absoluteStartTimeAtCreated =
absoluteCreatedTime + absoluteCurrentTimeAtCreated;
// To show whole graph with endDelay, we add negative endDelay amount to endTime. // To show whole graph with endDelay, we add negative endDelay amount to endTime.
const endTimeWithNegativeEndDelay = endTime - Math.min(absoluteEndDelay, 0); const endTimeWithNegativeEndDelay = endTime - Math.min(absoluteEndDelay, 0);
const absoluteEndTime = absoluteCreatedTime + endTimeWithNegativeEndDelay; const absoluteEndTime = absoluteCreatedTime + endTimeWithNegativeEndDelay;

View file

@ -5,7 +5,10 @@
"use strict"; "use strict";
const { arrayBufferSpec } = require("devtools/shared/specs/array-buffer"); const { arrayBufferSpec } = require("devtools/shared/specs/array-buffer");
const { FrontClassWithSpec, registerFront } = require("devtools/shared/protocol"); const {
FrontClassWithSpec,
registerFront,
} = require("devtools/shared/protocol");
/** /**
* A ArrayBufferClient provides a way to access ArrayBuffer from the * A ArrayBufferClient provides a way to access ArrayBuffer from the

View file

@ -4,8 +4,11 @@
"use strict"; "use strict";
const { FrontClassWithSpec, registerFront } = require("devtools/shared/protocol"); const {
const {changesSpec} = require("devtools/shared/specs/changes"); FrontClassWithSpec,
registerFront,
} = require("devtools/shared/protocol");
const { changesSpec } = require("devtools/shared/specs/changes");
/** /**
* ChangesFront, the front object for the ChangesActor * ChangesFront, the front object for the ChangesActor

View file

@ -3,13 +3,24 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict"; "use strict";
loader.lazyRequireGetter(this, "CSS_PROPERTIES_DB", loader.lazyRequireGetter(
"devtools/shared/css/properties-db", true); this,
"CSS_PROPERTIES_DB",
"devtools/shared/css/properties-db",
true
);
loader.lazyRequireGetter(this, "cssColors", loader.lazyRequireGetter(
"devtools/shared/css/color-db", true); this,
"cssColors",
"devtools/shared/css/color-db",
true
);
const { FrontClassWithSpec, registerFront } = require("devtools/shared/protocol"); const {
FrontClassWithSpec,
registerFront,
} = require("devtools/shared/protocol");
const { cssPropertiesSpec } = require("devtools/shared/specs/css-properties"); const { cssPropertiesSpec } = require("devtools/shared/specs/css-properties");
/** /**
@ -22,10 +33,17 @@ var NON_ASCII = "[^\\x00-\\x7F]";
var ESCAPE = "\\\\[^\n\r]"; var ESCAPE = "\\\\[^\n\r]";
var FIRST_CHAR = ["[_a-z]", NON_ASCII, ESCAPE].join("|"); var FIRST_CHAR = ["[_a-z]", NON_ASCII, ESCAPE].join("|");
var TRAILING_CHAR = ["[_a-z0-9-]", NON_ASCII, ESCAPE].join("|"); var TRAILING_CHAR = ["[_a-z0-9-]", NON_ASCII, ESCAPE].join("|");
var IS_VARIABLE_TOKEN = new RegExp(`^--(${FIRST_CHAR})(${TRAILING_CHAR})*$`, var IS_VARIABLE_TOKEN = new RegExp(
"i"); `^--(${FIRST_CHAR})(${TRAILING_CHAR})*$`,
"i"
);
loader.lazyRequireGetter(this, "CSS_TYPES", "devtools/shared/css/constants", true); loader.lazyRequireGetter(
this,
"CSS_TYPES",
"devtools/shared/css/constants",
true
);
/** /**
* Check that this is a CSS variable. * Check that this is a CSS variable.
@ -85,15 +103,18 @@ function CssProperties(db) {
this.pseudoElements = db.pseudoElements; this.pseudoElements = db.pseudoElements;
// supported feature // supported feature
this.cssColor4ColorFunction = hasFeature(db.supportedFeature, this.cssColor4ColorFunction = hasFeature(
"css-color-4-color-function"); db.supportedFeature,
"css-color-4-color-function"
);
this.isKnown = this.isKnown.bind(this); this.isKnown = this.isKnown.bind(this);
this.isInherited = this.isInherited.bind(this); this.isInherited = this.isInherited.bind(this);
this.supportsType = this.supportsType.bind(this); this.supportsType = this.supportsType.bind(this);
this.isValidOnClient = this.isValidOnClient.bind(this); this.isValidOnClient = this.isValidOnClient.bind(this);
this.supportsCssColor4ColorFunction = this.supportsCssColor4ColorFunction = this.supportsCssColor4ColorFunction.bind(
this.supportsCssColor4ColorFunction.bind(this); this
);
// A weakly held dummy HTMLDivElement to test CSS properties on the client. // A weakly held dummy HTMLDivElement to test CSS properties on the client.
this._dummyElements = new WeakMap(); this._dummyElements = new WeakMap();
@ -159,8 +180,10 @@ CssProperties.prototype = {
* @return {Boolean} * @return {Boolean}
*/ */
isInherited(property) { isInherited(property) {
return (this.properties[property] && this.properties[property].isInherited) || return (
isCssVariable(property); (this.properties[property] && this.properties[property].isInherited) ||
isCssVariable(property)
);
}, },
/** /**
@ -172,9 +195,11 @@ CssProperties.prototype = {
*/ */
supportsType(property, type) { supportsType(property, type) {
const id = CSS_TYPES[type]; const id = CSS_TYPES[type];
return this.properties[property] && return (
this.properties[property] &&
(this.properties[property].supports.includes(type) || (this.properties[property].supports.includes(type) ||
this.properties[property].supports.includes(id)); this.properties[property].supports.includes(id))
);
}, },
/** /**
@ -249,8 +274,8 @@ const initCssProperties = async function(toolbox) {
const db = await front.getCSSDatabase(); const db = await front.getCSSDatabase();
const cssProperties = new CssProperties(normalizeCssData(db)); const cssProperties = new CssProperties(normalizeCssData(db));
cachedCssProperties.set(client, {cssProperties, front}); cachedCssProperties.set(client, { cssProperties, front });
return {cssProperties, front}; return { cssProperties, front };
}; };
/** /**
@ -261,9 +286,11 @@ const initCssProperties = async function(toolbox) {
*/ */
function getCssProperties(toolbox) { function getCssProperties(toolbox) {
if (!cachedCssProperties.has(toolbox.target.client)) { if (!cachedCssProperties.has(toolbox.target.client)) {
throw new Error("The CSS database has not been initialized, please make " + throw new Error(
"sure initCssDatabase was called once before for this " + "The CSS database has not been initialized, please make " +
"toolbox."); "sure initCssDatabase was called once before for this " +
"toolbox."
);
} }
return cachedCssProperties.get(toolbox.target.client).cssProperties; return cachedCssProperties.get(toolbox.target.client).cssProperties;
} }
@ -289,7 +316,7 @@ function normalizeCssData(db) {
// If there is a `from` attributes, it means that it comes from RDP // If there is a `from` attributes, it means that it comes from RDP
// and it is not the client CSS_PROPERTIES_DB object. // and it is not the client CSS_PROPERTIES_DB object.
// (prevent comparing to CSS_PROPERTIES_DB to avoid loading client database) // (prevent comparing to CSS_PROPERTIES_DB to avoid loading client database)
if (typeof (db.from) == "string") { if (typeof db.from == "string") {
// Firefox 49's getCSSDatabase() just returned the properties object, but // Firefox 49's getCSSDatabase() just returned the properties object, but
// now it returns an object with multiple types of CSS information. // now it returns an object with multiple types of CSS information.
if (!db.properties) { if (!db.properties) {
@ -301,7 +328,10 @@ function normalizeCssData(db) {
const missingSubproperties = !db.properties.background.subproperties; const missingSubproperties = !db.properties.background.subproperties;
const missingIsInherited = !db.properties.font.isInherited; const missingIsInherited = !db.properties.font.isInherited;
const missingSomething = missingSupports || missingValues || missingSubproperties || const missingSomething =
missingSupports ||
missingValues ||
missingSubproperties ||
missingIsInherited; missingIsInherited;
if (missingSomething) { if (missingSomething) {
@ -313,11 +343,13 @@ function normalizeCssData(db) {
// Add "supports" information to the css properties if it's missing. // Add "supports" information to the css properties if it's missing.
if (missingSupports) { if (missingSupports) {
db.properties[name].supports = CSS_PROPERTIES_DB.properties[name].supports; db.properties[name].supports =
CSS_PROPERTIES_DB.properties[name].supports;
} }
// Add "values" information to the css properties if it's missing. // Add "values" information to the css properties if it's missing.
if (missingValues) { if (missingValues) {
db.properties[name].values = CSS_PROPERTIES_DB.properties[name].values; db.properties[name].values =
CSS_PROPERTIES_DB.properties[name].values;
} }
// Add "subproperties" information to the css properties if it's missing. // Add "subproperties" information to the css properties if it's missing.
if (missingSubproperties) { if (missingSubproperties) {

View file

@ -3,9 +3,12 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict"; "use strict";
const {Cu} = require("chrome"); const { Cu } = require("chrome");
const {deviceSpec} = require("devtools/shared/specs/device"); const { deviceSpec } = require("devtools/shared/specs/device");
const { FrontClassWithSpec, registerFront } = require("devtools/shared/protocol"); const {
FrontClassWithSpec,
registerFront,
} = require("devtools/shared/protocol");
const defer = require("devtools/shared/defer"); const defer = require("devtools/shared/defer");
class DeviceFront extends FrontClassWithSpec(deviceSpec) { class DeviceFront extends FrontClassWithSpec(deviceSpec) {

View file

@ -3,7 +3,10 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict"; "use strict";
const { FrontClassWithSpec, registerFront } = require("devtools/shared/protocol"); const {
FrontClassWithSpec,
registerFront,
} = require("devtools/shared/protocol");
const { emulationSpec } = require("devtools/shared/specs/emulation"); const { emulationSpec } = require("devtools/shared/specs/emulation");
/** /**

View file

@ -3,7 +3,10 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict"; "use strict";
const { FrontClassWithSpec, registerFront } = require("devtools/shared/protocol"); const {
FrontClassWithSpec,
registerFront,
} = require("devtools/shared/protocol");
const { framerateSpec } = require("devtools/shared/specs/framerate"); const { framerateSpec } = require("devtools/shared/specs/framerate");
/** /**

View file

@ -3,7 +3,10 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict"; "use strict";
const { FrontClassWithSpec, registerFront } = require("devtools/shared/protocol"); const {
FrontClassWithSpec,
registerFront,
} = require("devtools/shared/protocol");
const flags = require("devtools/shared/flags"); const flags = require("devtools/shared/flags");
const { const {
customHighlighterSpec, customHighlighterSpec,

View file

@ -7,8 +7,10 @@ const Telemetry = require("devtools/client/shared/telemetry");
const telemetry = new Telemetry(); const telemetry = new Telemetry();
const { NodePicker } = require("devtools/shared/fronts/inspector/node-picker"); const { NodePicker } = require("devtools/shared/fronts/inspector/node-picker");
const TELEMETRY_EYEDROPPER_OPENED = "DEVTOOLS_EYEDROPPER_OPENED_COUNT"; const TELEMETRY_EYEDROPPER_OPENED = "DEVTOOLS_EYEDROPPER_OPENED_COUNT";
const TELEMETRY_EYEDROPPER_OPENED_MENU = "DEVTOOLS_MENU_EYEDROPPER_OPENED_COUNT"; const TELEMETRY_EYEDROPPER_OPENED_MENU =
const SHOW_ALL_ANONYMOUS_CONTENT_PREF = "devtools.inspector.showAllAnonymousContent"; "DEVTOOLS_MENU_EYEDROPPER_OPENED_COUNT";
const SHOW_ALL_ANONYMOUS_CONTENT_PREF =
"devtools.inspector.showAllAnonymousContent";
const SHOW_UA_SHADOW_ROOTS_PREF = "devtools.inspector.showUserAgentShadowRoots"; const SHOW_UA_SHADOW_ROOTS_PREF = "devtools.inspector.showUserAgentShadowRoots";
const { const {
@ -23,12 +25,18 @@ const {
const Services = require("Services"); const Services = require("Services");
const defer = require("devtools/shared/defer"); const defer = require("devtools/shared/defer");
loader.lazyRequireGetter(this, "nodeConstants", loader.lazyRequireGetter(
"devtools/shared/dom-node-constants"); this,
loader.lazyRequireGetter(this, "Selection", "nodeConstants",
"devtools/client/framework/selection", true); "devtools/shared/dom-node-constants"
loader.lazyRequireGetter(this, "flags", );
"devtools/shared/flags"); loader.lazyRequireGetter(
this,
"Selection",
"devtools/client/framework/selection",
true
);
loader.lazyRequireGetter(this, "flags", "devtools/shared/flags");
/** /**
* Client side of the DOM walker. * Client side of the DOM walker.
@ -163,7 +171,9 @@ class WalkerFront extends FrontClassWithSpec(walkerSpec) {
const response = await this.getNodeActorFromObjectActor(grip.actor); const response = await this.getNodeActorFromObjectActor(grip.actor);
const nodeFront = response ? response.node : null; const nodeFront = response ? response.node : null;
if (!nodeFront) { if (!nodeFront) {
throw new Error("The ValueGrip passed could not be translated to a NodeFront"); throw new Error(
"The ValueGrip passed could not be translated to a NodeFront"
);
} }
return nodeFront; return nodeFront;
} }
@ -197,8 +207,8 @@ class WalkerFront extends FrontClassWithSpec(walkerSpec) {
* @param {Object} options * @param {Object} options
* - "reverse": search backwards * - "reverse": search backwards
*/ */
async search(query, options = { }) { async search(query, options = {}) {
const searchData = this.searchData = this.searchData || { }; const searchData = (this.searchData = this.searchData || {});
const result = await super.search(query, options); const result = await super.search(query, options);
const nodeList = result.list; const nodeList = result.list;
@ -213,8 +223,9 @@ class WalkerFront extends FrontClassWithSpec(walkerSpec) {
} }
// Move search result cursor and cycle if necessary. // Move search result cursor and cycle if necessary.
searchData.index = options.reverse ? searchData.index - 1 : searchData.index = options.reverse
searchData.index + 1; ? searchData.index - 1
: searchData.index + 1;
if (searchData.index >= nodeList.length) { if (searchData.index >= nodeList.length) {
searchData.index = 0; searchData.index = 0;
} }
@ -282,24 +293,30 @@ class WalkerFront extends FrontClassWithSpec(walkerSpec) {
} }
if (!targetFront) { if (!targetFront) {
console.warn("Got a mutation for an unexpected actor: " + targetID + console.warn(
", please file a bug on bugzilla.mozilla.org!"); "Got a mutation for an unexpected actor: " +
targetID +
", please file a bug on bugzilla.mozilla.org!"
);
console.trace(); console.trace();
continue; continue;
} }
const emittedMutation = Object.assign(change, { target: targetFront }); const emittedMutation = Object.assign(change, { target: targetFront });
if (change.type === "childList" || if (
change.type === "nativeAnonymousChildList") { change.type === "childList" ||
change.type === "nativeAnonymousChildList"
) {
// Update the ownership tree according to the mutation record. // Update the ownership tree according to the mutation record.
const addedFronts = []; const addedFronts = [];
const removedFronts = []; const removedFronts = [];
for (const removed of change.removed) { for (const removed of change.removed) {
const removedFront = this.get(removed); const removedFront = this.get(removed);
if (!removedFront) { if (!removedFront) {
console.error("Got a removal of an actor we didn't know about: " + console.error(
removed); "Got a removal of an actor we didn't know about: " + removed
);
continue; continue;
} }
// Remove from the ownership tree // Remove from the ownership tree
@ -313,8 +330,11 @@ class WalkerFront extends FrontClassWithSpec(walkerSpec) {
for (const added of change.added) { for (const added of change.added) {
const addedFront = this.get(added); const addedFront = this.get(added);
if (!addedFront) { if (!addedFront) {
console.error("Got an addition of an actor we didn't know " + console.error(
"about: " + added); "Got an addition of an actor we didn't know " +
"about: " +
added
);
continue; continue;
} }
addedFront.reparent(targetFront); addedFront.reparent(targetFront);
@ -342,8 +362,10 @@ class WalkerFront extends FrontClassWithSpec(walkerSpec) {
// first. // first.
for (const child of targetFront.treeChildren()) { for (const child of targetFront.treeChildren()) {
if (child.nodeType === nodeConstants.DOCUMENT_NODE) { if (child.nodeType === nodeConstants.DOCUMENT_NODE) {
console.warn("Got an unexpected frameLoad in the inspector, " + console.warn(
"please file a bug on bugzilla.mozilla.org!"); "Got an unexpected frameLoad in the inspector, " +
"please file a bug on bugzilla.mozilla.org!"
);
console.trace(); console.trace();
} }
} }
@ -362,7 +384,8 @@ class WalkerFront extends FrontClassWithSpec(walkerSpec) {
} else if (change.type === "shadowRootAttached") { } else if (change.type === "shadowRootAttached") {
targetFront._form.isShadowHost = true; targetFront._form.isShadowHost = true;
} else if (change.type === "customElementDefined") { } else if (change.type === "customElementDefined") {
targetFront._form.customElementLocation = change.customElementLocation; targetFront._form.customElementLocation =
change.customElementLocation;
} else if (change.type === "unretained") { } else if (change.type === "unretained") {
// Retained orphans were force-released without the intervention of // Retained orphans were force-released without the intervention of
// client (probably a navigated frame). // client (probably a navigated frame).
@ -377,13 +400,16 @@ class WalkerFront extends FrontClassWithSpec(walkerSpec) {
// Update the inlineTextChild property of the target for a selected list of // Update the inlineTextChild property of the target for a selected list of
// mutation types. // mutation types.
if (change.type === "inlineTextChild" || if (
change.type === "childList" || change.type === "inlineTextChild" ||
change.type === "shadowRootAttached" || change.type === "childList" ||
change.type === "nativeAnonymousChildList") { change.type === "shadowRootAttached" ||
change.type === "nativeAnonymousChildList"
) {
if (change.inlineTextChild) { if (change.inlineTextChild) {
targetFront.inlineTextChild = targetFront.inlineTextChild = types
types.getType("domnode").read(change.inlineTextChild, this); .getType("domnode")
.read(change.inlineTextChild, this);
} else { } else {
targetFront.inlineTextChild = undefined; targetFront.inlineTextChild = undefined;
} }
@ -411,7 +437,7 @@ class WalkerFront extends FrontClassWithSpec(walkerSpec) {
*/ */
onMutations() { onMutations() {
// Fetch and process the mutations. // Fetch and process the mutations.
this.getMutations({cleanup: this.autoCleanup}).catch(() => {}); this.getMutations({ cleanup: this.autoCleanup }).catch(() => {});
} }
isLocal() { isLocal() {
@ -448,20 +474,23 @@ class InspectorFront extends FrontClassWithSpec(inspectorSpec) {
// async initialization // async initialization
async initialize() { async initialize() {
await Promise.all([ await Promise.all([this._getWalker(), this._getHighlighter()]);
this._getWalker(),
this._getHighlighter(),
]);
this.selection = new Selection(this.walker); this.selection = new Selection(this.walker);
this.nodePicker = new NodePicker(this.highlighter, this.walker, this.selection); this.nodePicker = new NodePicker(
this.highlighter,
this.walker,
this.selection
);
} }
async _getWalker() { async _getWalker() {
const showAllAnonymousContent = Services.prefs.getBoolPref( const showAllAnonymousContent = Services.prefs.getBoolPref(
SHOW_ALL_ANONYMOUS_CONTENT_PREF); SHOW_ALL_ANONYMOUS_CONTENT_PREF
);
const showUserAgentShadowRoots = Services.prefs.getBoolPref( const showUserAgentShadowRoots = Services.prefs.getBoolPref(
SHOW_UA_SHADOW_ROOTS_PREF); SHOW_UA_SHADOW_ROOTS_PREF
);
this.walker = await this.getWalker({ this.walker = await this.getWalker({
showAllAnonymousContent, showAllAnonymousContent,
showUserAgentShadowRoots, showUserAgentShadowRoots,
@ -502,8 +531,10 @@ class InspectorFront extends FrontClassWithSpec(inspectorSpec) {
try { try {
highlighter = await super.getHighlighterByType(typeName); highlighter = await super.getHighlighterByType(typeName);
} catch (_) { } catch (_) {
throw new Error("The target doesn't support " + throw new Error(
`creating highlighters by types or ${typeName} is unknown`); "The target doesn't support " +
`creating highlighters by types or ${typeName} is unknown`
);
} }
return highlighter; return highlighter;
} }
@ -513,7 +544,7 @@ class InspectorFront extends FrontClassWithSpec(inspectorSpec) {
} }
async getOrCreateHighlighterByType(type) { async getOrCreateHighlighterByType(type) {
let front = this._highlighters.get(type); let front = this._highlighters.get(type);
if (!front) { if (!front) {
front = await this.getHighlighterByType(type); front = await this.getHighlighterByType(type);
this._highlighters.set(type, front); this._highlighters.set(type, front);

View file

@ -109,8 +109,11 @@ RuleRewriter.prototype = {
// Whether there are any newlines in the input text. // Whether there are any newlines in the input text.
this.hasNewLine = /[\r\n]/.test(this.inputString); this.hasNewLine = /[\r\n]/.test(this.inputString);
// The declarations. // The declarations.
this.declarations = parseNamedDeclarations(this.isCssPropertyKnown, this.inputString, this.declarations = parseNamedDeclarations(
true); this.isCssPropertyKnown,
this.inputString,
true
);
this.decl = null; this.decl = null;
this.result = null; this.result = null;
}, },
@ -196,17 +199,19 @@ RuleRewriter.prototype = {
// Push a closing paren on the stack. // Push a closing paren on the stack.
const pushParen = (token, closer) => { const pushParen = (token, closer) => {
result = result + text.substring(previousOffset, token.startOffset) + result =
result +
text.substring(previousOffset, token.startOffset) +
text.substring(token.startOffset, token.endOffset); text.substring(token.startOffset, token.endOffset);
// We set the location of the paren in a funny way, to handle // We set the location of the paren in a funny way, to handle
// the case where we've seen a function token, where the paren // the case where we've seen a function token, where the paren
// appears at the end. // appears at the end.
parenStack.push({closer, offset: result.length - 1}); parenStack.push({ closer, offset: result.length - 1 });
previousOffset = token.endOffset; previousOffset = token.endOffset;
}; };
// Pop a closing paren from the stack. // Pop a closing paren from the stack.
const popSomeParens = (closer) => { const popSomeParens = closer => {
while (parenStack.length > 0) { while (parenStack.length > 0) {
const paren = parenStack.pop(); const paren = parenStack.pop();
@ -216,7 +221,9 @@ RuleRewriter.prototype = {
// Found a non-matching closing paren, so quote it. Note that // Found a non-matching closing paren, so quote it. Note that
// these are processed in reverse order. // these are processed in reverse order.
result = result.substring(0, paren.offset) + "\\" + result =
result.substring(0, paren.offset) +
"\\" +
result.substring(paren.offset); result.substring(paren.offset);
anySanitized = true; anySanitized = true;
} }
@ -293,9 +300,11 @@ RuleRewriter.prototype = {
* @return {Number} index of the first non-whitespace character, or -1 * @return {Number} index of the first non-whitespace character, or -1
*/ */
skipWhitespaceBackward: function(string, index) { skipWhitespaceBackward: function(string, index) {
for (--index; for (
index >= 0 && (string[index] === " " || string[index] === "\t"); --index;
--index) { index >= 0 && (string[index] === " " || string[index] === "\t");
--index
) {
// Nothing. // Nothing.
} }
return index; return index;
@ -309,9 +318,12 @@ RuleRewriter.prototype = {
* function must check for that. * function must check for that.
*/ */
maybeTerminateDecl: function(index) { maybeTerminateDecl: function(index) {
if (index < 0 || index >= this.declarations.length if (
// No need to rewrite declarations in comments. index < 0 ||
|| ("commentOffsets" in this.declarations[index])) { index >= this.declarations.length ||
// No need to rewrite declarations in comments.
"commentOffsets" in this.declarations[index]
) {
return; return;
} }
@ -326,8 +338,8 @@ RuleRewriter.prototype = {
if (termDecl.terminator) { if (termDecl.terminator) {
// Insert the terminator just at the end of the declaration, // Insert the terminator just at the end of the declaration,
// before any trailing whitespace. // before any trailing whitespace.
this.result = this.result.substring(0, endIndex) + termDecl.terminator + this.result =
trailingText; this.result.substring(0, endIndex) + termDecl.terminator + trailingText;
// In a couple of cases, we may have had to add something to // In a couple of cases, we may have had to add something to
// terminate the declaration, but the termination did not // terminate the declaration, but the termination did not
// actually affect the property's value -- and at this spot, we // actually affect the property's value -- and at this spot, we
@ -404,16 +416,19 @@ RuleRewriter.prototype = {
// Insert the name and value separately, so we can report // Insert the name and value separately, so we can report
// sanitization changes properly. // sanitization changes properly.
const commentNamePart = const commentNamePart = this.inputString.substring(
this.inputString.substring(decl.offsets[0], decl.offsets[0],
decl.colonOffsets[1]); decl.colonOffsets[1]
);
this.result += unescapeCSSComment(commentNamePart); this.result += unescapeCSSComment(commentNamePart);
// When uncommenting, we must be sure to sanitize the text, to // When uncommenting, we must be sure to sanitize the text, to
// avoid things like /* decl: }; */, which will be accepted as // avoid things like /* decl: }; */, which will be accepted as
// a property but which would break the entire style sheet. // a property but which would break the entire style sheet.
let newText = this.inputString.substring(decl.colonOffsets[1], let newText = this.inputString.substring(
decl.offsets[1]); decl.colonOffsets[1],
decl.offsets[1]
);
newText = cssTrimRight(unescapeCSSComment(newText)); newText = cssTrimRight(unescapeCSSComment(newText));
this.result += this.sanitizeText(newText, index) + ";"; this.result += this.sanitizeText(newText, index) + ";";
@ -427,15 +442,27 @@ RuleRewriter.prototype = {
} else { } else {
// Disable it. Note that we use our special comment syntax // Disable it. Note that we use our special comment syntax
// here. // here.
const declText = this.inputString.substring(decl.offsets[0], const declText = this.inputString.substring(
decl.offsets[1]); decl.offsets[0],
this.result += "/*" + COMMENT_PARSING_HEURISTIC_BYPASS_CHAR + decl.offsets[1]
" " + escapeCSSComment(declText) + " */"; );
this.result +=
"/*" +
COMMENT_PARSING_HEURISTIC_BYPASS_CHAR +
" " +
escapeCSSComment(declText) +
" */";
} }
this.completeCopying(copyOffset); this.completeCopying(copyOffset);
if (isEnabled) { if (isEnabled) {
this.modifications.push({ type: "set", index, name, value: decl.value, priority }); this.modifications.push({
type: "set",
index,
name,
value: decl.value,
priority,
});
} else { } else {
this.modifications.push({ type: "disable", index, name }); this.modifications.push({ type: "disable", index, name });
} }
@ -472,8 +499,10 @@ RuleRewriter.prototype = {
let newIndentation = ""; let newIndentation = "";
if (this.hasNewLine) { if (this.hasNewLine) {
if (this.declarations.length > 0) { if (this.declarations.length > 0) {
newIndentation = this.getIndentation(this.inputString, newIndentation = this.getIndentation(
this.declarations[0].offsets[0]); this.inputString,
this.declarations[0].offsets[0]
);
} else if (this.defaultIndentation) { } else if (this.defaultIndentation) {
newIndentation = this.defaultIndentation; newIndentation = this.defaultIndentation;
} else { } else {
@ -489,8 +518,10 @@ RuleRewriter.prototype = {
// is actually used. // is actually used.
let savedWhitespace = ""; let savedWhitespace = "";
if (this.hasNewLine) { if (this.hasNewLine) {
const wsOffset = this.skipWhitespaceBackward(this.result, const wsOffset = this.skipWhitespaceBackward(
this.result.length); this.result,
this.result.length
);
if (this.result[wsOffset] === "\r" || this.result[wsOffset] === "\n") { if (this.result[wsOffset] === "\r" || this.result[wsOffset] === "\n") {
savedWhitespace = this.result.substring(wsOffset + 1); savedWhitespace = this.result.substring(wsOffset + 1);
this.result = this.result.substring(0, wsOffset + 1); this.result = this.result.substring(0, wsOffset + 1);
@ -504,8 +535,12 @@ RuleRewriter.prototype = {
newText += ";"; newText += ";";
if (!enabled) { if (!enabled) {
newText = "/*" + COMMENT_PARSING_HEURISTIC_BYPASS_CHAR + " " + newText =
escapeCSSComment(newText) + " */"; "/*" +
COMMENT_PARSING_HEURISTIC_BYPASS_CHAR +
" " +
escapeCSSComment(newText) +
" */";
} }
this.result += newIndentation + newText; this.result += newIndentation + newText;
@ -533,7 +568,13 @@ RuleRewriter.prototype = {
* enabled, false if disabled * enabled, false if disabled
*/ */
createProperty: function(index, name, value, priority, enabled) { createProperty: function(index, name, value, priority, enabled) {
this.editPromise = this.internalCreateProperty(index, name, value, priority, enabled); this.editPromise = this.internalCreateProperty(
index,
name,
value,
priority,
enabled
);
// Log the modification only if the created property is enabled. // Log the modification only if the created property is enabled.
if (enabled) { if (enabled) {
this.modifications.push({ type: "set", index, name, value, priority }); this.modifications.push({ type: "set", index, name, value, priority });
@ -564,9 +605,11 @@ RuleRewriter.prototype = {
// Note that this assumes that "set" never operates on disabled // Note that this assumes that "set" never operates on disabled
// properties. // properties.
this.result += this.inputString.substring(this.decl.offsets[0], this.result +=
this.decl.colonOffsets[1]) + this.inputString.substring(
this.sanitizeText(value, index); this.decl.offsets[0],
this.decl.colonOffsets[1]
) + this.sanitizeText(value, index);
if (priority === "important") { if (priority === "important") {
this.result += " !important"; this.result += " !important";
@ -607,10 +650,15 @@ RuleRewriter.prototype = {
// bother with this if we're looking at sources that already // bother with this if we're looking at sources that already
// have a newline somewhere. // have a newline somewhere.
if (this.hasNewLine) { if (this.hasNewLine) {
const nlOffset = this.skipWhitespaceBackward(this.result, const nlOffset = this.skipWhitespaceBackward(
this.decl.offsets[0]); this.result,
if (nlOffset < 0 || this.result[nlOffset] === "\r" || this.decl.offsets[0]
this.result[nlOffset] === "\n") { );
if (
nlOffset < 0 ||
this.result[nlOffset] === "\r" ||
this.result[nlOffset] === "\n"
) {
const trailingText = this.inputString.substring(copyOffset); const trailingText = this.inputString.substring(copyOffset);
const match = BLANK_LINE_RX.exec(trailingText); const match = BLANK_LINE_RX.exec(trailingText);
if (match) { if (match) {
@ -658,7 +706,7 @@ RuleRewriter.prototype = {
* |text| is the rewritten text of the rule. * |text| is the rewritten text of the rule.
*/ */
getResult: function() { getResult: function() {
return {changed: this.changedDeclarations, text: this.result}; return { changed: this.changedDeclarations, text: this.result };
}, },
}; };

View file

@ -4,7 +4,10 @@
"use strict"; "use strict";
const { FrontClassWithSpec, registerFront } = require("devtools/shared/protocol"); const {
FrontClassWithSpec,
registerFront,
} = require("devtools/shared/protocol");
const { const {
flexboxSpec, flexboxSpec,
flexItemSpec, flexItemSpec,
@ -132,8 +135,7 @@ class GridFront extends FrontClassWithSpec(gridSpec) {
} }
} }
class LayoutFront extends FrontClassWithSpec(layoutSpec) { class LayoutFront extends FrontClassWithSpec(layoutSpec) {}
}
exports.FlexboxFront = FlexboxFront; exports.FlexboxFront = FlexboxFront;
registerFront(FlexboxFront); registerFront(FlexboxFront);

View file

@ -4,12 +4,22 @@
"use strict"; "use strict";
const { memorySpec } = require("devtools/shared/specs/memory"); const { memorySpec } = require("devtools/shared/specs/memory");
const { FrontClassWithSpec, registerFront } = require("devtools/shared/protocol"); const {
FrontClassWithSpec,
registerFront,
} = require("devtools/shared/protocol");
loader.lazyRequireGetter(this, "FileUtils", loader.lazyRequireGetter(
"resource://gre/modules/FileUtils.jsm", true); this,
loader.lazyRequireGetter(this, "HeapSnapshotFileUtils", "FileUtils",
"devtools/shared/heapsnapshot/HeapSnapshotFileUtils"); "resource://gre/modules/FileUtils.jsm",
true
);
loader.lazyRequireGetter(
this,
"HeapSnapshotFileUtils",
"devtools/shared/heapsnapshot/HeapSnapshotFileUtils"
);
class MemoryFront extends FrontClassWithSpec(memorySpec) { class MemoryFront extends FrontClassWithSpec(memorySpec) {
constructor(client) { constructor(client) {
@ -42,8 +52,10 @@ class MemoryFront extends FrontClassWithSpec(memorySpec) {
async saveHeapSnapshot(options = {}) { async saveHeapSnapshot(options = {}) {
const snapshotId = await super.saveHeapSnapshot(options.boundaries); const snapshotId = await super.saveHeapSnapshot(options.boundaries);
if (!options.forceCopy && if (
(await HeapSnapshotFileUtils.haveHeapSnapshotTempFile(snapshotId))) { !options.forceCopy &&
(await HeapSnapshotFileUtils.haveHeapSnapshotTempFile(snapshotId))
) {
return HeapSnapshotFileUtils.getHeapSnapshotTempFilePath(snapshotId); return HeapSnapshotFileUtils.getHeapSnapshotTempFilePath(snapshotId);
} }
@ -72,8 +84,7 @@ class MemoryFront extends FrontClassWithSpec(memorySpec) {
snapshotId, snapshotId,
}); });
const outFilePath = const outFilePath = HeapSnapshotFileUtils.getNewUniqueHeapSnapshotTempFilePath();
HeapSnapshotFileUtils.getNewUniqueHeapSnapshotTempFilePath();
const outFile = new FileUtils.File(outFilePath); const outFile = new FileUtils.File(outFilePath);
const outFileStream = FileUtils.openSafeFileOutputStream(outFile); const outFileStream = FileUtils.openSafeFileOutputStream(outFile);

View file

@ -9,16 +9,16 @@ const {
registerFront, registerFront,
} = require("devtools/shared/protocol.js"); } = require("devtools/shared/protocol.js");
const { const { nodeSpec, nodeListSpec } = require("devtools/shared/specs/node");
nodeSpec,
nodeListSpec,
} = require("devtools/shared/specs/node");
const promise = require("promise"); const promise = require("promise");
const { SimpleStringFront } = require("devtools/shared/fronts/string"); const { SimpleStringFront } = require("devtools/shared/fronts/string");
loader.lazyRequireGetter(this, "nodeConstants", loader.lazyRequireGetter(
"devtools/shared/dom-node-constants"); this,
"nodeConstants",
"devtools/shared/dom-node-constants"
);
const HIDDEN_CLASS = "__fx-devtools-hide-shortcut__"; const HIDDEN_CLASS = "__fx-devtools-hide-shortcut__";
@ -146,7 +146,9 @@ class NodeFront extends FrontClassWithSpec(nodeSpec) {
// Get the owner actor for this actor (the walker), and find the // Get the owner actor for this actor (the walker), and find the
// parent node of this actor from it, creating a standin node if // parent node of this actor from it, creating a standin node if
// necessary. // necessary.
const parentNodeFront = ctx.marshallPool().ensureDOMNodeFront(form.parent); const parentNodeFront = ctx
.marshallPool()
.ensureDOMNodeFront(form.parent);
this.reparent(parentNodeFront); this.reparent(parentNodeFront);
} }
@ -155,8 +157,9 @@ class NodeFront extends FrontClassWithSpec(nodeSpec) {
} }
if (form.inlineTextChild) { if (form.inlineTextChild) {
this.inlineTextChild = this.inlineTextChild = types
types.getType("domnode").read(form.inlineTextChild, ctx); .getType("domnode")
.read(form.inlineTextChild, ctx);
} else { } else {
this.inlineTextChild = undefined; this.inlineTextChild = undefined;
} }
@ -192,8 +195,10 @@ class NodeFront extends FrontClassWithSpec(nodeSpec) {
let found = false; let found = false;
for (let i = 0; i < this.attributes.length; i++) { for (let i = 0; i < this.attributes.length; i++) {
const attr = this.attributes[i]; const attr = this.attributes[i];
if (attr.name == change.attributeName && if (
attr.namespace == change.attributeNamespace) { attr.name == change.attributeName &&
attr.namespace == change.attributeNamespace
) {
if (change.newValue !== null) { if (change.newValue !== null) {
attr.value = change.newValue; attr.value = change.newValue;
} else { } else {
@ -239,16 +244,19 @@ class NodeFront extends FrontClassWithSpec(nodeSpec) {
return this._form.nodeName; return this._form.nodeName;
} }
get displayName() { get displayName() {
const {displayName, nodeName} = this._form; const { displayName, nodeName } = this._form;
// Keep `nodeName.toLowerCase()` for backward compatibility // Keep `nodeName.toLowerCase()` for backward compatibility
return displayName || nodeName.toLowerCase(); return displayName || nodeName.toLowerCase();
} }
get doctypeString() { get doctypeString() {
return "<!DOCTYPE " + this._form.name + return (
(this._form.publicId ? " PUBLIC \"" + this._form.publicId + "\"" : "") + "<!DOCTYPE " +
(this._form.systemId ? " \"" + this._form.systemId + "\"" : "") + this._form.name +
">"; (this._form.publicId ? ' PUBLIC "' + this._form.publicId + '"' : "") +
(this._form.systemId ? ' "' + this._form.systemId + '"' : "") +
">"
);
} }
get baseURI() { get baseURI() {
@ -279,8 +287,11 @@ class NodeFront extends FrontClassWithSpec(nodeSpec) {
return this._form.isAfterPseudoElement; return this._form.isAfterPseudoElement;
} }
get isPseudoElement() { get isPseudoElement() {
return this.isBeforePseudoElement || this.isAfterPseudoElement || return (
this.isMarkerPseudoElement; this.isBeforePseudoElement ||
this.isAfterPseudoElement ||
this.isMarkerPseudoElement
);
} }
get isAnonymous() { get isAnonymous() {
return this._form.isAnonymous; return this._form.isAnonymous;
@ -333,7 +344,7 @@ class NodeFront extends FrontClassWithSpec(nodeSpec) {
} }
hasAttribute(name) { hasAttribute(name) {
this._cacheAttributes(); this._cacheAttributes();
return (name in this._attrMap); return name in this._attrMap;
} }
get hidden() { get hidden() {

View file

@ -3,7 +3,10 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict"; "use strict";
const { FrontClassWithSpec, registerFront } = require("devtools/shared/protocol"); const {
FrontClassWithSpec,
registerFront,
} = require("devtools/shared/protocol");
const { perfSpec } = require("devtools/shared/specs/perf"); const { perfSpec } = require("devtools/shared/specs/perf");
class PerfFront extends FrontClassWithSpec(perfSpec) { class PerfFront extends FrontClassWithSpec(perfSpec) {

View file

@ -3,21 +3,38 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict"; "use strict";
const { FrontClassWithSpec, registerFront } = require("devtools/shared/protocol"); const {
const { performanceRecordingSpec } = require("devtools/shared/specs/performance-recording"); FrontClassWithSpec,
registerFront,
} = require("devtools/shared/protocol");
const {
performanceRecordingSpec,
} = require("devtools/shared/specs/performance-recording");
loader.lazyRequireGetter(this, "PerformanceIO", loader.lazyRequireGetter(
"devtools/client/performance/modules/io"); this,
loader.lazyRequireGetter(this, "PerformanceRecordingCommon", "PerformanceIO",
"devtools/shared/performance/recording-common", true); "devtools/client/performance/modules/io"
loader.lazyRequireGetter(this, "RecordingUtils", );
"devtools/shared/performance/recording-utils"); loader.lazyRequireGetter(
this,
"PerformanceRecordingCommon",
"devtools/shared/performance/recording-common",
true
);
loader.lazyRequireGetter(
this,
"RecordingUtils",
"devtools/shared/performance/recording-utils"
);
/** /**
* This can be used on older Profiler implementations, but the methods cannot * This can be used on older Profiler implementations, but the methods cannot
* be changed -- you must introduce a new method, and detect the server. * be changed -- you must introduce a new method, and detect the server.
*/ */
class PerformanceRecordingFront extends FrontClassWithSpec(performanceRecordingSpec) { class PerformanceRecordingFront extends FrontClassWithSpec(
performanceRecordingSpec
) {
form(form) { form(form) {
this.actorID = form.actor; this.actorID = form.actor;
this._form = form; this._form = form;
@ -41,7 +58,7 @@ class PerformanceRecordingFront extends FrontClassWithSpec(performanceRecordingS
// just finished. This is because GC/Compositing markers can come into the array out // just finished. This is because GC/Compositing markers can come into the array out
// of order with the other markers, leading to strange collapsing in waterfall view. // of order with the other markers, leading to strange collapsing in waterfall view.
if (this._completed && !this._markersSorted) { if (this._completed && !this._markersSorted) {
this._markers = this._markers.sort((a, b) => (a.start > b.start)); this._markers = this._markers.sort((a, b) => a.start > b.start);
this._markersSorted = true; this._markersSorted = true;
} }
} }
@ -145,8 +162,10 @@ class PerformanceRecordingFront extends FrontClassWithSpec(performanceRecordingS
// PerformanceRecordingFront also needs to inherit from PerformanceRecordingCommon // PerformanceRecordingFront also needs to inherit from PerformanceRecordingCommon
// but as ES classes don't support multiple inheritance, we are overriding the // but as ES classes don't support multiple inheritance, we are overriding the
// prototype with PerformanceRecordingCommon methods. // prototype with PerformanceRecordingCommon methods.
Object.defineProperties(PerformanceRecordingFront.prototype, Object.defineProperties(
Object.getOwnPropertyDescriptors(PerformanceRecordingCommon)); PerformanceRecordingFront.prototype,
Object.getOwnPropertyDescriptors(PerformanceRecordingCommon)
);
exports.PerformanceRecordingFront = PerformanceRecordingFront; exports.PerformanceRecordingFront = PerformanceRecordingFront;
registerFront(PerformanceRecordingFront); registerFront(PerformanceRecordingFront);

View file

@ -4,14 +4,21 @@
"use strict"; "use strict";
const { Cu } = require("chrome"); const { Cu } = require("chrome");
const { FrontClassWithSpec, registerFront } = require("devtools/shared/protocol"); const {
const { PerformanceRecordingFront } = require("devtools/shared/fronts/performance-recording"); FrontClassWithSpec,
registerFront,
} = require("devtools/shared/protocol");
const {
PerformanceRecordingFront,
} = require("devtools/shared/fronts/performance-recording");
const { performanceSpec } = require("devtools/shared/specs/performance"); const { performanceSpec } = require("devtools/shared/specs/performance");
loader.lazyRequireGetter(this, "PerformanceIO", loader.lazyRequireGetter(
"devtools/client/performance/modules/io"); this,
loader.lazyRequireGetter(this, "getSystemInfo", "PerformanceIO",
"devtools/shared/system", true); "devtools/client/performance/modules/io"
);
loader.lazyRequireGetter(this, "getSystemInfo", "devtools/shared/system", true);
class PerformanceFront extends FrontClassWithSpec(performanceSpec) { class PerformanceFront extends FrontClassWithSpec(performanceSpec) {
constructor(client) { constructor(client) {
@ -63,8 +70,10 @@ class PerformanceFront extends FrontClassWithSpec(performanceSpec) {
get traits() { get traits() {
if (!this._traits) { if (!this._traits) {
Cu.reportError("Cannot access traits of PerformanceFront before " + Cu.reportError(
"calling `connect()`."); "Cannot access traits of PerformanceFront before " +
"calling `connect()`."
);
} }
return this._traits; return this._traits;
} }
@ -90,8 +99,8 @@ class PerformanceFront extends FrontClassWithSpec(performanceSpec) {
generation: origGeneration, generation: origGeneration,
} = recording.getStartingBufferStatus(); } = recording.getStartingBufferStatus();
const normalizedCurrent = (totalSize * (currentGeneration - origGeneration)) + const normalizedCurrent =
currentPosition; totalSize * (currentGeneration - origGeneration) + currentPosition;
const percent = (normalizedCurrent - origPosition) / totalSize; const percent = (normalizedCurrent - origPosition) / totalSize;
// Clamp between 0 and 1; can get negative percentage values when a new // Clamp between 0 and 1; can get negative percentage values when a new

View file

@ -3,8 +3,11 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict"; "use strict";
const {preferenceSpec} = require("devtools/shared/specs/preference"); const { preferenceSpec } = require("devtools/shared/specs/preference");
const { FrontClassWithSpec, registerFront } = require("devtools/shared/protocol"); const {
FrontClassWithSpec,
registerFront,
} = require("devtools/shared/protocol");
class PreferenceFront extends FrontClassWithSpec(preferenceSpec) { class PreferenceFront extends FrontClassWithSpec(preferenceSpec) {
constructor(client) { constructor(client) {

View file

@ -4,8 +4,11 @@
"use strict"; "use strict";
const {reflowSpec} = require("devtools/shared/specs/reflow"); const { reflowSpec } = require("devtools/shared/specs/reflow");
const { FrontClassWithSpec, registerFront } = require("devtools/shared/protocol"); const {
FrontClassWithSpec,
registerFront,
} = require("devtools/shared/protocol");
/** /**
* Usage example of the reflow front: * Usage example of the reflow front:

View file

@ -3,13 +3,26 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict"; "use strict";
const {Ci} = require("chrome"); const { Ci } = require("chrome");
const {rootSpec} = require("devtools/shared/specs/root"); const { rootSpec } = require("devtools/shared/specs/root");
const { FrontClassWithSpec, registerFront } = require("devtools/shared/protocol"); const {
FrontClassWithSpec,
registerFront,
} = require("devtools/shared/protocol");
loader.lazyRequireGetter(this, "getFront", "devtools/shared/protocol", true); loader.lazyRequireGetter(this, "getFront", "devtools/shared/protocol", true);
loader.lazyRequireGetter(this, "BrowsingContextTargetFront", "devtools/shared/fronts/targets/browsing-context", true); loader.lazyRequireGetter(
loader.lazyRequireGetter(this, "ContentProcessTargetFront", "devtools/shared/fronts/targets/content-process", true); this,
"BrowsingContextTargetFront",
"devtools/shared/fronts/targets/browsing-context",
true
);
loader.lazyRequireGetter(
this,
"ContentProcessTargetFront",
"devtools/shared/fronts/targets/content-process",
true
);
class RootFront extends FrontClassWithSpec(rootSpec) { class RootFront extends FrontClassWithSpec(rootSpec) {
constructor(client, form) { constructor(client, form) {
@ -113,7 +126,9 @@ class RootFront extends FrontClassWithSpec(rootSpec) {
}; };
switch (front.type) { switch (front.type) {
case Ci.nsIWorkerDebugger.TYPE_SERVICE: case Ci.nsIWorkerDebugger.TYPE_SERVICE:
const registration = result.service.find(r => r.scope === front.scope); const registration = result.service.find(
r => r.scope === front.scope
);
if (registration) { if (registration) {
// XXX: Race, sometimes a ServiceWorkerRegistrationInfo doesn't // XXX: Race, sometimes a ServiceWorkerRegistrationInfo doesn't
// have a scriptSpec, but its associated WorkerDebugger does. // have a scriptSpec, but its associated WorkerDebugger does.
@ -210,9 +225,9 @@ class RootFront extends FrontClassWithSpec(rootSpec) {
async getTab(filter) { async getTab(filter) {
const packet = {}; const packet = {};
if (filter) { if (filter) {
if (typeof (filter.outerWindowID) == "number") { if (typeof filter.outerWindowID == "number") {
packet.outerWindowID = filter.outerWindowID; packet.outerWindowID = filter.outerWindowID;
} else if (typeof (filter.tabId) == "number") { } else if (typeof filter.tabId == "number") {
packet.tabId = filter.tabId; packet.tabId = filter.tabId;
} else if ("tab" in filter) { } else if ("tab" in filter) {
const browser = filter.tab.linkedBrowser; const browser = filter.tab.linkedBrowser;

View file

@ -3,9 +3,12 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict"; "use strict";
const {screenshotSpec} = require("devtools/shared/specs/screenshot"); const { screenshotSpec } = require("devtools/shared/specs/screenshot");
const saveScreenshot = require("devtools/shared/screenshot/save"); const saveScreenshot = require("devtools/shared/screenshot/save");
const { FrontClassWithSpec, registerFront } = require("devtools/shared/protocol"); const {
FrontClassWithSpec,
registerFront,
} = require("devtools/shared/protocol");
class ScreenshotFront extends FrontClassWithSpec(screenshotSpec) { class ScreenshotFront extends FrontClassWithSpec(screenshotSpec) {
constructor(client) { constructor(client) {

View file

@ -5,7 +5,10 @@
"use strict"; "use strict";
const { sourceSpec } = require("devtools/shared/specs/source"); const { sourceSpec } = require("devtools/shared/specs/source");
const { FrontClassWithSpec, registerFront } = require("devtools/shared/protocol"); const {
FrontClassWithSpec,
registerFront,
} = require("devtools/shared/protocol");
const { ArrayBufferFront } = require("devtools/shared/fronts/array-buffer"); const { ArrayBufferFront } = require("devtools/shared/fronts/array-buffer");
/** /**

View file

@ -3,7 +3,10 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict"; "use strict";
const { FrontClassWithSpec, registerFront } = require("devtools/shared/protocol"); const {
FrontClassWithSpec,
registerFront,
} = require("devtools/shared/protocol");
const { childSpecs, storageSpec } = require("devtools/shared/specs/storage"); const { childSpecs, storageSpec } = require("devtools/shared/specs/storage");
for (const childSpec of Object.values(childSpecs)) { for (const childSpec of Object.values(childSpecs)) {

View file

@ -3,10 +3,16 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict"; "use strict";
const {DebuggerServer} = require("devtools/server/main"); const { DebuggerServer } = require("devtools/server/main");
const promise = require("promise"); const promise = require("promise");
const {longStringSpec, SimpleStringFront} = require("devtools/shared/specs/string"); const {
const { FrontClassWithSpec, registerFront } = require("devtools/shared/protocol"); longStringSpec,
SimpleStringFront,
} = require("devtools/shared/specs/string");
const {
FrontClassWithSpec,
registerFront,
} = require("devtools/shared/protocol");
class LongStringFront extends FrontClassWithSpec(longStringSpec) { class LongStringFront extends FrontClassWithSpec(longStringSpec) {
destroy() { destroy() {
@ -24,13 +30,14 @@ class LongStringFront extends FrontClassWithSpec(longStringSpec) {
string() { string() {
if (!this.strPromise) { if (!this.strPromise) {
const promiseRest = (thusFar) => { const promiseRest = thusFar => {
if (thusFar.length === this.length) { if (thusFar.length === this.length) {
return promise.resolve(thusFar); return promise.resolve(thusFar);
} }
return this.substring(thusFar.length, return this.substring(
thusFar.length + DebuggerServer.LONG_STRING_READ_LENGTH) thusFar.length,
.then((next) => promiseRest(thusFar + next)); thusFar.length + DebuggerServer.LONG_STRING_READ_LENGTH
).then(next => promiseRest(thusFar + next));
}; };
this.strPromise = promiseRest(this.initial); this.strPromise = promiseRest(this.initial);

View file

@ -13,7 +13,11 @@ const {
} = require("devtools/shared/specs/styles"); } = require("devtools/shared/specs/styles");
const promise = require("promise"); const promise = require("promise");
loader.lazyRequireGetter(this, "RuleRewriter", "devtools/shared/fronts/inspector/rule-rewriter"); loader.lazyRequireGetter(
this,
"RuleRewriter",
"devtools/shared/fronts/inspector/rule-rewriter"
);
/** /**
* PageStyleFront, the front object for the PageStyleActor * PageStyleFront, the front object for the PageStyleActor
@ -133,7 +137,7 @@ class StyleRuleFront extends FrontClassWithSpec(styleRuleSpec) {
return this._form.cssText; return this._form.cssText;
} }
get authoredText() { get authoredText() {
return (typeof this._form.authoredText === "string") return typeof this._form.authoredText === "string"
? this._form.authoredText ? this._form.authoredText
: this._form.cssText; : this._form.cssText;
} }
@ -215,7 +219,8 @@ class StyleRuleFront extends FrontClassWithSpec(styleRuleSpec) {
// Inline styles do not have any mediaText so we can return early. // Inline styles do not have any mediaText so we can return early.
return promise.resolve(this.location); return promise.resolve(this.location);
} }
return parentSheet.getOriginalLocation(this.line, this.column) return parentSheet
.getOriginalLocation(this.line, this.column)
.then(({ fromSourceMap, source, line, column }) => { .then(({ fromSourceMap, source, line, column }) => {
const location = { const location = {
href: source, href: source,
@ -235,7 +240,11 @@ class StyleRuleFront extends FrontClassWithSpec(styleRuleSpec) {
} }
async modifySelector(node, value) { async modifySelector(node, value) {
const response = await super.modifySelector(node, value, this.canSetRuleText); const response = await super.modifySelector(
node,
value,
this.canSetRuleText
);
if (response.ruleProps) { if (response.ruleProps) {
response.ruleProps = response.ruleProps.entries[0]; response.ruleProps = response.ruleProps.entries[0];

View file

@ -3,7 +3,10 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict"; "use strict";
const { FrontClassWithSpec, registerFront } = require("devtools/shared/protocol"); const {
FrontClassWithSpec,
registerFront,
} = require("devtools/shared/protocol");
const { const {
mediaRuleSpec, mediaRuleSpec,
styleSheetSpec, styleSheetSpec,
@ -11,10 +14,18 @@ const {
} = require("devtools/shared/specs/stylesheets"); } = require("devtools/shared/specs/stylesheets");
const promise = require("promise"); const promise = require("promise");
loader.lazyRequireGetter(this, "getIndentationFromPrefs", loader.lazyRequireGetter(
"devtools/shared/indentation", true); this,
loader.lazyRequireGetter(this, "getIndentationFromString", "getIndentationFromPrefs",
"devtools/shared/indentation", true); "devtools/shared/indentation",
true
);
loader.lazyRequireGetter(
this,
"getIndentationFromString",
"devtools/shared/indentation",
true
);
/** /**
* Corresponding client-side front for a MediaRuleActor. * Corresponding client-side front for a MediaRuleActor.
@ -118,18 +129,18 @@ class StyleSheetFront extends FrontClassWithSpec(styleSheetSpec) {
guessIndentation() { guessIndentation() {
const prefIndent = getIndentationFromPrefs(); const prefIndent = getIndentationFromPrefs();
if (prefIndent) { if (prefIndent) {
const {indentUnit, indentWithTabs} = prefIndent; const { indentUnit, indentWithTabs } = prefIndent;
return promise.resolve(indentWithTabs ? "\t" : " ".repeat(indentUnit)); return promise.resolve(indentWithTabs ? "\t" : " ".repeat(indentUnit));
} }
return (async function() { return async function() {
const longStr = await this.getText(); const longStr = await this.getText();
const source = await longStr.string(); const source = await longStr.string();
const {indentUnit, indentWithTabs} = getIndentationFromString(source); const { indentUnit, indentWithTabs } = getIndentationFromString(source);
return indentWithTabs ? "\t" : " ".repeat(indentUnit); return indentWithTabs ? "\t" : " ".repeat(indentUnit);
}.bind(this))(); }.bind(this)();
} }
} }

View file

@ -3,9 +3,17 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict"; "use strict";
const {addonTargetSpec} = require("devtools/shared/specs/targets/addon"); const { addonTargetSpec } = require("devtools/shared/specs/targets/addon");
const { FrontClassWithSpec, registerFront } = require("devtools/shared/protocol"); const {
loader.lazyRequireGetter(this, "BrowsingContextTargetFront", "devtools/shared/fronts/targets/browsing-context", true); FrontClassWithSpec,
registerFront,
} = require("devtools/shared/protocol");
loader.lazyRequireGetter(
this,
"BrowsingContextTargetFront",
"devtools/shared/fronts/targets/browsing-context",
true
);
class AddonTargetFront extends FrontClassWithSpec(addonTargetSpec) { class AddonTargetFront extends FrontClassWithSpec(addonTargetSpec) {
constructor(client) { constructor(client) {
@ -40,10 +48,12 @@ class AddonTargetFront extends FrontClassWithSpec(addonTargetSpec) {
// irrelevant warning messages. // irrelevant warning messages.
return false; return false;
} }
return this.type == "extension" && return (
this.temporarilyInstalled && this.type == "extension" &&
!this.isWebExtension && this.temporarilyInstalled &&
!this.isAPIExtension; !this.isWebExtension &&
!this.isAPIExtension
);
} }
/** /**
@ -56,8 +66,10 @@ class AddonTargetFront extends FrontClassWithSpec(addonTargetSpec) {
* the final target actor to use. * the final target actor to use.
*/ */
async connect() { async connect() {
if (this.isWebExtension && if (
this.client.mainRoot.traits.webExtensionAddonConnect) { this.isWebExtension &&
this.client.mainRoot.traits.webExtensionAddonConnect
) {
// The AddonTargetFront form is related to a WebExtensionActor instance, // The AddonTargetFront form is related to a WebExtensionActor instance,
// which isn't a target actor on its own, it is an actor living in the parent // which isn't a target actor on its own, it is an actor living in the parent
// process with access to the addon metadata, it can control the addon (e.g. // process with access to the addon metadata, it can control the addon (e.g.
@ -66,7 +78,9 @@ class AddonTargetFront extends FrontClassWithSpec(addonTargetSpec) {
// To retrieve the target actor instance, we call its "connect" method, (which // To retrieve the target actor instance, we call its "connect" method, (which
// fetches the target actor targetForm from a WebExtensionTargetActor instance). // fetches the target actor targetForm from a WebExtensionTargetActor instance).
const { form } = await super.connect(); const { form } = await super.connect();
const front = new BrowsingContextTargetFront(this.client, { actor: form.actor }); const front = new BrowsingContextTargetFront(this.client, {
actor: form.actor,
});
front.form(form); front.form(form);
this.manage(front); this.manage(front);
return front; return front;

View file

@ -3,12 +3,18 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict"; "use strict";
const {browsingContextTargetSpec} = require("devtools/shared/specs/targets/browsing-context"); const {
const { FrontClassWithSpec, registerFront } = require("devtools/shared/protocol"); browsingContextTargetSpec,
} = require("devtools/shared/specs/targets/browsing-context");
const {
FrontClassWithSpec,
registerFront,
} = require("devtools/shared/protocol");
const { TargetMixin } = require("./target-mixin"); const { TargetMixin } = require("./target-mixin");
class BrowsingContextTargetFront extends class BrowsingContextTargetFront extends TargetMixin(
TargetMixin(FrontClassWithSpec(browsingContextTargetSpec)) { FrontClassWithSpec(browsingContextTargetSpec)
) {
constructor(client) { constructor(client) {
super(client); super(client);
@ -127,7 +133,8 @@ class BrowsingContextTargetFront extends
response = await super.detach(); response = await super.detach();
} catch (e) { } catch (e) {
console.warn( console.warn(
`Error while detaching the browsing context target front: ${e.message}`); `Error while detaching the browsing context target front: ${e.message}`
);
} }
// Remove listeners set in attach // Remove listeners set in attach

View file

@ -3,12 +3,18 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict"; "use strict";
const {contentProcessTargetSpec} = require("devtools/shared/specs/targets/content-process"); const {
const { FrontClassWithSpec, registerFront } = require("devtools/shared/protocol"); contentProcessTargetSpec,
} = require("devtools/shared/specs/targets/content-process");
const {
FrontClassWithSpec,
registerFront,
} = require("devtools/shared/protocol");
const { TargetMixin } = require("./target-mixin"); const { TargetMixin } = require("./target-mixin");
class ContentProcessTargetFront extends class ContentProcessTargetFront extends TargetMixin(
TargetMixin(FrontClassWithSpec(contentProcessTargetSpec)) { FrontClassWithSpec(contentProcessTargetSpec)
) {
constructor(client) { constructor(client) {
super(client); super(client);

View file

@ -8,9 +8,23 @@
// This shouldn't happen, but Fronts should rather be part of client anyway. // This shouldn't happen, but Fronts should rather be part of client anyway.
// Otherwise gDevTools is only used for local tabs and should propably only // Otherwise gDevTools is only used for local tabs and should propably only
// used by a subclass, specific to local tabs. // used by a subclass, specific to local tabs.
loader.lazyRequireGetter(this, "gDevTools", "devtools/client/framework/devtools", true); loader.lazyRequireGetter(
loader.lazyRequireGetter(this, "TargetFactory", "devtools/client/framework/target", true); this,
loader.lazyRequireGetter(this, "ThreadClient", "devtools/shared/client/deprecated-thread-client"); "gDevTools",
"devtools/client/framework/devtools",
true
);
loader.lazyRequireGetter(
this,
"TargetFactory",
"devtools/client/framework/target",
true
);
loader.lazyRequireGetter(
this,
"ThreadClient",
"devtools/shared/client/deprecated-thread-client"
);
loader.lazyRequireGetter(this, "getFront", "devtools/shared/protocol", true); loader.lazyRequireGetter(this, "getFront", "devtools/shared/protocol", true);
/** /**
@ -107,7 +121,10 @@ function TargetMixin(parentClass) {
* } * }
*/ */
async getActorDescription(actorName) { async getActorDescription(actorName) {
if (this._protocolDescription && this._protocolDescription.types[actorName]) { if (
this._protocolDescription &&
this._protocolDescription.types[actorName]
) {
return this._protocolDescription.types[actorName]; return this._protocolDescription.types[actorName];
} }
const description = await this.client.mainRoot.protocolDescription(); const description = await this.client.mainRoot.protocolDescription();
@ -182,7 +199,11 @@ function TargetMixin(parentClass) {
if (this._inspector && this._inspector.actorID) { if (this._inspector && this._inspector.actorID) {
return this._inspector; return this._inspector;
} }
this._inspector = await getFront(this.client, "inspector", this.targetForm); this._inspector = await getFront(
this.client,
"inspector",
this.targetForm
);
this.emit("inspector", this._inspector); this.emit("inspector", this._inspector);
return this._inspector; return this._inspector;
} }
@ -202,7 +223,10 @@ function TargetMixin(parentClass) {
async getFront(typeName) { async getFront(typeName) {
let front = this.fronts.get(typeName); let front = this.fronts.get(typeName);
// the front might have been destroyed and no longer have an actor ID // the front might have been destroyed and no longer have an actor ID
if ((front && front.actorID) || (front && typeof front.then === "function")) { if (
(front && front.actorID) ||
(front && typeof front.then === "function")
) {
return front; return front;
} }
front = getFront(this.client, typeName, this.targetForm); front = getFront(this.client, typeName, this.targetForm);
@ -402,7 +426,8 @@ function TargetMixin(parentClass) {
async attachThread(options = {}) { async attachThread(options = {}) {
if (!this._threadActor) { if (!this._threadActor) {
throw new Error( throw new Error(
"TargetMixin sub class should set _threadActor before calling " + "attachThread" "TargetMixin sub class should set _threadActor before calling " +
"attachThread"
); );
} }
if (this.getTrait("hasThreadFront")) { if (this.getTrait("hasThreadFront")) {
@ -593,7 +618,9 @@ function TargetMixin(parentClass) {
} }
toString() { toString() {
const id = this._tab ? this._tab : this.targetForm && this.targetForm.actor; const id = this._tab
? this._tab
: this.targetForm && this.targetForm.actor;
return `Target:${id}`; return `Target:${id}`;
} }

View file

@ -3,12 +3,16 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict"; "use strict";
const {workerTargetSpec} = require("devtools/shared/specs/targets/worker"); const { workerTargetSpec } = require("devtools/shared/specs/targets/worker");
const { FrontClassWithSpec, registerFront } = require("devtools/shared/protocol"); const {
FrontClassWithSpec,
registerFront,
} = require("devtools/shared/protocol");
const { TargetMixin } = require("./target-mixin"); const { TargetMixin } = require("./target-mixin");
class WorkerTargetFront extends class WorkerTargetFront extends TargetMixin(
TargetMixin(FrontClassWithSpec(workerTargetSpec)) { FrontClassWithSpec(workerTargetSpec)
) {
constructor(client) { constructor(client) {
super(client); super(client);

View file

@ -8,7 +8,10 @@
const DevToolsUtils = require("devtools/shared/DevToolsUtils"); const DevToolsUtils = require("devtools/shared/DevToolsUtils");
const LongStringClient = require("devtools/shared/client/long-string-client"); const LongStringClient = require("devtools/shared/client/long-string-client");
const { FrontClassWithSpec, registerFront } = require("devtools/shared/protocol"); const {
FrontClassWithSpec,
registerFront,
} = require("devtools/shared/protocol");
const { webconsoleSpec } = require("devtools/shared/specs/webconsole"); const { webconsoleSpec } = require("devtools/shared/specs/webconsole");
/** /**
@ -256,9 +259,12 @@ class WebConsoleFront extends FrontClassWithSpec(webconsoleSpec) {
onResponse(packet); onResponse(packet);
this.pendingEvaluationResults.delete(packet.resultID); this.pendingEvaluationResults.delete(packet.resultID);
} else { } else {
DevToolsUtils.reportException("onEvaluationResult", DevToolsUtils.reportException(
"onEvaluationResult",
"No response handler for an evaluateJSAsync result (resultID: " + "No response handler for an evaluateJSAsync result (resultID: " +
packet.resultID + ")"); packet.resultID +
")"
);
} }
} }
@ -488,8 +494,7 @@ class WebConsoleFront extends FrontClassWithSpec(webconsoleSpec) {
} }
this.off("evaluationResult", this.onEvaluationResult); this.off("evaluationResult", this.onEvaluationResult);
this.off("serverNetworkEvent", this.onNetworkEvent); this.off("serverNetworkEvent", this.onNetworkEvent);
this._client.off("networkEventUpdate", this._client.off("networkEventUpdate", this.onNetworkEventUpdate);
this.onNetworkEventUpdate);
this._longStrings = null; this._longStrings = null;
this._client = null; this._client = null;
this.pendingEvaluationResults.clear(); this.pendingEvaluationResults.clear();
@ -532,8 +537,10 @@ class WebConsoleFront extends FrontClassWithSpec(webconsoleSpec) {
longStringClient.substring(initial.length, length, response => { longStringClient.substring(initial.length, length, response => {
if (response.error) { if (response.error) {
DevToolsUtils.reportException("getString", DevToolsUtils.reportException(
response.error + ": " + response.message); "getString",
response.error + ": " + response.message
);
reject(response); reject(response);
} }
resolve(initial + response.substring); resolve(initial + response.substring);

View file

@ -3,7 +3,10 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict"; "use strict";
const { FrontClassWithSpec, registerFront } = require("devtools/shared/protocol"); const {
FrontClassWithSpec,
registerFront,
} = require("devtools/shared/protocol");
const { webSocketSpec } = require("devtools/shared/specs/websocket"); const { webSocketSpec } = require("devtools/shared/specs/websocket");
/** /**
@ -58,7 +61,13 @@ class WebSocketFront extends FrontClassWithSpec(webSocketSpec) {
* @param string extensions * @param string extensions
*/ */
async _onWebSocketOpened(httpChannelId, effectiveURI, protocols, extensions) { async _onWebSocketOpened(httpChannelId, effectiveURI, protocols, extensions) {
this.emit("webSocketOpened", httpChannelId, effectiveURI, protocols, extensions); this.emit(
"webSocketOpened",
httpChannelId,
effectiveURI,
protocols,
extensions
);
} }
/** /**

View file

@ -3,9 +3,13 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict"; "use strict";
const { pushSubscriptionSpec } = const {
require("devtools/shared/specs/worker/push-subscription"); pushSubscriptionSpec,
const { FrontClassWithSpec, registerFront } = require("devtools/shared/protocol"); } = require("devtools/shared/specs/worker/push-subscription");
const {
FrontClassWithSpec,
registerFront,
} = require("devtools/shared/protocol");
class PushSubscriptionFront extends FrontClassWithSpec(pushSubscriptionSpec) { class PushSubscriptionFront extends FrontClassWithSpec(pushSubscriptionSpec) {
get endpoint() { get endpoint() {

View file

@ -3,12 +3,18 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict"; "use strict";
const { serviceWorkerRegistrationSpec } = const {
require("devtools/shared/specs/worker/service-worker-registration"); serviceWorkerRegistrationSpec,
const { FrontClassWithSpec, registerFront, types } = require("devtools/shared/protocol"); } = require("devtools/shared/specs/worker/service-worker-registration");
const {
FrontClassWithSpec,
registerFront,
types,
} = require("devtools/shared/protocol");
class ServiceWorkerRegistrationFront extends class ServiceWorkerRegistrationFront extends FrontClassWithSpec(
FrontClassWithSpec(serviceWorkerRegistrationSpec) { serviceWorkerRegistrationSpec
) {
get active() { get active() {
return this._form.active; return this._form.active;
} }

View file

@ -3,8 +3,13 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict"; "use strict";
const { serviceWorkerSpec } = require("devtools/shared/specs/worker/service-worker"); const {
const { FrontClassWithSpec, registerFront } = require("devtools/shared/protocol"); serviceWorkerSpec,
} = require("devtools/shared/specs/worker/service-worker");
const {
FrontClassWithSpec,
registerFront,
} = require("devtools/shared/protocol");
class ServiceWorkerFront extends FrontClassWithSpec(serviceWorkerSpec) { class ServiceWorkerFront extends FrontClassWithSpec(serviceWorkerSpec) {
get fetch() { get fetch() {

View file

@ -5,8 +5,9 @@
"use strict"; "use strict";
const { Cc, Ci } = require("chrome"); const { Cc, Ci } = require("chrome");
const { generateUUID } = const { generateUUID } = Cc["@mozilla.org/uuid-generator;1"].getService(
Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator); Ci.nsIUUIDGenerator
);
/** /**
* Returns a new `uuid`. * Returns a new `uuid`.

View file

@ -3,7 +3,9 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict"; "use strict";
const { flatten } = require("resource://devtools/shared/ThreadSafeDevToolsUtils.js"); const {
flatten,
} = require("resource://devtools/shared/ThreadSafeDevToolsUtils.js");
/** * Visitor ****************************************************************/ /** * Visitor ****************************************************************/
@ -11,7 +13,7 @@ const { flatten } = require("resource://devtools/shared/ThreadSafeDevToolsUtils.
* A Visitor visits each node and edge of a census report tree as the census * A Visitor visits each node and edge of a census report tree as the census
* report is being traversed by `walk`. * report is being traversed by `walk`.
*/ */
function Visitor() { } function Visitor() {}
exports.Visitor = Visitor; exports.Visitor = Visitor;
/** /**
@ -27,7 +29,7 @@ exports.Visitor = Visitor;
* The edge leading to this sub-report. The edge is null if (but not iff! * The edge leading to this sub-report. The edge is null if (but not iff!
* eg, null allocation stack edges) we are entering the root report. * eg, null allocation stack edges) we are entering the root report.
*/ */
Visitor.prototype.enter = function(breakdown, report, edge) { }; Visitor.prototype.enter = function(breakdown, report, edge) {};
/** /**
* The `exit` method is called when traversal of a sub-report has finished. * The `exit` method is called when traversal of a sub-report has finished.
@ -42,7 +44,7 @@ Visitor.prototype.enter = function(breakdown, report, edge) { };
* The edge leading to this sub-report. The edge is null if (but not iff! * The edge leading to this sub-report. The edge is null if (but not iff!
* eg, null allocation stack edges) we are entering the root report. * eg, null allocation stack edges) we are entering the root report.
*/ */
Visitor.prototype.exit = function(breakdown, report, edge) { }; Visitor.prototype.exit = function(breakdown, report, edge) {};
/** /**
* The `count` method is called when leaf nodes (reports whose breakdown is * The `count` method is called when leaf nodes (reports whose breakdown is
@ -58,7 +60,7 @@ Visitor.prototype.exit = function(breakdown, report, edge) { };
* The edge leading to this count report. The edge is null if we are * The edge leading to this count report. The edge is null if we are
* entering the root report. * entering the root report.
*/ */
Visitor.prototype.count = function(breakdown, report, edge) { }; Visitor.prototype.count = function(breakdown, report, edge) {};
/** * getReportEdges *********************************************************/ /** * getReportEdges *********************************************************/
@ -150,8 +152,11 @@ function recursiveWalk(breakdown, edge, report, visitor) {
visitor.exit(breakdown, report, edge); visitor.exit(breakdown, report, edge);
} else { } else {
visitor.enter(breakdown, report, edge); visitor.enter(breakdown, report, edge);
for (const { edge: ed, referent, breakdown: subBreakdown } for (const {
of getReportEdges(breakdown, report)) { edge: ed,
referent,
breakdown: subBreakdown,
} of getReportEdges(breakdown, report)) {
recursiveWalk(subBreakdown, ed, referent, visitor); recursiveWalk(subBreakdown, ed, referent, visitor);
} }
visitor.exit(breakdown, report, edge); visitor.exit(breakdown, report, edge);
@ -323,8 +328,8 @@ DiffVisitor.prototype.count = function(breakdown, report, edge) {
} }
}; };
const basisTotalBytes = exports.basisTotalBytes = Symbol("basisTotalBytes"); const basisTotalBytes = (exports.basisTotalBytes = Symbol("basisTotalBytes"));
const basisTotalCount = exports.basisTotalCount = Symbol("basisTotalCount"); const basisTotalCount = (exports.basisTotalCount = Symbol("basisTotalCount"));
/** /**
* Get the resulting report of the difference between the traversed census * Get the resulting report of the difference between the traversed census
@ -488,8 +493,10 @@ exports.getReportLeaves = function(indices, breakdown, report) {
exports.getCensusIndividuals = function(indices, countBreakdown, snapshot) { exports.getCensusIndividuals = function(indices, countBreakdown, snapshot) {
const bucketBreakdown = exports.countToBucketBreakdown(countBreakdown); const bucketBreakdown = exports.countToBucketBreakdown(countBreakdown);
const bucketReport = snapshot.takeCensus({ breakdown: bucketBreakdown }); const bucketReport = snapshot.takeCensus({ breakdown: bucketBreakdown });
const buckets = exports.getReportLeaves(indices, const buckets = exports.getReportLeaves(
bucketBreakdown, indices,
bucketReport); bucketBreakdown,
bucketReport
);
return flatten(buckets); return flatten(buckets);
}; };

View file

@ -3,9 +3,16 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict"; "use strict";
const { immutableUpdate } = require("resource://devtools/shared/ThreadSafeDevToolsUtils.js"); const {
const { Visitor, walk } = require("resource://devtools/shared/heapsnapshot/CensusUtils.js"); immutableUpdate,
const { deduplicatePaths } = require("resource://devtools/shared/heapsnapshot/shortest-paths"); } = require("resource://devtools/shared/ThreadSafeDevToolsUtils.js");
const {
Visitor,
walk,
} = require("resource://devtools/shared/heapsnapshot/CensusUtils.js");
const {
deduplicatePaths,
} = require("resource://devtools/shared/heapsnapshot/shortest-paths");
const DEFAULT_MAX_DEPTH = 4; const DEFAULT_MAX_DEPTH = 4;
const DEFAULT_MAX_SIBLINGS = 15; const DEFAULT_MAX_SIBLINGS = 15;
@ -163,9 +170,11 @@ LabelAndShallowSizeVisitor.prototype.shallowSize = function() {
* - {Number} shallowSize * - {Number} shallowSize
* - {Object} label * - {Object} label
*/ */
DominatorTreeNode.getLabelAndShallowSize = function(nodeId, DominatorTreeNode.getLabelAndShallowSize = function(
snapshot, nodeId,
breakdown) { snapshot,
breakdown
) {
const description = snapshot.describeNode(breakdown, nodeId); const description = snapshot.describeNode(breakdown, nodeId);
const visitor = new LabelAndShallowSizeVisitor(); const visitor = new LabelAndShallowSizeVisitor();
@ -194,16 +203,26 @@ DominatorTreeNode.getLabelAndShallowSize = function(nodeId,
* *
* @returns {DominatorTreeNode} * @returns {DominatorTreeNode}
*/ */
DominatorTreeNode.partialTraversal = function(dominatorTree, DominatorTreeNode.partialTraversal = function(
snapshot, dominatorTree,
breakdown, snapshot,
maxDepth = DEFAULT_MAX_DEPTH, breakdown,
maxSiblings = DEFAULT_MAX_SIBLINGS) { maxDepth = DEFAULT_MAX_DEPTH,
maxSiblings = DEFAULT_MAX_SIBLINGS
) {
function dfs(nodeId, depth) { function dfs(nodeId, depth) {
const { label, shallowSize } = const { label, shallowSize } = DominatorTreeNode.getLabelAndShallowSize(
DominatorTreeNode.getLabelAndShallowSize(nodeId, snapshot, breakdown); nodeId,
snapshot,
breakdown
);
const retainedSize = dominatorTree.getRetainedSize(nodeId); const retainedSize = dominatorTree.getRetainedSize(nodeId);
const node = new DominatorTreeNode(nodeId, label, shallowSize, retainedSize); const node = new DominatorTreeNode(
nodeId,
label,
shallowSize,
retainedSize
);
const childNodeIds = dominatorTree.getImmediatelyDominated(nodeId); const childNodeIds = dominatorTree.getImmediatelyDominated(nodeId);
const newDepth = depth + 1; const newDepth = depth + 1;
@ -237,7 +256,12 @@ DominatorTreeNode.partialTraversal = function(dominatorTree,
* *
* @returns {DominatorTreeNode} * @returns {DominatorTreeNode}
*/ */
DominatorTreeNode.insert = function(nodeTree, path, newChildren, moreChildrenAvailable) { DominatorTreeNode.insert = function(
nodeTree,
path,
newChildren,
moreChildrenAvailable
) {
function insert(tree, i) { function insert(tree, i) {
if (tree.nodeId !== path[i]) { if (tree.nodeId !== path[i]) {
return tree; return tree;
@ -252,8 +276,8 @@ DominatorTreeNode.insert = function(nodeTree, path, newChildren, moreChildrenAva
return tree.children return tree.children
? immutableUpdate(tree, { ? immutableUpdate(tree, {
children: tree.children.map(c => insert(c, i + 1)), children: tree.children.map(c => insert(c, i + 1)),
}) })
: tree; : tree;
} }
@ -306,11 +330,13 @@ DominatorTreeNode.getNodeByIdAlongPath = function(id, tree, path) {
* @param {Array<DominatorTreeNode>} treeNodes * @param {Array<DominatorTreeNode>} treeNodes
* @param {Number} maxNumPaths * @param {Number} maxNumPaths
*/ */
DominatorTreeNode.attachShortestPaths = function(snapshot, DominatorTreeNode.attachShortestPaths = function(
breakdown, snapshot,
start, breakdown,
treeNodes, start,
maxNumPaths = DEFAULT_MAX_NUM_PATHS) { treeNodes,
maxNumPaths = DEFAULT_MAX_NUM_PATHS
) {
const idToTreeNode = new Map(); const idToTreeNode = new Map();
const targets = []; const targets = [];
for (const node of treeNodes) { for (const node of treeNodes) {
@ -319,15 +345,20 @@ DominatorTreeNode.attachShortestPaths = function(snapshot,
targets.push(id); targets.push(id);
} }
const shortestPaths = snapshot.computeShortestPaths(start, const shortestPaths = snapshot.computeShortestPaths(
targets, start,
maxNumPaths); targets,
maxNumPaths
);
for (const [target, paths] of shortestPaths) { for (const [target, paths] of shortestPaths) {
const deduped = deduplicatePaths(target, paths); const deduped = deduplicatePaths(target, paths);
deduped.nodes = deduped.nodes.map(id => { deduped.nodes = deduped.nodes.map(id => {
const { label } = const { label } = DominatorTreeNode.getLabelAndShallowSize(
DominatorTreeNode.getLabelAndShallowSize(id, snapshot, breakdown); id,
snapshot,
breakdown
);
return { id, label }; return { id, label };
}); });

View file

@ -18,12 +18,12 @@ var workerCounter = 0;
* HeapAnalysesClient owns the worker, and terminating the worker is done by * HeapAnalysesClient owns the worker, and terminating the worker is done by
* terminating the client (see the `destroy` method). * terminating the client (see the `destroy` method).
*/ */
const HeapAnalysesClient = module.exports = function() { const HeapAnalysesClient = (module.exports = function() {
this._worker = new DevToolsWorker(WORKER_URL, { this._worker = new DevToolsWorker(WORKER_URL, {
name: `HeapAnalyses-${workerCounter++}`, name: `HeapAnalyses-${workerCounter++}`,
verbose: DevToolsUtils.dumpv.wantVerbose, verbose: DevToolsUtils.dumpv.wantVerbose,
}); });
}; });
/** /**
* Destroy the worker, causing it to release its resources (such as heap * Destroy the worker, causing it to release its resources (such as heap
@ -114,9 +114,11 @@ HeapAnalysesClient.prototype.getCreationTime = function(snapshotFilePath) {
* The result of calling CensusUtils.createParentMap on the generated * The result of calling CensusUtils.createParentMap on the generated
* report. Only exists if asTreeNode or asInvertedTreeNode are set. * report. Only exists if asTreeNode or asInvertedTreeNode are set.
*/ */
HeapAnalysesClient.prototype.takeCensus = function(snapshotFilePath, HeapAnalysesClient.prototype.takeCensus = function(
censusOptions, snapshotFilePath,
requestOptions = {}) { censusOptions,
requestOptions = {}
) {
return this._worker.performTask("takeCensus", { return this._worker.performTask("takeCensus", {
snapshotFilePath, snapshotFilePath,
censusOptions, censusOptions,
@ -190,10 +192,12 @@ HeapAnalysesClient.prototype.getCensusIndividuals = function(opts) {
* The result of calling CensusUtils.createParentMap on the generated * The result of calling CensusUtils.createParentMap on the generated
* delta. Only exists if asTreeNode or asInvertedTreeNode are set. * delta. Only exists if asTreeNode or asInvertedTreeNode are set.
*/ */
HeapAnalysesClient.prototype.takeCensusDiff = function(firstSnapshotFilePath, HeapAnalysesClient.prototype.takeCensusDiff = function(
secondSnapshotFilePath, firstSnapshotFilePath,
censusOptions, secondSnapshotFilePath,
requestOptions = {}) { censusOptions,
requestOptions = {}
) {
return this._worker.performTask("takeCensusDiff", { return this._worker.performTask("takeCensusDiff", {
firstSnapshotFilePath, firstSnapshotFilePath,
secondSnapshotFilePath, secondSnapshotFilePath,

View file

@ -14,7 +14,9 @@
importScripts("resource://gre/modules/workers/require.js"); importScripts("resource://gre/modules/workers/require.js");
importScripts("resource://devtools/shared/worker/helper.js"); importScripts("resource://devtools/shared/worker/helper.js");
const { censusReportToCensusTreeNode } = require("resource://devtools/shared/heapsnapshot/census-tree-node.js"); const {
censusReportToCensusTreeNode,
} = require("resource://devtools/shared/heapsnapshot/census-tree-node.js");
const DominatorTreeNode = require("resource://devtools/shared/heapsnapshot/DominatorTreeNode.js"); const DominatorTreeNode = require("resource://devtools/shared/heapsnapshot/DominatorTreeNode.js");
const CensusUtils = require("resource://devtools/shared/heapsnapshot/CensusUtils.js"); const CensusUtils = require("resource://devtools/shared/heapsnapshot/CensusUtils.js");
@ -46,8 +48,7 @@ const dominatorTreeSnapshots = [];
* @see HeapAnalysesClient.prototype.readHeapSnapshot * @see HeapAnalysesClient.prototype.readHeapSnapshot
*/ */
workerHelper.createTask(self, "readHeapSnapshot", ({ snapshotFilePath }) => { workerHelper.createTask(self, "readHeapSnapshot", ({ snapshotFilePath }) => {
snapshots[snapshotFilePath] = snapshots[snapshotFilePath] = ChromeUtils.readHeapSnapshot(snapshotFilePath);
ChromeUtils.readHeapSnapshot(snapshotFilePath);
return true; return true;
}); });
@ -72,26 +73,33 @@ workerHelper.createTask(self, "deleteHeapSnapshot", ({ snapshotFilePath }) => {
/** /**
* @see HeapAnalysesClient.prototype.takeCensus * @see HeapAnalysesClient.prototype.takeCensus
*/ */
workerHelper.createTask(self, "takeCensus", ( workerHelper.createTask(
{ snapshotFilePath, censusOptions, requestOptions }) => { self,
if (!snapshots[snapshotFilePath]) { "takeCensus",
throw new Error(`No known heap snapshot for '${snapshotFilePath}'`); ({ snapshotFilePath, censusOptions, requestOptions }) => {
} if (!snapshots[snapshotFilePath]) {
throw new Error(`No known heap snapshot for '${snapshotFilePath}'`);
let report = snapshots[snapshotFilePath].takeCensus(censusOptions);
let parentMap;
if (requestOptions.asTreeNode || requestOptions.asInvertedTreeNode) {
const opts = { filter: requestOptions.filter || null };
if (requestOptions.asInvertedTreeNode) {
opts.invert = true;
} }
report = censusReportToCensusTreeNode(censusOptions.breakdown, report, opts);
parentMap = CensusUtils.createParentMap(report);
}
return { report, parentMap }; let report = snapshots[snapshotFilePath].takeCensus(censusOptions);
}); let parentMap;
if (requestOptions.asTreeNode || requestOptions.asInvertedTreeNode) {
const opts = { filter: requestOptions.filter || null };
if (requestOptions.asInvertedTreeNode) {
opts.invert = true;
}
report = censusReportToCensusTreeNode(
censusOptions.breakdown,
report,
opts
);
parentMap = CensusUtils.createParentMap(report);
}
return { report, parentMap };
}
);
/** /**
* @see HeapAnalysesClient.prototype.getCensusIndividuals * @see HeapAnalysesClient.prototype.getCensusIndividuals
@ -109,29 +117,42 @@ workerHelper.createTask(self, "getCensusIndividuals", request => {
const dominatorTree = dominatorTrees[dominatorTreeId]; const dominatorTree = dominatorTrees[dominatorTreeId];
if (!dominatorTree) { if (!dominatorTree) {
throw new Error( throw new Error(
`There does not exist a DominatorTree with the id ${dominatorTreeId}`); `There does not exist a DominatorTree with the id ${dominatorTreeId}`
);
} }
const snapshot = dominatorTreeSnapshots[dominatorTreeId]; const snapshot = dominatorTreeSnapshots[dominatorTreeId];
const nodeIds = CensusUtils.getCensusIndividuals(indices, censusBreakdown, snapshot); const nodeIds = CensusUtils.getCensusIndividuals(
indices,
censusBreakdown,
snapshot
);
const nodes = nodeIds const nodes = nodeIds
.sort((a, b) => dominatorTree.getRetainedSize(b) - dominatorTree.getRetainedSize(a)) .sort(
(a, b) =>
dominatorTree.getRetainedSize(b) - dominatorTree.getRetainedSize(a)
)
.slice(0, maxIndividuals) .slice(0, maxIndividuals)
.map(id => { .map(id => {
const { label, shallowSize } = const { label, shallowSize } = DominatorTreeNode.getLabelAndShallowSize(
DominatorTreeNode.getLabelAndShallowSize(id, snapshot, labelBreakdown); id,
snapshot,
labelBreakdown
);
const retainedSize = dominatorTree.getRetainedSize(id); const retainedSize = dominatorTree.getRetainedSize(id);
const node = new DominatorTreeNode(id, label, shallowSize, retainedSize); const node = new DominatorTreeNode(id, label, shallowSize, retainedSize);
node.moreChildrenAvailable = false; node.moreChildrenAvailable = false;
return node; return node;
}); });
DominatorTreeNode.attachShortestPaths(snapshot, DominatorTreeNode.attachShortestPaths(
labelBreakdown, snapshot,
dominatorTree.root, labelBreakdown,
nodes, dominatorTree.root,
maxRetainingPaths); nodes,
maxRetainingPaths
);
return { nodes }; return { nodes };
}); });
@ -211,17 +232,20 @@ workerHelper.createTask(self, "getDominatorTree", request => {
if (!(dominatorTreeId >= 0 && dominatorTreeId < dominatorTrees.length)) { if (!(dominatorTreeId >= 0 && dominatorTreeId < dominatorTrees.length)) {
throw new Error( throw new Error(
`There does not exist a DominatorTree with the id ${dominatorTreeId}`); `There does not exist a DominatorTree with the id ${dominatorTreeId}`
);
} }
const dominatorTree = dominatorTrees[dominatorTreeId]; const dominatorTree = dominatorTrees[dominatorTreeId];
const snapshot = dominatorTreeSnapshots[dominatorTreeId]; const snapshot = dominatorTreeSnapshots[dominatorTreeId];
const tree = DominatorTreeNode.partialTraversal(dominatorTree, const tree = DominatorTreeNode.partialTraversal(
snapshot, dominatorTree,
breakdown, snapshot,
maxDepth, breakdown,
maxSiblings); maxDepth,
maxSiblings
);
const nodes = []; const nodes = [];
(function getNodes(node) { (function getNodes(node) {
@ -231,13 +255,15 @@ workerHelper.createTask(self, "getDominatorTree", request => {
getNodes(node.children[i]); getNodes(node.children[i]);
} }
} }
}(tree)); })(tree);
DominatorTreeNode.attachShortestPaths(snapshot, DominatorTreeNode.attachShortestPaths(
breakdown, snapshot,
dominatorTree.root, breakdown,
nodes, dominatorTree.root,
maxRetainingPaths); nodes,
maxRetainingPaths
);
return tree; return tree;
}); });
@ -257,7 +283,8 @@ workerHelper.createTask(self, "getImmediatelyDominated", request => {
if (!(dominatorTreeId >= 0 && dominatorTreeId < dominatorTrees.length)) { if (!(dominatorTreeId >= 0 && dominatorTreeId < dominatorTrees.length)) {
throw new Error( throw new Error(
`There does not exist a DominatorTree with the id ${dominatorTreeId}`); `There does not exist a DominatorTree with the id ${dominatorTreeId}`
);
} }
const dominatorTree = dominatorTrees[dominatorTreeId]; const dominatorTree = dominatorTrees[dominatorTreeId];
@ -272,19 +299,21 @@ workerHelper.createTask(self, "getImmediatelyDominated", request => {
const count = maxCount || DEFAULT_MAX_COUNT; const count = maxCount || DEFAULT_MAX_COUNT;
const end = start + count; const end = start + count;
const nodes = childIds const nodes = childIds.slice(start, end).map(id => {
.slice(start, end) const { label, shallowSize } = DominatorTreeNode.getLabelAndShallowSize(
.map(id => { id,
const { label, shallowSize } = snapshot,
DominatorTreeNode.getLabelAndShallowSize(id, snapshot, breakdown); breakdown
const retainedSize = dominatorTree.getRetainedSize(id); );
const node = new DominatorTreeNode(id, label, shallowSize, retainedSize); const retainedSize = dominatorTree.getRetainedSize(id);
node.parentId = nodeId; const node = new DominatorTreeNode(id, label, shallowSize, retainedSize);
// DominatorTree.getImmediatelyDominated will always return non-null here node.parentId = nodeId;
// because we got the id directly from the dominator tree. // DominatorTree.getImmediatelyDominated will always return non-null here
node.moreChildrenAvailable = dominatorTree.getImmediatelyDominated(id).length > 0; // because we got the id directly from the dominator tree.
return node; node.moreChildrenAvailable =
}); dominatorTree.getImmediatelyDominated(id).length > 0;
return node;
});
const path = []; const path = [];
let id = nodeId; let id = nodeId;
@ -296,11 +325,13 @@ workerHelper.createTask(self, "getImmediatelyDominated", request => {
const moreChildrenAvailable = childIds.length > end; const moreChildrenAvailable = childIds.length > end;
DominatorTreeNode.attachShortestPaths(snapshot, DominatorTreeNode.attachShortestPaths(
breakdown, snapshot,
dominatorTree.root, breakdown,
nodes, dominatorTree.root,
maxRetainingPaths); nodes,
maxRetainingPaths
);
return { nodes, moreChildrenAvailable, path }; return { nodes, moreChildrenAvailable, path };
}); });

View file

@ -23,8 +23,12 @@
"use strict"; "use strict";
const { Ci } = require("chrome"); const { Ci } = require("chrome");
loader.lazyRequireGetter(this, "FileUtils", loader.lazyRequireGetter(
"resource://gre/modules/FileUtils.jsm", true); this,
"FileUtils",
"resource://gre/modules/FileUtils.jsm",
true
);
loader.lazyRequireGetter(this, "OS", "resource://gre/modules/osfile.jsm", true); loader.lazyRequireGetter(this, "OS", "resource://gre/modules/osfile.jsm", true);
function getHeapSnapshotFileTemplate() { function getHeapSnapshotFileTemplate() {
@ -78,6 +82,5 @@ exports.haveHeapSnapshotTempFile = function(snapshotId) {
return Promise.resolve(false); return Promise.resolve(false);
} }
return OS.File.stat(path).then(() => true, return OS.File.stat(path).then(() => true, () => false);
() => false);
}; };

View file

@ -75,7 +75,9 @@ CensusTreeNodeCacheValue.prototype = null;
*/ */
CensusTreeNodeCache.hashFrame = function(frame) { CensusTreeNodeCache.hashFrame = function(frame) {
// eslint-disable-next-line max-len // eslint-disable-next-line max-len
return `FRAME,${frame.functionDisplayName},${frame.source},${frame.line},${frame.column},${frame.asyncCause}`; return `FRAME,${frame.functionDisplayName},${frame.source},${frame.line},${
frame.column
},${frame.asyncCause}`;
}; };
/** /**
@ -318,9 +320,11 @@ function values(cache) {
} }
function isNonEmpty(node) { function isNonEmpty(node) {
return (node.children !== undefined && node.children.length) return (
|| node.bytes !== 0 (node.children !== undefined && node.children.length) ||
|| node.count !== 0; node.bytes !== 0 ||
node.count !== 0
);
} }
/** /**
@ -388,7 +392,9 @@ CensusTreeNodeVisitor.prototype.count = function(breakdown, report, edge) {
*/ */
CensusTreeNodeVisitor.prototype.root = function() { CensusTreeNodeVisitor.prototype.root = function() {
if (!this._root) { if (!this._root) {
throw new Error("Attempt to get the root before walking the census report!"); throw new Error(
"Attempt to get the root before walking the census report!"
);
} }
if (this._nodeStack.length) { if (this._nodeStack.length) {
@ -468,10 +474,12 @@ CensusTreeNode.prototype = null;
* A number suitable for using with Array.prototype.sort. * A number suitable for using with Array.prototype.sort.
*/ */
function compareByTotal(node1, node2) { function compareByTotal(node1, node2) {
return Math.abs(node2.totalBytes) - Math.abs(node1.totalBytes) return (
|| Math.abs(node2.totalCount) - Math.abs(node1.totalCount) Math.abs(node2.totalBytes) - Math.abs(node1.totalBytes) ||
|| Math.abs(node2.bytes) - Math.abs(node1.bytes) Math.abs(node2.totalCount) - Math.abs(node1.totalCount) ||
|| Math.abs(node2.count) - Math.abs(node1.count); Math.abs(node2.bytes) - Math.abs(node1.bytes) ||
Math.abs(node2.count) - Math.abs(node1.count)
);
} }
/** /**
@ -485,10 +493,12 @@ function compareByTotal(node1, node2) {
* A number suitable for using with Array.prototype.sort. * A number suitable for using with Array.prototype.sort.
*/ */
function compareBySelf(node1, node2) { function compareBySelf(node1, node2) {
return Math.abs(node2.bytes) - Math.abs(node1.bytes) return (
|| Math.abs(node2.count) - Math.abs(node1.count) Math.abs(node2.bytes) - Math.abs(node1.bytes) ||
|| Math.abs(node2.totalBytes) - Math.abs(node1.totalBytes) Math.abs(node2.count) - Math.abs(node1.count) ||
|| Math.abs(node2.totalCount) - Math.abs(node1.totalCount); Math.abs(node2.totalBytes) - Math.abs(node1.totalBytes) ||
Math.abs(node2.totalCount) - Math.abs(node1.totalCount)
);
} }
/** /**
@ -515,8 +525,10 @@ function insertOrMergeNode(parentCacheValue, node) {
// When inverting, it is possible that multiple leaves in the census report // When inverting, it is possible that multiple leaves in the census report
// get merged into a single CensusTreeNode node. When this occurs, switch // get merged into a single CensusTreeNode node. When this occurs, switch
// from a single index to a set of indices. // from a single index to a set of indices.
if (val.node.reportLeafIndex !== undefined && if (
val.node.reportLeafIndex !== node.reportLeafIndex) { val.node.reportLeafIndex !== undefined &&
val.node.reportLeafIndex !== node.reportLeafIndex
) {
if (typeof val.node.reportLeafIndex === "number") { if (typeof val.node.reportLeafIndex === "number") {
const oldIndex = val.node.reportLeafIndex; const oldIndex = val.node.reportLeafIndex;
val.node.reportLeafIndex = new Set(); val.node.reportLeafIndex = new Set();
@ -582,7 +594,7 @@ function invert(tree) {
} }
path.pop(); path.pop();
}(tree)); })(tree);
// Ensure that the root node always has the totals. // Ensure that the root node always has the totals.
inverted.node.totalBytes = tree.totalBytes; inverted.node.totalBytes = tree.totalBytes;
@ -665,9 +677,11 @@ function makeFilterPredicate(filterString) {
} }
if (isSavedFrame(node.name)) { if (isSavedFrame(node.name)) {
return node.name.source.includes(filterString) return (
|| (node.name.functionDisplayName || "").includes(filterString) node.name.source.includes(filterString) ||
|| (node.name.asyncCause || "").includes(filterString); (node.name.functionDisplayName || "").includes(filterString) ||
(node.name.asyncCause || "").includes(filterString)
);
} }
return String(node.name).includes(filterString); return String(node.name).includes(filterString);
@ -704,11 +718,14 @@ function makeFilterPredicate(filterString) {
* *
* @returns {CensusTreeNode} * @returns {CensusTreeNode}
*/ */
exports.censusReportToCensusTreeNode = function(breakdown, report, exports.censusReportToCensusTreeNode = function(
options = { breakdown,
invert: false, report,
filter: null, options = {
}) { invert: false,
filter: null,
}
) {
// Reset the counter so that turning the same census report into a // Reset the counter so that turning the same census report into a
// CensusTreeNode tree repeatedly is idempotent. // CensusTreeNode tree repeatedly is idempotent.
censusTreeNodeIdCounter = 0; censusTreeNodeIdCounter = 0;
@ -743,7 +760,7 @@ exports.censusReportToCensusTreeNode = function(breakdown, report,
ensureSorted(node.children[i]); ensureSorted(node.children[i]);
} }
} }
}(result)); })(result);
return result; return result;
}; };

View file

@ -38,10 +38,12 @@ this.Census = (function() {
if (typeof subject === "object") { if (typeof subject === "object") {
dumpn(name); dumpn(name);
for (const prop in subject) { for (const prop in subject) {
count = walk(subject[prop], count = walk(
name + "[" + uneval(prop) + "]", subject[prop],
walker.enter(prop), name + "[" + uneval(prop) + "]",
count); walker.enter(prop),
count
);
} }
walker.done(); walker.done();
} else { } else {
@ -72,11 +74,15 @@ this.Census = (function() {
}; };
function expectedObject() { function expectedObject() {
throw new Error("Census mismatch: subject has leaf where basis has nested object"); throw new Error(
"Census mismatch: subject has leaf where basis has nested object"
);
} }
function expectedLeaf() { function expectedLeaf() {
throw new Error("Census mismatch: subject has nested object where basis has leaf"); throw new Error(
"Census mismatch: subject has nested object where basis has leaf"
);
} }
// Return a function that, given a 'basis' census, returns a census walker that // Return a function that, given a 'basis' census, returns a census walker that
@ -92,7 +98,7 @@ this.Census = (function() {
// - extra(prop): Called when the subject has a property named |prop|, but the // - extra(prop): Called when the subject has a property named |prop|, but the
// basis has no such property. This should return a walker that can check // basis has no such property. This should return a walker that can check
// the subject's value. // the subject's value.
function makeBasisChecker({compare, missing, extra}) { function makeBasisChecker({ compare, missing, extra }) {
return function makeWalker(basis) { return function makeWalker(basis) {
if (typeof basis === "object") { if (typeof basis === "object") {
const unvisited = new Set(Object.getOwnPropertyNames(basis)); const unvisited = new Set(Object.getOwnPropertyNames(basis));
@ -120,12 +126,15 @@ this.Census = (function() {
} }
function missingProp(prop) { function missingProp(prop) {
throw new Error("Census mismatch: subject lacks property present in basis: " + prop); throw new Error(
"Census mismatch: subject lacks property present in basis: " + prop
);
} }
function extraProp(prop) { function extraProp(prop) {
throw new Error("Census mismatch: subject has property not present in basis: " throw new Error(
+ prop); "Census mismatch: subject has property not present in basis: " + prop
);
} }
// Return a walker that checks that the subject census has counts all equal to // Return a walker that checks that the subject census has counts all equal to
@ -173,4 +182,4 @@ this.Census = (function() {
}; };
return Census; return Census;
}()); })();

View file

@ -9,7 +9,7 @@ this.EXPORTED_SYMBOLS = ["Match"];
this.Match = (function() { this.Match = (function() {
function Pattern(template) { function Pattern(template) {
// act like a constructor even as a function // act like a constructor even as a function
if (!(this instanceof Pattern)) { if (!(this instanceof Pattern)) {
return new Pattern(template); return new Pattern(template);
} }
@ -77,15 +77,17 @@ this.Match = (function() {
}; };
function isAtom(x) { function isAtom(x) {
return (typeof x === "number") || return (
(typeof x === "string") || typeof x === "number" ||
(typeof x === "boolean") || typeof x === "string" ||
(x === null) || typeof x === "boolean" ||
(typeof x === "object" && x instanceof RegExp); x === null ||
(typeof x === "object" && x instanceof RegExp)
);
} }
function isObject(x) { function isObject(x) {
return (x !== null) && (typeof x === "object"); return x !== null && typeof x === "object";
} }
function isFunction(x) { function isFunction(x) {
@ -93,12 +95,12 @@ this.Match = (function() {
} }
function isArrayLike(x) { function isArrayLike(x) {
return isObject(x) && ("length" in x); return isObject(x) && "length" in x;
} }
function matchAtom(act, exp) { function matchAtom(act, exp) {
if ((typeof exp) === "number" && isNaN(exp)) { if (typeof exp === "number" && isNaN(exp)) {
if ((typeof act) !== "number" || !isNaN(act)) { if (typeof act !== "number" || !isNaN(act)) {
throw new MatchError("expected NaN, got: " + quote(act)); throw new MatchError("expected NaN, got: " + quote(act));
} }
return true; return true;
@ -121,7 +123,9 @@ this.Match = (function() {
switch (typeof exp) { switch (typeof exp) {
case "string": case "string":
if (act !== exp) { if (act !== exp) {
throw new MatchError("expected " + quote(exp) + ", got " + quote(act)); throw new MatchError(
"expected " + quote(exp) + ", got " + quote(act)
);
} }
return true; return true;
case "boolean": case "boolean":
@ -142,8 +146,9 @@ this.Match = (function() {
for (const key in exp) { for (const key in exp) {
if (!(key in act)) { if (!(key in act)) {
throw new MatchError("expected property " + quote(key) throw new MatchError(
+ " not found in " + quote(act)); "expected property " + quote(key) + " not found in " + quote(act)
);
} }
match(act[key], exp[key]); match(act[key], exp[key]);
} }
@ -157,8 +162,9 @@ this.Match = (function() {
} }
if (act !== exp) { if (act !== exp) {
throw new MatchError("expected function: " + exp + throw new MatchError(
"\nbut got different function: " + act); "expected function: " + exp + "\nbut got different function: " + act
);
} }
} }
@ -169,15 +175,17 @@ this.Match = (function() {
const length = exp.length; const length = exp.length;
if (act.length !== exp.length) { if (act.length !== exp.length) {
throw new MatchError("expected array-like object of length " throw new MatchError(
+ length + ", got " + quote(act)); "expected array-like object of length " + length + ", got " + quote(act)
);
} }
for (let i = 0; i < length; i++) { for (let i = 0; i < length; i++) {
if (i in exp) { if (i in exp) {
if (!(i in act)) { if (!(i in act)) {
throw new MatchError("expected array property " + i + " not found in " throw new MatchError(
+ quote(act)); "expected array property " + i + " not found in " + quote(act)
);
} }
match(act[i], exp[i]); match(act[i], exp[i]);
} }

View file

@ -23,7 +23,10 @@ self.onmessage = e => {
} }
ok(threw, "Constructor shouldn't be usable"); ok(threw, "Constructor shouldn't be usable");
} catch (ex) { } catch (ex) {
ok(false, "Unexpected error inside worker:\n" + ex.toString() + "\n" + ex.stack); ok(
false,
"Unexpected error inside worker:\n" + ex.toString() + "\n" + ex.stack
);
} finally { } finally {
done(); done();
} }
@ -31,7 +34,7 @@ self.onmessage = e => {
// Proxy assertions to the main thread. // Proxy assertions to the main thread.
function ok(val, msg) { function ok(val, msg) {
console.log("ok(" + !!val + ", \"" + msg + "\")"); console.log("ok(" + !!val + ', "' + msg + '")');
self.postMessage({ self.postMessage({
type: "assertion", type: "assertion",
passed: !!val, passed: !!val,

View file

@ -14,17 +14,21 @@ var CC = Components.Constructor;
const { require } = ChromeUtils.import("resource://devtools/shared/Loader.jsm"); const { require } = ChromeUtils.import("resource://devtools/shared/Loader.jsm");
const { Match } = ChromeUtils.import("resource://test/Match.jsm"); const { Match } = ChromeUtils.import("resource://test/Match.jsm");
const { Census } = ChromeUtils.import("resource://test/Census.jsm"); const { Census } = ChromeUtils.import("resource://test/Census.jsm");
const { addDebuggerToGlobal } = const { addDebuggerToGlobal } = ChromeUtils.import(
ChromeUtils.import("resource://gre/modules/jsdebugger.jsm"); "resource://gre/modules/jsdebugger.jsm"
);
const DevToolsUtils = require("devtools/shared/DevToolsUtils"); const DevToolsUtils = require("devtools/shared/DevToolsUtils");
const HeapAnalysesClient = const HeapAnalysesClient = require("devtools/shared/heapsnapshot/HeapAnalysesClient");
require("devtools/shared/heapsnapshot/HeapAnalysesClient");
const Services = require("Services"); const Services = require("Services");
const { censusReportToCensusTreeNode } = require("devtools/shared/heapsnapshot/census-tree-node"); const {
censusReportToCensusTreeNode,
} = require("devtools/shared/heapsnapshot/census-tree-node");
const CensusUtils = require("devtools/shared/heapsnapshot/CensusUtils"); const CensusUtils = require("devtools/shared/heapsnapshot/CensusUtils");
const DominatorTreeNode = require("devtools/shared/heapsnapshot/DominatorTreeNode"); const DominatorTreeNode = require("devtools/shared/heapsnapshot/DominatorTreeNode");
const { deduplicatePaths } = require("devtools/shared/heapsnapshot/shortest-paths"); const {
deduplicatePaths,
} = require("devtools/shared/heapsnapshot/shortest-paths");
const { LabelAndShallowSizeVisitor } = DominatorTreeNode; const { LabelAndShallowSizeVisitor } = DominatorTreeNode;
// Always log packets when running tests. runxpcshelltests.py will throw // Always log packets when running tests. runxpcshelltests.py will throw
@ -38,8 +42,9 @@ if (Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_DEFAULT) {
}); });
} }
const SYSTEM_PRINCIPAL = Cc["@mozilla.org/systemprincipal;1"] const SYSTEM_PRINCIPAL = Cc["@mozilla.org/systemprincipal;1"].createInstance(
.createInstance(Ci.nsIPrincipal); Ci.nsIPrincipal
);
function dumpn(msg) { function dumpn(msg) {
dump("HEAPSNAPSHOT-TEST: " + msg + "\n"); dump("HEAPSNAPSHOT-TEST: " + msg + "\n");
@ -83,7 +88,7 @@ function assertThrows(f, val, msg) {
try { try {
f(); f();
} catch (exc) { } catch (exc) {
if ((exc === val) && (val !== 0 || 1 / exc === 1 / val)) { if (exc === val && (val !== 0 || 1 / exc === 1 / val)) {
return; return;
} else if (exc instanceof Error && exc.message === val) { } else if (exc instanceof Error && exc.message === val) {
return; return;
@ -91,7 +96,8 @@ function assertThrows(f, val, msg) {
fullmsg = "Assertion failed: expected exception " + val + ", got " + exc; fullmsg = "Assertion failed: expected exception " + val + ", got " + exc;
} }
if (fullmsg === undefined) { if (fullmsg === undefined) {
fullmsg = "Assertion failed: expected exception " + val + ", no exception thrown"; fullmsg =
"Assertion failed: expected exception " + val + ", no exception thrown";
} }
if (msg !== undefined) { if (msg !== undefined) {
fullmsg += " - " + msg; fullmsg += " - " + msg;
@ -103,12 +109,15 @@ function assertThrows(f, val, msg) {
* Returns the full path of the file with the specified name in a * Returns the full path of the file with the specified name in a
* platform-independent and URL-like form. * platform-independent and URL-like form.
*/ */
function getFilePath(name, allowMissing = false, usePlatformPathSeparator = false) { function getFilePath(
name,
allowMissing = false,
usePlatformPathSeparator = false
) {
const file = do_get_file(name, allowMissing); const file = do_get_file(name, allowMissing);
let path = Services.io.newFileURI(file).spec; let path = Services.io.newFileURI(file).spec;
let filePrePath = "file://"; let filePrePath = "file://";
if ("nsILocalFileWin" in Ci && if ("nsILocalFileWin" in Ci && file instanceof Ci.nsILocalFileWin) {
file instanceof Ci.nsILocalFileWin) {
filePrePath += "/"; filePrePath += "/";
} }
@ -131,7 +140,10 @@ function saveNewHeapSnapshot(opts = { runtime: true }) {
function readHeapSnapshot(filePath) { function readHeapSnapshot(filePath) {
const snapshot = ChromeUtils.readHeapSnapshot(filePath); const snapshot = ChromeUtils.readHeapSnapshot(filePath);
ok(snapshot, "Should have read a heap snapshot back from " + filePath); ok(snapshot, "Should have read a heap snapshot back from " + filePath);
ok(snapshot instanceof HeapSnapshot, "snapshot should be an instance of HeapSnapshot"); ok(
snapshot instanceof HeapSnapshot,
"snapshot should be an instance of HeapSnapshot"
);
return snapshot; return snapshot;
} }
@ -159,8 +171,11 @@ function saveHeapSnapshotAndTakeCensus(dbg = null, censusOptions = undefined) {
const filePath = saveNewHeapSnapshot(snapshotOptions); const filePath = saveNewHeapSnapshot(snapshotOptions);
const snapshot = readHeapSnapshot(filePath); const snapshot = readHeapSnapshot(filePath);
equal(typeof snapshot.takeCensus, "function", equal(
"snapshot should have a takeCensus method"); typeof snapshot.takeCensus,
"function",
"snapshot should have a takeCensus method"
);
return snapshot.takeCensus(censusOptions); return snapshot.takeCensus(censusOptions);
} }
@ -180,13 +195,19 @@ function saveHeapSnapshotAndComputeDominatorTree(dbg = null) {
const filePath = saveNewHeapSnapshot(snapshotOptions); const filePath = saveNewHeapSnapshot(snapshotOptions);
const snapshot = readHeapSnapshot(filePath); const snapshot = readHeapSnapshot(filePath);
equal(typeof snapshot.computeDominatorTree, "function", equal(
"snapshot should have a `computeDominatorTree` method"); typeof snapshot.computeDominatorTree,
"function",
"snapshot should have a `computeDominatorTree` method"
);
const dominatorTree = snapshot.computeDominatorTree(); const dominatorTree = snapshot.computeDominatorTree();
ok(dominatorTree, "Should be able to compute a dominator tree"); ok(dominatorTree, "Should be able to compute a dominator tree");
ok(dominatorTree instanceof DominatorTree, "Should be an instance of DominatorTree"); ok(
dominatorTree instanceof DominatorTree,
"Should be an instance of DominatorTree"
);
return dominatorTree; return dominatorTree;
} }
@ -197,7 +218,10 @@ function isSavedFrame(obj) {
function savedFrameReplacer(key, val) { function savedFrameReplacer(key, val) {
if (isSavedFrame(val)) { if (isSavedFrame(val)) {
return `<SavedFrame '${val.toString().split(/\n/g).shift()}'>`; return `<SavedFrame '${val
.toString()
.split(/\n/g)
.shift()}'>`;
} }
return val; return val;
} }
@ -243,50 +267,78 @@ function assertStructurallyEquivalent(actual, expected, path = "root") {
if (actual && typeof actual === "object") { if (actual && typeof actual === "object") {
const actualProtoString = Object.prototype.toString.call(actual); const actualProtoString = Object.prototype.toString.call(actual);
const expectedProtoString = Object.prototype.toString.call(expected); const expectedProtoString = Object.prototype.toString.call(expected);
equal(actualProtoString, expectedProtoString, equal(
`${path}: Object.prototype.toString.call() should be the same`); actualProtoString,
expectedProtoString,
`${path}: Object.prototype.toString.call() should be the same`
);
if (actualProtoString === "[object Map]") { if (actualProtoString === "[object Map]") {
const expectedKeys = new Set([...expected.keys()]); const expectedKeys = new Set([...expected.keys()]);
for (const key of actual.keys()) { for (const key of actual.keys()) {
ok(expectedKeys.has(key), ok(
`${path}: every key in actual is expected: ${String(key).slice(0, 10)}`); expectedKeys.has(key),
`${path}: every key in actual is expected: ${String(key).slice(
0,
10
)}`
);
expectedKeys.delete(key); expectedKeys.delete(key);
assertStructurallyEquivalent(actual.get(key), expected.get(key), assertStructurallyEquivalent(
path + ".get(" + String(key).slice(0, 20) + ")"); actual.get(key),
expected.get(key),
path + ".get(" + String(key).slice(0, 20) + ")"
);
} }
equal(expectedKeys.size, 0, equal(
expectedKeys.size,
0,
`${path}: every key in expected should also exist in actual,\ `${path}: every key in expected should also exist in actual,\
did not see ${[...expectedKeys]}`); did not see ${[...expectedKeys]}`
);
} else if (actualProtoString === "[object Set]") { } else if (actualProtoString === "[object Set]") {
const expectedItems = new Set([...expected]); const expectedItems = new Set([...expected]);
for (const item of actual) { for (const item of actual) {
ok(expectedItems.has(item), ok(
`${path}: every set item in actual should exist in expected: ${item}`); expectedItems.has(item),
`${path}: every set item in actual should exist in expected: ${item}`
);
expectedItems.delete(item); expectedItems.delete(item);
} }
equal(expectedItems.size, 0, equal(
expectedItems.size,
0,
`${path}: every set item in expected should also exist in actual,\ `${path}: every set item in expected should also exist in actual,\
did not see ${[...expectedItems]}`); did not see ${[...expectedItems]}`
);
} else { } else {
const expectedKeys = new Set(Object.keys(expected)); const expectedKeys = new Set(Object.keys(expected));
for (const key of Object.keys(actual)) { for (const key of Object.keys(actual)) {
ok(expectedKeys.has(key), ok(
`${path}: every key in actual should exist in expected: ${key}`); expectedKeys.has(key),
`${path}: every key in actual should exist in expected: ${key}`
);
expectedKeys.delete(key); expectedKeys.delete(key);
assertStructurallyEquivalent(actual[key], expected[key], path + "." + key); assertStructurallyEquivalent(
actual[key],
expected[key],
path + "." + key
);
} }
equal(expectedKeys.size, 0, equal(
expectedKeys.size,
0,
`${path}: every key in expected should also exist in actual,\ `${path}: every key in expected should also exist in actual,\
did not see ${[...expectedKeys]}`); did not see ${[...expectedKeys]}`
);
} }
} else { } else {
equal(actual, expected, `${path}: primitives should be equal`); equal(actual, expected, `${path}: primitives should be equal`);
@ -331,8 +383,12 @@ function assertDiff(breakdown, first, second, expected) {
* @param {Number} expectedShallowSize * @param {Number} expectedShallowSize
* @param {Object} expectedLabel * @param {Object} expectedLabel
*/ */
function assertLabelAndShallowSize(breakdown, givenDescription, function assertLabelAndShallowSize(
expectedShallowSize, expectedLabel) { breakdown,
givenDescription,
expectedShallowSize,
expectedLabel
) {
dumpn("Computing label and shallow size from node description:"); dumpn("Computing label and shallow size from node description:");
dumpn("Breakdown: " + JSON.stringify(breakdown, null, 4)); dumpn("Breakdown: " + JSON.stringify(breakdown, null, 4));
dumpn("Given description: " + JSON.stringify(givenDescription, null, 4)); dumpn("Given description: " + JSON.stringify(givenDescription, null, 4));
@ -342,7 +398,11 @@ function assertLabelAndShallowSize(breakdown, givenDescription,
dumpn("Expected shallow size: " + expectedShallowSize); dumpn("Expected shallow size: " + expectedShallowSize);
dumpn("Actual shallow size: " + visitor.shallowSize()); dumpn("Actual shallow size: " + visitor.shallowSize());
equal(visitor.shallowSize(), expectedShallowSize, "Shallow size should be correct"); equal(
visitor.shallowSize(),
expectedShallowSize,
"Shallow size should be correct"
);
dumpn("Expected label: " + JSON.stringify(expectedLabel, null, 4)); dumpn("Expected label: " + JSON.stringify(expectedLabel, null, 4));
dumpn("Actual label: " + JSON.stringify(visitor.label(), null, 4)); dumpn("Actual label: " + JSON.stringify(visitor.label(), null, 4));
@ -364,15 +424,21 @@ let TEST_NODE_ID_COUNTER = 0;
function makeTestDominatorTreeNode(opts, children) { function makeTestDominatorTreeNode(opts, children) {
const nodeId = TEST_NODE_ID_COUNTER++; const nodeId = TEST_NODE_ID_COUNTER++;
const node = Object.assign({ const node = Object.assign(
nodeId, {
label: undefined, nodeId,
shallowSize: 1, label: undefined,
retainedSize: (children || []).reduce((size, c) => size + c.retainedSize, 1), shallowSize: 1,
parentId: undefined, retainedSize: (children || []).reduce(
children, (size, c) => size + c.retainedSize,
moreChildrenAvailable: true, 1
}, opts); ),
parentId: undefined,
children,
moreChildrenAvailable: true,
},
opts
);
if (children && children.length) { if (children && children.length) {
children.map(c => (c.parentId = node.nodeId)); children.map(c => (c.parentId = node.nodeId));
@ -386,21 +452,36 @@ function makeTestDominatorTreeNode(opts, children) {
* `path` from the root to the node the `newChildren` should be inserted * `path` from the root to the node the `newChildren` should be inserted
* beneath. Assert that the resulting tree matches `expected`. * beneath. Assert that the resulting tree matches `expected`.
*/ */
function assertDominatorTreeNodeInsertion(tree, path, newChildren, function assertDominatorTreeNodeInsertion(
moreChildrenAvailable, expected) { tree,
path,
newChildren,
moreChildrenAvailable,
expected
) {
dumpn("Inserting new children into a dominator tree:"); dumpn("Inserting new children into a dominator tree:");
dumpn("Dominator tree: " + JSON.stringify(tree, null, 2)); dumpn("Dominator tree: " + JSON.stringify(tree, null, 2));
dumpn("Path: " + JSON.stringify(path, null, 2)); dumpn("Path: " + JSON.stringify(path, null, 2));
dumpn("New children: " + JSON.stringify(newChildren, null, 2)); dumpn("New children: " + JSON.stringify(newChildren, null, 2));
dumpn("Expected resulting tree: " + JSON.stringify(expected, null, 2)); dumpn("Expected resulting tree: " + JSON.stringify(expected, null, 2));
const actual = DominatorTreeNode.insert(tree, path, newChildren, moreChildrenAvailable); const actual = DominatorTreeNode.insert(
tree,
path,
newChildren,
moreChildrenAvailable
);
dumpn("Actual resulting tree: " + JSON.stringify(actual, null, 2)); dumpn("Actual resulting tree: " + JSON.stringify(actual, null, 2));
assertStructurallyEquivalent(actual, expected); assertStructurallyEquivalent(actual, expected);
} }
function assertDeduplicatedPaths({ target, paths, expectedNodes, expectedEdges }) { function assertDeduplicatedPaths({
target,
paths,
expectedNodes,
expectedEdges,
}) {
dumpn("Deduplicating paths:"); dumpn("Deduplicating paths:");
dumpn("target = " + target); dumpn("target = " + target);
dumpn("paths = " + JSON.stringify(paths, null, 2)); dumpn("paths = " + JSON.stringify(paths, null, 2));
@ -412,16 +493,21 @@ function assertDeduplicatedPaths({ target, paths, expectedNodes, expectedEdges }
dumpn("Actual nodes = " + nodes); dumpn("Actual nodes = " + nodes);
dumpn("Actual edges = " + JSON.stringify(edges, null, 2)); dumpn("Actual edges = " + JSON.stringify(edges, null, 2));
equal(nodes.length, expectedNodes.length, equal(
"actual number of nodes is equal to the expected number of nodes"); nodes.length,
expectedNodes.length,
"actual number of nodes is equal to the expected number of nodes"
);
equal(edges.length, expectedEdges.length, equal(
"actual number of edges is equal to the expected number of edges"); edges.length,
expectedEdges.length,
"actual number of edges is equal to the expected number of edges"
);
const expectedNodeSet = new Set(expectedNodes); const expectedNodeSet = new Set(expectedNodes);
const nodeSet = new Set(nodes); const nodeSet = new Set(nodes);
ok(nodeSet.size === nodes.length, ok(nodeSet.size === nodes.length, "each returned node should be unique");
"each returned node should be unique");
for (const node of nodes) { for (const node of nodes) {
ok(expectedNodeSet.has(node), `the ${node} node was expected`); ok(expectedNodeSet.has(node), `the ${node} node was expected`);
@ -430,15 +516,20 @@ function assertDeduplicatedPaths({ target, paths, expectedNodes, expectedEdges }
for (const expectedEdge of expectedEdges) { for (const expectedEdge of expectedEdges) {
let count = 0; let count = 0;
for (const edge of edges) { for (const edge of edges) {
if (edge.from === expectedEdge.from && if (
edge.to === expectedEdge.to && edge.from === expectedEdge.from &&
edge.name === expectedEdge.name) { edge.to === expectedEdge.to &&
edge.name === expectedEdge.name
) {
count++; count++;
} }
} }
equal(count, 1, equal(
"should have exactly one matching edge for the expected edge = " count,
+ JSON.stringify(expectedEdge)); 1,
"should have exactly one matching edge for the expected edge = " +
JSON.stringify(expectedEdge)
);
} }
} }

View file

@ -8,19 +8,23 @@ console.log("Initializing worker.");
self.onmessage = ex => { self.onmessage = ex => {
console.log("Starting test."); console.log("Starting test.");
try { try {
ok(ChromeUtils, ok(ChromeUtils, "Should have access to ChromeUtils in a worker.");
"Should have access to ChromeUtils in a worker."); ok(HeapSnapshot, "Should have access to HeapSnapshot in a worker.");
ok(HeapSnapshot,
"Should have access to HeapSnapshot in a worker.");
const filePath = ChromeUtils.saveHeapSnapshot({ globals: [this] }); const filePath = ChromeUtils.saveHeapSnapshot({ globals: [this] });
ok(true, "Should be able to save a snapshot."); ok(true, "Should be able to save a snapshot.");
const snapshot = ChromeUtils.readHeapSnapshot(filePath); const snapshot = ChromeUtils.readHeapSnapshot(filePath);
ok(snapshot, "Should be able to read a heap snapshot"); ok(snapshot, "Should be able to read a heap snapshot");
ok(snapshot instanceof HeapSnapshot, "Should be an instanceof HeapSnapshot"); ok(
snapshot instanceof HeapSnapshot,
"Should be an instanceof HeapSnapshot"
);
} catch (e) { } catch (e) {
ok(false, "Unexpected error inside worker:\n" + e.toString() + "\n" + e.stack); ok(
false,
"Unexpected error inside worker:\n" + e.toString() + "\n" + e.stack
);
} finally { } finally {
done(); done();
} }
@ -28,7 +32,7 @@ self.onmessage = ex => {
// Proxy assertions to the main thread. // Proxy assertions to the main thread.
function ok(val, msg) { function ok(val, msg) {
console.log("ok(" + !!val + ", \"" + msg + "\")"); console.log("ok(" + !!val + ', "' + msg + '")');
self.postMessage({ self.postMessage({
type: "assertion", type: "assertion",
passed: !!val, passed: !!val,

View file

@ -40,10 +40,7 @@ const description = {
domNode: {}, domNode: {},
}; };
const expected = [ const expected = ["objects", "Function"];
"objects",
"Function",
];
const shallowSize = 32; const shallowSize = 32;

View file

@ -39,10 +39,7 @@ const description = {
domNode: {}, domNode: {},
}; };
const expected = [ const expected = ["objects", "other"];
"objects",
"other",
];
const shallowSize = 10; const shallowSize = 10;

View file

@ -34,17 +34,14 @@ const description = {
other: { count: 0, bytes: 0 }, other: { count: 0, bytes: 0 },
}, },
strings: { strings: {
"JSString": { count: 1, bytes: 42 }, JSString: { count: 1, bytes: 42 },
}, },
scripts: {}, scripts: {},
other: {}, other: {},
domNode: {}, domNode: {},
}; };
const expected = [ const expected = ["strings", "JSString"];
"strings",
"JSString",
];
const shallowSize = 42; const shallowSize = 42;

View file

@ -46,11 +46,7 @@ const description = {
domNode: {}, domNode: {},
}; };
const expected = [ const expected = ["objects", "Array", stack];
"objects",
"Array",
stack,
];
const shallowSize = 512; const shallowSize = 512;

View file

@ -10,21 +10,25 @@ const maxNumPaths = 2;
// Mock data mapping node id to shortest paths to that node id. // Mock data mapping node id to shortest paths to that node id.
const shortestPaths = new Map([ const shortestPaths = new Map([
[1000, [ [
[pathEntry(1100, "a"), pathEntry(1200, "b")], 1000,
[pathEntry(1100, "c"), pathEntry(1300, "d")], [
]], [pathEntry(1100, "a"), pathEntry(1200, "b")],
[2000, [ [pathEntry(1100, "c"), pathEntry(1300, "d")],
[pathEntry(2100, "e"), pathEntry(2200, "f"), pathEntry(2300, "g")], ],
]], ],
[3000, [ [2000, [[pathEntry(2100, "e"), pathEntry(2200, "f"), pathEntry(2300, "g")]]],
[pathEntry(3100, "h")], [
[pathEntry(3100, "i")], 3000,
[pathEntry(3100, "j")], [
[pathEntry(3200, "k")], [pathEntry(3100, "h")],
[pathEntry(3300, "l")], [pathEntry(3100, "i")],
[pathEntry(3400, "m")], [pathEntry(3100, "j")],
]], [pathEntry(3200, "k")],
[pathEntry(3300, "l")],
[pathEntry(3400, "m")],
],
],
]); ]);
const actual = [ const actual = [
@ -101,11 +105,13 @@ const mockSnapshot = {
equal(start, startNodeId); equal(start, startNodeId);
equal(max, maxNumPaths); equal(max, maxNumPaths);
return new Map(nodeIds.map(nodeId => { return new Map(
const paths = shortestPaths.get(nodeId); nodeIds.map(nodeId => {
ok(paths, "Expected computeShortestPaths call for node id = " + nodeId); const paths = shortestPaths.get(nodeId);
return [nodeId, paths]; ok(paths, "Expected computeShortestPaths call for node id = " + nodeId);
})); return [nodeId, paths];
})
);
}, },
describeNode: (bd, nodeId) => { describeNode: (bd, nodeId) => {
@ -120,11 +126,13 @@ const mockSnapshot = {
}; };
function run_test() { function run_test() {
DominatorTreeNode.attachShortestPaths(mockSnapshot, DominatorTreeNode.attachShortestPaths(
breakdown, mockSnapshot,
startNodeId, breakdown,
actual, startNodeId,
maxNumPaths); actual,
maxNumPaths
);
dumpn("Expected = " + JSON.stringify(expected, null, 2)); dumpn("Expected = " + JSON.stringify(expected, null, 2));
dumpn("Actual = " + JSON.stringify(actual, null, 2)); dumpn("Actual = " + JSON.stringify(actual, null, 2));

View file

@ -34,12 +34,16 @@ function run_test() {
equal(actual, expected, `We should have got the node with id = ${id}`); equal(actual, expected, `We should have got the node with id = ${id}`);
} }
equal(null, equal(
DominatorTreeNode.getNodeByIdAlongPath(999999999999, tree, path), null,
"null is returned for nodes that are not even in the tree"); DominatorTreeNode.getNodeByIdAlongPath(999999999999, tree, path),
"null is returned for nodes that are not even in the tree"
);
const lastNodeId = tree.children[tree.children.length - 1].nodeId; const lastNodeId = tree.children[tree.children.length - 1].nodeId;
equal(null, equal(
DominatorTreeNode.getNodeByIdAlongPath(lastNodeId, tree, path), null,
"null is returned for nodes that are not along the path"); DominatorTreeNode.getNodeByIdAlongPath(lastNodeId, tree, path),
"null is returned for nodes that are not along the path"
);
} }

View file

@ -109,6 +109,11 @@ const expected = {
}; };
function run_test() { function run_test() {
assertDominatorTreeNodeInsertion(tree, path, newChildren, assertDominatorTreeNodeInsertion(
moreChildrenAvailable, expected); tree,
path,
newChildren,
moreChildrenAvailable,
expected
);
} }

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