From 4ba1e595bfae5f932d2a5ae5e0bad58eab6346a6 Mon Sep 17 00:00:00 2001 From: Nick Shirokov Date: Thu, 4 Jun 2026 18:32:02 +0300 Subject: [PATCH] =?UTF-8?q?feat(form-decompile,form-compile):=20=D1=81?= =?UTF-8?q?=D0=B5=D0=BC=D0=B0=D0=BD=D1=82=D0=B8=D0=BA=D0=B0=20title=20(?= =?UTF-8?q?=D0=BA=D0=BB=D0=B0=D1=81=D1=82=D0=B5=D1=80=20G)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Над-генерация заголовков элементов из имени. Различаем: - нет ключа title → авто-вывод из имени (помощь модели при создании форм); - title: "" → подавить ( не эмитим); - непустая строка → как есть. - compiler PS1+PY: Emit-Title/emit_title + Emit-Label проверяют наличие ключа, а не truthiness (раньше "" триггерило авто-вывод). - decompiler: ставит title:"" для авто-выводящих типов (page/popup/label, непривязанные поля, button без команды), когда <Title> в оригинале отсутствует. - docs/form-dsl-spec: семантика title. - tests: pages демонстрирует title:"" (+snapshot, сертифицирован в 1С). АварийныйРежим: diff 13→1. Регресс 32/32 PS1+PY, churn нулевой. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --- .../form-compile/scripts/form-compile.ps1 | 19 +++++++++++-------- .../form-compile/scripts/form-compile.py | 16 +++++++++------- .../form-decompile/scripts/form-decompile.ps1 | 11 ++++++++++- docs/form-dsl-spec.md | 2 +- tests/skills/cases/form-compile/pages.json | 2 +- .../Мастер/Forms/Форма/Ext/Form.xml | 6 ------ 6 files changed, 32 insertions(+), 24 deletions(-) diff --git a/.claude/skills/form-compile/scripts/form-compile.ps1 b/.claude/skills/form-compile/scripts/form-compile.ps1 index 219dfaba..b00e6fe3 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.25 — Compile 1C managed form from JSON or object metadata +# form-compile v1.26 — Compile 1C managed form from JSON or object metadata # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills param( [string]$JsonPath, @@ -2022,13 +2022,15 @@ function Title-FromName { } function Emit-Title { + # Нет ключа title → авто-вывод из имени (помощь модели). + # Явный title: "" (или null) → подавить (заголовок не эмитим). + # Явный непустой → эмитим как есть. param($el, [string]$name, [string]$indent, [switch]$auto) - $title = $el.title - if (-not $title -and $auto -and $name) { - $title = Title-FromName -name $name - } - if ($title) { - Emit-MLText -tag "Title" -text "$title" -indent $indent + $hasKey = $null -ne $el.PSObject.Properties['title'] + if ($hasKey) { + if ($el.title) { Emit-MLText -tag "Title" -text "$($el.title)" -indent $indent } + } elseif ($auto -and $name) { + Emit-MLText -tag "Title" -text "$(Title-FromName -name $name)" -indent $indent } } @@ -2434,7 +2436,8 @@ function Emit-Label { X "$indent<LabelDecoration name=`"$name`" id=`"$id`">" $inner = "$indent`t" - $labelTitle = if ($el.title) { "$($el.title)" } else { Title-FromName -name $name } + $hasTitleKey = $null -ne $el.PSObject.Properties['title'] + $labelTitle = if ($hasTitleKey) { "$($el.title)" } else { Title-FromName -name $name } if ($labelTitle) { $formatted = if ($el.hyperlink -eq $true) { "true" } else { "false" } X "$inner<Title formatted=`"$formatted`">" diff --git a/.claude/skills/form-compile/scripts/form-compile.py b/.claude/skills/form-compile/scripts/form-compile.py index 79b0f054..c69233be 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.25 — Compile 1C managed form from JSON or object metadata +# form-compile v1.26 — Compile 1C managed form from JSON or object metadata # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills import argparse import copy @@ -1611,11 +1611,13 @@ def title_from_name(name): def emit_title(lines, el, name, indent, auto=False): - title = el.get('title') - if not title and auto and name: - title = title_from_name(name) - if title: - emit_mltext(lines, indent, 'Title', str(title)) + # Нет ключа title → авто-вывод из имени (помощь модели). + # Явный title "" (или None) → подавить. Явный непустой → как есть. + if 'title' in el: + if el.get('title'): + emit_mltext(lines, indent, 'Title', str(el['title'])) + elif auto and name: + emit_mltext(lines, indent, 'Title', title_from_name(name)) # --- Type emitter --- @@ -2088,7 +2090,7 @@ def emit_label(lines, el, name, eid, indent): lines.append(f'{indent}<LabelDecoration name="{name}" id="{eid}">') inner = f'{indent}\t' - label_title = el.get('title') or title_from_name(name) + label_title = str(el['title'] or '') if 'title' in el else title_from_name(name) if label_title: formatted = 'true' if el.get('hyperlink') is True else 'false' lines.append(f'{inner}<Title formatted="{formatted}">') diff --git a/.claude/skills/form-decompile/scripts/form-decompile.ps1 b/.claude/skills/form-decompile/scripts/form-decompile.ps1 index 4acaf79e..dbd36e77 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.4 — Decompile 1C managed Form.xml to JSON DSL (draft) +# form-decompile v0.5 — Decompile 1C managed Form.xml to JSON DSL (draft) # Source: https://github.com/Nikolay-Shirokov/cc-1c-skills # ВНИМАНИЕ: раундтрип не гарантируется. Навык исключён из авто-использования моделью. param( @@ -499,6 +499,15 @@ function Decompile-Element { if ($kids) { $obj['children'] = $kids } } } + # title: "" — подавление авто-вывода: для типов, где компилятор вывел бы + # заголовок из имени, а в оригинале <Title> отсутствует. + if (-not $obj.Contains('title')) { + $autoTitle = $false + if ($tag -in @('LabelDecoration','Page','Popup')) { $autoTitle = $true } + elseif ($tag -eq 'Button') { $autoTitle = -not ($obj.Contains('command') -or $obj.Contains('stdCommand')) } + elseif ($tag -in @('InputField','CheckBoxField','RadioButtonField','LabelField','Table','CalendarField')) { $autoTitle = -not $obj.Contains('path') } + if ($autoTitle) { $obj['title'] = '' } + } Add-Layout $obj $node return $obj } diff --git a/docs/form-dsl-spec.md b/docs/form-dsl-spec.md index af486a02..36d7a06b 100644 --- a/docs/form-dsl-spec.md +++ b/docs/form-dsl-spec.md @@ -110,7 +110,7 @@ | Свойство | Тип | Описание | |----------|-----|----------| | `name` | string | Имя элемента (по умолчанию — из значения ключа типа) | -| `title` | string | Заголовок | +| `title` | string | Заголовок. **Нет ключа** → авто-вывод из имени (для page/popup/label и непривязанных полей/кнопок). **`""`** → подавить (заголовок не выводится). Непустая строка → как есть | | `hidden` | bool | `true` → `<Visible>false</Visible>` | | `disabled` | bool | `true` → `<Enabled>false</Enabled>` | | `readOnly` | bool | `true` → `<ReadOnly>true</ReadOnly>` | diff --git a/tests/skills/cases/form-compile/pages.json b/tests/skills/cases/form-compile/pages.json index c1e79c44..aded9c10 100644 --- a/tests/skills/cases/form-compile/pages.json +++ b/tests/skills/cases/form-compile/pages.json @@ -18,7 +18,7 @@ "properties": { "autoTitle": false }, "elements": [ { "pages": "СтраницыМастера", "pagesRepresentation": "None", "children": [ - { "page": "Шаг1", "title": "Параметры", "children": [ + { "page": "Шаг1", "title": "", "children": [ { "input": "Параметр1", "path": "Параметр1" } ]}, { "page": "Шаг2", "title": "Результат", "children": [ diff --git a/tests/skills/cases/form-compile/snapshots/pages/DataProcessors/Мастер/Forms/Форма/Ext/Form.xml b/tests/skills/cases/form-compile/snapshots/pages/DataProcessors/Мастер/Forms/Форма/Ext/Form.xml index c5094674..0ef9e502 100644 --- a/tests/skills/cases/form-compile/snapshots/pages/DataProcessors/Мастер/Forms/Форма/Ext/Form.xml +++ b/tests/skills/cases/form-compile/snapshots/pages/DataProcessors/Мастер/Forms/Форма/Ext/Form.xml @@ -14,12 +14,6 @@ <ExtendedTooltip name="СтраницыМастераРасширеннаяПодсказка" id="2"/> <ChildItems> <Page name="Шаг1" id="3"> - <Title> - <v8:item> - <v8:lang>ru</v8:lang> - <v8:content>Параметры</v8:content> - </v8:item> -