Перейти к содержанию

Правила написания и форматирования текста комментариев

С 2026-05-13 (MR'ы spa!903 + spa!904, задачи #2038789 + #2075762) парсер SPA понимает стандартный CommonMark/GFM. iOS и Android — пока на старом подмножестве (отдельная задача).


1. Поддерживаемое форматирование

Синтаксис Результат SPA лента SPA чат iOS Android
**текст** Жирный + + + +
__текст__ Курсив (нестандарт: в CommonMark __ = жирный) + + + +
~~текст~~ Зачёркнутый + + + +
((текст)) Подчёркнутый (нестандарт) + + + +
`текст` Inline-код, моноширинный + + + +
[текст](url) Именованная ссылка + + + +
# текст / ## текст / ### текст Заголовок → <strong> (без увеличения размера, как акцент) + +
```...``` Fenced code блок (моноширинный, с padding'ом) + +
\| a \| b \|
\| --- \| --- \|
\| 1 \| 2 \|
GFM-таблица → <table> с border, header row. Ширина: в ленте/МТФ растягивается по ширине контейнера ленты (на узком/мобильном экране — горизонтальный скролл при сжатии); в баблах чата — горизонтальный скролл внутри сообщения, поскольку ширина бабла ограничена. См. § 3 SPA. + +
#12345 Автоссылка на задачу + + + +
@user{userId} (@user28) Упоминание пользователя + + + +
URL (https://...) Автоматическая ссылка + + + +
URL Диска (https://.../spa/disk/...) Открывает папку/файл Диска в превью + +
\n (реальный перевод строки) Перенос строки + + + +

Главное отличие от стандарта: __текст__ = курсив (в GitHub-flavored Markdown это жирный). Для жирного используй только **текст**.


2. Что НЕ поддерживается ни на одном клиенте

  • HTML-теги (<br>, <b>, <p>, <div>, любые другие)
  • iOS: отображает теги как текст
  • SPA: интерпретирует в браузере (побочный эффект — нельзя обсуждать HTML-код в комментариях). <>, не входящие в валидный HTML-тег (математические знаки, шаблонные строки, SQL-логи), экранируются на бэкенде до сохранения и отображаются как обычный текст; валидные теги с атрибутом md-render (генерируемые markdown-процессором фронта) не затрагиваются
  • Маркированные / нумерованные списки (-, *, 1.) — план #2038789 их упоминал, но в работу не взяли. Используй тире-эм-даш с новой строки
  • Горизонтальные разделители (---) — план #2038789 их упоминал, не реализовано
  • Изображения в тексте (![alt](url))
  • Стандартный markdown-italic через одинарный * (*текст*) — поддерживается только __текст__

3. Рендеринг по клиентам

SPA (Angular, лента + чат)

Shared service: apps/spa/src/app/common/components/feed-comments/services/comment-markdown.service.ts (один на оба пайпа с 2026-05-13, MR spa!904).

Пайплайн обработки (упрощённо): 1. markdownProcess: - mdFencedCode<pre class="md-code-block"> (placeholder) - mdTable<div class="md-table-wrapper"><table class="md-table"> (placeholder, GFM с поддержкой alignment :--- / ---: / :---:) - mdCode<code> (placeholder, защита от ** внутри) - mdLink<a> (placeholder) - mdHeader<strong> (без placeholder — внутри заголовка работают taskLink / userLink / commonLinks) - mdBold / mdEm / mdDel / mdUnderlined<strong> / <em> / <del> / <u> 2. newLineBr\n<br> (только в основном тексте, внутри placeholder'ов newline сохраняется для <pre>) 3. commonLinks → URL → кликабельные <a> 4. taskLink#12345 → ссылка на задачу 5. expandableText → длинные комменты сворачиваются (но см. § 5 — known issue с placeholder'ами) 6. replaceSigAccept → стилизация подписей событий 51/52/70/76 7. userLink@user28 → ссылка на пользователя 8. restoreMarkdownTokens → подстановка HTML для всех placeholder'ов, multi-pass для вложенных ([code](url)) 9. getSafeHtml → whitelist-санитизация (см. § 5 — known issue с onclick= внутри fenced)

Стилизация code по типу события (только inline): - Events 51, 70, 80, 124 (позитивные): синий #2c88e0 - Events 52, 76 (негативные): красный #f44336

Стили таблиц (apps/spa/src/app/common/components/feed-comments/feed-comments.theme.scss:72-99): - .md-table-wrapperdisplay: block; overflow-x: auto; max-width: 100% (обеспечивает горизонтальный скролл при переполнении в обоих режимах). - .md-tablewidth: 100%; border-collapse: collapse; font-size: 0.95em (растягивается на всю ширину обёртки; колонки делят ширину пропорционально содержимому). - .md-table thbackground: var(--surface-zero); font-weight: 600 (фон шапки из темы). - Разница лента vs чат не в стилях обёртки, а в ширине родительского контейнера: в ленте контейнер широкий — таблица растягивается, в бабле чата контейнер уже — таблица упирается в overflow-x: auto. Дополнительная адаптация под бабл чата при необходимости — в feature-chat.theme.scss.

Чат-пайп (apps/spa/src/app/components/chat/ui/pipes/comment-text-to-html.pipe.ts) использует тот же CommentMarkdownService. До MR spa!904 markdown в чате вообще не работал.

iOS

Файл: 1fchat-ios/Categories/String+Extension.swift:84-234

Рендеринг через NSAttributedString: - **text** → bold font trait - __text__ → italic font trait - ~~text~~ → strikethrough - ((text)) → underline - `text` → monospace - [text](url) → NSLinkAttributeName - #12345 → кликабельный - @user123 → кликабельный badge

Не поддерживается на iOS: #/##/### заголовки, ``` fenced code блоки, | GFM | таблицы. Покажутся как plain text с символами разметки. Отдельная задача.

Android

Аналогично iOS. Те же ограничения.


4. Правила для автоматических комментариев (Анфиса, боты, API)

  1. Пиши обычный markdown (CommonMark/GFM). Не нужно «кастомного синтаксиса 1Формы» — поддерживается стандарт.
  2. 1Форма-специфика:
  3. __текст__ это курсив, не жирный — для жирного используй **текст**
  4. ((текст)) — подчёркнутый (опционально)
  5. #12345 — автоссылка на задачу, @user28 — упоминание пользователя
  6. Переносы строк — настоящий перевод строки (LF). Не \n как двусимвольный escape.
  7. Списки -/1. пока не рендерятся — используй тире-эм-даш с новой строки.
  8. Заголовки/fenced/таблицы в SPA работают, на iOS/Android — пока plain text. Учитывай аудиторию — если комментарий важен для мобильных пользователей, по возможности используй inline-разметку (**bold**, `code`) вместо блочной.

5. Known issues (follow-up, не блокирует use)

См. ServiceFlow/spa-feed-comments-md-followup-2038789.md: - expandableText видит placeholder MD:N вместо реального fenced code блока → длинные блоки кода не сворачиваются. - htmlHasPotentialRiskHtml ловит substring onclick= / <img / <script внутри escaped содержимого fenced code → весь HTML экранируется, блок рендерится как plain text.

Обе требуют рефакторинга processedValue$ pipeline (восстановление placeholder'ов после getSafeHtml).


6. Ссылки на сущности — URL-паттерны

В комментариях URL автоматически кликабельны (SPA, iOS, Android). Используй правильные паттерны:

Shorthand (парсится системой)

Синтаксис Результат Пример
#TaskId Ссылка на задачу #12345
@user{userId} Упоминание пользователя @user28

Полные URL (для сущностей без shorthand)

Задачи и гриды:

Сущность URL Пример
Задача https://{host}/spa/tasks/{taskId} /spa/tasks/12345
Грид категории https://{host}/spa/tasks/subcat/{subcatId}/grid /spa/tasks/subcat/5574/grid
Канбан категории https://{host}/spa/tasks/subcat/{subcatId}/kanban /spa/tasks/subcat/5574/kanban
Портал категории https://{host}/spa/tasks/subcat/{subcatId}/portal /spa/tasks/subcat/5574/portal

Администрирование:

Сущность URL Пример
Настройки категории https://{host}/spa/administration/subcategory/{subcatId} /spa/administration/subcategory/63540
ДП категории (список) https://{host}/spa/administration/ext-params-settings/subcat/{subcatId} /spa/administration/ext-params-settings/subcat/13759
Конкретный ДП https://{host}/spa/administration/ext-params-settings/{subcatId}/{extParamId} /spa/administration/ext-params-settings/13759/45012
SmartScripts https://{host}/spa/administration/smart-scripts/{scriptId} /spa/administration/smart-scripts/492
Пользователь (профиль) https://{host}/spa/users/{userId}/info /spa/users/28/info

Правила: - Задачи — ВСЕГДА shorthand #TaskId, не полный URL. Система автоматически рендерит кликабельную ссылку. - Для остальных сущностей — полный URL. Подставляй реальные ID из контекста. - На клиентских площадках домен другой (например client.1forma.ru), но пути те же.


7. Ключевые файлы

Клиент Файл Назначение
SPA common/components/feed-comments/services/comment-markdown.service.ts Shared markdown service — единая логика для ленты и чата (с 2026-05-13)
SPA common/components/feed-comments/services/comment-markdown.service.spec.ts Тесты shared сервиса (~49 кейсов, покрывают все форматы + edge cases)
SPA common/components/feed-comments/pipes/comment-text-to-html.pipe.ts Pipe для ленты (оркестрация: markdown service + taskLink/userLink/expandableText/getSafeHtml)
SPA components/chat/ui/pipes/comment-text-to-html.pipe.ts Pipe для чата (оркестрация для баблов)
SPA common/components/feed-comments/feed-comments.theme.scss Стили .md-code-block, .md-table-wrapper, .md-table
SPA common/components/feed-comments/pipes/decode-html-entities.pipe.ts Декодирование HTML-entities
iOS String+Extension.swift:84-234 markdownAttributes() (старый подмножество, без headers/fenced/tables)
iOS NSMutableAttributedString+Analyze.m:32-44 highlightTasksInText
iOS LinksInteractionTextView.m UITextView с обработкой кликов