Правило ESLint представляет собой модуль, экспортирующий объект с
двумя ключевыми частями: meta и create. Именно
эта структура определяет поведение линтера, способ анализа AST и
механизм генерации сообщений об ошибках.
Каждое правило оформляется как JavaScript-модуль:
export default {
meta: {
type: "problem",
docs: {
description: "описание правила",
recommended: true
},
schema: [],
fixable: "code",
messages: {
unexpected: "Найдено нарушение правила"
}
},
create(context) {
return {
Identifier(node) {
if (node.name === "var") {
context.report({
node,
messageId: "unexpected"
});
}
}
};
}
};
Эта структура делится на декларативную часть (meta) и
исполнительную (create), где происходит анализ кода.
Объект meta описывает свойства правила, не связанные
напрямую с анализом AST, но влияющие на его поведение в экосистеме
ESLint.
Поле type определяет категорию:
problem — потенциальные ошибки в кодеsuggestion — рекомендации по улучшению стиляlayout — форматирование и внешний вид кодаЭто поле используется для группировки правил и их семантической классификации.
Секция docs содержит документационные данные:
description — краткое описание логики правилаrecommended — флаг, указывающий, включено ли правило в
рекомендованный наборurl — ссылка на внешнюю документацию (в конфигурациях
ESLint)Пример:
docs: {
description: "Запрещает использование var",
recommended: true,
url: "https://eslint.org/docs/rules/no-var"
}
schema определяет структуру опций правила в формате JSON
Schema. ESLint использует её для валидации конфигурации.
Простейший вариант:
schema: []
Правило без опций.
Более сложный вариант:
schema: [
{
type: "object",
properties: {
allowGlobals: {
type: "boolean"
}
},
additionalProperties: false
}
]
Schema напрямую влияет на context.options, обеспечивая
предсказуемую структуру входных данных.
Объект messages содержит шаблоны сообщений об ошибках.
Вместо “сырого текста” ESLint рекомендует использовать
идентификаторы:
messages: {
unexpectedVar: "Использование var запрещено",
missingSemicolon: "Отсутствует точка с запятой"
}
Использование messageId повышает читаемость и облегчает
локализацию.
Поле fixable указывает, поддерживает ли правило
автоматическое исправление:
"code" — изменение кода"whitespace" — изменение только пробельных
символовЭто важно для интеграции с --fix.
Флаг deprecated: true помечает правило как устаревшее.
Он используется для миграции конфигураций и предупреждений.
Функция create(context) является центральной частью
правила. Она возвращает объект, содержащий обработчики узлов AST.
create(context) {
return {
Identifier(node) {
// обработка узла
}
};
}
context передается в каждое правило и предоставляет API
для взаимодействия с ESLint.
Основные возможности:
Основной метод для регистрации нарушений:
context.report({
node,
messageId: "unexpectedVar"
});
Также поддерживается динамическое сообщение:
context.report({
node,
message: "Ошибка в коде"
});
Содержит пользовательские параметры правила, прошедшие через schema.
const [options] = context.options;
if (options.allowGlobals) {
return;
}
Возвращает объект SourceCode, предоставляющий доступ к
исходному тексту и утилитам анализа:
const sourceCode = context.getSourceCode();
const text = sourceCode.getText(node);
Правила ESLint работают на основе AST (Abstract Syntax Tree). Каждый узел дерева может быть обработан через соответствующий селектор.
return {
VariableDeclaration(node) {},
FunctionDeclaration(node) {},
"Identifier[name='eval']"(node) {}
};
Селекторы позволяют точно фильтровать интересующие конструкции.
create(context) {
return {
VariableDeclaration(node) {
if (node.kind === "var") {
context.report({
node,
message: "Используйте let или const"
});
}
}
};
}
Если правило поддерживает автоматическое исправление, используется
fix:
context.report({
node,
message: "Замена var на let",
fix(fixer) {
return fixer.replaceText(node, "let");
}
});
replaceText(node, text) — замена текста узлаremove(node) — удалениеinsertTextBefore(node, text)insertTextAfter(node, text)Фиксеры должны быть детерминированными и не зависеть от внешнего состояния.
Внутренний механизм ESLint последовательно:
context для каждого правилаcreatereportconst sourceCode = context.getSourceCode();
sourceCode.getAllComments();
sourceCode.getTokens(node);
sourceCode.getFirstToken(node);
Это позволяет анализировать не только структуру, но и текстовую форму кода.
Комментарии обрабатываются как отдельные сущности:
const comments = sourceCode.getCommentsBefore(node);
Это используется в правилах, связанных с аннотациями и директивами.
Каждое правило может хранить состояние внутри
create:
create(context) {
let count = 0;
return {
Identifier(node) {
count++;
},
"Program:exit"() {
if (count > 10) {
context.report({
message: "Слишком много идентификаторов"
});
}
}
};
}
Событие Program:exit вызывается после завершения обхода
дерева.
ESLint поддерживает специальные хуки:
ProgramProgram:exit:exit для любого узлаПример:
return {
FunctionDeclaration(node) {
// вход в узел
},
"FunctionDeclaration:exit"(node) {
// выход из узла
}
};
Сообщения могут использовать параметры:
messages: {
unexpected: "Недопустимое значение {{name}}"
}
Использование:
context.report({
node,
messageId: "unexpected",
data: {
name: node.name
}
});
Флаг recommended используется конфигурациями ESLint для
автоматического включения правил в preset’ы. Это влияет на:
eslint:recommendedПравила часто сопровождаются указанием:
Эти данные обычно добавляются в meta.docs или
meta расширенные поля.
meta приводит к невозможности
документированияschema усложняет проверку конфигурации--fixПри усложнении логики структура может включать:
createcreate(context) {
const visited = new Set();
function checkNode(node) {
if (visited.has(node)) return;
visited.add(node);
}
return {
Identifier(node) {
checkNode(node);
}
};
}