eslint-plugin-vanilla-extract/src/css-rules/prefer-theme-tokens/rule-definition.ts
Ante Budimir 1d88c12e3d
Some checks failed
CI / Build (push) Has been cancelled
CI / Lint (push) Has been cancelled
CI / Test (push) Has been cancelled
feat 🥁: add prefer-theme-tokens rule
- Enforce theme tokens over hard-coded values in vanilla-extract styles (colors, spacing, font sizes, border radius/widths, shadows, z-index, opacity, font weights, transitions)
- Provide token suggestions from configured theme contracts; optional auto-fix for unambiguous replacements
2025-11-14 08:09:39 +02:00

126 lines
4.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import type { Rule } from 'eslint';
import { createThemeTokenVisitors } from './theme-token-visitor-creator.js';
import type { ThemeTokenOptions } from './theme-token-processor.js';
const rule: Rule.RuleModule = {
meta: {
type: 'suggestion',
docs: {
description:
'require theme tokens instead of hard-coded values for colors, spacing, font sizes, and border radius',
recommended: false,
},
fixable: 'code',
// Suggestions are reported from helper modules, so static analysis in this file cant detect them; disable the false positive.
// eslint-disable-next-line eslint-plugin/require-meta-has-suggestions
hasSuggestions: true,
schema: [
{
type: 'object',
properties: {
themeContracts: {
type: 'array',
items: {
type: 'string',
},
description: 'Array of theme contract file paths to analyze for intelligent token suggestions',
},
checkColors: {
type: 'boolean',
description: 'Check for hard-coded color values',
default: true,
},
checkSpacing: {
type: 'boolean',
description: 'Check for hard-coded spacing values',
default: true,
},
checkFontSizes: {
type: 'boolean',
description: 'Check for hard-coded font size values',
default: true,
},
checkBorderRadius: {
type: 'boolean',
description: 'Check for hard-coded border radius values',
default: true,
},
checkBorderWidths: {
type: 'boolean',
description: 'Check for hard-coded border width values',
default: true,
},
checkShadows: {
type: 'boolean',
description: 'Check for hard-coded shadow values',
default: true,
},
checkZIndex: {
type: 'boolean',
description: 'Check for hard-coded z-index values',
default: true,
},
checkOpacity: {
type: 'boolean',
description: 'Check for hard-coded opacity values',
default: true,
},
checkFontWeights: {
type: 'boolean',
description: 'Check for hard-coded font weight values',
default: true,
},
checkTransitions: {
type: 'boolean',
description: 'Check for hard-coded transition and animation values',
default: true,
},
allowedValues: {
type: 'array',
items: {
type: 'string',
},
description: 'Array of values that are allowed (e.g., "0", "auto", "100%")',
},
allowedProperties: {
type: 'array',
items: {
type: 'string',
},
description: 'Array of CSS properties to skip checking (supports both camelCase and kebab-case)',
},
autoFix: {
type: 'boolean',
description: 'Enable auto-fix for unambiguous token replacements',
default: false,
},
remBase: {
type: 'number',
description: 'Base font size for rem() calculations (default: 16)',
default: 16,
},
checkHelperFunctions: {
type: 'boolean',
description: 'Check helper function calls like rem(48) and suggest theme tokens (default: false)',
default: false,
},
},
additionalProperties: false,
},
],
messages: {
hardCodedValueWithToken: "Hard-coded {{property}} value '{{value}}' detected. Use theme token: {{tokenPath}}",
hardCodedValueGeneric:
"Hard-coded {{property}} value '{{value}}' detected. Consider using a theme token from {{categoryHint}}",
hardCodedValueNoContract:
"Hard-coded {{property}} value '{{value}}' detected. Consider using theme tokens for {{category}} values",
replaceWithToken: 'Replace with {{tokenPath}}',
},
},
create(context: Rule.RuleContext): Rule.RuleListener {
const options: ThemeTokenOptions = context.options[0] || {};
return createThemeTokenVisitors(context, options);
},
};
export default rule;