Skip to content

Commit

Permalink
Merge pull request #429 from fd4s/generic-scala3
Browse files Browse the repository at this point in the history
Generic derivation in Scala 3
  • Loading branch information
bplommer authored Mar 9, 2022
2 parents 814d9dd + 0114a25 commit b7442db
Show file tree
Hide file tree
Showing 34 changed files with 671 additions and 315 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,7 @@
/website/variables.js
/website/yarn.lock
target/
.metals/
.vscode/
.bloop/
metals.sbt
102 changes: 56 additions & 46 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,22 @@ val catsVersion = "2.7.0"

val enumeratumVersion = "1.7.0"

val magnoliaVersion = "0.17.0"
val magnolia2Version = "0.17.0"

val magnolia3Version = "1.1.0"

val refinedVersion = "0.9.27"

val shapelessVersion = "2.3.8"

val shapeless3Version = "3.0.4"

val scala212 = "2.12.14"
val scala212 = "2.12.15"

val scala213 = "2.13.8"

val scala3 = "3.0.2"
val scala3_1 = "3.1.1" // used in generic module as requiried for Magnolia

lazy val vulcan = project
.in(file("."))
Expand Down Expand Up @@ -77,19 +80,22 @@ lazy val generic = project
libraryDependencies ++= {
if (scalaVersion.value.startsWith("2"))
Seq(
"com.propensive" %% "magnolia" % magnoliaVersion,
"com.propensive" %% "magnolia" % magnolia2Version,
"com.chuusai" %% "shapeless" % shapelessVersion,
"org.scala-lang" % "scala-reflect" % scalaVersion.value % Provided
)
else
Seq("org.typelevel" %% "shapeless3-deriving" % shapeless3Version)
Seq(
"com.softwaremill.magnolia1_3" %% "magnolia" % magnolia3Version,
"org.typelevel" %% "shapeless3-deriving" % shapeless3Version
)
}
),
scalatestSettings,
publishSettings,
mimaSettings(excludeScala3 = true), // re-include scala 3 after publishing
scalaSettings ++ Seq(
crossScalaVersions += scala3
crossScalaVersions += scala3_1
),
testSettings
)
Expand Down Expand Up @@ -202,47 +208,51 @@ lazy val mdocSettings = Seq(
lazy val buildInfoSettings = Seq(
buildInfoPackage := "vulcan.build",
buildInfoObject := "info",
buildInfoKeys := Seq[BuildInfoKey](
scalaVersion,
scalacOptions,
sourceDirectory,
ThisBuild / latestVersion,
BuildInfoKey.map(ThisBuild / version) {
case (_, v) => "latestSnapshotVersion" -> v
},
BuildInfoKey.map(core / moduleName) {
case (k, v) => "core" ++ k.capitalize -> v
},
BuildInfoKey.map(core / crossScalaVersions) {
case (k, v) => "core" ++ k.capitalize -> v
},
BuildInfoKey.map(enumeratum / moduleName) {
case (k, v) => "enumeratum" ++ k.capitalize -> v
},
BuildInfoKey.map(enumeratum / crossScalaVersions) {
case (k, v) => "enumeratum" ++ k.capitalize -> v
},
BuildInfoKey.map(generic / moduleName) {
case (k, v) => "generic" ++ k.capitalize -> v
},
BuildInfoKey.map(generic / crossScalaVersions) {
case (k, v) => "generic" ++ k.capitalize -> v
},
BuildInfoKey.map(refined / moduleName) {
case (k, v) => "refined" ++ k.capitalize -> v
},
BuildInfoKey.map(refined / crossScalaVersions) {
case (k, v) => "refined" ++ k.capitalize -> v
},
LocalRootProject / organization,
core / crossScalaVersions,
BuildInfoKey("avroVersion" -> avroVersion),
BuildInfoKey("catsVersion" -> catsVersion),
BuildInfoKey("enumeratumVersion" -> enumeratumVersion),
BuildInfoKey("magnoliaVersion" -> magnoliaVersion),
BuildInfoKey("refinedVersion" -> refinedVersion),
BuildInfoKey("shapelessVersion" -> shapelessVersion)
)
buildInfoKeys := {
val magnolia: String =
if (scalaVersion.value.startsWith("3")) magnolia3Version else magnolia2Version
Seq[BuildInfoKey](
scalaVersion,
scalacOptions,
sourceDirectory,
ThisBuild / latestVersion,
BuildInfoKey.map(ThisBuild / version) {
case (_, v) => "latestSnapshotVersion" -> v
},
BuildInfoKey.map(core / moduleName) {
case (k, v) => "core" ++ k.capitalize -> v
},
BuildInfoKey.map(core / crossScalaVersions) {
case (k, v) => "core" ++ k.capitalize -> v
},
BuildInfoKey.map(enumeratum / moduleName) {
case (k, v) => "enumeratum" ++ k.capitalize -> v
},
BuildInfoKey.map(enumeratum / crossScalaVersions) {
case (k, v) => "enumeratum" ++ k.capitalize -> v
},
BuildInfoKey.map(generic / moduleName) {
case (k, v) => "generic" ++ k.capitalize -> v
},
BuildInfoKey.map(generic / crossScalaVersions) {
case (k, v) => "generic" ++ k.capitalize -> v
},
BuildInfoKey.map(refined / moduleName) {
case (k, v) => "refined" ++ k.capitalize -> v
},
BuildInfoKey.map(refined / crossScalaVersions) {
case (k, v) => "refined" ++ k.capitalize -> v
},
LocalRootProject / organization,
core / crossScalaVersions,
BuildInfoKey("avroVersion" -> avroVersion),
BuildInfoKey("catsVersion" -> catsVersion),
BuildInfoKey("enumeratumVersion" -> enumeratumVersion),
BuildInfoKey("magnoliaVersion" -> magnolia),
BuildInfoKey("refinedVersion" -> refinedVersion),
BuildInfoKey("shapelessVersion" -> shapelessVersion)
)
}
)

lazy val metadataSettings = Seq(
Expand Down
2 changes: 1 addition & 1 deletion docs/src/main/mdoc/modules.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ Codec[Day]

## Generic

The `@GENERIC_MODULE_NAME@` module provides generic derivation of [`Codec`][codec]s using [Magnolia](https://github.com/propensive/magnolia) for records and unions (currently not supported in Scala 3), and reflection for enumerations and fixed types.
The `@GENERIC_MODULE_NAME@` module provides generic derivation of [`Codec`][codec]s using [Magnolia](https://github.com/softwaremill/magnolia) for records and unions, and reflection for enumerations and fixed types.

To derive [`Codec`][codec]s for `case class`es or `sealed trait`s, we can use `Codec.derive`. Annotations like `@AvroDoc` and `@AvroNamespace` can be used to customize the documentation and namespace during derivation.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,14 @@ package object generic {
.collectFirst { case AvroNamespace(namespace) => namespace }
.getOrElse(caseClass.typeName.owner)

val shortName =
caseClass.annotations
.collectFirst { case AvroName(namespace) => namespace }
.getOrElse(caseClass.typeName.short)

val typeName =
s"$namespace.${caseClass.typeName.short}"
s"$namespace.$shortName"

val schema =
if (caseClass.isValueClass) {
caseClass.parameters.head.typeclass.schema
Expand Down
Loading

0 comments on commit b7442db

Please sign in to comment.