Открийте как работи ESLint, за да изгради правила за тестване, за да гарантира, че компонентите на системата за проектиране се използват правилно в производството

Ако създавате библиотека с компоненти на система за проектиране за вашата компания или общността с отворен код, има голям шанс да имате силни мнения за това как крайните потребители трябва да използват вашата система за проектиране.

За да сте сигурни, че вашата система за проектиране се използва по предвидения начин и за да намалите броя на възможните грешки, може да искате вашите потребители да се придържат към вашите най-добри практики. Следват два примера за възможни най-добри практики:

  • Избягване на вградени стилове във вашите елементи
  • Гарантиране, че подсказките не съдържат интерактивно съдържание.

Ако сте единственият човек, който проектира, разработва и използва вашата дизайнерска система, тогава можете да спите спокойно, знаейки, че вашата дизайнерска система се използва точно по предназначение.

Вероятно не сте единственият човек, който разработва системата за дизайн и със сигурност няма да присъствате, когато някой я използва. Как можете да сте сигурни, че всички спазват най-добрите практики на вашата система за проектиране? Можете да стискате палци и да вярвате, че вашите крайни потребители четат документацията, обръщат внимание на вашите предупреждения и никога не пропускат да спазват вашите правила.

За съжаление, това често не е така и е много лесно да пропуснете предупреждения или да разберете погрешно как правилно да използвате даден инструмент.

Чудесен начин да насърчите вашите потребители да следват вашите най-добри практики е чрез използването на ESLint, инструмент за статичен анализ за намиране на проблеми във вашия код.

По подразбиране ESLint се доставя с шепа общи най-добри практики, наречени правила и ще покаже червени криволичещи фигури във вашата IDE, ако правилата са били нарушени. Някои от тези правила включват:

  • Без дублиращи се ключове в обекти
  • Няма недостъпен код
  • Няма неизползвани променливи

Въпреки това, правилата, които активирате във вашия проект, не е необходимо да идват директно от ESLint. Популярни библиотеки като Cypress, Lodash и React имат ESLint конфигурации, които всеки може да използва в собствените си проекти, за да гарантира, че потребителите се придържат към най-добрите практики. Ако сте безстрашен изследовател на езика JavaScript, можете да отидете крачка напред и да създадете персонализирани правила, специфични за вашата система за проектиране, които можете да експортирате за други хора, за да ги използват в своите проекти.

В тази статия ще отделим малко време, за да разберем как инструменти като ESLint анализират JavaScript надолу в структура от данни, наречена абстрактно синтактично дърво (AST). След това ще разгледаме как работят правилата на ESLint и как да анализираме нашите Lit шаблони в HTML. Най-накрая ще започнем да създаваме нашите първи правила. Дори ще използваме вградения инструмент за тестване на ESLint, за да сме сигурни, че правилата ни работят при различни условия.

Предпоставката за тази статия е известно познаване на JavaScript + HTML. Малко опит в използването на ESLint и Lit може да е от полза, но не е необходимо.

Какво е абстрактно синтактично дърво?

За тези, които не са си цапали ръцете с компилатори преди, концептуализиране на това как разбираемият от човека език, който пишем в нашата IDE, се разбира (и трансформира) от инструменти като Webpack, Prettier и Babel може да се почувства като магия.

Под капака, когато инструмент като ESLint иска да започне да извършва действия срещу вашия JavaScript, той анализира кода ви. Парсирането е процес на вземане на JavaScript, който сте написали, и превръщането му в дървовидно представяне на кода, абстрактно синтактично дърво (AST).

Този процес на анализиране е разделен на две части, токенизиране и изграждане на дърво.

Токенизацията взема кода и го разделя на неща, наречени токени, които описват изолирани части от синтаксиса.

Токени за JavaScript програма като:

ще изглежда нещо подобно:

Втората стъпка в процеса на анализиране е изграждане на дърво, което преформатира токените в AST. AST описва всяка част от синтаксиса и нейната връзка с останалите.

Използвахме js-токени като бърз начин за токенизиране на JS за този пример, но няма да се занимаваме директно с токенизиране в тази статия.

Можем да визуализираме тази връзка, като анализираме следния оператор на JavaScript:

Той ще се трансформира в AST със следната структура:

Инструменти като Babel и Prettier превръщат вашия написан JavaScript в AST, за да анализират и трансформират кода, който сме написали. Babel използва AST, за да транспилира нашия код в удобна за браузър версия на JavaScript, докато Prettier използва AST, за да преформатира вашия код.

Станете любопитни с AST Explorer

За да проучите наистина как изглежда AST, поиграйте си с AST explorer. Запознайте се с AST Explorer, тъй като ще го използваме по-късно в статията.

Напишете просто изявление, като следното:

Ще видите, че най-горното ниво на дървото описва цялата програма и можем да погледнем в масива body, за да видим отделните съставни части на нашия горен израз, представени в AST.

Ако задържите курсора на мишката върху VariableDeclaration, можете да видите, че цялото твърдение отляво се маркира. Ако отидем ниво по-дълбоко в масива declarations, ще видите допълнителен възел VariableDeclarator. Ако продължим, накрая ще стигнем дъното. В случая на нашето изявление hello world, това е със стойността на променливата Identifier и Literal на променливата.

Нека преразгледаме нашия компонент от по-рано:

Ако преминете през дървото в AST Explorer, можете да видите, че структурата съответства на нашето изображение от по-рано. Обърнете специално внимание на възела TaggedTemplateExpression и възела TemplateLiteral. Това са тези, които ще ни бъдат полезни, когато пишем нашите ESLint правила.

Нашето извикване на функцията html е израз, но изглежда малко по-различно от дефинициите на други функции. Нека да видим как AST се различава с израз като следния:

Ако задържим курсора на мишката над heyThere() ExpressionStatement, виждаме, че свойствата съответстват на нашия html ExpressionStatement. Основната разлика е, че стойността в свойството expression изглежда различно. Изразът този път е CallExpression, който има набор от свойства, различни от тези на нашия TaggedTemplateExpression.

Ако погледнем назад към нашия TaggedTemplateExpression, можем да видим, че имаме свойства като етикет и квази.

Тагът ни дава някои подробности за името на функцията. Което в случая е html.

Това означава, че когато пишем нашето ESlint правило, ще можем да направим нещо подобно:

И накрая, ако погледнете в обекта TaggedTemplateExpression, ще видите свойство с име quasi. Този имот съдържа нашите два забележителни свойства expressions и quasis. Вземете следния израз:

Зеленото подчертаване, второто, ще живее в масива expressions и предоставя препратка към името на променливата. Подобно на quasis, елементите в масива са в реда, в който са дефинирани. Това прави много лесно съгласуването на вашия шаблонен литерал по-късно.

Ето един въпрос към вас, какво се случва, ако първият символ на нашия шаблонен литерал е израз? Как е представено това в нашия AST? Опитайте следния фрагмент в AST Explorer:

Отделете малко повече време за изследване на квази и изрази, ако все още ви се струват непознати.

Когато осъществявате достъп до стойността във вашия квази, ще видите наличния низ като суров или варен. Тези стойности определят дали последователностите за екраниране се игнорират или интерпретират. Аксел Раушмайер разглежда това малко по-подробно в тази статия.

За щастие, няма да е необходимо да се занимаваме директно с процеса на анализиране, когато пишем нашите ESLint правила. Покрихме много, защото разбирането на високо ниво за това как работят инструментите прави много по-интуитивно изживяване при разработка по-късно.

Ако се интересувате да научите малко повече за целия процес на компилиране, Super Tiny Compiler е наистина забавен начин да създадете свой собствен JavaScript компилатор, като използвате само няколкостотин реда код.

Как работят правилата на Eslint?

Моделът на посетителя

За щастие, не е необходимо да правим никаква трансформация, когато пишем правила на ESLint, а вместо това пишем нашите проверки срещу конкретни типове възли в нашия код. Тези възли са части от AST на нашия код.

След като ESLint анализира вашия код в AST, той преминава през дървото ви, посещавайки всеки възел по пътя. За тези, които са запознати с моделите на програмиране, може да разпознаете този модел като модела на посетител.

Моделът на посетителя е начин за стартиране на нова логика срещу обект, без да се модифицира обектът. ESLint използва модела на посетителя, за да отдели кода, използван за извършване на проверки спрямо вашия код от AST.

Нека да разгледаме „модела на посетителя в действие“.

Можете да видите, че внедрих посетителя с помощта на 3 блока код:

  1. ast.js: AST за const name = 'andrico'
  2. traverser.js: Алгоритъм, който пресича възлите на нашия AST.
  3. visitors.js: Обект от методи, при който даден метод се задейства, след като преходникът достигне съответния му възел. В нашия случай, когато преходникът достигне VariableDeclarator възел, той задейства нашата посетителска функция.

Нека разбием traverser малко повече:

Започваме в index.js, като създаваме екземпляр на нашия клас Traverser и преминаваме през нашия AST и нашите посетители. Под капака, нашият Traverser клас съхранява нашите AST и посетители като променливи на екземпляри, които да използваме по-късно.

След това извикваме метода traverse на инстанцията. Ако преминете към файла traverser.js, можете да видите, че когато извикаме traverse могат да се случат 5 неща:

  1. Възелът е null, което ще се случи, когато ръчно извикаме метода traverse без никакви аргументи. Когато това се случи, стартираме функцията за преминаване, използвайки AST, който съхранихме по време на инициализацията на класа.
  2. Възелът има тип Program, което ще се случи за възлите от най-високо ниво в нашия AST. Когато това се случи, ние рекурсивно извикваме метода за обхождане на дъщерните възли.
  3. Възелът има тип, който съответства на функция за посетител. Когато това се случи, ние задействаме нашата посетителска функция и преминаваме през възела като аргумент.
  4. Възелът има допълнителни декларации, така че ние продължаваме да извикваме нашата функция за преминаване на тези дъщерни декларации.
  5. Нашият възел не отговаря на нито едно от тези условия, което ще доведе до излизане от нашия метод за преминаване.

В контекста на нашия пример const name = 'andrico', нашата функция за преминаване ще продължи да си проправя път през AST, докато достигне VariableDeclarator, където ще извика посетителя, който дефинирахме в visitors.js. В този посетител проверяваме дали стойността е Andrico и ако е така, регистрираме съобщение, че това е невалидно име.

Отворете конзолата в CodeSandbox и вижте какво извежда. Опитайте да промените проверката във вашия посетител и вижте какво ще се случи, ако има нещо.

Добрата новина е, че ESLint управлява логиката на преминаване за нашия JavaScript. Другата добра новина е, че ще трябва да внедрим логиката на преминаване за нашия анализиран HTML 😄

Как изглежда правилото на Eslint?

Писането на ESLint правило не изисква нищо фантастично, това е просто обикновен стар JavaScript обект. Най-високото ниво на обекта може да получи две свойства: meta и create.

meta предоставя метаданните за правилото.

Свойството create е функция, която връща обект от посетители, които ESLint извиква, когато посещава всеки възел. Това следва същия принцип като фрагментите в кодовия пясък. И подобно на демонстрацията в нашия кодов пясък, името на всяка посетителска функция е името на възела, който искаме да посетим.

Всъщност можем дори да преназначим псевдокода от по-рано и да го украсим със специфичния за ESLint модел:

Функцията create предоставя също контекстен обект, който предоставя някои допълнителни помощни средства и информация за текущото правило. Помощникът, който ни интересува най-много в момента, е методът report(). Можем да извикаме report винаги, когато искаме грешка ESLint да се покаже в конзолата или IDE.

Context.report взема обект с шепа свойства, но най-много се интересуваме от следното:

  • съобщение: описанието на проблема
  • възел: AST възелът, свързан с проблема

Преди да продължите, защо не помислите за коригиране на псевдокода по-горе, за да показва грешка на ESLint, когато се извиква маркиран шаблон и литерала на шаблона няма съдържание, като това:

С основно разбиране на AST на JavaScript, модела на посетителите и анатомията на правилото на ESLint, единственото нещо, което остава да покрием, е как да анализираме нашия шаблонен низ в HTML, преди да можем да започнем да създаваме нашите правила.

За по-задълбочено четене на анатомията на правилото на ESLint, няма по-добро място за разглеждане от „официалните документи“.

Как можем да трансформираме нашите шаблони в HTML?

Когато използваме ESLint, имаме лукса ESLint да ни предостави нашия анализиран JavaScript AST. И докато ESLint не може да анализира нашия HTML, можем да използваме библиотека като parse5, за да анализираме валиден HTML низ в структура от данни, не по-различно от нашия JavaScript AST.

AST изследователят, който прекарахме толкова много време в изследване, дори има настройки за показване на HTML AST.

Тъй като едно от нашите правила ще ни попречи да преминем през вградени стилове, нека да видим как следното се представя като AST:

Ако се потопим в AST и потърсим нашия div, можем да видим, че ни е представена полезна информация. Най-забележителните са:

tagName: Което е името на html елемента. (в този случай div).

attrs: Което е масив от атрибути, представени като двойка ключ-стойност. Свойството attrs на нашия div съдържа един елемент. Артикулът има name от style и value от display:inline;.

Използвайки тази информация, вече можем да започнем да виждаме как да обединим всичко, което сме научили, за да създадем нашето първо правило за мъх.

Ето как можем да анализираме нашите JavaScript шаблони с помощта на библиотеката parse5:

Благодарение на инструменти като parse 5 и ESLint, можем да разтоварим много от сложната обработка и да се съсредоточим върху писането на кода за нашите специфични правила.

Отивайки по-нататък

Разгледахме и научихме основите за това как работи ESLINT и как да напишем първите си правила, за да тестваме дали кодът ни е съвместим с прости указания за система за проектиране. В следваща статия ще се потопим по-задълбочено в това как да настроите и изградите по-сложни ESLint правила и ще вземем всичко, което научихме, в нещо, което можете да използвате за вашите собствени системи за проектиране.

Първоначално публикувано на https://backlight.dev и написано от@AndricoKaroulla на 16 ноември 2021 г.

ресурси:

пясъчници:

ресурси: