"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.DebugServer = undefined; 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; }; }(); /** * Copyright (c) 2017-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ var _BreakpointManager = require("./BreakpointManager.js"); var _invariant = require("../common/invariant.js"); var _invariant2 = _interopRequireDefault(_invariant); var _DebugMessage = require("./../common/channel/DebugMessage.js"); var _DebuggerError = require("./../common/DebuggerError.js"); var _realm = require("./../../realm.js"); var _VariableManager = require("./VariableManager.js"); var _SteppingManager = require("./SteppingManager.js"); var _StopEventManager = require("./StopEventManager.js"); var _environment = require("./../../environment.js"); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } var DebugServer = exports.DebugServer = function () { function DebugServer(channel, realm) { _classCallCheck(this, DebugServer); this._channel = channel; this._realm = realm; this._breakpointManager = new _BreakpointManager.BreakpointManager(); this._variableManager = new _VariableManager.VariableManager(realm); this._stepManager = new _SteppingManager.SteppingManager(this._realm, /* default discard old steppers */false); this._stopEventManager = new _StopEventManager.StopEventManager(); this.waitForRun(undefined); } // the collection of breakpoints // the channel to communicate with the adapter _createClass(DebugServer, [{ key: "waitForRun", /* Block until adapter says to run /* ast: the current ast node we are stopped on /* reason: the reason the debuggee is stopping */ value: function waitForRun(ast) { var keepRunning = false; var request = void 0; while (!keepRunning) { request = this._channel.readIn(); keepRunning = this.processDebuggerCommand(request, ast); } } // Checking if the debugger needs to take any action on reaching this ast node }, { key: "checkForActions", value: function checkForActions(ast) { if (this._checkAndUpdateLastExecuted(ast)) { var stoppables = this._stepManager.getAndDeleteCompletedSteppers(ast); var breakpoint = this._breakpointManager.getStoppableBreakpoint(ast); if (breakpoint) stoppables.push(breakpoint); var reason = this._stopEventManager.getDebuggeeStopReason(ast, stoppables); if (reason) { (0, _invariant2.default)(ast.loc && ast.loc.source); this._channel.sendStoppedResponse(reason, ast.loc.source, ast.loc.start.line, ast.loc.start.column); this.waitForRun(ast); } } } // Process a command from a debugger. Returns whether Prepack should unblock // if it is blocked }, { key: "processDebuggerCommand", value: function processDebuggerCommand(request, ast) { var requestID = request.id; var command = request.command; var args = request.arguments; switch (command) { case _DebugMessage.DebugMessage.BREAKPOINT_ADD_COMMAND: (0, _invariant2.default)(args.kind === "breakpoint"); this._breakpointManager.addBreakpointMulti(args.breakpoints); this._channel.sendBreakpointsAcknowledge(_DebugMessage.DebugMessage.BREAKPOINT_ADD_ACKNOWLEDGE, requestID, args); break; case _DebugMessage.DebugMessage.BREAKPOINT_REMOVE_COMMAND: (0, _invariant2.default)(args.kind === "breakpoint"); this._breakpointManager.removeBreakpointMulti(args.breakpoints); this._channel.sendBreakpointsAcknowledge(_DebugMessage.DebugMessage.BREAKPOINT_REMOVE_ACKNOWLEDGE, requestID, args); break; case _DebugMessage.DebugMessage.BREAKPOINT_ENABLE_COMMAND: (0, _invariant2.default)(args.kind === "breakpoint"); this._breakpointManager.enableBreakpointMulti(args.breakpoints); this._channel.sendBreakpointsAcknowledge(_DebugMessage.DebugMessage.BREAKPOINT_ENABLE_ACKNOWLEDGE, requestID, args); break; case _DebugMessage.DebugMessage.BREAKPOINT_DISABLE_COMMAND: (0, _invariant2.default)(args.kind === "breakpoint"); this._breakpointManager.disableBreakpointMulti(args.breakpoints); this._channel.sendBreakpointsAcknowledge(_DebugMessage.DebugMessage.BREAKPOINT_DISABLE_ACKNOWLEDGE, requestID, args); break; case _DebugMessage.DebugMessage.PREPACK_RUN_COMMAND: (0, _invariant2.default)(args.kind === "run"); this._onDebuggeeResume(); return true; case _DebugMessage.DebugMessage.STACKFRAMES_COMMAND: (0, _invariant2.default)(args.kind === "stackframe"); this.processStackframesCommand(requestID, args, ast); break; case _DebugMessage.DebugMessage.SCOPES_COMMAND: (0, _invariant2.default)(args.kind === "scopes"); this.processScopesCommand(requestID, args); break; case _DebugMessage.DebugMessage.VARIABLES_COMMAND: (0, _invariant2.default)(args.kind === "variables"); this.processVariablesCommand(requestID, args); break; case _DebugMessage.DebugMessage.STEPINTO_COMMAND: (0, _invariant2.default)(ast !== undefined); this._stepManager.processStepCommand("in", ast); this._onDebuggeeResume(); return true; case _DebugMessage.DebugMessage.STEPOVER_COMMAND: (0, _invariant2.default)(ast !== undefined); this._stepManager.processStepCommand("over", ast); this._onDebuggeeResume(); return true; case _DebugMessage.DebugMessage.EVALUATE_COMMAND: (0, _invariant2.default)(args.kind === "evaluate"); this.processEvaluateCommand(requestID, args); break; default: throw new _DebuggerError.DebuggerError("Invalid command", "Invalid command from adapter: " + command); } return false; } }, { key: "processStackframesCommand", value: function processStackframesCommand(requestID, args, ast) { var frameInfos = []; var loc = this._getFrameLocation(ast ? ast.loc : null); var fileName = loc.fileName; var line = loc.line; var column = loc.column; // the UI displays the current frame as index 0, so we iterate backwards // from the current frame for (var i = this._realm.contextStack.length - 1; i >= 0; i--) { var frame = this._realm.contextStack[i]; var functionName = "(anonymous function)"; if (frame.function && frame.function.__originalName) { functionName = frame.function.__originalName; } var frameInfo = { id: this._realm.contextStack.length - 1 - i, functionName: functionName, fileName: fileName, line: line, column: column }; frameInfos.push(frameInfo); loc = this._getFrameLocation(frame.loc); fileName = loc.fileName; line = loc.line; column = loc.column; } this._channel.sendStackframeResponse(requestID, frameInfos); } }, { key: "_getFrameLocation", value: function _getFrameLocation(loc) { var fileName = "unknown"; var line = 0; var column = 0; if (loc && loc.source) { fileName = loc.source; line = loc.start.line; column = loc.start.column; } return { fileName: fileName, line: line, column: column }; } }, { key: "processScopesCommand", value: function processScopesCommand(requestID, args) { // first check that frameId is in the valid range if (args.frameId < 0 || args.frameId >= this._realm.contextStack.length) { throw new _DebuggerError.DebuggerError("Invalid command", "Invalid frame id for scopes request: " + args.frameId); } // here the frameId is in reverse order of the contextStack, ie frameId 0 // refers to last element of contextStack var stackIndex = this._realm.contextStack.length - 1 - args.frameId; var context = this._realm.contextStack[stackIndex]; (0, _invariant2.default)(context instanceof _realm.ExecutionContext); var scopes = []; var lexicalEnv = context.lexicalEnvironment; while (lexicalEnv) { var scope = { name: this._getScopeName(lexicalEnv.environmentRecord), // key used by UI to retrieve variables in this scope variablesReference: this._variableManager.getReferenceForValue(lexicalEnv), // the variables are easy to retrieve expensive: false }; scopes.push(scope); lexicalEnv = lexicalEnv.parent; } this._channel.sendScopesResponse(requestID, scopes); } }, { key: "_getScopeName", value: function _getScopeName(envRec) { if (envRec instanceof _environment.GlobalEnvironmentRecord) { return "Global"; } else if (envRec instanceof _environment.DeclarativeEnvironmentRecord) { if (envRec instanceof _environment.FunctionEnvironmentRecord) { return "Local: " + (envRec.$FunctionObject.__originalName || "anonymous function"); } else { return "Block"; } } else if (envRec instanceof _environment.ObjectEnvironmentRecord) { return "With"; } else { (0, _invariant2.default)(false, "Invalid type of environment record"); } } }, { key: "processVariablesCommand", value: function processVariablesCommand(requestID, args) { var variables = this._variableManager.getVariablesByReference(args.variablesReference); this._channel.sendVariablesResponse(requestID, variables); } }, { key: "processEvaluateCommand", value: function processEvaluateCommand(requestID, args) { var evalResult = this._variableManager.evaluate(args.frameId, args.expression); this._channel.sendEvaluateResponse(requestID, evalResult); } // actions that need to happen before Prepack can resume }, { key: "_onDebuggeeResume", value: function _onDebuggeeResume() { // resets the variable manager this._variableManager.clean(); } }, { key: "_checkAndUpdateLastExecuted", value: function _checkAndUpdateLastExecuted(ast) { if (ast.loc && ast.loc.source) { var filePath = ast.loc.source; var line = ast.loc.start.line; var column = ast.loc.start.column; // check if the current location is same as the last one if (this._lastExecuted && filePath === this._lastExecuted.filePath && line === this._lastExecuted.line && column === this._lastExecuted.column) { return false; } this._lastExecuted = { filePath: filePath, line: line, column: column }; return true; } return false; } }, { key: "shutdown", value: function shutdown() { // clean the channel pipes this._channel.shutdown(); } }]); return DebugServer; }(); //# sourceMappingURL=Debugger.js.map