feat(form-decompile,form-compile): группировка строк динамического списка (StructureItemGroup в ListSettings, кластер B)

Структура группировок дин-списка (`<dcsset:item StructureItemGroup>` → groupItems →
GroupItemField, вложенность через дочерний item) — переиспользована модель/реализация
из skd (Emit-GroupItems/Get-GroupFields), но плоская: группировка списка всегда
линейная цепочка одно-польных уровней над неявными деталями (без children/selection/
order/details — корпус подтверждает).

DSL — новый ключ `settings.grouping` (forgiving-синонимы `structure`/`группировка`):
- шорткат "A > B > C" (вложенные уровни, внешний→внутренний) или массив;
- элемент уровня — строка (имя поля) или объект {field, groupType?, periodAdditionType?,
  periodAdditionBegin?, periodAdditionEnd?} для нестандартного поля (ключи = теги
  исходника; periodAddition с авто-детектом ISO-дата/dcscor:Field).
Корпус 8.3.24 (29 форм/34 уровня): groupType Items 33 / Hierarchy 1, periodAddition нет.

Компилятор (ps1+py): Emit-ListGrouping + рекурсивная цепочка StructureItemGroup в
позиции после conditionalAppearance, до itemsViewMode. Оба пути — shape-дескриптор
(round-trip) и канонический (авторинг). Декомпилятор: Build-ListGrouping (линейная
цепочка; bail→$null на ветвлении/мультиполе/доп.содержимом = честный LOST, не порча);
Get-ListSettingsShape распознаёт `item`→`structure` (раньше → $null/канон-fallback,
из-за чего терялась группировка и додумывался itemsUserSettingID).

Выборка 17 форм с группировкой: match 0→10, TOTAL 75→25 (остаток — др. кластеры:
presentation xs:string, order-item use). Широкая (cat-a 102): match 82→84, TOTAL
280→256, ноль регрессий. Кейс dynamic-list-form (+grouping "Description > Code")
сертифицирован загрузкой в 1С. Регресс 43/43 (ps1+py).

Фикс по пути: PS-ловушка — одноэлементный массив разворачивался при return из
Parse-ListGrouping → строка → индексация давала char → пустой <field>. Unary comma ,@().

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Nick Shirokov
2026-06-12 19:09:48 +03:00
co-authored by Claude Opus 4.8
parent 081d3a8a2f
commit 43d36119cb
6 changed files with 245 additions and 6 deletions
@@ -20,6 +20,7 @@
{ "name": "Список", "type": "DynamicList", "useAlways": ["~Артикул", "Список.Code", "Description"], "settings": {
"mainTable": "Catalog.Товары", "dynamicDataRead": true, "autoSaveUserSettings": false,
"parameters": [ { "name": "ВыборТовара", "type": "CatalogRef.Товары", "valueListAllowed": true, "value": null } ],
"grouping": "Description > Code",
"order": [ "Description", "Code desc" ],
"filter": [ "Артикул = _ @off @user", "Артикул like %тест%", "Description подобно %abc%",
{ "field": "Code", "op": "=", "userSettingID": "auto", "userSettingPresentation": "Код товара" },
@@ -196,6 +196,28 @@
<dcsset:viewMode>Normal</dcsset:viewMode>
<dcsset:userSettingID>UUID-007</dcsset:userSettingID>
</dcsset:conditionalAppearance>
<dcsset:item xsi:type="dcsset:StructureItemGroup">
<dcsset:groupItems>
<dcsset:item xsi:type="dcsset:GroupItemField">
<dcsset:field>Description</dcsset:field>
<dcsset:groupType>Items</dcsset:groupType>
<dcsset:periodAdditionType>None</dcsset:periodAdditionType>
<dcsset:periodAdditionBegin xsi:type="xs:dateTime">0001-01-01T00:00:00</dcsset:periodAdditionBegin>
<dcsset:periodAdditionEnd xsi:type="xs:dateTime">0001-01-01T00:00:00</dcsset:periodAdditionEnd>
</dcsset:item>
</dcsset:groupItems>
<dcsset:item xsi:type="dcsset:StructureItemGroup">
<dcsset:groupItems>
<dcsset:item xsi:type="dcsset:GroupItemField">
<dcsset:field>Code</dcsset:field>
<dcsset:groupType>Items</dcsset:groupType>
<dcsset:periodAdditionType>None</dcsset:periodAdditionType>
<dcsset:periodAdditionBegin xsi:type="xs:dateTime">0001-01-01T00:00:00</dcsset:periodAdditionBegin>
<dcsset:periodAdditionEnd xsi:type="xs:dateTime">0001-01-01T00:00:00</dcsset:periodAdditionEnd>
</dcsset:item>
</dcsset:groupItems>
</dcsset:item>
</dcsset:item>
<dcsset:itemsViewMode>Normal</dcsset:itemsViewMode>
<dcsset:itemsUserSettingID>UUID-008</dcsset:itemsUserSettingID>
</ListSettings>