Как стать автором
Обновить

PowerShell: классическая схема именования в БЭМ и регулярные выражения

Время на прочтение10 мин
Количество просмотров2.8K

Напомню, я пишу скрипт на языке PowerShell для анализа файла на языке HTML. Сейчас меня интересуют способы проверки имен БЭМ-сущностей (имен классов CSS) на ошибки. Предполагается, что скрипт будет работать в программах-оболочках «Windows PowerShell» версии 5.1 и «PowerShell» версии 7. Я работаю в операционной системе «Windows 10».

Методология БЭМ была создана сотрудниками компании «Яндекс» во второй половине нулевых и приобрела определенную популярность в 2010-х не только в России, но и на Западе. Это методология веб-разработки, название расшифровывается фразой «Блок, Элемент, Модификатор». Эту методологию можно использовать в своем проекте на нескольких уровнях, от самого простого — на уровне соблюдения соглашения об именовании БЭМ-сущностей, до самого глубокого — в этом случае потребуется с самого начала соблюдать определенную структуру проекта и использовать определенные инструменты автоматизации работы.

Я не буду в этой статье подробно рассказывать про методологию БЭМ целиком, так как статья посвящена не этому. Но тем, кто интересуется этой технологией, я рекомендую сайт, созданный компанией «Яндекс» для объяснения и популяризации этой методологии (начать можно с раздела «Быстрый старт»). Кроме версии на русском там имеется и версия на английском языке. Хоть этот сайт уже заброшен года 3-4, но он остается самым информативным источником по теме.

Это, кстати, привычное поведение для компании «Яндекс»: начинания, не приносящие доход в течение нескольких лет, режутся без жалости (в данном случае доход не приносит поддержка сайта, сама технология, конечно, продолжает использоваться). Примерно такую же недальновидную политику когда-то в начале нулевых проводила компания «Microsoft», из-за чего, в частности, потеряла лидерство на рынке браузеров (моё личное мнение).

Соглашение по именованию в методологии БЭМ

«БЭМ-сущностями» называют блоки, элементы и модификаторы. В методологии БЭМ построение внешнего вида сайта происходит с помощью «кирпичиков»: блоков, элементов и модификаторов. На HTML-дереве БЭМ-сущности привязывают к HTML-элементам с помощью атрибута class HTML-элементов. К одному HTML-элементу можно привязать несколько БЭМ-сущностей. Говоря проще, имена БЭМ-сущностей — это названия классов CSS, привязанных к HTML-элементам.

По методологии БЭМ при именовании классов CSS (БЭМ-сущностей) должен соблюдаться свод правил, который называют «соглашением по именованию» («схемой именования»). Это соглашение по именованию описано в разделе «Соглашение по именованию» вышеупомянутого сайта.

В этом соглашении есть правила, которые регламентируют написание имен классов CSS, а есть правила, которые регламентируют использование имен классов CSS (БЭМ-сущностей). Например, одно из правил написания имен классов CSS гласит, что «имена записываются латиницей в нижнем регистре». А, к примеру, из другого правила, гласящего, что «имя блока задает пространство имен для его элементов и модификаторов» вытекает один из принципов использования имен БЭМ-сущностей (принцип принадлежности): «элемент — всегда часть блока и не должен использоваться отдельно от него».

В этой статье я буду рассматривать проверку правил написания имен классов CSS, а не проверку правил их использования. Для проверки правил написания достаточно проанализировать сами имена классов CSS здесь и сейчас, а для проверки правил использования имен БЭМ-сущностей придется анализировать расположение этих БЭМ-сущностей на ветках HTML-дерева, вложенность их друг в друга и так далее.

Разные схемы именования в БЭМ

На вышеупомянутом сайте описана схема именования, которую называют «классической». Однако, методология БЭМ позволяет использовать альтернативные схемы именования, некоторые из которых описаны на том же сайте. Например, альтернативная схема именования «Two Dashes» (по-русски «Два дефиса»), названная так потому, что в ней в качестве одного из разделителей используется двойной дефис-минус -- (в отличие от классической схемы именования).

На Западе, как мне кажется, более популярна схема именования, описанная на англоязычном сайте «getbem.com» в разделе «Naming». Обратите внимание, что схема именования, описанная под именем «Two Dashes» на сайте «Яндекса», отличается от схемы именования, описанной на сайте «getbem.com», хоть в них обеих используется в качестве одного из разделителей двойной дефис-минус --.

Классическая схема именования в БЭМ

Ниже я продемонстрирую несколько примеров имен БЭМ-сущностей (классов CSS) по классической схеме именования в методологии БЭМ:

block-name
block-name_bool-mod-name
block-name_mod-name_mod-value

block-name__element-name
block-name__element-name_bool-mod-name
block-name__element-name_mod-name_mod-value

В первой тройке имен сверху перечислены имя блока и два имени модификаторов блока.

Модификаторы в методологии БЭМ изменяют внешний вид или поведение блока или элемента блока. Модификаторы бывают двух типов: булевые и ключ-значение. Булевый модификатор своим присутствием подразумевает значение «истина» или «включено», а если он отсутствует, то считается, что придаваемое им изменение внешнего вида или поведения выключено. Модификатор «ключ-значение» подразумевает, что название модификатора состоит из названия (ключа) и значения, отделенных друг от друга разделителем (для классической схемы именования в данном случае разделителем выступает одиночный символ подчеркивания _).

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

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

Регулярные выражения для проверки имен БЭМ-сущностей

Конечно, для проверки имен классов CSS (имен БЭМ-сущностей) тянет использовать такой удобный инструмент, как регулярные выражения. Лично мне всегда нравились регулярные выражения своей гибкостью, но я с подозрением отношусь к длинным регулярным выражениям, потому что их трудно проверять. Да и вообще мне не хватает знаний об этом инструменте программиста и опыта работы с ним.

Я почитал в интернетах статьи по теме и заметил, что многие люди пытаются придумать для проверки имен БЭМ-сущностей одно универсальное регулярное выражение. У такого подхода два очевидных минуса. Во-первых, это не так-то просто сделать. Во-вторых, что более важно, одно универсальное регулярное выражение может дать лишь два простых ответа: валидно ли имя БЭМ-сущности или нет.

А мне хотелось бы в результате проверки имени БЭМ-сущности получить ответ, который будет содержать подсказку на способ исправления ошибки. Понятно, что для этого вариантов ответов должно быть множество для разных возможных ошибок. Таким образом, для проверки имени БЭМ-сущности я буду использовать ряд простых регулярных выражений, используемых в определенном порядке (порядок их использования важен).

В результате у меня получилась следующая функция на языке PowerShell:

#   Проверка названия класса на соответствие методологии БЭМ,
#   классическая схема именования с сайта
#   https://ru.bem.info/methodology/naming-convention/
function testBEMNameClassic($name) {
    if ($name -cnotmatch '^[a-z_-]+$')    { return 1 }
    if (($name -match '^-') -or
        ($name -match '-$') -or
        ($name -match '[_-]-') -or
        ($name -match '-_'))              { return 2 }
    if ($name -match '_{3,}')             { return 3 }
    if (($name -match '^_') -or
        ($name -match '_$'))              { return 4 }
    if ($name -match '__.+__')            { return 5 }
    if ($name -match '_.+__')             { return 6 }
    if ($name -match '[^_]_[^_]+_[^_]+_') { return 7 }
    return 0   #   Нет ошибок
}

Эта функция принимает в качестве параметра строку $name с именем класса CSS (с именем БЭМ-сущности). Функция возвращает число, содержащее номер ошибки, если найдена ошибка, и число 0, если ошибок не найдено.

Возможные способы использования этой функции в скрипте:

$err = testBEMNameClassic($class)

#   Если просто нужно проверить, валидно имя или нет.
#   (В случае 0 условие не сработает.)
if ($err) {
    #   Действия в случае ошибки
    #   ...
}

#   Если нужно обеспечить информативное сообщение об ошибке
switch ($err) {
    1 {"В БЭМ в имени разрешены только символы [a-z_-]."}
    2 {"В БЭМ дефис в именах только разделяет слова."}
    3 {"В БЭМ не используют больше двух подчеркиваний подряд."}
    4 {"В БЭМ подчеркивания используют как разделители."}
    5 {"В БЭМ не существует элементов элементов."}
    6 {"В БЭМ разделитель _ не может быть раньше __."}
    7 {"В БЭМ не может быть больше двух разделителей _."}
}

Как работает функция

Правило 1. Имена записываются латиницей в нижнем регистре. Также в именах могут использоваться символ подчеркивания _ и символ дефиса-минуса -. Проверка этого правила обеспечивается следующим кодом:

    if ($name -cnotmatch '^[a-z_-]+$')    { return 1 }

Тут следует иметь в виду, что в языке PowerShell операторы -match и -notmatch не чувствительны к регистру букв. А в данном случае регистр букв важен. Поэтому используем оператор -cnotmatch, который работает так же, как и оператор -notmatch, но отличается чувствительностью к регистру букв.

Для регулярных выражений используем одинарные кавычки. При использовании двойных кавычек символ $ будет интерпретирован как переменная, а это нам не нужно. В регулярном выражении символ $ (доллар) обозначает конец строки, а символ ^ (карет) — начало строки.

Квадратные скобки с группой символов внутри обозначают один символ, любой из перечисленных внутри квадратных скобок. Внутри квадратных скобок можно не только указывать символы один за другим, но и указывать диапазоны символов. Для указания диапазона символов используется дефис-минус -. Например, диапазон символов a-z. Из-за этого, чтобы указать сам символ дефис-минус, его можно указать либо самым первым внутри квадратных скобок, либо самым последним (как в нашем случае).

Символ плюс + (один из так называемых «квантификаторов») указывает, что символ перед ним может быть повторен один или более раз.

Вообще про регулярные выражения можно подробнее узнать, в частности, в документации к языку PowerShell на сайте компании «Microsoft».

Если имя БЭМ-сущности успешно прошло первую проверку, то переходим к следующей проверке и так далее.

Правило 2. Для разделения слов в именах используется дефис (-). Я истолковал это правило как «дефис используется только для разделения слов в именах». Проверка этого правила обеспечивается следующим кодом:

    if (($name -match '^-') -or
        ($name -match '-$') -or
        ($name -match '[_-]-') -or
        ($name -match '-_'))              { return 2 }

Тут четыре условия. Первое: имя не должно начинаться на дефис. Второе: имя не должно заканчиваться на дефис. Третье: в имени не должно встречаться больше одного дефиса подряд, либо комбинации символов _-. Четвертое: в имени не должно встречаться комбинации символов -_. Во всех этих четырех случаях дефис не разделяет слова, следовательно, считаем это ошибкой. Для успешного прохождения этой проверки слева и справа от дефиса могут быть только какие-нибудь буквы латинского алфавита.

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

    if ($name -match '_{3,}')             { return 3 }

Выражение {3,} — это еще один квантификатор. Оно указывает на то, что символ перед ним должен быть повторен три или более раз.

Правило 4. Разделители _ и __ предназначены только для разделения. Проверка этого правила обеспечивается следующим кодом:

    if (($name -match '^_') -or
        ($name -match '_$'))              { return 4 }

Тут два условия. Первое: имя БЭМ-сущности не может начинаться на один из разделителей _ или __. Второе: имя БЭМ-сущности не может заканчиваться на один из разделителей _ или __. Возможное совмещение этих разделителей с символом дефиса в середине имени БЭМ-сущности уже отсечено правилом 2. Для успешного прохождения этой проверки слева и справа от разделителей _ и __ должны быть буквы латинского алфавита.

Правило 5. В методологии БЭМ не существует элементов элементов (хотя это не исключает любой независимой вложенности элементов друг в друга в HTML-дереве). Это правило означает, что в имени БЭМ-сущности не может быть больше одного разделителя __. Проверка этого правила обеспечивается следующим кодом:

    if ($name -match '__.+__')            { return 5 }

Символ . (точка) в регулярных выражениях является одним из символов подстановки (по-английски «wildcard»), еще их называют символами-джокерами. Этот символ в данном случае означает любой символ. В сочетании с квантификатором + он означает один или более любых символов. Всё выражение '__.+__' целиком означает два разделителя __, между которыми есть от одного и более символов.

Правило 6. Разделитель _ не может находиться раньше разделителя __ в имени БЭМ-сущности (если смотреть слева направо). Проверка этого правила обеспечивается следующим кодом:

    if ($name -match '_.+__')             { return 6 }

Значение используемого здесь регулярного выражения должно быть понятно из объяснений для предыдущих правил.

Правило 7. В имени БЭМ-сущности не может быть больше двух разделителей _. Проверка этого правила обеспечивается следующим кодом:

    if ($name -match '[^_]_[^_]+_[^_]+_') { return 7 }

В данном случае символ ^ (карет) означает не начало строки, как ранее, а отрицание. Использование этого символа в начале группы символов внутри квадратных скобок изменяет смысл выражения с квадратными скобками на противоположный. Теперь группа символов в квадратных скобках означает один любой символ, но только не из тех, что перечислены внутри квадратных скобок.

В нашем случае, учитывая предыдущие проверки, выражение [^_] означает любую букву латинского алфавита (другие случаи отсечены предыдущими проверками).

Использование более простого и понятного выражения _[^_]+_[^_]+_ будет неправильным, потому что такое выражение посчитает модификатор элемента типа ключ-значение за ошибку, а это нам не нужно.

Заключение

В описанную выше функцию легко внести изменения, она проста и понятна. В нее также можно добавлять новые правила. Для включения в скрипт других схем именования можно создать другие функции похожим образом и настроить их переключение через конструкцию switch. Таким образом, номер используемой схемы именования может быть одним из настраиваемых параметров нашего скрипта для проверки имен классов CSS (имен БЭМ-сущностей) на соответствие методологии БЭМ.

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

На этой иллюстрации белым цветом выведены названия HTML-элементов в HTML-дереве из заданного файла с кодом на языке HTML. Голубым цветом выведены названия БЭМ-сущностей (названия классов CSS), привязанных к HTML-элементу, под которым они выведены. Под названиями БЭМ-сущностей, не прошедших валидацию, красным цветом выведены сообщения об ошибках. Если БЭМ-сущность прошла валидацию успешно, то под ней не выводится никаких сообщений.

Теги:
Хабы:
+4
Комментарии2

Публикации

Истории

Работа

Веб дизайнер
42 вакансии

Ближайшие события