Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion lib/rules/no-custom-classname.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const customConfig = require('../util/customConfig');
const astUtil = require('../util/ast');
const attrUtil = require('../util/attr');
const groupUtil = require('../util/groupMethods');
const pluginUtil = require('../util/plugin');
const removeDuplicatesFromArray = require('../util/removeDuplicatesFromArray');
const getOption = require('../util/settings');

Expand Down Expand Up @@ -63,6 +64,8 @@ module.exports = {

const mergedConfig = customConfig.resolve(twConfig);

const customPlugins = pluginUtil.getCustomPlugins(mergedConfig);

//----------------------------------------------------------------------
// Helpers
//----------------------------------------------------------------------
Expand All @@ -80,7 +83,8 @@ module.exports = {
classNames.forEach((className) => {
const idx = groupUtil.getGroupIndex(className, groups, mergedConfig.separator);
const whitelistIdx = groupUtil.getGroupIndex(className, whitelist, mergedConfig.separator);
if (idx === -1 && whitelistIdx === -1) {
const customPluginsIdx = groupUtil.getGroupIndex(className, customPlugins, mergedConfig.separator);
if (idx === -1 && whitelistIdx === -1 && customPluginsIdx === -1) {
context.report({
node,
messageId: 'customClassnameDetected',
Expand Down
59 changes: 59 additions & 0 deletions lib/util/plugin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/**
* Remove dot prefix from custom classnames
*
* @param {string} className
* @returns {string}
*/
function removeDotPrefix(className) {
if (className[0] !== '.') return className;
return className.slice(1);
}

/**
* Apply Tailwind CSS classname prefix
*
* @param {string} prefix
* @returns {Function}
*/
function applyPrefix(prefix) {
return (className) => prefix + className;
}

/**
* A custom helper function to extract custom utilities
*
* @param {Object} utilities
* @returns {string[]}
*/
function addUtilities(utilities) {
return Object.keys(utilities);
}

/**
* Extract custom plugins
*
* @param {Object} config
* @returns {Function}
*/
function extractPlugins(config) {
// TODO Provide other helper functions from https://tailwindcss.com/docs/plugins
return (plugin) => plugin.handler({ addUtilities, prefix: config.prefix, config });
}

/**
* Generates an array of classnames from custom plugins
*
* @param {Object} config
* @returns {string[]}
*/
function getCustomPlugins(config) {
const customPlugins = config.plugins.flatMap(extractPlugins(config)).map(removeDotPrefix);
if (config.prefix.length) {
return customPlugins.map(applyPrefix(config.prefix));
}
return customPlugins;
}

module.exports = {
getCustomPlugins,
};
41 changes: 41 additions & 0 deletions tests/lib/rules/no-custom-classname.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

var rule = require("../../../lib/rules/no-custom-classname");
var RuleTester = require("eslint").RuleTester;
var plugin = require("tailwindcss/plugin");

//------------------------------------------------------------------------------
// Tests
Expand Down Expand Up @@ -115,6 +116,46 @@ ruleTester.run("no-custom-classname", rule, {
<p class="text-indigo-500 group-hover:text-gray-500">Create a new project from a variety of starting templates.</p>
</div>`,
},
{
code: `<div class="w-full custom-utilities md:custom-utilities">with custom utilities</div>`,
options: [
{
config: {
plugins: [
plugin(({ addUtilities }) => {
const customUtilities = {
".custom-utilities": {
"text-align": "center",
},
};
return addUtilities(customUtilities, ["responsive"]);
}),
],
},
},
],
},
{
code: `<div class="tw-w-full tw-custom-utilities md_tw-custom-utilities">custom utilities with prefix</div>`,
options: [
{
config: {
prefix: "tw-",
separator: "_",
plugins: [
plugin(({ addUtilities }) => {
const customUtilities = {
".custom-utilities": {
"text-align": "center",
},
};
return addUtilities(customUtilities, ["responsive"]);
}),
],
},
},
],
},
],

invalid: [
Expand Down