27 lines
1.2 KiB
TypeScript
27 lines
1.2 KiB
TypeScript
import type { TaskItem } from "./contracts.ts";
|
|
|
|
export type NumberedTaskItem = TaskItem & { outlineRef: string };
|
|
|
|
export function numberTaskTree(tasks: TaskItem[]): NumberedTaskItem[] {
|
|
const ordered = [...tasks].sort((left, right) => left.sortOrder - right.sortOrder || left.createdAt.localeCompare(right.createdAt) || left.id.localeCompare(right.id));
|
|
const taskIds = new Set(ordered.map((task) => task.id));
|
|
const children = new Map<string | null, TaskItem[]>();
|
|
for (const task of ordered) {
|
|
const parentId = task.parentId !== null && taskIds.has(task.parentId) ? task.parentId : null;
|
|
children.set(parentId, [...(children.get(parentId) ?? []), task]);
|
|
}
|
|
|
|
const refs = new Map<string, string>();
|
|
const visit = (parentId: string | null, prefix: string) => {
|
|
for (const [index, task] of (children.get(parentId) ?? []).entries()) {
|
|
if (refs.has(task.id)) continue;
|
|
const outlineRef = prefix ? `${prefix}.${index + 1}` : `R${index + 1}`;
|
|
refs.set(task.id, outlineRef);
|
|
visit(task.id, outlineRef);
|
|
}
|
|
};
|
|
visit(null, "");
|
|
|
|
return ordered.map((task, index) => ({ ...task, outlineRef: refs.get(task.id) ?? `R${index + 1}` }));
|
|
}
|