Редактор сценариев
Для настройки без программирования

Константы в сценарии бота: полное руководство

Материал для тех, кто собирает логику из блоков: что именно называется константой, откуда она попадает в сценарий, как не ошибиться в полях с выражениями и в каком порядке движок разбирает циклы, условия и обычные подстановки в фигурных скобках.

Ниже — правила именования и поведения шаблонов в том виде, в каком их обычно описывают в редакторах с поддержкой isExp. Конкретный список констант на старте может отличаться у продукта; проверяйте подсказки редактора и документацию вашей среды.

Зачем вообще нужны константы

Сценарий — это цепочка шагов: отправить текст, прочитать строку таблицы, проверить условие, перейти к другой ветке. Чтобы следующий шаг опирался не на «воздух», а на факты предыдущих, все промежуточные значения складываются в общий набор данных.

Константа здесь — не «неизменяемая величина из учебника по C++», а именованный слот в этом наборе: строка, число, да/нет, список или структура с полями. В шаблоне вы ссылаетесь на неё по имени в фигурных скобках и подставляете в сообщение имя клиента, найденную строку, флаг из условия и т.д.

Откуда берутся значения и как они идут по цепочке

Старт и событие Update

Набор констант обычно формируется на событии Update: пользователь написал боту, нажал кнопку, пришло системное событие и т.п. В «стартовый» пакет попадают, как минимум, сведения о боте и о пользователе, текущие дата и время в часовом поясе бота. Если дальше по цепочке подключены внешние сервисы, туда же могут попасть поля, которые вы явно запрашиваете или пробрасываете сценарием.

Каждый блок в цепочке

Логика простая и предсказуемая:

  1. блок получает актуальный набор констант;
  2. выполняет свою работу;
  3. часто дописывает или перезаписывает значения;
  4. передаёт набор следующему блоку.

Если имя уже было, а вы записали его снова, побеждает последняя запись: вы всегда смотрите на свежий результат последнего шага, который успел изменить этот ключ.

Поля с поддержкой выражений (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} лежит:

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. Циклы — повтор фрагмента по элементам массива.
  2. Условия — ветвление «если / иначе».
  3. Дата и время — сдвиг от заданной точки на шкале времени.
  4. Математика — вычисление формулы.
  5. Обычные подстановки всех {…} и путей к полям массива.

Отсюда следует практическое следствие: нельзя рассчитывать, что сначала «везде подставятся константы», а уже потом сработает условие. Сначала раскрываются циклы и условия (с учётом вложенности), и только после этого — «простые» фигурные скобки.

Порядок шагов движка
1. {#EACH} … {/EACH}          — циклы по массиву
2. {#IF} … {#ELSE} … {/IF}   — условия
3. {#DATETIME; … ; …}        — дата и время
4. {#MATH} … {/MATH}         — формулы
5. {ПРЕФИКС.ТИП.ИМЯ} и пути  — обычные подстановки и [...]

Специальные конструкции: данные → шаблон → результат

7.1. Цикл {#EACH}{/EACH}

В {DEMO.ARRAY.PRODUCTS} лежит, например:

JSON · DEMO.ARRAY.PRODUCTS
[
  {
    "title": "Яблоко",
    "price": 50
  },
  {
    "title": "Груша",
    "price": 70
  }
]

Шаблон с циклом (разбит на строки для читаемости; в поле можно писать и в одну линию):

Шаблон · {#EACH}
Каталог:
{#EACH {DEMO.ARRAY.PRODUCTS} @N as P}
  {P}['title'] — {P}['price'] руб.;
{/EACH}
Результат
Каталог: Яблоко — 50 руб.; Груша — 70 руб.;

На выходе по смыслу строка выше. В заголовке цикла задают массив, имя для номера строки (@N) и имя текущего элемента (P); внутри тела используют {@N}, {P}['поле'] и при необходимости другие константы.

Если по ключу не массив или разметка цикла с ошибкой, текст может не измениться или цикл просто не выполнится.

7.2. Условие {#IF}{#ELSE}{/IF}

Тот же массив из двух товаров. Шаблон:

Шаблон · {#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}
{#DATETIME;
  …параметры источника (константа с моментом времени)… ;
  …смещение и формат вывода…
}

Модификатор сдвига: знак + или -, затем целое число, затем одна из единиц (латиницей, как в парсере):

ЕдиницаСмысл
daysсдвиг на N календарных дней
weeksсдвиг на N недель
hoursсдвиг на N часов
minutesсдвиг на N минут

Пример смысла: + 2 days — вперёд на два дня, - 1 weeks — назад на одну неделю (точный вид записи в третьей части {#DATETIME;…;…} задаёт ваш редактор). Остальной синтаксис блока и формат строки результата могут отличаться между версиями; главное — корректный момент в константе-источнике и согласованная запись модификатора.

7.4. Математика {#MATH}{/MATH}

В {DATA.ARRAY.LINE} лежит объект:

JSON · DATA.ARRAY.LINE
{
  "qty": 3,
  "price": 100
}

Шаблон:

Шаблон · {#MATH}
К оплате:
{#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}