98 lines
10 KiB
Markdown
98 lines
10 KiB
Markdown
# @suaveplan/undo - Enterprise-grade undo/redo engine with branching history, async commands, history compression, selective undo, and command merging
|
|
|
|
## Summary
|
|
|
|
Enterprise-grade undo/redo engine with branching history, async commands, history compression, selective undo, and command merging. Built for collaborative editors, document tools, and any application requiring robust, reversible state management.
|
|
|
|
<!-- begin:auto-docs -->
|
|
## Documentation tree
|
|
|
|
- [async-command](./src/async/async-command.md) — Provides factory functions and execution helpers for asynchronous commands in `@suaveplan/undo`. Async commands follow…
|
|
- [async-stack](./src/async/async-stack.md) — Implements `AsyncUndoStack<T>`, the asynchronous counterpart to `UndoStack<T>`. All mutation methods (`push`, `undo`, `…
|
|
- [branch](./src/branch/branch.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
|
- [branch](./src/branch/branch.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
|
- [command](./src/command/command.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
|
- [command](./src/command/command.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
|
- [compression](./src/compression/history-compressor.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
|
- [history-compressor](./src/compression/history-compressor.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
|
- [errors](./src/errors/undo-error.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
|
- [undo-error](./src/errors/undo-error.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
|
- [merge](./src/merge/command-merger.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
|
- [command-merger](./src/merge/command-merger.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
|
- [schemas](./src/schemas/undo.schemas.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
|
- [undo.schemas](./src/schemas/undo.schemas.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
|
- [selective](./src/selective/selective-undo.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
|
- [selective-undo](./src/selective/selective-undo.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
|
- [stack](./src/stack/stack.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
|
- [stack](./src/stack/stack.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
|
<!-- end:auto-docs --> - [branch](./src/branch/branch.md) — <!-- begin:auto-docs --> _(no submodules)_- [command](./src/command/command.md) — <!-- begin:auto-docs --> _(no submodules)_- [command](./src/command/command.md) — <!-- begin:auto-docs --> _(no submodules)_- [compression](./src/compression/history-compressor.md) — <!-- begin:auto-docs --> _(no submodules)_- [history-compressor](./src/compression/history-compressor.md) — <!-- begin:auto-docs --> _(no submodules)_- [errors](./src/errors/undo-error.md) — <!-- begin:auto-docs --> _(no submodules)_- [undo-error](./src/errors/undo-error.md) — <!-- begin:auto-docs --> _(no submodules)_- [merge](./src/merge/command-merger.md) — <!-- begin:auto-docs --> _(no submodules)_- [command-merger](./src/merge/command-merger.md) — <!-- begin:auto-docs --> _(no submodules)_- [schemas](./src/schemas/undo.schemas.md) — <!-- begin:auto-docs --> _(no submodules)_- [undo.schemas](./src/schemas/undo.schemas.md) — <!-- begin:auto-docs --> _(no submodules)_- [selective](./src/selective/selective-undo.md) — <!-- begin:auto-docs --> _(no submodules)_- [selective-undo](./src/selective/selective-undo.md) — <!-- begin:auto-docs --> _(no submodules)_- [stack](./src/stack/stack.md) — <!-- begin:auto-docs --> _(no submodules)_- [stack](./src/stack/stack.md) — <!-- begin:auto-docs --> _(no submodules)_- [branch](./src/branch/branch.md) — <!-- begin:auto-docs --> _(no submodules)_- [command](./src/command/command.md) — <!-- begin:auto-docs --> _(no submodules)_- [command](./src/command/command.md) — <!-- begin:auto-docs --> _(no submodules)_- [compression](./src/compression/history-compressor.md) — <!-- begin:auto-docs --> _(no submodules)_- [history-compressor](./src/compression/history-compressor.md) — <!-- begin:auto-docs --> _(no submodules)_- [errors](./src/errors/undo-error.md) — <!-- begin:auto-docs --> _(no submodules)_- [undo-error](./src/errors/undo-error.md) — <!-- begin:auto-docs --> _(no submodules)_- [merge](./src/merge/command-merger.md) — <!-- begin:auto-docs --> _(no submodules)_- [command-merger](./src/merge/command-merger.md) — <!-- begin:auto-docs --> _(no submodules)_- [schemas](./src/schemas/undo.schemas.md) — <!-- begin:auto-docs --> _(no submodules)_- [undo.schemas](./src/schemas/undo.schemas.md) — <!-- begin:auto-docs --> _(no submodules)_- [selective](./src/selective/selective-undo.md) — <!-- begin:auto-docs --> _(no submodules)_- [selective-undo](./src/selective/selective-undo.md) — <!-- begin:auto-docs --> _(no submodules)_- [stack](./src/stack/stack.md) — <!-- begin:auto-docs --> _(no submodules)_- [stack](./src/stack/stack.md) — <!-- begin:auto-docs --> _(no submodules)_- [branch](./src/branch/branch.md) — <!-- begin:auto-docs --> _(no submodules)_- [command](./src/command/command.md) — <!-- begin:auto-docs --> _(no submodules)_- [command](./src/command/command.md) — <!-- begin:auto-docs --> _(no submodules)_- [compression](./src/compression/history-compressor.md) — <!-- begin:auto-docs --> _(no submodules)_- [history-compressor](./src/compression/history-compressor.md) — <!-- begin:auto-docs --> _(no submodules)_- [errors](./src/errors/undo-error.md) — <!-- begin:auto-docs --> _(no submodules)_- [undo-error](./src/errors/undo-error.md) — <!-- begin:auto-docs --> _(no submodules)_- [merge](./src/merge/command-merger.md) — <!-- begin:auto-docs --> _(no submodules)_- [command-merger](./src/merge/command-merger.md) — <!-- begin:auto-docs --> _(no submodules)_- [schemas](./src/schemas/undo.schemas.md) — <!-- begin:auto-docs --> _(no submodules)_- [undo.schemas](./src/schemas/undo.schemas.md) — <!-- begin:auto-docs --> _(no submodules)_- [selective](./src/selective/selective-undo.md) — <!-- begin:auto-docs --> _(no submodules)_- [selective-undo](./src/selective/selective-undo.md) — <!-- begin:auto-docs --> _(no submodules)_- [stack](./src/stack/stack.md) — <!-- begin:auto-docs --> _(no submodules)_- [stack](./src/stack/stack.md) — <!-- begin:auto-docs --> _(no submodules)_- [branch](./src/branch/branch.md) — <!-- begin:auto-docs --> _(no submodules)_- [command](./src/command/command.md) — <!-- begin:auto-docs --> _(no submodules)_ - [command](./src/command/command.md) — <!-- begin:auto-docs --> _(no submodules)_- [compression](./src/compression/history-compressor.md) — <!-- begin:auto-docs --> _(no submodules)_ - [history-compressor](./src/compression/history-compressor.md) — <!-- begin:auto-docs --> _(no submodules)_- [errors](./src/errors/undo-error.md) — <!-- begin:auto-docs --> _(no submodules)_ - [undo-error](./src/errors/undo-error.md) — <!-- begin:auto-docs --> _(no submodules)_- [merge](./src/merge/command-merger.md) — <!-- begin:auto-docs --> _(no submodules)_ - [command-merger](./src/merge/command-merger.md) — <!-- begin:auto-docs --> _(no submodules)_- [schemas](./src/schemas/undo.schemas.md) — <!-- begin:auto-docs --> _(no submodules)_ - [undo.schemas](./src/schemas/undo.schemas.md) — <!-- begin:auto-docs --> _(no submodules)_- [selective](./src/selective/selective-undo.md) — <!-- begin:auto-docs --> _(no submodules)_ - [selective-undo](./src/selective/selective-undo.md) — <!-- begin:auto-docs --> _(no submodules)_- [stack](./src/stack/stack.md) — <!-- begin:auto-docs --> _(no submodules)_ - [stack](./src/stack/stack.md) — <!-- begin:auto-docs --> _(no submodules)_
|
|
## Install
|
|
|
|
```bash
|
|
bun add @suaveplan/undo
|
|
```
|
|
|
|
## Quick Start
|
|
|
|
```ts
|
|
import { UndoStack, createCommand } from "@suaveplan/undo";
|
|
|
|
interface Counter { value: number }
|
|
|
|
const stack = new UndoStack<Counter>({ value: 0 });
|
|
|
|
const inc = createCommand(
|
|
"Increment",
|
|
(s) => ({ value: s.value + 1 }),
|
|
(s) => ({ value: s.value - 1 }),
|
|
);
|
|
|
|
stack.push(inc);
|
|
console.log(stack.current.value); // 1
|
|
stack.undo();
|
|
console.log(stack.current.value); // 0
|
|
stack.redo();
|
|
console.log(stack.current.value); // 1
|
|
```
|
|
|
|
### Branching History
|
|
|
|
```ts
|
|
import { BranchingHistory, createCommand } from "@suaveplan/undo";
|
|
|
|
const h = new BranchingHistory({ value: 0 });
|
|
h.push(createCommand("A", (s) => ({ value: s.value + 1 }), (s) => ({ value: s.value - 1 })));
|
|
h.undo();
|
|
h.push(createCommand("B", (s) => ({ value: s.value + 2 }), (s) => ({ value: s.value - 2 }))); // forks
|
|
console.log(h.branches.length); // 2
|
|
```
|
|
|
|
## Modules
|
|
|
|
| Module | Description |
|
|
|--------|-------------|
|
|
| [`src/command/command.md`](src/command/command.md) | Command factories and execution helpers |
|
|
| [`src/stack/stack.md`](src/stack/stack.md) | Synchronous linear undo/redo stack |
|
|
| [`src/branch/branch.md`](src/branch/branch.md) | Branching history manager |
|
|
| [`src/async/async-command.md`](src/async/async-command.md) | Async command factories |
|
|
| [`src/async/async-stack.md`](src/async/async-stack.md) | Async undo/redo stack |
|
|
| [`src/compression/history-compressor.md`](src/compression/history-compressor.md) | History compression |
|
|
| [`src/selective/selective-undo.md`](src/selective/selective-undo.md) | Selective undo by command ID |
|
|
| [`src/merge/command-merger.md`](src/merge/command-merger.md) | Command merging / coalescing |
|
|
| [`src/types/undo.types.md`](src/types/undo.types.md) | All types and type guards |
|
|
| [`src/schemas/undo.schemas.md`](src/schemas/undo.schemas.md) | Zod option schemas |
|
|
| [`src/errors/undo-error.md`](src/errors/undo-error.md) | Structured errors and codes |
|
|
|
|
## Benchmarks
|
|
|
|
Measured on an AMD Ryzen 5 (WSL2), 1000 iterations:
|
|
|
|
| Operation | Throughput |
|
|
|-----------|-----------|
|
|
| UndoStack push/undo/redo (closure) | ~250k ops/s |
|
|
| UndoStack push/undo (patch, 50 fields) | ~15k ops/s |
|
|
| compressHistory (1000 entries, depth 100) | ~2k ops/s |
|
|
|
|
> A >10% regression from baseline fails the CI performance gate.
|
|
|