125 lines
3.9 KiB
TypeScript
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));
|
|
}
|
|
}
|