From 6d8424a28936679d621acb8d47fbfc90e03121bf Mon Sep 17 00:00:00 2001 From: Binh Nguyen Date: Mon, 17 Sep 2018 11:21:34 +0700 Subject: [PATCH] Update scalameta to 4.0.0 RC1 (#53) * Update sbt to 1.2.1 * Migrage to scalameta 4.0.0-RC1 * Document ScalametaUtils * Construct Term.Ref and Type.Ref by hand * Format files * Simplify command and remove unused vars * Run scalafmt --- build.sbt | 5 ++- project/build.properties | 2 +- project/plugins.sbt | 2 +- .../codegen/ApolloSourceGenerator.scala | 4 +- .../muki/graphql/codegen/CodeGenStyles.scala | 6 +-- .../codegen/GraphQLQueryGenerator.scala | 2 +- ...nerator.scala => ScalametaGenerator.scala} | 25 ++++++------ .../muki/graphql/codegen/ScalametaUtils.scala | 40 +++++++++++++++++++ 8 files changed, 64 insertions(+), 22 deletions(-) rename src/main/scala/rocks/muki/graphql/codegen/{ScalaSourceGenerator.scala => ScalametaGenerator.scala} (92%) create mode 100644 src/main/scala/rocks/muki/graphql/codegen/ScalametaUtils.scala diff --git a/build.sbt b/build.sbt index 9300dbc..0e10fb3 100644 --- a/build.sbt +++ b/build.sbt @@ -1,6 +1,7 @@ name := "sbt-graphql" organization := "rocks.muki" sbtPlugin := true +enablePlugins(SbtPlugin) val circeVersion = "0.9.3" val catsVersion = "1.4.0" @@ -12,8 +13,8 @@ libraryDependencies ++= Seq( "org.typelevel" %% "cats-core" % catsVersion, "org.typelevel" %% "cats-testkit" % catsVersion % Test, "org.scalaj" %% "scalaj-http" % "2.3.0", - "org.scalameta" %% "scalameta" % "3.7.4", - "org.scalatest" %% "scalatest" % "3.0.4" % Test + "org.scalameta" %% "scalameta" % "4.0.0-RC1", + "org.scalatest" %% "scalatest" % "3.0.5" % Test ) // scripted test settings diff --git a/project/build.properties b/project/build.properties index 8b697bb..0cd8b07 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=1.1.0 +sbt.version=1.2.3 diff --git a/project/plugins.sbt b/project/plugins.sbt index e902dd8..f38f1d1 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -8,7 +8,7 @@ addSbtPlugin("com.typesafe.sbt" % "sbt-git" % "0.9.3") addSbtPlugin("com.dwijnand" % "sbt-travisci" % "1.1.1") // plugin project -libraryDependencies += "org.typelevel" %% "cats-core" % "1.0.0-MF" +libraryDependencies += "org.typelevel" %% "cats-core" % "1.4.0" // testing libraryDependencies += "org.scala-sbt" %% "scripted-plugin" % sbtVersion.value diff --git a/src/main/scala/rocks/muki/graphql/codegen/ApolloSourceGenerator.scala b/src/main/scala/rocks/muki/graphql/codegen/ApolloSourceGenerator.scala index fbb993b..d884428 100644 --- a/src/main/scala/rocks/muki/graphql/codegen/ApolloSourceGenerator.scala +++ b/src/main/scala/rocks/muki/graphql/codegen/ApolloSourceGenerator.scala @@ -259,7 +259,7 @@ case class ApolloSourceGenerator(fileName: String, generateFieldType(field) { tpe => if (field.isObjectLike || field.isUnion) { // prepend the type qualifier for nested object/case class structures - Type.Name((typeQualifiers :+ field.name.capitalize).mkString(".")) + ScalametaUtils.typeRefOf(typeQualifiers, field.name.capitalize) } else { // this branch handles non-enum or case class types, which means we don't need the // typeQualifiers here. @@ -310,7 +310,7 @@ case class ApolloSourceGenerator(fileName: String, val tpe = generateFieldType(field) { tpe => field.selection.map(_.interfaces).filter(_.nonEmpty) match { case Some(interfaces) => - interfaces.map(x => Type.Name(x): Type).reduce(Type.With(_, _)) + interfaces.map(t => Type.Name(t): Type).reduce(Type.With(_, _)) case None => Type.Name(tpe.namedType.name) } diff --git a/src/main/scala/rocks/muki/graphql/codegen/CodeGenStyles.scala b/src/main/scala/rocks/muki/graphql/codegen/CodeGenStyles.scala index f4ce9ea..d41b01a 100644 --- a/src/main/scala/rocks/muki/graphql/codegen/CodeGenStyles.scala +++ b/src/main/scala/rocks/muki/graphql/codegen/CodeGenStyles.scala @@ -27,7 +27,7 @@ object CodeGenStyles { val Apollo: Style = context => { val schema = context.schema val inputFiles = context.graphQLFiles - val packageName = Term.Name(context.packageName) + val packageName = ScalametaUtils.termRefOf(context.packageName) // Generate the GraphQLQuery trait val graphQLQueryFile = context.targetDirectory / s"${GraphQLQueryGenerator.name}.scala" @@ -129,7 +129,7 @@ object CodeGenStyles { val Sangria: Style = context => { val schema = context.schema val inputFiles = context.graphQLFiles - val packageName = Term.Name(context.packageName) + val packageName = ScalametaUtils.termRefOf(context.packageName) val result = for { queryDocument <- DocumentLoader.merged(schema, inputFiles.toList) @@ -151,7 +151,7 @@ object CodeGenStyles { case Right(file) => List(file) case Left(error) => - context.log.err(s"Error during code genreation $error") + context.log.err(s"Error during code generation $error") sys.error("Code generation failed") } diff --git a/src/main/scala/rocks/muki/graphql/codegen/GraphQLQueryGenerator.scala b/src/main/scala/rocks/muki/graphql/codegen/GraphQLQueryGenerator.scala index 81ef8c3..0202bb6 100644 --- a/src/main/scala/rocks/muki/graphql/codegen/GraphQLQueryGenerator.scala +++ b/src/main/scala/rocks/muki/graphql/codegen/GraphQLQueryGenerator.scala @@ -40,7 +40,7 @@ object GraphQLQueryGenerator { * @return the GraphQLTrait source code */ def sourceCode(packageName: String): Pkg = - q"""package ${Term.Name(packageName)} { + q"""package ${ScalametaUtils.termRefOf(packageName)} { $traitDefinition }""" diff --git a/src/main/scala/rocks/muki/graphql/codegen/ScalaSourceGenerator.scala b/src/main/scala/rocks/muki/graphql/codegen/ScalametaGenerator.scala similarity index 92% rename from src/main/scala/rocks/muki/graphql/codegen/ScalaSourceGenerator.scala rename to src/main/scala/rocks/muki/graphql/codegen/ScalametaGenerator.scala index 0dbbd3d..b87602c 100644 --- a/src/main/scala/rocks/muki/graphql/codegen/ScalaSourceGenerator.scala +++ b/src/main/scala/rocks/muki/graphql/codegen/ScalametaGenerator.scala @@ -54,9 +54,9 @@ case class ScalametaGenerator(moduleName: Term.Name, def generateTemplate(traits: List[String], prefix: String = moduleName.value + "."): Template = { // TODO fix constructor names - val templateInits = traits - .map(prefix + _) - .map(name => Init(Type.Name(name), Name.Anonymous(), Nil)) + val templateInits = traits.map(name => + Init(ScalametaUtils.typeRefOf(prefix, name), Name.Anonymous(), Nil)) + val emptySelf = Self(Name.Anonymous(), None) Template(Nil, templateInits, emptySelf, List.empty) @@ -74,7 +74,7 @@ case class ScalametaGenerator(moduleName: Term.Name, case schema.ListInputType(wrapped) => t"List[${typeOf(wrapped)}]" case tpe: schema.ScalarType[_] if tpe == schema.IDType => - Type.Name(moduleName.value + ".ID") + ScalametaUtils.typeRefOf(moduleName.value, "ID") case tpe: schema.Type => genType(tpe) } @@ -85,7 +85,7 @@ case class ScalametaGenerator(moduleName: Term.Name, def fieldType(field: TypedDocument.Field, prefix: String = ""): Type = generateFieldType(field) { tpe => if (field.isObjectLike || field.isUnion) - Type.Name(prefix + field.name.capitalize) + ScalametaUtils.typeRefOf(prefix, field.name.capitalize) else Type.Name(tpe.namedType.name) } @@ -101,7 +101,7 @@ case class ScalametaGenerator(moduleName: Term.Name, selection: TypedDocument.Selection): List[Stat] = selection.fields.flatMap { // render enumerations (union types) - case TypedDocument.Field(name, tpe, None, unionTypes) + case TypedDocument.Field(name, _, None, unionTypes) if unionTypes.nonEmpty => val unionName = Type.Name(name.capitalize) val objectName = Term.Name(unionName.value) @@ -129,7 +129,7 @@ case class ScalametaGenerator(moduleName: Term.Name, ) // render a nested case class for a deeper selection - case TypedDocument.Field(name, tpe, Some(selection), _) => + case TypedDocument.Field(name, _, Some(selection), _) => val stats = generateSelectionStats(prefix + name.capitalize + ".")(selection) val params = @@ -158,14 +158,15 @@ case class ScalametaGenerator(moduleName: Term.Name, termParam(varDef.name, fieldType(varDef)) } - val name = operation.name.getOrElse(sys.error("found unnamed operation")) - val prefix = moduleName.value + "." + name + "." + val operationName = + operation.name.getOrElse(sys.error("found unnamed operation")) + val prefix = moduleName.value + "." + operationName + "." val stats = generateSelectionStats(prefix)(operation.selection) val params = generateSelectionParams(prefix)(operation.selection) - val tpeName = Type.Name(name) - val termName = Term.Name(name) - val variableTypeName = Type.Name(name + "Variables") + val tpeName = Type.Name(operationName) + val termName = Term.Name(operationName) + val variableTypeName = Type.Name(operationName + "Variables") List[Stat]( q"case class $tpeName(..$params)", diff --git a/src/main/scala/rocks/muki/graphql/codegen/ScalametaUtils.scala b/src/main/scala/rocks/muki/graphql/codegen/ScalametaUtils.scala new file mode 100644 index 0000000..b4bfc19 --- /dev/null +++ b/src/main/scala/rocks/muki/graphql/codegen/ScalametaUtils.scala @@ -0,0 +1,40 @@ +package rocks.muki.graphql.codegen + +import scala.meta._ + +/** + * More robust way to parse [[Type.Ref]] and [[Term.Ref]] from String. + * More discussion: https://gitter.im/scalameta/scalameta?at=5b9ba14f8909f71f75d1b4bd + */ +object ScalametaUtils { + + def typeRefOf(typeTerm: String): Type.Ref = { + typeTerm.parse[Type].get.asInstanceOf[Type.Ref] + } + + def typeRefOf(term: String, typeTerm: String): Type.Ref = { + typeRefOf(term.split('.'), typeTerm) + } + + def typeRefOf(terms: Seq[String], typeTerm: String): Type.Ref = { + if (terms.isEmpty) { + Type.Name(typeTerm) + } else { + Type.Select(termRefOf(terms), Type.Name(typeTerm)) + } + } + + // terms must not be empty + def termRefOf(terms: Seq[String]): Term.Ref = { + val termArray = terms.map(Term.Name(_)) + termArray.headOption.fold( + throw new IllegalStateException("Term must not be empty") + ) { head => + termArray.drop(1).foldLeft[Term.Ref](head)((r, t) => Term.Select(r, t)) + } + } + + def termRefOf(term: String): Term.Ref = { + termRefOf(term.split('.')) + } +}