import AsyncActionQueue from '../AsyncActionQueue'; const EventEmitter = require('events'); class UndoQueue { // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied private inner_: any[] = []; private size_ = 20; public pop() { return this.inner_.pop(); } // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied public push(e: any) { this.inner_.push(e); while (this.length > this.size_) { this.inner_.splice(0, 1); } } public get length(): number { return this.inner_.length; } // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied public at(index: number): any { return this.inner_[index]; } } export default class UndoRedoService { private pushAsyncQueue: AsyncActionQueue = new AsyncActionQueue(700); private undoStates: UndoQueue = new UndoQueue(); private redoStates: UndoQueue = new UndoQueue(); // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied private eventEmitter: any = new EventEmitter(); private isUndoing = false; public constructor() { this.push = this.push.bind(this); } // eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied public on(eventName: string, callback: Function) { return this.eventEmitter.on(eventName, callback); } // eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied public off(eventName: string, callback: Function) { return this.eventEmitter.removeListener(eventName, callback); } // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied public push(state: any) { this.undoStates.push(state); this.redoStates = new UndoQueue(); this.eventEmitter.emit('stackChange'); } // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied public schedulePush(state: any) { this.pushAsyncQueue.push(async () => { this.push(state); }); } // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied public async undo(redoState: any) { if (this.isUndoing) return; if (!this.canUndo) throw new Error('Nothing to undo'); this.isUndoing = true; await this.pushAsyncQueue.processAllNow(); const state = this.undoStates.pop(); this.redoStates.push(redoState); this.eventEmitter.emit('stackChange'); this.isUndoing = false; return state; } // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied public async redo(undoState: any) { if (this.isUndoing) return; if (!this.canRedo) throw new Error('Nothing to redo'); this.isUndoing = true; await this.pushAsyncQueue.processAllNow(); const state = this.redoStates.pop(); this.undoStates.push(undoState); this.eventEmitter.emit('stackChange'); this.isUndoing = false; return state; } public async reset() { this.undoStates = new UndoQueue(); this.redoStates = new UndoQueue(); this.isUndoing = false; const output = this.pushAsyncQueue.reset(); this.eventEmitter.emit('stackChange'); return output; } public get canUndo(): boolean { return !!this.undoStates.length; } public get canRedo(): boolean { return !!this.redoStates.length; } }