mirror of
https://github.com/antebudimir/eslint-plugin-vanilla-extract.git
synced 2026-01-03 10:01:38 +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
e95a3ce9c2
16 changed files with 3197 additions and 21 deletions
|
|
@ -0,0 +1,912 @@
|
|||
import path from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
import tsParser from '@typescript-eslint/parser';
|
||||
import { run } from 'eslint-vitest-rule-tester';
|
||||
import rule from '../rule-definition.js';
|
||||
|
||||
const valids = [
|
||||
// Using theme tokens - should pass
|
||||
{
|
||||
code: `
|
||||
import { style } from '@vanilla-extract/css';
|
||||
import { vars } from './test-theme.css';
|
||||
const myStyle = style({
|
||||
color: vars.colors.brand,
|
||||
backgroundColor: vars.colors.background,
|
||||
});
|
||||
`,
|
||||
},
|
||||
|
||||
// Allowed keywords
|
||||
{
|
||||
code: `
|
||||
import { style } from '@vanilla-extract/css';
|
||||
const myStyle = style({
|
||||
color: 'transparent',
|
||||
backgroundColor: 'currentcolor',
|
||||
});
|
||||
`,
|
||||
},
|
||||
|
||||
// When checks are disabled
|
||||
{
|
||||
code: `
|
||||
import { style } from '@vanilla-extract/css';
|
||||
const myStyle = style({
|
||||
color: '#ff0000',
|
||||
});
|
||||
`,
|
||||
options: [{ checkColors: false }],
|
||||
},
|
||||
|
||||
// Allowed values option
|
||||
{
|
||||
code: `
|
||||
import { style } from '@vanilla-extract/css';
|
||||
const myStyle = style({
|
||||
margin: '0',
|
||||
padding: 'auto',
|
||||
width: '100%',
|
||||
});
|
||||
`,
|
||||
},
|
||||
|
||||
// Allowed properties option
|
||||
{
|
||||
code: `
|
||||
import { style } from '@vanilla-extract/css';
|
||||
const myStyle = style({
|
||||
borderWidth: '1px',
|
||||
});
|
||||
`,
|
||||
options: [{ allowedProperties: ['borderWidth'] }],
|
||||
},
|
||||
|
||||
// Helper functions are NOT flagged by default (checkHelperFunctions: false)
|
||||
{
|
||||
code: `
|
||||
import { style } from '@vanilla-extract/css';
|
||||
import { rem } from 'polished';
|
||||
const myStyle = style({
|
||||
padding: rem(16),
|
||||
margin: rem(8),
|
||||
});
|
||||
`,
|
||||
options: [{ themeContracts: ['./test-theme.css.ts'] }],
|
||||
},
|
||||
|
||||
// Checks disabled for new categories
|
||||
{
|
||||
code: `
|
||||
import { style } from '@vanilla-extract/css';
|
||||
const myStyle = style({
|
||||
borderWidth: '2px',
|
||||
boxShadow: '0 4px 6px rgba(0,0,0,0.1)',
|
||||
zIndex: 10,
|
||||
opacity: 0.5,
|
||||
fontWeight: 700,
|
||||
transition: '0.3s ease',
|
||||
});
|
||||
`,
|
||||
options: [{
|
||||
checkBorderWidths: false,
|
||||
checkShadows: false,
|
||||
checkZIndex: false,
|
||||
checkOpacity: false,
|
||||
checkFontWeights: false,
|
||||
checkTransitions: false,
|
||||
}],
|
||||
},
|
||||
];
|
||||
|
||||
// Resolve absolute path to the local test theme contracts
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
const themeAbs = path.resolve(__dirname, './test-theme.css.ts');
|
||||
const themeWithRemAbs = path.resolve(__dirname, './test-theme-with-rem.css.ts');
|
||||
|
||||
const invalids = [
|
||||
// Hard-coded color with exact theme match via absolute themeContracts path
|
||||
{
|
||||
code: `
|
||||
import { style } from '@vanilla-extract/css';
|
||||
const myStyle = style({
|
||||
color: '#0055FF',
|
||||
});
|
||||
`,
|
||||
options: [{ themeContracts: [themeAbs] }],
|
||||
errors: [
|
||||
{
|
||||
messageId: 'hardCodedValueWithToken',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// Hard-coded spacing with exact theme match via absolute themeContracts path
|
||||
{
|
||||
code: `
|
||||
import { style } from '@vanilla-extract/css';
|
||||
const myStyle = style({
|
||||
margin: '8px',
|
||||
});
|
||||
`,
|
||||
options: [{ themeContracts: [themeAbs] }],
|
||||
errors: [
|
||||
{
|
||||
messageId: 'hardCodedValueWithToken',
|
||||
},
|
||||
],
|
||||
},
|
||||
// Hard-coded color without theme contract
|
||||
{
|
||||
code: `
|
||||
import { style } from '@vanilla-extract/css';
|
||||
const myStyle = style({
|
||||
color: '#0055FF',
|
||||
});
|
||||
`,
|
||||
errors: [
|
||||
{
|
||||
messageId: 'hardCodedValueNoContract',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// Hard-coded spacing
|
||||
{
|
||||
code: `
|
||||
import { style } from '@vanilla-extract/css';
|
||||
const myStyle = style({
|
||||
margin: '8px',
|
||||
});
|
||||
`,
|
||||
errors: [
|
||||
{
|
||||
messageId: 'hardCodedValueNoContract',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// Hard-coded font size
|
||||
{
|
||||
code: `
|
||||
import { style } from '@vanilla-extract/css';
|
||||
const myStyle = style({
|
||||
fontSize: '16px',
|
||||
});
|
||||
`,
|
||||
errors: [
|
||||
{
|
||||
messageId: 'hardCodedValueNoContract',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// Hard-coded border radius
|
||||
{
|
||||
code: `
|
||||
import { style } from '@vanilla-extract/css';
|
||||
const myStyle = style({
|
||||
borderRadius: '4px',
|
||||
});
|
||||
`,
|
||||
errors: [
|
||||
{
|
||||
messageId: 'hardCodedValueNoContract',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// RGB color
|
||||
{
|
||||
code: `
|
||||
import { style } from '@vanilla-extract/css';
|
||||
const myStyle = style({
|
||||
color: 'rgb(255, 0, 0)',
|
||||
});
|
||||
`,
|
||||
errors: [
|
||||
{
|
||||
messageId: 'hardCodedValueNoContract',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// Named color
|
||||
{
|
||||
code: `
|
||||
import { style } from '@vanilla-extract/css';
|
||||
const myStyle = style({
|
||||
color: 'red',
|
||||
});
|
||||
`,
|
||||
errors: [
|
||||
{
|
||||
messageId: 'hardCodedValueNoContract',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// Multiple hard-coded values
|
||||
{
|
||||
code: `
|
||||
import { style } from '@vanilla-extract/css';
|
||||
const myStyle = style({
|
||||
color: '#0055FF',
|
||||
backgroundColor: '#ffffff',
|
||||
margin: '8px',
|
||||
fontSize: '16px',
|
||||
});
|
||||
`,
|
||||
errors: [
|
||||
{
|
||||
messageId: 'hardCodedValueNoContract',
|
||||
},
|
||||
{
|
||||
messageId: 'hardCodedValueNoContract',
|
||||
},
|
||||
{
|
||||
messageId: 'hardCodedValueNoContract',
|
||||
},
|
||||
{
|
||||
messageId: 'hardCodedValueNoContract',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// Nested structures (media queries, selectors)
|
||||
{
|
||||
code: `
|
||||
import { style } from '@vanilla-extract/css';
|
||||
const myStyle = style({
|
||||
'@media': {
|
||||
'(min-width: 768px)': {
|
||||
color: '#0055FF',
|
||||
},
|
||||
},
|
||||
selectors: {
|
||||
'&:hover': {
|
||||
backgroundColor: '#ffffff',
|
||||
},
|
||||
},
|
||||
});
|
||||
`,
|
||||
errors: [
|
||||
{
|
||||
messageId: 'hardCodedValueNoContract',
|
||||
},
|
||||
{
|
||||
messageId: 'hardCodedValueNoContract',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// Recipe with hard-coded values
|
||||
{
|
||||
code: `
|
||||
import { recipe } from '@vanilla-extract/recipes';
|
||||
const button = recipe({
|
||||
base: {
|
||||
color: '#0055FF',
|
||||
},
|
||||
variants: {
|
||||
size: {
|
||||
sm: { fontSize: '12px' },
|
||||
lg: { fontSize: '20px' },
|
||||
},
|
||||
},
|
||||
});
|
||||
`,
|
||||
errors: [
|
||||
{
|
||||
messageId: 'hardCodedValueNoContract',
|
||||
},
|
||||
{
|
||||
messageId: 'hardCodedValueNoContract',
|
||||
},
|
||||
{
|
||||
messageId: 'hardCodedValueNoContract',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// globalStyle with hard-coded values
|
||||
{
|
||||
code: `
|
||||
import { globalStyle } from '@vanilla-extract/css';
|
||||
globalStyle('body', {
|
||||
color: '#1f2937',
|
||||
margin: '0px',
|
||||
});
|
||||
`,
|
||||
errors: [
|
||||
{
|
||||
messageId: 'hardCodedValueNoContract',
|
||||
},
|
||||
{
|
||||
messageId: 'hardCodedValueNoContract',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// Test rem() evaluation - spacing
|
||||
{
|
||||
code: `
|
||||
import { style } from '@vanilla-extract/css';
|
||||
const myStyle = style({
|
||||
margin: '0.5rem',
|
||||
});
|
||||
`,
|
||||
options: [{ themeContracts: [themeWithRemAbs] }],
|
||||
errors: [
|
||||
{
|
||||
messageId: 'hardCodedValueWithToken',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// Test rem() evaluation - fontSize
|
||||
{
|
||||
code: `
|
||||
import { style } from '@vanilla-extract/css';
|
||||
const myStyle = style({
|
||||
fontSize: '1rem',
|
||||
});
|
||||
`,
|
||||
options: [{ themeContracts: [themeWithRemAbs] }],
|
||||
errors: [
|
||||
{
|
||||
messageId: 'hardCodedValueWithToken',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// Test rem() evaluation - borderRadius
|
||||
{
|
||||
code: `
|
||||
import { style } from '@vanilla-extract/css';
|
||||
const myStyle = style({
|
||||
borderRadius: '0.25rem',
|
||||
});
|
||||
`,
|
||||
options: [{ themeContracts: [themeWithRemAbs] }],
|
||||
errors: [
|
||||
{
|
||||
messageId: 'hardCodedValueWithToken',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// Test color matching with rem theme
|
||||
{
|
||||
code: `
|
||||
import { style } from '@vanilla-extract/css';
|
||||
const myStyle = style({
|
||||
backgroundColor: '#5614b8',
|
||||
});
|
||||
`,
|
||||
options: [{ themeContracts: [themeWithRemAbs] }],
|
||||
errors: [
|
||||
{
|
||||
messageId: 'hardCodedValueWithToken',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// Test RGB color matching with rem theme
|
||||
{
|
||||
code: `
|
||||
import { style } from '@vanilla-extract/css';
|
||||
const myStyle = style({
|
||||
color: 'rgb(255, 255, 255)',
|
||||
});
|
||||
`,
|
||||
options: [{ themeContracts: [themeWithRemAbs] }],
|
||||
errors: [
|
||||
{
|
||||
messageId: 'hardCodedValueWithToken',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// Test helper function detection with checkHelperFunctions: true
|
||||
{
|
||||
code: `
|
||||
import { style } from '@vanilla-extract/css';
|
||||
import { rem } from 'polished';
|
||||
const myStyle = style({
|
||||
padding: rem(16),
|
||||
});
|
||||
`,
|
||||
options: [{ themeContracts: [themeWithRemAbs], checkHelperFunctions: true }],
|
||||
errors: [
|
||||
{
|
||||
messageId: 'hardCodedValueWithToken',
|
||||
data: {
|
||||
value: '1rem',
|
||||
property: 'padding',
|
||||
tokenPath: 'lightTheme.spacing.medium',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// Test helper function with multiple matches
|
||||
{
|
||||
code: `
|
||||
import { style } from '@vanilla-extract/css';
|
||||
import { rem } from 'polished';
|
||||
const myStyle = style({
|
||||
fontSize: rem(16),
|
||||
});
|
||||
`,
|
||||
options: [{ themeContracts: [themeWithRemAbs], checkHelperFunctions: true }],
|
||||
errors: [
|
||||
{
|
||||
messageId: 'hardCodedValueWithToken',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// Border widths - string literal
|
||||
{
|
||||
code: `
|
||||
import { style } from '@vanilla-extract/css';
|
||||
const myStyle = style({
|
||||
borderWidth: '2px',
|
||||
borderTopWidth: '1px',
|
||||
});
|
||||
`,
|
||||
errors: [
|
||||
{ messageId: 'hardCodedValueNoContract' },
|
||||
{ messageId: 'hardCodedValueNoContract' },
|
||||
],
|
||||
},
|
||||
|
||||
// Border shorthand
|
||||
{
|
||||
code: `
|
||||
import { style } from '@vanilla-extract/css';
|
||||
const myStyle = style({
|
||||
border: '1px solid red',
|
||||
borderTop: '2px dashed blue',
|
||||
});
|
||||
`,
|
||||
errors: [
|
||||
{ messageId: 'hardCodedValueNoContract' },
|
||||
{ messageId: 'hardCodedValueNoContract' },
|
||||
],
|
||||
},
|
||||
|
||||
// Shadows - boxShadow and textShadow
|
||||
{
|
||||
code: `
|
||||
import { style } from '@vanilla-extract/css';
|
||||
const myStyle = style({
|
||||
boxShadow: '0 4px 6px rgba(0,0,0,0.1)',
|
||||
textShadow: '1px 1px 2px black',
|
||||
});
|
||||
`,
|
||||
errors: [
|
||||
{ messageId: 'hardCodedValueNoContract' },
|
||||
{ messageId: 'hardCodedValueNoContract' },
|
||||
],
|
||||
},
|
||||
|
||||
// Z-index - numeric literal
|
||||
{
|
||||
code: `
|
||||
import { style } from '@vanilla-extract/css';
|
||||
const myStyle = style({
|
||||
zIndex: 10,
|
||||
});
|
||||
`,
|
||||
errors: [
|
||||
{ messageId: 'hardCodedValueNoContract' },
|
||||
],
|
||||
},
|
||||
|
||||
// Z-index - string literal
|
||||
{
|
||||
code: `
|
||||
import { style } from '@vanilla-extract/css';
|
||||
const myStyle = style({
|
||||
zIndex: '100',
|
||||
});
|
||||
`,
|
||||
errors: [
|
||||
{ messageId: 'hardCodedValueNoContract' },
|
||||
],
|
||||
},
|
||||
|
||||
// Opacity - numeric literal
|
||||
{
|
||||
code: `
|
||||
import { style } from '@vanilla-extract/css';
|
||||
const myStyle = style({
|
||||
opacity: 0.5,
|
||||
});
|
||||
`,
|
||||
errors: [
|
||||
{ messageId: 'hardCodedValueNoContract' },
|
||||
],
|
||||
},
|
||||
|
||||
// Opacity - string literal
|
||||
{
|
||||
code: `
|
||||
import { style } from '@vanilla-extract/css';
|
||||
const myStyle = style({
|
||||
opacity: '0.8',
|
||||
});
|
||||
`,
|
||||
errors: [
|
||||
{ messageId: 'hardCodedValueNoContract' },
|
||||
],
|
||||
},
|
||||
|
||||
// Font weight - numeric literal
|
||||
{
|
||||
code: `
|
||||
import { style } from '@vanilla-extract/css';
|
||||
const myStyle = style({
|
||||
fontWeight: 700,
|
||||
});
|
||||
`,
|
||||
errors: [
|
||||
{ messageId: 'hardCodedValueNoContract' },
|
||||
],
|
||||
},
|
||||
|
||||
// Font weight - string literal (named)
|
||||
{
|
||||
code: `
|
||||
import { style } from '@vanilla-extract/css';
|
||||
const myStyle = style({
|
||||
fontWeight: 'bold',
|
||||
});
|
||||
`,
|
||||
errors: [
|
||||
{ messageId: 'hardCodedValueNoContract' },
|
||||
],
|
||||
},
|
||||
|
||||
// Transitions - duration
|
||||
{
|
||||
code: `
|
||||
import { style } from '@vanilla-extract/css';
|
||||
const myStyle = style({
|
||||
transition: '0.3s ease-in-out',
|
||||
transitionDuration: '200ms',
|
||||
});
|
||||
`,
|
||||
errors: [
|
||||
{ messageId: 'hardCodedValueNoContract' },
|
||||
{ messageId: 'hardCodedValueNoContract' },
|
||||
],
|
||||
},
|
||||
|
||||
// Animation
|
||||
{
|
||||
code: `
|
||||
import { style } from '@vanilla-extract/css';
|
||||
const myStyle = style({
|
||||
animation: '1s ease-in',
|
||||
animationDuration: '500ms',
|
||||
});
|
||||
`,
|
||||
errors: [
|
||||
{ messageId: 'hardCodedValueNoContract' },
|
||||
{ messageId: 'hardCodedValueNoContract' },
|
||||
],
|
||||
},
|
||||
|
||||
// Template literal with helper functions (checkHelperFunctions: true)
|
||||
{
|
||||
code: `
|
||||
import { style } from '@vanilla-extract/css';
|
||||
import { rem } from 'polished';
|
||||
const myStyle = style({
|
||||
boxShadow: \`\${rem(4)} \${rem(8)} \${rem(16)} rgba(0,0,0,0.14)\`,
|
||||
});
|
||||
`,
|
||||
options: [{ checkHelperFunctions: true }],
|
||||
errors: [
|
||||
{ messageId: 'hardCodedValueNoContract' },
|
||||
],
|
||||
},
|
||||
|
||||
// Multiple new categories together
|
||||
{
|
||||
code: `
|
||||
import { style } from '@vanilla-extract/css';
|
||||
const myStyle = style({
|
||||
borderWidth: '1px',
|
||||
boxShadow: '0 2px 4px black',
|
||||
zIndex: 999,
|
||||
opacity: 0.75,
|
||||
fontWeight: 600,
|
||||
transition: '0.2s linear',
|
||||
});
|
||||
`,
|
||||
errors: [
|
||||
{ messageId: 'hardCodedValueNoContract' },
|
||||
{ messageId: 'hardCodedValueNoContract' },
|
||||
{ messageId: 'hardCodedValueNoContract' },
|
||||
{ messageId: 'hardCodedValueNoContract' },
|
||||
{ messageId: 'hardCodedValueNoContract' },
|
||||
{ messageId: 'hardCodedValueNoContract' },
|
||||
],
|
||||
},
|
||||
|
||||
// HSL color
|
||||
{
|
||||
code: `
|
||||
import { style } from '@vanilla-extract/css';
|
||||
const myStyle = style({
|
||||
color: 'hsl(200, 50%, 50%)',
|
||||
});
|
||||
`,
|
||||
errors: [
|
||||
{ messageId: 'hardCodedValueNoContract' },
|
||||
],
|
||||
},
|
||||
|
||||
// RGBA color
|
||||
{
|
||||
code: `
|
||||
import { style } from '@vanilla-extract/css';
|
||||
const myStyle = style({
|
||||
backgroundColor: 'rgba(255, 0, 0, 0.5)',
|
||||
});
|
||||
`,
|
||||
errors: [
|
||||
{ messageId: 'hardCodedValueNoContract' },
|
||||
],
|
||||
},
|
||||
|
||||
// Filter property (shadow category)
|
||||
{
|
||||
code: `
|
||||
import { style } from '@vanilla-extract/css';
|
||||
const myStyle = style({
|
||||
filter: 'blur(10px)',
|
||||
});
|
||||
`,
|
||||
errors: [
|
||||
{ messageId: 'hardCodedValueNoContract' },
|
||||
],
|
||||
},
|
||||
|
||||
// Numeric literals for all new categories
|
||||
{
|
||||
code: `
|
||||
import { style } from '@vanilla-extract/css';
|
||||
const myStyle = style({
|
||||
zIndex: 5,
|
||||
opacity: 1,
|
||||
fontWeight: 400,
|
||||
});
|
||||
`,
|
||||
errors: [
|
||||
{ messageId: 'hardCodedValueNoContract' },
|
||||
{ messageId: 'hardCodedValueNoContract' },
|
||||
{ messageId: 'hardCodedValueNoContract' },
|
||||
],
|
||||
},
|
||||
|
||||
// fontFace with hard-coded values
|
||||
{
|
||||
code: `
|
||||
import { fontFace } from '@vanilla-extract/css';
|
||||
const myFont = fontFace({
|
||||
fontWeight: 700,
|
||||
});
|
||||
`,
|
||||
errors: [
|
||||
{ messageId: 'hardCodedValueNoContract' },
|
||||
],
|
||||
},
|
||||
|
||||
// All new categories without theme contract (to test getCategoryName paths)
|
||||
{
|
||||
code: `
|
||||
import { style } from '@vanilla-extract/css';
|
||||
const myStyle = style({
|
||||
borderWidth: '3px',
|
||||
borderTopWidth: '2px',
|
||||
boxShadow: '0 0 10px rgba(0,0,0,0.5)',
|
||||
textShadow: '2px 2px 4px black',
|
||||
filter: 'drop-shadow(0 4px 8px rgba(0,0,0,0.2))',
|
||||
zIndex: 50,
|
||||
opacity: 0.9,
|
||||
fontWeight: 500,
|
||||
transition: '0.5s cubic-bezier(0.25,0.1,0.25,1)',
|
||||
animation: '2s ease-out',
|
||||
});
|
||||
`,
|
||||
errors: [
|
||||
{ messageId: 'hardCodedValueNoContract' },
|
||||
{ messageId: 'hardCodedValueNoContract' },
|
||||
{ messageId: 'hardCodedValueNoContract' },
|
||||
{ messageId: 'hardCodedValueNoContract' },
|
||||
{ messageId: 'hardCodedValueNoContract' },
|
||||
{ messageId: 'hardCodedValueNoContract' },
|
||||
{ messageId: 'hardCodedValueNoContract' },
|
||||
{ messageId: 'hardCodedValueNoContract' },
|
||||
{ messageId: 'hardCodedValueNoContract' },
|
||||
{ messageId: 'hardCodedValueNoContract' },
|
||||
],
|
||||
},
|
||||
|
||||
// String variants of numeric categories
|
||||
{
|
||||
code: `
|
||||
import { style } from '@vanilla-extract/css';
|
||||
const myStyle = style({
|
||||
zIndex: '25',
|
||||
opacity: '0.3',
|
||||
fontWeight: '300',
|
||||
});
|
||||
`,
|
||||
errors: [
|
||||
{ messageId: 'hardCodedValueNoContract' },
|
||||
{ messageId: 'hardCodedValueNoContract' },
|
||||
{ messageId: 'hardCodedValueNoContract' },
|
||||
],
|
||||
},
|
||||
|
||||
// Edge case: named font weights
|
||||
{
|
||||
code: `
|
||||
import { style } from '@vanilla-extract/css';
|
||||
const myStyle = style({
|
||||
fontWeight: 'bolder',
|
||||
});
|
||||
`,
|
||||
errors: [
|
||||
{ messageId: 'hardCodedValueNoContract' },
|
||||
],
|
||||
},
|
||||
|
||||
// Edge case: various transition timing functions
|
||||
{
|
||||
code: `
|
||||
import { style } from '@vanilla-extract/css';
|
||||
const myStyle = style({
|
||||
transitionTimingFunction: 'ease',
|
||||
animationTimingFunction: 'linear',
|
||||
});
|
||||
`,
|
||||
errors: [
|
||||
{ messageId: 'hardCodedValueNoContract' },
|
||||
{ messageId: 'hardCodedValueNoContract' },
|
||||
],
|
||||
},
|
||||
|
||||
// Border shorthand variants
|
||||
{
|
||||
code: `
|
||||
import { style } from '@vanilla-extract/css';
|
||||
const myStyle = style({
|
||||
borderTop: '3px dotted green',
|
||||
borderRight: '1px solid black',
|
||||
borderBottom: '2px dashed blue',
|
||||
borderLeft: '4px double red',
|
||||
});
|
||||
`,
|
||||
errors: [
|
||||
{ messageId: 'hardCodedValueNoContract' },
|
||||
{ messageId: 'hardCodedValueNoContract' },
|
||||
{ messageId: 'hardCodedValueNoContract' },
|
||||
{ messageId: 'hardCodedValueNoContract' },
|
||||
],
|
||||
},
|
||||
|
||||
// Outline (also a border-width category property)
|
||||
{
|
||||
code: `
|
||||
import { style } from '@vanilla-extract/css';
|
||||
const myStyle = style({
|
||||
outline: '2px solid red',
|
||||
outlineWidth: '3px',
|
||||
});
|
||||
`,
|
||||
errors: [
|
||||
{ messageId: 'hardCodedValueNoContract' },
|
||||
{ messageId: 'hardCodedValueNoContract' },
|
||||
],
|
||||
},
|
||||
|
||||
// Template literals for new categories (checkHelperFunctions: true)
|
||||
{
|
||||
code: `
|
||||
import { style } from '@vanilla-extract/css';
|
||||
import { rem } from 'polished';
|
||||
const myStyle = style({
|
||||
borderWidth: \`\${rem(2)}\`,
|
||||
boxShadow: \`\${rem(0)} \${rem(4)} \${rem(8)} rgba(0,0,0,0.2)\`,
|
||||
fontWeight: \`700\`,
|
||||
transition: \`\${0.3}s ease\`,
|
||||
});
|
||||
`,
|
||||
options: [{ checkHelperFunctions: true }],
|
||||
errors: [
|
||||
{ messageId: 'hardCodedValueNoContract' },
|
||||
{ messageId: 'hardCodedValueNoContract' },
|
||||
{ messageId: 'hardCodedValueNoContract' },
|
||||
{ messageId: 'hardCodedValueNoContract' },
|
||||
],
|
||||
},
|
||||
|
||||
// CallExpression for new categories (checkHelperFunctions: true)
|
||||
{
|
||||
code: `
|
||||
import { style } from '@vanilla-extract/css';
|
||||
import { rem } from 'polished';
|
||||
const myStyle = style({
|
||||
borderWidth: rem(2),
|
||||
borderRadius: rem(8),
|
||||
});
|
||||
`,
|
||||
options: [{ checkHelperFunctions: true }],
|
||||
errors: [
|
||||
{ messageId: 'hardCodedValueNoContract' },
|
||||
{ messageId: 'hardCodedValueNoContract' },
|
||||
],
|
||||
},
|
||||
|
||||
// Template literals for spacing, fontSize, borderRadius with helpers
|
||||
{
|
||||
code: `
|
||||
import { style } from '@vanilla-extract/css';
|
||||
import { rem } from 'polished';
|
||||
const myStyle = style({
|
||||
margin: \`\${rem(16)}\`,
|
||||
fontSize: \`\${rem(14)}\`,
|
||||
borderRadius: \`\${rem(4)}\`,
|
||||
});
|
||||
`,
|
||||
options: [{ checkHelperFunctions: true }],
|
||||
errors: [
|
||||
{ messageId: 'hardCodedValueNoContract' },
|
||||
{ messageId: 'hardCodedValueNoContract' },
|
||||
{ messageId: 'hardCodedValueNoContract' },
|
||||
],
|
||||
},
|
||||
|
||||
// CallExpression for all main categories
|
||||
{
|
||||
code: `
|
||||
import { style } from '@vanilla-extract/css';
|
||||
import { rem } from 'polished';
|
||||
const myStyle = style({
|
||||
padding: rem(12),
|
||||
fontSize: rem(16),
|
||||
borderRadius: rem(8),
|
||||
borderWidth: rem(1),
|
||||
});
|
||||
`,
|
||||
options: [{ checkHelperFunctions: true }],
|
||||
errors: [
|
||||
{ messageId: 'hardCodedValueNoContract' },
|
||||
{ messageId: 'hardCodedValueNoContract' },
|
||||
{ messageId: 'hardCodedValueNoContract' },
|
||||
{ messageId: 'hardCodedValueNoContract' },
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
run({
|
||||
name: 'vanilla-extract/prefer-theme-tokens',
|
||||
rule: rule,
|
||||
languageOptions: {
|
||||
parser: tsParser,
|
||||
parserOptions: {
|
||||
ecmaVersion: 2022,
|
||||
sourceType: 'module',
|
||||
},
|
||||
},
|
||||
valid: valids,
|
||||
invalid: invalids,
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue