eslint-plugin-tailwindcss
Advanced tools
Comparing version 1.14.3 to 1.15.0
@@ -168,3 +168,3 @@ /** | ||
type: 'Order', | ||
members: 'order\\-${order}', | ||
members: '(order\\-${order}|\\-order\\-${-order})', | ||
}, | ||
@@ -736,3 +736,3 @@ ], | ||
type: 'Brightness', | ||
members: 'bightness\\-${brightness}', | ||
members: 'brightness\\-${brightness}', | ||
}, | ||
@@ -739,0 +739,0 @@ { |
@@ -113,4 +113,4 @@ /** | ||
if (troubles.length) { | ||
troubles.forEach((t) => { | ||
const re = new RegExp('^' + t.prefix); | ||
troubles.forEach((issue) => { | ||
const re = new RegExp('^' + issue.prefix); | ||
const conflicting = slot.filter((c) => re.test(c)); | ||
@@ -117,0 +117,0 @@ context.report({ |
@@ -7,2 +7,20 @@ /** | ||
// Ambiguous values | ||
// ================ | ||
// Supported hints: length, color, angle, list | ||
// ------------------------------------------- | ||
// | ||
// border-[color/width] | ||
// text-[color/size] | ||
// ring-[color/width] | ||
// ring-offset-[color/width] | ||
// stroke-[current/width] | ||
// bg-[color/(position/size)] | ||
// | ||
// font-[family/weight] | ||
const angle = require('./types/angle'); | ||
const color = require('./types/color'); | ||
const length = require('./types/length'); | ||
/** | ||
@@ -19,2 +37,30 @@ * Escape special chars for regular expressions | ||
/** | ||
* Get additional opacity suffix if property supports it | ||
* | ||
* @param {String} propName The property | ||
* @param {Object} config Tailwind CSS Config | ||
* @returns {String} The suffix or an empty string | ||
*/ | ||
function getOpacitySuffix(propName, config) { | ||
if (['backgroundColor', 'textColor', 'placeholderColor'].includes(propName)) { | ||
return generateOptionalOpacitySuffix(config); | ||
} | ||
return ''; | ||
} | ||
/** | ||
* Generates the opacity suffix based on config | ||
* | ||
* @param {Object} config Tailwind CSS Config | ||
* @returns {String} The suffix or an empty string | ||
*/ | ||
function generateOptionalOpacitySuffix(config) { | ||
const opacityKeys = !config.theme['opacity'] ? [] : Object.keys(config.theme['opacity']); | ||
if (opacityKeys.length === 0) { | ||
return ''; | ||
} | ||
return `(\\/(${opacityKeys.join('|')}))?`; | ||
} | ||
/** | ||
* Generate the possible options for the RegEx | ||
@@ -29,3 +75,3 @@ * | ||
function generateOptions(propName, keys, config, isNegative = false) { | ||
const arbitraryOption = '\\[.*\\]'; | ||
const genericArbitraryOption = '\\[(.*)\\]'; | ||
const supportArbitrary = config.mode === 'jit' && !isNegative; | ||
@@ -38,7 +84,5 @@ const defaultKeyIndex = keys.findIndex((v) => v === 'DEFAULT'); | ||
case 'dark': | ||
// Optional `dark` class | ||
return config.darkMode === 'class' ? 'dark' : ''; | ||
case 'placeholderColor': | ||
case 'textColor': | ||
case 'backgroundColor': | ||
case 'gradientColorStops': | ||
case 'borderColor': | ||
@@ -48,7 +92,15 @@ case 'divideColor': | ||
case 'ringOffsetColor': | ||
case 'textColor': | ||
case 'stroke': | ||
case 'gradientColorStops': | ||
case 'placeholderColor': | ||
// Colors can use segments like 'indigo' and 'indigo-light' | ||
// https://tailwindcss.com/docs/customizing-colors#color-object-syntax | ||
const options = []; | ||
// Conditionnaly generates the opacity suffix | ||
const opacitySuffix = supportArbitrary ? getOpacitySuffix(propName, config) : ''; | ||
keys.forEach((k) => { | ||
const color = config.theme[propName][k] || config.theme.colors[k]; | ||
if (typeof color === 'string') { | ||
options.push(escapeSpecialChars(k)); | ||
options.push(escapeSpecialChars(k) + opacitySuffix); | ||
} else { | ||
@@ -61,12 +113,166 @@ const variants = Object.keys(color).map((colorKey) => escapeSpecialChars(colorKey)); | ||
} | ||
options.push(k + '(\\-(' + variants.join('|') + '))' + (hasDefault ? '?' : '')); | ||
options.push(k + '(\\-(' + variants.join('|') + '))' + (hasDefault ? '?' : '') + opacitySuffix); | ||
} | ||
}); | ||
if (supportArbitrary) { | ||
options.push(arbitraryOption); | ||
const arbitraryColors = [...color.mergedColorValues]; | ||
switch (propName) { | ||
case 'gradientColorStops': | ||
case 'placeholderColor': | ||
arbitraryColors.push(color.RGBAPercentages); // RGBA % 0.5[%] | ||
arbitraryColors.push(color.optionalColorPrefixedVar); | ||
arbitraryColors.push(color.notHSLAPlusWildcard); | ||
break; | ||
default: | ||
arbitraryColors.push(color.mandatoryColorPrefixed); | ||
} | ||
options.push(`\\[(${arbitraryColors.join('|')})\\]`); | ||
} | ||
return '(' + options.join('|') + ')'; | ||
case 'borderWidth': | ||
case 'divideWidth': | ||
case 'fontSize': | ||
case 'ringWidth': | ||
case 'ringOffsetWidth': | ||
if (supportArbitrary) { | ||
keys.push(length.selectedUnitsRegEx); | ||
keys.push(length.anyCalcRegEx); | ||
// Mandatory `length:` prefix + wildcard | ||
keys.push(`\\[length\\:.{1,}\\]`); | ||
} | ||
return '(' + keys.join('|') + ')'; | ||
case 'strokeWidth': | ||
if (supportArbitrary) { | ||
keys.push(length.selectedUnitsRegEx); | ||
keys.push(length.anyCalcRegEx); | ||
// Mandatory `length:` prefix + calc + wildcard | ||
keys.push(`\\[length\\:calc\\(.{1,}\\)\\]`); | ||
// Mandatory `length:` prefix + wildcard + optional units | ||
keys.push(`\\[length\\:(.{1,})(${length.selectedUnits.join('|')})?\\]`); | ||
} | ||
return '(' + keys.join('|') + ')'; | ||
case 'gap': | ||
case 'height': | ||
case 'lineHeight': | ||
case 'maxHeight': | ||
case 'maxWidth': | ||
case 'minHeight': | ||
case 'minWidth': | ||
case 'padding': | ||
case 'width': | ||
case 'inset': | ||
case 'letterSpacing': | ||
case 'margin': | ||
case 'space': | ||
case 'blur': | ||
case 'brightness': | ||
case 'contrast': | ||
case 'grayscale': | ||
case 'hueRotate': | ||
case 'invert': | ||
case 'saturate': | ||
case 'sepia': | ||
case 'backdropBlur': | ||
case 'backdropBrightness': | ||
case 'backdropContrast': | ||
case 'backdropGrayscale': | ||
case 'backdropHueRotate': | ||
case 'backdropInvert': | ||
case 'backdropOpacity': | ||
case 'backdropSaturate': | ||
case 'backdropSepia': | ||
case 'transitionDuration': | ||
case 'transitionTimingFunction': | ||
case 'transitionDelay': | ||
case 'animation': | ||
case 'transformOrigin': | ||
case 'scale': | ||
case 'translate': | ||
case 'skew': | ||
case 'cursor': | ||
case 'outline': | ||
if (supportArbitrary) { | ||
// All units | ||
keys.push(length.mergedUnitsRegEx); | ||
// Forbidden prefixes | ||
keys.push(`\\[(?!(angle|color|length|list)\:).{1,}\\]`); | ||
} | ||
return '(' + keys.join('|') + ')'; | ||
case 'fill': | ||
if (supportArbitrary) { | ||
// All units | ||
keys.push(length.mergedUnitsRegEx); | ||
// Forbidden prefixes | ||
keys.push(`\\[(?!(angle|length|list)\:).{1,}\\]`); | ||
} | ||
return '(' + keys.join('|') + ')'; | ||
case 'placeholderOpacity': | ||
case 'textOpacity': | ||
case 'backgroundOpacity': | ||
case 'borderOpacity': | ||
case 'divideOpacity': | ||
case 'ringOpacity': | ||
case 'opacity': | ||
if (supportArbitrary) { | ||
// 0 ... .5 ... 1 | ||
keys.push(`\\[(0(\\.\\d{1,})?|\\.\\d{1,}|1)\\]`); | ||
keys.push(length.anyCalcRegEx); | ||
// Unprefixed var() | ||
keys.push(`\\[var\\(\\-\\-[A-Za-z\\-]{1,}\\)\\]`); | ||
} | ||
return '(' + keys.join('|') + ')'; | ||
case 'rotate': | ||
if (supportArbitrary) { | ||
keys.push(`\\[(${angle.mergedAngleValues.join('|')})\\]`); | ||
} | ||
return '(' + keys.join('|') + ')'; | ||
case 'gridTemplateColumns': | ||
case 'gridColumn': | ||
case 'gridColumnStart': | ||
case 'gridColumnEnd': | ||
case 'gridTemplateRows': | ||
case 'gridRow': | ||
case 'gridRowStart': | ||
case 'gridRowEnd': | ||
case 'gridAutoColumns': | ||
case 'gridAutoRows': | ||
if (supportArbitrary) { | ||
// Forbidden prefixes | ||
keys.push(`\\[(?!(angle|color|length)\:).{1,}\\]`); | ||
} | ||
return '(' + keys.join('|') + ')'; | ||
case 'listStyleType': | ||
if (supportArbitrary) { | ||
// Forbidden prefixes | ||
keys.push(`\\[(?!(angle|color|length|list)\:).{1,}\\]`); | ||
} | ||
return '(' + keys.join('|') + ')'; | ||
case 'objectPosition': | ||
if (supportArbitrary) { | ||
// Forbidden prefixes | ||
keys.push(`\\[(?!(angle|color|length)\:).{1,}\\]`); | ||
} | ||
return '(' + keys.join('|') + ')'; | ||
case 'backgroundPosition': | ||
case 'backgroundSize': | ||
case 'backgroundImage': | ||
case 'fontFamily': | ||
case 'fontWeight': | ||
case 'boxShadow': | ||
case 'dropShadow': | ||
case 'transitionProperty': | ||
case 'typography': | ||
case 'aspectRatio': | ||
case 'lineClamp': | ||
// Cannot be arbitrary? | ||
return '(' + keys.join('|') + ')'; | ||
case 'flexGrow': | ||
case 'flexShrink': | ||
case 'order': | ||
case 'zIndex': | ||
case 'flex': | ||
case 'borderRadius': | ||
default: | ||
if (supportArbitrary) { | ||
keys.push(arbitraryOption); | ||
keys.push(genericArbitraryOption); | ||
} | ||
@@ -196,3 +402,7 @@ return '(' + keys.join('|') + ')'; | ||
function getSuffix(className, separator = ':') { | ||
return className.split(separator).pop(); | ||
const arbitraryArr = className.split('-['); | ||
if (arbitraryArr.length === 1) { | ||
return className.split(separator).pop(); | ||
} | ||
return arbitraryArr[0].split(separator).pop() + '-[' + arbitraryArr[1]; | ||
} | ||
@@ -199,0 +409,0 @@ |
{ | ||
"name": "eslint-plugin-tailwindcss", | ||
"version": "1.14.3", | ||
"version": "1.15.0", | ||
"description": "Rules enforcing best practices while using Tailwind CSS", | ||
@@ -5,0 +5,0 @@ "keywords": [ |
@@ -15,10 +15,6 @@ # eslint-plugin-tailwindcss | ||
- [Performance gains](https://github.com/francoismassart/eslint-plugin-tailwindcss/pull/42) on `no-custom-classname` and `no-contradicting-classname` (by [larrifax](https://github.com/larrifax) π) | ||
- Better support for [JIT mode arbitrary values](https://github.com/francoismassart/eslint-plugin-tailwindcss/pull/40) | ||
- Add support for [tagged templates](https://github.com/francoismassart/eslint-plugin-tailwindcss/pull/41) (by [larrifax](https://github.com/larrifax) π) | ||
- Support for [color opacity shorthand](https://tailwindcss.com/docs/just-in-time-mode#color-opacity-shorthand) | ||
- [Include "plugins": ["tailwindcss"]](https://github.com/francoismassart/eslint-plugin-tailwindcss/issues/44) in the `recommended` preset(by [kripod](https://github.com/kripod) π) | ||
- [Support dark class](https://github.com/francoismassart/eslint-plugin-tailwindcss/issues/43) when `darkMode` is set to `class` | ||
[View all releases on github](https://github.com/francoismassart/eslint-plugin-tailwindcss/releases) | ||
@@ -126,2 +122,6 @@ | ||
- `only-valid-arbitrary-values`: | ||
- e.g. avoid `top-[42]`, only `0` value can be unitless. | ||
- e.g. avoid `text-[rgba(10%,20%,30,50%)]`, can't mix `%` and `0-255`. | ||
## Alternatives | ||
@@ -128,0 +128,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
91590
22
2709