diff --git a/.claude/skills/form-compile/scripts/form-compile.ps1 b/.claude/skills/form-compile/scripts/form-compile.ps1 index 2f6141ff..c13096c2 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.100 — Compile 1C managed form from JSON or object metadata +# form-compile v1.101 — Compile 1C managed form from JSON or object metadata # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills param( [string]$JsonPath, @@ -1890,11 +1890,11 @@ function Emit-AppearanceValue { } function Emit-ConditionalAppearance { - param($items, [string]$indent, $blockViewMode = $null, $blockUserSettingID = $null) + param($items, [string]$indent, $blockViewMode = $null, $blockUserSettingID = $null, [string]$wrapTag = 'dcsset:conditionalAppearance') $hasItems = $items -and $items.Count -gt 0 $hasBlockMeta = ($null -ne $blockViewMode) -or ($null -ne $blockUserSettingID) if (-not $hasItems -and -not $hasBlockMeta) { return } - X "$indent" + X "$indent<$wrapTag>" foreach ($ca in $items) { X "$indent`t" if ($ca.use -eq $false) { X "$indent`t`tfalse" } @@ -1915,7 +1915,12 @@ function Emit-ConditionalAppearance { X "$indent`t`t" } if ($ca.presentation) { - if ($ca.presentation -is [hashtable] -or $ca.presentation -is [System.Collections.IDictionary] -or $ca.presentation -is [PSCustomObject]) { Emit-MLText -tag "dcsset:presentation" -text $ca.presentation -indent "$indent`t`t" } + if ($ca.presentation -is [hashtable] -or $ca.presentation -is [System.Collections.IDictionary] -or $ca.presentation -is [PSCustomObject]) { + # Мультиязык → LocalStringType (платформа объявляет тип у локализованного presentation) + X "$indent`t`t" + Emit-MLItems -val $ca.presentation -indent "$indent`t`t`t" + X "$indent`t`t" + } else { X "$indent`t`t$(Esc-Xml "$($ca.presentation)")" } } if ($ca.viewMode) { X "$indent`t`t$(Esc-Xml "$($ca.viewMode)")" } @@ -1942,7 +1947,7 @@ function Emit-ConditionalAppearance { $uid = if ("$blockUserSettingID" -eq 'auto') { New-Guid-String } else { "$blockUserSettingID" } X "$indent`t$(Esc-Xml $uid)" } - X "$indent" + X "$indent" } # --- 5. Type emitter --- @@ -4674,10 +4679,18 @@ function Emit-DLParameters { } function Emit-Attributes { - param($attrs, [string]$indent) + param($attrs, [string]$indent, $conditionalAppearance = $null) + $hasCA = $conditionalAppearance -and @($conditionalAppearance).Count -gt 0 # Платформа ВСЕГДА эмитит (100% корпуса; 162 формы — пустой ). - if (-not $attrs -or $attrs.Count -eq 0) { X "$indent"; return } + if ((-not $attrs -or $attrs.Count -eq 0) -and -not $hasCA) { X "$indent"; return } + if (-not $attrs -or $attrs.Count -eq 0) { + # Нет реквизитов, но есть условное оформление (последний child ) + X "$indent" + Emit-ConditionalAppearance -items $conditionalAppearance -indent "$indent`t" -wrapTag 'ConditionalAppearance' + X "$indent" + return + } X "$indent" $seenAttrs = @{} @@ -4890,6 +4903,8 @@ function Emit-Attributes { X "$indent`t" } + # Условное оформление формы — последний child (та же DCS-грамматика, что settings CA) + Emit-ConditionalAppearance -items $conditionalAppearance -indent "$indent`t" -wrapTag 'ConditionalAppearance' X "$indent" } @@ -5465,7 +5480,7 @@ if ($def.elements -and $def.elements.Count -gt 0) { } # 12g. Attributes -Emit-Attributes -attrs $def.attributes -indent "`t" +Emit-Attributes -attrs $def.attributes -indent "`t" -conditionalAppearance $def.conditionalAppearance # 12h. Parameters Emit-Parameters -params $def.parameters -indent "`t" diff --git a/.claude/skills/form-compile/scripts/form-compile.py b/.claude/skills/form-compile/scripts/form-compile.py index f9ba8b66..1297b97b 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.100 — Compile 1C managed form from JSON or object metadata +# form-compile v1.101 — Compile 1C managed form from JSON or object metadata # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse import copy @@ -1640,12 +1640,12 @@ def emit_appearance_value(lines, key, val, indent): lines.append(f'{indent}') -def emit_conditional_appearance(lines, items, indent, block_view_mode=None, block_user_setting_id=None): +def emit_conditional_appearance(lines, items, indent, block_view_mode=None, block_user_setting_id=None, wrap_tag='dcsset:conditionalAppearance'): has_items = bool(items) and len(items) > 0 has_block_meta = (block_view_mode is not None) or (block_user_setting_id is not None) if not has_items and not has_block_meta: return - lines.append(f'{indent}') + lines.append(f'{indent}<{wrap_tag}>') for ca in (items or []): lines.append(f'{indent}\t') if ca.get('use') is False: @@ -1670,7 +1670,10 @@ def emit_conditional_appearance(lines, items, indent, block_view_mode=None, bloc lines.append(f'{indent}\t\t') if ca.get('presentation'): if isinstance(ca['presentation'], dict): - emit_mltext(lines, f'{indent}\t\t', 'dcsset:presentation', ca['presentation']) + # Мультиязык → LocalStringType (платформа объявляет тип у локализованного presentation) + lines.append(f'{indent}\t\t') + emit_ml_items(lines, f'{indent}\t\t\t', ca['presentation']) + lines.append(f'{indent}\t\t') else: lines.append(f'{indent}\t\t{esc_xml(str(ca["presentation"]))}') if ca.get('viewMode'): @@ -1695,7 +1698,7 @@ def emit_conditional_appearance(lines, items, indent, block_view_mode=None, bloc if block_user_setting_id is not None: uid = new_uuid() if str(block_user_setting_id) == 'auto' else str(block_user_setting_id) lines.append(f'{indent}\t{esc_xml(uid)}') - lines.append(f'{indent}') + lines.append(f'{indent}') def write_utf8_bom(path, content): @@ -4388,11 +4391,18 @@ def emit_dl_parameters(lines, params, indent): emit_dl_parameter(lines, p, parsed, indent) -def emit_attributes(lines, attrs, indent): +def emit_attributes(lines, attrs, indent, conditional_appearance=None): + has_ca = bool(conditional_appearance) and len(conditional_appearance) > 0 # Платформа ВСЕГДА эмитит (100% корпуса; 162 формы — пустой ). - if not attrs or len(attrs) == 0: + if (not attrs or len(attrs) == 0) and not has_ca: lines.append(f'{indent}') return + if not attrs or len(attrs) == 0: + # Нет реквизитов, но есть условное оформление (последний child ) + lines.append(f'{indent}') + emit_conditional_appearance(lines, conditional_appearance, f'{indent}\t', wrap_tag='ConditionalAppearance') + lines.append(f'{indent}') + return lines.append(f'{indent}') seen_attrs = set() @@ -4595,6 +4605,8 @@ def emit_attributes(lines, attrs, indent): lines.append(f'{inner}') lines.append(f'{indent}\t') + # Условное оформление формы — последний child (та же DCS-грамматика, что settings CA) + emit_conditional_appearance(lines, conditional_appearance, f'{indent}\t', wrap_tag='ConditionalAppearance') lines.append(f'{indent}') @@ -5297,7 +5309,7 @@ def main(): lines.append('\t') # Attributes - emit_attributes(lines, defn.get('attributes'), '\t') + emit_attributes(lines, defn.get('attributes'), '\t', conditional_appearance=defn.get('conditionalAppearance')) # Parameters emit_parameters(lines, defn.get('parameters'), '\t') diff --git a/.claude/skills/form-decompile/scripts/form-decompile.ps1 b/.claude/skills/form-decompile/scripts/form-decompile.ps1 index 7bc88f74..87ededa7 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.76 — Decompile 1C managed Form.xml to JSON DSL (draft) +# form-decompile v0.77 — Decompile 1C managed Form.xml to JSON DSL (draft) # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills # ВНИМАНИЕ: раундтрип не гарантируется. Навык исключён из авто-использования моделью. param( @@ -145,7 +145,8 @@ function Fail-Ring3 { [Console]::Error.WriteLine("Для точечной работы с этой формой используй /form-edit.") exit 3 } -foreach ($el in $xmlDoc.SelectNodes("//*[local-name()='ConditionalAppearance']")) { Fail-Ring3 -kind "ConditionalAppearance" -loc "form/ConditionalAppearance" } +# ConditionalAppearance со scope (привязка к области) пока не воспроизводим — fail-ring3 только в этом случае. +foreach ($el in $xmlDoc.SelectNodes("//*[local-name()='ConditionalAppearance']/*[local-name()='item']/*[local-name()='scope'][node()]")) { Fail-Ring3 -kind "ConditionalAppearance со scope" -loc "form/ConditionalAppearance/item/scope" } # --- 1c. Compact JSON serializer (созвучно skd-decompile: 2-проб. indent, inline в пределах lineLimit) --- function Convert-StringToJsonLiteral { @@ -2099,6 +2100,16 @@ if ($attrsNode) { if ($attrs.Count -gt 0) { $dsl['attributes'] = @($attrs) } } +# conditionalAppearance формы ( — последний child ; +# та же DCS-грамматика, что settings.conditionalAppearance → переиспользуем Build-ConditionalAppearance) +if ($attrsNode) { + $caNode = $attrsNode.SelectSingleNode("lf:ConditionalAppearance", $ns) + if ($caNode) { + $ca = Build-ConditionalAppearance -caNode $caNode -loc "form/conditionalAppearance" + if (@($ca).Count -gt 0) { $dsl['conditionalAppearance'] = @($ca) } + } +} + # parameters $parsNode = $root.SelectSingleNode("lf:Parameters", $ns) if ($parsNode) { diff --git a/docs/form-dsl-spec.md b/docs/form-dsl-spec.md index 020c568f..88e81316 100644 --- a/docs/form-dsl-spec.md +++ b/docs/form-dsl-spec.md @@ -985,6 +985,31 @@ Forgiving-синонимы типа: XML-имя (`SpreadSheetDocumentField`) и --- +## 7c. conditionalAppearance — условное оформление формы + +Форменный ключ `conditionalAppearance` (XML `` — последний child ``). +**Грамматика идентична `settings.conditionalAppearance` дин-списка** (DCS — см. §«order/filter/conditionalAppearance»): +массив объектов `{ selection?, filter?, appearance?, presentation?, viewMode?, userSettingID?, use? }`. + +```json +"conditionalAppearance": [ + { "selection": ["ОбычноеПоле"], "filter": ["ЧисловоеПоле > 100"], + "appearance": { "ЦветФона": "style:FormBackColor" }, + "presentation": { "ru": "Подсветка", "en": "Highlight" } } +] +``` + +- `selection` — массив имён форматируемых полей (``). +- `filter` — условие (filter-shorthand, как в СКД). +- `appearance` — словарь «параметр-DCS: значение» (рус. verbatim: `ЦветТекста`/`ЦветФона`/`Шрифт`/…). Цвет → `v8ui:Color`. +- `presentation` — мультиязык → `xsi:type="v8:LocalStringType"`. + +Декомпилятор/компилятор переиспользуют `Build-ConditionalAppearance`/`Emit-ConditionalAppearance` настроек списка +(отличие — тег-обёртка `ConditionalAppearance` без `dcsset:` и без блок-мета). `scope` (привязка к области) в формах +не встречается; форма со `scope` → fail-ring3. + +--- + ## 8. Система типов (shorthand) ### Примитивные типы diff --git a/tests/skills/cases/form-compile/input-fields.json b/tests/skills/cases/form-compile/input-fields.json index 9c574529..ef84b43b 100644 --- a/tests/skills/cases/form-compile/input-fields.json +++ b/tests/skills/cases/form-compile/input-fields.json @@ -67,6 +67,10 @@ { "name": "ФлагЯвный", "type": "boolean" }, { "name": "ФлагТумблер", "type": "boolean" }, { "name": "ЧисловоеПоле", "type": "number(10,2)" } + ], + "conditionalAppearance": [ + { "selection": ["ОбычноеПоле"], "filter": ["ЧисловоеПоле > 100"], "appearance": { "ЦветФона": "style:FormBackColor" }, + "presentation": { "ru": "Подсветка", "en": "Highlight" } } ] } } 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 2daf4900..3092635c 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 @@ -592,5 +592,37 @@ + + + + + ОбычноеПоле + + + + + ЧисловоеПоле + Greater + 100 + + + + + ЦветФона + style:FormBackColor + + + + + ru + Подсветка + + + en + Highlight + + + +