feat(debugger): integrate NX Tcl Remote Debugger into NX Postprocessor
build_and_puplish.yml / build_and_publish (release) Successful in 35s
build_and_puplish.yml / build_and_publish (release) Successful in 35s
Embed the NX Tcl Remote Debugger into the NX Postprocessor extension. Add a new debugging client, protocol, and adapter logic to drive attach/launch, breakpoints, stepping, and evaluation via the runtime adapter. - Introduced a client debugger with a new adapter and protocol - Wired attach/launch, breakpoints, stepping, and evaluation - Updated docs and licensing to reflect the embedded debugger
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
'use strict';
|
||||
|
||||
const { PassThrough } = require('node:stream');
|
||||
const { NxDebugAdapter } = require('./debugAdapter');
|
||||
|
||||
function frameMessage(message) {
|
||||
const json = JSON.stringify(message);
|
||||
return `Content-Length: ${Buffer.byteLength(json, 'utf8')}\r\n\r\n${json}`;
|
||||
}
|
||||
|
||||
class NxInlineDebugAdapter {
|
||||
constructor() {
|
||||
this.input = new PassThrough();
|
||||
this.output = new PassThrough();
|
||||
this.outputBuffer = Buffer.alloc(0);
|
||||
this.listeners = new Set();
|
||||
this.disposed = false;
|
||||
|
||||
this.onDidSendMessage = (listener, thisArgs, disposables) => {
|
||||
const registration = { listener, thisArgs };
|
||||
this.listeners.add(registration);
|
||||
const disposable = {
|
||||
dispose: () => this.listeners.delete(registration),
|
||||
};
|
||||
if (Array.isArray(disposables)) disposables.push(disposable);
|
||||
return disposable;
|
||||
};
|
||||
|
||||
this.output.on('data', (chunk) => this.onOutput(chunk));
|
||||
this.adapter = new NxDebugAdapter(this.input, this.output);
|
||||
}
|
||||
|
||||
handleMessage(message) {
|
||||
if (!this.disposed) this.input.write(frameMessage(message));
|
||||
}
|
||||
|
||||
onOutput(chunk) {
|
||||
this.outputBuffer = Buffer.concat([this.outputBuffer, chunk]);
|
||||
while (true) {
|
||||
const headerEnd = this.outputBuffer.indexOf('\r\n\r\n');
|
||||
if (headerEnd < 0) return;
|
||||
const header = this.outputBuffer.subarray(0, headerEnd).toString('ascii');
|
||||
const match = /Content-Length:\s*(\d+)/i.exec(header);
|
||||
if (!match) throw new Error('missing DAP Content-Length header from NX adapter');
|
||||
const contentLength = Number(match[1]);
|
||||
const messageEnd = headerEnd + 4 + contentLength;
|
||||
if (this.outputBuffer.length < messageEnd) return;
|
||||
|
||||
const payload = this.outputBuffer.subarray(headerEnd + 4, messageEnd).toString('utf8');
|
||||
this.outputBuffer = this.outputBuffer.subarray(messageEnd);
|
||||
const message = JSON.parse(payload);
|
||||
for (const { listener, thisArgs } of [...this.listeners]) {
|
||||
listener.call(thisArgs, message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dispose() {
|
||||
if (this.disposed) return;
|
||||
this.disposed = true;
|
||||
this.adapter.dispose();
|
||||
this.input.end();
|
||||
this.output.destroy();
|
||||
this.listeners.clear();
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { NxInlineDebugAdapter, frameMessage };
|
||||
Reference in New Issue
Block a user