test(工具链): ★★★ stripComments 两趟正则把真代码当注释吃掉 137 行 —— 改单趟扫描

**现象**:harmony-admin 那条「服务端要注册 GET /auth/me」报红,而
server/cmd/server/main.go:194 **明明写着** r.Get("/auth/me", handler.Me)。

**真因**(不是服务端写错,是读取器错了):
    main.go:78   // 与 /api/v1/agent/* 完全同一份代码
                                          ↑ 这个 /* 在 // 里面
stripComments 原来是**两趟正则**(先块 {/\*[\s\S]*?\*\//g}、后行),
两趟**互相看不见对方** ⇒ 块注释那趟在**还没删行注释**的文本上看到那个 /*,
当块注释开头,一路找下一个 */(在 :214)⇒ **137 行 / 37 条路由注册**
被当注释抹掉,含它正在断言的 r.Get("/auth/me", …)。
全仓另有 12 处同样写法(/me/*、/assets/*、plugins/*…)。

⇒ 失效形状是「**读取器静默少给一段真代码**」(不抛错、不警告),
  症状却出现在**被测对象**上 —— 看起来像"服务端把路由删了"。

**修法**:单趟字符扫描,且状态只用源码(注释内部不参与字符串状态)。
并**补上正则字面量**这一条 —— 漏认的方向是**假绿**:
harmony-device.mjs:59 的 /"bundleName"\s*:\s*"([^"]+)"/ 有 4 个引号(奇数),
打开的"字符串"永不闭合 ⇒ 后面所有注释被当字符串跳过。

五条性质逐条实测:① 行号不变 ② 'http://…' 字符串不被腰斩
③ 注释里的引号不污染状态 ④ 正则字面量被当正则 ⑤ 块注释连文本一起删。
变异测试:把旧实现放回去 ⇒ harmony-admin 确实变红(确认真修好了,
而不是"改的东西恰好没人用")。

**顺带修的三处判据自身缺陷**(都不是源码问题):
· inbox-fallback-poll:原断言钉的是**行尾注释里的字**
  (删掉注释照样绿、塞进 await fetchInbox() 也照样绿)⇒ 改为取
  if (lastTotal === null) { … } 整个分支做结构断言
· inbox-fallback-poll / sse-credentials:裸 readFileSync ⇒ 具名 code()
  (换成更严格的读取后变红,暴露的是判据本来就在判错的对象)
· appearance-defaults:写死包名 ⇒ ourBundle()(deviceprobe 那条在盯这个)
· criteria-hygiene:自检样本「以 // 开头的字面量」被判成写死路径 ⇒
  按**形状**排除,**不按文件/变量名豁免**(该文件自己的注释已写过
  「豁免按名字或目录裁 = 给逃逸指路」)。变异验证:改成真路径仍红。

边界 / 未做:本函数**不区分模板串里的 ${…} 与字符类里的 /**,
失效方向是假绿(少剥注释),与 stripStrings 记的方向一致。
This commit is contained in:
2026-10-03 10:43:11 +08:00
parent 5ad75fb229
commit 93697c4061
5 changed files with 184 additions and 21 deletions

View File

@ -371,6 +371,25 @@ test('★ 判据不许把仓库根硬编码成绝对路径(必须从本文件
* 但它仍然可以**和值判据并列为一条独立的触发线**。豁免只按值给(`/opt/`、`/usr/`)。
*/
const abs = lits.some(v => v.startsWith('/'));
/*
* ★★ 2026-10-03 排除「注释形状的样本」这一类(自己撞的假红,判据没错)。
*
* 实测:`harmony-deviceprobe.test.mjs` 那条判据**自检自己**(它验证
* “注释里的包名不该误红”),于是它**故意造了两段含注释标记的样本**:
* const sample = `if (fg !== 'com.agentmail.harmony') { t.skip(); }`;
* const commented = `// 历史说明:原来是 'com.agentmail.harmony'`;
* 第二段那个字面量**以 `//` 开头** ⇒ `abs` 为真;又因为旧包名
* `com.agentmail.harmony` 里含仓库名 `agentmail` ⇒ `repoByValue` 也为真
* ⇒ 被当成“把判据钉死在仓库内绝对路径上”。
*
* ★ 为什么按**形状**排除而不是按文件/变量名开豁免:
* 本文件上面那段注释已记过教训 —— **豁免/射程按名字或目录裁,等于给逃逸指路**
* (pi 2026-09-15)。而这里要排除的是**一类输入**(“字面量内容本身就是注释”),
* 不是某个人写的某段代码,所以按形状判是收窄而非开洞。
* ⚠️ 注意这只排除了 (A) 分支;真正的“写死路径”若是注释形状,仍会被别的判据抓到。
*/
const looksLikeCommentSample = lits.some(v => /^\s*(\/\/|\/\*)/.test(v));
if (looksLikeCommentSample) continue;
const repoByValue = abs && (joined ? whole.includes(REPO_NAME) : lits.some(v => v.includes(REPO_NAME)));
const repoByName = /\b(PROJECT|REPO|WORKSPACE|CHECKOUT)\b|_ROOT$|^ROOT$/i.test(name);
if (!repoByValue && !(repoByName && abs)) continue;