mirror of
https://github.com/antebudimir/eslint-plugin-vanilla-extract.git
synced 2026-01-02 17:43:31 +00:00
feat 🥁: initialize project with complete codebase
This commit is contained in:
commit
d569dea1fb
35 changed files with 4413 additions and 0 deletions
91
src/css-rules/custom-order/property-order-enforcer.ts
Normal file
91
src/css-rules/custom-order/property-order-enforcer.ts
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
import type { Rule } from 'eslint';
|
||||
import { generateFixesForCSSOrder } from '../shared-utils/css-order-fixer.js';
|
||||
import { createCSSPropertyPriorityMap } from '../shared-utils/css-property-priority-map.js';
|
||||
import type { CSSPropertyInfo } from '../concentric-order/types.js';
|
||||
|
||||
/**
|
||||
* Enforces a custom ordering of CSS properties based on user-defined groups.
|
||||
*
|
||||
* @param ruleContext The ESLint rule context used for reporting and fixing.
|
||||
* @param cssPropertyInfoList An array of CSS property information objects to be ordered.
|
||||
* @param userDefinedGroups Array of user-defined property groups for custom ordering.
|
||||
* @param sortRemainingProperties Strategy for sorting properties not in user-defined groups
|
||||
* ('alphabetical' or 'concentric'). Defaults to 'concentric'.
|
||||
*
|
||||
* This function compares CSS properties based on their group priority and position within
|
||||
* those groups. Properties not part of user-defined groups are sorted according to the
|
||||
* specified strategy. If an ordering violation is detected, an ESLint report is generated
|
||||
* with a suggested fix.
|
||||
*/
|
||||
export const enforceCustomGroupOrder = (
|
||||
ruleContext: Rule.RuleContext,
|
||||
cssPropertyInfoList: CSSPropertyInfo[],
|
||||
userDefinedGroups: string[] = [],
|
||||
sortRemainingProperties?: 'alphabetical' | 'concentric',
|
||||
): void => {
|
||||
if (cssPropertyInfoList.length <= 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
const cssPropertyPriorityMap = createCSSPropertyPriorityMap(userDefinedGroups);
|
||||
|
||||
const compareProperties = (firstProperty: CSSPropertyInfo, secondProperty: CSSPropertyInfo) => {
|
||||
const firstPropertyInfo = cssPropertyPriorityMap.get(firstProperty.name) || {
|
||||
groupIndex: Infinity,
|
||||
positionInGroup: Infinity,
|
||||
inUserGroup: false,
|
||||
};
|
||||
const secondPropertyInfo = cssPropertyPriorityMap.get(secondProperty.name) || {
|
||||
groupIndex: Infinity,
|
||||
positionInGroup: Infinity,
|
||||
inUserGroup: false,
|
||||
};
|
||||
|
||||
if (firstPropertyInfo.inUserGroup !== secondPropertyInfo.inUserGroup) {
|
||||
return firstPropertyInfo.inUserGroup ? -1 : 1;
|
||||
}
|
||||
|
||||
if (firstPropertyInfo.inUserGroup) {
|
||||
if (firstPropertyInfo.groupIndex !== secondPropertyInfo.groupIndex) {
|
||||
return firstPropertyInfo.groupIndex - secondPropertyInfo.groupIndex;
|
||||
}
|
||||
return firstPropertyInfo.positionInGroup - secondPropertyInfo.positionInGroup;
|
||||
}
|
||||
|
||||
// For properties not in user-defined groups
|
||||
if (sortRemainingProperties === 'alphabetical') {
|
||||
return firstProperty.name.localeCompare(secondProperty.name);
|
||||
} else {
|
||||
return (
|
||||
firstPropertyInfo.groupIndex - secondPropertyInfo.groupIndex ||
|
||||
firstPropertyInfo.positionInGroup - secondPropertyInfo.positionInGroup
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const sortedPropertyList = [...cssPropertyInfoList].sort(compareProperties);
|
||||
|
||||
// Find the first pair that violates the new ordering
|
||||
const violatingProperty = cssPropertyInfoList
|
||||
.slice(0, -1)
|
||||
.find((currentProperty, index) => currentProperty.name !== sortedPropertyList[index]?.name);
|
||||
|
||||
if (violatingProperty) {
|
||||
ruleContext.report({
|
||||
node: violatingProperty.node as Rule.Node,
|
||||
messageId: 'incorrectOrder',
|
||||
data: {
|
||||
currentProperty: violatingProperty.name,
|
||||
nextProperty: sortedPropertyList[cssPropertyInfoList.indexOf(violatingProperty)]?.name || '',
|
||||
},
|
||||
fix: (fixer) =>
|
||||
generateFixesForCSSOrder(
|
||||
fixer,
|
||||
ruleContext,
|
||||
cssPropertyInfoList,
|
||||
compareProperties,
|
||||
(propertyInfo) => propertyInfo.node as Rule.Node,
|
||||
),
|
||||
});
|
||||
}
|
||||
};
|
||||
42
src/css-rules/custom-order/recipe-order-enforcer.ts
Normal file
42
src/css-rules/custom-order/recipe-order-enforcer.ts
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
import type { Rule } from 'eslint';
|
||||
import { TSESTree } from '@typescript-eslint/utils';
|
||||
import { processRecipeProperties } from '../shared-utils/recipe-property-processor.js';
|
||||
import { processStyleNode } from '../shared-utils/style-node-processor.js';
|
||||
import { enforceUserDefinedGroupOrderInStyleObject } from './style-object-processor.js';
|
||||
|
||||
/**
|
||||
* Enforces custom group ordering of CSS properties within a recipe function call.
|
||||
*
|
||||
* @param ruleContext The ESLint rule context for reporting and fixing issues.
|
||||
* @param callExpression The CallExpression node representing the recipe function call.
|
||||
* @param userDefinedGroups An array of property groups in the desired order.
|
||||
*
|
||||
* This function does the following:
|
||||
* 1. Validates that the first argument of the recipe function is an ObjectExpression.
|
||||
* 2. Processes the recipe object's properties if valid.
|
||||
* 3. Applies custom group ordering to CSS properties in relevant properties (e.g., 'base', 'variants').
|
||||
* 4. Processes nested selectors and style objects recursively.
|
||||
*/
|
||||
export const enforceUserDefinedGroupOrderInRecipe = (
|
||||
ruleContext: Rule.RuleContext,
|
||||
callExpression: TSESTree.CallExpression,
|
||||
userDefinedGroups: string[],
|
||||
sortRemainingPropertiesMethod?: 'alphabetical' | 'concentric',
|
||||
): void => {
|
||||
if (!callExpression.arguments[0] || callExpression.arguments[0].type !== 'ObjectExpression') {
|
||||
return;
|
||||
}
|
||||
|
||||
const recipeObjectExpression = callExpression.arguments[0];
|
||||
|
||||
processRecipeProperties(ruleContext, recipeObjectExpression, (currentContext, styleObject) =>
|
||||
processStyleNode(currentContext, styleObject, (styleContext, styleObjectNode) =>
|
||||
enforceUserDefinedGroupOrderInStyleObject(
|
||||
styleContext,
|
||||
styleObjectNode,
|
||||
userDefinedGroups,
|
||||
sortRemainingPropertiesMethod,
|
||||
),
|
||||
),
|
||||
);
|
||||
};
|
||||
55
src/css-rules/custom-order/rule-definition.ts
Normal file
55
src/css-rules/custom-order/rule-definition.ts
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
import type { Rule } from 'eslint';
|
||||
import { availableGroups } from '../concentric-order/concentric-groups.js';
|
||||
import { createNodeVisitors } from '../shared-utils/order-strategy-visitor-creator.js';
|
||||
|
||||
interface CustomGroupRuleConfiguration {
|
||||
groupOrder?: string[];
|
||||
sortRemainingProperties: 'alphabetical' | 'concentric';
|
||||
}
|
||||
|
||||
const customGroupOrderRule: Rule.RuleModule = {
|
||||
meta: {
|
||||
type: 'suggestion',
|
||||
docs: {
|
||||
description: 'enforce custom group CSS property ordering in vanilla-extract styles',
|
||||
category: 'Stylistic Issues',
|
||||
recommended: true,
|
||||
},
|
||||
fixable: 'code',
|
||||
schema: [
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
groupOrder: {
|
||||
type: 'array',
|
||||
items: {
|
||||
enum: availableGroups,
|
||||
},
|
||||
},
|
||||
sortRemainingProperties: {
|
||||
enum: ['alphabetical', 'concentric'],
|
||||
},
|
||||
},
|
||||
additionalProperties: false,
|
||||
},
|
||||
],
|
||||
messages: {
|
||||
incorrectOrder:
|
||||
"Property '{{nextProperty}}' should come before '{{currentProperty}}' according to custom CSS group ordering.",
|
||||
},
|
||||
},
|
||||
create(ruleContext: Rule.RuleContext) {
|
||||
const ruleConfiguration = ruleContext.options[0] as CustomGroupRuleConfiguration;
|
||||
const userDefinedGroupOrder = ruleConfiguration?.groupOrder ?? [];
|
||||
const sortRemainingPropertiesMethod = ruleConfiguration?.sortRemainingProperties ?? 'alphabetical';
|
||||
|
||||
return createNodeVisitors(
|
||||
ruleContext,
|
||||
'userDefinedGroupOrder',
|
||||
userDefinedGroupOrder,
|
||||
sortRemainingPropertiesMethod,
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
export default customGroupOrderRule;
|
||||
79
src/css-rules/custom-order/style-object-processor.ts
Normal file
79
src/css-rules/custom-order/style-object-processor.ts
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
import type { Rule } from 'eslint';
|
||||
import { AST_NODE_TYPES, TSESTree } from '@typescript-eslint/utils';
|
||||
import { concentricGroups } from '../concentric-order/concentric-groups.js';
|
||||
import { createCSSPropertyPriorityMap } from '../shared-utils/css-property-priority-map.js';
|
||||
import { isSelectorsObject, processNestedSelectors } from '../shared-utils/nested-selectors-processor.js';
|
||||
import { getPropertyName, separateProperties } from '../shared-utils/property-separator.js';
|
||||
import { enforceCustomGroupOrder } from './property-order-enforcer.js';
|
||||
import type { CSSPropertyInfo } from '../concentric-order/types.js';
|
||||
|
||||
/**
|
||||
* Enforces a custom ordering of CSS properties based on user-defined groups in a given style object.
|
||||
*
|
||||
* @param context The ESLint rule context for reporting and fixing issues.
|
||||
* @param styleObject The ObjectExpression node representing the style object to be processed.
|
||||
* @param userDefinedGroups An array of property groups in the desired order.
|
||||
* @param sortRemainingPropertiesMethod Strategy for sorting properties not in user-defined groups ('alphabetical' or 'concentric'). Defaults to 'concentric'.
|
||||
*
|
||||
* This function:
|
||||
* 1. Validates the input styleObject.
|
||||
* 2. Handles 'selectors' objects separately, processing their nested style objects.
|
||||
* 3. Creates a priority map based on user-defined groups.
|
||||
* 4. Processes regular properties, creating a list of CSSPropertyInfo objects.
|
||||
* 5. Enforces custom group ordering on the properties.
|
||||
* 6. Recursively processes nested selectors and style objects.
|
||||
*/
|
||||
export const enforceUserDefinedGroupOrderInStyleObject = (
|
||||
ruleContext: Rule.RuleContext,
|
||||
styleObject: TSESTree.ObjectExpression,
|
||||
userDefinedGroups: string[],
|
||||
sortRemainingPropertiesMethod: 'alphabetical' | 'concentric' = 'concentric',
|
||||
): void => {
|
||||
if (!styleObject || styleObject.type !== AST_NODE_TYPES.ObjectExpression) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isSelectorsObject(styleObject)) {
|
||||
styleObject.properties.forEach((property) => {
|
||||
if (property.type === AST_NODE_TYPES.Property && property.value.type === AST_NODE_TYPES.ObjectExpression) {
|
||||
enforceUserDefinedGroupOrderInStyleObject(
|
||||
ruleContext,
|
||||
property.value,
|
||||
userDefinedGroups,
|
||||
sortRemainingPropertiesMethod,
|
||||
);
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const cssPropertyPriorityMap = createCSSPropertyPriorityMap(userDefinedGroups);
|
||||
|
||||
const { regularProperties } = separateProperties(styleObject.properties);
|
||||
const cssPropertyInfoList: CSSPropertyInfo[] = regularProperties.map((property) => {
|
||||
const propertyName = getPropertyName(property);
|
||||
const propertyInfo = cssPropertyPriorityMap.get(propertyName);
|
||||
const group =
|
||||
userDefinedGroups.find((groupName) => concentricGroups[groupName]?.includes(propertyName)) || 'remaining';
|
||||
|
||||
return {
|
||||
name: propertyName,
|
||||
node: property,
|
||||
priority: propertyInfo?.groupIndex ?? Number.MAX_SAFE_INTEGER,
|
||||
positionInGroup: propertyInfo?.positionInGroup ?? Number.MAX_SAFE_INTEGER,
|
||||
group,
|
||||
inUserGroup: propertyInfo?.inUserGroup ?? false,
|
||||
};
|
||||
});
|
||||
|
||||
enforceCustomGroupOrder(ruleContext, cssPropertyInfoList, userDefinedGroups, sortRemainingPropertiesMethod);
|
||||
|
||||
processNestedSelectors(ruleContext, styleObject, (nestedContext, nestedNode) =>
|
||||
enforceUserDefinedGroupOrderInStyleObject(
|
||||
nestedContext,
|
||||
nestedNode,
|
||||
userDefinedGroups,
|
||||
sortRemainingPropertiesMethod,
|
||||
),
|
||||
);
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue