Imported from pavelvdo/universal-xml-exchange2 (
.cursor/skills/1c-extensions/SKILL.md). Install upstream withnpx skills add pavelvdo/universal-xml-exchange2 --skill 1c-extensions. Copyright stays with the author.
1C Extensions — аннотации и ИзменениеИКонтроль
Руководство по работе с аннотациями расширений конфигурации 1С:Предприятие и механизмом &ИзменениеИКонтроль. Алгоритм переноса правок адаптирован из skirdinsa/1c-merge-prompt.
Глубокий платформенный референс (терминология, заимствованные объекты, расширение данных): .cursor/docs/platform/Глава 30. Расширение конфигурации.md.
A. Дерево решений: какую аннотацию использовать
Задача: изменить поведение типового метода в расширении.
КРИТИЧЕСКОЕ ОГРАНИЧЕНИЕ: &Перед и &После применимы ТОЛЬКО к процедурам (Процедура). Для функций (Функция) они НЕ работают. Если перехватываемый метод — функция → сразу переходить к п.4 или п.5.
1. Метод — процедура? Нужна логика ДО вызова?
→ &Перед
Перед объявлением: прочитать сигнатуру базовой процедуры и воспроизвести её параметры один в один.
2. Метод — процедура? Нужна логика ПОСЛЕ вызова?
→ &После
Перед объявлением: прочитать сигнатуру базовой процедуры и воспроизвести её параметры один в один.
3. Метод — процедура? Нужно изменить параметры?
→ &Перед + &После (через ДополнительныеПараметры)
4. Нужно условное поведение: при выключенной настройке/feature-flag выполнить стандартный метод, при включённой — собственную замену?
→ &Вместо + ПродолжитьВызов(...) в off-ветке
Это делегирование владельцу поведения. Не копировать тело типового метода в локальную функцию.
5. Нужно изменить код ВНУТРИ тела метода (процедура или функция)?
→ &ИзменениеИКонтроль
6. Нужна полная замена метода (процедура или функция)?
→ &Вместо + ПродолжитьВызов() внутри (крайний случай, ломается при обновлениях)
Приоритет: &Перед / &После (только для процедур) > &ИзменениеИКонтроль > &Вместо. Исключение: условная замена с fallback на стандартное поведение — это &Вместо + ПродолжитьВызов(...), а не локальная копия базы в &ИзменениеИКонтроль. Каждый следующий уровень усложняет поддержку при обновлении конфигурации.
Hook composability
Перехваченная процедура расширения — общая точка композиции доработок. Не ставь feature-flag или предметный фильтр как ранний Возврат поверх всего тела &Перед, &После, &Вместо или &ИзменениеИКонтроль, если ниже может быть несколько независимых смысловых блоков.
Правильно: guard ограничивает только блок своей фичи.
Если pavНастройки.ИспользоватьНовуюЛогику() Тогда
ВыполнитьНовуюЛогику(Объект);
КонецЕсли;
ВыполнитьДругуюДоработку(Объект);
Для &Вместо ветка, в которой новая логика не выполняется, должна явно вызывать ПродолжитьВызов(...), если нет архитектурно обоснованной полной замены типового поведения.
См. AP-046 в .cursor/rules/bsl-antipatterns.mdc и .cursor/docs/antipatterns/bsl-antipatterns.md.
Owner of Behavior
У перехваченного метода базовой конфигурации есть владелец поведения — база. Расширение не должно становиться вторым владельцем поведения через локальную копию типового тела, если доступно делегирование владельцу.
Матрица выбора:
| Сценарий | Аннотация | Почему |
|---|---|---|
| Дополнительное поведение до базовой процедуры | &Перед |
База остаётся владельцем основного поведения |
| Дополнительное поведение после базовой процедуры | &После |
Расширение добавляет свой блок, не копирует базу |
| Точечная правка внутри базового тела | &ИзменениеИКонтроль + узкие #Вставка / #Удаление |
Контроль применимости остаётся привязан к настоящей базе |
| Условная замена: off-ветка = стандартное поведение, on-ветка = собственное | &Вместо + ПродолжитьВызов(...) в off-ветке |
Off-ветка делегирует владельцу поведения и не drift-ит |
| Off-ветка feature-flag вызывает локальную копию типового тела | Запрещено без архитектурного обоснования | Это Substituted Authority (AP-047): локальная подмена владельца поведения |
Если локальная реализация всё же должна стать источником истины, это решение должно быть оформлено как уровень 4 Preference Hierarchy из .cursor/rules/existing-mechanism-priority.mdc: почему нельзя делегировать, какой drift-риск принимается, как проверяется актуальность копии.
См. AP-047 в .cursor/rules/bsl-antipatterns.mdc и .cursor/docs/antipatterns/bsl-antipatterns.md.
B. Синтаксис и правила &ИзменениеИКонтроль
Директивы
- Удаление фрагмента:
#Удаление…#КонецУдаления - Вставка фрагмента:
#Вставка…#КонецВставки
Ограничения
- Код вне директив должен побитово совпадать с типовым: пробелы, переносы строк, кавычки, порядок объявлений. Любое расхождение приведёт к ошибке применимости расширения.
- Один метод можно изменять через
&ИзменениеИКонтрольтолько в одном расширении. - При переименовании метода в типовой конфигурации — переименовать и в расширении.
- Имя процедуры/функции в расширении имеет префикс расширения (например,
pavIU_ИмяПроцедуры).
Пример
&ИзменениеИКонтроль("ИмяПроцедуры")
Процедура pavIU_ИмяПроцедуры(...)
#Удаление
// старая строка
#КонецУдаления
#Вставка
// новый код
#КонецВставки
КонецПроцедуры
Пример: вставка нового кода между типовыми строками
Самый частый сценарий — добавить логику расширения между двумя существующими строками типового кода. Новый код обязательно оборачивается в #Вставка/#КонецВставки:
&ИзменениеИКонтроль("ОбработатьВыполнение")
Процедура КД_ОбработатьВыполнение(Параметр1, Параметр2)
БазовыйВызов(); // типовой код — НЕ ТРОГАТЬ
#Вставка
Если Условие Тогда
МояПроцедураРасширения();
КонецЕсли;
#КонецВставки
ТиповойВызов(); // типовой код — НЕ ТРОГАТЬ
КонецПроцедуры
Анти-паттерн (ЗАПРЕЩЕНО — код добавлен без директив, расширение сломается):
&ИзменениеИКонтроль("ОбработатьВыполнение")
Процедура КД_ОбработатьВыполнение(Параметр1, Параметр2)
БазовыйВызов();
// ЭТО ОШИБКА — новый код без #Вставка/#КонецВставки!
Если Условие Тогда
МояПроцедураРасширения();
КонецЕсли;
ТиповойВызов();
КонецПроцедуры
HALT: Неприкосновенность типового кода в &ИзменениеИКонтроль
СТОП перед любой правкой метода с &ИзменениеИКонтроль.
Код ВНЕ директив #Вставка/#КонецВставки и #Удаление/#КонецУдаления — это типовой код конфигурации. Он ДОЛЖЕН побитово совпадать с оригиналом.
ЗАПРЕЩЕНО вне директив:
- Переименовывать переменные
- Менять форматирование (пробелы, отступы, пустые строки)
- Рефакторить код (извлекать функции, менять структуру)
- Удалять или добавлять строки
- Менять порядок операторов
- Исправлять «ошибки» типового кода
- Добавлять/удалять/перемещать разметку
#Область/#КонецОбласти
РАЗРЕШЕНО менять код ТОЛЬКО внутри #Вставка/#КонецВставки.
При рефакторинге или «наведении порядка», затрагивающем модуль расширения с &ИзменениеИКонтроль:
- Определить, какой код является типовым (вне
#Вставка/#КонецВставки) - Рефакторить / добавлять
#ОбластьТОЛЬКО в собственный код расширения (внутри блоков#Вставкаили в собственных, не заимствованных, процедурах/функциях) - Типовой код — НЕ ТРОГАТЬ, включая его разметку
#Область
C. Анти-паттерны
- Сигнатура при &Перед / &После должна точно совпадать с базовой процедурой. Если базовая процедура имеет параметры — они должны быть в той же последовательности и с теми же именами в процедуре расширения. Несовпадение числа или имён параметров приводит к ошибке применения расширения на старте.
- Не применять
&Перед/&Послек функциям — платформа это не поддерживает. Для функций:&Вместо(с ПродолжитьВызов()) или&ИзменениеИКонтроль. - Не менять форматирование вне блоков
#Вставка/#Удаление. - Не добавлять пустые строки в неизменённые участки.
- Не использовать
&ИзменениеИКонтроль, если задачу решают&Перед/&После(и метод — процедура). - Не размещать бизнес-логику внутри директив — выносить в отдельные процедуры/функции расширения, в блоках
#Вставкаоставлять только вызовы. - Запрещённый паттерн: рефакторинг типового кода вне #Вставка — переименование переменных, изменение отступов, извлечение функций в коде вне директив ломает применимость расширения.
- Запрещённый паттерн: добавление #Область в типовой код — при «наведении порядка» в модуле расширения не добавлять и не дублировать разметку
#Областьв заимствованном типовом коде; только внутри#Вставкаили в собственных процедурах/функциях расширения. - Запрещённый паттерн: hook-scope early return (AP-046) — feature-flag или предметный guard не должен ранним
Возвратотключать всё тело перехваченной процедуры; оборачивать только блок своей доработки. - Запрещённый паттерн: Substituted Authority (AP-047) — не делать локальный дубликат тела базового метода как fallback-ветку feature-flag в
&ИзменениеИКонтроль; использовать&Вместо+ПродолжитьВызов(...)или узкую доработку через#Вставка/#Удаление.
D. Алгоритм переноса правок после обновления конфигурации
Адаптация из skirdinsa/1c-merge-prompt.
Вход (3 файла)
- Старая типовая процедура/функция (до обновления, без изменений).
- Старая с изменениями — та же процедура с директивами
#Вставка/#Удаление. - Новая типовая — процедура/функция после обновления конфигурации (без изменений).
Выход
- Новая процедура/функция с корректно перенесёнными директивами.
Жёсткие правила переноса
- Итоговый код побитово совпадает с файлом 3, кроме блоков внутри директив.
- Имя процедуры/функции берётся из файла 2 (с префиксом расширения), не из файла 3.
- Запрещено менять форматирование: пробелы, отступы, пустые строки, кавычки, порядок объявлений.
Алгоритм
- Извлечь все блоки
#Вставка/#Удалениеиз файла 2. - Для каждого блока определить якоря — строки типового кода до и после блока.
- Найти соответствующие якоря в файле 3 (сопоставление через diff файла 1 и файла 3).
- Если якорь найден — вставить директиву в то же место.
- Если якорь удалён или перемещён — пометить конфликт для ручного разрешения.
E. Процесс работы с &ИзменениеИКонтроль
- Убедиться:
&Перед/&Послене решают задачу. - Заимствовать метод: команда «Добавить в расширение» в конфигураторе.
- Внести правки через директивы
#Вставка/#Удаление. - Проверить применимость расширения в конфигураторе.
- После обновления типовой конфигурации: «Восстановить соответствие» → перенести правки по алгоритму (раздел D).
- Вести журнал изменённых методов для поддержки при следующих обновлениях.
Интеграция
- Стандарты кодирования: .cursor/docs/1c-coding-standards.md — раздел «Аннотации расширений».
- Паттерны делегирования: .cursor/skills/1c-agent-patterns/SKILL.md — выбор аннотации при проектировании, реализация через onec-code-writer.
- Загрузка расширения после правок: через Конфигуратор (Конфигурация → Расширения → Загрузить из файлов).