Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master' into simplify_scala3_pro…
Browse files Browse the repository at this point in the history
…duct_derivation
  • Loading branch information
jcazevedo committed Jun 26, 2024
2 parents 0a97284 + 5aca894 commit 1208caf
Show file tree
Hide file tree
Showing 92 changed files with 1,941 additions and 130 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ jobs:
scala: ['2.12', '2.13', '3']
include:
- scala: '2.12'
scala-version: 2.12.18
scala-version: 2.12.19
- scala: '2.13'
scala-version: 2.13.12
scala-version: 2.13.14
- scala: '3'
scala-version: 3.3.0
scala-version: 3.3.3

steps:
- name: Checkout repository
Expand Down
1 change: 1 addition & 0 deletions .scalafix.conf
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ OrganizeImports {
importSelectorsOrder = Ascii
importsOrder = Ascii
removeUnused = false
targetDialect = Scala2
}
6 changes: 5 additions & 1 deletion .scalafmt.conf
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
version = 3.7.14
version = 3.8.2

runner.dialect = scala213
align.preset = none
Expand All @@ -8,4 +8,8 @@ fileOverride {
"glob:**/scala-3*/**" {
runner.dialect = scala3
}

"glob:**/generic-scala3/**" {
runner.dialect = scala3
}
}
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
### 0.17.7 (Jun 9, 2024)

- New features
- Added support for Scala 3 derivation of `EnumConfigWriter` and `EnumConfigConvert` using a `derives` clause.
- Added a new `pureconfig-generic-scala3` module, a drop-in replacement of Scala 2's `pureconfig-generic` for semiauto derivation in Scala 3. It supports most of the types supported in `pureconfig-generic` and accepts product and coproduct hints.

### 0.17.6 (Feb 22, 2024)

- New features
- Added new `pureconfig-pekko` and `pureconfig-pekko-http` modules with relevant `ConfigReader`s and `ConfigWriter`s
for Pekko and Pekko HTTP types.

### 0.17.5 (Jan 18, 2024)

Maintenance update to update dependency versions.

### 0.17.4 (May 11, 2023)

Maintenance update to update dependency versions and fix issues with previously published modules.
Expand Down
12 changes: 10 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<img src="docs/src/main/resources/microsite/img/pureconfig-logo-1040x1200.png" width="130px" height="150px" align="right">

[![Build Status](https://github.com/pureconfig/pureconfig/workflows/CI/badge.svg?branch=master)](https://github.com/pureconfig/pureconfig/actions?query=workflow%3ACI+branch%3Amaster)
[![Build Status](https://github.com/pureconfig/pureconfig/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/pureconfig/pureconfig/actions?query=workflow%3ACI+branch%3Amaster)
[![Coverage Status](https://coveralls.io/repos/github/pureconfig/pureconfig/badge.svg?branch=master)](https://coveralls.io/github/pureconfig/pureconfig?branch=master)
[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.github.pureconfig/pureconfig_2.12/badge.svg)](https://search.maven.org/artifact/com.github.pureconfig/pureconfig_2.12)
[![Scaladoc](https://javadoc.io/badge/com.github.pureconfig/pureconfig-core_2.12.svg)](https://javadoc.io/page/com.github.pureconfig/pureconfig-core_2.12/latest/pureconfig/index.html)
Expand Down Expand Up @@ -34,9 +34,17 @@ To use PureConfig in an existing SBT project with Scala 2.12 or a later version,
`build.sbt`:

```scala
libraryDependencies += "com.github.pureconfig" %% "pureconfig" % "0.17.4"
libraryDependencies += "com.github.pureconfig" %% "pureconfig" % "0.17.7"
```

For Scala 3, add the following dependency to your `build.sbt`:

```scala
libraryDependencies += "com.github.pureconfig" %% "pureconfig-core" % "0.17.7"
```

While a lot of the documentation will also apply to Scala 3, there is a specific guide for Scala 3's derivation that you can [find here](scala-3-derivation.html).

For a full example of `build.sbt` you can have a look at this [build.sbt](https://github.com/pureconfig/pureconfig/blob/master/example/build.sbt).

Earlier versions of Scala had bugs which can cause subtle compile-time problems in PureConfig.
Expand Down
11 changes: 9 additions & 2 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ ThisBuild / organization := "com.github.pureconfig"
// Enable the OrganizeImports Scalafix rule and semanticdb for scalafix.
ThisBuild / semanticdbEnabled := true
ThisBuild / semanticdbVersion := scalafixSemanticdb.revision
ThisBuild / scalafixDependencies += "com.github.liancheng" %% "organize-imports" % "0.6.0"

// taken from https://github.com/scala/bug/issues/12632
ThisBuild / libraryDependencySchemes ++= Seq(
Expand Down Expand Up @@ -60,6 +59,7 @@ lazy val enum = module(project) in file("modules/enum")
lazy val enumeratum = module(project) in file("modules/enumeratum")
lazy val fs2 = module(project) in file("modules/fs2")
lazy val generic = genericModule(project) in file("modules/generic") dependsOn `generic-base`
lazy val `generic-scala3` = genericModule(project) in file("modules/generic-scala3") dependsOn `generic-base`
lazy val `generic-base` = genericModule(project) in file("modules/generic-base")
lazy val hadoop = module(project) in file("modules/hadoop")
lazy val http4s = module(project) in file("modules/http4s")
Expand All @@ -68,6 +68,8 @@ lazy val ip4s = module(project) in file("modules/ip4s")
lazy val javax = module(project) in file("modules/javax")
lazy val joda = module(project) in file("modules/joda")
lazy val magnolia = module(project) in file("modules/magnolia") dependsOn `generic-base`
lazy val pekko = module(project) in file("modules/pekko")
lazy val `pekko-http` = module(project) in file("modules/pekko-http")
lazy val `scala-xml` = module(project) in file("modules/scala-xml")
lazy val scalaz = module(project) in file("modules/scalaz")
lazy val spark = module(project) in file("modules/spark")
Expand Down Expand Up @@ -170,7 +172,9 @@ lazy val lintFlags = forScalaVersions {
"-encoding",
"UTF-8", // arg for -encoding
"-feature",
"-unchecked"
"-unchecked",
"-old-syntax",
"-no-indent"
)

case (maj, min) => throw new Exception(s"Unknown Scala version $maj.$min")
Expand All @@ -179,6 +183,9 @@ lazy val lintFlags = forScalaVersions {
// Use the same Scala 2.12 version in the root project as in subprojects
scalaVersion := scala212

// Setting no cross build for the aggregating root project so that we can have proper per project exclusions.
crossScalaVersions := Nil

// do not publish the root project
publish / skip := true

Expand Down
2 changes: 1 addition & 1 deletion bundle/docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<img src="docs/src/main/resources/microsite/img/pureconfig-logo-1040x1200.png" width="130px" height="150px" align="right">

[![Build Status](https://github.com/pureconfig/pureconfig/workflows/CI/badge.svg?branch=master)](https://github.com/pureconfig/pureconfig/actions?query=workflow%3ACI+branch%3Amaster)
[![Build Status](https://github.com/pureconfig/pureconfig/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/pureconfig/pureconfig/actions?query=workflow%3ACI+branch%3Amaster)
[![Coverage Status](https://coveralls.io/repos/github/pureconfig/pureconfig/badge.svg?branch=master)](https://coveralls.io/github/pureconfig/pureconfig?branch=master)
[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.github.pureconfig/pureconfig_2.12/badge.svg)](https://search.maven.org/artifact/com.github.pureconfig/pureconfig_2.12)
[![Scaladoc](https://javadoc.io/badge/com.github.pureconfig/pureconfig-core_2.12.svg)](https://javadoc.io/page/com.github.pureconfig/pureconfig-core_2.12/latest/pureconfig/index.html)
Expand Down
2 changes: 1 addition & 1 deletion core/build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ name := "pureconfig-core"

crossScalaVersions := Seq(scala212, scala213, scala3)

libraryDependencies += "com.typesafe" % "config" % "1.4.2"
libraryDependencies += "com.typesafe" % "config" % "1.4.3"
5 changes: 5 additions & 0 deletions core/src/main/scala-2/pureconfig/ReaderDerives.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package pureconfig

trait ReaderDerives {
// `derives` clauses are only supported in Scala 3
}
10 changes: 10 additions & 0 deletions core/src/main/scala-3/pureconfig/ReaderDerives.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package pureconfig

import scala.deriving.Mirror

import pureconfig.generic.derivation._

trait ReaderDerives {
inline def derived[A](using m: Mirror.Of[A]): ConfigReader[A] =
ConfigReaderDerivation.Default.deriveConfigReader[A]
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,29 @@ package derivation
import scala.compiletime.summonFrom
import scala.deriving.Mirror

@deprecated(
"Custom derivation is deprecated in pureconfig-core. If you only need the default behavior, please use the default `derives` behavior. If you need configuration please use the `pureconfig-generic-scala3` module instead.",
"0.17.7"
)
trait ConfigReaderDerivation extends CoproductConfigReaderDerivation with ProductConfigReaderDerivation {
extension (c: ConfigReader.type) {
inline def derived[A](using m: Mirror.Of[A]): ConfigReader[A] =
inline m match {
case given Mirror.ProductOf[A] => derivedProduct
case given Mirror.SumOf[A] => derivedSum
}
deriveConfigReader[A]
}

inline def deriveConfigReader[A](using m: Mirror.Of[A]): ConfigReader[A] =
inline m match {
case given Mirror.ProductOf[A] => derivedProduct
case given Mirror.SumOf[A] => derivedSum
}

/** Summons a `ConfigReader` for a given type `A`. It first tries to find an existing given instance of
* `ConfigReader[A]`. If none is found, it tries to derive one using this `ConfigReaderDerivation` instance. This
* method differs from `derived` in that the latter doesn't try to find an existing instance first.
*/
protected inline def summonConfigReader[A] = summonFrom {
case reader: ConfigReader[A] => reader
case given Mirror.Of[A] => ConfigReader.derived[A]
}

/** Summons a `ConfigReader` for a given type `A`. It first tries to find an existing given instance of
Expand All @@ -24,11 +40,13 @@ trait ConfigReaderDerivation extends CoproductConfigReaderDerivation with Produc
}
}

@deprecated("Derivation of ConfigReaders using `derives` is now supported without an import.", "0.17.7")
object ConfigReaderDerivation {
object Default
extends ConfigReaderDerivation
with CoproductConfigReaderDerivation(ConfigFieldMapping(PascalCase, KebabCase), "type")
with ProductConfigReaderDerivation(ConfigFieldMapping(CamelCase, KebabCase))
}

@deprecated("Derivation of ConfigReaders using `derives` is now supported without an import.", "0.17.7")
val default = ConfigReaderDerivation.Default
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ import pureconfig.error.{CannotConvert, ConfigReaderFailures}
import pureconfig.generic.derivation.ConfigReaderDerivation
import pureconfig.generic.derivation.Utils._

@deprecated(
"Custom derivation is deprecated in pureconfig-core. If you only need the default behavior, please use the default `derives` behavior. If you need configuration please use the `pureconfig-generic-scala3` module instead.",
"0.17.7"
)
trait CoproductConfigReaderDerivation(fieldMapping: ConfigFieldMapping, optionField: String) {
self: ConfigReaderDerivation =>
inline def derivedSum[A](using m: Mirror.SumOf[A]): ConfigReader[A] =
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package pureconfig
package generic
package derivation

import scala.deriving.Mirror

import com.typesafe.config.ConfigValue

trait EnumConfigConvert[A] extends ConfigConvert[A]

object EnumConfigConvert {
inline def derived[A: Mirror.SumOf]: EnumConfigConvert[A] =
new EnumConfigConvert[A] {
val reader = EnumConfigReaderDerivation.Default.EnumConfigReader.derived[A]
val writer = EnumConfigWriterDerivation.Default.EnumConfigWriter.derived[A]

def from(cur: ConfigCursor): ConfigReader.Result[A] = reader.from(cur)
def to(a: A): ConfigValue = writer.to(a)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package pureconfig
package generic
package derivation

import scala.compiletime.{constValue, erasedValue, error, summonInline}
import scala.deriving.Mirror

import com.typesafe.config.{ConfigValue, ConfigValueFactory}

import pureconfig.error.{CannotConvert, ConfigReaderFailures}
import pureconfig.generic.derivation.Utils._

type EnumConfigWriter[A] = EnumConfigWriterDerivation.Default.EnumConfigWriter[A]

trait EnumConfigWriterDerivation(transformName: String => String) {

trait EnumConfigWriter[A] extends ConfigWriter[A]

object EnumConfigWriter {
inline def derived[A](using m: Mirror.SumOf[A]): EnumConfigWriter[A] =
new EnumConfigWriter[A] {
assertIsEnum[m.MirroredElemTypes]
val labels = transformedLabels[A](transformName).toVector

def to(a: A): ConfigValue =
ConfigValueFactory.fromAnyRef(labels(m.ordinal(a)))
}
}

private inline def assertIsEnum[T <: Tuple]: Unit =
inline erasedValue[T] match {
case _: (h *: t) =>
inline summonInline[Mirror.Of[h]] match {
case m: Mirror.Singleton => assertIsEnum[t]
case _ => error("Enums cannot include parameterized cases.")
}
case _: EmptyTuple => ()
}
}

object EnumConfigWriterDerivation {
object Default extends EnumConfigWriterDerivation(ConfigFieldMapping(PascalCase, KebabCase))
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,13 @@ package derivation
import scala.compiletime.ops.int._
import scala.compiletime.{constValue, constValueTuple, erasedValue, summonFrom, summonInline}
import scala.deriving.Mirror

import pureconfig.error._
import pureconfig.generic.derivation.Utils._

@deprecated(
"Custom derivation is deprecated in pureconfig-core. If you only need the default behavior, please use the default `derives` behavior. If you need configuration please use the `pureconfig-generic-scala3` module instead.",
"0.17.7"
)
trait ProductConfigReaderDerivation(fieldMapping: ConfigFieldMapping) { self: ConfigReaderDerivation =>

inline def derivedProduct[A](using m: Mirror.ProductOf[A]): ConfigReader[A] =
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package pureconfig.generic
package derivation

import scala.compiletime.{constValue, erasedValue, summonFrom, summonInline}
import scala.compiletime.{constValue, erasedValue}
import scala.deriving.Mirror

object Utils {
Expand Down
7 changes: 6 additions & 1 deletion core/src/main/scala/pureconfig/ConfigReader.scala
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,12 @@ trait ConfigReader[A] {

/** Provides methods to create [[ConfigReader]] instances.
*/
object ConfigReader extends BasicReaders with CollectionReaders with ProductReaders with ExportedReaders {
object ConfigReader
extends BasicReaders
with CollectionReaders
with ProductReaders
with ExportedReaders
with ReaderDerives {

/** The type of most config PureConfig reading methods.
*
Expand Down
9 changes: 9 additions & 0 deletions docs/docs/docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,15 @@ libraryDependencies += "com.github.pureconfig" %% "pureconfig" % "@VERSION@"

For a full example of `build.sbt` you can have a look at this [build.sbt](https://github.com/pureconfig/pureconfig/blob/master/example/build.sbt).

Users of Scala 3 need to add the following dependency to their `build.sbt`:

```scala
libraryDependencies += "com.github.pureconfig" %% "pureconfig-core" % "@VERSION@"
```

While a lot of the documentation will also apply to Scala 3, there is a specific guide for Scala 3's derivation that you can [find here](scala-3-derivation.html).


Earlier versions of Scala had bugs which can cause subtle compile-time problems in PureConfig.
As a result we recommend only using the latest Scala versions within the minor series.

Expand Down
2 changes: 1 addition & 1 deletion docs/docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ layout: home

<img src="img/pureconfig-logo-1040x1200.png" width="130px" height="150px" align="right" alt="PureConfig">

[![Build Status](https://github.com/pureconfig/pureconfig/workflows/CI/badge.svg?branch=master)](https://github.com/pureconfig/pureconfig/actions?query=workflow%3ACI+branch%3Amaster)
[![Build Status](https://github.com/pureconfig/pureconfig/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/pureconfig/pureconfig/actions?query=workflow%3ACI+branch%3Amaster)
[![Coverage Status](https://coveralls.io/repos/github/pureconfig/pureconfig/badge.svg?branch=master)](https://coveralls.io/github/pureconfig/pureconfig?branch=master)
[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.github.pureconfig/pureconfig_2.12/badge.svg)](https://search.maven.org/artifact/com.github.pureconfig/pureconfig_2.12)
[![Scaladoc](https://javadoc.io/badge/com.github.pureconfig/pureconfig-core_2.12.svg)](https://javadoc.io/page/com.github.pureconfig/pureconfig-core_2.12/latest/pureconfig/index.html)
Expand Down
4 changes: 2 additions & 2 deletions example/build.sbt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name := "pureconfig-example"
version := "1.0"
scalaVersion := "2.12.18"
scalaVersion := "2.12.19"

val VersionPattern = """ThisBuild / version := "([^"]*)"""".r
val pureconfigVersion = IO.read(file("../version.sbt")).trim match {
Expand All @@ -12,7 +12,7 @@ val pureconfigVersion = IO.read(file("../version.sbt")).trim match {

libraryDependencies += "com.github.pureconfig" %% "pureconfig" % pureconfigVersion

crossScalaVersions := Seq("2.12.18", "2.13.12")
crossScalaVersions := Seq("2.12.19", "2.13.14")

val versionSpecificFlags =
Def.setting {
Expand Down
2 changes: 1 addition & 1 deletion modules/akka-http/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ for other classes are welcome :)
In addition to [core PureConfig](https://github.com/pureconfig/pureconfig), you'll need:

```scala
libraryDependencies += "com.github.pureconfig" %% "pureconfig-akka-http" % "0.17.4"
libraryDependencies += "com.github.pureconfig" %% "pureconfig-akka-http" % "0.17.7"
```

## Example
Expand Down
2 changes: 1 addition & 1 deletion modules/akka/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Adds support for selected [Akka](http://akka.io/) classes to PureConfig.
In addition to [core PureConfig](https://github.com/pureconfig/pureconfig), you'll need:

```scala
libraryDependencies += "com.github.pureconfig" %% "pureconfig-akka" % "0.17.4"
libraryDependencies += "com.github.pureconfig" %% "pureconfig-akka" % "0.17.7"
```

## Example
Expand Down
2 changes: 1 addition & 1 deletion modules/cats-effect/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Adds support for loading configuration using [cats-effect](https://github.com/ty
In addition to [core pureconfig](https://github.com/pureconfig/pureconfig), you'll need:

```scala
libraryDependencies += "com.github.pureconfig" %% "pureconfig-cats-effect" % "0.17.4"
libraryDependencies += "com.github.pureconfig" %% "pureconfig-cats-effect" % "0.17.7"
```

## Example
Expand Down
Loading

0 comments on commit 1208caf

Please sign in to comment.