Шаблоны, вставки и варианты
Recipe собирает страницу из повторно используемых шаблонов и фрагментов и выбирает варианты по настройкам. Эта глава описывает словарь Recipe и правила вставки, выбора и ссылок.
Словарь Recipe
Recipe (simai.composition.recipe) содержит пять понятий.
| Понятие | Что это |
|---|---|
| Шаблон (template) | общая форма страницы или секции с параметрами и именованными местами вставки |
| Фрагмент (fragment) | повторно используемая часть без параметров и мест вставки |
| Место вставки (insertSlot) | точка внутри шаблона, куда вызывающий передаёт содержимое |
| Выбор (select) | выбор одной ветви по значению настройки |
| Вход (input) | объявленное значение извне: параметр, настройка сайта или содержимое |
Если повторяемая часть должна принимать параметры или вложенные элементы, это шаблон, как бы она ни называлась в библиотеке. Ссылка на фрагмент с параметрами — ошибка. Так у каждого вида источника ровно одна проверяемая форма.
Записи Recipe
Каждая запись дерева Recipe — ровно одно из трёх, всегда вместе с id:
node— обычный узел будущего Document;ref— ссылка на шаблон или фрагмент;select— выбор ветви.
Внутри слота узла допустима ещё одна запись — insertSlot, место вставки
шаблона (см. Словарь Recipe). Корнем Recipe она быть не может.
Значения внутри узла тоже обёрнуты одной оболочкой: literal (готовое JSON,
без подстановок внутри), input (объявленный вход Recipe) или parameter
(параметр ближайшего вызова шаблона). Ни преобразования типов, ни вычисления
выражений нет.
Пример: статья с двумя шапками
Шаблон статьи объявляет места вставки header и main. Recipe передаёт в
header выбор между краткой и расширенной шапкой, а в main — текст статьи:
"slots": {
"header": [{
"id": "header-choice",
"select": {
"value": {"input": "headerMode"},
"cases": {
"compact": {"id": "chosen-header", "ref": {"kind": "fragment", "owner": "example/library",
"ref": "header.compact", "policy": "pinned", "revision": "r1"}},
"expanded": {"id": "chosen-header", "ref": {"kind": "fragment", "owner": "example/library",
"ref": "header.expanded", "policy": "pinned", "revision": "r1"}}
}
}
}],
"main": [{
"id": "body",
"node": {
"type": "content.paragraph",
"data": {"content": {"input": "body"}},
"bindings": [{"input": "body", "target": "content"}]
}
}]
}
При headerMode = expanded Document выглядит так: страница → секция с
заголовком «Расширенная шапка» и строкой «Дополнительная строка шапки» →
абзац с текстом статьи. При compact строки нет. Обратите внимание: в
Document нет команды «выбери вариант» — выбор уже сделан.
Полный Recipe, источники и ожидаемые результаты обоих режимов — в проверяемом JSON; работающий пример — в главе Пример: статья с двумя шапками.
Правила вставки
- Переданный слот заменяет содержимое по умолчанию из шаблона.
- Отсутствующий слот использует содержимое по умолчанию.
- Пустой массив
[]намеренно очищает место. - Переданный, но нигде не использованный слот — ошибка: иначе потерялись бы данные автора.
- Ограничения слота проверяются после раскрытия, а затем ещё раз по манифесту конечного типа.
Правила выбора
- Значение выбора — строка из заранее перечисленного набора. Условий на JavaScript в Recipe нет.
- Если вход не передан, берётся его значение по умолчанию; затем — явная
ветвь
missingCase. - Неизвестное значение, отказ доступа или ошибка источника — ошибка, а не тихий переход к ветви по умолчанию.
- Синтаксис проверяется у всех ветвей, а источник читается только у выбранной: Framework загружает источник только активного варианта. Поэтому правка неиспользуемой шапки не заставляет пересобирать страницу.
Закреплённые и следующие ссылки
Ссылка на шаблон или фрагмент называет владельца, имя и политику:
pinned(рекомендуемый выбор) — точная ревизия в полеrevision; несовпадение даётrevision_mismatch;follow-published— следовать за опубликованной ревизией через указательpointer. Это явный выбор, и он попадает в перечень зависимостей отдельной записью.
Поле policy обязательно: ссылка без него отклоняется.
Ссылка, которая прямо или косвенно ведёт сама на себя, даёт reference_cycle
с полной цепочкой вызовов.
Устойчивые идентификаторы
Каждый узел Document получает идентификатор, вычисленный из пути сборки:
n- и SHA-256 от идентификатора Recipe и цепочки шагов (узел, ссылка, выбор,
слот, вставка). Следствия:
- перестановка соседей сохраняет идентификаторы;
- перенос узла в другое место меняет идентификатор;
- ревизия источника в идентификатор не входит — обновление шаблона не ломает ссылки на узлы.
Recipe как содержимое страницы сайта
Recipe может быть содержимым обычной страницы сайта документации. В Docara Markdown-файл страницы хранит только заголовок и путь к JSON-описанию:
---
title: Каталог товаров
composition_recipe: composition/catalog/descriptor.json
---
При сборке Docara получает HTML через модуль композиции из закреплённой поставки Framework, а затем добавляет обычную оболочку документации: меню, тему, поиск и навигацию. Исходники Framework для этого не нужны.
Смотрите также
- Как проходит сборка — путь сборки.
- Входы и источники данных — входы Recipe.
- Снимки и кеш — перечень зависимостей.
- Диагностика — диагностика.