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

XO — это инструмент для статического анализа кода JavaScript и TypeScript, построенный поверх ESLint. Его основная идея заключается в предоставлении готового набора правил и единого стандарта качества кода без необходимости вручную собирать десятки ESLint-плагинов и конфигураций.

В отличие от классической настройки ESLint, где разработчик самостоятельно выбирает правила, плагины и параметры, XO предлагает подход «из коробки». При этом система конфигурации остается достаточно гибкой и позволяет адаптировать стандарт под требования конкретного проекта.

Конфигурация XO строится вокруг нескольких ключевых механизмов:

  • настройки в package.json;
  • отдельного файла конфигурации;
  • переопределения правил ESLint;
  • управления файлами и каталогами;
  • поддержки TypeScript;
  • настройки окружений выполнения;
  • работы с Prettier и дополнительными плагинами.

Способы задания конфигурации

XO поддерживает несколько вариантов хранения настроек.

Конфигурация в package.json

Наиболее распространённый способ — использование раздела xo внутри файла package.json.

Пример:

{
    "name": "my-project",
    "xo": {
        "space": 4,
        "semicolon": true
    }
}

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


Отдельный конфигурационный файл

Для крупных проектов часто используется отдельный файл:

xo.config.js

или

xo.config.cjs

Пример:

export default {
    space: 4,
    semicolon: true
};

Либо для CommonJS:

module.exports = {
    space: 4,
    semicolon: true
};

Отдельный файл позволяет:

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

Базовые параметры форматирования

Несмотря на использование ESLint, XO содержит собственные параметры для наиболее популярных настроек форматирования.

Управление точкой с запятой

По умолчанию XO требует использование точек с запятой.

Включение:

{
    "xo": {
        "semicolon": true
    }
}

Отключение:

{
    "xo": {
        "semicolon": false
    }
}

Пример:

const name = 'John'

или

const name = 'John';

в зависимости от выбранной конфигурации.


Количество пробелов

Настройка отступов производится через параметр space.

Два пробела:

{
    "xo": {
        "space": 2
    }
}

Четыре пробела:

{
    "xo": {
        "space": 4
    }
}

Пример:

function calculate() {
    return 42;
}

Игнорирование файлов

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

  • сборочные каталоги;
  • автоматически генерируемый код;
  • сторонние библиотеки;
  • временные файлы.

Для этого используется параметр ignores.

Пример:

{
    "xo": {
        "ignores": [
            "dist/**",
            "coverage/**",
            "vendor/**"
        ]
    }
}

После этого XO не будет проверять указанные пути.


Игнорирование отдельных файлов

{
    "xo": {
        "ignores": [
            "src/generated.js"
        ]
    }
}

Игнорирование по маске

{
    "xo": {
        "ignores": [
            "**/*.min.js"
        ]
    }
}

Это особенно полезно для минифицированных файлов.


Управление расширениями файлов

По умолчанию XO анализирует JavaScript-файлы, однако список можно расширить.

Пример:

{
    "xo": {
        "extensions": [
            "js",
            "mjs",
            "cjs"
        ]
    }
}

После этого линтер будет учитывать все перечисленные типы файлов.


Настройка окружений

Многие ESLint-правила зависят от среды выполнения программы.

Например:

  • браузер;
  • Node.js;
  • Service Worker;
  • Jest;
  • Web Worker.

Для этого используется параметр envs.

Node.js

{
    "xo": {
        "envs": [
            "node"
        ]
    }
}

Теперь глобальные объекты Node.js будут считаться допустимыми:

console.log(process.version);

Браузер

{
    "xo": {
        "envs": [
            "browser"
        ]
    }
}

После этого корректно распознаются:

window.location.href;
document.title;

Несколько окружений

{
    "xo": {
        "envs": [
            "browser",
            "node"
        ]
    }
}

Такой вариант встречается в универсальных библиотеках.


Глобальные переменные

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

Для их объявления применяется параметр globals.

Пример:

{
    "xo": {
        "globals": [
            "APP_CONFIG",
            "VERSION"
        ]
    }
}

Теперь обращения к этим идентификаторам не будут вызывать предупреждений:

console.log(APP_CONFIG.apiUrl);

Переопределение правил ESLint

Одним из наиболее важных элементов конфигурации XO является свойство rules.

Оно позволяет изменять встроенные правила ESLint.

Пример:

{
    "xo": {
        "rules": {
            "no-console": "off"
        }
    }
}

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

console.log('Debug');

не будет считаться ошибкой.


Изменение уровня серьёзности

ESLint поддерживает три уровня:

Значение Описание
off правило отключено
warn предупреждение
error ошибка

Пример:

{
    "xo": {
        "rules": {
            "eqeqeq": "warn"
        }
    }
}

Передача параметров правилам

Многие правила принимают дополнительные настройки.

Пример:

{
    "xo": {
        "rules": {
            "max-depth": [
                "error",
                3
            ]
        }
    }
}

Код с вложенностью более трёх уровней будет вызывать ошибку.


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

Разные части проекта могут требовать различных наборов правил.

Для этого применяется механизм overrides.

Пример:

export default {
    overrides: [
        {
            files: [
                "test/**/*.js"
            ],
            rules: {
                "no-unused-expressions": "off"
            }
        }
    ]
};

Теперь правило будет отключено только для тестов.


Несколько наборов переопределений

export default {
    overrides: [
        {
            files: ["src/**/*.js"],
            rules: {
                "no-console": "error"
            }
        },
        {
            files: ["scripts/**/*.js"],
            rules: {
                "no-console": "off"
            }
        }
    ]
};

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


Поддержка TypeScript

XO имеет встроенную поддержку TypeScript.

Для её включения обычно достаточно установить необходимые зависимости.

После этого становятся доступны проверки файлов:

.ts
.tsx

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

{
    "xo": {
        "typescript": true
    }
}

Настройка tsconfig

При наличии нескольких конфигураций TypeScript можно явно указать нужный файл.

{
    "xo": {
        "typescript": {
            "project": "./tsconfig.json"
        }
    }
}

Несколько проектов TypeScript

{
    "xo": {
        "typescript": {
            "project": [
                "packages/*/tsconfig.json"
            ]
        }
    }
}

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


Работа с Prettier

XO может использоваться совместно с Prettier.

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

  • XO отвечает за качество кода;
  • Prettier отвечает за форматирование.

Пример:

{
    "scripts": {
        "lint": "xo",
        "format": "prettier --write ."
    }
}

Такое разделение позволяет избежать конфликтов между инструментами.


Добавление собственных ESLint-плагинов

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

Пример:

export default {
    plugins: [
        "eslint-plugin-unicorn"
    ]
};

После подключения становятся доступны правила выбранного плагина.


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

export default {
    rules: {
        "unicorn/filename-case": [
            "error",
            {
                case: "kebabCase"
            }
        ]
    }
};

Теперь XO будет контролировать стиль именования файлов.


Конфигурация для монорепозиториев

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

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

root/
├── package.json
├── xo.config.js
├── packages/
│   ├── api/
│   ├── ui/
│   └── core/

Общая конфигурация:

export default {
    space: 4,
    semicolon: true,
    ignores: [
        "**/dist/**"
    ]
};

Каждый пакет автоматически наследует эти настройки.


Исключение правил для отдельных строк

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

Отключение следующей строки:

// eslint-disable-next-line no-console
console.log('Debug');

Отключение блока:

/* eslint-disable no-console */

console.log('One');
console.log('Two');

/* eslint-enable no-console */

Поскольку XO использует ESLint, все подобные механизмы полностью поддерживаются.


Проверка только определённых файлов

Конфигурация может ограничивать анализ конкретными шаблонами.

Пример:

export default {
    files: [
        "src/**/*.js"
    ]
};

В этом случае проверка будет выполняться только внутри каталога src.


Расширение существующей конфигурации

Часто используется корпоративный стандарт кодирования, общий для нескольких проектов.

Пример:

import companyConfig from '@company/xo-config';

export default {
    ...companyConfig,
    rules: {
        ...companyConfig.rules,
        'no-console': 'off'
    }
};

Такой подход позволяет централизованно поддерживать единый стиль разработки и при необходимости локально изменять отдельные правила.


Практическая конфигурация для серверного проекта

export default {
    space: 4,
    semicolon: true,

    envs: [
        'node'
    ],

    ignores: [
        'dist/**',
        'coverage/**'
    ],

    rules: {
        'no-console': 'off',
        'max-depth': [
            'error',
            4
        ],
        'max-lines': [
            'warn',
            500
        ]
    }
};

Особенности такой конфигурации:

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

Практическая конфигурация для фронтенд-приложения

export default {
    envs: [
        'browser'
    ],

    space: 2,

    ignores: [
        'build/**'
    ],

    globals: [
        'APP_VERSION'
    ],

    rules: {
        'no-alert': 'error',
        'no-console': 'warn'
    }
};

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


Рекомендации по организации конфигурации

Для небольших проектов:

  • использовать настройки внутри package.json;
  • избегать большого количества переопределений;
  • придерживаться стандартных правил XO.

Для средних проектов:

  • выносить конфигурацию в отдельный файл;
  • активно использовать overrides;
  • разделять настройки для тестов и основного кода.

Для крупных проектов и монорепозиториев:

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

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