154 lines
4.7 KiB
Python
154 lines
4.7 KiB
Python
#!/usr/bin/env python3
|
|
"""Build enum order -> presentation map from 1C XML routes."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import json
|
|
import xml.etree.ElementTree as ET
|
|
from pathlib import Path
|
|
from typing import Any
|
|
|
|
|
|
NS = {
|
|
"md": "http://v8.3/MDClasses",
|
|
"v8": "http://v8.1c.ru/8.1/data/core",
|
|
}
|
|
|
|
|
|
def load_json(path: Path) -> dict[str, Any]:
|
|
return json.loads(path.read_text(encoding="utf-8-sig"))
|
|
|
|
|
|
def local_name(tag: str) -> str:
|
|
return tag.rsplit("}", 1)[-1]
|
|
|
|
|
|
def child_text(parent: ET.Element, name: str) -> str | None:
|
|
for child in list(parent):
|
|
if local_name(child.tag) == name:
|
|
return child.text or ""
|
|
return None
|
|
|
|
|
|
def properties(element: ET.Element) -> ET.Element | None:
|
|
for child in list(element):
|
|
if local_name(child.tag) == "Properties":
|
|
return child
|
|
return None
|
|
|
|
|
|
def synonym(props: ET.Element | None) -> str | None:
|
|
if props is None:
|
|
return None
|
|
for syn in list(props):
|
|
if local_name(syn.tag) != "Synonym":
|
|
continue
|
|
for item in list(syn):
|
|
lang = None
|
|
content = None
|
|
for child in list(item):
|
|
if local_name(child.tag) == "lang":
|
|
lang = child.text
|
|
elif local_name(child.tag) == "content":
|
|
content = child.text
|
|
if lang == "ru" and content:
|
|
return content
|
|
return None
|
|
|
|
|
|
def enum_values(path: Path) -> list[dict[str, Any]]:
|
|
root = ET.parse(path).getroot()
|
|
enum = next((node for node in root.iter() if local_name(node.tag) == "Enum"), None)
|
|
if enum is None:
|
|
return []
|
|
child_objects = next((node for node in list(enum) if local_name(node.tag) == "ChildObjects"), None)
|
|
if child_objects is None:
|
|
return []
|
|
values = []
|
|
order = 0
|
|
for node in list(child_objects):
|
|
if local_name(node.tag) != "EnumValue":
|
|
continue
|
|
props = properties(node)
|
|
name = child_text(props, "Name") if props is not None else None
|
|
values.append(
|
|
{
|
|
"order": order,
|
|
"uuid": (node.attrib.get("uuid") or "").lower() or None,
|
|
"name": name,
|
|
"synonym": synonym(props),
|
|
}
|
|
)
|
|
order += 1
|
|
return values
|
|
|
|
|
|
def is_base_config(top: dict[str, Any]) -> bool:
|
|
relative = str(top.get("relative_path") or "")
|
|
return relative.startswith("Enums\\")
|
|
|
|
|
|
def route_score(row: dict[str, Any]) -> tuple[int, str]:
|
|
return (1 if str(row.get("relative_path") or "").startswith("Enums\\") else 0, str(row.get("relative_path") or ""))
|
|
|
|
|
|
def main() -> int:
|
|
parser = argparse.ArgumentParser(description="Build 1C enum presentation map.")
|
|
parser.add_argument("--index", type=Path, required=True)
|
|
parser.add_argument("--output", type=Path, required=True)
|
|
args = parser.parse_args()
|
|
|
|
index = load_json(args.index)
|
|
enums: dict[str, dict[str, Any]] = {}
|
|
for guid, item in (index.get("objects") or {}).items():
|
|
tops = [
|
|
top
|
|
for top in item.get("xml_top_objects") or []
|
|
if top.get("xml_kind") == "Enum" and top.get("name") and top.get("path")
|
|
]
|
|
if not tops:
|
|
continue
|
|
tops.sort(key=lambda top: (not is_base_config(top), top.get("relative_path") or ""))
|
|
top = tops[0]
|
|
path = Path(top["path"])
|
|
if not path.is_file():
|
|
continue
|
|
try:
|
|
values = enum_values(path)
|
|
except ET.ParseError as error:
|
|
values = []
|
|
parse_error = str(error)
|
|
else:
|
|
parse_error = None
|
|
key = str(top["name"])
|
|
candidate = {
|
|
"guid": guid,
|
|
"name": top.get("name"),
|
|
"synonym": top.get("synonym"),
|
|
"relative_path": top.get("relative_path"),
|
|
"path": top.get("path"),
|
|
"parse_error": parse_error,
|
|
"values": values,
|
|
"by_order": {str(value["order"]): value for value in values},
|
|
"by_uuid": {value["uuid"]: value for value in values if value.get("uuid")},
|
|
}
|
|
existing = enums.get(key)
|
|
if existing is None or route_score(candidate) > route_score(existing):
|
|
enums[key] = candidate
|
|
|
|
result = {
|
|
"schema": "onec_enum_presentation_map.v1",
|
|
"index": str(args.index),
|
|
"enum_count": len(enums),
|
|
"enums": dict(sorted(enums.items())),
|
|
}
|
|
args.output.parent.mkdir(parents=True, exist_ok=True)
|
|
args.output.write_text(json.dumps(result, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
|
|
print(json.dumps({"output": str(args.output), "enum_count": len(enums)}, ensure_ascii=False))
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|