From 701d56b0750d3f18a9217967ad98c389f4442886 Mon Sep 17 00:00:00 2001 From: Nick Shirokov Date: Sun, 7 Jun 2026 14:58:17 +0300 Subject: [PATCH] =?UTF-8?q?feat(form-decompile,form-compile):=20=D1=80?= =?UTF-8?q?=D0=B0=D0=B7=D0=BC=D0=B0=D0=B7=D0=B0=D0=BD=D0=BD=D1=8B=D0=B9=20?= =?UTF-8?q?=D0=B1=D0=BB=D0=BE=D0=BA=20=D1=81=D0=BA=D0=B0=D0=BB=D1=8F=D1=80?= =?UTF-8?q?=D0=BE=D0=B2=20InputField=20+=20=D0=BE=D0=B1=D1=89=D0=B8=D0=B5?= =?UTF-8?q?=20cell-=D1=81=D0=B2=D0=BE=D0=B9=D1=81=D1=82=D0=B2=D0=B0=20?= =?UTF-8?q?=D0=BF=D0=BE=D0=BB=D0=B5=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Партия простых скаляров полей, которые не захватывались (платформа эмитит явное не-дефолтное значение): - InputField-специфичные: Wrap, OpenButton, ListChoiceMode, ExtendedEditMultipleValues, ChooseType, ChoiceButtonRepresentation — в Emit-Input / InputField-кейс. - Общие cell-свойства поля-колонки (Input/Label/Picture/CheckBox/ColumnGroup): ShowInHeader, ShowInFooter, AutoCellHeight, FooterHorizontalAlign, HeaderHorizontalAlign — вынесены в общий Emit-CommonElementProps / Add-Layout (захват «как есть»). ColumnGroup: собственная эмиссия ShowInHeader убрана (общий путь покрывает) — устранён двойной эмит. TOTAL diff lines выборки 2.17: 3179 → 2912 (-267), match 17 → 20 (+3 чистых формы). Все обработанные скаляры residual → 0. Снапшот input-fields (+скаляры) сертифицирован в 1С (8.3.24). Регресс form-compile 34/34 зелёный на ps + python. decompile v0.39, compile v1.57. Co-Authored-By: Claude Opus 4.8 --- .../form-compile/scripts/form-compile.ps1 | 24 +++++++++++++---- .../form-compile/scripts/form-compile.py | 26 +++++++++++++++---- .../form-decompile/scripts/form-decompile.ps1 | 13 +++++++++- docs/form-dsl-spec.md | 13 +++++++++- .../cases/form-compile/input-fields.json | 2 +- .../ПоляВвода/Forms/Форма/Ext/Form.xml | 7 +++++ 6 files changed, 72 insertions(+), 13 deletions(-) diff --git a/.claude/skills/form-compile/scripts/form-compile.ps1 b/.claude/skills/form-compile/scripts/form-compile.ps1 index 54d4ec44..3e11f62c 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.56 — Compile 1C managed form from JSON or object metadata +# form-compile v1.57 — Compile 1C managed form from JSON or object metadata # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills param( [string]$JsonPath, @@ -2432,6 +2432,9 @@ function Emit-Element { "multiLine"=1;"passwordMode"=1;"choiceButton"=1;"clearButton"=1 "spinButton"=1;"dropListButton"=1;"markIncomplete"=1;"skipOnInput"=1;"inputHint"=1 "textEdit"=1 + "wrap"=1;"openButton"=1;"listChoiceMode"=1;"showInFooter"=1 + "extendedEditMultipleValues"=1;"chooseType"=1;"autoCellHeight"=1 + "choiceButtonRepresentation"=1;"footerHorizontalAlign"=1;"headerHorizontalAlign"=1 # label/hyperlink "hyperlink"=1;"formatted"=1 # group-specific @@ -2543,6 +2546,12 @@ function Emit-CommonElementProps { } if ($el.enableStartDrag -eq $true) { X "$indenttrue" } if ($el.fileDragMode) { X "$indent$($el.fileDragMode)" } + # Cell-свойства поля в таблице (общие для Input/Label/Picture/CheckBox): захват «как есть» + foreach ($p in @(@('showInHeader','ShowInHeader'), @('showInFooter','ShowInFooter'), @('autoCellHeight','AutoCellHeight'))) { + if ($null -ne $el.($p[0])) { X "$indent<$($p[1])>$(if ($el.($p[0])){'true'}else{'false'})" } + } + if ($el.footerHorizontalAlign) { X "$indent$($el.footerHorizontalAlign)" } + if ($el.headerHorizontalAlign) { X "$indent$($el.headerHorizontalAlign)" } } function Emit-Layout { @@ -2712,10 +2721,7 @@ function Emit-ColumnGroup { if ($orientation) { X "$inner$orientation" } if ($el.showTitle -eq $false) { X "$innerfalse" } - if ($null -ne $el.showInHeader) { - $shVal = if ($el.showInHeader) { "true" } else { "false" } - X "$inner$shVal" - } + # showInHeader эмитится общим Emit-CommonElementProps (через Emit-Layout) Emit-CommonFlags -el $el -indent $inner Emit-Layout -el $el -indent $inner @@ -2768,6 +2774,14 @@ function Emit-Input { if ($el.markIncomplete -eq $true) { X "$innertrue" } if ($el.editMode) { X "$inner$($el.editMode)" } if ($el.textEdit -eq $false) { X "$innerfalse" } + # InputField-специфичные скаляры (захват «как есть»: платформа эмитит явное не-дефолтное значение) + foreach ($p in @( + @('wrap','Wrap'), @('openButton','OpenButton'), @('listChoiceMode','ListChoiceMode'), + @('extendedEditMultipleValues','ExtendedEditMultipleValues'), @('chooseType','ChooseType') + )) { + if ($null -ne $el.($p[0])) { X "$inner<$($p[1])>$(if ($el.($p[0])){'true'}else{'false'})" } + } + if ($el.choiceButtonRepresentation) { X "$inner$($el.choiceButtonRepresentation)" } Emit-Layout -el $el -indent $inner -multiLineDefault ([bool]($el.multiLine -eq $true)) if ($el.inputHint) { diff --git a/.claude/skills/form-compile/scripts/form-compile.py b/.claude/skills/form-compile/scripts/form-compile.py index dab697f9..c1ee2f0a 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.56 — Compile 1C managed form from JSON or object metadata +# form-compile v1.57 — Compile 1C managed form from JSON or object metadata # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse import copy @@ -1771,7 +1771,10 @@ KNOWN_KEYS = { "groupHorizontalAlign", "groupVerticalAlign", "horizontalAlign", "multiLine", "passwordMode", "choiceButton", "clearButton", "spinButton", "dropListButton", "markIncomplete", "skipOnInput", "inputHint", - "textEdit", + "textEdit", "choiceList", + "wrap", "openButton", "listChoiceMode", "showInHeader", "showInFooter", + "extendedEditMultipleValues", "chooseType", "autoCellHeight", + "choiceButtonRepresentation", "footerHorizontalAlign", "headerHorizontalAlign", "hyperlink", "formatted", "showTitle", "united", "collapsed", "behavior", "children", "columns", @@ -2198,6 +2201,14 @@ def emit_common_element_props(lines, el, indent): lines.append(f"{indent}true") if el.get('fileDragMode'): lines.append(f"{indent}{el['fileDragMode']}") + # Cell-свойства поля в таблице (общие для Input/Label/Picture/CheckBox): захват «как есть» + for key, tag in (('showInHeader', 'ShowInHeader'), ('showInFooter', 'ShowInFooter'), ('autoCellHeight', 'AutoCellHeight')): + if el.get(key) is not None: + lines.append(f'{indent}<{tag}>{"true" if el[key] else "false"}') + if el.get('footerHorizontalAlign'): + lines.append(f"{indent}{el['footerHorizontalAlign']}") + if el.get('headerHorizontalAlign'): + lines.append(f"{indent}{el['headerHorizontalAlign']}") def emit_layout(lines, el, indent, skip_height=False, multi_line_default=False): @@ -2620,9 +2631,7 @@ def emit_column_group(lines, el, name, eid, indent): if el.get('showTitle') is False: lines.append(f'{inner}false') - if el.get('showInHeader') is not None: - sh_val = 'true' if el['showInHeader'] else 'false' - lines.append(f'{inner}{sh_val}') + # showInHeader эмитится общим emit_common_element_props (через emit_layout) emit_common_flags(lines, el, inner) emit_layout(lines, el, inner) @@ -2673,6 +2682,13 @@ def emit_input(lines, el, name, eid, indent): lines.append(f'{inner}{el["editMode"]}') if el.get('textEdit') is False: lines.append(f'{inner}false') + # InputField-специфичные скаляры (захват «как есть»: платформа эмитит явное не-дефолтное значение) + for key, tag in (('wrap', 'Wrap'), ('openButton', 'OpenButton'), ('listChoiceMode', 'ListChoiceMode'), + ('extendedEditMultipleValues', 'ExtendedEditMultipleValues'), ('chooseType', 'ChooseType')): + if el.get(key) is not None: + lines.append(f'{inner}<{tag}>{"true" if el[key] else "false"}') + if el.get('choiceButtonRepresentation'): + lines.append(f'{inner}{el["choiceButtonRepresentation"]}') emit_layout(lines, el, inner, multi_line_default=(el.get('multiLine') is True)) if el.get('inputHint'): diff --git a/.claude/skills/form-decompile/scripts/form-decompile.ps1 b/.claude/skills/form-decompile/scripts/form-decompile.ps1 index cdef99c7..f5604d5b 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.38 — Decompile 1C managed Form.xml to JSON DSL (draft) +# form-decompile v0.39 — Decompile 1C managed Form.xml to JSON DSL (draft) # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills # ВНИМАНИЕ: раундтрип не гарантируется. Навык исключён из авто-использования моделью. param( @@ -753,6 +753,12 @@ function Add-Layout { $gha = Get-Child $node 'GroupHorizontalAlign'; if ($gha) { $obj['groupHorizontalAlign'] = $gha } $gva = Get-Child $node 'GroupVerticalAlign'; if ($gva) { $obj['groupVerticalAlign'] = $gva } $ha = Get-Child $node 'HorizontalAlign'; if ($ha) { $obj['horizontalAlign'] = $ha } + # Cell-свойства поля в таблице (общие для Input/Label/Picture/CheckBox): захват «как есть» + foreach ($p in @('ShowInHeader','ShowInFooter','AutoCellHeight')) { + $v = Get-Child $node $p; if ($null -ne $v) { $obj[($p.Substring(0,1).ToLower()+$p.Substring(1))] = ($v -eq 'true') } + } + $fha = Get-Child $node 'FooterHorizontalAlign'; if ($fha) { $obj['footerHorizontalAlign'] = $fha } + $hha = Get-Child $node 'HeaderHorizontalAlign'; if ($hha) { $obj['headerHorizontalAlign'] = $hha } } # TitleLocation у check/radio (зеркало Emit-TitleLocation): @@ -1032,6 +1038,11 @@ function Decompile-Element { foreach ($p in @('ChoiceButton','ClearButton','SpinButton','DropListButton')) { $v = Get-Child $node $p; if ($null -ne $v) { $obj[($p.Substring(0,1).ToLower()+$p.Substring(1))] = (To-Bool $v) } } + # InputField-специфичные скаляры (захват «как есть») + foreach ($p in @('Wrap','OpenButton','ListChoiceMode','ExtendedEditMultipleValues','ChooseType')) { + $v = Get-Child $node $p; if ($null -ne $v) { $obj[($p.Substring(0,1).ToLower()+$p.Substring(1))] = (To-Bool $v) } + } + $cbr = Get-Child $node 'ChoiceButtonRepresentation'; if ($cbr) { $obj['choiceButtonRepresentation'] = $cbr } $cl = Decompile-ChoiceList $node; if ($cl) { $obj['choiceList'] = $cl } } 'CheckBoxField' { diff --git a/docs/form-dsl-spec.md b/docs/form-dsl-spec.md index baf49cd8..052bcf65 100644 --- a/docs/form-dsl-spec.md +++ b/docs/form-dsl-spec.md @@ -216,8 +216,13 @@ companion-панели с собственным контентом. Оба не | `defaultItem` | `` | `true` (элемент активируется по умолчанию) | | `enableStartDrag` | `` | `true` (разрешить начало перетаскивания) | | `fileDragMode` | `` | `AsFile`/… (режим drag-n-drop файлов) | +| `showInHeader` | `` | bool — показывать в шапке таблицы (поле-колонка) | +| `showInFooter` | `` | bool — показывать в подвале таблицы | +| `autoCellHeight` | `` | bool — авто-высота ячейки | +| `footerHorizontalAlign` | `` | `Left`/`Right`/`Center` | +| `headerHorizontalAlign` | `` | `Left`/`Right`/`Center`/`Auto` | -> `defaultItem`/`enableStartDrag`/`fileDragMode`/`skipOnInput` — общие для любого типа элемента (таблица, поле, надпись, картинка, кнопка), не только таблицы. +> `defaultItem`/`enableStartDrag`/`fileDragMode`/`skipOnInput` + cell-свойства (`showInHeader`/`showInFooter`/`autoCellHeight`/`footerHorizontalAlign`/`headerHorizontalAlign`) — общие для любого поля-колонки (input, label, picField, check). ### 4.2. События элемента и автоименование обработчиков @@ -301,6 +306,12 @@ companion-панели с собственным контентом. Оба не | `skipOnInput` | bool | Пропускать при вводе | | `inputHint` | string | Подсказка ввода (placeholder) | | `choiceList` | array | Список выбора: массив `{ value, presentation?/title? }` — та же грамматика, что у `radio` (см. ниже) | +| `wrap` | bool | Перенос по словам (``) | +| `openButton` | bool | Кнопка открытия (``) | +| `listChoiceMode` | bool | Режим выбора из списка (``) | +| `extendedEditMultipleValues` | bool | Расширенное редактирование нескольких значений | +| `chooseType` | bool | Выбор типа (``) | +| `choiceButtonRepresentation` | string | `ShowInInputField`, `ShowInDropList`, `ShowInDropListAndInInputField` | | `width` | int | Ширина | | `height` | int | Высота | | `horizontalStretch` | bool | Растягивание по горизонтали | diff --git a/tests/skills/cases/form-compile/input-fields.json b/tests/skills/cases/form-compile/input-fields.json index be87a43f..ab843b18 100644 --- a/tests/skills/cases/form-compile/input-fields.json +++ b/tests/skills/cases/form-compile/input-fields.json @@ -18,7 +18,7 @@ "elements": [ { "input": "ОбычноеПоле", "path": "ОбычноеПоле", "title": "Обычное поле", "tooltip": "Введите значение поля", "tooltipRepresentation": "ShowBottom", "editMode": "EnterOnInput" }, { "labelField": "Ссылка", "path": "ОбычноеПоле", "titleLocation": "left", "hyperlink": true }, - { "input": "МногострочноеПоле", "path": "МногострочноеПоле", "multiLine": true, "height": 5, "title": "Комментарий" }, + { "input": "МногострочноеПоле", "path": "МногострочноеПоле", "multiLine": true, "height": 5, "title": "Комментарий", "wrap": false, "showInHeader": false, "showInFooter": false, "autoCellHeight": true, "footerHorizontalAlign": "Right", "openButton": false, "chooseType": false }, { "input": "ПолеПароля", "path": "ПолеПароля", "passwordMode": true, "title": "Пароль" }, { "input": "ПолеСКнопками", "path": "ПолеСКнопками", "choiceButton": true, "clearButton": true, "title": "Выбор" }, { "input": "ПолеСписокВыбора", "path": "ПолеСписокВыбора", "title": "Список выбора", "choiceList": [ diff --git a/tests/skills/cases/form-compile/snapshots/input-fields/DataProcessors/ПоляВвода/Forms/Форма/Ext/Form.xml b/tests/skills/cases/form-compile/snapshots/input-fields/DataProcessors/ПоляВвода/Forms/Форма/Ext/Form.xml index f1754f32..4300ab90 100644 --- a/tests/skills/cases/form-compile/snapshots/input-fields/DataProcessors/ПоляВвода/Forms/Форма/Ext/Form.xml +++ b/tests/skills/cases/form-compile/snapshots/input-fields/DataProcessors/ПоляВвода/Forms/Форма/Ext/Form.xml @@ -44,6 +44,13 @@ true + false + false + false + false + false + true + Right false 5