| /** | 
|  * @fileoverview Rule to flag no-unneeded-ternary | 
|  * @author Gyandeep Singh | 
|  */ | 
|   | 
| "use strict"; | 
|   | 
| const astUtils = require("./utils/ast-utils"); | 
|   | 
| // Operators that always result in a boolean value | 
| const BOOLEAN_OPERATORS = new Set(["==", "===", "!=", "!==", ">", ">=", "<", "<=", "in", "instanceof"]); | 
| const OPERATOR_INVERSES = { | 
|     "==": "!=", | 
|     "!=": "==", | 
|     "===": "!==", | 
|     "!==": "===" | 
|   | 
|     // Operators like < and >= are not true inverses, since both will return false with NaN. | 
| }; | 
| const OR_PRECEDENCE = astUtils.getPrecedence({ type: "LogicalExpression", operator: "||" }); | 
|   | 
| //------------------------------------------------------------------------------ | 
| // Rule Definition | 
| //------------------------------------------------------------------------------ | 
|   | 
| module.exports = { | 
|     meta: { | 
|         type: "suggestion", | 
|   | 
|         docs: { | 
|             description: "disallow ternary operators when simpler alternatives exist", | 
|             category: "Stylistic Issues", | 
|             recommended: false, | 
|             url: "https://eslint.org/docs/rules/no-unneeded-ternary" | 
|         }, | 
|   | 
|         schema: [ | 
|             { | 
|                 type: "object", | 
|                 properties: { | 
|                     defaultAssignment: { | 
|                         type: "boolean", | 
|                         default: true | 
|                     } | 
|                 }, | 
|                 additionalProperties: false | 
|             } | 
|         ], | 
|   | 
|         fixable: "code" | 
|     }, | 
|   | 
|     create(context) { | 
|         const options = context.options[0] || {}; | 
|         const defaultAssignment = options.defaultAssignment !== false; | 
|         const sourceCode = context.getSourceCode(); | 
|   | 
|         /** | 
|          * Test if the node is a boolean literal | 
|          * @param {ASTNode} node - The node to report. | 
|          * @returns {boolean} True if the its a boolean literal | 
|          * @private | 
|          */ | 
|         function isBooleanLiteral(node) { | 
|             return node.type === "Literal" && typeof node.value === "boolean"; | 
|         } | 
|   | 
|         /** | 
|          * Creates an expression that represents the boolean inverse of the expression represented by the original node | 
|          * @param {ASTNode} node A node representing an expression | 
|          * @returns {string} A string representing an inverted expression | 
|          */ | 
|         function invertExpression(node) { | 
|             if (node.type === "BinaryExpression" && Object.prototype.hasOwnProperty.call(OPERATOR_INVERSES, node.operator)) { | 
|                 const operatorToken = sourceCode.getFirstTokenBetween( | 
|                     node.left, | 
|                     node.right, | 
|                     token => token.value === node.operator | 
|                 ); | 
|                 const text = sourceCode.getText(); | 
|   | 
|                 return text.slice(node.range[0], | 
|                     operatorToken.range[0]) + OPERATOR_INVERSES[node.operator] + text.slice(operatorToken.range[1], node.range[1]); | 
|             } | 
|   | 
|             if (astUtils.getPrecedence(node) < astUtils.getPrecedence({ type: "UnaryExpression" })) { | 
|                 return `!(${astUtils.getParenthesisedText(sourceCode, node)})`; | 
|             } | 
|             return `!${astUtils.getParenthesisedText(sourceCode, node)}`; | 
|         } | 
|   | 
|         /** | 
|          * Tests if a given node always evaluates to a boolean value | 
|          * @param {ASTNode} node - An expression node | 
|          * @returns {boolean} True if it is determined that the node will always evaluate to a boolean value | 
|          */ | 
|         function isBooleanExpression(node) { | 
|             return node.type === "BinaryExpression" && BOOLEAN_OPERATORS.has(node.operator) || | 
|                 node.type === "UnaryExpression" && node.operator === "!"; | 
|         } | 
|   | 
|         /** | 
|          * Test if the node matches the pattern id ? id : expression | 
|          * @param {ASTNode} node - The ConditionalExpression to check. | 
|          * @returns {boolean} True if the pattern is matched, and false otherwise | 
|          * @private | 
|          */ | 
|         function matchesDefaultAssignment(node) { | 
|             return node.test.type === "Identifier" && | 
|                    node.consequent.type === "Identifier" && | 
|                    node.test.name === node.consequent.name; | 
|         } | 
|   | 
|         return { | 
|   | 
|             ConditionalExpression(node) { | 
|                 if (isBooleanLiteral(node.alternate) && isBooleanLiteral(node.consequent)) { | 
|                     context.report({ | 
|                         node, | 
|                         loc: node.consequent.loc.start, | 
|                         message: "Unnecessary use of boolean literals in conditional expression.", | 
|                         fix(fixer) { | 
|                             if (node.consequent.value === node.alternate.value) { | 
|   | 
|                                 // Replace `foo ? true : true` with just `true`, but don't replace `foo() ? true : true` | 
|                                 return node.test.type === "Identifier" ? fixer.replaceText(node, node.consequent.value.toString()) : null; | 
|                             } | 
|                             if (node.alternate.value) { | 
|   | 
|                                 // Replace `foo() ? false : true` with `!(foo())` | 
|                                 return fixer.replaceText(node, invertExpression(node.test)); | 
|                             } | 
|   | 
|                             // Replace `foo ? true : false` with `foo` if `foo` is guaranteed to be a boolean, or `!!foo` otherwise. | 
|   | 
|                             return fixer.replaceText(node, isBooleanExpression(node.test) ? astUtils.getParenthesisedText(sourceCode, node.test) : `!${invertExpression(node.test)}`); | 
|                         } | 
|                     }); | 
|                 } else if (!defaultAssignment && matchesDefaultAssignment(node)) { | 
|                     context.report({ | 
|                         node, | 
|                         loc: node.consequent.loc.start, | 
|                         message: "Unnecessary use of conditional expression for default assignment.", | 
|                         fix: fixer => { | 
|                             const shouldParenthesizeAlternate = ( | 
|                                 astUtils.getPrecedence(node.alternate) < OR_PRECEDENCE && | 
|                                 !astUtils.isParenthesised(sourceCode, node.alternate) | 
|                             ); | 
|                             const alternateText = shouldParenthesizeAlternate | 
|                                 ? `(${sourceCode.getText(node.alternate)})` | 
|                                 : astUtils.getParenthesisedText(sourceCode, node.alternate); | 
|                             const testText = astUtils.getParenthesisedText(sourceCode, node.test); | 
|   | 
|                             return fixer.replaceText(node, `${testText} || ${alternateText}`); | 
|                         } | 
|                     }); | 
|                 } | 
|             } | 
|         }; | 
|     } | 
| }; |