atom-nuclide
Version:
A unified developer experience for web and mobile development, built as a suite of features on top of Atom to provide hackability and the support of an active community.
361 lines (302 loc) • 13.5 kB
JavaScript
Object.defineProperty(exports, '__esModule', {
value: true
});
var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; desc = parent = undefined; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } };
function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { var callNext = step.bind(null, 'next'); var callThrow = step.bind(null, 'throw'); function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(callNext, callThrow); } } callNext(); }); }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
/*
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the license found in the LICENSE file in
* the root directory of this source tree.
*/
var _assert2;
function _assert() {
return _assert2 = _interopRequireDefault(require('assert'));
}
var _settings2;
function _settings() {
return _settings2 = require('./settings');
}
var _utils2;
function _utils() {
return _utils2 = require('./utils');
}
var _utils4;
function _utils3() {
return _utils4 = _interopRequireDefault(require('./utils'));
}
var _helpers2;
function _helpers() {
return _helpers2 = require('./helpers');
}
var _Handler2;
function _Handler() {
return _Handler2 = _interopRequireDefault(require('./Handler'));
}
var _frame2;
function _frame() {
return _frame2 = require('./frame');
}
var _DbgpSocket2;
function _DbgpSocket() {
return _DbgpSocket2 = require('./DbgpSocket');
}
var _FileCache2;
function _FileCache() {
return _FileCache2 = _interopRequireDefault(require('./FileCache'));
}
var _events2;
function _events() {
return _events2 = require('events');
}
var _eventKit2;
function _eventKit() {
return _eventKit2 = require('event-kit');
}
var SESSION_END_EVENT = 'session-end-event';
// Handles all 'Debug.*' Chrome dev tools messages
var DebuggerHandler = (function (_default) {
_inherits(DebuggerHandler, _default);
function DebuggerHandler(clientCallback, connectionMultiplexer) {
_classCallCheck(this, DebuggerHandler);
_get(Object.getPrototypeOf(DebuggerHandler.prototype), 'constructor', this).call(this, 'Debugger', clientCallback);
this._hadFirstContinuationCommand = false;
this._connectionMultiplexer = connectionMultiplexer;
this._files = new (_FileCache2 || _FileCache()).default(clientCallback);
this._emitter = new (_events2 || _events()).EventEmitter();
this._subscriptions = new (_eventKit2 || _eventKit()).CompositeDisposable(this._connectionMultiplexer.onStatus(this._onStatusChanged.bind(this)), this._connectionMultiplexer.onNotification(this._onNotification.bind(this)));
}
_createClass(DebuggerHandler, [{
key: 'onSessionEnd',
value: function onSessionEnd(callback) {
(_utils4 || _utils3()).default.log('onSessionEnd');
this._emitter.on(SESSION_END_EVENT, callback);
}
}, {
key: 'handleMethod',
value: _asyncToGenerator(function* (id, method, params) {
switch (method) {
// TODO: Add Console (aka logging) support
case 'enable':
this._debuggerEnable(id);
break;
case 'pause':
yield this._sendBreakCommand(id);
break;
case 'stepInto':
this._sendContinuationCommand((_DbgpSocket2 || _DbgpSocket()).COMMAND_STEP_INTO);
break;
case 'stepOut':
this._sendContinuationCommand((_DbgpSocket2 || _DbgpSocket()).COMMAND_STEP_OUT);
break;
case 'stepOver':
this._sendContinuationCommand((_DbgpSocket2 || _DbgpSocket()).COMMAND_STEP_OVER);
break;
case 'resume':
this._sendContinuationCommand((_DbgpSocket2 || _DbgpSocket()).COMMAND_RUN);
break;
case 'setPauseOnExceptions':
yield this._setPauseOnExceptions(id, params);
break;
case 'setAsyncCallStackDepth':
case 'skipStackFrames':
this.replyWithError(id, 'Not implemented');
break;
case 'getScriptSource':
// TODO: Handle file read errors.
// TODO: Handle non-file scriptIds
this.replyToCommand(id, { scriptSource: yield this._files.getFileSource(params.scriptId) });
break;
case 'setBreakpointByUrl':
this._setBreakpointByUrl(id, params);
break;
case 'removeBreakpoint':
yield this._removeBreakpoint(id, params);
break;
case 'evaluateOnCallFrame':
var compatParams = (0, (_utils2 || _utils()).makeExpressionHphpdCompatible)(params);
var result = yield this._connectionMultiplexer.evaluateOnCallFrame(Number(compatParams.callFrameId), compatParams.expression);
this.replyToCommand(id, result);
break;
case 'setDebuggerSettings':
(0, (_settings2 || _settings()).updateSettings)(params);
break;
default:
this.unknownMethod(id, method, params);
break;
}
})
}, {
key: '_setPauseOnExceptions',
value: _asyncToGenerator(function* (id, params) {
var state = params.state;
yield this._connectionMultiplexer.getBreakpointStore().setPauseOnExceptions(String(id), state);
this.replyToCommand(id, {});
})
}, {
key: '_setBreakpointByUrl',
value: _asyncToGenerator(function* (id, params) {
var lineNumber = params.lineNumber;
var url = params.url;
var columnNumber = params.columnNumber;
var condition = params.condition;
if (!url || columnNumber !== 0) {
this.replyWithError(id, 'Invalid arguments to Debugger.setBreakpointByUrl: ' + JSON.stringify(params));
return;
}
this._files.registerFile(url);
var path = (0, (_helpers2 || _helpers()).uriToPath)(url);
var breakpointStore = this._connectionMultiplexer.getBreakpointStore();
// Chrome lineNumber is 0-based while xdebug lineno is 1-based.
var breakpointId = yield breakpointStore.setFileLineBreakpoint(String(id), path, lineNumber + 1, condition);
var breakpoint = yield breakpointStore.getBreakpoint(breakpointId);
(0, (_assert2 || _assert()).default)(breakpoint != null);
this.replyToCommand(id, {
breakpointId: breakpointId,
resolved: breakpoint.resolved,
locations: [(0, (_helpers2 || _helpers()).getBreakpointLocation)(breakpoint)]
});
})
}, {
key: '_removeBreakpoint',
value: _asyncToGenerator(function* (id, params) {
var breakpointId = params.breakpointId;
yield this._connectionMultiplexer.removeBreakpoint(breakpointId);
this.replyToCommand(id, { id: breakpointId });
})
}, {
key: '_debuggerEnable',
value: function _debuggerEnable(id) {
this.replyToCommand(id, {});
this._sendFakeLoaderBreakpoint();
}
}, {
key: '_getStackFrames',
value: _asyncToGenerator(function* () {
var _this = this;
var frames = yield this._connectionMultiplexer.getStackFrames();
return yield Promise.all(frames.stack.map(function (frame, frameIndex) {
return _this._convertFrame(frame, frameIndex);
}));
})
}, {
key: '_convertFrame',
value: _asyncToGenerator(function* (frame, frameIndex) {
(_utils4 || _utils3()).default.log('Converting frame: ' + JSON.stringify(frame));
var file = this._files.registerFile((0, (_frame2 || _frame()).fileUrlOfFrame)(frame));
var location = (0, (_frame2 || _frame()).locationOfFrame)(frame);
var hasSource = yield file.hasSource();
if (!hasSource) {
location.scriptId = '';
}
return {
callFrameId: (0, (_frame2 || _frame()).idOfFrame)(frame),
functionName: (0, (_frame2 || _frame()).functionOfFrame)(frame),
location: location,
scopeChain: yield this._connectionMultiplexer.getScopesForFrame(frameIndex)
};
})
}, {
key: '_sendContinuationCommand',
value: function _sendContinuationCommand(command) {
if (!this._hadFirstContinuationCommand) {
this._hadFirstContinuationCommand = true;
this.sendMethod('Debugger.resumed');
this._connectionMultiplexer.listen();
return;
}
(_utils4 || _utils3()).default.log('Sending continuation command: ' + command);
this._connectionMultiplexer.sendContinuationCommand(command);
}
}, {
key: '_sendBreakCommand',
value: _asyncToGenerator(function* (id) {
var response = yield this._connectionMultiplexer.sendBreakCommand();
if (!response) {
this.replyWithError(id, 'Unable to break');
}
})
}, {
key: '_onStatusChanged',
value: _asyncToGenerator(function* (status, params) {
(_utils4 || _utils3()).default.log('Sending status: ' + status);
switch (status) {
case (_DbgpSocket2 || _DbgpSocket()).STATUS_BREAK:
yield this._sendPausedMessage();
break;
case (_DbgpSocket2 || _DbgpSocket()).STATUS_RUNNING:
this.sendMethod('Debugger.resumed');
break;
case (_DbgpSocket2 || _DbgpSocket()).STATUS_STOPPED:
case (_DbgpSocket2 || _DbgpSocket()).STATUS_ERROR:
case (_DbgpSocket2 || _DbgpSocket()).STATUS_END:
this._endSession();
break;
case (_DbgpSocket2 || _DbgpSocket()).STATUS_STARTING:
case (_DbgpSocket2 || _DbgpSocket()).STATUS_STOPPING:
// These two should be hidden by the ConnectionMultiplexer
break;
default:
(_utils4 || _utils3()).default.logErrorAndThrow('Unexpected status: ' + status);
}
})
}, {
key: '_onNotification',
value: _asyncToGenerator(function* (notifyName, params) {
switch (notifyName) {
case (_DbgpSocket2 || _DbgpSocket()).BREAKPOINT_RESOLVED_NOTIFICATION:
(0, (_assert2 || _assert()).default)(params);
var breakpoint = params;
this.sendMethod('Debugger.breakpointResolved', {
breakpointId: breakpoint.chromeId,
location: (0, (_helpers2 || _helpers()).getBreakpointLocation)(breakpoint)
});
break;
default:
(_utils4 || _utils3()).default.logErrorAndThrow('Unexpected notification: ' + notifyName);
}
})
// May only call when in paused state.
}, {
key: '_sendPausedMessage',
value: _asyncToGenerator(function* () {
var requestSwitchMessage = this._connectionMultiplexer.getRequestSwitchMessage();
this._connectionMultiplexer.resetRequestSwitchMessage();
if (requestSwitchMessage != null) {
this.sendUserMessage('outputWindow', {
level: 'info',
text: requestSwitchMessage
});
}
this.sendMethod('Debugger.paused', {
callFrames: yield this._getStackFrames(),
reason: 'breakpoint', // TODO: better reason?
threadSwitchMessage: requestSwitchMessage,
data: {}
});
})
}, {
key: '_sendFakeLoaderBreakpoint',
value: function _sendFakeLoaderBreakpoint() {
this.sendMethod('Debugger.paused', {
callFrames: [],
reason: 'breakpoint', // TODO: better reason?
data: {}
});
}
}, {
key: '_endSession',
value: function _endSession() {
(_utils4 || _utils3()).default.log('DebuggerHandler: Ending session');
this._subscriptions.dispose();
this._emitter.emit(SESSION_END_EVENT);
}
}]);
return DebuggerHandler;
})((_Handler2 || _Handler()).default);
exports.DebuggerHandler = DebuggerHandler;