"use strict"; const matchValue = require("match-value"); const operations = require("../operations"); const typeOf = require("../type-of"); const NoChange = require("./util/no-change"); // FIXME: Generalize to all predicate lists? function createHandler(type) { let subItemProperty = matchValue(type, { notCondition: "condition", notExpression: "expression" }); return function flattenNotPredicates(expression) { // Flattens multiple levels of like-typed not(...) wrappers, ending up with a logically equivalent subtree // `notCondition(condition)` -> `notCondition(condition)` // `notCondition(notCondition(condition))` -> `condition` // `notCondition(notCondition(notCondition(condition)))` -> `notCondition(condition)` // etc. let notLevels = 0; let currentItem = expression; while(typeOf(currentItem) === type) { notLevels += 1; currentItem = currentItem[subItemProperty]; } if (notLevels === 1) { return NoChange; } else { let hasNot = (notLevels % 2) === 1; if (hasNot) { return operations.not(currentItem); } else { return currentItem; } } }; } module.exports = { name: "flatten-not-predicates", category: [ "readability" ], visitors: { notExpression: createHandler("notExpression"), notCondition: createHandler("notCondition") } };