feat(form-decompile,form-compile): dataParameters динсписка + nil-значение схема-параметра (valueListAllowed)

Раундтрип терял две вещи в настройках динамического списка реквизита (форма ВыборПодписантовПечатныхФорм):
1. <dcsset:dataParameters> — значения параметров запроса в ListSettings (список SettingsParameterValue
   {use, parameter, value?}). Не захватывались/не эмитились вовсе.
2. <dcssch:value xsi:nil/> у схема-параметра при valueListAllowed=true: компилятор по умолчанию его
   пропускал (if valueListAllowed → return), но платформа пишет не всегда (корпус 27 с / 47 без).

dataParameters: грамматика портирована из skd-compile (Emit-DataParameters + Parse-DataParamShorthand +
Test/Emit-EmptyValue) — консистентно с СКД (shorthand "Имя @off" / объект). Form-нюанс: значение
опционально (use=false плейсхолдер без value-узла, в отличие от skd-settings). compile эмитит после
filter (XSD-порядок). decompile: Build-FormDataParameters (объект с полным valueType / shorthand).

nil-значение: декомпилятор ставит явный маркер value:null при valueListAllowed+nil-тег; компилятор
эмитит nil при valueListAllowed + явный value (различает absent от null через Has-DLProp/value_explicit).

Корпус: dataParameters в 9 формах (17 items, все use=false, 4 со значениями DesignTimeValue/ent:/decimal).
Верификация: таргет-раундтрип формы → match (22→0); 9 dataParameters-форм — категория закрыта (остаток —
др. категории filter userSettingPresentation/MultipleValue*). Регресс form-compile 43/43 (ps1+py,
PY-паритет снэпшота); 1С-cert dynamic-list-form (vla-nil + dataParameters грузятся). spec.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Nick Shirokov
2026-06-12 15:00:19 +03:00
co-authored by Claude Opus 4.8
parent b794560492
commit 819b7fa126
6 changed files with 364 additions and 6 deletions
@@ -1,4 +1,4 @@
# form-decompile v0.107 — Decompile 1C managed Form.xml to JSON DSL (draft)
# form-decompile v0.108 — Decompile 1C managed Form.xml to JSON DSL (draft)
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
# ВНИМАНИЕ: раундтрип не гарантируется. Навык исключён из авто-использования моделью.
param(
@@ -1231,6 +1231,44 @@ function Build-DLInputParameters {
return @($items)
}
# dcsset:dataParameters → массив (shorthand "Имя @off" для value-less / объект для типизированного
# значения). Грамматика зеркалит skd-compile Emit-DataParameters (form-контекст: значение опционально,
# в отличие от skd-settings). Без «auto»-компактизации (нужна машинерия сравнения с top-level).
function Build-FormDataParameters {
param($dpNode)
$entries = @()
foreach ($it in @($dpNode.SelectNodes("dcscor:item", $ns))) {
$pn = Get-Text $it "dcscor:parameter"
$use = Get-Text $it "dcscor:use"
$valNode = $it.SelectSingleNode("dcscor:value", $ns)
$usidN = $it.SelectSingleNode("dcsset:userSettingID", $ns)
$vmN = $it.SelectSingleNode("dcsset:viewMode", $ns)
$uspN = $it.SelectSingleNode("dcsset:userSettingPresentation", $ns)
if ($valNode -or $usidN -or $vmN -or $uspN) {
$obj = [ordered]@{ parameter = $pn }
if ($valNode) {
if ($valNode.GetAttribute("nil", $NS_XSI) -eq 'true') { $obj['nilValue'] = $true }
else {
$vType = $valNode.GetAttribute("type", $NS_XSI); $vVal = $valNode.InnerText
if ($vType -match 'decimal$' -and $vVal -match '^-?\d+$') { $obj['value'] = [int]$vVal }
elseif ($vType -match 'boolean$') { $obj['value'] = ($vVal -eq 'true') }
else { $obj['value'] = $vVal }
if ($vType) { $obj['valueType'] = $vType }
}
}
if ($use -eq 'false') { $obj['use'] = $false }
if ($usidN) { $obj['userSettingID'] = 'auto' }
if ($vmN) { $obj['viewMode'] = $vmN.InnerText }
if ($uspN) { $usp = Get-MLText $uspN; if ($null -ne $usp) { $obj['userSettingPresentation'] = $usp } }
$entries += $obj
} else {
$s = $pn; if ($use -eq 'false') { $s += ' @off' }
$entries += $s
}
}
return ,$entries
}
function Build-DLParameter {
param($pNode)
$name = Get-Child $pNode 'name'
@@ -1249,10 +1287,14 @@ function Build-DLParameter {
$vtNode = $pNode.SelectSingleNode("dcssch:valueType", $ns)
$typeVal = $null
if ($vtNode) { $typeVal = Decompile-Type $vtNode; if ($typeVal) { $o['type'] = $typeVal } }
# value — опускаем nil (дефолт)
# value — опускаем nil (дефолт), КРОМЕ valueListAllowed+nil: платформа пишет <value xsi:nil/>
# не всегда (корпус 27 с / 47 без), а компилятор при valueListAllowed по умолчанию его НЕ эмитит →
# явный маркер value:null, чтобы реэмитить nil. (Различается через Has-DLProp в компиляторе.)
$vNode = $pNode.SelectSingleNode("dcssch:value", $ns)
if ($vNode -and ($vNode.GetAttribute("nil", $NS_XSI) -ne 'true')) {
$o['value'] = Convert-TypedValue -raw $vNode.InnerText -xsiType ($vNode.GetAttribute("type", $NS_XSI))
} elseif ($vNode -and ((Get-Child $pNode 'valueListAllowed') -eq 'true')) {
$o['value'] = $null
}
# useRestriction — опускаем true (дефолт), фиксируем false
if ((Get-Child $pNode 'useRestriction') -eq 'false') { $o['useRestriction'] = $false }
@@ -2499,6 +2541,13 @@ if ($attrsNode) {
$ca = Build-ConditionalAppearance -caNode $caNode -loc "settings/conditionalAppearance"
if (@($ca).Count -gt 0) { $so['conditionalAppearance'] = @($ca) }
}
# Параметры данных компоновки (dcsset:dataParameters) — значения параметров запроса в
# настройках. Грамматика как у СКД (shorthand "Имя @off" / объект). См. Build-FormDataParameters.
$dpNode = $lsNode.SelectSingleNode("dcsset:dataParameters", $ns)
if ($dpNode -and $dpNode.SelectSingleNode("dcscor:item", $ns)) {
$dp = Build-FormDataParameters $dpNode
if (@($dp).Count -gt 0) { $so['dataParameters'] = @($dp) }
}
# Форма скелета ListSettings: дескриптор только для НЕ-каноничных форм (частичные/минимальные).
# Канон → $null (компилятор регенерит полный скелет, как раньше).
$lsShape = Get-ListSettingsShape $lsNode