src / todoManager.ts
import fs from 'fs';
import path from 'path';
export interface TodoItem {
id: number;
task: string;
completed: boolean;
}
export class TodoManager {
private todos: TodoItem[] = [];
private filePath: string;
constructor() {
this.filePath = path.join(__dirname, '../todos.json');
this.load();
}
private load() {
if (fs.existsSync(this.filePath)) {
try {
const data = fs.readFileSync(this.filePath, 'utf-8');
this.todos = JSON.parse(data);
// Safety: Ensure IDs are actually numbers if JSON got messed up
this.todos.forEach(t => t.id = Number(t.id));
} catch (e) {
console.error("Failed to parse todos.json", e);
this.todos = [];
}
} else {
this.todos = [];
}
}
private save() {
try {
fs.writeFileSync(this.filePath, JSON.stringify(this.todos, null, 2));
} catch (e) {
console.error("Failed to save todos.json", e);
}
}
add(task: string): string {
// Generate safe sequential ID
const maxId = this.todos.length > 0 ? Math.max(...this.todos.map(t => t.id)) : 0;
const id = maxId + 1;
this.todos.push({ id, task, completed: false });
this.save();
return `Success: Added task #${id}: "${task}"`;
}
complete(id: number): string {
// Robust finding: coerce both to string to be safe, then strict compare
const todo = this.todos.find(t => t.id === Number(id));
if (!todo) {
return `Error: Task #${id} not found. Available IDs: ${this.todos.map(t => t.id).join(", ")}`;
}
todo.completed = true;
this.save();
return `Success: Task #${id} marked as COMPLETED.`;
}
remove(id: number): string {
const startCount = this.todos.length;
this.todos = this.todos.filter(t => t.id !== Number(id));
if (this.todos.length === startCount) {
return `Error: Task #${id} not found.`;
}
this.save();
return `Success: Task #${id} deleted from list.`;
}
clear(): string {
const count = this.todos.length;
this.todos = [];
this.save();
return `Success: Cleared all ${count} tasks. The list is empty.`;
}
list(): string {
if (this.todos.length === 0) return "Status: The todo list is empty.";
const pending = this.todos.filter(t => !t.completed);
const done = this.todos.filter(t => t.completed);
let output = "";
if (pending.length > 0) {
output += "--- PENDING TASKS ---\n";
output += pending.map(t => `[ ] #${t.id}: ${t.task}`).join('\n');
} else {
output += "--- NO PENDING TASKS --- (Good job!)";
}
if (done.length > 0) {
output += "\n\n--- COMPLETED ---\n";
output += done.map(t => `[x] #${t.id}: ${t.task}`).join('\n');
}
return output;
}
}