"""Build markdown wiki pages from discovered Help HTML.""" from __future__ import annotations import json import shutil from dataclasses import dataclass from datetime import datetime, timezone from pathlib import Path from export1c_help.convert import default_link_rewrite, extract_h1, html_to_markdown from export1c_help.discover import HelpPage, build_link_title_map, discover_help_pages from export1c_help.naming import assign_titles from export1c_help.types_map import DIR_TO_RU from export1c_help.__version__ import __version__ @dataclass class ExportStats: pages_total: int = 0 pages_written: int = 0 pages_skipped_empty: int = 0 images_copied: int = 0 def _is_effectively_empty(md: str) -> bool: plain = re_sub_md(md) return len(plain) < 20 def re_sub_md(md: str) -> str: import re t = re.sub(r"\[\[([^\]|]+)(?:\|[^\]]+)?\]\]", r"\1", md) t = re.sub(r"\[([^\]]+)\]\([^)]+\)", r"\1", t) t = re.sub(r"[#*_`|-]", " ", t) t = re.sub(r"\s+", " ", t).strip() return t def build_home(pages: list[HelpPage], titles: dict[str, str], *, source_label: str) -> str: by_type: dict[str, list[HelpPage]] = {} for p in pages: by_type.setdefault(p.type_dir, []).append(p) lines = [ f"# Справка конфигурации", "", f"Автогенерация из встроенной справки 1С (`Ext/Help/ru.html`).", "", f"- Источник: `{source_label}`", f"- Страниц: **{len(pages)}**", f"- Инструмент: `export_1c_help` v{__version__}", f"- Дата: {datetime.now(timezone.utc).strftime('%Y-%m-%d %H:%M UTC')}", "", "## Разделы", "", ] for type_dir in sorted(by_type, key=lambda d: DIR_TO_RU.get(d, d)): label = DIR_TO_RU.get(type_dir, type_dir) group = sorted(by_type[type_dir], key=lambda p: titles[p.meta_key].casefold()) lines.append(f"### {label} ({len(group)})") lines.append("") for p in group: title = titles[p.meta_key] lines.append(f"- [[{title}]]") lines.append("") return "\n".join(lines).rstrip() + "\n" def build_sidebar(pages: list[HelpPage], titles: dict[str, str]) -> str: by_type: dict[str, list[HelpPage]] = {} for p in pages: by_type.setdefault(p.type_dir, []).append(p) lines = ["# Справка", "", "[[Home|Оглавление]]", ""] for type_dir in sorted(by_type, key=lambda d: DIR_TO_RU.get(d, d)): label = DIR_TO_RU.get(type_dir, type_dir) lines.append(f"### {label}") lines.append("") # only object-level in sidebar to keep it usable objs = [p for p in by_type[type_dir] if not p.is_form] objs.sort(key=lambda p: titles[p.meta_key].casefold()) for p in objs[:80]: lines.append(f"- [[{titles[p.meta_key]}]]") if len(objs) > 80: lines.append(f"- … ещё {len(objs) - 80} (см. [[Home]])") lines.append("") return "\n".join(lines).rstrip() + "\n" def export_help( src_root: Path, out_dir: Path, *, include_forms: bool = True, skip_empty: bool = True, clean: bool = False, source_label: str | None = None, ) -> ExportStats: """Convert all help pages into a wiki working tree at out_dir.""" src_root = src_root.resolve() out_dir = out_dir.resolve() stats = ExportStats() pages = discover_help_pages(src_root, include_forms=include_forms) stats.pages_total = len(pages) h1_by_meta: dict[str, str | None] = {} html_cache: dict[str, str] = {} for p in pages: html = p.path.read_text(encoding="utf-8-sig", errors="ignore") html_cache[p.meta_key] = html h1_by_meta[p.meta_key] = extract_h1(html) titles, files = assign_titles(pages, h1_by_meta) link_map = build_link_title_map(pages, titles) if clean and out_dir.exists(): for child in out_dir.iterdir(): if child.name == ".git": continue if child.is_dir(): shutil.rmtree(child) else: child.unlink() out_dir.mkdir(parents=True, exist_ok=True) def rewrite(href: str, text: str) -> str: return default_link_rewrite(href, text, link_map) manifest_pages: list[dict] = [] for p in pages: html = html_cache[p.meta_key] title = titles[p.meta_key] md = html_to_markdown(html, rewrite_link=rewrite, strip_first_h1=title) if skip_empty and _is_effectively_empty(md): stats.pages_skipped_empty += 1 continue # footer md = ( md.rstrip() + "\n\n---\n\n" + f"*Мета: `{p.meta_key}` · файл: `{p.rel_posix}`*\n" ) fname = files[p.meta_key] (out_dir / fname).write_text(md, encoding="utf-8") stats.pages_written += 1 # copy sibling images help_dir = p.path.parent for img in help_dir.iterdir(): if img.suffix.lower() in {".png", ".jpg", ".jpeg", ".gif", ".bmp", ".webp"}: target = out_dir / img.name if not target.exists(): shutil.copy2(img, target) stats.images_copied += 1 manifest_pages.append( { "meta_key": p.meta_key, "title": title, "filename": fname, "type_dir": p.type_dir, "object": p.object_name, "form": p.form_name, "source": p.rel_posix, } ) label = source_label or str(src_root) written_keys = {m["meta_key"] for m in manifest_pages} written_pages = [p for p in pages if p.meta_key in written_keys] (out_dir / "Home.md").write_text( build_home(written_pages, titles, source_label=label), encoding="utf-8", ) (out_dir / "_Sidebar.md").write_text( build_sidebar(written_pages, titles), encoding="utf-8", ) manifest = { "tool": "export_1c_help", "version": __version__, "source": label, "exported_at": datetime.now(timezone.utc).isoformat(), "pages_total": stats.pages_total, "pages_written": stats.pages_written, "pages_skipped_empty": stats.pages_skipped_empty, "pages": manifest_pages, } (out_dir / "manifest.json").write_text( json.dumps(manifest, ensure_ascii=False, indent=2) + "\n", encoding="utf-8", ) return stats