From 1b56e7a735416b98b07c6a368845f964af7cb875 Mon Sep 17 00:00:00 2001 From: Nick Shirokov Date: Sat, 6 Jun 2026 16:42:26 +0300 Subject: [PATCH] =?UTF-8?q?feat(form-decompile,form-compile):=20=D1=87?= =?UTF-8?q?=D0=B5=D1=81=D1=82=D0=BD=D0=BE-=D1=82=D0=B0=D0=B1=D0=BB=D0=B8?= =?UTF-8?q?=D1=87=D0=BD=D1=8B=D0=B5=20=D1=81=D0=B2=D0=BE=D0=B9=D1=81=D1=82?= =?UTF-8?q?=D0=B2=D0=B0=20ChangeRowSet/Order,=20AutoInsertNewRow,=20Enable?= =?UTF-8?q?Drag,=20RowFilter=20(=D0=BA=D0=BB=D0=B0=D1=81=D1=82=D0=B5=D1=80?= =?UTF-8?q?=20Table=20group=20A)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Свойства редактируемых (ValueTable) таблиц формы, терявшиеся при раундтрипе: - ChangeRowSet/ChangeRowOrder — теперь эмитятся явным значением, включая false (платформа пишет false на ValueTable; раньше компилятор эмитил только true → false терялся). Декомпилятор захватывает фактическое значение. - AutoInsertNewRow — новый ключ (автодобавление строки), захват/эмиссия при true. - EnableDrag — декомпилятор теперь захватывает (компилятор уже эмитил). - RowFilter — nil-плейсхолдер (в корпусе ВСЕГДА nil, 0 с контентом). DSL-ключ rowFilter: null; компилятор эмитит nil при наличии ключа. Зеркало в form-compile.py идентично (py==ps1 проверено на ValueTable-формах). Валидация: все четыре — 0 LOST / 0 ADDED (полностью закрыты); round-trip CLEAN на ValueTable-формах (БанкиУниверсальногоОбмена, БанковскиеСчета); регресс 33/33 ps+py; harness 7971→7774 (−197), 0 fail. Вывод байт-идентичен реальным формам платформы. Spec: changeRowSet/changeRowOrder/autoInsertNewRow/enableDrag/rowFilter в table-секции. Co-Authored-By: Claude Opus 4.8 --- .../form-compile/scripts/form-compile.ps1 | 16 ++++++++++++---- .../form-compile/scripts/form-compile.py | 18 ++++++++++++------ .../form-decompile/scripts/form-decompile.ps1 | 9 ++++++--- docs/form-dsl-spec.md | 7 +++++-- 4 files changed, 35 insertions(+), 15 deletions(-) diff --git a/.claude/skills/form-compile/scripts/form-compile.ps1 b/.claude/skills/form-compile/scripts/form-compile.ps1 index cd8775e7..67845d3a 100644 --- a/.claude/skills/form-compile/scripts/form-compile.ps1 +++ b/.claude/skills/form-compile/scripts/form-compile.ps1 @@ -1,4 +1,4 @@ -# form-compile v1.41 — Compile 1C managed form from JSON or object metadata +# form-compile v1.42 — Compile 1C managed form from JSON or object metadata # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills param( [string]$JsonPath, @@ -2337,7 +2337,7 @@ function Emit-Element { # hierarchy "children"=1;"columns"=1 # table-specific - "changeRowSet"=1;"changeRowOrder"=1;"header"=1;"footer"=1 + "changeRowSet"=1;"changeRowOrder"=1;"autoInsertNewRow"=1;"rowFilter"=1;"header"=1;"footer"=1 "commandBarLocation"=1;"searchStringLocation"=1;"viewStatusLocation"=1;"searchControlLocation"=1 "excludedCommands"=1 "choiceMode"=1;"initialTreeView"=1;"enableDrag"=1;"enableStartDrag"=1 @@ -3016,8 +3016,16 @@ function Emit-Table { X "$inner$($el.representation)" } if ($el.titleLocation) { X "$inner$(Map-TitleLoc "$($el.titleLocation)")" } - if ($el.changeRowSet -eq $true) { X "$innertrue" } - if ($el.changeRowOrder -eq $true) { X "$innertrue" } + # ChangeRowSet/Order — эмитим явное значение (в т.ч. false: платформа пишет его на ValueTable) + if ($el.PSObject.Properties['changeRowSet'] -and $null -ne $el.changeRowSet) { + X "$inner$(if ($el.changeRowSet -eq $true){'true'}else{'false'})" + } + if ($el.PSObject.Properties['changeRowOrder'] -and $null -ne $el.changeRowOrder) { + X "$inner$(if ($el.changeRowOrder -eq $true){'true'}else{'false'})" + } + if ($el.autoInsertNewRow -eq $true) { X "$innertrue" } + # RowFilter — nil-плейсхолдер (всегда пустой); ключ присутствует → эмитим + if ($el.PSObject.Properties['rowFilter']) { X "$inner" } if ($el.height) { X "$inner$($el.height)" } if ($el.header -eq $false) { X "$inner
false
" } if ($el.footer -eq $true) { X "$inner
true
" } diff --git a/.claude/skills/form-compile/scripts/form-compile.py b/.claude/skills/form-compile/scripts/form-compile.py index 42d0a5a6..fd508f9c 100644 --- a/.claude/skills/form-compile/scripts/form-compile.py +++ b/.claude/skills/form-compile/scripts/form-compile.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# form-compile v1.41 — Compile 1C managed form from JSON or object metadata +# form-compile v1.42 — Compile 1C managed form from JSON or object metadata # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse import copy @@ -1775,7 +1775,7 @@ KNOWN_KEYS = { "hyperlink", "formatted", "showTitle", "united", "collapsed", "children", "columns", - "changeRowSet", "changeRowOrder", "header", "footer", + "changeRowSet", "changeRowOrder", "autoInsertNewRow", "rowFilter", "header", "footer", "commandBarLocation", "searchStringLocation", "viewStatusLocation", "searchControlLocation", "excludedCommands", "pagesRepresentation", @@ -2716,10 +2716,16 @@ def emit_table(lines, el, name, eid, indent): lines.append(f'{inner}{el["representation"]}') if el.get('titleLocation'): lines.append(f'{inner}{map_title_loc(el["titleLocation"])}') - if el.get('changeRowSet') is True: - lines.append(f'{inner}true') - if el.get('changeRowOrder') is True: - lines.append(f'{inner}true') + # ChangeRowSet/Order — явное значение (в т.ч. false: платформа пишет его на ValueTable) + if 'changeRowSet' in el and el['changeRowSet'] is not None: + lines.append(f'{inner}{"true" if el["changeRowSet"] is True else "false"}') + if 'changeRowOrder' in el and el['changeRowOrder'] is not None: + lines.append(f'{inner}{"true" if el["changeRowOrder"] is True else "false"}') + if el.get('autoInsertNewRow') is True: + lines.append(f'{inner}true') + # RowFilter — nil-плейсхолдер (ключ присутствует → эмитим) + if 'rowFilter' in el: + lines.append(f'{inner}') if el.get('height'): lines.append(f'{inner}{el["height"]}') if el.get('header') is False: diff --git a/.claude/skills/form-decompile/scripts/form-decompile.ps1 b/.claude/skills/form-decompile/scripts/form-decompile.ps1 index 6813fa08..15db297c 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.23 — Decompile 1C managed Form.xml to JSON DSL (draft) +# form-decompile v0.24 — Decompile 1C managed Form.xml to JSON DSL (draft) # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills # ВНИМАНИЕ: раундтрип не гарантируется. Навык исключён из авто-использования моделью. param( @@ -974,8 +974,11 @@ function Decompile-Element { Add-CommonProps $obj $node $name $tl = Get-Child $node 'TitleLocation'; if ($tl) { $obj['titleLocation'] = $tl.ToLower() } $rep = Get-Child $node 'Representation'; if ($rep) { $obj['representation'] = $rep } - if ((Get-Child $node 'ChangeRowSet') -eq 'true') { $obj['changeRowSet'] = $true } - if ((Get-Child $node 'ChangeRowOrder') -eq 'true') { $obj['changeRowOrder'] = $true } + $crs = Get-Child $node 'ChangeRowSet'; if ($null -ne $crs) { $obj['changeRowSet'] = ($crs -eq 'true') } + $cro = Get-Child $node 'ChangeRowOrder'; if ($null -ne $cro) { $obj['changeRowOrder'] = ($cro -eq 'true') } + if ((Get-Child $node 'AutoInsertNewRow') -eq 'true') { $obj['autoInsertNewRow'] = $true } + if ((Get-Child $node 'EnableDrag') -eq 'true') { $obj['enableDrag'] = $true } + if ($node.SelectSingleNode("lf:RowFilter", $ns)) { $obj['rowFilter'] = $null } if ((Get-Child $node 'Header') -eq 'false') { $obj['header'] = $false } if ((Get-Child $node 'Footer') -eq 'true') { $obj['footer'] = $true } $htr = Get-Child $node 'HeightInTableRows'; if ($htr) { $obj['height'] = [int]$htr } diff --git a/docs/form-dsl-spec.md b/docs/form-dsl-spec.md index 56f99a31..d5af86d0 100644 --- a/docs/form-dsl-spec.md +++ b/docs/form-dsl-spec.md @@ -315,8 +315,11 @@ | `path` | string | DataPath | | `columns` | array | Колонки (элементы input/check/labelField/picField, либо `columnGroup` для группировки) | | `representation` | string | `List`, `Tree`, `HierarchicalList` | -| `changeRowSet` | bool | Разрешить добавление/удаление строк | -| `changeRowOrder` | bool | Разрешить перемещение строк | +| `changeRowSet` | bool | Разрешить добавление/удаление строк (эмитится явное значение, в т.ч. `false`) | +| `changeRowOrder` | bool | Разрешить перемещение строк (явное значение) | +| `autoInsertNewRow` | bool | Автодобавление новой строки | +| `enableDrag` | bool | Разрешить перетаскивание из таблицы | +| `rowFilter` | null | Отбор строк (nil-плейсхолдер ``); значение всегда `null` | | `height` | int | Высота в строках таблицы | | `header` | bool | Показывать шапку | | `footer` | bool | Показывать подвал |