feat 🥁: add no-trailing-zero rule

- New rule that flags and fixes unnecessary trailing zeros in numeric values
- Handles various CSS units, negative numbers, and decimal values
- Preserves non-trailing zeros in numbers like 11.01rem and 2.05em
- Includes comprehensive test coverage for edge cases
This commit is contained in:
Ante Budimir 2025-10-22 06:06:33 +03:00
parent 24681ebad9
commit 9263c5dd24
9 changed files with 909 additions and 5 deletions

View file

@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [1.12.0] - 2025-10-22
- Add new rule `no-trailing-zero` that flags and fixes unnecessary trailing zeros in numeric values
- Handles various CSS units, negative numbers, and decimal values
- Preserves non-trailing zeros in numbers like 11.01rem and 2.05em
- Includes comprehensive test coverage for edge cases
## [1.11.1] - 2025-10-15
- Improve README structure and clarity

View file

@ -259,6 +259,7 @@ The recommended configuration enables the following rules with error severity:
- `vanilla-extract/concentric-order`: Enforces concentric CSS property ordering
- `vanilla-extract/no-empty-style-blocks`: Prevents empty style blocks
- `vanilla-extract/no-trailing-zero`: Disallows trailing zeros in numeric CSS values
- `vanilla-extract/no-unknown-unit`: Prohibits usage of unrecognized CSS units
- `vanilla-extract/no-zero-unit`: Removes unnecessary units for zero values
@ -464,6 +465,37 @@ export const recipeWithEmptyVariants = recipe({
});
```
## vanilla-extract/no-trailing-zero
This rule disallows trailing zeros in numeric CSS values within vanilla-extract style objects. It helps maintain cleaner
and more consistent CSS by removing unnecessary trailing zeros from decimal numbers.
```typescript
// ❌ Incorrect
import { style } from '@vanilla-extract/css';
export const myStyle = style({
margin: '1.0px',
padding: '2.50rem',
opacity: 1.0,
lineHeight: 2.50,
width: '0.0em',
transition: 'all 0.30s ease',
});
// ✅ Correct
import { style } from '@vanilla-extract/css';
export const myStyle = style({
margin: '1px',
padding: '2.5rem',
opacity: 1,
lineHeight: 2.5,
width: '0',
transition: 'all 0.3s ease',
});
```
## vanilla-extract/no-unknown-unit
This rule enforces the use of valid CSS units in vanilla-extract style objects. It prevents typos and non-standard units
@ -612,17 +644,17 @@ The roadmap outlines the project's current status and future plans:
- Recommended ESLint configuration for the plugin.
- `no-zero-unit` rule to disallow units when the value is zero.
- `no-unknown-unit` rule to disallow unknown units.
- Support for using the plugins recommended config via the extends field (as discussed in
- `no-trailing-zero` rule to disallow trailing zeros in numbers.
- Support for using the plugin's recommended config via the extends field (as discussed in
[issue #3](https://github.com/antebudimir/eslint-plugin-vanilla-extract/issues/3))
- Comprehensive rule testing.
### Current Work
- `no-number-trailing-zero` rule to disallow trailing zeros in numbers.
- `no-px-unit` rule to disallow use of `px` units with configurable whitelist.
### Upcoming Features
- `no-px-unit` rule to disallow use of `px` units with configurable whitelist.
- `prefer-logical-properties` rule to enforce use of logical properties.
- `prefer-theme-tokens` rule to enforce use of theme tokens instead of hard-coded values when available.
- `no-global-style` rule to disallow use of `globalStyle` function.

View file

@ -1,6 +1,6 @@
{
"name": "@antebudimir/eslint-plugin-vanilla-extract",
"version": "1.11.1",
"version": "1.12.0",
"description": "ESLint plugin for enforcing best practices in vanilla-extract CSS styles, including CSS property ordering and additional linting rules.",
"author": "Ante Budimir",
"license": "MIT",

View file

@ -0,0 +1,538 @@
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',
},
],
});

View file

@ -0,0 +1 @@
export { default } from './rule-definition.js';

View file

@ -0,0 +1,23 @@
import type { Rule } from 'eslint';
import { createTrailingZeroVisitors } from './trailing-zero-visitor-creator.js';
const noTrailingZeroRule: Rule.RuleModule = {
meta: {
type: 'suggestion',
docs: {
description: 'disallow trailing zeros in numeric CSS values',
category: 'Stylistic Issues',
recommended: true,
},
fixable: 'code',
schema: [],
messages: {
trailingZero: 'Numeric value "{{ value }}" has unnecessary trailing zeros. Use "{{ fixed }}" instead.',
},
},
create(context) {
return createTrailingZeroVisitors(context);
},
};
export default noTrailingZeroRule;

View file

@ -0,0 +1,197 @@
import type { Rule } from 'eslint';
import { TSESTree } from '@typescript-eslint/utils';
/**
* Regex to match numbers with trailing zeros.
* Matches patterns like:
* - 1.0, 2.50, 0.0, 0.50
* - 1.0px, 2.50rem, 0.0em
* - -1.0, -2.50px
*
* Groups:
* 1: Optional minus sign
* 2: Integer part
* 3: Significant fractional digits (optional)
* 4: Trailing zeros
* 5: Optional unit
*/
const TRAILING_ZERO_REGEX = /^(-?)(\d+)\.(\d*[1-9])?(0+)([a-z%]+)?$/i;
/**
* Checks if a value has trailing zeros and returns the fixed value if needed.
*
* @param value The string value to check
* @returns Object with hasTrailingZero flag and fixed value, or null if no trailing zeros
*/
export const checkTrailingZero = (value: string): { hasTrailingZero: boolean; fixed: string } | null => {
const trimmedValue = value.trim();
const match = trimmedValue.match(TRAILING_ZERO_REGEX);
if (!match) {
return null;
}
const [, minus = '', integerPart, significantFractional = '', , unit = ''] = match;
// Handle special case: 0.0 or 0.00 etc. should become just "0"
if (integerPart === '0' && !significantFractional) {
return {
hasTrailingZero: true,
fixed: '0',
};
}
// If there's no significant fractional part (e.g., "1.0" -> "1")
if (!significantFractional) {
return {
hasTrailingZero: true,
fixed: `${minus}${integerPart}${unit}`,
};
}
// If there's a significant fractional part (e.g., "1.50" -> "1.5")
return {
hasTrailingZero: true,
fixed: `${minus}${integerPart}.${significantFractional}${unit}`,
};
};
/**
* Processes a single string value and checks for trailing zeros in all numeric values.
* Handles strings with multiple numeric values (e.g., "1.0px 2.50em").
* Also handles values within function calls (e.g., "rotate(45.0deg)").
*
* @param value The string value to process
* @returns Object with hasTrailingZero flag and fixed value, or null if no trailing zeros
*/
export const processStringValue = (value: string): { hasTrailingZero: boolean; fixed: string } | null => {
// First, try to match the entire value
const directMatch = checkTrailingZero(value);
if (directMatch?.hasTrailingZero) {
return directMatch;
}
// Split by whitespace to handle multiple values
const parts = value.split(/(\s+)/);
let hasAnyTrailingZero = false;
const fixedParts = parts.map((part) => {
// Preserve whitespace
if (/^\s+$/.test(part)) {
return part;
}
// Try to match the whole part first
const result = checkTrailingZero(part);
if (result?.hasTrailingZero) {
hasAnyTrailingZero = true;
return result.fixed;
}
// If no match, try to find and replace numbers within the part (e.g., inside function calls)
const regex = /(-?\d+)\.(\d*[1-9])?(0+)(?![0-9])([a-z%]+)?/gi;
const fixedPart = part.replace(
regex,
(_: string, integerWithSign: string, significantFractional: string, __: string, unit: string) => {
// Reconstruct the number without trailing zeros
const integerPart = integerWithSign;
const sig = significantFractional || '';
const u = unit || '';
// Handle 0.0 case - if it's zero and no unit, return just '0', otherwise keep the unit
if (integerPart === '0' && !sig) {
hasAnyTrailingZero = true;
return u ? `0${u}` : '0';
}
// Handle X.0 case
if (!sig) {
hasAnyTrailingZero = true;
return `${integerPart}${u}`;
}
// Handle X.Y0 case
hasAnyTrailingZero = true;
return `${integerPart}.${sig}${u}`;
},
);
return fixedPart;
});
if (!hasAnyTrailingZero) {
return null;
}
return {
hasTrailingZero: true,
fixed: fixedParts.join(''),
};
};
/**
* Recursively processes a style object, reporting and fixing instances of trailing zeros in numeric values.
*
* @param ruleContext The ESLint rule context.
* @param node The ObjectExpression node representing the style object to be processed.
*/
export const processTrailingZeroInStyleObject = (
ruleContext: Rule.RuleContext,
node: TSESTree.ObjectExpression,
): void => {
node.properties.forEach((property) => {
if (property.type !== 'Property') {
return;
}
// Process direct string literal values
if (property.value.type === 'Literal' && typeof property.value.value === 'string') {
const result = processStringValue(property.value.value);
if (result?.hasTrailingZero) {
ruleContext.report({
node: property.value,
messageId: 'trailingZero',
data: {
value: property.value.value,
fixed: result.fixed,
},
fix: (fixer) => fixer.replaceText(property.value, `'${result.fixed}'`),
});
}
}
// Process numeric literal values (e.g., margin: 1.0)
if (property.value.type === 'Literal' && typeof property.value.value === 'number') {
// Use the raw property to get the original source text (which preserves trailing zeros)
const rawValue = property.value.raw || property.value.value.toString();
const result = checkTrailingZero(rawValue);
if (result?.hasTrailingZero) {
ruleContext.report({
node: property.value,
messageId: 'trailingZero',
data: {
value: rawValue,
fixed: result.fixed,
},
fix: (fixer) => fixer.replaceText(property.value, result.fixed),
});
}
}
// Process nested objects (selectors, media queries, etc.)
if (property.value.type === 'ObjectExpression') {
processTrailingZeroInStyleObject(ruleContext, property.value);
}
// Process arrays (for styleVariants with array values)
if (property.value.type === 'ArrayExpression') {
property.value.elements.forEach((element) => {
if (element && element.type === 'ObjectExpression') {
processTrailingZeroInStyleObject(ruleContext, element);
}
});
}
});
};

View file

@ -0,0 +1,103 @@
import type { Rule } from 'eslint';
import { AST_NODE_TYPES, TSESTree } from '@typescript-eslint/utils';
import { processRecipeProperties } from '../shared-utils/recipe-property-processor.js';
import { ReferenceTracker, createReferenceTrackingVisitor } from '../shared-utils/reference-tracker.js';
import { processStyleNode } from '../shared-utils/style-node-processor.js';
import { processTrailingZeroInStyleObject } from './trailing-zero-processor.js';
/**
* Creates ESLint rule visitors for detecting and processing trailing zeros in numeric CSS values.
* Uses reference tracking to automatically detect vanilla-extract functions based on their import statements.
*
* @param context The ESLint rule context.
* @returns An object with visitor functions for the ESLint rule.
*/
export const createTrailingZeroVisitors = (context: Rule.RuleContext): Rule.RuleListener => {
const tracker = new ReferenceTracker();
const trackingVisitor = createReferenceTrackingVisitor(tracker);
return {
// Include the reference tracking visitors
...trackingVisitor,
CallExpression(node) {
if (node.callee.type !== AST_NODE_TYPES.Identifier) {
return;
}
const functionName = node.callee.name;
// Check if this function is tracked as a vanilla-extract function
if (!tracker.isTrackedFunction(functionName)) {
return;
}
const originalName = tracker.getOriginalName(functionName);
if (!originalName) {
return;
}
// Handle different function types based on their original imported name
switch (originalName) {
case 'fontFace':
if (node.arguments.length > 0 && node.arguments[0]?.type === AST_NODE_TYPES.ObjectExpression) {
processTrailingZeroInStyleObject(context, node.arguments[0] as TSESTree.ObjectExpression);
}
break;
case 'globalFontFace':
if (node.arguments.length > 1 && node.arguments[1]?.type === AST_NODE_TYPES.ObjectExpression) {
processTrailingZeroInStyleObject(context, node.arguments[1] as TSESTree.ObjectExpression);
}
break;
case 'style':
if (node.arguments.length > 0) {
processStyleNode(context, node.arguments[0] as TSESTree.ObjectExpression, processTrailingZeroInStyleObject);
}
break;
case 'styleVariants':
case 'keyframes':
// For styleVariants and keyframes, the argument is an object where each property value is a style object
if (node.arguments.length > 0 && node.arguments[0]?.type === AST_NODE_TYPES.ObjectExpression) {
const variantsObject = node.arguments[0] as TSESTree.ObjectExpression;
variantsObject.properties.forEach((property) => {
if (property.type === 'Property' && property.value.type === 'ObjectExpression') {
processTrailingZeroInStyleObject(context, property.value);
}
});
}
break;
case 'globalStyle':
if (node.arguments.length >= 2) {
processStyleNode(context, node.arguments[1] as TSESTree.ObjectExpression, processTrailingZeroInStyleObject);
}
break;
case 'globalKeyframes':
// For globalKeyframes, the second argument is an object where each property value is a style object
if (node.arguments.length >= 2 && node.arguments[1]?.type === AST_NODE_TYPES.ObjectExpression) {
const keyframesObject = node.arguments[1] as TSESTree.ObjectExpression;
keyframesObject.properties.forEach((property) => {
if (property.type === 'Property' && property.value.type === 'ObjectExpression') {
processTrailingZeroInStyleObject(context, property.value);
}
});
}
break;
case 'recipe':
if (node.arguments.length > 0 && node.arguments[0]?.type === AST_NODE_TYPES.ObjectExpression) {
processRecipeProperties(
context,
node.arguments[0] as TSESTree.ObjectExpression,
processTrailingZeroInStyleObject,
);
}
break;
}
},
};
};

View file

@ -2,19 +2,21 @@ import alphabeticalOrderRule from './css-rules/alphabetical-order/index.js';
import concentricOrderRule from './css-rules/concentric-order/index.js';
import customOrderRule from './css-rules/custom-order/rule-definition.js';
import noEmptyStyleBlocksRule from './css-rules/no-empty-blocks/rule-definition.js';
import noTrailingZeroRule from './css-rules/no-trailing-zero/rule-definition.js';
import noUnknownUnitRule from './css-rules/no-unknown-unit/rule-definition.js';
import noZeroUnitRule from './css-rules/no-zero-unit/rule-definition.js';
const vanillaExtract = {
meta: {
name: '@antebudimir/eslint-plugin-vanilla-extract',
version: '1.11.1',
version: '1.12.0',
},
rules: {
'alphabetical-order': alphabeticalOrderRule,
'concentric-order': concentricOrderRule,
'custom-order': customOrderRule,
'no-empty-style-blocks': noEmptyStyleBlocksRule,
'no-trailing-zero': noTrailingZeroRule,
'no-unknown-unit': noUnknownUnitRule,
'no-zero-unit': noZeroUnitRule,
},
@ -29,6 +31,7 @@ Object.assign(vanillaExtract.configs, {
rules: {
'vanilla-extract/concentric-order': 'error',
'vanilla-extract/no-empty-style-blocks': 'error',
'vanilla-extract/no-trailing-zero': 'error',
'vanilla-extract/no-unknown-unit': 'error',
'vanilla-extract/no-zero-unit': 'error',
},