From 4434493446577960cc8a4d918b1f38855f9f357a Mon Sep 17 00:00:00 2001 From: Nick Shirokov Date: Sat, 13 Jun 2026 16:48:49 +0300 Subject: [PATCH] =?UTF-8?q?fix(form-decompile):=20whitespace-=D0=BA=D0=BE?= =?UTF-8?q?=D0=BD=D1=82=D0=B5=D0=BD=D1=82=20input=20ML=20(footerText/warni?= =?UTF-8?q?ngOnEdit/inputHint/nonselectedPictureText)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit FooterText с whitespace-контентом (`\n` — blank-footer, оба языка) схлопывался в пустой ``: декомпилятор читал через Get-LangText, PreserveWhitespace=false стрипал → "" → компилятор эмитил self-closing. Тот же whitespace-ML корень, что у Attribute>Title / choiceList presentation / Column>Title. Фикс: input ML-чтения footerText (3) / warningOnEdit (4) / inputHint (1) / nonselectedPictureText (2) → Get-LangTextWS (восстанавливает значимый пробел/перенос из WS-дока; безопасный суперсет — для непустого контента идентичен). Многострочный `\n`-контент раундтрипится (Esc-Xml сохраняет перенос, тег спанит строки как оригинал). Корпус: 2 формы (НастройкиОтправкиЭДО acc+erp). Проверка 25 форм с FooterText/ WarningOnEdit/NonselectedPictureText: match 25/25, 0 dec-fail. Декомпилятор-only. ps1==py байт-в-байт. Регресс 43/43. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../form-decompile/scripts/form-decompile.ps1 | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/.claude/skills/form-decompile/scripts/form-decompile.ps1 b/.claude/skills/form-decompile/scripts/form-decompile.ps1 index c8bac26c..27495365 100644 --- a/.claude/skills/form-decompile/scripts/form-decompile.ps1 +++ b/.claude/skills/form-decompile/scripts/form-decompile.ps1 @@ -1,4 +1,4 @@ -# form-decompile v0.140 — Decompile 1C managed Form.xml to JSON DSL (draft) +# form-decompile v0.141 — Decompile 1C managed Form.xml to JSON DSL (draft) # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills # ВНИМАНИЕ: раундтрип не гарантируется. Навык исключён из авто-использования моделью. param( @@ -1906,9 +1906,9 @@ function Decompile-Element { $mi = Get-Child $node 'AutoMarkIncomplete'; if ($null -ne $mi) { $obj['markIncomplete'] = ($mi -eq 'true') } $em = Get-Child $node 'EditMode'; if ($em) { $obj['editMode'] = $em } $tl = Get-Child $node 'TitleLocation'; if ($tl) { $obj['titleLocation'] = $tl.ToLower() } - $ih = $node.SelectSingleNode("lf:InputHint", $ns); if ($ih) { $t = Get-LangText $ih; if ($t) { $obj['inputHint'] = $t } } - $woe = $node.SelectSingleNode("lf:WarningOnEdit", $ns); if ($woe) { $t = Get-LangText $woe; if ($null -ne $t) { $obj['warningOnEdit'] = $t } } - $ftxt = $node.SelectSingleNode("lf:FooterText", $ns); if ($ftxt) { $t = Get-LangText $ftxt; if ($null -ne $t) { $obj['footerText'] = $t } } + $ih = $node.SelectSingleNode("lf:InputHint", $ns); if ($ih) { $t = Get-LangTextWS $ih; if ($t) { $obj['inputHint'] = $t } } + $woe = $node.SelectSingleNode("lf:WarningOnEdit", $ns); if ($woe) { $t = Get-LangTextWS $woe; if ($null -ne $t) { $obj['warningOnEdit'] = $t } } + $ftxt = $node.SelectSingleNode("lf:FooterText", $ns); if ($ftxt) { $t = Get-LangTextWS $ftxt; if ($null -ne $t) { $obj['footerText'] = $t } } foreach ($p in @('ChoiceButton','ClearButton','SpinButton','DropListButton','ChoiceListButton')) { $v = Get-Child $node $p; if ($null -ne $v) { $obj[($p.Substring(0,1).ToLower()+$p.Substring(1))] = (To-Bool $v) } } @@ -1956,7 +1956,7 @@ function Decompile-Element { if ($null -eq $cbt) { $obj['checkBoxType'] = '' } elseif ($cbt -ne 'Auto') { $obj['checkBoxType'] = $cbt.Substring(0,1).ToLower() + $cbt.Substring(1) } Add-TitleLocation $obj $node 'Right' - $woe = $node.SelectSingleNode("lf:WarningOnEdit", $ns); if ($woe) { $t = Get-LangText $woe; if ($null -ne $t) { $obj['warningOnEdit'] = $t } } + $woe = $node.SelectSingleNode("lf:WarningOnEdit", $ns); if ($woe) { $t = Get-LangTextWS $woe; if ($null -ne $t) { $obj['warningOnEdit'] = $t } } Add-FormatProps $obj $node } 'RadioButtonField' { @@ -1967,7 +1967,7 @@ function Decompile-Element { $em = Get-Child $node 'EditMode'; if ($em) { $obj['editMode'] = $em } $rbt = Get-Child $node 'RadioButtonType'; if ($rbt) { $obj['radioButtonType'] = $rbt } $cc = Get-Child $node 'ColumnsCount'; if ($cc) { $obj['columnsCount'] = [int]$cc } - $woe = $node.SelectSingleNode("lf:WarningOnEdit", $ns); if ($woe) { $t = Get-LangText $woe; if ($null -ne $t) { $obj['warningOnEdit'] = $t } } + $woe = $node.SelectSingleNode("lf:WarningOnEdit", $ns); if ($woe) { $t = Get-LangTextWS $woe; if ($null -ne $t) { $obj['warningOnEdit'] = $t } } $cl = Decompile-ChoiceList $node; if ($cl) { $obj['choiceList'] = $cl } } 'LabelDecoration' { @@ -1988,10 +1988,10 @@ function Decompile-Element { if ((Get-Child $node 'Hiperlink') -eq 'true') { $obj['hyperlink'] = $true } # PasswordMode на LabelField — платформа эмитит явный false (редко); захват факт. значения $pm = Get-Child $node 'PasswordMode'; if ($null -ne $pm) { $obj['passwordMode'] = ($pm -eq 'true') } - $woe = $node.SelectSingleNode("lf:WarningOnEdit", $ns); if ($woe) { $t = Get-LangText $woe; if ($null -ne $t) { $obj['warningOnEdit'] = $t } } + $woe = $node.SelectSingleNode("lf:WarningOnEdit", $ns); if ($woe) { $t = Get-LangTextWS $woe; if ($null -ne $t) { $obj['warningOnEdit'] = $t } } # FooterDataPath / FooterText — общие cell-свойства колонки (как у input), не только input $fdp = Get-Child $node 'FooterDataPath'; if ($fdp) { $obj['footerDataPath'] = $fdp } - $ftxt = $node.SelectSingleNode("lf:FooterText", $ns); if ($ftxt) { $t = Get-LangText $ftxt; if ($null -ne $t) { $obj['footerText'] = $t } } + $ftxt = $node.SelectSingleNode("lf:FooterText", $ns); if ($ftxt) { $t = Get-LangTextWS $ftxt; if ($null -ne $t) { $obj['footerText'] = $t } } Add-FormatProps $obj $node } 'PictureDecoration' { @@ -2000,7 +2000,7 @@ function Decompile-Element { # title декорации — единая ML-text форма с formatted (атрибут у PictureDecoration) $tiNode = $node.SelectSingleNode("lf:Title", $ns) if ($tiNode) { $tv = Get-MLFormattedValue $tiNode; if ($null -ne $tv) { $obj['title'] = $tv } } - $npt = $node.SelectSingleNode("lf:NonselectedPictureText", $ns); if ($npt) { $t = Get-LangText $npt; if ($null -ne $t) { $obj['nonselectedPictureText'] = $t } } + $npt = $node.SelectSingleNode("lf:NonselectedPictureText", $ns); if ($npt) { $t = Get-LangTextWS $npt; if ($null -ne $t) { $obj['nonselectedPictureText'] = $t } } $ref = $node.SelectSingleNode("lf:Picture/xr:Ref", $ns) $abs = $node.SelectSingleNode("lf:Picture/xr:Abs", $ns) if ($ref) { $obj['src'] = $ref.InnerText } elseif ($abs) { $obj['src'] = "abs:$($abs.InnerText)" } # встроенная картинка → префикс abs: @@ -2018,10 +2018,10 @@ function Decompile-Element { $tl = Get-Child $node 'TitleLocation'; if ($tl) { $obj['titleLocation'] = $tl.ToLower() } if ((Get-Child $node 'Hyperlink') -eq 'true') { $obj['hyperlink'] = $true } $vp = Get-PictureRef $node 'ValuesPicture'; if ($null -ne $vp) { $obj['valuesPicture'] = $vp } - $npt = $node.SelectSingleNode("lf:NonselectedPictureText", $ns); if ($npt) { $t = Get-LangText $npt; if ($null -ne $t) { $obj['nonselectedPictureText'] = $t } } + $npt = $node.SelectSingleNode("lf:NonselectedPictureText", $ns); if ($npt) { $t = Get-LangTextWS $npt; if ($null -ne $t) { $obj['nonselectedPictureText'] = $t } } # FooterDataPath / FooterText — общие cell-свойства колонки (как у input/labelField) $fdp = Get-Child $node 'FooterDataPath'; if ($fdp) { $obj['footerDataPath'] = $fdp } - $ftxt = $node.SelectSingleNode("lf:FooterText", $ns); if ($ftxt) { $t = Get-LangText $ftxt; if ($null -ne $t) { $obj['footerText'] = $t } } + $ftxt = $node.SelectSingleNode("lf:FooterText", $ns); if ($ftxt) { $t = Get-LangTextWS $ftxt; if ($null -ne $t) { $obj['footerText'] = $t } } } 'CalendarField' { $obj[$key] = $name