src/language-js/printer-estree.js/printFunctionParams
function printFunctionParams(path, print, options, expandArg, printTypeParams) {
  const fun = path.getValue();
  const parent = path.getParentNode();
  const paramsField = fun.parameters ? "parameters" : "params";
  const isParametersInTestCall = isTestCall(parent);
  const shouldHugParameters = shouldHugArguments(fun);
  const shouldExpandParameters =
    expandArg &&
    !(fun[paramsField] && fun[paramsField].some((n) => n.comments));

  const typeParams = printTypeParams
    ? printFunctionTypeParameters(path, options, print)
    : "";

  let printed = [];
  if (fun[paramsField]) {
    const lastArgIndex = fun[paramsField].length - 1;

    printed = path.map((childPath, index) => {
      const parts = [];
      const param = childPath.getValue();

      parts.push(print(childPath));

      if (index === lastArgIndex) {
        if (fun.rest) {
          parts.push(",", line);
        }
      } else if (
        isParametersInTestCall ||
        shouldHugParameters ||
        shouldExpandParameters
      ) {
        parts.push(", ");
      } else if (isNextLineEmpty(options.originalText, param, options.locEnd)) {
        parts.push(",", hardline, hardline);
      } else {
        parts.push(",", line);
      }

      return concat(parts);
    }, paramsField);
  }

  if (fun.rest) {
    printed.push(concat(["...", path.call(print, "rest")]));
  }

  if (printed.length === 0) {
    return concat([
      typeParams,
      "(",
      comments.printDanglingComments(
        path,
        options,
        /* sameIndent */ true,
        (comment) =>
          getNextNonSpaceNonCommentCharacter(
            options.originalText,
            comment,
            options.locEnd
          ) === ")"
      ),
      ")",
    ]);
  }

  const lastParam = getLast(fun[paramsField]);

  // If the parent is a call with the first/last argument expansion and this is the
  // params of the first/last argument, we don't want the arguments to break and instead
  // want the whole expression to be on a new line.
  //
  // Good:                 Bad:
  //   verylongcall(         verylongcall((
  //     (a, b) => {           a,
  //     }                     b,
  //   })                    ) => {
  //                         })
  if (shouldExpandParameters) {
    return group(
      concat([
        removeLines(typeParams),
        "(",
        concat(printed.map(removeLines)),
        ")",
      ])
    );
  }

  // Single object destructuring should hug
  //
  // function({
  //   a,
  //   b,
  //   c
  // }) {}
  const hasNotParameterDecorator = fun[paramsField].every(
    (param) => !param.decorators
  );
  if (shouldHugParameters && hasNotParameterDecorator) {
    return concat([typeParams, "(", concat(printed), ")"]);
  }

  // don't break in specs, eg; `it("should maintain parens around done even when long", (done) => {})`
  if (isParametersInTestCall) {
    return concat([typeParams, "(", concat(printed), ")"]);
  }

  const isFlowShorthandWithOneArg =
    (isObjectTypePropertyAFunction(parent, options) ||
      isTypeAnnotationAFunction(parent, options) ||
      parent.type === "TypeAlias" ||
      parent.type === "UnionTypeAnnotation" ||
      parent.type === "TSUnionType" ||
      parent.type === "IntersectionTypeAnnotation" ||
      (parent.type === "FunctionTypeAnnotation" &&
        parent.returnType === fun)) &&
    fun[paramsField].length === 1 &&
    fun[paramsField][0].name === null &&
    fun[paramsField][0].typeAnnotation &&
    fun.typeParameters === null &&
    isSimpleFlowType(fun[paramsField][0].typeAnnotation) &&
    !fun.rest;

  if (isFlowShorthandWithOneArg) {
    if (options.arrowParens === "always") {
      return concat(["(", concat(printed), ")"]);
    }
    return concat(printed);
  }

  const canHaveTrailingComma =
    !(lastParam && lastParam.type === "RestElement") && !fun.rest;

  return concat([
    typeParams,
    "(",
    indent(concat([softline, concat(printed)])),
    ifBreak(
      canHaveTrailingComma && shouldPrintComma(options, "all") ? "," : ""
    ),
    softline,
    ")",
  ]);
}