src/language-js/print/statement.js/expressionNeedsASIProtection
function expressionNeedsASIProtection(path, options) {
  const node = path.getValue();
  switch (node.type) {
    case "ParenthesizedExpression":
    case "TypeCastExpression":
    case "ArrayExpression":
    case "ArrayPattern":
    case "TemplateLiteral":
    case "TemplateElement":
    case "RegExpLiteral":
      return true;
    case "ArrowFunctionExpression": {
      if (!shouldPrintParamsWithoutParens(path, options)) {
        return true;
      }
      break;
    }
    case "UnaryExpression": {
      const { prefix, operator } = node;
      if (prefix && (operator === "+" || operator === "-")) {
        return true;
      }
      break;
    }
    case "BindExpression": {
      if (!node.object) {
        return true;
      }
      break;
    }
    case "Literal": {
      if (node.regex) {
        return true;
      }
      break;
    }
    default: {
      if (isJsxNode(node)) {
        return true;
      }
    }
  }

  if (pathNeedsParens(path, options)) {
    return true;
  }

  if (!hasNakedLeftSide(node)) {
    return false;
  }

  return path.call(
    (childPath) => expressionNeedsASIProtection(childPath, options),
    ...getLeftSidePathName(path, node)
  );
}