executor-fn
Version:
A lightweight function wrapper with optional state, history, undo/redo, and reset support. Use like a normal function or unlock powerful time-travel features.
112 lines (97 loc) • 4.13 kB
TypeScript
// Options for configuring Executor
// =========================
// Options for configuring Executor
// =========================
export type ExecutorOptions<T> = {
storeHistory?: boolean;
initialArgs?: any[];
callNow?: boolean;
metadataFn?: (value: T) => any; // attach metadata to history entries
maxHistory?: number; // limit history size
noDuplicate?: boolean; // 🆕 prevent duplicates in history
equalityFn?: (a: T, b: T) => boolean; // skip follow-up duplicate entries
onError?: (error: unknown) => void; // gracefully handle errors
historyStep?: number; // 🆕 throttle: only save every Nth entry
groupBy?: (value: T) => string; // 🆕 categorize history entries
};
// =========================
// A single history record
// =========================
export type HistoryEntry<T> = {
value: T;
meta?: any;
group?: string; // 🆕 optional grouping label
_index?: number; // 🆕 insertion index (for restore ordering in sort)
_time?: number; // 🆕 exact time of insertion
};
// =========================
// Executor instance type
// =========================
export type ExecutorInstance<T> = ((...args: any[]) => Promise<T>) & {
value: T;
initialValue: T;
history?: HistoryEntry<T>[];
redoStack?: HistoryEntry<T>[];
// Core
log(): void;
reset(): T;
undo(steps?: number): T;
redo(steps?: number): T;
jumpTo(index: number): T | undefined;
replaceAt(index: number, newValue: T): T | undefined;
insertAt(index: number, newValue: T): T | undefined;
removeAt(index: number): T | undefined;
// Serialization
serializeHistory(): string;
deserializeHistory(data: HistoryEntry<T>[]): void;
exportHistory(): string; // full state export (JSON string)
importHistory(json: string): void; // full state import (JSON string)
// File-based persistence 🆕
exportHistoryToFile(filename?: string): void; // download history as JSON file
importHistoryFromFile(): Promise<T>; // restore history from chosen JSON file
// History management
clearHistory(): T;
batch(callback: () => void): void;
pauseHistory(): void;
resumeHistory(): void;
filterHistory(predicate: (entry: HistoryEntry<T>) => boolean): HistoryEntry<T>[]; // query history
split(...ranges: Array<[number, number] | number[]>): Record<string, ExecutorInstance<T>>; // split into multiple executors
// 🆕 Advanced history ops
copy(histories: HistoryEntry<T>[][]): T; // overwrite with other histories
merge(
histories: HistoryEntry<T>[][],
opts?: { position?: "start" | "end" | number; overwrite?: boolean }
): T;
sort(
orderOrFn?: "default" | "asc" | "desc" | "groupAsc" | "groupDesc" | ((a: T, b: T) => number)
): T;
// Subscriptions
_subscribe(cb: () => void): void;
_unsubscribe(cb: () => void): void;
};
// =========================
// Main Executor function
// =========================
export function Executor<T>(
callback: (...args: any[]) => T | Promise<T>,
options?: ExecutorOptions<T>
): ExecutorInstance<T>;
// =========================
// React hook integration
// =========================
export function useExecutor<T>(executor: ExecutorInstance<T>): T;
// =========================
// Combine multiple executors into one group
// =========================
export type ExecutorGroup = {
undo(): any[]; // returns array of results from each executor
redo(): any[]; // same
reset(): any[]; // same
clearHistory(): any[]; // same
export(): string[]; // JSON dumps from each executor
importAll(dataArr: string[]): void; // safer than "import"
};
export namespace Executor {
export function combine(...executors: ExecutorInstance<any>[]): ExecutorGroup;
}
// Note: This is a simplified type definition. The actual implementation may have more details.