CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-xo

JavaScript/TypeScript linter (ESLint wrapper) with great defaults

Overview
Eval results
Files

configuration.mddocs/

Configuration

XO supports multiple configuration methods including flat config files, CLI options, and programmatic configuration. The configuration system is built on top of ESLint's flat config format with XO-specific extensions.

Capabilities

XO Configuration Options

Core configuration options that control XO's linting behavior.

interface XoConfigOptions {
  /** 
   * Use spaces for indentation
   * - boolean: true for 2 spaces, false for tabs
   * - number: specific number of spaces
   * - string: parsed as boolean or number
   * - undefined: use default (tabs)
   */
  space?: Space;
  
  /** Use semicolons at the end of statements */
  semicolon?: boolean;
  
  /** 
   * Use Prettier to format code
   * - true: Enable Prettier formatting
   * - 'compat': Disable conflicting rules for separate Prettier usage
   */
  prettier?: boolean | 'compat';
  
  /** Add React support and React-specific linting rules */
  react?: boolean;
  
  /** Files to ignore, can be a glob pattern or array of patterns */
  ignores?: string | string[];
}

// Utility type for space configuration
type Space = boolean | number | string | undefined;

Flat Config Items

XO extends ESLint's flat config format with additional options.

interface XoConfigItem extends XoConfigOptions {
  /** 
   * Glob patterns indicating files this configuration applies to
   * If not specified, applies to all files
   */
  files?: string | string[];
  
  /** 
   * Glob patterns indicating files this configuration should NOT apply to
   * Takes precedence over files patterns
   */
  ignores?: string | string[];
  
  // Inherits all ESLint Linter.Config properties:
  // languageOptions, plugins, rules, settings, etc.
}

type FlatXoConfig = XoConfigItem | XoConfigItem[];

Linter Options

Options that control the linter's behavior and execution context.

interface LinterOptions {
  /** Current working directory to use for relative paths */
  cwd: string;
  
  /** Write fixes to the files automatically */
  fix?: boolean;
  
  /** Path to the file being linted (required for lintText) */
  filePath?: string;
  
  /** Show only errors and NOT warnings */
  quiet?: boolean;
  
  /** 
   * Auto-configure type-aware linting on unincluded TypeScript files
   * Ensures TypeScript files are linted with type-aware parser
   */
  ts?: boolean;
  
  /** Custom path to config file to use for the linter */
  configPath?: string;
}

Text Linting Options

Options specific to linting text content rather than files.

interface LintTextOptions {
  /** Path to the file being linted (used for rule context) */
  filePath: string;
  
  /** Warn if the file is ignored by configuration */
  warnIgnored?: boolean;
}

Configuration File Formats

Flat Config (Recommended)

Create a xo.config.js file in your project root:

// xo.config.js
export default [
  {
    space: 2,
    semicolon: true,
    prettier: false
  },
  {
    files: ["src/**/*.{js,ts}"],
    react: true,
    prettier: true
  },
  {
    files: ["test/**/*.js"],
    space: 4,
    rules: {
      // Custom ESLint rules
      "no-console": "off"
    }
  },
  {
    ignores: ["dist/**", "coverage/**"]
  }
];

TypeScript Config

// xo.config.ts
import type { FlatXoConfig } from "xo";

const config: FlatXoConfig = [
  {
    space: 2,
    semicolon: true,
    languageOptions: {
      parserOptions: {
        project: "./tsconfig.json"
      }
    }
  },
  {
    files: ["**/*.tsx"],
    react: true,
    prettier: true
  }
];

export default config;

Per-Directory Configuration

// xo.config.js
export default [
  // Global defaults
  {
    space: 2,
    semicolon: true
  },
  
  // Frontend specific
  {
    files: ["frontend/**/*.{js,ts,jsx,tsx}"],
    react: true,
    prettier: true,
    space: 2
  },
  
  // Backend specific
  {
    files: ["backend/**/*.{js,ts}"],
    react: false,
    space: 4,
    rules: {
      "n/no-process-env": "off"
    }
  },
  
  // Test files
  {
    files: ["**/*.test.{js,ts}"],
    rules: {
      "no-console": "off"
    }
  }
];

CLI Configuration

Override configuration via command-line options:

# Override space configuration
xo --space 4 --semicolon --react

# Use custom config file
xo --config ./custom-xo.config.js

# Ignore additional patterns
xo --ignore "temp/**" --ignore "*.generated.js"

Programmatic Configuration

Configure XO programmatically when creating instances:

import Xo from "xo";

// Basic configuration
const xo = new Xo(
  {
    cwd: process.cwd(),
    fix: true,
    quiet: false
  },
  {
    space: 2,
    semicolon: true,
    react: true,
    ignores: ["dist/**", "coverage/**"]
  }
);

// Advanced configuration with custom rules
const advancedXo = new Xo(
  { cwd: "./src", fix: false },
  {
    space: 4,
    prettier: "compat",
    // Configuration will be merged with defaults
  }
);

Configuration Resolution

XO resolves configuration in the following order (later options override earlier ones):

  1. Default XO configuration: Built-in opinionated defaults
  2. Flat config file: xo.config.js, xo.config.ts, etc.
  3. Base XO config: Passed to constructor or CLI
  4. CLI options: Command-line flags
  5. Environment-specific: GitHub Actions auto-quiet mode

TypeScript Configuration

XO automatically handles TypeScript configuration:

// xo.config.ts
export default [
  {
    // TypeScript files automatically get type-aware linting
    files: ["**/*.{ts,tsx}"],
    languageOptions: {
      parserOptions: {
        project: true, // Use nearest tsconfig.json
        tsconfigRootDir: import.meta.dirname
      }
    }
  },
  {
    // Override for specific files
    files: ["scripts/**/*.ts"],
    languageOptions: {
      parserOptions: {
        project: "./scripts/tsconfig.json"
      }
    }
  }
];

Prettier Integration

Configure Prettier integration:

// xo.config.js with Prettier
export default [
  {
    prettier: true,
    space: 2,
    semicolon: true,
    // XO will validate Prettier config matches XO options
  },
  {
    // Compatibility mode - let Prettier handle formatting separately
    files: ["formatted/**/*.js"],
    prettier: "compat"
  }
];

Ignore Patterns

Configure file ignoring:

// xo.config.js
export default [
  {
    // Global ignores (no files specified)
    ignores: [
      "dist/**",
      "coverage/**", 
      "node_modules/**",
      "*.min.js"
    ]
  },
  {
    // Conditional ignores
    files: ["src/**/*.js"],
    ignores: ["src/**/*.generated.js"]
  }
];

Default Configuration

XO includes comprehensive defaults:

// Default ignore patterns
const defaultIgnores = [
  "**/node_modules/**",
  "**/bower_components/**", 
  "flow-typed/**",
  "coverage/**",
  "{tmp,temp}/**",
  "**/*.min.js",
  "vendor/**",
  "dist/**",
  "tap-snapshots/*.{cjs,js}"
];

// Default file extensions
const jsExtensions = ["js", "jsx", "mjs", "cjs"];
const tsExtensions = ["ts", "tsx", "cts", "mts"];
const allExtensions = [...jsExtensions, ...tsExtensions];

Configuration Conversion

Convert XO config to ESLint config:

import { xoToEslintConfig } from "xo";

const xoConfig = [
  { space: 2, semicolon: true, react: true }
];

const eslintConfig = xoToEslintConfig(xoConfig, {
  prettierOptions: { semi: true, tabWidth: 2 }
});

// Use with ESLint directly
import { ESLint } from "eslint";
const eslint = new ESLint({ overrideConfig: eslintConfig });

Environment-Specific Configuration

// xo.config.js
const isCI = process.env.CI === "true";
const isDevelopment = process.env.NODE_ENV === "development";

export default [
  {
    space: 2,
    semicolon: true,
    // Adjust for CI environment
    ...(isCI && { 
      quiet: true,
      // More strict rules in CI
      rules: {
        "no-console": "error"
      }
    }),
    // Development-friendly rules
    ...(isDevelopment && {
      rules: {
        "no-console": "warn",
        "no-debugger": "warn"
      }
    })
  }
];

Install with Tessl CLI

npx tessl i tessl/npm-xo

docs

cli-interface.md

configuration.md

index.md

programmatic-api.md

tile.json