import assert from "node:assert/strict"; import { test } from "bun:test"; import { parseMdtodoImport } from "./mdtodo-import.ts"; test("MDTODO import preserves three Rxx levels and attaches reports", () => { const plan = parseMdtodoImport({ sourcePath: "/tmp/demo/MDTODO.md", sourceModifiedAt: "2026-07-15T12:00:00.000Z", markdown: `# Demo\n\n## R1 Root [in_progress]\n\nSee [任务报告](./details/R1_Task_Report.md).\n\n### R1.1 Child [completed]\n\n#### R1.1.1 Deep child [blocked]\n`, reports: [{ href: "./details/R1_Task_Report.md", sourcePath: "/tmp/demo/details/R1_Task_Report.md", body: "# R1 report\n\nPassed.", modifiedAt: "2026-07-17T09:30:00.000Z" }] }); assert.equal(plan.groupName, "Demo"); assert.deepEqual(plan.summary, { taskCount: 1, subtaskCount: 1, subsubtaskCount: 1, reportCount: 1, missingReportCount: 0, flattenedTaskCount: 0, warningCount: 0 }); assert.equal(plan.tasks[0]?.status, "in_progress"); assert.equal(plan.tasks[1]?.status, "completed"); assert.equal(plan.tasks[2]?.status, "blocked"); assert.equal(plan.tasks[2]?.parentSourceId, "R1.1"); assert.equal(plan.tasks[0]?.reports[0]?.body, "# R1 report\n\nPassed."); assert.equal(plan.tasks[0]?.startAt, "2026-07-14T12:00:00.000Z"); assert.equal(plan.tasks[0]?.dueAt, "2026-07-17T09:30:00.000Z"); assert.equal(plan.tasks[1]?.startAt, "2026-07-14T12:00:00.000Z"); assert.equal(plan.tasks[1]?.dueAt, "2026-07-15T12:00:00.000Z"); }); test("MDTODO import flattens only levels deeper than subsubtask", () => { const plan = parseMdtodoImport({ sourcePath: "/tmp/demo/MDTODO.md", sourceModifiedAt: "2026-07-15T12:00:00.000Z", markdown: "# Demo\n\n## R2 Root\n\n### R2.9 Child\n\n#### R2.9.1 Grandchild\n\n##### R2.9.1.1 Deeper\n", reports: [] }); assert.equal(plan.tasks[2]?.parentSourceId, "R2.9"); assert.equal(plan.tasks[3]?.parentSourceId, "R2.9"); assert.equal(plan.summary.subsubtaskCount, 2); assert.equal(plan.summary.flattenedTaskCount, 1); }); test("MDTODO import reports missing linked report files", () => { const plan = parseMdtodoImport({ sourcePath: "/tmp/demo/MDTODO.md", sourceModifiedAt: "2026-07-15T12:00:00.000Z", markdown: "# Demo\n\n## R1 Root\n\n[Task report](./R1_Task_Report.md)\n", reports: [] }); assert.equal(plan.summary.missingReportCount, 1); assert.equal(plan.warnings[0]?.code, "report_file_missing"); }); test("MDTODO import expands a parent range to contain report-dated children", () => { const plan = parseMdtodoImport({ sourcePath: "/tmp/demo/MDTODO.md", sourceModifiedAt: "2026-07-15T12:00:00.000Z", markdown: `# Demo\n\n## R1 Root\n\n### R1.1 Child\n\nSee [Task report](./R1.1_Task_Report.md).\n`, reports: [{ href: "./R1.1_Task_Report.md", sourcePath: "/tmp/demo/R1.1_Task_Report.md", body: "# Child report", modifiedAt: "2026-07-17T09:30:00.000Z" }] }); assert.equal(plan.tasks[1]?.startAt, "2026-07-16T09:30:00.000Z"); assert.equal(plan.tasks[1]?.dueAt, "2026-07-17T09:30:00.000Z"); assert.equal(plan.tasks[0]?.startAt, "2026-07-14T12:00:00.000Z"); assert.equal(plan.tasks[0]?.dueAt, "2026-07-17T09:30:00.000Z"); }); test("MDTODO import never truncates title content at URL colons", () => { const plan = parseMdtodoImport({ sourcePath: "/tmp/demo/MDTODO.md", sourceModifiedAt: "2026-07-15T12:00:00.000Z", markdown: "# Demo\n\n## R1\n\n完成 [UniDesk #2361](https://github.com/pikasTech/unidesk/issues/2361) 并保留后续文本。\n", reports: [] }); assert.equal(plan.tasks[0]?.title, "R1 完成 [UniDesk #2361](https://github.com/pikasTech/unidesk/issues/2361) 并保留后续文本。"); });