feat: 0.9.0 忽略规则、增量缓存跨会话持久化、快照基线、字符级预算自适应与性能基准E2E - 忽略规则(gitignore简化子集:目录整树剪枝不枚举不计数、扩展名通配与名字匹配、随偏好持久化)、扫描增量缓存落盘userData跨会话自动注入(LRU 8对、防御性解析、渲染端零改动)、快照基线(保存/加载JSON对照六类状态变迁统计与条目标注、对照随重扫刷新、报告附快照口径)、字符级变更组预算随输入规模自适应(下限与固定值一致小输入零变化、大输入按总组流半数放宽上限100万封顶)、大文件性能基准E2E(5万行<15s与300KB GBK<10s耗时断言)+新功能E2E、文档与版本号同步
This commit is contained in:
+7
-1
@@ -20,7 +20,7 @@ z = 补丁版本号(Patch)
|
||||
> **`x` 永远是 `0`,永远不要提升到 `1.0.0`。**
|
||||
> 版本迭代**只允许修改 `y` 和 `z`**,`x` 保持 `0` 不变。
|
||||
|
||||
当前基线版本:**`0.8.0`**
|
||||
当前基线版本:**`0.9.0`**
|
||||
|
||||
---
|
||||
|
||||
@@ -98,6 +98,12 @@ z = 补丁版本号(Patch)
|
||||
- 增量重扫:folderScan 枚举 stat 保留 size+mtimeMs 指纹,扫描结果携带增量缓存(ScanCacheEntry:双侧指纹 + 状态 + semSame 语义判定参与记录) · 重扫携带上次缓存时指纹一致的条目零 IO 沿用;语义判等开关翻转按 semSame 纯内存组合(different ↔ semantic-same 零 IO),仅"上次未参与语义而本次需要"的条目读内容补判 · unreadable 不进缓存(重扫重试)、截断忽略缓存且 cache 产出为空(条目不完整不可信) · IPC folder:scan 增 previous 参数(主进程防御性校验数组形态) · FolderView 增「重新扫描」按钮(不重选目录直接刷新) · 已知取舍:mtime 未变视为内容未变(rsync/make 同款,手动改回时间戳不防)
|
||||
- 字符级逐组预算制(变更组粒度放宽):第二阶段从"任一超限整体降级"改为逐组判定——组流 ≤ 5 万且编辑距离 ≤ 5000 且在总预算(10 万字符)内的组走字符级,超限/预算耗尽的组仅按行级配对输出(emitGroupLineLevel:行归一化 LCS + 相邻块配 modified 词级高亮 + 多余侧 removed/added,与行级路径同构含超长行词级防护) · DiffResult 增 charModePartial 部分降级标志(与 charModeDowngraded 互斥:全部组降级仍整体降级) · Toolbar「部分降级」标记、toast 提示、报告头部选项说明(plainOptions 增 partial 描述) · 行为变更:0.7.x 整体降级的多组混合输入在 0.8.0 为部分降级(特性而非回归,测试固化新行为)
|
||||
- 拖拽导入 E2E:helpers 增 dropFiles(真实 Chromium DataTransfer/DragEvent 合成拖放,覆盖 dropPane → file.arrayBuffer → decodeBuffer IPC → 编码探测全链路) · 4 用例:空面板拖入渲染、双侧拖入对比、非文本扩展名拒绝、多文件提示取首个
|
||||
0.9.0 ← 忽略规则 · 增量缓存跨会话持久化 · 快照基线 · 字符级预算自适应 · 性能基准 E2E(已发布):
|
||||
- 忽略规则:ignoreRules 纯逻辑模块(gitignore 简化子集——`dir/` 目录名匹配整树剪枝(不枚举不计数,不占用 maxFiles)、`*.ext` 扩展名通配、`name` 名字精确匹配;大小写不敏感;`#` 注释与空白行跳过;多段路径与非法通配整体忽略;上限 50 条/单条 500 字符双重防御) · folderScan listFiles BFS 内剪枝(双侧共用同一 matcher) · 被忽略项不进结果/缓存/total/truncated,规则变化后缓存按指纹自然失效(未命中走全量判定) · FolderView「忽略规则」下拉(每行一条文本域草稿、应用并重扫、清空规则,入口标注规则数) · 规则随偏好 localStorage 持久化(启动恢复并随扫描下发,损坏字段防御性过滤) · IPC folder:scan 增 ignoreRules 参数(isIgnoreRulesArray 校验)
|
||||
- 增量缓存跨会话持久化:scanCacheStore 纯数据模块(userData/scan-cache.json 落盘;目录对键归一化——反斜杠转斜杠/去尾分隔符/Windows 盘符小写;LRU 上限 8 对按 savedAt 淘汰,当前写入对永不淘汰;解析全部防御性校验——JSON 非法/版本不符整体回退空存储,单条 entry 异常仅丢弃该条) · 主进程 folder:scan 渲染端未携带内存缓存时自动注入盘上缓存(跨会话首次扫描增量),扫描成功且未截断异步落盘(读-改-写,失败静默) · 渲染端链路零改动(内存缓存优先逻辑保留)
|
||||
- 快照基线:snapshotDiff 纯逻辑模块(快照结构 version/leftDir/rightDir/semantic/truncated/total/entries/savedAt,parseSnapshot 全字段防御校验绝不部分加载;diffSnapshot 按 rel 对齐产出六类变迁——fixed/regressed/new/gone/changed/stable,以 isDiffStatus 为主轴;snapshotDirsMatch 目录对一致性校验) · 「保存快照」复用报告保存管线落盘 JSON(默认名带时间戳) · 「加载快照」走打开文件对话框读取(目录对不一致/文件无效/读取失败/无当前结果四类拦截提示) · 对照模式接管 FolderView 列表渲染:变迁统计徽章(点击单选过滤)替换常规统计行、平铺全路径行 + 变迁徽章(gone 回退快照数据展示)、默认隐藏 stable、搜索共用、退出对照恢复 · 对照随重扫自动刷新(目录对仍一致时),退出文件夹对比清空 · 对照模式导出报告附「快照对照」口径行(三格式)
|
||||
- 字符级预算自适应:charGroupBudget(totalGroupChars) = clamp(总组流/2, 下限 10 万, 上限 100 万)——下限与 0.8.0 固定值一致(小输入行为与已固化测试零变化),大输入但变更组普遍较小的场景按比例放宽(上限封顶最坏总耗时仍有界,单组 5 万/编辑距离 5000 不变) · plainOptions 字案与 Toolbar title 同步("预算随规模自适应") · 行为固化测试:400 组跨行重组总流 48 万 → 预算 24 万 → 200 组字符级(固定预算仅 83 组)
|
||||
- 性能基准 E2E:5 万行双文件 20 处差异——打开右侧到「有差异」出现耗时 < 15s(万级行实测秒级,慢机 4 倍余量防 flaky,断言失败即性能回归) · 300KB GBK 15000 行——打开到状态栏行数渲染 < 10s · 新功能 E2E:忽略规则目录剪枝重扫、增量缓存跨重启(scan-cache.json 落盘断言 + 第二实例重扫正确)、快照保存→修复差异→加载对照变迁
|
||||
...
|
||||
0.y.z ← 长期停留,永不进入 1.x
|
||||
```
|
||||
|
||||
+21
-9
@@ -51,8 +51,12 @@ src/main/
|
||||
├── decode.ts # 解码与编码探测纯逻辑(Uint8Array 入参,同步与 worker 路径共用)
|
||||
├── decode.test.ts # 解码单元测试(BOM 三种/严格 UTF-8/GBK 回退/二进制启发式)
|
||||
├── decodeWorker.ts # 解码 worker_threads 入口(覆盖率排除,逻辑由 decode 测试覆盖)
|
||||
├── folderScan.ts # 文件夹对比纯逻辑(递归枚举/对齐/字节判定/采样近似/受控并发比对/语义判等/单点失败降级)
|
||||
├── folderScan.test.ts # 文件夹扫描单元测试(真实临时目录:状态判定/递归/symlink/截断/近似/语义判等/目录降级/unreadable)
|
||||
├── folderScan.ts # 文件夹对比纯逻辑(递归枚举/对齐/字节判定/采样近似/受控并发比对/语义判等/单点失败降级/忽略规则剪枝)
|
||||
├── folderScan.test.ts # 文件夹扫描单元测试(真实临时目录:状态判定/递归/symlink/截断/近似/语义判等/目录降级/unreadable/忽略规则)
|
||||
├── ignoreRules.ts # 忽略规则纯逻辑(gitignore 简化子集编译为 matcher,无 electron 依赖)
|
||||
├── ignoreRules.test.ts # 忽略规则单元测试(目录剪枝/通配/名字匹配/大小写/非法输入/条数上限/IPC 校验)
|
||||
├── scanCacheStore.ts # 扫描缓存跨会话持久化纯数据(目录对键归一化/LRU/防御性解析)
|
||||
├── scanCacheStore.test.ts # 缓存存储单元测试(解析回退/条目过滤/键归一化/LRU 淘汰/序列化往返)
|
||||
├── windowState.ts # 应用状态持久化纯逻辑(bounds 校验/钳制,无 electron 依赖)
|
||||
└── windowState.test.ts # 应用状态单元测试(解析回退/工作区钳制/最小尺寸)
|
||||
src/renderer/src/
|
||||
@@ -64,8 +68,10 @@ src/renderer/src/
|
||||
│ ├── createDiffWorker.test.ts # worker 工厂(环境回退/实例化)
|
||||
│ ├── createDiffWorker.ts # worker 工厂:环境不支持时返回 null 由调用方回退
|
||||
│ ├── report.test.ts # 单文件报告生成测试
|
||||
│ ├── folderReport.ts # 文件夹报告生成器(HTML/TXT/MD 三格式)
|
||||
│ ├── folderReport.ts # 文件夹报告生成器(HTML/TXT/MD 三格式,快照对照口径附注)
|
||||
│ ├── folderReport.test.ts # 文件夹报告测试(统计/结论/三格式/截断警示/unreadable)
|
||||
│ ├── snapshotDiff.ts # 快照基线纯逻辑(结构/解析校验/目录对匹配/六类变迁对照)
|
||||
│ ├── snapshotDiff.test.ts # 快照单元测试(解析防御/变迁判定/双侧空集/unreadable 语义)
|
||||
│ └── textUtils.test.ts # 文本扩展名与行数统计测试
|
||||
├── hooks/
|
||||
│ ├── useDiff.test.ts # worker 化计算 hook(快路径/去抖/过期丢弃/回退/卸载清理/字符级大字符量重路径/选项变化保留旧结果防滚动塌陷)
|
||||
@@ -76,11 +82,11 @@ src/renderer/src/
|
||||
│ ├── DiffView.test.tsx # 对比视图(渲染/滚动同步/右键/拖放)
|
||||
│ ├── folderTree.ts # 文件夹条目树纯逻辑(建树/状态聚合/扁平化/过滤含扩展名/子树收集)
|
||||
│ ├── folderTree.test.ts # 条目树单元测试(聚合排序/折叠/过滤/搜索/扩展名过滤/relExt)
|
||||
│ ├── FolderView.test.tsx # 文件夹视图(树形渲染/折叠/统计徽章点击过滤/搜索/扩展名下拉/目录双击/重新扫描/双击/导出菜单/虚拟滚动/resize 重算)
|
||||
│ ├── FolderView.test.tsx # 文件夹视图(树形渲染/折叠/统计徽章点击过滤/搜索/扩展名下拉/忽略规则下拉/快照对照模式/目录双击/重新扫描/双击/导出菜单/虚拟滚动/resize 重算)
|
||||
│ ├── TextInputModal.test.tsx # 粘贴文本弹窗
|
||||
│ └── Toolbar.test.tsx # 工具栏(选项/导航/导出菜单向上弹出/计算中禁用/字符级开关与空白选项联动灰显勾选+已包含徽标+点击解释+已降级与部分降级标记)
|
||||
└── __tests__/
|
||||
├── App.test.tsx # 应用集成级测试(加载/拖拽/粘贴/导出/容错/toast 队列/清空确认/状态栏行数/大输入回退/文件夹模式进出与双击/语义判等链路/差异文件导航/扫描竞态丢弃过期结果/增量重扫携带缓存/目录聚合导航/字符级部分降级)
|
||||
├── App.test.tsx # 应用集成级测试(加载/拖拽/粘贴/导出/容错/toast 队列/清空确认/状态栏行数/大输入回退/文件夹模式进出与双击/语义判等链路/差异文件导航/扫描竞态丢弃过期结果/增量重扫携带缓存/目录聚合导航/字符级部分降级/忽略规则链路与持久化/快照保存加载对照与拦截)
|
||||
└── main.test.ts # 入口挂载冒烟测试
|
||||
```
|
||||
|
||||
@@ -96,7 +102,7 @@ src/renderer/src/
|
||||
- 行级:新增、删除(含左/右行号、空槽 lineNo 为 `null`)
|
||||
- 词级:同一删除/新增配对为 `modified` 并产生左右 `segs`
|
||||
- 忽略选项:`ignoreCase`、`trimWhitespace`、`ignoreBlankLines`、`ignoreAllWhitespace` 生效与关闭;忽略所有空白覆盖行首尾空白、换行结构差异不受其影响、空行数量差异需配合忽略空行、与大小写忽略组合、展示文本保持原文
|
||||
- 字符级对比(`charMode`):判等组(跨行重组一致 / 空行数量差异 / 行内空白与全角空格 / 与忽略大小写组合 / 一致但行数不等短侧空槽仍 unchanged / 展示原文);定位组(行内替换 modified 与 segs 结构 / 行内删除与新增的对侧行回拉(含行首行尾流界跨界)/ 整行增删不误配对 / 多块修改穿插 / 删除段空白继承 / 跨行变更行号单调);换位专项组(换位场景 jsdiff 对齐任意,断言只锚定不变量:segs 拼接无损 / 高亮不越侧 / 行号单调 / 同行 ne-eq-ne 多块变更仅输出一个 modified 不重复行);降级组(归一化流超 3 万字符自动降级行级并带 `charModeDowngraded` 标志 / 编辑距离超限快速降级(内部参数 charDiffMaxEdit 注入小阈值毫秒级构造)/ 降级结果与等效行级选项一致 / 恰好阈值不降级 / 未开启不携带标志 / 全部组超限整体降级不出现 partial);逐组预算制部分降级组(0.8.0):组总流超预算时预算内组字符级、预算外组行级配对(`charModePartial` 置位、segs 拼接无损、超长行触发词级防护 segs 为 null、行号单调)/ 单组流超上限仅该组行级其余组字符级精确定位 / 单组编辑距离超限仅该组行级(charDiffMaxEdit 注入)/ 行级降级组内行数不等按序配对多余侧 added
|
||||
- 字符级对比(`charMode`):判等组(跨行重组一致 / 空行数量差异 / 行内空白与全角空格 / 与忽略大小写组合 / 一致但行数不等短侧空槽仍 unchanged / 展示原文);定位组(行内替换 modified 与 segs 结构 / 行内删除与新增的对侧行回拉(含行首行尾流界跨界)/ 整行增删不误配对 / 多块修改穿插 / 删除段空白继承 / 跨行变更行号单调);换位专项组(换位场景 jsdiff 对齐任意,断言只锚定不变量:segs 拼接无损 / 高亮不越侧 / 行号单调 / 同行 ne-eq-ne 多块变更仅输出一个 modified 不重复行);降级组(归一化流超 3 万字符自动降级行级并带 `charModeDowngraded` 标志 / 编辑距离超限快速降级(内部参数 charDiffMaxEdit 注入小阈值毫秒级构造)/ 降级结果与等效行级选项一致 / 恰好阈值不降级 / 未开启不携带标志 / 全部组超限整体降级不出现 partial);逐组预算制部分降级组(0.8.0):组总流超预算时预算内组字符级、预算外组行级配对(`charModePartial` 置位、segs 拼接无损、超长行触发词级防护 segs 为 null、行号单调)/ 单组流超上限仅该组行级其余组字符级精确定位 / 单组编辑距离超限仅该组行级(charDiffMaxEdit 注入)/ 行级降级组内行数不等按序配对多余侧 added;预算自适应组(0.9.0):charGroupBudget 函数边界(小输入取下限 / 大输入按总组流一半向上取整 / 上限封顶 100 万 / 非有限输入回退下限)/ 大输入跨行重组 400 组总流 48 万 → 预算 24 万 → 200 组字符级(固定预算仅 83 组,行为放宽固化)/ 总流未超下限两倍时与历史固定预算行为完全一致(回归锚)
|
||||
- 超长行防护:任一侧超过阈值跳过词级高亮(segs 为 null),行仍为 modified;边界长度仍产生 segs
|
||||
- 行切分:结尾换行不产生多余空行
|
||||
|
||||
@@ -164,12 +170,15 @@ src/renderer/src/
|
||||
- 边界与选项:两个空目录 / maxFiles 截断(truncated + total + 条目数受限;截断后不再深入子目录,total 为已遍历下限) / 超 maxContentBytes 同大小文件头部采样一致判 same 带 approximate / 采样头部不同直接 different
|
||||
- 受控并发:跨多个并发批次(> 2×SCAN_CONCURRENCY)的混合状态全部判定正确、条目排序与并发执行顺序无关
|
||||
- 增量重扫(0.8.0,previous 缓存):指纹一致(size+mtime 未变)零 IO 沿用判定(decode 计数零增长)/ 语义开关翻转按 semSame 纯内存组合(different ↔ semantic-same 零 IO,开→关→开三轮)/ 上次未参与语义(semSame null)而本次开启读内容补判 / 指纹变化(内容修改)重新判定且文件增删正确 / 单侧缺失形状变化不误沿用 / 本次截断忽略 previous 且 cache 产出为空 / unreadable 不进缓存(故障恢复后重扫正确判定)
|
||||
- 忽略规则(0.9.0):目录规则整树剪枝(深层子树不枚举、不计数、不进结果与缓存)/ 扩展名通配与名字匹配跳过文件(大小写不敏感)/ 被忽略文件不占用 maxFiles(原本截断的场景忽略后完整扫描)/ 规则变化后重扫缓存未命中的重新纳入条目走全量判定 / 空规则数组与全非法规则不产生任何剪枝
|
||||
|
||||
### 5.10 文件夹视图(`FolderView.tsx`)与条目树(`folderTree.ts`)
|
||||
- 条目树纯逻辑:按路径分段聚合目录/文件(同层字典序);目录聚合子树状态(different > unreadable > only > 语义同 > 相同)与文件计数;折叠目录子树隐藏;过滤(onlyDiff / statusFilter / query 子串不区分大小写 / exts 扩展名集合);空目录剪枝由“过滤后建树”天然保证;relExt 取文件名段扩展名(小写、无扩展名空串、不误取目录名中的点)
|
||||
- 渲染:目录路径卡片 / 重新扫描、重新选择、导出报告与返回按钮 / 统计徽章(相同/语义同/不同/仅左/仅右/无法读取/总数;语义关闭隐藏语义同、无失败隐藏无法读取)
|
||||
- 树形交互:目录行点击折叠展开(默认全展开);搜索命中强制展开命中路径、清空恢复用户折叠;无命中提示
|
||||
- 扩展名过滤(0.8.0):下拉展示全量条目 ext→count(字典序、无扩展名单列);点选过滤与其他条件取交集、计数切 N / 总数;多选并集、再点取消、清除按钮复位;与状态过滤双激活空态提示;点击外部关闭且过滤状态保留
|
||||
- 忽略规则(0.9.0):已有规则时入口标注数量并高亮;下拉打开以当前规则初始化草稿,逐行解析去空白去空行(截断至 50 条)后应用回调并关闭;清空规则回调空数组;点击外部关闭不触发回调
|
||||
- 快照对照模式(0.9.0):变迁统计徽章(已修复/新增差异/新文件/已移除/仍有差异/保持一致)与基线时间替换常规统计行;对照条目平铺全路径渲染、行尾变迁徽章、gone 回退快照数据;零计数变迁不占位;默认隐藏 stable、点击徽章单选过滤再点取消;双击当前条目进单文件对比、已移除条目双击无效;退出对照恢复常规视图;全 stable 空态提示
|
||||
- 过滤:仅看差异隐藏 same 与 semantic-same;徽章点击状态精确过滤(激活态高亮、与仅看差异互斥联动)
|
||||
- 目录行双击(0.8.0):触发 onOpenDir 携带目录相对路径;双击前折叠态自动展开(toggle 残留消除);重新扫描按钮触发 onRescan 且扫描中禁用
|
||||
- 双击文件回调携带原始条目;大小格式化(B/KB 与缺失占位);approximate 渲染 ≈ 标注;语义同条目双击提示;截断提示;空态提示(无文件 / 全部一致 / 过滤无结果)
|
||||
@@ -188,6 +197,10 @@ src/renderer/src/
|
||||
- 文件夹新功能(0.7.0):语义判等徽章与过滤(CRLF/LF 差异计语义同)→ 树形折叠展开 → 搜索 → 文件夹报告 TXT 真实落盘(判定口径 + 结论 + 全量条目)
|
||||
- 增量重扫(0.8.0):真实目录修改文件后点「重新扫描」状态正确更新(相同→不同→改回相同,真实 mtime 变化走指纹判定)
|
||||
- 拖拽导入(0.8.0):dropFiles 合成 DataTransfer 拖放——空面板拖入渲染(arrayBuffer → decodeBuffer IPC 全链路)、双侧拖入对比、非文本扩展名拒绝、多文件提示取首个
|
||||
- 忽略规则(0.9.0):真实目录含 node_modules 子树——无规则时差异参与对比,输入规则应用重扫后整树剪枝(不同归零、空态一致提示、被忽略条目消失)
|
||||
- 增量缓存跨会话持久化(0.9.0):第一实例扫描后 userData/scan-cache.json 落盘(等待异步写盘,断言含条目与合法结构)→ 同 userData 第二实例重扫同目录结果正确(主进程注入盘上缓存)
|
||||
- 快照基线(0.9.0):保存快照真实落盘(JSON 含版本与条目)→ 修复差异 + 新增文件重扫 → 加载快照对照(已修复/新文件变迁统计与条目标注)→ 退出对照恢复
|
||||
- 大文件性能基准(0.9.0):5 万行双文件 20 处差异——打开右侧到「有差异」出现耗时 < 15s;300KB GBK 15000 行——打开到状态栏行数渲染 < 10s(万级实测秒级,上限按慢机 4 倍余量防 flaky,断言失败即性能回归)
|
||||
- 偏好持久化:跨实例重启恢复比较选项与视图开关(同一 userData)
|
||||
- 隔离:每用例启动清空 localStorage + 重载,避免偏好跨用例污染(偏好用例验证实例显式跳过清理)
|
||||
|
||||
@@ -230,10 +243,9 @@ npm run build
|
||||
|
||||
## 9. 演进方向(后续迭代)
|
||||
|
||||
- 文件夹对比:增量缓存跨会话持久化(userData 落盘,重启后仍可增量) · 文件夹对比快照基线(保存/加载上次结果对比) · 忽略规则(排除 node_modules 等目录/文件过滤器)
|
||||
- 字符级对比能力扩展:变更组预算制的自适应(按输入规模动态放宽预算)
|
||||
- E2E 覆盖扩展:大文件性能基准(万级行计算耗时上限断言)
|
||||
- 文件夹对比:快照 vs 当前的逐行文本对照(快照保存内容或按需读盘,对照视图内差异明细) · 忽略规则高级 glob(`**` 跨段、否定规则 `!`)
|
||||
- 主进程 IPC 层补充集成测试(folder:scan 并发场景)
|
||||
- mac 构建实际验证(entitlements 配置就绪但从未打包跑通)
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user