mirror of
https://github.com/antebudimir/eslint-plugin-vanilla-extract.git
synced 2026-01-02 09:33:33 +00:00
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
This commit is contained in:
parent
d5eae5dfc8
commit
1d88c12e3d
16 changed files with 3201 additions and 21 deletions
126
src/css-rules/prefer-theme-tokens/rule-definition.ts
Normal file
126
src/css-rules/prefer-theme-tokens/rule-definition.ts
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
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 can’t 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;
|
||||
Loading…
Add table
Add a link
Reference in a new issue