Метаданные правила

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

Объект метаданных располагается в свойстве meta экспортируемого правила:

module.exports = {
    meta: {
        // метаданные правила
    },

    create(context) {
        return {};
    }
};

Метаданные не участвуют непосредственно в анализе AST, однако играют важную роль при работе редакторов кода, генерации документации, автоматическом исправлении ошибок и конфигурировании наборов правил.


Структура объекта meta

Типичная структура метаданных выглядит следующим образом:

module.exports = {
    meta: {
        type: "problem",

        docs: {
            description: "Disallow foo identifiers",
            recommended: true
        },

        fixable: "code",

        hasSuggestions: true,

        schema: [],

        messages: {
            forbiddenFoo: "Identifier 'foo' is not allowed."
        }
    },

    create(context) {
        return {};
    }
};

Основными свойствами являются:

  • type
  • docs
  • fixable
  • hasSuggestions
  • schema
  • messages
  • deprecated
  • replacedBy

Некоторые из них обязательны только в определённых ситуациях.


Свойство type

Поле type определяет категорию правила. ESLint использует эту информацию для классификации найденных проблем.

Допустимые значения:

Значение Назначение
problem Ошибки, потенциально приводящие к неправильной работе программы
suggestion Улучшение структуры и качества кода
layout Форматирование и оформление кода

Тип problem

Используется для обнаружения реальных ошибок.

Пример:

meta: {
    type: "problem"
}

Подобные правила могут обнаруживать:

  • использование несуществующих переменных;
  • недостижимый код;
  • ошибочные конструкции языка.

Тип suggestion

Предназначен для рекомендаций по улучшению кода.

meta: {
    type: "suggestion"
}

Такие правила могут:

  • предлагать более современные конструкции;
  • запрещать устаревшие подходы;
  • обеспечивать единообразие архитектуры.

Тип layout

Используется исключительно для оформления.

meta: {
    type: "layout"
}

Примеры:

  • количество пробелов;
  • расположение фигурных скобок;
  • переносы строк;
  • выравнивание элементов.

Свойство docs

Раздел docs содержит информацию о документации правила.

Пример:

meta: {
    docs: {
        description: "Disallow foo identifiers",
        recommended: true
    }
}

description

Краткое описание назначения правила.

docs: {
    description: "Disallow foo identifiers"
}

Описание используется:

  • в документации плагинов;
  • при генерации справочных материалов;
  • различными инструментами анализа.

Описание должно быть коротким и понятным.


Флаг указывает, входит ли правило в рекомендуемый набор.

docs: {
    description: "Disallow foo identifiers",
    recommended: true
}

Значения:

recommended: true

или

recommended: false

Если правило включено в рекомендуемую конфигурацию, пользователи получают его автоматически после подключения набора рекомендаций.


url

Во многих современных плагинах указывается ссылка на документацию правила.

docs: {
    description: "Disallow foo identifiers",
    url: "https://example.com/rules/no-foo"
}

Редакторы кода могут отображать эту ссылку непосредственно в сообщениях ESLint.


Свойство fixable

Поле fixable сообщает ESLint, что правило поддерживает автоматическое исправление.

Допустимые значения:

fixable: "code"

или

fixable: "whitespace"

fixable: “code”

Используется, когда правило изменяет программную логику или структуру кода.

meta: {
    fixable: "code"
}

Пример автоматического исправления:

context.report({
    node,
    messageId: "replaceVar",
    fix(fixer) {
        return fixer.replaceText(node, "let");
    }
});

fixable: “whitespace”

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

meta: {
    fixable: "whitespace"
}

Примеры:

  • добавление пробелов;
  • удаление лишних пробелов;
  • исправление отступов.

Важность указания fixable

Если правило использует функцию fix, но не содержит свойство:

fixable: "code"

или

fixable: "whitespace"

ESLint выдаст ошибку при загрузке правила.

Таким образом предотвращается случайное создание исправлений без соответствующего объявления.


Свойство hasSuggestions

Начиная с современных версий ESLint правила могут не только автоматически исправлять код, но и предлагать варианты исправлений.

Для этого используется:

meta: {
    hasSuggestions: true
}

Назначение предложений

Предложения отображаются в редакторах:

  • Visual Studio Code;
  • WebStorm;
  • Neovim с интеграцией ESLint;
  • других IDE.

Пользователь самостоятельно выбирает подходящий вариант исправления.


Пример

Метаданные:

meta: {
    hasSuggestions: true
}

Отчёт:

context.report({
    node,
    messageId: "avoidVar",

    suggest: [
        {
            messageId: "replaceWithLet",

            fix(fixer) {
                return fixer.replaceText(node, "let");
            }
        }
    ]
});

Обязательность hasSuggestions

Если правило использует массив:

suggest: []

но в метаданных отсутствует:

hasSuggestions: true

ESLint завершит работу с ошибкой.


Свойство schema

Свойство schema описывает структуру параметров правила.

Оно позволяет:

  • проверять корректность конфигурации;
  • предотвращать ошибки пользователей;
  • автоматически документировать параметры.

Пустая схема

Если правило не принимает параметры:

meta: {
    schema: []
}

Это наиболее распространённый вариант.


Схема с объектом

Предположим, правило принимает настройку:

{
    allowFoo: true
}

Тогда схема может выглядеть следующим образом:

meta: {
    schema: [
        {
            type: "object",
            properties: {
                allowFoo: {
                    type: "boolean"
                }
            },
            additionalProperties: false
        }
    ]
}

Проверка конфигурации

Конфигурация:

{
    "my-plugin/no-foo": [
        "error",
        {
            allowFoo: true
        }
    ]
}

Будет успешно обработана.

Однако настройка:

{
    "my-plugin/no-foo": [
        "error",
        {
            allowFoo: "yes"
        }
    ]
}

приведёт к ошибке валидации, поскольку ожидается логическое значение.


Использование JSON Schema

Поле schema базируется на стандарте JSON Schema.

Поддерживаются такие конструкции, как:

type
properties
required
enum
items
minimum
maximum
oneOf
anyOf
allOf

Пример ограничения набора значений:

schema: [
    {
        enum: ["always", "never"]
    }
]

Допустимая конфигурация:

["error", "always"]

Недопустимая:

["error", "sometimes"]

Свойство messages

Раздел messages содержит шаблоны сообщений об ошибках.

Вместо непосредственной передачи текста в context.report() рекомендуется использовать идентификаторы сообщений.


Пример

Метаданные:

meta: {
    messages: {
        forbiddenFoo: "Identifier 'foo' is forbidden."
    }
}

Использование:

context.report({
    node,
    messageId: "forbiddenFoo"
});

Преимущества messageId

Использование идентификаторов обеспечивает:

  • единообразие сообщений;
  • централизованное хранение текстов;
  • упрощение сопровождения;
  • удобство локализации.

Подстановка параметров в сообщения

Сообщения могут содержать плейсхолдеры.

Метаданные:

messages: {
    forbiddenName:
        "Identifier '{{name}}' is forbidden."
}

Отчёт:

context.report({
    node,
    messageId: "forbiddenName",
    data: {
        name: node.name
    }
});

Результат:

Identifier 'foo' is forbidden.

Свойство deprecated

Если правило считается устаревшим, используется флаг:

meta: {
    deprecated: true
}

Это сообщает пользователям и инструментам, что правило больше не рекомендуется к использованию.


Причины устаревания

Наиболее распространённые причины:

  • появление более совершенного правила;
  • изменение API ESLint;
  • объединение нескольких правил в одно;
  • прекращение поддержки функциональности.

Свойство replacedBy

Для устаревших правил можно указать замену.

meta: {
    deprecated: true,
    replacedBy: ["new-rule"]
}

При просмотре документации становится понятно, каким правилом следует заменить старое.


Несколько замен

Иногда одно правило разбивается на несколько новых.

meta: {
    deprecated: true,
    replacedBy: [
        "new-rule-a",
        "new-rule-b"
    ]
}

Полный пример метаданных

module.exports = {
    meta: {
        type: "suggestion",

        docs: {
            description:
                "Disallow foo identifiers",
            recommended: true,
            url:
                "https://example.com/rules/no-foo"
        },

        fixable: "code",

        hasSuggestions: true,

        schema: [
            {
                type: "object",
                properties: {
                    allowFoo: {
                        type: "boolean"
                    }
                },
                additionalProperties: false
            }
        ],

        messages: {
            forbiddenFoo:
                "Identifier 'foo' is forbidden.",

            replaceWithBar:
                "Replace with 'bar'."
        }
    },

    create(context) {
        return {};
    }
};

В данном примере правило:

  • относится к категории рекомендаций;
  • входит в рекомендуемый набор;
  • имеет документацию;
  • поддерживает автоматическое исправление;
  • предоставляет предложения для IDE;
  • валидирует пользовательские параметры;
  • использует централизованные сообщения об ошибках.

Взаимосвязь метаданных и context.report

Большинство возможностей context.report() опирается на сведения из объекта meta.

Соответствие выглядит следующим образом:

Возможность Свойство meta
Автоисправление fixable
Предложения hasSuggestions
Идентификаторы сообщений messages
Настройки правила schema
Документация docs
Категория правила type

Из-за этой взаимосвязи объект meta фактически выступает контрактом между правилом, ядром ESLint, редакторами кода и инструментами экосистемы.


Практические рекомендации по проектированию метаданных

При разработке собственных правил обычно придерживаются следующих принципов:

  1. Всегда указывать type.
  2. Добавлять подробное описание в docs.description.
  3. Использовать messageId вместо строковых сообщений внутри context.report().
  4. Определять schema даже для простых настроек.
  5. Указывать fixable только при действительно безопасном исправлении.
  6. Использовать hasSuggestions для неоднозначных вариантов исправления.
  7. Поддерживать актуальность ссылок в docs.url.
  8. Помечать устаревшие правила через deprecated и replacedBy.

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