Files
site/WESP_REL/scripts/build_registration_source.py
2026-07-17 12:57:18 +03:00

253 lines
6.0 KiB
Python

#!/usr/bin/env python3
import ast
import io
import os
import re
import tokenize
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
OUT = ROOT.parent / "исходный_код_WESP.txt"
SKIP_DIRS = {
"__pycache__",
".git",
".pytest_cache",
".cursor",
"tests",
"migrations",
"vendor",
"logs",
"legacy",
}
SKIP_FILES = {
"proga.py",
}
EXTS = {".py", ".js", ".html", ".css"}
def should_skip_file(path: Path) -> bool:
if path.name in SKIP_FILES:
return True
if "legacy" in path.name.lower():
return True
return False
def should_skip_dir(name: str) -> bool:
return name in SKIP_DIRS
def iter_source_files():
for dirpath, dirnames, filenames in os.walk(ROOT):
dirnames[:] = [d for d in dirnames if not should_skip_dir(d)]
rel = Path(dirpath).relative_to(ROOT)
if any(part in SKIP_DIRS for part in rel.parts):
continue
for name in sorted(filenames):
path = Path(dirpath) / name
if path.suffix.lower() in EXTS and not should_skip_file(path):
yield path
def _drop_docstring(body):
if not body:
return body
first = body[0]
if not isinstance(first, ast.Expr):
return body
val = first.value
if isinstance(val, ast.Constant) and isinstance(val.value, str):
return body[1:]
return body
class _DocstringStripper(ast.NodeTransformer):
def visit_FunctionDef(self, node):
self.generic_visit(node)
node.body = _drop_docstring(node.body)
return node
def visit_AsyncFunctionDef(self, node):
self.generic_visit(node)
node.body = _drop_docstring(node.body)
return node
def visit_ClassDef(self, node):
self.generic_visit(node)
node.body = _drop_docstring(node.body)
return node
def visit_Module(self, node):
self.generic_visit(node)
node.body = _drop_docstring(node.body)
return node
def strip_python_comments(source: str) -> str:
out = []
try:
for tok in tokenize.generate_tokens(io.StringIO(source).readline):
if tok.type == tokenize.COMMENT:
continue
out.append(tok)
return tokenize.untokenize(out)
except (tokenize.TokenError, SyntaxError):
return source
def strip_python(source: str) -> str:
try:
tree = ast.parse(source)
tree = _DocstringStripper().visit(tree)
ast.fix_missing_locations(tree)
source = ast.unparse(tree)
except SyntaxError:
pass
return strip_python_comments(source)
def strip_js(source: str) -> str:
result = []
i = 0
n = len(source)
in_single = False
in_double = False
in_template = False
in_line_comment = False
in_block_comment = False
escape = False
while i < n:
ch = source[i]
nxt = source[i + 1] if i + 1 < n else ""
if in_line_comment:
if ch == "\n":
in_line_comment = False
result.append(ch)
i += 1
continue
if in_block_comment:
if ch == "*" and nxt == "/":
in_block_comment = False
i += 2
continue
i += 1
continue
if in_single:
result.append(ch)
if escape:
escape = False
elif ch == "\\":
escape = True
elif ch == "'":
in_single = False
i += 1
continue
if in_double:
result.append(ch)
if escape:
escape = False
elif ch == "\\":
escape = True
elif ch == '"':
in_double = False
i += 1
continue
if in_template:
result.append(ch)
if escape:
escape = False
elif ch == "\\":
escape = True
elif ch == "`":
in_template = False
i += 1
continue
if ch == "/" and nxt == "/":
in_line_comment = True
i += 2
continue
if ch == "/" and nxt == "*":
in_block_comment = True
i += 2
continue
if ch == "'":
in_single = True
result.append(ch)
i += 1
continue
if ch == '"':
in_double = True
result.append(ch)
i += 1
continue
if ch == "`":
in_template = True
result.append(ch)
i += 1
continue
result.append(ch)
i += 1
return "".join(result)
def strip_html_css(source: str) -> str:
source = re.sub(r"<!--[\s\S]*?-->", "", source)
source = strip_js(source)
return source
def collapse_blank_lines(text: str) -> str:
lines = [ln.rstrip() for ln in text.splitlines()]
cleaned = []
blank_run = 0
for ln in lines:
if not ln.strip():
blank_run += 1
if blank_run <= 2:
cleaned.append("")
continue
blank_run = 0
cleaned.append(ln)
return "\n".join(cleaned).strip("\n")
def strip_file(path: Path) -> str:
text = path.read_text(encoding="utf-8", errors="replace")
ext = path.suffix.lower()
if ext == ".py":
body = strip_python(text)
elif ext == ".js":
body = strip_js(text)
else:
body = strip_html_css(text)
return collapse_blank_lines(body)
def main():
chunks = []
for path in iter_source_files():
body = strip_file(path)
if body:
chunks.append(body)
content = "\n\n".join(chunks)
OUT.write_text(content + "\n", encoding="utf-8")
lines = content.count("\n") + (1 if content else 0)
print(f"Written: {OUT}")
print(f"Files: {len(chunks)}")
print(f"Lines: {lines}")
print(f"Size: {OUT.stat().st_size} bytes")
if __name__ == "__main__":
main()