2026-10-20 23:49:20 +02:00
|
|
|
#!/usr/bin/env node
|
2026-10-21 00:13:51 +02:00
|
|
|
import { load, save, add, has, complete, remove, format } from "./todo.js";
|
2026-10-20 23:49:20 +02:00
|
|
|
|
|
|
|
|
const FILE = process.env.TODO_FILE ?? "todos.json";
|
2026-10-21 00:13:51 +02:00
|
|
|
const USAGE = "Usage: todo [ls | add <text> | done <id> | rm <id>]";
|
|
|
|
|
const [cmd = "ls", ...args] = process.argv.slice(2);
|
|
|
|
|
|
|
|
|
|
function fail(message) {
|
|
|
|
|
console.error(message);
|
|
|
|
|
process.exit(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function parseId(todos, arg) {
|
2026-10-21 00:26:22 +02:00
|
|
|
if (!/^\d+$/.test(arg ?? "")) fail(`Invalid id: ${arg ?? "(missing)"}\n${USAGE}`);
|
2026-10-21 00:13:51 +02:00
|
|
|
const id = Number(arg);
|
|
|
|
|
if (!has(todos, id)) fail(`No todo with id ${id}`);
|
|
|
|
|
return id;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!["ls", "add", "done", "rm"].includes(cmd)) fail(`Unknown command: ${cmd}\n${USAGE}`);
|
|
|
|
|
|
|
|
|
|
let todos;
|
|
|
|
|
try {
|
|
|
|
|
todos = load(FILE);
|
|
|
|
|
} catch (err) {
|
|
|
|
|
fail(err.message);
|
|
|
|
|
}
|
2026-10-20 23:49:20 +02:00
|
|
|
|
|
|
|
|
switch (cmd) {
|
2026-10-21 00:13:51 +02:00
|
|
|
case "add": {
|
|
|
|
|
const text = args.join(" ").trim();
|
|
|
|
|
if (!text) fail(`Missing todo text\n${USAGE}`);
|
|
|
|
|
todos = add(todos, text);
|
2026-10-20 23:49:20 +02:00
|
|
|
break;
|
2026-10-21 00:13:51 +02:00
|
|
|
}
|
2026-10-20 23:49:20 +02:00
|
|
|
case "done":
|
2026-10-21 00:13:51 +02:00
|
|
|
todos = complete(todos, parseId(todos, args[0]));
|
2026-10-20 23:49:20 +02:00
|
|
|
break;
|
|
|
|
|
case "rm":
|
2026-10-21 00:13:51 +02:00
|
|
|
todos = remove(todos, parseId(todos, args[0]));
|
2026-10-20 23:49:20 +02:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2026-10-21 00:26:22 +02:00
|
|
|
if (cmd !== "ls") {
|
|
|
|
|
try {
|
|
|
|
|
save(FILE, todos);
|
|
|
|
|
} catch (err) {
|
|
|
|
|
fail(err.message);
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-10-20 23:49:20 +02:00
|
|
|
console.log(format(todos));
|