Продолжаю дорабатывать небольшой скрипт на языке PowerShell для работы в программах-оболочках «Windows PowerShell» версии 5.1 и «PowerShell» версии 7 (я работаю в операционной системе «Windows 10»). Скрипт разбирает заданный файл с кодом на языке HTML с помощью методов библиотеки «HTML Agility Pack» и выводит в консоль HTML-дерево HTML-страницы из файла. При выводе в консоль HTML-дерева внимание пользователя с помощью цвета фокусирую на значениях атрибутов «class» HTML-элементов. Далее выполняю анализ названий БЭМ-сущностей на соответствие методологии БЭМ («Блок, Элемент, Модификатор»). Скрипт может быть полезен при изучении методологии БЭМ, схем именования в БЭМ и так далее.
Про визуализацию HTML-дерева я писал в статье «PowerShell: обход и визуализация HTML-дерева из файла». Про методологию БЭМ и соглашениях по именованию, использующихся в рамках этой методологии, я писал в статье «PowerShell: классическая схема именования в БЭМ и регулярные выражения».
В данной статье я буду придерживаться классической схемы именования в БЭМ, но всё изложенное здесь можно легко применить, слегка модифицировав, и к другим схемам именования.
Порядок действий
В вышеупомянутой статье я описал функцию testBEMNameClassic
, в которой с помощью ряда регулярных выражений, применяемых в определенном порядке, происходит анализ слова (названия класса CSS) из атрибута «class» HTML-элемента на ошибки с точки зрения схемы именования в методологии БЭМ. Эта функция возвращает число 0, если ошибок не обнаружено, или число, отличное от нуля (код ошибки), если обнаружена ошибка.
После этой проверки, если найдена ошибка, я вывожу сообщение об ошибке. Если ошибка не найдена, можно заняться распознаванием типа БЭМ-сущности. В коде на языке PowerShell это может выглядеть примерно так:
$err = testBEMNameClassic($class)
if ($err) {
# Выводим сообщение об ошибке
# ...
} else {
# Распознаём тип БЭМ-сущности, выводим в консоль
# ...
}
В переменной $class
содержится одно из слов из значения атрибута «class» HTML-элемента. Если в этом атрибуте содержится несколько слов, то они будут проанализированы поочередно в цикле (этот цикл в коде выше не показан). Напомню, слова в атрибуте «class» HTML-элемента разделяются пробельными символами (пробелом, символом горизонтальной табуляции, символами новой строки).
Таким образом, на этапе распознавания типа БЭМ-сущности можно считать, что входящие для распознавания слова написаны с полным соблюдением соглашения по именованию методологии БЭМ. (В нашем случае — это классическая схема именования, но в скрипте я реализую еще две альтернативные схемы именования. При желании кроме реализованных трех схем по именованию можно добавить какие-нибудь еще.)
Распознание типа БЭМ-сущности
Насколько я понимаю, типов БЭМ-сущности может быть всего шесть:
блок;
модификатор блока булевый;
модификатор блока ключ-значение;
элемент;
модификатор элемента булевый;
модификатор элемента ключ-значение.
Добавим в код выше код на языке PowerShell для распознавания типа БЭМ-сущности по ее названию с помощью регулярных выражений:
# Распознаём тип БЭМ-сущности, выводим в консоль
if ($class -cmatch '^[a-z-]+$')
{ "блок" }
elseif ($class -cmatch '^[a-z-]+_[a-z-]+$')
{ "модификатор блока булевый" }
elseif ($class -cmatch '^[a-z-]+_[a-z-]+_[a-z-]+$')
{ "модификатор блока ключ-значение" }
elseif ($class -cmatch '^[a-z-]+__[a-z-]+$')
{ "элемент" }
elseif ($class -cmatch '^[a-z-]+__[a-z-]+_[a-z-]+$')
{ "модификатор элемента булевый" }
elseif ($class -cmatch '^[a-z-]+__[a-z-]+_[a-z-]+_[a-z-]+$')
{ "модификатор элемента ключ-значение" }
else # если эта ветка задействуется, значит, ранее что-то
# не учтено и следует проверить предыдущие шаги,
# в том числе на этапе поиска ошибок
{ "не знаю, что это" }
В языке PowerShell оператор -match
— один из ряда операторов, работающих с регулярными выражениями. Этот оператор не чувствителен к регистру букв. В коде выше я использую оператор -cmatch
. Добавленная в начало названия этого оператора латинская буква c
обозначает слово «case» (по-русски в данном случае оно означает «регистр букв»), то есть оператор -cmatch
чувствителен к регистру букв.
Для нас это важно, потому что классическая схема именования в методологии БЭМ разрешает составлять названия БЭМ-сущностей только из латиницы в нижнем регистре (то есть разрешается использовать только строчные (маленькие) буквы). Кроме латиницы в названиях могут использоваться символ дефиса-минуса -
и символ подчеркивания _
.
Я уже немного описывал в другой статье синтаксис регулярных выражений, но не повредит напомнить, что символ ^
(карет) обозначает в регулярном выражении начало строки, а символ $
(доллар) — конец строки. Регулярное выражение в коде выше заключено в одинарные кавычки потому, что при использовании двойных кавычек символ $
будет интерпретирован не так, как нам нужно для регулярных выражений (в языке PowerShell с символа $
начинаются переменные).
Символ +
в регулярном выражении имеет специальное значение (такие символы в регулярных выражениях называют «квантификаторами»). В данном случае он означает повторение символа, стоящего перед ним, один или более раз. В данном случае перед символом +
в регулярных выражениях выше находятся квадратные скобки, которые означают один любой символ из содержащихся внутри квадратных скобок. Таким образом, выражение [a-z-]+
означает один или более символов, каждый из которых может быть либо строчной (маленькой) буквой латиницы, либо дефисом-минусом -
.
Диапазон строчных букв латиницы внутри квадратных скобок обозначен выражением a-z
. Так как в данном случае дефис-минус -
обозначает диапазон, то сам символ дефиса-минуса -
можно указать либо в начале выражения внутри квадратных скобок, либо в конце выражения внутри квадратных скобок (наш случай).
Учитывая, что название любой БЭМ-сущности сводится к одному или нескольким наборам символов [a-z-]+
, отделенных друг от друга соответствующими разделителями _
(одинарный символ подчеркивания) и __
(двойной символ подчеркивания), можно легко произвести распознавание разных типов БЭМ-сущностей:
Название блока содержит только один набор символов
[a-z-]+
, разделителей нет;Название булевого модификатора блока содержит два набора символов
[a-z-]+
, отделенных друг от друга разделителем_
;Название модификатора блока ключ-значение содержит три набора символов
[a-z-]+
, отделенных друг от друга двумя разделителями_
;Название элемента содержит два набора символов
[a-z-]+
, отделенных друг от друга разделителем__
;Название булевого модификатора элемента содержит три набора символов
[a-z-]+
, отделенных друг от друга разделителем__
и разделителем_
;Название модификатора элемента ключ-значение содержит четыре набора символов
[a-z-]+
, отделенных друг от друга разделителями__
и двумя_
.
Два замечания
Интересно, что шесть веток распознавания типов БЭМ-сущностей в коде выше можно безболезненно переставить местами в любом порядке. То есть регулярные выражения в этих ветках не зависят от предыдущих регулярных выражений. Это отличается от того, как написан анализ названий БЭМ-сущностей на ошибки в функции testBEMNameClassic
. Напомню, что там тоже используется ряд относительно коротких регулярных выражений, используемых поочередно. В функции testBEMNameClassic
порядок использования регулярных выражений важен.
Кроме этого, стоит обратить внимание на последнюю ветку в коде выше. Если я в скрипте всё написал правильно, то эта ветка никогда не будет задействована: для любого слова из атрибута «class» HTML-элемента либо будет показана ошибка (слово не укладывается в схему именования методологии БЭМ), либо будет показан тип БЭМ-сущности. Если эта ветка таки задействуется, значит, где-то ранее в скрипте допущена ошибка.
Заключение
Работа скрипта с распознаванием типа БЭМ-сущностей может выглядеть так:
В принципе, это уже можно использовать для обучения. Но мне интересно написать поиск более сложных ошибок. Например, поиск нарушений принципа принадлежности (элемент не должен находиться вне контекста своего блока) и других. Для этого, по идее, нужно будет сопоставлять названия разных БЭМ-сущностей на одном и том же узле HTML-дерева, а также на разных узлах.