Перейти к содержимому

10. Описания

Описание — это голая строка в любом теле: модуля, фасета, интерфейса, проекции, процесса. Рендереры обращаются с текстом описания как с markdown с двумя расширениями: перекрёстные ссылки ([[…]]) и интерполяция меток (@…). Они появляются везде, где показываются описания: всплывающие подсказки, документация автодополнения, боковые панели, тела виджетов.

module Payments {
team: Payments
labels {
domain: Payments
security.zone: PCI
}
"
# Payments
Core payment processor for the **@domain** domain, operating
in the *@security.zone* zone. Published events are consumed
by [[Orders]] and [[Notifications]].
> Every transaction in the platform flows through this service.
"
interface Authorize
interface Refund
}

Описание рендерится с markdown-форматированием, с подставленными @domain и @security.zone, и с [[Orders]] и [[Notifications]], отрендеренными как кликабельные ссылки на соответствующие модули.

Подмножество markdown

Поддерживаются следующие конструкции CommonMark:

КонструкцияПример
Жирный**bold**
Курсив*italic*
Зачёркивание~~struck~~
Встроенный код`code`
Заголовки# H1, ## H2, ### H3
Спискиупорядоченные, неупорядоченные, вложенные
Таблицытаблицы на вертикальных чертах в стиле GFM
Цитаты> note
Блоки кодаогороженные тройными обратными кавычками, опционально с языком
Горизонтальная линия---
Внешние ссылки[text](https://...)

Следующее не поддерживается и либо рендерится как литеральный текст, либо вырезается:

  • Сырой HTML (граница безопасности — рендереры агрессивно очищают).
  • Изображения (описания — это текст; визуальное место в виджетах и проекциях).
  • Сноски, списки определений, списки задач.
  • Автоматическое связывание голых URL (используйте явное [text](url)).

Один ранг заголовков

Заголовки (#, ##, ###) все рендерятся с одинаковым визуальным рангом. У описаний один уровень заголовков; глубина не несёт семантического веса. Вы вольны использовать несколько # для читаемости исходника, но не полагайтесь на визуальную иерархию между H1 и H3.

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

Перекрёстные ссылки: [[…]]

[[…]] ссылается на другое объявление в модели. Две формы:

По стабильному идентификатору:

"Routes to [[#pay002]] for downstream processing."

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

По человекочитаемому имени:

"Published events are consumed by [[Orders]] and [[Notifications]]."

Разрешается по всему рабочему пространству. Если два объявления имеют общее имя, ссылка неоднозначна — рендерер помечает её как ошибку, а LSP выдаёт диагностику с перечислением кандидатов. Снимите неоднозначность, переключившись на форму с идентификатором.

Имена могут быть с пространством имён; форма с пространством имён сопоставляется целиком:

"See [[Personal.Banking.Payments]] for the legacy path."

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

Интерполяция меток: @…

@labelPath подставляет значение метки, объявленной на (или каскадированной в) тот же узел, к которому прикреплено описание. Путь зеркалит форму квалифицированного имени, используемую в labels { }:

module Payments {
labels {
domain: Payments
sla.tier: gold
}
"Owned by @team. SLA tier: @sla.tier. Operates in @domain."
}

Рендерится примерно как: «Owned by Payments. SLA tier: gold. Operates in Payments.»

Разрешение идёт по цепочке типов — если узел не объявляет метку сам, но наследует её от родительского типа, используется унаследованное значение.

Локальная область видимости

@ читает метки на владеющем узле, никогда — на узлах, на которые есть ссылки:

module A {
labels { domain: Sales }
"Domain: @domain" // resolves to "Sales"
}
module B {
labels { domain: Ops }
"Other module's domain: @domain" // resolves to "Ops" (B's own label),
// NOT A's domain
}

Описание на модуле A не может читать метки на модуле B. Для межузлового доступа используйте [[B]] — но ссылка не интерполирует.

Отсутствующие метки всплывают

Если @labelPath не разрешается, рендерер выводит литеральную метку-страж <missing:labelPath>, а LSP выдаёт предупреждение в месте интерполяции. Тихий откат к пустой строке запрещён — опечатки и устаревшие ссылки обязаны быть видимы.

module C {
"Owner: @owner" // no 'owner' label declared or inherited
}

Рендерится как: «Owner: <missing:owner>» с предупреждением LSP.

Несколько описаний склеиваются

В теле может быть несколько голых строк. Они соединяются через \n в порядке объявления:

module Payments {
"First paragraph about the service."
team: Payments
"Second paragraph, declared after the team field. Order in the source
doesn't matter for resolution but does matter for description joining."
interface Authorize
}

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

Разобранный пример

Реальное описание из демо Payments:

module #pay001 Payments {
team: Payments
labels {
domain: Payments
security.zone: PCI
criticality: High
}
"
Core **payment processing** service for the *@domain* domain.
Operates in the `@security.zone` zone with criticality *@criticality*.
> Every transaction in the platform flows through this service
> before reaching an external processor.
**Capabilities.** Authorize, capture, and refund transactions;
route to processors via [[#pay002]]; publish `PaymentEvents`
consumed by [[Orders]] and [[Notifications]].
**Compliance.** PCI-DSS scope. See the
[internal runbook](https://wiki.acme.com/pci).
"
interface Authorize
interface Refund
interface PaymentEvents
}

Это рендерится как полная markdown-карточка с подстановками меток и живыми перекрёстными ссылками на #pay002, Orders и Notifications.

Где живёт резолвер

Резолвер перекрёстных ссылок и интерполятор меток — часть пакета core, а не только LSP. И LSP (для диагностик и всплывающих подсказок), и клиентские просмотрщики (для рендеринга) используют один и тот же резолвер. Итог: описания выглядят идентично везде, где они показываются.

Итоги

  • Описания — голые строки, обрабатываемые как markdown с двумя расширениями Archlang.
  • [[#id]] и [[Name]] ссылаются на другие объявления.
  • @labelPath подставляет значение метки на том же узле.
  • Заголовки все рендерятся с одним рангом; сырой HTML и изображения не поддерживаются.
  • Отсутствующие ссылки и отсутствующие пути меток всплывают как ошибки, никогда не тихо.
  • Несколько описаний голыми строками склеиваются.

Что дальше

Глава 11: Стандартная библиотека → — от базовых видов к service, command, event и остальной лексике стандартной библиотеки.