Skip to content

Commit

Permalink
Merge pull request #162 from eed3si9n/wip/selftype
Browse files Browse the repository at this point in the history
Enumerate transitive self types
  • Loading branch information
eed3si9n authored Jan 18, 2022
2 parents 38fcd61 + 9067150 commit 106a608
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 19 deletions.
31 changes: 21 additions & 10 deletions library/src/main/scala/sbt/contraband/CodecCodeGen.scala
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,9 @@ class CodecCodeGen(
}
val allDefinitions = ds flatMap getAllDefinitions
val dependencies: Map[String, List[String]] = Map(allDefinitions map { d =>
val requiredFormats = getRequiredFormats(s, d)
val requiredFormats =
if (ds.contains(d)) getRequiredFormats(s, d)
else getAllRequiredFormats(s, d :: Nil)
fullFormatsName(s, d) -> (d match {
case i: InterfaceTypeDefinition =>
lookupChildLeaves(s, i).map(c => fullFormatsName(s, c)) ::: requiredFormats
Expand Down Expand Up @@ -277,7 +279,7 @@ class CodecCodeGen(
val typeFormats =
d match {
case _: EnumTypeDefinition => Nil
case c: RecordLikeDefinition => c.fields flatMap (f => lookupFormats(f.fieldType))
case c: RecordLikeDefinition => c.fields flatMap { f => lookupFormats(s, f.fieldType) }
}
typeFormats ++ codecParents
}
Expand Down Expand Up @@ -335,15 +337,24 @@ class CodecCodeGen(
ListMap(new File(genFile(s, syntheticDefinition).getParentFile, s"$name.scala") -> code)
}

private def lookupFormats(tpe: ast.Type): List[String] =
lookupDefinition(tpe.name) match {
case Some((s, d)) => fullFormatsName(s, d) :: Nil
case _ => formatsForType(tpe)
private def lookupFormats(s0: Document, tpe: ast.Type): List[String] =
tpe match {
case LazyType(t, _) => lookupFormats(s0, t)
case ListType(t, _) => lookupFormats(s0, t)
case NotNullType(t, _) => lookupFormats(s0, t)
case NamedType(names, _) =>
// check if this is a locally defined type, which we know the format
lookupDefinition(s0, tpe.name) match {
case Some((s, d)) =>
fullFormatsName(s, d) :: getRequiredFormats(s, d)
case _ =>
formatsForType(tpe)
}
}

private def lookupDefinition(fullName: String): Option[(Document, TypeDefinition)] = {
private def lookupDefinition(s0: Document, fullName: String): Option[(Document, TypeDefinition)] = {
val (ns, name) = splitName(fullName)
(includedSchemas flatMap { s =>
((s0 :: includedSchemas) flatMap { s =>
s.definitions collect {
case d: TypeDefinition if d.name == name && d.namespace == ns => (s, d)
}
Expand Down Expand Up @@ -383,8 +394,8 @@ object CodecCodeGen {
tpe.removeTypeParameters.name match {
case "boolean" | "byte" | "char" | "float" | "int" | "long" | "short" | "double" | "String" => Nil
case "Boolean" | "Byte" | "Char" | "Float" | "Int" | "Long" | "Short" | "Double" => Nil
case "java.util.UUID" | "java.net.URI" | "java.net.URL" | "java.util.Calendar" | "java.math.BigInteger" | "java.math.BigDecimal" |
"java.io.File" =>
case "java.util.UUID" | "java.net.URI" | "java.net.URL" | "java.util.Date" | "java.util.Calendar" | "java.math.BigInteger" |
"java.math.BigDecimal" | "java.io.File" =>
Nil
case "StringStringMap" => Nil
case "Throwable" | "java.lang.Throwable" => Nil
Expand Down
31 changes: 30 additions & 1 deletion library/src/test/scala/GraphQLCodecCodeGenSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package sbt.contraband
import verify._
import java.io.File
import parser.SchemaParser
import ast.{ NamedType, Type }
import GraphQLExample._
import scala.util.Success

Expand Down Expand Up @@ -120,11 +121,39 @@ object GraphQLCodecCodeGenSpec extends BasicTestSuite with EqualLines {
)
}

test("generate a codec for an interfaces, whose child contains custom field") {
val Success(ast) = SchemaParser.parse(intfExampleWithEmbed)
val code = mkCodecCodeGen.generate(ast)

assertEquals(
code(new File("generated", "InterfaceExampleFormats.scala")).stripSpace,
"""/**
| * This code is generated using [[https://www.scala-sbt.org/contraband/ sbt-contraband]].
| */
|
|// DO NOT EDIT MANUALLY
|package generated
|
|import _root_.sjsonnew.JsonFormat
|
|trait InterfaceExampleFormats { self: generated.TestItemDetailFormats with com.example.StatusFormats with sjsonnew.BasicJsonProtocol with generated.ChildTypeFormats =>
| implicit lazy val InterfaceExampleFormat: JsonFormat[com.example.InterfaceExample] = flatUnionFormat1[com.example.InterfaceExample, com.example.ChildType]("type")
|}""".stripMargin.stripSpace
)
}

val codecParents = List("sjsonnew.BasicJsonProtocol")
val instantiateJavaLazy = (s: String) => s"mkLazy($s)"
val javaOption = "com.example.Option"
val scalaArray = "Vector"
val formatsForType: ast.Type => List[String] = CodecCodeGen.formatsForType
val formatsForType: ast.Type => List[String] =
CodecCodeGen.extensibleFormatsForType {
case NamedType(List("com", "example", "Status"), _) =>
"com.example.StatusFormats" :: Nil
case other =>
CodecCodeGen.formatsForType(other)
}

def mkCodecCodeGen: CodecCodeGen =
new CodecCodeGen(codecParents, instantiateJavaLazy, javaOption, scalaArray, formatsForType, Nil)
}
17 changes: 17 additions & 0 deletions library/src/test/scala/GraphQLExample.scala
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,23 @@ type ChildType implements InterfaceExample {
name: String
field: Int
}
"""

val intfExampleWithEmbed = """
package com.example @target(Scala)
@codecPackage("generated")
## Example of an interface
interface InterfaceExample {}
type ChildType implements InterfaceExample {
detail: [com.example.TestItemDetail]
}
type TestItemDetail {
## Indicates whether the event represents a test success, failure, error, skipped, ignored, canceled, pending.
status: com.example.Status!
}
"""

val twoLevelIntfExample = """
Expand Down
15 changes: 7 additions & 8 deletions library/src/test/scala/JsonSchemaExample.scala
Original file line number Diff line number Diff line change
Expand Up @@ -957,7 +957,7 @@ package generated
import _root_.sjsonnew.JsonFormat
trait GreetingsFormats { self: generated.GreetingHeaderFormats with sjsonnew.BasicJsonProtocol with generated.SimpleGreetingFormats with generated.GreetingExtraImplFormats with generated.GreetingWithAttachmentsFormats =>
trait GreetingsFormats { self: generated.GreetingHeaderFormats with generated.PriorityLevelFormats with sjsonnew.BasicJsonProtocol with generated.SimpleGreetingFormats with generated.GreetingExtraImplFormats with generated.GreetingWithAttachmentsFormats =>
implicit lazy val GreetingsFormat: JsonFormat[com.example.Greetings] = flatUnionFormat3[com.example.Greetings, com.example.SimpleGreeting, com.example.GreetingExtraImpl, com.example.GreetingWithAttachments]("type")
}
/**
Expand All @@ -969,7 +969,7 @@ package generated
import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError }
trait SimpleGreetingFormats { self: generated.GreetingHeaderFormats with sjsonnew.BasicJsonProtocol =>
trait SimpleGreetingFormats { self: generated.GreetingHeaderFormats with generated.PriorityLevelFormats with sjsonnew.BasicJsonProtocol =>
implicit lazy val SimpleGreetingFormat: JsonFormat[com.example.SimpleGreeting] = new JsonFormat[com.example.SimpleGreeting] {
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): com.example.SimpleGreeting = {
__jsOpt match {
Expand Down Expand Up @@ -1000,7 +1000,7 @@ package generated
import _root_.sjsonnew.JsonFormat
trait GreetingExtraFormats { self: generated.GreetingHeaderFormats with sjsonnew.BasicJsonProtocol with generated.GreetingExtraImplFormats =>
trait GreetingExtraFormats { self: generated.GreetingHeaderFormats with generated.PriorityLevelFormats with sjsonnew.BasicJsonProtocol with generated.GreetingExtraImplFormats =>
implicit lazy val GreetingExtraFormat: JsonFormat[com.example.GreetingExtra] = flatUnionFormat1[com.example.GreetingExtra, com.example.GreetingExtraImpl]("type")
}
/**
Expand All @@ -1012,7 +1012,7 @@ package generated
import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError }
trait GreetingExtraImplFormats { self: generated.GreetingHeaderFormats with sjsonnew.BasicJsonProtocol =>
trait GreetingExtraImplFormats { self: generated.GreetingHeaderFormats with generated.PriorityLevelFormats with sjsonnew.BasicJsonProtocol =>
implicit lazy val GreetingExtraImplFormat: JsonFormat[com.example.GreetingExtraImpl] = new JsonFormat[com.example.GreetingExtraImpl] {
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): com.example.GreetingExtraImpl = {
__jsOpt match {
Expand Down Expand Up @@ -1047,7 +1047,7 @@ package generated
import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError }
trait GreetingWithAttachmentsFormats { self: generated.GreetingHeaderFormats with sjsonnew.BasicJsonProtocol =>
trait GreetingWithAttachmentsFormats { self: generated.GreetingHeaderFormats with generated.PriorityLevelFormats with sjsonnew.BasicJsonProtocol =>
implicit lazy val GreetingWithAttachmentsFormat: JsonFormat[com.example.GreetingWithAttachments] = new JsonFormat[com.example.GreetingWithAttachments] {
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): com.example.GreetingWithAttachments = {
__jsOpt match {
Expand Down Expand Up @@ -1080,7 +1080,7 @@ package generated
import _root_.sjsonnew.{ Unbuilder, Builder, JsonFormat, deserializationError }
trait GreetingHeaderFormats { self: java.util.DateFormats with generated.PriorityLevelFormats with sjsonnew.BasicJsonProtocol =>
trait GreetingHeaderFormats { self: generated.PriorityLevelFormats with sjsonnew.BasicJsonProtocol =>
implicit lazy val GreetingHeaderFormat: JsonFormat[com.example.GreetingHeader] = new JsonFormat[com.example.GreetingHeader] {
override def read[J](__jsOpt: Option[J], unbuilder: Unbuilder[J]): com.example.GreetingHeader = {
__jsOpt match {
Expand Down Expand Up @@ -1143,8 +1143,7 @@ implicit lazy val PriorityLevelFormat: JsonFormat[com.example.PriorityLevel] = n
// DO NOT EDIT MANUALLY
package generated
trait CustomProtocol extends java.util.DateFormats
with sjsonnew.BasicJsonProtocol
trait CustomProtocol extends sjsonnew.BasicJsonProtocol
with generated.PriorityLevelFormats
with generated.GreetingHeaderFormats
with generated.SimpleGreetingFormats
Expand Down

0 comments on commit 106a608

Please sign in to comment.