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 — параметры схемы дин-списка