Skip to content

Releases: kevin-lee/refined4s

v1.1.0

06 Nov 22:18
Compare
Choose a tag to compare

1.1.0 - 2024-11-07

New Features

  • Add Scala.js support for refined4s-chimney (#387)

v1.0.0

02 Nov 11:29
Compare
Choose a tag to compare

1.0.0 - 2024-11-02

Breaking Change

  • Fix: Scala.js support is broken (#370)

    To fix it, the following changes were made:

    • Added

      • scalajs-java-securerandom to use java.security.SecureRandom for java.util.UUID
      • scala-java-time for java.time in Scala.js
      • a custom URL implementation for Scala.js because there's no alternative to java.net.URL
    • Made other necessary changes, including removing code unavailable in JavaScript.

    • Fixed the tests for JavaScript. There were issues with Long and BigInt values less than -9007199254740991L and greater than 9007199254740991L.

v0.19.0

31 Aug 16:31
Compare
Choose a tag to compare

0.19.0 - 2024-09-01

New Features

  • [refined4s-circe] Add KeyEncoder, KeyDecoder and KeyCodec for Newtype and Refined (#355)

  • [refined4s-core] Add toUrl to Uri, and add toUri to toUrl (#356)

    Uri("https://www.google.com").toUrl
    // Url("https://www.google.com")
    
    Url("https://www.google.com").toUri
    // Uri("https://www.google.com")

  • [refined4s-core] Add toURL to Uri, and add toURI to toUrl (#358)

    Uri("https://www.google.com").toURL
    // java.net.URL("https://www.google.com")
    
    Url("https://www.google.com").toURI
    // java.net.URI("https://www.google.com")

  • [refined4s-circe] Add KeyEncoder and KeyDecoder for pre-defined refined types (#361)

  • [refined4s-circe] Add KeyEncoder and KeyDecoder to refined4s.modules.circe.derivation.generic.auto (#369)

    Thanks to @ivan-klass for the KeyEncoder and KeyDecoder request and PR (#353).


  • Update sbt plugins (#372)

    • sbt-ci-release to 1.6.1
    • sbt-wartremover to 3.2.0
    • sbt-scalafix to 0.12.1
    • sbt-scalafmt to 2.5.2
    • sbt-scoverage to 2.1.1
    • sbt-mdoc to 2.5.4
    • sbt-docusaur to 0.16.0
    • sbt-tpolecat to 0.5.2
    • com.github.xuwei-k:scalafix-rules to 0.4.5

  • Update GitHub Actions: Update javaOptions (#376)
    env:
      GH_SBT_OPTS: "-Xss64m -Xms1024m -Xmx8G -XX:MaxMetaspaceSize=2G -XX:-UseGCOverheadLimit -XX:MaxInlineLevel=18 -XX:+UnlockExperimentalVMOptions"
      GH_JVM_OPTS: "-Xss64m -Xms1024m -Xmx8G -XX:MaxMetaspaceSize=2G -XX:-UseGCOverheadLimit -XX:MaxInlineLevel=18 -XX:+UnlockExperimentalVMOptions -XX:+UseJVMCICompiler"

  • [refined4s-refined-compat-scala2] Bump Scala 2.12 to 2.12.16 (#379)

v0.18.0

17 Aug 14:47
Compare
Choose a tag to compare

0.18.0 - 2024-08-18

New Features

refined4s-chimney Add missing type-classes for Chimney

  • [refined4s-chimney] Add missing Transformer to unwrap value for ChimneyNewtype (#340)

    import refined4s.*
    import refined4s.modules.chimney.derivation.*
    
    final case class Person(name: Person.Name)
    object Person {
      type Name = Name.Type
      object Name extends Newtype[String], ChimneyNewtype[String]
    }
    
    final case class User(name: String)
    
    import io.scalaland.chimney.*
    import io.scalaland.chimney.dsl.*
    
    val person = Person(Person.Name("Wade Wilson"))
    
    val deadpool = person.transformInto[User] // This is currently not possible.

  • [refined4s-chimney] Add missing Transformer to unwrap value for ChimneyRefined (#341)

    import refined4s.*
    import refined4s.modules.chimney.derivation.*
    
    final case class Person(name: Person.NotEmptyStr)
    object Person {
      type NotEmptyStr = NotEmptyStr.Type
      object NotEmptyStr extends Refined[String], ChimneyRefined[String] {
        inline def invalidReason(a: String): String = "non-empty String"
    
        inline def predicate(a: String): Boolean = a != ""
      }
    }
    
    final case class User(name: String)
    
    import io.scalaland.chimney.*
    import io.scalaland.chimney.dsl.*
    
    val person = Person(Person.NotEmptyStr("Wade Wilson"))
    
    val deadpool = person.transformInto[User] // This was not possible.

  • [refined4s-chimney] Add PartialTransformer to transform Refined[A] to Newtype[Refined[A]] for ChimneyRefined (#342)

    import refined4s.*
    import refined4s.modules.chimney.derivation.*
    
    import io.scalaland.chimney.*
    import io.scalaland.chimney.dsl.*
    
    final case class XMen(name: XMen.NotEmptyStr)
    object XMen {
      type NotEmptyStr = NotEmptyStr.Type
      object NotEmptyStr extends Refined[String], ChimneyRefined[String] {
        inline def invalidReason(a: String): String = "non-empty String"
    
        inline def predicate(a: String): Boolean = a != ""
      }
    }
    
    
    import refined4s.types.all.*
    
    final case class MarvelCharacter(name: MarvelCharacter.Name)
    object MarvelCharacter {
      type Name = Name.Type
      object Name extends Newtype[NonEmptyString], ChimneyNewtype[NonEmptyString]
    }
    
    val logan = XMen(XMen.NotEmptyStr("James Howlett"))
    
    import refined4s.modules.chimney.derivation.types.all.*
    
    val wolverine = logan.transformIntoPartial[MarvelCharacter]

  • [refined4s-chimney] Add PartialTransformer to transform Newtype[A] to Newtype[Refined[A]] for ChimneyNewtype (#346)

    import refined4s.*
    import refined4s.modules.chimney.derivation.*
    
    import io.scalaland.chimney.*
    import io.scalaland.chimney.dsl.*
    
    final case class XMen(name: XMen.Name)
    object XMen {
      type Name = Name.Type
      object Name extends Newtype[String], ChimneyNewtype[String]
    }
    
    import refined4s.types.all.*
    
    final case class MarvelCharacter(name: MarvelCharacter.Name)
    object MarvelCharacter {
      type Name = Name.Type
      object Name extends Newtype[NonEmptyString], ChimneyNewtype[NonEmptyString]
    }
    
    val logan = XMen(XMen.Name("James Howlett"))
    
    import refined4s.modules.chimney.derivation.types.all.*
    
    val wolverine = logan.transformIntoPartial[MarvelCharacter]

v0.17.0

11 Aug 10:23
Compare
Choose a tag to compare

0.17.0 - 2024-08-11

New Features

Add refined4s-chimney


refined4s.modules.chimney.derivation.generic.auto

  • [refined4s-chimney] Add refined4s.modules.chimney.derivation.generic.auto for auto derivation for Chimney (#325)
import io.scalaland.chimney
import refined4s.modules.chimney.derivation.generic.auto.given
import refined4s.types.all.PosInt
import refined4s.{Newtype, Refined}

val emailRegEx =
  """([a-zA-Z0-9]+([-_\.\+]+[a-zA-Z0-9]+)*@[a-zA-Z0-9]+([-_]+[a-zA-Z0-9]+)*(?:[.][a-zA-Z0-9]+([-_]+[a-zA-Z0-9]+)*)+)""".r

final case class Foo(id: Foo.Id, baz: Foo.Baz)
object Foo {
  type Id = Id.Type
  object Id extends Newtype[PosInt]

  type Name = Name.Type
  object Name extends Newtype[String]

  type Email = Email.Type
  object Email extends Refined[String] {

    override def invalidReason(a: String): String = s"Invalid email: $a"

    override def predicate(a: String): Boolean = emailRegEx.findFirstMatchIn(a).isDefined
  }

  final case class Baz(name: Name, email: Email)
}

final case class Bar(id: Bar.Code, baz: Bar.Baz)
object Bar {
  type Code = Code.Type
  object Code extends Newtype[PosInt]

  type Label = Label.Type
  object Label extends Newtype[String]

  type Email = Email.Type
  object Email extends Refined[String] {

    override def invalidReason(a: String): String = s"Invalid email: $a"

    override def predicate(a: String): Boolean = emailRegEx.findFirstMatchIn(a).isDefined
  }

  final case class Baz(name: Label, email: Email)
}

val id = Foo.Id(PosInt(123))
id.into[Bar.Code].transform
// Bar.Code(PosInt(123))

val name = Foo.Name("Kevin")
name.into[Bar.Label].transform
// Bar.Label("Kevin")

val email = Foo.Email("[email protected]")
email.intoPartial[Bar.Email].transform
// Result[Bar.Email] = Value(Bar.Email("[email protected]"))

Foo(id, Foo.Baz(name, email).intoPartial[Bar].transform
// Result[Bar] = Value(Bar(id = Code(PosInt(123)), Bar.Baz(name = Bar.Label("Kevin"), Bar.Email("[email protected]"))))

refined4s.modules.chimney.derivation.ChimneyNewtype

  • [refined4s-chimney] Add refined4s.modules.chimney.derivation.ChimneyNewtype for Newtype derivation for Chimney (#326)
import refined4s.Newtype
import refined4s.types.all.PosInt

import refined4s.modules.chimney.derivation.*

type Id = Id.Type
object Id extends Newtype[PosInt], ChimneyNewtype[PosInt]

type Name = Name.Type
object Name extends Newtype[String], ChimneyNewtype[String]

refined4s.modules.chimney.derivation.ChimneyRefined

  • [refined4s-chimney] Add refined4s.modules.chimney.derivation.ChimneyRefined for Refined derivation for Chimney (#327)
import refined4s.types.all.*
import refined4s.Refined

import refined4s.modules.chimney.derivation.*

type Email = Email.Type
object Email extends Refined[String], ChimneyRefined[String] {
  val emailRegEx =
    """([a-zA-Z0-9]+([-_\.\+]+[a-zA-Z0-9]+)*@[a-zA-Z0-9]+([-_]+[a-zA-Z0-9]+)*(?:[.][a-zA-Z0-9]+([-_]+[a-zA-Z0-9]+)*)+)""".r

  override def invalidReason(a: String): String = s"Invalid email: $a"

  override def predicate(a: String): Boolean = emailRegEx.findFirstMatchIn(a).isDefined
}

refined4s.modules.chimney.derivation.types.strings

  • [refined4s-chimney] Add refined4s.modules.chimney.derivation.types.strings to support Chimney for pre-defined refined types in refined4s.types.strings (#331)
import refined4s.modules.chimney.derivation.types.strings.given

refined4s.modules.chimney.derivation.types.numeric

  • [refined4s-chimney] Add refined4s.modules.chimney.derivation.types.numeric to support Chimney for pre-defined refined types in refined4s.types.numeric (#332)
import refined4s.modules.chimney.derivation.types.numeric.given

refined4s.modules.chimney.derivation.types.network

  • [refined4s-chimney] Add refined4s.modules.chimney.derivation.types.network to support Chimney for pre-defined refined types in refined4s.types.network (#333)
import refined4s.modules.chimney.derivation.types.network.given

refined4s.modules.chimney.derivation.types.all

  • [refined4s-chimney] Add refined4s.modules.chimney.derivation.types.all to support Chimney for pre-defined refined types in refined4s.types.all (#334)

It's for all pre-defined types in strings, numeric and network.

import refined4s.modules.chimney.derivation.types.all.given

Internal Housekeeping

  • Bump Scala to 3.3.3, the latest Long-Term Support (LTS) version (#319)

v0.16.0

03 Aug 13:48
Compare
Choose a tag to compare

0.16.0 - 2024-08-03

Improvement

  • [refined4s-core] Add unicode encoding for the error message from NonBlankString.from (#312)
    val s = "\u0009\u200a\u2004\u1680"
    // String = "	   "
    NonBlankString.from(s)
    // Left(Invalid value: [	   ], unicode=[\u0009\u200a\u2004\u1680]. It must be not all whitespace non-empty String)
  • [refined4s-circe] Add numeric, strings and network objects in refined4s.modules.circe.derivation.types

v0.15.0

13 Apr 11:48
Compare
Choose a tag to compare

0.15.0 - 2024-04-13

New Features

  • [refined4s-core] Add NonBlankString which can be neither all whitespace chars nor an empty String (#281)

    NonBlankString("")
    // Invalid value: [""]. It must be not all whitespace non-empty String
    
    NonBlankString(" ")
    // Invalid value: [" "]. It must be not all whitespace non-empty String
    
    NonBlankString("   ")
    // Invalid value: ["   "]. It must be not all whitespace non-empty String
    
    NonBlankString("\n")
    // Invalid value: ["\n"]. It must be not all whitespace non-empty String
    
    NonBlankString("\t")
    // Invalid value: ["\t"]. It must be not all whitespace non-empty String
    
    NonBlankString("\t\n")
    // Invalid value: ["\t\n"]. It must be not all whitespace non-empty String
    
    NonBlankString(" \t \n")
    // Invalid value: [" \t \n"]. It must be not all whitespace non-empty String
  • [refined4s-cats] Add cats support for NonBlankString (#283)

  • [refined4s-circe] Add circe support for NonBlankString (#284)

  • [refined4s-pureconfig] Add pureconfig support for NonBlankString (#285)

  • [refined4s-doobie] Add doobie support for NonBlankString (#286)

  • [refined4s-extras-render] Add extras-render support for NonBlankString (#287)

  • [refined4s-tapir] Add tapir support for NonBlankString (#288)

v0.14.0

05 Apr 10:35
Compare
Choose a tag to compare

0.14.0 - 2024-04-05

New Features

  • Add refined4s-tapir to support tapir (#272)
  • [refined4s-tapir] Add TapirNewtypeSchema and TapirRefinedSchema to support sttp.tapir.Schema for refined4s (#273)
  • [refined4s-tapir] Add Schemas for pre-defined refined types (#276)
  • [refined4s-tapir] Add Schema type-class instances with auto deriving (#278)

v0.13.0

21 Jan 01:09
Compare
Choose a tag to compare

0.13.0 - 2024-01-21

New Features

  • [refined4s-core] Add Url to refined4s.types.network and the type-class instances for Url in the other modules (#246)

  • [refined4s-core] Add Uuid String which can be validated as java.util.UUID and the type-class instances for Uuid in the other modules (#248)

  • [refined4s-core] Add Uri.apply(java.net.URI) (#251)

  • [refined4s-core] Add Url.apply(java.net.URL) (#252)

  • [refined4s-refined-compat-scala2] Add Uri, Url and Uuid (#255)

v0.12.0

20 Jan 06:19
Compare
Choose a tag to compare

0.12.0 - 2024-01-20

New Feature

  • [refined4s-core] Make pre-defined types in types.all importable from each type category (i.e. numeric, strings and network) (#237)

    So it means a type like refined4s.types.numeric.NegInt should be exactly the same as refined4s.types.all.NegInt.


  • Add refined4s-refined-compat modules for compatibility with the refined library in Scala 2 (#241)
    • refined4s-refined-compat-scala2 for compatibility with refined in Scala 2
    • refined4s-refined-compat-scala3 for just using refined4s in Scala 3

  • Add RefinedCompatAllTypes to refined4s-refined-compat-scala2 and refined4s-refined-compat-scala3 (#243)

Internal Change

  • [refined4s-core] Move MinValue and MaxValue from each MinMax to Min and Max (#239)

    e.g.)

    type NegInt = NegInt.Type
    object NegInt extends Numeric[Int], MinMax[Int] {
      override def min: Type = apply(Int.MinValue)
      override def max: Type = apply(-1)
    
      val MinValue: Type = min
      val MaxValue: Type = max
    }

    to

    trait Min[A] {
      self: NewtypeBase[A] =>
      def min: Type
    
      val MinValue: Type = min
    }
    
    trait Max[A] {
      self: NewtypeBase[A] =>
      def max: Type
    
      val MaxValue: Type = max
    }