长内容类覆盖核对(ui-coverage.py)¶
位置:
deploy/nfos/tools/ui-coverage.py| 语言:python3 | 是否需要 root:否
工具性质:本地静态核对(只读 CSS + 页面 JS;只写 --out 指定的文件)
运行前提:仓库检出必须在场(加载 apps/web/tests/lint-layout.py)。可从任意位置运行(工具自动向上找到含 deploy/nfos 的祖先目录)
部署状态:随仓库检出运行,不部署到 /opt/Cy/services/system.d/nfos/
用途¶
逐条核对「真实页面用到的 nf-* 类 → 命中哪条显示完整性规则」。
源码 docstring(逐字引用):
没有浏览器时,这是“真实页面兜底检查”的替代品:
1) 从真实页面 JS 里抽出它用到的 nf-* 类名(class="..." / className / 字符串字面量);
2) 从 nf.css 里解析出“与显示完整性有关”的规则(overflow / white-space / min-width /
max-width / max-height / overflow-wrap / word-break / text-overflow / width:max-content);
3) 逐类列出命中的规则(选择器 + 行号 + 关键声明),并标出“无任何完整性规则覆盖”的类。
实现要点:
| 环节 | 源码行为 |
|---|---|
| 类名抽取 | 4 条正则 CLASS_RX:class="..."、class='...'、class: '...'、以及形如 'nf-a nf-b' 的字符串字面量;只保留以 nf- 开头的词元 |
| 规则解析 | importlib 加载 lint-layout.py,用其 split_rules(css) + decls(body) 取声明;只保留 KEYS 里的属性(overflow / overflow-x / overflow-y / white-space / min-width / max-width / max-height / height / overflow-wrap / word-break / text-overflow / width / display / flex / min-height) |
| 匹配 | 对角色的选择器做词边界匹配 (^\|[\s,>+~(])\.<类名>(?![\w-])(支持后代/逗号/子选择器等组合) |
| 未覆盖 | 无匹配的类归入 uncovered 并单独输出一行,措辞为“(无完整性规则命中,通常是无害的原子类/装饰类: ...)” |
典型场景¶
- 新增/改写页面模块后,确认它用到的长内容容器类(表格、
kv、code、弹层、抽屉、通知列表等)在 CSS 里确有显示完整性声明; - 排查“某一列/某块内容显示不全”时,先把该类是否被任何规则覆盖查清楚,再决定改 CSS 还是改页面结构;
- 与
ui-keyrules.py(最终生效声明)、ui-delta.py(前后对比)、ui-audit.py(模式计数)联用,构成无浏览器时的证据链。
用法与参数¶
源码 docstring 给出的用法(逐字引用,.scratch/ 为升级前旧路径;本页按新位置书写,路径参数不变):
用法:
python .scratch/ui-coverage.py --css apps/web/index/css/nf.css \
--pages apps/web/console/js/pages/dashboard.js apps/web/online/js/pages/alerts.js ... \
--out .scratch/ui-coverage.txt
参数来自 argparse.ArgumentParser():
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
--css |
字符串(文件路径) | 无默认值(required=True) |
被核对的 CSS 文件 |
--pages |
字符串列表(nargs='+',空格分隔多个) |
无默认值(required=True) |
要核对的一个或多个页面 JS 文件 |
--out |
字符串(文件路径) | ''(空 = 写 stdout) |
输出文件;给值时打印 written: <path> (<N> bytes) |
无参数时的默认行为:没有默认行为 —— --css 与 --pages 都是必填,缺任一者 argparse 会报错并以退出码 2 结束。
两个路径参数都按当前工作目录解析(源码不做仓库根拼接),因此推荐在仓库根执行并传相对路径。
示例¶
从仓库根目录执行(页面文件按需替换为实际要核对的页面):
python deploy/nfos/tools/ui-coverage.py --css apps/web/index/css/nf.css `
--pages apps/web/console/js/pages/dashboard.js apps/web/online/js/pages/alerts.js `
--out .scratch/ui-coverage.txt
期望输出形态:
正文形如:
== 真实页面「长内容」类覆盖核对 ==
css: apps/web/index/css/nf.css
css 中与显示完整性相关的规则条数: ...
----- apps/web/console/js/pages/dashboard.js (用到 12 个 nf-* 类) -----
.nf-table -> 3 条规则
L1234 .nf-table display:table; ...
(无完整性规则命中,通常是无害的原子类/装饰类: nf-tag, ...)
| 情形 | 期望退出码 |
|---|---|
| 正常完成 | 0(源码未调用 sys.exit) |
缺 --css / --pages |
2(argparse 报错) |
CSS 或页面文件不存在 / --out 不可写 |
1(Python traceback) |
lint-layout.py 缺失或接口变更(split_rules/decls 不存在) |
1(importlib/AttributeError traceback) |
“未覆盖的类”不影响退出码:本工具输出的是清单,不是断言。
依赖与权限¶
- 语言/版本:Python 3(
#!/usr/bin/env python3)。 - 第三方依赖:无,标准库
argparse/importlib.util/io/os/re/sys。 - 仓库依赖:必需 ——
load_lint()用importlib.util.spec_from_file_location加载<repo>/apps/web/tests/lint-layout.py,并依赖其split_rules/decls两个函数。 - 权限:不需要 root;不需要网络(纯离线);写权限仅用于
--out。
风险与注意事项¶
- 只读输入,只写
--out:不修改 CSS、不修改页面 JS、不改lint-layout.py。不传--out时只写 stdout,不落盘。 - 类名抽取是启发式:只认 4 条正则形式;动态拼出来的类名(模板字符串、变量拼接、
'nf-' + x)抽不到,会低估覆盖率。 - “无完整性规则命中”不等于有问题:输出里已按源码措辞标注“通常是无害的原子类/装饰类”。真正需要关注的是那些本应是长内容容器却零命中的类。
- 依赖
lint-layout.py的当前接口:split_rules/decls的签名或返回值变化会让本工具直接报错(这是回归信号,不是静默降级)。 - 覆盖率统计的是“该类名出现在至少一条含完整性属性的选择器里”,不判断声明的值是否合理(例如
overflow:hidden本身就可能正是致病写法)。
回滚¶
本工具不部署到线上、不改线上系统;不改动任何被核对文件。
- 产出/改动位置:仅
--out指定的文件(例如.scratch/ui-coverage.txt)。 - 清理方式:
- 不给
--out时无任何落盘物,无需清理;线上侧无需回滚。