Todo-CLI 交互式待办工具 v1.0.0-ts-精简学习版本v0.1 // 极简交互式Todo待办工具 | 核心功能增删改查本地JSON持久化 // 运行 bun src/todocli.ts 输入 exit 退出 import fs from fs/promises; import path from path; import readline from readline; // 持久化文件路径 const TASK_FILE path.resolve(__dirname, ./tasks.json); // 核心类型 type Task { id: number; title: string; priority: low | medium | high; status: active | done; }; type TaskStore { list: Task[]; nextId: number; }; // ---------------------- 文件读写核心工具 ---------------------- // 加载任务文件不存在返回空模板 async function loadTasks(): PromiseTaskStore { try { const raw await fs.readFile(TASK_FILE, utf8); return JSON.parse(raw) as TaskStore; } catch { return { list: [], nextId: 1 }; } } // 保存任务到本地json全量覆盖写入 async function saveTasks(store: TaskStore) { await fs.writeFile(TASK_FILE, JSON.stringify(store, null, 2), utf8); } // 错误打印工具 function errLog(msg: string) { console.log(\x1b[31m❌ ${msg}\x1b[0m); } // 成功打印封装统一绿色输出 function sucLog(msg: string) { console.log(\x1b[32m✅ ${msg}\x1b[0m); } // ---------------------- 完整CRUD业务命令 ---------------------- const cmdMap: Recordstring, (args: string[]) Promisevoid { // 【增】add 标题 --priorityhigh --done创建即完成 add: async (args) { const priorityArg args.find(item item.startsWith(--priority)); const priority priorityArg ? (priorityArg.split()[1] as Task[priority]) : medium; // 判断是否创建直接完成 const createDone args.includes(--done); // 过滤配置参数提取任务标题 const title args.filter(i !i.startsWith(--)).join( ).trim(); if (!title) return errLog(必须输入任务标题); const store await loadTasks(); const newTask: Task { id: store.nextId, title, priority, status: createDone ? done : active }; store.list.push(newTask); store.nextId 1; await saveTasks(store); const statusText createDone ? 已完成 : 待完成; sucLog(创建任务 #${newTask.id}【${statusText}】${title}); }, // 【查】list / list --statusactive/done list: async (args) { const statusArg args.find(item item.startsWith(--status)); const filterStatus statusArg ? statusArg.split()[1] : all; const store await loadTasks(); let showList store.list; if (filterStatus ! all) showList store.list.filter(t t.status filterStatus); console.log(\x1b[32m 任务列表\x1b[0m); if (showList.length 0) return console.log( 暂无任务); showList.forEach(t { const stat t.status active ? 待完成 : 已完成; console.log( ID:${t.id} | ${t.title} | 优先级:${t.priority} | ${stat}); }); }, // 【改】标记完成 done id done: async (args) { const id Number(args[0]); if (isNaN(id) || id 0) return errLog(请输入合法数字ID); const store await loadTasks(); const target store.list.find(t t.id id); if (!target) return errLog(不存在ID${id}的任务); target.status done; await saveTasks(store); sucLog(任务#${id}已标记完成); }, // 【改】update 1 --title新标题 --prioritylow update: async (args) { const id Number(args[0]); if (isNaN(id) || id 0) return errLog(第一个参数必须是任务ID); const titleArg args.find(i i.startsWith(--title)); const prioArg args.find(i i.startsWith(--priority)); const store await loadTasks(); const target store.list.find(t t.id id); if (!target) return errLog(不存在ID${id}的任务); // 按需更新字段 if (titleArg) target.title titleArg.split()[1]; if (prioArg) target.priority prioArg.split()[1] as Task[priority]; await saveTasks(store); sucLog(任务#${id}修改成功); }, // 【删】删除单条任务 delete id delete: async (args) { const id Number(args[0]); if (isNaN(id) || id 0) return errLog(请输入合法数字ID); const store await loadTasks(); const oldLen store.list.length; store.list store.list.filter(t t.id ! id); if (store.list.length oldLen) return errLog(不存在ID${id}的任务); await saveTasks(store); sucLog(任务#${id}已删除); }, // 批量清理已完成任务 clear clear: async () { const store await loadTasks(); const before store.list.length; store.list store.list.filter(t t.status ! done); const del before - store.list.length; await saveTasks(store); sucLog(清理完成移除${del}条已完成任务); } }; // ---------------------- 交互主循环 ---------------------- // 启动交互式命令行主程序负责终端输入输出、命令循环监听 async function startCli() { // 创建readline交互实例用于读取终端键盘输入与打印输出 const rl readline.createInterface({ input: process.stdin, // 标准输入流接收用户键盘输入 output: process.stdout, // 标准输出流向控制台打印文字 prompt: \x1b[32mtodo \x1b[0m // 自定义输入提示符\x1b[32m设置绿色字体\x1b[0m重置字体颜色 }); console.clear(); console.log( Todo极简工具【增删改查】); console.log(可用命令); console.log(add 任务名 --prioritylow/medium/high --done 创建任务--done直接完成); console.log(list --statusactive/done 查看任务); console.log(done ID 标记任务完成); console.log(update ID --title新标题 --priorityhigh 修改任务); console.log(delete ID 删除单条任务); console.log(clear 清空全部已完成任务); console.log(exit 退出程序\n); // 在控制台输出自定义提示符 todo 等待用户输入命令 rl.prompt(); // 监听用户按下回车的输入事件input 为用户输入的整行文本 rl.on(line, async (input) { // 去除输入文本首尾多余空格 const line input.trim(); // 判断输入为exit执行退出逻辑 if (line exit) { sucLog(退出程序数据已保存); // 关闭readline交互实例 rl.close(); // 终止当前事件回调后续代码执行 return; } // 用户仅输入空格/直接回车无有效内容重新弹出输入提示符 if (!line) { rl.prompt(); return; } // 以任意空白符空格、Tab分割整行输入拆分为命令参数数组 const parts line.split(/\s/); // 数组第一个元素为主命令add/list/update等 const cmd parts[0]; // 截取数组剩余所有元素作为命令的参数列表 const args parts.slice(1); // 判断输入的命令不存在 if (!cmdMap[cmd]) { errLog(未知命令${cmd}); } else { // 执行对应命令的异步处理函数捕获命令内部异常并打印错误 await cmdMap[cmd](args).catch(e errLog((e as Error).message)); } // 打印空行分隔两次命令输出优化控制台阅读体验 console.log(); // 执行完一条命令后再次弹出提示符等待下一次输入形成循环交互 rl.prompt(); }); // 监听readline关闭事件彻底结束Node/Bun进程0代表正常退出码 rl.on(close, () process.exit(0)); } // 启动程序捕获全局致命异常 startCli().catch(e errLog(全局异常${(e as Error).message}));0.1

相关新闻

最新新闻

SerenityOS 命令行选项解析指南:getopt 与 getopt_long 用法、返回值与底层实现

SerenityOS 命令行选项解析指南:getopt 与 getopt_long 用法、返回值与底层实现

SerenityOS 命令行选项解析指南:getopt 与 getopt_long 用法、返回值与底层实现 【免费下载链接】serenity The Serenity Operating System 🐞 项目地址: https://gitcode.com/GitHub_Trending/se/serenity 导读 本文以 getopt(3) 手册 为核心&a…

2026/9/26 23:24:47
轻量服务器还是ECS?大促云服务器选购与避坑实战指南

轻量服务器还是ECS?大促云服务器选购与避坑实战指南

每年大促节点,群里永远有人在问同一个问题:“38元的轻量服务器到底怎么抢?为什么我每次点进去都是已售罄?68元直购和99元的ECS我到底选哪个?”作为一个常年帮团队和自己采购云服务器的老用户,我太清楚这种纠…

2026/9/27 19:13:42
为 AI 代理的 Review 动作编写 Cedar 审批门控策略:review-agent-governance 策略编写实战指南

为 AI 代理的 Review 动作编写 Cedar 审批门控策略:review-agent-governance 策略编写实战指南

为 AI 代理的 Review 动作编写 Cedar 审批门控策略:review-agent-governance 策略编写实战指南 【免费下载链接】agents Multi-harness agentic plugin marketplace for Claude Code, Codex, Cursor, OpenCode, GitHub Copilot, and Google Antigravity 项目地址:…

2026/9/27 15:27:56
PaddleOCR 手写数学公式识别算法 CAN 实战指南:Counting-Aware Network 训练、评估与推理部署

PaddleOCR 手写数学公式识别算法 CAN 实战指南:Counting-Aware Network 训练、评估与推理部署

PaddleOCR 手写数学公式识别算法 CAN 实战指南:Counting-Aware Network 训练、评估与推理部署 【免费下载链接】PaddleOCR Turn any PDF or image document into structured data for your AI. A powerful, lightweight OCR toolkit that bridges the gap between i…

2026/9/27 19:54:03
Spring源码解析:构造器注入的类型转换与候选匹配机制

Spring源码解析:构造器注入的类型转换与候选匹配机制

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/27 9:16:41
openai-agents-python 多模型接入指南:深入解析 AnyLLMModel 适配层与 any-llm 路由

openai-agents-python 多模型接入指南:深入解析 AnyLLMModel 适配层与 any-llm 路由

openai-agents-python 多模型接入指南:深入解析 AnyLLMModel 适配层与 any-llm 路由 【免费下载链接】openai-agents-python A lightweight, powerful framework for multi-agent workflows 项目地址: https://gitcode.com/GitHub_Trending/op/openai-agents-pyth…

2026/9/26 21:11:24

日新闻

周新闻