src/language-js/printer-estree.js/formatTernaryOperator
function formatTernaryOperator(path, options, print, operatorOptions) {
  const n = path.getValue();
  const parts = [];
  const operatorOpts = Object.assign(
    {
      beforeParts: () => [""],
      afterParts: () => [""],
      shouldCheckJsx: true,
      operatorName: "ConditionalExpression",
      consequentNode: "consequent",
      alternateNode: "alternate",
      testNode: "test"
    },
    operatorOptions || {}
  );

  // We print a ConditionalExpression in either "JSX mode" or "normal mode".
  // See tests/jsx/conditional-expression.js for more info.
  let jsxMode = false;
  const parent = path.getParentNode();
  let forceNoIndent = parent.type === operatorOpts.operatorName;

  // Find the outermost non-ConditionalExpression parent, and the outermost
  // ConditionalExpression parent. We'll use these to determine if we should
  // print in JSX mode.
  let currentParent;
  let previousParent;
  let i = 0;
  do {
    previousParent = currentParent || n;
    currentParent = path.getParentNode(i);
    i++;
  } while (currentParent && currentParent.type === operatorOpts.operatorName);
  const firstNonConditionalParent = currentParent || parent;
  const lastConditionalParent = previousParent;

  if (
    (operatorOpts.shouldCheckJsx && isJSXNode(n[operatorOpts.testNode])) ||
    isJSXNode(n[operatorOpts.consequentNode]) ||
    isJSXNode(n[operatorOpts.alternateNode]) ||
    conditionalExpressionChainContainsJSX(lastConditionalParent)
  ) {
    jsxMode = true;
    forceNoIndent = true;

    // Even though they don't need parens, we wrap (almost) everything in
    // parens when using ?: within JSX, because the parens are analogous to
    // curly braces in an if statement.
    const wrap = doc =>
      concat([
        ifBreak("(", ""),
        indent(concat([softline, doc])),
        softline,
        ifBreak(")", "")
      ]);

    // The only things we don't wrap are:
    // * Nested conditional expressions in alternates
    // * null
    const isNull = node =>
      node.type === "NullLiteral" ||
      (node.type === "Literal" && node.value === null);

    parts.push(
      " ? ",
      isNull(n[operatorOpts.consequentNode])
        ? path.call(print, operatorOpts.consequentNode)
        : wrap(path.call(print, operatorOpts.consequentNode)),
      " : ",
      n[operatorOpts.alternateNode].type === operatorOpts.operatorName ||
      isNull(n[operatorOpts.alternateNode])
        ? path.call(print, operatorOpts.alternateNode)
        : wrap(path.call(print, operatorOpts.alternateNode))
    );
  } else {
    // normal mode
    const part = concat([
      line,
      "? ",
      n[operatorOpts.consequentNode].type === operatorOpts.operatorName
        ? ifBreak("", "(")
        : "",
      align(2, path.call(print, operatorOpts.consequentNode)),
      n[operatorOpts.consequentNode].type === operatorOpts.operatorName
        ? ifBreak("", ")")
        : "",
      line,
      ": ",
      align(2, path.call(print, operatorOpts.alternateNode))
    ]);
    parts.push(
      parent.type === operatorOpts.operatorName
        ? options.useTabs
          ? dedent(indent(part))
          : align(Math.max(0, options.tabWidth - 2), part)
        : part
    );
  }

  // In JSX mode, we want a whole chain of ConditionalExpressions to all
  // break if any of them break. That means we should only group around the
  // outer-most ConditionalExpression.
  const maybeGroup = doc =>
    jsxMode
      ? parent === firstNonConditionalParent ? group(doc) : doc
      : group(doc); // Always group in normal mode.

  // Break the closing paren to keep the chain right after it:
  // (a
  //   ? b
  //   : c
  // ).call()
  const breakClosingParen =
    !jsxMode && parent.type === "MemberExpression" && !parent.computed;

  return maybeGroup(
    concat(
      [].concat(
        operatorOpts.beforeParts(),
        forceNoIndent ? concat(parts) : indent(concat(parts)),
        operatorOpts.afterParts(breakClosingParen)
      )
    )
  );
}