feat(meta-compile,meta-decompile): Command>Picture — структурный блок (v1.29/v0.20)

Ключ `picture` команды компилятор писал плоской строкой, склеивая содержимое
структурного блока: <Picture><xr:Ref>CommonPicture.X</xr:Ref>
<xr:LoadTransparent>false</xr:LoadTransparent></Picture> → «CommonPicture.Xfalse»
(декомпилятор брал .InnerText всего блока). Багофикс формы значения.

Зеркало form-compile/form-decompile:
  • picture — строка-ref (StdPicture.X / CommonPicture.X; встроенная abs: → <xr:Abs>)
    + sibling `loadTransparent` (дефолт true, конвенция кнопки/команды — фиксируем
    только false) ЛИБО объект {src, loadTransparent?, transparentPixel?}.
  • Emit-CommandPicture (компилятор) + структурный захват в декомпиляторе.
Структура {Ref, LoadTransparent} стабильна на корпусе (40/40, Std/CommonPicture).

Попутно (вскрыто roundtrip-сверкой ps1↔py): в py object-form реквизита список
flags не лоуэркейзился (в отличие от строкового пути), из-за чего декомпиляторный
`indexAdditional` не матчил `indexadditional` — PS -contains регистронезависим, а
py `in` нет → py писал DontIndex вместо IndexWithAdditionalOrder. Фикс зеркалит
строковый путь.

Роундтрип 120 объектов: match 94→95, TOTAL 183→158 (−25), Command>Picture=0,
новых diff нет. Регресс 46/46 ps1+py, ps1↔py identical. spec §7.1.3, кейс
catalog-command (3 формы picture: строка/loadTransparent:false/объект+transparentPixel).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Nick Shirokov
2026-07-04 14:48:20 +03:00
parent d72a946eb5
commit 1212cbd9ed
8 changed files with 171 additions and 15 deletions
@@ -1,4 +1,4 @@
# meta-compile v1.28 — Compile 1C metadata object from JSON
# meta-compile v1.29 — Compile 1C metadata object from JSON
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
param(
[Parameter(Mandatory)]
@@ -1580,6 +1580,29 @@ function Emit-Attribute {
X "$indent</Attribute>"
}
# <Picture> команды — структурный блок (зеркало form-compile). Дефолт LoadTransparent=true (конвенция
# кнопки/команды): фиксируем только false. Значение: строка-ref + sibling `loadTransparent` ЛИБО объект
# {src, loadTransparent?, transparentPixel?}. src с префиксом "abs:" → <xr:Abs>, иначе <xr:Ref>. Нет → <Picture/>.
function Emit-CommandPicture {
param([string]$indent, $cmd)
$pic = $cmd.picture
if (-not $pic) { X "$indent<Picture/>"; return }
$src = $null; $lt = $true; $tpx = $null
if ($pic -is [string]) { $src = "$pic"; if ($cmd.loadTransparent -eq $false) { $lt = $false } }
else {
$src = if ($pic.src) { "$($pic.src)" } elseif ($pic.ref) { "$($pic.ref)" } else { "" }
if ($pic.loadTransparent -eq $false) { $lt = $false }
$tpx = $pic.transparentPixel
}
if (-not $src) { X "$indent<Picture/>"; return }
X "$indent<Picture>"
if ($src -match '^abs:(.*)$') { X "$indent`t<xr:Abs>$(Esc-Xml $matches[1])</xr:Abs>" }
else { X "$indent`t<xr:Ref>$(Esc-Xml $src)</xr:Ref>" }
X "$indent`t<xr:LoadTransparent>$(if ($lt) { 'true' } else { 'false' })</xr:LoadTransparent>"
if ($tpx) { X "$indent`t<xr:TransparentPixel x=`"$($tpx.x)`" y=`"$($tpx.y)`"/>" }
X "$indent</Picture>"
}
# --- 8b. Command emitter ---
# $cmd — объект свойств команды. Поля (omit-on-default): synonym/tooltip (ML), comment, group,
# commandParameterType (тип), parameterUseMode (Single), modifiesData (false), representation (Auto),
@@ -1608,7 +1631,7 @@ function Emit-Command {
$rep = if ($cmd.representation) { "$($cmd.representation)" } else { "Auto" }
X "$indent`t`t<Representation>$rep</Representation>"
Emit-MLText "$indent`t`t" "ToolTip" $cmd.tooltip
if ($cmd.picture) { X "$indent`t`t<Picture>$(Esc-Xml "$($cmd.picture)")</Picture>" } else { X "$indent`t`t<Picture/>" }
Emit-CommandPicture "$indent`t`t" $cmd
if ($cmd.shortcut) { X "$indent`t`t<Shortcut>$(Esc-Xml "$($cmd.shortcut)")</Shortcut>" } else { X "$indent`t`t<Shortcut/>" }
$osu = if ($cmd.onMainServerUnavalableBehavior) { "$($cmd.onMainServerUnavalableBehavior)" } else { "Auto" }
X "$indent`t`t<OnMainServerUnavalableBehavior>$osu</OnMainServerUnavalableBehavior>"
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
# meta-compile v1.28 — Compile 1C metadata object from JSON
# meta-compile v1.29 — Compile 1C metadata object from JSON
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import argparse
@@ -832,7 +832,8 @@ def parse_attribute_shorthand(val):
'synonym': val['synonym'] if val.get('synonym') is not None else split_camel_case(name),
'tooltip': val.get('tooltip'),
'comment': str(val['comment']) if val.get('comment') else '',
'flags': list(val.get('flags', [])),
# Лоуэркейз как в строковом пути (стр.809): проверки флагов регистронезависимы (зеркало PS -contains).
'flags': [str(f).strip().lower() for f in val.get('flags', [])],
'fillChecking': fc,
'indexing': str(val['indexing']) if val.get('indexing') else '',
'multiLine': True if val.get('multiLine') is True else False,
@@ -1630,6 +1631,39 @@ def emit_attribute(indent, parsed, context):
# 9. TabularSection emitter
# ---------------------------------------------------------------------------
def emit_command_picture(indent, cmd):
"""<Picture> команды — структурный блок (зеркало form-compile). Дефолт LoadTransparent=true (конвенция
кнопки/команды): фиксируем только false. Значение: строка-ref + sibling loadTransparent ЛИБО объект
{src, loadTransparent?, transparentPixel?}. src с префиксом "abs:" → <xr:Abs>, иначе <xr:Ref>. Нет → <Picture/>."""
pic = cmd.get('picture')
if not pic:
X(f'{indent}<Picture/>')
return
lt = True
tpx = None
if isinstance(pic, str):
src = pic
if cmd.get('loadTransparent') is False:
lt = False
else:
src = str(pic.get('src') or pic.get('ref') or '')
if pic.get('loadTransparent') is False:
lt = False
tpx = pic.get('transparentPixel')
if not src:
X(f'{indent}<Picture/>')
return
X(f'{indent}<Picture>')
m = re.match(r'^abs:(.*)$', src)
if m:
X(f'{indent}\t<xr:Abs>{esc_xml(m.group(1))}</xr:Abs>')
else:
X(f'{indent}\t<xr:Ref>{esc_xml(src)}</xr:Ref>')
X(f'{indent}\t<xr:LoadTransparent>{"true" if lt else "false"}</xr:LoadTransparent>')
if tpx:
X(f'{indent}\t<xr:TransparentPixel x="{tpx.get("x")}" y="{tpx.get("y")}"/>')
X(f'{indent}</Picture>')
def emit_command(indent, cmd_name, cmd):
X(f'{indent}<Command uuid="{new_uuid()}">')
X(f'{indent}\t<Properties>')
@@ -1651,10 +1685,7 @@ def emit_command(indent, cmd_name, cmd):
X(f'{indent}\t\t<ModifiesData>{"true" if cmd.get("modifiesData") is True else "false"}</ModifiesData>')
X(f'{indent}\t\t<Representation>{cmd.get("representation") or "Auto"}</Representation>')
emit_mltext(f'{indent}\t\t', 'ToolTip', cmd.get('tooltip'))
if cmd.get('picture'):
X(f'{indent}\t\t<Picture>{esc_xml(str(cmd["picture"]))}</Picture>')
else:
X(f'{indent}\t\t<Picture/>')
emit_command_picture(f'{indent}\t\t', cmd)
if cmd.get('shortcut'):
X(f'{indent}\t\t<Shortcut>{esc_xml(str(cmd["shortcut"]))}</Shortcut>')
else:
@@ -1,4 +1,4 @@
# meta-decompile v0.19 — XML объекта метаданных 1С → JSON-черновик формата meta-compile
# meta-decompile v0.20 — XML объекта метаданных 1С → JSON-черновик формата meta-compile
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
#
# Пилот: только Catalog. Инверс meta-compile (omit-on-default: ключ эмитим только
@@ -589,7 +589,25 @@ if ($childObjs) {
$mdN = $cp.SelectSingleNode('md:ModifiesData', $nsm); if ($mdN -and $mdN.InnerText -eq 'true') { $o['modifiesData'] = $true }
$repN = $cp.SelectSingleNode('md:Representation', $nsm); if ($repN -and $repN.InnerText -ne 'Auto') { $o['representation'] = $repN.InnerText }
$ctt = Get-MLValue ($cp.SelectSingleNode('md:ToolTip', $nsm)); if ($null -ne $ctt) { $o['tooltip'] = $ctt }
$picN = $cp.SelectSingleNode('md:Picture', $nsm); if ($picN -and $picN.InnerText) { $o['picture'] = $picN.InnerText }
# <Picture> — структурный блок (зеркало form-decompile Set-CommandPicture). Дефолт LoadTransparent=true:
# скаляр `picture` + sibling `loadTransparent:false` при отклонении; объект {src,loadTransparent?,transparentPixel} при TransparentPixel.
$refN = $cp.SelectSingleNode('md:Picture/xr:Ref', $nsm)
$absN = $cp.SelectSingleNode('md:Picture/xr:Abs', $nsm)
if ($refN -or $absN) {
$psrc = if ($refN) { $refN.InnerText } else { "abs:$($absN.InnerText)" }
$ltN = $cp.SelectSingleNode('md:Picture/xr:LoadTransparent', $nsm)
$ltFalse = ($ltN -and $ltN.InnerText -eq 'false')
$tpxN = $cp.SelectSingleNode('md:Picture/xr:TransparentPixel', $nsm)
if ($tpxN) {
$po = [ordered]@{ src = $psrc }
if ($ltFalse) { $po['loadTransparent'] = $false }
$po['transparentPixel'] = [ordered]@{ x = [int]$tpxN.GetAttribute('x'); y = [int]$tpxN.GetAttribute('y') }
$o['picture'] = $po
} else {
$o['picture'] = $psrc
if ($ltFalse) { $o['loadTransparent'] = $false }
}
}
$scN = $cp.SelectSingleNode('md:Shortcut', $nsm); if ($scN -and $scN.InnerText) { $o['shortcut'] = $scN.InnerText }
$osuN = $cp.SelectSingleNode('md:OnMainServerUnavalableBehavior', $nsm); if ($osuN -and $osuN.InnerText -ne 'Auto') { $o['onMainServerUnavalableBehavior'] = $osuN.InnerText }
$cmdMap[$cn] = $o
+14 -3
View File
@@ -444,15 +444,26 @@ JSON DSL для описания объектов метаданных конф
| `parameterUseMode` | ParameterUseMode | `Single` (`Single`/`Multiple`) |
| `modifiesData` | ModifiesData | `false` (bool) |
| `representation` | Representation | `Auto` |
| `picture` / `shortcut` | Picture / Shortcut | пусто |
| `picture` | Picture | пусто (структурный блок, см. ниже) |
| `loadTransparent` | Picture/LoadTransparent | `true` (bool, sibling `picture`) |
| `shortcut` | Shortcut | пусто |
| `onMainServerUnavalableBehavior` | OnMainServerUnavalableBehavior | `Auto` |
**`picture`** — картинка команды `<Picture>` (структурный блок `<xr:Ref>`+`<xr:LoadTransparent>`, зеркало form-compile).
Значение: строка-ref (`StdPicture.X` / `CommonPicture.X`; встроенная — префикс `abs:``<xr:Abs>`) ЛИБО объект
`{src, loadTransparent?, transparentPixel?}`. LoadTransparent платформа пишет всегда, **дефолт `true`** (конвенция
кнопки/команды) — фиксируем только `false`: строкой-ref + sibling-ключ `loadTransparent: false`, либо внутри объекта.
`transparentPixel: {x, y}``<xr:TransparentPixel>`. Декомпилятор: скаляр при LoadTransparent=true без пикселя,
иначе объект.
```json
"commands": {
"ПечатьЭтикеток": {
"synonym": "Печать этикеток", "group": "FormCommandBarImportant",
"commandParameterType": "CatalogRef.Номенклатура", "modifiesData": true
}
"commandParameterType": "CatalogRef.Номенклатура", "modifiesData": true,
"picture": "StdPicture.Print"
},
"ЗагрузитьИзФайла": { "picture": "CommonPicture.Загрузка", "loadTransparent": false }
}
```
@@ -9,7 +9,16 @@
"commandParameterType": "CatalogRef.Номенклатура",
"parameterUseMode": "Multiple",
"modifiesData": true,
"tooltip": "Печать этикеток для выбранных товаров"
"tooltip": "Печать этикеток для выбранных товаров",
"picture": "StdPicture.Print"
},
"ЗагрузитьИзФайла": {
"synonym": "Загрузить из файла",
"picture": "CommonPicture.Загрузка",
"loadTransparent": false
},
"ОбновитьСписок": {
"picture": { "src": "StdPicture.Refresh", "transparentPixel": { "x": 0, "y": 0 } }
}
}
},
@@ -114,7 +114,59 @@
<v8:content>Печать этикеток для выбранных товаров</v8:content>
</v8:item>
</ToolTip>
<Picture/>
<Picture>
<xr:Ref>StdPicture.Print</xr:Ref>
<xr:LoadTransparent>true</xr:LoadTransparent>
</Picture>
<Shortcut/>
<OnMainServerUnavalableBehavior>Auto</OnMainServerUnavalableBehavior>
</Properties>
</Command>
<Command uuid="UUID-013">
<Properties>
<Name>ЗагрузитьИзФайла</Name>
<Synonym>
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>Загрузить из файла</v8:content>
</v8:item>
</Synonym>
<Comment/>
<Group></Group>
<CommandParameterType/>
<ParameterUseMode>Single</ParameterUseMode>
<ModifiesData>false</ModifiesData>
<Representation>Auto</Representation>
<ToolTip/>
<Picture>
<xr:Ref>CommonPicture.Загрузка</xr:Ref>
<xr:LoadTransparent>false</xr:LoadTransparent>
</Picture>
<Shortcut/>
<OnMainServerUnavalableBehavior>Auto</OnMainServerUnavalableBehavior>
</Properties>
</Command>
<Command uuid="UUID-014">
<Properties>
<Name>ОбновитьСписок</Name>
<Synonym>
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>Обновить список</v8:content>
</v8:item>
</Synonym>
<Comment/>
<Group></Group>
<CommandParameterType/>
<ParameterUseMode>Single</ParameterUseMode>
<ModifiesData>false</ModifiesData>
<Representation>Auto</Representation>
<ToolTip/>
<Picture>
<xr:Ref>StdPicture.Refresh</xr:Ref>
<xr:LoadTransparent>true</xr:LoadTransparent>
<xr:TransparentPixel x="0" y="0"/>
</Picture>
<Shortcut/>
<OnMainServerUnavalableBehavior>Auto</OnMainServerUnavalableBehavior>
</Properties>
@@ -0,0 +1,6 @@
&НаКлиенте
Процедура ОбработкаКоманды(ПараметрКоманды, ПараметрыВыполненияКоманды)
// Вставьте обработчик команды.
КонецПроцедуры
@@ -0,0 +1,6 @@
&НаКлиенте
Процедура ОбработкаКоманды(ПараметрКоманды, ПараметрыВыполненияКоманды)
// Вставьте обработчик команды.
КонецПроцедуры