feat(form-decompile,form-compile): CommandSet (отключённые команды) — общее свойство поля

Ранее excludedCommands обрабатывался только для Table-элемента и форм-уровня.
Обычные поля (InputField/LabelField/CheckBoxField/SpreadSheetDocumentField/HTML/
Formatted/Picture) идут через Emit-SimpleField и др. — CommandSet там терялся
(кластер SpreadSheetDocumentField>CommandSet, baseline impact ~1443).

Централизовал: захват в Add-CommonProps (декомпилятор, общий для всех полей),
эмит в Emit-Layout (компилятор ps1+py), убрал дубль из Table-эмиттера. CommandSet —
дочерний элемент базового FormField в схеме, позиция фиксирована независимо от
подтипа → ранняя (после TitleLocation, перед скалярами/Height), как у spreadsheet.

Таргет-верификация (новый цикл category-forms.py): 43 формы корпуса с CommandSet →
после фикса 0 остатка (CommandSet + ExcludedCommand cascade), 26 стали match.
Кейс table пере-сертифицирован в 1С (ранняя позиция грузится), ps1==py, регресс 43/43.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Nick Shirokov
2026-06-10 21:41:43 +03:00
co-authored by Claude Opus 4.8
parent d5d19710cb
commit d8689b3674
4 changed files with 31 additions and 18 deletions
@@ -1,4 +1,4 @@
# form-compile v1.108 — Compile 1C managed form from JSON or object metadata
# form-compile v1.109 — Compile 1C managed form from JSON or object metadata
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
param(
[string]$JsonPath,
@@ -3326,6 +3326,13 @@ function Emit-Appearance {
function Emit-Layout {
param($el, [string]$indent, [switch]$skipHeight, [bool]$multiLineDefault = $false)
# CommandSet (отключённые команды редактора) — общее свойство поля (input/label/check/
# spreadsheet/html/formatted/picture); в схеме рано (после TitleLocation, перед скалярами).
if ($el.excludedCommands -and @($el.excludedCommands).Count -gt 0) {
X "$indent<CommandSet>"
foreach ($cmd in $el.excludedCommands) { X "$indent`t<ExcludedCommand>$cmd</ExcludedCommand>" }
X "$indent</CommandSet>"
}
Emit-CommonElementProps -el $el -indent $indent
$amwExplicit = ($el.PSObject.Properties.Name -contains 'autoMaxWidth')
if ($amwExplicit) {
@@ -4235,11 +4242,7 @@ function Emit-Table {
if ($el.searchControlLocation) { X "$inner<SearchControlLocation>$($el.searchControlLocation)</SearchControlLocation>" }
Emit-Layout -el $el -indent $inner
if ($el.excludedCommands -and $el.excludedCommands.Count -gt 0) {
X "$inner<CommandSet>"
foreach ($cmd in $el.excludedCommands) { X "$inner`t<ExcludedCommand>$cmd</ExcludedCommand>" }
X "$inner</CommandSet>"
}
# CommandSet таблицы эмитится через Emit-Layout (общий механизм поля)
# Оформление (цвета/граница таблицы) — перед компаньонами
Emit-Appearance -el $el -indent $inner -profile 'field'
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
# form-compile v1.108 — Compile 1C managed form from JSON or object metadata
# form-compile v1.109 — Compile 1C managed form from JSON or object metadata
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import argparse
import copy
@@ -3100,6 +3100,12 @@ def emit_layout(lines, el, indent, skip_height=False, multi_line_default=False):
# с историческим выводом input/label, чтобы не сдвигать существующие снапшоты.
# skip_height: подавить <Height> (зарезервирован; Table теперь эмитит <Height> generic-ом + свой <HeightInTableRows>).
# multi_line_default: input без явного autoMaxWidth при multiLine → AutoMaxWidth=false.
# CommandSet (отключённые команды редактора) — общее свойство поля; в схеме рано (после TitleLocation).
if el.get('excludedCommands') and len(el['excludedCommands']) > 0:
lines.append(f'{indent}<CommandSet>')
for cmd in el['excludedCommands']:
lines.append(f'{indent}\t<ExcludedCommand>{cmd}</ExcludedCommand>')
lines.append(f'{indent}</CommandSet>')
emit_common_element_props(lines, el, indent)
if 'autoMaxWidth' in el:
if el.get('autoMaxWidth') is False:
@@ -3965,11 +3971,7 @@ def emit_table(lines, el, name, eid, indent):
lines.append(f'{inner}<SearchControlLocation>{el["searchControlLocation"]}</SearchControlLocation>')
emit_layout(lines, el, inner)
if el.get('excludedCommands'):
lines.append(f'{inner}<CommandSet>')
for cmd in el['excludedCommands']:
lines.append(f'{inner}\t<ExcludedCommand>{cmd}</ExcludedCommand>')
lines.append(f'{inner}</CommandSet>')
# CommandSet таблицы эмитится через emit_layout (общий механизм поля)
# Оформление (цвета/граница таблицы) — перед компаньонами
emit_appearance(lines, el, inner, 'field')
@@ -1,4 +1,4 @@
# form-decompile v0.84 — Decompile 1C managed Form.xml to JSON DSL (draft)
# form-decompile v0.85 — Decompile 1C managed Form.xml to JSON DSL (draft)
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
# ВНИМАНИЕ: раундтрип не гарантируется. Навык исключён из авто-использования моделью.
param(
@@ -1027,6 +1027,14 @@ function Add-CommonProps {
$fp = Get-PictureRef $node 'FooterPicture'; if ($null -ne $fp) { $obj['footerPicture'] = $fp }
$ev = Get-Events $node $elName
if ($ev) { $obj['events'] = $ev }
# CommandSet — общий для полей (input/label/check/spreadsheet/html/formatted/picture):
# список отключённых команд редактора. Только <ExcludedCommand>, пустого не бывает.
$csNode = $node.SelectSingleNode("lf:CommandSet", $ns)
if ($csNode) {
$exc = New-Object System.Collections.ArrayList
foreach ($ec in @($csNode.SelectNodes("lf:ExcludedCommand", $ns))) { [void]$exc.Add($ec.InnerText) }
if ($exc.Count -gt 0) { $obj['excludedCommands'] = @($exc) }
}
}
# --- 3. Type decompile (inverse of Emit-Type) ---
@@ -20,17 +20,17 @@
<AutoMarkIncomplete>true</AutoMarkIncomplete>
<ViewStatusLocation>None</ViewStatusLocation>
<SearchControlLocation>None</SearchControlLocation>
<Height>80</Height>
<SettingsNamedItemDetailedRepresentation>false</SettingsNamedItemDetailedRepresentation>
<MaxRowsCount>5</MaxRowsCount>
<AutoMaxRowsCount>false</AutoMaxRowsCount>
<HeightControlVariant>UseHeightInTableRows</HeightControlVariant>
<CommandSet>
<ExcludedCommand>Add</ExcludedCommand>
<ExcludedCommand>Delete</ExcludedCommand>
<ExcludedCommand>MoveUp</ExcludedCommand>
<ExcludedCommand>MoveDown</ExcludedCommand>
</CommandSet>
<Height>80</Height>
<SettingsNamedItemDetailedRepresentation>false</SettingsNamedItemDetailedRepresentation>
<MaxRowsCount>5</MaxRowsCount>
<AutoMaxRowsCount>false</AutoMaxRowsCount>
<HeightControlVariant>UseHeightInTableRows</HeightControlVariant>
<ContextMenu name="ДанныеКонтекстноеМеню" id="2">
<ChildItems>
<ButtonGroup name="МенюГруппа" id="3">