UNPKG

@antebudimir/eslint-plugin-vanilla-extract

Version:

Comprehensive ESLint plugin for vanilla-extract with CSS property ordering, style validation, and best practices enforcement. Supports alphabetical, concentric and custom CSS ordering, auto-fixing, and zero-runtime safety.

538 lines (529 loc) 14.7 kB
import tsParser from '@typescript-eslint/parser'; import { run } from 'eslint-vitest-rule-tester'; import noTrailingZeroRule from '../rule-definition.js'; run({ name: 'vanilla-extract/no-trailing-zero', rule: noTrailingZeroRule, languageOptions: { parser: tsParser, parserOptions: { ecmaVersion: 2022, sourceType: 'module', }, }, valid: [ { code: ` import { style } from '@vanilla-extract/css'; const myStyle = style({ margin: '0', padding: '1px', width: '1.5rem', height: '0.5em', fontSize: '2rem', }); `, name: 'should allow values without trailing zeros', }, { code: ` import { style } from '@vanilla-extract/css'; const myStyle = style({ margin: 0, padding: 1, opacity: 0.5, lineHeight: 1.5, }); `, name: 'should allow numeric literals without trailing zeros', }, { code: ` import { recipe } from '@vanilla-extract/css'; const myRecipe = recipe({ base: { margin: '1px', padding: '0.5rem', }, variants: { size: { small: { height: '10px', width: '0.75em', }, }, }, }); `, name: 'should allow recipe values without trailing zeros', }, { code: ` import { style } from '@vanilla-extract/css'; const myStyle = style({ ...spreadProps, margin: '1px', '@media': { '1.0rem': '0.5rem' // Key shouldn't be checked } }); `, name: 'should ignore spread elements and object keys', }, { code: ` import { style } from '@vanilla-extract/css'; const myStyle = style({ margin: \`1.0\${someUnit}\`, // Template literal padding: someVariable, width: calculateWidth(), }); `, name: 'should ignore non-literal values', }, { code: ` import { globalStyle } from '@vanilla-extract/css'; const callExpression = someObject.fontFace({ src: '...' }); // Non-Identifier callee `, name: 'should ignore member expression callees', }, { code: ` import { fontFace } from '@vanilla-extract/css'; fontFace(); // Missing arguments `, name: 'should handle missing fontFace arguments', }, { code: ` import { globalFontFace } from '@vanilla-extract/css'; globalFontFace('my-font'); // Missing style argument `, name: 'should handle missing globalFontFace style argument', }, { code: ` import { style } from '@vanilla-extract/css'; const myStyle = style({ margin: '10px', padding: '100rem', width: '1000%', }); `, name: 'should allow integers without decimal points', }, { code: ` import { style } from '@vanilla-extract/css'; const myStyle = style({ margin: '11.01rem', padding: '2.05em', width: '0.101%', height: '10.001px', }); `, name: 'should not flag zeros in the middle of decimal numbers', }, ], invalid: [ { code: ` import { style } from '@vanilla-extract/css'; const myStyle = style({ margin: '1.0px', padding: '2.50rem', }); `, errors: [{ messageId: 'trailingZero' }, { messageId: 'trailingZero' }], output: ` import { style } from '@vanilla-extract/css'; const myStyle = style({ margin: '1px', padding: '2.5rem', }); `, name: 'should fix trailing zeros in string values with units', }, { code: ` import { style } from '@vanilla-extract/css'; const myStyle = style({ opacity: 1.0, lineHeight: 2.50, }); `, errors: [{ messageId: 'trailingZero' }, { messageId: 'trailingZero' }], output: ` import { style } from '@vanilla-extract/css'; const myStyle = style({ opacity: 1, lineHeight: 2.5, }); `, name: 'should fix trailing zeros in numeric literals', }, { code: ` import { style } from '@vanilla-extract/css'; const myStyle = style({ margin: '0.0', padding: '0.00px', width: '0.0rem', }); `, errors: [{ messageId: 'trailingZero' }, { messageId: 'trailingZero' }, { messageId: 'trailingZero' }], output: ` import { style } from '@vanilla-extract/css'; const myStyle = style({ margin: '0', padding: '0', width: '0', }); `, name: 'should convert 0.0 to 0', }, { code: ` import { recipe } from '@vanilla-extract/css'; const myRecipe = recipe({ base: { margin: '1.0px', }, variants: { size: { small: { height: '2.50vh', }, }, }, }); `, errors: [{ messageId: 'trailingZero' }, { messageId: 'trailingZero' }], output: ` import { recipe } from '@vanilla-extract/css'; const myRecipe = recipe({ base: { margin: '1px', }, variants: { size: { small: { height: '2.5vh', }, }, }, }); `, name: 'should handle recipe trailing zeros', }, { code: ` import { style } from '@vanilla-extract/css'; const myStyle = style({ margin: '1.0px', '@media': { '(min-width: 768px)': { padding: '2.50rem' } } }); `, errors: 2, output: ` import { style } from '@vanilla-extract/css'; const myStyle = style({ margin: '1px', '@media': { '(min-width: 768px)': { padding: '2.5rem' } } }); `, name: 'should handle nested media queries', }, { code: ` import { style } from '@vanilla-extract/css'; const myStyle = style({ '::before': { content: '""', margin: '1.0px' } }); `, errors: 1, output: ` import { style } from '@vanilla-extract/css'; const myStyle = style({ '::before': { content: '""', margin: '1px' } }); `, name: 'should handle pseudo-elements', }, { code: ` import { style } from '@vanilla-extract/css'; const myStyle = style({ margin: '1.0px', nested: { object: { padding: '2.50rem', deeper: { width: '3.00%' } } } }); `, errors: 3, output: ` import { style } from '@vanilla-extract/css'; const myStyle = style({ margin: '1px', nested: { object: { padding: '2.5rem', deeper: { width: '3%' } } } }); `, name: 'should handle multiple levels of nesting', }, { code: ` import { fontFace, globalFontFace } from '@vanilla-extract/css'; fontFace({ src: '...', lineGap: '1.0rem' }); globalFontFace('my-font', { src: '...', sizeAdjust: '100.0%' }); `, errors: 2, output: ` import { fontFace, globalFontFace } from '@vanilla-extract/css'; fontFace({ src: '...', lineGap: '1rem' }); globalFontFace('my-font', { src: '...', sizeAdjust: '100%' }); `, name: 'should handle fontFace and globalFontFace arguments', }, { code: ` import { globalKeyframes, globalStyle } from '@vanilla-extract/css'; globalKeyframes('spin', { '0%': { transform: 'rotate(0deg)' }, '100%': { transform: 'rotate(360.0deg)' } }); globalStyle('html', { margin: '1.0px', padding: '2.50rem' }); `, errors: 3, output: ` import { globalKeyframes, globalStyle } from '@vanilla-extract/css'; globalKeyframes('spin', { '0%': { transform: 'rotate(0deg)' }, '100%': { transform: 'rotate(360deg)' } }); globalStyle('html', { margin: '1px', padding: '2.5rem' }); `, name: 'should handle globalKeyframes and globalStyle arguments', }, { code: ` import { globalStyle } from '@vanilla-extract/css'; globalStyle('html', { '@media': { '(min-width: 768px)': { margin: '1.0px' } } }); `, errors: 1, output: ` import { globalStyle } from '@vanilla-extract/css'; globalStyle('html', { '@media': { '(min-width: 768px)': { margin: '1px' } } }); `, name: 'should handle nested globalStyle arguments', }, { code: ` import { style } from '@vanilla-extract/css'; const myStyle = style({ margin: '-1.0px', padding: '-2.50rem', top: '-0.0vh', }); `, errors: [{ messageId: 'trailingZero' }, { messageId: 'trailingZero' }, { messageId: 'trailingZero' }], output: ` import { style } from '@vanilla-extract/css'; const myStyle = style({ margin: '-1px', padding: '-2.5rem', top: '0', }); `, name: 'should handle negative values with trailing zeros', }, { code: ` import { style } from '@vanilla-extract/css'; const myStyle = style({ margin: '1.50em', padding: '0.50rem', width: '10.00%', }); `, errors: [{ messageId: 'trailingZero' }, { messageId: 'trailingZero' }, { messageId: 'trailingZero' }], output: ` import { style } from '@vanilla-extract/css'; const myStyle = style({ margin: '1.5em', padding: '0.5rem', width: '10%', }); `, name: 'should remove trailing zeros from decimal values', }, { code: ` import { style } from '@vanilla-extract/css'; const myStyle = style({ padding: '1.0px 2.50rem 3.00em 0.50vh', }); `, errors: 1, output: ` import { style } from '@vanilla-extract/css'; const myStyle = style({ padding: '1px 2.5rem 3em 0.5vh', }); `, name: 'should handle multiple values in a single string', }, { code: ` import { style } from '@vanilla-extract/css'; const myStyle = style({ transition: 'all 0.30s ease', animation: 'spin 2.0s linear', }); `, errors: 2, output: ` import { style } from '@vanilla-extract/css'; const myStyle = style({ transition: 'all 0.3s ease', animation: 'spin 2s linear', }); `, name: 'should handle time units', }, { code: ` import { style } from '@vanilla-extract/css'; const myStyle = style({ transform: 'rotate(45.0deg)', filter: 'hue-rotate(180.00deg)', }); `, errors: 2, output: ` import { style } from '@vanilla-extract/css'; const myStyle = style({ transform: 'rotate(45deg)', filter: 'hue-rotate(180deg)', }); `, name: 'should handle angle units', }, { code: ` import { styleVariants } from '@vanilla-extract/css'; const variants = styleVariants({ small: { padding: '1.0px' }, medium: { padding: '2.50px' }, large: { padding: '3.00px' }, }); `, errors: 3, output: ` import { styleVariants } from '@vanilla-extract/css'; const variants = styleVariants({ small: { padding: '1px' }, medium: { padding: '2.5px' }, large: { padding: '3px' }, }); `, name: 'should handle styleVariants', }, { code: ` import { keyframes } from '@vanilla-extract/css'; const spin = keyframes({ '0%': { transform: 'rotate(0.0deg)' }, '50%': { transform: 'rotate(180.0deg)' }, '100%': { transform: 'rotate(360.0deg)' }, }); `, errors: 3, output: ` import { keyframes } from '@vanilla-extract/css'; const spin = keyframes({ '0%': { transform: 'rotate(0deg)' }, '50%': { transform: 'rotate(180deg)' }, '100%': { transform: 'rotate(360deg)' }, }); `, name: 'should handle keyframes', }, { code: ` import { style } from '@vanilla-extract/css'; const myStyle = style({ margin: '1.000px', padding: '2.5000rem', width: '0.00000em', }); `, errors: 3, output: ` import { style } from '@vanilla-extract/css'; const myStyle = style({ margin: '1px', padding: '2.5rem', width: '0', }); `, name: 'should handle multiple trailing zeros', }, ], });