【AST】Научит вас писать плагины для Eslint.

JavaScript
【AST】Научит вас писать плагины для Eslint.

предисловие

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

В этой статье я расскажу вам об общей истории различных инструментов Lint, а затем шаг за шагом создам свой собственный плагин ESLint и научу вас его использовать.ASTАбстрактное синтаксическое дерево для формулировки правил этого плагина.

Это поможет вам понять принцип реализации ESLint.

Цели и очки знаний

эта статьяESLintЦель плагина — отключить в разработке проекта:console.time().

  • Абстрактное синтаксическое дерево AST
  • ESLint
  • публиковать нпм
  • модульный тест

Сборка строительных лесов плагинов

Здесь мы используемyeomanа такжеgenerator-eslintСкаффолдинг-код для сборки плагина. Установить:

npm install -g yo generator-eslint

Создайте новую локальную папку eslint-plugin-demofortutorial:

mkdir eslint-plugin-demofortutorial
cd eslint-plugin-demofortutorial

Инициализируйте структуру проекта плагина ESLint:

yo eslint:plugin // 搭建一个初始化的目录结构

Структура каталогов файла на данный момент такова:

.
├── README.md
├── lib
│   ├── index.js
│   └── rules
├── package.json
└── tests
    └── lib
        └── rules

Установите зависимости:

npm install

На этом этапе среда настроена.

Создать правило

Терминальное исполнение:

yo eslint:rule // 生成默认 eslint rule 模版文件

На данный момент структура проекта такова:

.
├── README.md
├── docs // 使用文档
│   └── rules
│       └── no-console-time.md
├── lib // eslint 规则开发
│   ├── index.js
│   └── rules // 此目录下可以构建多个规则,本文只拿一个规则来讲解
│       └── no-console-time.js
├── package.json
└── tests // 单元测试
    └── lib
        └── rules
            └── no-console-time.js

В приведенной выше структуре нам нужно разрабатывать плагины Eslint в каталоге ./lib/, вот расположение определяющих его правил.

АСТ в ESLint

в официальной письменной формеESLintПеред подключением необходимо понятьESLintПринцип работы. вESLintМетод использования должен быть знаком всем, я не буду его здесь объяснять, если вы не понимаете, вы можете нажать на официальную документацию.Как настроить ESLint в своем проекте.

При разработке командных проектов компании исходный код, написанный разными разработчиками, отличается, то вESLintКак анализировать исходный код, написанный каждым человеком?

Как разработчики, перед лицом таких проблем мы должны знать, как использоватьабстрактные средства! ТакJavascriptКак воплощается абстракция?

Вот такAST(Абстрактное синтаксическое дерево (AST)), а затем идет стократно просмотренная диаграмма предложения.

существуетESLint, esprima используется по умолчанию для разбора того, что мы пишемJavascriptоператор, пусть он сгенерирует абстрактное синтаксическое дерево, а затем перейдите кперехватыватьПроверьте, соответствует ли он нашему предписанному методу записи, и, наконец, позвольте ему отобразить ошибку, предупреждение или нормальный проход.ESLintСуть в правиле(rules), а ядро ​​определения правил является использованиеASTпроверить. Каждое правило не зависит друг от друга и может быть отключено установкойoff,предупреждатьwarn⚠️ и ошибкаerror❌, разумеется, никаких подсказок для нормального прохождения давать не нужно.

создание правила

вышеизложенное закончилосьESLintа такжеASTПосле отношений мы можем официально ввести разработку конкретных правил. Сначала посмотрите на ранее сгенерированныйlib/rules/no-console-time.js:

/**
 * @fileoverview no console.time()
 * @author Allan91
 */
"use strict";

//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------

module.exports = {
    meta: {
        docs: {
            description: "no console.time()",
            category: "Fill me in",
            recommended: false
        },
        fixable: null,  // or "code" or "whitespace"
        schema: [
            // fill in your schema
        ]
    },

    create: function(context) {

        // variables should be defined here

        //----------------------------------------------------------------------
        // Helpers
        //----------------------------------------------------------------------

        // any helper functions should go here or else delete this section

        //----------------------------------------------------------------------
        // Public
        //----------------------------------------------------------------------

        return {

            // give me methods

        };
    }
};

Этот файл дает шаблон для написания правил, одно правило соответствует экспортируемомуnodeмодуль, который состоит изmetaа такжеcreateСостоит из двух частей.

  • meta представляет собой метаданные этого правила, такие как его категория, документ, схема допустимых параметров и т. д.
  • create: если meta выражает то, что мы хотим сделать, то create выражает то, как это правило будет анализировать код;

Create возвращает объект, наиболее распространенный из которыхимя ключадаASTв абстрактном синтаксическом деревеСелектор, в этом селекторе мы можем получить соответствующий выбранный контент, а затем мы можем сделать определенные суждения для выбранного контента, чтобы увидеть, удовлетворяет ли он нашим правилам. Если не устраивает, доступенcontext.reportкидать вопросы,ESLintБудет использовать нашу конфигурацию для отображения брошенного контента по-другому.

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

Создано этой статьейESLintПлагины предназначены для предотвращения использования их разработчиками в проектах.console.time(), сначала посмотрите, как этот код выглядит в абстрактном синтаксическом дереве:

Среди них мы будем использовать следующий контент, чтобы определить, содержит ли кодconsole.time:

Тогда мы на основе вышеизложенногоAST(Абстрактный китайский метод)lib/rules/no-console-time.jsНапишите правила так:

/**
 * @fileoverview no console.time()
 * @author Allan91
 */
"use strict";

//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------

module.exports = {
    meta: {
        docs: {
            description: "no console.time()",
            category: "Fill me in",
            recommended: false
        },
        fixable: null,  // or "code" or "whitespace"
        schema: [
            // fill in your schema
        ],
        // 报错信息描述
        messages: {
            avoidMethod: "console method '{{name}}' is forbidden.",
        },
    },

    create: function(context) {
        return {
            // 键名为ast中选择器名
            'CallExpression MemberExpression': (node) => {
                // 如果在ast中满足以下条件,就用 context.report() 进行对外警告⚠️
                if (node.property.name === 'time' && node.object.name === 'console') {
                    context.report({
                        node,
                        messageId: 'avoidMethod',
                        data: {
                            name: 'time',
                        },
                    });
                }
            },
        };
    }
};

Изменить сноваlib/index.js:

"use strict";

module.exports = {
    rules: {
        'no-console-time': require('./rules/no-console-time'),
    },
    configs: {
        recommended: {
            rules: {
                'demofortutorial/no-console-time': 2, // 可以省略 eslint-plugin 前缀
            },
        },
    },
};

Слишком далеко,EslintПлагин создан. Все, что вам нужно сделать дальше, это опубликовать этот проект вплатформа нпм. Выполнение корневого каталога:

npm publish

Открытьnpmплатформу, вы можете выполнить поиск по опубликованным вышеeslint-plugin-demofortutorialПакет узлов.

как использовать

После публикации установите этот пакет в нужные вам проекты:

npm install eslint-plugin-demofortutorial -D

затем в.eslintrc.jsСредняя конфигурация:

"extends": [
    "eslint:recommended",
    "plugin:eslint-plugin-demofortutorial/recommended",
],
"plugins": [
    'demofortutorial'
],

если не раньше.eslintrc.jsфайл, вы можете выполнить следующую команду для создания:

npm install -g eslint
eslint --init

На этом этапе, если текущий проектJSзапись в документеconsole.time, появятся следующие эффекты:

Модульное тестирование (идеальное)

для полногоnpmС точки зрения пакетов вышеописанное является лишь «полуфабрикатом», и нам необходимо написать юнит-тесты, чтобы обеспечить его целостность и безопасность.

Далее, чтобы завершить модульный тест, в./tests/lib/rules/no-console-time.jsНапишите следующий код в:

'use strict';

// ------------------------------------------------------------------------------
// Requirements
// ------------------------------------------------------------------------------

let rule = require('../../../lib/rules/no-console-time');

let RuleTester = require('eslint').RuleTester;

// ------------------------------------------------------------------------------
// Tests
// ------------------------------------------------------------------------------

let ruleTester = new RuleTester({
    parserOptions: {
        ecmaVersion: 10,
    },
});

ruleTester.run('no-console-time', rule, {

    valid: [ // 合法示例
        '_.time({a:1});',
        "_.time('abc');",
        "_.time(['a', 'b', 'c']);",
        "lodash.time('abc');",
        'lodash.time({a:1});',
        'abc.time',
        "lodash.time(['a', 'b', 'c']);",
    ],

    invalid: [ // 不合法示例
        {
            code: 'console.time()',
            errors: [
                {
                    messageId: 'avoidMethod',
                },
            ],
        },
        {
            code: "console.time.call({}, 'hello')",
            errors: [
                {
                    messageId: 'avoidMethod',
                },
            ],
        },
        {
            code: "console.time.apply({}, ['hello'])",
            errors: [
                {
                    messageId: 'avoidMethod',
                },
            ],
        },
        {
            code: 'console.time.call(new Int32Array([1, 2, 3, 4, 5]));',
            errors: 1,
        },
    ],
});

Подробнее о приведенном выше тестовом коде см.официальная документация.

Выполнение корневого каталога:

npm run test

На этом разработка этого пакета завершена. Разработка других правил аналогична, например, вы можете продолжить разработку других спецификаций, таких как ️console.log(),debuggerПредупреждение и тд.

разное

из-за автогенерацииESLintпроект зависит отeslintВерсия все еще находится на стадии 3.x, что приведет к следующим ошибкам при разборе синтаксиса модульного теста:

'Parsing error: Invalid ecmaVersion.'

Рекомендуется обновить пакет до"eslint": "^5.16.0".



над.

ПроверитьРепозиторий проекта на Github

ПроверитьПакеты, опубликованные на Npm





Использованная литература:

zhuanlan.zhihu.com/p/32297243 En. Wikipedia.org/wiki/lint_(… octoverse.github.com/ jslint.com medium.com/@Anton/why-… Woohoo.Фермер online.net/blog/2013/0… eslint.org jscs.info GitHub.com/Вавилон/Вавилон… GitHub.com/Yanni Passenger Access/О… Woohoo.Фермер online.net/blog/2016/0… medium.com/@mark E log/ просто…

Внеклассные знания: краткая история Lint

Lint 是为了解决代码不严谨而导致各种问题的一种工具。 Например==а также===Сочетание может вызвать некоторые странные проблемы.

JSLint и JSHint

В 2002 году Дуглас Крокфорд разработал, возможно, первый инструмент проверки синтаксиса для JavaScript — JSLint, исходный код которого был открыт в 2010 году.

JSLint действительно помог многим разработчикам JavaScript сэкономить много времени на устранении неполадок в своем коде с момента его появления. Но проблема с JSLint тоже очевидна —трудно настраиваемый, все стили кода и правила встроены; кроме того, Дуглас Крокфорд соблюдает прекрасную традицию «использовать и использовать» в даосизме и не будет нарушать открытую конфигурацию или изменять правила, которые он считает правильными. Так что Антон Ковалев пожаловался: «JSLint нужен только для того, чтобы сделать стиль вашего кода более похожим на Дугласа Крокфорда», и в 2011 году форкнул оригинальный проект для разработки JSHint.«Почему я разветвил JSLint на JSHint»

Характеристики JSHint:Настраиваемый, а документация относительно полная и удобная для разработчиков. Вскоре люди перешли с JSLint на JSHint.

Рождение ESLint

В ближайшие несколько лет все будут использовать JSHint в первую очередь для инструментов обнаружения кода, но поворотный момент наступил в 2013 году, когда Закас обнаружил, что JSHint не может удовлетворить потребности его собственного нормотворчества, и сотрудничал с Антоном. После обсуждения выяснилось, что на JShint этого добиться невозможно, и Закас также предполагает изобрестиASTкорп. Итак, в июне 2013 года Zakas выпустила новый инструмент для анализа — ESLint.«Знакомство с ESLint»

Ранний исходный код ESLint:

var ast = esprima.parse(text, { loc: true, range: true }),
    walk = astw(ast);

walk(function(node) {
    api.emit(node.type, node);
});

return messages;

Контратака ESLint

Появление ESLint не поколебало доминирования JSHint.Поскольку первый использует правила обработки AST и использует Esprima для разбора кода, скорость выполнения намного ниже, чем у JSHint, для которого требуется всего один шаг.; Во-вторых, уже было много редакторов, которые имели идеальную поддержку JSHint, и экология была достаточно сильна. Что действительно делает ESLint контратакой, так этоECMAScript 6внешность.

В июне 2015 года была официально выпущена спецификация ES2015. Однако после релиза представленные на рынке браузеры имеют крайне ограниченную поддержку последних стандартов. Если вы хотите заранее испытать новейший стандартный синтаксис, вы должны полагаться наBabelПодобные инструменты компилируют код до ES5 или ниже, а некоторые экспериментальные функции можно транспилировать с помощью Babel. Но в настоящее время JSHint не может обеспечить поддержку в краткосрочной перспективе, а ESLint нужен только подходящий синтаксический анализатор для продолжения проверки lint. Команда Babel разработала инструмент для ESLint, чтобы заменить парсер по умолчанию, что мы и видим сейчас.babel-eslint, что делает ESLint первым инструментом lint, поддерживающим синтаксис ES6.

Также в 2015 году все более широкое распространение становился React, а появившийся вскоре JSX становился все более популярным. Сам ESLint также не поддерживает синтаксис JSX. Но из-за масштабируемости,eslint-plugin-reactПоявление ESLint позволяет ESLint в то же время поддерживать правила, специфичные для React.

В 2016 году команда разработчиков JSCS посчитала, что принципы реализации ESLint и JSCS слишком похожи, а проблемы, которые нужно было решить, были одинаковыми, и в конце концов решила объединиться с ESLint и прекратить обслуживание JSCS.

Текущие основные инструменты lint и графики трендов на рынке:

С тех пор ESLint доминировал в реках и озерах и стал основным интерфейсным инструментом для замены JSHint.