--- a/devtools/client/debugger/new/debugger.js
+++ b/devtools/client/debugger/new/debugger.js
@@ -72,111 +72,101 @@ var Debugger =
module.exports = __webpack_require__(1);
/***/ },
/* 1 */
/***/ function(module, exports, __webpack_require__) {
var React = __webpack_require__(2);
-
+
var _require = __webpack_require__(3),
bindActionCreators = _require.bindActionCreators,
combineReducers = _require.combineReducers;
-
+
var ReactDOM = __webpack_require__(22);
-
+
var _require2 = __webpack_require__(23),
getClient = _require2.getClient,
firefox = _require2.firefox;
-
- var _require3 = __webpack_require__(178),
+
+ var _require3 = __webpack_require__(129),
renderRoot = _require3.renderRoot,
bootstrap = _require3.bootstrap,
- L10N = _require3.L10N;
-
- var _require4 = __webpack_require__(65),
+ L10N = _require3.L10N,
+ unmountRoot = _require3.unmountRoot;
+
+ var _require4 = __webpack_require__(197),
getValue = _require4.getValue,
isFirefoxPanel = _require4.isFirefoxPanel;
-
- var configureStore = __webpack_require__(227);
-
- var _require5 = __webpack_require__(237),
+
+ var configureStore = __webpack_require__(244);
+
+ var _require5 = __webpack_require__(254),
onConnect = _require5.onConnect,
onFirefoxConnect = _require5.onFirefoxConnect;
-
- var reducers = __webpack_require__(238);
- var selectors = __webpack_require__(253);
-
- var App = __webpack_require__(254);
-
+
+ var reducers = __webpack_require__(288);
+ var selectors = __webpack_require__(303);
+
+ var App = __webpack_require__(304);
+
var createStore = configureStore({
log: getValue("logging.actions"),
makeThunkArgs: (args, state) => {
return Object.assign({}, args, { client: getClient(state) });
}
});
-
+
var store = createStore(combineReducers(reducers));
- var actions = bindActionCreators(__webpack_require__(255), store.dispatch);
-
+ var actions = bindActionCreators(__webpack_require__(314), store.dispatch);
+
if (!isFirefoxPanel()) {
window.L10N = L10N;
- window.L10N.setBundle(__webpack_require__(500));
- }
-
+ window.L10N.setBundle(__webpack_require__(636));
+ }
+
window.appStore = store;
-
+
// Expose the bound actions so external things can do things like
// selecting a source.
window.actions = {
selectSource: actions.selectSource,
selectSourceURL: actions.selectSourceURL
};
-
+
// Globals needed for mocha integration tests
window.getGlobalsForTesting = () => {
return {
debuggerStore: store,
launchpadStore: window.launchpadStore,
selectors,
actions
};
};
-
- function unmountRoot() {
- var mount = document.querySelector("#mount div");
- ReactDOM.unmountComponentAtNode(mount);
- }
-
+
if (isFirefoxPanel()) {
(function () {
- var sourceMap = __webpack_require__(257);
- var prettyPrint = __webpack_require__(268);
-
+ var sourceMap = __webpack_require__(316);
+ var prettyPrint = __webpack_require__(383);
+
module.exports = {
bootstrap: (_ref) => {
var threadClient = _ref.threadClient,
tabTarget = _ref.tabTarget,
toolbox = _ref.toolbox;
-
- // jlast: remove when docker updates
- if (!window.L10N) {
- window.L10N = L10N;
- window.L10N.setBundle(__webpack_require__(500));
- }
-
+
firefox.setThreadClient(threadClient);
firefox.setTabTarget(tabTarget);
renderRoot(React, ReactDOM, App, store);
firefox.initPage(actions);
return onFirefoxConnect(actions, firefox);
},
destroy: () => {
- unmountRoot();
+ unmountRoot(ReactDOM);
sourceMap.destroyWorker();
prettyPrint.destroyWorker();
},
store: store,
actions: actions,
selectors: selectors,
client: firefox.clientCommands
};
@@ -191,92 +181,92 @@ var Debugger =
module.exports = devtoolsRequire("devtools/client/shared/vendor/react");
/***/ },
/* 3 */
/***/ function(module, exports, __webpack_require__) {
'use strict';
-
+
exports.__esModule = true;
exports.compose = exports.applyMiddleware = exports.bindActionCreators = exports.combineReducers = exports.createStore = undefined;
-
+
var _createStore = __webpack_require__(4);
-
+
var _createStore2 = _interopRequireDefault(_createStore);
-
+
var _combineReducers = __webpack_require__(17);
-
+
var _combineReducers2 = _interopRequireDefault(_combineReducers);
-
+
var _bindActionCreators = __webpack_require__(19);
-
+
var _bindActionCreators2 = _interopRequireDefault(_bindActionCreators);
-
+
var _applyMiddleware = __webpack_require__(20);
-
+
var _applyMiddleware2 = _interopRequireDefault(_applyMiddleware);
-
+
var _compose = __webpack_require__(21);
-
+
var _compose2 = _interopRequireDefault(_compose);
-
+
var _warning = __webpack_require__(18);
-
+
var _warning2 = _interopRequireDefault(_warning);
-
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
-
+
/*
* This is a dummy function to check if the function name has been altered by minification.
* If the function has been minified and NODE_ENV !== 'production', warn the user.
*/
function isCrushed() {}
-
+
if (false) {
(0, _warning2["default"])('You are currently using minified code outside of NODE_ENV === \'production\'. ' + 'This means that you are running a slower development build of Redux. ' + 'You can use loose-envify (https://github.com/zertosh/loose-envify) for browserify ' + 'or DefinePlugin for webpack (http://stackoverflow.com/questions/30030031) ' + 'to ensure you have the correct code for your production build.');
}
-
+
exports.createStore = _createStore2["default"];
exports.combineReducers = _combineReducers2["default"];
exports.bindActionCreators = _bindActionCreators2["default"];
exports.applyMiddleware = _applyMiddleware2["default"];
exports.compose = _compose2["default"];
/***/ },
/* 4 */
/***/ function(module, exports, __webpack_require__) {
'use strict';
-
+
exports.__esModule = true;
exports.ActionTypes = undefined;
exports["default"] = createStore;
-
+
var _isPlainObject = __webpack_require__(5);
-
+
var _isPlainObject2 = _interopRequireDefault(_isPlainObject);
-
+
var _symbolObservable = __webpack_require__(15);
-
+
var _symbolObservable2 = _interopRequireDefault(_symbolObservable);
-
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
-
+
/**
* These are private action types reserved by Redux.
* For any unknown actions, you must return the current state.
* If the current state is undefined, you must return the initial state.
* Do not reference these action types directly in your code.
*/
var ActionTypes = exports.ActionTypes = {
INIT: '@@redux/INIT'
};
-
+
/**
* Creates a Redux store that holds the state tree.
* The only way to change the data in the store is to call `dispatch()` on it.
*
* There should only be a single store in your app. To specify how different
* parts of the state tree respond to actions, you may combine several reducers
* into a single reducer function by using `combineReducers`.
*
@@ -294,55 +284,55 @@ var Debugger =
* time travel, persistence, etc. The only store enhancer that ships with Redux
* is `applyMiddleware()`.
*
* @returns {Store} A Redux store that lets you read the state, dispatch actions
* and subscribe to changes.
*/
function createStore(reducer, initialState, enhancer) {
var _ref2;
-
+
if (typeof initialState === 'function' && typeof enhancer === 'undefined') {
enhancer = initialState;
initialState = undefined;
}
-
+
if (typeof enhancer !== 'undefined') {
if (typeof enhancer !== 'function') {
throw new Error('Expected the enhancer to be a function.');
}
-
+
return enhancer(createStore)(reducer, initialState);
}
-
+
if (typeof reducer !== 'function') {
throw new Error('Expected the reducer to be a function.');
}
-
+
var currentReducer = reducer;
var currentState = initialState;
var currentListeners = [];
var nextListeners = currentListeners;
var isDispatching = false;
-
+
function ensureCanMutateNextListeners() {
if (nextListeners === currentListeners) {
nextListeners = currentListeners.slice();
}
}
-
+
/**
* Reads the state tree managed by the store.
*
* @returns {any} The current state tree of your application.
*/
function getState() {
return currentState;
}
-
+
/**
* Adds a change listener. It will be called any time an action is dispatched,
* and some part of the state tree may potentially have changed. You may then
* call `getState()` to read the current state tree inside the callback.
*
* You may call `dispatch()` from a change listener, with the following
* caveats:
*
@@ -360,35 +350,35 @@ var Debugger =
*
* @param {Function} listener A callback to be invoked on every dispatch.
* @returns {Function} A function to remove this change listener.
*/
function subscribe(listener) {
if (typeof listener !== 'function') {
throw new Error('Expected listener to be a function.');
}
-
+
var isSubscribed = true;
-
+
ensureCanMutateNextListeners();
nextListeners.push(listener);
-
+
return function unsubscribe() {
if (!isSubscribed) {
return;
}
-
+
isSubscribed = false;
-
+
ensureCanMutateNextListeners();
var index = nextListeners.indexOf(listener);
nextListeners.splice(index, 1);
};
}
-
+
/**
* Dispatches an action. It is the only way to trigger a state change.
*
* The `reducer` function, used to create the store, will be called with the
* current state tree and the given `action`. Its return value will
* be considered the **next** state of the tree, and the change listeners
* will be notified.
*
@@ -408,136 +398,136 @@ var Debugger =
*
* Note that, if you use a custom middleware, it may wrap `dispatch()` to
* return something else (for example, a Promise you can await).
*/
function dispatch(action) {
if (!(0, _isPlainObject2["default"])(action)) {
throw new Error('Actions must be plain objects. ' + 'Use custom middleware for async actions.');
}
-
+
if (typeof action.type === 'undefined') {
throw new Error('Actions may not have an undefined "type" property. ' + 'Have you misspelled a constant?');
}
-
+
if (isDispatching) {
throw new Error('Reducers may not dispatch actions.');
}
-
+
try {
isDispatching = true;
currentState = currentReducer(currentState, action);
} finally {
isDispatching = false;
}
-
+
var listeners = currentListeners = nextListeners;
for (var i = 0; i < listeners.length; i++) {
listeners[i]();
}
-
+
return action;
}
-
+
/**
* Replaces the reducer currently used by the store to calculate the state.
*
* You might need this if your app implements code splitting and you want to
* load some of the reducers dynamically. You might also need this if you
* implement a hot reloading mechanism for Redux.
*
* @param {Function} nextReducer The reducer for the store to use instead.
* @returns {void}
*/
function replaceReducer(nextReducer) {
if (typeof nextReducer !== 'function') {
throw new Error('Expected the nextReducer to be a function.');
}
-
+
currentReducer = nextReducer;
dispatch({ type: ActionTypes.INIT });
}
-
+
/**
* Interoperability point for observable/reactive libraries.
* @returns {observable} A minimal observable of state changes.
* For more information, see the observable proposal:
* https://github.com/zenparsing/es-observable
*/
function observable() {
var _ref;
-
+
var outerSubscribe = subscribe;
return _ref = {
/**
* The minimal observable subscription method.
* @param {Object} observer Any object that can be used as an observer.
* The observer object should have a `next` method.
* @returns {subscription} An object with an `unsubscribe` method that can
* be used to unsubscribe the observable from the store, and prevent further
* emission of values from the observable.
*/
-
+
subscribe: function subscribe(observer) {
if (typeof observer !== 'object') {
throw new TypeError('Expected the observer to be an object.');
}
-
+
function observeState() {
if (observer.next) {
observer.next(getState());
}
}
-
+
observeState();
var unsubscribe = outerSubscribe(observeState);
return { unsubscribe: unsubscribe };
}
}, _ref[_symbolObservable2["default"]] = function () {
return this;
}, _ref;
}
-
+
// When a store is created, an "INIT" action is dispatched so that every
// reducer returns their initial state. This effectively populates
// the initial state tree.
dispatch({ type: ActionTypes.INIT });
-
+
return _ref2 = {
dispatch: dispatch,
subscribe: subscribe,
getState: getState,
replaceReducer: replaceReducer
}, _ref2[_symbolObservable2["default"]] = observable, _ref2;
}
/***/ },
/* 5 */
/***/ function(module, exports, __webpack_require__) {
var baseGetTag = __webpack_require__(6),
getPrototype = __webpack_require__(12),
isObjectLike = __webpack_require__(14);
-
+
/** `Object#toString` result references. */
var objectTag = '[object Object]';
-
+
/** Used for built-in method references. */
var funcProto = Function.prototype,
objectProto = Object.prototype;
-
+
/** Used to resolve the decompiled source of functions. */
var funcToString = funcProto.toString;
-
+
/** Used to check objects for own properties. */
var hasOwnProperty = objectProto.hasOwnProperty;
-
+
/** Used to infer the `Object` constructor. */
var objectCtorString = funcToString.call(Object);
-
+
/**
* Checks if `value` is a plain object, that is, an object created by the
* `Object` constructor or one with a `[[Prototype]]` of `null`.
*
* @static
* @memberOf _
* @since 0.8.0
* @category Lang
@@ -568,181 +558,181 @@ var Debugger =
var proto = getPrototype(value);
if (proto === null) {
return true;
}
var Ctor = hasOwnProperty.call(proto, 'constructor') && proto.constructor;
return typeof Ctor == 'function' && Ctor instanceof Ctor &&
funcToString.call(Ctor) == objectCtorString;
}
-
+
module.exports = isPlainObject;
/***/ },
/* 6 */
/***/ function(module, exports, __webpack_require__) {
var Symbol = __webpack_require__(7),
getRawTag = __webpack_require__(10),
objectToString = __webpack_require__(11);
-
+
/** `Object#toString` result references. */
var nullTag = '[object Null]',
undefinedTag = '[object Undefined]';
-
+
/** Built-in value references. */
var symToStringTag = Symbol ? Symbol.toStringTag : undefined;
-
+
/**
* The base implementation of `getTag` without fallbacks for buggy environments.
*
* @private
* @param {*} value The value to query.
* @returns {string} Returns the `toStringTag`.
*/
function baseGetTag(value) {
if (value == null) {
return value === undefined ? undefinedTag : nullTag;
}
return (symToStringTag && symToStringTag in Object(value))
? getRawTag(value)
: objectToString(value);
}
-
+
module.exports = baseGetTag;
/***/ },
/* 7 */
/***/ function(module, exports, __webpack_require__) {
var root = __webpack_require__(8);
-
+
/** Built-in value references. */
var Symbol = root.Symbol;
-
+
module.exports = Symbol;
/***/ },
/* 8 */
/***/ function(module, exports, __webpack_require__) {
var freeGlobal = __webpack_require__(9);
-
+
/** Detect free variable `self`. */
var freeSelf = typeof self == 'object' && self && self.Object === Object && self;
-
+
/** Used as a reference to the global object. */
var root = freeGlobal || freeSelf || Function('return this')();
-
+
module.exports = root;
/***/ },
/* 9 */
/***/ function(module, exports) {
/* WEBPACK VAR INJECTION */(function(global) {/** Detect free variable `global` from Node.js. */
var freeGlobal = typeof global == 'object' && global && global.Object === Object && global;
-
+
module.exports = freeGlobal;
-
+
/* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }())))
/***/ },
/* 10 */
/***/ function(module, exports, __webpack_require__) {
var Symbol = __webpack_require__(7);
-
+
/** Used for built-in method references. */
var objectProto = Object.prototype;
-
+
/** Used to check objects for own properties. */
var hasOwnProperty = objectProto.hasOwnProperty;
-
+
/**
* Used to resolve the
* [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
* of values.
*/
var nativeObjectToString = objectProto.toString;
-
+
/** Built-in value references. */
var symToStringTag = Symbol ? Symbol.toStringTag : undefined;
-
+
/**
* A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values.
*
* @private
* @param {*} value The value to query.
* @returns {string} Returns the raw `toStringTag`.
*/
function getRawTag(value) {
var isOwn = hasOwnProperty.call(value, symToStringTag),
tag = value[symToStringTag];
-
+
try {
value[symToStringTag] = undefined;
var unmasked = true;
} catch (e) {}
-
+
var result = nativeObjectToString.call(value);
if (unmasked) {
if (isOwn) {
value[symToStringTag] = tag;
} else {
delete value[symToStringTag];
}
}
return result;
}
-
+
module.exports = getRawTag;
/***/ },
/* 11 */
/***/ function(module, exports) {
/** Used for built-in method references. */
var objectProto = Object.prototype;
-
+
/**
* Used to resolve the
* [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring)
* of values.
*/
var nativeObjectToString = objectProto.toString;
-
+
/**
* Converts `value` to a string using `Object.prototype.toString`.
*
* @private
* @param {*} value The value to convert.
* @returns {string} Returns the converted string.
*/
function objectToString(value) {
return nativeObjectToString.call(value);
}
-
+
module.exports = objectToString;
/***/ },
/* 12 */
/***/ function(module, exports, __webpack_require__) {
var overArg = __webpack_require__(13);
-
+
/** Built-in value references. */
var getPrototype = overArg(Object.getPrototypeOf, Object);
-
+
module.exports = getPrototype;
/***/ },
/* 13 */
/***/ function(module, exports) {
/**
@@ -753,17 +743,17 @@ var Debugger =
* @param {Function} transform The argument transform.
* @returns {Function} Returns the new function.
*/
function overArg(func, transform) {
return function(arg) {
return func(transform(arg));
};
}
-
+
module.exports = overArg;
/***/ },
/* 14 */
/***/ function(module, exports) {
/**
@@ -788,121 +778,121 @@ var Debugger =
* // => false
*
* _.isObjectLike(null);
* // => false
*/
function isObjectLike(value) {
return value != null && typeof value == 'object';
}
-
+
module.exports = isObjectLike;
/***/ },
/* 15 */
/***/ function(module, exports, __webpack_require__) {
/* WEBPACK VAR INJECTION */(function(global) {/* global window */
'use strict';
-
+
module.exports = __webpack_require__(16)(global || window || this);
-
+
/* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }())))
/***/ },
/* 16 */
/***/ function(module, exports) {
'use strict';
-
+
module.exports = function symbolObservablePonyfill(root) {
var result;
var Symbol = root.Symbol;
-
+
if (typeof Symbol === 'function') {
if (Symbol.observable) {
result = Symbol.observable;
} else {
result = Symbol('observable');
Symbol.observable = result;
}
} else {
result = '@@observable';
}
-
+
return result;
};
/***/ },
/* 17 */
/***/ function(module, exports, __webpack_require__) {
'use strict';
-
+
exports.__esModule = true;
exports["default"] = combineReducers;
-
+
var _createStore = __webpack_require__(4);
-
+
var _isPlainObject = __webpack_require__(5);
-
+
var _isPlainObject2 = _interopRequireDefault(_isPlainObject);
-
+
var _warning = __webpack_require__(18);
-
+
var _warning2 = _interopRequireDefault(_warning);
-
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
-
+
function getUndefinedStateErrorMessage(key, action) {
var actionType = action && action.type;
var actionName = actionType && '"' + actionType.toString() + '"' || 'an action';
-
+
return 'Given action ' + actionName + ', reducer "' + key + '" returned undefined. ' + 'To ignore an action, you must explicitly return the previous state.';
}
-
+
function getUnexpectedStateShapeWarningMessage(inputState, reducers, action) {
var reducerKeys = Object.keys(reducers);
var argumentName = action && action.type === _createStore.ActionTypes.INIT ? 'initialState argument passed to createStore' : 'previous state received by the reducer';
-
+
if (reducerKeys.length === 0) {
return 'Store does not have a valid reducer. Make sure the argument passed ' + 'to combineReducers is an object whose values are reducers.';
}
-
+
if (!(0, _isPlainObject2["default"])(inputState)) {
return 'The ' + argumentName + ' has unexpected type of "' + {}.toString.call(inputState).match(/\s([a-z|A-Z]+)/)[1] + '". Expected argument to be an object with the following ' + ('keys: "' + reducerKeys.join('", "') + '"');
}
-
+
var unexpectedKeys = Object.keys(inputState).filter(function (key) {
return !reducers.hasOwnProperty(key);
});
-
+
if (unexpectedKeys.length > 0) {
return 'Unexpected ' + (unexpectedKeys.length > 1 ? 'keys' : 'key') + ' ' + ('"' + unexpectedKeys.join('", "') + '" found in ' + argumentName + '. ') + 'Expected to find one of the known reducer keys instead: ' + ('"' + reducerKeys.join('", "') + '". Unexpected keys will be ignored.');
}
}
-
+
function assertReducerSanity(reducers) {
Object.keys(reducers).forEach(function (key) {
var reducer = reducers[key];
var initialState = reducer(undefined, { type: _createStore.ActionTypes.INIT });
-
+
if (typeof initialState === 'undefined') {
throw new Error('Reducer "' + key + '" returned undefined during initialization. ' + 'If the state passed to the reducer is undefined, you must ' + 'explicitly return the initial state. The initial state may ' + 'not be undefined.');
}
-
+
var type = '@@redux/PROBE_UNKNOWN_ACTION_' + Math.random().toString(36).substring(7).split('').join('.');
if (typeof reducer(undefined, { type: type }) === 'undefined') {
throw new Error('Reducer "' + key + '" returned undefined when probed with a random type. ' + ('Don\'t try to handle ' + _createStore.ActionTypes.INIT + ' or other actions in "redux/*" ') + 'namespace. They are considered private. Instead, you must return the ' + 'current state for any unknown actions, unless it is undefined, ' + 'in which case you must return the initial state, regardless of the ' + 'action type. The initial state may not be undefined.');
}
});
}
-
+
/**
* Turns an object whose values are different reducer functions, into a single
* reducer function. It will call every child reducer, and gather their results
* into a single state object, whose keys correspond to the keys of the passed
* reducer functions.
*
* @param {Object} reducers An object whose values correspond to different
* reducer functions that need to be combined into one. One handy way to obtain
@@ -919,39 +909,39 @@ var Debugger =
var finalReducers = {};
for (var i = 0; i < reducerKeys.length; i++) {
var key = reducerKeys[i];
if (typeof reducers[key] === 'function') {
finalReducers[key] = reducers[key];
}
}
var finalReducerKeys = Object.keys(finalReducers);
-
+
var sanityError;
try {
assertReducerSanity(finalReducers);
} catch (e) {
sanityError = e;
}
-
+
return function combination() {
var state = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];
var action = arguments[1];
-
+
if (sanityError) {
throw sanityError;
}
-
+
if (false) {
var warningMessage = getUnexpectedStateShapeWarningMessage(state, finalReducers, action);
if (warningMessage) {
(0, _warning2["default"])(warningMessage);
}
}
-
+
var hasChanged = false;
var nextState = {};
for (var i = 0; i < finalReducerKeys.length; i++) {
var key = finalReducerKeys[i];
var reducer = finalReducers[key];
var previousStateForKey = state[key];
var nextStateForKey = reducer(previousStateForKey, action);
if (typeof nextStateForKey === 'undefined') {
@@ -965,17 +955,17 @@ var Debugger =
};
}
/***/ },
/* 18 */
/***/ function(module, exports) {
'use strict';
-
+
exports.__esModule = true;
exports["default"] = warning;
/**
* Prints a warning in the console if it exists.
*
* @param {String} message The warning message.
* @returns {void}
*/
@@ -995,25 +985,25 @@ var Debugger =
/* eslint-enable no-empty */
}
/***/ },
/* 19 */
/***/ function(module, exports) {
'use strict';
-
+
exports.__esModule = true;
exports["default"] = bindActionCreators;
function bindActionCreator(actionCreator, dispatch) {
return function () {
return dispatch(actionCreator.apply(undefined, arguments));
};
}
-
+
/**
* Turns an object whose values are action creators, into an object with the
* same keys, but with every function wrapped into a `dispatch` call so they
* may be invoked directly. This is just a convenience method, as you can call
* `store.dispatch(MyActionCreators.doSomething())` yourself just fine.
*
* For convenience, you can also pass a single function as the first argument,
* and get a function in return.
@@ -1029,21 +1019,21 @@ var Debugger =
* every action creator wrapped into the `dispatch` call. If you passed a
* function as `actionCreators`, the return value will also be a single
* function.
*/
function bindActionCreators(actionCreators, dispatch) {
if (typeof actionCreators === 'function') {
return bindActionCreator(actionCreators, dispatch);
}
-
+
if (typeof actionCreators !== 'object' || actionCreators === null) {
throw new Error('bindActionCreators expected an object or a function, instead received ' + (actionCreators === null ? 'null' : typeof actionCreators) + '. ' + 'Did you write "import ActionCreators from" instead of "import * as ActionCreators from"?');
}
-
+
var keys = Object.keys(actionCreators);
var boundActionCreators = {};
for (var i = 0; i < keys.length; i++) {
var key = keys[i];
var actionCreator = actionCreators[key];
if (typeof actionCreator === 'function') {
boundActionCreators[key] = bindActionCreator(actionCreator, dispatch);
}
@@ -1051,29 +1041,29 @@ var Debugger =
return boundActionCreators;
}
/***/ },
/* 20 */
/***/ function(module, exports, __webpack_require__) {
'use strict';
-
+
exports.__esModule = true;
-
+
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
-
+
exports["default"] = applyMiddleware;
-
+
var _compose = __webpack_require__(21);
-
+
var _compose2 = _interopRequireDefault(_compose);
-
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
-
+
/**
* Creates a store enhancer that applies middleware to the dispatch method
* of the Redux store. This is handy for a variety of tasks, such as expressing
* asynchronous actions in a concise manner, or logging every action payload.
*
* See `redux-thunk` package as an example of the Redux middleware.
*
* Because middleware is potentially asynchronous, this should be the first
@@ -1084,82 +1074,82 @@ var Debugger =
*
* @param {...Function} middlewares The middleware chain to be applied.
* @returns {Function} A store enhancer applying the middleware.
*/
function applyMiddleware() {
for (var _len = arguments.length, middlewares = Array(_len), _key = 0; _key < _len; _key++) {
middlewares[_key] = arguments[_key];
}
-
+
return function (createStore) {
return function (reducer, initialState, enhancer) {
var store = createStore(reducer, initialState, enhancer);
var _dispatch = store.dispatch;
var chain = [];
-
+
var middlewareAPI = {
getState: store.getState,
dispatch: function dispatch(action) {
return _dispatch(action);
}
};
chain = middlewares.map(function (middleware) {
return middleware(middlewareAPI);
});
_dispatch = _compose2["default"].apply(undefined, chain)(store.dispatch);
-
+
return _extends({}, store, {
dispatch: _dispatch
});
};
};
}
/***/ },
/* 21 */
/***/ function(module, exports) {
"use strict";
-
+
exports.__esModule = true;
exports["default"] = compose;
/**
* Composes single-argument functions from right to left. The rightmost
* function can take multiple arguments as it provides the signature for
* the resulting composite function.
*
* @param {...Function} funcs The functions to compose.
* @returns {Function} A function obtained by composing the argument functions
* from right to left. For example, compose(f, g, h) is identical to doing
* (...args) => f(g(h(...args))).
*/
-
+
function compose() {
for (var _len = arguments.length, funcs = Array(_len), _key = 0; _key < _len; _key++) {
funcs[_key] = arguments[_key];
}
-
+
if (funcs.length === 0) {
return function (arg) {
return arg;
};
} else {
var _ret = function () {
var last = funcs[funcs.length - 1];
var rest = funcs.slice(0, -1);
return {
v: function v() {
return rest.reduceRight(function (composed, f) {
return f(composed);
}, last.apply(undefined, arguments));
}
};
}();
-
+
if (typeof _ret === "object") return _ret.v;
}
}
/***/ },
/* 22 */
/***/ function(module, exports, __webpack_require__) {
@@ -1174,21 +1164,21 @@ var Debugger =
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
// Based off https://github.com/ForbesLindesay/umd/blob/master/template.js
;(function(f) {
// CommonJS
if (true) {
module.exports = f(__webpack_require__(2));
-
+
// RequireJS
} else if (typeof define === "function" && define.amd) {
define(['react'], f);
-
+
// <script>
} else {
var g;
if (typeof window !== "undefined") {
g = window;
} else if (typeof global !== "undefined") {
g = global;
} else if (typeof self !== "undefined") {
@@ -1196,258 +1186,246 @@ var Debugger =
} else {
// works providing we're not in "use strict";
// needed for Java 8 Nashorn
// see https://github.com/facebook/react/issues/3037
g = this;
}
g.ReactDOM = f(g.React);
}
-
+
})(function(React) {
return React.__SECRET_DOM_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
});
/***/ },
/* 23 */
/***/ function(module, exports, __webpack_require__) {
const { Task } = __webpack_require__(24);
const firefox = __webpack_require__(25);
- const chrome = __webpack_require__(116);
- const { createSource } = __webpack_require__(115);
-
+ const chrome = __webpack_require__(123);
+ const { createSource } = __webpack_require__(122);
+
let clientType = null;
function getClient() {
if (clientType === "chrome" || clientType === "node") {
return chrome.clientCommands;
}
-
+
return firefox.clientCommands;
}
-
+
function startDebugging(connTarget, actions) {
if (connTarget.type === "node") {
return startDebuggingNode(connTarget.param, actions);
}
-
+
const target = connTarget.type === "chrome" ? chrome : firefox;
return startDebuggingTab(target, connTarget.param, actions);
}
-
+
function startDebuggingNode(tabId, actions) {
return Task.spawn(function* () {
clientType = "node";
-
+
const tabs = yield chrome.connectNodeClient();
const tab = tabs.find(t => t.id.indexOf(tabId) !== -1);
-
+
yield chrome.connectNode(tab.tab);
chrome.initPage(actions, { clientType });
-
+
return { tabs, tab, client: chrome };
});
}
-
+
function startDebuggingTab(targetEnv, tabId, actions) {
return Task.spawn(function* () {
const tabs = yield targetEnv.connectClient();
const tab = tabs.find(t => t.id.indexOf(tabId) !== -1);
yield targetEnv.connectTab(tab.tab);
-
+
clientType = targetEnv === firefox ? "firefox" : "chrome";
targetEnv.initPage(actions, { clientType });
-
+
return { tabs, tab, client: targetEnv };
});
}
-
+
module.exports = {
getClient,
startDebugging,
firefox,
chrome,
createSource
};
-
/***/ },
/* 24 */
/***/ function(module, exports) {
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80 filetype=javascript: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
-
+
/**
* This object provides the public module functions.
*/
- var Task = {
+ const Task = {
// XXX: Not sure if this works in all cases...
async: function (task) {
return function () {
return Task.spawn(task, this, arguments);
};
},
-
+
/**
* Creates and starts a new task.
* @param task A generator function
* @return A promise, resolved when the task terminates
*/
spawn: function (task, scope, args) {
return new Promise(function (resolve, reject) {
- var iterator = task.apply(scope, args);
-
- var callNext = lastValue => {
- var iteration = iterator.next(lastValue);
+ const iterator = task.apply(scope, args);
+
+ const callNext = lastValue => {
+ const iteration = iterator.next(lastValue);
Promise.resolve(iteration.value).then(value => {
if (iteration.done) {
resolve(value);
} else {
callNext(value);
}
}).catch(error => {
reject(error);
iterator.throw(error);
});
};
-
+
callNext(undefined);
});
}
};
-
+
module.exports = { Task };
/***/ },
/* 25 */
/***/ function(module, exports, __webpack_require__) {
- var _require = __webpack_require__(26),
- DebuggerClient = _require.DebuggerClient,
- DebuggerTransport = _require.DebuggerTransport,
- TargetFactory = _require.TargetFactory,
- WebsocketTransport = _require.WebsocketTransport;
-
- var _require2 = __webpack_require__(65),
- getValue = _require2.getValue;
-
- var _require3 = __webpack_require__(113),
- setupCommands = _require3.setupCommands,
- clientCommands = _require3.clientCommands;
-
- var _require4 = __webpack_require__(114),
- setupEvents = _require4.setupEvents,
- clientEvents = _require4.clientEvents;
-
- var debuggerClient = null;
- var threadClient = null;
- var tabTarget = null;
-
+ const { DebuggerClient, DebuggerTransport,
+ TargetFactory, WebsocketTransport } = __webpack_require__(26);
+ const { getValue } = __webpack_require__(65);
+ const { setupCommands, clientCommands } = __webpack_require__(120);
+ const { setupEvents, clientEvents } = __webpack_require__(121);
+
+ let debuggerClient = null;
+ let threadClient = null;
+ let tabTarget = null;
+
function getThreadClient() {
return threadClient;
}
-
+
function setThreadClient(client) {
threadClient = client;
}
-
+
function getTabTarget() {
return tabTarget;
}
-
+
function setTabTarget(target) {
tabTarget = target;
}
-
+
function lookupTabTarget(tab) {
- var options = { client: debuggerClient, form: tab, chrome: false };
+ const options = { client: debuggerClient, form: tab, chrome: false };
return TargetFactory.forRemoteTab(options);
}
-
+
function createTabs(tabs) {
return tabs.map(tab => {
return {
title: tab.title,
url: tab.url,
id: tab.actor,
tab,
clientType: "firefox"
};
});
}
-
+
function connectClient() {
- var useProxy = !getValue("firefox.webSocketConnection");
- var firefoxHost = getValue(useProxy ? "firefox.proxyHost" : "firefox.webSocketHost");
-
- var socket = new WebSocket(`ws://${ firefoxHost }`);
- var transport = useProxy ? new DebuggerTransport(socket) : new WebsocketTransport(socket);
-
+ const useProxy = !getValue("firefox.webSocketConnection");
+ const firefoxHost = getValue(useProxy ? "firefox.proxyHost" : "firefox.webSocketHost");
+
+ const socket = new WebSocket(`ws://${ firefoxHost }`);
+ const transport = useProxy ? new DebuggerTransport(socket) : new WebsocketTransport(socket);
+
return new Promise((resolve, reject) => {
debuggerClient = new DebuggerClient(transport);
debuggerClient.connect().then(() => {
if (debuggerClient !== null) {
return debuggerClient.listTabs().then(response => {
resolve(createTabs(response.tabs));
});
}
return resolve([]);
}).catch(err => {
console.log(err);
resolve([]);
});
});
}
-
+
function connectTab(tab) {
return new Promise((resolve, reject) => {
window.addEventListener("beforeunload", () => {
- var tt = getTabTarget();
+ const tt = getTabTarget();
if (tt !== null) {
tt.destroy();
}
});
-
+
lookupTabTarget(tab).then(target => {
tabTarget = target;
target.activeTab.attachThread({}, (res, _threadClient) => {
threadClient = _threadClient;
threadClient.resume();
resolve();
});
});
});
}
-
+
function initPage(actions) {
tabTarget = getTabTarget();
threadClient = getThreadClient();
-
- if (!threadClient || !tabTarget || !actions) {
+
+ if (!threadClient || !tabTarget) {
return;
}
-
+
setupCommands({ threadClient, tabTarget, debuggerClient });
-
+
if (actions) {
// Listen to all the requested events.
setupEvents({ threadClient, actions });
Object.keys(clientEvents).forEach(eventName => {
if (threadClient) {
threadClient.addListener(eventName, clientEvents[eventName]);
}
});
}
}
-
+
module.exports = {
connectClient,
connectTab,
clientCommands,
clientEvents,
getThreadClient,
setThreadClient,
getTabTarget,
@@ -1468,17 +1446,17 @@ var Debugger =
const AppConstants = __webpack_require__(44);
const EventEmitter = __webpack_require__(34);
const WebsocketTransport = __webpack_require__(59);
const Menu = __webpack_require__(60);
const MenuItem = __webpack_require__(61);
const Tree = __webpack_require__(62);
const sourceUtils = __webpack_require__(63);
const frame = __webpack_require__(64);
-
+
module.exports = {
KeyShortcuts,
PrefsHelper,
DebuggerClient,
DebuggerTransport,
TargetFactory,
DevToolsUtils,
AppConstants,
@@ -1494,22 +1472,22 @@ var Debugger =
/***/ },
/* 27 */
/***/ function(module, exports, __webpack_require__) {
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
+
const { Services: { appinfo }} = __webpack_require__(28);
const EventEmitter = __webpack_require__(34);
const isOSX = appinfo.OS === "Darwin";
"use strict";
-
+
// List of electron keys mapped to DOM API (DOM_VK_*) key code
const ElectronKeysMapping = {
"F1": "DOM_VK_F1",
"F2": "DOM_VK_F2",
"F3": "DOM_VK_F3",
"F4": "DOM_VK_F4",
"F5": "DOM_VK_F5",
"F6": "DOM_VK_F6",
@@ -1548,17 +1526,17 @@ var Debugger =
"Escape": "DOM_VK_ESCAPE",
"Esc": "DOM_VK_ESCAPE",
"Tab": "DOM_VK_TAB",
"VolumeUp": "DOM_VK_VOLUME_UP",
"VolumeDown": "DOM_VK_VOLUME_DOWN",
"VolumeMute": "DOM_VK_VOLUME_MUTE",
"PrintScreen": "DOM_VK_PRINTSCREEN",
};
-
+
/**
* Helper to listen for keyboard events decribed in .properties file.
*
* let shortcuts = new KeyShortcuts({
* window
* });
* shortcuts.on("Ctrl+F", event => {
* // `event` is the KeyboardEvent which relates to the key shortcuts
@@ -1572,32 +1550,32 @@ var Debugger =
*/
function KeyShortcuts({ window, target }) {
this.window = window;
this.target = target || window;
this.keys = new Map();
this.eventEmitter = new EventEmitter();
this.target.addEventListener("keydown", this);
}
-
+
/*
* Parse an electron-like key string and return a normalized object which
* allow efficient match on DOM key event. The normalized object matches DOM
* API.
*
* @param DOMWindow window
* Any DOM Window object, just to fetch its `KeyboardEvent` object
* @param String str
* The shortcut string to parse, following this document:
* https://github.com/electron/electron/blob/master/docs/api/accelerator.md
*/
KeyShortcuts.parseElectronKey = function(window, str) {
let modifiers = str.split("+");
let key = modifiers.pop();
-
+
let shortcut = {
ctrl: false,
meta: false,
alt: false,
shift: false,
// Set for character keys
key: undefined,
// Set for non-character keys
@@ -1618,41 +1596,41 @@ var Debugger =
shortcut.ctrl = true;
} else if (mod === "Shift") {
shortcut.shift = true;
} else {
console.error("Unsupported modifier:", mod, "from key:", str);
return null;
}
}
-
+
// Plus is a special case. It's a character key and shouldn't be matched
// against a keycode as it is only accessible via Shift/Capslock
if (key === "Plus") {
key = "+";
}
-
+
if (typeof key === "string" && key.length === 1) {
// Match any single character
shortcut.key = key.toLowerCase();
} else if (key in ElectronKeysMapping) {
// Maps the others manually to DOM API DOM_VK_*
key = ElectronKeysMapping[key];
shortcut.keyCode = window.KeyboardEvent[key];
// Used only to stringify the shortcut
shortcut.keyCodeString = key;
shortcut.key = key;
} else {
console.error("Unsupported key:", key);
return null;
}
-
+
return shortcut;
};
-
+
KeyShortcuts.stringify = function(shortcut) {
let list = [];
if (shortcut.alt) {
list.push("Alt");
}
if (shortcut.ctrl) {
list.push("Ctrl");
}
@@ -1666,23 +1644,23 @@ var Debugger =
if (shortcut.key) {
key = shortcut.key.toUpperCase();
} else {
key = shortcut.keyCodeString;
}
list.push(key);
return list.join("+");
};
-
+
KeyShortcuts.prototype = {
destroy() {
this.target.removeEventListener("keydown", this);
this.keys.clear();
},
-
+
doesEventMatchShortcut(event, shortcut) {
if (shortcut.meta != event.metaKey) {
return false;
}
if (shortcut.ctrl != event.ctrlKey) {
return false;
}
if (shortcut.alt != event.altKey) {
@@ -1694,68 +1672,68 @@ var Debugger =
event.key.match(/[a-zA-Z]/)) {
return false;
}
if (shortcut.keyCode) {
return event.keyCode == shortcut.keyCode;
} else if (event.key in ElectronKeysMapping) {
return ElectronKeysMapping[event.key] === shortcut.key;
}
-
+
// get the key from the keyCode if key is not provided.
let key = event.key || String.fromCharCode(event.keyCode);
-
+
// For character keys, we match if the final character is the expected one.
// But for digits we also accept indirect match to please azerty keyboard,
// which requires Shift to be pressed to get digits.
return key.toLowerCase() == shortcut.key ||
(shortcut.key.match(/^[0-9]$/) &&
event.keyCode == shortcut.key.charCodeAt(0));
},
-
+
handleEvent(event) {
for (let [key, shortcut] of this.keys) {
if (this.doesEventMatchShortcut(event, shortcut)) {
this.eventEmitter.emit(key, event);
}
}
},
-
+
on(key, listener) {
if (typeof listener !== "function") {
throw new Error("KeyShortcuts.on() expects a function as " +
"second argument");
}
if (!this.keys.has(key)) {
let shortcut = KeyShortcuts.parseElectronKey(this.window, key);
// The key string is wrong and we were unable to compute the key shortcut
if (!shortcut) {
return;
}
this.keys.set(key, shortcut);
}
this.eventEmitter.on(key, listener);
},
-
+
off(key, listener) {
this.eventEmitter.off(key, listener);
},
};
exports.KeyShortcuts = KeyShortcuts;
/***/ },
/* 28 */
/***/ function(module, exports, __webpack_require__) {
const Services = __webpack_require__(29);
const SplitBox = __webpack_require__(30);
// const SplitBoxCSS = require("./client/shared/components/splitter/SplitBox.css")
const sprintf = __webpack_require__(33).sprintf;
-
+
module.exports = {
Services,
SplitBox,
// SplitBoxCSS,
sprintf
};
@@ -1768,23 +1746,23 @@ var Debugger =
/***/ },
/* 30 */
/***/ function(module, exports, __webpack_require__) {
const React = __webpack_require__(2);
const ReactDOM = __webpack_require__(31);
const Draggable = React.createFactory(__webpack_require__(32));
const { DOM: dom, PropTypes } = React;
-
+
/**
* This component represents a Splitter. The splitter supports vertical
* as well as horizontal mode.
*/
const SplitBox = React.createClass({
-
+
propTypes: {
// Custom class name. You can use more names separated by a space.
className: PropTypes.string,
// Initial size of controlled panel.
initialSize: PropTypes.any,
// Optional initial width of controlled panel.
initialWidth: PropTypes.number,
// Optional initial height of controlled panel.
@@ -1805,197 +1783,197 @@ var Debugger =
endPanelControl: PropTypes.bool,
// Size of the splitter handle bar.
splitterSize: PropTypes.number,
// True if the splitter bar is vertical (default is vertical).
vert: PropTypes.bool,
// Optional style properties passed into the splitbox
style: PropTypes.object
},
-
+
displayName: "SplitBox",
-
+
getDefaultProps() {
return {
splitterSize: 5,
vert: true,
endPanelControl: false,
endPanelCollapsed: false,
startPanelCollapsed: false
};
},
-
+
/**
* The state stores the current orientation (vertical or horizontal)
* and the current size (width/height). All these values can change
* during the component's life time.
*/
getInitialState() {
return {
vert: this.props.vert,
width: this.props.initialWidth || this.props.initialSize,
height: this.props.initialHeight || this.props.initialSize
};
},
-
+
componentWillReceiveProps(nextProps) {
if (this.props.vert !== nextProps.vert) {
this.setState({ vert: nextProps.vert });
}
},
-
+
// Dragging Events
-
+
/**
* Set 'resizing' cursor on entire document during splitter dragging.
* This avoids cursor-flickering that happens when the mouse leaves
* the splitter bar area (happens frequently).
*/
onStartMove() {
const splitBox = ReactDOM.findDOMNode(this);
const doc = splitBox.ownerDocument;
let defaultCursor = doc.documentElement.style.cursor;
doc.documentElement.style.cursor =
(this.state.vert ? "ew-resize" : "ns-resize");
-
+
splitBox.classList.add("dragging");
-
+
this.setState({
defaultCursor: defaultCursor
});
},
-
+
onStopMove() {
const splitBox = ReactDOM.findDOMNode(this);
const doc = splitBox.ownerDocument;
doc.documentElement.style.cursor = this.state.defaultCursor;
-
+
splitBox.classList.remove("dragging");
},
-
+
screenX() {
// NOTE: in practice the window might have a border which calls for comparing window.outerWidth and window.innerWidth
return window.screenX;
},
-
+
screenY() {
// NOTE: in practice the window might have a border which calls for comparing window.outerHeight and window.innerHeight
return window.screenY;
},
-
+
/**
* Adjust size of the controlled panel. Depending on the current
* orientation we either remember the width or height of
* the splitter box.
*/
onMove(x, y) {
const node = ReactDOM.findDOMNode(this);
const doc = node.ownerDocument;
const win = doc.defaultView;
-
+
let size;
let { endPanelControl } = this.props;
-
+
if (this.state.vert) {
// Switch the control flag in case of RTL. Note that RTL
// has impact on vertical splitter only.
let dir = win.getComputedStyle(doc.documentElement).direction;
if (dir == "rtl") {
endPanelControl = !endPanelControl;
}
-
+
let innerOffset = x - this.screenX();
size = endPanelControl ?
(node.offsetLeft + node.offsetWidth) - innerOffset :
innerOffset - node.offsetLeft;
-
+
this.setState({
width: size
});
} else {
let innerOffset = y - this.screenY();
size = endPanelControl ?
(node.offsetTop + node.offsetHeight) - innerOffset :
innerOffset - node.offsetTop;
-
+
this.setState({
height: size
});
}
},
-
+
// Rendering
preparePanelStyles() {
const vert = this.state.vert;
const {
minSize, maxSize, startPanelCollapsed, endPanelControl,
endPanelCollapsed } = this.props;
let leftPanelStyle, rightPanelStyle;
-
+
// Set proper size for panels depending on the current state.
if (vert) {
let startWidth = endPanelControl ? null : this.state.width,
endWidth = endPanelControl ? this.state.width : null;
-
+
leftPanelStyle = {
maxWidth: endPanelControl ? null : maxSize,
minWidth: endPanelControl ? null : minSize,
width: startPanelCollapsed ? 0 : startWidth
};
rightPanelStyle = {
maxWidth: endPanelControl ? maxSize : null,
minWidth: endPanelControl ? minSize : null,
width: endPanelCollapsed ? 0 : endWidth
};
} else {
let startHeight = endPanelControl ? null : this.state.height,
endHeight = endPanelControl ? this.state.height : null;
-
+
leftPanelStyle = {
maxHeight: endPanelControl ? null : maxSize,
minHeight: endPanelControl ? null : minSize,
height: endPanelCollapsed ? maxSize : startHeight
};
rightPanelStyle = {
maxHeight: endPanelControl ? maxSize : null,
minHeight: endPanelControl ? minSize : null,
height: startPanelCollapsed ? maxSize : endHeight
};
}
-
+
return { leftPanelStyle, rightPanelStyle };
},
-
+
render() {
const vert = this.state.vert;
const {
startPanelCollapsed,
startPanel,
endPanel,
endPanelControl,
splitterSize,
endPanelCollapsed
} = this.props;
-
+
let style = Object.assign({}, this.props.style);
-
+
// Calculate class names list.
let classNames = ["split-box"];
classNames.push(vert ? "vert" : "horz");
if (this.props.className) {
classNames = classNames.concat(this.props.className.split(" "));
}
-
+
const { leftPanelStyle, rightPanelStyle } = this.preparePanelStyles();
-
+
// Calculate splitter size
let splitterStyle = {
flex: `0 0 ${splitterSize}px`
};
-
+
return (
dom.div({
className: classNames.join(" "),
style: style },
!startPanelCollapsed ?
dom.div({
className: endPanelControl ? "uncontrolled" : "controlled",
style: leftPanelStyle },
@@ -2013,17 +1991,17 @@ var Debugger =
className: endPanelControl ? "controlled" : "uncontrolled",
style: rightPanelStyle },
endPanel
) : null
)
);
}
});
-
+
module.exports = SplitBox;
/***/ },
/* 31 */
/***/ function(module, exports, __webpack_require__) {
/**
@@ -2037,21 +2015,21 @@ var Debugger =
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
// Based off https://github.com/ForbesLindesay/umd/blob/master/template.js
;(function(f) {
// CommonJS
if (true) {
module.exports = f(__webpack_require__(2));
-
+
// RequireJS
} else if (typeof define === "function" && define.amd) {
define(['react'], f);
-
+
// <script>
} else {
var g;
if (typeof window !== "undefined") {
g = window;
} else if (typeof global !== "undefined") {
g = global;
} else if (typeof self !== "undefined") {
@@ -2059,78 +2037,78 @@ var Debugger =
} else {
// works providing we're not in "use strict";
// needed for Java 8 Nashorn
// see https://github.com/facebook/react/issues/3037
g = this;
}
g.ReactDOM = f(g.React);
}
-
+
})(function(React) {
return React.__SECRET_DOM_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
});
/***/ },
/* 32 */
/***/ function(module, exports, __webpack_require__) {
/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
- const React = __webpack_require__(2);
- const ReactDOM = __webpack_require__(31);
- const { DOM: dom, PropTypes } = React;
-
- const Draggable = React.createClass({
- displayName: "Draggable",
-
- propTypes: {
- onMove: PropTypes.func.isRequired,
- onStart: PropTypes.func,
- onStop: PropTypes.func,
- style: PropTypes.object,
- className: PropTypes.string
- },
-
- startDragging(ev) {
- ev.preventDefault();
- const doc = ReactDOM.findDOMNode(this).ownerDocument;
- doc.addEventListener("mousemove", this.onMove);
- doc.addEventListener("mouseup", this.onUp);
- this.props.onStart && this.props.onStart();
- },
-
- onMove(ev) {
- ev.preventDefault();
- // Use screen coordinates so, moving mouse over iframes
- // doesn't mangle (relative) coordinates.
- this.props.onMove(ev.screenX, ev.screenY);
- },
-
- onUp(ev) {
- ev.preventDefault();
- const doc = ReactDOM.findDOMNode(this).ownerDocument;
- doc.removeEventListener("mousemove", this.onMove);
- doc.removeEventListener("mouseup", this.onUp);
- this.props.onStop && this.props.onStop();
- },
-
- render() {
- return dom.div({
- style: this.props.style,
- className: this.props.className,
- onMouseDown: this.startDragging
- });
- }
- });
-
- module.exports = Draggable;
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+ const React = __webpack_require__(2);
+ const ReactDOM = __webpack_require__(31);
+ const { DOM: dom, PropTypes } = React;
+
+ const Draggable = React.createClass({
+ displayName: "Draggable",
+
+ propTypes: {
+ onMove: PropTypes.func.isRequired,
+ onStart: PropTypes.func,
+ onStop: PropTypes.func,
+ style: PropTypes.object,
+ className: PropTypes.string
+ },
+
+ startDragging(ev) {
+ ev.preventDefault();
+ const doc = ReactDOM.findDOMNode(this).ownerDocument;
+ doc.addEventListener("mousemove", this.onMove);
+ doc.addEventListener("mouseup", this.onUp);
+ this.props.onStart && this.props.onStart();
+ },
+
+ onMove(ev) {
+ ev.preventDefault();
+ // Use screen coordinates so, moving mouse over iframes
+ // doesn't mangle (relative) coordinates.
+ this.props.onMove(ev.screenX, ev.screenY);
+ },
+
+ onUp(ev) {
+ ev.preventDefault();
+ const doc = ReactDOM.findDOMNode(this).ownerDocument;
+ doc.removeEventListener("mousemove", this.onMove);
+ doc.removeEventListener("mouseup", this.onUp);
+ this.props.onStop && this.props.onStop();
+ },
+
+ render() {
+ return dom.div({
+ style: this.props.style,
+ className: this.props.className,
+ onMouseDown: this.startDragging
+ });
+ }
+ });
+
+ module.exports = Draggable;
/***/ },
/* 33 */
/***/ function(module, exports, __webpack_require__) {
/**
* Copyright (c) 2007-2016, Alexandru Marasteanu <hello [at) alexei (dot] ro>
@@ -2154,22 +2132,22 @@ var Debugger =
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
-
+
/* globals window, exports, define */
-
+
(function(window) {
'use strict'
-
+
var re = {
not_string: /[^s]/,
not_bool: /[^t]/,
not_type: /[^T]/,
not_primitive: /[^v]/,
number: /[diefg]/,
numeric_arg: /bcdiefguxX/,
json: /[j]/,
@@ -2177,25 +2155,25 @@ var Debugger =
text: /^[^\x25]+/,
modulo: /^\x25{2}/,
placeholder: /^\x25(?:([1-9]\d*)\$|\(([^\)]+)\))?(\+)?(0|'[^$])?(-)?(\d+)?(?:\.(\d+))?([b-gijosStTuvxX])/,
key: /^([a-z_][a-z_\d]*)/i,
key_access: /^\.([a-z_][a-z_\d]*)/i,
index_access: /^\[(\d+)\]/,
sign: /^[\+\-]/
}
-
+
function sprintf() {
var key = arguments[0], cache = sprintf.cache
if (!(cache[key] && cache.hasOwnProperty(key))) {
cache[key] = sprintf.parse(key)
}
return sprintf.format.call(null, cache[key], arguments)
}
-
+
sprintf.format = function(parse_tree, argv) {
var cursor = 1, tree_length = parse_tree.length, node_type = '', arg, output = [], i, k, match, pad, pad_character, pad_length, is_positive = true, sign = ''
for (i = 0; i < tree_length; i++) {
node_type = get_type(parse_tree[i])
if (node_type === 'string') {
output[output.length] = parse_tree[i]
}
else if (node_type === 'array') {
@@ -2210,29 +2188,29 @@ var Debugger =
}
}
else if (match[1]) { // positional argument (explicit)
arg = argv[match[1]]
}
else { // positional argument (implicit)
arg = argv[cursor++]
}
-
+
if (re.not_type.test(match[8]) && re.not_primitive.test(match[8]) && get_type(arg) == 'function') {
arg = arg()
}
-
+
if (re.numeric_arg.test(match[8]) && (get_type(arg) != 'number' && isNaN(arg))) {
throw new TypeError(sprintf("[sprintf] expecting number but found %s", get_type(arg)))
}
-
+
if (re.number.test(match[8])) {
is_positive = arg >= 0
}
-
+
switch (match[8]) {
case 'b':
arg = parseInt(arg, 10).toString(2)
break
case 'c':
arg = String.fromCharCode(parseInt(arg, 10))
break
case 'd':
@@ -2296,19 +2274,19 @@ var Debugger =
pad_length = match[6] - (sign + arg).length
pad = match[6] ? (pad_length > 0 ? str_repeat(pad_character, pad_length) : '') : ''
output[output.length] = match[5] ? sign + arg + pad : (pad_character === '0' ? sign + pad + arg : pad + sign + arg)
}
}
}
return output.join('')
}
-
+
sprintf.cache = {}
-
+
sprintf.parse = function(fmt) {
var _fmt = fmt, match = [], parse_tree = [], arg_names = 0
while (_fmt) {
if ((match = re.text.exec(_fmt)) !== null) {
parse_tree[parse_tree.length] = match[0]
}
else if ((match = re.modulo.exec(_fmt)) !== null) {
parse_tree[parse_tree.length] = '%'
@@ -2346,61 +2324,61 @@ var Debugger =
}
else {
throw new SyntaxError("[sprintf] unexpected placeholder")
}
_fmt = _fmt.substring(match[0].length)
}
return parse_tree
}
-
+
var vsprintf = function(fmt, argv, _argv) {
_argv = (argv || []).slice(0)
_argv.splice(0, 0, fmt)
return sprintf.apply(null, _argv)
}
-
+
/**
* helpers
*/
function get_type(variable) {
if (typeof variable === 'number') {
return 'number'
}
else if (typeof variable === 'string') {
return 'string'
}
else {
return Object.prototype.toString.call(variable).slice(8, -1).toLowerCase()
}
}
-
+
var preformattedPadding = {
'0': ['', '0', '00', '000', '0000', '00000', '000000', '0000000'],
' ': ['', ' ', ' ', ' ', ' ', ' ', ' ', ' '],
'_': ['', '_', '__', '___', '____', '_____', '______', '_______'],
}
function str_repeat(input, multiplier) {
if (multiplier >= 0 && multiplier <= 7 && preformattedPadding[input]) {
return preformattedPadding[input][multiplier]
}
return Array(multiplier + 1).join(input)
}
-
+
/**
* export to either browser or node.js
*/
if (true) {
exports.sprintf = sprintf
exports.vsprintf = vsprintf
}
else {
window.sprintf = sprintf
window.vsprintf = vsprintf
-
+
if (typeof define === 'function' && define.amd) {
define(function() {
return {
sprintf: sprintf,
vsprintf: vsprintf
}
})
}
@@ -2410,42 +2388,42 @@ var Debugger =
/***/ },
/* 34 */
/***/ function(module, exports, __webpack_require__) {
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
+
/**
* EventEmitter.
*/
-
+
var EventEmitter = function EventEmitter() {};
module.exports = EventEmitter;
-
+
const { Cu } = __webpack_require__(35);
const promise = __webpack_require__(40);
-
+
/**
* Decorate an object with event emitter functionality.
*
* @param Object aObjectToDecorate
* Bind all public methods of EventEmitter to
* the aObjectToDecorate object.
*/
EventEmitter.decorate = function EventEmitter_decorate (aObjectToDecorate) {
let emitter = new EventEmitter();
aObjectToDecorate.on = emitter.on.bind(emitter);
aObjectToDecorate.off = emitter.off.bind(emitter);
aObjectToDecorate.once = emitter.once.bind(emitter);
aObjectToDecorate.emit = emitter.emit.bind(emitter);
};
-
+
EventEmitter.prototype = {
/**
* Connect a listener.
*
* @param string aEvent
* The event name to which we're connecting.
* @param function aListener
* Called when the event is fired.
@@ -2453,48 +2431,48 @@ var Debugger =
on: function EventEmitter_on(aEvent, aListener) {
if (!this._eventEmitterListeners)
this._eventEmitterListeners = new Map();
if (!this._eventEmitterListeners.has(aEvent)) {
this._eventEmitterListeners.set(aEvent, []);
}
this._eventEmitterListeners.get(aEvent).push(aListener);
},
-
+
/**
* Listen for the next time an event is fired.
*
* @param string aEvent
* The event name to which we're connecting.
* @param function aListener
* (Optional) Called when the event is fired. Will be called at most
* one time.
* @return promise
* A promise which is resolved when the event next happens. The
* resolution value of the promise is the first event argument. If
* you need access to second or subsequent event arguments (it's rare
* that this is needed) then use aListener
*/
once: function EventEmitter_once(aEvent, aListener) {
let deferred = promise.defer();
-
+
let handler = (aEvent, aFirstArg, ...aRest) => {
this.off(aEvent, handler);
if (aListener) {
aListener.apply(null, [aEvent, aFirstArg, ...aRest]);
}
deferred.resolve(aFirstArg);
};
-
+
handler._originalListener = aListener;
this.on(aEvent, handler);
-
+
return deferred.promise;
},
-
+
/**
* Remove a previously-registered event listener. Works for events
* registered with either on or once.
*
* @param string aEvent
* The event name whose listener we're disconnecting.
* @param function aListener
* The listener to remove.
@@ -2504,34 +2482,34 @@ var Debugger =
return;
let listeners = this._eventEmitterListeners.get(aEvent);
if (listeners) {
this._eventEmitterListeners.set(aEvent, listeners.filter(l => {
return l !== aListener && l._originalListener !== aListener;
}));
}
},
-
+
/**
* Emit an event. All arguments to this method will
* be sent to listener functions.
*/
emit: function EventEmitter_emit(aEvent) {
if (!this._eventEmitterListeners || !this._eventEmitterListeners.has(aEvent)) {
return;
}
-
+
let originalListeners = this._eventEmitterListeners.get(aEvent);
for (let listener of this._eventEmitterListeners.get(aEvent)) {
// If the object was destroyed during event emission, stop
// emitting.
if (!this._eventEmitterListeners) {
break;
}
-
+
// If listeners were removed during emission, make sure the
// event handler we're going to fire wasn't removed.
if (originalListeners === this._eventEmitterListeners.get(aEvent) ||
this._eventEmitterListeners.get(aEvent).some(l => l === listener)) {
try {
listener.apply(null, arguments);
}
catch (ex) {
@@ -2548,32 +2526,32 @@ var Debugger =
/***/ },
/* 35 */
/***/ function(module, exports, __webpack_require__) {
/*
* A sham for https://developer.mozilla.org/en-US/Add-ons/SDK/Low-Level_APIs/chrome
*/
-
+
var { inDOMUtils } = __webpack_require__(36);
-
+
var ourServices = {
inIDOMUtils: inDOMUtils,
nsIClipboardHelper: {
copyString: () => {}
},
nsIXULChromeRegistry: {
isLocaleRTL: () => {return false;}
},
nsIDOMParser: {
-
- },
- };
-
+
+ },
+ };
+
module.exports = {
Cc: name => {
if(typeof console !== "undefined") {
console.log('Cc sham for', name);
}
return {
getService: (name) => ourServices[name],
createInstance: (iface) => ourServices[iface],
@@ -2592,17 +2570,17 @@ var Debugger =
"DISPATCH_SYNC":1
},
nsIDOMNode: typeof HTMLElement !== "undefined" ? HTMLElement : null,
nsIFocusManager: {
MOVEFOCUS_BACKWARD: 2,
MOVEFOCUS_FORWARD: 1,
},
nsIDOMKeyEvent: {
-
+
},
nsIDOMCSSRule: {"UNKNOWN_RULE":0,"STYLE_RULE":1,"CHARSET_RULE":2,"IMPORT_RULE":3,"MEDIA_RULE":4,"FONT_FACE_RULE":5,"PAGE_RULE":6,"KEYFRAMES_RULE":7,"KEYFRAME_RULE":8,"MOZ_KEYFRAMES_RULE":7,"MOZ_KEYFRAME_RULE":8,"NAMESPACE_RULE":10,"COUNTER_STYLE_RULE":11,"SUPPORTS_RULE":12,"FONT_FEATURE_VALUES_RULE":14},
inIDOMUtils: "inIDOMUtils",
nsIClipboardHelper: "nsIClipboardHelper",
nsIXULChromeRegistry: "nsIXULChromeRegistry",
},
Cu: {
reportError: msg => { (typeof console !== "undefined") ? console.error(msg) : dump(msg) },
@@ -2615,58 +2593,58 @@ var Debugger =
};
/***/ },
/* 36 */
/***/ function(module, exports, __webpack_require__) {
// A sham for inDOMUtils.
-
+
"use strict";
-
+
var { CSSLexer } = __webpack_require__(37);
var { cssColors } = __webpack_require__(38);
var { cssProperties } = __webpack_require__(39);
-
+
var cssRGBMap;
-
+
// From inIDOMUtils.idl.
var EXCLUDE_SHORTHANDS = (1 << 0);
var INCLUDE_ALIASES = (1 << 1);
var TYPE_LENGTH = 0;
var TYPE_PERCENTAGE = 1;
var TYPE_COLOR = 2;
var TYPE_URL = 3;
var TYPE_ANGLE = 4;
var TYPE_FREQUENCY = 5;
var TYPE_TIME = 6;
var TYPE_GRADIENT = 7;
var TYPE_TIMING_FUNCTION = 8;
var TYPE_IMAGE_RECT = 9;
var TYPE_NUMBER = 10;
-
+
function getCSSLexer(text) {
return new CSSLexer(text);
}
-
+
function rgbToColorName(r, g, b) {
if (!cssRGBMap) {
cssRGBMap = new Map();
for (let name in cssColors) {
cssRGBMap.set(JSON.stringify(cssColors[name]), name);
}
}
let value = cssRGBMap.get(JSON.stringify([r, g, b]));
if (!value) {
throw new Error("no such color");
}
return value;
}
-
+
// Taken from dom/tests/mochitest/ajax/mochikit/MochiKit/Color.js
function _hslValue(n1, n2, hue) {
if (hue > 6.0) {
hue -= 6.0;
} else if (hue < 0.0) {
hue += 6.0;
}
var val;
@@ -2676,17 +2654,17 @@ var Debugger =
val = n2;
} else if (hue < 4.0) {
val = n1 + (n2 - n1) * (4.0 - hue);
} else {
val = n1;
}
return val;
}
-
+
// Taken from dom/tests/mochitest/ajax/mochikit/MochiKit/Color.js
// and then modified.
function hslToRGB([hue, saturation, lightness]) {
var red;
var green;
var blue;
if (saturation === 0) {
red = lightness;
@@ -2703,59 +2681,59 @@ var Debugger =
var f = _hslValue;
var h6 = hue * 6.0;
red = f(m1, m2, h6 + 2);
green = f(m1, m2, h6);
blue = f(m1, m2, h6 - 2);
}
return [red, green, blue];
}
-
+
function colorToRGBA(name) {
name = name.trim().toLowerCase();
if (name in cssColors) {
return cssColors[name];
}
-
+
if (name === "transparent") {
return [0, 0, 0, 0];
}
-
+
let lexer = getCSSLexer(name);
-
+
let getToken = function() {
while (true) {
let token = lexer.nextToken();
if (!token || token.tokenType !== "comment" ||
token.tokenType !== "whitespace") {
return token;
}
}
};
-
+
let requireComma = function(token) {
if (token.tokenType !== "symbol" || token.text !== ",") {
return null;
}
return getToken();
};
-
+
let func = getToken();
if (!func || func.tokenType !== "function") {
return null;
}
let alpha = false;
if (func.text === "rgb" || func.text === "hsl") {
// Nothing.
} else if (func.text === "rgba" || func.text === "hsla") {
alpha = true;
} else {
return null;
}
-
+
let vals = [];
for (let i = 0; i < 3; ++i) {
let token = getToken();
if (i > 0) {
token = requireComma(token);
}
if (token.tokenType !== "number" || !token.isInteger) {
return null;
@@ -2763,146 +2741,146 @@ var Debugger =
let num = token.number;
if (num < 0) {
num = 0;
} else if (num > 255) {
num = 255;
}
vals.push(num);
}
-
+
if (func.text === "hsl" || func.text === "hsla") {
vals = hslToRGB(vals);
}
-
+
if (alpha) {
let token = requireComma(getToken());
if (token.tokenType !== "number") {
return null;
}
let num = token.number;
if (num < 0) {
num = 0;
} else if (num > 1) {
num = 1;
}
vals.push(num);
} else {
vals.push(1);
}
-
+
let parenToken = getToken();
if (!parenToken || parenToken.tokenType !== "symbol" ||
parenToken.text !== ")") {
return null;
}
if (getToken() !== null) {
return null;
}
-
+
return vals;
}
-
+
function isValidCSSColor(name) {
return colorToRGBA(name) !== null;
}
-
+
function isVariable(name) {
return name.startsWith("--");
}
-
+
function cssPropertyIsShorthand(name) {
if (isVariable(name)) {
return false;
}
if (!(name in cssProperties)) {
throw Error("unknown property " + name);
}
return !!cssProperties[name].subproperties;
}
-
+
function getSubpropertiesForCSSProperty(name) {
if (isVariable(name)) {
return [name];
}
if (!(name in cssProperties)) {
throw Error("unknown property " + name);
}
if ("subproperties" in cssProperties[name]) {
return cssProperties[name].subproperties.slice();
}
return [name];
}
-
+
function getCSSValuesForProperty(name) {
if (isVariable(name)) {
return ["initial", "inherit", "unset"];
}
if (!(name in cssProperties)) {
throw Error("unknown property " + name);
}
return cssProperties[name].values.slice();
}
-
+
function getCSSPropertyNames(flags) {
let names = Object.keys(cssProperties);
if ((flags & EXCLUDE_SHORTHANDS) !== 0) {
names = names.filter((name) => cssProperties[name].subproperties);
}
if ((flags & INCLUDE_ALIASES) === 0) {
names = names.filter((name) => !cssProperties[name].alias);
}
return names;
}
-
+
function cssPropertySupportsType(name, type) {
if (isVariable(name)) {
return false;
}
if (!(name in cssProperties)) {
throw Error("unknown property " + name);
}
return (cssProperties[name].supports & (1 << type)) !== 0;
}
-
+
function isInheritedProperty(name) {
if (isVariable(name)) {
return true;
}
if (!(name in cssProperties)) {
return false;
}
return cssProperties[name].inherited;
}
-
+
function cssPropertyIsValid(name, value) {
if (isVariable(name)) {
return true;
}
if (!(name in cssProperties)) {
return false;
}
let elt = document.createElement("div");
elt.style = name + ":" + value;
return elt.style.length > 0;
}
-
+
exports.inDOMUtils = {
getCSSLexer,
rgbToColorName,
colorToRGBA,
isValidCSSColor,
cssPropertyIsShorthand,
getSubpropertiesForCSSProperty,
getCSSValuesForProperty,
getCSSPropertyNames,
cssPropertySupportsType,
isInheritedProperty,
cssPropertyIsValid,
-
+
// Constants.
EXCLUDE_SHORTHANDS,
INCLUDE_ALIASES,
TYPE_LENGTH,
TYPE_PERCENTAGE,
TYPE_COLOR,
TYPE_URL,
TYPE_ANGLE,
@@ -2915,117 +2893,117 @@ var Debugger =
};
/***/ },
/* 37 */
/***/ function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;"use strict";
-
+
(function (root, factory) {
// Universal Module Definition (UMD) to support AMD, CommonJS/Node.js,
// Rhino, and plain browser loading.
if (true) {
!(__WEBPACK_AMD_DEFINE_ARRAY__ = [exports], __WEBPACK_AMD_DEFINE_FACTORY__ = (factory), __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? (__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
} else if (typeof exports !== 'undefined') {
factory(exports);
} else {
factory(root);
}
}(this, function (exports) {
-
+
function between(num, first, last) { return num >= first && num <= last; }
function digit(code) { return between(code, 0x30,0x39); }
function hexdigit(code) { return digit(code) || between(code, 0x41,0x46) || between(code, 0x61,0x66); }
function uppercaseletter(code) { return between(code, 0x41,0x5a); }
function lowercaseletter(code) { return between(code, 0x61,0x7a); }
function letter(code) { return uppercaseletter(code) || lowercaseletter(code); }
function nonascii(code) { return code >= 0x80; }
function namestartchar(code) { return letter(code) || nonascii(code) || code == 0x5f; }
function namechar(code) { return namestartchar(code) || digit(code) || code == 0x2d; }
function nonprintable(code) { return between(code, 0,8) || code == 0xb || between(code, 0xe,0x1f) || code == 0x7f; }
function newline(code) { return code == 0xa; }
function whitespace(code) { return newline(code) || code == 9 || code == 0x20; }
-
+
var maximumallowedcodepoint = 0x10ffff;
-
+
var InvalidCharacterError = function(message) {
this.message = message;
};
InvalidCharacterError.prototype = new Error;
InvalidCharacterError.prototype.name = 'InvalidCharacterError';
-
+
function stringFromCode(code) {
if(code <= 0xffff) return String.fromCharCode(code);
// Otherwise, encode astral char as surrogate pair.
code -= Math.pow(2, 20);
var lead = Math.floor(code/Math.pow(2, 10)) + 0xd800;
var trail = code % Math.pow(2, 10) + 0xdc00;
return String.fromCharCode(lead) + String.fromCharCode(trail);
}
-
+
function* tokenize(str, options) {
if (options === undefined) {
options = {};
}
if (options.loc === undefined) {
options.loc = false;
}
if (options.offsets === undefined) {
options.offsets = false;
}
if (options.keepComments === undefined) {
options.keepComments = false;
}
if (options.startOffset === undefined) {
options.startOffset = 0;
}
-
+
var i = options.startOffset - 1;
var code;
-
+
// Line number information.
var line = 0;
var column = 0;
// The only use of lastLineLength is in reconsume().
var lastLineLength = 0;
var incrLineno = function() {
line += 1;
lastLineLength = column;
column = 0;
};
var locStart = {line:line, column:column};
var offsetStart = i;
-
+
var codepoint = function(i) {
if(i >= str.length) {
return -1;
}
return str.charCodeAt(i);
};
var next = function(num) {
if(num === undefined)
num = 1;
if(num > 3)
throw "Spec Error: no more than three codepoints of lookahead.";
-
+
var rcode;
for (var offset = i + 1; num-- > 0; ++offset) {
rcode = codepoint(offset);
if (rcode === 0xd && codepoint(offset+1) === 0xa) {
++offset;
rcode = 0xa;
} else if (rcode === 0xd || rcode === 0xc) {
rcode = 0xa;
} else if (rcode === 0x0) {
rcode = 0xfffd;
}
}
-
+
return rcode;
};
var consume = function(num) {
if(num === undefined)
num = 1;
while(num-- > 0) {
++i;
code = codepoint(i);
@@ -3053,17 +3031,17 @@ var Debugger =
return true;
};
var eof = function(codepoint) {
if(codepoint === undefined) codepoint = code;
return codepoint == -1;
};
var donothing = function() {};
var parseerror = function() { console.log("Parse error at index " + i + ", processing codepoint 0x" + code.toString(16) + ".");return true; };
-
+
var consumeAToken = function() {
consume();
if (!options.keepComments) {
while(code == 0x2f && next() == 0x2a) {
consumeAComment();
consume();
}
}
@@ -3203,33 +3181,33 @@ var Debugger =
}
else if(namestartchar(code)) {
reconsume();
return consumeAnIdentlikeToken();
}
else if(eof()) return new EOFToken();
else return new DelimToken(code);
};
-
+
var consumeAComment = function() {
consume();
var comment = "";
while(true) {
consume();
if(code == 0x2a && next() == 0x2f) {
consume();
break;
} else if(eof()) {
break;
}
comment += stringFromCode(code);
}
return new CommentToken(comment);
};
-
+
var consumeANumericToken = function() {
var num = consumeANumber();
var token;
if(wouldStartAnIdentifier(next(1), next(2), next(3))) {
token = new DimensionToken();
token.value = num.value;
token.repr = num.repr;
token.type = num.type;
@@ -3246,17 +3224,17 @@ var Debugger =
token.repr = num.repr;
token.type = num.type;
}
token.number = token.value;
token.isInteger = token.type === "integer";
// FIXME hasSign
return token;
};
-
+
var consumeAnIdentlikeToken = function() {
var str = consumeAName();
if(str.toLowerCase() == "url" && next() == 0x28) {
consume();
while(whitespace(next(1)) && whitespace(next(2)))
consume();
if((next() == 0x22 || next() == 0x27) ||
(whitespace(next()) && (next(2) == 0x22 || next(2) == 0x27))) {
@@ -3274,17 +3252,17 @@ var Debugger =
}
} else if(next() == 0x28) {
consume();
return new FunctionToken(str);
} else {
return new IdentToken(str);
}
};
-
+
var consumeAStringToken = function(endingCodePoint) {
if(endingCodePoint === undefined) endingCodePoint = code;
var string = "";
while(consume()) {
if(code == endingCodePoint || eof()) {
return new StringToken(string);
} else if(newline(code)) {
reconsume();
@@ -3297,17 +3275,17 @@ var Debugger =
} else {
string += stringFromCode(consumeEscape());
}
} else {
string += stringFromCode(code);
}
}
};
-
+
var consumeAURLToken = function() {
var token = new URLToken("");
while(whitespace(next())) consume();
if(eof(next())) return token;
while(consume()) {
if(code == 0x29 || eof()) {
break;
} else if(whitespace(code)) {
@@ -3334,17 +3312,17 @@ var Debugger =
}
} else {
token.value += stringFromCode(code);
}
}
token.text = token.value;
return token;
};
-
+
var consumeEscape = function() {
// Assume the the current character is the \
// and the next code point is not a newline.
consume();
if(hexdigit(code)) {
// Consume 1-6 hex digits
var digits = [code];
for(var total = 0; total < 5; total++) {
@@ -3360,41 +3338,41 @@ var Debugger =
if( value > maximumallowedcodepoint ) value = 0xfffd;
return value;
} else if(eof()) {
return 0xfffd;
} else {
return code;
}
};
-
+
var areAValidEscape = function(c1, c2) {
if(c1 != 0x5c) return false;
if(newline(c2)) return false;
return true;
};
var startsWithAValidEscape = function() {
return areAValidEscape(code, next());
};
-
+
var wouldStartAnIdentifier = function(c1, c2, c3) {
if(c1 == 0x2d) {
return namestartchar(c2) || c2 == 0x2d || areAValidEscape(c2, c3);
} else if(namestartchar(c1)) {
return true;
} else if(c1 == 0x5c) {
return areAValidEscape(c1, c2);
} else {
return false;
}
};
var startsWithAnIdentifier = function() {
return wouldStartAnIdentifier(code, next(1), next(2));
};
-
+
var wouldStartANumber = function(c1, c2, c3) {
if(c1 == 0x2b || c1 == 0x2d) {
if(digit(c2)) return true;
if(c2 == 0x2e && digit(c3)) return true;
return false;
} else if(c1 == 0x2e) {
if(digit(c2)) return true;
return false;
@@ -3402,31 +3380,31 @@ var Debugger =
return true;
} else {
return false;
}
};
var startsWithANumber = function() {
return wouldStartANumber(code, next(1), next(2));
};
-
+
var consumeAName = function() {
var result = "";
while(consume()) {
if(namechar(code)) {
result += stringFromCode(code);
} else if(startsWithAValidEscape()) {
result += stringFromCode(consumeEscape());
} else {
reconsume();
return result;
}
}
};
-
+
var consumeANumber = function() {
var repr = [];
var type = "integer";
if(next() == 0x2b || next() == 0x2d) {
consume();
repr += stringFromCode(code);
}
while(digit(next())) {
@@ -3466,37 +3444,37 @@ var Debugger =
while(digit(next())) {
consume();
repr += stringFromCode(code);
}
}
var value = convertAStringToANumber(repr);
return {type:type, value:value, repr:repr};
};
-
+
var convertAStringToANumber = function(string) {
// CSS's number rules are identical to JS, afaik.
return +string;
};
-
+
var consumeTheRemnantsOfABadURL = function() {
while(consume()) {
if(code == 0x2d || eof()) {
return;
} else if(startsWithAValidEscape()) {
consumeEscape();
donothing();
} else {
donothing();
}
}
};
-
-
-
+
+
+
var iterationCount = 0;
while(!eof(next())) {
var token = consumeAToken();
if (options.loc) {
token.loc = {};
token.loc.start = {line:locStart.line, column:locStart.column};
token.loc.end = {line:line, column:column};
}
@@ -3504,128 +3482,128 @@ var Debugger =
token.startOffset = offsetStart;
token.endOffset = i + 1;
}
yield token;
iterationCount++;
if(iterationCount > str.length*2) return "I'm infinite-looping!";
}
}
-
+
function CSSParserToken() { throw "Abstract Base Class"; }
CSSParserToken.prototype.toJSON = function() {
return {token: this.tokenType};
};
CSSParserToken.prototype.toString = function() { return this.tokenType; };
CSSParserToken.prototype.toSource = function() { return ''+this; };
-
+
function BadStringToken(text) {
this.text = text;
return this;
}
BadStringToken.prototype = Object.create(CSSParserToken.prototype);
BadStringToken.prototype.tokenType = "bad_string";
-
+
function BadURLToken() { return this; }
BadURLToken.prototype = Object.create(CSSParserToken.prototype);
BadURLToken.prototype.tokenType = "bad_url";
-
+
function WhitespaceToken() { return this; }
WhitespaceToken.prototype = Object.create(CSSParserToken.prototype);
WhitespaceToken.prototype.tokenType = "whitespace";
WhitespaceToken.prototype.toString = function() { return "WS"; };
WhitespaceToken.prototype.toSource = function() { return " "; };
-
+
function CDOToken() { return this; }
CDOToken.prototype = Object.create(CSSParserToken.prototype);
CDOToken.prototype.tokenType = "htmlcomment";
CDOToken.prototype.toSource = function() { return "<!--"; };
-
+
function CDCToken() { return this; }
CDCToken.prototype = Object.create(CSSParserToken.prototype);
CDCToken.prototype.tokenType = "htmlcomment";
CDCToken.prototype.toSource = function() { return "-->"; };
-
+
function ColonToken() { return this; }
ColonToken.prototype = Object.create(CSSParserToken.prototype);
ColonToken.prototype.tokenType = "symbol";
ColonToken.prototype.text = ":";
-
+
function SemicolonToken() { return this; }
SemicolonToken.prototype = Object.create(CSSParserToken.prototype);
SemicolonToken.prototype.tokenType = "symbol";
SemicolonToken.prototype.text = ";";
-
+
function CommaToken() { return this; }
CommaToken.prototype = Object.create(CSSParserToken.prototype);
CommaToken.prototype.tokenType = "symbol";
CommaToken.prototype.text = ",";
-
+
function GroupingToken() { throw "Abstract Base Class"; }
GroupingToken.prototype = Object.create(CSSParserToken.prototype);
-
+
function OpenCurlyToken() { this.value = "{"; this.mirror = "}"; return this; }
OpenCurlyToken.prototype = Object.create(GroupingToken.prototype);
OpenCurlyToken.prototype.tokenType = "symbol";
OpenCurlyToken.prototype.text = "{";
-
+
function CloseCurlyToken() { this.value = "}"; this.mirror = "{"; return this; }
CloseCurlyToken.prototype = Object.create(GroupingToken.prototype);
CloseCurlyToken.prototype.tokenType = "symbol";
CloseCurlyToken.prototype.text = "}";
-
+
function OpenSquareToken() { this.value = "["; this.mirror = "]"; return this; }
OpenSquareToken.prototype = Object.create(GroupingToken.prototype);
OpenSquareToken.prototype.tokenType = "symbol";
OpenSquareToken.prototype.text = "[";
-
+
function CloseSquareToken() { this.value = "]"; this.mirror = "["; return this; }
CloseSquareToken.prototype = Object.create(GroupingToken.prototype);
CloseSquareToken.prototype.tokenType = "symbol";
CloseSquareToken.prototype.text = "]";
-
+
function OpenParenToken() { this.value = "("; this.mirror = ")"; return this; }
OpenParenToken.prototype = Object.create(GroupingToken.prototype);
OpenParenToken.prototype.tokenType = "symbol";
OpenParenToken.prototype.text = "(";
-
+
function CloseParenToken() { this.value = ")"; this.mirror = "("; return this; }
CloseParenToken.prototype = Object.create(GroupingToken.prototype);
CloseParenToken.prototype.tokenType = "symbol";
CloseParenToken.prototype.text = ")";
-
+
function IncludeMatchToken() { return this; }
IncludeMatchToken.prototype = Object.create(CSSParserToken.prototype);
IncludeMatchToken.prototype.tokenType = "includes";
-
+
function DashMatchToken() { return this; }
DashMatchToken.prototype = Object.create(CSSParserToken.prototype);
DashMatchToken.prototype.tokenType = "dashmatch";
-
+
function PrefixMatchToken() { return this; }
PrefixMatchToken.prototype = Object.create(CSSParserToken.prototype);
PrefixMatchToken.prototype.tokenType = "beginsmatch";
-
+
function SuffixMatchToken() { return this; }
SuffixMatchToken.prototype = Object.create(CSSParserToken.prototype);
SuffixMatchToken.prototype.tokenType = "endsmatch";
-
+
function SubstringMatchToken() { return this; }
SubstringMatchToken.prototype = Object.create(CSSParserToken.prototype);
SubstringMatchToken.prototype.tokenType = "containsmatch";
-
+
function ColumnToken() { return this; }
ColumnToken.prototype = Object.create(CSSParserToken.prototype);
ColumnToken.prototype.tokenType = "||";
-
+
function EOFToken() { return this; }
EOFToken.prototype = Object.create(CSSParserToken.prototype);
EOFToken.prototype.tokenType = "EOF";
EOFToken.prototype.toSource = function() { return ""; };
-
+
function DelimToken(code) {
this.value = stringFromCode(code);
this.text = this.value;
return this;
}
DelimToken.prototype = Object.create(CSSParserToken.prototype);
DelimToken.prototype.tokenType = "symbol";
DelimToken.prototype.toString = function() { return "DELIM("+this.value+")"; };
@@ -3635,62 +3613,62 @@ var Debugger =
return json;
};
DelimToken.prototype.toSource = function() {
if(this.value == "\\")
return "\\\n";
else
return this.value;
};
-
+
function StringValuedToken() { throw "Abstract Base Class"; }
StringValuedToken.prototype = Object.create(CSSParserToken.prototype);
StringValuedToken.prototype.ASCIIMatch = function(str) {
return this.value.toLowerCase() == str.toLowerCase();
};
StringValuedToken.prototype.toJSON = function() {
var json = this.constructor.prototype.constructor.prototype.toJSON.call(this);
json.value = this.value;
return json;
};
-
+
function IdentToken(val) {
this.value = val;
this.text = val;
}
IdentToken.prototype = Object.create(StringValuedToken.prototype);
IdentToken.prototype.tokenType = "ident";
IdentToken.prototype.toString = function() { return "IDENT("+this.value+")"; };
IdentToken.prototype.toSource = function() {
return escapeIdent(this.value);
};
-
+
function FunctionToken(val) {
this.value = val;
this.text = val;
this.mirror = ")";
}
FunctionToken.prototype = Object.create(StringValuedToken.prototype);
FunctionToken.prototype.tokenType = "function";
FunctionToken.prototype.toString = function() { return "FUNCTION("+this.value+")"; };
FunctionToken.prototype.toSource = function() {
return escapeIdent(this.value) + "(";
};
-
+
function AtKeywordToken(val) {
this.value = val;
this.text = val;
}
AtKeywordToken.prototype = Object.create(StringValuedToken.prototype);
AtKeywordToken.prototype.tokenType = "at";
AtKeywordToken.prototype.toString = function() { return "AT("+this.value+")"; };
AtKeywordToken.prototype.toSource = function() {
return "@" + escapeIdent(this.value);
};
-
+
function HashToken(val) {
this.value = val;
this.text = val;
this.type = "unrestricted";
}
HashToken.prototype = Object.create(StringValuedToken.prototype);
HashToken.prototype.tokenType = "hash";
HashToken.prototype.toString = function() { return "HASH("+this.value+")"; };
@@ -3702,48 +3680,48 @@ var Debugger =
};
HashToken.prototype.toSource = function() {
if(this.type == "id") {
return "#" + escapeIdent(this.value);
} else {
return "#" + escapeHash(this.value);
}
};
-
+
function StringToken(val) {
this.value = val;
this.text = val;
}
StringToken.prototype = Object.create(StringValuedToken.prototype);
StringToken.prototype.tokenType = "string";
StringToken.prototype.toString = function() {
return '"' + escapeString(this.value) + '"';
};
-
+
function CommentToken(val) {
this.value = val;
}
CommentToken.prototype = Object.create(StringValuedToken.prototype);
CommentToken.prototype.tokenType = "comment";
CommentToken.prototype.toString = function() {
return '/*' + this.value + '*/';
}
CommentToken.prototype.toSource = CommentToken.prototype.toString;
-
+
function URLToken(val) {
this.value = val;
this.text = val;
}
URLToken.prototype = Object.create(StringValuedToken.prototype);
URLToken.prototype.tokenType = "url";
URLToken.prototype.toString = function() { return "URL("+this.value+")"; };
URLToken.prototype.toSource = function() {
return 'url("' + escapeString(this.value) + '")';
};
-
+
function NumberToken() {
this.value = null;
this.type = "integer";
this.repr = "";
}
NumberToken.prototype = Object.create(CSSParserToken.prototype);
NumberToken.prototype.tokenType = "number";
NumberToken.prototype.toString = function() {
@@ -3754,32 +3732,32 @@ var Debugger =
NumberToken.prototype.toJSON = function() {
var json = this.constructor.prototype.constructor.prototype.toJSON.call(this);
json.value = this.value;
json.type = this.type;
json.repr = this.repr;
return json;
};
NumberToken.prototype.toSource = function() { return this.repr; };
-
+
function PercentageToken() {
this.value = null;
this.repr = "";
}
PercentageToken.prototype = Object.create(CSSParserToken.prototype);
PercentageToken.prototype.tokenType = "percentage";
PercentageToken.prototype.toString = function() { return "PERCENTAGE("+this.value+")"; };
PercentageToken.prototype.toJSON = function() {
var json = this.constructor.prototype.constructor.prototype.toJSON.call(this);
json.value = this.value;
json.repr = this.repr;
return json;
};
PercentageToken.prototype.toSource = function() { return this.repr + "%"; };
-
+
function DimensionToken() {
this.value = null;
this.type = "integer";
this.repr = "";
this.unit = "";
}
DimensionToken.prototype = Object.create(CSSParserToken.prototype);
DimensionToken.prototype.tokenType = "dimension";
@@ -3797,27 +3775,27 @@ var Debugger =
var unit = escapeIdent(this.unit);
if(unit[0].toLowerCase() == "e" && (unit[1] == "-" || between(unit.charCodeAt(1), 0x30, 0x39))) {
// Unit is ambiguous with scinot
// Remove the leading "e", replace with escape.
unit = "\\65 " + unit.slice(1, unit.length);
}
return source+unit;
};
-
+
function escapeIdent(string) {
string = ''+string;
var result = '';
var firstcode = string.charCodeAt(0);
for(var i = 0; i < string.length; i++) {
var code = string.charCodeAt(i);
if(code === 0x0) {
throw new InvalidCharacterError('Invalid character: the input contains U+0000.');
}
-
+
if(
between(code, 0x1, 0x1f) || code == 0x7f ||
(i === 0 && between(code, 0x30, 0x39)) ||
(i == 1 && between(code, 0x30, 0x39) && firstcode == 0x2d)
) {
result += '\\' + code.toString(16) + ' ';
} else if(
code >= 0x80 ||
@@ -3829,66 +3807,66 @@ var Debugger =
) {
result += string[i];
} else {
result += '\\' + string[i];
}
}
return result;
}
-
+
function escapeHash(string) {
// Escapes the contents of "unrestricted"-type hash tokens.
// Won't preserve the ID-ness of "id"-type hash tokens;
// use escapeIdent() for that.
string = ''+string;
var result = '';
for(var i = 0; i < string.length; i++) {
var code = string.charCodeAt(i);
if(code === 0x0) {
throw new InvalidCharacterError('Invalid character: the input contains U+0000.');
}
-
+
if(
code >= 0x80 ||
code == 0x2d ||
code == 0x5f ||
between(code, 0x30, 0x39) ||
between(code, 0x41, 0x5a) ||
between(code, 0x61, 0x7a)
) {
result += string[i];
} else {
result += '\\' + code.toString(16) + ' ';
}
}
return result;
}
-
+
function escapeString(string) {
string = ''+string;
var result = '';
for(var i = 0; i < string.length; i++) {
var code = string.charCodeAt(i);
-
+
if(code === 0x0) {
throw new InvalidCharacterError('Invalid character: the input contains U+0000.');
}
-
+
if(between(code, 0x1, 0x1f) || code == 0x7f) {
result += '\\' + code.toString(16) + ' ';
} else if(code == 0x22 || code == 0x5c) {
result += '\\' + string[i];
} else {
result += string[i];
}
}
return result;
}
-
+
// Exportation.
exports.tokenize = tokenize;
exports.IdentToken = IdentToken;
exports.FunctionToken = FunctionToken;
exports.AtKeywordToken = AtKeywordToken;
exports.HashToken = HashToken;
exports.StringToken = StringToken;
exports.BadStringToken = BadStringToken;
@@ -3914,17 +3892,17 @@ var Debugger =
exports.CloseParenToken = CloseParenToken;
exports.OpenSquareToken = OpenSquareToken;
exports.CloseSquareToken = CloseSquareToken;
exports.OpenCurlyToken = OpenCurlyToken;
exports.CloseCurlyToken = CloseCurlyToken;
exports.EOFToken = EOFToken;
exports.CSSParserToken = CSSParserToken;
exports.GroupingToken = GroupingToken;
-
+
function TokenStream(tokens) {
// Assume that tokens is a iterator.
this.tokens = tokens;
this.token = undefined;
this.stored = [];
}
TokenStream.prototype.consume = function(num) {
if(num === undefined) num = 1;
@@ -3956,23 +3934,23 @@ var Debugger =
return new EOFToken();
this.stored.push(n.value);
}
return this.stored[0];
};
TokenStream.prototype.reconsume = function() {
this.stored.unshift(this.token);
};
-
+
function parseerror(s, msg) {
console.log("Parse error at token " + s.i + ": " + s.token + ".\n" + msg);
return true;
}
function donothing(){ return true; }
-
+
function consumeAListOfRules(s, topLevel) {
var rules = [];
var rule;
while(s.consume()) {
if(s.token instanceof WhitespaceToken) {
continue;
} else if(s.token instanceof EOFToken) {
return rules;
@@ -3984,49 +3962,49 @@ var Debugger =
s.reconsume();
if(rule = consumeAnAtRule(s)) rules.push(rule);
} else {
s.reconsume();
if(rule = consumeAQualifiedRule(s)) rules.push(rule);
}
}
}
-
+
function consumeAnAtRule(s) {
s.consume();
var rule = new AtRule(s.token.value);
while(s.consume()) {
if(s.token instanceof SemicolonToken || s.token instanceof EOFToken) {
return rule;
} else if(s.token instanceof OpenCurlyToken) {
rule.value = consumeASimpleBlock(s);
return rule;
} else {
s.reconsume();
rule.prelude.push(consumeAComponentValue(s));
}
}
}
-
+
function consumeAQualifiedRule(s) {
var rule = new QualifiedRule();
while(s.consume()) {
if(s.token instanceof EOFToken) {
parseerror(s, "Hit EOF when trying to parse the prelude of a qualified rule.");
return;
} else if(s.token instanceof OpenCurlyToken) {
rule.value = consumeASimpleBlock(s);
return rule;
} else {
s.reconsume();
rule.prelude.push(consumeAComponentValue(s));
}
}
}
-
+
function consumeAListOfDeclarations(s) {
var decls = [];
while(s.consume()) {
if(s.token instanceof WhitespaceToken || s.token instanceof SemicolonToken) {
donothing();
} else if(s.token instanceof EOFToken) {
return decls;
} else if(s.token instanceof AtKeywordToken) {
@@ -4041,17 +4019,17 @@ var Debugger =
} else {
parseerror(s);
s.reconsume();
while(!(s.next() instanceof SemicolonToken || s.next() instanceof EOFToken))
consumeAComponentValue(s);
}
}
}
-
+
function consumeADeclaration(s) {
// Assumes that the next input token will be an ident token.
s.consume();
var decl = new Declaration(s.token.value);
while(s.next() instanceof WhitespaceToken) s.consume();
if(!(s.next() instanceof ColonToken)) {
parseerror(s);
return;
@@ -4072,133 +4050,133 @@ var Debugger =
decl.important = true;
break;
} else {
break;
}
}
return decl;
}
-
+
function consumeAComponentValue(s) {
s.consume();
if(s.token instanceof OpenCurlyToken || s.token instanceof OpenSquareToken || s.token instanceof OpenParenToken)
return consumeASimpleBlock(s);
if(s.token instanceof FunctionToken)
return consumeAFunction(s);
return s.token;
}
-
+
function consumeASimpleBlock(s) {
var mirror = s.token.mirror;
var block = new SimpleBlock(s.token.value);
block.startToken = s.token;
while(s.consume()) {
if(s.token instanceof EOFToken || (s.token instanceof GroupingToken && s.token.value == mirror))
return block;
else {
s.reconsume();
block.value.push(consumeAComponentValue(s));
}
}
}
-
+
function consumeAFunction(s) {
var func = new Func(s.token.value);
while(s.consume()) {
if(s.token instanceof EOFToken || s.token instanceof CloseParenToken)
return func;
else {
s.reconsume();
func.value.push(consumeAComponentValue(s));
}
}
}
-
+
function normalizeInput(input) {
if(typeof input == "string")
return new TokenStream(tokenize(input));
if(input instanceof TokenStream)
return input;
if(typeof (input.next) == "function")
return new TokenStream(input);
if(input.length !== undefined)
return new TokenStream(input[Symbol.iterator]());
else throw SyntaxError(input);
}
-
+
function parseAStylesheet(s) {
s = normalizeInput(s);
var sheet = new Stylesheet();
sheet.value = consumeAListOfRules(s, "top-level");
return sheet;
}
-
+
function parseAListOfRules(s) {
s = normalizeInput(s);
return consumeAListOfRules(s);
}
-
+
function parseARule(s) {
s = normalizeInput(s);
while(s.next() instanceof WhitespaceToken) s.consume();
if(s.next() instanceof EOFToken) throw SyntaxError();
var rule;
var startToken = s.next();
if(startToken instanceof AtKeywordToken) {
rule = consumeAnAtRule(s);
} else {
rule = consumeAQualifiedRule(s);
if(!rule) throw SyntaxError();
}
rule.startToken = startToken;
rule.endToken = s.token;
return rule;
}
-
+
function parseADeclaration(s) {
s = normalizeInput(s);
while(s.next() instanceof WhitespaceToken) s.consume();
if(!(s.next() instanceof IdentToken)) throw SyntaxError();
var decl = consumeADeclaration(s);
if(decl)
return decl;
else
throw SyntaxError();
}
-
+
function parseAListOfDeclarations(s) {
s = normalizeInput(s);
return consumeAListOfDeclarations(s);
}
-
+
function parseAComponentValue(s) {
s = normalizeInput(s);
while(s.next() instanceof WhitespaceToken) s.consume();
if(s.next() instanceof EOFToken) throw SyntaxError();
var val = consumeAComponentValue(s);
if(!val) throw SyntaxError();
while(s.next() instanceof WhitespaceToken) s.consume();
if(s.next() instanceof EOFToken)
return val;
throw SyntaxError();
}
-
+
function parseAListOfComponentValues(s) {
s = normalizeInput(s);
var vals = [];
while(true) {
var val = consumeAComponentValue(s);
if(val instanceof EOFToken)
return vals;
else
vals.push(val);
}
}
-
+
function parseACommaSeparatedListOfComponentValues(s) {
s = normalizeInput(s);
var listOfCVLs = [];
while(true) {
var vals = [];
while(true) {
var val = consumeAComponentValue(s);
if(val instanceof EOFToken) {
@@ -4208,132 +4186,132 @@ var Debugger =
listOfCVLs.push(vals);
break;
} else {
vals.push(val);
}
}
}
}
-
-
+
+
function CSSParserRule() { throw "Abstract Base Class"; }
CSSParserRule.prototype.toString = function(indent) {
return JSON.stringify(this,null,indent);
};
CSSParserRule.prototype.toJSON = function() {
return {type:this.type, value:this.value};
};
-
+
function Stylesheet() {
this.value = [];
return this;
}
Stylesheet.prototype = Object.create(CSSParserRule.prototype);
Stylesheet.prototype.type = "STYLESHEET";
-
+
function AtRule(name) {
this.name = name;
this.prelude = [];
this.value = null;
return this;
}
AtRule.prototype = Object.create(CSSParserRule.prototype);
AtRule.prototype.type = "AT-RULE";
AtRule.prototype.toJSON = function() {
var json = this.constructor.prototype.constructor.prototype.toJSON.call(this);
json.name = this.name;
json.prelude = this.prelude;
return json;
};
-
+
function QualifiedRule() {
this.prelude = [];
this.value = [];
return this;
}
QualifiedRule.prototype = Object.create(CSSParserRule.prototype);
QualifiedRule.prototype.type = "QUALIFIED-RULE";
QualifiedRule.prototype.toJSON = function() {
var json = this.constructor.prototype.constructor.prototype.toJSON.call(this);
json.prelude = this.prelude;
return json;
};
-
+
function Declaration(name) {
this.name = name;
this.value = [];
this.important = false;
return this;
}
Declaration.prototype = Object.create(CSSParserRule.prototype);
Declaration.prototype.type = "DECLARATION";
Declaration.prototype.toJSON = function() {
var json = this.constructor.prototype.constructor.prototype.toJSON.call(this);
json.name = this.name;
json.important = this.important;
return json;
};
-
+
function SimpleBlock(type) {
this.name = type;
this.value = [];
return this;
}
SimpleBlock.prototype = Object.create(CSSParserRule.prototype);
SimpleBlock.prototype.type = "BLOCK";
SimpleBlock.prototype.toJSON = function() {
var json = this.constructor.prototype.constructor.prototype.toJSON.call(this);
json.name = this.name;
return json;
};
-
+
function Func(name) {
this.name = name;
this.value = [];
return this;
}
Func.prototype = Object.create(CSSParserRule.prototype);
Func.prototype.type = "FUNCTION";
Func.prototype.toJSON = function() {
var json = this.constructor.prototype.constructor.prototype.toJSON.call(this);
json.name = this.name;
return json;
};
-
+
function CSSLexer(text) {
this.stream = tokenize(text, {
loc: true,
offsets: true,
keepComments: true
});
this.lineNumber = 0;
this.columnNumber = 0;
return this;
}
-
+
CSSLexer.prototype.performEOFFixup = function(input, preserveBackslash) {
// Just lie for now.
return "";
};
-
+
CSSLexer.prototype.nextToken = function() {
if (!this.stream) {
return null;
}
let v = this.stream.next();
if (v.done || v.value.tokenType === "EOF") {
this.stream = null;
return null;
}
this.lineNumber = v.value.loc.start.line;
this.columnNumber = v.value.loc.start.column;
return v.value;
};
-
+
// Exportation.
exports.CSSParserRule = CSSParserRule;
exports.Stylesheet = Stylesheet;
exports.AtRule = AtRule;
exports.QualifiedRule = QualifiedRule;
exports.Declaration = Declaration;
exports.SimpleBlock = SimpleBlock;
exports.Func = Func;
@@ -4341,17 +4319,17 @@ var Debugger =
exports.parseAListOfRules = parseAListOfRules;
exports.parseARule = parseARule;
exports.parseADeclaration = parseADeclaration;
exports.parseAListOfDeclarations = parseAListOfDeclarations;
exports.parseAComponentValue = parseAComponentValue;
exports.parseAListOfComponentValues = parseAListOfComponentValues;
exports.parseACommaSeparatedListOfComponentValues = parseACommaSeparatedListOfComponentValues;
exports.CSSLexer = CSSLexer;
-
+
}));
/***/ },
/* 38 */
/***/ function(module, exports) {
// auto-generated from nsColorNameList.h
@@ -6649,67 +6627,67 @@ var Debugger =
/***/ },
/* 40 */
/***/ function(module, exports) {
/*
* A sham for https://dxr.mozilla.org/mozilla-central/source/toolkit/modules/Promise.jsm
*/
-
+
/**
* Promise.jsm is mostly the Promise web API with a `defer` method. Just drop this in here,
* and use the native web API (although building with webpack/babel, it may replace this
* with it's own version if we want to target environments that do not have `Promise`.
*/
-
+
let p = typeof window != "undefined" ? window.Promise : Promise;
p.defer = function defer() {
var resolve, reject;
var promise = new Promise(function() {
resolve = arguments[0];
reject = arguments[1];
});
return {
resolve: resolve,
reject: reject,
promise: promise
};
}
-
+
module.exports = p;
/***/ },
/* 41 */
/***/ function(module, exports, __webpack_require__) {
/* eslint-env browser */
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
+
// TODO: Get rid of this code once the marionette server loads transport.js as
// an SDK module (see bug 1000814)
-
+
"use strict";
-
+
const DevToolsUtils = __webpack_require__(42);
const { dumpn, dumpv } = DevToolsUtils;
const StreamUtils = __webpack_require__(48);
const { Packet, JSONPacket, BulkPacket } =
__webpack_require__(49);
const promise = __webpack_require__(40);
const EventEmitter = __webpack_require__(34);
const utf8 = __webpack_require__(52);
-
+
const PACKET_HEADER_MAX = 200;
-
+
/**
* An adapter that handles data transfers between the debugger client and
* server. It can work with both nsIPipe and nsIServerSocket transports so
* long as the properly created input and output streams are specified.
* (However, for intra-process connections, LocalDebuggerTransport, below,
* is more efficient than using an nsIPipe pair with DebuggerTransport.)
*
* @param input nsIAsyncInputStream
@@ -6759,54 +6737,54 @@ var Debugger =
* an optional nsresult or object, typically passed when the transport is
* closed due to some error in a underlying stream.
*
* See ./packets.js and the Remote Debugging Protocol specification for more
* details on the format of these packets.
*/
function DebuggerTransport(socket) {
EventEmitter.decorate(this);
-
+
this._socket = socket;
-
+
// The current incoming (possibly partial) header, which will determine which
// type of Packet |_incoming| below will become.
this._incomingHeader = "";
// The current incoming Packet object
this._incoming = null;
// A queue of outgoing Packet objects
this._outgoing = [];
-
+
this.hooks = null;
this.active = false;
-
+
this._incomingEnabled = true;
this._outgoingEnabled = true;
-
+
this.close = this.close.bind(this);
}
-
+
DebuggerTransport.prototype = {
/**
* Transmit an object as a JSON packet.
*
* This method returns immediately, without waiting for the entire
* packet to be transmitted, registering event handlers as needed to
* transmit the entire packet. Packets are transmitted in the order
* they are passed to this method.
*/
send: function(object) {
this.emit("send", object);
-
+
let packet = new JSONPacket(this);
packet.object = object;
this._outgoing.push(packet);
this._flushOutgoing();
},
-
+
/**
* Transmit streaming data via a bulk packet.
*
* This method initiates the bulk send process by queuing up the header data.
* The caller receives eventual access to a stream for writing.
*
* N.B.: Do *not* attempt to close the stream handed to you, as it will
* continue to be used by this transport afterwards. Most users should
@@ -6840,180 +6818,180 @@ var Debugger =
* @return Promise
* The promise is resolved when copying completes or
* rejected if any (unexpected) errors occur.
* This object also emits "progress" events for each chunk
* that is copied. See stream-utils.js.
*/
startBulkSend: function(header) {
this.emit("startBulkSend", header);
-
+
let packet = new BulkPacket(this);
packet.header = header;
this._outgoing.push(packet);
this._flushOutgoing();
return packet.streamReadyForWriting;
},
-
+
/**
* Close the transport.
* @param reason nsresult / object (optional)
* The status code or error message that corresponds to the reason for
* closing the transport (likely because a stream closed or failed).
*/
close: function(reason) {
this.emit("onClosed", reason);
-
+
this.active = false;
this._socket.close();
this._destroyIncoming();
this._destroyAllOutgoing();
if (this.hooks) {
this.hooks.onClosed(reason);
this.hooks = null;
}
if (reason) {
dumpn("Transport closed: " + DevToolsUtils.safeErrorString(reason));
} else {
dumpn("Transport closed.");
}
},
-
+
/**
* The currently outgoing packet (at the top of the queue).
*/
get _currentOutgoing() {
return this._outgoing[0];
},
-
+
/**
* Flush data to the outgoing stream. Waits until the output stream notifies
* us that it is ready to be written to (via onOutputStreamReady).
*/
_flushOutgoing: function() {
if (!this._outgoingEnabled || this._outgoing.length === 0) {
return;
}
-
+
// If the top of the packet queue has nothing more to send, remove it.
if (this._currentOutgoing.done) {
this._finishCurrentOutgoing();
}
-
+
if (this._outgoing.length > 0) {
setTimeout(this.onOutputStreamReady.bind(this), 0);
}
},
-
+
/**
* Pause this transport's attempts to write to the output stream. This is
* used when we've temporarily handed off our output stream for writing bulk
* data.
*/
pauseOutgoing: function() {
this._outgoingEnabled = false;
},
-
+
/**
* Resume this transport's attempts to write to the output stream.
*/
resumeOutgoing: function() {
this._outgoingEnabled = true;
this._flushOutgoing();
},
-
+
// nsIOutputStreamCallback
/**
* This is called when the output stream is ready for more data to be written.
* The current outgoing packet will attempt to write some amount of data, but
* may not complete.
*/
onOutputStreamReady: DevToolsUtils.makeInfallible(function() {
if (!this._outgoingEnabled || this._outgoing.length === 0) {
return;
}
-
+
try {
this._currentOutgoing.write({
write: data => {
let count = data.length;
this._socket.send(data);
return count;
}
});
} catch(e) {
if (e.result != Cr.NS_BASE_STREAM_WOULD_BLOCK) {
this.close(e.result);
return;
} else {
throw e;
}
}
-
+
this._flushOutgoing();
}, "DebuggerTransport.prototype.onOutputStreamReady"),
-
+
/**
* Remove the current outgoing packet from the queue upon completion.
*/
_finishCurrentOutgoing: function() {
if (this._currentOutgoing) {
this._currentOutgoing.destroy();
this._outgoing.shift();
}
},
-
+
/**
* Clear the entire outgoing queue.
*/
_destroyAllOutgoing: function() {
for (let packet of this._outgoing) {
packet.destroy();
}
this._outgoing = [];
},
-
+
/**
* Initialize the input stream for reading. Once this method has been called,
* we watch for packets on the input stream, and pass them to the appropriate
* handlers via this.hooks.
*/
ready: function() {
this.active = true;
this._waitForIncoming();
},
-
+
/**
* Asks the input stream to notify us (via onInputStreamReady) when it is
* ready for reading.
*/
_waitForIncoming: function() {
if (this._incomingEnabled && !this._socket.onmessage) {
this._socket.onmessage = this.onInputStreamReady.bind(this);
}
},
-
+
/**
* Pause this transport's attempts to read from the input stream. This is
* used when we've temporarily handed off our input stream for reading bulk
* data.
*/
pauseIncoming: function() {
this._incomingEnabled = false;
},
-
+
/**
* Resume this transport's attempts to read from the input stream.
*/
resumeIncoming: function() {
this._incomingEnabled = true;
this._flushIncoming();
this._waitForIncoming();
},
-
+
// nsIInputStreamCallback
/**
* Called when the stream is either readable or closed.
*/
onInputStreamReady:
DevToolsUtils.makeInfallible(function(event) {
let data = event.data;
// TODO: ws-tcp-proxy decodes utf-8, but the transport expects to see the
@@ -7024,213 +7002,213 @@ var Debugger =
return data.length;
},
readBytes(count) {
let result = data.slice(0, count);
data = data.slice(count);
return result;
},
};
-
+
try {
while (data && this._incomingEnabled &&
this._processIncoming(stream, stream.available())) {}
this._waitForIncoming();
} catch(e) {
if (e.result != Cr.NS_BASE_STREAM_WOULD_BLOCK) {
this.close(e.result);
} else {
throw e;
}
}
}, "DebuggerTransport.prototype.onInputStreamReady"),
-
+
/**
* Process the incoming data. Will create a new currently incoming Packet if
* needed. Tells the incoming Packet to read as much data as it can, but
* reading may not complete. The Packet signals that its data is ready for
* delivery by calling one of this transport's _on*Ready methods (see
* ./packets.js and the _on*Ready methods below).
* @return boolean
* Whether incoming stream processing should continue for any
* remaining data.
*/
_processIncoming: function(stream, count) {
dumpv("Data available: " + count);
-
+
if (!count) {
dumpv("Nothing to read, skipping");
return false;
}
-
+
try {
if (!this._incoming) {
dumpv("Creating a new packet from incoming");
-
+
if (!this._readHeader(stream)) {
return false; // Not enough data to read packet type
}
-
+
// Attempt to create a new Packet by trying to parse each possible
// header pattern.
this._incoming = Packet.fromHeader(this._incomingHeader, this);
if (!this._incoming) {
throw new Error("No packet types for header: " +
this._incomingHeader);
}
}
-
+
if (!this._incoming.done) {
// We have an incomplete packet, keep reading it.
dumpv("Existing packet incomplete, keep reading");
this._incoming.read(stream);
}
} catch(e) {
let msg = "Error reading incoming packet: (" + e + " - " + e.stack + ")";
dumpn(msg);
-
+
// Now in an invalid state, shut down the transport.
this.close();
return false;
}
-
+
if (!this._incoming.done) {
// Still not complete, we'll wait for more data.
dumpv("Packet not done, wait for more");
return true;
}
-
+
// Ready for next packet
this._flushIncoming();
return true;
},
-
+
/**
* Read as far as we can into the incoming data, attempting to build up a
* complete packet header (which terminates with ":"). We'll only read up to
* PACKET_HEADER_MAX characters.
* @return boolean
* True if we now have a complete header.
*/
_readHeader: function(stream) {
let amountToRead = PACKET_HEADER_MAX - this._incomingHeader.length;
this._incomingHeader +=
StreamUtils.delimitedRead(stream, ":", amountToRead);
if (dumpv.wantVerbose) {
dumpv("Header read: " + this._incomingHeader);
}
-
+
if (this._incomingHeader.endsWith(":")) {
if (dumpv.wantVerbose) {
dumpv("Found packet header successfully: " + this._incomingHeader);
}
return true;
}
-
+
if (this._incomingHeader.length >= PACKET_HEADER_MAX) {
throw new Error("Failed to parse packet header!");
}
-
+
// Not enough data yet.
return false;
},
-
+
/**
* If the incoming packet is done, log it as needed and clear the buffer.
*/
_flushIncoming: function() {
if (!this._incoming.done) {
return;
}
if (dumpn.wantLogging) {
dumpn("Got: " + this._incoming);
}
this._destroyIncoming();
},
-
+
/**
* Handler triggered by an incoming JSONPacket completing it's |read| method.
* Delivers the packet to this.hooks.onPacket.
*/
_onJSONObjectReady: function(object) {
DevToolsUtils.executeSoon(DevToolsUtils.makeInfallible(() => {
// Ensure the transport is still alive by the time this runs.
if (this.active) {
this.emit("onPacket", object);
this.hooks.onPacket(object);
}
}, "DebuggerTransport instance's this.hooks.onPacket"));
},
-
+
/**
* Handler triggered by an incoming BulkPacket entering the |read| phase for
* the stream portion of the packet. Delivers info about the incoming
* streaming data to this.hooks.onBulkPacket. See the main comment on the
* transport at the top of this file for more details.
*/
_onBulkReadReady: function(...args) {
DevToolsUtils.executeSoon(DevToolsUtils.makeInfallible(() => {
// Ensure the transport is still alive by the time this runs.
if (this.active) {
this.emit("onBulkPacket", ...args);
this.hooks.onBulkPacket(...args);
}
}, "DebuggerTransport instance's this.hooks.onBulkPacket"));
},
-
+
/**
* Remove all handlers and references related to the current incoming packet,
* either because it is now complete or because the transport is closing.
*/
_destroyIncoming: function() {
if (this._incoming) {
this._incoming.destroy();
}
this._incomingHeader = "";
this._incoming = null;
}
-
- };
-
+
+ };
+
exports.DebuggerTransport = DebuggerTransport;
-
+
/**
* An adapter that handles data transfers between the debugger client and
* server when they both run in the same process. It presents the same API as
* DebuggerTransport, but instead of transmitting serialized messages across a
* connection it merely calls the packet dispatcher of the other side.
*
* @param other LocalDebuggerTransport
* The other endpoint for this debugger connection.
*
* @see DebuggerTransport
*/
function LocalDebuggerTransport(other) {
EventEmitter.decorate(this);
-
+
this.other = other;
this.hooks = null;
-
+
/*
* A packet number, shared between this and this.other. This isn't used
* by the protocol at all, but it makes the packet traces a lot easier to
* follow.
*/
this._serial = this.other ? this.other._serial : { count: 0 };
this.close = this.close.bind(this);
}
-
+
LocalDebuggerTransport.prototype = {
/**
* Transmit a message by directly calling the onPacket handler of the other
* endpoint.
*/
send: function(packet) {
this.emit("send", packet);
-
+
let serial = this._serial.count++;
if (dumpn.wantLogging) {
/* Check 'from' first, as 'echo' packets have both. */
if (packet.from) {
dumpn("Packet " + serial + " sent from " + uneval(packet.from));
} else if (packet.to) {
dumpn("Packet " + serial + " sent to " + uneval(packet.to));
}
@@ -7245,121 +7223,121 @@ var Debugger =
}
if (other.hooks) {
other.emit("onPacket", packet);
other.hooks.onPacket(packet);
}
}, "LocalDebuggerTransport instance's this.other.hooks.onPacket"));
}
},
-
+
/**
* Send a streaming bulk packet directly to the onBulkPacket handler of the
* other endpoint.
*
* This case is much simpler than the full DebuggerTransport, since there is
* no primary stream we have to worry about managing while we hand it off to
* others temporarily. Instead, we can just make a single use pipe and be
* done with it.
*/
startBulkSend: function({actor, type, length}) {
this.emit("startBulkSend", {actor, type, length});
-
+
let serial = this._serial.count++;
-
+
dumpn("Sent bulk packet " + serial + " for actor " + actor);
if (!this.other) {
return;
}
-
+
let pipe = new Pipe(true, true, 0, 0, null);
-
+
DevToolsUtils.executeSoon(DevToolsUtils.makeInfallible(() => {
dumpn("Received bulk packet " + serial);
if (!this.other.hooks) {
return;
}
-
+
// Receiver
let deferred = promise.defer();
let packet = {
actor: actor,
type: type,
length: length,
copyTo: (output) => {
let copying =
StreamUtils.copyStream(pipe.inputStream, output, length);
deferred.resolve(copying);
return copying;
},
stream: pipe.inputStream,
done: deferred
};
-
+
this.other.emit("onBulkPacket", packet);
this.other.hooks.onBulkPacket(packet);
-
+
// Await the result of reading from the stream
deferred.promise.then(() => pipe.inputStream.close(), this.close);
}, "LocalDebuggerTransport instance's this.other.hooks.onBulkPacket"));
-
+
// Sender
let sendDeferred = promise.defer();
-
+
// The remote transport is not capable of resolving immediately here, so we
// shouldn't be able to either.
DevToolsUtils.executeSoon(() => {
let copyDeferred = promise.defer();
-
+
sendDeferred.resolve({
copyFrom: (input) => {
let copying =
StreamUtils.copyStream(input, pipe.outputStream, length);
copyDeferred.resolve(copying);
return copying;
},
stream: pipe.outputStream,
done: copyDeferred
});
-
+
// Await the result of writing to the stream
copyDeferred.promise.then(() => pipe.outputStream.close(), this.close);
});
-
+
return sendDeferred.promise;
},
-
+
/**
* Close the transport.
*/
close: function() {
this.emit("close");
-
+
if (this.other) {
// Remove the reference to the other endpoint before calling close(), to
// avoid infinite recursion.
let other = this.other;
this.other = null;
other.close();
}
if (this.hooks) {
try {
this.hooks.onClosed();
} catch(ex) {
console.error(ex);
}
this.hooks = null;
}
},
-
+
/**
* An empty method for emulating the DebuggerTransport API.
*/
ready: function() {},
-
+
/**
* Helper function that makes an object fully immutable.
*/
_deepFreeze: function(object) {
Object.freeze(object);
for (let prop in object) {
// Freeze the properties that are objects, not on the prototype, and not
// already frozen. Note that this might leave an unfrozen reference
@@ -7367,209 +7345,209 @@ var Debugger =
// an unfrozen object.
if (object.hasOwnProperty(prop) && typeof object === "object" &&
!Object.isFrozen(object)) {
this._deepFreeze(o[prop]);
}
}
}
};
-
+
exports.LocalDebuggerTransport = LocalDebuggerTransport;
-
+
/**
* A transport for the debugging protocol that uses nsIMessageSenders to
* exchange packets with servers running in child processes.
*
* In the parent process, |sender| should be the nsIMessageSender for the
* child process. In a child process, |sender| should be the child process
* message manager, which sends packets to the parent.
*
* |prefix| is a string included in the message names, to distinguish
* multiple servers running in the same child process.
*
* This transport exchanges messages named 'debug:<prefix>:packet', where
* <prefix> is |prefix|, whose data is the protocol packet.
*/
function ChildDebuggerTransport(sender, prefix) {
EventEmitter.decorate(this);
-
+
this._sender = sender.QueryInterface(Ci.nsIMessageSender);
this._messageName = "debug:" + prefix + ":packet";
}
-
+
/*
* To avoid confusion, we use 'message' to mean something that
* nsIMessageSender conveys, and 'packet' to mean a remote debugging
* protocol packet.
*/
ChildDebuggerTransport.prototype = {
constructor: ChildDebuggerTransport,
-
+
hooks: null,
-
+
ready: function () {
this._sender.addMessageListener(this._messageName, this);
},
-
+
close: function () {
this._sender.removeMessageListener(this._messageName, this);
this.emit("onClosed");
this.hooks.onClosed();
},
-
+
receiveMessage: function ({data}) {
this.emit("onPacket", data);
this.hooks.onPacket(data);
},
-
+
send: function (packet) {
this.emit("send", packet);
this._sender.sendAsyncMessage(this._messageName, packet);
},
-
+
startBulkSend: function() {
throw new Error("Can't send bulk data to child processes.");
}
};
-
+
exports.ChildDebuggerTransport = ChildDebuggerTransport;
-
+
// WorkerDebuggerTransport is defined differently depending on whether we are
// on the main thread or a worker thread. In the former case, we are required
// by the devtools loader, and isWorker will be false. Otherwise, we are
// required by the worker loader, and isWorker will be true.
//
// Each worker debugger supports only a single connection to the main thread.
// However, its theoretically possible for multiple servers to connect to the
// same worker. Consequently, each transport has a connection id, to allow
// messages from multiple connections to be multiplexed on a single channel.
-
+
if (typeof WorkerGlobalScope === 'undefined') { // i.e. not in a worker
(function () { // Main thread
/**
* A transport that uses a WorkerDebugger to send packets from the main
* thread to a worker thread.
*/
function WorkerDebuggerTransport(dbg, id) {
this._dbg = dbg;
this._id = id;
this.onMessage = this._onMessage.bind(this);
}
-
+
WorkerDebuggerTransport.prototype = {
constructor: WorkerDebuggerTransport,
-
+
ready: function () {
this._dbg.addListener(this);
},
-
+
close: function () {
this._dbg.removeListener(this);
if (this.hooks) {
this.hooks.onClosed();
}
},
-
+
send: function (packet) {
this._dbg.postMessage(JSON.stringify({
type: "message",
id: this._id,
message: packet
}));
},
-
+
startBulkSend: function () {
throw new Error("Can't send bulk data from worker threads!");
},
-
+
_onMessage: function (message) {
let packet = JSON.parse(message);
if (packet.type !== "message" || packet.id !== this._id) {
return;
}
-
+
if (this.hooks) {
this.hooks.onPacket(packet.message);
}
}
};
-
+
exports.WorkerDebuggerTransport = WorkerDebuggerTransport;
}).call(this);
} else {
(function () { // Worker thread
/*
* A transport that uses a WorkerDebuggerGlobalScope to send packets from a
* worker thread to the main thread.
*/
function WorkerDebuggerTransport(scope, id) {
this._scope = scope;
this._id = id;
this._onMessage = this._onMessage.bind(this);
}
-
+
WorkerDebuggerTransport.prototype = {
constructor: WorkerDebuggerTransport,
-
+
ready: function () {
this._scope.addEventListener("message", this._onMessage);
},
-
+
close: function () {
this._scope.removeEventListener("message", this._onMessage);
if (this.hooks) {
this.hooks.onClosed();
}
},
-
+
send: function (packet) {
this._scope.postMessage(JSON.stringify({
type: "message",
id: this._id,
message: packet
}));
},
-
+
startBulkSend: function () {
throw new Error("Can't send bulk data from worker threads!");
},
-
+
_onMessage: function (event) {
let packet = JSON.parse(event.data);
if (packet.type !== "message" || packet.id !== this._id) {
return;
}
-
+
if (this.hooks) {
this.hooks.onPacket(packet.message);
}
}
};
-
+
exports.WorkerDebuggerTransport = WorkerDebuggerTransport;
}).call(this);
}
/***/ },
/* 42 */
/***/ function(module, exports, __webpack_require__) {
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
+
/* General utilities used throughout devtools. */
var { Ci, Cu, Cc, components } = __webpack_require__(35);
const { Services } = __webpack_require__(28);
var promise = __webpack_require__(40);
-
+
const { FileUtils } = __webpack_require__(43);
-
+
/**
* Turn the error |aError| into a string, without fail.
*/
exports.safeErrorString = function safeErrorString(aError) {
try {
let errorString = aError.toString();
if (typeof errorString == "string") {
// Attempt to attach a stack to |errorString|. If it throws an error, or
@@ -7577,49 +7555,49 @@ var Debugger =
try {
if (aError.stack) {
let stack = aError.stack.toString();
if (typeof stack == "string") {
errorString += "\nStack: " + stack;
}
}
} catch (ee) { }
-
+
// Append additional line and column number information to the output,
// since it might not be part of the stringified error.
if (typeof aError.lineNumber == "number" && typeof aError.columnNumber == "number") {
errorString += "Line: " + aError.lineNumber + ", column: " + aError.columnNumber;
}
-
+
return errorString;
}
} catch (ee) { }
-
+
// We failed to find a good error description, so do the next best thing.
return Object.prototype.toString.call(aError);
};
-
+
/**
* Report that |aWho| threw an exception, |aException|.
*/
exports.reportException = function reportException(aWho, aException) {
let msg = aWho + " threw an exception: " + exports.safeErrorString(aException);
-
+
console.log(msg);
-
+
// if (Cu && console.error) {
// /*
// * Note that the xpcshell test harness registers an observer for
// * console messages, so when we're running tests, this will cause
// * the test to quit.
// */
// console.error(msg);
// }
};
-
+
/**
* Given a handler function that may throw, return an infallible handler
* function that calls the fallible handler, and logs any exceptions it
* throws.
*
* @param aHandler function
* A handler function, which may throw.
* @param aName string
@@ -7627,63 +7605,63 @@ var Debugger =
* aHandler.name.
*
* (SpiderMonkey does generate good names for anonymous functions, but we
* don't have a way to get at them from JavaScript at the moment.)
*/
exports.makeInfallible = function makeInfallible(aHandler, aName) {
if (!aName)
aName = aHandler.name;
-
+
return function(/* arguments */) {
// try {
return aHandler.apply(this, arguments);
// } catch (ex) {
// let who = "Handler function";
// if (aName) {
// who += " " + aName;
// }
// return exports.reportException(who, ex);
// }
};
};
-
+
/**
* Waits for the next tick in the event loop to execute a callback.
*/
exports.executeSoon = function executeSoon(aFn) {
setTimeout(aFn, 0);
};
-
+
/**
* Waits for the next tick in the event loop.
*
* @return Promise
* A promise that is resolved after the next tick in the event loop.
*/
exports.waitForTick = function waitForTick() {
let deferred = promise.defer();
exports.executeSoon(deferred.resolve);
return deferred.promise;
};
-
+
/**
* Waits for the specified amount of time to pass.
*
* @param number aDelay
* The amount of time to wait, in milliseconds.
* @return Promise
* A promise that is resolved after the specified amount of time passes.
*/
exports.waitForTime = function waitForTime(aDelay) {
let deferred = promise.defer();
setTimeout(deferred.resolve, aDelay);
return deferred.promise;
};
-
+
/**
* Like Array.prototype.forEach, but doesn't cause jankiness when iterating over
* very large arrays by yielding to the browser and continuing execution on the
* next tick.
*
* @param Array aArray
* The array being iterated over.
* @param Function aFn
@@ -7691,48 +7669,48 @@ var Debugger =
* returned by this function, iterating over the array will be paused
* until the respective promise is resolved.
* @returns Promise
* A promise that is resolved once the whole array has been iterated
* over, and all promises returned by the aFn callback are resolved.
*/
exports.yieldingEach = function yieldingEach(aArray, aFn) {
const deferred = promise.defer();
-
+
let i = 0;
let len = aArray.length;
let outstanding = [deferred.promise];
-
+
(function loop() {
const start = Date.now();
-
+
while (i < len) {
// Don't block the main thread for longer than 16 ms at a time. To
// maintain 60fps, you have to render every frame in at least 16ms; we
// aren't including time spent in non-JS here, but this is Good
// Enough(tm).
if (Date.now() - start > 16) {
exports.executeSoon(loop);
return;
}
-
+
try {
outstanding.push(aFn(aArray[i], i++));
} catch (e) {
deferred.reject(e);
return;
}
}
-
+
deferred.resolve();
}());
-
+
return promise.all(outstanding);
};
-
+
/**
* Like XPCOMUtils.defineLazyGetter, but with a |this| sensitive getter that
* allows the lazy getter to be defined on a prototype and work correctly with
* instances.
*
* @param Object aObject
* The prototype object to define the lazy getter on.
* @param String aKey
@@ -7742,28 +7720,28 @@ var Debugger =
* called with the |this| value of the current instance.
*/
exports.defineLazyPrototypeGetter =
function defineLazyPrototypeGetter(aObject, aKey, aCallback) {
Object.defineProperty(aObject, aKey, {
configurable: true,
get: function() {
const value = aCallback.call(this);
-
+
Object.defineProperty(this, aKey, {
configurable: true,
writable: true,
value: value
});
-
+
return value;
}
});
};
-
+
/**
* Safely get the property value from a Debugger.Object for a given key. Walks
* the prototype chain until the property is found.
*
* @param Debugger.Object aObject
* The Debugger.Object to get the value from.
* @param String aKey
* The key to look for.
@@ -7784,17 +7762,17 @@ var Debugger =
aObj = aObj.proto;
} while (aObj);
} catch (e) {
// If anything goes wrong report the error and return undefined.
exports.reportException("getProperty", e);
}
return undefined;
};
-
+
/**
* Determines if a descriptor has a getter which doesn't call into JavaScript.
*
* @param Object aDesc
* The descriptor to check for a safe getter.
* @return Boolean
* Whether a safe getter was found.
*/
@@ -7804,17 +7782,17 @@ var Debugger =
try {
let fn = aDesc.get.unwrap();
return fn && fn.callable && fn.class == "Function" && fn.script === undefined;
} catch (e) {
// Avoid exception 'Object in compartment marked as invisible to Debugger'
return false;
}
};
-
+
/**
* Check if it is safe to read properties and execute methods from the given JS
* object. Safety is defined as being protected from unintended code execution
* from content scripts (or cross-compartment code).
*
* See bugs 945920 and 946752 for discussion.
*
* @type Object aObj
@@ -7823,87 +7801,87 @@ var Debugger =
* True if it is safe to read properties from aObj, or false otherwise.
*/
exports.isSafeJSObject = function isSafeJSObject(aObj) {
// If we are running on a worker thread, Cu is not available. In this case,
// we always return false, just to be on the safe side.
if (isWorker) {
return false;
}
-
+
if (Cu.getGlobalForObject(aObj) ==
Cu.getGlobalForObject(exports.isSafeJSObject)) {
return true; // aObj is not a cross-compartment wrapper.
}
-
+
let principal = Cu.getObjectPrincipal(aObj);
if (Services.scriptSecurityManager.isSystemPrincipal(principal)) {
return true; // allow chrome objects
}
-
+
return Cu.isXrayWrapper(aObj);
};
-
+
exports.dumpn = function dumpn(str) {
if (exports.dumpn.wantLogging) {
console.log("DBG-SERVER: " + str + "\n");
}
};
-
+
// We want wantLogging to be writable. The exports object is frozen by the
// loader, so define it on dumpn instead.
exports.dumpn.wantLogging = false;
-
+
/**
* A verbose logger for low-level tracing.
*/
exports.dumpv = function(msg) {
if (exports.dumpv.wantVerbose) {
exports.dumpn(msg);
}
};
-
+
// We want wantLogging to be writable. The exports object is frozen by the
// loader, so define it on dumpn instead.
exports.dumpv.wantVerbose = false;
-
+
/**
* Utility function for updating an object with the properties of
* other objects.
*
* @param aTarget Object
* The object being updated.
* @param aNewAttrs Object
* The rest params are objects to update aTarget with. You
* can pass as many as you like.
*/
exports.update = function update(aTarget, ...aArgs) {
for (let attrs of aArgs) {
for (let key in attrs) {
let desc = Object.getOwnPropertyDescriptor(attrs, key);
-
+
if (desc) {
Object.defineProperty(aTarget, key, desc);
}
}
}
-
+
return aTarget;
};
-
+
/**
* Utility function for getting the values from an object as an array
*
* @param aObject Object
* The object to iterate over
*/
exports.values = function values(aObject) {
return Object.keys(aObject).map(k => aObject[k]);
};
-
+
/**
* Defines a getter on a specified object that will be created upon first use.
*
* @param aObject
* The object to define the lazy getter on.
* @param aName
* The name of the getter to define on aObject.
* @param aLambda
@@ -7915,50 +7893,50 @@ var Debugger =
get: function() {
delete aObject[aName];
return aObject[aName] = aLambda.apply(aObject);
},
configurable: true,
enumerable: true
});
};
-
+
// DEPRECATED: use DevToolsUtils.assert(condition, message) instead!
let haveLoggedDeprecationMessage = false;
exports.dbg_assert = function dbg_assert(cond, e) {
if (!haveLoggedDeprecationMessage) {
haveLoggedDeprecationMessage = true;
const deprecationMessage = "DevToolsUtils.dbg_assert is deprecated! Use DevToolsUtils.assert instead!"
+ Error().stack;
console.log(deprecationMessage);
if (typeof console === "object" && console && console.warn) {
console.warn(deprecationMessage);
}
}
-
+
if (!cond) {
return e;
}
};
-
+
const { AppConstants } = __webpack_require__(44);
-
+
/**
* No operation. The empty function.
*/
exports.noop = function() { };
-
+
function reallyAssert(condition, message) {
if (!condition) {
const err = new Error("Assertion failure: " + message);
exports.reportException("DevToolsUtils.assert", err);
throw err;
}
}
-
+
/**
* DevToolsUtils.assert(condition, message)
*
* @param Boolean condition
* @param String message
*
* Assertions are enabled when any of the following are true:
* - This is a DEBUG_JS_MODULES build
@@ -7973,17 +7951,17 @@ var Debugger =
* This is an improvement over `dbg_assert`, which doesn't actually cause any
* fatal behavior, and is therefore much easier to accidentally ignore.
*/
Object.defineProperty(exports, "assert", {
get: () => (AppConstants.DEBUG || AppConstants.DEBUG_JS_MODULES || this.testing)
? reallyAssert
: exports.noop,
});
-
+
/**
* Defines a getter on a specified object for a module. The module will not
* be imported until first use.
*
* @param aObject
* The object to define the lazy getter on.
* @param aName
* The name of the getter to define on aObject for the module.
@@ -7998,23 +7976,23 @@ var Debugger =
aSymbol)
{
this.defineLazyGetter(aObject, aName, function XPCU_moduleLambda() {
var temp = {};
Cu.import(aResource, temp);
return temp[aSymbol || aName];
});
};
-
+
const { NetUtil } = __webpack_require__(45);
-
+
const { TextDecoder, OS } = __webpack_require__(46);
-
+
const NetworkHelper = __webpack_require__(47);
-
+
/**
* Performs a request to load the desired URL and returns a promise.
*
* @param aURL String
* The URL we will request.
* @param aOptions Object
* An object with the following optional properties:
* - loadFromCache: if false, will bypass the cache and
@@ -8040,138 +8018,138 @@ var Debugger =
// Create a channel.
let url = aURL.split(" -> ").pop();
let channel;
try {
channel = newChannelForURL(url, aOptions);
} catch (ex) {
return promise.reject(ex);
}
-
+
// Set the channel options.
channel.loadFlags = aOptions.loadFromCache
? channel.LOAD_FROM_CACHE
: channel.LOAD_BYPASS_CACHE;
-
+
if (aOptions.window) {
// Respect private browsing.
channel.loadGroup = aOptions.window.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocumentLoader)
.loadGroup;
}
-
+
let deferred = promise.defer();
let onResponse = (stream, status, request) => {
if (!components.isSuccessCode(status)) {
deferred.reject(new Error(`Failed to fetch ${url}. Code ${status}.`));
return;
}
-
+
try {
// We cannot use NetUtil to do the charset conversion as if charset
// information is not available and our default guess is wrong the method
// might fail and we lose the stream data. This means we can't fall back
// to using the locale default encoding (bug 1181345).
-
+
// Read and decode the data according to the locale default encoding.
let available = stream.available();
let source = NetUtil.readInputStreamToString(stream, available);
stream.close();
-
+
// If the channel or the caller has correct charset information, the
// content will be decoded correctly. If we have to fall back to UTF-8 and
// the guess is wrong, the conversion fails and convertToUnicode returns
// the input unmodified. Essentially we try to decode the data as UTF-8
// and if that fails, we use the locale specific default encoding. This is
// the best we can do if the source does not provide charset info.
let charset = channel.contentCharset || aOptions.charset || "UTF-8";
let unicodeSource = NetworkHelper.convertToUnicode(source, charset);
-
+
deferred.resolve({
content: unicodeSource,
contentType: request.contentType
});
} catch (ex) {
let uri = request.originalURI;
if (ex.name === "NS_BASE_STREAM_CLOSED" && uri instanceof Ci.nsIFileURL) {
// Empty files cause NS_BASE_STREAM_CLOSED exception. Use OS.File to
// differentiate between empty files and other errors (bug 1170864).
// This can be removed when bug 982654 is fixed.
-
+
uri.QueryInterface(Ci.nsIFileURL);
let result = OS.File.read(uri.file.path).then(bytes => {
// Convert the bytearray to a String.
let decoder = new TextDecoder();
let content = decoder.decode(bytes);
-
+
// We can't detect the contentType without opening a channel
// and that failed already. This is the best we can do here.
return {
content,
contentType: "text/plain"
};
});
-
+
deferred.resolve(result);
} else {
deferred.reject(ex);
}
}
};
-
+
// Open the channel
try {
NetUtil.asyncFetch(channel, onResponse);
} catch (ex) {
return promise.reject(ex);
}
-
+
return deferred.promise;
}
-
+
/**
* Opens a channel for given URL. Tries a bit harder than NetUtil.newChannel.
*
* @param {String} url - The URL to open a channel for.
* @param {Object} options - The options object passed to @method fetch.
* @return {nsIChannel} - The newly created channel. Throws on failure.
*/
function newChannelForURL(url, { policy }) {
let channelOptions = {
contentPolicyType: policy,
loadUsingSystemPrincipal: true,
uri: url
};
-
+
try {
return NetUtil.newChannel(channelOptions);
} catch (e) {
// In the xpcshell tests, the script url is the absolute path of the test
// file, which will make a malformed URI error be thrown. Add the file
// scheme to see if it helps.
channelOptions.uri = "file://" + url;
-
+
return NetUtil.newChannel(channelOptions);
}
}
-
+
// Fetch is defined differently depending on whether we are on the main thread
// or a worker thread.
if (typeof WorkerGlobalScope === "undefined") { // i.e. not in a worker
exports.fetch = mainThreadFetch;
} else {
// Services is not available in worker threads, nor is there any other way
// to fetch a URL. We need to enlist the help from the main thread here, by
// issuing an rpc request, to fetch the URL on our behalf.
exports.fetch = function(url, options) {
return rpc("fetch", url, options);
};
}
-
+
/**
* Returns a promise that is resolved or rejected when all promises have settled
* (resolved or rejected).
*
* This differs from Promise.all, which will reject immediately after the first
* rejection, instead of waiting for the remaining promises to settle.
*
* @param values
@@ -8184,81 +8162,81 @@ var Debugger =
* resolved values in the given order, or undefined if values is an
* empty array. The reject reason will be forwarded from the first
* promise in the list of given promises to be rejected.
*/
exports.settleAll = values => {
if (values === null || typeof (values[Symbol.iterator]) != "function") {
throw new Error("settleAll() expects an iterable.");
}
-
+
let deferred = promise.defer();
-
+
values = Array.isArray(values) ? values : [...values];
let countdown = values.length;
let resolutionValues = new Array(countdown);
let rejectionValue;
let rejectionOccurred = false;
-
+
if (!countdown) {
deferred.resolve(resolutionValues);
return deferred.promise;
}
-
+
function checkForCompletion() {
if (--countdown > 0) {
return;
}
if (!rejectionOccurred) {
deferred.resolve(resolutionValues);
} else {
deferred.reject(rejectionValue);
}
}
-
+
for (let i = 0; i < values.length; i++) {
let index = i;
let value = values[i];
let resolver = result => {
resolutionValues[index] = result;
checkForCompletion();
};
let rejecter = error => {
if (!rejectionOccurred) {
rejectionValue = error;
rejectionOccurred = true;
}
checkForCompletion();
};
-
+
if (value && typeof (value.then) == "function") {
value.then(resolver, rejecter);
} else {
// Given value is not a promise, forward it as a resolution value.
resolver(value);
}
}
-
+
return deferred.promise;
};
-
+
/**
* When the testing flag is set, various behaviors may be altered from
* production mode, typically to enable easier testing or enhanced debugging.
*/
var testing = false;
Object.defineProperty(exports, "testing", {
get: function() {
return testing;
},
set: function(state) {
testing = state;
}
});
-
+
/**
* Open the file at the given path for reading.
*
* @param {String} filePath
*
* @returns Promise<nsIInputStream>
*/
exports.openFileStream = function(filePath) {
@@ -8266,42 +8244,42 @@ var Debugger =
const uri = NetUtil.newURI(new FileUtils.File(filePath));
NetUtil.asyncFetch(
{ uri, loadUsingSystemPrincipal: true },
(stream, result) => {
if (!components.isSuccessCode(result)) {
reject(new Error(`Could not open "${filePath}": result = ${result}`));
return;
}
-
+
resolve(stream);
}
);
});
};
-
+
exports.isGenerator = function(fn) {
if (typeof fn !== "function") {
return false;
}
let proto = Object.getPrototypeOf(fn);
if (!proto) {
return false;
}
let ctor = proto.constructor;
if (!ctor) {
return false;
}
return ctor.name == "GeneratorFunction";
};
-
+
exports.isPromise = function(p) {
return p && typeof p.then === "function";
};
-
+
/**
* Return true if `thing` is a SavedFrame, false otherwise.
*/
exports.isSavedFrame = function(thing) {
return Object.prototype.toString.call(thing) === "[object SavedFrame]";
};
@@ -8316,17 +8294,17 @@ var Debugger =
/***/ },
/* 44 */
/***/ function(module, exports) {
/*
* A sham for https://dxr.mozilla.org/mozilla-central/source/toolkit/modules/AppConstants.jsm
*/
-
+
module.exports = { AppConstants: {} };
/***/ },
/* 45 */
/***/ function(module, exports) {
/*
@@ -8375,17 +8353,17 @@ var Debugger =
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-
+
/*
* Creator:
* Joe Hewitt
* Contributors
* John J. Barton (IBM Almaden)
* Jan Odvarko (Mozilla Corp.)
* Max Stepanov (Aptana Inc.)
* Rob Campbell (Mozilla Corp.)
@@ -8395,26 +8373,26 @@ var Debugger =
* Kevin Decker
* Mike Ratcliffe (Comartis AG)
* Hernan RodrÃguez Colmeiro
* Austin Andrews
* Christoph Dorn
* Steven Roussey (AppCenter Inc, Network54)
* Mihai Sucan (Mozilla Corp.)
*/
-
+
"use strict";
-
+
const {components, Cc, Ci, Cu} = __webpack_require__(35);
const { NetUtil } = __webpack_require__(45);
const DevToolsUtils = __webpack_require__(42);
-
+
// The cache used in the `nsIURL` function.
const gNSURLStore = new Map();
-
+
/**
* Helper object for networking stuff.
*
* Most of the following functions have been taken from the Firebug source. They
* have been modified to match the Firefox coding rules.
*/
var NetworkHelper = {
/**
@@ -8434,17 +8412,17 @@ var Debugger =
try {
conv.charset = aCharset || "UTF-8";
return conv.ConvertToUnicode(aText);
}
catch (ex) {
return aText;
}
},
-
+
/**
* Reads all available bytes from aStream and converts them to aCharset.
*
* @param nsIInputStream aStream
* @param string aCharset
* @returns string
* UTF-16 encoded string based on the content of aStream and aCharset.
*/
@@ -8454,115 +8432,115 @@ var Debugger =
try {
text = NetUtil.readInputStreamToString(aStream, aStream.available())
return this.convertToUnicode(text, aCharset);
}
catch (err) {
return text;
}
},
-
+
/**
* Reads the posted text from aRequest.
*
* @param nsIHttpChannel aRequest
* @param string aCharset
* The content document charset, used when reading the POSTed data.
* @returns string or null
* Returns the posted string if it was possible to read from aRequest
* otherwise null.
*/
readPostTextFromRequest: function NH_readPostTextFromRequest(aRequest, aCharset)
{
if (aRequest instanceof Ci.nsIUploadChannel) {
let iStream = aRequest.uploadStream;
-
+
let isSeekableStream = false;
if (iStream instanceof Ci.nsISeekableStream) {
isSeekableStream = true;
}
-
+
let prevOffset;
if (isSeekableStream) {
prevOffset = iStream.tell();
iStream.seek(Ci.nsISeekableStream.NS_SEEK_SET, 0);
}
-
+
// Read data from the stream.
let text = this.readAndConvertFromStream(iStream, aCharset);
-
+
// Seek locks the file, so seek to the beginning only if necko hasn't
// read it yet, since necko doesn't seek to 0 before reading (at lest
// not till 459384 is fixed).
if (isSeekableStream && prevOffset == 0) {
iStream.seek(Ci.nsISeekableStream.NS_SEEK_SET, 0);
}
return text;
}
return null;
},
-
+
/**
* Reads the posted text from the page's cache.
*
* @param nsIDocShell aDocShell
* @param string aCharset
* @returns string or null
* Returns the posted string if it was possible to read from
* aDocShell otherwise null.
*/
readPostTextFromPage: function NH_readPostTextFromPage(aDocShell, aCharset)
{
let webNav = aDocShell.QueryInterface(Ci.nsIWebNavigation);
return this.readPostTextFromPageViaWebNav(webNav, aCharset);
},
-
+
/**
* Reads the posted text from the page's cache, given an nsIWebNavigation
* object.
*
* @param nsIWebNavigation aWebNav
* @param string aCharset
* @returns string or null
* Returns the posted string if it was possible to read from
* aWebNav, otherwise null.
*/
readPostTextFromPageViaWebNav:
function NH_readPostTextFromPageViaWebNav(aWebNav, aCharset)
{
if (aWebNav instanceof Ci.nsIWebPageDescriptor) {
let descriptor = aWebNav.currentDescriptor;
-
+
if (descriptor instanceof Ci.nsISHEntry && descriptor.postData &&
descriptor instanceof Ci.nsISeekableStream) {
descriptor.seek(NS_SEEK_SET, 0);
-
+
return this.readAndConvertFromStream(descriptor, aCharset);
}
}
return null;
},
-
+
/**
* Gets the web appId that is associated with aRequest.
*
* @param nsIHttpChannel aRequest
* @returns number|null
* The appId for the given request, if available.
*/
getAppIdForRequest: function NH_getAppIdForRequest(aRequest)
{
try {
return this.getRequestLoadContext(aRequest).appId;
} catch (ex) {
// request loadContent is not always available.
}
return null;
},
-
+
/**
* Gets the topFrameElement that is associated with aRequest. This
* works in single-process and multiprocess contexts. It may cross
* the content/chrome boundary.
*
* @param nsIHttpChannel aRequest
* @returns nsIDOMElement|null
* The top frame element for the given request.
@@ -8571,158 +8549,158 @@ var Debugger =
{
try {
return this.getRequestLoadContext(aRequest).topFrameElement;
} catch (ex) {
// request loadContent is not always available.
}
return null;
},
-
+
/**
* Gets the nsIDOMWindow that is associated with aRequest.
*
* @param nsIHttpChannel aRequest
* @returns nsIDOMWindow or null
*/
getWindowForRequest: function NH_getWindowForRequest(aRequest)
{
try {
return this.getRequestLoadContext(aRequest).associatedWindow;
} catch (ex) {
// TODO: bug 802246 - getWindowForRequest() throws on b2g: there is no
// associatedWindow property.
}
return null;
},
-
+
/**
* Gets the nsILoadContext that is associated with aRequest.
*
* @param nsIHttpChannel aRequest
* @returns nsILoadContext or null
*/
getRequestLoadContext: function NH_getRequestLoadContext(aRequest)
{
try {
return aRequest.notificationCallbacks.getInterface(Ci.nsILoadContext);
} catch (ex) { }
-
+
try {
return aRequest.loadGroup.notificationCallbacks.getInterface(Ci.nsILoadContext);
} catch (ex) { }
-
+
return null;
},
-
+
/**
* Determines whether the request has been made for the top level document.
*
* @param nsIHttpChannel aRequest
* @returns Boolean True if the request represents the top level document.
*/
isTopLevelLoad: function(aRequest)
{
if (aRequest instanceof Ci.nsIChannel) {
let loadInfo = aRequest.loadInfo;
if (loadInfo && loadInfo.parentOuterWindowID == loadInfo.outerWindowID) {
return (aRequest.loadFlags & Ci.nsIChannel.LOAD_DOCUMENT_URI);
}
}
-
+
return false;
},
-
+
/**
* Loads the content of aUrl from the cache.
*
* @param string aUrl
* URL to load the cached content for.
* @param string aCharset
* Assumed charset of the cached content. Used if there is no charset
* on the channel directly.
* @param function aCallback
* Callback that is called with the loaded cached content if available
* or null if something failed while getting the cached content.
*/
loadFromCache: function NH_loadFromCache(aUrl, aCharset, aCallback)
{
let channel = NetUtil.newChannel({uri: aUrl, loadUsingSystemPrincipal: true});
-
+
// Ensure that we only read from the cache and not the server.
channel.loadFlags = Ci.nsIRequest.LOAD_FROM_CACHE |
Ci.nsICachingChannel.LOAD_ONLY_FROM_CACHE |
Ci.nsICachingChannel.LOAD_BYPASS_LOCAL_CACHE_IF_BUSY;
-
+
NetUtil.asyncFetch(
channel,
(aInputStream, aStatusCode, aRequest) => {
if (!components.isSuccessCode(aStatusCode)) {
aCallback(null);
return;
}
-
+
// Try to get the encoding from the channel. If there is none, then use
// the passed assumed aCharset.
let aChannel = aRequest.QueryInterface(Ci.nsIChannel);
let contentCharset = aChannel.contentCharset || aCharset;
-
+
// Read the content of the stream using contentCharset as encoding.
aCallback(this.readAndConvertFromStream(aInputStream, contentCharset));
});
},
-
+
/**
* Parse a raw Cookie header value.
*
* @param string aHeader
* The raw Cookie header value.
* @return array
* Array holding an object for each cookie. Each object holds the
* following properties: name and value.
*/
parseCookieHeader: function NH_parseCookieHeader(aHeader)
{
let cookies = aHeader.split(";");
let result = [];
-
+
cookies.forEach(function(aCookie) {
let equal = aCookie.indexOf("=");
let name = aCookie.substr(0, equal);
let value = aCookie.substr(equal + 1);
result.push({name: unescape(name.trim()),
value: unescape(value.trim())});
});
-
+
return result;
},
-
+
/**
* Parse a raw Set-Cookie header value.
*
* @param string aHeader
* The raw Set-Cookie header value.
* @return array
* Array holding an object for each cookie. Each object holds the
* following properties: name, value, secure (boolean), httpOnly
* (boolean), path, domain and expires (ISO date string).
*/
parseSetCookieHeader: function NH_parseSetCookieHeader(aHeader)
{
let rawCookies = aHeader.split(/\r\n|\n|\r/);
let cookies = [];
-
+
rawCookies.forEach(function(aCookie) {
let equal = aCookie.indexOf("=");
let name = unescape(aCookie.substr(0, equal).trim());
let parts = aCookie.substr(equal + 1).split(";");
let value = unescape(parts.shift().trim());
-
+
let cookie = {name: name, value: value};
-
+
parts.forEach(function(aPart) {
let part = aPart.trim();
if (part.toLowerCase() == "secure") {
cookie.secure = true;
}
else if (part.toLowerCase() == "httponly") {
cookie.httpOnly = true;
}
@@ -8736,23 +8714,23 @@ var Debugger =
try {
pair[1] = pair[1].replace(/-/g, ' ');
cookie.expires = new Date(pair[1]).toISOString();
}
catch (ex) { }
}
}
});
-
+
cookies.push(cookie);
});
-
+
return cookies;
},
-
+
// This is a list of all the mime category maps jviereck could find in the
// firebug code base.
mimeCategoryMap: {
"text/plain": "txt",
"text/html": "html",
"text/xml": "xml",
"text/xsl": "txt",
"text/xul": "txt",
@@ -8814,53 +8792,53 @@ var Debugger =
"audio/wav": "media",
"audio/x-wav": "media",
"text/json": "json",
"application/x-json": "json",
"application/json-rpc": "json",
"application/x-web-app-manifest+json": "json",
"application/manifest+json": "json"
},
-
+
/**
* Check if the given MIME type is a text-only MIME type.
*
* @param string aMimeType
* @return boolean
*/
isTextMimeType: function NH_isTextMimeType(aMimeType)
{
if (aMimeType.indexOf("text/") == 0) {
return true;
}
-
+
// XML and JSON often come with custom MIME types, so in addition to the
// standard "application/xml" and "application/json", we also look for
// variants like "application/x-bigcorp+xml". For JSON we allow "+json" and
// "-json" as suffixes.
if (/^application\/\w+(?:[\.-]\w+)*(?:\+xml|[-+]json)$/.test(aMimeType)) {
return true;
}
-
+
let category = this.mimeCategoryMap[aMimeType] || null;
switch (category) {
case "txt":
case "js":
case "json":
case "css":
case "html":
case "svg":
case "xml":
return true;
-
+
default:
return false;
}
},
-
+
/**
* Takes a securityInfo object of nsIRequest, the nsIRequest itself and
* extracts security information from them.
*
* @param object securityInfo
* The securityInfo object of a request. If null channel is assumed
* to be insecure.
* @param object httpActivity
@@ -8887,22 +8865,22 @@ var Debugger =
* If state == weak: Same as state == secure and
* - weaknessReasons: list of reasons that cause the request to be
* considered weak. See getReasonsForWeakness.
*/
parseSecurityInfo: function NH_parseSecurityInfo(securityInfo, httpActivity) {
const info = {
state: "insecure",
};
-
+
// The request did not contain any security info.
if (!securityInfo) {
return info;
}
-
+
/**
* Different scenarios to consider here and how they are handled:
* - request is HTTP, the connection is not secure
* => securityInfo is null
* => state === "insecure"
*
* - request is HTTPS, the connection is secure
* => .securityState has STATE_IS_SECURE flag
@@ -8924,27 +8902,27 @@ var Debugger =
* http://hg.mozilla.org/mozilla-central/annotate/def6ed9d1c1a/
* security/manager/ssl/nsNSSCallbacks.cpp#l1233
* - request is mixed content (which makes no sense whatsoever)
* => .securityState has STATE_IS_BROKEN flag
* => .errorCode is NOT an NSS error code
* => .errorMessage is not available
* => state === "weak"
*/
-
+
securityInfo.QueryInterface(Ci.nsITransportSecurityInfo);
securityInfo.QueryInterface(Ci.nsISSLStatusProvider);
-
+
const wpl = Ci.nsIWebProgressListener;
const NSSErrorsService = Cc['@mozilla.org/nss_errors_service;1']
.getService(Ci.nsINSSErrorsService);
const SSLStatus = securityInfo.SSLStatus;
if (!NSSErrorsService.isNSSErrorCode(securityInfo.errorCode)) {
const state = securityInfo.securityState;
-
+
let uri = null;
if (httpActivity.channel && httpActivity.channel.URI) {
uri = httpActivity.channel.URI;
}
if (uri && !uri.schemeIs("https") && !uri.schemeIs("wss")) {
// it is not enough to look at the transport security info - schemes other than
// https and wss are subject to downgrade/etc at the scheme level and should
// always be considered insecure
@@ -8961,58 +8939,58 @@ var Debugger =
// This was most likely an https request that was aborted before
// validation. Return info as info.state = insecure.
return info;
} else {
DevToolsUtils.reportException("NetworkHelper.parseSecurityInfo",
"Security state " + state + " has no known STATE_IS_* flags.");
return info;
}
-
+
// Cipher suite.
info.cipherSuite = SSLStatus.cipherName;
-
+
// Protocol version.
info.protocolVersion = this.formatSecurityProtocol(SSLStatus.protocolVersion);
-
+
// Certificate.
info.cert = this.parseCertificateInfo(SSLStatus.serverCert);
-
+
// HSTS and HPKP if available.
if (httpActivity.hostname) {
const sss = Cc("@mozilla.org/ssservice;1")
.getService(Ci.nsISiteSecurityService);
-
-
+
+
// SiteSecurityService uses different storage if the channel is
// private. Thus we must give isSecureHost correct flags or we
// might get incorrect results.
let flags = (httpActivity.private) ?
Ci.nsISocketProvider.NO_PERMANENT_STORAGE : 0;
-
+
let host = httpActivity.hostname;
-
+
info.hsts = sss.isSecureHost(sss.HEADER_HSTS, host, flags);
info.hpkp = sss.isSecureHost(sss.HEADER_HPKP, host, flags);
} else {
DevToolsUtils.reportException("NetworkHelper.parseSecurityInfo",
"Could not get HSTS/HPKP status as hostname is not available.");
info.hsts = false;
info.hpkp = false;
}
-
+
} else {
// The connection failed.
info.state = "broken";
info.errorMessage = securityInfo.errorMessage;
}
-
+
return info;
},
-
+
/**
* Takes an nsIX509Cert and returns an object with certificate information.
*
* @param nsIX509Cert cert
* The certificate to extract the information from.
* @return object
* An object with following format:
* {
@@ -9025,40 +9003,40 @@ var Debugger =
parseCertificateInfo: function NH_parseCertifificateInfo(cert) {
let info = {};
if (cert) {
info.subject = {
commonName: cert.commonName,
organization: cert.organization,
organizationalUnit: cert.organizationalUnit,
};
-
+
info.issuer = {
commonName: cert.issuerCommonName,
organization: cert.issuerOrganization,
organizationUnit: cert.issuerOrganizationUnit,
};
-
+
info.validity = {
start: cert.validity.notBeforeLocalDay,
end: cert.validity.notAfterLocalDay,
};
-
+
info.fingerprint = {
sha1: cert.sha1Fingerprint,
sha256: cert.sha256Fingerprint,
};
} else {
DevToolsUtils.reportException("NetworkHelper.parseCertificateInfo",
"Secure connection established without certificate.");
}
-
+
return info;
},
-
+
/**
* Takes protocolVersion of SSLStatus object and returns human readable
* description.
*
* @param Number version
* One of nsISSLStatus version constants.
* @return string
* One of TLSv1, TLSv1.1, TLSv1.2 if @param version is valid,
@@ -9073,119 +9051,119 @@ var Debugger =
case Ci.nsISSLStatus.TLS_VERSION_1_2:
return "TLSv1.2";
default:
DevToolsUtils.reportException("NetworkHelper.formatSecurityProtocol",
"protocolVersion " + version + " is unknown.");
return "Unknown";
}
},
-
+
/**
* Takes the securityState bitfield and returns reasons for weak connection
* as an array of strings.
*
* @param Number state
* nsITransportSecurityInfo.securityState.
*
* @return Array[String]
* List of weakness reasons. A subset of { cipher } where
* * cipher: The cipher suite is consireded to be weak (RC4).
*/
getReasonsForWeakness: function NH_getReasonsForWeakness(state) {
const wpl = Ci.nsIWebProgressListener;
-
+
// If there's non-fatal security issues the request has STATE_IS_BROKEN
// flag set. See http://hg.mozilla.org/mozilla-central/file/44344099d119
// /security/manager/ssl/nsNSSCallbacks.cpp#l1233
let reasons = [];
-
+
if (state & wpl.STATE_IS_BROKEN) {
let isCipher = state & wpl.STATE_USES_WEAK_CRYPTO;
-
+
if (isCipher) {
reasons.push("cipher");
}
-
+
if (!isCipher) {
DevToolsUtils.reportException("NetworkHelper.getReasonsForWeakness",
"STATE_IS_BROKEN without a known reason. Full state was: " + state);
}
}
-
+
return reasons;
},
-
+
/**
* Parse a url's query string into its components
*
* @param string aQueryString
* The query part of a url
* @return array
* Array of query params {name, value}
*/
parseQueryString: function(aQueryString) {
// Make sure there's at least one param available.
// Be careful here, params don't necessarily need to have values, so
// no need to verify the existence of a "=".
if (!aQueryString) {
return;
}
-
+
// Turn the params string into an array containing { name: value } tuples.
let paramsArray = aQueryString.replace(/^[?&]/, "").split("&").map(e => {
let param = e.split("=");
return {
name: param[0] ? NetworkHelper.convertToUnicode(unescape(param[0])) : "",
value: param[1] ? NetworkHelper.convertToUnicode(unescape(param[1])) : ""
}});
-
+
return paramsArray;
},
-
+
/**
* Helper for getting an nsIURL instance out of a string.
*/
nsIURL: function(aUrl, aStore = gNSURLStore) {
if (aStore.has(aUrl)) {
return aStore.get(aUrl);
}
-
+
var uri = Services.io.newURI(aUrl).QueryInterface(Ci.nsIURL);
aStore.set(aUrl, uri);
return uri;
}
};
-
+
for (let prop of Object.getOwnPropertyNames(NetworkHelper)) {
exports[prop] = NetworkHelper[prop];
}
/***/ },
/* 48 */
/***/ function(module, exports, __webpack_require__) {
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
+
const { Ci, Cc, Cr, CC } = __webpack_require__(35);
const { Services } = __webpack_require__(28);
const { dumpv } = __webpack_require__(42);
const EventEmitter = __webpack_require__(34);
const promise = __webpack_require__(40);
-
+
const IOUtil = Cc("@mozilla.org/io-util;1").getService(Ci.nsIIOUtil);
-
+
const ScriptableInputStream = CC("@mozilla.org/scriptableinputstream;1",
"nsIScriptableInputStream", "init");
-
+
const BUFFER_SIZE = 0x8000;
-
+
/**
* This helper function (and its companion object) are used by bulk senders and
* receivers to read and write data in and out of other streams. Functions that
* make use of this tool are passed to callers when it is time to read or write
* bulk data. It is highly recommended to use these copier functions instead of
* the stream directly because the copier enforces the agreed upon length.
* Since bulk mode reuses an existing stream, the sender and receiver must write
* and read exactly the agreed upon amount of data, or else the entire transport
@@ -9213,107 +9191,107 @@ var Debugger =
* @return Promise
* The promise is resolved when copying completes or rejected if any
* (unexpected) errors occur.
*/
function copyStream(input, output, length) {
let copier = new StreamCopier(input, output, length);
return copier.copy();
}
-
+
function StreamCopier(input, output, length) {
EventEmitter.decorate(this);
this._id = StreamCopier._nextId++;
this.input = input;
// Save off the base output stream, since we know it's async as we've required
this.baseAsyncOutput = output;
if (IOUtil.outputStreamIsBuffered(output)) {
this.output = output;
} else {
this.output = Cc("@mozilla.org/network/buffered-output-stream;1")
.createInstance(Ci.nsIBufferedOutputStream);
this.output.init(output, BUFFER_SIZE);
}
this._length = length;
this._amountLeft = length;
this._deferred = promise.defer();
-
+
this._copy = this._copy.bind(this);
this._flush = this._flush.bind(this);
this._destroy = this._destroy.bind(this);
-
+
// Copy promise's then method up to this object.
// Allows the copier to offer a promise interface for the simple succeed or
// fail scenarios, but also emit events (due to the EventEmitter) for other
// states, like progress.
this.then = this._deferred.promise.then.bind(this._deferred.promise);
this.then(this._destroy, this._destroy);
-
+
// Stream ready callback starts as |_copy|, but may switch to |_flush| at end
// if flushing would block the output stream.
this._streamReadyCallback = this._copy;
}
StreamCopier._nextId = 0;
-
+
StreamCopier.prototype = {
-
+
copy: function() {
// Dispatch to the next tick so that it's possible to attach a progress
// event listener, even for extremely fast copies (like when testing).
Services.tm.currentThread.dispatch(() => {
try {
this._copy();
} catch (e) {
this._deferred.reject(e);
}
}, 0);
return this;
},
-
+
_copy: function() {
let bytesAvailable = this.input.available();
let amountToCopy = Math.min(bytesAvailable, this._amountLeft);
this._debug("Trying to copy: " + amountToCopy);
-
+
let bytesCopied;
try {
bytesCopied = this.output.writeFrom(this.input, amountToCopy);
} catch (e) {
if (e.result == Cr.NS_BASE_STREAM_WOULD_BLOCK) {
this._debug("Base stream would block, will retry");
this._debug("Waiting for output stream");
this.baseAsyncOutput.asyncWait(this, 0, 0, Services.tm.currentThread);
return;
} else {
throw e;
}
}
-
+
this._amountLeft -= bytesCopied;
this._debug("Copied: " + bytesCopied +
", Left: " + this._amountLeft);
this._emitProgress();
-
+
if (this._amountLeft === 0) {
this._debug("Copy done!");
this._flush();
return;
}
-
+
this._debug("Waiting for input stream");
this.input.asyncWait(this, 0, 0, Services.tm.currentThread);
},
-
+
_emitProgress: function() {
this.emit("progress", {
bytesSent: this._length - this._amountLeft,
totalBytes: this._length
});
},
-
+
_flush: function() {
try {
this.output.flush();
} catch (e) {
if (e.result == Cr.NS_BASE_STREAM_WOULD_BLOCK ||
e.result == Cr.NS_ERROR_FAILURE) {
this._debug("Flush would block, will retry");
this._streamReadyCallback = this._flush;
@@ -9321,43 +9299,43 @@ var Debugger =
this.baseAsyncOutput.asyncWait(this, 0, 0, Services.tm.currentThread);
return;
} else {
throw e;
}
}
this._deferred.resolve();
},
-
+
_destroy: function() {
this._destroy = null;
this._copy = null;
this._flush = null;
this.input = null;
this.output = null;
},
-
+
// nsIInputStreamCallback
onInputStreamReady: function() {
this._streamReadyCallback();
},
-
+
// nsIOutputStreamCallback
onOutputStreamReady: function() {
this._streamReadyCallback();
},
-
+
_debug: function(msg) {
// Prefix logs with the copier ID, which makes logs much easier to
// understand when several copiers are running simultaneously
dumpv("Copier: " + this._id + " " + msg);
}
-
- };
-
+
+ };
+
/**
* Read from a stream, one byte at a time, up to the next |delimiter|
* character, but stopping if we've read |count| without finding it. Reading
* also terminates early if there are less than |count| bytes available on the
* stream. In that case, we only read as many bytes as the stream currently has
* to offer.
* TODO: This implementation could be removed if bug 984651 is fixed, which
* provides a native version of the same idea.
@@ -9369,59 +9347,59 @@ var Debugger =
* The max number of characters to read while searching.
* @return string
* The data collected. If the delimiter was found, this string will
* end with it.
*/
function delimitedRead(stream, delimiter, count) {
dumpv("Starting delimited read for " + delimiter + " up to " +
count + " bytes");
-
+
let scriptableStream;
if (stream.readBytes) {
scriptableStream = stream;
} else {
scriptableStream = new ScriptableInputStream(stream);
}
-
+
let data = "";
-
+
// Don't exceed what's available on the stream
count = Math.min(count, stream.available());
-
+
if (count <= 0) {
return data;
}
-
+
let char;
while (char !== delimiter && count > 0) {
char = scriptableStream.readBytes(1);
count--;
data += char;
}
-
+
return data;
}
-
+
module.exports = {
copyStream: copyStream,
delimitedRead: delimitedRead
};
/***/ },
/* 49 */
/***/ function(module, exports, __webpack_require__) {
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
+
"use strict";
-
+
/**
* Packets contain read / write functionality for the different packet types
* supported by the debugging protocol, so that a transport can focus on
* delivery and queue management without worrying too much about the specific
* packet types.
*
* They are intended to be "one use only", so a new packet should be
* instantiated for each incoming or outgoing packet.
@@ -9431,206 +9409,206 @@ var Debugger =
* Called when the input stream has data to read
* * write(stream)
* Called when the output stream is ready to write
* * get done()
* Returns true once the packet is done being read / written
* * destroy()
* Called to clean up at the end of use
*/
-
+
const { Cc, Ci, Cu } = __webpack_require__(35);
const DevToolsUtils = __webpack_require__(42);
const { dumpn, dumpv } = DevToolsUtils;
const StreamUtils = __webpack_require__(48);
const promise = __webpack_require__(40);
-
+
/*DevToolsUtils.defineLazyGetter(this, "unicodeConverter", () => {
const unicodeConverter = Cc("@mozilla.org/intl/scriptableunicodeconverter")
.createInstance(Ci.nsIScriptableUnicodeConverter);
unicodeConverter.charset = "UTF-8";
return unicodeConverter;
});*/
const utf8 = __webpack_require__(50);
-
+
// The transport's previous check ensured the header length did not exceed 20
// characters. Here, we opt for the somewhat smaller, but still large limit of
// 1 TiB.
const PACKET_LENGTH_MAX = Math.pow(2, 40);
-
+
/**
* A generic Packet processing object (extended by two subtypes below).
*/
function Packet(transport) {
this._transport = transport;
this._length = 0;
}
-
+
/**
* Attempt to initialize a new Packet based on the incoming packet header we've
* received so far. We try each of the types in succession, trying JSON packets
* first since they are much more common.
* @param header string
* The packet header string to attempt parsing.
* @param transport DebuggerTransport
* The transport instance that will own the packet.
* @return Packet
* The parsed packet of the matching type, or null if no types matched.
*/
Packet.fromHeader = function(header, transport) {
return JSONPacket.fromHeader(header, transport) ||
BulkPacket.fromHeader(header, transport);
};
-
+
Packet.prototype = {
-
+
get length() {
return this._length;
},
-
+
set length(length) {
if (length > PACKET_LENGTH_MAX) {
throw Error("Packet length " + length + " exceeds the max length of " +
PACKET_LENGTH_MAX);
}
this._length = length;
},
-
+
destroy: function() {
this._transport = null;
}
-
- };
-
+
+ };
+
exports.Packet = Packet;
-
+
/**
* With a JSON packet (the typical packet type sent via the transport), data is
* transferred as a JSON packet serialized into a string, with the string length
* prepended to the packet, followed by a colon ([length]:[packet]). The
* contents of the JSON packet are specified in the Remote Debugging Protocol
* specification.
* @param transport DebuggerTransport
* The transport instance that will own the packet.
*/
function JSONPacket(transport) {
Packet.call(this, transport);
this._data = "";
this._done = false;
}
-
+
/**
* Attempt to initialize a new JSONPacket based on the incoming packet header
* we've received so far.
* @param header string
* The packet header string to attempt parsing.
* @param transport DebuggerTransport
* The transport instance that will own the packet.
* @return JSONPacket
* The parsed packet, or null if it's not a match.
*/
JSONPacket.fromHeader = function(header, transport) {
let match = this.HEADER_PATTERN.exec(header);
-
+
if (!match) {
return null;
}
-
+
dumpv("Header matches JSON packet");
let packet = new JSONPacket(transport);
packet.length = +match[1];
return packet;
};
-
+
JSONPacket.HEADER_PATTERN = /^(\d+):$/;
-
+
JSONPacket.prototype = Object.create(Packet.prototype);
-
+
Object.defineProperty(JSONPacket.prototype, "object", {
/**
* Gets the object (not the serialized string) being read or written.
*/
get: function() { return this._object; },
-
+
/**
* Sets the object to be sent when write() is called.
*/
set: function(object) {
this._object = object;
let data = JSON.stringify(object);
this._data = data;
this.length = this._data.length;
}
});
-
+
JSONPacket.prototype.read = function(stream, scriptableStream) {
dumpv("Reading JSON packet");
-
+
// Read in more packet data.
this._readData(stream, scriptableStream);
-
+
if (!this.done) {
// Don't have a complete packet yet.
return;
}
-
+
let json = this._data;
try {
json = utf8.decode(json);
this._object = JSON.parse(json);
} catch(e) {
let msg = "Error parsing incoming packet: " + json + " (" + e +
" - " + e.stack + ")";
if (console.error) {
console.error(msg);
}
dumpn(msg);
return;
}
-
+
this._transport._onJSONObjectReady(this._object);
}
-
+
JSONPacket.prototype._readData = function(stream, scriptableStream) {
if (!scriptableStream) {
scriptableStream = stream;
}
if (dumpv.wantVerbose) {
dumpv("Reading JSON data: _l: " + this.length + " dL: " +
this._data.length + " sA: " + stream.available());
}
let bytesToRead = Math.min(this.length - this._data.length,
stream.available());
this._data += scriptableStream.readBytes(bytesToRead);
this._done = this._data.length === this.length;
}
-
+
JSONPacket.prototype.write = function(stream) {
dumpv("Writing JSON packet");
-
+
if (this._outgoing === undefined) {
// Format the serialized packet to a buffer
this._outgoing = this.length + ":" + this._data;
}
-
+
let written = stream.write(this._outgoing, this._outgoing.length);
this._outgoing = this._outgoing.slice(written);
this._done = !this._outgoing.length;
}
-
+
Object.defineProperty(JSONPacket.prototype, "done", {
get: function() { return this._done; }
});
-
+
JSONPacket.prototype.toString = function() {
return JSON.stringify(this._object, null, 2);
}
-
+
exports.JSONPacket = JSONPacket;
-
+
/**
* With a bulk packet, data is transferred by temporarily handing over the
* transport's input or output stream to the application layer for writing data
* directly. This can be much faster for large data sets, and avoids various
* stages of copies and data duplication inherent in the JSON packet type. The
* bulk packet looks like:
*
* bulk [actor] [type] [length]:[data]
@@ -9641,226 +9619,226 @@ var Debugger =
* @param transport DebuggerTransport
* The transport instance that will own the packet.
*/
function BulkPacket(transport) {
Packet.call(this, transport);
this._done = false;
this._readyForWriting = promise.defer();
}
-
+
/**
* Attempt to initialize a new BulkPacket based on the incoming packet header
* we've received so far.
* @param header string
* The packet header string to attempt parsing.
* @param transport DebuggerTransport
* The transport instance that will own the packet.
* @return BulkPacket
* The parsed packet, or null if it's not a match.
*/
BulkPacket.fromHeader = function(header, transport) {
let match = this.HEADER_PATTERN.exec(header);
-
+
if (!match) {
return null;
}
-
+
dumpv("Header matches bulk packet");
let packet = new BulkPacket(transport);
packet.header = {
actor: match[1],
type: match[2],
length: +match[3]
};
return packet;
};
-
+
BulkPacket.HEADER_PATTERN = /^bulk ([^: ]+) ([^: ]+) (\d+):$/;
-
+
BulkPacket.prototype = Object.create(Packet.prototype);
-
+
BulkPacket.prototype.read = function(stream) {
dumpv("Reading bulk packet, handing off input stream");
-
+
// Temporarily pause monitoring of the input stream
this._transport.pauseIncoming();
-
+
let deferred = promise.defer();
-
+
this._transport._onBulkReadReady({
actor: this.actor,
type: this.type,
length: this.length,
copyTo: (output) => {
dumpv("CT length: " + this.length);
let copying = StreamUtils.copyStream(stream, output, this.length);
deferred.resolve(copying);
return copying;
},
stream: stream,
done: deferred
});
-
+
// Await the result of reading from the stream
deferred.promise.then(() => {
dumpv("onReadDone called, ending bulk mode");
this._done = true;
this._transport.resumeIncoming();
}, this._transport.close);
-
+
// Ensure this is only done once
this.read = () => {
throw new Error("Tried to read() a BulkPacket's stream multiple times.");
};
}
-
+
BulkPacket.prototype.write = function(stream) {
dumpv("Writing bulk packet");
-
+
if (this._outgoingHeader === undefined) {
dumpv("Serializing bulk packet header");
// Format the serialized packet header to a buffer
this._outgoingHeader = "bulk " + this.actor + " " + this.type + " " +
this.length + ":";
}
-
+
// Write the header, or whatever's left of it to write.
if (this._outgoingHeader.length) {
dumpv("Writing bulk packet header");
let written = stream.write(this._outgoingHeader,
this._outgoingHeader.length);
this._outgoingHeader = this._outgoingHeader.slice(written);
return;
}
-
+
dumpv("Handing off output stream");
-
+
// Temporarily pause the monitoring of the output stream
this._transport.pauseOutgoing();
-
+
let deferred = promise.defer();
-
+
this._readyForWriting.resolve({
copyFrom: (input) => {
dumpv("CF length: " + this.length);
let copying = StreamUtils.copyStream(input, stream, this.length);
deferred.resolve(copying);
return copying;
},
stream: stream,
done: deferred
});
-
+
// Await the result of writing to the stream
deferred.promise.then(() => {
dumpv("onWriteDone called, ending bulk mode");
this._done = true;
this._transport.resumeOutgoing();
}, this._transport.close);
-
+
// Ensure this is only done once
this.write = () => {
throw new Error("Tried to write() a BulkPacket's stream multiple times.");
};
}
-
+
Object.defineProperty(BulkPacket.prototype, "streamReadyForWriting", {
get: function() {
return this._readyForWriting.promise;
}
});
-
+
Object.defineProperty(BulkPacket.prototype, "header", {
get: function() {
return {
actor: this.actor,
type: this.type,
length: this.length
};
},
-
+
set: function(header) {
this.actor = header.actor;
this.type = header.type;
this.length = header.length;
},
});
-
+
Object.defineProperty(BulkPacket.prototype, "done", {
get: function() { return this._done; },
});
-
-
+
+
BulkPacket.prototype.toString = function() {
return "Bulk: " + JSON.stringify(this.header, null, 2);
}
-
+
exports.BulkPacket = BulkPacket;
-
+
/**
* RawPacket is used to test the transport's error handling of malformed
* packets, by writing data directly onto the stream.
* @param transport DebuggerTransport
* The transport instance that will own the packet.
* @param data string
* The raw string to send out onto the stream.
*/
function RawPacket(transport, data) {
Packet.call(this, transport);
this._data = data;
this.length = data.length;
this._done = false;
}
-
+
RawPacket.prototype = Object.create(Packet.prototype);
-
+
RawPacket.prototype.read = function(stream) {
// This hasn't yet been needed for testing.
throw Error("Not implmented.");
}
-
+
RawPacket.prototype.write = function(stream) {
let written = stream.write(this._data, this._data.length);
this._data = this._data.slice(written);
this._done = !this._data.length;
}
-
+
Object.defineProperty(RawPacket.prototype, "done", {
get: function() { return this._done; }
});
-
+
exports.RawPacket = RawPacket;
/***/ },
/* 50 */
/***/ function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_RESULT__;/* WEBPACK VAR INJECTION */(function(module, global) {/*! https://mths.be/utf8js v2.0.0 by @mathias */
;(function(root) {
-
+
// Detect free variables `exports`
var freeExports = typeof exports == 'object' && exports;
-
+
// Detect free variable `module`
var freeModule = typeof module == 'object' && module &&
module.exports == freeExports && module;
-
+
// Detect free variable `global`, from Node.js or Browserified code,
// and use it as `root`
var freeGlobal = typeof global == 'object' && global;
if (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal) {
root = freeGlobal;
}
-
+
/*--------------------------------------------------------------------------*/
-
+
var stringFromCharCode = String.fromCharCode;
-
+
// Taken from https://mths.be/punycode
function ucs2decode(string) {
var output = [];
var counter = 0;
var length = string.length;
var value;
var extra;
while (counter < length) {
@@ -9877,17 +9855,17 @@ var Debugger =
counter--;
}
} else {
output.push(value);
}
}
return output;
}
-
+
// Taken from https://mths.be/punycode
function ucs2encode(array) {
var length = array.length;
var index = -1;
var value;
var output = '';
while (++index < length) {
value = array[index];
@@ -9895,31 +9873,31 @@ var Debugger =
value -= 0x10000;
output += stringFromCharCode(value >>> 10 & 0x3FF | 0xD800);
value = 0xDC00 | value & 0x3FF;
}
output += stringFromCharCode(value);
}
return output;
}
-
+
function checkScalarValue(codePoint) {
if (codePoint >= 0xD800 && codePoint <= 0xDFFF) {
throw Error(
'Lone surrogate U+' + codePoint.toString(16).toUpperCase() +
' is not a scalar value'
);
}
}
/*--------------------------------------------------------------------------*/
-
+
function createByte(codePoint, shift) {
return stringFromCharCode(((codePoint >> shift) & 0x3F) | 0x80);
}
-
+
function encodeCodePoint(codePoint) {
if ((codePoint & 0xFFFFFF80) == 0) { // 1-byte sequence
return stringFromCharCode(codePoint);
}
var symbol = '';
if ((codePoint & 0xFFFFF800) == 0) { // 2-byte sequence
symbol = stringFromCharCode(((codePoint >> 6) & 0x1F) | 0xC0);
}
@@ -9931,134 +9909,134 @@ var Debugger =
else if ((codePoint & 0xFFE00000) == 0) { // 4-byte sequence
symbol = stringFromCharCode(((codePoint >> 18) & 0x07) | 0xF0);
symbol += createByte(codePoint, 12);
symbol += createByte(codePoint, 6);
}
symbol += stringFromCharCode((codePoint & 0x3F) | 0x80);
return symbol;
}
-
+
function utf8encode(string) {
var codePoints = ucs2decode(string);
var length = codePoints.length;
var index = -1;
var codePoint;
var byteString = '';
while (++index < length) {
codePoint = codePoints[index];
byteString += encodeCodePoint(codePoint);
}
return byteString;
}
-
+
/*--------------------------------------------------------------------------*/
-
+
function readContinuationByte() {
if (byteIndex >= byteCount) {
throw Error('Invalid byte index');
}
-
+
var continuationByte = byteArray[byteIndex] & 0xFF;
byteIndex++;
-
+
if ((continuationByte & 0xC0) == 0x80) {
return continuationByte & 0x3F;
}
-
+
// If we end up here, it’s not a continuation byte
throw Error('Invalid continuation byte');
}
-
+
function decodeSymbol() {
var byte1;
var byte2;
var byte3;
var byte4;
var codePoint;
-
+
if (byteIndex > byteCount) {
throw Error('Invalid byte index');
}
-
+
if (byteIndex == byteCount) {
return false;
}
-
+
// Read first byte
byte1 = byteArray[byteIndex] & 0xFF;
byteIndex++;
-
+
// 1-byte sequence (no continuation bytes)
if ((byte1 & 0x80) == 0) {
return byte1;
}
-
+
// 2-byte sequence
if ((byte1 & 0xE0) == 0xC0) {
var byte2 = readContinuationByte();
codePoint = ((byte1 & 0x1F) << 6) | byte2;
if (codePoint >= 0x80) {
return codePoint;
} else {
throw Error('Invalid continuation byte');
}
}
-
+
// 3-byte sequence (may include unpaired surrogates)
if ((byte1 & 0xF0) == 0xE0) {
byte2 = readContinuationByte();
byte3 = readContinuationByte();
codePoint = ((byte1 & 0x0F) << 12) | (byte2 << 6) | byte3;
if (codePoint >= 0x0800) {
checkScalarValue(codePoint);
return codePoint;
} else {
throw Error('Invalid continuation byte');
}
}
-
+
// 4-byte sequence
if ((byte1 & 0xF8) == 0xF0) {
byte2 = readContinuationByte();
byte3 = readContinuationByte();
byte4 = readContinuationByte();
codePoint = ((byte1 & 0x0F) << 0x12) | (byte2 << 0x0C) |
(byte3 << 0x06) | byte4;
if (codePoint >= 0x010000 && codePoint <= 0x10FFFF) {
return codePoint;
}
}
-
+
throw Error('Invalid UTF-8 detected');
}
-
+
var byteArray;
var byteCount;
var byteIndex;
function utf8decode(byteString) {
byteArray = ucs2decode(byteString);
byteCount = byteArray.length;
byteIndex = 0;
var codePoints = [];
var tmp;
while ((tmp = decodeSymbol()) !== false) {
codePoints.push(tmp);
}
return ucs2encode(codePoints);
}
-
+
/*--------------------------------------------------------------------------*/
-
+
var utf8 = {
'version': '2.0.0',
'encode': utf8encode,
'decode': utf8decode
};
-
+
// Some AMD build optimizers, like r.js, check for specific condition patterns
// like the following:
if (
true
) {
!(__WEBPACK_AMD_DEFINE_RESULT__ = function() {
return utf8;
}.call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
@@ -10070,62 +10048,62 @@ var Debugger =
var hasOwnProperty = object.hasOwnProperty;
for (var key in utf8) {
hasOwnProperty.call(utf8, key) && (freeExports[key] = utf8[key]);
}
}
} else { // in Rhino or a web browser
root.utf8 = utf8;
}
-
+
}(this));
-
+
/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(51)(module), (function() { return this; }())))
/***/ },
/* 51 */
/***/ function(module, exports) {
- module.exports = function(module) {
- if(!module.webpackPolyfill) {
- module.deprecate = function() {};
- module.paths = [];
- // module.parent = undefined by default
- module.children = [];
- module.webpackPolyfill = 1;
- }
- return module;
- }
+ module.exports = function(module) {
+ if(!module.webpackPolyfill) {
+ module.deprecate = function() {};
+ module.paths = [];
+ // module.parent = undefined by default
+ module.children = [];
+ module.webpackPolyfill = 1;
+ }
+ return module;
+ }
/***/ },
/* 52 */
/***/ function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_RESULT__;/* WEBPACK VAR INJECTION */(function(module, global) {/*! https://mths.be/utf8js v2.0.0 by @mathias */
;(function(root) {
-
+
// Detect free variables `exports`
var freeExports = typeof exports == 'object' && exports;
-
+
// Detect free variable `module`
var freeModule = typeof module == 'object' && module &&
module.exports == freeExports && module;
-
+
// Detect free variable `global`, from Node.js or Browserified code,
// and use it as `root`
var freeGlobal = typeof global == 'object' && global;
if (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal) {
root = freeGlobal;
}
-
+
/*--------------------------------------------------------------------------*/
-
+
var stringFromCharCode = String.fromCharCode;
-
+
// Taken from https://mths.be/punycode
function ucs2decode(string) {
var output = [];
var counter = 0;
var length = string.length;
var value;
var extra;
while (counter < length) {
@@ -10142,17 +10120,17 @@ var Debugger =
counter--;
}
} else {
output.push(value);
}
}
return output;
}
-
+
// Taken from https://mths.be/punycode
function ucs2encode(array) {
var length = array.length;
var index = -1;
var value;
var output = '';
while (++index < length) {
value = array[index];
@@ -10160,31 +10138,31 @@ var Debugger =
value -= 0x10000;
output += stringFromCharCode(value >>> 10 & 0x3FF | 0xD800);
value = 0xDC00 | value & 0x3FF;
}
output += stringFromCharCode(value);
}
return output;
}
-
+
function checkScalarValue(codePoint) {
if (codePoint >= 0xD800 && codePoint <= 0xDFFF) {
throw Error(
'Lone surrogate U+' + codePoint.toString(16).toUpperCase() +
' is not a scalar value'
);
}
}
/*--------------------------------------------------------------------------*/
-
+
function createByte(codePoint, shift) {
return stringFromCharCode(((codePoint >> shift) & 0x3F) | 0x80);
}
-
+
function encodeCodePoint(codePoint) {
if ((codePoint & 0xFFFFFF80) == 0) { // 1-byte sequence
return stringFromCharCode(codePoint);
}
var symbol = '';
if ((codePoint & 0xFFFFF800) == 0) { // 2-byte sequence
symbol = stringFromCharCode(((codePoint >> 6) & 0x1F) | 0xC0);
}
@@ -10196,134 +10174,134 @@ var Debugger =
else if ((codePoint & 0xFFE00000) == 0) { // 4-byte sequence
symbol = stringFromCharCode(((codePoint >> 18) & 0x07) | 0xF0);
symbol += createByte(codePoint, 12);
symbol += createByte(codePoint, 6);
}
symbol += stringFromCharCode((codePoint & 0x3F) | 0x80);
return symbol;
}
-
+
function utf8encode(string) {
var codePoints = ucs2decode(string);
var length = codePoints.length;
var index = -1;
var codePoint;
var byteString = '';
while (++index < length) {
codePoint = codePoints[index];
byteString += encodeCodePoint(codePoint);
}
return byteString;
}
-
+
/*--------------------------------------------------------------------------*/
-
+
function readContinuationByte() {
if (byteIndex >= byteCount) {
throw Error('Invalid byte index');
}
-
+
var continuationByte = byteArray[byteIndex] & 0xFF;
byteIndex++;
-
+
if ((continuationByte & 0xC0) == 0x80) {
return continuationByte & 0x3F;
}
-
+
// If we end up here, it’s not a continuation byte
throw Error('Invalid continuation byte');
}
-
+
function decodeSymbol() {
var byte1;
var byte2;
var byte3;
var byte4;
var codePoint;
-
+
if (byteIndex > byteCount) {
throw Error('Invalid byte index');
}
-
+
if (byteIndex == byteCount) {
return false;
}
-
+
// Read first byte
byte1 = byteArray[byteIndex] & 0xFF;
byteIndex++;
-
+
// 1-byte sequence (no continuation bytes)
if ((byte1 & 0x80) == 0) {
return byte1;
}
-
+
// 2-byte sequence
if ((byte1 & 0xE0) == 0xC0) {
var byte2 = readContinuationByte();
codePoint = ((byte1 & 0x1F) << 6) | byte2;
if (codePoint >= 0x80) {
return codePoint;
} else {
throw Error('Invalid continuation byte');
}
}
-
+
// 3-byte sequence (may include unpaired surrogates)
if ((byte1 & 0xF0) == 0xE0) {
byte2 = readContinuationByte();
byte3 = readContinuationByte();
codePoint = ((byte1 & 0x0F) << 12) | (byte2 << 6) | byte3;
if (codePoint >= 0x0800) {
checkScalarValue(codePoint);
return codePoint;
} else {
throw Error('Invalid continuation byte');
}
}
-
+
// 4-byte sequence
if ((byte1 & 0xF8) == 0xF0) {
byte2 = readContinuationByte();
byte3 = readContinuationByte();
byte4 = readContinuationByte();
codePoint = ((byte1 & 0x0F) << 0x12) | (byte2 << 0x0C) |
(byte3 << 0x06) | byte4;
if (codePoint >= 0x010000 && codePoint <= 0x10FFFF) {
return codePoint;
}
}
-
+
throw Error('Invalid UTF-8 detected');
}
-
+
var byteArray;
var byteCount;
var byteIndex;
function utf8decode(byteString) {
byteArray = ucs2decode(byteString);
byteCount = byteArray.length;
byteIndex = 0;
var codePoints = [];
var tmp;
while ((tmp = decodeSymbol()) !== false) {
codePoints.push(tmp);
}
return ucs2encode(codePoints);
}
-
+
/*--------------------------------------------------------------------------*/
-
+
var utf8 = {
'version': '2.0.0',
'encode': utf8encode,
'decode': utf8decode
};
-
+
// Some AMD build optimizers, like r.js, check for specific condition patterns
// like the following:
if (
true
) {
!(__WEBPACK_AMD_DEFINE_RESULT__ = function() {
return utf8;
}.call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
@@ -10335,46 +10313,46 @@ var Debugger =
var hasOwnProperty = object.hasOwnProperty;
for (var key in utf8) {
hasOwnProperty.call(utf8, key) && (freeExports[key] = utf8[key]);
}
}
} else { // in Rhino or a web browser
root.utf8 = utf8;
}
-
+
}(this));
-
+
/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(51)(module), (function() { return this; }())))
/***/ },
/* 53 */
/***/ function(module, exports, __webpack_require__) {
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
+
const { Ci, Cu, components } = __webpack_require__(35);
const { Services } = __webpack_require__(28);
const DevToolsUtils = __webpack_require__(42);
-
+
// WARNING I swapped the sync one for the async one here
// const promise = require("resource://devtools/shared/deprecated-sync-thenables.js", {}).Promise;
const promise = __webpack_require__(40);
-
+
const events = __webpack_require__(54);
const { WebConsoleClient } = __webpack_require__(56);
/* const { DebuggerSocket } = require("../shared/security/socket");*/
/* const Authentication = require("../shared/security/auth");*/
-
+
const noop = () => {};
-
+
/**
* TODO: Get rid of this API in favor of EventTarget (bug 1042642)
*
* Add simple event notification to a prototype object. Any object that has
* some use for event notifications or the observer pattern in general can be
* augmented with the necessary facilities by passing its prototype to this
* function.
*
@@ -10391,118 +10369,118 @@ var Debugger =
* Called when the event is fired. If the same listener
* is added more than once, it will be called once per
* addListener call.
*/
aProto.addListener = function(aName, aListener) {
if (typeof aListener != "function") {
throw TypeError("Listeners must be functions.");
}
-
+
if (!this._listeners) {
this._listeners = {};
}
-
+
this._getListeners(aName).push(aListener);
};
-
+
/**
* Add a listener to the event source for a given event. The
* listener will be removed after it is called for the first time.
*
* @param aName string
* The event to listen for.
* @param aListener function
* Called when the event is fired.
*/
aProto.addOneTimeListener = function(aName, aListener) {
let l = (...args) => {
this.removeListener(aName, l);
aListener.apply(null, args);
};
this.addListener(aName, l);
};
-
+
/**
* Remove a listener from the event source previously added with
* addListener().
*
* @param aName string
* The event name used during addListener to add the listener.
* @param aListener function
* The callback to remove. If addListener was called multiple
* times, all instances will be removed.
*/
aProto.removeListener = function(aName, aListener) {
if (!this._listeners || (aListener && !this._listeners[aName])) {
return;
}
-
+
if (!aListener) {
this._listeners[aName] = [];
}
else {
this._listeners[aName] =
this._listeners[aName].filter(function(l) { return l != aListener; });
}
};
-
+
/**
* Returns the listeners for the specified event name. If none are defined it
* initializes an empty list and returns that.
*
* @param aName string
* The event name.
*/
aProto._getListeners = function(aName) {
if (aName in this._listeners) {
return this._listeners[aName];
}
this._listeners[aName] = [];
return this._listeners[aName];
};
-
+
/**
* Notify listeners of an event.
*
* @param aName string
* The event to fire.
* @param arguments
* All arguments will be passed along to the listeners,
* including the name argument.
*/
aProto.emit = function() {
if (!this._listeners) {
return;
}
-
+
let name = arguments[0];
let listeners = this._getListeners(name).slice(0);
-
+
for (let listener of listeners) {
try {
listener.apply(null, arguments);
} catch (e) {
// Prevent a bad listener from interfering with the others.
DevToolsUtils.reportException("notify event '" + name + "'", e);
}
}
};
}
-
+
/**
* Set of protocol messages that affect thread state, and the
* state the actor is in after each message.
*/
const ThreadStateTypes = {
"paused": "paused",
"resumed": "attached",
"detached": "detached"
};
-
+
/**
* Set of protocol messages that are sent by the server without a prior request
* by the client.
*/
const UnsolicitedNotifications = {
"consoleAPICall": "consoleAPICall",
"eventNotification": "eventNotification",
"fileActivity": "fileActivity",
@@ -10527,63 +10505,63 @@ var Debugger =
"appOpen": "appOpen",
"appClose": "appClose",
"appInstall": "appInstall",
"appUninstall": "appUninstall",
"evaluationResult": "evaluationResult",
"newSource": "newSource",
"updatedSource": "updatedSource",
};
-
+
/**
* Set of pause types that are sent by the server and not as an immediate
* response to a client request.
*/
const UnsolicitedPauses = {
"resumeLimit": "resumeLimit",
"debuggerStatement": "debuggerStatement",
"breakpoint": "breakpoint",
"DOMEvent": "DOMEvent",
"watchpoint": "watchpoint",
"exception": "exception"
};
-
+
/**
* Creates a client for the remote debugging protocol server. This client
* provides the means to communicate with the server and exchange the messages
* required by the protocol in a traditional JavaScript API.
*/
const DebuggerClient = exports.DebuggerClient = function(aTransport)
{
this._transport = aTransport;
this._transport.hooks = this;
-
+
// Map actor ID to client instance for each actor type.
this._clients = new Map();
-
+
this._pendingRequests = new Map();
this._activeRequests = new Map();
this._eventsEnabled = true;
-
+
this.traits = {};
-
+
this.request = this.request.bind(this);
this.localTransport = this._transport.onOutputStreamReady === undefined;
-
+
/*
* As the first thing on the connection, expect a greeting packet from
* the connection's root actor.
*/
this.mainRoot = null;
this.expectReply("root", (aPacket) => {
this.mainRoot = new RootClient(this, aPacket);
this.emit("connected", aPacket.applicationType, aPacket.traits);
});
};
-
+
/**
* A declarative helper for defining methods that send requests to the server.
*
* @param aPacketSkeleton
* The form of the packet to send. Can specify fields to be filled from
* the parameters by using the |args| function.
* @param telemetry
* The unique suffix of the telemetry histogram id.
@@ -10611,81 +10589,81 @@ var Debugger =
let histogramId = "DEVTOOLS_DEBUGGER_RDP_"
+ transportType + telemetry + "_MS";
histogram = Services.telemetry.getHistogramById(histogramId);
startTime = +new Date();
}
let outgoingPacket = {
to: aPacketSkeleton.to || this.actor
};
-
+
let maxPosition = -1;
for (let k of Object.keys(aPacketSkeleton)) {
if (aPacketSkeleton[k] instanceof DebuggerClient.Argument) {
let { position } = aPacketSkeleton[k];
outgoingPacket[k] = aPacketSkeleton[k].getArgument(args);
maxPosition = Math.max(position, maxPosition);
} else {
outgoingPacket[k] = aPacketSkeleton[k];
}
}
-
+
if (before) {
outgoingPacket = before.call(this, outgoingPacket);
}
-
+
return this.request(outgoingPacket, DevToolsUtils.makeInfallible((aResponse) => {
if (after) {
let { from } = aResponse;
aResponse = after.call(this, aResponse);
if (!aResponse.from) {
aResponse.from = from;
}
}
-
+
// The callback is always the last parameter.
let thisCallback = args[maxPosition + 1];
if (thisCallback) {
thisCallback(aResponse);
}
-
+
if (histogram) {
histogram.add(+new Date() - startTime);
}
}, "DebuggerClient.requester request callback"));
}, "DebuggerClient.requester");
};
-
+
function args(aPos) {
return new DebuggerClient.Argument(aPos);
}
-
+
DebuggerClient.Argument = function(aPosition) {
this.position = aPosition;
};
-
+
DebuggerClient.Argument.prototype.getArgument = function(aParams) {
if (!(this.position in aParams)) {
throw new Error("Bad index into params: " + this.position);
}
return aParams[this.position];
};
-
+
// Expose these to save callers the trouble of importing DebuggerSocket
DebuggerClient.socketConnect = function(options) {
// Defined here instead of just copying the function to allow lazy-load
return DebuggerSocket.connect(options);
};
DevToolsUtils.defineLazyGetter(DebuggerClient, "Authenticators", () => {
return Authentication.Authenticators;
});
DevToolsUtils.defineLazyGetter(DebuggerClient, "AuthenticationResult", () => {
return Authentication.AuthenticationResult;
});
-
+
DebuggerClient.prototype = {
/**
* Connect to the server and start exchanging protocol messages.
*
* @param aOnConnected function
* If specified, will be called when the greeting packet is
* received from the debugging server.
*
@@ -10694,71 +10672,71 @@ var Debugger =
* is the application type, by default "browser", and the second
* element is the traits object (help figure out the features
* and behaviors of the server we connect to. See RootActor).
*/
connect: function(aOnConnected) {
return Promise.race([
new Promise((resolve, reject) => {
this.emit("connect");
-
+
// Also emit the event on the |DebuggerClient| object (not on the instance),
// so it's possible to track all instances.
events.emit(DebuggerClient, "connect", this);
-
+
this.addOneTimeListener("connected", (aName, aApplicationType, aTraits) => {
this.traits = aTraits;
if (aOnConnected) {
aOnConnected(aApplicationType, aTraits);
}
resolve([aApplicationType, aTraits]);
});
-
+
this._transport.ready();
}),
new Promise((resolve, reject) => {
setTimeout(() => reject(new Error("Connect timeout error")), 6000);
})
]);
},
-
+
/**
* Shut down communication with the debugging server.
*
* @param aOnClosed function
* If specified, will be called when the debugging connection
* has been closed.
*/
close: function(aOnClosed) {
// Disable detach event notifications, because event handlers will be in a
// cleared scope by the time they run.
this._eventsEnabled = false;
-
+
let cleanup = () => {
this._transport.close();
this._transport = null;
};
-
+
// If the connection is already closed,
// there is no need to detach client
// as we won't be able to send any message.
if (this._closed) {
cleanup();
if (aOnClosed) {
aOnClosed();
}
return;
}
-
+
if (aOnClosed) {
this.addOneTimeListener("closed", function(aEvent) {
aOnClosed();
});
}
-
+
// Call each client's `detach` method by calling
// lastly registered ones first to give a chance
// to detach child clients first.
let clients = [...this._clients.values()];
this._clients.clear();
const detachClients = () => {
let client = clients.pop();
if (!client) {
@@ -10769,31 +10747,31 @@ var Debugger =
if (client.detach) {
client.detach(detachClients);
return;
}
detachClients();
};
detachClients();
},
-
+
/*
* This function exists only to preserve DebuggerClient's interface;
* new code should say 'client.mainRoot.listTabs()'.
*/
listTabs: function(aOnResponse) { return this.mainRoot.listTabs(aOnResponse); },
-
+
/*
* This function exists only to preserve DebuggerClient's interface;
* new code should say 'client.mainRoot.listAddons()'.
*/
listAddons: function(aOnResponse) { return this.mainRoot.listAddons(aOnResponse); },
-
+
getTab: function(aFilter) { return this.mainRoot.getTab(aFilter); },
-
+
/**
* Attach to a tab actor.
*
* @param string aTabActor
* The actor ID for the tab to attach.
* @param function aOnResponse
* Called with the response packet and a TabClient
* (which will be undefined on error).
@@ -10804,57 +10782,57 @@ var Debugger =
let cachedResponse = {
cacheDisabled: cachedTab.cacheDisabled,
javascriptEnabled: cachedTab.javascriptEnabled,
traits: cachedTab.traits,
};
DevToolsUtils.executeSoon(() => aOnResponse(cachedResponse, cachedTab));
return promise.resolve([cachedResponse, cachedTab]);
}
-
+
let packet = {
to: aTabActor,
type: "attach"
};
return this.request(packet).then(aResponse => {
let tabClient;
if (!aResponse.error) {
tabClient = new TabClient(this, aResponse);
this.registerClient(tabClient);
}
aOnResponse(aResponse, tabClient);
return [aResponse, tabClient];
});
},
-
+
attachWorker: function DC_attachWorker(aWorkerActor, aOnResponse = noop) {
let workerClient = this._clients.get(aWorkerActor);
if (workerClient !== undefined) {
let response = {
from: workerClient.actor,
type: "attached",
url: workerClient.url
};
DevToolsUtils.executeSoon(() => aOnResponse(response, workerClient));
return promise.resolve([response, workerClient]);
}
-
+
return this.request({ to: aWorkerActor, type: "attach" }).then(aResponse => {
if (aResponse.error) {
aOnResponse(aResponse, null);
return [aResponse, null];
}
-
+
let workerClient = new WorkerClient(this, aResponse);
this.registerClient(workerClient);
aOnResponse(aResponse, workerClient);
return [aResponse, workerClient];
});
},
-
+
/**
* Attach to an addon actor.
*
* @param string aAddonActor
* The actor ID for the addon to attach.
* @param function aOnResponse
* Called with the response packet and a AddonClient
* (which will be undefined on error).
@@ -10870,17 +10848,17 @@ var Debugger =
addonClient = new AddonClient(this, aAddonActor);
this.registerClient(addonClient);
this.activeAddon = addonClient;
}
aOnResponse(aResponse, addonClient);
return [aResponse, addonClient];
});
},
-
+
/**
* Attach to a Web Console actor.
*
* @param string aConsoleActor
* The ID for the console actor to attach to.
* @param array aListeners
* The console listeners you want to start.
* @param function aOnResponse
@@ -10889,32 +10867,32 @@ var Debugger =
*/
attachConsole:
function(aConsoleActor, aListeners, aOnResponse = noop) {
let packet = {
to: aConsoleActor,
type: "startListeners",
listeners: aListeners,
};
-
+
return this.request(packet).then(aResponse => {
let consoleClient;
if (!aResponse.error) {
if (this._clients.has(aConsoleActor)) {
consoleClient = this._clients.get(aConsoleActor);
} else {
consoleClient = new WebConsoleClient(this, aResponse);
this.registerClient(consoleClient);
}
}
aOnResponse(aResponse, consoleClient);
return [aResponse, consoleClient];
});
},
-
+
/**
* Attach to a global-scoped thread actor for chrome debugging.
*
* @param string aThreadActor
* The actor ID for the thread to attach.
* @param function aOnResponse
* Called with the response packet and a ThreadClient
* (which will be undefined on error).
@@ -10923,62 +10901,62 @@ var Debugger =
* - useSourceMaps: whether to use source maps or not.
*/
attachThread: function(aThreadActor, aOnResponse = noop, aOptions = {}) {
if (this._clients.has(aThreadActor)) {
let client = this._clients.get(aThreadActor);
DevToolsUtils.executeSoon(() => aOnResponse({}, client));
return promise.resolve([{}, client]);
}
-
+
let packet = {
to: aThreadActor,
type: "attach",
options: aOptions
};
return this.request(packet).then(aResponse => {
if (!aResponse.error) {
var threadClient = new ThreadClient(this, aThreadActor);
this.registerClient(threadClient);
}
aOnResponse(aResponse, threadClient);
return [aResponse, threadClient];
});
},
-
+
/**
* Attach to a trace actor.
*
* @param string aTraceActor
* The actor ID for the tracer to attach.
* @param function aOnResponse
* Called with the response packet and a TraceClient
* (which will be undefined on error).
*/
attachTracer: function(aTraceActor, aOnResponse = noop) {
if (this._clients.has(aTraceActor)) {
let client = this._clients.get(aTraceActor);
DevToolsUtils.executeSoon(() => aOnResponse({}, client));
return promise.resolve([{}, client]);
}
-
+
let packet = {
to: aTraceActor,
type: "attach"
};
return this.request(packet).then(aResponse => {
if (!aResponse.error) {
var traceClient = new TraceClient(this, aTraceActor);
this.registerClient(traceClient);
}
aOnResponse(aResponse, traceClient);
return [aResponse, traceClient];
});
},
-
+
/**
* Fetch the ChromeActor for the main process or ChildProcessActor for a
* a given child process ID.
*
* @param number aId
* The ID for the process to attach (returned by `listProcesses`).
* Connected to the main process if omitted, or is 0.
*/
@@ -10987,33 +10965,33 @@ var Debugger =
to: "root",
type: "getProcess"
};
if (typeof (aId) == "number") {
packet.id = aId;
}
return this.request(packet);
},
-
+
/**
* Release an object actor.
*
* @param string aActor
* The actor ID to send the request to.
* @param aOnResponse function
* If specified, will be called with the response packet when
* debugging server responds.
*/
release: DebuggerClient.requester({
to: args(0),
type: "release"
}, {
telemetry: "RELEASE"
}),
-
+
/**
* Send a request to the debugging server.
*
* @param aRequest object
* A JSON packet to send to the debugging server.
* @param aOnResponse function
* If specified, will be called with the JSON response packet when
* debugging server responds.
@@ -11069,26 +11047,26 @@ var Debugger =
"'" + aRequest.to + "' " +
"can't be sent as the connection is closed.";
let resp = { error: "connectionClosed", message: msg };
if (aOnResponse) {
aOnResponse(resp);
}
return promise.reject(resp);
}
-
+
let request = new Request(aRequest);
request.format = "json";
request.stack = components.stack;
if (aOnResponse) {
request.on("json-reply", aOnResponse);
}
-
+
this._sendOrQueueRequest(request);
-
+
// Implement a Promise like API on the returned object
// that resolves/rejects on request response
let deferred = promise.defer();
function listenerJson(resp) {
request.off("json-reply", listenerJson);
request.off("bulk-reply", listenerBulk);
if (resp.error) {
deferred.reject(resp);
@@ -11099,20 +11077,20 @@ var Debugger =
function listenerBulk(resp) {
request.off("json-reply", listenerJson);
request.off("bulk-reply", listenerBulk);
deferred.resolve(resp);
}
request.on("json-reply", listenerJson);
request.on("bulk-reply", listenerBulk);
request.then = deferred.promise.then.bind(deferred.promise);
-
+
return request;
},
-
+
/**
* Transmit streaming data via a bulk request.
*
* This method initiates the bulk send process by queuing up the header data.
* The caller receives eventual access to a stream for writing.
*
* Since this opens up more options for how the server might respond (it could
* send back either JSON or bulk data), and the returned Request object emits
@@ -11192,67 +11170,67 @@ var Debugger =
throw Error("Bulk packet is missing the required 'type' field.");
}
if (!request.actor) {
throw Error("'" + request.type + "' bulk packet has no destination.");
}
if (!request.length) {
throw Error("'" + request.type + "' bulk packet has no length.");
}
-
+
request = new Request(request);
request.format = "bulk";
-
+
this._sendOrQueueRequest(request);
-
+
return request;
},
-
+
/**
* If a new request can be sent immediately, do so. Otherwise, queue it.
*/
_sendOrQueueRequest(request) {
let actor = request.actor;
if (!this._activeRequests.has(actor)) {
this._sendRequest(request);
} else {
this._queueRequest(request);
}
},
-
+
/**
* Send a request.
* @throws Error if there is already an active request in flight for the same
* actor.
*/
_sendRequest(request) {
let actor = request.actor;
this.expectReply(actor, request);
-
+
if (request.format === "json") {
this._transport.send(request.request);
return false;
}
-
+
this._transport.startBulkSend(request.request).then((...args) => {
request.emit("bulk-send-ready", ...args);
});
},
-
+
/**
* Queue a request to be sent later. Queues are only drained when an in
* flight request to a given actor completes.
*/
_queueRequest(request) {
let actor = request.actor;
let queue = this._pendingRequests.get(actor) || [];
queue.push(request);
this._pendingRequests.set(actor, queue);
},
-
+
/**
* Attempt the next request to a given actor (if any).
*/
_attemptNextRequest(actor) {
if (this._activeRequests.has(actor)) {
return;
}
let queue = this._pendingRequests.get(actor);
@@ -11260,132 +11238,132 @@ var Debugger =
return;
}
let request = queue.shift();
if (queue.length === 0) {
this._pendingRequests.delete(actor);
}
this._sendRequest(request);
},
-
+
/**
* Arrange to hand the next reply from |aActor| to the handler bound to
* |aRequest|.
*
* DebuggerClient.prototype.request / startBulkRequest usually takes care of
* establishing the handler for a given request, but in rare cases (well,
* greetings from new root actors, is the only case at the moment) we must be
* prepared for a "reply" that doesn't correspond to any request we sent.
*/
expectReply: function(aActor, aRequest) {
if (this._activeRequests.has(aActor)) {
throw Error("clashing handlers for next reply from " + uneval(aActor));
}
-
+
// If a handler is passed directly (as it is with the handler for the root
// actor greeting), create a dummy request to bind this to.
if (typeof aRequest === "function") {
let handler = aRequest;
aRequest = new Request();
aRequest.on("json-reply", handler);
}
-
+
this._activeRequests.set(aActor, aRequest);
},
-
+
// Transport hooks.
-
+
/**
* Called by DebuggerTransport to dispatch incoming packets as appropriate.
*
* @param aPacket object
* The incoming packet.
*/
onPacket: function(aPacket) {
if (!aPacket.from) {
DevToolsUtils.reportException(
"onPacket",
new Error("Server did not specify an actor, dropping packet: " +
JSON.stringify(aPacket)));
return;
}
-
+
// If we have a registered Front for this actor, let it handle the packet
// and skip all the rest of this unpleasantness.
let front = this.getActor(aPacket.from);
if (front) {
front.onPacket(aPacket);
return;
}
-
+
if (this._clients.has(aPacket.from) && aPacket.type) {
let client = this._clients.get(aPacket.from);
let type = aPacket.type;
if (client.events.indexOf(type) != -1) {
client.emit(type, aPacket);
// we ignore the rest, as the client is expected to handle this packet.
return;
}
}
-
+
let activeRequest;
// See if we have a handler function waiting for a reply from this
// actor. (Don't count unsolicited notifications or pauses as
// replies.)
if (this._activeRequests.has(aPacket.from) &&
!(aPacket.type in UnsolicitedNotifications) &&
!(aPacket.type == ThreadStateTypes.paused &&
aPacket.why.type in UnsolicitedPauses)) {
activeRequest = this._activeRequests.get(aPacket.from);
this._activeRequests.delete(aPacket.from);
}
-
+
// If there is a subsequent request for the same actor, hand it off to the
// transport. Delivery of packets on the other end is always async, even
// in the local transport case.
this._attemptNextRequest(aPacket.from);
-
+
// Packets that indicate thread state changes get special treatment.
if (aPacket.type in ThreadStateTypes &&
this._clients.has(aPacket.from) &&
typeof this._clients.get(aPacket.from)._onThreadState == "function") {
this._clients.get(aPacket.from)._onThreadState(aPacket);
}
-
+
// TODO: Bug 1151156 - Remove once Gecko 40 is on b2g-stable.
if (!this.traits.noNeedToFakeResumptionOnNavigation) {
// On navigation the server resumes, so the client must resume as well.
// We achieve that by generating a fake resumption packet that triggers
// the client's thread state change listeners.
if (aPacket.type == UnsolicitedNotifications.tabNavigated &&
this._clients.has(aPacket.from) &&
this._clients.get(aPacket.from).thread) {
let thread = this._clients.get(aPacket.from).thread;
let resumption = { from: thread._actor, type: "resumed" };
thread._onThreadState(resumption);
}
}
-
+
// Only try to notify listeners on events, not responses to requests
// that lack a packet type.
if (aPacket.type) {
this.emit(aPacket.type, aPacket);
}
-
+
if (activeRequest) {
let emitReply = () => activeRequest.emit("json-reply", aPacket);
if (activeRequest.stack) {
Cu.callFunctionWithAsyncStack(emitReply, activeRequest.stack,
"DevTools RDP");
} else {
emitReply();
}
}
},
-
+
/**
* Called by the DebuggerTransport to dispatch incoming bulk packets as
* appropriate.
*
* @param packet object
* The incoming packet, which contains:
* * actor: Name of actor that will receive the packet
* * type: Name of actor's method that should be called on receipt
@@ -11408,79 +11386,79 @@ var Debugger =
* @return Promise
* The promise is resolved when copying completes or rejected
* if any (unexpected) errors occur.
* This object also emits "progress" events for each chunk
* that is copied. See stream-utils.js.
*/
onBulkPacket: function(packet) {
let { actor, type, length } = packet;
-
+
if (!actor) {
DevToolsUtils.reportException(
"onBulkPacket",
new Error("Server did not specify an actor, dropping bulk packet: " +
JSON.stringify(packet)));
return;
}
-
+
// See if we have a handler function waiting for a reply from this
// actor.
if (!this._activeRequests.has(actor)) {
return;
}
-
+
let activeRequest = this._activeRequests.get(actor);
this._activeRequests.delete(actor);
-
+
// If there is a subsequent request for the same actor, hand it off to the
// transport. Delivery of packets on the other end is always async, even
// in the local transport case.
this._attemptNextRequest(actor);
-
+
activeRequest.emit("bulk-reply", packet);
},
-
+
/**
* Called by DebuggerTransport when the underlying stream is closed.
*
* @param aStatus nsresult
* The status code that corresponds to the reason for closing
* the stream.
*/
onClosed: function(aStatus) {
this._closed = true;
this.emit("closed");
-
+
// Reject all pending and active requests
let reject = function(type, request, actor) {
// Server can send packets on its own and client only pass a callback
// to expectReply, so that there is no request object.
let msg;
if (request.request) {
msg = "'" + request.request.type + "' " + type + " request packet" +
" to '" + actor + "' " +
"can't be sent as the connection just closed.";
} else {
msg = "server side packet from '" + actor + "' can't be received " +
"as the connection just closed.";
}
let packet = { error: "connectionClosed", message: msg };
request.emit("json-reply", packet);
};
-
+
let pendingRequests = new Map(this._pendingRequests);
this._pendingRequests.clear();
pendingRequests.forEach((list, actor) => {
list.forEach(request => reject("pending", request, actor));
});
let activeRequests = new Map(this._activeRequests);
this._activeRequests.clear();
activeRequests.forEach(reject.bind(null, "active"));
-
+
// The |_pools| array on the client-side currently is used only by
// protocol.js to store active fronts, mirroring the actor pools found in
// the server. So, read all usages of "pool" as "protocol.js front".
//
// In the normal case where we shutdown cleanly, the toolbox tells each tool
// to close, and they each call |destroy| on any fronts they were using.
// When |destroy| or |cleanup| is called on a protocol.js front, it also
// removes itself from the |_pools| array. Once the toolbox has shutdown,
@@ -11492,17 +11470,17 @@ var Debugger =
// on them clear their state, reject pending requests, and remove themselves
// from |_pools|. This saves the toolbox from hanging indefinitely, in case
// it waits for some server response before shutdown that will now never
// arrive.
for (let pool of this._pools) {
pool.cleanup();
}
},
-
+
registerClient: function(client) {
let actorID = client.actor;
if (!actorID) {
throw new Error("DebuggerServer.registerClient expects " +
"a client instance with an `actor` attribute.");
}
if (!Array.isArray(client.events)) {
throw new Error("DebuggerServer.registerClient expects " +
@@ -11515,90 +11493,90 @@ var Debugger =
"have an `emit` function.");
}
if (this._clients.has(actorID)) {
throw new Error("DebuggerServer.registerClient already registered " +
"a client for this actor.");
}
this._clients.set(actorID, client);
},
-
+
unregisterClient: function(client) {
let actorID = client.actor;
if (!actorID) {
throw new Error("DebuggerServer.unregisterClient expects " +
"a Client instance with a `actor` attribute.");
}
this._clients.delete(actorID);
},
-
+
/**
* Actor lifetime management, echos the server's actor pools.
*/
__pools: null,
get _pools() {
if (this.__pools) {
return this.__pools;
}
this.__pools = new Set();
return this.__pools;
},
-
+
addActorPool: function(pool) {
this._pools.add(pool);
},
removeActorPool: function(pool) {
this._pools.delete(pool);
},
getActor: function(actorID) {
let pool = this.poolFor(actorID);
return pool ? pool.get(actorID) : null;
},
-
+
poolFor: function(actorID) {
for (let pool of this._pools) {
if (pool.has(actorID)) return pool;
}
return null;
},
-
+
/**
* Currently attached addon.
*/
activeAddon: null
};
-
+
eventSource(DebuggerClient.prototype);
-
+
function Request(request) {
this.request = request;
}
-
+
Request.prototype = {
-
+
on: function(type, listener) {
events.on(this, type, listener);
},
-
+
off: function(type, listener) {
events.off(this, type, listener);
},
-
+
once: function(type, listener) {
events.once(this, type, listener);
},
-
+
emit: function(type, ...args) {
events.emit(this, type, ...args);
},
-
+
get actor() { return this.request.to || this.request.actor; }
-
- };
-
+
+ };
+
/**
* Creates a tab client for the remote debugging protocol server. This client
* is a front to the tab actor created in the server side, hiding the protocol
* details in a traditional JavaScript API.
*
* @param aClient DebuggerClient
* The debugger client parent.
* @param aForm object
@@ -11610,52 +11588,52 @@ var Debugger =
this._threadActor = aForm.threadActor;
this.javascriptEnabled = aForm.javascriptEnabled;
this.cacheDisabled = aForm.cacheDisabled;
this.thread = null;
this.request = this.client.request;
this.traits = aForm.traits || {};
this.events = ["workerListChanged"];
}
-
+
TabClient.prototype = {
get actor() { return this._actor; },
get _transport() { return this.client._transport; },
-
+
/**
* Attach to a thread actor.
*
* @param object aOptions
* Configuration options.
* - useSourceMaps: whether to use source maps or not.
* @param function aOnResponse
* Called with the response packet and a ThreadClient
* (which will be undefined on error).
*/
attachThread: function(aOptions = {}, aOnResponse = noop) {
if (this.thread) {
DevToolsUtils.executeSoon(() => aOnResponse({}, this.thread));
return promise.resolve([{}, this.thread]);
}
-
+
let packet = {
to: this._threadActor,
type: "attach",
options: aOptions
};
return this.request(packet).then(aResponse => {
if (!aResponse.error) {
this.thread = new ThreadClient(this, this._threadActor);
this.client.registerClient(this.thread);
}
aOnResponse(aResponse, this.thread);
return [aResponse, this.thread];
});
},
-
+
/**
* Detach the client from the tab actor.
*
* @param function aOnResponse
* Called with the response packet.
*/
detach: DebuggerClient.requester({
type: "detach"
@@ -11667,212 +11645,212 @@ var Debugger =
return aPacket;
},
after: function(aResponse) {
this.client.unregisterClient(this);
return aResponse;
},
telemetry: "TABDETACH"
}),
-
+
/**
* Bring the window to the front.
*/
focus: DebuggerClient.requester({
type: "focus"
}, {}),
-
+
/**
* Reload the page in this tab.
*
* @param [optional] object options
* An object with a `force` property indicating whether or not
* this reload should skip the cache
*/
reload: function(options = { force: false }) {
return this._reload(options);
},
_reload: DebuggerClient.requester({
type: "reload",
options: args(0)
}, {
telemetry: "RELOAD"
}),
-
+
/**
* Navigate to another URL.
*
* @param string url
* The URL to navigate to.
*/
navigateTo: DebuggerClient.requester({
type: "navigateTo",
url: args(0)
}, {
telemetry: "NAVIGATETO"
}),
-
+
/**
* Reconfigure the tab actor.
*
* @param object aOptions
* A dictionary object of the new options to use in the tab actor.
* @param function aOnResponse
* Called with the response packet.
*/
reconfigure: DebuggerClient.requester({
type: "reconfigure",
options: args(0)
}, {
telemetry: "RECONFIGURETAB"
}),
-
+
listWorkers: DebuggerClient.requester({
type: "listWorkers"
}, {
telemetry: "LISTWORKERS"
}),
-
+
attachWorker: function(aWorkerActor, aOnResponse) {
this.client.attachWorker(aWorkerActor, aOnResponse);
},
-
+
/**
* Resolve a location ({ url, line, column }) to its current
* source mapping location.
*
* @param {String} arg[0].url
* @param {Number} arg[0].line
* @param {Number?} arg[0].column
*/
resolveLocation: DebuggerClient.requester({
type: "resolveLocation",
location: args(0)
}),
};
-
+
eventSource(TabClient.prototype);
-
+
function WorkerClient(aClient, aForm) {
this.client = aClient;
this._actor = aForm.from;
this._isClosed = false;
this._url = aForm.url;
-
+
this._onClose = this._onClose.bind(this);
-
+
this.addListener("close", this._onClose);
-
+
this.traits = {};
}
-
+
WorkerClient.prototype = {
get _transport() {
return this.client._transport;
},
-
+
get request() {
return this.client.request;
},
-
+
get actor() {
return this._actor;
},
-
+
get url() {
return this._url;
},
-
+
get isClosed() {
return this._isClosed;
},
-
+
detach: DebuggerClient.requester({ type: "detach" }, {
after: function(aResponse) {
if (this.thread) {
this.client.unregisterClient(this.thread);
}
this.client.unregisterClient(this);
return aResponse;
},
-
+
telemetry: "WORKERDETACH"
}),
-
+
attachThread: function(aOptions = {}, aOnResponse = noop) {
if (this.thread) {
let response = [{
type: "connected",
threadActor: this.thread._actor,
consoleActor: this.consoleActor,
}, this.thread];
DevToolsUtils.executeSoon(() => aOnResponse(response));
return response;
}
-
+
// The connect call on server doesn't attach the thread as of version 44.
return this.request({
to: this._actor,
type: "connect",
options: aOptions,
}).then(connectReponse => {
if (connectReponse.error) {
aOnResponse(connectReponse, null);
return [connectResponse, null];
}
-
+
return this.request({
to: connectReponse.threadActor,
type: "attach",
options: aOptions
}).then(attachResponse => {
if (attachResponse.error) {
aOnResponse(attachResponse, null);
}
-
+
this.thread = new ThreadClient(this, connectReponse.threadActor);
this.consoleActor = connectReponse.consoleActor;
this.client.registerClient(this.thread);
-
+
aOnResponse(connectReponse, this.thread);
return [connectResponse, this.thread];
});
});
},
-
+
_onClose: function() {
this.removeListener("close", this._onClose);
-
+
if (this.thread) {
this.client.unregisterClient(this.thread);
}
this.client.unregisterClient(this);
this._isClosed = true;
},
-
+
reconfigure: function() {
return Promise.resolve();
},
-
+
events: ["close"]
};
-
+
eventSource(WorkerClient.prototype);
-
+
function AddonClient(aClient, aActor) {
this._client = aClient;
this._actor = aActor;
this.request = this._client.request;
this.events = [];
}
-
+
AddonClient.prototype = {
get actor() { return this._actor; },
get _transport() { return this._client._transport; },
-
+
/**
* Detach the client from the addon actor.
*
* @param function aOnResponse
* Called with the response packet.
*/
detach: DebuggerClient.requester({
type: "detach"
@@ -11882,17 +11860,17 @@ var Debugger =
this._client.activeAddon = null;
}
this._client.unregisterClient(this);
return aResponse;
},
telemetry: "ADDONDETACH"
})
};
-
+
/**
* A RootClient object represents a root actor on the server. Each
* DebuggerClient keeps a RootClient instance representing the root actor
* for the initial connection; DebuggerClient's 'listTabs' and
* 'listChildProcesses' methods forward to that root actor.
*
* @param aClient object
* The client connection to which this actor belongs.
@@ -11910,65 +11888,65 @@ var Debugger =
*/
function RootClient(aClient, aGreeting) {
this._client = aClient;
this.actor = aGreeting.from;
this.applicationType = aGreeting.applicationType;
this.traits = aGreeting.traits;
}
exports.RootClient = RootClient;
-
+
RootClient.prototype = {
constructor: RootClient,
-
+
/**
* List the open tabs.
*
* @param function aOnResponse
* Called with the response packet.
*/
listTabs: DebuggerClient.requester({ type: "listTabs" },
{ telemetry: "LISTTABS" }),
-
+
/**
* List the installed addons.
*
* @param function aOnResponse
* Called with the response packet.
*/
listAddons: DebuggerClient.requester({ type: "listAddons" },
{ telemetry: "LISTADDONS" }),
-
+
/**
* List the registered workers.
*
* @param function aOnResponse
* Called with the response packet.
*/
listWorkers: DebuggerClient.requester({ type: "listWorkers" },
{ telemetry: "LISTWORKERS" }),
-
+
/**
* List the registered service workers.
*
* @param function aOnResponse
* Called with the response packet.
*/
listServiceWorkerRegistrations: DebuggerClient.requester({ type: "listServiceWorkerRegistrations" },
{ telemetry: "LISTSERVICEWORKERREGISTRATIONS" }),
-
+
/**
* List the running processes.
*
* @param function aOnResponse
* Called with the response packet.
*/
listProcesses: DebuggerClient.requester({ type: "listProcesses" },
{ telemetry: "LISTPROCESSES" }),
-
+
/**
* Fetch the TabActor for the currently selected tab, or for a specific
* tab given as first parameter.
*
* @param [optional] object aFilter
* A dictionary object with following optional attributes:
* - outerWindowID: used to match tabs in parent process
* - tabId: used to match tabs in child processes
@@ -11976,17 +11954,17 @@ var Debugger =
* If nothing is specified, returns the actor for the currently
* selected tab.
*/
getTab: function(aFilter) {
let packet = {
to: this.actor,
type: "getTab"
};
-
+
if (aFilter) {
if (typeof (aFilter.outerWindowID) == "number") {
packet.outerWindowID = aFilter.outerWindowID;
} else if (typeof (aFilter.tabId) == "number") {
packet.tabId = aFilter.tabId;
} else if ("tab" in aFilter) {
let browser = aFilter.tab.linkedBrowser;
if (browser.frameLoader.tabParent) {
@@ -12000,37 +11978,37 @@ var Debugger =
packet.outerWindowID = windowUtils.outerWindowID;
}
} else {
// Throw if a filter object have been passed but without
// any clearly idenfified filter.
throw new Error("Unsupported argument given to getTab request");
}
}
-
+
return this.request(packet);
},
-
+
/**
* Description of protocol's actors and methods.
*
* @param function aOnResponse
* Called with the response packet.
*/
protocolDescription: DebuggerClient.requester({ type: "protocolDescription" },
{ telemetry: "PROTOCOLDESCRIPTION" }),
-
+
/*
* Methods constructed by DebuggerClient.requester require these forwards
* on their 'this'.
*/
get _transport() { return this._client._transport; },
get request() { return this._client.request; }
};
-
+
/**
* Creates a thread client for the remote debugging protocol server. This client
* is a front to the thread actor created in the server side, hiding the
* protocol details in a traditional JavaScript API.
*
* @param aClient DebuggerClient|TabClient
* The parent of the thread (tab for tab-scoped debuggers, DebuggerClient
* for chrome debuggers).
@@ -12042,37 +12020,37 @@ var Debugger =
this.client = aClient instanceof DebuggerClient ? aClient : aClient.client;
this._actor = aActor;
this._frameCache = [];
this._scriptCache = {};
this._pauseGrips = {};
this._threadGrips = {};
this.request = this.client.request;
}
-
+
ThreadClient.prototype = {
_state: "paused",
get state() { return this._state; },
get paused() { return this._state === "paused"; },
-
+
_pauseOnExceptions: false,
_ignoreCaughtExceptions: false,
_pauseOnDOMEvents: null,
-
+
_actor: null,
get actor() { return this._actor; },
-
+
get _transport() { return this.client._transport; },
-
+
_assertPaused: function(aCommand) {
if (!this.paused) {
throw Error(aCommand + " command sent while not paused. Currently " + this._state);
}
},
-
+
/**
* Resume a paused thread. If the optional aLimit parameter is present, then
* the thread will also pause when that limit is reached.
*
* @param [optional] object aLimit
* An object with a type property set to the appropriate limit (next,
* step, or finish) per the remote debugging protocol specification.
* Use null to specify no limit.
@@ -12080,21 +12058,21 @@ var Debugger =
* Called with the response packet.
*/
_doResume: DebuggerClient.requester({
type: "resume",
resumeLimit: args(0)
}, {
before: function(aPacket) {
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._state = "resuming";
-
+
if (this._pauseOnExceptions) {
aPacket.pauseOnExceptions = this._pauseOnExceptions;
}
if (this._ignoreCaughtExceptions) {
aPacket.ignoreCaughtExceptions = this._ignoreCaughtExceptions;
}
if (this._pauseOnDOMEvents) {
aPacket.pauseOnDOMEvents = this._pauseOnDOMEvents;
@@ -12105,142 +12083,142 @@ var Debugger =
if (aResponse.error) {
// There was an error resuming, back to paused state.
this._state = "paused";
}
return aResponse;
},
telemetry: "RESUME"
}),
-
+
/**
* Reconfigure the thread actor.
*
* @param object aOptions
* A dictionary object of the new options to use in the thread actor.
* @param function aOnResponse
* Called with the response packet.
*/
reconfigure: DebuggerClient.requester({
type: "reconfigure",
options: args(0)
}, {
telemetry: "RECONFIGURETHREAD"
}),
-
+
/**
* Resume a paused thread.
*/
resume: function(aOnResponse) {
return this._doResume(null, aOnResponse);
},
-
+
/**
* Resume then pause without stepping.
*
* @param function aOnResponse
* Called with the response packet.
*/
resumeThenPause: function(aOnResponse) {
return this._doResume({ type: "break" }, aOnResponse);
},
-
+
/**
* Step over a function call.
*
* @param function aOnResponse
* Called with the response packet.
*/
stepOver: function(aOnResponse) {
return this._doResume({ type: "next" }, aOnResponse);
},
-
+
/**
* Step into a function call.
*
* @param function aOnResponse
* Called with the response packet.
*/
stepIn: function(aOnResponse) {
return this._doResume({ type: "step" }, aOnResponse);
},
-
+
/**
* Step out of a function call.
*
* @param function aOnResponse
* Called with the response packet.
*/
stepOut: function(aOnResponse) {
return this._doResume({ type: "finish" }, aOnResponse);
},
-
+
/**
* Immediately interrupt a running thread.
*
* @param function aOnResponse
* Called with the response packet.
*/
interrupt: function(aOnResponse) {
return this._doInterrupt(null, aOnResponse);
},
-
+
/**
* Pause execution right before the next JavaScript bytecode is executed.
*
* @param function aOnResponse
* Called with the response packet.
*/
breakOnNext: function(aOnResponse) {
return this._doInterrupt("onNext", aOnResponse);
},
-
+
/**
* Interrupt a running thread.
*
* @param function aOnResponse
* Called with the response packet.
*/
_doInterrupt: DebuggerClient.requester({
type: "interrupt",
when: args(0)
}, {
telemetry: "INTERRUPT"
}),
-
+
/**
* Enable or disable pausing when an exception is thrown.
*
* @param boolean aFlag
* Enables pausing if true, disables otherwise.
* @param function aOnResponse
* Called with the response packet.
*/
pauseOnExceptions: function(aPauseOnExceptions,
aIgnoreCaughtExceptions,
aOnResponse = noop) {
this._pauseOnExceptions = aPauseOnExceptions;
this._ignoreCaughtExceptions = aIgnoreCaughtExceptions;
-
+
// Otherwise send the flag using a standard resume request.
if (!this.paused) {
return this.interrupt(aResponse => {
if (aResponse.error) {
// Can't continue if pausing failed.
aOnResponse(aResponse);
return aResponse;
}
return this.resume(aOnResponse);
});
}
-
+
aOnResponse();
return promise.resolve();
},
-
+
/**
* Enable pausing when the specified DOM events are triggered. Disabling
* pausing on an event can be realized by calling this method with the updated
* array of events that doesn't contain it.
*
* @param array|string events
* An array of strings, representing the DOM event types to pause on,
* or "*" to pause on all DOM events. Pass an empty array to
@@ -12261,17 +12239,17 @@ var Debugger =
// Can't continue if pausing failed.
if (response.error) {
onResponse(response);
return response;
}
return this.resume(onResponse);
});
},
-
+
/**
* Send a clientEvaluate packet to the debuggee. Response
* will be a resume packet.
*
* @param string aFrame
* The actor ID of the frame where the evaluation should take place.
* @param string aExpression
* The expression that will be evaluated in the scope of the frame
@@ -12295,97 +12273,97 @@ var Debugger =
if (aResponse.error) {
// There was an error resuming, back to paused state.
this._state = "paused";
}
return aResponse;
},
telemetry: "CLIENTEVALUATE"
}),
-
+
/**
* Detach from the thread actor.
*
* @param function aOnResponse
* Called with the response packet.
*/
detach: DebuggerClient.requester({
type: "detach"
}, {
after: function(aResponse) {
this.client.unregisterClient(this);
this._parent.thread = null;
return aResponse;
},
telemetry: "THREADDETACH"
}),
-
+
/**
* Release multiple thread-lifetime object actors. If any pause-lifetime
* actors are included in the request, a |notReleasable| error will return,
* but all the thread-lifetime ones will have been released.
*
* @param array actors
* An array with actor IDs to release.
*/
releaseMany: DebuggerClient.requester({
type: "releaseMany",
actors: args(0),
}, {
telemetry: "RELEASEMANY"
}),
-
+
/**
* Promote multiple pause-lifetime object actors to thread-lifetime ones.
*
* @param array actors
* An array with actor IDs to promote.
*/
threadGrips: DebuggerClient.requester({
type: "threadGrips",
actors: args(0)
}, {
telemetry: "THREADGRIPS"
}),
-
+
/**
* Return the event listeners defined on the page.
*
* @param aOnResponse Function
* Called with the thread's response.
*/
eventListeners: DebuggerClient.requester({
type: "eventListeners"
}, {
telemetry: "EVENTLISTENERS"
}),
-
+
/**
* Request the loaded sources for the current thread.
*
* @param aOnResponse Function
* Called with the thread's response.
*/
getSources: DebuggerClient.requester({
type: "sources"
}, {
telemetry: "SOURCES"
}),
-
+
/**
* Clear the thread's source script cache. A scriptscleared event
* will be sent.
*/
_clearScripts: function() {
if (Object.keys(this._scriptCache).length > 0) {
this._scriptCache = {};
this.emit("scriptscleared");
}
},
-
+
/**
* Request frames from the callstack for the current thread.
*
* @param aStart integer
* The number of the youngest stack frame to return (the youngest
* frame is 0).
* @param aCount integer
* The maximum number of frames to return, or null to return all
@@ -12395,240 +12373,240 @@ var Debugger =
*/
getFrames: DebuggerClient.requester({
type: "frames",
start: args(0),
count: args(1)
}, {
telemetry: "FRAMES"
}),
-
+
/**
* An array of cached frames. Clients can observe the framesadded and
* framescleared event to keep up to date on changes to this cache,
* and can fill it using the fillFrames method.
*/
get cachedFrames() { return this._frameCache; },
-
+
/**
* true if there are more stack frames available on the server.
*/
get moreFrames() {
return this.paused && (!this._frameCache || this._frameCache.length == 0
|| !this._frameCache[this._frameCache.length - 1].oldest);
},
-
+
/**
* Ensure that at least aTotal stack frames have been loaded in the
* ThreadClient's stack frame cache. A framesadded event will be
* sent when the stack frame cache is updated.
*
* @param aTotal number
* The minimum number of stack frames to be included.
* @param aCallback function
* Optional callback function called when frames have been loaded
* @returns true if a framesadded notification should be expected.
*/
fillFrames: function(aTotal, aCallback = noop) {
this._assertPaused("fillFrames");
if (this._frameCache.length >= aTotal) {
return false;
}
-
+
let numFrames = this._frameCache.length;
-
+
this.getFrames(numFrames, aTotal - numFrames, (aResponse) => {
if (aResponse.error) {
aCallback(aResponse);
return;
}
-
+
let threadGrips = DevToolsUtils.values(this._threadGrips);
-
+
for (let i in aResponse.frames) {
let frame = aResponse.frames[i];
if (!frame.where.source) {
// Older servers use urls instead, so we need to resolve
// them to source actors
for (let grip of threadGrips) {
if (grip instanceof SourceClient && grip.url === frame.url) {
frame.where.source = grip._form;
}
}
}
-
+
this._frameCache[frame.depth] = frame;
}
-
+
// If we got as many frames as we asked for, there might be more
// frames available.
this.emit("framesadded");
-
+
aCallback(aResponse);
});
-
+
return true;
},
-
+
/**
* Clear the thread's stack frame cache. A framescleared event
* will be sent.
*/
_clearFrames: function() {
if (this._frameCache.length > 0) {
this._frameCache = [];
this.emit("framescleared");
}
},
-
+
/**
* Return a ObjectClient object for the given object grip.
*
* @param aGrip object
* A pause-lifetime object grip returned by the protocol.
*/
pauseGrip: function(aGrip) {
if (aGrip.actor in this._pauseGrips) {
return this._pauseGrips[aGrip.actor];
}
-
+
let client = new ObjectClient(this.client, aGrip);
this._pauseGrips[aGrip.actor] = client;
return client;
},
-
+
/**
* Get or create a long string client, checking the grip client cache if it
* already exists.
*
* @param aGrip Object
* The long string grip returned by the protocol.
* @param aGripCacheName String
* The property name of the grip client cache to check for existing
* clients in.
*/
_longString: function(aGrip, aGripCacheName) {
if (aGrip.actor in this[aGripCacheName]) {
return this[aGripCacheName][aGrip.actor];
}
-
+
let client = new LongStringClient(this.client, aGrip);
this[aGripCacheName][aGrip.actor] = client;
return client;
},
-
+
/**
* Return an instance of LongStringClient for the given long string grip that
* is scoped to the current pause.
*
* @param aGrip Object
* The long string grip returned by the protocol.
*/
pauseLongString: function(aGrip) {
return this._longString(aGrip, "_pauseGrips");
},
-
+
/**
* Return an instance of LongStringClient for the given long string grip that
* is scoped to the thread lifetime.
*
* @param aGrip Object
* The long string grip returned by the protocol.
*/
threadLongString: function(aGrip) {
return this._longString(aGrip, "_threadGrips");
},
-
+
/**
* Clear and invalidate all the grip clients from the given cache.
*
* @param aGripCacheName
* The property name of the grip cache we want to clear.
*/
_clearObjectClients: function(aGripCacheName) {
for (let id in this[aGripCacheName]) {
this[aGripCacheName][id].valid = false;
}
this[aGripCacheName] = {};
},
-
+
/**
* Invalidate pause-lifetime grip clients and clear the list of current grip
* clients.
*/
_clearPauseGrips: function() {
this._clearObjectClients("_pauseGrips");
},
-
+
/**
* Invalidate thread-lifetime grip clients and clear the list of current grip
* clients.
*/
_clearThreadGrips: function() {
this._clearObjectClients("_threadGrips");
},
-
+
/**
* Handle thread state change by doing necessary cleanup and notifying all
* registered listeners.
*/
_onThreadState: function(aPacket) {
this._state = ThreadStateTypes[aPacket.type];
// The debugger UI may not be initialized yet so we want to keep
// the packet around so it knows what to pause state to display
// when it's initialized
this._lastPausePacket = aPacket.type === "resumed" ? null : aPacket;
this._clearFrames();
this._clearPauseGrips();
aPacket.type === ThreadStateTypes.detached && this._clearThreadGrips();
this.client._eventsEnabled && this.emit(aPacket.type, aPacket);
},
-
+
getLastPausePacket: function() {
return this._lastPausePacket;
},
-
+
/**
* Return an EnvironmentClient instance for the given environment actor form.
*/
environment: function(aForm) {
return new EnvironmentClient(this.client, aForm);
},
-
+
/**
* Return an instance of SourceClient for the given source actor form.
*/
source: function(aForm) {
if (aForm.actor in this._threadGrips) {
return this._threadGrips[aForm.actor];
}
-
+
return this._threadGrips[aForm.actor] = new SourceClient(this, aForm);
},
-
+
/**
* Request the prototype and own properties of mutlipleObjects.
*
* @param aOnResponse function
* Called with the request's response.
* @param actors [string]
* List of actor ID of the queried objects.
*/
getPrototypesAndProperties: DebuggerClient.requester({
type: "prototypesAndProperties",
actors: args(0)
}, {
telemetry: "PROTOTYPESANDPROPERTIES"
}),
-
+
events: ["newSource"]
};
-
+
eventSource(ThreadClient.prototype);
-
+
/**
* Creates a tracing profiler client for the remote debugging protocol
* server. This client is a front to the trace actor created on the
* server side, hiding the protocol details in a traditional
* JavaScript API.
*
* @param aClient DebuggerClient
* The debugger client parent.
@@ -12639,36 +12617,36 @@ var Debugger =
this._client = aClient;
this._actor = aActor;
this._activeTraces = new Set();
this._waitingPackets = new Map();
this._expectedPacket = 0;
this.request = this._client.request;
this.events = [];
}
-
+
TraceClient.prototype = {
get actor() { return this._actor; },
get tracing() { return this._activeTraces.size > 0; },
-
+
get _transport() { return this._client._transport; },
-
+
/**
* Detach from the trace actor.
*/
detach: DebuggerClient.requester({
type: "detach"
}, {
after: function(aResponse) {
this._client.unregisterClient(this);
return aResponse;
},
telemetry: "TRACERDETACH"
}),
-
+
/**
* Start a new trace.
*
* @param aTrace [string]
* An array of trace types to be recorded by the new trace.
*
* @param aName string
* The name of the new trace.
@@ -12680,28 +12658,28 @@ var Debugger =
type: "startTrace",
name: args(1),
trace: args(0)
}, {
after: function(aResponse) {
if (aResponse.error) {
return aResponse;
}
-
+
if (!this.tracing) {
this._waitingPackets.clear();
this._expectedPacket = 0;
}
this._activeTraces.add(aResponse.name);
-
+
return aResponse;
},
telemetry: "STARTTRACE"
}),
-
+
/**
* End a trace. If a name is provided, stop the named
* trace. Otherwise, stop the most recently started trace.
*
* @param aName string
* The name of the trace to stop.
*
* @param aOnResponse function
@@ -12710,68 +12688,68 @@ var Debugger =
stopTrace: DebuggerClient.requester({
type: "stopTrace",
name: args(0)
}, {
after: function(aResponse) {
if (aResponse.error) {
return aResponse;
}
-
+
this._activeTraces.delete(aResponse.name);
-
+
return aResponse;
},
telemetry: "STOPTRACE"
})
};
-
+
/**
* Grip clients are used to retrieve information about the relevant object.
*
* @param aClient DebuggerClient
* The debugger client parent.
* @param aGrip object
* A pause-lifetime object grip returned by the protocol.
*/
function ObjectClient(aClient, aGrip)
{
this._grip = aGrip;
this._client = aClient;
this.request = this._client.request;
}
exports.ObjectClient = ObjectClient;
-
+
ObjectClient.prototype = {
get actor() { return this._grip.actor; },
get _transport() { return this._client._transport; },
-
+
valid: true,
-
+
get isFrozen() {
return this._grip.frozen;
},
get isSealed() {
return this._grip.sealed;
},
get isExtensible() {
return this._grip.extensible;
},
-
+
getDefinitionSite: DebuggerClient.requester({
type: "definitionSite"
}, {
before: function(aPacket) {
if (this._grip.class != "Function") {
throw new Error("getDefinitionSite is only valid for function grips.");
}
return aPacket;
}
}),
-
+
/**
* Request the names of a function's formal parameters.
*
* @param aOnResponse function
* Called with an object of the form:
* { parameterNames:[<parameterName>, ...] }
* where each <parameterName> is the name of a parameter.
*/
@@ -12781,40 +12759,40 @@ var Debugger =
before: function(aPacket) {
if (this._grip.class !== "Function") {
throw new Error("getParameterNames is only valid for function grips.");
}
return aPacket;
},
telemetry: "PARAMETERNAMES"
}),
-
+
/**
* Request the names of the properties defined on the object and not its
* prototype.
*
* @param aOnResponse function Called with the request's response.
*/
getOwnPropertyNames: DebuggerClient.requester({
type: "ownPropertyNames"
}, {
telemetry: "OWNPROPERTYNAMES"
}),
-
+
/**
* Request the prototype and own properties of the object.
*
* @param aOnResponse function Called with the request's response.
*/
getPrototypeAndProperties: DebuggerClient.requester({
type: "prototypeAndProperties"
}, {
telemetry: "PROTOTYPEANDPROPERTIES"
}),
-
+
/**
* Request a PropertyIteratorClient instance to ease listing
* properties for this object.
*
* @param options Object
* A dictionary object with various boolean attributes:
* - ignoreSafeGetters Boolean
* If true, do not iterate over safe getters.
@@ -12837,17 +12815,17 @@ var Debugger =
after: function(aResponse) {
if (aResponse.iterator) {
return { iterator: new PropertyIteratorClient(this._client, aResponse.iterator) };
}
return aResponse;
},
telemetry: "ENUMPROPERTIES"
}),
-
+
/**
* Request a PropertyIteratorClient instance to enumerate entries in a
* Map/Set-like object.
*
* @param aOnResponse function Called with the request's response.
*/
enumEntries: DebuggerClient.requester({
type: "enumEntries"
@@ -12862,129 +12840,129 @@ var Debugger =
if (response.iterator) {
return {
iterator: new PropertyIteratorClient(this._client, response.iterator)
};
}
return response;
}
}),
-
+
/**
* Request the property descriptor of the object's specified property.
*
* @param aName string The name of the requested property.
* @param aOnResponse function Called with the request's response.
*/
getProperty: DebuggerClient.requester({
type: "property",
name: args(0)
}, {
telemetry: "PROPERTY"
}),
-
+
/**
* Request the prototype of the object.
*
* @param aOnResponse function Called with the request's response.
*/
getPrototype: DebuggerClient.requester({
type: "prototype"
}, {
telemetry: "PROTOTYPE"
}),
-
+
/**
* Request the display string of the object.
*
* @param aOnResponse function Called with the request's response.
*/
getDisplayString: DebuggerClient.requester({
type: "displayString"
}, {
telemetry: "DISPLAYSTRING"
}),
-
+
/**
* Request the scope of the object.
*
* @param aOnResponse function Called with the request's response.
*/
getScope: DebuggerClient.requester({
type: "scope"
}, {
before: function(aPacket) {
if (this._grip.class !== "Function") {
throw new Error("scope is only valid for function grips.");
}
return aPacket;
},
telemetry: "SCOPE"
}),
-
+
/**
* Request the promises directly depending on the current promise.
*/
getDependentPromises: DebuggerClient.requester({
type: "dependentPromises"
}, {
before: function(aPacket) {
if (this._grip.class !== "Promise") {
throw new Error("getDependentPromises is only valid for promise " +
"grips.");
}
return aPacket;
}
}),
-
+
/**
* Request the stack to the promise's allocation point.
*/
getPromiseAllocationStack: DebuggerClient.requester({
type: "allocationStack"
}, {
before: function(aPacket) {
if (this._grip.class !== "Promise") {
throw new Error("getAllocationStack is only valid for promise grips.");
}
return aPacket;
}
}),
-
+
/**
* Request the stack to the promise's fulfillment point.
*/
getPromiseFulfillmentStack: DebuggerClient.requester({
type: "fulfillmentStack"
}, {
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.
*/
getPromiseRejectionStack: DebuggerClient.requester({
type: "rejectionStack"
}, {
before: function(packet) {
if (this._grip.class !== "Promise") {
throw new Error("getPromiseRejectionStack is only valid for " +
"promise grips.");
}
return packet;
}
})
};
-
+
/**
* A PropertyIteratorClient provides a way to access to property names and
* values of an object efficiently, slice by slice.
* Note that the properties can be sorted in the backend,
* this is controled while creating the PropertyIteratorClient
* from ObjectClient.enumProperties.
*
* @param aClient DebuggerClient
@@ -12993,90 +12971,90 @@ var Debugger =
* A PropertyIteratorActor grip returned by the protocol via
* TabActor.enumProperties request.
*/
function PropertyIteratorClient(aClient, aGrip) {
this._grip = aGrip;
this._client = aClient;
this.request = this._client.request;
}
-
+
PropertyIteratorClient.prototype = {
get actor() { return this._grip.actor; },
-
+
/**
* Get the total number of properties available in the iterator.
*/
get count() { return this._grip.count; },
-
+
/**
* Get one or more property names that correspond to the positions in the
* indexes parameter.
*
* @param indexes Array
* An array of property indexes.
* @param aCallback Function
* The function called when we receive the property names.
*/
names: DebuggerClient.requester({
type: "names",
indexes: args(0)
}, {}),
-
+
/**
* Get a set of following property value(s).
*
* @param start Number
* The index of the first property to fetch.
* @param count Number
* The number of properties to fetch.
* @param aCallback Function
* The function called when we receive the property values.
*/
slice: DebuggerClient.requester({
type: "slice",
start: args(0),
count: args(1)
}, {}),
-
+
/**
* Get all the property values.
*
* @param aCallback Function
* The function called when we receive the property values.
*/
all: DebuggerClient.requester({
type: "all"
}, {}),
};
-
+
/**
* A LongStringClient provides a way to access "very long" strings from the
* debugger server.
*
* @param aClient DebuggerClient
* The debugger client parent.
* @param aGrip Object
* A pause-lifetime long string grip returned by the protocol.
*/
function LongStringClient(aClient, aGrip) {
this._grip = aGrip;
this._client = aClient;
this.request = this._client.request;
}
exports.LongStringClient = LongStringClient;
-
+
LongStringClient.prototype = {
get actor() { return this._grip.actor; },
get length() { return this._grip.length; },
get initial() { return this._grip.initial; },
get _transport() { return this._client._transport; },
-
+
valid: true,
-
+
/**
* Get the substring of this LongString from aStart to aEnd.
*
* @param aStart Number
* The starting index.
* @param aEnd Number
* The ending index.
* @param aCallback Function
@@ -13085,33 +13063,33 @@ var Debugger =
substring: DebuggerClient.requester({
type: "substring",
start: args(0),
end: args(1)
}, {
telemetry: "SUBSTRING"
}),
};
-
+
/**
* A SourceClient provides a way to access the source text of a script.
*
* @param aClient ThreadClient
* The thread client parent.
* @param aForm Object
* The form sent across the remote debugging protocol.
*/
function SourceClient(aClient, aForm) {
this._form = aForm;
this._isBlackBoxed = aForm.isBlackBoxed;
this._isPrettyPrinted = aForm.isPrettyPrinted;
this._activeThread = aClient;
this._client = aClient.client;
}
-
+
SourceClient.prototype = {
get _transport() {
return this._client._transport;
},
get isBlackBoxed() {
return this._isBlackBoxed;
},
get isPrettyPrinted() {
@@ -13121,17 +13099,17 @@ var Debugger =
return this._form.actor;
},
get request() {
return this._client.request;
},
get url() {
return this._form.url;
},
-
+
/**
* Black box this SourceClient's source.
*
* @param aCallback Function
* The callback function called when we receive the response from the server.
*/
blackBox: DebuggerClient.requester({
type: "blackbox"
@@ -13142,17 +13120,17 @@ var Debugger =
this._isBlackBoxed = true;
if (this._activeThread) {
this._activeThread.emit("blackboxchange", this);
}
}
return aResponse;
}
}),
-
+
/**
* Un-black box this SourceClient's source.
*
* @param aCallback Function
* The callback function called when we receive the response from the server.
*/
unblackBox: DebuggerClient.requester({
type: "unblackbox"
@@ -13163,48 +13141,48 @@ var Debugger =
this._isBlackBoxed = false;
if (this._activeThread) {
this._activeThread.emit("blackboxchange", this);
}
}
return aResponse;
}
}),
-
+
/**
* Get Executable Lines from a source
*
* @param aCallback Function
* The callback function called when we receive the response from the server.
*/
getExecutableLines: function(cb = noop) {
let packet = {
to: this._form.actor,
type: "getExecutableLines"
};
-
+
return this._client.request(packet).then(res => {
cb(res.lines);
return res.lines;
});
},
-
+
/**
* Get a long string grip for this SourceClient's source.
*/
source: function(aCallback = noop) {
let packet = {
to: this._form.actor,
type: "source"
};
return this._client.request(packet).then(aResponse => {
return this._onSourceResponse(aResponse, aCallback);
});
},
-
+
/**
* Pretty print this source's text.
*/
prettyPrint: function(aIndent, aCallback = noop) {
const packet = {
to: this._form.actor,
type: "prettyPrint",
indent: aIndent
@@ -13213,17 +13191,17 @@ var Debugger =
if (!aResponse.error) {
this._isPrettyPrinted = true;
this._activeThread._clearFrames();
this._activeThread.emit("prettyprintchange", this);
}
return this._onSourceResponse(aResponse, aCallback);
});
},
-
+
/**
* Stop pretty printing this source's text.
*/
disablePrettyPrint: function(aCallback = noop) {
const packet = {
to: this._form.actor,
type: "disablePrettyPrint"
};
@@ -13231,45 +13209,45 @@ var Debugger =
if (!aResponse.error) {
this._isPrettyPrinted = false;
this._activeThread._clearFrames();
this._activeThread.emit("prettyprintchange", this);
}
return this._onSourceResponse(aResponse, aCallback);
});
},
-
+
_onSourceResponse: function(aResponse, aCallback) {
if (aResponse.error) {
aCallback(aResponse);
return aResponse;
}
-
+
if (typeof aResponse.source === "string") {
aCallback(aResponse);
return aResponse;
}
-
+
let { contentType, source } = aResponse;
let longString = this._activeThread.threadLongString(source);
return longString.substring(0, longString.length).then(function(aResponse) {
if (aResponse.error) {
aCallback(aResponse);
return aReponse;
}
-
+
let response = {
source: aResponse.substring,
contentType: contentType
};
aCallback(response);
return response;
});
},
-
+
/**
* Request to set a breakpoint in the specified location.
*
* @param object aLocation
* The location and condition of the breakpoint in
* the form of { line[, column, condition] }.
* @param function aOnResponse
* Called with the thread's response.
@@ -13277,32 +13255,32 @@ var Debugger =
setBreakpoint: function({ line, column, condition, noSliding }, aOnResponse = noop) {
// A helper function that sets the breakpoint.
let doSetBreakpoint = aCallback => {
let root = this._client.mainRoot;
let location = {
line: line,
column: column
};
-
+
let packet = {
to: this.actor,
type: "setBreakpoint",
location: location,
condition: condition,
noSliding: noSliding
};
-
+
// Backwards compatibility: send the breakpoint request to the
// thread if the server doesn't support Debugger.Source actors.
if (!root.traits.debuggerSourceActors) {
packet.to = this._activeThread.actor;
packet.location.url = this.url;
}
-
+
return this._client.request(packet).then(aResponse => {
// Ignoring errors, since the user may be setting a breakpoint in a
// dead script that will reappear on a page reload.
let bpClient;
if (aResponse.actor) {
bpClient = new BreakpointClient(
this._client,
this,
@@ -13313,39 +13291,39 @@ var Debugger =
}
aOnResponse(aResponse, bpClient);
if (aCallback) {
aCallback();
}
return [aResponse, bpClient];
});
};
-
+
// If the debuggee is paused, just set the breakpoint.
if (this._activeThread.paused) {
return doSetBreakpoint();
}
// Otherwise, force a pause in order to set the breakpoint.
return this._activeThread.interrupt().then(aResponse => {
if (aResponse.error) {
// Can't set the breakpoint if pausing failed.
aOnResponse(aResponse);
return aResponse;
}
-
+
const { type, why } = aResponse;
const cleanUp = type == "paused" && why.type == "interrupted"
? () => this._activeThread.resume()
: noop;
-
+
return doSetBreakpoint(cleanUp);
});
}
};
-
+
/**
* Breakpoint clients are used to remove breakpoints that are no longer used.
*
* @param aClient DebuggerClient
* The debugger client parent.
* @param aSourceClient SourceClient
* The source where this breakpoint exists
* @param aActor string
@@ -13359,91 +13337,91 @@ var Debugger =
function BreakpointClient(aClient, aSourceClient, aActor, aLocation, aCondition) {
this._client = aClient;
this._actor = aActor;
this.location = aLocation;
this.location.actor = aSourceClient.actor;
this.location.url = aSourceClient.url;
this.source = aSourceClient;
this.request = this._client.request;
-
+
// The condition property should only exist if it's a truthy value
if (aCondition) {
this.condition = aCondition;
}
}
-
+
BreakpointClient.prototype = {
-
+
_actor: null,
get actor() { return this._actor; },
get _transport() { return this._client._transport; },
-
+
/**
* Remove the breakpoint from the server.
*/
remove: DebuggerClient.requester({
type: "delete"
}, {
telemetry: "DELETE"
}),
-
+
/**
* Determines if this breakpoint has a condition
*/
hasCondition: function() {
let root = this._client.mainRoot;
// XXX bug 990137: We will remove support for client-side handling of
// conditional breakpoints
if (root.traits.conditionalBreakpoints) {
return "condition" in this;
} else {
return "conditionalExpression" in this;
}
},
-
+
/**
* Get the condition of this breakpoint. Currently we have to
* support locally emulated conditional breakpoints until the
* debugger servers are updated (see bug 990137). We used a
* different property when moving it server-side to ensure that we
* are testing the right code.
*/
getCondition: function() {
let root = this._client.mainRoot;
if (root.traits.conditionalBreakpoints) {
return this.condition;
} else {
return this.conditionalExpression;
}
},
-
+
/**
* Set the condition of this breakpoint
*/
setCondition: function(gThreadClient, aCondition, noSliding) {
let root = this._client.mainRoot;
let deferred = promise.defer();
-
+
if (root.traits.conditionalBreakpoints) {
let info = {
line: this.location.line,
column: this.location.column,
condition: aCondition,
noSliding
};
-
+
// Remove the current breakpoint and add a new one with the
// condition.
this.remove(aResponse => {
if (aResponse && aResponse.error) {
deferred.reject(aResponse);
return;
}
-
+
this.source.setBreakpoint(info, (aResponse, aNewBreakpoint) => {
if (aResponse && aResponse.error) {
deferred.reject(aResponse);
} else {
deferred.resolve(aNewBreakpoint);
}
});
});
@@ -13452,126 +13430,126 @@ var Debugger =
if (aCondition === "") {
delete this.conditionalExpression;
}
else {
this.conditionalExpression = aCondition;
}
deferred.resolve(this);
}
-
+
return deferred.promise;
}
};
-
+
eventSource(BreakpointClient.prototype);
-
+
/**
* Environment clients are used to manipulate the lexical environment actors.
*
* @param aClient DebuggerClient
* The debugger client parent.
* @param aForm Object
* The form sent across the remote debugging protocol.
*/
function EnvironmentClient(aClient, aForm) {
this._client = aClient;
this._form = aForm;
this.request = this._client.request;
}
exports.EnvironmentClient = EnvironmentClient;
-
+
EnvironmentClient.prototype = {
-
+
get actor() {
return this._form.actor;
},
get _transport() { return this._client._transport; },
-
+
/**
* Fetches the bindings introduced by this lexical environment.
*/
getBindings: DebuggerClient.requester({
type: "bindings"
}, {
telemetry: "BINDINGS"
}),
-
+
/**
* Changes the value of the identifier whose name is name (a string) to that
* represented by value (a grip).
*/
assign: DebuggerClient.requester({
type: "assign",
name: args(0),
value: args(1)
}, {
telemetry: "ASSIGN"
})
};
-
+
eventSource(EnvironmentClient.prototype);
/***/ },
/* 54 */
/***/ function(module, exports, __webpack_require__) {
/* WEBPACK VAR INJECTION */(function(module) {/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
-
+
module.metadata = {
"stability": "unstable"
};
-
+
const UNCAUGHT_ERROR = 'An error event was emitted for which there was no listener.';
const BAD_LISTENER = 'The event listener must be a function.';
-
+
const { ns } = __webpack_require__(55);
-
+
const event = ns();
-
+
const EVENT_TYPE_PATTERN = /^on([A-Z]\w+$)/;
exports.EVENT_TYPE_PATTERN = EVENT_TYPE_PATTERN;
-
+
// Utility function to access given event `target` object's event listeners for
// the specific event `type`. If listeners for this type does not exists they
// will be created.
const observers = function observers(target, type) {
if (!target) throw TypeError("Event target must be an object");
let listeners = event(target);
return type in listeners ? listeners[type] : listeners[type] = [];
};
-
+
/**
* Registers an event `listener` that is called every time events of
* specified `type` is emitted on the given event `target`.
* @param {Object} target
* Event target object.
* @param {String} type
* The type of event.
* @param {Function} listener
* The listener function that processes the event.
*/
function on(target, type, listener) {
if (typeof(listener) !== 'function')
throw new Error(BAD_LISTENER);
-
+
let listeners = observers(target, type);
if (!~listeners.indexOf(listener))
listeners.push(listener);
}
exports.on = on;
-
-
+
+
var onceWeakMap = new WeakMap();
-
-
+
+
/**
* Registers an event `listener` that is called only the next time an event
* of the specified `type` is emitted on the given event `target`.
* @param {Object} target
* Event target object.
* @param {String} type
* The type of the event.
* @param {Function} listener
@@ -13582,17 +13560,17 @@ var Debugger =
off(target, type, observer);
onceWeakMap.delete(listener);
listener.apply(target, args);
};
onceWeakMap.set(listener, replacement);
on(target, type, replacement);
}
exports.once = once;
-
+
/**
* Execute each of the listeners in order with the supplied arguments.
* All the exceptions that are thrown by listeners during the emit
* are caught and can be handled by listeners of 'error' event. Thrown
* exceptions are passed as an argument to an 'error' event listener.
* If no 'error' listener is registered exception will be logged into an
* error console.
* @param {Object} target
@@ -13601,27 +13579,27 @@ var Debugger =
* The type of event.
* @params {Object|Number|String|Boolean} args
* Arguments that will be passed to listeners.
*/
function emit (target, type, ...args) {
emitOnObject(target, type, target, ...args);
}
exports.emit = emit;
-
+
/**
* A variant of emit that allows setting the this property for event listeners
*/
function emitOnObject(target, type, thisArg, ...args) {
let all = observers(target, '*').length;
let state = observers(target, type);
let listeners = state.slice();
let count = listeners.length;
let index = 0;
-
+
// If error event and there are no handlers (explicit or catch-all)
// then print error message to the console.
if (count === 0 && type === 'error' && all === 0)
console.exception(args[0]);
while (index < count) {