关键类最终生效声明(ui-keyrules.py)¶
位置:
deploy/nfos/tools/ui-keyrules.py| 语言:python3 | 是否需要 root:否
工具性质:本地静态核对(只读 CSS;只写 --out 指定的文件)
运行前提:仓库检出必须在场(加载 apps/web/tests/lint-layout.py)。可从任意位置运行(工具自动向上找到含 deploy/nfos 的祖先目录)
部署状态:随仓库检出运行,不部署到 /opt/Cy/services/system.d/nfos/
用途¶
输出「关键类最终生效的显示完整性声明」,并带上 @media 上下文。
源码 docstring(逐字引用):
用途:无浏览器时的“类 → 命中哪条规则”逐条核对(报告里的覆盖表)。
按 CSS 文件顺序做**层叠折叠**(同选择器 + 同 @media 后者胜出),
这样“追加区块覆盖旧行”的修复方式不会被误读。
实现要点:
| 环节 | 源码行为 |
|---|---|
| 折叠键 | (media.strip(), 归一化选择器) —— 同选择器 + 同 @media 文件顺序后者胜出(cur['props'].update(keep)、cur['line'] = line) |
| 属性过滤 | 只保留 PROPS:display / overflow / overflow-x / overflow-y / white-space / text-overflow / overflow-wrap / word-break / min-width / max-width / min-height / max-height / width / height / flex / grid-template-columns |
| 合并选择器 | 用 lint_layout.split_sel(sel) 拆开(如 .nf-table th, .nf-table td),避免“精确等于选择器”的查表漏掉声明 |
| 被查的类 | 源码内 KEYS 列表共 48 个关键选择器(表格 nf-table*、nf-kv*、nf-code/nf-terminal*、弹层 nf-modal*/nf-drawer*、nf-nowrap/nf-truncate-safe/nf-wrap、标签 nf-tag/nf-badge/nf-level/nf-status、浮层 nf-search-results/nf-user-menu/nf-notify-*/nf-toast-body、布局 nf-page*/nf-card-body/nf-split/nf-aside/nf-side/nf-nav*、nf-grid*/nf-theme/nf-error-banner-detail/nf-scroll/nf-tabs) |
| 追加区块标记 | 以 css.find('WEB-UI-CLIP-FIX BEGIN') 定位“结尾追加区块”起始偏移,行首偏移 ≥ 该偏移的规则标记为 NEW,否则 old |
| 摘要行 | 打印 css sha16=... bytes=... 追加区块起始偏移=...(找不到标记时为 -1) |
典型场景¶
- 确认“追加区块覆盖旧行”的修复真的生效(同一个类/同一个
@media下,最终留下的是新区块里的声明); - 排查“CSS 里明明写了
overflow-wrap:anywhere却没效果”时,检查是否被同选择器、同@media的后一条规则覆盖掉; - 与
ui-delta.py(前后对比)、ui-coverage.py(类覆盖率)、ui-audit.py(模式计数)联用,出具无浏览器时的“显示完整性证据表”。
用法与参数¶
源码 docstring 给出的用法(逐字引用,.scratch/ 为升级前旧路径;本页按新位置书写,路径参数不变):
参数来自 argparse.ArgumentParser():
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
--css |
字符串(文件路径) | 无默认值(required=True) |
被核对的 CSS 文件 |
--out |
字符串(文件路径) | ''(空 = 写 stdout) |
输出文件;给值时打印 written: <path> (<N> bytes) |
无参数时的默认行为:没有默认行为 —— --css 是必填,缺失时 argparse 报错并以退出码 2 结束。
--css按当前工作目录解析(源码不做仓库根拼接),推荐在仓库根执行并传相对路径。
示例¶
从仓库根目录执行:
python deploy/nfos/tools/ui-keyrules.py --css apps/web/index/css/nf.css --out .scratch/ui-keyrules.txt
期望输出形态:
正文形如:
== 关键类:最终生效的显示完整性声明(css=apps/web/index/css/nf.css)==
css sha16=... bytes=... 追加区块起始偏移=...
--- .nf-table ---
[base] L1234 old display:table; width:100%; min-width:0
[max-width:900px] L5678 NEW display:block; overflow-x:auto
--- .nf-code ---
(css 中无此选择器的完整性声明)
| 情形 | 期望退出码 |
|---|---|
| 正常完成 | 0(源码未调用 sys.exit) |
缺 --css |
2(argparse 报错) |
CSS 文件不存在 / --out 不可写 |
1(Python traceback) |
lint-layout.py 缺失或 split_rules/decls/split_sel 接口变更 |
1(importlib/AttributeError traceback) |
“某类无声明”不影响退出码:本工具输出的是清单,不是断言。
依赖与权限¶
- 语言/版本:Python 3(
#!/usr/bin/env python3)。 - 第三方依赖:无,标准库
argparse/importlib.util/io/os/re/sys(哈希用__import__('hashlib'))。 - 仓库依赖:必需 ——
load_lint()加载<repo>/apps/web/tests/lint-layout.py,依赖其split_rules/decls/split_sel。 - 权限:不需要 root;不需要网络(纯离线);写权限仅用于
--out。
风险与注意事项¶
- 只读输入,只写
--out:不修改 CSS、不改lint-layout.py。不传--out时只写 stdout,不落盘。 - 折叠模型是简化的层叠:只按「同
@media+ 同选择器字符串」判定后者胜出,不计算 CSS 特异性(specificity)、不处理!important的完整语义、不合并不同选择器写法(.nf-code与.nf-code.foo视为两个键)。它是“读表工具”,不是浏览器渲染等价物。 NEW/old依赖追加区块标记:以WEB-UI-CLIP-FIX BEGIN的字符偏移为界;若该标记不存在(偏移=-1),所有规则都会被标为old。源码里判定表达式含一个恒真项(v['line'] * 0 + 1),对结果无功能影响,无需据此怀疑输出。- 只查
KEYS里那 48 个选择器;不在列表里的类不会出现在报告里。 - 输出中的
[base]表示该规则不在任何@media内;[<条件>]为该@media的条件文本。
回滚¶
本工具不部署到线上、不改线上系统;不改动任何被核对文件。
- 产出/改动位置:仅
--out指定的文件(例如.scratch/ui-keyrules.txt)。 - 清理方式:
- 不给
--out时无任何落盘物,无需清理;线上侧无需回滚。