UNPKG

eslint-plugin-tailwindcss

Version:
102 lines (81 loc) 3.17 kB
const { separatorRegEx } = require('../regex'); function bigSign(bigIntValue) { return (bigIntValue > 0n) - (bigIntValue < 0n); } function prefixCandidate(context, selector) { let prefix = context.tailwindConfig.prefix; return typeof prefix === 'function' ? prefix(selector) : prefix + selector; } // Polyfill for older Tailwind CSS versions function getClassOrderPolyfill(classes, { env }) { // A list of utilities that are used by certain Tailwind CSS utilities but // that don't exist on their own. This will result in them "not existing" and // sorting could be weird since you still require them in order to make the // host utitlies work properly. (Thanks Biology) let parasiteUtilities = new Set([prefixCandidate(env.context, 'group'), prefixCandidate(env.context, 'peer')]); let classNamesWithOrder = []; for (let className of classes) { let order = env.generateRules(new Set([className]), env.context).sort(([a], [z]) => bigSign(z - a))[0]?.[0] ?? null; if (order === null && parasiteUtilities.has(className)) { // This will make sure that it is at the very beginning of the // `components` layer which technically means 'before any // components'. order = env.context.layerOrder.components; } classNamesWithOrder.push([className, order]); } return classNamesWithOrder; } function sortClasses(classStr, { env, ignoreFirst = false, ignoreLast = false }) { if (typeof classStr !== 'string' || classStr === '') { return classStr; } // Ignore class attributes containing `{{`, to match Prettier behaviour: // https://github.com/prettier/prettier/blob/main/src/language-html/embed.js#L83-L88 if (classStr.includes('{{')) { return classStr; } let result = ''; let parts = classStr.split(separatorRegEx); let classes = parts.filter((_, i) => i % 2 === 0); let whitespace = parts.filter((_, i) => i % 2 !== 0); if (classes[classes.length - 1] === '') { classes.pop(); } let prefix = ''; if (ignoreFirst) { prefix = `${classes.shift() ?? ''}${whitespace.shift() ?? ''}`; } let suffix = ''; if (ignoreLast) { suffix = `${whitespace.pop() ?? ''}${classes.pop() ?? ''}`; } let classNamesWithOrder = env.context.getClassOrder ? env.context.getClassOrder(classes) : getClassOrderPolyfill(classes, { env }); classes = classNamesWithOrder .sort(([, a], [, z]) => { if (a === z) return 0; // if (a === null) return options.unknownClassPosition === 'start' ? -1 : 1 // if (z === null) return options.unknownClassPosition === 'start' ? 1 : -1 if (a === null) return -1; if (z === null) return 1; return bigSign(a - z); }) .map(([className]) => className); for (let i = 0; i < classes.length; i++) { result += `${classes[i]}${whitespace[i] ?? ''}`; } return prefix + result + suffix; } /** * * @param {Array} unordered the unordered classnames * @param context * @returns {Array} the ordered classnames */ function order(unordered, context) { const sorted = sortClasses(unordered.join(' '), { env: { context: context } }); return sorted; } module.exports = order;