Files
export_1c_help/export1c_help/export.py
T
mihailkudravcev aec0407b87 Initial release: export 1C Help to Gitea wiki.
Convert Ext/Help/ru.html to Markdown and push to a wiki git repository.
2026-07-23 14:54:04 +03:00

200 lines
6.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""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