<commit_before>package de.zalando.swagger

import java.net.URI

import de.zalando.apifirst.Domain
import Domain._
import TypeMetaConverter._
import de.zalando.apifirst.new_naming._
import strictModel._

import scala.collection.mutable
import scala.language.{implicitConversions, postfixOps}

/**
 * @author  slasch 
 * @since   14.10.2015.
 */
class TypeConverter(base: URI, model: strictModel.SwaggerModel, keyPrefix: String) extends ParameterNaming with DiscriminatorMemoizer {

  lazy val convert: NamedTypes =
    fromDefinitions(model.definitions) ++
      fromPaths(model.paths) ++
      fromParameters(model.parameters)

  private type TypeConstructor = TypeMeta => Type
  private type TypeConstructors = Seq[TypeConstructor]

  private def fromParameters(parameters: ParameterDefinitions): NamedTypes =
    Option(parameters).toSeq.flatten flatMap { p =>
      fromParamListItem(base / "parameters" / p._1, p._2)
    }

  private def fromDefinitions(definitions: Definitions): NamedTypes =
    Option(definitions).toSeq.flatten flatMap { d =>
      fromSchema(base / "definitions" / d._1, d._2, None)
    }

  private def fromPaths(paths: Paths): NamedTypes =
    fromPathParameters(paths) ++ fromResponses(paths).flatten ++ fromOperationParameters(paths).toSeq.flatten

  private def fromPathParameters(paths: Paths): NamedTypes =
    allPathItems(paths) flatMap fromNamedParamListItem

  private def forAllOperations[T](paths: Paths, logic: (Reference, Operation) => T) = for {
    (prefix, path) <- Option(paths).toSeq.flatten
    operationName <- path.operationNames
    operation = path.operation(operationName)
    name = base / "paths" / prefix / operationName
  } yield logic(name, operation)

  private def fromOperationParameters(paths: Paths): Iterable[NamedTypes] =
    forAllOperations(paths, parametersCollector)

  private def parametersCollector(name: Reference, operation: Operation): NamedTypes =
    Option(operation.parameters).toSeq.flatten flatMap {
      fromParamListItem(name, _)
    }

  private def allPathItems(paths: Paths): Seq[(Reference, ParametersListItem)] = for {
    (url, pathItem) <- Option(paths).toSeq.flatten
    parameterList <- Option(pathItem.parameters).toSeq
    paramListItem <- parameterList
    name = base / "paths" / url  / ""
  } yield name -> paramListItem

  private def responseCollector: (Reference, Operation) => (Reference, Responses) = (name, op) => name -> op.responses

  private def fromResponses(paths: Paths): Seq[NamedTypes] = for {
    (prefix, responses) <- forAllOperations(paths, responseCollector)
    (suffix, response) <- responses
    fullName = prefix / "responses" / suffix
  } yield fromSchemaOrFileSchema(fullName, response.schema, Some(Nil))

  private def fromNamedParamListItem[T](pair: (Reference, ParametersListItem)): NamedTypes =
    fromParamListItem(pair._1, pair._2)

  private def fromParamListItem[T](name: Reference, param: ParametersListItem): NamedTypes = param match {
    case r : JsonReference => Seq(fromReference(name, r, None))
    case nb: NonBodyParameterCommons[_, _] => Seq(fromNonBodyParameter(name, nb))
    case bp: BodyParameter[_] => fromBodyParameter(name, bp)
  }

  private def fromBodyParameter[T](name: Reference, param: BodyParameter[T]): NamedTypes =
    fromSchemaOrFileSchema(name / param.name, param.schema, if (param.required) Some(Seq(param.name)) else Some(Nil))

  private def fromSchemaOrReference[T](name: Reference, param: SchemaOrReference[T], required: Option[Seq[String]]): NamedTypes =
    Option(param).toSeq flatMap {
      case Left(s) => fromSchema(name, s, required)
      case Right(r: JsonReference) => Seq(fromReference(name, r, required))
    }

  private def fromSchemaOrFileSchema[T](name: Reference, param: SchemaOrFileSchema[T], required: Option[Seq[String]]): NamedTypes =
    param match {
      case any if any == null => Seq(fromNull(name))
      case Left(s: SchemaOrReference[_]) => fromSchemaOrReference(name, s, required)
      case Right(fs: FileSchema[_]) => Seq(fromFileSchema(fs, required))
    }

  private def fromSchemaOrSchemaArray[T](name: Reference, param: SchemaOrSchemaArray[T], required: Option[Seq[String]]): NamedTypes =
    param match {
      case Right(sa) => fromSchemaArray(name, sa, required)
      case Left(sr) => fromSchemaOrReference(name, sr, required)
    }

  private def fromSchemaArray(name: Reference, sa: SchemaArray, required: Option[Seq[String]]): NamedTypes =
    sa flatMap { s => fromSchemaOrFileSchema(name, s, required) }

  private def fromSchema[T](name: Reference, param: Schema[_], required: Option[Seq[String]]): NamedTypes = {
    val tpe = if (param.`type` != null) param.`type` else PrimitiveType.OBJECT
    tpe match {
      case t: ArrayJsonSchemaType => Seq(fromArrayJsonSchema(name, param, t))
      case p: PrimitiveType.Val => fromPrimitiveType(name, param, p, required)
    }
  }

  private def fromPrimitiveType(name: Reference, param: Schema[_], p: PrimitiveType.Val, required: Option[Seq[String]]): NamedTypes = {
    p match {
      case PrimitiveType.ARRAY =>
        require(param.items.nonEmpty, s"Items should not be empty for $name")
        val types = fromSchemaOrSchemaArray(name, param.items.get, None)
        checkRequired(name, required, wrapInArray(types.head, None)) +: types.tail
      case PrimitiveType.OBJECT =>
        val obj = param.allOf map {
          extensionType(name, required)
        } getOrElse {
          val typeName = typeNameFromInlinedReference(param) getOrElse name
          val catchAll = fromSchemaOrBoolean(name / "additionalProperties", param.additionalProperties, param)
          val normal = fromSchemaProperties(name, param.properties, paramRequired(param.required))
          val types = fromTypes(name, normal ++ catchAll.toSeq.flatten, typeName)<commit_msg>#10: Every part of the composition is required<commit_after>package de.zalando.swagger

import java.net.URI

import de.zalando.apifirst.Domain
import Domain._
import TypeMetaConverter._
import de.zalando.apifirst.new_naming._
import strictModel._

import scala.collection.mutable
import scala.language.{implicitConversions, postfixOps}

/**
 * @author  slasch 
 * @since   14.10.2015.
 */
class TypeConverter(base: URI, model: strictModel.SwaggerModel, keyPrefix: String) extends ParameterNaming with DiscriminatorMemoizer {

  lazy val convert: NamedTypes =
    fromDefinitions(model.definitions) ++
      fromPaths(model.paths) ++
      fromParameters(model.parameters)

  private type TypeConstructor = TypeMeta => Type
  private type TypeConstructors = Seq[TypeConstructor]

  private def fromParameters(parameters: ParameterDefinitions): NamedTypes =
    Option(parameters).toSeq.flatten flatMap { p =>
      fromParamListItem(base / "parameters" / p._1, p._2)
    }

  private def fromDefinitions(definitions: Definitions): NamedTypes =
    Option(definitions).toSeq.flatten flatMap { d =>
      fromSchema(base / "definitions" / d._1, d._2, None)
    }

  private def fromPaths(paths: Paths): NamedTypes =
    fromPathParameters(paths) ++ fromResponses(paths).flatten ++ fromOperationParameters(paths).toSeq.flatten

  private def fromPathParameters(paths: Paths): NamedTypes =
    allPathItems(paths) flatMap fromNamedParamListItem

  private def forAllOperations[T](paths: Paths, logic: (Reference, Operation) => T) = for {
    (prefix, path) <- Option(paths).toSeq.flatten
    operationName <- path.operationNames
    operation = path.operation(operationName)
    name = base / "paths" / prefix / operationName
  } yield logic(name, operation)

  private def fromOperationParameters(paths: Paths): Iterable[NamedTypes] =
    forAllOperations(paths, parametersCollector)

  private def parametersCollector(name: Reference, operation: Operation): NamedTypes =
    Option(operation.parameters).toSeq.flatten flatMap {
      fromParamListItem(name, _)
    }

  private def allPathItems(paths: Paths): Seq[(Reference, ParametersListItem)] = for {
    (url, pathItem) <- Option(paths).toSeq.flatten
    parameterList <- Option(pathItem.parameters).toSeq
    paramListItem <- parameterList
    name = base / "paths" / url  / ""
  } yield name -> paramListItem

  private def responseCollector: (Reference, Operation) => (Reference, Responses) = (name, op) => name -> op.responses

  private def fromResponses(paths: Paths): Seq[NamedTypes] = for {
    (prefix, responses) <- forAllOperations(paths, responseCollector)
    (suffix, response) <- responses
    fullName = prefix / "responses" / suffix
  } yield fromSchemaOrFileSchema(fullName, response.schema, Some(Nil))

  private def fromNamedParamListItem[T](pair: (Reference, ParametersListItem)): NamedTypes =
    fromParamListItem(pair._1, pair._2)

  private def fromParamListItem[T](name: Reference, param: ParametersListItem): NamedTypes = param match {
    case r : JsonReference => Seq(fromReference(name, r, None))
    case nb: NonBodyParameterCommons[_, _] => Seq(fromNonBodyParameter(name, nb))
    case bp: BodyParameter[_] => fromBodyParameter(name, bp)
  }

  private def fromBodyParameter[T](name: Reference, param: BodyParameter[T]): NamedTypes =
    fromSchemaOrFileSchema(name / param.name, param.schema, if (param.required) Some(Seq(param.name)) else Some(Nil))

  private def fromSchemaOrReference[T](name: Reference, param: SchemaOrReference[T], required: Option[Seq[String]]): NamedTypes =
    Option(param).toSeq flatMap {
      case Left(s) => fromSchema(name, s, required)
      case Right(r: JsonReference) => Seq(fromReference(name, r, required))
    }

  private def fromSchemaOrFileSchema[T](name: Reference, param: SchemaOrFileSchema[T], required: Option[Seq[String]]): NamedTypes =
    param match {
      case any if any == null => Seq(fromNull(name))
      case Left(s: SchemaOrReference[_]) => fromSchemaOrReference(name, s, required)
      case Right(fs: FileSchema[_]) => Seq(fromFileSchema(fs, required))
    }

  private def fromSchemaOrSchemaArray[T](name: Reference, param: SchemaOrSchemaArray[T], required: Option[Seq[String]]): NamedTypes =
    param match {
      case Right(sa) => fromSchemaArray(name, sa, required)
      case Left(sr) => fromSchemaOrReference(name, sr, required)
    }

  private def fromSchemaArray(name: Reference, sa: SchemaArray, required: Option[Seq[String]]): NamedTypes =
    sa flatMap { s => fromSchemaOrFileSchema(name, s, required) }

  private def fromSchema[T](name: Reference, param: Schema[_], required: Option[Seq[String]]): NamedTypes = {
    val tpe = if (param.`type` != null) param.`type` else PrimitiveType.OBJECT
    tpe match {
      case t: ArrayJsonSchemaType => Seq(fromArrayJsonSchema(name, param, t))
      case p: PrimitiveType.Val => fromPrimitiveType(name, param, p, required)
    }
  }

  private def fromPrimitiveType(name: Reference, param: Schema[_], p: PrimitiveType.Val, required: Option[Seq[String]]): NamedTypes = {
    p match {
      case PrimitiveType.ARRAY =>
        require(param.items.nonEmpty, s"Items should not be empty for $name")
        val types = fromSchemaOrSchemaArray(name, param.items.get, None)
        checkRequired(name, required, wrapInArray(types.head, None)) +: types.tail
      case PrimitiveType.OBJECT =>
        val obj = param.allOf map {
          extensionType(name, None) // "None" means that everything defined as a part of the composition is required
        } getOrElse {
          val typeName = typeNameFromInlinedReference(param) getOrElse name
          val catchAll = fromSchemaOrBoolean(name / "additionalProperties", param.additionalProperties, param)
          val normal = fromSchemaProperties(name, param.properties, paramRequired(param.required))
          val types = fromTypes(name, normal ++ catchAll.toSeq.flatten, typeName)
{'fraction_non_alphanumeric': 0.11349327888378424, 'fraction_numerical': 0.002552322613578356, 'mean_word_length': 4.482742537313433, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 49, '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': '5010989', 'n_tokens_mistral': 3497, 'n_tokens_neox': 3412, 'n_words': 849}