Пишем свои ESLint-правила

Леонид Лебедев, Яндекс.Маркет

Пишем свои ESLint-правила

Леонид Лебедев, Яндекс.Маркет

О себе

Цель доклада

План

  1. Введение
  2. Теория
  3. Практика
  4. Альтернативы
  5. Выводы

План

  1. Введение
  2. Теория
  3. Практика
  4. Альтернативы
  5. Выводы

ESLint

Зачем использовать?

Популярные руководства

  1. Airbnb JavaScript Style Guide (eslint-config-airbnb)
  2. JavaScript Standard Style Guide (eslint-config-standard)
  3. Google JavaScript Style Guide (eslint-config-google)
  4. Idiomatic JavaScript Style Guide

Зачем писать свои правила?

План

  1. Введение
  2. Теория
  3. Практика
  4. Альтернативы
  5. Выводы

Теория

  1. Плагин
  2. AST
  3. Правило ESLint

Плагин

Модуль, который расширяет набор встроенных правил

Встроенные правила: no-var, no-tabs

eslint-plugin-react: react/jsx-uses-vars, react/display-name

Плагин

Создать плагин можно с помощью Yeoman генератора от ESLint
yo eslint:plugin

            eslint-plugin-market
                /docs
                /lib
                /tests
                package.json
        

Плагин

lib/index.js
            module.exports = {
                rules: {
                    'no-only': {...},
                },
            };
        

Плагин

В проектном .eslintrc.js подключаем созданный плагин
                module.exports = {
                    plugins: ['market'],
                    rules: {
                        'market/no-only': 'error',
                    },
                };
            

AST

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

AST

                    function sum(a, b) {
                        return a + b;
                    }
                

AST

                    function sum(a, b) {
                        return a + b;
                    }
                
Program

AST

                    function sum(a, b) {
                        return a + b;
                    }
                
Program
FunctionDeclaration
<span><font style="font-size: 24px">FunctionDeclaration</font></span><br>

AST

                    function sum(a, b) {
                        return a + b;
                    }
                
Program
FunctionDeclaration
<span><font style="font-size: 24px">FunctionDeclaration</font></span><br>
params: [...]
generator: false
async: false
expression: false

AST

                    function sum(a, b) {
                        return a + b;
                    }
                
Program
FunctionDeclaration
<span><font style="font-size: 24px">FunctionDeclaration</font></span><br>
params: [...]
generator: false
async: false
expression: false
BlockStatement
<span><font style="font-size: 24px">BlockStatement</font></span><br>

AST

                    function sum(a, b) {
                        return a + b;
                    }
                
Program
FunctionDeclaration
<span><font style="font-size: 24px">FunctionDeclaration</font></span><br>
params: [...]
generator: false
async: false
expression: false
BlockStatement
<span><font style="font-size: 24px">BlockStatement</font></span><br>
ReturnStatement
<span style="font-size: 24px">ReturnStatement</span>

AST

                    function sum(a, b) {
                        return a + b;
                    }
                
Program
FunctionDeclaration
<span><font style="font-size: 24px">FunctionDeclaration</font></span><br>
params: [...]
generator: false
async: false
expression: false
BlockStatement
<span><font style="font-size: 24px">BlockStatement</font></span><br>
ReturnStatement
<span style="font-size: 24px">ReturnStatement</span>
BinaryExpression
<span style="font-size: 24px">BinaryExpression</span>

AST

                    function sum(a, b) {
                        return a + b;
                    }
                
Program
FunctionDeclaration
<span><font style="font-size: 24px">FunctionDeclaration</font></span><br>
params: [...]
generator: false
async: false
expression: false
BlockStatement
<span><font style="font-size: 24px">BlockStatement</font></span><br>
ReturnStatement
<span style="font-size: 24px">ReturnStatement</span>
BinaryExpression
<span style="font-size: 24px">BinaryExpression</span>
                    function sum(a, b) {
                        return a + b;
                    }
                

Правила

Файл, содержащий условия, при котором ESLint сообщает о проблеме

            module.exports = {
                meta: {...},
                create(context) {...},
            };
        
Working with Rules
            meta: {
                type: 'problem',
                docs: {
                     description: 'Function declarations are disallowed',
                     category: 'Possible Errors',
                },
                fixable: 'code',
                schema: [],
            },
        
            create(context) {
                return {
                    [selector](node) {
                        context.report ({...});
                    },
                };
            }
        
            create(context) {
                return {
                    [selector](node) {
                        context.report ({...});
                    },
                };
            }
        
            context: {
                id,
                options,
                report({...}),
                ... (опции парсера)
            }
        
            context: {
                id,
                options,
                report({...}),
                ... (опции парсера)
            }
        
            context.report({
                node,
                message: 'Don\'t use "only"',
                loc: {start: ..., end: ...},
                fix(fixer) {...},
            });
        
            create(context) {
                return {
                    [selector](node) {
                        context.report ({...});
                    },
                };
            }
        

Селектор

Селектор — это строка, которая будет использоваться для сопоставления узлам AST.

Селектор

                    function sum(a, b) {
                        return a + b;
                    }
                
Program
FunctionDeclaration
<span><font style="font-size: 24px">FunctionDeclaration</font></span><br>
BlockStatement
<span><font style="font-size: 24px">BlockStatement</font></span><br>
ReturnStatement
<span style="font-size: 24px">ReturnStatement</span>
BinaryExpression
<span style="font-size: 24px">BinaryExpression</span>

Примеры селекторов

            create(context) {
                return {
                    [selector](node) {
                        context.report ({
                            node,
                            message: 'Don\'t use "only"',
                        });
                    },
                };
            }
        

План

  1. Введение
  2. Теория
  3. Практика
  4. Альтернативы
  5. Выводы
            const {makeSuite} = require('ginny');
             
            module.exports = makeSuite('Проверка кнопки «Купить»', {
                id: 'market-215',
                test() {
                    return this.expect(this.button.name).toBe('Купить');
                },
            });
        
            const {makeSuite} = require('ginny');
             
            module.exports = makeSuite('Проверка кнопки «Купить» only', {
                id: 'market-215',
                test() {
                    return this.expect(this.button.name).toBe('Купить');
                },
            });
        

План

  1. Введение
  2. Теория
  3. Практика
  4. Альтернативы
  5. Выводы

Альтернативы

План

  1. Введение
  2. Теория
  3. Практика
  4. Альтернативы
  5. Выводы

Выводы

Контакты

github: leonidlebedev
telegram: leonidlebedev
email: leonidlebedev@yandex-team.ru
Презентация: /presentations