From 01e5e69a94c69e8a097f7bd9bfff1f7892b18496 Mon Sep 17 00:00:00 2001 From: Nihal Gonsalves Date: Fri, 29 Dec 2023 11:59:38 +0100 Subject: [PATCH] fix: support tag.div`` and tag(Component)`` --- lib/rules/classnames-order.js | 2 +- .../enforces-negative-arbitrary-values.js | 2 +- lib/rules/enforces-shorthand.js | 7 +- lib/rules/migration-from-tailwind-2.js | 2 +- lib/rules/no-arbitrary-value.js | 2 +- lib/rules/no-contradicting-classname.js | 2 +- lib/rules/no-custom-classname.js | 2 +- package-lock.json | 2 +- package.json | 2 +- tests/lib/rules/arbitrary-values.js | 9 + tests/lib/rules/classnames-order.js | 168 +++++++++--------- .../enforces-negative-arbitrary-values.js | 9 + tests/lib/rules/enforces-shorthand.js | 10 ++ tests/lib/rules/migration-from-tailwind-2.js | 18 ++ tests/lib/rules/no-arbitrary-value.js | 9 + tests/lib/rules/no-contradicting-classname.js | 104 +++++------ tests/lib/rules/no-custom-classname.js | 102 +++++------ 17 files changed, 256 insertions(+), 196 deletions(-) diff --git a/lib/rules/classnames-order.js b/lib/rules/classnames-order.js index d3782d7..e7e3573 100644 --- a/lib/rules/classnames-order.js +++ b/lib/rules/classnames-order.js @@ -235,7 +235,7 @@ module.exports = { TextAttribute: attributeVisitor, CallExpression: callExpressionVisitor, TaggedTemplateExpression: function (node) { - if (!tags.includes(node.tag.name)) { + if (!tags.includes(node.tag.name ?? node.tag.object?.name ?? node.tag.callee?.name)) { return; } diff --git a/lib/rules/enforces-negative-arbitrary-values.js b/lib/rules/enforces-negative-arbitrary-values.js index 2ef01f3..1218993 100644 --- a/lib/rules/enforces-negative-arbitrary-values.js +++ b/lib/rules/enforces-negative-arbitrary-values.js @@ -179,7 +179,7 @@ module.exports = { TextAttribute: attributeVisitor, CallExpression: callExpressionVisitor, TaggedTemplateExpression: function (node) { - if (!tags.includes(node.tag.name)) { + if (!tags.includes(node.tag.name ?? node.tag.object?.name ?? node.tag.callee?.name)) { return; } parseForNegativeArbitraryClassNames(node, node.quasi); diff --git a/lib/rules/enforces-shorthand.js b/lib/rules/enforces-shorthand.js index 1fcc366..8419c79 100644 --- a/lib/rules/enforces-shorthand.js +++ b/lib/rules/enforces-shorthand.js @@ -350,9 +350,8 @@ module.exports = { } else if (hasY || hasX) { const xOrY = hasX ? 'x' : 'y'; const xOrYType = getBodyByShorthand(targetGroups, classname.parentType, xOrY); - const patchedName = `${cls.variants}${important}${minus}${mergedConfig.prefix}${xOrYType}${ - absoluteVal.length ? '-' + absoluteVal : '' - }`; + const patchedName = `${cls.variants}${important}${minus}${mergedConfig.prefix}${xOrYType}${absoluteVal.length ? '-' + absoluteVal : '' + }`; const toBeReplaced = sameVariantAndValue .filter((c) => { const candidates = hasX ? ['l', 'r'] : ['t', 'b']; @@ -489,7 +488,7 @@ module.exports = { TextAttribute: attributeVisitor, CallExpression: callExpressionVisitor, TaggedTemplateExpression: function (node) { - if (!tags.includes(node.tag.name)) { + if (!tags.includes(node.tag.name ?? node.tag.object?.name ?? node.tag.callee?.name)) { return; } diff --git a/lib/rules/migration-from-tailwind-2.js b/lib/rules/migration-from-tailwind-2.js index 434d102..5de0f0f 100644 --- a/lib/rules/migration-from-tailwind-2.js +++ b/lib/rules/migration-from-tailwind-2.js @@ -290,7 +290,7 @@ module.exports = { TextAttribute: attributeVisitor, CallExpression: callExpressionVisitor, TaggedTemplateExpression: function (node) { - if (!tags.includes(node.tag.name)) { + if (!tags.includes(node.tag.name ?? node.tag.object?.name ?? node.tag.callee?.name)) { return; } parseForObsoleteClassNames(node, node.quasi); diff --git a/lib/rules/no-arbitrary-value.js b/lib/rules/no-arbitrary-value.js index eac5e25..93142d8 100644 --- a/lib/rules/no-arbitrary-value.js +++ b/lib/rules/no-arbitrary-value.js @@ -179,7 +179,7 @@ module.exports = { TextAttribute: attributeVisitor, CallExpression: callExpressionVisitor, TaggedTemplateExpression: function (node) { - if (!tags.includes(node.tag.name)) { + if (!tags.includes(node.tag.name ?? node.tag.object?.name ?? node.tag.callee?.name)) { return; } parseForArbitraryValues(node, node.quasi); diff --git a/lib/rules/no-contradicting-classname.js b/lib/rules/no-contradicting-classname.js index 188f3d7..b4af173 100644 --- a/lib/rules/no-contradicting-classname.js +++ b/lib/rules/no-contradicting-classname.js @@ -203,7 +203,7 @@ module.exports = { TextAttribute: attributeVisitor, CallExpression: callExpressionVisitor, TaggedTemplateExpression: function (node) { - if (!tags.includes(node.tag.name)) { + if (!tags.includes(node.tag.name ?? node.tag.object?.name ?? node.tag.callee?.name)) { return; } diff --git a/lib/rules/no-custom-classname.js b/lib/rules/no-custom-classname.js index aceb171..97216be 100644 --- a/lib/rules/no-custom-classname.js +++ b/lib/rules/no-custom-classname.js @@ -182,7 +182,7 @@ module.exports = { TextAttribute: attributeVisitor, CallExpression: callExpressionVisitor, TaggedTemplateExpression: function (node) { - if (!tags.includes(node.tag.name)) { + if (!tags.includes(node.tag.name ?? node.tag.object?.name ?? node.tag.callee?.name)) { return; } astUtil.parseNodeRecursive(node, node.quasi, parseForCustomClassNames, false, false, ignoredKeys); diff --git a/package-lock.json b/package-lock.json index 8e7aa1d..0a7f06e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,7 +28,7 @@ "vue-eslint-parser": "^9.1.0" }, "engines": { - "node": ">=12.13.0" + "node": ">=14.0.0" }, "peerDependencies": { "tailwindcss": "^3.4.0" diff --git a/package.json b/package.json index eb99550..10dd111 100644 --- a/package.json +++ b/package.json @@ -48,7 +48,7 @@ }, "packageManager": "npm@10.2.5+sha256.8002e3e7305d2abd4016e1368af48d49b066c269079eeb10a56e7d6598acfdaa", "engines": { - "node": ">=12.13.0" + "node": ">=14.0.0" }, "license": "MIT" } diff --git a/tests/lib/rules/arbitrary-values.js b/tests/lib/rules/arbitrary-values.js index 70e47c4..2416317 100644 --- a/tests/lib/rules/arbitrary-values.js +++ b/tests/lib/rules/arbitrary-values.js @@ -677,5 +677,14 @@ ruleTester.run("arbitrary-values", rule, { options: config, errors: generateErrors("stroke-[angle:var(--some)]"), }, + ...(['myTag', 'myTag.subTag', 'myTag(SomeComponent)'].map(tag => ({ + code: `${tag}\`stroke-[var(--some)] stroke-['yolo'] stroke-[angle:var(--some)]\``, + errors: generateErrors("stroke-[angle:var(--some)]"), + options: [ + { + tags: ["myTag"], + }, + ], + }))), ], }); diff --git a/tests/lib/rules/classnames-order.js b/tests/lib/rules/classnames-order.js index b797f01..d0ba4ca 100644 --- a/tests/lib/rules/classnames-order.js +++ b/tests/lib/rules/classnames-order.js @@ -187,8 +187,8 @@ ruleTester.run("classnames-order", rule, { }, }, }, - { - code: `myTag\` + ...(['myTag', 'myTag.subTag', 'myTag(SomeComponent)'].map(tag => ({ + code: `${tag}\` container flex w-12 @@ -200,7 +200,7 @@ ruleTester.run("classnames-order", rule, { tags: ["myTag"], }, ], - }, + }))), { code: `
Number values
`, settings: { @@ -691,86 +691,88 @@ ruleTester.run("classnames-order", rule, { `, errors: generateErrors(2), }, - { - code: ` - myTag\` - invalid - sm:w-6 - container - w-12 - flex - lg:w-4 - \`;`, - output: ` - myTag\` - invalid - container - flex - w-12 - sm:w-6 - lg:w-4 - \`;`, - options: [ - { - tags: ["myTag"], - }, - ], - errors: errors, - }, - { - code: ` - const buttonClasses = myTag\` - \${fullWidth ? "w-12" : "w-6"} - container - \${fullWidth ? "sm:w-8" : "sm:w-4"} - lg:w-9 - flex - \${hasError && "bg-red"} - \`;`, - output: ` - const buttonClasses = myTag\` - \${fullWidth ? "w-12" : "w-6"} - container - \${fullWidth ? "sm:w-8" : "sm:w-4"} - flex - lg:w-9 - \${hasError && "bg-red"} - \`;`, - options: [ - { - tags: ["myTag"], - }, - ], - errors: errors, - }, - { - code: ` - const buttonClasses = myTag\` - \${fullWidth ? "w-12" : "w-6"} - flex - container - \${fullWidth ? "sm:w-7" : "sm:w-4"} - lg:py-4 - sm:py-6 - \${hasError && "bg-red"} - \`;`, - output: ` - const buttonClasses = myTag\` - \${fullWidth ? "w-12" : "w-6"} - container - flex - \${fullWidth ? "sm:w-7" : "sm:w-4"} - sm:py-6 - lg:py-4 - \${hasError && "bg-red"} - \`;`, - options: [ - { - tags: ["myTag"], - }, - ], - errors: generateErrors(2), - }, + ...(['myTag', 'myTag.subTag', 'myTag(SomeComponent)'].flatMap(tag => ([ + { + code: ` + ${tag}\` + invalid + sm:w-6 + container + w-12 + flex + lg:w-4 + \`;`, + output: ` + ${tag}\` + invalid + container + flex + w-12 + sm:w-6 + lg:w-4 + \`;`, + options: [ + { + tags: ["myTag"], + }, + ], + errors: errors, + }, + { + code: ` + const buttonClasses = ${tag}\` + \${fullWidth ? "w-12" : "w-6"} + container + \${fullWidth ? "sm:w-8" : "sm:w-4"} + lg:w-9 + flex + \${hasError && "bg-red"} + \`;`, + output: ` + const buttonClasses = ${tag}\` + \${fullWidth ? "w-12" : "w-6"} + container + \${fullWidth ? "sm:w-8" : "sm:w-4"} + flex + lg:w-9 + \${hasError && "bg-red"} + \`;`, + options: [ + { + tags: ["myTag"], + }, + ], + errors: errors, + }, + { + code: ` + const buttonClasses = ${tag}\` + \${fullWidth ? "w-12" : "w-6"} + flex + container + \${fullWidth ? "sm:w-7" : "sm:w-4"} + lg:py-4 + sm:py-6 + \${hasError && "bg-red"} + \`;`, + output: ` + const buttonClasses = ${tag}\` + \${fullWidth ? "w-12" : "w-6"} + container + flex + \${fullWidth ? "sm:w-7" : "sm:w-4"} + sm:py-6 + lg:py-4 + \${hasError && "bg-red"} + \`;`, + options: [ + { + tags: ["myTag"], + }, + ], + errors: generateErrors(2), + }, + ]))), { code: ` classnames([ diff --git a/tests/lib/rules/enforces-negative-arbitrary-values.js b/tests/lib/rules/enforces-negative-arbitrary-values.js index f1433c3..1fd9df2 100644 --- a/tests/lib/rules/enforces-negative-arbitrary-values.js +++ b/tests/lib/rules/enforces-negative-arbitrary-values.js @@ -140,5 +140,14 @@ ruleTester.run("enforces-negative-arbitrary-values", rule, { code: `
support named group/peer syntax
`, errors: generateErrors("group/edit:-inset-[1px]"), }, + ...(['myTag', 'myTag.subTag', 'myTag(SomeComponent)'].map(tag => ({ + code: `${tag}\`-my-[1px] -mx-[1px]\``, + errors: generateErrors("-my-[1px] -mx-[1px]"), + options: [ + { + tags: ["myTag"], + }, + ], + }))), ], }); diff --git a/tests/lib/rules/enforces-shorthand.js b/tests/lib/rules/enforces-shorthand.js index d14368b..110ee3a 100644 --- a/tests/lib/rules/enforces-shorthand.js +++ b/tests/lib/rules/enforces-shorthand.js @@ -701,5 +701,15 @@ ruleTester.run("shorthands", rule, { output: `
New size-* utilities
`, errors: [generateError(["md:h-5", "md:w-5"], "md:size-5")], }, + ...(['myTag', 'myTag.subTag', 'myTag(SomeComponent)'].map(tag => ({ + code: `${tag}\`overflow-hidden text-ellipsis whitespace-nowrap text-white text-xl\``, + output: `${tag}\`truncate text-white text-xl\``, + errors: [generateError(["overflow-hidden", "text-ellipsis", "whitespace-nowrap"], "truncate")], + options: [ + { + tags: ["myTag"], + }, + ], + }))), ], }); diff --git a/tests/lib/rules/migration-from-tailwind-2.js b/tests/lib/rules/migration-from-tailwind-2.js index 9bf133f..0ada3e7 100644 --- a/tests/lib/rules/migration-from-tailwind-2.js +++ b/tests/lib/rules/migration-from-tailwind-2.js @@ -382,5 +382,23 @@ ruleTester.run("migration-from-tailwind-2", rule, { filename: "test.vue", parser: require.resolve("vue-eslint-parser"), }, + ...(['myTag', 'myTag.subTag', 'myTag(SomeComponent)'].map(tag => ({ + code: `${tag}\`flex-grow-0\``, + output: `${tag}\`grow-0\``, + errors: [ + { + messageId: "classnameChanged", + data: { + deprecated: "flex-grow-0", + updated: "grow-0", + }, + }, + ], + options: [ + { + tags: ["myTag"], + }, + ], + }))), ], }); diff --git a/tests/lib/rules/no-arbitrary-value.js b/tests/lib/rules/no-arbitrary-value.js index f564813..870c892 100644 --- a/tests/lib/rules/no-arbitrary-value.js +++ b/tests/lib/rules/no-arbitrary-value.js @@ -160,5 +160,14 @@ ruleTester.run("no-arbitrary-value", rule, { code: `
Dynamic viewport units
`, errors: generateErrors(["min-h-[75dvh]"]), }, + ...(['myTag', 'myTag.subTag', 'myTag(SomeComponent)'].map(tag => ({ + code: `${tag}\`w-[100px]\``, + errors: generateErrors("w-[100px]"), + options: [ + { + tags: ["myTag"], + }, + ], + }))), ], }); diff --git a/tests/lib/rules/no-contradicting-classname.js b/tests/lib/rules/no-contradicting-classname.js index 89adda1..7a04111 100644 --- a/tests/lib/rules/no-contradicting-classname.js +++ b/tests/lib/rules/no-contradicting-classname.js @@ -135,9 +135,9 @@ ruleTester.run("no-contradicting-classname", rule, { `, options: config, }, - { + ...(['myTag', 'myTag.subTag', 'myTag(SomeComponent)'].map(tag => ({ code: ` - myTag\` + ${tag}\` text-white rounded-md py-5 @@ -165,7 +165,7 @@ ruleTester.run("no-contradicting-classname", rule, { tags: ["myTag"], }, ], - }, + }))), { code: `
@@ -432,54 +432,56 @@ ruleTester.run("no-contradicting-classname", rule, { );`, errors: generateErrors(["p-2 p-4", "w-1 w-2", "py-1 py-2", "px-2 px-4"]), }, - { - code: ` - myTag\` - invalid bis - sm:w-6 - w-8 - container - w-12 - flex - lg:w-4 - \`;`, - options: [{ tags: ["myTag"] }], - errors: generateErrors("w-8 w-12"), - }, - { - code: ` - myTag\` - px-2 - px-4 - \${ - !isDisabled && - \` - py-1 - py-2 - \` - } - \${ - isDisabled && - \` - w-1 - w-2 - \` - } - \` - `, - options: [{ tags: ["myTag"] }], - errors: generateErrors(["py-1 py-2", "w-1 w-2", "px-2 px-4"]), - }, - { - code: `myTag\`\${enabled && "px-2 px-0"}\``, - options: [{ tags: ["myTag"] }], - errors: generateErrors("px-2 px-0"), - }, - { - code: `myTag\`\${enabled ? "px-2 px-0" : ""}\``, - options: [{ tags: ["myTag"] }], - errors: generateErrors("px-2 px-0"), - }, + ...(['myTag', 'myTag.subTag', 'myTag(SomeComponent)'].flatMap(tag => [ + { + code: ` + ${tag}\` + invalid bis + sm:w-6 + w-8 + container + w-12 + flex + lg:w-4 + \`;`, + options: [{ tags: ["myTag"] }], + errors: generateErrors("w-8 w-12"), + }, + { + code: ` + ${tag}\` + px-2 + px-4 + \${ + !isDisabled && + \` + py-1 + py-2 + \` + } + \${ + isDisabled && + \` + w-1 + w-2 + \` + } + \` + `, + options: [{ tags: ["myTag"] }], + errors: generateErrors(["py-1 py-2", "w-1 w-2", "px-2 px-4"]), + }, + { + code: `${tag}\`\${enabled && "px-2 px-0"}\``, + options: [{ tags: ["myTag"] }], + errors: generateErrors("px-2 px-0"), + }, + { + code: `${tag}\`\${enabled ? "px-2 px-0" : ""}\``, + options: [{ tags: ["myTag"] }], + errors: generateErrors("px-2 px-0"), + }, + ])), { code: `
diff --git a/tests/lib/rules/no-custom-classname.js b/tests/lib/rules/no-custom-classname.js index 0840cb0..d1db21a 100644 --- a/tests/lib/rules/no-custom-classname.js +++ b/tests/lib/rules/no-custom-classname.js @@ -444,9 +444,9 @@ ruleTester.run("no-custom-classname", rule, { }, ], }, - { + ...(['myTag', 'myTag.subTag', 'myTag(SomeComponent)'].map(tag => ({ code: ` - myTag\` + ${tag}\` sm:w-6 w-8 container @@ -455,7 +455,7 @@ ruleTester.run("no-custom-classname", rule, { lg:w-4 \`;`, options: [{ tags: ["myTag"] }], - }, + }))), { code: `
@@ -1224,53 +1224,55 @@ ruleTester.run("no-custom-classname", rule, { ], errors: generateErrors("dark"), }, - { - code: ` - myTag\` - sm:w-6 - hello - w-8 - container - w-12 - world - flex - lg:w-4 - \`;`, - options: [{ tags: ["myTag"] }], - errors: generateErrors("hello world"), - }, - { - code: ` - myTag\` - px-4 - custom-1 - py-1 - \${ - !isDisabled && - \` - lg:focus:ring-1 - custom-2 - focus:ring-2 - \` - } - \${ - isDisabled && - \` - lg:opacity-25 - custom-3 - opacity-50 - \` - } - \` - `, - options: [{ tags: ["myTag"] }], - errors: generateErrors("custom-2 custom-3 custom-1"), - }, - { - code: `myTag\`custom-1 \${isDisabled ? "custom-2" : "m-4"}\``, - options: [{ tags: ["myTag"] }], - errors: generateErrors("custom-2 custom-1"), - }, + ...(['myTag', 'myTag.subTag', 'myTag(SomeComponent)'].flatMap(tag => ([ + { + code: ` + ${tag}\` + sm:w-6 + hello + w-8 + container + w-12 + world + flex + lg:w-4 + \`;`, + options: [{ tags: ["myTag"] }], + errors: generateErrors("hello world"), + }, + { + code: ` + ${tag}\` + px-4 + custom-1 + py-1 + \${ + !isDisabled && + \` + lg:focus:ring-1 + custom-2 + focus:ring-2 + \` + } + \${ + isDisabled && + \` + lg:opacity-25 + custom-3 + opacity-50 + \` + } + \` + `, + options: [{ tags: ["myTag"] }], + errors: generateErrors("custom-2 custom-3 custom-1"), + }, + { + code: `${tag}\`custom-1 \${isDisabled ? "custom-2" : "m-4"}\``, + options: [{ tags: ["myTag"] }], + errors: generateErrors("custom-2 custom-1"), + }, + ]))), { code: `