feat(meta-decompile): разбор внешних источников данных и раундтрип

Декомпилятор собирает DSL источника целиком: читает файл источника, подтягивает файлы таблиц
из <Источник>/Tables/ и складывает поля, ключи, ссылки и функции обратно в тот же синтаксис,
который принимает meta-compile. Ссылки на поля возвращаются короткими именами, таблица без
собственных свойств — коротким массивом полей, функция с типом по умолчанию — одной строкой.

Это замыкает дешёвый контур проверки: XML → декомпиляция → компиляция → сравнение с исходником,
без 1С и без Docker. На нём и проверено: наша выгрузка, выгрузка платформы и четыре таблицы
внешних источников из чужого рабочего проекта возвращаются байт в байт. У выгрузки платформы
остаются два известных расхождения: значение незаполненного родителя (платформа сама сбрасывает
его при любой загрузке) и формы (декомпилятор их не захватывает — так задумано).

Побочно закрыт дефект, к внешним источникам не относящийся: xs:base64Binary разбирался как
ХранилищеЗначения, хотя это ДвоичныеДанные. Различать их можно по квалификаторам —
у ХранилищеЗначения платформа пишет v8:ValueStorage, а у двоичных данных есть
BinaryDataQualifiers. Компилятор научен типу BinaryData (и BinaryData(N)) — до этого он
принимал такое имя, но эмитил его как есть, то есть невалидный XML.

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 14:32:43 +03:00
co-authored by Claude Opus 5
parent 123d6e326b
commit 24cfe6a0a6
10 changed files with 920 additions and 9 deletions
@@ -0,0 +1,33 @@
{
"type": "ExternalDataSource",
"name": "PG",
"dataLockControlMode": "AutomaticAndManaged",
"tables": {
"prices": ["product_id: Number(10,0)", "price: Number(15,2)"],
"products": {
"nameInDataSource": "eds.public.products",
"tableDataType": "ObjectData",
"keyFields": ["id"],
"presentationField": "name",
"transactionsIsolationLevel": "ReadUncommitted",
"fields": [
"id: Number(10,0)",
"name: String(150)",
"photo: BinaryData | nullable",
{
"name": "cost",
"type": "Number(15,2)",
"nameInDataSource": "cost_net",
"flags": ["readonly"]
}
]
}
},
"functions": {
"total": {
"expression": "public.f_total(&1, &2)",
"returns": "Number(15,2)"
},
"nextKey": "NEXT VALUE FOR public.seq_key"
}
}