Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More β†’
Socket
Sign inDemoInstall
Socket

eslint-plugin-tailwindcss

Package Overview
Dependencies
Maintainers
1
Versions
184
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

eslint-plugin-tailwindcss - npm Package Compare versions

Comparing version 3.6.0-beta.0 to 3.6.0-beta.1

4

lib/config/groups.js
/**
* @fileoverview Default grouping for Tailwind CSS classnames following the order of the official docs
* @fileoverview Default groups for Tailwind CSS classnames
* @description The hierarchy of `members` can be useful to detect redundant and/or contradicting classnames
* @version v3.0.0
* @version v3.1.3
* @see https://tailwindcss.com/docs

@@ -6,0 +6,0 @@ * @author François Massart

@@ -13,2 +13,3 @@ /**

const getOption = require('../util/settings');
const groups = require('../config/groups').groups;
const parserUtil = require('../util/parser');

@@ -53,6 +54,2 @@ const order = require('../util/prettier/order');

},
groups: {
type: 'array',
items: { type: 'object' },
},
removeDuplicates: {

@@ -76,3 +73,3 @@ default: true,

const twConfig = getOption(context, 'config');
const groupsConfig = getOption(context, 'groups');
const groupsConfig = groups;
const removeDuplicates = getOption(context, 'removeDuplicates');

@@ -92,126 +89,2 @@

/**
* Get the index of a variant within a className
* @param {String} str The input string (haystack)
* @param {Array} arr The list of possible variants (needle)
* @param {Boolean} beginning Optional, starts from the beginning
* @returns {Number}
*/
const getPrefixIndex = (str, arr, beginning = false) => {
const start = beginning ? '^' : '';
let idx = arr.findIndex((el) => {
const separator = '\\' + mergedConfig.separator;
const pattern = `${start}${el}${separator}.*`;
const re = new RegExp(pattern);
return re.test(str);
}, str);
return idx;
};
/**
* Add left '0' padding to given number
* @param {Number} num The input number
* @param {Number} size Optional, the desired length
* @returns {String}
*/
const pad = (num, size = 2) => {
let str = '' + num;
while (str.length < size) {
str = '0' + str;
}
return str;
};
/**
* Generate an Array of Array, grouping class by responsive variants
* @param {Array} classNames
* @returns {Array} an Array (one entry per responsive variant), each entry is an array of classnames
*/
const getResponsiveGroups = (classNames) => {
const responsiveVariants = Object.keys(mergedConfig.theme.screens);
const classnamesByResponsive = [[]];
responsiveVariants.forEach((prefix) => {
classnamesByResponsive.push([]);
});
classNames.forEach((cls) => {
const idx = parseInt(getSpecificity(cls, responsiveVariants, true), 10);
classnamesByResponsive[idx].push(cls);
});
return classnamesByResponsive;
};
/**
* Parse each classname and populate the `sorted` and `extra` arrays
* @param {Array} classNames
* @returns {Object} An object with `sorted` and `extra` arrays
*/
const getSortedGroups = (classNames) => {
// Init assets before sorting
const groups = groupUtil.getGroups(groupsConfig, mergedConfig);
const sorted = groupUtil.initGroupSlots(groups);
const extras = [];
// Move each classname inside its dedicated group
classNames.forEach((className) => {
const trimmed = className.replace(/\s{1,}/g, '');
const idx = groupUtil.getGroupIndex(trimmed, groups, mergedConfig.separator);
if (idx > -1) {
sorted[idx].push(className);
} else {
extras.push(className);
}
});
// Sorts each groups' classnames
sorted.forEach((slot) => {
slot.sort(sortTailwindClasses);
});
return {
sorted,
extras,
};
};
/**
* Get a padded string version of the sorting key
* @param {String} classname
* @param {Array} variants
* @param {Boolean} beginning
* @returns {String}
*/
const getSpecificity = (classname, variants, beginning = false) => {
// Index can be -1, 0... Adding 1 for better readability... -1 becomes 0
return pad(getPrefixIndex(classname, variants, beginning) + 1, 2);
};
/**
* Sort classnames by using a sorting key
* @param {String} a A classname
* @param {String} b Another classname
* @returns {Number} -1, 0 or +1
*/
const sortTailwindClasses = (a, b) => {
const responsiveVariants = Object.keys(mergedConfig.theme.screens);
const themeVariants = ['dark'];
// motion-safe/reduce are not present...
// TODO Check if already present due to custom config overwiting the default `variantOrder`
const stateVariants = [...mergedConfig.variantOrder, 'motion-safe', 'motion-reduce'];
const aIdxStr = `${getSpecificity(a, responsiveVariants, true)}${getSpecificity(
a,
themeVariants
)}${getSpecificity(a, stateVariants)}`;
const bIdxStr = `${getSpecificity(b, responsiveVariants, true)}${getSpecificity(
b,
themeVariants
)}${getSpecificity(b, stateVariants)}`;
const aIdx = parseInt(aIdxStr, 10);
const bIdx = parseInt(bIdxStr, 10);
if (aIdx < bIdx) {
return -1;
}
if (aIdx > bIdx) {
return 1;
}
return 0;
};
/**
* Recursive function crawling into child nodes

@@ -333,6 +206,10 @@ * @param {ASTNode} node The root node of the current parsing

const attributeVisitor = function (node) {
if (!astUtil.isValidJSXAttribute(node)) {
if (!astUtil.isClassAttribute(node)) {
return;
}
sortNodeArgumentValue(node);
if (astUtil.isLiteralAttributeValue(node)) {
sortNodeArgumentValue(node);
} else if (node.value.type === 'JSXExpressionContainer') {
sortNodeArgumentValue(node, node.value.expression);
}
};

@@ -339,0 +216,0 @@

@@ -145,6 +145,10 @@ /**

const attributeVisitor = function (node) {
if (!astUtil.isValidJSXAttribute(node)) {
if (!astUtil.isClassAttribute(node)) {
return;
}
parseForNegativeArbitraryClassNames(node);
if (astUtil.isLiteralAttributeValue(node)) {
parseForNegativeArbitraryClassNames(node);
} else if (node.value.type === 'JSXExpressionContainer') {
parseForNegativeArbitraryClassNames(node, node.value.expression);
}
};

@@ -151,0 +155,0 @@

@@ -373,6 +373,10 @@ /**

const attributeVisitor = function (node) {
if (!astUtil.isValidJSXAttribute(node)) {
if (!astUtil.isClassAttribute(node)) {
return;
}
parseForShorthandCandidates(node);
if (astUtil.isLiteralAttributeValue(node)) {
parseForShorthandCandidates(node);
} else if (node.value.type === 'JSXExpressionContainer') {
parseForShorthandCandidates(node, node.value.expression);
}
};

@@ -379,0 +383,0 @@

@@ -258,6 +258,10 @@ /**

const attributeVisitor = function (node) {
if (!astUtil.isValidJSXAttribute(node)) {
if (!astUtil.isClassAttribute(node)) {
return;
}
parseForObsoleteClassNames(node);
if (astUtil.isLiteralAttributeValue(node)) {
parseForObsoleteClassNames(node);
} else if (node.value.type === 'JSXExpressionContainer') {
parseForObsoleteClassNames(node, node.value.expression);
}
};

@@ -264,0 +268,0 @@

@@ -144,6 +144,10 @@ /**

const attributeVisitor = function (node) {
if (!astUtil.isValidJSXAttribute(node)) {
if (!astUtil.isClassAttribute(node)) {
return;
}
parseForArbitraryValues(node);
if (astUtil.isLiteralAttributeValue(node)) {
parseForArbitraryValues(node);
} else if (node.value.type === 'JSXExpressionContainer') {
parseForArbitraryValues(node, node.value.expression);
}
};

@@ -150,0 +154,0 @@

@@ -131,6 +131,10 @@ /**

const attributeVisitor = function (node) {
if (!astUtil.isValidJSXAttribute(node)) {
if (!astUtil.isClassAttribute(node)) {
return;
}
astUtil.parseNodeRecursive(node, null, parseForContradictingClassNames, true);
if (astUtil.isLiteralAttributeValue(node)) {
astUtil.parseNodeRecursive(node, null, parseForContradictingClassNames, true);
} else if (node.value.type === 'JSXExpressionContainer') {
astUtil.parseNodeRecursive(node, node.value.expression, parseForContradictingClassNames, true);
}
};

@@ -137,0 +141,0 @@

@@ -140,6 +140,10 @@ /**

const attributeVisitor = function (node) {
if (!astUtil.isValidJSXAttribute(node)) {
if (!astUtil.isClassAttribute(node)) {
return;
}
astUtil.parseNodeRecursive(node, null, parseForCustomClassNames);
if (astUtil.isLiteralAttributeValue(node)) {
astUtil.parseNodeRecursive(node, null, parseForCustomClassNames);
} else if (node.value.type === 'JSXExpressionContainer') {
astUtil.parseNodeRecursive(node, node.value.expression, parseForCustomClassNames);
}
};

@@ -146,0 +150,0 @@

@@ -262,2 +262,4 @@ /**

extractClassnamesFromValue,
isClassAttribute,
isLiteralAttributeValue,
isValidJSXAttribute,

@@ -264,0 +266,0 @@ isValidVueAttribute,

'use strict';
const defaultGroups = require('../config/groups').groups;

@@ -22,4 +21,2 @@ function getOption(context, name) {

return ['**/*.css', '!**/node_modules', '!**/.*', '!**/dist', '!**/build'];
case 'groups':
return defaultGroups;
case 'removeDuplicates':

@@ -26,0 +23,0 @@ return true;

{
"name": "eslint-plugin-tailwindcss",
"version": "3.6.0-beta.0",
"version": "3.6.0-beta.1",
"description": "Rules enforcing best practices while using Tailwind CSS",

@@ -5,0 +5,0 @@ "keywords": [

@@ -42,3 +42,3 @@ # eslint-plugin-tailwindcss

> Custom `dark` class, `.grid-flow-dense`, `.text-start`, `.text-end`, `.mix-blend-plus-lighter`, `.border-spacing...`
- BREAKING CHANGE: `groupByResponsive`, `officialSorting` and `prependCustom` are deprecated ☠️. The official sorting is always used for `classnames-order`.
- BREAKING CHANGE: `groups`, `groupByResponsive`, `officialSorting` and `prependCustom` are deprecated ☠️. The official sorting from `prettier-plugin-tailwindcss` is always used by `classnames-order`.
> This was required in order to support classnames generated by plugins.

@@ -161,14 +161,19 @@ - FIX: [Many fixes](https://github.com/francoismassart/eslint-plugin-tailwindcss/pull/132) including support for classnames generated by plugins.

{
"settings": {
"tailwindcss": {
settings: {
tailwindcss: {
// These are the default values but feel free to customize
"callees": ["classnames", "clsx", "ctl"],
"config": "tailwind.config.js",
"cssFiles": ["**/*.css", "!**/node_modules", "!**/.*", "!**/dist", "!**/build"],
"cssFilesRefreshRate": 5_000,
"groups": defaultGroups, // imported from groups.js
"removeDuplicates": true,
"whitelist": []
}
}
callees: ["classnames", "clsx", "ctl"],
config: "tailwind.config.js",
cssFiles: [
"**/*.css",
"!**/node_modules",
"!**/.*",
"!**/dist",
"!**/build",
],
cssFilesRefreshRate: 5_000,
removeDuplicates: true,
whitelist: [],
},
},
}

@@ -175,0 +180,0 @@ ```

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚑️ by Socket Inc