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:03 +03:00
parent a38874280c
commit 4c2c72abce
7 changed files with 127 additions and 82 deletions
+22 -9
View File
@@ -79,7 +79,7 @@
}
```
Ключ — имя события, значение — имя процедуры-обработчика.
Ключ — имя события, значение — имя процедуры-обработчика. **Тот же формат `events` используется и на элементах** (§4.1) — единый способ описания событий во всём DSL.
### Доступные события
@@ -114,8 +114,7 @@
| `hidden` | bool | `true``<Visible>false</Visible>` |
| `disabled` | bool | `true``<Enabled>false</Enabled>` |
| `readOnly` | bool | `true``<ReadOnly>true</ReadOnly>` |
| `on` | string[] | Массив имён событий |
| `handlers` | object | Явные имена обработчиков: `{"OnChange": "МойОбработчик"}` |
| `events` | object | Обработчики событий: `{ "ИмяСобытия": "ИмяОбработчика" }` — тот же формат, что у событий формы (§3). Значение `null` → имя по конвенции (§4.2). См. §4.2 |
### 4.1a. Общие layout-свойства
@@ -136,14 +135,25 @@
| `horizontalAlign` | `<HorizontalAlign>` | `Left`, `Center`, `Right` |
| `skipOnInput` | `<SkipOnInput>` | `true` |
### 4.2. Автоименование обработчиков
### 4.2. События элемента и автоименование обработчиков
При указании `"on"` без `"handlers"` имя обработчика генерируется автоматически:
События элемента описываются мапой `events` (как у формы):
```json
{ "input": "Контрагент", "path": "Объект.Контрагент",
"events": { "OnChange": "КонтрагентПриИзменении" } }
```
<ИмяЭлемента><РусскийСуффикс>
Значение — имя процедуры-обработчика. Если вместо имени указать **`null`**, имя
генерируется автоматически по конвенции 1С `<ИмяЭлемента><РусскийСуффикс>`:
```json
{ "input": "Контрагент", "path": "Объект.Контрагент",
"events": { "OnChange": null } } // → обработчик КонтрагентПриИзменении
```
Суффиксы для авто-имени:
| Событие | Суффикс |
|---------|---------|
| `OnChange` | `ПриИзменении` |
@@ -163,7 +173,10 @@
| `OnCurrentPageChange` | `ПриСменеСтраницы` |
| `TextEditEnd` | `ОкончаниеВводаТекста` |
Пример: элемент `Контрагент` + событие `OnChange` → обработчик `КонтрагентПриИзменении`.
> **Legacy-формат (принимается, но устарел).** Ранее события элемента задавались парой
> `on` (массив имён событий) + `handlers` (переопределение имён): `{ "on": ["OnChange"], "handlers": { … } }`.
> Компилятор по-прежнему его принимает ради совместимости, но рекомендуемый и
> единственный эмитируемый формат — мапа `events`. Новые формы пишите через `events`.
### 4.3. Типы элементов
@@ -184,7 +197,7 @@
#### input — InputField
```json
{ "input": "Организация", "path": "Объект.Организация", "on": ["OnChange"] }
{ "input": "Организация", "path": "Объект.Организация", "events": { "OnChange": "ОрганизацияПриИзменении" } }
```
| Свойство | Тип | Описание |
@@ -211,7 +224,7 @@
#### check — CheckBoxField
```json
{ "check": "ФлагАктивности", "path": "Активен", "on": ["OnChange"] }
{ "check": "ФлагАктивности", "path": "Активен", "events": { "OnChange": "ФлагАктивностиПриИзменении" } }
```
| Свойство | Тип | Описание |