Skip to content

Commit

Permalink
Merge pull request #1486 from astridej/use-circe-in-codegen
Browse files Browse the repository at this point in the history
Switch out uPickle for Circe in codegen
  • Loading branch information
Baccata authored Apr 12, 2024
2 parents ee9abfb + fa554a4 commit 189df10
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 56 deletions.
4 changes: 3 additions & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -373,7 +373,9 @@ lazy val codegen = projectMatrix
Dependencies.Alloy.openapi,
Dependencies.Smithytranslate.proto,
"com.lihaoyi" %% "os-lib" % "0.9.3",
"com.lihaoyi" %% "upickle" % "3.2.0",
Dependencies.Circe.core.value,
Dependencies.Circe.parser.value,
Dependencies.Circe.generic.value,
Dependencies.collectionsCompat.value,
"org.scala-lang" % "scala-reflect" % scalaVersion.value,
"io.get-coursier" %% "coursier" % "2.1.9"
Expand Down
57 changes: 19 additions & 38 deletions modules/codegen/src/smithy4s/codegen/SmithyBuildJson.scala
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,9 @@ package smithy4s.codegen
import smithy4s.codegen.internals.SmithyBuild
import smithy4s.codegen.internals.SmithyBuildMaven
import smithy4s.codegen.internals.SmithyBuildMavenRepository
import upickle.default._
import io.circe.{Json, parser}

private[codegen] object SmithyBuildJson {

def toJson(
imports: Seq[String],
dependencies: Seq[String],
Expand All @@ -43,47 +42,29 @@ private[codegen] object SmithyBuildJson {
def merge(
json1: String,
json2: String
): String = {
val j1 = read[ujson.Value](json1)
val j2 = read[ujson.Value](json2)
val merged = mergeJs(j1, j2)
val finalJs = removeArrayDuplicates(merged)
finalJs.render(indent = 4)
}
): String = (for {
j1 <- parser.parse(json1)
j2 <- parser.parse(json2)
merged = mergeJs(j1, j2)
} yield merged).left.map(err => throw err).merge.spaces4

private def mergeJs(
v1: ujson.Value,
v2: ujson.Value
): ujson.Value = {
(v1, v2) match {
case (ujson.Obj(obj1), ujson.Obj(obj2)) =>
val result = obj2.foldLeft(obj1.toMap) {
case (elements, (key, value2)) =>
val value = elements.get(key) match {
case None =>
value2
case Some(value1) =>
mergeJs(value1, value2)
v1: Json,
v2: Json
): Json = {
(v1.asObject, v2.asObject, v1.asArray, v2.asArray) match {
// copied from circe's deepMerge method, however in order to handle concat + deduplication on arrays we need to do it manually here
case (Some(lhs), Some(rhs), _, _) =>
Json.fromJsonObject(
lhs.toIterable.foldLeft(rhs) { case (acc, (key, value)) =>
rhs(key).fold(acc.add(key, value)) { r =>
acc.add(key, mergeJs(value, r))
}
elements.updated(key, value)
}
ujson.Obj.from(result)
case (arr1: ujson.Arr, arr2: ujson.Arr) =>
ujson.Arr(arr1.arr ++ arr2.arr)
case (_, _) => v1
}
}

private def removeArrayDuplicates(js: ujson.Value): ujson.Value = {
js match {
case ujson.Obj(obj1) =>
ujson.Obj.from(
obj1.toList.map { case (key, value) =>
key -> removeArrayDuplicates(value)
}
)
case (arr1: ujson.Arr) => arr1.arr.distinct
case x => x
case (_, _, Some(arr1), Some(arr2)) =>
Json.arr((arr1 ++ arr2).distinct: _*)
case _ => v1
}
}
}
12 changes: 7 additions & 5 deletions modules/codegen/src/smithy4s/codegen/internals/SmithyBuild.scala
Original file line number Diff line number Diff line change
Expand Up @@ -17,29 +17,31 @@
package smithy4s.codegen
package internals

import upickle.default._
import io.circe.Codec
import io.circe.generic.semiauto._
import io.circe.syntax._

private[internals] final case class SmithyBuild(
version: String,
imports: Seq[String],
maven: SmithyBuildMaven
)
private[codegen] object SmithyBuild {
implicit val codecs: ReadWriter[SmithyBuild] = macroRW
def writeJson(sb: SmithyBuild): String = write(sb, indent = 4)
implicit val codecs: Codec[SmithyBuild] = deriveCodec
def writeJson(sb: SmithyBuild): String = sb.asJson.spaces4
}

private[internals] final case class SmithyBuildMaven(
dependencies: Seq[String],
repositories: Seq[SmithyBuildMavenRepository]
)
private[codegen] object SmithyBuildMaven {
implicit val codecs: ReadWriter[SmithyBuildMaven] = macroRW
implicit val codecs: Codec[SmithyBuildMaven] = deriveCodec
}

private[internals] final case class SmithyBuildMavenRepository(
url: String
)
private[codegen] object SmithyBuildMavenRepository {
implicit val codecs: ReadWriter[SmithyBuildMavenRepository] = macroRW
implicit val codecs: Codec[SmithyBuildMavenRepository] = deriveCodec
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,17 +30,17 @@ final class SmithyBuildSpec extends munit.FunSuite {
assertEquals(
actual,
"""|{
| "version": "1.0",
| "imports": [
| "version" : "1.0",
| "imports" : [
| "src/"
| ],
| "maven": {
| "dependencies": [
| "maven" : {
| "dependencies" : [
| "dep"
| ],
| "repositories": [
| "repositories" : [
| {
| "url": "repo"
| "url" : "repo"
| }
| ]
| }
Expand Down Expand Up @@ -73,18 +73,61 @@ final class SmithyBuildSpec extends munit.FunSuite {
assertEquals(
actual,
"""|{
| "version": "1.0",
| "imports": [
| "version" : "1.0",
| "imports" : [
| "src/main/smithy"
| ],
| "maven": {
| "dependencies": [
| "maven" : {
| "dependencies" : [
| "oterh",
| "dep1"
| ],
| "repositories": []
| "repositories" : [
| ]
| },
| "custom" : "attribute"
|}""".stripMargin
)
}

test("merge two json de-duplicating arrays") {
val actual = SmithyBuildJson.merge(
"""|{
| "version": "1.0",
| "imports": ["src/main/smithy"],
| "maven": {
| "dependencies": ["oterh", "dep1"],
| "repositories": []
| }
|}
|""".stripMargin,
"""|{
| "version": "1.0",
| "imports": ["src/main/smithy"],
| "maven": {
| "dependencies": ["dep1"],
| "repositories": []
| },
| "custom": "attribute"
|}
|""".stripMargin
)
assertEquals(
actual,
"""|{
| "version" : "1.0",
| "imports" : [
| "src/main/smithy"
| ],
| "maven" : {
| "dependencies" : [
| "oterh",
| "dep1"
| ],
| "repositories" : [
| ]
| },
| "custom": "attribute"
| "custom" : "attribute"
|}""".stripMargin
)
}
Expand Down

0 comments on commit 189df10

Please sign in to comment.