Инициализировать репозиторий «Дейл»

Первый коммит: модульный монолит ядра (.NET 10) и gRPC-сервисы
ai/ml/telegram, фронтенд Vue 3/Vite/Tailwind, документация (ТЗ,
инструкция пользователя, техдокументация, код-стайл), бэклог,
скрипты развёртывания и архив прототипа LeadRadar.
This commit is contained in:
Rustam Khalimov
2026-09-11 02:50:17 +03:00
commit 9e07568ddd
1402 changed files with 177470 additions and 0 deletions
+155
View File
@@ -0,0 +1,155 @@
"""Понижение XML-док комментариев с private/internal членов до обычных `//` (код-стайл «Дейл» §5).
Правило: XML-doc — только на public/protected. Приватные детали реализации — при необходимости короткий
обычный комментарий. Скрипт сохраняет текст (теги <param>/<returns> и т.п. разворачиваются в читаемый вид).
Режимы:
python scripts/fix_private_docs.py --preview [N] # показать N примеров (по умолчанию 10)
python scripts/fix_private_docs.py --apply # применить
python scripts/fix_private_docs.py --check # сколько блоков будет изменено
"""
import os
import re
import sys
ROOT = r"C:\telbase\src"
EXC = ("bin", "obj", "node_modules", ".git")
DOC_RE = re.compile(r"^(\s*)///[ \t]?(.*)$")
ACC_RE = re.compile(r"\b(public|protected|private|internal)\b")
def demote(block_content):
"""block_content: список строк после '///'. Возвращает список строк текста обычного комментария."""
t = "\n".join(block_content)
t = re.sub(r"<summary>\s*(.*?)\s*</summary>", r"\1", t, flags=re.S)
t = re.sub(r"<remarks>\s*(.*?)\s*</remarks>", r"\1", t, flags=re.S)
t = re.sub(r"<typeparamref\s+name=\"([^\"]+)\"\s*/?>", r"\1", t)
t = re.sub(r"<paramref\s+name=\"([^\"]+)\"\s*/?>", r"\1", t)
t = re.sub(r"<typeparam\s+name=\"([^\"]+)\"\s*>\s*(.*?)\s*</typeparam>", r"\1: \2", t, flags=re.S)
t = re.sub(r"<param\s+name=\"([^\"]+)\"\s*>\s*(.*?)\s*</param>", r"\1: \2", t, flags=re.S)
t = re.sub(r"<returns>\s*(.*?)\s*</returns>", r"Возвращает: \1", t, flags=re.S)
t = re.sub(
r"<exception\s+cref=\"([^\"]+)\"\s*>\s*(.*?)\s*</exception>",
r"Исключение \1: \2",
t,
flags=re.S,
)
t = re.sub(r"<see\s+cref=\"([^\"]+)\"\s*/?>", r"\1", t)
t = re.sub(r"<seealso\s+cref=\"[^\"]+\"\s*/?>", "", t)
t = re.sub(r"<inheritdoc\s*/?>", "", t)
t = re.sub(r"</?c>", "", t)
t = re.sub(r"<[^>]+>", "", t)
out = []
for line in t.split("\n"):
s = line.strip()
if s:
out.append(s)
return out
def iter_cs():
for dp, dn, fn in os.walk(ROOT):
dn[:] = [d for d in dn if d not in EXC]
for f in fn:
if f.endswith(".cs"):
yield os.path.join(dp, f)
def find_blocks(lines):
"""Возвращает список (start, end, block_content, decl_index, decl)."""
res = []
i = 0
while i < len(lines):
m = DOC_RE.match(lines[i].rstrip("\r"))
if not m:
i += 1
continue
start = i
block = []
while i < len(lines):
m2 = DOC_RE.match(lines[i].rstrip("\r"))
if not m2:
break
block.append(m2.group(2))
i += 1
end = i # exclusive
j = i
decl = ""
while j < len(lines):
s = lines[j].strip()
if s == "" or s.startswith("["):
j += 1
continue
decl = s
break
if not decl:
continue
if not any("<summary>" in b or "</summary>" in b for b in block):
continue
am = ACC_RE.search(decl)
if am and am.group(1) in ("private", "internal"):
res.append((start, end, block, decl))
return res
def process_file(path, apply):
raw = open(path, "rb").read().decode("utf-8")
lines = raw.splitlines(keepends=True)
plain = [l.rstrip("\r\n") for l in lines]
endings = [l[len(l.rstrip("\r\n")):] for l in lines]
blocks = find_blocks(plain)
if not blocks:
return 0, []
changes = []
for start, end, block, decl in blocks:
indent = DOC_RE.match(plain[start]).group(1)
comments = demote(block)
new_lines = [indent + "//" + (" " + c if c else "") for c in comments]
changes.append((start, end, new_lines, decl))
# применяем с конца
for start, end, new_lines, decl in reversed(changes):
ending = endings[start] if endings[start] else (endings[end - 1] if end > start else "\n")
replacement = [nl + ending for nl in new_lines]
lines[start:end] = replacement
if apply:
open(path, "w", encoding="utf-8", newline="").write("".join(lines))
return len(changes), [(b[0], b[3], demote(b[2])) for b in [(s, e, bl, d) for s, e, bl, d in blocks]]
def main():
if "--preview" in sys.argv:
n = 10
idx = sys.argv.index("--preview")
if idx + 1 < len(sys.argv) and sys.argv[idx + 1].isdigit():
n = int(sys.argv[idx + 1])
shown = 0
for path in iter_cs():
raw = open(path, "rb").read().decode("utf-8")
plain = [l.rstrip("\r\n") for l in raw.split("\n")]
for start, end, block, decl in find_blocks(plain):
print("FILE:", os.path.relpath(path, r"C:\telbase"), f"line {start + 1}")
print(" DECL:", decl[:100])
print(" BEFORE:")
for b in plain[start:end]:
print(" ", b)
print(" AFTER:")
for c in demote(block):
print(" // " + c)
print()
shown += 1
if shown >= n:
return
return
apply = "--apply" in sys.argv
total = 0
files = 0
for path in iter_cs():
cnt, _ = process_file(path, apply)
if cnt:
files += 1
total += cnt
print(("APPLIED" if apply else "DRY-RUN"), "blocks:", total, "files:", files)
if __name__ == "__main__":
main()