mirror of
https://github.com/aculix/negotium.git
synced 2026-09-11 07:28:17 +00:00
feat: add pure task operations and bounded undo stack
Task operations become pure functions over arrays. Ids move from Date.now() to crypto.randomUUID(), with a fallback for non-secure contexts, since people do self-host this over plain HTTP on a LAN. Undo gets its own module so tasks.js stays pure. It covers single deletes and clear-completed batches, and clamps indices because the list can change between recording an entry and undoing it.
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
/** Bounded stack of reversible operations. Kept separate from tasks.js so that
|
||||
* module stays purely functional while this one holds the state. */
|
||||
export function createUndoStack(limit = 10) {
|
||||
const entries = []
|
||||
|
||||
return {
|
||||
push(entry) {
|
||||
entries.push(entry)
|
||||
if (entries.length > limit) entries.shift()
|
||||
},
|
||||
pop() {
|
||||
return entries.length > 0 ? entries.pop() : null
|
||||
},
|
||||
get size() {
|
||||
return entries.length
|
||||
},
|
||||
clear() {
|
||||
entries.length = 0
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverses one entry against the current task list.
|
||||
*
|
||||
* Indices are clamped because the list may have changed since the entry was
|
||||
* recorded — a task deleted from position 5 can be restored into a list that
|
||||
* has since shrunk to two items, and landing at the end beats throwing.
|
||||
*
|
||||
* `clearCompleted` entries must record `removed` in ascending index order, so
|
||||
* re-inserting front to back puts each task back where it was.
|
||||
*/
|
||||
export function applyUndo(tasks, entry) {
|
||||
if (!entry) return tasks
|
||||
|
||||
if (entry.type === 'delete') {
|
||||
const next = [...tasks]
|
||||
next.splice(Math.min(entry.index, next.length), 0, entry.task)
|
||||
return next
|
||||
}
|
||||
|
||||
if (entry.type === 'clearCompleted') {
|
||||
const next = [...tasks]
|
||||
for (const { task, index } of entry.removed) {
|
||||
next.splice(Math.min(index, next.length), 0, task)
|
||||
}
|
||||
return next
|
||||
}
|
||||
|
||||
return tasks
|
||||
}
|
||||
Reference in New Issue
Block a user