UNPKG

eslint-plugin-de-morgan

Version:

ESLint plugin for transforming negated boolean expressions via De Morgan’s laws

85 lines (84 loc) 2.64 kB
import { findOutermostParenthesizedNode } from './find-outermost-parenthesized-node.js' /** * Determines if a logical expression is "pure" - meaning it doesn't mix * different logical operators (&& and ||) at the same nesting level within its * outermost parentheses. * * Examples: * * - `!(a && b)` → true (no mixed operators) * - `((a && b) || c)` → true (operators at different nesting levels) * - `(a && b || c)` → false (mixed operators at same level). * * The function traverses up the AST to find the outermost parenthesized * expression, then analyzes the logical operators within that scope. * * @param node - The AST node to analyze. * @param context - ESLint rule context, used to get source code. * @returns True if the expression doesn't mix operators at the top level. */ function isPureGroup(node, context) { let outermostNode = findOutermostParenthesizedNode( node, context.sourceCode.getText(), ) return !hasMixedOperators( getCodeInsideParentheses(context.sourceCode.getText(outermostNode)), ) } /** * Analyzes the given code string (which is assumed to have no outer * parentheses) and determines if, at the top level (outside of any nested * groups), the logical operators are uniform. In other words, if both `&&` and * `||` are found at the top level, it returns true indicating a mix. * * @param code - The code string to analyze. * @returns True if a mix of `&&` and `||` is found at the top level, false * otherwise. */ function hasMixedOperators(code) { let depth = 0 let operatorFound = null for (let i = 0; i < code.length; i++) { let char = code[i] if (char === '(') { depth++ continue } if (char === ')') { depth-- continue } if (depth !== 0) { continue } let twoChars = code.slice(i, i + 2) if (twoChars === '&&' || twoChars === '||') { if (operatorFound === null) { operatorFound = twoChars } else if (operatorFound !== twoChars) { return true } i++ } } return false } /** * Extracts the inner code from a code string that is wrapped in parentheses. If * the code starts with `!(`, the function removes the leading `!(` and the * final `)`. If it starts with `(` it removes only the outer parentheses. * * @param code - The code string to process. * @returns The inner code, with the outermost parentheses removed. */ function getCodeInsideParentheses(code) { if (code.startsWith('!(')) { return code.slice(2, -1) } if (code.startsWith('(')) { return code.slice(1, -1) } return code } export { isPureGroup }