Scala

Valar

0.6.0

Validators derived at compile time

A validation library for Scala 3 that derives validators from your types at compile time. If a field type is missing a validator, the compiler reports every missing one, names the fields, and tells you what to add. Validators compose in two modes: zip to collect all errors in one pass, flatMap to stop at the first. Errors carry field paths, so failures point to the exact location in nested data.

Examples

Validators compose. Zip collects all errors in one pass

val user = (
  field("name", nonEmpty),
  field("age", between(0, 150)),
  field("email", matches(emailPattern))
).zip  // collects all errors in one pass

user.validate(input)

Compile-time derivation from case classes

case class Config(host: String, port: Int, debug: Boolean)

// Valar derives the validator from the type at compile time.
// Missing validators cause a compile error, not a runtime one.
val validator = Validator.derived[Config]

Structured errors with field paths

val result = user.validate(badInput)
// Left(List(
//   ValidationError("name", "must not be empty"),
//   ValidationError("age", "must be between 0 and 150"),
//   ValidationError("email", "must match pattern")
// ))

Fail-fast with flatMap, accumulate with zip

// Stop at the first error
val strict = nameV.flatMap(_ => ageV).flatMap(_ => emailV)

// Collect all errors in one pass
val lenient = (nameV, ageV, emailV).zip

Cross-compiles to JVM and Scala Native

// build.sbt
lazy val core = crossProject(JVMPlatform, NativePlatform)
  .settings(
    name := "valar-core",
    libraryDependencies += "net.ghoula" %%% "valar-core" % "0.6.0"
  )

Features

Compile-time derivation through Scala 3 inline macros and Mirror types
Error accumulation with zip, fail-fast with flatMap
Structured errors with field paths, severity, and error codes
Cross-compiles to JVM and Scala Native