From b551ede4924049386fe8e0b7bf64f1d9a3d15747 Mon Sep 17 00:00:00 2001 From: francoismassart Date: Tue, 11 Jan 2022 16:15:36 +0100 Subject: [PATCH 1/9] WIP on html parser --- lib/rules/classnames-order.js | 15 ++++++- lib/util/ast.js | 22 +++++++++- package-lock.json | 16 +++++++ package.json | 2 + tests/lib/rules/wip.js | 81 +++++++++++++++++++++++++++++++++++ 5 files changed, 133 insertions(+), 3 deletions(-) create mode 100644 tests/lib/rules/wip.js diff --git a/lib/rules/classnames-order.js b/lib/rules/classnames-order.js index 57a072b4..a3ce49bd 100644 --- a/lib/rules/classnames-order.js +++ b/lib/rules/classnames-order.js @@ -226,8 +226,13 @@ module.exports = { if (arg === null) { originalClassNamesValue = astUtil.extractValueFromNode(node); const range = astUtil.extractRangeFromNode(node); - start = range[0] + 1; - end = range[1] - 1; + if (node.type === 'TextAttribute') { + start = range[0]; + end = range[1]; + } else { + start = range[0] + 1; + end = range[1] - 1; + } } else { switch (arg.type) { case 'TemplateLiteral': @@ -338,6 +343,12 @@ module.exports = { } sortNodeArgumentValue(node); }, + TextAttribute: function (node) { + if (!astUtil.isValidJSXAttribute(node)) { + return; + } + sortNodeArgumentValue(node); + }, CallExpression: function (node) { if (callees.findIndex((name) => node.callee.name === name) === -1) { return; diff --git a/lib/util/ast.js b/lib/util/ast.js index b692e086..2ab41a05 100644 --- a/lib/util/ast.js +++ b/lib/util/ast.js @@ -14,7 +14,18 @@ const removeDuplicatesFromArray = require('./removeDuplicatesFromArray'); * @returns {Boolean} */ function isClassAttribute(node) { - return node.name && /^class(Name)?$/.test(node.name.name); + if (!node.name) { + return false; + } + let name = ''; + switch (node.type) { + case 'TextAttribute': + name = node.name; + break; + default: + name = node.name.name; + } + return /^class(Name)?$/.test(name); } /** @@ -47,6 +58,9 @@ function isVueLiteralAttributeValue(node) { * @returns {Boolean} */ function isLiteralAttributeValue(node) { + if (node.type === 'TextAttribute' && node.name === 'class' && typeof node.value === 'string') { + return true; + } if (node.value) { switch (node.value.type) { case 'Literal': @@ -97,6 +111,9 @@ function isValidVueAttribute(node) { } function extractRangeFromNode(node) { + if (node.type === 'TextAttribute' && node.name === 'class') { + return [node.valueSpan.fullStart.offset, node.valueSpan.end.offset]; + } switch (node.value.type) { case 'JSXExpressionContainer': return node.value.expression.range; @@ -106,6 +123,9 @@ function extractRangeFromNode(node) { } function extractValueFromNode(node) { + if (node.type === 'TextAttribute' && node.name === 'class') { + return node.value; + } switch (node.value.type) { case 'JSXExpressionContainer': return node.value.expression.value; diff --git a/package-lock.json b/package-lock.json index 70c80367..ab950033 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,6 +4,22 @@ "lockfileVersion": 1, "requires": true, "dependencies": { + "@angular-eslint/bundled-angular-compiler": { + "version": "13.0.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/bundled-angular-compiler/-/bundled-angular-compiler-13.0.1.tgz", + "integrity": "sha512-Eih9Kh0hxHO4+3in9mgjksQecym0p+3p+287y3LLihIc7gCkAO4xZeHGVGiC8qUX72PNUXkDlyskI9oHjK9Axw==", + "dev": true + }, + "@angular-eslint/template-parser": { + "version": "13.0.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/template-parser/-/template-parser-13.0.1.tgz", + "integrity": "sha512-GEJzVLS4Sb4UdurqaPD1/ucGhagGAQCp17CIgjpcXRwzxBZ9OLqbO/rx8diRbADp+1rceVq4BhADsg3VdsOsuw==", + "dev": true, + "requires": { + "@angular-eslint/bundled-angular-compiler": "13.0.1", + "eslint-scope": "^5.1.0" + } + }, "@babel/code-frame": { "version": "7.12.11", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", diff --git a/package.json b/package.json index e52a7229..c050c975 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "bugs": "https://github.com/francoismassart/eslint-plugin-tailwindcss/issues", "main": "lib/index.js", "scripts": { + "wip": "mocha tests/lib/rules/wip.js", "test": "mocha tests --recursive" }, "files": [ @@ -29,6 +30,7 @@ "tailwindcss": "^3.0.7" }, "devDependencies": { + "@angular-eslint/template-parser": "^13.0.1", "@tailwindcss/aspect-ratio": "^0.4.0", "@tailwindcss/forms": "^0.4.0", "@tailwindcss/line-clamp": "^0.3.0", diff --git a/tests/lib/rules/wip.js b/tests/lib/rules/wip.js new file mode 100644 index 00000000..40d187b5 --- /dev/null +++ b/tests/lib/rules/wip.js @@ -0,0 +1,81 @@ +/** + * @fileoverview Use a consistent orders for the Tailwind CSS classnames, based on property then on variants + * @author François Massart + */ +"use strict"; + +//------------------------------------------------------------------------------ +// Requirements +//------------------------------------------------------------------------------ + +var rule = require("../../../lib/rules/classnames-order"); +var RuleTester = require("eslint").RuleTester; + +//------------------------------------------------------------------------------ +// Tests +//------------------------------------------------------------------------------ + +var parserOptions = { + ecmaVersion: 2019, + sourceType: "module", + ecmaFeatures: { + jsx: true, + }, +}; + +var ruleTester = new RuleTester({ parserOptions }); + +var errors = [ + { + messageId: "invalidOrder", + }, +]; + +ruleTester.run("classnames-order", rule, { + valid: [], + invalid: [ + { + code: ` +
+
+
`, + output: ` +
+
+
`, + errors: [...errors, ...errors], + parser: require.resolve("@angular-eslint/template-parser"), + }, + { + code: `
:)
`, + output: `
:)
`, + errors: errors, + parser: require.resolve("@angular-eslint/template-parser"), + }, + { + code: ` +
+ :) +
`, + output: ` +
+ :) +
`, + errors: errors, + parser: require.resolve("@angular-eslint/template-parser"), + options: [ + { + groupByResponsive: false, + }, + ], + }, + ], +}); From 5e0676c03867e829f0ee1dfd3c8a9de062ac6df0 Mon Sep 17 00:00:00 2001 From: francoismassart Date: Wed, 12 Jan 2022 22:01:00 +0100 Subject: [PATCH 2/9] Testing with `@angular-eslint/template-parser` --- lib/rules/classnames-order.js | 22 +++-- lib/rules/no-contradicting-classname.js | 15 ++-- lib/rules/no-custom-classname.js | 15 ++-- lib/util/ast.js | 4 + package.json | 2 +- tests/lib/rules/wip/classnames-order.js | 81 +++++++++++++++++++ .../rules/wip/no-contradicting-classname.js | 73 +++++++++++++++++ tests/lib/rules/wip/no-custom-classname.js | 50 ++++++++++++ 8 files changed, 237 insertions(+), 25 deletions(-) create mode 100644 tests/lib/rules/wip/classnames-order.js create mode 100644 tests/lib/rules/wip/no-contradicting-classname.js create mode 100644 tests/lib/rules/wip/no-custom-classname.js diff --git a/lib/rules/classnames-order.js b/lib/rules/classnames-order.js index a3ce49bd..3e89acdc 100644 --- a/lib/rules/classnames-order.js +++ b/lib/rules/classnames-order.js @@ -336,19 +336,17 @@ module.exports = { //---------------------------------------------------------------------- // Public //---------------------------------------------------------------------- + + const attributeVisitor = function (node) { + if (!astUtil.isValidJSXAttribute(node)) { + return; + } + sortNodeArgumentValue(node); + }; + const scriptVisitor = { - JSXAttribute: function (node) { - if (!astUtil.isValidJSXAttribute(node)) { - return; - } - sortNodeArgumentValue(node); - }, - TextAttribute: function (node) { - if (!astUtil.isValidJSXAttribute(node)) { - return; - } - sortNodeArgumentValue(node); - }, + JSXAttribute: attributeVisitor, + TextAttribute: attributeVisitor, CallExpression: function (node) { if (callees.findIndex((name) => node.callee.name === name) === -1) { return; diff --git a/lib/rules/no-contradicting-classname.js b/lib/rules/no-contradicting-classname.js index bbcb21b6..538642a7 100644 --- a/lib/rules/no-contradicting-classname.js +++ b/lib/rules/no-contradicting-classname.js @@ -129,13 +129,16 @@ module.exports = { // Public //---------------------------------------------------------------------- + const attributeVisitor = function (node) { + if (!astUtil.isValidJSXAttribute(node)) { + return; + } + astUtil.parseNodeRecursive(node, null, parseForContradictingClassNames, true); + }; + const scriptVisitor = { - JSXAttribute: function (node) { - if (!astUtil.isValidJSXAttribute(node)) { - return; - } - astUtil.parseNodeRecursive(node, null, parseForContradictingClassNames, true); - }, + JSXAttribute: attributeVisitor, + TextAttribute: attributeVisitor, CallExpression: function (node) { if (callees.findIndex((name) => node.callee.name === name) === -1) { return; diff --git a/lib/rules/no-custom-classname.js b/lib/rules/no-custom-classname.js index 5abb5b6d..ddd4314d 100644 --- a/lib/rules/no-custom-classname.js +++ b/lib/rules/no-custom-classname.js @@ -125,13 +125,16 @@ module.exports = { // Public //---------------------------------------------------------------------- + const attributeVisitor = function (node) { + if (!astUtil.isValidJSXAttribute(node)) { + return; + } + astUtil.parseNodeRecursive(node, null, parseForCustomClassNames); + }; + const scriptVisitor = { - JSXAttribute: function (node) { - if (!astUtil.isValidJSXAttribute(node)) { - return; - } - astUtil.parseNodeRecursive(node, null, parseForCustomClassNames); - }, + JSXAttribute: attributeVisitor, + TextAttribute: attributeVisitor, CallExpression: function (node) { if (callees.findIndex((name) => node.callee.name === name) === -1) { return; diff --git a/lib/util/ast.js b/lib/util/ast.js index 2ab41a05..7dd27221 100644 --- a/lib/util/ast.js +++ b/lib/util/ast.js @@ -4,6 +4,10 @@ 'use strict'; +// context.parserPath +// /.../eslint-plugin-tailwindcss/node_modules/espree/espree.js +// /.../eslint-plugin-tailwindcss/node_modules/@angular-eslint/template-parser/dist/index.js + const attrUtil = require('./attr'); const removeDuplicatesFromArray = require('./removeDuplicatesFromArray'); diff --git a/package.json b/package.json index 99e21b66..86c75c80 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ "bugs": "https://github.com/francoismassart/eslint-plugin-tailwindcss/issues", "main": "lib/index.js", "scripts": { - "wip": "mocha tests/lib/rules/wip.js", + "wip": "mocha tests/lib/rules/wip/ --recursive", "test": "mocha tests --recursive" }, "files": [ diff --git a/tests/lib/rules/wip/classnames-order.js b/tests/lib/rules/wip/classnames-order.js new file mode 100644 index 00000000..7ba04444 --- /dev/null +++ b/tests/lib/rules/wip/classnames-order.js @@ -0,0 +1,81 @@ +/** + * @fileoverview Use a consistent orders for the Tailwind CSS classnames, based on property then on variants + * @author François Massart + */ +"use strict"; + +//------------------------------------------------------------------------------ +// Requirements +//------------------------------------------------------------------------------ + +var rule = require("../../../../lib/rules/classnames-order"); +var RuleTester = require("eslint").RuleTester; + +//------------------------------------------------------------------------------ +// Tests +//------------------------------------------------------------------------------ + +var parserOptions = { + ecmaVersion: 2019, + sourceType: "module", + ecmaFeatures: { + jsx: true, + }, +}; + +var ruleTester = new RuleTester({ parserOptions }); + +var errors = [ + { + messageId: "invalidOrder", + }, +]; + +ruleTester.run("classnames-order", rule, { + valid: [], + invalid: [ + { + code: ` +
+
+
`, + output: ` +
+
+
`, + errors: [...errors, ...errors], + parser: require.resolve("@angular-eslint/template-parser"), + }, + { + code: `
:)
`, + output: `
:)
`, + errors: errors, + parser: require.resolve("@angular-eslint/template-parser"), + }, + { + code: ` +
+ :) +
`, + output: ` +
+ :) +
`, + errors: errors, + parser: require.resolve("@angular-eslint/template-parser"), + options: [ + { + groupByResponsive: false, + }, + ], + }, + ], +}); diff --git a/tests/lib/rules/wip/no-contradicting-classname.js b/tests/lib/rules/wip/no-contradicting-classname.js new file mode 100644 index 00000000..59bab196 --- /dev/null +++ b/tests/lib/rules/wip/no-contradicting-classname.js @@ -0,0 +1,73 @@ +/** + * @fileoverview Avoid contradicting Tailwind CSS classnames (e.g. 'w-3 w-5') + * @author François Massart + */ +"use strict"; + +//------------------------------------------------------------------------------ +// Requirements +//------------------------------------------------------------------------------ + +var rule = require("../../../../lib/rules/no-contradicting-classname"); +var RuleTester = require("eslint").RuleTester; + +//------------------------------------------------------------------------------ +// Tests +//------------------------------------------------------------------------------ + +var parserOptions = { + ecmaVersion: 2019, + sourceType: "module", + ecmaFeatures: { + jsx: true, + }, +}; + +var config = [ + { + config: { + mode: "jit", + theme: { + aspectRatio: { + 1: "1", + 9: "9", + 16: "16", + }, + order: { + "-1": "-1", + 0: "0", + }, + zIndex: { + "-1": "-1", + 0: "0", + }, + }, + }, + }, +]; + +var ruleTester = new RuleTester({ parserOptions }); + +ruleTester.run("no-contradicting-classname", rule, { + valid: [ + { + code: '
Accepts shorthands
', + parser: require.resolve("@angular-eslint/template-parser"), + }, + ], + + invalid: [ + { + code: '
', + errors: [ + { + messageId: "conflictingClassnames", + data: { + classnames: "w-1, w-2", + }, + }, + ], + parser: require.resolve("@angular-eslint/template-parser"), + }, + ], +}); diff --git a/tests/lib/rules/wip/no-custom-classname.js b/tests/lib/rules/wip/no-custom-classname.js new file mode 100644 index 00000000..8acf5815 --- /dev/null +++ b/tests/lib/rules/wip/no-custom-classname.js @@ -0,0 +1,50 @@ +/** + * @fileoverview Detect classnames which do not belong to Tailwind CSS + * @author no-custom-classname + */ +"use strict"; + +//------------------------------------------------------------------------------ +// Requirements +//------------------------------------------------------------------------------ + +var rule = require("../../../../lib/rules/no-custom-classname"); +var RuleTester = require("eslint").RuleTester; + +//------------------------------------------------------------------------------ +// Tests +//------------------------------------------------------------------------------ + +var parserOptions = { + ecmaVersion: 2019, + sourceType: "module", + ecmaFeatures: { + jsx: true, + }, +}; + +var ruleTester = new RuleTester({ parserOptions }); + +ruleTester.run("no-custom-classname", rule, { + valid: [ + { + code: `
Only Tailwind CSS classnames
`, + parser: require.resolve("@angular-eslint/template-parser"), + }, + ], + + invalid: [ + { + code: `
my-custom is not defined in Tailwind CSS!
`, + errors: [ + { + messageId: "customClassnameDetected", + data: { + classname: "my-custom", + }, + }, + ], + parser: require.resolve("@angular-eslint/template-parser"), + }, + ], +}); From bb3979121170c2bfab5b9bedc4cf3dc23ad73c57 Mon Sep 17 00:00:00 2001 From: francoismassart Date: Wed, 12 Jan 2022 22:01:53 +0100 Subject: [PATCH 3/9] 3.2.1-beta.0 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 77f81a71..6eaf13f0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "eslint-plugin-tailwindcss", - "version": "3.2.0", + "version": "3.2.1-beta.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 86c75c80..7287e0b6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "eslint-plugin-tailwindcss", - "version": "3.2.0", + "version": "3.2.1-beta.0", "description": "Rules enforcing best practices while using Tailwind CSS", "keywords": [ "eslint", From cb0a521bdf6ae2d48a4928ddfdf28db1faf1e907 Mon Sep 17 00:00:00 2001 From: francoismassart Date: Thu, 13 Jan 2022 10:15:41 +0100 Subject: [PATCH 4/9] FIX #73 --- lib/util/groupMethods.js | 2 +- tests/lib/rules/no-custom-classname.js | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/lib/util/groupMethods.js b/lib/util/groupMethods.js index 3e3e39e8..4f62e07c 100644 --- a/lib/util/groupMethods.js +++ b/lib/util/groupMethods.js @@ -29,7 +29,7 @@ const length = require('./types/length'); * @returns {String} Escaped version */ function escapeSpecialChars(str) { - return str.replace(/[\-\.\/]/g, '\\$&'); + return str.replace(/\W/g, '\\$&'); } /** diff --git a/tests/lib/rules/no-custom-classname.js b/tests/lib/rules/no-custom-classname.js index fef59eb3..d4f83355 100644 --- a/tests/lib/rules/no-custom-classname.js +++ b/tests/lib/rules/no-custom-classname.js @@ -525,6 +525,17 @@ ruleTester.run("no-custom-classname", rule, { code: `
Disabling transform
`, }, + { + code: ` +
Nasty prefix
`, + options: [ + { + config: { + prefix: "p/r[e].f!-x_", + }, + }, + ], + }, ], invalid: [ From 228a907ee94f12e39e1b5e41f5753181140efd10 Mon Sep 17 00:00:00 2001 From: francoismassart Date: Mon, 17 Jan 2022 14:52:16 +0100 Subject: [PATCH 5/9] 3.2.2-beta.0 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index c3bab9b2..df595b26 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "eslint-plugin-tailwindcss", - "version": "3.2.1", + "version": "3.2.2-beta.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 963a4806..2ee108da 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "eslint-plugin-tailwindcss", - "version": "3.2.1", + "version": "3.2.2-beta.0", "description": "Rules enforcing best practices while using Tailwind CSS", "keywords": [ "eslint", From 2059ca2ac52f5f07d33e871252d0ffa1ffcc2de4 Mon Sep 17 00:00:00 2001 From: francoismassart Date: Wed, 19 Jan 2022 10:54:09 +0100 Subject: [PATCH 6/9] Add `TextAttribute` visitor --- lib/rules/enforces-shorthand.js | 15 +++++++++------ lib/rules/migration-from-tailwind-2.js | 15 +++++++++------ lib/rules/no-arbitrary-value.js | 15 +++++++++------ 3 files changed, 27 insertions(+), 18 deletions(-) diff --git a/lib/rules/enforces-shorthand.js b/lib/rules/enforces-shorthand.js index 72168f93..16cd6d05 100644 --- a/lib/rules/enforces-shorthand.js +++ b/lib/rules/enforces-shorthand.js @@ -342,13 +342,16 @@ module.exports = { // Public //---------------------------------------------------------------------- + const attributeVisitor = function (node) { + if (!astUtil.isValidJSXAttribute(node)) { + return; + } + parseForShorthandCandidates(node); + }; + const scriptVisitor = { - JSXAttribute: function (node) { - if (!astUtil.isValidJSXAttribute(node)) { - return; - } - parseForShorthandCandidates(node); - }, + JSXAttribute: attributeVisitor, + TextAttribute: attributeVisitor, CallExpression: function (node) { if (callees.findIndex((name) => node.callee.name === name) === -1) { return; diff --git a/lib/rules/migration-from-tailwind-2.js b/lib/rules/migration-from-tailwind-2.js index d0d5ff9f..71fc4a01 100644 --- a/lib/rules/migration-from-tailwind-2.js +++ b/lib/rules/migration-from-tailwind-2.js @@ -241,13 +241,16 @@ module.exports = { // Public //---------------------------------------------------------------------- + const attributeVisitor = function (node) { + if (!astUtil.isValidJSXAttribute(node)) { + return; + } + parseForObsoleteClassNames(node); + }; + const scriptVisitor = { - JSXAttribute: function (node) { - if (!astUtil.isValidJSXAttribute(node)) { - return; - } - parseForObsoleteClassNames(node); - }, + JSXAttribute: attributeVisitor, + TextAttribute: attributeVisitor, CallExpression: function (node) { if (callees.findIndex((name) => node.callee.name === name) === -1) { return; diff --git a/lib/rules/no-arbitrary-value.js b/lib/rules/no-arbitrary-value.js index 57214317..1ca97914 100644 --- a/lib/rules/no-arbitrary-value.js +++ b/lib/rules/no-arbitrary-value.js @@ -138,13 +138,16 @@ module.exports = { // Public //---------------------------------------------------------------------- + const attributeVisitor = function (node) { + if (!astUtil.isValidJSXAttribute(node)) { + return; + } + parseForArbitraryValues(node); + }; + const scriptVisitor = { - JSXAttribute: function (node) { - if (!astUtil.isValidJSXAttribute(node)) { - return; - } - parseForArbitraryValues(node); - }, + JSXAttribute: attributeVisitor, + TextAttribute: attributeVisitor, CallExpression: function (node) { if (callees.findIndex((name) => node.callee.name === name) === -1) { return; From a4468a9ad92db4f3b5ec3fe82397322128dd87fb Mon Sep 17 00:00:00 2001 From: francoismassart Date: Thu, 20 Jan 2022 09:33:56 +0100 Subject: [PATCH 7/9] CLEANING --- package.json | 1 - tests/lib/rules/classnames-order.js | 41 ++++++++++ tests/lib/rules/no-contradicting-classname.js | 13 +++ tests/lib/rules/no-custom-classname.js | 23 +++++- tests/lib/rules/wip.js | 81 ------------------- tests/lib/rules/wip/classnames-order.js | 81 ------------------- .../rules/wip/no-contradicting-classname.js | 73 ----------------- tests/lib/rules/wip/no-custom-classname.js | 50 ------------ 8 files changed, 73 insertions(+), 290 deletions(-) delete mode 100644 tests/lib/rules/wip.js delete mode 100644 tests/lib/rules/wip/classnames-order.js delete mode 100644 tests/lib/rules/wip/no-contradicting-classname.js delete mode 100644 tests/lib/rules/wip/no-custom-classname.js diff --git a/package.json b/package.json index 86d9bbde..ff3cc0b8 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,6 @@ "bugs": "https://github.com/francoismassart/eslint-plugin-tailwindcss/issues", "main": "lib/index.js", "scripts": { - "wip": "mocha tests/lib/rules/wip/ --recursive", "test": "mocha tests --recursive" }, "files": [ diff --git a/tests/lib/rules/classnames-order.js b/tests/lib/rules/classnames-order.js index 8a73b5aa..5895ba38 100644 --- a/tests/lib/rules/classnames-order.js +++ b/tests/lib/rules/classnames-order.js @@ -661,5 +661,46 @@ ruleTester.run("classnames-order", rule, { })`, errors: errors, }, + { + code: ` +
+
`, + output: ` +
+
`, + errors: [...errors, ...errors], + parser: require.resolve("@angular-eslint/template-parser"), + }, + { + code: `
:)
`, + output: `
:)
`, + errors: errors, + parser: require.resolve("@angular-eslint/template-parser"), + }, + { + code: ` +
+ :) +
`, + output: ` +
+ :) +
`, + errors: errors, + parser: require.resolve("@angular-eslint/template-parser"), + options: [ + { + groupByResponsive: false, + }, + ], + }, ], }); diff --git a/tests/lib/rules/no-contradicting-classname.js b/tests/lib/rules/no-contradicting-classname.js index 920255d3..52b4c8a2 100644 --- a/tests/lib/rules/no-contradicting-classname.js +++ b/tests/lib/rules/no-contradicting-classname.js @@ -184,6 +184,12 @@ ruleTester.run("no-contradicting-classname", rule, { `, }, + { + code: ` +
Accepts shorthands
+
Accepts shorthands
`, + parser: require.resolve("@angular-eslint/template-parser"), + }, ], invalid: [ @@ -406,6 +412,13 @@ ruleTester.run("no-contradicting-classname", rule, { options: config, errors: generateErrors("aspect-none aspect-w-16"), }, + { + code: ` +
+
`, + errors: [...generateErrors("w-1 w-2"), ...generateErrors("block flex")], + parser: require.resolve("@angular-eslint/template-parser"), + }, // { // code: ` //
diff --git a/tests/lib/rules/no-custom-classname.js b/tests/lib/rules/no-custom-classname.js index 775fb84b..c4f221f2 100644 --- a/tests/lib/rules/no-custom-classname.js +++ b/tests/lib/rules/no-custom-classname.js @@ -535,10 +535,6 @@ ruleTester.run("no-custom-classname", rule, { code: `
Disabling transform
`, }, - { - code: ` -
Disabling transform
`, - }, { code: `
Nasty prefix
`, @@ -585,6 +581,25 @@ ruleTester.run("no-custom-classname", rule, { }, ], }, + { + code: ` +
Using
+
HTML
`, + parser: require.resolve("@angular-eslint/template-parser"), + }, + { + code: ` +
Using HTML
+
With nasty prefix
`, + options: [ + { + config: { + prefix: "p/r[e].f!-x_", + }, + }, + ], + parser: require.resolve("@angular-eslint/template-parser"), + }, ], invalid: [ diff --git a/tests/lib/rules/wip.js b/tests/lib/rules/wip.js deleted file mode 100644 index 40d187b5..00000000 --- a/tests/lib/rules/wip.js +++ /dev/null @@ -1,81 +0,0 @@ -/** - * @fileoverview Use a consistent orders for the Tailwind CSS classnames, based on property then on variants - * @author François Massart - */ -"use strict"; - -//------------------------------------------------------------------------------ -// Requirements -//------------------------------------------------------------------------------ - -var rule = require("../../../lib/rules/classnames-order"); -var RuleTester = require("eslint").RuleTester; - -//------------------------------------------------------------------------------ -// Tests -//------------------------------------------------------------------------------ - -var parserOptions = { - ecmaVersion: 2019, - sourceType: "module", - ecmaFeatures: { - jsx: true, - }, -}; - -var ruleTester = new RuleTester({ parserOptions }); - -var errors = [ - { - messageId: "invalidOrder", - }, -]; - -ruleTester.run("classnames-order", rule, { - valid: [], - invalid: [ - { - code: ` -
-
-
`, - output: ` -
-
-
`, - errors: [...errors, ...errors], - parser: require.resolve("@angular-eslint/template-parser"), - }, - { - code: `
:)
`, - output: `
:)
`, - errors: errors, - parser: require.resolve("@angular-eslint/template-parser"), - }, - { - code: ` -
- :) -
`, - output: ` -
- :) -
`, - errors: errors, - parser: require.resolve("@angular-eslint/template-parser"), - options: [ - { - groupByResponsive: false, - }, - ], - }, - ], -}); diff --git a/tests/lib/rules/wip/classnames-order.js b/tests/lib/rules/wip/classnames-order.js deleted file mode 100644 index 7ba04444..00000000 --- a/tests/lib/rules/wip/classnames-order.js +++ /dev/null @@ -1,81 +0,0 @@ -/** - * @fileoverview Use a consistent orders for the Tailwind CSS classnames, based on property then on variants - * @author François Massart - */ -"use strict"; - -//------------------------------------------------------------------------------ -// Requirements -//------------------------------------------------------------------------------ - -var rule = require("../../../../lib/rules/classnames-order"); -var RuleTester = require("eslint").RuleTester; - -//------------------------------------------------------------------------------ -// Tests -//------------------------------------------------------------------------------ - -var parserOptions = { - ecmaVersion: 2019, - sourceType: "module", - ecmaFeatures: { - jsx: true, - }, -}; - -var ruleTester = new RuleTester({ parserOptions }); - -var errors = [ - { - messageId: "invalidOrder", - }, -]; - -ruleTester.run("classnames-order", rule, { - valid: [], - invalid: [ - { - code: ` -
-
-
`, - output: ` -
-
-
`, - errors: [...errors, ...errors], - parser: require.resolve("@angular-eslint/template-parser"), - }, - { - code: `
:)
`, - output: `
:)
`, - errors: errors, - parser: require.resolve("@angular-eslint/template-parser"), - }, - { - code: ` -
- :) -
`, - output: ` -
- :) -
`, - errors: errors, - parser: require.resolve("@angular-eslint/template-parser"), - options: [ - { - groupByResponsive: false, - }, - ], - }, - ], -}); diff --git a/tests/lib/rules/wip/no-contradicting-classname.js b/tests/lib/rules/wip/no-contradicting-classname.js deleted file mode 100644 index 59bab196..00000000 --- a/tests/lib/rules/wip/no-contradicting-classname.js +++ /dev/null @@ -1,73 +0,0 @@ -/** - * @fileoverview Avoid contradicting Tailwind CSS classnames (e.g. 'w-3 w-5') - * @author François Massart - */ -"use strict"; - -//------------------------------------------------------------------------------ -// Requirements -//------------------------------------------------------------------------------ - -var rule = require("../../../../lib/rules/no-contradicting-classname"); -var RuleTester = require("eslint").RuleTester; - -//------------------------------------------------------------------------------ -// Tests -//------------------------------------------------------------------------------ - -var parserOptions = { - ecmaVersion: 2019, - sourceType: "module", - ecmaFeatures: { - jsx: true, - }, -}; - -var config = [ - { - config: { - mode: "jit", - theme: { - aspectRatio: { - 1: "1", - 9: "9", - 16: "16", - }, - order: { - "-1": "-1", - 0: "0", - }, - zIndex: { - "-1": "-1", - 0: "0", - }, - }, - }, - }, -]; - -var ruleTester = new RuleTester({ parserOptions }); - -ruleTester.run("no-contradicting-classname", rule, { - valid: [ - { - code: '
Accepts shorthands
', - parser: require.resolve("@angular-eslint/template-parser"), - }, - ], - - invalid: [ - { - code: '
', - errors: [ - { - messageId: "conflictingClassnames", - data: { - classnames: "w-1, w-2", - }, - }, - ], - parser: require.resolve("@angular-eslint/template-parser"), - }, - ], -}); diff --git a/tests/lib/rules/wip/no-custom-classname.js b/tests/lib/rules/wip/no-custom-classname.js deleted file mode 100644 index 8acf5815..00000000 --- a/tests/lib/rules/wip/no-custom-classname.js +++ /dev/null @@ -1,50 +0,0 @@ -/** - * @fileoverview Detect classnames which do not belong to Tailwind CSS - * @author no-custom-classname - */ -"use strict"; - -//------------------------------------------------------------------------------ -// Requirements -//------------------------------------------------------------------------------ - -var rule = require("../../../../lib/rules/no-custom-classname"); -var RuleTester = require("eslint").RuleTester; - -//------------------------------------------------------------------------------ -// Tests -//------------------------------------------------------------------------------ - -var parserOptions = { - ecmaVersion: 2019, - sourceType: "module", - ecmaFeatures: { - jsx: true, - }, -}; - -var ruleTester = new RuleTester({ parserOptions }); - -ruleTester.run("no-custom-classname", rule, { - valid: [ - { - code: `
Only Tailwind CSS classnames
`, - parser: require.resolve("@angular-eslint/template-parser"), - }, - ], - - invalid: [ - { - code: `
my-custom is not defined in Tailwind CSS!
`, - errors: [ - { - messageId: "customClassnameDetected", - data: { - classname: "my-custom", - }, - }, - ], - parser: require.resolve("@angular-eslint/template-parser"), - }, - ], -}); From f163c944c06754b02c7add3253c72c6d70a8a0a2 Mon Sep 17 00:00:00 2001 From: francoismassart Date: Thu, 20 Jan 2022 10:22:37 +0100 Subject: [PATCH 8/9] README --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index b1546bee..e9e20622 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,9 @@ If you enjoy my work you can: ## Latest changelog +- FIX: [Escaping special characters in the `prefix`](https://github.com/francoismassart/eslint-plugin-tailwindcss/issues/73) +- FIX: [Formating HTML files](https://github.com/francoismassart/eslint-plugin-tailwindcss/issues/85) is now possible using `@angular-eslint/template-parser` + - New feature: [crawling `ArrayExpression` elements and `ObjectExpression`](https://github.com/francoismassart/eslint-plugin-tailwindcss/pull/103), see [issue #99](https://github.com/francoismassart/eslint-plugin-tailwindcss/issues/99) (by [matt-tingen](https://github.com/matt-tingen) 🙏) - New rule: [`no-arbitrary-value`](https://github.com/francoismassart/eslint-plugin-tailwindcss/issues/89) which forbid using arbitrary values in classnames - New rule: [default for `cssFiles` option used by `no-custom-classname`](https://github.com/francoismassart/eslint-plugin-tailwindcss/issues/37) From 4010a62dd26b1523d96318eb831b0367350e470b Mon Sep 17 00:00:00 2001 From: francoismassart Date: Thu, 20 Jan 2022 10:24:52 +0100 Subject: [PATCH 9/9] 3.3.1-beta.0 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index dfe045e2..a2aee41b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "eslint-plugin-tailwindcss", - "version": "3.3.0", + "version": "3.3.1-beta.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index ff3cc0b8..f450f9ff 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "eslint-plugin-tailwindcss", - "version": "3.3.0", + "version": "3.3.1-beta.0", "description": "Rules enforcing best practices while using Tailwind CSS", "keywords": [ "eslint",