update
This commit is contained in:
136
scripts/check-completed-order.mjs
Normal file
136
scripts/check-completed-order.mjs
Normal file
@@ -0,0 +1,136 @@
|
||||
// 回归测试:writer 把 `# 已完成任务` 排到「全部任务」及其 `##` 子分类之后、`# 回收站` 之前
|
||||
//
|
||||
// 背景:v3.4 把 `# 已完成任务` 升级为真实分类(kind=COMPLETED),但 parser 按文件顺序
|
||||
// 累积 categories,外部手工编辑 / 老文件会让它夹在「全部任务」容器和 `##` 子分类之间。
|
||||
// v3.5 修复:writer 分三遍写出,强制把 `# 已完成任务` 放到期望位置。
|
||||
//
|
||||
// 跑法:node scripts/check-completed-order.mjs
|
||||
|
||||
import { writeMarkdown } from '../src/markdown-writer.js';
|
||||
import { check, ok, bad, summary, printSummary } from './_lib/check.mjs';
|
||||
import { makeStore } from './_lib/store-fixture.mjs';
|
||||
|
||||
console.log('\n[1] 故意错序的 categories 数组,writer 强制按期望顺序写出');
|
||||
|
||||
// 模拟用户文件里的乱序:COMPLETED 排在 ## 子分类之前(v3.4 老文件 / 外部编辑后的产物)。
|
||||
// writer 必须按 `全部任务 > ## 子分类 > 已完成任务 > 回收站` 的视觉顺序输出。
|
||||
const categories = [
|
||||
{ name: '全部任务', kind: 'other_tasks', parentOtherTasks: false, tasks: [] },
|
||||
{ name: '已完成任务', kind: 'completed', parentOtherTasks: false, tasks: [
|
||||
{ text: '买牛奶', completed: true, important: false, current: false }
|
||||
] },
|
||||
{ name: '工作', kind: 'normal', parentOtherTasks: true, tasks: [
|
||||
{ text: '写周报', completed: false, important: false, current: false }
|
||||
] },
|
||||
{ name: '未分类', kind: 'normal', parentOtherTasks: true, tasks: [
|
||||
{ text: '看牙医', completed: false, important: false, current: false }
|
||||
] },
|
||||
{ name: '回收站', kind: 'trash', parentOtherTasks: false, tasks: [
|
||||
{ text: '误删的任务', completed: false, important: false, current: false }
|
||||
] }
|
||||
];
|
||||
|
||||
const md = writeMarkdown(categories);
|
||||
|
||||
const idxAllTasks = md.indexOf('# 全部任务');
|
||||
const idxCompleted = md.indexOf('# 已完成任务');
|
||||
const idxSubWork = md.indexOf('## 工作');
|
||||
const idxSubUncat = md.indexOf('## 未分类');
|
||||
const idxTrash = md.indexOf('# 回收站');
|
||||
|
||||
check('# 全部任务 出现在 # 已完成任务 之前',
|
||||
idxAllTasks >= 0 && idxCompleted >= 0 && idxAllTasks < idxCompleted,
|
||||
`全部任务=${idxAllTasks}, 已完成=${idxCompleted}`);
|
||||
|
||||
check('## 工作 子分类 出现在 # 已完成任务 之前',
|
||||
idxSubWork >= 0 && idxCompleted >= 0 && idxSubWork < idxCompleted,
|
||||
`工作=${idxSubWork}, 已完成=${idxCompleted}`);
|
||||
|
||||
check('## 未分类 子分类 出现在 # 已完成任务 之前',
|
||||
idxSubUncat >= 0 && idxCompleted >= 0 && idxSubUncat < idxCompleted,
|
||||
`未分类=${idxSubUncat}, 已完成=${idxCompleted}`);
|
||||
|
||||
check('# 已完成任务 出现在 # 回收站 之前',
|
||||
idxCompleted >= 0 && idxTrash >= 0 && idxCompleted < idxTrash,
|
||||
`已完成=${idxCompleted}, 回收站=${idxTrash}`);
|
||||
|
||||
console.log('\n[2] 子分类相对顺序保留(不被 sort 打乱)');
|
||||
|
||||
// 用户手工调整过 ## 子分类顺序:未分类 → 工作 → 学习 → 111
|
||||
// 即使 writer 重排了 COMPLETED / TRASH 的位置,## 子分类之间的顺序必须原样保留。
|
||||
const ordered = [
|
||||
{ name: '全部任务', kind: 'other_tasks', parentOtherTasks: false, tasks: [] },
|
||||
{ name: '已完成任务', kind: 'completed', parentOtherTasks: false, tasks: [
|
||||
{ text: '买牛奶', completed: true }
|
||||
] },
|
||||
{ name: '未分类', kind: 'normal', parentOtherTasks: true, tasks: [] },
|
||||
{ name: '工作', kind: 'normal', parentOtherTasks: true, tasks: [] },
|
||||
{ name: '学习', kind: 'normal', parentOtherTasks: true, tasks: [] },
|
||||
{ name: '111', kind: 'normal', parentOtherTasks: true, tasks: [] },
|
||||
{ name: '回收站', kind: 'trash', parentOtherTasks: false, tasks: [] }
|
||||
];
|
||||
const md2 = writeMarkdown(ordered);
|
||||
const iUncat = md2.indexOf('## 未分类');
|
||||
const iWork = md2.indexOf('## 工作');
|
||||
const iStudy = md2.indexOf('## 学习');
|
||||
const i111 = md2.indexOf('## 111');
|
||||
check('## 子分类相对顺序:未分类 < 工作 < 学习 < 111',
|
||||
iUncat >= 0 && iWork > iUncat && iStudy > iWork && i111 > iStudy,
|
||||
`未分类=${iUncat}, 工作=${iWork}, 学习=${iStudy}, 111=${i111}`);
|
||||
|
||||
console.log('\n[3] 空 COMPLETED 分类不写出(与原行为一致)');
|
||||
|
||||
// 没有已完成任务时,整个 `# 已完成任务` 段应该消失(避免空标题噪音)。
|
||||
// 但 `# 全部任务` 和 `## 工作` 仍然存在。
|
||||
const noCompleted = [
|
||||
{ name: '全部任务', kind: 'other_tasks', parentOtherTasks: false, tasks: [] },
|
||||
{ name: '已完成任务', kind: 'completed', parentOtherTasks: false, tasks: [] },
|
||||
{ name: '工作', kind: 'normal', parentOtherTasks: true, tasks: [
|
||||
{ text: '写周报', completed: false }
|
||||
] },
|
||||
{ name: '回收站', kind: 'trash', parentOtherTasks: false, tasks: [] }
|
||||
];
|
||||
const md3 = writeMarkdown(noCompleted);
|
||||
check('空 # 已完成任务 不写出',
|
||||
md3.indexOf('# 已完成任务') === -1);
|
||||
check('# 全部任务 仍然写出',
|
||||
md3.indexOf('# 全部任务') >= 0);
|
||||
check('## 工作 仍然写出',
|
||||
md3.indexOf('## 工作') >= 0);
|
||||
|
||||
console.log('\n[4] 复杂场景:重复 ## 未分类 / 多个已完成分类 / TODAY 兜底');
|
||||
|
||||
// 模拟用户 todo.md 的复杂场景:两个 `## 未分类`、多个 kind=COMPLETED 分类、TODAY 兜底
|
||||
const complex = [
|
||||
{ name: '全部任务', kind: 'other_tasks', parentOtherTasks: false, tasks: [] },
|
||||
{ name: '已完成任务', kind: 'completed', parentOtherTasks: false, tasks: [
|
||||
{ text: 'task1', completed: true }
|
||||
] },
|
||||
{ name: '未分类', kind: 'normal', parentOtherTasks: true, tasks: [
|
||||
{ text: 'orphan1', completed: false }
|
||||
] },
|
||||
{ name: '学习', kind: 'normal', parentOtherTasks: true, tasks: [] },
|
||||
{ name: '未分类', kind: 'normal', parentOtherTasks: true, tasks: [
|
||||
{ text: 'orphan2', completed: false }
|
||||
] },
|
||||
{ name: '我的一天', kind: 'today', parentOtherTasks: false, tasks: [
|
||||
{ text: 'today1', completed: false }
|
||||
] },
|
||||
{ name: '回收站', kind: 'trash', parentOtherTasks: false, tasks: [
|
||||
{ text: 'trashed', completed: false }
|
||||
] }
|
||||
];
|
||||
const md4 = writeMarkdown(complex);
|
||||
const lastCompleted = md4.lastIndexOf('# 已完成任务');
|
||||
const firstTrash = md4.indexOf('# 回收站');
|
||||
check('复杂场景下 # 已完成任务 仍在 # 回收站 之前',
|
||||
lastCompleted >= 0 && firstTrash >= 0 && lastCompleted < firstTrash,
|
||||
`最后一个#已完成=${lastCompleted}, 第一个#回收站=${firstTrash}`);
|
||||
|
||||
const allTrash = md4.match(/^# 回收站/gm) || [];
|
||||
check('复杂场景下 # 回收站 仍是文件最后一段(不被多个已完成分类挤到中间)',
|
||||
allTrash.length === 1 && md4.trimEnd().endsWith('trashed'),
|
||||
`trash 行数=${allTrash.length}, 末尾=${md4.trimEnd().slice(-30)}`);
|
||||
|
||||
console.log(`\n结果:通过 ${summary.pass} / 失败 ${summary.fail}`);
|
||||
process.exit(summary.fail === 0 ? 0 : 1);
|
||||
Reference in New Issue
Block a user