UNPKG

eslint-plugin-nommon

Version:
187 lines (159 loc) 7.39 kB
const END_COMMA = /\.$/u; const END_ROUND_BRACKET = /\)$/u; /** * Returns true if node is static string * @param {ASTNode} node The AST node to check * @returns {boolean} true if node is Literal or TemplateLiteral without expressions */ function isNodeStaticString(node) { return node.type === "Literal" || ( node.type === "TemplateLiteral" && node.expressions.length === 0 ); } /** * Returns true if node is static string or concatenation of static strings. * @param {ASTNode} node The AST node to check * @returns {boolean} Check result */ function isNodeHasOnlyStringConcatenation(node) { if (isNodeStaticString(node)) { return true; } return ( node.type === "BinaryExpression" && isNodeHasOnlyStringConcatenation(node.left) && node.operator === "+" && isNodeHasOnlyStringConcatenation(node.right) ); } // eslint-disable-next-line jsdoc/require-jsdoc -- desc function reportError(context, node, obj) { context.report(Object.assign({ message: "Only static no.jpath allowed", node }, obj)); } module.exports = { meta: { docs: { description: "Forbid hanging hyphens" }, schema: [{ type: "object", properties: { hyphens: { type: "array" } } }], fixable: true }, create(context) { return { CallExpression(node) { // accept only obj.prop() if (node.callee.type !== "MemberExpression") { return; } // accept only no.prop() if (node.callee.object.name !== "no") { return; } // accept only no.jpath() if (node.callee.property.name !== "jpath") { return; } const firstArgument = node.arguments[0]; // no.jpath('.path', data) - VALID // no.jpath(`.path`, data) - VALID // no.jpath('.foo' + '.bar', data) - VALID if (isNodeHasOnlyStringConcatenation(firstArgument)) { return; } if (firstArgument.type === "TemplateLiteral") { // no.jpath(`.foo.${ bar }`, data) if (firstArgument.expressions.every(item => item.type === "Identifier" || item.type === "MemberExpression")) { const firstQuasis = firstArgument.quasis[0]; // no.jpath(`.${ foo }`, data) if (firstQuasis && firstQuasis.value.raw === ".") { reportError(context, node); return; } reportError(context, node, { fix(fixer) { const sourceCode = context.getSourceCode(); let replaceText = sourceCode.getText(node); const varsToObject = []; const { expressions } = firstArgument; for (let i = 0; i < expressions.length; i++) { const exressionNode = expressions[i]; let jpathVariableName; let exressionName; if (exressionNode.type === "Identifier") { jpathVariableName = exressionNode.name; exressionName = exressionNode.name; varsToObject.push(exressionNode.name); } else { jpathVariableName = `jpathVariable${i}`; exressionName = sourceCode.getText(exressionNode); varsToObject.push(`${jpathVariableName}: ${exressionName}`); } const nextReplaceText = replaceText // eslint-disable-next-line require-unicode-regexp -- desc .replace(new RegExp(`\\.\\\${\\s*${exressionName}\\s*}`), () => `[${jpathVariableName}]`) // eslint-disable-next-line require-unicode-regexp -- desc .replace(new RegExp(`\\[\\s*\\\${\\s*${exressionName}\\s*}\\s*]`), () => `[${jpathVariableName}]`) // eslint-disable-next-line require-unicode-regexp -- desc .replace(new RegExp(`"\\\${\\s*${exressionName}\\s*}"`), () => jpathVariableName); // I can't fix its if (replaceText === nextReplaceText) { return null; } replaceText = nextReplaceText; } replaceText = replaceText .replace( END_ROUND_BRACKET, `, { ${varsToObject.join(", ")} })` ); return fixer.replaceText(node, replaceText); } }); return; } } // no.jpath('.foo.' + bar, data) if ( firstArgument.type === "BinaryExpression" && firstArgument.left.type === "Literal" && firstArgument.left.value.endsWith(".") && firstArgument.operator === "+" && firstArgument.right.type === "Identifier" ) { reportError(context, node, { fix(fixer) { const sourceCode = context.getSourceCode().getText(node); const stringValue = firstArgument.left.value; const variableValue = firstArgument.right.name; // no.jpath('.' + foo, data) if (stringValue === ".") { return null; } const replaceText = sourceCode .replace(` + ${variableValue}`, "") .replace( stringValue, stringValue.replace(END_COMMA, `[${variableValue}]`) ) .replace( END_ROUND_BRACKET, `, { ${variableValue} })` ); return fixer.replaceText(node, replaceText); } }); return; } reportError(context, node); } }; } };