---
url: https://docs.juniper.bot/message-templates/advanced/tags.md
description: Описание всех доступных тегов шаблонного движка JuniperBot
---

# Теги

Теги — набор различных встроенных конструкций и операций над шаблоном. Они объявляются с помощью [островков кода](code-islands) и
определяют поведение шаблона.

::: tip Рекомендация
Перед изучением тегов рекомендуется ознакомиться со статьями [Типы данных](../types/index) и [Конвертация типов](../types/type-convert).
:::

## Команды { #commands }

Теги команд выполняют какую-либо операцию, но ничего не печатают в результат шаблона.

### `set`

Команда `set` является операцией присваивания переменной в шаблоне. Она вычислит результат выражения и запишет его в
переменную с указанным названием:

```template
{% set five = 2 + 3 %}
```

В примере выше результат вычисления `2 + 3` (`5`) будет записан в переменную `five`.

Команда `set` также поддерживает составные операторы присваивания, используя основные [бинарные операторы](expressions#binary) для
арифметических операций (`+`, `-`, `*`, `**`, `/`, `//`) и объединения строк (`~`):

```template
{% set value = 2 %}
{% set value += 3 %}
```

В примере выше результирующее значение переменной будет равно 5.

Название переменной является [идентификатором](expressions#identifiers) и может содержать только латинские буквы, цифры и
нижнее подчеркивание, но не может начинаться с цифры.

`set` как команда не генерирует контент, она просто объявляет переменную или перезаписывает существующую переменную с
этим именем.

### `global`

Переменные, объявленные командой `set`, имеют локальную область видимости и будут доступны только в шаблоне, в котором
они были объявлены. Команда `global` позволяет объявить переменную глобально.

Это значит, что эта переменная будет доступна в последующих интерпретируемых шаблонах этого сообщения, в
[макросах](#macro) и в действии, вызываемом через [`run`](#run). Например, переменная, определенная глобальной в
шаблоне сообщения станет сразу доступна в шаблоне панели.

```template
{% global six = 3 + 3 %}
```

В примере выше результат вычисления `3 + 3` (`6`) будет записан в переменную `six` и доступен глобально.

::: tip Локальное переопределение

Переменная, объявленная командой `set`, имеет локальную область видимости, поэтому она может переопределить значение
переменной, ранее объявленное командой `global` с таким же названием. Она не перезапишет значение глобальной переменной,
а именно что переопределит его.

Сбросить переопределённое значение `set` и вернуть переменной её глобальное значение можно, указав этой переменной
неопределённое значение, например, названием любой несуществующей переменной:

```template
{% global value = 'global_value' %}
{{ value }}
{# ^ распечатает "global_value" #}
{% set value = 'set_value' %}
{{ value }}
{# ^ распечатает "set_value" #}
{% set value = undefined %}
{# ^ "undefined" может быть название любой несуществующей переменной #}
{{ value }}
{# ^ распечатает "global_value" #}
```

:::

### `do`

Команда `do` вычисляет указанное выражение, не печатая ничего в шаблон.

```template
{% do channel.sendMessage('My message!') %}
```

Данная команда может быть полезна для тихого вызова каких-либо функций или методов у объектов.

### `require`

Команда `require` является расширением тэга [`return`](#return) и выглядит следующим образом:

```template
{% require выражение returning 'Произошла какая-то ошибка' %}
```

Эта команда вернет ошибку если результат вычисления выражения будет равен:

* `null`;
* `undefined`;
* `false`;
* пустая строка;
* `0`.

Вместо строки можно передать заполненный [Embed](../types/discord/embed) (но НЕ отправляя его методом `send`).

Будучи расширением тэга [`return`](#return), данная команда имеет аналогичное поведение в [трансформациях](#transforms) и [макросах](#macro).

### `use`

Команда `use` включает дополнительную функциональность шаблонного движка или меняет его поведение.

#### strict

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

* Попытка вывести неопределённую переменную;
* Попытка обратиться к несуществующему свойству объекта;
* Попытка вызвать несуществующую функцию, метод объекта или с некорректно переданными в неё аргументами.

Строгий режим включается следующим образом:

```template
{% use 'strict' %}
```

### `run`

Команда `run` используется для запуска указанного [Действия](../../cmd/custom/actions/index) с передачей в него параметров (опционально).
Эта операция полностью прервёт текущее выполняемое действие.

::: warning Внимание
Данный тег работает только в [Действиях](../../cmd/custom/actions/index) пользовательских команд для "маршрутизации" одного действия в другое.
:::

Используйте UUID действия для его запуска:

```template
{% run 'aebf9ae8-c62a-4348-b153-a7c0a0173da1' %}
```

::: info Информация
Вы можете получить этот UUID из самого действия в настройках команды (нажмите иконку "i").

Оба действия должны быть частью одной команды, т.е. действие команды А не может быть запущено из действия команды Б.
:::

Для передачи параметров в запускаемое действие используйте следующий синтаксис:

```template
{% run 'aebf9ae8-c62a-4348-b153-a7c0a0173da1' with { 'param1': 123 } %}
```

Выражение после `with` на самом деле просто [карта](../types/index#maps), поэтому можно указать там объявленную ранее переменную карты.
Эти параметры будут доступны как часть переменной [parameters](../types/custom-commands/parameters) в запускаемом действии:

```template
{{ parameters.param1 }}
```

Шаблон выше распечатает `123` в запускаемом действии.

Вы также можете использовать сам [parameters](../types/custom-commands/parameters) в родительском действии для передачи данных в дочернее.
Следующий пример сделает абсолютно то же самое, как и предыдущий, просто другим способом:

```template
{% do parameters.store('param1', 123) %}
{% run 'aebf9ae8-c62a-4348-b153-a7c0a0173da1' %}
```

::: warning Внимание
Действия могут запускать друг друга цепочкой до трёх раз. Квоты методов при этом остаются общие для всей цепочки.
:::

## Управляющие конструкции { #control }

Шаблонный движок JuniperBot реализует базовые управляющие конструкции: условия и циклы

### Условия — `if/elseif/else` { #if }

Условие — самая простая управляющая конструкция. Здесь поддерживаются последовательные конструкции `elseif`, а также
распространённую конструкцию `else`.

```template
{% if (выражение) %}
... Блок вычисляется если "выражение" вычислено как true ...
{% elseif (другоеВыражение) %}
... Блок вычисляется если "другоеВыражение" вычислено как true,
 а так же "выражение" вычислено как false ...
{% else %}
... Блок вычисляется если ни одно из 
указанных условий не было удовлетворено ...
{% endif %}
```

Обратите внимание, что вся конструкция `if` выведет содержимое только первого блока, выражение которого будет вычислено
как `true` согласно правилам [Конвертации типов](../types/type-convert).

С точки зрения области видимости переменных, внутреннее содержимое блока `if` разделяет контекст с родительским
контекстом. Это означает, что условия могут влиять на переменные во внешней области видимости.

```template
{% set variable = "раз" %}
{% if (true) %}
    {% set variable = "два" %}
{% endif %}
{{ variable }}
```

Предыдущий пример генерирует сообщение `два`, что иллюстрирует как область видимости в условиях разделяет контекст с родительской конструкцией.

```template
{% if (1 != 2) %}
    {% return 'Один не равен двум. Внезапно!' %}
{% endif %}
А вот этот текст шаблон не выведет из-за ошибки.
```

Пример выше демонстрирует, как можно с помощью условия вернуть ошибку.

### Циклы — `for`  { #loops }

Поддерживаются циклы над списками или картами.

```template
{# Пример цикла над списком #}
{% for item in list %}
... Контент с использованием переменной item ...
{% endfor %}

{# Пример цикла над картой #}
{% for key, value in map %}
... Контент с использованием переменных key и value карты ...
{% endfor %}
```

Область видимости переменных-итераторов (`item`, `key`, `value` в примерах выше) ограничена лишь блоком цикла, даже если
их переопределять с помощью команды [`set`](#set).

#### Переменная `loop` { #loop-variable }

Циклы `for` объявляют дополнительную переменную с идентификатором `loop`. Она предоставляет доступ к полезным свойствам внутри цикла:

| Свойство    | Описание                                                                                |
|:------------|:----------------------------------------------------------------------------------------|
| `length`    | Размер списка или карты                                                                 |
| `index`     | Номер текущей итерации, начинающийся с 1                                                |
| `index0`    | Номер текущей итерации, начинающийся с 0                                                |
| `revindex`  | Количество оставшихся итераций до достижения конца списка или карты, заканчивается на 1 |
| `revindex0` | Количество оставшихся итераций до достижения конца списка или карты, заканчивается на 0 |
| `first`     | Свойство, равное `true` для самой первой итерации                                       |
| `last`      | Свойство, равное `true` для самой последней итерации                                    |
| `parent`    | Получение доступа к родительскому контексту                                             |

```template
{% for item in [1, 2, 3] %}
    {% if (loop.first) %}
        Начало
    {% endif %}
{% endfor %}
```

Предыдущий пример распечатает слово `Начало` только один раз во время первой итерации.

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

```template
{% set loop = 1 %}
{% for item in [1, 2, 3] %}
    {% if (loop.first) %}
        {{ loop.parent.loop }}
        {% set loop = 2 %}
    {% endif %}
{% endfor %}
{{ loop }}
```

Предыдущий пример распечатает `1 2`. Обратите внимание, что присваивание значения переменной `loop` внутри цикла не
перезаписывает `loop` самого цикла. Эта переменная далее будет доступна уже вне цикла.

::: warning Ограничения

1. Максимально допустимая вложенность циклов — 2;
2. Максимальное количество итераций цикла, включая итерации вложенных в него циклов — 3000.

:::

### Трансформации — `transform` { #transforms }

Трансформация - разновидность цикла `for`, используемая для преобразования одного списка в другой.
Каждая итерация такого цикла ожидает вызов тега `return` с указанием нового значения для соответствующего элемента списка:

```template
{% transform item in [1, 2, 3] as newList %}
    {% return 'element:' ~ item %}
{% endtransform %}
{{ newList }}
```

Предыдущий пример преобразует список `[1, 2, 3]` в `['element:1', 'element:2', 'element:3']` и сохранит в переменную `newList`.

В случае, если в рамках итерации тег `return` не был вызван, элемент списка пропускается.
Таким образом, используя трансформацию, можно отфильтровать список:

```template
{% transform item in [1, 2, 3] as newList %}
    {% if (item != 2) %}
        {% return item %}
    {% endif %}
{% endtransform %}
{{ newList }}
```

Предыдущий пример преобразует список `[1, 2, 3]` в `[1, 3]`, исключая из результата второй элемент согласно установленному условию.

::: info Информация
Трансформации наследуют все особенности работы циклов `for`, включая переменную `loop` и доступ к родительскому контексту.
:::

::: warning Внимание
Трансформации не могут использовать вложенные списки/карты, такие элементы будут исключены из результата трансформации. Другими словами, нельзя делать списки списков и списки карт.

Кроме этого, трансформации ничего не печатают в шаблон, все островки вывода внутри трансформаций игнорируются.
:::

### `break/continue` { #break-continue }

Вы можете прерывать выполнение итераций [циклов](#loops) и [трансформаций](#transforms), используя теги `break` и `continue`.

`break` прерывает текущую и все последующие итерации цикла:

```template
{% for item in [1, 2, 3, 4] %}
    start:{{item}}
    {% if (item > 2) %}
        {% break %}
    {% endif %}
    end:{{item}}
{% endfor %}
```

Предыдущий пример распечатает `start:1 end:1 start:2 end:2 start:3`, поскольку третья и все последующие итерации прерываются условием `item > 2`.

`continue` прерывает только текущую итерацию цикла:

```template
{% for item in [1, 2, 3] %}
    start:{{item}}
    {% if (item == 2) %}
        {% continue %}
    {% endif %}
    end:{{item}}
{% endfor %}
```

Предыдущий пример распечатает `start:1 end:1 start:2 start:3 end:3`. Обратите внимание на отсутствие части `end:2`, так как вторая итерация прерывается выполнением условия `item == 2`.

### `return`

Тег `return` прерывает генерацию шаблона и возвращает ошибку. Он также используется в [трансформациях](#transforms) и [макросах](#macro).

```template
{% return 'Произошла какая-то ошибка' %}
```

Вместо строки можно передать заполненный [Embed](../types/discord/embed) (но НЕ отправляя его функцией `send`).

Вы также можете передать `null`, это предотвратит отправку любого результата шаблона, включая любые ошибки:

```template
{% return null %}
```

## Прочее { #other }

### `macro`

Макросы — конструкции, позволяющие минимизировать дублирование однообразного кода шаблона.

Это достигается вынесением переиспользуемой части шаблона в именованную конструкцию `macro/endmacro`, которая также предоставляет возможность передачи внутрь каких-либо входных данных:

```template
{% macro macroName(firstArgument, secondArgument, ...) %}
  ... переиспользуемый шаблон ....
{% endmacro %}
```

#### Название макроса { #macro-name }

Названием макроса должен быть уникальный [идентификатор](expressions#identifiers). Макрос с конкретным названием может
быть определён только один раз, попытка повторно определить макрос с уже существующим названием приведёт к ошибке исполнения шаблона.

#### Аргументы макроса { #macro-arguments }

Аргументы макроса — список идентификаторов, представляющие собой входные переменные, которые можно использовать внутри макроса.
Список аргументов опционален, Вы можете создать макрос вообще без аргументов. Их передача так же опциональна.

#### Область видимости { #macro-scope }

Шаблон макроса имеет доступ к ограниченному числу переменных:

* Переданные в макрос аргументы;
* Переменные, объявленные [глобально](#global) на момент запуска макроса;
* Переменные, доступные в шаблоне по-умолчанию.

Обычные переменные, объявленные внутри макроса, доступны только в контексте выполнения этого макроса. [Глобальные](#global) будут ожидаемо доступны во всем шаблоне.

#### Запуск макроса { #macro-execute }

Объявленные макросы запускаются аналогично встроенным [функциям](functions). Их можно считать своего рода "пользовательскими функциями".

```template
{% macro fullname(firstName, lastName) %}
  {{ firstName ~ ' ' ~ lastName }}
{% endmacro %}

{{ fullname('Илон', 'Маск') }}
```

В данном примере мы создали простейший макрос для получения полного имени из двух входных переменных (имени и фамилии).
Результатом вызова макроса является строка, получившаяся в результате обработки шаблона этого макроса с указанными аргументами.

Кроме этого, Вы можете использовать тэг [return](#return) для случаев, когда макрос должен вернуть значение какой-либо конкретной переменной или выражения, например:

```template
{% macro fullname(firstName, lastName) %}
  Блаблабла
  {% return firstName ~ ' ' ~ lastName %}
{% endmacro %}

{{ fullname('Илон', 'Маск') }}
```

Результат выполнения этого шаблона будет аналогичен предыдущему. Обратите внимание на "Блаблабла" в шаблоне макроса.
В данном случае этот текст выведен не будет, поскольку макрос использует [return](#return) для возврата конкретных данных.

::: warning Внимание
Макросы не могут запускать другие макросы.
:::

### `include`

Данный тег используется для вставки глобального шаблона в текущий шаблон.
Для более подробной информации посетите статью [Глобальные шаблоны](../shared-templates).

```template
{% include 'my_template' %}
```

В данном примере мы вставили глобальный шаблон с названием `my_template`.

#### Область видимости { #include-scope }

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

Все объявленные в основном шаблоне переменные будут доступны внутри глобального шаблона, а все переменные,
объявленные внутри глобального шаблона, станут доступны в основном шаблоне после выполнения тэга `include`.

Однако, данное поведение можно изменить с помощью дополнительного ключа `scoped`:

```template
{% include 'my_template' scoped %}
```

В данном случае глобальный шаблон будет выполнен в собственном контексте. Он не будет иметь доступ к переменным,
объявленным в основном шаблоне, а переменные, созданные в процессе выполнения глобального шаблона, не будут
доступны в основном шаблоне.

::: warning "Внимание"
[Глобальные переменные](#global) и [макросы](#macro) являются исключением.

Даже в режиме `scoped` они будут доступны в глобальных шаблонах, и их объявление сделает их доступными в основном шаблоне.
:::

В случае, когда в режиме `scoped` всё же необходимо передать какие-то данные внутрь глобального шаблона,
можно использовать следующую конструкцию:

```template
{% include 'my_template' scoped with { 'param1': 123 } %}
```

Выражение после `with` на самом деле просто [карта](../types/index#maps), поэтому можно указать там объявленную ранее переменную карты.
Указанные данные будут доступны как обычные переменные внутри глобального шаблона.

В примере выше переменная `param1` будет иметь значение `123`.

### `filter`

Конструкция фильтра — ещё одна возможность применять [функции](functions) к указанному контенту.
Она использует содержимое указанного тела блока как аргумент для указанной функции.

```template
{% filter lower | capitalize -%}
HELLO WORLD
{%- endfilter %}
```

Предыдущий пример распечатает сообщение `Hello world`. Как мы видим, результатом фильтра является выполнение двух
функций над телом блока. Сперва фильтр применяет функцию `lower` к содержимому `HELLO WORLD`, генерируя `hello world`,
после этого применяет функцию `capitalize`, генерируя результирующее `Hello world`.

### `verbatim`

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

```template
{% verbatim %}
{{ test }}
{% endverbatim %}
```

Предыдущий пример распечатает сообщение `{{ test }}`.
