prowm/rasterizer.ts
2025-02-06 02:21:37 +01:00

125 lines
3.9 KiB
TypeScript

import { Action } from "./action.ts";
export type Board = {
title: string;
columns: Column[];
};
export type Column = {
id: number;
title: string;
tasks: Task[];
};
export type Task = {
id: number;
content: string;
subTasks: Task[];
};
export class Rasterizer {
private board: Board = { title: "", columns: [] };
private columnIds = 0;
private taskIds = 0;
public constructor(
private actions: Action[],
) {}
public rasterize(): Board {
this.rasterizeAction(this.actions.length - 1);
return this.board;
}
private rasterizeAction(idx: number) {
const action = this.actions[idx];
const k = action.kind;
if (k.tag === "init") {
this.board.title = k.title;
return;
}
this.rasterizeAction(idx - 1);
switch (k.tag) {
case "addColumn":
this.board.columns
.splice(k.idx, 0, {
id: this.columnIds++,
title: k.title,
tasks: [],
});
return;
case "editColumn":
this.board.columns[k.idx].title = k.title;
return;
case "deleteColumn":
this.board.columns.splice(k.idx, 1);
return;
case "moveColumn": {
const column = this.board.columns[k.idx];
this.board.columns
.splice(k.idx, 1);
this.board.columns
.splice(k.idx + k.delta, 0, column);
return;
}
case "addTask": {
const column = this.board.columns[k.path[0]];
if (k.path.length === 1) {
column.tasks.splice(idx, 0, {
id: this.taskIds++,
content: k.content,
subTasks: [],
});
return;
}
this.taskAt(column.tasks, k.path.slice(1))
.subTasks.splice(idx, 0, {
id: this.taskIds++,
content: k.content,
subTasks: [],
});
return;
}
case "editTask": {
const column = this.board.columns[k.path[0]];
this.taskAt(column.tasks, k.path.slice(1))
.content = k.content;
return;
}
case "deleteTask": {
const column = this.board.columns[k.path[0]];
this.taskAt(column.tasks, k.path.slice(1, k.path.length - 1))
.subTasks.splice(k.path.at(-1)!, 1);
return;
}
case "moveTask": {
const srcColumn = this.board.columns[k.srcPath[0]];
const destColumn = this.board.columns[k.destPath[0]];
const task = this.taskAt(srcColumn.tasks, k.srcPath.slice(1));
if (k.srcPath.length === 2) {
srcColumn.tasks.splice(k.srcPath.at(-1)!, 1);
} else {
this.taskAt(
srcColumn.tasks,
k.srcPath.slice(1, k.srcPath.length - 1),
).subTasks.splice(k.srcPath.at(-1)!, 1);
}
if (k.destPath.length === 1) {
destColumn.tasks.splice(idx, 0, task);
return;
}
this.taskAt(destColumn.tasks, k.destPath.slice(1))
.subTasks.splice(idx, 0, task);
return;
}
}
const _: never = k;
}
private taskAt(tasks: Task[], path: number[]): Task {
if (path.length === 1) {
return tasks[path[0]];
}
return this.taskAt(tasks[path[0]].subTasks, path.slice(1));
}
}