ESlint code quality tool

Написати чистий і якісний код з першого разу дуже важко. Досвід показує, що пропустивши десь крапку з комою або звернушись до неіснуючої змінної можна потратити багато часу на дебагінг і пошук причин чому якийсь кусок коду не працює як так очікувалось. Дуже важко за всім вслідкувати, особливо якщо над кодом працює більше ніж одна людина. Тому важливо якомога більше процесів автоматизувати, щоб код був якіснішим і на рев’ю приходила версія без тупих синтаксичних помилок.

Даний пост просто підсумує мої знання про інструменти і правила які виконують статичний аналіз коду (static code analysis).

Основною IDE  з якою я працюю є WebStorm. Він надзвичайно зручний для аналізу коду зразу під час його написання і дозволяє автоматично форматувати його по заданих правилах. Ці правила задаються вручну в налаштуваннях Code style або можна завантажити файл з налаштуваннями. На даний момент WebStorm дозволяє використовувати правила JSCS. Вони будуть використовуватись для автоматичного форматування коду комбінацією клавіш Ctrl+Alt+L.

JSCS хороший інструмент, але уже устарівший. Він був інтегрований в ESLint який ми дальше і будемо використовувати для перевірки коду.

Аналіз коду за допомогою ESLint.

Для початку нам потрібно створити файл .eslintrc в якому будуть правила і стиль нашого коду (code convention). Для прикладу можна взяти даний варіант:

{
  "root": true,
  "env": {
    "es6": true,
    "browser": true,
    "commonjs": true
  },
  "globals": {
  },
  "ecmaFeatures": {
    "modules": true,
    "spread": true,
    "restParams": true
  },
  "parserOptions": {
    "sourceType": "module"
  },
  "extends": "eslint:recommended",
  "rules": {
    "strict": [
      "warn",
      "global"
    ],
    "no-multi-spaces": "warn",
    "curly": [
      "warn",
      "all"
    ],
    "operator-linebreak": [
      "warn",
      "after"
    ],
    "camelcase": [
      "warn",
      {
        "properties": "always"
      }
    ],
    "max-len": [
      "warn",
      120
    ],
    "indent": [
      "warn",
      "tab",
      {
        "SwitchCase": 1
      }
    ],
    "no-multi-str": "warn",
    "no-mixed-spaces-and-tabs": "warn",
    "no-trailing-spaces": "warn",
    "space-unary-ops": [
      "warn",
      {
        "nonwords": false,
        "overrides": {}
      }
    ],
    "brace-style": [
      "warn",
      "1tbs",
      {
        "allowSingleLine": true
      }
    ],
    "keyword-spacing": [
      "warn",
      {}
    ],
    "space-infix-ops": "warn",
    "space-before-blocks": [
      "warn",
      "always"
    ],
    "eol-last": "warn",
    "space-before-function-paren": [
      "warn",
      "always"
    ],
    "array-bracket-spacing": [
      "warn",
      "never",
      {
        "singleValue": true
      }
    ],
    "space-in-parens": [
      "warn",
      "never"
    ],
    "no-multiple-empty-lines": "warn",
    "no-with": "warn",
    "no-spaced-func": "warn",
    "key-spacing": [
      "warn",
      {
        "beforeColon": false,
        "afterColon": true
      }
    ],
    "no-unused-vars": [
      "warn",
      {
        "vars": "all",
        "args": "all"
      }
    ],
    "dot-notation": "warn",
    "semi": [
      "warn",
      "always"
    ]
  }
}

Описувати що кожне правило значить немає великого сенсу. Цю інформацію можна отримати на офіційному сайті – ESLint rules. Важливо нагадати що в даному прикладі всі правила будуть повертати попередження (warn) а не помилки (error). Це легко змінити замінивши “warn” на “error”. Попередження замість помилок будуть корисні, якщо у вас уже написано багато коду, і не хочеться щоб на все поверталися помилки, а їх можуть бути тисячі.

Дані правила розширюють уже існуючі і рекомендовані, які називаються “eslint:recommended”. Повний список правил можна знайти на GitHub проекту – список правила “eslint:recommended”.

По цих правилах буде виконуватись аналіз всього коду який ви вкажете. Якщо якісь папки або файли потрібно виключити з аналізу, можна додати файл .eslintignore , наприклад з таким вмістом:


**/vendor/**
**/excluded/*.js

Тепер потрібно налаштувати IDE щоб вона могла автоматично підсвічувати помилки в коді. Для цього переходимо в File/Settings/Languages & Frameworks/JavaScript/Code Quality Tools/ESLint. Вмикаємо перевірку (Enable) і вказуємо шляхи до NodeJs, ESLint модуля і до файлу з правилами, які ми щойно описали.

Якщо ще не встановлений модуль ESLint, то потрібно виконати команду:

npm install eslint -g

Встановивши його глобально “-g” тепер можна запустити аналіз любого файлу або папки (src – це назва папки в якій лежать інші папки і файли .js)

eslint src

В консолі ми повинні отримати список файлів в яких виявлені помилки. Нижче приклад взятий з інету:

Наступним кроком буде додавання команди на лінтінг в package.json файл. Це не обов’язково, але якщо робити проект якісно, то ця команда має бути там вказана. Додаємо її в розділ scripts:

"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "node index.js",
    "lint": "eslint src"
  },

Тепер виконати лінтінг можна командою:

npm run lint

Нашу команду ми назвали “lint” хоча можна використовувати будь-яке слово.

Автоматична перевірка коду перед комітом (pre-commit).

Тепер найголовніше.

Написати правила і налаштувати IDE – це хорошо, але вони не можуть заставити нікого писати код якісно і запускати цей аналіз. Тому ми додаєме git hook – команду для Гіта, щоб перед кожним комітом він виконував аналіз і забороняв цей коміт, якщо виявлені помилки. Для цього не забудьть в усіх правилах змінити рівень з “warn” на “error”. В цьому випадку аналіз буде завершуватись з помилкою і код не буде закомічений. Це врятує тих хто потім буде перевіряти даний код)

Для цього необхідно зайти в папку .git/hooks вашого проекту (зазвичай вона прихована і її не видно в IDE) і додати туди файл pre-commit (файл без розширення). Приклад:

#!/bin/sh

npm run lint

Тепер кожен коміт буде автоматично перевірятися на якість коду.

Автоматичне форматування коду (Reformat code).

Якщо після запуску аналізу в консолі було виведено що знайдено 4000-5000 помилок – не потрібно засмучуватись. Більшість з них можна виправити автоматичним форматуванням, яке в IDE WebStorm виконується дуже просто. Необхідно вибрати потрібну папку, а в пункті меню вибрати Code/Reformat Code або Ctrl+Alt+l.

Форматування коду виконується по описаних вами правилах або ручними налаштуваннями в IDE. Чи використовує WebStorm правила описані в Code Quality ESlint для форматування – я не впевнений, але точно знаю що правила можна вказати у файлі конфігурації JSCS .jscsrc . Не даремно я згадував про нього на початку статті.

WebStorm на даний момент (березень 2017р.) не підтримує Code Style імпорт з ESLint файлу, але добре працює з JSCS. Правила описані для ESLint можна просто конвертувати у відповідний формат за допомогою модуля polyjuice.

npm install --save-dev polyjuice

Встановивши його можна виконувати конвертування:

To ESLint

You must provide the files to be assessed by using the options --jshint and --jscs, for instance:

$ polyjuice --jshint .jshintrc --jscs .jscsrc > .eslintrc

Note you are allowed to pass in any number of files
To JSHint and JSCS

You must provide the file to be assessed by using the option --eslint and also which output you want by using either --to-jshint or --to-jscs, for instance:

$ polyjuice --eslint .eslintrc --to-jshint > .jshintrc

Note you are allowed to pass in any number of files

Отриманий на виході файл потрібно імпортувати в IDE. Після застосування змін можна форматувати наш код автоматично, відповідно до описаних правил. Це реально збереже багато часу і нервів.

Приклад коду конфігурації .jscsrc:

{
  "requireCurlyBraces": [
    "if",
    "else",
    "for",
    "while",
    "do",
    "try",
    "catch"
  ],
  "requireOperatorBeforeLineBreak": true,
  "requireCamelCaseOrUpperCaseIdentifiers": {
    "allExcept": ["browser_version"]
  },
  "maximumLineLength": {
    "value": 120,
    "allExcept": ["comments", "regex"]
  },
  "validateIndentation": {
    "value": "\t",
    "allExcept": ["emptyLines"]
  },
  "disallowMultipleLineStrings": true,
  "disallowMixedSpacesAndTabs": true,
  "disallowTrailingWhitespace": true,
  "disallowSpaceAfterPrefixUnaryOperators": true,
  "disallowKeywordsOnNewLine": ["else"],
  "requireSpaceAfterKeywords": [
    "if",
    "else",
    "for",
    "while",
    "do",
    "switch",
    "return",
    "try",
    "catch"
  ],
  "requireSpaceBeforeBinaryOperators": [
    "=", "+=", "-=", "*=", "/=", "%=", "<<=", ">>=", ">>>=",
    "&=", "|=", "^=", "+=",

    "+", "-", "*", "/", "%", "<<", ">>", ">>>", "&",
    "|", "^", "&&", "||", "===", "==", ">=",
    "<=", "<", ">", "!=", "!=="
  ],
  "requireSpaceAfterBinaryOperators": true,
  "requireSpacesInConditionalExpression": true,
  "requireSpaceBeforeBlockStatements": true,
  "requireSpacesInForStatement": true,
  "requireLineFeedAtFileEnd": true,
  "requireSpacesInFunctionExpression": {
    "beforeOpeningCurlyBrace": true,
    "beforeOpeningRoundBrace": true
  },
  "requireSpacesInFunctionDeclaration": {
    "beforeOpeningRoundBrace": true,
    "beforeOpeningCurlyBrace": true
  },
  "disallowSpacesInsideObjectBrackets": "all",
  "disallowSpacesInsideArrayBrackets": "all",
  "disallowSpacesInsideParentheses": true,

  "disallowMultipleLineBreaks": true,
  "disallowNewlineBeforeBlockStatements": true,
  "disallowKeywords": ["with"],
  "disallowSpacesInCallExpression": true,
  "disallowSpaceAfterObjectKeys": true,
  "disallowUnusedVariables": true,
  "requireSpaceBeforeObjectValues": true,
  "requireCapitalizedConstructors": true,
  "requireDotNotation": true,
  "requireSemicolons": true,
  "validateParameterSeparator": ", ",
  "requireSpaceBetweenArguments": true
}

І останнє.

Всі правила можна доналаштовувати вручну. В прикладах скриптів налаштування не вказане одне важливе правило, яке часто використовується в роботі. Перенесення аргументів функції на новий рядок, якщо їхня довжина перевищує максимальну довжину рядку (в нашому випадку це 120 символів). Вибираємо Code Style/JavaScript табу Wrapping and Braces і в ній знаходимо Function declaration parameters. Вибираємо найбільш підходящий варіант і забираємо позначку Align when multiline  – це допоможе вберегтися від помилки no-mixed-spaces-and-tabs, тому що при переносі можливий варіант, що перед аргументом буде стояти пробіл (ну це звичайно якщо в іншому правилі вказано щоб ці пробіли були обов’язкові між аргументами)

Тепер ваш код буде набагато якіснішим і його буде приємніше читати (якщо не дивитись що там написано). Зі свого досвіду використання цих правил, можу сказати що на початку вони будуть жахливо бісити, особливо коли треба щось вмержити швиденько, але з часом звикаєш писати якісно і у відповідності до цих правил.

Схожі статті