eslint-plugin-tailwindcss
Advanced tools
Comparing version 3.8.3 to 3.9.0-beta.0
@@ -172,2 +172,16 @@ /** | ||
const templateVisitor = { | ||
CallExpression: function (node) { | ||
if (callees.findIndex((name) => node.callee.name === name) === -1) { | ||
return; | ||
} | ||
node.arguments.forEach((arg) => { | ||
astUtil.parseNodeRecursive(node, arg, parseForCustomClassNames); | ||
}); | ||
}, | ||
// TaggedTemplateExpression: function (node) { | ||
// if (!tags.includes(node.tag.name)) { | ||
// return; | ||
// } | ||
// astUtil.parseNodeRecursive(node, node.quasi, parseForCustomClassNames); | ||
// }, | ||
VAttribute: function (node) { | ||
@@ -177,3 +191,15 @@ if (!astUtil.isValidVueAttribute(node)) { | ||
} | ||
astUtil.parseNodeRecursive(node, null, parseForCustomClassNames); | ||
if (astUtil.isVLiteralValue(node)) { | ||
astUtil.parseNodeRecursive(node, null, parseForCustomClassNames); | ||
} | ||
if (astUtil.isArrayExpression(node)) { | ||
node.value.expression.elements.forEach((arg) => { | ||
astUtil.parseNodeRecursive(node, arg, parseForCustomClassNames); | ||
}); | ||
} | ||
if (astUtil.isObjectExpression(node)) { | ||
node.value.expression.properties.forEach((prop) => { | ||
astUtil.parseNodeRecursive(node, prop, parseForCustomClassNames); | ||
}); | ||
} | ||
}, | ||
@@ -180,0 +206,0 @@ }; |
@@ -42,3 +42,15 @@ /** | ||
function isVueClassAttribute(node) { | ||
return node.key && /^class$/.test(node.key.name); | ||
switch (true) { | ||
case node.key && /^class$/.test(node.key.name): | ||
// class="vue-classes-as-litteral" | ||
return true; | ||
break; | ||
case node.key && node.key.name.name && /^bind$/.test(node.key.name.name) && /^class$/.test(node.key.argument.name): | ||
// v-bind:class="vue-classes-as-bind" | ||
// :class="vue-classes-as-bind" | ||
return true; | ||
break; | ||
default: | ||
return false; | ||
} | ||
} | ||
@@ -52,7 +64,42 @@ | ||
*/ | ||
function isVueLiteralAttributeValue(node) { | ||
if (node.value && node.value.type === 'VLiteral') { | ||
return true; | ||
function isVLiteralValue(node) { | ||
return node.value && node.value.type === 'VLiteral'; | ||
} | ||
/** | ||
* Find out if node's value attribute is an ArrayExpression | ||
* | ||
* @param {ASTNode} node The AST node being checked | ||
* @returns {Boolean} | ||
*/ | ||
function isArrayExpression(node) { | ||
return node.value && node.value.type === 'VExpressionContainer' && node.value.expression.type === 'ArrayExpression'; | ||
} | ||
/** | ||
* Find out if node's value attribute is an ObjectExpression | ||
* | ||
* @param {ASTNode} node The AST node being checked | ||
* @returns {Boolean} | ||
*/ | ||
function isObjectExpression(node) { | ||
return node.value && node.value.type === 'VExpressionContainer' && node.value.expression.type === 'ObjectExpression'; | ||
} | ||
/** | ||
* Find out if node's value attribute is just simple text | ||
* | ||
* @param {ASTNode} node The AST node being checked | ||
* @returns {Boolean} | ||
*/ | ||
function isVueValidAttributeValue(node) { | ||
switch (true) { | ||
case isVLiteralValue(node): // Simple string | ||
case isArrayExpression(node): // ['tw-unknown-class'] | ||
case isObjectExpression(node): // {'tw-unknown-class': true} | ||
return true; | ||
break; | ||
default: | ||
return false; | ||
} | ||
return false; | ||
} | ||
@@ -113,3 +160,3 @@ | ||
} | ||
if (!isVueLiteralAttributeValue(node)) { | ||
if (!isVueValidAttributeValue(node)) { | ||
// No support for dynamic or conditional classnames | ||
@@ -140,2 +187,12 @@ return false; | ||
return node.value.expression.value; | ||
case 'VExpressionContainer': | ||
switch (node.value.expression.type) { | ||
case 'ArrayExpression': | ||
return node.value.expression.elements; | ||
break; | ||
case 'ObjectExpression': | ||
return node.value.expression.properties; | ||
break; | ||
} | ||
return node.value.expression.value; | ||
default: | ||
@@ -170,4 +227,4 @@ return node.value.value; | ||
* | ||
* @param {ASTNode} arg The AST node child argument being checked | ||
* @param {ASTNode} node The current root node being parsed by eslint | ||
* @param {ASTNode} rootNode The current root node being parsed by eslint | ||
* @param {ASTNode} childNode The AST node child argument being checked | ||
* @param {Function} cb The callback function | ||
@@ -178,7 +235,8 @@ * @param {Boolean} skipConditional Optional, indicate distinct parsing for conditional nodes | ||
*/ | ||
function parseNodeRecursive(node, arg, cb, skipConditional = false, isolate = false) { | ||
function parseNodeRecursive(rootNode, childNode, cb, skipConditional = false, isolate = false) { | ||
// TODO allow vue non litteral | ||
let originalClassNamesValue; | ||
let classNames; | ||
if (arg === null) { | ||
originalClassNamesValue = extractValueFromNode(node); | ||
if (childNode === null) { | ||
originalClassNamesValue = extractValueFromNode(rootNode); | ||
({ classNames } = extractClassnamesFromValue(originalClassNamesValue)); | ||
@@ -190,4 +248,4 @@ classNames = removeDuplicatesFromArray(classNames); | ||
} | ||
cb(classNames, node); | ||
} else if (arg === undefined) { | ||
cb(classNames, rootNode); | ||
} else if (childNode === undefined) { | ||
// Ignore invalid child candidates (probably inside complex TemplateLiteral) | ||
@@ -198,29 +256,29 @@ return; | ||
let trim = false; | ||
switch (arg.type) { | ||
switch (childNode.type) { | ||
case 'TemplateLiteral': | ||
arg.expressions.forEach((exp) => { | ||
parseNodeRecursive(node, exp, cb, skipConditional, forceIsolation); | ||
childNode.expressions.forEach((exp) => { | ||
parseNodeRecursive(rootNode, exp, cb, skipConditional, forceIsolation); | ||
}); | ||
arg.quasis.forEach((quasis) => { | ||
parseNodeRecursive(node, quasis, cb, skipConditional, isolate); | ||
childNode.quasis.forEach((quasis) => { | ||
parseNodeRecursive(rootNode, quasis, cb, skipConditional, isolate); | ||
}); | ||
return; | ||
case 'ConditionalExpression': | ||
parseNodeRecursive(node, arg.consequent, cb, skipConditional, forceIsolation); | ||
parseNodeRecursive(node, arg.alternate, cb, skipConditional, forceIsolation); | ||
parseNodeRecursive(rootNode, childNode.consequent, cb, skipConditional, forceIsolation); | ||
parseNodeRecursive(rootNode, childNode.alternate, cb, skipConditional, forceIsolation); | ||
return; | ||
case 'LogicalExpression': | ||
parseNodeRecursive(node, arg.right, cb, skipConditional, forceIsolation); | ||
parseNodeRecursive(rootNode, childNode.right, cb, skipConditional, forceIsolation); | ||
return; | ||
case 'ArrayExpression': | ||
arg.elements.forEach((el) => { | ||
parseNodeRecursive(node, el, cb, skipConditional, forceIsolation); | ||
childNode.elements.forEach((el) => { | ||
parseNodeRecursive(rootNode, el, cb, skipConditional, forceIsolation); | ||
}); | ||
return; | ||
case 'ObjectExpression': | ||
arg.properties.forEach((prop) => { | ||
const isUsedByClassNamesPlugin = node.callee && node.callee.name === 'classnames'; | ||
childNode.properties.forEach((prop) => { | ||
const isUsedByClassNamesPlugin = rootNode.callee && rootNode.callee.name === 'classnames'; | ||
parseNodeRecursive( | ||
node, | ||
rootNode, | ||
isUsedByClassNamesPlugin ? prop.key : prop.value, | ||
@@ -233,8 +291,11 @@ cb, | ||
return; | ||
case 'Property': | ||
parseNodeRecursive(rootNode, childNode.key, cb, skipConditional, forceIsolation); | ||
return; | ||
case 'Literal': | ||
trim = true; | ||
originalClassNamesValue = arg.value; | ||
originalClassNamesValue = childNode.value; | ||
break; | ||
case 'TemplateElement': | ||
originalClassNamesValue = arg.value.raw; | ||
originalClassNamesValue = childNode.value.raw; | ||
break; | ||
@@ -248,3 +309,3 @@ } | ||
} | ||
const targetNode = isolate ? null : node; | ||
const targetNode = isolate ? null : rootNode; | ||
cb(classNames, targetNode); | ||
@@ -284,4 +345,7 @@ } | ||
isLiteralAttributeValue, | ||
isArrayExpression, | ||
isObjectExpression, | ||
isValidJSXAttribute, | ||
isValidVueAttribute, | ||
isVLiteralValue, | ||
parseNodeRecursive, | ||
@@ -288,0 +352,0 @@ getTemplateElementPrefix, |
{ | ||
"name": "eslint-plugin-tailwindcss", | ||
"version": "3.8.3", | ||
"version": "3.9.0-beta.0", | ||
"description": "Rules enforcing best practices while using Tailwind CSS", | ||
@@ -21,2 +21,3 @@ "keywords": [ | ||
"scripts": { | ||
"wip": "mocha tests/lib/rules/wip.js", | ||
"test": "mocha tests --recursive" | ||
@@ -23,0 +24,0 @@ }, |
@@ -37,3 +37,3 @@ # eslint-plugin-tailwindcss | ||
| **Current Sponsors** <br /> Any amount is appreciated. | <a href="https://github.com/acewf" target="_blank"><img src="https://avatars.githubusercontent.com/u/4835572?s=150&v=4" width="75" height="75" style="border-radius:100%;" alt="@acewf"></a> <a href="https://github.com/charkour" target="_blank"><img src="https://avatars.githubusercontent.com/u/33156025?s=150&v=4" width="75" height="75" style="border-radius:100%;" alt="@charkour"></a> <a href="https://github.com/dailydotdev" target="_blank"><img class="avatar" src="https://avatars.githubusercontent.com/u/41463883?s=150&v=4" width="75" height="75" style="border-radius:100%;" alt="@dailydotdev"></a> | | ||
| **Past sponsors** <br /> Even if this is just a one-time thing. <br /> [Become a backer](https://github.com/sponsors/francoismassart?frequency=one-time) | <a href="https://github.com/mongolyy" target="_blank"><img src="https://avatars.githubusercontent.com/u/10972787?s=100&v=4" width="50" height="50" style="border-radius:100%;" alt="@mongolyy"></a> <a href="https://github.com/t3dotgg" target="_blank"><img src="https://avatars.githubusercontent.com/u/6751787?s=100&v=4" width="50" height="50" style="border-radius:100%;" alt="@t3dotgg"></a> | | ||
| **Past sponsors** <br /> Even if this is just a one-time thing. <br /> [Become a backer](https://github.com/sponsors/francoismassart?frequency=one-time) | <a href="https://github.com/aniravi24" target="_blank"><img src="https://avatars.githubusercontent.com/u/5902976?s=100&v=4" width="50" height="50" style="border-radius:100%;" alt="@aniravi24"></a> <a href="https://github.com/mongolyy" target="_blank"><img src="https://avatars.githubusercontent.com/u/10972787?s=100&v=4" width="50" height="50" style="border-radius:100%;" alt="@mongolyy"></a> <a href="https://github.com/t3dotgg" target="_blank"><img src="https://avatars.githubusercontent.com/u/6751787?s=100&v=4" width="50" height="50" style="border-radius:100%;" alt="@t3dotgg"></a> | | ||
| **Contributors** <br /> This project can evolve thanks to all the people who contribute. <br /> You are welcome to [contribute](CONTRIBUTING.md) to this project by reporting issues, feature requests or even opening Pull Requests. | <a href="https://github.com/francoismassart/eslint-plugin-tailwindcss/graphs/contributors"><img src="https://contrib.rocks/image?repo=francoismassart/eslint-plugin-tailwindcss&width=300&columns=4" /></a> | | ||
@@ -40,0 +40,0 @@ | **Supporters** <br /> Talk about the plugin on your social networks | <a href="https://twitter.com/search?q=eslint-plugin-tailwindcss&src=recent_search_click" target="_blank">eslint-plugin-tailwindcss on Twitter</a> | |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
165148
4459
1