exit(path, { opts: { tdz = false } = {} }) {
          const consequent = path.get("consequent");
          const alternate = path.get("alternate");
          const test = path.get("test");

          const evalResult = evaluate(test, { tdz });
          const isPure = test.isPure();

          const replacements = [];
          if (evalResult.confident && !isPure && test.isSequenceExpression()) {
            replacements.push(
              t.expressionStatement(extractSequenceImpure(test))
            );
          }

          // we can check if a test will be truthy 100% and if so then we can inline
          // the consequent and completely ignore the alternate
          //
          //   if (true) { foo; } -> { foo; }
          //   if ("foo") { foo; } -> { foo; }
          //
          if (evalResult.confident && evalResult.value) {
            path.replaceWithMultiple([
              ...replacements,
              ...toStatements(consequent),
              ...extractVars(alternate)
            ]);
            return;
          }

          // we can check if a test will be falsy 100% and if so we can inline the
          // alternate if there is one and completely remove the consequent
          //
          //   if ("") { bar; } else { foo; } -> { foo; }
          //   if ("") { bar; } ->
          //
          if (evalResult.confident && !evalResult.value) {
            if (alternate.node) {
              path.replaceWithMultiple([
                ...replacements,
                ...toStatements(alternate),
                ...extractVars(consequent)
              ]);
              return;
            } else {
              path.replaceWithMultiple([
                ...replacements,
                ...extractVars(consequent)
              ]);
            }
          }

          // remove alternate blocks that are empty
          //
          //   if (foo) { foo; } else {} -> if (foo) { foo; }
          //
          if (alternate.isBlockStatement() && !alternate.node.body.length) {
            alternate.remove();
            // For if-statements babel-traverse replaces with an empty block
            path.node.alternate = null;
          }

          // if the consequent block is empty turn alternate blocks into a consequent
          // and flip the test
          //
          //   if (foo) {} else { bar; } -> if (!foo) { bar; }
          //
          if (
            consequent.isBlockStatement() &&
            !consequent.node.body.length &&
            alternate.isBlockStatement() &&
            alternate.node.body.length
          ) {
            consequent.replaceWith(alternate.node);
            alternate.remove();
            // For if-statements babel-traverse replaces with an empty block
            path.node.alternate = null;
            test.replaceWith(t.unaryExpression("!", test.node, true));
          }
        }
Use exit handler to traverse in a dfs post-order fashion
to remove use strict