eslint-plugin-vanilla-extract/src/css-rules/no-empty-blocks/empty-nested-style-processor.ts
Ante Budimir 7dc7204749 feat 🥁: add no-zero-unit rule
This rule enforces unitless zero values in vanilla-extract style objects:
- Automatically removes unnecessary units from zero values
- Handles both positive and negative zero values
- Preserves units where required (time properties, CSS functions)
- Works with all vanilla-extract APIs
2025-04-12 20:53:34 +03:00

75 lines
2.7 KiB
TypeScript

import type { Rule } from 'eslint';
import { TSESTree } from '@typescript-eslint/utils';
import { isEmptyObject } from '../shared-utils/empty-object-processor.js';
import { removeNodeWithComma } from './node-remover.js';
import { areAllChildrenEmpty, getStyleKeyName } from './property-utils.js';
/**
* Processes nested style objects like selectors and media queries.
*/
export const processEmptyNestedStyles = (
ruleContext: Rule.RuleContext,
node: TSESTree.ObjectExpression,
reportedNodes: Set<TSESTree.Node>,
): void => {
node.properties.forEach((property) => {
if (property.type !== 'Property') {
return;
}
const propertyName = getStyleKeyName(property.key);
if (!propertyName) {
return;
}
// Handle selectors, media queries, and supports
if ((propertyName === 'selectors' || propertyName.startsWith('@')) && property.value.type === 'ObjectExpression') {
// If the container is empty or all its children are empty, remove the entire property
if (isEmptyObject(property.value) || areAllChildrenEmpty(property.value)) {
if (!reportedNodes.has(property)) {
reportedNodes.add(property);
const messageId =
propertyName === 'selectors'
? 'emptySelectors'
: propertyName === '@media'
? 'emptyMedia'
: propertyName === '@supports'
? 'emptySupports'
: 'emptyConditionalStyle';
ruleContext.report({
node: property as Rule.Node,
messageId,
fix(fixer) {
return removeNodeWithComma(ruleContext, property, fixer);
},
});
}
return;
}
// Process individual selectors or media queries if we're not removing the entire container
property.value.properties.forEach((nestedProperty) => {
if (nestedProperty.type === 'Property') {
if (nestedProperty.value.type === 'ObjectExpression') {
if (isEmptyObject(nestedProperty.value)) {
if (!reportedNodes.has(nestedProperty)) {
reportedNodes.add(nestedProperty);
ruleContext.report({
node: nestedProperty as Rule.Node,
messageId: 'emptyNestedStyle',
fix(fixer) {
return removeNodeWithComma(ruleContext, nestedProperty, fixer);
},
});
}
} else {
// Recursively process nested styles (for deeply nested selectors/media)
processEmptyNestedStyles(ruleContext, nestedProperty.value, reportedNodes);
}
}
}
});
}
});
};