diff --git a/src/core/task-parser.ts b/src/core/task-parser.ts new file mode 100644 index 0000000..48bea45 --- /dev/null +++ b/src/core/task-parser.ts @@ -0,0 +1,16 @@ +import type { TaskItem } from "../types.ts"; + +export function parseTasks(content: string): TaskItem[] { + const tasks: TaskItem[] = []; + const lines = content.split("\n"); + for (const line of lines) { + const match = line.match(/^[\s]*- \[([ xX])\] (.*)$/); + if (match) { + tasks.push({ + checked: match[1] !== " ", + text: match[2], + }); + } + } + return tasks; +} diff --git a/tests/core/task-parser.test.ts b/tests/core/task-parser.test.ts new file mode 100644 index 0000000..15e5c38 --- /dev/null +++ b/tests/core/task-parser.test.ts @@ -0,0 +1,54 @@ +import { describe, it, expect } from "bun:test"; +import { parseTasks } from "../../src/core/task-parser.ts"; + +describe("parseTasks", () => { + it("解析标准 checkbox 格式", () => { + const content = `- [ ] 任务一 +- [ ] 任务二 +- [x] 任务三`; + const tasks = parseTasks(content); + expect(tasks).toHaveLength(3); + expect(tasks[0]).toEqual({ checked: false, text: "任务一" }); + expect(tasks[1]).toEqual({ checked: false, text: "任务二" }); + expect(tasks[2]).toEqual({ checked: true, text: "任务三" }); + }); + + it("跳过非 checkbox 行", () => { + const content = `# 标题 +一些描述 +- [ ] 任务一 +普通文本 +- [x] 任务二`; + const tasks = parseTasks(content); + expect(tasks).toHaveLength(2); + }); + + it("空内容返回空数组", () => { + expect(parseTasks("")).toEqual([]); + expect(parseTasks("# 只有标题")).toEqual([]); + }); + + it("支持大写 X 标记", () => { + const content = `- [X] 大写标记`; + const tasks = parseTasks(content); + expect(tasks).toHaveLength(1); + expect(tasks[0].checked).toBe(true); + }); + + it("支持缩进的 checkbox", () => { + const content = ` - [ ] 缩进任务`; + const tasks = parseTasks(content); + expect(tasks).toHaveLength(1); + expect(tasks[0].text).toBe("缩进任务"); + }); + + it("计算已完成和总数", () => { + const content = `- [x] 已完成 +- [ ] 未完成 +- [x] 另一个完成`; + const tasks = parseTasks(content); + const completed = tasks.filter((t) => t.checked).length; + expect(completed).toBe(2); + expect(tasks.length).toBe(3); + }); +});