From d87a7e3c56172ea2a8be777701ca41ec78303f23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mareks=20Ramp=C4=81ns?= <8796159+mr-git@users.noreply.github.com> Date: Wed, 22 Jul 2026 13:25:08 +0300 Subject: [PATCH 01/14] update SBT to 1.12.14 --- project/build.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/build.properties b/project/build.properties index 46e43a9..08bd811 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=1.8.2 +sbt.version = 1.12.14 From e1f97e088ed351f77ed5c3ea73851619ce057820 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mareks=20Ramp=C4=81ns?= <8796159+mr-git@users.noreply.github.com> Date: Wed, 22 Jul 2026 13:30:47 +0300 Subject: [PATCH 02/14] update Scala to 3.3.8 --- project/Version.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/Version.scala b/project/Version.scala index ab6a01c..1b09c2d 100644 --- a/project/Version.scala +++ b/project/Version.scala @@ -1,5 +1,5 @@ object Version { - val scala = "3.2.1" + val scala = "3.3.8" val circe = "0.14.4" From d166c79f0d07745144b1b7ccb830dbde40a7fec9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mareks=20Ramp=C4=81ns?= <8796159+mr-git@users.noreply.github.com> Date: Wed, 22 Jul 2026 13:31:14 +0300 Subject: [PATCH 03/14] update circe to 0.14.16 --- build.sbt | 4 +--- project/Version.scala | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/build.sbt b/build.sbt index 55af674..045f88c 100644 --- a/build.sbt +++ b/build.sbt @@ -1,5 +1,3 @@ -import sbt.librarymanagement.For3Use2_13 - name := "derivation" publish / skip := true @@ -94,7 +92,7 @@ lazy val `circe-compat_213` = project .settings( name := "derivation-circe-compat213", target := (file("modules") / "circe" / "target-compat213" / "jvm").getAbsoluteFile, - libraryDependencies += "io.circe" %% "circe-core" % Version.circe cross For3Use2_13(), + libraryDependencies += "io.circe" %% "circe-core" % Version.circe, defaultSettings, ) .dependsOn(derivation) diff --git a/project/Version.scala b/project/Version.scala index 1b09c2d..d8c259a 100644 --- a/project/Version.scala +++ b/project/Version.scala @@ -1,7 +1,7 @@ object Version { val scala = "3.3.8" - val circe = "0.14.4" + val circe = "0.14.16" val munit = "0.7.29" From a91c6fb4906b715291fe78988f794838a89ef6d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mareks=20Ramp=C4=81ns?= <8796159+mr-git@users.noreply.github.com> Date: Wed, 22 Jul 2026 13:31:35 +0300 Subject: [PATCH 04/14] update munit to 1.3.4 --- build.sbt | 2 +- project/Version.scala | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.sbt b/build.sbt index 045f88c..3775944 100644 --- a/build.sbt +++ b/build.sbt @@ -13,7 +13,7 @@ ThisBuild / organizationHomepage := Some(url("https://evolution.com")) ThisBuild / versionScheme := Some("early-semver") -testFrameworks += new TestFramework("munit.Framework") +testFrameworks += TestFrameworks.MUnit val scala3Settings = scalacOptions ++= Vector( "-Yexplicit-nulls", diff --git a/project/Version.scala b/project/Version.scala index d8c259a..262a3c5 100644 --- a/project/Version.scala +++ b/project/Version.scala @@ -3,7 +3,7 @@ object Version { val circe = "0.14.16" - val munit = "0.7.29" + val munit = "1.3.4" val tapir = "1.2.9" From 6dd962cd97e996547c89502b1666e138d4b7e92d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mareks=20Ramp=C4=81ns?= <8796159+mr-git@users.noreply.github.com> Date: Wed, 22 Jul 2026 13:32:02 +0300 Subject: [PATCH 05/14] update tapir to 1.13.28 --- project/Version.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/Version.scala b/project/Version.scala index 262a3c5..ef81d1d 100644 --- a/project/Version.scala +++ b/project/Version.scala @@ -5,7 +5,7 @@ object Version { val munit = "1.3.4" - val tapir = "1.2.9" + val tapir = "1.13.28" val playJson = "2.9.3" From 38896901ddfefff0c7afd0b20c5bf062d3c36841 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mareks=20Ramp=C4=81ns?= <8796159+mr-git@users.noreply.github.com> Date: Wed, 22 Jul 2026 13:32:20 +0300 Subject: [PATCH 06/14] update cats to 2.13.0 --- project/Version.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/Version.scala b/project/Version.scala index ef81d1d..680ebe7 100644 --- a/project/Version.scala +++ b/project/Version.scala @@ -9,5 +9,5 @@ object Version { val playJson = "2.9.3" - val cats = "2.9.0" + val cats = "2.13.0" } From 0d310907e35f4d027c2e22190ea4ea588a1d26a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mareks=20Ramp=C4=81ns?= <8796159+mr-git@users.noreply.github.com> Date: Wed, 22 Jul 2026 13:33:24 +0300 Subject: [PATCH 07/14] switch `play-json` from `com.typesafe.play` to `org.playframework` (2.9.3 -> 3.0.6) --- build.sbt | 2 +- project/Version.scala | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.sbt b/build.sbt index 3775944..b4a5467 100644 --- a/build.sbt +++ b/build.sbt @@ -119,7 +119,7 @@ lazy val playJson = project .in(modules / "playJson") .settings( name := "derivation-play-json", - libraryDependencies += "com.typesafe.play" %% "play-json" % Version.playJson cross CrossVersion.for3Use2_13, + libraryDependencies += "org.playframework" %% "play-json" % Version.playJson, defaultSettings, ) .dependsOn(derivation) diff --git a/project/Version.scala b/project/Version.scala index 680ebe7..fa4afb5 100644 --- a/project/Version.scala +++ b/project/Version.scala @@ -7,7 +7,7 @@ object Version { val tapir = "1.13.28" - val playJson = "2.9.3" + val playJson = "3.0.6" val cats = "2.13.0" } From 0799ecf50399fcfa39a3351e6e22c659b9b13d83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mareks=20Ramp=C4=81ns?= <8796159+mr-git@users.noreply.github.com> Date: Wed, 22 Jul 2026 13:35:40 +0300 Subject: [PATCH 08/14] udpate sbt-scalafmt to 2.6.2 --- project/plugins.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/plugins.sbt b/project/plugins.sbt index 6f267f9..e9606db 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,4 +1,4 @@ -addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.5.0") +addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.6.2") addSbtPlugin("com.github.sbt" % "sbt-release" % "1.1.0") From 58ff593c36c994217f4e0b9fe445418616ff8bab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mareks=20Ramp=C4=81ns?= <8796159+mr-git@users.noreply.github.com> Date: Wed, 22 Jul 2026 13:36:21 +0300 Subject: [PATCH 09/14] udpate sbt-artifactory-plugin to 0.1.2 --- project/plugins.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/plugins.sbt b/project/plugins.sbt index e9606db..0a2a988 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -2,4 +2,4 @@ addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.6.2") addSbtPlugin("com.github.sbt" % "sbt-release" % "1.1.0") -addSbtPlugin("com.evolution" % "sbt-artifactory-plugin" % "0.0.2") +addSbtPlugin("com.evolution" % "sbt-artifactory-plugin" % "0.1.2") From 7bd8b9948de1771504ca638937ac227659bde239 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mareks=20Ramp=C4=81ns?= <8796159+mr-git@users.noreply.github.com> Date: Wed, 22 Jul 2026 13:37:11 +0300 Subject: [PATCH 10/14] udpate scalafmt to 3.11.4 --- .scalafmt.conf | 6 ++++-- build.sbt | 2 ++ .../src/main/scala/evo/derivation/cats/EvoEq.scala | 8 ++++++-- .../main/scala/evo/derivation/circe/EvoCodec.scala | 1 - .../scala/evo/derivation/circe/EvoDecoder.scala | 9 ++++++--- .../scala/evo/derivation/circe/EvoEncoder.scala | 13 ++++++++----- .../derivation/circe/deriveEnumerationCodec.scala | 1 - .../scala/evo/derivation/config/ConfigMacro.scala | 1 - .../main/scala/evo/derivation/config/package.scala | 2 -- .../scala/evo/derivation/internal/product.scala | 1 - .../scala/evo/derivation/template/Template.scala | 9 ++++++--- .../scala/evo/derivation/play/json/EvoReads.scala | 13 +++++++++---- .../scala/evo/derivation/play/json/EvoWrites.scala | 13 ++++++++----- 13 files changed, 49 insertions(+), 30 deletions(-) diff --git a/.scalafmt.conf b/.scalafmt.conf index 13c4a18..5fededf 100644 --- a/.scalafmt.conf +++ b/.scalafmt.conf @@ -1,4 +1,4 @@ -version = "3.7.2" +version = "3.11.4" runner.dialect = scala3 maxColumn = 120 @@ -8,6 +8,8 @@ indent.main = 4 align.preset = most +rewrite.scala3 = common + rewrite.scala3.insertEndMarkerMinLines = 7 -rewrite.scala3.removeEndMarkerMaxLines = 5 \ No newline at end of file +rewrite.scala3.removeEndMarkerMaxLines = 5 diff --git a/build.sbt b/build.sbt index b4a5467..865bd6a 100644 --- a/build.sbt +++ b/build.sbt @@ -15,6 +15,8 @@ ThisBuild / versionScheme := Some("early-semver") testFrameworks += TestFrameworks.MUnit +addCommandAlias("fmt", "scalafmtRepo") + val scala3Settings = scalacOptions ++= Vector( "-Yexplicit-nulls", "-encoding", diff --git a/modules/cats/src/main/scala/evo/derivation/cats/EvoEq.scala b/modules/cats/src/main/scala/evo/derivation/cats/EvoEq.scala index 1889adf..fd1f900 100644 --- a/modules/cats/src/main/scala/evo/derivation/cats/EvoEq.scala +++ b/modules/cats/src/main/scala/evo/derivation/cats/EvoEq.scala @@ -30,12 +30,16 @@ trait EvoEq[A] extends BaseEvoEq[A] with cats.kernel.Eq[A] with Equiv[A]: def equiv(x: A, y: A): Boolean = eqv(x, y) object EvoEq extends ConsistentTemplate[BaseEvoEq, EvoEq] with SummonHierarchy: - override def product[A](using mirror: Mirror.ProductOf[A])(fields: All[BaseEvoEq, mirror.MirroredElemTypes])(using + override def product[A](using + mirror: Mirror.ProductOf[A], + )(fields: All[BaseEvoEq, mirror.MirroredElemTypes])(using => Config[A], A <:< Product, ): EvoEq[A] = ProductEq(fields) - override def sum[A](using mirror: Mirror.SumOf[A])( + override def sum[A](using + mirror: Mirror.SumOf[A], + )( subs: All[BaseEvoEq, mirror.MirroredElemTypes], mkSubMap: => Map[String, BaseEvoEq[A]], )(using config: => Config[A], matching: Matching[A]): EvoEq[A] = SumEq(mkSubMap) diff --git a/modules/circe/src/main/scala/evo/derivation/circe/EvoCodec.scala b/modules/circe/src/main/scala/evo/derivation/circe/EvoCodec.scala index 49e1a2b..8356c80 100644 --- a/modules/circe/src/main/scala/evo/derivation/circe/EvoCodec.scala +++ b/modules/circe/src/main/scala/evo/derivation/circe/EvoCodec.scala @@ -36,5 +36,4 @@ object EvoObjectCodec: export encoder.encodeObject override def decodeAccumulating(c: HCursor) = decoder.decodeAccumulating(c) - end EvoCodecImpl end EvoObjectCodec diff --git a/modules/circe/src/main/scala/evo/derivation/circe/EvoDecoder.scala b/modules/circe/src/main/scala/evo/derivation/circe/EvoDecoder.scala index 751da2d..0ab3831 100644 --- a/modules/circe/src/main/scala/evo/derivation/circe/EvoDecoder.scala +++ b/modules/circe/src/main/scala/evo/derivation/circe/EvoDecoder.scala @@ -24,7 +24,9 @@ object EvoDecoder extends ConsistentTemplate[Decoder, EvoDecoder] with SummonHie type Provide[A] = EvoDecoder[A] - def product[A](using mirror: Mirror.ProductOf[A])( + def product[A](using + mirror: Mirror.ProductOf[A], + )( fields: LazySummon.All[Decoder, mirror.MirroredElemTypes], )(using config: => Config[A], ev: A <:< Product): EvoDecoder[A] = new: @@ -35,7 +37,6 @@ object EvoDecoder extends ConsistentTemplate[Decoder, EvoDecoder] with SummonHie )(decoder: LazySummon.Of[Decoder], info: ForField[_ <: A]): Decoder.Result[decoder.FieldType] = val cursor = if info.embed then cur else cur.downField(info.name) decoder.use(cursor.as[decoder.FieldType]) - end onField def apply(cur: HCursor): Decoder.Result[A] = fields.useEitherFast(infos)(onField(cur)) match @@ -48,7 +49,9 @@ object EvoDecoder extends ConsistentTemplate[Decoder, EvoDecoder] with SummonHie case Left(_) => Validated.invalidNel(DecodingFailure("unknown error", Nil)) case Right(tuple) => Validated.Valid(mirror.fromProduct(tuple)) - def sum[A](using mirror: Mirror.SumOf[A])( + def sum[A](using + mirror: Mirror.SumOf[A], + )( subs: LazySummon.All[Decoder, mirror.MirroredElemTypes], mkSubMap: => Map[String, Decoder[A]], )(using config: => Config[A], matching: Matching[A]): EvoDecoder[A] = new: diff --git a/modules/circe/src/main/scala/evo/derivation/circe/EvoEncoder.scala b/modules/circe/src/main/scala/evo/derivation/circe/EvoEncoder.scala index 1e6a591..50d90e1 100644 --- a/modules/circe/src/main/scala/evo/derivation/circe/EvoEncoder.scala +++ b/modules/circe/src/main/scala/evo/derivation/circe/EvoEncoder.scala @@ -20,7 +20,9 @@ abstract class EvoTemplateEncoder extends Template: type Provide[A] >: EvoObjectEncoder[A] <: EvoEncoder[A] - def product[A](using mirror: Mirror.ProductOf[A])( + def product[A](using + mirror: Mirror.ProductOf[A], + )( fieldInstances: LazySummon.All[Encoder, mirror.MirroredElemTypes], )(using config: => Config[A], ev: A <:< Product): EvoObjectEncoder[A] = new: lazy val infos = config.top.fields.map(_._2) @@ -33,13 +35,15 @@ abstract class EvoTemplateEncoder extends Template: def encodeObject(a: A): JsonObject = val fields = tupleFromProduct(a) type Res = Vector[(String, Json)] - val results = fieldInstances.useCollect[Res, ForField[_]](fields, infos)( - [X] => (info: ForField[_], a: X, enc: Encoder[X]) => encodeField(info, enc(a)), + val results = fieldInstances.useCollect[Res, ForField[_]](fields, infos)([X] => + (info: ForField[_], a: X, enc: Encoder[X]) => encodeField(info, enc(a)), ) JsonObject.fromIterable(results.flatten) end encodeObject - def sum[A](using mirror: Mirror.SumOf[A])( + def sum[A](using + mirror: Mirror.SumOf[A], + )( subs: LazySummon.All[Encoder, mirror.MirroredElemTypes], mkEncoders: => Map[String, Encoder[A]], )(using config: => Config[A], matching: Matching[A]): EvoObjectEncoder[A] = new: @@ -58,7 +62,6 @@ abstract class EvoTemplateEncoder extends Template: (field -> Json.fromString(discrimValue)) +: obj case None => JsonObject.singleton(discrimValue, json) - end match end encodeObject end EvoTemplateEncoder diff --git a/modules/circe/src/main/scala/evo/derivation/circe/deriveEnumerationCodec.scala b/modules/circe/src/main/scala/evo/derivation/circe/deriveEnumerationCodec.scala index 671d86f..b8833e6 100644 --- a/modules/circe/src/main/scala/evo/derivation/circe/deriveEnumerationCodec.scala +++ b/modules/circe/src/main/scala/evo/derivation/circe/deriveEnumerationCodec.scala @@ -38,7 +38,6 @@ private object EnumerationCodec: case Right(value) if value == name => Right(mirror.fromProduct(EmptyTuple)) case Right(value) => Left(DecodingFailure(s"got $value, expected $name", c.history)) case Left(err) => Left(err) - end apply def apply(a: A): Json = Json.fromString(name) } diff --git a/modules/core/src/main/scala/evo/derivation/config/ConfigMacro.scala b/modules/core/src/main/scala/evo/derivation/config/ConfigMacro.scala index 0af9b4e..3f9415d 100644 --- a/modules/core/src/main/scala/evo/derivation/config/ConfigMacro.scala +++ b/modules/core/src/main/scala/evo/derivation/config/ConfigMacro.scala @@ -81,7 +81,6 @@ class ConfigMacro(using q: Quotes): val annots = annotations(sym) '{ ($name, $annots) } - end subtypeAnnotation private def subtypeAnnotations[T: Type](sym: Symbol): Expr[Vector[(String, AllAnnotations[T])]] = val subtypes = Varargs(sym.children.map(subtypeAnnotation)) diff --git a/modules/core/src/main/scala/evo/derivation/config/package.scala b/modules/core/src/main/scala/evo/derivation/config/package.scala index fa26013..b19b4d2 100644 --- a/modules/core/src/main/scala/evo/derivation/config/package.scala +++ b/modules/core/src/main/scala/evo/derivation/config/package.scala @@ -27,5 +27,3 @@ case class AllAnnotations[T]( subtypes: Vector[(String, AllAnnotations[T])], ): lazy val bySubtype = subtypes.toMap - -end AllAnnotations diff --git a/modules/core/src/main/scala/evo/derivation/internal/product.scala b/modules/core/src/main/scala/evo/derivation/internal/product.scala index aa8aa9d..b48b07e 100644 --- a/modules/core/src/main/scala/evo/derivation/internal/product.scala +++ b/modules/core/src/main/scala/evo/derivation/internal/product.scala @@ -8,7 +8,6 @@ def tupleFromProduct[A](a: A)(using m: Mirror.ProductOf[A])(using A <:< Product) type MP[a] = Mirror.ProductOf[a] { type MirroredElemTypes = m.MirroredElemTypes } val coeMirror = coerce.liftCo[MP](m) Tuple.fromProductTyped[A & Product](coerce(a))(using coeMirror) -end tupleFromProduct private def subtypeToIntersectionEq[A, B](using ev: A <:< B): A =:= (A & B) = given (A <:< (A & B)) = ev.liftCo[[x] =>> A & x] diff --git a/modules/core/src/main/scala/evo/derivation/template/Template.scala b/modules/core/src/main/scala/evo/derivation/template/Template.scala index 3263038..9c1629b 100644 --- a/modules/core/src/main/scala/evo/derivation/template/Template.scala +++ b/modules/core/src/main/scala/evo/derivation/template/Template.scala @@ -37,7 +37,9 @@ trait Template: /** called for the case classes derivation */ - def product[A](using mirror: Mirror.ProductOf[A])( + def product[A](using + mirror: Mirror.ProductOf[A], + )( fields: LazySummon.All[OfField, mirror.MirroredElemTypes], )(using => Config[A], A <:< Product): Provide[A] @@ -46,7 +48,9 @@ trait Template: * WARNING: mkSubMap makes assumption that you can use your subtype instances as instances for the target type, use * with great caution! */ - def sum[A](using mirror: Mirror.SumOf[A])( + def sum[A](using + mirror: Mirror.SumOf[A], + )( subs: LazySummon.All[OfSubtype, mirror.MirroredElemTypes], mkSubMap: => Map[String, OfSubtype[A]], )(using config: => Config[A], matching: Matching[A]): Provide[A] @@ -113,7 +117,6 @@ trait ConsistentTemplate[TC[_], Prov[_]] extends Template: type OfSubtype[A] = TC[A] type OfNewtype[A] = TC[A] type Provide[A] = Prov[A] -end ConsistentTemplate /** event more simplified trait, useful when your define derivation for your own typeclass */ diff --git a/modules/playJson/src/main/scala/evo/derivation/play/json/EvoReads.scala b/modules/playJson/src/main/scala/evo/derivation/play/json/EvoReads.scala index d971fd0..9d48fe5 100644 --- a/modules/playJson/src/main/scala/evo/derivation/play/json/EvoReads.scala +++ b/modules/playJson/src/main/scala/evo/derivation/play/json/EvoReads.scala @@ -41,11 +41,15 @@ object EvoReads extends ConsistentTemplate[Reads, EvoReads] with SummonHierarchy def newtype[A](using nt: ValueClass[A])(using reads: Reads[nt.Representation]): EvoReads[A] = json => json.validate[nt.Representation].map(nt.from) - def product[A](using mirror: Mirror.ProductOf[A])( + def product[A](using + mirror: Mirror.ProductOf[A], + )( fields: LazySummon.All[Reads, mirror.MirroredElemTypes], )(using => Config[A], A <:< Product): EvoReads[A] = new ProductReadsMake(fields) - def sum[A](using mirror: Mirror.SumOf[A])( + def sum[A](using + mirror: Mirror.SumOf[A], + )( subs: LazySummon.All[Reads, mirror.MirroredElemTypes], mkSubMap: => Map[String, Reads[A]], )(using config: => Config[A], matching: Matching[A]): EvoReads[A] = @@ -64,8 +68,9 @@ object EvoReads extends ConsistentTemplate[Reads, EvoReads] with SummonHierarchy for { obj <- json.validate[JsObject] keys = obj.keys - result <- if keys.size == 1 then JsSuccess(keys.head) - else JsError("Expecting an object with a single key") + result <- + if keys.size == 1 then JsSuccess(keys.head) + else JsError("Expecting an object with a single key") } yield (result, obj.apply(result)) class ProductReadsMake[A](using mirror: Mirror.ProductOf[A])( diff --git a/modules/playJson/src/main/scala/evo/derivation/play/json/EvoWrites.scala b/modules/playJson/src/main/scala/evo/derivation/play/json/EvoWrites.scala index be2a8d8..85b0e24 100644 --- a/modules/playJson/src/main/scala/evo/derivation/play/json/EvoWrites.scala +++ b/modules/playJson/src/main/scala/evo/derivation/play/json/EvoWrites.scala @@ -21,14 +21,18 @@ trait EvoWrites[A] extends Writes[A] object EvoWrites extends ConsistentTemplate[Writes, EvoWrites] with SummonHierarchy: - override def product[A](using mirror: Mirror.ProductOf[A])( + override def product[A](using + mirror: Mirror.ProductOf[A], + )( fields: All[Writes, mirror.MirroredElemTypes], )(using => Config[A], A <:< Product): EvoWrites[A] = ProductWrites(fields) /** called for the sealed trait \ enum derivation */ - override def sum[A](using mirror: Mirror.SumOf[A])( + override def sum[A](using + mirror: Mirror.SumOf[A], + )( subs: All[Writes, mirror.MirroredElemTypes], mkSubMap: => Map[String, Writes[A]], )(using config: => Config[A], matching: Matching[A]): EvoWrites[A] = @@ -54,8 +58,8 @@ object EvoWrites extends ConsistentTemplate[Writes, EvoWrites] with SummonHierar val fields = tupleFromProduct(a) type Res = Vector[(String, JsValue)] - val results = fieldInstances.useCollect[Res, ForField[_ <: A]](fields, infos)( - [X] => (info: ForField[_ <: A], a: X, enc: Writes[X]) => encodeField(info, enc.writes(a)), + val results = fieldInstances.useCollect[Res, ForField[_ <: A]](fields, infos)([X] => + (info: ForField[_ <: A], a: X, enc: Writes[X]) => encodeField(info, enc.writes(a)), ) JsObject(results.flatten) end writes @@ -78,7 +82,6 @@ object EvoWrites extends ConsistentTemplate[Writes, EvoWrites] with SummonHierar obj + (field -> JsString(discrimValue)) case None => JsObject.apply(Seq(discrimValue -> json)) - end match end writes end SumWrites end EvoWrites From 18fb8e34357acfe79723be2d6de6117809651e37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mareks=20Ramp=C4=81ns?= <8796159+mr-git@users.noreply.github.com> Date: Wed, 22 Jul 2026 16:59:48 +0300 Subject: [PATCH 11/14] update CI and Release workflows to be the same as in other Evo's repos --- .github/mergify.yml | 31 ----------------- .github/workflows/ci.yml | 50 +++++++++++++++++++++++++++ .github/workflows/release.yml | 10 +++--- .github/workflows/scala-steward.yml | 29 ---------------- .github/workflows/scala.yml | 53 ----------------------------- .gitignore | 3 +- .scalafix.conf | 5 --- build.sbt | 8 ++--- project/plugins.sbt | 10 ++++-- 9 files changed, 69 insertions(+), 130 deletions(-) delete mode 100644 .github/mergify.yml create mode 100644 .github/workflows/ci.yml delete mode 100644 .github/workflows/scala-steward.yml delete mode 100644 .github/workflows/scala.yml delete mode 100644 .scalafix.conf diff --git a/.github/mergify.yml b/.github/mergify.yml deleted file mode 100644 index 5723d43..0000000 --- a/.github/mergify.yml +++ /dev/null @@ -1,31 +0,0 @@ -pull_request_rules: - - name: Request reviews and label Steward's PRs - conditions: - - author=evolution-scala-bot[bot] - actions: - request_reviews: - users: [ Odomontois, FunFunFine ] - label: - add: [ dependency-update ] - - - name: Merge Steward's PRs - conditions: - - author=evolution-scala-bot[bot] - - or: - - and: - - "#files=1" - - or: - - files=project/build.properties - - files=project/plugins.sbt - - body~=labels:.*semver-patch - - "#approved-reviews-by>=1" - - check-success~= build - actions: - merge: - method: rebase - - - name: Delete head branch after merge - conditions: - - merged - actions: - delete_head_branch: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..05e2acf --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,50 @@ +name: CI + +on: + push: + branches: [ base ] + pull_request: + +jobs: + test: + + runs-on: ubuntu-latest + + strategy: + matrix: + scala: + - 3.3.8 + + steps: + - uses: actions/checkout@v7 + + - uses: coursier/cache-action@v8 + + - name: setup Java 17 + uses: actions/setup-java@v5 + with: + java-version: '17' + distribution: 'temurin' + cache: 'sbt' + + - name: setup SBT + uses: sbt/setup-sbt@v1 + + - name: check code ${{ matrix.scala }} + run: sbt "++${{ matrix.scala }}; clean; check" + + - name: build ${{ matrix.scala }} + run: sbt "++${{ matrix.scala }}; clean; coverage; test; coverageAggregate" + + - name: locate coverage report + id: coverage + if: success() + run: echo "file=$(find . -path '*/coverage-report/cobertura.xml' | head -1)" >> "$GITHUB_OUTPUT" + + - name: test coverage + if: success() + uses: coverallsapp/github-action@v2 + with: + file: ${{ steps.coverage.outputs.file }} + format: cobertura + flag-name: Scala ${{ matrix.scala }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 4b8e4da..3b7a7cc 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,11 +1,11 @@ -name: Publish new Release +name: Publish Release on: - release: - types: [published] - branches: [base] + push: + tags: + - 'v*' jobs: release: - uses: evolution-gaming/scala-github-actions/.github/workflows/release.yml@v1 + uses: evolution-gaming/scala-github-actions/.github/workflows/release.yml@v5 secrets: inherit diff --git a/.github/workflows/scala-steward.yml b/.github/workflows/scala-steward.yml deleted file mode 100644 index bbfc360..0000000 --- a/.github/workflows/scala-steward.yml +++ /dev/null @@ -1,29 +0,0 @@ -on: - schedule: - - cron: '0 0,12 * * *' - workflow_dispatch: - -name: Launch Scala Steward - -jobs: - scala-steward: - runs-on: ubuntu-latest - name: Launch Scala Steward - steps: - - - name: Generate token - id: generate-token - uses: tibdex/github-app-token@v1 - with: - app_id: 225513 - private_key: ${{ secrets.STEWARD_APP_PRIVATE_KEY }} - - - name: Launch Scala Steward - uses: scala-steward-org/scala-steward-action@v2 - with: - # used for authoring updates: - github-token: ${{ steps.generate-token.outputs.token }} - author-email: 225513+evolution-scala-bot[bot]@users.noreply.github.com - author-name: evolution-scala-bot[bot] - github-app-id: 225513 - github-app-key: ${{ secrets.STEWARD_APP_PRIVATE_KEY }} diff --git a/.github/workflows/scala.yml b/.github/workflows/scala.yml deleted file mode 100644 index 06f465d..0000000 --- a/.github/workflows/scala.yml +++ /dev/null @@ -1,53 +0,0 @@ -name: Scala CI - -on: - push: - branches: [ "base" ] - tags: ["v*"] - pull_request: - branches: [ "base" ] - workflow_dispatch: - -permissions: - contents: read - -jobs: - build: - - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v3 - - - uses: coursier/cache-action@v6 - - - uses: actions/setup-java@v3 - with: - java-version: '17' - distribution: 'temurin' - cache: 'sbt' - - - name: Check format - run: sbt scalafmtCheck - - - name: Run tests - run: sbt test - - publish: - name: Publish Artifacts - needs: [ build ] - if: github.event_name != 'pull_request' && (github.ref == 'refs/heads/base' || startsWith(github.ref, 'refs/tags/v')) - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - - uses: actions/setup-java@v3 - with: - distribution: temurin - java-version: 17 - cache: 'sbt' - - - uses: coursier/cache-action@v6 - diff --git a/.gitignore b/.gitignore index 56d3702..01cecb3 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,5 @@ project/**/metals.sbt .idea .bsp .vscode -.DS_Store \ No newline at end of file +.DS_Store +target/ diff --git a/.scalafix.conf b/.scalafix.conf deleted file mode 100644 index f5c3a09..0000000 --- a/.scalafix.conf +++ /dev/null @@ -1,5 +0,0 @@ -OrganizeImports { - groups = ["re:javax?\\.", "scala.", "cherry." "*"] - removeUnused = false - groupedImports = AggressiveMerge -} \ No newline at end of file diff --git a/build.sbt b/build.sbt index 865bd6a..4add870 100644 --- a/build.sbt +++ b/build.sbt @@ -16,11 +16,12 @@ ThisBuild / versionScheme := Some("early-semver") testFrameworks += TestFrameworks.MUnit addCommandAlias("fmt", "scalafmtRepo") +//addCommandAlias("check", "all versionPolicyCheck Compile/doc scalafmtCheckRepo") +addCommandAlias("check", "+scalafmtCheckRepo") +addCommandAlias("build", "+all compile test") val scala3Settings = scalacOptions ++= Vector( "-Yexplicit-nulls", - "-encoding", - "utf-8", "-Yshow-suppressed-errors", ) @@ -47,7 +48,7 @@ lazy val publishSettings = Vector( publishMavenStyle := true, Test / publishArtifact := false, versionScheme := Some("early-semver"), - description := "A derivation library for scala 3 with annotation based configuration.", + description := "A derivation library for Scala 3 with annotation based configuration.", scmInfo := Some( ScmInfo( url("https://github.com/evolution-gaming/derivation"), @@ -55,7 +56,6 @@ lazy val publishSettings = Vector( ), ), licenses += ("MIT", url("https://opensource.org/licenses/MIT")), - releaseCrossBuild := true, publishTo := Some(Resolver.evolutionReleases), ) diff --git a/project/plugins.sbt b/project/plugins.sbt index 0a2a988..cb68b31 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,5 +1,11 @@ -addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.6.2") +addSbtPlugin("org.scoverage" % "sbt-scoverage" % "2.4.4") + +addSbtPlugin("com.github.sbt" % "sbt-dynver" % "5.1.1") -addSbtPlugin("com.github.sbt" % "sbt-release" % "1.1.0") +addSbtPlugin("com.evolution" % "sbt-scalac-opts-plugin" % "0.1.0") addSbtPlugin("com.evolution" % "sbt-artifactory-plugin" % "0.1.2") + +addSbtPlugin("ch.epfl.scala" % "sbt-version-policy" % "3.3.0") + +addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.6.2") From 99df9606bbc56bd8ed5a0c174a03cbd4e85befd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mareks=20Ramp=C4=81ns?= <8796159+mr-git@users.noreply.github.com> Date: Wed, 22 Jul 2026 17:10:41 +0300 Subject: [PATCH 12/14] disable `sbt-scalac-opts-plugin` --- build.sbt | 3 +++ modules/cats/src/main/scala/evo/derivation/cats/EvoEq.scala | 6 ++++-- .../scala/evo/derivation/circe/deriveEnumerationCodec.scala | 3 ++- modules/core/src/main/scala/evo/derivation/LazySummon.scala | 2 +- .../src/main/scala/evo/derivation/template/Template.scala | 6 ++++-- project/plugins.sbt | 2 +- 6 files changed, 15 insertions(+), 7 deletions(-) diff --git a/build.sbt b/build.sbt index 4add870..c1be4c2 100644 --- a/build.sbt +++ b/build.sbt @@ -23,6 +23,9 @@ addCommandAlias("build", "+all compile test") val scala3Settings = scalacOptions ++= Vector( "-Yexplicit-nulls", "-Yshow-suppressed-errors", + "--explain", + "--explain-types", + "--deprecation", ) val testDependencies = libraryDependencies ++= Vector( diff --git a/modules/cats/src/main/scala/evo/derivation/cats/EvoEq.scala b/modules/cats/src/main/scala/evo/derivation/cats/EvoEq.scala index fd1f900..021ded4 100644 --- a/modules/cats/src/main/scala/evo/derivation/cats/EvoEq.scala +++ b/modules/cats/src/main/scala/evo/derivation/cats/EvoEq.scala @@ -17,11 +17,13 @@ object BaseEvoEq: inline given [A]: BaseEvoEq[A] = summonFrom { case byCats: cats.kernel.Eq[A] => - new: + class NamedByCats extends BaseEvoEq[A]: def eqv(a: A, b: A) = byCats.eqv(a, b) + new NamedByCats case byScala: Equiv[A] => - new: + class NamedByScala extends BaseEvoEq[A]: def eqv(a: A, b: A) = byScala.equiv(a, b) + new NamedByScala } end BaseEvoEq diff --git a/modules/circe/src/main/scala/evo/derivation/circe/deriveEnumerationCodec.scala b/modules/circe/src/main/scala/evo/derivation/circe/deriveEnumerationCodec.scala index b8833e6..36eb500 100644 --- a/modules/circe/src/main/scala/evo/derivation/circe/deriveEnumerationCodec.scala +++ b/modules/circe/src/main/scala/evo/derivation/circe/deriveEnumerationCodec.scala @@ -63,7 +63,7 @@ private object EnumerationCodec: val matching: Matching[A] = Matching.create[A] val decoder: Decoder[A] = codecs.reduceLeft(_ or _) - new EnumerationCodec[A] { + class NamedEnumerationCodec extends EnumerationCodec[A] { def apply(c: HCursor): Decoder.Result[A] = c.value.asString match case None => Left(DecodingFailure(s"Expected string value, got ${c.value}", c.history)) @@ -74,5 +74,6 @@ private object EnumerationCodec: def apply(a: A): Json = Json.fromString(matching.matched(a)) } + new NamedEnumerationCodec } end EnumerationCodec diff --git a/modules/core/src/main/scala/evo/derivation/LazySummon.scala b/modules/core/src/main/scala/evo/derivation/LazySummon.scala index 85a9faa..62e4eb2 100644 --- a/modules/core/src/main/scala/evo/derivation/LazySummon.scala +++ b/modules/core/src/main/scala/evo/derivation/LazySummon.scala @@ -131,7 +131,7 @@ object LazySummon: case _ => true } if err - then Left(errors.result) + then Left(errors.result()) else Right(Tuple.fromIArray(elements.result()).asInstanceOf[Fields]) end useEithers diff --git a/modules/core/src/main/scala/evo/derivation/template/Template.scala b/modules/core/src/main/scala/evo/derivation/template/Template.scala index 9c1629b..24a8d5e 100644 --- a/modules/core/src/main/scala/evo/derivation/template/Template.scala +++ b/modules/core/src/main/scala/evo/derivation/template/Template.scala @@ -70,12 +70,14 @@ trait Template: } inline def lazySummonForProduct[From, A: Mirror.ProductOf]: LazySummonByConfig[Provide, From, A] = - new: + class NamedLazySummonByConfig extends LazySummonByConfig[Provide, From, A]: def instance(using => Config[A]): Provide[A] = deriveForProduct[A] + new NamedLazySummonByConfig inline def lazySummonForSum[From, A: Mirror.SumOf]: LazySummonByConfig[Provide, From, A] = - new: + class NamedLazySummonByConfig extends LazySummonByConfig[Provide, From, A]: def instance(using => Config[A]): Provide[A] = deriveForSum[From, A] + new NamedLazySummonByConfig private[template] inline def deriveForSum[From, A](using config: => Config[A], diff --git a/project/plugins.sbt b/project/plugins.sbt index cb68b31..d887f34 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -2,7 +2,7 @@ addSbtPlugin("org.scoverage" % "sbt-scoverage" % "2.4.4") addSbtPlugin("com.github.sbt" % "sbt-dynver" % "5.1.1") -addSbtPlugin("com.evolution" % "sbt-scalac-opts-plugin" % "0.1.0") +//addSbtPlugin("com.evolution" % "sbt-scalac-opts-plugin" % "0.1.0") addSbtPlugin("com.evolution" % "sbt-artifactory-plugin" % "0.1.2") From f41fdb544a47aa18bb97ef91e69b91694b486a83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mareks=20Ramp=C4=81ns?= <8796159+mr-git@users.noreply.github.com> Date: Wed, 22 Jul 2026 18:47:19 +0300 Subject: [PATCH 13/14] restore the circe dependency for `derivation-circe-compat213` --- build.sbt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index c1be4c2..5bb2c0c 100644 --- a/build.sbt +++ b/build.sbt @@ -1,3 +1,5 @@ +import sbt.librarymanagement.For3Use2_13 + name := "derivation" publish / skip := true @@ -97,7 +99,7 @@ lazy val `circe-compat_213` = project .settings( name := "derivation-circe-compat213", target := (file("modules") / "circe" / "target-compat213" / "jvm").getAbsoluteFile, - libraryDependencies += "io.circe" %% "circe-core" % Version.circe, + libraryDependencies += "io.circe" %% "circe-core" % Version.circe cross For3Use2_13(), defaultSettings, ) .dependsOn(derivation) From c4b54b39f6c9ca42250fda841a713aa6ec2308b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mareks=20Ramp=C4=81ns?= <8796159+mr-git@users.noreply.github.com> Date: Wed, 22 Jul 2026 18:50:37 +0300 Subject: [PATCH 14/14] restore encoding scalacOptions --- build.sbt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build.sbt b/build.sbt index 5bb2c0c..fe1b5bb 100644 --- a/build.sbt +++ b/build.sbt @@ -25,6 +25,8 @@ addCommandAlias("build", "+all compile test") val scala3Settings = scalacOptions ++= Vector( "-Yexplicit-nulls", "-Yshow-suppressed-errors", + "-encoding", + "utf-8", "--explain", "--explain-types", "--deprecation",