Skip to content

Commit

Permalink
Add rawSchema inclusion with test
Browse files Browse the repository at this point in the history
  • Loading branch information
travisbrown committed Nov 10, 2020
1 parent 1ceb19a commit 9046e53
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 18 deletions.
42 changes: 24 additions & 18 deletions argus/src/main/scala/argus/macros/FromSchema.scala
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,11 @@ object JsonEngs {
* @param outPathPackage Optional package name, that if specified and if outPath also specified writes the package name
* to the output file (defaults to None, so no package name is written).
* @param name The name used for the root case class that is generated. Defaults to "Root"
* @param rawSchema Includes the raw schema string in the companion object
*/
@compileTimeOnly("You must enable the macro paradise plugin.")
class fromSchemaJson(json: String, debug: Boolean = false, jsonEng: Option[JsonEng] = None, outPath: Option[String] = None,
outPathPackage: Option[String] = None, name: String = "Root") extends StaticAnnotation {
outPathPackage: Option[String] = None, name: String = "Root", rawSchema: Boolean = false) extends StaticAnnotation {
def macroTransform(annottees: Any*): Any = macro SchemaMacros.fromSchemaMacroImpl
}

Expand All @@ -41,10 +42,11 @@ class fromSchemaJson(json: String, debug: Boolean = false, jsonEng: Option[JsonE
* @param outPathPackage Optional package name, that if specified and if outPath also specified writes the package name
* to the output file (defaults to None, so no package name is written).
* @param name The name used for the root case class that is generated. Defaults to "Root"
* @param rawSchema Includes the raw schema string in the companion object
*/
@compileTimeOnly("You must enable the macro paradise plugin.")
class fromSchemaResource(path: String, debug: Boolean = false, jsonEng: Option[JsonEng] = None, outPath: Option[String] = None,
outPathPackage: Option[String] = None, name: String = "Root") extends StaticAnnotation {
outPathPackage: Option[String] = None, name: String = "Root", rawSchema: Boolean = false) extends StaticAnnotation {
def macroTransform(annottees: Any*): Any = macro SchemaMacros.fromSchemaMacroImpl
}

Expand All @@ -59,10 +61,11 @@ class fromSchemaResource(path: String, debug: Boolean = false, jsonEng: Option[J
* @param outPathPackage Optional package name, that if specified and if outPath also specified writes the package name
* to the output file (defaults to None, so no package name is written).
* @param name The name used for the root case class that is generated. Defaults to "Root"
* @param rawSchema Includes the raw schema string in the companion object
*/
@compileTimeOnly("You must enable the macro paradise plugin.")
class fromSchemaURL(url: String, debug: Boolean = false, jsonEng: Option[JsonEng] = None, outPath: Option[String],
outPathPackage: Option[String] = None, name: String = "Root") extends StaticAnnotation {
outPathPackage: Option[String] = None, name: String = "Root", rawSchema: Boolean = false) extends StaticAnnotation {
def macroTransform(annottees: Any*): Any = macro SchemaMacros.fromSchemaMacroImpl
}

Expand All @@ -75,17 +78,17 @@ class SchemaMacros(val c: Context) {
private val helpers = new ASTHelpers[c.universe.type](c.universe)
import helpers._

case class Params(schema: Schema.Root, rawSchema: String, debug: Boolean, jsonEnd: Option[JsonEng], outPath: Option[String],
outPathPackage: Option[String], name: String)
case class Params(schema: Schema.Root, debug: Boolean, jsonEnd: Option[JsonEng], outPath: Option[String],
outPathPackage: Option[String], name: String, rawSchema: Option[String])

private def extractParams(prefix: Tree): Params = {
val q"new $name (..$paramASTs)" = prefix
val (Ident(TypeName(fn: String))) = name

val commonParams = ("debug", false) :: ("jsonEng", q"Some(JsonEngs.Circe)") :: ("outPath", None) ::
("outPathPackage", None) :: ("name", "Root") :: Nil
("outPathPackage", None) :: ("name", "Root") :: ("rawSchema", false) :: Nil

val (paramsWithoutSchema, schemaString)= fn match {
val (params, schemaString)= fn match {
case "fromSchemaResource" => {
val params = paramsToMap(("path", "Path missing") :: commonParams, paramASTs)
(params, Source.fromInputStream(getClass.getResourceAsStream(params("path").asInstanceOf[String])).getLines().mkString("\n"))
Expand All @@ -102,16 +105,20 @@ class SchemaMacros(val c: Context) {

case _ => c.abort(c.enclosingPosition, "Didn't know annotation " + fn)
}
val params = paramsWithoutSchema + ("schema" -> Schema.fromJson(schemaString)) + ("rawSchema" -> schemaString)
val rawSchema = if (params("rawSchema").asInstanceOf[Boolean]) {
Some(schemaString)
} else {
None
}

Params(
params("schema").asInstanceOf[Schema.Root],
params("rawSchema").asInstanceOf[String],
Schema.fromJson(schemaString),
params("debug").asInstanceOf[Boolean],
params("jsonEng") match { case q"Some(JsonEngs.Circe)" => Some(JsonEngs.Circe); case q"None" => None },
params("outPath").asInstanceOf[Option[String]],
params("outPathPackage").asInstanceOf[Option[String]],
params("name").asInstanceOf[String]
params("name").asInstanceOf[String],
rawSchema
)
}

Expand Down Expand Up @@ -149,9 +156,7 @@ class SchemaMacros(val c: Context) {
def fromSchemaMacroImpl(annottees: c.Expr[Any]*): c.Expr[Any] = {
val params = extractParams(c.prefix.tree)
val schema = params.schema
val schemaString = params.rawSchema
val name = TypeName(params.name)
val hasSchemaInstanceName = TermName(params.name + "HasSchema")
val rawSchema = params.rawSchema.map(_.filter(_ != '\n'))

val result: Tree = annottees map (_.tree) match {

Expand All @@ -160,16 +165,17 @@ class SchemaMacros(val c: Context) {

val (_, defs) = modelBuilder.mkSchemaDef(params.name, schema)

val rawSchemaDef = rawSchema.map { s =>
q"""val rawSchema: String = $s"""
}.toList

q"""
$mods object $tname extends { ..$earlydefns } with ..$parents { $self =>
..$stats

class enum extends scala.annotation.StaticAnnotation
class union extends scala.annotation.StaticAnnotation
val schemaString = $schemaString.filter(_ != '\n')
implicit val $hasSchemaInstanceName: jsonschema.HasSchema[$name] = new jsonschema.HasSchema[$name] {
override val schema: String = schemaString
}
..$rawSchemaDef
..$defs
..${ mkCodecs(params.jsonEnd, defs, tname.toString :: Nil) }
}
Expand Down
22 changes: 22 additions & 0 deletions argus/src/test/scala/argus/macros/FromSchemaSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -592,6 +592,28 @@ class FromSchemaSpec extends AnyFlatSpec with Matchers with JsonMatchers {
Schema.Person(age=Some(42)).age should === (Some(42))
}

it should "support raw schema inclusion" in {
val expected = """
{
"definitions" : {
"SSN" : { "type": "string" },
"Names" : { "type": "array", "items": { "type": "string" } }
}
}
""".filter(_ != '\n')

@fromSchemaJson("""
{
"definitions" : {
"SSN" : { "type": "string" },
"Names" : { "type": "array", "items": { "type": "string" } }
}
}
""", rawSchema = true)
object Foo

Foo.rawSchema should === (expected)
}
"Complex example" should "work end to end" in {
@fromSchemaResource("/vega-lite-schema.json")
object Vega
Expand Down

0 comments on commit 9046e53

Please sign in to comment.