<commit_before>package scala.models

import lib.generator.{CodeGenerator, GeneratorUtil}
import com.bryzek.apidoc.generator.v0.models.{File, InvocationForm}
import com.bryzek.apidoc.spec.v0.models._
import scala.generator.{ScalaDatatype, ScalaPrimitive, ScalaOperation, ScalaParameter, ScalaResource, ScalaService, ScalaUtil}

object Play2RouteGenerator extends CodeGenerator {

  override def invoke(form: InvocationForm): Either[Seq[String], Seq[File]] = {
    new Play2RouteGenerator(form).invoke
  }
}


/**
 * Generates a Play routes file based on the service description
 * from api.json
 */
case class Play2RouteGenerator(form: InvocationForm) {

  private[this] val GlobalPad = 5

  private[this] val service = form.service
  private[this] val scalaService = ScalaService(service)

  def invoke(): Either[Seq[String], Seq[File]] = {
    scalaService.resources.flatMap { resource =>
      resource.operations.map { op =>
        Play2Route(scalaService, op, resource)
      }
    } match {
      case Nil => {
        Left(
          Seq(s"Service[${service.organization.key}/${service.application.key}] does not have any resource operations - cannot generate play routes")
        )
      }
      case all => {
        val maxVerbLength = all.map(_.verb.toString.length).toSeq.sorted.last
        val maxUrlLength = all.map(_.url.length).toSeq.sorted.last
        val (paramStart, pathStart) = all.partition(_.url.startsWith("/:"))

        Right(
          Seq(File(
            "routes",
            None,
            ApidocComments(form.service.version, form.userAgent).forPlayRoutes + "\n\n" +
              (pathStart ++ paramStart).map { r =>
                Seq(
                  r.verb,
                  " " * (maxVerbLength - r.verb.toString.length + GlobalPad),
                  r.url,
                  " " * (maxUrlLength - r.url.length + GlobalPad),
                  r.method,
                  "(",
                  r.params.mkString(", "),
                  ")"
                ).mkString("")
              }.mkString("\n")
          ))
        )
      }
    }
  }
}

private[models] case class Play2Route(
  ssd: ScalaService,
  op: ScalaOperation,
  resource: ScalaResource
) {

  val verb = op.method
  val url = op.path
  val params = parametersWithTypesAndDefaults(
    op.parameters.
      filter { param =>
        param.location match {
          case ParameterLocation.Form => false
          case ParameterLocation.Query => true
          case ParameterLocation.Path => true
          case ParameterLocation.Header => false
          case ParameterLocation.UNDEFINED(_) => false
        }
      }.
      filter { param =>
        param.datatype match {
          case (_: ScalaPrimitive) | ScalaDatatype.List(_) => true
          case ScalaDatatype.Map(_) => false
          case ScalaDatatype.Option(inner) => true
        }
      }
  )

  val method = "%s.%s".format(
    "controllers." + lib.Text.underscoreAndDashToInitCap(resource.plural),
    GeneratorUtil.urlToMethodName(resource.path, resource.operations.map(_.path), op.method, url)
  )

  private def parametersWithTypesAndDefaults(params: Iterable[ScalaParameter]): Iterable[String] = {
    params.map { param =>
      Seq(
        Some(definition(param)),
        param.default.map( d =>
          param.datatype match {
            case ScalaDatatype.List(_) => {
              sys.error("Cannot set defaults for lists")
            }
            case ScalaDatatype.Map(_) => {
              sys.error("Cannot set defaults for maps")
            }
            case ScalaDatatype.Option(_) => {
              sys.error("Cannot set defaults for options")
            }
            case p: ScalaPrimitive => {
              "?= " + defaultForPrimitive(p, d)
            }
          }
        )
      ).flatten.mkString(" ")
    }<commit_msg>Set better defaults for collections<commit_after>package scala.models

import lib.generator.{CodeGenerator, GeneratorUtil}
import com.bryzek.apidoc.generator.v0.models.{File, InvocationForm}
import com.bryzek.apidoc.spec.v0.models._
import scala.generator.{ScalaDatatype, ScalaPrimitive, ScalaOperation, ScalaParameter, ScalaResource, ScalaService, ScalaUtil}

object Play2RouteGenerator extends CodeGenerator {

  override def invoke(form: InvocationForm): Either[Seq[String], Seq[File]] = {
    new Play2RouteGenerator(form).invoke
  }
}


/**
 * Generates a Play routes file based on the service description
 * from api.json
 */
case class Play2RouteGenerator(form: InvocationForm) {

  private[this] val GlobalPad = 5

  private[this] val service = form.service
  private[this] val scalaService = ScalaService(service)

  def invoke(): Either[Seq[String], Seq[File]] = {
    scalaService.resources.flatMap { resource =>
      resource.operations.map { op =>
        Play2Route(scalaService, op, resource)
      }
    } match {
      case Nil => {
        Left(
          Seq(s"Service[${service.organization.key}/${service.application.key}] does not have any resource operations - cannot generate play routes")
        )
      }
      case all => {
        val maxVerbLength = all.map(_.verb.toString.length).toSeq.sorted.last
        val maxUrlLength = all.map(_.url.length).toSeq.sorted.last
        val (paramStart, pathStart) = all.partition(_.url.startsWith("/:"))

        Right(
          Seq(File(
            "routes",
            None,
            ApidocComments(form.service.version, form.userAgent).forPlayRoutes + "\n\n" +
              (pathStart ++ paramStart).map { r =>
                Seq(
                  r.verb,
                  " " * (maxVerbLength - r.verb.toString.length + GlobalPad),
                  r.url,
                  " " * (maxUrlLength - r.url.length + GlobalPad),
                  r.method,
                  "(",
                  r.params.mkString(", "),
                  ")"
                ).mkString("")
              }.mkString("\n")
          ))
        )
      }
    }
  }
}

private[models] case class Play2Route(
  ssd: ScalaService,
  op: ScalaOperation,
  resource: ScalaResource
) {

  val verb = op.method
  val url = op.path
  val params = parametersWithTypesAndDefaults(
    op.parameters.
      filter { param =>
        param.location match {
          case ParameterLocation.Form => false
          case ParameterLocation.Query => true
          case ParameterLocation.Path => true
          case ParameterLocation.Header => false
          case ParameterLocation.UNDEFINED(_) => false
        }
      }.
      filter { param =>
        param.datatype match {
          case (_: ScalaPrimitive) | ScalaDatatype.List(_) => true
          case ScalaDatatype.Map(_) => false
          case ScalaDatatype.Option(inner) => true
        }
      }
  )

  val method = "%s.%s".format(
    "controllers." + lib.Text.underscoreAndDashToInitCap(resource.plural),
    GeneratorUtil.urlToMethodName(resource.path, resource.operations.map(_.path), op.method, url)
  )

  private def parametersWithTypesAndDefaults(params: Iterable[ScalaParameter]): Iterable[String] = {
    params.map { param =>
      Seq(
        Some(definition(param)),
        param.default.flatMap( d =>
          param.datatype match {
            case ScalaDatatype.List(v) => Some("?= Nil")
            case ScalaDatatype.Map(_) => Some("?= Map()")
            case ScalaDatatype.Option(inner) => None
            case p: ScalaPrimitive => Some("?= " + defaultForPrimitive(p, d))
          }
        )
      ).flatten.mkString(" ")
    }
{'fraction_non_alphanumeric': 0.11795281887245102, 'fraction_numerical': 0.0021324803411968546, 'mean_word_length': 2.1796610169491526, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 45, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5324691', 'n_tokens_mistral': 2204, 'n_tokens_neox': 2134, 'n_words': 439}