Skip to content

Commit

Permalink
Merge pull request #1825 from blast-hardcheese/generalizing-terminology
Browse files Browse the repository at this point in the history
Generalizing terminology
  • Loading branch information
blast-hardcheese committed Oct 10, 2023
2 parents 34957b4 + 401b43c commit 0c544d3
Show file tree
Hide file tree
Showing 89 changed files with 662 additions and 629 deletions.
58 changes: 44 additions & 14 deletions modules/core/src/main/scala/dev/guardrail/Common.scala
Original file line number Diff line number Diff line change
@@ -1,30 +1,60 @@
package dev.guardrail

import _root_.io.swagger.v3.oas.models.OpenAPI
import io.swagger.v3.oas.models.security.{ SecurityScheme => SwSecurityScheme }
import cats.data.NonEmptyList
import cats.syntax.all._
import cats.Id
import java.nio.file.Path
import java.net.URI

import dev.guardrail.core.{ SupportDefinition, Tracker }
import dev.guardrail.core.extract.CustomTypeName
import dev.guardrail.generators.{ Clients, Servers }
import dev.guardrail.generators.ProtocolDefinitions
import dev.guardrail.languages.LA
import dev.guardrail.terms.client.ClientTerms
import dev.guardrail.terms.framework.FrameworkTerms
import dev.guardrail.terms.protocol.RandomType
import dev.guardrail.terms.server.ServerTerms
import dev.guardrail.terms.{ CollectionsLibTerms, CoreTerms, LanguageTerms, ProtocolTerms, SecurityRequirements, SwaggerTerms }
import dev.guardrail.terms.{ CollectionsLibTerms, CoreTerms, LanguageTerms, ProtocolTerms, SecurityRequirements, SecurityScheme, SwaggerTerms }

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

private[this] def extractSecuritySchemes[L <: LA, F[_]](
spec: OpenAPI,
prefixes: List[String]
)(implicit Sw: SwaggerTerms[L, F], Sc: LanguageTerms[L, F]): F[Map[String, SecurityScheme[L]]] = {
import Sw._
import Sc._

Tracker(spec)
.downField("components", _.getComponents)
.flatDownField("securitySchemes", _.getSecuritySchemes)
.indexedDistribute
.value
.flatTraverse { case (schemeName, scheme) =>
val typeName = CustomTypeName(scheme, prefixes)
for {
tpe <- typeName.fold(Option.empty[L#Type].pure[F])(x => parseType(Tracker.cloneHistory(scheme, x)))
parsedScheme <- scheme.downField("type", _.getType).unwrapTracker.traverse {
case SwSecurityScheme.Type.APIKEY => extractApiKeySecurityScheme(schemeName, scheme, tpe).widen[SecurityScheme[L]]
case SwSecurityScheme.Type.HTTP => extractHttpSecurityScheme(schemeName, scheme, tpe).widen[SecurityScheme[L]]
case SwSecurityScheme.Type.OPENIDCONNECT => extractOpenIdConnectSecurityScheme(schemeName, scheme, tpe).widen[SecurityScheme[L]]
case SwSecurityScheme.Type.OAUTH2 => extractOAuth2SecurityScheme(schemeName, scheme, tpe).widen[SecurityScheme[L]]
case SwSecurityScheme.Type.MUTUALTLS => extractMutualTLSSecurityScheme(schemeName, scheme, tpe).widen[SecurityScheme[L]]
}
} yield parsedScheme.toList.map(scheme => schemeName -> scheme)
}
.map(_.toMap)
}

def prepareDefinitions[L <: LA, F[_]](
kind: CodegenTarget,
context: Context,
swagger: Tracker[OpenAPI],
spec: Tracker[OpenAPI],
dtoPackage: List[String],
supportPackage: NonEmptyList[String]
)(implicit
Expand All @@ -40,15 +70,15 @@ object Common {
import Sw._

Sw.log.function("prepareDefinitions")(for {
proto @ ProtocolDefinitions(protocolElems, protocolImports, packageObjectImports, packageObjectContents, _) <- P.fromSwagger(
swagger,
proto @ ProtocolDefinitions(protocolElems, protocolImports, packageObjectImports, packageObjectContents, _) <- P.fromSpec(
spec,
dtoPackage,
supportPackage,
context.propertyRequirement
)

serverUrls = NonEmptyList.fromList(
swagger
spec
.downField("servers", _.getServers)
.flatExtract(server =>
server
Expand All @@ -66,23 +96,23 @@ object Common {
.toList
)
)
basePath = swagger
basePath = spec
.downField("servers", _.getServers)
.cotraverse(_.downField("url", _.getUrl))
.headOption
.flatMap(_.unwrapTracker)
.flatMap(url => Option(new URI(url).getPath))
.filter(_ != "/")

paths = swagger.downField("paths", _.getPaths)
paths = spec.downField("paths", _.getPaths)
globalSecurityRequirements = NonEmptyList
.fromList(swagger.downField("security", _.getSecurity).indexedDistribute)
.fromList(spec.downField("security", _.getSecurity).indexedDistribute)
.flatMap(SecurityRequirements(_, SecurityRequirements.Global))
components = swagger.downField("components", _.getComponents)
components = spec.downField("components", _.getComponents)
requestBodies <- extractCommonRequestBodies(components)
routes <- extractOperations(paths, requestBodies, globalSecurityRequirements)
prefixes <- Cl.vendorPrefixes()
securitySchemes <- SwaggerUtil.extractSecuritySchemes(swagger.unwrapTracker, prefixes)
securitySchemes <- extractSecuritySchemes(spec.unwrapTracker, prefixes)
classNamedRoutes <- routes.traverse(route => getClassName(route.operation, prefixes, context.tagsBehaviour).map(_ -> route))
groupedRoutes = classNamedRoutes
.groupMap(_._1)(_._2)
Expand All @@ -92,14 +122,14 @@ object Common {
codegen <- kind match {
case CodegenTarget.Client =>
for {
clientMeta <- C.fromSwagger(context, frameworkImports)(serverUrls, basePath, groupedRoutes)(protocolElems, securitySchemes, components)
clientMeta <- C.fromSpec(context, frameworkImports)(serverUrls, basePath, groupedRoutes)(protocolElems, securitySchemes, components)
Clients(clients, supportDefinitions) = clientMeta
frameworkImplicits <- getFrameworkImplicits()
} yield CodegenDefinitions[L](clients, List.empty, supportDefinitions, frameworkImplicits)

case CodegenTarget.Server =>
for {
serverMeta <- Se.fromSwagger(context, supportPackage, basePath, frameworkImports)(groupedRoutes)(protocolElems, securitySchemes, components)
serverMeta <- Se.fromSpec(context, supportPackage, basePath, frameworkImports)(groupedRoutes)(protocolElems, securitySchemes, components)
Servers(servers, supportDefinitions) = serverMeta
frameworkImplicits <- getFrameworkImplicits()
} yield CodegenDefinitions[L](List.empty, servers, supportDefinitions, frameworkImplicits)
Expand Down Expand Up @@ -198,7 +228,7 @@ object Common {

def processArgs[L <: LA, F[_]](
args: NonEmptyList[Args]
)(implicit C: CoreTerms[L, F]): F[NonEmptyList[ReadSwagger[Target[List[WriteTree]]]]] = {
)(implicit C: CoreTerms[L, F]): F[NonEmptyList[ReadSpec[Target[List[WriteTree]]]]] = {
import C._
args.traverse(arg =>
for {
Expand All @@ -211,7 +241,7 @@ object Common {

def runM[L <: LA, F[_]](
args: NonEmptyList[Args]
)(implicit C: CoreTerms[L, F]): F[NonEmptyList[ReadSwagger[Target[List[WriteTree]]]]] = {
)(implicit C: CoreTerms[L, F]): F[NonEmptyList[ReadSpec[Target[List[WriteTree]]]]] = {
import C._

for {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ import io.swagger.parser.OpenAPIParser
import io.swagger.v3.oas.models.OpenAPI
import io.swagger.v3.parser.core.models.ParseOptions

case class ReadSwagger[T](path: Path, next: OpenAPI => T)
object ReadSwagger {
def readSwagger[T](rs: ReadSwagger[Target[T]]): Target[T] =
case class ReadSpec[T](path: Path, next: OpenAPI => T)
object ReadSpec {
def readSwagger[T](rs: ReadSpec[Target[T]]): Target[T] =
if (rs.path.toFile.exists()) {
val opts = new ParseOptions()
opts.setResolve(true)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import dev.guardrail.MissingArg
import dev.guardrail.NoArgsSpecified
import dev.guardrail.NoFramework
import dev.guardrail.PrintHelp
import dev.guardrail.ReadSwagger
import dev.guardrail.ReadSpec
import dev.guardrail.Target
import dev.guardrail.UnparseableArgument
import dev.guardrail.WriteTree
Expand Down Expand Up @@ -100,7 +100,7 @@ class CoreTermInterp[L <: LA](
}
}

def processArgSet(targetInterpreter: Framework[L, Target])(args: Args): Target[ReadSwagger[Target[List[WriteTree]]]] =
def processArgSet(targetInterpreter: Framework[L, Target])(args: Args): Target[ReadSpec[Target[List[WriteTree]]]] =
Target.log.function("processArgSet")(
for {
_ <- Target.log.debug("Processing arguments")
Expand All @@ -119,9 +119,9 @@ class CoreTermInterp[L <: LA](
} yield customImport
)
_ <- Target.log.debug("Finished processing arguments")
} yield ReadSwagger(
} yield ReadSpec(
Paths.get(specPath),
swagger =>
spec =>
try {
import targetInterpreter._
val Sw = implicitly[SwaggerTerms[L, Target]]
Expand All @@ -135,7 +135,7 @@ class CoreTermInterp[L <: LA](
.prepareDefinitions[L, Target](
kind,
context,
Tracker(swagger),
Tracker(spec),
definitionsPkgName.toList ++ ("definitions" :: dtoPackage),
definitionsPkgName :+ "support"
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ object Tracker extends HighPriorityTrackerEvidence with HighPriorityTrackerSynta
def apply(a: A): B
}

def apply(swagger: OpenAPI): Tracker[OpenAPI] = new Tracker(swagger, Vector.empty)
def apply(spec: OpenAPI): Tracker[OpenAPI] = new Tracker(spec, Vector.empty)
def cloneHistory[A, B](tracker: Tracker[A], value: B): Tracker[B] = new Tracker(value, tracker.history)
def unapply[A](instance: Tracker[A]): Some[(String, A)] = Some((instance.showHistory, instance.unwrapTracker))
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ object VendorExtension {
}

object VendorExtensible {

def build[F](f: F => String => Option[Any]): VendorExtensible[F] =
new VendorExtensible[F] {
def extract[T](from: F, key: String)(implicit T: Extractable[T]): Option[T] =
Expand Down
Loading

0 comments on commit 0c544d3

Please sign in to comment.