docs: 阶段2收尾——ADR-016/typecheck链/阶段3移交清单/README
- ADR-016:saxes ^6.0.0(勘误:计划曾误写 ^0.9)/commander ^14 根依赖/清洗三件套 同 range + 镜像直调 launder.naughtyHref/tsx ^4 CLI 直吃 TS;跨包接线(根 tsconfig paths 三方消费、build 侧 dist+prebuild、tsconfig 双链型并存);根 engines 升 >=22.12(对齐 sanitize-html 2.18 engines,CI node 22 与本机 24 均满足) - 根 typecheck 链扩为四段:追加 pnpm --filter @sf/adapter-wp typecheck - Plan 2 文末新增"移交阶段 3 清单"定稿(7 项:taxonomyRefs 自建缺失 term、 media_bundle 映射、connection 库级唯一索引、REST 重审项、导入消费接口、 Task 0.2 cms 备份续传携带、versions.ts bump 纪律);Task 9 与验收节勾选 - README:快速开始加 pnpm sf 示例;目录结构/文档导航/当前状态更新为阶段 2 完成 - 三绿:lint / typecheck(四段)/ test 263 全部通过(数量不变) Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,23 @@
|
||||
# ADR-016:阶段 2 新增依赖与跨包接线
|
||||
|
||||
- **状态**:已采纳(Plan 2 Task 9 收尾,阶段 2;许可证已逐项核验——saxes ISC,commander/sanitize-html/parse-srcset/launder/tsx 均 MIT)
|
||||
|
||||
## 决策一:新增依赖(选型 / 版本范围 / 定位)
|
||||
|
||||
1. **saxes `^6.0.0`**(@sf/adapter-wp 运行时依赖)——WXR 流式 SAX 解析的唯一解析库。**勘误**:Plan 2 Task 3 曾误写"锁 ^0.9"(0.x 是多年前的旧版本线),实施时按 npm 实际主线锁 `^6.0.0`;默认不解析外部实体(XXE 面由测试钉死)。`versions.ts` 的 `PARSER_VERSION` 常量须与实际解析版本同步(当前 `'saxes 6.0.0'`)。
|
||||
2. **commander `^14.0.0`(根依赖)**——CLI 入口在仓库根 `scripts/sf.ts`,而 @sf/adapter-wp 定位纯函数包、不消费 CLI 框架;commander 放根,不给库包带入无关运行时依赖。
|
||||
3. **清洗三件套 `sanitize-html ^2` + `parse-srcset ^1` + `launder ^1`**(@sf/adapter-wp 运行时依赖,三条 range 并存)——sanitize-html 是清洗本体;srcset/imagesrcset 审计用 parse-srcset(sanitize-html 内部即同库依赖);URL 拒绝判定**直接调用 `launder.naughtyHref`**——sanitize-html 2.18 内部即解构调用同一函数,镜像判定与库本体零漂移(依赖升级时由参数化对抗测试护栏兜底)。三件套用同一主版本 range 跟随解析:launder/parse-srcset 本是 sanitize-html 的传递依赖,若单独锁死版本,会造成"镜像调用的 launder"与"库内部用的 launder"版本 skew。类型:@types/sanitize-html、@types/parse-srcset 走 devDependencies;launder 无官方类型,本包自带 d.ts 垫片(`src/types/launder.d.ts`)。
|
||||
4. **tsx `^4`(根 devDependency)**——CLI 直吃 TS 源码:`pnpm sf` = `tsx scripts/sf.ts`,无需预构建 dist(apps/api 的 Nest 装饰器源码同样可跑);tsx 属开发工具链,不进任何运行时依赖。
|
||||
|
||||
## 决策二:跨包接线
|
||||
|
||||
5. **根 tsconfig paths 三方消费(单源)**:`@sf/contracts` 与 `@sf/adapter-wp` 到各自 `src/index.ts` 的映射只在根 `tsconfig.json` compilerOptions.paths 维护一份——包级 tsc 经 extends 继承;vitest 不读 tsconfig paths,由 `vitest.config.ts` 的 `resolve.alias` 镜射同一映射;tsx 原生读 tsconfig paths。三方(包级 tsc / vitest / tsx)全部直连 `src/index.ts`——日常开发链 import 不经 dist、无预构建依赖。
|
||||
6. **build 侧 dist + prebuild**:@sf/adapter-wp 的 `tsconfig.build.json` 把 `@sf/contracts` 改指 `packages/contracts/dist/src/index.d.ts`(emit 程序不得包含包外源文件,TS6059),由 prebuild 先 `pnpm --filter @sf/contracts build` 供给 dist 声明。dist 只为发布产物完整性负责;typecheck / test / CLI 通道不依赖它。
|
||||
7. **tsconfig 双链型并存**:contracts extends `tsconfig.base.json`(无跨包 import,不需要 paths);adapter-wp extends **根 tsconfig.json**(为继承 baseUrl/paths 跨包映射)。两条 extends 链并存是有意的:包是否需要跨包映射决定挂哪条链,不为形式统一强行并链。**src-vs-dist 的最终口径即上述 5+6:开发链 src 直连、build 链 dist+prebuild,双轨并存**(Plan 1 终审前瞻项在此落定)。
|
||||
|
||||
## 决策三:engines 口径
|
||||
|
||||
8. **根 engines 升 `>=22.12`**:sanitize-html 2.18 的 engines 要求 node `>=22.12.0`,根原口径 `>=22` 会放行 sanitize-html 不支持的 22.0–22.11。升根一行对齐(CI 的 node 22 取最新 22.x、本机 24 均满足);否决的替代方案是 pin sanitize-html 旧版——为迁就旧 patch 版 node 反向锁死清洗库,不取。后续新增依赖若 engines 高于根,同理评估升根而非降依赖。
|
||||
|
||||
- **理由**:全部依赖均为单一职责引入(解析/清洗/CLI/TS 执行各一),无重叠;版本范围统一锁主版本(`^`),与"锁版本 + 核许可证 + 记 ADR"的新增依赖三纪律一致;跨包接线坚持单源配置(paths 一份、alias 镜射),把 skew 面压到最小。
|
||||
- **权衡/陷阱**:① vitest alias 是根 paths 的人工镜射,新增 workspace 包时两处要同步改;② build 链与开发链对 `@sf/contracts` 的解析目标不同(dist 声明 vs src),dist 过期只影响产物不影响日常——发布前跑 build 即可暴露;③ launder 镜像判定的等价性依赖"sanitize-html 内部继续用 launder 同一函数",升级 sanitize-html 大版本时须重验(对抗测试在 `test/html-sanitize.test.ts`);④ engines 对齐的是传递依赖里最严的要求,属"就高"策略,接受它对低版本 node 的排斥。
|
||||
@@ -138,18 +138,30 @@ cms-one/
|
||||
- [ ] Step 2: 峰值内存记录——smoke 脚本内 `setInterval(100ms)` 采样 `heapUsed` 与 `rss` 取 max(瞬时值无意义);流式断言:解析 5.5MB 文件峰值 heapUsed < 100MB(不整读)
|
||||
- [ ] Step 3: 耗时记录;结果写 evidence 文档;commit `test(evidence): 阶段2真实WXR冒烟通过`
|
||||
|
||||
### Task 9: 阶段 2 收尾
|
||||
### Task 9: 阶段 2 收尾 ✅ 完成(ADR-016 定稿 / typecheck 四段链 / 根 engines 升 >=22.12 / 移交阶段 3 清单 / README,同批一个 docs commit;三绿 263 不变;不 push——推送由用户执行)
|
||||
|
||||
- [ ] ADR-016(saxes/commander/sanitize-html 选型与许可证);根 typecheck 链加 @sf/adapter-wp;lint 全绿;contracts 首个消费者接线验证(adapter-wp workspace 依赖 contracts——**Plan 1 终审前瞻项落实**:import 路径用 dist 还是 src 的决策一并入 ADR-016)
|
||||
- [ ] **Task 7 审查移交**:① connection (site_id,name) 库级唯一索引须在第二个写入方(REST 通道)出现前完成 ② media_bundle→WXR attachment URL 的映射策略(uploads 路径约定)记入阶段 3 计划输入 ③ REST 化时重审:白名单 TOCTOU、cwd 自动放行、connection.kind 枚举扩 ④ sanitize-html engines>=22.12 与根 engines>=22 的口径(升根或记 ADR)
|
||||
- [ ] 全量三绿 + push;plan 勾选;**移交阶段 3 清单**(内容/分类/媒体入库:media 魔数校验、source_records 落库、稳定身份 upsert、checksum skip、route_registry 生成;**续传携带:Task 0.2 cms 数据备份(用户暂缓,阶段 6 L3 验收前必须补做**——责任链不断)
|
||||
- [x] ADR-016(saxes/commander/sanitize-html 选型与许可证);根 typecheck 链加 @sf/adapter-wp;lint 全绿;contracts 首个消费者接线验证(adapter-wp workspace 依赖 contracts——**Plan 1 终审前瞻项落实**:import 路径用 dist 还是 src 的决策一并入 ADR-016)
|
||||
- [x] **Task 7 审查移交**:① connection (site_id,name) 库级唯一索引须在第二个写入方(REST 通道)出现前完成 ② media_bundle→WXR attachment URL 的映射策略(uploads 路径约定)记入阶段 3 计划输入 ③ REST 化时重审:白名单 TOCTOU、cwd 自动放行、connection.kind 枚举扩 ④ sanitize-html engines>=22.12 与根 engines>=22 的口径(升根或记 ADR)——①~④ 均已沉淀至文末"移交阶段 3 清单",④ 已落 ADR-016 决策三(根 engines 升 >=22.12)
|
||||
- [x] 全量三绿 + plan 勾选;**移交阶段 3 清单**(见文末新节定稿);push 由用户执行(本任务不 push)
|
||||
|
||||
## 验收(对照 spec §15 阶段 2)
|
||||
|
||||
- [ ] `source:register` 三类输入登记幂等,快照 content-addressed 且不可变
|
||||
- [ ] 脱敏夹具全链全绿(mini.xml → 5 row + 0 意外 unsupported)
|
||||
- [ ] 大文件不整读内存(5.5MB 峰值 <100MB)
|
||||
- [ ] 恶意/畸形输入安全失败(外部实体/超限/截断——带位置错误,不崩溃不静默)
|
||||
- [ ] 解析器不访问网络(测试钉死)
|
||||
- [ ] 真实 WXR 冒烟计数与基线逐项一致;unsupported 75 条分类清晰
|
||||
- [ ] 三绿(lint/typecheck/test)+ 全部推送
|
||||
- [x] `source:register` 三类输入登记幂等,快照 content-addressed 且不可变
|
||||
- [x] 脱敏夹具全链全绿(mini.xml → 5 row + 0 意外 unsupported)
|
||||
- [x] 大文件不整读内存(5.5MB 峰值 <100MB)
|
||||
- [x] 恶意/畸形输入安全失败(外部实体/超限/截断——带位置错误,不崩溃不静默)
|
||||
- [x] 解析器不访问网络(测试钉死)
|
||||
- [x] 真实 WXR 冒烟计数与基线逐项一致;unsupported 75 条分类清晰
|
||||
- [x] 三绿(lint/typecheck/test,263 测试);推送由用户执行(Task 9 不 push)
|
||||
|
||||
---
|
||||
|
||||
## 移交阶段 3 清单(Plan 2 收官定稿——散落各任务的移交项汇总,阶段 3 计划的必读输入)
|
||||
|
||||
1. **taxonomyRefs 解析:wp:term 表不完备(真实数据实证)**——本 WXR 的 term 表缺 category(148 引用/5 nicename)与 post_tag(659 引用/471 nicename)条目(WordPress 7.1.3 导出行为)。阶段 3 做 slug→term 解析时须按 **(domain, nicename) 自建缺失 term**(item 引用的 value 作 name),不能只依赖 wp:term 事件。锚点设计已被实数据正向验证:term 表覆盖的 taxonomy 内 nicename≡slug 100%(706/706,见 `docs/evidence/phase2-smoke.md`)。
|
||||
2. **media_bundle → WXR attachment URL 映射策略**——media 清单(snapshot metadata.manifest,相对路径)与 WXR item 的 attachment_url/图库引用之间的映射须定策略(WordPress uploads 路径约定 `wp-content/uploads/<yyyy>/<mm>/<file>`;路径对拍 + 失配报告)——消费清单时面对。
|
||||
3. **connection (site_id, name) 库级唯一索引**——现为应用层 select-then-insert(事务 + advisory lock 保护,register.service.ts 注释已注明);**第二写入方(REST 通道)出现前**必须落库级唯一约束。
|
||||
4. **REST 通道落地时重审**——路径白名单 TOCTOU(校验与 open 之间的窗口)、CLI cwd 自动放行的去留、connection.kind 枚举扩('cli' 之外的新来源值)。
|
||||
5. **导入管道消费接口**——registerSource 返回值与 snapshot metadata 形状(含 storageRoot/manifest)是阶段 3 的输入契约,消费侧若需变形优先加法扩展;source_records 落库用稳定身份键(ADR-006);checksum skip 语义:changed=false → skip(报告 created/skipped 即导入前投影,spec §7.5)。
|
||||
6. **续传携带:Task 0.2 cms 数据备份**(用户暂缓)——**阶段 6 L3 验收前必须补做,责任链不断**。
|
||||
7. **versions.ts bump 纪律提醒**——映射表(DEFAULT_TYPE_ROUTES / STATUS_MAP / META_KEYS)或清洗白名单(SANITIZE_CONFIG)任何实质变更,须 bump 对应 MAPPING_VERSION / SANITIZER_VERSION(bump 语义 JSDoc 已冻结于 `packages/adapter-wordpress/src/versions.ts`);下游以版本块判断是否需要重新标准化(spec §7.5)。
|
||||
|
||||
Reference in New Issue
Block a user