From 786bdf97d95241687929e719fd16637159fac528 Mon Sep 17 00:00:00 2001 From: Nick Shirokov Date: Sun, 7 Jun 2026 13:47:28 +0300 Subject: [PATCH] =?UTF-8?q?feat(form-decompile,form-compile):=20Additional?= =?UTF-8?q?Columns=20=E2=80=94=20=D0=B4=D0=BE=D0=BF.=20=D0=BA=D0=BE=D0=BB?= =?UTF-8?q?=D0=BE=D0=BD=D0=BA=D0=B8=20=D1=82=D0=B0=D0=B1=D0=BB=D0=B8=D1=87?= =?UTF-8?q?=D0=BD=D1=8B=D1=85=20=D1=87=D0=B0=D1=81=D1=82=D0=B5=D0=B9=20?= =?UTF-8?q?=D0=BE=D0=B1=D1=8A=D0=B5=D0=BA=D1=82=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit у главного реквизита-объекта (3654 формы, 10187 блоков) — форма-определённые доп. колонки табличных частей. Декомпилятор читал только прямые (SelectNodes lf:Column), теряя AdditionalColumns целиком (часто весь блок объекта). Ключ реквизита additionalColumns: [{ table, columns: [] }]; — та же грамматика, что у columns (name/type/title/functionalOptions). Общие хелперы Emit/Decompile-AttrColumn (переиспользуются прямыми колонками и AdditionalColumns). Порядок схемы: прямые сначала, затем AdditionalColumns-группы. TOTAL diff lines выборки 2.17: 3695 → 3347 (-348). Attribute>Columns/AdditionalColumns residual → 0. Новый кейс additional-columns (DataProcessor с табчастью + форма) сертифицирован в 1С (8.3.24). Регресс form-compile 34/34 зелёный на ps + python. decompile v0.37, compile v1.55. Co-Authored-By: Claude Opus 4.8 --- .../form-compile/scripts/form-compile.ps1 | 38 ++- .../form-compile/scripts/form-compile.py | 38 ++- .../form-decompile/scripts/form-decompile.ps1 | 33 ++- docs/form-dsl-spec.md | 3 +- .../form-compile/additional-columns.json | 38 +++ .../additional-columns/Configuration.xml | 252 ++++++++++++++++++ .../DataProcessors/ДопКолонки.xml | 128 +++++++++ .../ДопКолонки/Ext/ManagerModule.bsl | 0 .../ДопКолонки/Ext/ObjectModule.bsl | 0 .../DataProcessors/ДопКолонки/Forms/Форма.xml | 22 ++ .../ДопКолонки/Forms/Форма/Ext/Form.xml | 49 ++++ .../Forms/Форма/Ext/Form/Module.bsl | 19 ++ .../Ext/ClientApplicationInterface.xml | 18 ++ .../additional-columns/Languages/Русский.xml | 16 ++ 14 files changed, 621 insertions(+), 33 deletions(-) create mode 100644 tests/skills/cases/form-compile/additional-columns.json create mode 100644 tests/skills/cases/form-compile/snapshots/additional-columns/Configuration.xml create mode 100644 tests/skills/cases/form-compile/snapshots/additional-columns/DataProcessors/ДопКолонки.xml create mode 100644 tests/skills/cases/form-compile/snapshots/additional-columns/DataProcessors/ДопКолонки/Ext/ManagerModule.bsl create mode 100644 tests/skills/cases/form-compile/snapshots/additional-columns/DataProcessors/ДопКолонки/Ext/ObjectModule.bsl create mode 100644 tests/skills/cases/form-compile/snapshots/additional-columns/DataProcessors/ДопКолонки/Forms/Форма.xml create mode 100644 tests/skills/cases/form-compile/snapshots/additional-columns/DataProcessors/ДопКолонки/Forms/Форма/Ext/Form.xml create mode 100644 tests/skills/cases/form-compile/snapshots/additional-columns/DataProcessors/ДопКолонки/Forms/Форма/Ext/Form/Module.bsl create mode 100644 tests/skills/cases/form-compile/snapshots/additional-columns/Ext/ClientApplicationInterface.xml create mode 100644 tests/skills/cases/form-compile/snapshots/additional-columns/Languages/Русский.xml diff --git a/.claude/skills/form-compile/scripts/form-compile.ps1 b/.claude/skills/form-compile/scripts/form-compile.ps1 index 0d23f188..c9da793b 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.54 — Compile 1C managed form from JSON or object metadata +# form-compile v1.55 — Compile 1C managed form from JSON or object metadata # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills param( [string]$JsonPath, @@ -3616,6 +3616,17 @@ function Emit-FunctionalOptions { X "$indent" } +# Колонка реквизита (ValueTable/Tree или AdditionalColumns): name/Title/Type/FunctionalOptions. +function Emit-AttrColumn { + param($col, [string]$indent) + $colId = New-Id + X "$indent" + if ($col.title) { Emit-MLText -tag "Title" -text $col.title -indent "$indent`t" } + Emit-Type -typeStr "$($col.type)" -indent "$indent`t" + Emit-FunctionalOptions -fo $col.functionalOptions -indent "$indent`t" + X "$indent" +} + function Emit-Attributes { param($attrs, [string]$indent) @@ -3684,19 +3695,22 @@ function Emit-Attributes { Emit-FunctionalOptions -fo $attr.functionalOptions -indent $inner - # Columns (for ValueTable/ValueTree). Для дин-списка (есть settings) колонки НЕ эмитим — - # они служат лишь для формирования UseAlways (поля выше). - if ($attr.columns -and $attr.columns.Count -gt 0 -and -not $attr.settings) { + # Columns: прямые (ValueTable/Tree) + (доп. колонки + # табличных частей объекта). Порядок схемы: прямые сначала, затем AdditionalColumns-группы. + # Для дин-списка (есть settings) прямые колонки НЕ эмитим (служат лишь для UseAlways). + $hasDirectCols = $attr.columns -and $attr.columns.Count -gt 0 -and -not $attr.settings + $hasAddCols = $attr.additionalColumns -and @($attr.additionalColumns).Count -gt 0 + if ($hasDirectCols -or $hasAddCols) { X "$inner" - foreach ($col in $attr.columns) { - $colId = New-Id - X "$inner`t" - if ($col.title) { - Emit-MLText -tag "Title" -text $col.title -indent "$inner`t`t" + if ($hasDirectCols) { + foreach ($col in $attr.columns) { Emit-AttrColumn -col $col -indent "$inner`t" } + } + if ($hasAddCols) { + foreach ($ac in @($attr.additionalColumns)) { + X "$inner`t" + foreach ($col in @($ac.columns)) { Emit-AttrColumn -col $col -indent "$inner`t`t" } + X "$inner`t" } - Emit-Type -typeStr "$($col.type)" -indent "$inner`t`t" - Emit-FunctionalOptions -fo $col.functionalOptions -indent "$inner`t`t" - X "$inner`t" } X "$inner" } diff --git a/.claude/skills/form-compile/scripts/form-compile.py b/.claude/skills/form-compile/scripts/form-compile.py index 7e00c709..712a1b9e 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.54 — Compile 1C managed form from JSON or object metadata +# form-compile v1.55 — Compile 1C managed form from JSON or object metadata # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse import copy @@ -3292,6 +3292,17 @@ def emit_functional_options(lines, fo, indent): lines.append(f'{indent}') +def emit_attr_column(lines, col, indent): + # Колонка реквизита (ValueTable/Tree или AdditionalColumns): name/Title/Type/FunctionalOptions. + col_id = new_id() + lines.append(f'{indent}') + if col.get('title'): + emit_mltext(lines, f'{indent}\t', 'Title', col['title']) + emit_type(lines, str(col.get('type', '')), f'{indent}\t') + emit_functional_options(lines, col.get('functionalOptions'), f'{indent}\t') + lines.append(f'{indent}') + + def emit_attributes(lines, attrs, indent): if not attrs or len(attrs) == 0: return @@ -3354,18 +3365,21 @@ def emit_attributes(lines, attrs, indent): emit_functional_options(lines, attr.get('functionalOptions'), inner) - # Columns (for ValueTable/ValueTree). Для дин-списка (есть settings) колонки НЕ эмитим — - # они служат лишь для формирования UseAlways. - if attr.get('columns') and len(attr['columns']) > 0 and not attr.get('settings'): + # Columns: прямые + (доп. колонки табличных частей объекта). + # Прямые сначала, затем AdditionalColumns-группы. Для дин-списка (settings) прямые НЕ эмитим. + has_direct_cols = bool(attr.get('columns')) and len(attr['columns']) > 0 and not attr.get('settings') + has_add_cols = bool(attr.get('additionalColumns')) and len(attr['additionalColumns']) > 0 + if has_direct_cols or has_add_cols: lines.append(f'{inner}') - for col in attr['columns']: - col_id = new_id() - lines.append(f'{inner}\t') - if col.get('title'): - emit_mltext(lines, f'{inner}\t\t', 'Title', col['title']) - emit_type(lines, str(col.get('type', '')), f'{inner}\t\t') - emit_functional_options(lines, col.get('functionalOptions'), f'{inner}\t\t') - lines.append(f'{inner}\t') + if has_direct_cols: + for col in attr['columns']: + emit_attr_column(lines, col, f'{inner}\t') + if has_add_cols: + for ac in attr['additionalColumns']: + lines.append(f'{inner}\t') + for col in (ac.get('columns') or []): + emit_attr_column(lines, col, f'{inner}\t\t') + lines.append(f'{inner}\t') lines.append(f'{inner}') # Settings (динамический список) diff --git a/.claude/skills/form-decompile/scripts/form-decompile.ps1 b/.claude/skills/form-decompile/scripts/form-decompile.ps1 index e7cafc48..abb46023 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.36 — Decompile 1C managed Form.xml to JSON DSL (draft) +# form-decompile v0.37 — Decompile 1C managed Form.xml to JSON DSL (draft) # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills # ВНИМАНИЕ: раундтрип не гарантируется. Навык исключён из авто-использования моделью. param( @@ -816,6 +816,16 @@ function Decompile-FunctionalOptions { return $null } +# Колонка реквизита (прямая или внутри AdditionalColumns): name/type/title/functionalOptions. +function Decompile-AttrColumn { + param($c) + $co = [ordered]@{}; $co['name'] = $c.GetAttribute("name") + $cty = Decompile-Type ($c.SelectSingleNode("lf:Type", $ns)); if ($cty) { $co['type'] = $cty } + $ctNode = $c.SelectSingleNode("lf:Title", $ns); if ($ctNode) { $t = Get-LangText $ctNode; if ($null -ne $t) { $co['title'] = $t } } + $cfo = Decompile-FunctionalOptions $c; if ($cfo) { $co['functionalOptions'] = $cfo } + return $co +} + # Общие свойства элемента (visible/enabled/readonly/title/events) → в hash function Add-CommonProps { param($obj, $node, [string]$elName) @@ -1320,14 +1330,21 @@ if ($attrsNode) { $colsNode = $a.SelectSingleNode("lf:Columns", $ns) if ($colsNode) { $cols = New-Object System.Collections.ArrayList - foreach ($c in @($colsNode.SelectNodes("lf:Column", $ns))) { - $co = [ordered]@{}; $co['name'] = $c.GetAttribute("name") - $cty = Decompile-Type ($c.SelectSingleNode("lf:Type", $ns)); if ($cty) { $co['type'] = $cty } - $ctNode = $c.SelectSingleNode("lf:Title", $ns); if ($ctNode) { $t = Get-LangText $ctNode; if ($null -ne $t) { $co['title'] = $t } } - $cfo = Decompile-FunctionalOptions $c; if ($cfo) { $co['functionalOptions'] = $cfo } - [void]$cols.Add($co) - } + foreach ($c in @($colsNode.SelectNodes("lf:Column", $ns))) { [void]$cols.Add((Decompile-AttrColumn $c)) } if ($cols.Count -gt 0) { $ao['columns'] = @($cols) } + # AdditionalColumns: доп. колонки табличных частей объекта (группа на табличную часть) + $addNodes = @($colsNode.SelectNodes("lf:AdditionalColumns", $ns)) + if ($addNodes.Count -gt 0) { + $addList = New-Object System.Collections.ArrayList + foreach ($an in $addNodes) { + $acObj = [ordered]@{}; $acObj['table'] = $an.GetAttribute("table") + $acCols = New-Object System.Collections.ArrayList + foreach ($c in @($an.SelectNodes("lf:Column", $ns))) { [void]$acCols.Add((Decompile-AttrColumn $c)) } + $acObj['columns'] = @($acCols) + [void]$addList.Add($acObj) + } + $ao['additionalColumns'] = @($addList) + } } # UseAlways: поля, всегда читаемые. Префикс "ИмяРеквизита." снимаем. # ValueTable (есть columns): useAlways:true на совпавшей колонке; остальные → массив атрибута. diff --git a/docs/form-dsl-spec.md b/docs/form-dsl-spec.md index 51328bfe..dd503373 100644 --- a/docs/form-dsl-spec.md +++ b/docs/form-dsl-spec.md @@ -615,7 +615,8 @@ Pages поддерживает `pagesRepresentation`: `None`, `TabsOnTop`, `Tabs | `useAlways` | array | Поля, всегда читаемые (`Имя.Поле…`). Массив коротких имён полей (forgiving: с/без префикса `Имя.`). **Две формы**: этот массив на реквизите ИЛИ `useAlways: true` на колонке (`columns[*]`) — компилятор сливает. Для дин-списка — только массив (колонки не эмитятся, но формируют ``) | | `savedData` | bool | Сохраняемые данные | | `fillChecking` | string | `Show`, `DontShow` | -| `columns` | array | Колонки для ValueTable/ValueTree | +| `columns` | array | Колонки для ValueTable/ValueTree (`{ name, type, title?, functionalOptions?, useAlways? }`) | +| `additionalColumns` | array | Доп. колонки табличных частей объекта: `[{ table: "Объект.ТабЧасть", columns: [] }]`. У главного реквизита-объекта; `` — та же грамматика, что у `columns`. Эмитятся в `` после прямых колонок | | `settings` | object | Настройки динамического списка (только `type: "DynamicList"`) | ### settings — динамический список diff --git a/tests/skills/cases/form-compile/additional-columns.json b/tests/skills/cases/form-compile/additional-columns.json new file mode 100644 index 00000000..29a028d7 --- /dev/null +++ b/tests/skills/cases/form-compile/additional-columns.json @@ -0,0 +1,38 @@ +{ + "name": "Доп. колонки табличной части объекта (AdditionalColumns)", + "preRun": [ + { + "script": "meta-compile/scripts/meta-compile", + "input": { + "type": "DataProcessor", + "name": "ДопКолонки", + "tabularSections": [ + { "name": "Прочее", "attributes": [ { "name": "Значение", "type": "String", "length": 50 } ] } + ] + }, + "args": { "-JsonPath": "{inputFile}", "-OutputDir": "{workDir}" } + }, + { + "script": "form-add/scripts/form-add", + "args": { "-ObjectPath": "{workDir}/DataProcessors/ДопКолонки.xml", "-FormName": "Форма" } + } + ], + "params": { "outputPath": "DataProcessors/ДопКолонки/Forms/Форма/Ext/Form.xml" }, + "validatePath": "DataProcessors/ДопКолонки/Forms/Форма/Ext/Form.xml", + "input": { + "title": "Доп. колонки", + "elements": [ + { "label": "Подпись", "title": "Форма с доп. колонками табличной части" } + ], + "attributes": [ + { "name": "Объект", "type": "DataProcessorObject.ДопКолонки", "main": true, + "additionalColumns": [ + { "table": "Объект.Прочее", "columns": [ + { "name": "Доступность", "type": "boolean" }, + { "name": "Служебная", "type": "string" } + ]} + ] + } + ] + } +} diff --git a/tests/skills/cases/form-compile/snapshots/additional-columns/Configuration.xml b/tests/skills/cases/form-compile/snapshots/additional-columns/Configuration.xml new file mode 100644 index 00000000..14441583 --- /dev/null +++ b/tests/skills/cases/form-compile/snapshots/additional-columns/Configuration.xml @@ -0,0 +1,252 @@ + + + + + + UUID-002 + UUID-003 + + + UUID-004 + UUID-005 + + + UUID-006 + UUID-007 + + + UUID-008 + UUID-009 + + + UUID-010 + UUID-011 + + + UUID-012 + UUID-013 + + + UUID-014 + UUID-015 + + + + TestConfig + + + ru + TestConfig + + + + + Version8_3_24 + ManagedApplication + + PlatformApplication + + Russian + + + + + false + false + false + + + + + + + + + + + + + + + + + + + + + + Biometrics + true + + + Location + false + + + BackgroundLocation + false + + + BluetoothPrinters + false + + + WiFiPrinters + false + + + Contacts + false + + + Calendars + false + + + PushNotifications + false + + + LocalNotifications + false + + + InAppPurchases + false + + + PersonalComputerFileExchange + false + + + Ads + false + + + NumberDialing + false + + + CallProcessing + false + + + CallLog + false + + + AutoSendSMS + false + + + ReceiveSMS + false + + + SMSLog + false + + + Camera + false + + + Microphone + false + + + MusicLibrary + false + + + PictureAndVideoLibraries + false + + + AudioPlaybackAndVibration + false + + + BackgroundAudioPlaybackAndVibration + false + + + InstallPackages + false + + + OSBackup + true + + + ApplicationUsageStatistics + false + + + BarcodeScanning + false + + + BackgroundAudioRecording + false + + + AllFilesAccess + false + + + Videoconferences + false + + + NFC + false + + + DocumentScanning + false + + + SpeechToText + false + + + Geofences + false + + + IncomingShareRequests + false + + + AllIncomingShareRequestsTypesProcessing + false + + + + + + Normal + + + Language.Русский + + + + + + Managed + NotAutoFree + DontUse + DontUse + TaxiEnableVersion8_2 + DontUse + Version8_3_24 + + + + Русский + ДопКолонки + + + \ No newline at end of file diff --git a/tests/skills/cases/form-compile/snapshots/additional-columns/DataProcessors/ДопКолонки.xml b/tests/skills/cases/form-compile/snapshots/additional-columns/DataProcessors/ДопКолонки.xml new file mode 100644 index 00000000..a3be3c64 --- /dev/null +++ b/tests/skills/cases/form-compile/snapshots/additional-columns/DataProcessors/ДопКолонки.xml @@ -0,0 +1,128 @@ + + + + + + UUID-002 + UUID-003 + + + UUID-004 + UUID-005 + + + + ДопКолонки + + + ru + Доп колонки + + + + false + DataProcessor.ДопКолонки.Form.Форма + + false + + + + +
Форма
+ + + + UUID-007 + UUID-008 + + + UUID-009 + UUID-010 + + + + Прочее + + + ru + Прочее + + + + + DontCheck + + + + DontCheck + false + false + Auto + + + false + + + Auto + Auto + + false + Use + false + + + + Use + + + + + + + + + + + Значение + + + ru + Значение + + + + + xs:string + + 50 + Variable + + + false + + + + false + + false + false + + + false + + DontCheck + Items + + + Auto + Auto + + + Auto + + + + +
+
+
diff --git a/tests/skills/cases/form-compile/snapshots/additional-columns/DataProcessors/ДопКолонки/Ext/ManagerModule.bsl b/tests/skills/cases/form-compile/snapshots/additional-columns/DataProcessors/ДопКолонки/Ext/ManagerModule.bsl new file mode 100644 index 00000000..e69de29b diff --git a/tests/skills/cases/form-compile/snapshots/additional-columns/DataProcessors/ДопКолонки/Ext/ObjectModule.bsl b/tests/skills/cases/form-compile/snapshots/additional-columns/DataProcessors/ДопКолонки/Ext/ObjectModule.bsl new file mode 100644 index 00000000..e69de29b diff --git a/tests/skills/cases/form-compile/snapshots/additional-columns/DataProcessors/ДопКолонки/Forms/Форма.xml b/tests/skills/cases/form-compile/snapshots/additional-columns/DataProcessors/ДопКолонки/Forms/Форма.xml new file mode 100644 index 00000000..dffeea01 --- /dev/null +++ b/tests/skills/cases/form-compile/snapshots/additional-columns/DataProcessors/ДопКолонки/Forms/Форма.xml @@ -0,0 +1,22 @@ + + +
+ + Форма + + + ru + Форма + + + + Managed + false + + PlatformApplication + MobilePlatformApplication + + + +
+
\ No newline at end of file diff --git a/tests/skills/cases/form-compile/snapshots/additional-columns/DataProcessors/ДопКолонки/Forms/Форма/Ext/Form.xml b/tests/skills/cases/form-compile/snapshots/additional-columns/DataProcessors/ДопКолонки/Forms/Форма/Ext/Form.xml new file mode 100644 index 00000000..5916fefb --- /dev/null +++ b/tests/skills/cases/form-compile/snapshots/additional-columns/DataProcessors/ДопКолонки/Forms/Форма/Ext/Form.xml @@ -0,0 +1,49 @@ + +
+ + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Доп. колонки</v8:content> + </v8:item> + + false + + + + + <v8:item> + <v8:lang>ru</v8:lang> + <v8:content>Форма с доп. колонками табличной части</v8:content> + </v8:item> + + + + + + + + + cfg:DataProcessorObject.ДопКолонки + + true + + + + + xs:boolean + + + + + xs:string + + 0 + Variable + + + + + + + + diff --git a/tests/skills/cases/form-compile/snapshots/additional-columns/DataProcessors/ДопКолонки/Forms/Форма/Ext/Form/Module.bsl b/tests/skills/cases/form-compile/snapshots/additional-columns/DataProcessors/ДопКолонки/Forms/Форма/Ext/Form/Module.bsl new file mode 100644 index 00000000..8ead4cec --- /dev/null +++ b/tests/skills/cases/form-compile/snapshots/additional-columns/DataProcessors/ДопКолонки/Forms/Форма/Ext/Form/Module.bsl @@ -0,0 +1,19 @@ +#Область ОбработчикиСобытийФормы + +#КонецОбласти + +#Область ОбработчикиСобытийЭлементовФормы + +#КонецОбласти + +#Область ОбработчикиКомандФормы + +#КонецОбласти + +#Область ОбработчикиОповещений + +#КонецОбласти + +#Область СлужебныеПроцедурыИФункции + +#КонецОбласти \ No newline at end of file diff --git a/tests/skills/cases/form-compile/snapshots/additional-columns/Ext/ClientApplicationInterface.xml b/tests/skills/cases/form-compile/snapshots/additional-columns/Ext/ClientApplicationInterface.xml new file mode 100644 index 00000000..3c1161b2 --- /dev/null +++ b/tests/skills/cases/form-compile/snapshots/additional-columns/Ext/ClientApplicationInterface.xml @@ -0,0 +1,18 @@ + + + + + UUID-002 + + + + + UUID-004 + + + + + + + + \ No newline at end of file diff --git a/tests/skills/cases/form-compile/snapshots/additional-columns/Languages/Русский.xml b/tests/skills/cases/form-compile/snapshots/additional-columns/Languages/Русский.xml new file mode 100644 index 00000000..37c60d78 --- /dev/null +++ b/tests/skills/cases/form-compile/snapshots/additional-columns/Languages/Русский.xml @@ -0,0 +1,16 @@ + + + + + Русский + + + ru + Русский + + + + ru + + + \ No newline at end of file