dsh-tiddlywiki 0.30.45 → 0.30.46
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/docs/CHANGELOG.md +1 -0
- package/lib/client.js +13 -13
- package/package.json +1 -1
- package/src/client/note-widget-upload-ui.ts +82 -0
- package/src/client/note-widget.ts +10 -37
package/docs/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
> 最近几个主要版本的一句话记录(完整变更见 [Releases](https://github.com/bbqisbbq/dsh-tiddlywiki/releases) / git log)。
|
|
6
6
|
|
|
7
|
+
- **v0.30.46**(2026-09-30):`src/client/note-widget.ts` **615 → 588** —— 新模块 `note-widget-upload-ui.ts`(82):上传的**接线**那一组(「上传」按钮 + 隐藏的 file input + 拖放到编辑器上,连同它自有的 `dragDepth`)。分层刻意分成两个文件:`note-widget-upload.ts` 是**动作**(`uploadInto`:校验大小 → POST → 在光标处插入 Markdown 行 → toast),`note-widget-upload-ui.ts` 是**接线**(File 从哪来、何时给编辑器挂 `.dsh-tw-note-drop` 高亮)。分界线:整组只问卡片要两样东西 —— 编辑器(拖放目标 + 插入点)与 `wikiQuery`(附件必须落在**这张卡片的目标库**里),卡片侧不再持有任何上传状态(`footLeft.append(upload.button, …)` 一行替代原 36 行)。
|
|
7
8
|
- **v0.30.45**(2026-09-29):**`note-widget.ts` 拆分第四轮 —— 抽出「保存 / 在 TW 中编辑」整组(677 → 615 行),并在同一轮**抓出一条被注释满足的假绿守门**。① 新模块 `src/client/note-widget-save.ts`(187 行)拿走 `saveDone` · `saving`(在途互斥)· `doSave` · `doEdit` —— 这四样是 `build()` 里唯一真的"说话"的一段(发请求、读回执、弹 toast、改按钮状态与文案)。**分界线(可复用)**:先把这段代码**读写到的闭包状态**列出来,再逐样决定怎么传 —— 它自带的 `saving` **跟着函数走**(同 v0.30.44);卡片**留在原地**的四样各有理由:`close()` 是卡片自己的可见性收尾、`postEditAndOpen()` **两条路径共用**(`doEdit` 与 `openNative`)所以必须住在两者都看得见的地方、`loadedToken` 的**主人是「🕘 最近」picker**(它写、这里只读)⇒ 按 getter/setter 传、`scope` 这里只读**一个**方法(`stoppedTarget()`)⇒ 传函数而不是整个模块。② `const doSave = async (): Promise<void> => {` 这一行**逐字保留**:`verify-wiki-focus.mjs` 用 `indexOf(那句签名)` 定位函数体、再断言其后 900 字符内出现 `stoppedTarget()`(=「卡片保存同样要拒绝未运行的目标库」,v0.29.0);它是**族读**(`readFamily('src/client/note-widget')`)⇒ 搬到新文件仍命中。③ ⚠️ **本版最重要的一条:那条判据在搬迁后变成了假绿,是反向验证抓出来的。** 第一次跑两种注入(**删掉整个 `stoppedTarget()` 拒绝分支** / **把 `doSave` 改名**)——`verify-wiki-focus` **两次都照样绿**。根因:它是拿**未剥注释**的族文本做 `indexOf`,而新模块的**模块头注释**逐字引用了那句签名、还在同一段里提到 `stoppedTarget()` ⇒ `indexOf` 先命中**注释**,900 字符窗口里出现的 `stoppedTarget()` 也来自注释,**断言被自己的文档满足**(这条注释本身是为了解释"为什么这一行不许改名",属于"越写越安全"的反面)。修法:`verify-wiki-focus.mjs` 新增 `stripComments()`(**先剥行注释、再剥块注释** —— 顺序承重,v0.30.14 在 `verify-client-i18n` 里踩过反序吞代码的坑),那条测试的五条断言全部改跑在剥注释的源码上。**加固后重跑同样的两种注入 ⇒ 两次都稳定 FAIL**(删分支 ⇒「卡片保存同样要拒绝未运行的目标库」;改名 ⇒「找不到 doSave」),还原后文件哈希与注入前**逐字节一致** ⇒ 绿。⇒ 结论:`grep`/`indexOf` 型判据在**拆分**这件事上尤其脆 —— 模块头注释几乎必然会引用被搬走的那句签名,所以凡"定位函数体 + 窗口内找符号"的断言,**必须剥注释**。④ **其余守门一条都不用改**(逐个核实,不是猜):`verify-frame-guards` 按模块族读并在测试里剥注释行,`dispose()` / `open()` / `openNative()` / `installCardDrag()` / `positionCard()` 都留在卡片里;`verify-wiki-focus:770` 那条**按精确路径**读卡片、钉 `const mark = …note.defaultMark…` 的断言同样不受影响(被断言的那行没离开卡片)。⑤ 一个**诚实的差异**写进模块头(不改变可观察行为):旧代码直接闭包引用 `editor`/`titleInput`/`tagEditor`/`saveBtn`/`editBtn`,新代码经 `deps.getUi()`,于是两个函数各多一条 `ui === undefined` 早退(实践中不可达 —— 两者都由 `build()` 建出来的按钮与编辑器键位触发,写出来只为类型收窄)。**验证**:`typecheck` / `build`(client bundle 770,645 字节,仍 minify)/ 客户端五守门(`verify-frame-guards` / `verify-wiki-focus` / `verify-tw-origin` / `verify-client-i18n` / `verify-frame-surface`)/ `verify-editor-popup` / `verify:unit`(退出码 0)/ 全量 `npm run verify` 四档退出码 0(E2E / WIKI SWITCH / WIKI FARM BOOT / LARGE WIKI CHECKS 全绿)/ `verify-line-endings`(260 个文本文件全 LF)/ `verify-version-consistency` 全绿。
|
|
8
9
|
- **v0.30.44**(2026-09-29):**`note-widget.ts` 拆分第三轮 —— 抽出「草稿生命周期」整族,连同它持有的两个状态一起搬走(750 → 677 行)**。① 新模块 `src/client/note-widget-autosave.ts` 拿走 `resetTitle` / `flushDraft` / `scheduleDraft` / `hideDraftBanner` / `resetForNewNote`,**以及它们闭包里的 `draftTimer` 与 `persistedSignature`** —— 这一轮与前两轮都不同:**状态跟着函数整片搬走**,卡片只经模块返回的句柄读写(`resetTitle` / `flush` / `schedule` / `hideBanner` / `resetForNewNote` / `clearTimer` / `setPersistedSignature` / `markPersisted`)。② **为什么这次状态必须走**(而不是像 v0.30.41 的 scope 片那样只传访问器):`verify-frame-guards.mjs` 把两条不变量**按名字**钉在 `resetForNewNote` 的函数体里(`/clearTimeout\(draftTimer\)/` + `/persistedSignature\s*=/`),它们编码的正是 v0.22.8 的「幽灵草稿」事故 —— 「保存 / 丢弃后重置编辑器」必须①取消防抖定时器、②把这段空内容记成"已定型",否则 500ms 后那次防抖会把 `{text:'', title:'<时间戳>'}` 写成草稿、下次打开对着空编辑器报「已恢复未保存草稿」。把变量与函数整片搬走 ⇒ 两处字面量**逐字保留**、**一个守门都没有改**;反过来「改名成 `draft.timer` 再放宽断言」会把判据从「钉不变量」降级成「钉新名字」,那才是真正的损失。③ 卡片侧保留 `flushDraft` / `scheduleDraft` / `hideDraftBanner` / `resetTitle` 四个**局部别名**(`const { flush: flushDraft, … } = autosave`):这些名字在 `build()` / `dispose()` / `open()` 里有十几处调用,改名只放大 diff、不增加信息(v0.30.38 那条「优先抽取、少改名」)。④ 顺带删掉一处**只写不读的死状态** `autoTitle`:自 v0.29.0 起 `flushDraft` 的判据已从「正文为空 **且** 标题是自动生成的那个」升级成「正文为空」(守门还专门断言它不得再引用 `autoTitle`),于是这个变量只剩赋值 —— 把一个只写不读的变量搬进新文件等于把债务搬进新家。⑤ 两个**诚实的差异**写进了模块头,都不改变可观察行为:`getUi()` 可能返回 `undefined` ⇒ 模块里多了早退(旧代码直接闭包引用 `editor`/`titleInput`/`tagEditor`,那时卡片必然已 `build()`,真为 undefined 会抛 TypeError);`opened` / `disposed` **刻意不进**新模块,按谓词传进去(它们属于卡片的可见性生命周期,与 `note-widget-recent.ts` 同款处理)。⑥ **反向验证**:删掉模块里 `resetForNewNote` 的 `clearTimeout(draftTimer)` ⇒ `verify-frame-guards` 稳定 FAIL 在「保存/丢弃后重置必须取消防抖并记录已定型签名」;还原后文件哈希与注入前**逐字节一致** ⇒ 绿。**验证**:`typecheck` / `build`(client bundle 770,128 字节,仍 minify)/ 客户端五守门(`verify-frame-guards` / `verify-wiki-focus` / `verify-tw-origin` / `verify-client-i18n` / `verify-frame-surface`)/ `verify:unit`(42 套,退出码 0)/ 全量 `npm run verify` 四档退出码 0 / `verify-line-endings` / `verify-version-consistency` 全绿。
|
|
9
10
|
- **v0.30.43**(2026-09-29):**`note-widget.ts` 拆分第二轮 —— 抽出「卡片摆在哪 + 怎么拖」,817 → 750 行;顺手修掉一批写错版本号的注释**。① 新模块 `src/client/note-widget-placement.ts`(109 行)拿走两件事:`positionCard(root, card, anchor?)`(有锚点就贴在输入框上方、否则右下角,视口夹取)与 `installCardDrag({ root, card, head, closeBtn })`(标题栏拖动,pointer events + `setPointerCapture`)。**分界线怎么定的**:问「这段代码需要卡片给它什么」—— 两半都**只碰 DOM 元素和自己私有的手势状态**(`dragState`),对 wiki 名册 / 草稿 / 保存 token **零依赖**,所以一个访问器、一个 setter 都不用传(与前两轮的 `note-widget-scope.ts` 恰好相反:那边七个状态必须用访问器过桥)。这轮也因此**没有一个守门需要放宽** —— 全仓库 `grep` 不到任何 `dragState`/`applyDrag`/`pointerdown` 的断言。② 两个「别顺手清理掉」的语义已写进模块头:**`positionCard()` 每次 open 都跑**,所以拖过的位置**刻意不跨 open 保留**(下一次打开重新贴锚点);拖动的监听器挂在 `dispose()` 会移除的 DOM 上,所以**故意没有卸载步骤**。③ **补了一条守门**(`verify-frame-guards.mjs`,「每次 open 都重新定位 + 拖动接线只有一份实现」):前半钉 `open()` 里那次调用必须带上锚点(谁改成"记住位置"就是改了行为),后半**按精确路径**单独读卡片本体、断言 `setPointerCapture`/`pointerdown`/`dragState` 都**不在**卡片里(族读会把模块拼进来、分不出谁实现的 —— 这里正是"族读"与"精确读"必须各用一次的场景)。**反向验证**:去掉锚点参数 ⇒ 红;把 `dragState` 塞回卡片 ⇒ 红;还原后文件哈希与原文件一致。⚠️ 写这条守门时踩到 `bodyOf()` 的一个坑:**签名里别带 `{`** —— `bodyOf` 会自己跳到函数体的第一个花括号,签名带上 `{` 它就从那里往后找**内层**块,取到的不是整个函数(第一次断言因此假失败,已把这条写进脚本注释)。④ **顺带修掉 7 处写错版本号的注释**:上一轮(v0.30.41)的 `note-widget-scope.ts` 拆分被注释成了「v0.30.42」——`src/client/note-widget-scope.ts:4`、`src/client/note-widget.ts:36/111`、`scripts/verify-tw-origin.mjs:169`、`scripts/verify-wiki-focus.mjs:314/345/791` 全部改回 **v0.30.41**(`git log -S` 确认它们确实随 `d2417c5` 落地)。**教训与 v0.30.42 的 barrel 那条同源**:注释里的版本号/文件名/公共面**没有任何自动化校验**,只能靠人复核(顺带说明:这类"注释说的版本 ≠ 实际落地版本"不会让任何关卡变红)。**验证**:`typecheck` / `build`(client bundle 769,654 字节,仍 minify)/ 客户端五守门(`verify-frame-guards` / `verify-wiki-focus` / `verify-tw-origin` / `verify-client-i18n` / `verify-frame-surface`)/ `verify:unit`(42 套,退出码 0)/ 全量 `npm run verify` 四档退出码 0 / `verify-line-endings` / `verify-version-consistency` 全绿。
|