audit(docs/29): 全项目审计——修分片载入卸载截断高危、Sidebar memo 击穿与 Rust 资源/搜索/恢复上限等 20 余处

三线并行审计(编辑器核心/Rust 后端/服务与组件)+ App 编排层自审。
高危:分片载入未收尾时窗格卸载回写部分序列化,干净标签会被静默
截断——cleanup 补 muted 守卫,create 完成回调补取消守卫。
性能:gitSync/outline/收起回调稳定化保住 Sidebar memo;光标行列
rAF 合并;图片显示解析加缓存;导出图片并发解析;chunkLoader
偏移前缀表;围栏切点只认顶格(列表内嵌围栏等价回归实测)。
Rust:资源命令 async 化 + 32MB 上限;搜索 junction 越界校验;
recovery/workspace 条数与单条上限;启动坏库改名重建 + WAL;
validate 补 ext:: 黑名单与 ref 形态;init 先种 .gitignore
(含 .*.tmp-* 防崩溃残留被提交);游离 HEAD 不再猜分支。
验证:vitest 122+2、tsc、构建通过;Rust 过 rustfmt 解析、
validate 纯函数抽出实跑断言、命令对账 28=28。
This commit is contained in:
Muse
2026-11-14 18:00:31 +08:00
parent 527ca5ecc5
commit fb2315a2f3
28 changed files with 657 additions and 140 deletions

View File

@@ -0,0 +1,43 @@
// 回归(docs/29 高危):EditorPane 卸载最终回写的守卫。
// 分片载入未收尾(muted)时 cleanup 跳过回写——否则部分序列化会把干净
// 标签静默截断。该交错(卸载提交时追加仍在途)在 jsdom 里无法自动化
// 复现:React act 会把待办异步工作抽干,分片追加总是先跑完(已实测
// 三种卸载方式均如此),故中途卸载一例靠代码复核保证(muted 仅在追加
// 完成/失败的收尾回调里解除,cleanup 只在 !muted 时回写),这里只锁
// 对照组:正常文档卸载时最终回写照常发生(守卫不能误伤正常路径)。
import { describe, it, expect, vi } from 'vitest'
import { createRoot } from 'react-dom/client'
import { act } from 'react-dom/test-utils'
import EditorPane from '../src/components/EditorPane'
const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms))
describe('EditorPane 卸载回写', () => {
it('普通文档卸载:最终回写照常', async () => {
const container = document.createElement('div')
document.body.appendChild(container)
const root = createRoot(container)
const onFinalMarkdown = vi.fn()
let readyApi: { editor: unknown } | null = null
const onReady = vi.fn((api: { editor: unknown }) => { if (api.editor) readyApi = api })
await act(async () => {
root.render(
<EditorPane
tabId="t1"
initialMarkdown={'# 小文档\n\n你好,世界。\n'}
onMarkdown={() => undefined}
onFinalMarkdown={onFinalMarkdown}
onCursor={() => undefined}
onReady={onReady}
focusMode={false}
typewriter={false}
/>,
)
})
for (let i = 0; i < 200 && !readyApi; i++) await sleep(10)
expect(readyApi).not.toBeNull()
await act(async () => { root.unmount() })
expect(onFinalMarkdown).toHaveBeenCalledTimes(1)
expect(onFinalMarkdown.mock.calls[0][1]).toContain('你好,世界。')
}, 30000)
})