src/language-js/print/ternary.js/wrap
function printTernaryOperator(path, options, print, operatorOptions) {
  const node = path.getValue();
  const consequentNode = node[operatorOptions.consequentNodePropertyName];
  const alternateNode = node[operatorOptions.alternateNodePropertyName];
  const parts = [];

  // 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();
  const isParentTest =
    parent.type === operatorOptions.conditionalNodeType &&
    operatorOptions.testNodePropertyNames.some((prop) => parent[prop] === node);
  let forceNoIndent =
    parent.type === operatorOptions.conditionalNodeType && !isParentTest;

  // 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 || node;
    currentParent = path.getParentNode(i);
    i++;
  } while (
    currentParent &&
    currentParent.type === operatorOptions.conditionalNodeType &&
    operatorOptions.testNodePropertyNames.every(
      (prop) => currentParent[prop] !== previousParent
    )
  );
  const firstNonConditionalParent = currentParent || parent;
  const lastConditionalParent = previousParent;

  if (
    operatorOptions.shouldCheckJsx &&
    (isJSXNode(node[operatorOptions.testNodePropertyNames[0]]) ||
      isJSXNode(consequentNode) ||
      isJSXNode(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
    // * undefined
    const isNil = (node) =>
      node.type === "NullLiteral" ||
      (node.type === "Literal" && node.value === null) ||
      (node.type === "Identifier" && node.name === "undefined");

    parts.push(
      " ? ",
      isNil(consequentNode)
        ? path.call(print, operatorOptions.consequentNodePropertyName)
        : wrap(path.call(print, operatorOptions.consequentNodePropertyName)),
      " : ",
      alternateNode.type === operatorOptions.conditionalNodeType ||
        isNil(alternateNode)
        ? path.call(print, operatorOptions.alternateNodePropertyName)
        : wrap(path.call(print, operatorOptions.alternateNodePropertyName))
    );
  } else {
    // normal mode
    const part = concat([
      line,
      "? ",
      consequentNode.type === operatorOptions.conditionalNodeType
        ? ifBreak("", "(")
        : "",
      align(2, path.call(print, operatorOptions.consequentNodePropertyName)),
      consequentNode.type === operatorOptions.conditionalNodeType
        ? ifBreak("", ")")
        : "",
      line,
      ": ",
      alternateNode.type === operatorOptions.conditionalNodeType
        ? path.call(print, operatorOptions.alternateNodePropertyName)
        : align(2, path.call(print, operatorOptions.alternateNodePropertyName)),
    ]);
    parts.push(
      parent.type !== operatorOptions.conditionalNodeType ||
        parent[operatorOptions.alternateNodePropertyName] === node ||
        isParentTest
        ? part
        : options.useTabs
        ? dedent(indent(part))
        : align(Math.max(0, options.tabWidth - 2), part)
    );
  }

  // 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 comments = flat([
    ...operatorOptions.testNodePropertyNames.map(
      (propertyName) => node[propertyName].comments
    ),
    consequentNode.comments,
    alternateNode.comments,
  ]).filter(Boolean);
  const shouldBreak = comments.some(
    (comment) =>
      handleComments.isBlockComment(comment) &&
      hasNewlineInRange(
        options.originalText,
        options.locStart(comment),
        options.locEnd(comment)
      )
  );
  const maybeGroup = (doc) =>
    parent === firstNonConditionalParent
      ? group(doc, { shouldBreak })
      : shouldBreak
      ? concat([doc, breakParent])
      : doc;

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

  const result = maybeGroup(
    concat(
      [].concat(
        ((testDoc) =>
          /**
           *     a
           *       ? b
           *       : multiline
           *         test
           *         node
           *       ^^ align(2)
           *       ? d
           *       : e
           */
          parent.type === operatorOptions.conditionalNodeType &&
          parent[operatorOptions.alternateNodePropertyName] === node
            ? align(2, testDoc)
            : testDoc)(concat(operatorOptions.beforeParts())),
        forceNoIndent ? concat(parts) : indent(concat(parts)),
        operatorOptions.afterParts(breakClosingParen)
      )
    )
  );

  return isParentTest
    ? group(concat([indent(concat([softline, result])), softline]))
    : result;
}