109 lines
4.2 KiB
Python
109 lines
4.2 KiB
Python
"""Build human-readable indexes for a library:
|
||
|
||
<lib>/INDEX.md overview: counts by category / aging / year
|
||
<lib>/laws/<category>/README.md per-category index, grouped by year (desc)
|
||
|
||
Usage (from the repo root):
|
||
python -m scripts.build_index --lib tax
|
||
"""
|
||
|
||
import argparse
|
||
import json
|
||
from collections import Counter
|
||
from datetime import datetime
|
||
from pathlib import Path
|
||
|
||
INDEX_COLUMNS = ["category", "aging", "formulatedyear"]
|
||
|
||
|
||
def esc(text: str) -> str:
|
||
return (text or "").replace("|", "\\|").strip()
|
||
|
||
|
||
def year_of(rec: dict) -> str:
|
||
# Version year from the title first (official revision year); fall back
|
||
# to the publish year for documents whose title carries none.
|
||
return rec.get("formulatedyear") or (rec.get("publish_time") or "")[:4] \
|
||
or "未知"
|
||
|
||
|
||
def build_category_readme(lib_dir: Path, category: str, records: list) -> None:
|
||
lines = [f"# {category}({len(records)} 篇)", ""]
|
||
by_year = {}
|
||
for r in records:
|
||
by_year.setdefault(year_of(r), []).append(r)
|
||
years = sorted((y for y in by_year if y != "未知"), reverse=True)
|
||
if "未知" in by_year:
|
||
years.append("未知")
|
||
for y in years:
|
||
rows = sorted(by_year[y], key=lambda r: r.get("title", ""))
|
||
lines += [f"## {y}", "",
|
||
"| 标题 | 文号 | 有效性 | 成文日期 | 官网 |",
|
||
"|---|---|---|---|---|"]
|
||
for r in rows:
|
||
md = Path(r["file_url"]).name
|
||
lines.append(
|
||
f"| [{esc(r['title'])}]({md}) | {esc(r.get('document_number', ''))} "
|
||
f"| {esc(r.get('aging', ''))} | {esc(r.get('written_date', ''))} "
|
||
f"| [查看]({r.get('url', '')}) |")
|
||
lines.append("")
|
||
(lib_dir / "laws" / category / "README.md").write_text(
|
||
"\n".join(lines), encoding="utf-8")
|
||
|
||
|
||
def build_index(lib_dir: Path, lib_name: str, records: list) -> None:
|
||
today = datetime.now().strftime("%Y-%m-%d")
|
||
by_cat = Counter(r["category"] for r in records)
|
||
by_aging = Counter(r.get("aging") or "官方页面未标注" for r in records)
|
||
by_year = Counter(year_of(r) for r in records)
|
||
|
||
lines = [f"# {lib_name}索引", "",
|
||
f"共 {len(records)} 篇 · 更新于 {today}", "",
|
||
"## 按分类", "",
|
||
"| 分类 | 篇数 |", "|---|---|"]
|
||
for cat, n in by_cat.most_common():
|
||
lines.append(f"| [{cat}](laws/{cat}/README.md) | {n} |")
|
||
lines += ["", "## 按有效性(aging)", "", "| 状态 | 篇数 |", "|---|---|"]
|
||
for k, n in by_aging.most_common():
|
||
lines.append(f"| {k} | {n} |")
|
||
lines += ["", "## 按年份", "", "| 年份 | 篇数 |", "|---|---|"]
|
||
for y in sorted((y for y in by_year if y != "未知"), reverse=True):
|
||
lines.append(f"| {y} | {by_year[y]} |")
|
||
if "未知" in by_year:
|
||
lines.append(f"| 未知 | {by_year['未知']} |")
|
||
lines.append("")
|
||
(lib_dir / "INDEX.md").write_text("\n".join(lines), encoding="utf-8")
|
||
|
||
|
||
def main(argv=None) -> int:
|
||
p = argparse.ArgumentParser(prog="scripts.build_index",
|
||
description="build INDEX.md + per-category README.md")
|
||
p.add_argument("--lib", default="tax")
|
||
p.add_argument("--out", default="",
|
||
help="repo root (default: parent of this script's dir)")
|
||
args = p.parse_args(argv)
|
||
repo_root = Path(args.out).resolve() if args.out else \
|
||
Path(__file__).resolve().parents[1]
|
||
lib_dir = repo_root / args.lib
|
||
|
||
registry = json.loads((repo_root / "registry.json").read_text(encoding="utf-8"))
|
||
lib_name = next((l["name"] for l in registry["libraries"]
|
||
if l["id"] == args.lib), args.lib)
|
||
|
||
records = [json.loads(line)
|
||
for line in (lib_dir / "metadata" / "metadata.jsonl")
|
||
.read_text(encoding="utf-8").splitlines() if line.strip()]
|
||
by_cat = {}
|
||
for r in records:
|
||
by_cat.setdefault(r["category"], []).append(r)
|
||
for cat, recs in by_cat.items():
|
||
build_category_readme(lib_dir, cat, recs)
|
||
build_index(lib_dir, lib_name, records)
|
||
print(f"index built: {lib_dir / 'INDEX.md'} + {len(by_cat)} category READMEs "
|
||
f"({len(records)} records)")
|
||
return 0
|
||
|
||
|
||
if __name__ == "__main__":
|
||
raise SystemExit(main())
|