Initial SQL-only 1C adapter baseline

This commit is contained in:
2026-07-22 03:03:47 +03:00
commit e2503b77e7
545 changed files with 184711 additions and 0 deletions
+84
View File
@@ -0,0 +1,84 @@
"""Mechanical section summaries for Config brace trees.
This module intentionally does not name sections as attributes, tabular
sections, forms, etc. It only reports paths, shapes, strings, and GUIDs so a
higher-level validator can attach semantics using XML or other evidence.
"""
from __future__ import annotations
from dataclasses import asdict, dataclass
from typing import Any
from .payload import GUID_RE, collect_strings, scalar
@dataclass(frozen=True)
class SectionSummary:
path: str
node_type: str
list_len: int | None
first_scalars: list[str]
string_count_sampled: int
guid_count_sampled: int
strings_sample: list[str]
guids_sample: list[str]
def to_dict(self) -> dict[str, Any]:
return asdict(self)
def _children(node: Any) -> list[Any]:
if isinstance(node, dict) and node.get("type") in {"list", "sequence"}:
return node.get("items") or []
return []
def _atoms(node: Any, limit: int) -> list[str]:
values: list[str] = []
def walk(value: Any) -> None:
if len(values) >= limit:
return
if isinstance(value, dict) and value.get("type") in {"atom", "string"}:
text = scalar(value)
if text:
values.append(text)
return
for child in _children(value):
walk(child)
walk(node)
return values
def summarize_section(node: Any, path: str, *, limit: int = 200) -> SectionSummary:
children = _children(node)
atoms = _atoms(node, limit)
strings = collect_strings(node, limit=limit)
guids = sorted(set(value.lower() for value in atoms if GUID_RE.fullmatch(value)))
return SectionSummary(
path=path,
node_type=node.get("type") if isinstance(node, dict) else type(node).__name__,
list_len=len(children) if children else None,
first_scalars=[scalar(child) for child in children[:12]],
string_count_sampled=len(strings),
guid_count_sampled=len(guids),
strings_sample=strings[:50],
guids_sample=guids[:50],
)
def summarize_sections(tree: Any, *, max_depth: int = 2, limit: int = 200) -> list[SectionSummary]:
summaries: list[SectionSummary] = []
def walk(node: Any, path: list[int], depth: int) -> None:
if depth > max_depth:
return
if path:
summaries.append(summarize_section(node, ".".join(str(part) for part in path), limit=limit))
for index, child in enumerate(_children(node)):
walk(child, [*path, index], depth + 1)
walk(tree, [], 0)
return summaries