UNPKG

eslint-plugin-readable-tailwind

Version:

auto-wraps tailwind classes after a certain print width or class count into multiple lines to improve readability.

323 lines 11.7 kB
import { MatcherType } from "../types/rule.js"; import { getLiteralNodesByMatchers, getObjectPath, isCalleeMatchers, isCalleeName, isCalleeRegex, isInsideConditionalExpressionTest, isInsideLogicalExpressionLeft, isTagMatchers, isTagName, isTagRegex, isVariableMatchers, isVariableName, isVariableRegex, matchesPathPattern } from "../utils/matchers.js"; import { getLiteralsByESNodeAndRegex } from "../utils/regex.js"; import { deduplicateLiterals, getQuotes, getWhitespace, matchesName } from "../utils/utils.js"; export function getLiteralsByESVariableDeclarator(ctx, node, variables) { const literals = variables.reduce((literals, variable) => { if (!node.init) { return literals; } if (!isESVariableSymbol(node.id)) { return literals; } if (isVariableName(variable)) { if (!matchesName(variable, node.id.name)) { return literals; } literals.push(...getLiteralsByESExpression(ctx, [node.init])); } else if (isVariableRegex(variable)) { literals.push(...getLiteralsByESNodeAndRegex(ctx, node, variable)); } else if (isVariableMatchers(variable)) { if (!matchesName(variable[0], node.id.name)) { return literals; } literals.push(...getLiteralsByESMatchers(ctx, node.init, variable[1])); } return literals; }, []); return deduplicateLiterals(literals); } export function getLiteralsByESCallExpression(ctx, node, callees) { const literals = callees.reduce((literals, callee) => { if (!isESCalleeSymbol(node.callee)) { return literals; } if (isCalleeName(callee)) { if (!matchesName(callee, node.callee.name)) { return literals; } literals.push(...getLiteralsByESExpression(ctx, node.arguments)); } else if (isCalleeRegex(callee)) { literals.push(...getLiteralsByESNodeAndRegex(ctx, node, callee)); } else if (isCalleeMatchers(callee)) { if (!matchesName(callee[0], node.callee.name)) { return literals; } literals.push(...getLiteralsByESMatchers(ctx, node, callee[1])); } return literals; }, []); return deduplicateLiterals(literals); } export function getLiteralsByTaggedTemplateExpression(ctx, node, tags) { const literals = tags.reduce((literals, tag) => { if (!isTaggedTemplateSymbol(node.tag)) { return literals; } if (isTagName(tag)) { if (tag !== node.tag.name) { return literals; } literals.push(...getLiteralsByESTemplateLiteral(ctx, node.quasi)); } else if (isTagRegex(tag)) { literals.push(...getLiteralsByESNodeAndRegex(ctx, node, tag)); } else if (isTagMatchers(tag)) { if (tag[0] !== node.tag.name) { return literals; } literals.push(...getLiteralsByESMatchers(ctx, node, tag[1])); } return literals; }, []); return deduplicateLiterals(literals); } export function getLiteralsByESLiteralNode(ctx, node) { if (isESSimpleStringLiteral(node)) { const literal = getStringLiteralByESStringLiteral(ctx, node); return literal ? [literal] : []; } if (isESTemplateLiteral(node)) { return getLiteralsByESTemplateLiteral(ctx, node); } if (isESTemplateElement(node) && hasESNodeParentExtension(node)) { const literal = getLiteralByESTemplateElement(ctx, node); return literal ? [literal] : []; } return []; } export function getLiteralsByESMatchers(ctx, node, matchers) { const matcherFunctions = getESMatcherFunctions(matchers); const literalNodes = getLiteralNodesByMatchers(ctx, node, matcherFunctions); const literals = literalNodes.reduce((literals, literalNode) => { literals.push(...getLiteralsByESLiteralNode(ctx, literalNode)); return literals; }, []); return deduplicateLiterals(literals); } export function getLiteralNodesByRegex(ctx, node, regex) { const sourceCode = ctx.sourceCode.getText(node); const matchedNodes = []; const matches = sourceCode.matchAll(regex); for (const groups of matches) { if (!groups.indices || groups.indices.length < 2) { continue; } for (const [startIndex] of groups.indices.slice(1)) { const literalNode = ctx.sourceCode.getNodeByRangeIndex((node.range?.[0] ?? 0) + startIndex); if (!literalNode) { continue; } matchedNodes.push(literalNode); } } return matchedNodes; } export function getStringLiteralByESStringLiteral(ctx, node) { const raw = node.raw; const content = node.value; if (!raw || !node.loc || !node.range || !node.parent.loc || !node.parent.range) { return; } const quotes = getQuotes(raw); const whitespaces = getWhitespace(content); return { ...quotes, ...whitespaces, content, loc: node.loc, node: node, parent: node.parent, range: node.range, raw, type: "StringLiteral" }; } function getLiteralByESTemplateElement(ctx, node) { const raw = ctx.sourceCode.getText(node); const content = node.value.raw; if (!raw || !node.loc || !node.range || !node.parent.loc || !node.parent.range) { return; } const quotes = getQuotes(raw); const whitespaces = getWhitespace(content); const braces = getBracesByString(ctx, raw); return { ...whitespaces, ...quotes, ...braces, content, loc: node.loc, node: node, parent: node.parent, range: node.range, raw, type: "TemplateLiteral" }; } function getLiteralsByESExpression(ctx, args) { return args.reduce((acc, node) => { if (node.type === "SpreadElement") { return acc; } acc.push(...getLiteralsByESLiteralNode(ctx, node)); return acc; }, []); } export function getLiteralsByESTemplateLiteral(ctx, node) { return node.quasis.map(quasi => { if (!hasESNodeParentExtension(quasi)) { return; } return getLiteralByESTemplateElement(ctx, quasi); }).filter((literal) => literal !== undefined); } export function findParentESTemplateLiteralByESTemplateElement(node) { if (!hasESNodeParentExtension(node)) { return; } if (node.parent.type === "TemplateLiteral") { return node.parent; } return findParentESTemplateLiteralByESTemplateElement(node.parent); } export function isESObjectKey(node) { return (node.parent.type === "Property" && node.parent.parent.type === "ObjectExpression" && node.parent.key === node); } export function isInsideObjectValue(node) { if (!hasESNodeParentExtension(node)) { return false; } // Allow call expressions as object values if (isESCallExpression(node)) { return false; } if (node.parent.type === "Property" && node.parent.parent.type === "ObjectExpression" && node.parent.value === node) { return true; } return isInsideObjectValue(node.parent); } export function isESSimpleStringLiteral(node) { return (node.type === "Literal" && "value" in node && typeof node.value === "string"); } export function isESStringLike(node) { return isESSimpleStringLiteral(node) || isESTemplateElement(node); } export function isESTemplateLiteral(node) { return node.type === "TemplateLiteral"; } export function isESTemplateElement(node) { return node.type === "TemplateElement"; } export function isESNode(node) { return (node !== null && typeof node === "object" && "type" in node); } export function isESCallExpression(node) { return node.type === "CallExpression"; } function isESCalleeSymbol(node) { return node.type === "Identifier" && !!node.parent && isESCallExpression(node.parent); } function isTaggedTemplateExpression(node) { return node.type === "TaggedTemplateExpression"; } function isTaggedTemplateSymbol(node) { return node.type === "Identifier" && !!node.parent && isTaggedTemplateExpression(node.parent); } export function isESVariableDeclarator(node) { return node.type === "VariableDeclarator"; } function isESVariableSymbol(node) { return node.type === "Identifier" && !!node.parent && isESVariableDeclarator(node.parent); } export function hasESNodeParentExtension(node) { return "parent" in node && !!node.parent; } function getBracesByString(ctx, raw) { const closingBraces = raw.startsWith("}") ? "}" : undefined; const openingBraces = raw.endsWith("${") ? "${" : undefined; return { closingBraces, openingBraces }; } function getESMatcherFunctions(matchers) { return matchers.reduce((matcherFunctions, matcher) => { switch (matcher.match) { case MatcherType.String: { matcherFunctions.push(node => { if (isInsideConditionalExpressionTest(node)) { return false; } if (isInsideLogicalExpressionLeft(node)) { return false; } if (!hasESNodeParentExtension(node)) { return false; } return (!isESObjectKey(node) && !isInsideObjectValue(node) && isESStringLike(node)); }); break; } case MatcherType.ObjectKey: { matcherFunctions.push(node => { if (isInsideConditionalExpressionTest(node)) { return false; } if (isInsideLogicalExpressionLeft(node)) { return false; } if (!hasESNodeParentExtension(node)) { return false; } if (!isESObjectKey(node)) { return false; } const path = getObjectPath(node); return path && matcher.pathPattern ? matchesPathPattern(path, matcher.pathPattern) : true; }); break; } case MatcherType.ObjectValue: { matcherFunctions.push(node => { if (isInsideConditionalExpressionTest(node)) { return false; } if (isInsideLogicalExpressionLeft(node)) { return false; } if (!hasESNodeParentExtension(node)) { return false; } if (isESObjectKey(node)) { return false; } const path = getObjectPath(node); const matchesPattern = path !== undefined && matcher.pathPattern ? matchesPathPattern(path, matcher.pathPattern) : true; return isInsideObjectValue(node) && isESStringLike(node) && matchesPattern; }); break; } } return matcherFunctions; }, []); } //# sourceMappingURL=es.js.map