fix(fe): 修弹层编译不过(链首被删),检查器补上 wx:if 链校验
## Bug 上一批把 9 个记录分支从弹层整体搬到 addrecord 页时,连带删掉了带 wx:if 的 第一支(weight),整条链从 wx:elif 开头。小程序直接报 Bad attr `wx:elif` with message: `wx:if not found, then something must be wrong` 整个组件编译不过 —— 不是少个样式,是弹层完全打不开。把现在的链首 (就医前摘要)改成 wx:if。 ## 检查器补这一条 这种错「删对了 9 支、漏改 1 个属性」就会发生,而且是编译期爆炸, 检查器原来完全看不见。 判断必须靠真正的标签栈。中间走错两次,都值得写下来: **① 按缩进深度分链 —— 不行。** 这个项目里 scroll-view 和它的子节点缩进 是一样深的,「同层」判断会把父节点当兄弟节点。而且更糟的是它不报错: 前一条链的 wx:if 被当成这一条的链首,注入错误也查不出来,是个假绿。 **② 给 void 标签列白名单 —— 不行。** wxml 里 <image></image> 是显式闭合的, 把它当 void 就变成「开标签不入栈、闭标签却弹栈」,一路把父级弹光,8 个误报。 只认 /> 就够。 **③ 自闭合不能用单独的捕获组。** 属性那段是贪婪的,会把 /> 里的 / 一起吃掉, (\/?) 永远匹配空。多行写的 <input ... /> 因此被当成非自闭合入了栈, 把整份栈层级带偏,7 个误报。改成从 attrs 尾部 /\/\s*$/ 判断。 ## 自测 把链首改回 wx:elif → 精确报第 96 行那一处,其余 24 个 wxml 零误报; 还原 → 恢复绿。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -96,8 +96,8 @@ module.exports.sel = function (map, key, index, def) {
|
||||
搬到 pages/addrecord —— 字段由后端 record_types.fields 驱动,一个页面吃掉
|
||||
全部 24 种,不再每种一个 wx:elif。弹层现在只管「不是记一笔」的那些事:
|
||||
提醒、海报、档案、发帖、评论…… -->
|
||||
<!-- 就医前摘要 -->
|
||||
<block wx:elif="{{innerType === 'vetSummary'}}">
|
||||
<!-- 就医前摘要。这是链上第一支,必须是 wx:if -->
|
||||
<block wx:if="{{innerType === 'vetSummary'}}">
|
||||
<view class="sheet-h3">就医前摘要</view>
|
||||
<view class="sheet-p pre">宠物:{{pet.name}}
|
||||
阶段:{{pet.stage}}
|
||||
|
||||
@@ -91,6 +91,48 @@ for (const f of files.filter((f) => f.endsWith('.wxml'))) {
|
||||
}
|
||||
}
|
||||
|
||||
// wx:if / wx:elif / wx:else 链的第一支必须是 wx:if。
|
||||
// 删掉链首那一支(比如把 9 个记录分支整体搬走)会让整条链从 wx:elif 开头,
|
||||
// 小程序报「wx:if not found」直接编译不过——整个组件一起挂,不是少个样式。
|
||||
//
|
||||
// 判断必须靠真正的标签栈,不能靠缩进:这个项目里 scroll-view 和它的子节点
|
||||
// 缩进是一样深的,按缩进判「同层」会把父节点当成兄弟节点,什么都查不出来。
|
||||
{
|
||||
const noComment = src.replace(/<!--[\s\S]*?-->/g, '');
|
||||
const stack = [{ last: null }]; // 每层记「上一个兄弟节点带的条件指令」
|
||||
const re = /<(\/?)([a-zA-Z][\w-]*)((?:[^>"']|"[^"]*"|'[^']*')*)>/g;
|
||||
let m;
|
||||
while ((m = re.exec(noComment))) {
|
||||
const [, closing, tag, rawAttrs] = m;
|
||||
// 自闭合要从 attrs 尾部判断:属性那段是贪婪的,会把 /> 里的 / 一起吃掉,
|
||||
// 单独用一个 (\/?) 捕获组永远是空的。多行写的 <input ... /> 就是这么
|
||||
// 被当成非自闭合、入了栈,把整份栈的层级全带偏,满屏误报。
|
||||
const selfClose = /\/\s*$/.test(rawAttrs);
|
||||
const attrs = rawAttrs.replace(/\/\s*$/, '');
|
||||
const top = stack[stack.length - 1];
|
||||
if (closing) {
|
||||
if (stack.length > 1) stack.pop();
|
||||
continue;
|
||||
}
|
||||
const cond = /\bwx:if\b/.test(attrs) ? 'if'
|
||||
: /\bwx:elif\b/.test(attrs) ? 'elif'
|
||||
: /\bwx:else\b/.test(attrs) ? 'else' : '';
|
||||
if (cond === 'elif' || cond === 'else') {
|
||||
if (top.last !== 'if' && top.last !== 'elif') {
|
||||
const line = noComment.slice(0, m.index).split('\n').length;
|
||||
problems.push(`${r}: 第 ${line} 行附近 <${tag} wx:${cond}> 前面没有 wx:if` +
|
||||
` —— 链首被删了,这个文件编译不过`);
|
||||
}
|
||||
}
|
||||
// 没带条件的兄弟节点会把链断开,所以无条件覆盖
|
||||
top.last = cond || null;
|
||||
// 不搞「void 标签」白名单:wxml 里 <image></image> 是显式闭合的,
|
||||
// 把它当 void 就会「开标签不入栈、闭标签却弹栈」,一路把父级弹光,
|
||||
// 于是满屏误报。只认 /> 自闭合,其余一律入栈。
|
||||
if (!selfClose) stack.push({ last: null });
|
||||
}
|
||||
}
|
||||
|
||||
// 事件绑定的方法必须真的存在——绑了个不存在的方法,点了没反应且不报错
|
||||
if (fs.existsSync(js)) {
|
||||
const code = read(js);
|
||||
|
||||
Reference in New Issue
Block a user