eslint-plugin-structural-police v1.1.5
structural-police
eslint plugin для контроля структуры файлов и импортов
Установка
npm i eslint-plugin-structural-police
Быстрый старт
// .eslintrc.[js|yml|json]
{
"plugins": [
// ... какие-то твои плагины
"structural-police"
],
"extends": [
// ... какие-то твои конфиги плагинов
// один из конфигов
"plugin:structural-police/recommended"
// или
"plugin:structural-police/featureSliced"
],
}Правила плагина
import-order
Настройка
Правило import-order принимает 8 аргументов:
groups:array of object - Массив групп импортов (подробнее в пункте "Группы")behaviorRelatedComment:string - Вариант поведения комментариев, находящихся непосредственно перед импортов при использовании функции автофикса (флаг --fix). При значенииlink(default value) все комментарии перемещаются вместе с импортом. При значенииremoveвсе комментарии удаляютсяblankLineAfterEveryGroup:boolean - Нужно ли после каждой группы импортов вставлять пустую строку (default value: false)groupNamePrefix:string - Префикс необходимый, чтобы отличать обычные комментарии от названий групп импортов (default value: ' # '). Например:// # GroupNameoldGroupNamePrefix:string - Префикс, необходимый при изменении настройкиgroupNamePrefix, чтобы удалить названия групп со старым префиксомwithinGroupSort:array of string - Массив строк формирующих регулярные выражения, в порядке которых будут сортироваться пути импортов внутри групп. То есть передав['^([A-Z]|[a-z])', '^[.]']внутри группы будут идти сначала импорты начинающиеся с букв, а потом - с точки. При использовании этой настройки все импорты внутри группы будут отсортированы по алфавиту. Если нужно включить только сортировку по алфавиту, то нужно передать массив с одной регуляркой -['^']customErrorMessages:object - Объект с колбэками, формирующими тексты ошибок (подробнее в пункте "Кастомные сообщения ошибок")optimizedFix:boolean - Если true (default value: false), то в начале файла добавляется ошибка аккумулятор, которая содержит фикс функцию, устраняющую все ошибки данного правила за один проход линта. Рекомендуется использовать при запуске с флагом--fix, чтобы не запускать скрипт несколько раз для устранения всех ошибок
Группы
У каждого объекта группы есть 5 параметров:
name. Если естьname, то перед этой группой необходим комментарий с названием группыpriorityотвечает за приоритет разбора импортов по группам. То есть если импорт удовлетворяет условиям двух групп, то он будет размещен в групу с наивысшим приоритетом (default value: 1)blankLineAfterотвечает за наличие пустой строки после группы (default value: false)importPathMatchсодержит регулярное выражение или строку для формирования регулярного выражения (без флагов), по которому проверяется импортируемый путьimportAbsPathMatchсодержит регулярное выражение или строку для формирования регулярного выражения (без флагов), по которому проверяется абсолютный путь до импортируемого файла. То есть находясь в файлеsrc/feature/index.tsи импортируя из../ui/form.ts, по регулярному выражениюimportAbsPathMatchбудет проверяться путьsrc/ui/form.ts
Пример
groups: [
{ priority: 0, importPathMatch: /^/, blankLineAfter: true },
{ name: 'actions', priority: 2, importAbsPathMatch: /Action/, blankLineAfter: false },
{ name: 'stores', priority: 2, importAbsPathMatch: /Store/ },
{ name: 'styles', priority: 1, importPathMatch: /.css$/, blankLineAfter: true },
]Кастомные сообщения ошибок
Если есть желание изменить тексты ошибок выбрасываемых линтом, то можно сделать это, передав
в аргумент customErrorMessages объект со своими колбэками.
В правиле есть три типа ошибок mustBeAfter, blankLineDetected, blankLineExpected,
needAddComment и needRemoveComment, каждый из которых вызывается при разных проблемах:
1. mustBeAfter вызывается, если нарушен порядок импортов
2. blankLineDetected вызывается, если обнаружена лишняя пустая строка между импортами
3. blankLineExpected вызывается, если после группы с blankLineAfter нет пустой строки
4. needAddComment вызывается, если перед группой с name нет комментария с названием
5. needRemoveComment вызывается для неправильных названий групп
Ниже приведен объект с дефолтными колбэками, тут же можно посмотреть какие аргументы должны принимать колбэки
const defaultErrorMessages = {
mustBeAfter: ({ importPath, mustBeAfterImportPath }) =>
`This import must be after import from "${mustBeAfterImportPath}"`,
blankLineDetected: ({ importPath, groupName }) =>
`Must not be blank line after import from "${importPath}"`,
blankLineExpected: ({ importPath, groupName }) =>
`Need blank line after imports group "${groupName}"`,
needAddComment: ({ groupName, newComment }) =>
`Before imports group "${groupName}" must be comment with groups name "${newComment}"`,
needRemoveComment: () =>
`Need remove wrong groups name`,
}import-permission-schema
Настройка
Правило import-permission-schema принимает 5 аргументов:
schema:object - Схема валидации импортов (подробнее в пункте "Схема")inheritance:boolean - Наследование правил. Если у дочернего узла нет собственных правил, то будут применены правила ближайшего родителяentryPoints:array of string - Массив путей до валидируемых файловeverywhereAllowed:array of string - Массив путей до файлов, импорт которых всегда доступенcustomErrorMessages:object - Объект с колбэками, формирующими тексты ошибок (подробнее в пункте "Кастомные сообщения ошибок")
Схема
Схема описывает структуру проекта, по которой линтер будет проверять корректность расположения файлов и возможность осуществления импортов.
В схеме могут использоваться 3 ключех слова:
__rules__- В данном объекте линтер будет искать правила для конкретного узла схемы__any__- Разрешает любую структуру дочерниих файлов. Если__any__установленtrue, то линтер прекращает поиск правил глубже по схеме и применяет ко всем вложенным файлам уже найденые правила, если такие были__var__<variable_name>- При помощи такой конструкции можно обобщить несколько разноименных директорий с одинаковой внутренней структурой, чтобы исключить дублирование в схеме. Например в директории apps у нас лежит три приложения app-a, app-b и app-c. Если у первых двух одинаковая структура, то схему можно составить следующим образом:
apps: {
'app-c': {
// Какая-то схема
},
__var__similar_apps: {
// Какая-то другая схема
},
},В данном случае проверка будет происходить следующим образом:
Поиск правил для файла apps/app-c/index.ts: Зашли в apps, зашли в app-c,
нашли правила для index.ts
Поиск правил для файла apps/app-a/index.ts: Зашли в apps, не нашли объект
app-a, поэтому зашли в первый попавшийся __var__<variable_name>, если такой есть
Кастомные сообщения ошибок
Если есть желание изменить тексты ошибок выбрасываемых линтом, то можно сделать это, передав
в аргумент customErrorMessages объект со своими колбэками.
В правиле есть три типа ошибок importDisallow, missingFile и missingRules, каждый из
которых вызывается при разных проблемах:
1. importDisallow вызывается, если в файле найден импорт из запрещенного правилами (схемой) источника
2. missingFile вызывается, если проверяемый файл не описан в схеме
3. missingRules вызывается для проверяемого файла в схеме не найдены правила
Ниже приведен объект с дефолтными колбэками, тут же можно посмотреть какие аргументы должны принимать колбэки
const defaultErrorMessages = {
importDisallow: ({ filePath, importPath, absoluteImportPath }) =>
`Not allowed to import from "${absoluteImportPath}"`,
missingFile: ({ schemaPath, missingNode }) =>
`The file is not described in the schema. In "${schemaPath}" expected a node "${missingNode}"`,
missingRules: ({ schemaPath }) =>
`There is no set of rules in the "${schemaPath}"`,
}Правила
Правила можно передать в любой узел схемы под ключем __rules__. Правила содержат 3 необязательных ключа:
defaultAllowed:boolean - Импорт со всех адресов разрешен, если true. Запрещен, если false (default value: true)allowed:array of string - Массив разрешенных адресов для исключения изdefaultAllowed = truedisallowed:array of string - Массив запрещенных адресов для исключения изdefaultAllowed = false
!!! Важно !!!
- На одном уровне вложенности может быть только одно ключевое слово
__var__<variable_name> __var__переменные не должны повторяться- Если в узле отсутствуют правила и аргумент inheritance выставлен на false (отключено наследование правил), то это приведет к ошибке
!!! Интересно !!!
Переменные, указанные при составлении дерева файлов можно использовать в написании правил.
apps: {
__var__similar_apps: {
featuers: {},
shared: {},
},
},В нашей схеме есть переменная <similar_apps>, полученная при указании ключевого слова __var__
вместо названий приложений app-a, app-b. И мы хотим разрешить импорт из shared в
featuers, но только в рамках одного приложения (то есть в app-b/featuers нельзя сделать
импорт модуля из app-a/shared).
Настроить такие ограничения можно разместив следующие правила в объекте features
__rules__: {
defaultAllowed: false,
allowed: [
'apps/__var__similar_apps/shared',
],
},Логика проверки путей работает таким образом, что она вместо __var__ переменных подставит узлы,
из пути проверяемого файла. То есть находясь в файле apps/app-a/featuers/index.ts
переменная varsimilar_apps, используемая в правилах будет заменена на app-a, а
находясь в apps/app-b/featuers/index.ts - на app-b.
Проще говоря, переменная __var__<variable_name> - это текущая директория для каждого файла
no-default-export
Правило no-default-export запрещает использование дефолтных экспортов