Linting
Dispersa includes a plugin-based linting system to validate design tokens against semantic rules. Linting helps maintain token quality by enforcing naming conventions, requiring descriptions, detecting deprecated usage, and more.
Why linting?
Section titled “Why linting?”Design tokens are the foundation of your design system. Linting ensures:
- Consistency — Enforce naming conventions across all tokens
- Documentation — Require descriptions for better discoverability
- Maintainability — Detect deprecated tokens
- Quality — Find duplicate values and path structure issues
Quick start
Section titled “Quick start”Standalone lint
Section titled “Standalone lint”Run linting independently of the build:
import { lint } from 'dispersa'import { dispersaPlugin } from 'dispersa/lint'
const result = await lint({ resolver: './tokens.resolver.json', plugins: { dispersa: dispersaPlugin }, rules: { 'dispersa/require-description': 'warn', 'dispersa/case-check': ['error', { format: 'kebab-case' }], },})
console.log(`Found ${result.errorCount} errors, ${result.warningCount} warnings`)As part of build
Section titled “As part of build”Enable linting in your build configuration:
import { build, css } from 'dispersa'import { dispersaPlugin } from 'dispersa/lint'
const result = await build({ resolver: './tokens.resolver.json', buildPath: './dist', lint: { enabled: true, plugins: { dispersa: dispersaPlugin }, rules: { 'dispersa/case-check': ['error', { format: 'kebab-case' }], }, }, outputs: [css({ name: 'css', file: 'tokens.css', preset: 'bundle' })],})When failOnError is true (default), lint errors will cause the build to fail.
Predefined configurations
Section titled “Predefined configurations”Dispersa ships with three predefined lint configurations:
| Config | Description |
|---|---|
minimal | Only no-deprecated-usage as warning |
recommended | Balanced rules for most projects |
strict | All rules enabled as errors (or warnings) |
import { lint } from 'dispersa'import { recommendedConfig } from 'dispersa/lint'
const result = await lint({ resolver: './tokens.resolver.json', ...recommendedConfig,})What’s included
Section titled “What’s included”Minimal:
dispersa/no-deprecated-usage: warn
Recommended:
dispersa/require-description: warndispersa/case-check: error (kebab-case)dispersa/no-deprecated-usage: warn
Strict:
dispersa/require-description: errordispersa/case-check: error (kebab-case)dispersa/no-deprecated-usage: errordispersa/no-duplicate-values: error
Pipeline integration
Section titled “Pipeline integration”Linting runs in the pipeline after alias resolution but before filters and transforms:
1. Resolve → 2. Preprocess → 3. Parse → ... → 9. Lint → 10. Filter → 11. Transform → 12. RenderThis means linting operates on fully resolved tokens with all references expanded.
Built-in rules
Section titled “Built-in rules”Dispersa includes five built-in rules:
| Rule | Description |
|---|---|
require-description | Enforce $description on tokens |
case-check | Enforce case format (kebab-case, camelCase, etc.) |
no-deprecated-usage | Detect references to $deprecated tokens |
no-duplicate-values | Find tokens with identical values |
path-schema | Validate token path structure with patterns |
Creating custom rules
Section titled “Creating custom rules”Extend linting with your own rules and plugins:
import { createRule } from 'dispersa/lint'
const noPrimaryColors = createRule<'NO_PRIMARY'>({ meta: { name: 'no-primary-colors', description: 'Disallow "primary" in token names', messages: { NO_PRIMARY: "Token '{{name}}' contains 'primary'", }, }, create({ tokens, report }) { for (const token of Object.values(tokens)) { if (token.name.includes('primary')) { report({ token, messageId: 'NO_PRIMARY', data: { name: token.name } }) } } },})Output formats
Section titled “Output formats”Lint results can be formatted in different ways:
import { formatLintJson, formatLintStylish, formatLintCompact } from 'dispersa/lint'
console.log(formatLintStylish(result))console.log(formatLintJson(result))console.log(formatLintCompact(result))Available formats:
stylish- Human-readable format (default)json- Machine-parseable JSONcompact- Single-line format for CI systems