Add the project rules, requirements and task records

This commit is contained in:
ZacharyZhang-NY committed 2026-10-08 22:32:28 -04:00
1 parent 570671abc3
commit ca6782d37d
252 files changed
+3829 -8

No files matched your search

+95
View File
@@ -0,0 +1,95 @@
#!/usr/bin/env python3
"""Writes docs/test-map.md: each PRD id, its tasks, their tests."""
import os
import re
import subprocess
ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
LATER = ("MAIL", "AGENT")
# Where each area's tests live, named or not.
WHERE = {
"UX": "crates/ely-ui/tests、shell.sh、doc-shell.sh、settings.sh",
"FILE": "crates/ely-files、crates/ely-office、recovery.sh、autosave.sh",
"LOK": "crates/ely-lok/src/client/tests、crates/ely-lok/src/view/tests、lokview.sh",
"DOC": "apps/ely-doc/src/tests、doc-props.sh",
"TABLE": "apps/ely-table/src/tests、theme.sh",
"SHOW": "apps/ely-show/src/tests",
"PDF": "apps/ely-pdf/src/tests、crates/ely-pdf-engine/tests、pdf-recovery.sh",
"TREE": "apps/ely-tree/src/tests",
"MARK": "apps/ely-mark 单测、mark-*.sh",
"PERF": "tests/perf/bench.py、lag.sh",
"QA": "见 docs/qa.md",
}
def read(name):
with open(os.path.join(ROOT, name)) as text:
return text.read()
def ids():
"""PRD table rows: id and its requirement."""
for line in read("PRD.md").splitlines():
if m := re.match(r"\| ([A-Z]+-\d+) \| (.+?) \|", line):
yield m.group(1), m.group(2).split("|")[0].strip()
def cites(line):
"""PRD ids a line names: single, lists, ranges."""
cited = set()
for prefix, rest in re.findall(r"([A-Z]+)-(\d+(?:(?: ?至 ?|、)(?:[A-Z]+-)?\d+)*)", line):
numbers = re.split(r"(?: ?至 ?|、)(?:[A-Z]+-)?", rest)
ranges = re.findall(r"(?: ?至 ?|、)", rest)
n = [int(x) for x in numbers]
cited.add(n[0])
for kind, (a, b) in zip(ranges, zip(n, n[1:])):
cited.update(range(a, b + 1) if "至" in kind else [b])
yield from (f"{prefix}-{k:02d}" for k in sorted(cited))
cited = set()
def tasks():
"""Task lines and decisions: a label, the PRD ids, the line."""
for line in read("tasks/TASKS.md").splitlines():
if m := re.match(r"- \[(.)\] (C[\d.]+[a-z]?) ", line):
yield m.group(2) + ("" if m.group(1) == "x" else f"({m.group(1)})"), set(cites(line)), line
for line in read("agents.md").splitlines():
if m := re.match(r"- (\d{4}-\d\d-\d\d)[^:]*:.*?((C[\d.]+)", line):
yield f"决策 {m.group(2)}", set(cites(line)), line
def known():
"""Test function and script names present in the tree."""
found = subprocess.run(["grep", "-rhoE", r"fn [a-z0-9_]+\(", "crates", "apps", "--include=*.rs"],
cwd=ROOT, capture_output=True, text=True).stdout
names = {name[3:-1] for name in found.split()}
names |= {f for f in os.listdir(os.path.join(ROOT, "tests", "scripts"))}
return names
def main():
present = known()
rows = ["# 功能编号与测试对照", "", "对应 PRD §22。由 `scripts/test-map.py` 从 PRD、`tasks/TASKS.md` 与 `agents.md` 生成:每个编号列出引用它的任务与决策,其中写明、且在代码里确有其名的测试(单测函数名或 `tests/scripts` 的脚本),以及该领域测试所在之处。邮件与 Agent 属第二批,不列。", "",
"| 编号 | 要求 | 任务 | 记下的测试 | 测试所在 |", "| --- | --- | --- | --- | --- |"]
listed = list(tasks())
for id_, need in ids():
if id_.startswith(LATER):
continue
mine = [(label, line) for label, cited, line in listed if id_ in cited]
named = []
for _, line in mine:
for name in re.findall(r"`([a-z0-9_.-]+)`|([a-z0-9-]+\.sh)", line):
name = name[0] or name[1]
if name in present and name not in named:
named.append(name)
labels = list(dict.fromkeys(label for label, _ in mine))
where = WHERE[id_.split("-")[0]]
rows.append(f"| {id_} | {need} | {'、'.join(labels) or '无'} | {'、'.join(f'`{n}`' for n in named) or '—'} | {where} |")
with open(os.path.join(ROOT, "docs", "test-map.md"), "w") as out:
out.write("\n".join(rows) + "\n")
print(f"docs/test-map.md: {len(rows) - 6} ids")
if __name__ == "__main__":
main()