Files
T

93 lines
3.9 KiB
Python
Raw Normal View History

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""骨架单一可信源闸门:`prd/2b-界面布局.md` §二 ↔ 原型里的 FROZEN 表。
为什么单拎出来:页面里的自检只能证明「渲染出来的板块 == FROZEN 表」,
证明不了「FROZEN 表 == ②段原文」。两张表各改一边就没人发现,所以这条闸门
直接把②段那份 Markdown 当权威读,逐页逐位比。
判据:板块**数量**必须相等,**顺序**必须相等,名字**互为前缀**(②段的名字带
「(可点入)」这类注解,不是给界面抄的标题,⛔ 不逐字比)。
用法:python _tools/check_skeleton.py
"""
import argparse
import os, re, sys
HERE = os.path.dirname(os.path.abspath(__file__))
UI = os.path.abspath(os.path.join(HERE, ".."))
GOAL = os.path.abspath(os.path.join(UI, ".."))
DOC = os.path.join(GOAL, "prd", "2b-界面布局.md")
PROTO = os.path.join(UI, "mcn-workbench.html")
Z2 = "\u3000\u3000" # 全角空格:注释切到右边界用
def from_doc(path=None):
s = open(path or DOC, encoding="utf-8").read()
if "## 二、八页骨架" not in s or "## 三、页面流转" not in s:
raise SystemExit("⛔ 读不到②段的 §二 八页骨架 —— 文件被改结构了?")
seg = s[s.index("## 二、八页骨架"):s.index("## 三、页面流转")]
out, cur = {}, None
for line in seg.split("\n"):
m = re.match(r"^### (P\d) ", line)
if m:
cur = m.group(1).lower()
out[cur] = []
continue
m2 = re.match(r"^\s*(\d+)\.\s*(.+)$", line)
if cur and m2:
out[cur].append(m2.group(2).split("——")[0].strip())
return out
def from_proto(path=None):
s = open(path or PROTO, encoding="utf-8").read()
m = re.search(r"^const FROZEN=\{(.*?)^\};", s, re.S | re.M)
if not m:
raise SystemExit("⛔ 原型里找不到 const FROZEN 表")
out = {}
# ⚠️ 逗号必须可选:表里最后一项后面没有逗号 —— 早前写成必选,p8 被静默漏掉
# (表现为「页面集合不同」,不是静默通过,但那也是漏;已修)
for k, body in re.findall(r"^\s*(p\d):\[(.*?)\],?\s*$", m.group(1), re.M):
items = re.findall(r"'([^']*)'", body)
out[k] = items[1:] # 第 0 项是页面标题
if len(out) != 8:
raise SystemExit("⛔ FROZEN 表只解析出 %d 页(应为 8):%s" % (len(out), sorted(out)))
return out
def norm(x):
return x.split("(")[0].strip()
def main():
ap = argparse.ArgumentParser(description="骨架单一可信源闸门(②段原文 ↔ 原型 FROZEN 表)")
ap.add_argument("--doc", default=None, help="②段界面布局文档(默认 prd/2b-界面布局.md)")
ap.add_argument("--proto", default=None, help="原型 HTML(默认 ui/mcn-workbench.html)")
a = ap.parse_args()
doc, proto = from_doc(a.doc), from_proto(a.proto)
bad = []
if set(doc) != set(proto):
bad.append("页面集合不同:②段 %s / 原型 %s" % (sorted(doc), sorted(proto)))
for p in sorted(set(doc) & set(proto)):
a, b = doc[p], proto[p]
if len(a) != len(b):
bad.append("%s 板块数 ②段 %d ≠ 原型 %d(②段 %s / 原型 %s)" % (p, len(a), len(b), a, b))
continue
for i, (x, y) in enumerate(zip(a, b)):
nx, ny = norm(x), norm(y)
if not (nx.startswith(ny) or ny.startswith(nx)):
bad.append("%s 第 %d 块 ②段「%s」≠ 原型「%s」" % (p, i + 1, x, y))
n = sum(len(v) for v in doc.values())
if bad:
print("FAIL 骨架与②段不一致(②段 %d 个板块):" % n)
for x in bad:
print(" · " + x)
return 1
print("PASS 骨架冻结:八页 %d 个板块,②段 2b-界面布局.md §二 与原型 FROZEN 表逐页逐位一致" % n)
return 0
if __name__ == "__main__":
sys.exit(main())