From 75b77caf9b8fc2823954d33ff44d3489b59a0bc7 Mon Sep 17 00:00:00 2001 From: Nick Shirokov Date: Fri, 12 Jun 2026 11:40:16 +0300 Subject: [PATCH] =?UTF-8?q?feat(form-decompile,form-compile):=20InputField?= =?UTF-8?q?=20availableTypes=20+=20typeDomainEnabled=20(=D0=BE=D0=B3=D1=80?= =?UTF-8?q?=D0=B0=D0=BD=D0=B8=D1=87=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=B4=D0=BE?= =?UTF-8?q?=D1=81=D1=82=D1=83=D0=BF=D0=BD=D1=8B=D1=85=20=D1=82=D0=B8=D0=BF?= =?UTF-8?q?=D0=BE=D0=B2)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Раундтрип терял блок ограничения типов у поля ввода на составном/характеристика-типе: + (напр. ЯндексМаркетВитринаФулфилмент/РегламентноеЗадание — поле ИмяПользователя с AvailableTypes=xs:string Length=0 Variable). Корпус (acc+erp 8.3.24): AvailableTypes встречается в 18 местах, ВСЕ — на InputField (полное покрытие scope). Содержимое — стандартный 1С type-description (+qualifiers), тот же формат, что у реквизитов → переиспользуем существующий механизм типов: - decompile: Decompile-Type на узле → компактная DSL-строка (одиночная/мультитип "a | b") - compile (ps1+py): Emit-Type с tag='AvailableTypes' (сам разбирает мультитип); TypeDomainEnabled — bool pass-through availableTypes — формат типа реквизита (§Типы): одиночный или составной через "|". Верификация: таргет-раундтрип всех 17 форм с AvailableTypes → 15 match, остаток 6 строк в 2 формах — ДРУГИЕ категории (ExtendedTooltip/Value), не AvailableTypes; целевая форма match (было 8 → 0). Регресс form-compile 43/43 (ps1+py); 1С-cert кейса input-fields (поле с мультитип AvailableTypes грузится в платформу). spec обновлён. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../form-compile/scripts/form-compile.ps1 | 6 +- .../form-compile/scripts/form-compile.py | 8 ++- .../form-decompile/scripts/form-decompile.ps1 | 6 +- docs/form-dsl-spec.md | 2 + .../cases/form-compile/input-fields.json | 6 +- .../ПоляВвода/Forms/Форма/Ext/Form.xml | 66 ++++++++++++++----- 6 files changed, 74 insertions(+), 20 deletions(-) diff --git a/.claude/skills/form-compile/scripts/form-compile.ps1 b/.claude/skills/form-compile/scripts/form-compile.ps1 index c6a145ec..c2b5263b 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.127 — Compile 1C managed form from JSON or object metadata +# form-compile v1.128 — Compile 1C managed form from JSON or object metadata # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills param( [string]$JsonPath, @@ -3640,6 +3640,10 @@ function Emit-Input { )) { if ($null -ne $el.($p[0])) { X "$inner<$($p[1])>$(if ($el.($p[0])){'true'}else{'false'})" } } + # Ограничение доступных типов (поле на составном типе): домен типов + явный набор. + # availableTypes — формат типа реквизита (§type); Emit-Type сам разбирает мультитип "a | b". + if ($null -ne $el.typeDomainEnabled) { X "$inner$(if ($el.typeDomainEnabled){'true'}else{'false'})" } + if ($el.availableTypes) { Emit-Type -typeStr $el.availableTypes -indent $inner -tag 'AvailableTypes' } # InputField-специфичные value-скаляры foreach ($p in @( @('choiceForm','ChoiceForm'), @('choiceHistoryOnInput','ChoiceHistoryOnInput'), diff --git a/.claude/skills/form-compile/scripts/form-compile.py b/.claude/skills/form-compile/scripts/form-compile.py index b940c055..690edb91 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.127 — Compile 1C managed form from JSON or object metadata +# form-compile v1.128 — Compile 1C managed form from JSON or object metadata # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse import copy @@ -3728,6 +3728,12 @@ def emit_input(lines, el, name, eid, indent): ('quickChoice', 'QuickChoice'), ('autoChoiceIncomplete', 'AutoChoiceIncomplete')): if el.get(key) is not None: lines.append(f'{inner}<{tag}>{"true" if el[key] else "false"}') + # Ограничение доступных типов (поле на составном типе): домен типов + явный набор. + # availableTypes — формат типа реквизита (§type); emit_type сам разбирает мультитип "a | b". + if el.get('typeDomainEnabled') is not None: + lines.append(f'{inner}{"true" if el["typeDomainEnabled"] else "false"}') + if el.get('availableTypes'): + emit_type(lines, el['availableTypes'], inner, tag='AvailableTypes') # InputField-специфичные value-скаляры for key, tag in (('choiceForm', 'ChoiceForm'), ('choiceHistoryOnInput', 'ChoiceHistoryOnInput'), ('choiceFoldersAndItems', 'ChoiceFoldersAndItems'), ('footerDataPath', 'FooterDataPath')): diff --git a/.claude/skills/form-decompile/scripts/form-decompile.ps1 b/.claude/skills/form-decompile/scripts/form-decompile.ps1 index bb4919d3..9b8dc107 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 v1.01 — Decompile 1C managed Form.xml to JSON DSL (draft) +# form-decompile v1.02 — Decompile 1C managed Form.xml to JSON DSL (draft) # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills # ВНИМАНИЕ: раундтрип не гарантируется. Навык исключён из авто-использования моделью. param( @@ -1651,6 +1651,10 @@ function Decompile-Element { } else { $obj[$key] = $txt } } } + # Ограничение доступных типов (поле на составном/характеристика-типе): домен типов + явный набор. + # availableTypes — тот же формат типа, что у реквизитов (§type), захват через Decompile-Type. + $tde = Get-Child $node 'TypeDomainEnabled'; if ($null -ne $tde) { $obj['typeDomainEnabled'] = (To-Bool $tde) } + $atNode = $node.SelectSingleNode("lf:AvailableTypes", $ns); if ($atNode) { $at = Decompile-Type $atNode; if ($at) { $obj['availableTypes'] = $at } } $cbr = Get-Child $node 'ChoiceButtonRepresentation'; if ($cbr) { $obj['choiceButtonRepresentation'] = $cbr } $cbp = Get-PictureRef $node 'ChoiceButtonPicture'; if ($null -ne $cbp) { $obj['choiceButtonPicture'] = $cbp } if ((Get-Child $node 'TextEdit') -eq 'false') { $obj['textEdit'] = $false } diff --git a/docs/form-dsl-spec.md b/docs/form-dsl-spec.md index d651b4b2..a7e039ad 100644 --- a/docs/form-dsl-spec.md +++ b/docs/form-dsl-spec.md @@ -407,6 +407,8 @@ companion-панели с собственным контентом. Оба не | `choiceFoldersAndItems` | string | Выбор групп и элементов (``): `Items`, `Folders`, `FoldersAndItems` | | `fixingInTable` | string | Фиксация колонки в таблице (``): `Left`, `Right`, `None`. Так же у `labelField` и др. полей | | `footerDataPath` | string | DataPath подвала колонки таблицы (``) | +| `availableTypes` | string | Ограничение доступных типов поля на составном/характеристика-типе (``). Формат типа реквизита (§«Типы»): одиночный (`string`, `CatalogRef.Валюты`) или составной через `\|` (`string \| boolean \| decimal(10,2)`). Редкое (~18 в корпусе, только InputField) | +| `typeDomainEnabled` | bool | Включён ли домен типов (``); обычно `false` при заданном `availableTypes`. Захват «как есть» | | `choiceButtonRepresentation` | string | `ShowInInputField`, `ShowInDropList`, `ShowInDropListAndInInputField` | | `minValue` / `maxValue` | number/string | Мин./макс. значение (``/`` с обязательным `xsi:type`). **JSON-число → `xs:decimal`, строка → `xs:string`** (тип сохраняется декомпилятором через тип JSON-значения) | | `width` | int | Ширина | diff --git a/tests/skills/cases/form-compile/input-fields.json b/tests/skills/cases/form-compile/input-fields.json index 6ad314ab..32da4b8d 100644 --- a/tests/skills/cases/form-compile/input-fields.json +++ b/tests/skills/cases/form-compile/input-fields.json @@ -50,7 +50,8 @@ { "check": "Флаг", "path": "Флаг", "title": "Включено", "warningOnEdit": { "ru": "Изменение флага требует подтверждения", "en": "Confirm flag change" }, "extendedTooltip": { "width": 45 } }, { "check": "ФлагПлатформенный", "path": "ФлагПлатформенный", "title": "Слева", "titleLocation": "" }, { "check": "ФлагЯвный", "path": "ФлагЯвный", "title": "Сверху", "titleLocation": "top" }, - { "check": "ФлагТумблер", "path": "ФлагТумблер", "title": "Тумблер", "checkBoxType": "switcher", "format": "БЛ=Нет; БИ=Да" } + { "check": "ФлагТумблер", "path": "ФлагТумблер", "title": "Тумблер", "checkBoxType": "switcher", "format": "БЛ=Нет; БИ=Да" }, + { "input": "ПолеСоставное", "path": "ПолеСоставное", "title": "Ограничение типов", "typeDomainEnabled": false, "availableTypes": "string | boolean" } ], "attributes": [ { "name": "Объект", "type": "DataProcessorObject.ПоляВвода", "main": true }, @@ -67,7 +68,8 @@ { "name": "ФлагЯвный", "type": "boolean" }, { "name": "ФлагТумблер", "type": "boolean" }, { "name": "ЧисловоеПоле", "type": "number(10,2)" }, - { "name": "ДатаПоля", "type": "dateTime" } + { "name": "ДатаПоля", "type": "dateTime" }, + { "name": "ПолеСоставное", "type": "string | boolean" } ], "conditionalAppearance": [ { "selection": ["ОбычноеПоле"], "filter": ["ЧисловоеПоле > 100"], "appearance": { "ЦветФона": "style:FormBackColor", "Текст": "Плоский текст" }, 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 618dfa34..e7ae7804 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 @@ -427,15 +427,35 @@ + + ПолеСоставное + + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Ограничение типов</v8:content> + </v8:item> + + false + + xs:string + + 0 + Variable + + xs:boolean + + + + - + cfg:DataProcessorObject.ПоляВвода true - + <v8:item> <v8:lang>ru</v8:lang> @@ -450,7 +470,7 @@ </v8:StringQualifiers> </Type> </Attribute> - <Attribute name="МногострочноеПоле" id="45"> + <Attribute name="МногострочноеПоле" id="48"> <Title> <v8:item> <v8:lang>ru</v8:lang> @@ -465,7 +485,7 @@ </v8:StringQualifiers> </Type> </Attribute> - <Attribute name="ПолеПароля" id="46"> + <Attribute name="ПолеПароля" id="49"> <Title> <v8:item> <v8:lang>ru</v8:lang> @@ -480,7 +500,7 @@ </v8:StringQualifiers> </Type> </Attribute> - <Attribute name="ПолеСКнопками" id="47"> + <Attribute name="ПолеСКнопками" id="50"> <Title> <v8:item> <v8:lang>ru</v8:lang> @@ -495,7 +515,7 @@ </v8:StringQualifiers> </Type> </Attribute> - <Attribute name="ПолеСписокВыбора" id="48"> + <Attribute name="ПолеСписокВыбора" id="51"> <Title> <v8:item> <v8:lang>ru</v8:lang> @@ -510,7 +530,7 @@ </v8:StringQualifiers> </Type> </Attribute> - <Attribute name="ПолеПодсказка" id="49"> + <Attribute name="ПолеПодсказка" id="52"> <Title> <v8:item> <v8:lang>ru</v8:lang> @@ -525,7 +545,7 @@ </v8:StringQualifiers> </Type> </Attribute> - <Attribute name="ПолеСвязи" id="50"> + <Attribute name="ПолеСвязи" id="53"> <Title> <v8:item> <v8:lang>ru</v8:lang> @@ -540,7 +560,7 @@ </v8:StringQualifiers> </Type> </Attribute> - <Attribute name="ПолеСвязиКратко" id="51"> + <Attribute name="ПолеСвязиКратко" id="54"> <Title> <v8:item> <v8:lang>ru</v8:lang> @@ -555,7 +575,7 @@ </v8:StringQualifiers> </Type> </Attribute> - <Attribute name="Флаг" id="52"> + <Attribute name="Флаг" id="55"> <Title> <v8:item> <v8:lang>ru</v8:lang> @@ -566,7 +586,7 @@ <v8:Type>xs:boolean</v8:Type> </Type> </Attribute> - <Attribute name="ФлагПлатформенный" id="53"> + <Attribute name="ФлагПлатформенный" id="56"> <Title> <v8:item> <v8:lang>ru</v8:lang> @@ -577,7 +597,7 @@ <v8:Type>xs:boolean</v8:Type> </Type> </Attribute> - <Attribute name="ФлагЯвный" id="54"> + <Attribute name="ФлагЯвный" id="57"> <Title> <v8:item> <v8:lang>ru</v8:lang> @@ -588,7 +608,7 @@ <v8:Type>xs:boolean</v8:Type> </Type> </Attribute> - <Attribute name="ФлагТумблер" id="55"> + <Attribute name="ФлагТумблер" id="58"> <Title> <v8:item> <v8:lang>ru</v8:lang> @@ -599,7 +619,7 @@ <v8:Type>xs:boolean</v8:Type> </Type> </Attribute> - <Attribute name="ЧисловоеПоле" id="56"> + <Attribute name="ЧисловоеПоле" id="59"> <Title> <v8:item> <v8:lang>ru</v8:lang> @@ -615,7 +635,7 @@ </v8:NumberQualifiers> </Type> </Attribute> - <Attribute name="ДатаПоля" id="57"> + <Attribute name="ДатаПоля" id="60"> <Title> <v8:item> <v8:lang>ru</v8:lang> @@ -629,6 +649,22 @@ </v8:DateQualifiers> </Type> </Attribute> + <Attribute name="ПолеСоставное" id="61"> + <Title> + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Поле составное</v8:content> + </v8:item> + + + xs:string + + 0 + Variable + + xs:boolean + +