Анализ принципа уценки-это

Markdown

предисловие

В последнее время я много использовал markdown-it, разработал несколько плагинов, в процессе изучил исходный код и, наконец, написал эту статью. Читатели, которым необходимо знать подробности, могут читать самостоятельно.Документация.

Эта статья разделена на две части: принципиальный анализ и принцип применения (написание плагинов).

Принцип уценки – это

Введите строку кода уценки и, наконец, получите строку html-кода, общий процесс выглядит следующим образом:

1.png

Объясним весь процесс на простом примере:​# 我是一个例子-> ​<h1>我是一个例子</h1>​

Сначала он будет получен парсером, после обработки по каждому правилу парсинга будет получен поток токенов, а затем поток токенов будет получен рендерером, который после обработки будет постепенно склеен в html-строку по каждому правилу рендеринга.

парсер

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

Технические характеристикисостояния:

Мы можем думать о документе Markdown как о серии блоков,Кусокпредставляет собой структурированный элемент, такой как абзацы, цитаты, списки, заголовки, правила и блоки кода. Некоторые блоки (такие как кавычки и элементы списка) могут содержать другие блоки; другие (такие как заголовки и абзацы) содержатв линиюСодержимое, такое как текст, ссылки, выделенный текст, изображения, встроенный код и т. д.

Приоритет синтаксического анализа блочных структур всегда выше, чем у встроенных структур. Это означает, что синтаксический анализ можно выполнить в два этапа: 1. Определить блочную структуру документов уценки; 2. Анализируйте строки текста в абзацах, заголовках и других блочных структурах как встроенные структуры.

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

Блоки бывают двух видов:контейнерный блока такжелистовой блок, блоки-контейнеры могут содержать другие блоки, но конечные блоки не могут содержать другие блоки.

При специальном синтаксическом анализе он будет анализироваться по двум измерениям строки и символа.

Для каждой строки интерпретация приводит к следующим трем способам:

  1. Используется для закрытия одной или нескольких блочных структур.

  2. Используется для создания одной или нескольких новых блочных структур в качестве потомков последней открытой блочной структуры.

  3. Текст можно добавить в последнюю (самую глубокую) открытую блочную структуру, оставшуюся в дереве.

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

Символы включают непробельные символы и пробелы (​U+0020​), символы табуляции (​U+0009​), новые строки (​U+000A​), списки строк (​U+000B​), переводы форм (​ U+ 000C​) или возврат каретки (​U+000D​) этих пробельных символов. Здесь мы не расширяемся.

В этот период будут затронуты следующие правила: блочные, встроенные, заголовочные и текстовые.

  1. блочные правила, которые будут использоваться для парсинга# 我是一个例子​
  • Сначала войдите в функцию токенизации, которая содержит одиннадцать правил блокировки.

  • правило заголовка

  • Получите три токена heading_open, inline, heading_close

  1. встроенные правила, которые будут использоваться для разбора​我是一个例子​
  • Сначала введите функцию разбора, которая содержит четыре встроенных правила.

  • текстовые правила

  • получить токен текста

После парсинга получаем 3+1 токены:

2.png

поток токенов

В результате мы получаем здесь не дерево AST, а массив, который уценка-это вызывает поток токенов. Зачем?

Официальное объяснение:

  • Токены — это простой массив. (AST — это объект)

  • Открытые вкладки и закрытые вкладки могут быть изолированы.

  • Относитесь к «встроенному контейнеру» как к объекту токена блока особого типа. Он имеет вложенные токены, такие как жирный шрифт, курсив, текст и т. Д.

Какая польза от этого? Это дает возможность параллельно обрабатывать токены типа block и inline.

После создания потока токенов они передаются вrenderer.

Рендерер

Он перебирает все токены, передавая каждый токен правилу с тем же именем, что и атрибут типа токена. markdown — имеет девять встроенных правил: ограждения, встроенный код, блоки кода, блоки HTML, встроенный HTML, изображения, жесткие разрывы строк, мягкие разрывы строк и текст.

Токены, атрибут type которых отсутствует во встроенных правилах, будут переданы вrenderTokenОн рассматривается как общий токен в середине и не будет здесь раскрываться.

Вернемся к нашему примеру:

heading_open будет отображаться как<h1>

встроенный текст будет отображаться как我是一个例子

heading_close будет отображаться как</h1>

плагин markdown-it

Некоторые плагины markdown-it используют вышеуказанные принципы.

markdown-it-container

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

Как это достигается? Мы можем сделать вывод о потоке токенов блока контента на основе предыдущего введения:

Первая и третья строки имеют токены блоков, один для открытия и один для закрытия. Вторая строка — это встроенный токен, содержимое которого является встроенным.

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

По сути, мы сканируем строку за строкой, чтобы найти совпадение.::: tipтакую ​​грамматику блока контента, начните анализировать ее как блочную структуру, пока не будет:::конец линии. Каждая из этих строк будет проанализирована как параграф_открытый, встроенный, параграф_закрытый.

Проанализированный поток токенов, наконец, отображается отдельно.<div>, несколько тегов p,</div>.

markdown-it-anchor

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

Здесь также можно предположить, вставлен ли токен перед токеном, который изначально был типа heading_open? Этот токен отображается как якорь.

На самом деле токен действительно вставлен, но больше одного, потому что якорь кликабельный, поэтому на самом деле это ссылка, то есть три токена link_open, inline и link_close. И он вставляется не перед heading_open, а во встроенный подэлемент между heading_open и heading_close, потому что ​#​ соответствует синтаксису ​Markdown.

Меры предосторожности: 1. Поскольку в заголовке могут быть специальные символы, такие как @#$, хэш URL будет недействительным, поэтому вам нужно экранировать хеш-значение якоря. 2. Могут быть заголовки с одинаковым названием, поэтому хэш нужно пометить

Добавьте атрибуты к ссылкам

Есть официальный пример написания плагина: добавляем атрибут target="_blank" ко всем ссылкам.

Есть два способа:

  1. Изменить правило рендерера
// 如果覆盖,或者是对默认渲染器的代理,则记住老的渲染器。
var defaultRender = md.renderer.rules.link_open || function(tokens, idx, options, env, self) {
  return self.renderToken(tokens, idx, options);
};

md.renderer.rules.link_open = function (tokens, idx, options, env, self) {
  // 如果你确认其他的插件不能添加 `target` - 放弃以下检查:
  var aIndex = tokens[idx].attrIndex('target');

  if (aIndex < 0) {
    tokens[idx].attrPush(['target', '_blank']); // 添加新属性
  } else {
    tokens[idx].attrs[aIndex][1] = '_blank';    // 替换已经存在的属性值
  }

  // 传递 token 到默认的渲染器。
  return defaultRender(tokens, idx, options, env, self);
};
  1. изменить токен
var iterator = require('markdown-it-for-inline');

var md = require('markdown-it')()
            .use(iterator, 'url_new_win', 'link_open', function (tokens, idx) {
              var aIndex = tokens[idx].attrIndex('target');

              if (aIndex < 0) {
                tokens[idx].attrPush(['target', '_blank']);
              } else {
                tokens[idx].attrs[aIndex][1] = '_blank';
              }
            });

выделять

В примере, приведенном в официальном документе здесь, используется highlight.js, а используемая технология относительно сложна (в основном компиляция синтаксических деревьев различных языков), поэтому я не буду объяснять ее здесь.

Эпилог

markdown — это классическая библиотека js для парсинга уценки, в которой идеи и дизайны можно тщательно обдумать и долго вспоминать.