diff --git a/.claude/skills/form-compile/scripts/form-compile.ps1 b/.claude/skills/form-compile/scripts/form-compile.ps1 index bf51422d..0494f2f8 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.92 — Compile 1C managed form from JSON or object metadata +# form-compile v1.93 — Compile 1C managed form from JSON or object metadata # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills param( [string]$JsonPath, @@ -4711,11 +4711,28 @@ function Emit-Attributes { # Нет items → контейнеры всё равно эмитятся (blockMeta) = каноничный пустой скелет платформы. $lsi = "$si`t" X "$si" - Emit-Filter -items $st.filter -indent $lsi -blockViewMode 'Normal' -blockUserSettingID $script:CANON_FILTER_ID - Emit-Order -items $st.order -indent $lsi -blockViewMode 'Normal' -blockUserSettingID $script:CANON_ORDER_ID - Emit-ConditionalAppearance -items $st.conditionalAppearance -indent $lsi -blockViewMode 'Normal' -blockUserSettingID $script:CANON_CA_ID - X "$lsiNormal" - X "$lsi$($script:CANON_ITEMS_ID)" + if ($st.PSObject.Properties['listSettings'] -and $null -ne $st.listSettings) { + # Частичная/минимальная форма скелета — эмитим ТОЛЬКО указанные части с их блок-метой. + # meta: 'v'=viewMode, 'u'=userSettingID (контейнеры); itemsViewMode/itemsUserSettingID → present. + foreach ($prop in $st.listSettings.PSObject.Properties) { + $tag = $prop.Name; $meta = "$($prop.Value)" + $bvm = if ($meta -match 'v') { 'Normal' } else { $null } + switch ($tag) { + 'filter' { $bus = if ($meta -match 'u') { $script:CANON_FILTER_ID } else { $null }; Emit-Filter -items $st.filter -indent $lsi -blockViewMode $bvm -blockUserSettingID $bus } + 'order' { $bus = if ($meta -match 'u') { $script:CANON_ORDER_ID } else { $null }; Emit-Order -items $st.order -indent $lsi -blockViewMode $bvm -blockUserSettingID $bus } + 'conditionalAppearance' { $bus = if ($meta -match 'u') { $script:CANON_CA_ID } else { $null }; Emit-ConditionalAppearance -items $st.conditionalAppearance -indent $lsi -blockViewMode $bvm -blockUserSettingID $bus } + 'itemsViewMode' { X "$lsiNormal" } + 'itemsUserSettingID' { X "$lsi$($script:CANON_ITEMS_ID)" } + } + } + } else { + # Полный каноничный скелет (умолчание, ~93% форм) — без изменений. + Emit-Filter -items $st.filter -indent $lsi -blockViewMode 'Normal' -blockUserSettingID $script:CANON_FILTER_ID + Emit-Order -items $st.order -indent $lsi -blockViewMode 'Normal' -blockUserSettingID $script:CANON_ORDER_ID + Emit-ConditionalAppearance -items $st.conditionalAppearance -indent $lsi -blockViewMode 'Normal' -blockUserSettingID $script:CANON_CA_ID + X "$lsiNormal" + X "$lsi$($script:CANON_ITEMS_ID)" + } X "$si" X "$inner" } diff --git a/.claude/skills/form-compile/scripts/form-compile.py b/.claude/skills/form-compile/scripts/form-compile.py index d443ff77..e4683c85 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.92 — Compile 1C managed form from JSON or object metadata +# form-compile v1.93 — Compile 1C managed form from JSON or object metadata # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse import copy @@ -4414,11 +4414,32 @@ def emit_attributes(lines, attrs, indent): # Нет items → контейнеры всё равно эмитятся (blockMeta) = каноничный пустой скелет платформы. lsi = f'{si}\t' lines.append(f'{si}') - emit_filter(lines, s.get('filter'), lsi, block_view_mode='Normal', block_user_setting_id=CANON_FILTER_ID) - emit_order(lines, s.get('order'), lsi, block_view_mode='Normal', block_user_setting_id=CANON_ORDER_ID) - emit_conditional_appearance(lines, s.get('conditionalAppearance'), lsi, block_view_mode='Normal', block_user_setting_id=CANON_CA_ID) - lines.append(f'{lsi}Normal') - lines.append(f'{lsi}{CANON_ITEMS_ID}') + ls_shape = s.get('listSettings') + if ls_shape is not None: + # Частичная/минимальная форма скелета — эмитим ТОЛЬКО указанные части с их блок-метой. + for tag, meta in ls_shape.items(): + meta = str(meta) + bvm = 'Normal' if 'v' in meta else None + if tag == 'filter': + bus = CANON_FILTER_ID if 'u' in meta else None + emit_filter(lines, s.get('filter'), lsi, block_view_mode=bvm, block_user_setting_id=bus) + elif tag == 'order': + bus = CANON_ORDER_ID if 'u' in meta else None + emit_order(lines, s.get('order'), lsi, block_view_mode=bvm, block_user_setting_id=bus) + elif tag == 'conditionalAppearance': + bus = CANON_CA_ID if 'u' in meta else None + emit_conditional_appearance(lines, s.get('conditionalAppearance'), lsi, block_view_mode=bvm, block_user_setting_id=bus) + elif tag == 'itemsViewMode': + lines.append(f'{lsi}Normal') + elif tag == 'itemsUserSettingID': + lines.append(f'{lsi}{CANON_ITEMS_ID}') + else: + # Полный каноничный скелет (умолчание, ~93% форм) — без изменений. + emit_filter(lines, s.get('filter'), lsi, block_view_mode='Normal', block_user_setting_id=CANON_FILTER_ID) + emit_order(lines, s.get('order'), lsi, block_view_mode='Normal', block_user_setting_id=CANON_ORDER_ID) + emit_conditional_appearance(lines, s.get('conditionalAppearance'), lsi, block_view_mode='Normal', block_user_setting_id=CANON_CA_ID) + lines.append(f'{lsi}Normal') + lines.append(f'{lsi}{CANON_ITEMS_ID}') lines.append(f'{si}') lines.append(f'{inner}') diff --git a/.claude/skills/form-decompile/scripts/form-decompile.ps1 b/.claude/skills/form-decompile/scripts/form-decompile.ps1 index 20170a1a..6a9250ce 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.69 — Decompile 1C managed Form.xml to JSON DSL (draft) +# form-decompile v0.70 — Decompile 1C managed Form.xml to JSON DSL (draft) # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills # ВНИМАНИЕ: раундтрип не гарантируется. Навык исключён из авто-использования моделью. param( @@ -113,6 +113,31 @@ function Test-ListSettingsHasContent { return $false } +# Форма ListSettings: ordered-карта present top-level элементов (filter/order/conditionalAppearance → +# блок-мета 'v'/'u'/'vu'/''; itemsViewMode/itemsUserSettingID → $true). Возвращает $null, если форма == +# полному каноничному скелету (компилятор регенерит сам) ИЛИ содержит неподдержанные top-level элементы +# (item/dataParameters/viewMode/userSettingID/… → fallback на канон). Иначе — дескриптор для компилятора. +function Get-ListSettingsShape { + param($lsNode) + if (-not $lsNode) { return $null } + $shape = [ordered]@{} + foreach ($child in $lsNode.ChildNodes) { + if ($child.NodeType -ne [System.Xml.XmlNodeType]::Element) { continue } + $tag = $child.LocalName + if ($tag -in @('filter','order','conditionalAppearance')) { + $hasVM = $null -ne $child.SelectSingleNode("dcsset:viewMode", $ns) + $hasUS = $null -ne $child.SelectSingleNode("dcsset:userSettingID", $ns) + $shape[$tag] = "$(if ($hasVM) {'v'})$(if ($hasUS) {'u'})" + } elseif ($tag -eq 'itemsViewMode') { $shape['itemsViewMode'] = $true } + elseif ($tag -eq 'itemsUserSettingID') { $shape['itemsUserSettingID'] = $true } + else { return $null } # item/dataParameters/itemsUserSettingPresentation/… → канон-fallback + } + # Полный каноничный скелет → опускаем (компилятор регенерит) + if ($shape.Count -eq 5 -and $shape['filter'] -eq 'vu' -and $shape['order'] -eq 'vu' -and ` + $shape['conditionalAppearance'] -eq 'vu' -and $shape['itemsViewMode'] -eq $true -and $shape['itemsUserSettingID'] -eq $true) { return $null } + return $shape +} + # --- 1b. Ring-3 scan: конструкции вне зоны поддержки (draft list) --- function Fail-Ring3 { param([string]$kind, [string]$loc) @@ -1955,6 +1980,10 @@ if ($attrsNode) { $ca = Build-ConditionalAppearance -caNode $caNode -loc "settings/conditionalAppearance" if (@($ca).Count -gt 0) { $so['conditionalAppearance'] = @($ca) } } + # Форма скелета ListSettings: дескриптор только для НЕ-каноничных форм (частичные/минимальные). + # Канон → $null (компилятор регенерит полный скелет, как раньше). + $lsShape = Get-ListSettingsShape $lsNode + if ($null -ne $lsShape) { $so['listSettings'] = $lsShape } } if ($so.Count -gt 0) { $ao['settings'] = $so } } diff --git a/docs/form-dsl-spec.md b/docs/form-dsl-spec.md index 572a8fa7..f19fb120 100644 --- a/docs/form-dsl-spec.md +++ b/docs/form-dsl-spec.md @@ -814,7 +814,9 @@ Pages поддерживает `pagesRepresentation`: `None`, `TabsOnTop`, `Tabs `ManualQuery` выводится из наличия `query` — отдельным ключом не задаётся. -Пустой блок настроек компоновщика (`ListSettings`) генерируется автоматически (каноничный скелет платформы); указывать ничего не нужно. +Пустой блок настроек компоновщика (`ListSettings`) генерируется автоматически (каноничный полный скелет платформы — filter+order+conditionalAppearance+itemsViewMode+itemsUserSettingID, ~93% форм); указывать ничего не нужно. + +| `listSettings` | object | **Дескриптор формы скелета ``** — только для НЕ-каноничных (частичных/минимальных) форм. Ordered-карта present top-level элементов: контейнеры `filter`/`order`/`conditionalAppearance` → блок-мета (`"vu"`=viewMode+userSettingID, `"u"`=только userSettingID, `"v"`, `""`); `itemsViewMode`/`itemsUserSettingID` → `true`. Компилятор эмитит ТОЛЬКО указанные части (контент берёт из `filter`/`order`/`conditionalAppearance`). Нет ключа → полный каноничный скелет. Декомпилятор пишет дескриптор только для отклонений от канона | #### parameters — параметры схемы дин-списка