feat(form-decompile,form-compile): единая ML-text форма для заголовков декораций (Label/Picture) — переиспользование Resolve-MLFormatted

Заголовок декорации — formatted-aware текст (как extendedTooltip). Раньше LabelDecoration
нёс formatted отдельным sibling-ключом, PictureDecoration терял атрибут formatted вовсе
(эмитил голый <Title> через generic Emit-Title). Теперь оба идут через общий
Emit-DecorationTitle → Resolve-MLFormatted (та же единая ML-text форма, что у extendedTooltip):
- title декорации: строка (formatted авто-детектится по разметке) / {ru,en} / {text, formatted}.
- атрибут <Title formatted="…"> эмитится ВСЕГДА (специфика декораций); для обычных элементов
  Emit-Title остаётся без formatted (formatted — только у декораций, подтверждено корпусом:
  LabelDecoration 6568 + PictureDecoration 2, прочие 0).
- back-compat: sibling-ключ formatted принимается как override авто-детекта; компилятор-вывод
  LabelDecoration не изменился.

Декомпилятор (v0.27): декорации захватывают title через Get-MLFormattedValue (гибрид);
sibling formatted больше не выводится (форматированные обычно становятся просто строкой
с markup внутри). Компилятор (ps1+py v1.45): Emit-DecorationTitle для Label+Picture.

Валидация: LabelDecoration formatted round-trip CLEAN; PictureDecoration Title-formatted
закрыт (29→0); регресс 33/33 ps+py; py==ps1; harness 8202→8144. Spec обновлён.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Nick Shirokov
2026-06-06 18:43:08 +03:00
co-authored by Claude Opus 4.8
parent 684cd17d5f
commit b147e491ee
4 changed files with 50 additions and 31 deletions
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
# form-compile v1.44 — Compile 1C managed form from JSON or object metadata
# form-compile v1.45 — Compile 1C managed form from JSON or object metadata
# Source: https://github.com/Nikolay-Shirokov/cc-1c-skills
import argparse
import copy
@@ -2639,21 +2639,29 @@ def emit_radio_button_field(lines, el, name, eid, indent):
lines.append(f'{indent}</RadioButtonField>')
# Заголовок декорации (Label/Picture): formatted-aware <Title> через единую ML-text форму
# (reuse resolve_ml_formatted, как у extendedTooltip). Sibling-ключ formatted — back-compat override.
def emit_decoration_title(lines, el, name, indent, auto=False):
has_key = 'title' in el
title_val = el['title'] if has_key else (title_from_name(name) if (auto and name) else None)
if title_val:
text, fmt = resolve_ml_formatted(title_val)
if 'formatted' in el:
fmt = bool(el['formatted'])
lines.append(f'{indent}<Title formatted="{"true" if fmt else "false"}">')
emit_ml_items(lines, f'{indent}\t', text)
lines.append(f'{indent}</Title>')
if el.get('tooltip'):
emit_mltext(lines, indent, 'ToolTip', el['tooltip'])
if el.get('tooltipRepresentation'):
lines.append(f'{indent}<ToolTipRepresentation>{el["tooltipRepresentation"]}</ToolTipRepresentation>')
def emit_label(lines, el, name, eid, indent):
lines.append(f'{indent}<LabelDecoration name="{name}" id="{eid}">')
inner = f'{indent}\t'
label_title = el['title'] if 'title' in el else title_from_name(name)
if label_title:
# formatted — независимое свойство (НЕ выводится из hyperlink).
formatted = 'true' if el.get('formatted') is True else 'false'
lines.append(f'{inner}<Title formatted="{formatted}">')
emit_ml_items(lines, f'{inner}\t', label_title)
lines.append(f'{inner}</Title>')
if el.get('tooltip'):
emit_mltext(lines, inner, 'ToolTip', el['tooltip'])
if el.get('tooltipRepresentation'):
lines.append(f'{inner}<ToolTipRepresentation>{el["tooltipRepresentation"]}</ToolTipRepresentation>')
emit_decoration_title(lines, el, name, inner, auto=True)
emit_common_flags(lines, el, inner)
@@ -2971,7 +2979,7 @@ def emit_picture_decoration(lines, el, name, eid, indent):
lines.append(f'{indent}<PictureDecoration name="{name}" id="{eid}">')
inner = f'{indent}\t'
emit_title(lines, el, name, inner)
emit_decoration_title(lines, el, name, inner)
emit_common_flags(lines, el, inner)
if el.get('picture') or el.get('src'):