From 5f396e48c3aad8f394295494307cd08b4d190980 Mon Sep 17 00:00:00 2001 From: Finn Merlett Date: Sun, 4 Sep 2022 16:41:25 +0100 Subject: [PATCH 1/2] add support for tw prop from Twin --- lib/util/ast.js | 2 +- tests/lib/rules/classnames-order.js | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/lib/util/ast.js b/lib/util/ast.js index 225f2ba..f022091 100644 --- a/lib/util/ast.js +++ b/lib/util/ast.js @@ -28,7 +28,7 @@ function isClassAttribute(node) { default: name = node.name.name; } - return /^class(Name)?$/.test(name); + return /^class(Name)?$|^tw$/.test(name); } /** diff --git a/tests/lib/rules/classnames-order.js b/tests/lib/rules/classnames-order.js index a8ba0ee..4e0f21e 100644 --- a/tests/lib/rules/classnames-order.js +++ b/tests/lib/rules/classnames-order.js @@ -65,6 +65,9 @@ ruleTester.run("classnames-order", rule, { { code: `
Simple, basic
`, }, + { + code: `
Simple, using 'tw' prop
`, + }, { code: "
ctl + exp
", }, @@ -91,6 +94,9 @@ ruleTester.run("classnames-order", rule, { { code: `
Extra space at the end
`, }, + { + code: `
Extra space at the end, but with 'tw' prop
`, + }, { code: `
'p', then 'py' then 'px'
`, }, @@ -292,6 +298,11 @@ ruleTester.run("classnames-order", rule, { output: `
Enhancing readability
`, errors: errors, }, + { + code: `
Enhancing readability with 'tw' prop
`, + output: `
Enhancing readability with 'tw' prop
`, + errors: errors, + }, { code: `
:)...
`, output: `
:)...
`, From 937659fcafd2d8a89f0e3f01ff3e40e6d6e6f230 Mon Sep 17 00:00:00 2001 From: Koen Poelhekke Date: Tue, 15 Nov 2022 16:54:59 +0100 Subject: [PATCH 2/2] Add classRegex option to support custom attributes --- .gitignore | 1 + README.md | 2 ++ docs/rules/classnames-order.md | 4 ++++ docs/rules/enforces-negative-arbitrary-values.md | 4 ++++ docs/rules/enforces-shorthand.md | 4 ++++ docs/rules/migration-from-tailwind-2.md | 4 ++++ docs/rules/no-arbitrary-value.md | 4 ++++ docs/rules/no-contradicting-classname.md | 4 ++++ docs/rules/no-custom-classname.md | 4 ++++ lib/rules/classnames-order.js | 3 ++- lib/rules/enforces-negative-arbitrary-values.js | 3 ++- lib/rules/enforces-shorthand.js | 3 ++- lib/rules/migration-from-tailwind-2.js | 3 ++- lib/rules/no-arbitrary-value.js | 3 ++- lib/rules/no-contradicting-classname.js | 3 ++- lib/rules/no-custom-classname.js | 3 ++- lib/util/ast.js | 10 ++++++---- lib/util/settings.js | 2 ++ tests/lib/rules/classnames-order.js | 15 +++++++++++++++ 19 files changed, 68 insertions(+), 11 deletions(-) diff --git a/.gitignore b/.gitignore index 68b21f0..96e4deb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /node_modules .DS_Store +.idea diff --git a/README.md b/README.md index c4b614f..37ec292 100644 --- a/README.md +++ b/README.md @@ -176,6 +176,8 @@ All these settings have nice default values that are explained in each rules' do cssFilesRefreshRate: 5_000, removeDuplicates: true, whitelist: [], + tags: [], + classRegex: "^class(Name)?$" // can be modified to support custom attributes. E.g. "^tw$" for `twin.macro` }, }, } diff --git a/docs/rules/classnames-order.md b/docs/rules/classnames-order.md index b121198..b8af993 100644 --- a/docs/rules/classnames-order.md +++ b/docs/rules/classnames-order.md @@ -58,3 +58,7 @@ Duplicate classnames are automatically removed but you can always disable this b ### `tags` (default: `[]`) Optional, if you are using tagged templates, you should provide the tags in this array. + +### `classRegex` (default: `"^class(Name)?$"`) + +Optional, can be used to support custom attribues diff --git a/docs/rules/enforces-negative-arbitrary-values.md b/docs/rules/enforces-negative-arbitrary-values.md index cbc6d00..e6fec5c 100644 --- a/docs/rules/enforces-negative-arbitrary-values.md +++ b/docs/rules/enforces-negative-arbitrary-values.md @@ -72,3 +72,7 @@ Finally, the plugin will [merge the provided configuration](https://tailwindcss. ### `tags` (default: `[]`) Optional, if you are using tagged templates, you should provide the tags in this array. + +### `classRegex` (default: `"^class(Name)?$"`) + +Optional, can be used to support custom attribues diff --git a/docs/rules/enforces-shorthand.md b/docs/rules/enforces-shorthand.md index b095eb9..0230845 100644 --- a/docs/rules/enforces-shorthand.md +++ b/docs/rules/enforces-shorthand.md @@ -65,6 +65,10 @@ Finally, the plugin will [merge the provided configuration](https://tailwindcss. Optional, if you are using tagged templates, you should provide the tags in this array. +### `classRegex` (default: `"^class(Name)?$"`) + +Optional, can be used to support custom attribues + ## Further Reading This rule will fix the issue for you. diff --git a/docs/rules/migration-from-tailwind-2.md b/docs/rules/migration-from-tailwind-2.md index 79d1df6..ba7b9e6 100644 --- a/docs/rules/migration-from-tailwind-2.md +++ b/docs/rules/migration-from-tailwind-2.md @@ -109,3 +109,7 @@ Finally, the plugin will [merge the provided configuration](https://tailwindcss. ### `tags` (default: `[]`) Optional, if you are using tagged templates, you should provide the tags in this array. + +### `classRegex` (default: `"^class(Name)?$"`) + +Optional, can be used to support custom attribues diff --git a/docs/rules/no-arbitrary-value.md b/docs/rules/no-arbitrary-value.md index 5e1a3c3..0c7525b 100644 --- a/docs/rules/no-arbitrary-value.md +++ b/docs/rules/no-arbitrary-value.md @@ -55,6 +55,10 @@ Finally, the plugin will [merge the provided configuration](https://tailwindcss. Optional, if you are using tagged templates, you should provide the tags in this array. +### `classRegex` (default: `"^class(Name)?$"`) + +Optional, can be used to support custom attribues + ## Further Reading This rule will not fix the issue for you because it cannot guess the correct class candidate. diff --git a/docs/rules/no-contradicting-classname.md b/docs/rules/no-contradicting-classname.md index 1e6993c..8c131d1 100644 --- a/docs/rules/no-contradicting-classname.md +++ b/docs/rules/no-contradicting-classname.md @@ -55,6 +55,10 @@ Finally, the plugin will [merge the provided configuration](https://tailwindcss. Optional, if you are using tagged templates, you should provide the tags in this array. +### `classRegex` (default: `"^class(Name)?$"`) + +Optional, can be used to support custom attribues + ## Further Reading This rule will not fix the issue but will let you know about the issue. diff --git a/docs/rules/no-custom-classname.md b/docs/rules/no-custom-classname.md index 14e9ef9..e8210d4 100644 --- a/docs/rules/no-custom-classname.md +++ b/docs/rules/no-custom-classname.md @@ -83,6 +83,10 @@ The `whitelist` options should be set to: - or if you don't like regular expressions (but you should): `['skin\\-summer', 'skin\\-xmas', 'custom\\-1', 'custom\\-2', 'custom\\-3']` +### `classRegex` (default: `"^class(Name)?$"`) + +Optional, can be used to support custom attribues + ## Further Reading This rule will not fix the issue but will let you know about the issue. diff --git a/lib/rules/classnames-order.js b/lib/rules/classnames-order.js index 01a2575..6243f04 100644 --- a/lib/rules/classnames-order.js +++ b/lib/rules/classnames-order.js @@ -68,6 +68,7 @@ module.exports = { const callees = getOption(context, 'callees'); const tags = getOption(context, 'tags'); const twConfig = getOption(context, 'config'); + const classRegex = getOption(context, 'classRegex'); const groupsConfig = groups; const removeDuplicates = getOption(context, 'removeDuplicates'); @@ -199,7 +200,7 @@ module.exports = { //---------------------------------------------------------------------- const attributeVisitor = function (node) { - if (!astUtil.isClassAttribute(node)) { + if (!astUtil.isClassAttribute(node, classRegex)) { return; } if (astUtil.isLiteralAttributeValue(node)) { diff --git a/lib/rules/enforces-negative-arbitrary-values.js b/lib/rules/enforces-negative-arbitrary-values.js index 778c5f2..0b3e219 100644 --- a/lib/rules/enforces-negative-arbitrary-values.js +++ b/lib/rules/enforces-negative-arbitrary-values.js @@ -59,6 +59,7 @@ module.exports = { const callees = getOption(context, 'callees'); const tags = getOption(context, 'tags'); const twConfig = getOption(context, 'config'); + const classRegex = getOption(context, 'classRegex'); const mergedConfig = customConfig.resolve(twConfig); @@ -142,7 +143,7 @@ module.exports = { //---------------------------------------------------------------------- const attributeVisitor = function (node) { - if (!astUtil.isClassAttribute(node)) { + if (!astUtil.isClassAttribute(node, classRegex)) { return; } if (astUtil.isLiteralAttributeValue(node)) { diff --git a/lib/rules/enforces-shorthand.js b/lib/rules/enforces-shorthand.js index 698af31..a4573e6 100644 --- a/lib/rules/enforces-shorthand.js +++ b/lib/rules/enforces-shorthand.js @@ -59,6 +59,7 @@ module.exports = { const callees = getOption(context, 'callees'); const tags = getOption(context, 'tags'); const twConfig = getOption(context, 'config'); + const classRegex = getOption(context, 'classRegex'); const mergedConfig = customConfig.resolve(twConfig); @@ -370,7 +371,7 @@ module.exports = { //---------------------------------------------------------------------- const attributeVisitor = function (node) { - if (!astUtil.isClassAttribute(node)) { + if (!astUtil.isClassAttribute(node, classRegex)) { return; } if (astUtil.isLiteralAttributeValue(node)) { diff --git a/lib/rules/migration-from-tailwind-2.js b/lib/rules/migration-from-tailwind-2.js index 06482c2..5ba8944 100644 --- a/lib/rules/migration-from-tailwind-2.js +++ b/lib/rules/migration-from-tailwind-2.js @@ -64,6 +64,7 @@ module.exports = { const callees = getOption(context, 'callees'); const tags = getOption(context, 'tags'); const twConfig = getOption(context, 'config'); + const classRegex = getOption(context, 'classRegex'); const mergedConfig = customConfig.resolve(twConfig); @@ -255,7 +256,7 @@ module.exports = { //---------------------------------------------------------------------- const attributeVisitor = function (node) { - if (!astUtil.isClassAttribute(node)) { + if (!astUtil.isClassAttribute(node, classRegex)) { return; } if (astUtil.isLiteralAttributeValue(node)) { diff --git a/lib/rules/no-arbitrary-value.js b/lib/rules/no-arbitrary-value.js index 551543e..c7096f1 100644 --- a/lib/rules/no-arbitrary-value.js +++ b/lib/rules/no-arbitrary-value.js @@ -58,6 +58,7 @@ module.exports = { const callees = getOption(context, 'callees'); const tags = getOption(context, 'tags'); const twConfig = getOption(context, 'config'); + const classRegex = getOption(context, 'classRegex'); const mergedConfig = customConfig.resolve(twConfig); @@ -141,7 +142,7 @@ module.exports = { //---------------------------------------------------------------------- const attributeVisitor = function (node) { - if (!astUtil.isClassAttribute(node)) { + if (!astUtil.isClassAttribute(node, classRegex)) { return; } if (astUtil.isLiteralAttributeValue(node)) { diff --git a/lib/rules/no-contradicting-classname.js b/lib/rules/no-contradicting-classname.js index 8810f89..1cdb5f2 100644 --- a/lib/rules/no-contradicting-classname.js +++ b/lib/rules/no-contradicting-classname.js @@ -59,6 +59,7 @@ module.exports = { const callees = getOption(context, 'callees'); const tags = getOption(context, 'tags'); const twConfig = getOption(context, 'config'); + const classRegex = getOption(context, 'classRegex'); const mergedConfig = customConfig.resolve(twConfig); @@ -133,7 +134,7 @@ module.exports = { //---------------------------------------------------------------------- const attributeVisitor = function (node) { - if (!astUtil.isClassAttribute(node)) { + if (!astUtil.isClassAttribute(node, classRegex)) { return; } if (astUtil.isLiteralAttributeValue(node)) { diff --git a/lib/rules/no-custom-classname.js b/lib/rules/no-custom-classname.js index af60b3e..4c72209 100644 --- a/lib/rules/no-custom-classname.js +++ b/lib/rules/no-custom-classname.js @@ -81,6 +81,7 @@ module.exports = { const cssFiles = getOption(context, 'cssFiles'); const cssFilesRefreshRate = getOption(context, 'cssFilesRefreshRate'); const whitelist = getOption(context, 'whitelist'); + const classRegex = getOption(context, 'classRegex'); const mergedConfig = customConfig.resolve(twConfig); const contextFallback = // Set the created contextFallback in the cache if it does not exist yet. @@ -137,7 +138,7 @@ module.exports = { //---------------------------------------------------------------------- const attributeVisitor = function (node) { - if (!astUtil.isClassAttribute(node)) { + if (!astUtil.isClassAttribute(node, classRegex)) { return; } if (astUtil.isLiteralAttributeValue(node)) { diff --git a/lib/util/ast.js b/lib/util/ast.js index f022091..8cad354 100644 --- a/lib/util/ast.js +++ b/lib/util/ast.js @@ -14,9 +14,10 @@ const removeDuplicatesFromArray = require('./removeDuplicatesFromArray'); * Find out if node is `class` or `className` * * @param {ASTNode} node The AST node being checked + * @param {String} classRegex Regex to test the attribute that is being checked against * @returns {Boolean} */ -function isClassAttribute(node) { +function isClassAttribute(node, classRegex) { if (!node.name) { return false; } @@ -28,7 +29,7 @@ function isClassAttribute(node) { default: name = node.name.name; } - return /^class(Name)?$|^tw$/.test(name); + return new RegExp(classRegex).test(name); } /** @@ -81,10 +82,11 @@ function isLiteralAttributeValue(node) { * Find out if the node is a valid candidate for our rules * * @param {ASTNode} node The AST node being checked + * @param {String} classRegex Regex to test the attribute that is being checked against * @returns {Boolean} */ -function isValidJSXAttribute(node) { - if (!isClassAttribute(node)) { +function isValidJSXAttribute(node, classRegex) { + if (!isClassAttribute(node, classRegex)) { // Only run for class[Name] attributes return false; } diff --git a/lib/util/settings.js b/lib/util/settings.js index 93967f9..14dcc29 100644 --- a/lib/util/settings.js +++ b/lib/util/settings.js @@ -24,6 +24,8 @@ function getOption(context, name) { return []; case 'whitelist': return []; + case 'classRegex': + return "^class(Name)?$" } } diff --git a/tests/lib/rules/classnames-order.js b/tests/lib/rules/classnames-order.js index 4e0f21e..dbf62e6 100644 --- a/tests/lib/rules/classnames-order.js +++ b/tests/lib/rules/classnames-order.js @@ -67,6 +67,11 @@ ruleTester.run("classnames-order", rule, { }, { code: `
Simple, using 'tw' prop
`, + options: [ + { + classRegex: "^tw$", + }, + ], }, { code: "
ctl + exp
", @@ -96,6 +101,11 @@ ruleTester.run("classnames-order", rule, { }, { code: `
Extra space at the end, but with 'tw' prop
`, + options: [ + { + classRegex: "^tw$", + }, + ], }, { code: `
'p', then 'py' then 'px'
`, @@ -301,6 +311,11 @@ ruleTester.run("classnames-order", rule, { { code: `
Enhancing readability with 'tw' prop
`, output: `
Enhancing readability with 'tw' prop
`, + options: [ + { + classRegex: "^tw$", + }, + ], errors: errors, }, {