# -*- coding: utf-8 -*- """票 11 ⑤:API-SUMMARY.md 的 URL 与代码 @*Mapping 对账。 基准 = dump_api_out.txt(dump_api.py 现场生成); 文档侧提取所有 (GET|POST) + /api/... 组合(表格行与行内代码通吃),剥查询串后集合比对。 用法:py -3 -X utf8 .scratch/customer-rework/recon_urls.py """ import io import re import sys from pathlib import Path sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8") ROOT = Path(r"e:\code\crm-backend-matt") DUMP = ROOT / ".scratch" / "customer-rework" / "dump_api_out.txt" DOC = ROOT / ".scratch" / "customer-module" / "API-SUMMARY.md" PAIR = re.compile(r"(GET|POST)[^/\n]*?(/api/[A-Za-z0-9/_\-]+)") def norm(p: str) -> str: return p.split("?", 1)[0].rstrip("/") code_set = set() cur_module = "" cur_ctrl = "" # 客户域文档范围:crm-customer 全部 + crm-rule 客户规则族(交接篇 §2.1:其余族勿抄进客户 API-SUMMARY) RULE_SCOPE_ALLOW = {"CustomerReminderRuleController.java", "CustomerDedupRuleController.java"} excluded = set() for line in DUMP.read_text(encoding="utf-8").splitlines(): if line.startswith("######## MODULE"): cur_module = line.split()[-1] continue if line.startswith("==== "): cur_ctrl = line.split()[1] continue m = re.match(r"(GET|POST|PUT|DELETE|ANY)\s+(/api/\S+?)\s\s", line) if not m or m.group(1) not in ("GET", "POST"): continue if cur_module == "crm-rule" and cur_ctrl not in RULE_SCOPE_ALLOW: excluded.add(f"{cur_ctrl}: {m.group(1)} {norm(m.group(2))}") continue code_set.add((m.group(1), norm(m.group(2)))) doc_text = DOC.read_text(encoding="utf-8") doc_set = set() for m in PAIR.finditer(doc_text): doc_set.add((m.group(1), norm(m.group(2)))) missing_in_doc = sorted(code_set - doc_set) stale_in_doc = sorted(doc_set - code_set) print(f"code endpoints in customer-domain scope (GET/POST): {len(code_set)}") print(f"excluded (crm-rule non-customer families, out of doc scope): {len(excluded)}") print(f"doc endpoints (unique verb+path): {len(doc_set)}") print(f"--- in code, missing from doc ({len(missing_in_doc)}):") for v, p in missing_in_doc: print(f" {v} {p}") print(f"--- in doc, not in code ({len(stale_in_doc)}):") for v, p in stale_in_doc: print(f" {v} {p}") print("RECONCILE:", "OK zero diff" if not missing_in_doc and not stale_in_doc else "DIFF FOUND")