feat(meta-compile,meta-decompile): условный профильный StandardAttributes для Catalog (v1.16/v0.3)

Раундтрип-находка (класс-2 + новый DSL-блок). Правило платформы, выведенное из корпуса
(1596/1640 каталогов) и подтверждённое синтетикой: блок <StandardAttributes> материализуется
ТОЛЬКО при кастомизации ≥1 стандартного реквизита; 0 all-default блоков, 44 голых без блока.
При материализации платформа заполняет характеристический профиль (Owner{FC=ShowError,FFV=true},
Parent{FFV=true}, Description{FC=ShowError}), не зависящий от иерархии/владельца.

Было: meta-compile писал блок ВСЕГДА единым all-default шаблоном (неверные пер-атрибутные
дефолты) → ADDED-блок у 44 голых + потеря профиля/кастомизаций у 1596.

Стало:
- meta-compile (дуал-порт): блок эмитится только при наличии DSL-ключа `standardAttributes`
  (map реквизит→{synonym,fillChecking,fillFromFillingValue,fullTextSearch,dataHistory}); база =
  профиль типа (stdAttrProfile), поверх — override. Emit-StandardAttribute параметризован (ov).
  Эмиттер общий (Emit-StandardAttributesProfiled $type) — подключён только Catalog; прочие 13
  типов пока на старом безусловном пути (мигрируем при их пилоте).
- meta-decompile: захват `standardAttributes` как отклонений от профиля (блока нет → ключ опущен).
- spec meta-dsl-spec.md v2.2: раздел 7.1.1 (правило, профиль, формат).
- тест-кейс catalog-standard-attributes (профиль + override synonym + Code.fillChecking).

Валидация: byte-match блока на синтетике; полный прогон −27k строк (474339→447285), обвал
cascade ADDED 11538→1242; регресс 34/34 (ps+py); 1С-cert снэпшотов зелёный.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Nick Shirokov
2026-07-01 11:12:56 +03:00
co-authored by Claude Opus 4.8
parent 85e13e95f2
commit df5c1ee17d
16 changed files with 827 additions and 1433 deletions
@@ -1,4 +1,4 @@
# meta-decompile v0.2 — XML объекта метаданных 1С → JSON-черновик формата meta-compile
# meta-decompile v0.3 — XML объекта метаданных 1С → JSON-черновик формата meta-compile
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
#
# Пилот: только Catalog. Инверс meta-compile (omit-on-default: ключ эмитим только
@@ -226,6 +226,40 @@ Add-EnumProp 'choiceMode' 'ChoiceMode' 'BothWays'
Add-EnumProp 'dataLockControlMode' 'DataLockControlMode' 'Automatic'
Add-EnumProp 'fullTextSearch' 'FullTextSearch' 'Use'
# --- StandardAttributes: блок есть ⟺ кастомизация ≥1 стандартного реквизита.
# Захватываем ОТКЛОНЕНИЯ от профиля материализованного блока (профиль компилятор восстановит сам).
# Профиль Catalog: Owner{FC=ShowError,FFV=true}, Parent{FFV=true}, Description{FC=ShowError}. ---
$catStdProfile = @{
'Owner' = @{ fillChecking = 'ShowError'; fillFromFillingValue = $true }
'Parent' = @{ fillFromFillingValue = $true }
'Description' = @{ fillChecking = 'ShowError' }
}
$saNode = $props.SelectSingleNode('md:StandardAttributes', $nsm)
if ($saNode) {
$saMap = [ordered]@{}
foreach ($sa in @($saNode.SelectNodes('xr:StandardAttribute', $nsm))) {
$an = $sa.GetAttribute('name')
$prof = if ($catStdProfile.ContainsKey($an)) { $catStdProfile[$an] } else { @{} }
$ov = [ordered]@{}
# FillChecking (профиль или DontCheck)
$fcN = $sa.SelectSingleNode('xr:FillChecking', $nsm); $fc = if ($fcN) { $fcN.InnerText } else { 'DontCheck' }
$profFc = if ($prof.ContainsKey('fillChecking')) { $prof['fillChecking'] } else { 'DontCheck' }
if ($fc -ne $profFc) { $ov['fillChecking'] = $fc }
# FillFromFillingValue (профиль или false)
$ffvN = $sa.SelectSingleNode('xr:FillFromFillingValue', $nsm); $ffv = ($ffvN -and $ffvN.InnerText -eq 'true')
$profFfv = ($prof['fillFromFillingValue'] -eq $true)
if ($ffv -ne $profFfv) { $ov['fillFromFillingValue'] = $ffv }
# Synonym (профиль пуст)
$syn = Get-MLru ($sa.SelectSingleNode('xr:Synonym', $nsm))
if ($syn) { $ov['synonym'] = $syn }
# FullTextSearch / DataHistory (профиль = Use)
$ftsN = $sa.SelectSingleNode('xr:FullTextSearch', $nsm); if ($ftsN -and $ftsN.InnerText -ne 'Use') { $ov['fullTextSearch'] = $ftsN.InnerText }
$dhN = $sa.SelectSingleNode('xr:DataHistory', $nsm); if ($dhN -and $dhN.InnerText -ne 'Use') { $ov['dataHistory'] = $dhN.InnerText }
if ($ov.Count -gt 0) { $saMap[$an] = $ov }
}
$dsl['standardAttributes'] = $saMap # даже пустой = блок есть (чистый профиль)
}
# --- ChildObjects: Attributes + TabularSections ---
$childObjs = $objNode.SelectSingleNode('md:ChildObjects', $nsm)
if ($childObjs) {