fix(form-validate,cfe-borrow): остаточные ложные ошибки на формах платформы

Корпусный прогон (УТ/БП/ERP, 21 097 форм) после понижения Command/Action
оставлял 8 форм с ошибками. Разобраны все, дефектов оказалось два.

1. Вложенная таблица. Путь Items.<Таблица>.CurrentData.<Поле> разрешался
   ОДНИМ шагом: если таблица сама привязана через Items.*, корнем
   оставался литерал «Items», и типовая форма объявлялась битой
   (НастройкаПравилОбработкиЗаявокСотрудников в БП и ERP). Теперь
   разрешение идёт цепочкой, со страховкой от кольца ссылок.

2. AutoCommandBar с обычным id вместо -1. Это соглашение, а не требование:
   21 094 формы из 21 097 используют -1, но три платформа выгружает с
   обычным id и грузит их без нареканий. Понижено до предупреждения;
   ошибка осталась на случай, когда id вообще не число.

Оставшиеся три формы — дубли id элементов и команд. Это НЕ ложные
срабатывания: измерение по корпусу показало ровно по одному случаю на
21 097 форм, то есть опечатки вендора, а не структурное правило (были бы
пулы id раздельными, пересечений были бы тысячи). Плюс кейс duplicate-id
прямо требует считать дубль ошибкой.

Итого по корпусу: 283 формы с ошибками → 3.

Заодно дооформлена фикстура cfe-borrow/container-types (пространство имён
веб-сервису, документ журналу и последовательности): verify-snapshots по
cfe-borrow теперь 12/12.
This commit is contained in:
Nick Shirokov
2026-08-12 20:20:02 +03:00
parent 71f047291c
commit af00aa4711
32 changed files with 1266 additions and 34 deletions
@@ -1,4 +1,4 @@
# form-validate v1.14 — Validate 1C managed form
# form-validate v1.15 — Validate 1C managed form
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
param(
[Parameter(Mandatory)]
@@ -201,10 +201,15 @@ if (-not $stopped) {
if ($acb) {
$acbName = $acb.GetAttribute("name")
$acbId = $acb.GetAttribute("id")
# id=-1 — соглашение, а не требование: в корпусе УТ/БП/ERP так у 21 094 форм из 21 097,
# но три формы платформа выгружает с обычным id и грузит их без нареканий. Поэтому
# предупреждение; ошибка — только если id вовсе не число.
if ($acbId -eq "-1") {
Report-OK "AutoCommandBar: name='$acbName', id=$acbId"
} elseif ($acbId -match '^-?\d+$') {
Report-Warn "AutoCommandBar id='$acbId', usually '-1'"
} else {
Report-Error "AutoCommandBar id='$acbId', expected '-1'"
Report-Error "AutoCommandBar id='$acbId' is not a number"
}
} else {
Report-Error "AutoCommandBar element missing"
@@ -484,11 +489,19 @@ if (-not $stopped) {
$segments = $cleanPath -split '\.'
$rootAttr = $segments[0]
# Resolve Items.<TableName>.CurrentData.<Field>... — table element, not attribute
if ($rootAttr -eq 'Items') {
# Resolve Items.<TableName>.CurrentData.<Field>... — table element, not attribute.
# Разрешаем ЦЕПОЧКОЙ: таблица во вложенной таблице сама привязана через Items.*, и один
# шаг оставлял корнем литерал «Items» — форма платформы объявлялась битой (типовые
# НастройкаПравилОбработкиЗаявокСотрудников в БП и ERP).
$itemsHops = 0
$itemsBroken = $false
while ($rootAttr -eq 'Items') {
$itemsHops++
if ($itemsHops -gt 10) { $itemsBroken = $true; break } # страховка от кольца ссылок
if ($segments.Count -lt 3 -or $segments[2] -ne 'CurrentData') {
Report-Warn "[$tag] '$elName': $bTag='$dataPath' — unknown Items.* shape, expected Items.<Table>.CurrentData.*"
continue
$itemsBroken = $true
break
}
$tableName = $segments[1]
$tableEl = $null
@@ -501,17 +514,21 @@ if (-not $stopped) {
if (-not $tableEl) {
Report-Error "[$tag] '$elName': $bTag='$dataPath' — table element '$tableName' not found"
$pathErrors++
continue
$itemsBroken = $true
break
}
$tableDpNode = $tableEl.Node.SelectSingleNode("f:DataPath", $nsMgr)
if (-not $tableDpNode -or -not $tableDpNode.InnerText.Trim()) {
# Table without DataPath — can't resolve further, accept silently
continue
$itemsBroken = $true
break
}
$tableDp = $tableDpNode.InnerText.Trim() -replace '\[\d+\]', ''
if ($tableDp.StartsWith('~')) { $tableDp = $tableDp.Substring(1) }
$rootAttr = ($tableDp -split '\.')[0]
$segments = $tableDp -split '\.'
$rootAttr = $segments[0]
}
if ($itemsBroken) { continue }
if (-not $attrMap.ContainsKey($rootAttr)) {
Report-Error "[$tag] '$elName': $bTag='$dataPath' — attribute '$rootAttr' not found"