feat(form-decompile,form-compile): унификация событий элементов на events-мапу (кластер Events DSL)

Несогласованность DSL: события ФОРМЫ описывались интуитивной мапой
events:{Событие:Обработчик}, а события ЭЛЕМЕНТА — двумя сущностями
on:[...] + handlers:{...}. Два способа для одного понятия путали модель.

Унифицировано на единую мапу events:{Событие:ИмяОбработчика} на форме И
элементах (как form-level). Декомпилятор эмитит только её, с явными именами
обработчиков (прозрачно, консистентно с form-level).

Компилятор (ps1+py):
- Emit-Events читает events-мапу (основной формат); значение null/"" →
  имя по конвенции ИмяЭлемента+суффикс (прощающий fallback).
- legacy on/handlers по-прежнему принимаются ради совместимости (не эмитятся).
- choiceButton: проверка StartChoice через оба формата (Test-ElementEvent).
- events добавлен в whitelist ключей элемента.

Декомпилятор: Get-Events → упорядоченная мапа {Событие:Обработчик} в порядке
документа; убраны on/handlers и инверсия авто-имён.

spec/SKILL.md: events как единственный рекомендованный формат, on/handlers
помечены legacy. В SKILL.md только явные имена (null-сахар — деталь spec,
инструкцию не раздуваем).

Корпус acc_8.3.24: 190 элементов в 114/400 форм теряли Events до фикса (баг
on/handlers разобран отдельным коммитом). Раундтрип 2.17: Events ушли из топа
LOST, match 4→6, 0 compile-fail. Регресс ps+py 32/32, снэпшот events (добавлен
блок Events у поля с переименованным обработчиком) сертифицирован в 1С 8.3.24.

Follow-up: form-edit использует расширенный on с {event,callType} —
унификация отдельным решением (см. BACKLOG).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Nick Shirokov
2026-06-05 12:46:56 +03:00
co-authored by Claude Opus 4.8
parent a38874280c
commit 4c2c72abce
7 changed files with 127 additions and 82 deletions
+3 -3
View File
@@ -17,9 +17,9 @@
"title": "События",
"events": { "OnCreateAtServer": "ПриСозданииНаСервере", "OnOpen": "ПриОткрытии" },
"elements": [
{ "input": "Организация", "path": "Организация", "on": ["OnChange", "StartChoice"] },
{ "input": "Период", "path": "Период", "handlers": { "OnChange": "ПериодПриИзменении" } },
{ "label": "Подсказка", "title": "Нажмите для перехода", "hyperlink": true, "on": ["Click"] }
{ "input": "Организация", "path": "Организация", "events": { "OnChange": "ОрганизацияПриИзменении", "StartChoice": "ОрганизацияНачалоВыбора" } },
{ "input": "Период", "path": "Период", "events": { "OnChange": "ПериодПриИзменении" } },
{ "label": "Подсказка", "title": "Нажмите для перехода", "hyperlink": true, "events": { "Click": null } }
],
"attributes": [
{ "name": "Объект", "type": "DataProcessorObject.События", "main": true },
@@ -26,6 +26,9 @@
<DataPath>Период</DataPath>
<ContextMenu name="ПериодКонтекстноеМеню" id="5"/>
<ExtendedTooltip name="ПериодРасширеннаяПодсказка" id="6"/>
<Events>
<Event name="OnChange">ПериодПриИзменении</Event>
</Events>
</InputField>
<LabelDecoration name="Подсказка" id="7">
<Title formatted="true">