Константы в сценарии бота: полное руководство
Материал для тех, кто собирает логику из блоков: что именно называется константой, откуда она попадает в сценарий, как не ошибиться в полях с выражениями и в каком порядке движок разбирает циклы, условия и обычные подстановки в фигурных скобках.
isExp. Конкретный список констант на старте может отличаться у продукта; проверяйте подсказки редактора и документацию вашей среды.
Зачем вообще нужны константы
Сценарий — это цепочка шагов: отправить текст, прочитать строку таблицы, проверить условие, перейти к другой ветке. Чтобы следующий шаг опирался не на «воздух», а на факты предыдущих, все промежуточные значения складываются в общий набор данных.
Константа здесь — не «неизменяемая величина из учебника по C++», а именованный слот в этом наборе: строка, число, да/нет, список или структура с полями. В шаблоне вы ссылаетесь на неё по имени в фигурных скобках и подставляете в сообщение имя клиента, найденную строку, флаг из условия и т.д.
Откуда берутся значения и как они идут по цепочке
Старт и событие Update
Набор констант обычно формируется на событии Update: пользователь написал боту, нажал кнопку, пришло системное событие и т.п. В «стартовый» пакет попадают, как минимум, сведения о боте и о пользователе, текущие дата и время в часовом поясе бота. Если дальше по цепочке подключены внешние сервисы, туда же могут попасть поля, которые вы явно запрашиваете или пробрасываете сценарием.
Каждый блок в цепочке
Логика простая и предсказуемая:
- блок получает актуальный набор констант;
- выполняет свою работу;
- часто дописывает или перезаписывает значения;
- передаёт набор следующему блоку.
Если имя уже было, а вы записали его снова, побеждает последняя запись: вы всегда смотрите на свежий результат последнего шага, который успел изменить этот ключ.
Поля с поддержкой выражений (isExp)
Не в каждом поле редактора разрешены шаблоны. Если у параметра включена поддержка выражений (в интерфейсе это часто подписано как «выражение» или «шаблон»,
в технических материалах — isExp), то внутри строки работают подстановки вроде {ПРЕФИКС.ТИП.ИМЯ} и специальные блоки вроде {#IF}.
Выключено — текст чаще всего уходит на выполнение «как есть», без подстановок. Перед тем как вставить длинное {MAIN.STRING…}
или условие {#IF}, имеет смысл глянуть на переключатель режима поля: иначе фигурные скобки могут уехать к пользователю буквально.
Как выглядит имя константы
Общий вид ключа — три части через две точки (ровно две, не больше и не меньше в типичной схеме):
{ПрефиксКомпонента.Тип.Имя}
Средняя часть — тип данных. Чаще всего встречаются:
STRING— обычный текст;ARRAY— список или объект с полями (удобно для строк таблицы, каталогов);BOOL— да/нет, в том числе результат пункта условия.
Иллюстративные примеры (имена могут отличаться в вашем продукте):
# STRING — строка
{MAIN.STRING.USER_TELEGRAM_ID}
# ARRAY — строка таблицы, список или объект
{DATA.ARRAY.CURRENT_ROW}
# BOOL — результат условия (идентификатор пункта в имени)
{MAIN.BOOL.CONDITION_12_RESULT}
Подсказки редактора, которые подставляют готовый ключ в поле, обычно строятся по тому же принципу: префикс, тип, имя.
Работа с ARRAY
Вывести значение целиком
Если написать только имя без индексов и путей, в текст попадёт «сырое» представление — нередко это одна длинная строка в формате JSON. Удобно для отладки; для клиентского сообщения так делают реже.
Допустим, в {DATA.ARRAY.USER} лежит:
[
{
"name": "Анна",
"id": 10
},
{
"name": "Борис",
"id": 20
}
]
Шаблон целиком без индексов:
Данные: {DATA.ARRAY.USER}
В сообщение попадёт длинная строка с JSON всего массива — удобно сверить структуру при отладке.
Доступ к полю или элементу
После имени константы указывают шаги в квадратных скобках: индекс элемента или имя поля.
# индекс 0, поле name (в кавычках)
{DATA.ARRAY.USER}[0]['name']
→ Анна
# индекс 1, поле NAME (регистр имени поля часто не важен)
{DATA.ARRAY.USER}[1][NAME]
→ Борис
Если путь неверный (нет индекса или ключа), фрагмент может остаться в тексте в том виде, как вы его набрали — это сигнал проверить и данные, и запись пути.
Вложенность
Для вложенных объектов и списков скобки чередуются по уровню, например:
{DATA.ARRAY.ORDER}['items'][0]['title']
Смысл: заказ → список позиций → первая позиция → заголовок.
Порядок обработки текста в поле с выражениями
Если выражения включены, разбор идёт в фиксированном порядке:
- Циклы — повтор фрагмента по элементам массива.
- Условия — ветвление «если / иначе».
- Дата и время — сдвиг от заданной точки на шкале времени.
- Математика — вычисление формулы.
- Обычные подстановки всех
{…}и путей к полям массива.
Отсюда следует практическое следствие: нельзя рассчитывать, что сначала «везде подставятся константы», а уже потом сработает условие. Сначала раскрываются циклы и условия (с учётом вложенности), и только после этого — «простые» фигурные скобки.
1. {#EACH} … {/EACH} — циклы по массиву
2. {#IF} … {#ELSE} … {/IF} — условия
3. {#DATETIME; … ; …} — дата и время
4. {#MATH} … {/MATH} — формулы
5. {ПРЕФИКС.ТИП.ИМЯ} и пути — обычные подстановки и [...]
Специальные конструкции: данные → шаблон → результат
7.1. Цикл {#EACH} … {/EACH}
В {DEMO.ARRAY.PRODUCTS} лежит, например:
[
{
"title": "Яблоко",
"price": 50
},
{
"title": "Груша",
"price": 70
}
]
Шаблон с циклом (разбит на строки для читаемости; в поле можно писать и в одну линию):
Каталог:
{#EACH {DEMO.ARRAY.PRODUCTS} @N as P}
{P}['title'] — {P}['price'] руб.;
{/EACH}
Каталог: Яблоко — 50 руб.; Груша — 70 руб.;
На выходе по смыслу строка выше. В заголовке цикла задают массив, имя для номера строки (@N)
и имя текущего элемента (P); внутри тела используют {@N}, {P}['поле'] и при необходимости другие константы.
Если по ключу не массив или разметка цикла с ошибкой, текст может не измениться или цикл просто не выполнится.
7.2. Условие {#IF} … {#ELSE} … {/IF}
Тот же массив из двух товаров. Шаблон:
{#IF LEN({DEMO.ARRAY.PRODUCTS}) > 0}
В каталоге есть позиции
{#ELSE}
Каталог пуст
{/IF}
В каталоге есть позиции
Каталог пуст
Что допустимо в выражении {#IF}
Текст условия — от ключевого слова {#IF} до границы ветки ({#ELSE} или {/IF}) — разбирается как отдельное выражение.
Ниже перечислены типичные элементы грамматики; точный набор может зависеть от версии редактора, но перечисленное совпадает с тем, как парсер обычно ожидает лексемы «в лоб», без скрытых синонимов.
| Категория | Элементы |
|---|---|
| Сравнения | ==, !=, >, <, >=, <= |
| Логика | AND, OR — только в верхнем регистре, как в парсере. Слева и справа от токена не должно быть букв или цифр: иначе подстрока вроде SCORE или ORDER не считается разделителем и ломает разбор. |
| Скобки | ( ) — группировка и вложенность подвыражений. |
| Литералы | true и false; числа — целые и с десятичной точкой; строки в одинарных '…' или двойных "…" кавычках. Внутри строки допускается экранирование \' и \". |
| Ссылки на константы | Ключ {КОМПОНЕНТ.ТИП.ИМЯ} с необязательным путём […]. До вычисления самого условия такие вставки подставляются как литералы: строка в кавычках, число, true/false. Если значения нет, подставляется пустая строка ''. |
| Функции | LEN({…}[путь]) — для массива возвращает длину массива, иначе длину строкового представления скаляра. EMPTY({…}[путь]) даёт true, если значение null, пустая строка или пустой массив []. Эти вызовы разбираются до подстановки путей внутри аргумента функции. |
Практический вывод: пишите AND/OR заглавными и отделяйте их пробелами от имён полей и констант; проверяйте кавычки в строках и экранирование.
Для отладки сложного условия временно выведите промежуточные куски в отдельное поле или упростите выражение скобками, пока не убедитесь, что литералы и ссылки подставляются так, как вы ожидаете.
7.3. Дата и время {#DATETIME}
Блок ожидает корректно заполненную структуру момента времени: дата, время, зона, метка — в том виде, в каком её отдаёт константа.
Смысл шаблона: взять момент, например из {MAIN.ARRAY.EVENT}['start'], прибавить смещение (например, два дня) и получить одну строку результата.
Нет данных или неверный формат — вместо даты вы часто увидите служебное сообщение в квадратных скобках: так проще отловить ошибку в черновике или при отладке.
{#DATETIME;
…параметры источника (константа с моментом времени)… ;
…смещение и формат вывода…
}
Модификатор сдвига: знак + или -, затем целое число, затем одна из единиц (латиницей, как в парсере):
| Единица | Смысл |
|---|---|
days | сдвиг на N календарных дней |
weeks | сдвиг на N недель |
hours | сдвиг на N часов |
minutes | сдвиг на N минут |
Пример смысла: + 2 days — вперёд на два дня, - 1 weeks — назад на одну неделю (точный вид записи в третьей части {#DATETIME;…;…} задаёт ваш редактор).
Остальной синтаксис блока и формат строки результата могут отличаться между версиями; главное — корректный момент в константе-источнике и согласованная запись модификатора.
7.4. Математика {#MATH} … {/MATH}
В {DATA.ARRAY.LINE} лежит объект:
{
"qty": 3,
"price": 100
}
Шаблон:
К оплате:
{#MATH}
{DATA.ARRAY.LINE}['qty'] * {DATA.ARRAY.LINE}['price']
{/MATH}
руб.
К оплате: 300 руб.
Типичный набор операций внутри формулы:
| Операция | Вид |
|---|---|
| Сложение / вычитание | + и - |
| Умножение / деление | * и / |
| Степень | ^ |
| Унарный плюс и минус | перед числом или выражением в скобках |
| Скобки | ( ) |
| Округление | функции ROUND, CEIL, FLOOR (где второй аргумент задаёт знаки после запятой — если это поддерживается) |
Ссылки {…}['поле'] внутри MATH должны давать число или строку, которую можно прочитать как число.
Иначе вместо результата вы увидите блок с пометкой ошибки внутри {#MATH}…{/MATH} — например, при делении на ноль или при «пустом» значении.
Что может пойти не так
Спецблоки разбираются до обычных подстановок; при ошибке разметки или данных вы чаще всего получаете либо «немой» текст как в редакторе, либо явное сообщение в квадратных скобках, либо внутри {#MATH} — префикс #ERROR с пояснением.
Ниже сведены типичные случаи по каждой конструкции.
Таблица ошибок спецконструкций
{#EACH}
| Ситуация | Поведение / что увидит пользователь |
|---|---|
Нет закрывающего {/EACH} или сломан синтаксис заголовка цикла |
Цикл не выполняется, текст может остаться как написан в поле |
| По ключу не массив или значение отсутствует | Тело цикла не размножается; исходный блок или его часть остаётся без изменений |
| Вложенные циклы расставлены неверно | Неверное сопоставление открывающих и закрывающих тегов; фрагмент не обрабатывается как цикл |
{#IF} / {#ELSE} / {/IF}
| Ситуация | Поведение |
|---|---|
Нет закрывающей } у {#IF или нет {/IF} |
В текст вставляется сообщение об ошибке в квадратных скобках (префикс вроде «ошибка IF/ELSE» — формулировка зависит от продукта) |
| Выражение после подстановки констант не парсится | То же: явная ошибка в квадратных скобках; возможен список строк для отладки |
| Пустое или некорректное сравнение | Ошибка выражения в тексте или ложная ветка — в зависимости от правил парсера |
{#DATETIME;…}
| Ситуация | Поведение |
|---|---|
| Нет значения по пути, пусто | Сообщение об ошибке в квадратных скобках (префикс «ошибка DATETIME» или аналог) |
| Не тот набор полей (не схема «дата + время + зона + timestamp») | Сообщение: значение не соответствует ожидаемой структуре |
| Неверный часовой пояс или невалидные поля даты/времени | Сообщение о неверном формате или зоне |
{#MATH}…{/MATH}
| Ситуация | Поведение |
|---|---|
| Ссылка на константу не найдена | Блок заменяется на вариант с #ERROR и текстом причины внутри границ MATH |
| По пути лежит массив или не число | То же: #ERROR с пояснением |
| После подстановки выражение некорректно (скобки, лишние символы) | #ERROR с текстом от парсера |
| Деление на ноль | #ERROR, явное указание деления на ноль |
Неизвестная функция или неверное число аргументов у ROUND / CEIL / FLOOR |
#ERROR с соответствующим текстом |
Константы и данные вне спецблоков
| Ситуация | Что увидите |
|---|---|
| Опечатка в имени обычной константы | Имя может остаться буквально; для ARRAY — проверьте имя и тип |
ARRAY: битый JSON или пусто | Часть текста может исчезнуть или обнулиться — смотрите источник данных |
Практические советы
- Сначала убедитесь, что предыдущий блок действительно пишет нужную константу — по названию блока и подсказкам поля.
- Шаблоны с подстановками вставляйте только туда, где включены выражения.
- Для массивов сверяйте реальную форму: список или объект, точные имена полей; для проверки временно выведите константу целиком.
- Сложную разметку дробите на шаги: отдельно условие или цикл, отдельно «чистый» текст с простыми
STRING. - Квадратные скобки с текстом ошибки в сообщении чаще всего указывают на условие или дату/время, а не на «полный отказ» бота.
Краткий глоссарий
| Термин | Значение |
|---|---|
| Константа | Именованное значение в общем наборе данных сценария |
| Ключ | Строка вида {A.B.C} с двумя точками между частями |
| Update | Событие, с которого обычно стартует набор констант |
STRING / ARRAY / BOOL | Тип в середине имени |
| Выражение в поле | Режим, когда разрешены {…} и спецблоки |
| Спецблок | {#EACH}, {#IF}, {#DATETIME}, {#MATH} |