зеркало из https://github.com/mozilla/pjs.git
Bug 693265 - Carefully review the exposed GCLI API; r=msucan
This commit is contained in:
Родитель
2ad9dd48b9
Коммит
6c5692b6e7
|
@ -38,82 +38,21 @@
|
|||
|
||||
let EXPORTED_SYMBOLS = [ "GcliCommands" ];
|
||||
|
||||
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
Components.utils.import("resource:///modules/gcli.jsm");
|
||||
Components.utils.import("resource:///modules/HUDService.jsm");
|
||||
|
||||
let bundleName = "chrome://browser/locale/devtools/gclicommands.properties";
|
||||
let stringBundle = Services.strings.createBundle(bundleName);
|
||||
|
||||
let gcli = gcli._internal.require("gcli/index");
|
||||
let canon = gcli._internal.require("gcli/canon");
|
||||
|
||||
|
||||
let document;
|
||||
|
||||
/**
|
||||
* The exported API
|
||||
*/
|
||||
let GcliCommands = {
|
||||
/**
|
||||
* Allow HUDService to inform us of the document against which we work
|
||||
*/
|
||||
setDocument: function GcliCommands_setDocument(aDocument) {
|
||||
document = aDocument;
|
||||
},
|
||||
|
||||
/**
|
||||
* Undo the effects of GcliCommands.setDocument()
|
||||
*/
|
||||
unsetDocument: function GcliCommands_unsetDocument() {
|
||||
document = undefined;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Lookup a string in the GCLI string bundle
|
||||
* @param aName The name to lookup
|
||||
* @return The looked up name
|
||||
*/
|
||||
function lookup(aName)
|
||||
{
|
||||
try {
|
||||
return stringBundle.GetStringFromName(aName);
|
||||
} catch (ex) {
|
||||
throw new Error("Failure in lookup('" + aName + "')");
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Lookup a string in the GCLI string bundle
|
||||
* @param aName The name to lookup
|
||||
* @param aSwaps An array of swaps. See stringBundle.formatStringFromName
|
||||
* @return The looked up name
|
||||
*/
|
||||
function lookupFormat(aName, aSwaps)
|
||||
{
|
||||
try {
|
||||
return stringBundle.formatStringFromName(aName, aSwaps, aSwaps.length);
|
||||
} catch (ex) {
|
||||
Services.console.logStringMessage("Failure in lookupFormat('" + aName + "')");
|
||||
throw new Error("Failure in lookupFormat('" + aName + "')");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 'echo' command
|
||||
*/
|
||||
gcli.addCommand({
|
||||
name: "echo",
|
||||
description: lookup("echoDesc"),
|
||||
description: gcli.lookup("echoDesc"),
|
||||
params: [
|
||||
{
|
||||
name: "message",
|
||||
type: "string",
|
||||
description: lookup("echoMessageDesc")
|
||||
description: gcli.lookup("echoMessageDesc")
|
||||
}
|
||||
],
|
||||
returnType: "string",
|
||||
|
@ -123,17 +62,19 @@ gcli.addCommand({
|
|||
});
|
||||
|
||||
|
||||
let canon = gcli._internal.require("gcli/canon");
|
||||
|
||||
/**
|
||||
* 'help' command
|
||||
*/
|
||||
gcli.addCommand({
|
||||
name: "help",
|
||||
returnType: "html",
|
||||
description: lookup("helpDesc"),
|
||||
description: gcli.lookup("helpDesc"),
|
||||
exec: function Command_help(args, context) {
|
||||
let output = [];
|
||||
|
||||
output.push("<strong>" + lookup("helpAvailable") + ":</strong><br/>");
|
||||
output.push("<strong>" + gcli.lookup("helpAvailable") + ":</strong><br/>");
|
||||
|
||||
let commandNames = canon.getCommandNames();
|
||||
commandNames.sort();
|
||||
|
@ -160,8 +101,8 @@ gcli.addCommand({
|
|||
*/
|
||||
gcli.addCommand({
|
||||
name: "console",
|
||||
description: lookup("consoleDesc"),
|
||||
manual: lookup("consoleManual")
|
||||
description: gcli.lookup("consoleDesc"),
|
||||
manual: gcli.lookup("consoleManual")
|
||||
});
|
||||
|
||||
/**
|
||||
|
@ -169,7 +110,7 @@ gcli.addCommand({
|
|||
*/
|
||||
gcli.addCommand({
|
||||
name: "console clear",
|
||||
description: lookup("consoleclearDesc"),
|
||||
description: gcli.lookup("consoleclearDesc"),
|
||||
exec: function(args, context) {
|
||||
let hud = HUDService.getHudReferenceById(context.environment.hudId);
|
||||
hud.gcliterm.clearOutput();
|
||||
|
|
|
@ -79,12 +79,6 @@ XPCOMUtils.defineLazyGetter(this, "gcli", function () {
|
|||
return obj.gcli;
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "GcliCommands", function () {
|
||||
var obj = {};
|
||||
Cu.import("resource:///modules/GcliCommands.jsm", obj);
|
||||
return obj.GcliCommands;
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "StyleInspector", function () {
|
||||
var obj = {};
|
||||
Cu.import("resource:///modules/devtools/StyleInspector.jsm", obj);
|
||||
|
@ -133,6 +127,23 @@ function LogFactory(aMessagePrefix)
|
|||
return log;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the various Command JSMs.
|
||||
* Should be called when the console first opens.
|
||||
*
|
||||
* @return an object containing the EXPORTED_SYMBOLS from all the command
|
||||
* modules. In general there is no reason when JSMs need to export symbols
|
||||
* except when they need the host environment to inform them of things like the
|
||||
* current window/document/etc.
|
||||
*/
|
||||
function loadCommands() {
|
||||
let commandExports = {};
|
||||
|
||||
Cu.import("resource:///modules/GcliCommands.jsm", commandExports);
|
||||
|
||||
return commandExports;
|
||||
}
|
||||
|
||||
let log = LogFactory("*** HUDService:");
|
||||
|
||||
const HUD_STRINGS_URI = "chrome://global/locale/headsUpDisplay.properties";
|
||||
|
@ -6882,6 +6893,11 @@ catch (ex) {
|
|||
// GcliTerm
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Some commands need customization - this is how we get at them.
|
||||
*/
|
||||
let commandExports = undefined;
|
||||
|
||||
/**
|
||||
* GcliTerm
|
||||
*
|
||||
|
@ -6932,7 +6948,10 @@ function GcliTerm(aContentWindow, aHudId, aDocument, aConsole, aHintNode)
|
|||
|
||||
gcli._internal.commandOutputManager.addListener(this.onCommandOutput, this);
|
||||
gcli._internal.createView(this.opts);
|
||||
GcliCommands.setDocument(aContentWindow.document);
|
||||
|
||||
if (!commandExports) {
|
||||
commandExports = loadCommands();
|
||||
}
|
||||
}
|
||||
|
||||
GcliTerm.prototype = {
|
||||
|
@ -6957,7 +6976,6 @@ GcliTerm.prototype = {
|
|||
*/
|
||||
destroy: function Gcli_destroy()
|
||||
{
|
||||
GcliCommands.unsetDocument();
|
||||
gcli._internal.removeView(this.opts);
|
||||
gcli._internal.commandOutputManager.removeListener(this.onCommandOutput, this);
|
||||
|
||||
|
|
|
@ -630,11 +630,52 @@ var require = define.globalDomain.require.bind(define.globalDomain);
|
|||
* http://opensource.org/licenses/BSD-3-Clause
|
||||
*/
|
||||
|
||||
var mozl10n = {};
|
||||
|
||||
(function(aMozl10n) {
|
||||
var temp = {};
|
||||
Components.utils.import("resource://gre/modules/Services.jsm", temp);
|
||||
var stringBundle = temp.Services.strings.createBundle(
|
||||
"chrome://browser/locale/devtools/gclicommands.properties");
|
||||
|
||||
/**
|
||||
* Lookup a string in the GCLI string bundle
|
||||
* @param name The name to lookup
|
||||
* @return The looked up name
|
||||
*/
|
||||
aMozl10n.lookup = function(name) {
|
||||
try {
|
||||
return stringBundle.GetStringFromName(name);
|
||||
}
|
||||
catch (ex) {
|
||||
throw new Error("Failure in lookup('" + name + "')");
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Lookup a string in the GCLI string bundle
|
||||
* @param name The name to lookup
|
||||
* @param swaps An array of swaps. See stringBundle.formatStringFromName
|
||||
* @return The looked up name
|
||||
*/
|
||||
aMozl10n.lookupFormat = function(name, swaps) {
|
||||
try {
|
||||
return stringBundle.formatStringFromName(name, swaps, swaps.length);
|
||||
}
|
||||
catch (ex) {
|
||||
throw new Error("Failure in lookupFormat('" + name + "')");
|
||||
}
|
||||
};
|
||||
|
||||
})(mozl10n);
|
||||
|
||||
define('gcli/index', ['require', 'exports', 'module' , 'gcli/canon', 'gcli/types/basic', 'gcli/types/javascript', 'gcli/types/node', 'gcli/cli', 'gcli/ui/inputter', 'gcli/ui/arg_fetch', 'gcli/ui/menu', 'gcli/ui/focus'], function(require, exports, module) {
|
||||
|
||||
// The API for use by command authors
|
||||
exports.addCommand = require('gcli/canon').addCommand;
|
||||
exports.removeCommand = require('gcli/canon').removeCommand;
|
||||
exports.lookup = mozl10n.lookup;
|
||||
exports.lookupFormat = mozl10n.lookupFormat;
|
||||
|
||||
// Internal startup process. Not exported
|
||||
require('gcli/types/basic').startup();
|
||||
|
@ -4197,16 +4238,17 @@ Requisition.prototype._onCommandAssignmentChange = function(ev) {
|
|||
/**
|
||||
* Assignments have an order, so we need to store them in an array.
|
||||
* But we also need named access ...
|
||||
* @return The found assignment, or undefined, if no match was found
|
||||
*/
|
||||
Requisition.prototype.getAssignment = function(nameOrNumber) {
|
||||
var name = (typeof nameOrNumber === 'string') ?
|
||||
nameOrNumber :
|
||||
Object.keys(this._assignments)[nameOrNumber];
|
||||
return this._assignments[name];
|
||||
return this._assignments[name] || undefined;
|
||||
},
|
||||
|
||||
/**
|
||||
* Where parameter name == assignment names - they are the same.
|
||||
* Where parameter name == assignment names - they are the same
|
||||
*/
|
||||
Requisition.prototype.getParameterNames = function() {
|
||||
return Object.keys(this._assignments);
|
||||
|
@ -5041,210 +5083,8 @@ ExecutionContext.prototype.createPromise = function() {
|
|||
|
||||
define('gcli/promise', ['require', 'exports', 'module' ], function(require, exports, module) {
|
||||
|
||||
|
||||
/**
|
||||
* Create an unfulfilled promise
|
||||
* @constructor
|
||||
*/
|
||||
function Promise() {
|
||||
this._status = Promise.PENDING;
|
||||
this._value = undefined;
|
||||
this._onSuccessHandlers = [];
|
||||
this._onErrorHandlers = [];
|
||||
|
||||
// Debugging help
|
||||
this._id = Promise._nextId++;
|
||||
Promise._outstanding[this._id] = this;
|
||||
};
|
||||
|
||||
/**
|
||||
* We give promises and ID so we can track which are outstanding
|
||||
*/
|
||||
Promise._nextId = 0;
|
||||
|
||||
/**
|
||||
* Outstanding promises. Handy list for debugging only.
|
||||
*/
|
||||
Promise._outstanding = [];
|
||||
|
||||
/**
|
||||
* Recently resolved promises. Also for debugging only.
|
||||
*/
|
||||
Promise._recent = [];
|
||||
|
||||
/**
|
||||
* A promise can be in one of 2 states.
|
||||
* The ERROR and SUCCESS states are terminal, the PENDING state is the only
|
||||
* start state.
|
||||
*/
|
||||
Promise.ERROR = -1;
|
||||
Promise.PENDING = 0;
|
||||
Promise.SUCCESS = 1;
|
||||
|
||||
/**
|
||||
* Yeay for RTTI.
|
||||
*/
|
||||
Promise.prototype.isPromise = true;
|
||||
|
||||
/**
|
||||
* Have we either been resolve()ed or reject()ed?
|
||||
*/
|
||||
Promise.prototype.isComplete = function() {
|
||||
return this._status != Promise.PENDING;
|
||||
};
|
||||
|
||||
/**
|
||||
* Have we resolve()ed?
|
||||
*/
|
||||
Promise.prototype.isResolved = function() {
|
||||
return this._status == Promise.SUCCESS;
|
||||
};
|
||||
|
||||
/**
|
||||
* Have we reject()ed?
|
||||
*/
|
||||
Promise.prototype.isRejected = function() {
|
||||
return this._status == Promise.ERROR;
|
||||
};
|
||||
|
||||
/**
|
||||
* Take the specified action of fulfillment of a promise, and (optionally)
|
||||
* a different action on promise rejection.
|
||||
*/
|
||||
Promise.prototype.then = function(onSuccess, onError) {
|
||||
if (typeof onSuccess === 'function') {
|
||||
if (this._status === Promise.SUCCESS) {
|
||||
onSuccess.call(null, this._value);
|
||||
} else if (this._status === Promise.PENDING) {
|
||||
this._onSuccessHandlers.push(onSuccess);
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof onError === 'function') {
|
||||
if (this._status === Promise.ERROR) {
|
||||
onError.call(null, this._value);
|
||||
} else if (this._status === Promise.PENDING) {
|
||||
this._onErrorHandlers.push(onError);
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Like then() except that rather than returning <tt>this</tt> we return
|
||||
* a promise which resolves when the original promise resolves.
|
||||
*/
|
||||
Promise.prototype.chainPromise = function(onSuccess) {
|
||||
var chain = new Promise();
|
||||
chain._chainedFrom = this;
|
||||
this.then(function(data) {
|
||||
try {
|
||||
chain.resolve(onSuccess(data));
|
||||
} catch (ex) {
|
||||
chain.reject(ex);
|
||||
}
|
||||
}, function(ex) {
|
||||
chain.reject(ex);
|
||||
});
|
||||
return chain;
|
||||
};
|
||||
|
||||
/**
|
||||
* Supply the fulfillment of a promise
|
||||
*/
|
||||
Promise.prototype.resolve = function(data) {
|
||||
return this._complete(this._onSuccessHandlers, Promise.SUCCESS, data, 'resolve');
|
||||
};
|
||||
|
||||
/**
|
||||
* Renege on a promise
|
||||
*/
|
||||
Promise.prototype.reject = function(data) {
|
||||
return this._complete(this._onErrorHandlers, Promise.ERROR, data, 'reject');
|
||||
};
|
||||
|
||||
/**
|
||||
* Internal method to be called on resolve() or reject().
|
||||
* @private
|
||||
*/
|
||||
Promise.prototype._complete = function(list, status, data, name) {
|
||||
// Complain if we've already been completed
|
||||
if (this._status != Promise.PENDING) {
|
||||
console.group('Promise already closed');
|
||||
console.error('Attempted ' + name + '() with ', data);
|
||||
console.error('Previous status = ', this._status,
|
||||
', previous value = ', this._value);
|
||||
console.trace();
|
||||
|
||||
console.groupEnd();
|
||||
return this;
|
||||
}
|
||||
|
||||
this._status = status;
|
||||
this._value = data;
|
||||
|
||||
// Call all the handlers, and then delete them
|
||||
list.forEach(function(handler) {
|
||||
handler.call(null, this._value);
|
||||
}, this);
|
||||
delete this._onSuccessHandlers;
|
||||
delete this._onErrorHandlers;
|
||||
|
||||
// Remove the given {promise} from the _outstanding list, and add it to the
|
||||
// _recent list, pruning more than 20 recent promises from that list.
|
||||
delete Promise._outstanding[this._id];
|
||||
Promise._recent.push(this);
|
||||
while (Promise._recent.length > 20) {
|
||||
Promise._recent.shift();
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Takes an array of promises and returns a promise that that is fulfilled once
|
||||
* all the promises in the array are fulfilled
|
||||
* @param promiseList The array of promises
|
||||
* @return the promise that is fulfilled when all the array is fulfilled
|
||||
*/
|
||||
Promise.group = function(promiseList) {
|
||||
if (!(promiseList instanceof Array)) {
|
||||
promiseList = Array.prototype.slice.call(arguments);
|
||||
}
|
||||
|
||||
// If the original array has nothing in it, return now to avoid waiting
|
||||
if (promiseList.length === 0) {
|
||||
return new Promise().resolve([]);
|
||||
}
|
||||
|
||||
var groupPromise = new Promise();
|
||||
var results = [];
|
||||
var fulfilled = 0;
|
||||
|
||||
var onSuccessFactory = function(index) {
|
||||
return function(data) {
|
||||
results[index] = data;
|
||||
fulfilled++;
|
||||
// If the group has already failed, silently drop extra results
|
||||
if (groupPromise._status !== Promise.ERROR) {
|
||||
if (fulfilled === promiseList.length) {
|
||||
groupPromise.resolve(results);
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
promiseList.forEach(function(promise, index) {
|
||||
var onSuccess = onSuccessFactory(index);
|
||||
var onError = groupPromise.reject.bind(groupPromise);
|
||||
promise.then(onSuccess, onError);
|
||||
});
|
||||
|
||||
return groupPromise;
|
||||
};
|
||||
|
||||
exports.Promise = Promise;
|
||||
Components.utils.import("resource:///modules/devtools/Promise.jsm");
|
||||
exports.Promise = Promise;
|
||||
|
||||
});
|
||||
/*
|
||||
|
|
Загрузка…
Ссылка в новой задаче