feat(meta-validate): проверка ссылок на поля таблицы внешнего источника

Свойства таблицы ссылаются на её же поля шестичастным путём
(ExternalDataSource.И.Table.Т.Field.П). Опечатка в имени поля даёт «Неизвестный объект
метаданных» при загрузке, а глазами в таком пути её не видно. Проверка 21 разбирает форму
пути, требует, чтобы таблица в ссылке была той же самой, и чтобы поле существовало —
в сообщении перечисляются имеющиеся поля.

Отдельно: таблица без ключевых полей даёт предупреждение, а не ошибку. Загрузку XML такой
таблицы платформа принимает молча (измерено на 8.3.24.1691), Конфигуратор интерактивно
требует ключ, а рабочие конфигурации без ключей существуют — значит это повод предупредить,
а не отвергнуть.

Закрыты последние пункты плана: раздел про внешние источники в docs/meta-dsl-spec.md
(формой и связями с общими конвенциями, без дублирования таблицы свойств — она живёт
в reference навыка) и кейсы meta-validate, включая негативный.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NBsZA5cr2WFThtgp7i5WVi
This commit is contained in:
Nick Shirokov
2026-09-06 15:35:56 +03:00
co-authored by Claude Opus 5
parent 24cfe6a0a6
commit 89ce1af9fa
18 changed files with 1576 additions and 2 deletions
@@ -1,4 +1,4 @@
# meta-validate v1.26 — Validate 1C metadata object structure (Python port)
# meta-validate v1.27 — Validate 1C metadata object structure (Python port)
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import argparse
import os
@@ -1778,6 +1778,48 @@ if not is_adopted:
if form_refs_checked > 0 and not form_ref_bad:
report_ok(f"20. Form refs: {form_refs_checked} resolved")
# ── Check 21: таблица внешнего источника — ссылки на поля и наличие ключа ──
# Свойства таблицы ссылаются на её же поля полным путём. Опечатка в имени поля даёт
# «Неизвестный объект метаданных» при загрузке, а найти её глазами в шестичастном пути трудно.
if md_type == "Table":
field_names = set()
if child_obj_node is not None:
for f in find_all(child_obj_node, "md:Field/md:Properties/md:Name"):
field_names.add(inner_text(f))
eds_refs_checked = 0
eds_refs_bad = False
for tag, is_list in (("KeyFields", True), ("InputByString", True), ("DataLockFields", True),
("PresentationField", False), ("ParentField", False), ("DataVersionField", False)):
if is_list:
refs = [inner_text(n) for n in find_all(props_node, f"md:{tag}/xr:Field")]
else:
n = find(props_node, f"md:{tag}")
refs = [inner_text(n)] if n is not None and inner_text(n) else []
for ref in refs:
eds_refs_checked += 1
parts = ref.split(".")
# Ожидается ExternalDataSource.<Источник>.Table.<Таблица>.Field.<Поле>
if len(parts) != 6 or parts[0] != "ExternalDataSource" or parts[2] != "Table" or parts[4] != "Field":
report_error(f"21. {tag} '{ref}' — ожидается ExternalDataSource.<Источник>.Table.<Таблица>.Field.<Поле>")
eds_refs_bad = True
continue
if parts[3] != obj_name:
report_error(f"21. {tag} '{ref}' — ссылка на поле ЧУЖОЙ таблицы (эта: {obj_name})")
eds_refs_bad = True
continue
if parts[5] not in field_names:
known = ", ".join(sorted(field_names)) if field_names else "полей нет"
report_error(f"21. {tag} '{ref}' — поля '{parts[5]}' нет в таблице (есть: {known})")
eds_refs_bad = True
if eds_refs_checked > 0 and not eds_refs_bad:
report_ok(f"21. Field refs: {eds_refs_checked} resolved")
# Ключ: загрузка XML таблицу без ключа принимает (проверено на платформе), а Конфигуратор
# интерактивно требует. Отсюда предупреждение, а не ошибка: рабочие конфигурации без ключа есть.
if not find_all(props_node, "md:KeyFields/xr:Field"):
report_warn("21. KeyFields пуст — платформа такую таблицу загрузит, но форма записи и набор записей будут недоступны")
# ── Final output ──────────────────────────────────────────────
finalize()