diff --git a/.gitignore b/.gitignore index 411fe4011..7831aa60d 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,7 @@ .vscode !.vscode/launch.json !.vscode/tasks.json +!browser-ext/lib # output node_modules @@ -27,4 +28,4 @@ TestResults TestLogs .DS_Store .mono -**/*.DotSettings.user \ No newline at end of file +**/*.DotSettings.user diff --git a/browser-ext/lib/dap-protocol.js b/browser-ext/lib/dap-protocol.js new file mode 100644 index 000000000..9f75e320c --- /dev/null +++ b/browser-ext/lib/dap-protocol.js @@ -0,0 +1,226 @@ +/** + * DAP Protocol Helpers + * + * Type definitions and utilities for the Debug Adapter Protocol. + * Used by both content and background scripts. + */ + +// DAP Request Commands +const DapCommands = { + // Lifecycle + INITIALIZE: 'initialize', + ATTACH: 'attach', + CONFIGURATION_DONE: 'configurationDone', + DISCONNECT: 'disconnect', + + // Execution Control + CONTINUE: 'continue', + NEXT: 'next', + STEP_IN: 'stepIn', + STEP_OUT: 'stepOut', + PAUSE: 'pause', + TERMINATE: 'terminate', + + // Reverse Execution + STEP_BACK: 'stepBack', + REVERSE_CONTINUE: 'reverseContinue', + + // Information + THREADS: 'threads', + STACK_TRACE: 'stackTrace', + SCOPES: 'scopes', + VARIABLES: 'variables', + SOURCE: 'source', + + // Evaluation + EVALUATE: 'evaluate', + SET_VARIABLE: 'setVariable', + + // Breakpoints + SET_BREAKPOINTS: 'setBreakpoints', + SET_FUNCTION_BREAKPOINTS: 'setFunctionBreakpoints', + SET_EXCEPTION_BREAKPOINTS: 'setExceptionBreakpoints', +}; + +// DAP Event Types +const DapEvents = { + // Lifecycle + INITIALIZED: 'initialized', + TERMINATED: 'terminated', + EXITED: 'exited', + + // Execution + STOPPED: 'stopped', + CONTINUED: 'continued', + + // Output + OUTPUT: 'output', + + // Other + THREAD: 'thread', + BREAKPOINT: 'breakpoint', + MODULE: 'module', + LOADED_SOURCE: 'loadedSource', + PROCESS: 'process', + CAPABILITIES: 'capabilities', + PROGRESS_START: 'progressStart', + PROGRESS_UPDATE: 'progressUpdate', + PROGRESS_END: 'progressEnd', + INVALIDATED: 'invalidated', + MEMORY: 'memory', +}; + +// Stopped Event Reasons +const StoppedReasons = { + STEP: 'step', + BREAKPOINT: 'breakpoint', + EXCEPTION: 'exception', + PAUSE: 'pause', + ENTRY: 'entry', + GOTO: 'goto', + FUNCTION_BREAKPOINT: 'function breakpoint', + DATA_BREAKPOINT: 'data breakpoint', + INSTRUCTION_BREAKPOINT: 'instruction breakpoint', +}; + +// Output Categories +const OutputCategories = { + CONSOLE: 'console', + IMPORTANT: 'important', + STDOUT: 'stdout', + STDERR: 'stderr', + TELEMETRY: 'telemetry', +}; + +// Evaluate Contexts +const EvaluateContexts = { + WATCH: 'watch', + REPL: 'repl', + HOVER: 'hover', + CLIPBOARD: 'clipboard', + VARIABLES: 'variables', +}; + +/** + * Create a DAP request message + * + * @param {number} seq - Sequence number + * @param {string} command - DAP command name + * @param {object} args - Command arguments + * @returns {object} DAP request message + */ +function createDapRequest(seq, command, args = {}) { + return { + seq, + type: 'request', + command, + arguments: args, + }; +} + +/** + * Create a DAP response message + * + * @param {number} seq - Sequence number + * @param {number} requestSeq - Original request sequence number + * @param {string} command - DAP command name + * @param {boolean} success - Whether request succeeded + * @param {object} body - Response body + * @param {string} message - Error message (if success is false) + * @returns {object} DAP response message + */ +function createDapResponse(seq, requestSeq, command, success, body = {}, message = '') { + return { + seq, + type: 'response', + request_seq: requestSeq, + command, + success, + body, + message: success ? undefined : message, + }; +} + +/** + * Create a DAP event message + * + * @param {number} seq - Sequence number + * @param {string} event - Event type + * @param {object} body - Event body + * @returns {object} DAP event message + */ +function createDapEvent(seq, event, body = {}) { + return { + seq, + type: 'event', + event, + body, + }; +} + +/** + * Parse a DAP message + * + * @param {string|object} message - JSON string or parsed object + * @returns {object} Parsed message with helper properties + */ +function parseDapMessage(message) { + const msg = typeof message === 'string' ? JSON.parse(message) : message; + + return { + raw: msg, + isRequest: msg.type === 'request', + isResponse: msg.type === 'response', + isEvent: msg.type === 'event', + seq: msg.seq, + requestSeq: msg.request_seq, + command: msg.command, + event: msg.event, + success: msg.success, + body: msg.body || {}, + message: msg.message, + }; +} + +/** + * Check if a message indicates a capability + * + * @param {object} capabilities - Capabilities object from initialize response + * @param {string} name - Capability name + * @returns {boolean} + */ +function hasCapability(capabilities, name) { + return capabilities && capabilities[name] === true; +} + +// Export for use in other modules +if (typeof module !== 'undefined' && module.exports) { + module.exports = { + DapCommands, + DapEvents, + StoppedReasons, + OutputCategories, + EvaluateContexts, + createDapRequest, + createDapResponse, + createDapEvent, + parseDapMessage, + hasCapability, + }; +} + +// Make available globally for browser scripts +if (typeof window !== 'undefined') { + window.DapProtocol = { + DapCommands, + DapEvents, + StoppedReasons, + OutputCategories, + EvaluateContexts, + createDapRequest, + createDapResponse, + createDapEvent, + parseDapMessage, + hasCapability, + }; +}