0ad/binaries/data/mods/mod/tools/dap/jsdebugger.js
Dunedan 93ce94655d
Use @stylistic/brace-style for eslint
Up to now `eslint-plugin-brace-rules` was used to enforce a common brace
style for JavaScript code. This plugin was however updated the last time
over 9 years ago and will be incompatible with ESLint v10, as that
[removes `context.getSourceCode()`][1], the plugin relies on.

To keep the eslint config working with ESLint v10, this replaces
`eslint-plugin-brace-rules` with the [`@stylistic/brace-style`][2] rule
from `@stylistic/eslint-plugin`, a package we already use.

While `@stylistic/brace-style` doesn't offer an option to format braces
in exactly the same way as before, the "allman" style seems to be the
one closest to the existing code.

[1]: https://eslint.org/blog/2025/11/eslint-v10.0.0-alpha.0-released/#removed-deprecated-rule-context-members
[2]: https://eslint.style/rules/brace-style
2026-01-12 21:33:52 +01:00

203 lines
4.2 KiB
JavaScript

import { logger } from 'tools/dap/logger.js';
export class JsDebugger
{
constructor()
{
this.debugger = new Debugger();
this.logger = logger.getLogger("SpiderDebugger");
this.events = [];
this.sourcesReferences = [];
this.currentFrame = null;
this.hooks = {
'onDebuggerAttached': [],
'onDebuggerDetached': [],
'onNewGlobalObject': [],
'onDebuggerStatement': [],
'onNewScript': [],
'onEnterFrame': [],
'onUncaughtException': [],
'onStopInFrame': [],
'onRsumeInFrame': [],
};
this.debugger.uncaughtExceptionHook = (e) =>
{
this._runHooks('onUncaughtException', e);
};
this.debugger.onNewGlobalObject = (global) =>
{
this._runHooks('onNewGlobalObject', global);
};
this.debugger.onDebuggerStatement = (frame) =>
{
this._runHooks('onDebuggerStatement', frame);
};
this.debugger.onNewScript = (script, global) =>
{
this._runHooks('onNewScript', { script, global });
};
this.debugger.onEnterFrame = (frame) =>
{
this._runHooks('onEnterFrame', frame);
};
this.debuggerAttached = false;
}
_runHooks(event, data)
{
this.logger.trace(`Running hook for ${event}`);
for (const hookInfo of this.hooks[event])
{
this.logger.trace(`Running hook for ${hookInfo.source}-${event}`);
if (typeof hookInfo.callback !== 'function')
{
this.logger.warn(`Hook for ${event} is not a function: ${hook.source}`);
continue;
}
try
{
hookInfo.callback(data);
}
catch(e)
{
this.logger.error(`Error in hook for ${hookInfo.source}-${event}: ${e.message}`);
this.logger.error(uneval(e.stack));
}
}
}
on(event, callback, source)
{
if (!event || typeof event !== 'string')
{
this.logger.warn('Invalid event name');
return;
}
if (!this.hooks[event])
{
this.logger.warn(`No hooks registered for event: ${event}`);
return;
}
if (!source || typeof source !== 'string')
{
this.logger.warn(`Invalid source name for event ${event}`);
return;
}
if (typeof callback !== 'function')
{
this.logger.warn(`Callback for event ${source}:${event} is not a function`);
return;
}
this.hooks[event].push({ callback, source });
this.logger.debug(`Hook added for event: ${event}`);
}
get instance()
{
return this.debugger;
}
setAttached(attached)
{
this.debuggerAttached = attached;
if (attached)
{
this.logger.debug("Debugger attached");
this._runHooks('onDebuggerAttached', {});
}
else
{
this.logger.debug("Debugger detached");
this._runHooks('onDebuggerDetached', {});
}
}
pushEvent(eventName, eventData, source)
{
if (!eventName || typeof eventName !== 'string')
{
this.logger.warn('Invalid event name');
return;
}
if (source && typeof source !== 'string')
{
this.logger.warn('Invalid source name');
return;
}
this.logger.debug(`Pushing event: ${source}-${eventName}`);
this.events.push({
'type': 'event',
'event': eventName,
'body': eventData
});
}
stopInframe(frame, onHandler)
{
if (!frame || !(frame instanceof Debugger.Frame))
{
this.logger.error('Invalid frame provided to stopInframe');
return;
}
this.currentFrame = frame;
frame.currentLocation = frame.script.getOffsetLocation(frame.offset);
this.logger.debug(`Stop at ${frame.script.url}:${frame.currentLocation.lineNumber}:${frame.currentLocation.columnNumber}`);
this.logger.debug(`Frame type: ${frame.type}`);
if (onHandler && typeof onHandler === 'function')
onHandler();
this._runHooks('onStopInFrame', frame);
Engine.WaitForMessage();
this._runHooks('onRsumeInFrame', frame);
this.logger.debug("Client continue");
}
registerHookName(event, source)
{
if (!event || typeof event !== 'string')
{
this.logger.warn('Invalid event name');
return;
}
if (!source || typeof source !== 'string')
{
this.logger.warn(`Invalid source name for ${event}`);
return;
}
if (this.hooks[event])
{
this.logger.warn(`Hooks already registered for event: ${event}`);
return;
}
this.hooks[event] = [];
this.logger.debug(`Hook registered for event: ${event} from source: ${source}`);
}
triggerHook(event, data)
{
if (!event || typeof event !== 'string')
{
this.logger.warn('Invalid event name');
return;
}
this._runHooks(event, data);
}
}