跳转至

关键类最终生效声明(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/ 为升级前旧路径;本页按新位置书写,路径参数不变):

用法:
  python .scratch/ui-keyrules.py --css apps/web/index/css/nf.css --out .scratch/ui-keyrules.txt

参数来自 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

期望输出形态:

written: .scratch/ui-keyrules.txt (23456 bytes)

正文形如:

== 关键类:最终生效的显示完整性声明(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)。
  • 清理方式:
Remove-Item -Force .scratch/ui-keyrules.txt
  • 不给 --out 时无任何落盘物,无需清理;线上侧无需回滚。