Зачеркнутый текст

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

~~Это зачеркнутый текст~~

При парсинге такой текст преобразуется в структуру AST (Abstract Syntax Tree), где элемент delete или del обозначает узел зачеркнутого текста. Remark и Rehype предоставляют возможности для работы с этими узлами на разных этапах обработки.


Remark: парсинг и генерация

Remark работает с Markdown на уровне синтаксического дерева. Для зачеркнутого текста важно понимать, что Remark представляет его через узел типа delete:

import { unified } from 'unified';
import remarkParse from 'remark-parse';
import remarkStringify from 'remark-stringify';

const markdown = '~~Зачеркнутый текст~~';
const processor = unified()
  .use(remarkParse)
  .use(remarkStringify);

const tree = processor.parse(markdown);
console.log(tree);

В результате структура узла будет выглядеть примерно так:

{
  "type": "root",
  "children": [
    {
      "type": "paragraph",
      "children": [
        {
          "type": "delete",
          "children": [
            { "type": "text", "value": "Зачеркнутый текст" }
          ]
        }
      ]
    }
  ]
}

Ключевые моменты:

  • Узел delete хранит текст внутри свойства children.
  • Для модификации или анализа зачеркнутого текста достаточно работать с этим узлом.
  • remarkStringify автоматически преобразует узел обратно в Markdown с тильдами.

Rehype: преобразование в HTML

Rehype отвечает за работу с HTML. После парсинга Markdown с Remark можно использовать remark-rehype для конвертации в HTML. Зачеркнутый текст в HTML представляется тегом <del>.

import { unified } from 'unified';
import remarkParse from 'remark-parse';
import remarkRehype from 'remark-rehype';
import rehypeStringify from 'rehype-stringify';

const markdown = '~~Зачеркнутый текст~~';
const html = await unified()
  .use(remarkParse)
  .use(remarkRehype)
  .use(rehypeStringify)
  .process(markdown);

console.log(html.toString()); // <p><del>Зачеркнутый текст</del></p>

Особенности:

  • Узел delete в Remark автоматически преобразуется в <del> при переходе к Rehype.
  • Можно использовать плагины Rehype для дальнейшей обработки <del>, например, для стилизации или добавления атрибутов.

Кастомизация обработки зачеркнутого текста

Для тонкой настройки преобразования можно писать плагины для Remark и Rehype:

Remark-плагин для изменения текста внутри delete

function remarkDeleteModifier() {
  return (tree) => {
    visit(tree, 'delete', (node) => {
      node.children.forEach(child => {
        if (child.type === 'text') {
          child.value = `[ЗАЧЕРКНУТО] ${child.value}`;
        }
      });
    });
  };
}

import { visit } from 'unist-util-visit';

const processed = await unified()
  .use(remarkParse)
  .use(remarkDeleteModifier)
  .use(remarkStringify)
  .process('~~Пример~~');

console.log(processed.toString()); // ~~[ЗАЧЕРКНУТО] Пример~~

Rehype-плагин для добавления атрибутов к <del>

function rehypeDelClass() {
  return (tree) => {
    visit(tree, 'element', (node) => {
      if (node.tagName === 'del') {
        node.properties = { className: ['strikethrough'] };
      }
    });
  };
}

import { visit } from 'unist-util-visit';

const htmlWithClass = await unified()
  .use(remarkParse)
  .use(remarkRehype)
  .use(rehypeDelClass)
  .use(rehypeStringify)
  .process('~~Важно~~');

console.log(htmlWithClass.toString()); // <p><del class="strikethrough">Важно</del></p>

Взаимодействие между Remark и Rehype

  • Remark отвечает за синтаксис Markdown, включая распознавание ~~ как зачеркнутого текста (delete).
  • Rehype отвечает за HTML-рендеринг, где delete превращается в <del>.
  • Между ними можно вставлять кастомные плагины для модификации текста, добавления классов, обработки событий или атрибутов.
  • Любые изменения на уровне Remark отражаются в HTML через Rehype после конвертации.

Практические советы

  1. Для анализа текста используйте unist-util-visit или подобные утилиты — это стандартная практика для обхода AST.
  2. Для стилизации <del> лучше делать через Rehype, чтобы не трогать Markdown напрямую.
  3. При генерации Markdown из AST remarkStringify корректно восстанавливает тильды для delete.
  4. Можно объединять несколько плагинов: один для модификации текста, другой для атрибутов HTML — это обеспечивает гибкость и чистоту кода.

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