Skip to content

Commit

Permalink
Merge pull request #402 from blast-hardcheese/tracker
Browse files Browse the repository at this point in the history
Better error messages
  • Loading branch information
blast-hardcheese committed Oct 3, 2019
2 parents 78bc52d + f23cbf7 commit 397621c
Show file tree
Hide file tree
Showing 50 changed files with 1,192 additions and 681 deletions.
9 changes: 6 additions & 3 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ val catsVersion = "1.6.0"
val catsEffectVersion = "1.0.0"
val circeVersion = "0.10.1"
val http4sVersion = "0.20.0"
val scalacheckVersion = "1.14.0"
val scalatestVersion = "3.0.8"
val javaparserVersion = "3.7.1"
val endpointsVersion = "0.8.0"
Expand Down Expand Up @@ -168,7 +169,8 @@ addCompilerPlugin("org.typelevel" % "kind-projector" % kindProjectorVersion cro
publishMavenStyle := true

val testDependencies = Seq(
"org.scalatest" %% "scalatest" % scalatestVersion % Test
"org.scalatest" %% "scalatest" % scalatestVersion % Test,
"org.scalacheck" %% "scalacheck" % scalacheckVersion % Test
)

val excludedWarts = Set(Wart.DefaultArguments, Wart.Product, Wart.Serializable, Wart.Any)
Expand All @@ -187,9 +189,9 @@ val codegenSettings = Seq(
"-encoding",
"utf8"
) ++ (if (scalaVersion.value.startsWith("2.11.")) {
List("-Xexperimental", "-Xlint:_")
List("-Xexperimental", "-Xlint:-missing-interpolator,_")
} else {
List("-Xlint:-unused,_")
List("-Xlint:-unused,-missing-interpolator,_")
}),
parallelExecution in Test := true
)
Expand Down Expand Up @@ -221,6 +223,7 @@ lazy val codegen = (project in file("modules/codegen"))
scalacOptions ++= List(
"-language:higherKinds",
"-Ywarn-unused-import",
"-Xlint:_,-missing-interpolator"
),
bintrayRepository := {
if (isSnapshot.value) "snapshots"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ object ClientGenerator {
supportDefinitions <- generateSupportDefinitions(context.tracing, securitySchemes)
clients <- groupedRoutes.traverse({
case (className, unsortedRoutes) =>
val routes = unsortedRoutes.sortBy(r => (r.path, r.method))
val routes = unsortedRoutes.sortBy(r => (r.path.unwrapTracker, r.method))
val clientName = s"${className.lastOption.getOrElse("").capitalize}Client"
def splitOperationParts(operationId: String): (List[String], String) = {
val parts = operationId.split('.')
Expand Down
57 changes: 35 additions & 22 deletions modules/codegen/src/main/scala/com/twilio/guardrail/Common.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,23 @@ import cats.data.NonEmptyList
import cats.free.Free
import cats.implicits._
import cats.Id
import com.twilio.guardrail.core.Tracker
import com.twilio.guardrail.extract.SecurityOptional
import com.twilio.guardrail.languages.LA
import com.twilio.guardrail.protocol.terms.protocol.{ ArrayProtocolTerms, EnumProtocolTerms, ModelProtocolTerms, PolyProtocolTerms, ProtocolSupportTerms }
import com.twilio.guardrail.terms.framework.FrameworkTerms
import com.twilio.guardrail.protocol.terms.client.ClientTerms
import com.twilio.guardrail.protocol.terms.server.ServerTerms
import com.twilio.guardrail.shims._
import com.twilio.guardrail.terms.{ CoreTerms, ScalaTerms, SecurityRequirements, SwaggerTerms }
import java.nio.file.Path
import scala.collection.JavaConverters._
import java.net.URI

case class SupportDefinition[L <: LA](className: L#TermName, imports: List[L#Import], definition: L#ClassDefinition)

object Common {
val resolveFile: Path => List[String] => Path = root => _.foldLeft(root)(_.resolve(_))

def prepareDefinitions[L <: LA, F[_]](kind: CodegenTarget, context: Context, swagger: OpenAPI)(
def prepareDefinitions[L <: LA, F[_]](kind: CodegenTarget, context: Context, swagger: Tracker[OpenAPI])(
implicit
C: ClientTerms[L, F],
R: ArrayProtocolTerms[L, F],
Expand All @@ -43,26 +42,40 @@ object Common {
proto <- ProtocolGenerator.fromSwagger[L, F](swagger)
ProtocolDefinitions(protocolElems, protocolImports, packageObjectImports, packageObjectContents) = proto

serverUrls = Option(swagger.getServers)
.map(_.asScala.toList)
.map(_.flatMap({ x =>
Option(x.getUrl())
.map({ x =>
val uri = new URI(x.iterateWhileM[Id](_.stripSuffix("/"))(_.endsWith("/")))
val scheme = Option(uri.getScheme).orElse(Option(uri.getHost).filterNot(_.isEmpty).map(_ => "http")).getOrElse(null) // Only force a scheme if we have a host, falling back to null as required by URI
new URI(scheme, uri.getUserInfo, uri.getHost, uri.getPort, "", uri.getQuery, uri.getFragment)
})
.filterNot(_.toString().isEmpty)
}))
.flatMap(NonEmptyList.fromList(_))
basePath = swagger.basePath()

paths = swagger.getPathsOpt()
globalSecurityRequirements = Option(swagger.getSecurity).flatMap(SecurityRequirements(_, SecurityOptional(swagger), SecurityRequirements.Global))
requestBodies <- extractCommonRequestBodies(Option(swagger.getComponents))
serverUrls = NonEmptyList.fromList(
swagger
.downField("servers", _.getServers)
.flatExtract(
server =>
server
.downField("url", _.getUrl)
.get
.map({ x =>
val uri = new URI(x.iterateWhileM[Id](_.stripSuffix("/"))(_.endsWith("/")))
@SuppressWarnings(Array("org.wartremover.warts.Null"))
val scheme = Option(uri.getScheme).orElse(Option(uri.getHost).filterNot(_.isEmpty).map(_ => "http")).getOrElse(null) // Only force a scheme if we have a host, falling back to null as required by URI
new URI(scheme, uri.getUserInfo, uri.getHost, uri.getPort, "", uri.getQuery, uri.getFragment)
})
.filterNot(_.toString().isEmpty)
.toList
)
)
basePath = swagger
.downField("servers", _.getServers)
.cotraverse(_.downField("url", _.getUrl))
.headOption
.flatMap(_.get)
.flatMap(url => Option(new URI(url).getPath))
.filter(_ != "/")

paths = swagger.downField("paths", _.getPaths)
globalSecurityRequirements = NonEmptyList
.fromList(swagger.downField("security", _.getSecurity).get)
.flatMap(SecurityRequirements(_, SecurityOptional(swagger.get), SecurityRequirements.Global))
requestBodies <- extractCommonRequestBodies(swagger.downField("components", _.getComponents).get)
routes <- extractOperations(paths, requestBodies, globalSecurityRequirements)
prefixes <- vendorPrefixes()
securitySchemes <- SwaggerUtil.extractSecuritySchemes(swagger, prefixes)
securitySchemes <- SwaggerUtil.extractSecuritySchemes(swagger.get, prefixes)
classNamedRoutes <- routes.traverse(route => getClassName(route.operation, prefixes).map(_ -> route))
groupedRoutes = classNamedRoutes
.groupBy(_._1)
Expand All @@ -82,7 +95,7 @@ object Common {
case CodegenTarget.Server =>
for {
serverMeta <- ServerGenerator
.fromSwagger[L, F](context, swagger, frameworkImports)(groupedRoutes)(protocolElems, securitySchemes)
.fromSwagger[L, F](context, basePath, frameworkImports)(groupedRoutes)(protocolElems, securitySchemes)
Servers(servers, supportDefinitions) = serverMeta
frameworkImplicits <- getFrameworkImplicits()
} yield CodegenDefinitions[L](List.empty, servers, supportDefinitions, frameworkImplicits)
Expand Down

0 comments on commit 397621c

Please sign in to comment.