src/language-js/print/jsx.js/printJsxOpeningElement
function printJsxOpeningElement(path, options, print) {
  const n = path.getValue();

  const nameHasComments =
    (n.name && hasComment(n.name)) ||
    (n.typeParameters && hasComment(n.typeParameters));

  // Don't break self-closing elements with no attributes and no comments
  if (n.selfClosing && !n.attributes.length && !nameHasComments) {
    return concat([
      "<",
      path.call(print, "name"),
      path.call(print, "typeParameters"),
      " />",
    ]);
  }

  // don't break up opening elements with a single long text attribute
  if (
    n.attributes &&
    n.attributes.length === 1 &&
    n.attributes[0].value &&
    isStringLiteral(n.attributes[0].value) &&
    !n.attributes[0].value.value.includes("\n") &&
    // We should break for the following cases:
    // <div
    //   // comment
    //   attr="value"
    // >
    // <div
    //   attr="value"
    //   // comment
    // >
    !nameHasComments &&
    !hasComment(n.attributes[0])
  ) {
    return group(
      concat([
        "<",
        path.call(print, "name"),
        path.call(print, "typeParameters"),
        " ",
        concat(path.map(print, "attributes")),
        n.selfClosing ? " />" : ">",
      ])
    );
  }

  const lastAttrHasTrailingComments =
    n.attributes.length &&
    hasComment(getLast(n.attributes), CommentCheckFlags.Trailing);

  const bracketSameLine =
    // Simple tags (no attributes and no comment in tag name) should be
    // kept unbroken regardless of `jsxBracketSameLine`
    (!n.attributes.length && !nameHasComments) ||
    (options.jsxBracketSameLine &&
      // We should print the bracket in a new line for the following cases:
      // <div
      //   // comment
      // >
      // <div
      //   attr // comment
      // >
      (!nameHasComments || n.attributes.length) &&
      !lastAttrHasTrailingComments);

  // We should print the opening element expanded if any prop value is a
  // string literal with newlines
  const shouldBreak =
    n.attributes &&
    n.attributes.some(
      (attr) =>
        attr.value &&
        isStringLiteral(attr.value) &&
        attr.value.value.includes("\n")
    );

  return group(
    concat([
      "<",
      path.call(print, "name"),
      path.call(print, "typeParameters"),
      concat([
        indent(
          concat(path.map((attr) => concat([line, print(attr)]), "attributes"))
        ),
        n.selfClosing ? line : bracketSameLine ? ">" : softline,
      ]),
      n.selfClosing ? "/>" : bracketSameLine ? "" : ">",
    ]),
    { shouldBreak }
  );
}