Files
index/index1c/parse_modules.py
T
mihailkudravcev 91521e6604 Release 0.3.4 with external processing indexing.
Add virtual baseconf support for external data processors so reindex can discover and index them alongside regular src-based configurations, and update docs to use generic examples without workspace-specific names.
2026-07-21 13:03:25 +03:00

96 lines
2.9 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.
"""Индексация BSL-модулей конфигурации."""
from __future__ import annotations
import re
from dataclasses import dataclass
from pathlib import Path
from .config import OBJECT_TYPE_FOLDERS
# Процедура/Функция Имя(...)
RE_SYMBOL = re.compile(
r"(?im)^\s*(?:&[А-Яа-яA-Za-z_]+)*\s*"
r"(?:Процедура|Функция|Procedure|Function)\s+"
r"([А-Яа-яA-Za-z_][А-Яа-яA-Za-z0-9_]*)"
)
# Лимит тела для FTS (символы) — полные гигантские модули не кладём целиком.
MAX_BODY_CHARS = 200_000
@dataclass
class ModuleRec:
config: str
rel_path: str
abs_path: str
owner: str
module_kind: str
symbols: list[str]
body: str
line_count: int
size: int
mtime_ns: int
def _module_kind(rel: Path) -> str:
name = rel.name
if name == "Module.bsl":
parent = rel.parent.name
if parent == "Form":
return "FormModule"
if parent == "Ext":
# CommonModules/.../Ext/Module.bsl или HTTPServices/.../Ext/Module.bsl
return "Module"
return "Module"
if name.endswith("Module.bsl"):
return name[: -len(".bsl")] # ObjectModule, ManagerModule, ...
return name
def _owner_from_rel(rel: Path) -> str:
"""Documents/ЗаказКлиента/Ext/ObjectModule.bsl → Document.ЗаказКлиента."""
parts = rel.parts
if not parts:
return ""
# Внешняя обработка: <Обработка>/Ext/ObjectModule.bsl
if len(parts) >= 3 and parts[1] == "Ext":
return f"ExternalDataProcessor.{parts[0]}"
# Форма внешней обработки: <Обработка>/Forms/<Форма>/Ext/Form/Module.bsl
if len(parts) >= 6 and parts[1] == "Forms":
return f"ExternalDataProcessor.{parts[0]}.Form.{parts[2]}"
folder = parts[0]
otype = OBJECT_TYPE_FOLDERS.get(folder)
if otype and len(parts) >= 2:
return f"{otype}.{parts[1]}"
return folder
def parse_bsl_file(path: Path, *, config: str, src_root: Path) -> ModuleRec | None:
try:
st = path.stat()
text = path.read_text(encoding="utf-8-sig", errors="replace")
except OSError:
return None
rel = path.relative_to(src_root).as_posix()
symbols = sorted(set(RE_SYMBOL.findall(text)))
body = text if len(text) <= MAX_BODY_CHARS else text[:MAX_BODY_CHARS]
return ModuleRec(
config=config,
rel_path=rel,
abs_path=str(path),
owner=_owner_from_rel(Path(rel)),
module_kind=_module_kind(Path(rel)),
symbols=symbols,
body=body,
line_count=text.count("\n") + (1 if text and not text.endswith("\n") else 0),
size=st.st_size,
mtime_ns=getattr(st, "st_mtime_ns", int(st.st_mtime * 1e9)),
)
def iter_bsl_files(src: Path) -> list[Path]:
if not src.is_dir():
return []
return sorted(src.rglob("*.bsl"))