Skip to content

Commit

Permalink
CatsToValid
Browse files Browse the repository at this point in the history
  • Loading branch information
xuwei-k committed Jan 8, 2025
1 parent 50e9c4f commit 45fced0
Show file tree
Hide file tree
Showing 3 changed files with 171 additions and 0 deletions.
46 changes: 46 additions & 0 deletions input/src/main/scala/fix/CatsToValidTest.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
rule = CatsToValid
*/
package fix

import cats.data.Validated
import cats.data.ValidatedNec
import cats.data.ValidatedNel
import cats.syntax.all.*

class CatsToValidTest {
def f1[A](x: Option[A]): Validated[String, A] = x match {
case Some(value) => Validated.valid(value)
case None => Validated.invalid("error 1")
}

def f2[A](x: Option[A]): ValidatedNec[String, A] = x match {
case Some(value) => Validated.valid(value)
case None => Validated.invalidNec("error 2")
}

def f3[A](x: Option[A]): ValidatedNel[String, A] = x match {
case Some(value) => Validated.valid(value)
case None => Validated.invalidNel("error 3")
}

def f4[A](x: Option[A]): Validated[String, A] = x match {
case Some(value) => Validated.valid(value)
case _ => Validated.invalid("error 4")
}

def f5[A](x: Option[A]): Validated[String, A] = x match {
case None => Validated.invalid("error 5")
case Some(value) => Validated.valid(value)
}

def f6[A](x: Option[A], c: Boolean): Validated[String, A] = x match {
case Some(value) if c => Validated.valid(value)
case _ => Validated.invalid("error 6")
}

def f7[A](x: Option[A]): Validated[String, A] = x match {
case Some(value) => value.valid
case _ => "error 7".invalid
}
}
25 changes: 25 additions & 0 deletions output/src/main/scala/fix/CatsToValidTest.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package fix

import cats.data.Validated
import cats.data.ValidatedNec
import cats.data.ValidatedNel
import cats.syntax.all.*

class CatsToValidTest {
def f1[A](x: Option[A]): Validated[String, A] = x.toValid("error 1")

def f2[A](x: Option[A]): ValidatedNec[String, A] = x.toValidNec("error 2")

def f3[A](x: Option[A]): ValidatedNel[String, A] = x.toValidNel("error 3")

def f4[A](x: Option[A]): Validated[String, A] = x.toValid("error 4")

def f5[A](x: Option[A]): Validated[String, A] = x.toValid("error 5")

def f6[A](x: Option[A], c: Boolean): Validated[String, A] = x match {
case Some(value) if c => Validated.valid(value)
case _ => Validated.invalid("error 6")
}

def f7[A](x: Option[A]): Validated[String, A] = x.toValid("error 7")
}
100 changes: 100 additions & 0 deletions rules/src/main/scala/fix/CatsToValid.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package fix

import scala.meta.Case
import scala.meta.Pat
import scala.meta.Term
import scala.meta.transversers._
import scalafix.Patch
import scalafix.v1.SyntacticDocument
import scalafix.v1.SyntacticRule
import scalafix.v1.XtensionSeqPatch

class CatsToValid extends SyntacticRule("CatsToValid") {
override def fix(implicit doc: SyntacticDocument): Patch = {
doc.tree.collect {
case t @ Term.Match.After_4_4_5(
_,
CatsToValid.Cases(method, err),
Nil
) =>
Patch.replaceTree(t, s"${t.expr}.${method}(${err})")
}.asPatch
}
}

object CatsToValid {
private object InvalidMethod {
def unapply(value: String): Option[String] = PartialFunction.condOpt(value) {
case "invalidNec" => "toValidNec"
case "invalidNel" => "toValidNel"
case "invalid" => "toValid"
}
}

private object WrapValid {
def unapply(t: Term): Option[Term.Name] = PartialFunction.condOpt(t) {
case Term.Apply.After_4_6_0(
Term.Select(Term.Name("Validated"), Term.Name("valid")),
Term.ArgClause((x: Term.Name) :: Nil, None)
) =>
x
case Term.Select(x: Term.Name, Term.Name("valid")) =>
x
}
}

private object WrapInvalid {
def unapply(t: Term): Option[(String, Term)] = PartialFunction.condOpt(t) {
case Term.Apply.After_4_6_0(
Term.Select(
Term.Name("Validated"),
Term.Name(CatsToValid.InvalidMethod(method))
),
Term.ArgClause(err :: Nil, None)
) =>
(method, err)
case Term.Select(err, Term.Name(CatsToValid.InvalidMethod(method))) =>
(method, err)
}
}

private object SomeCase {
def unapply(c: Case): Boolean = PartialFunction.cond(c) {
case Case(
Pat.Extract.After_4_6_0(
Term.Name("Some"),
Pat.ArgClause(Pat.Var(x1: Term.Name) :: Nil)
),
None,
WrapValid(x2)
) =>
x1.value == x2.value
}
}

private object NoneCase {
def unapply(c: Case): Option[(String, Term)] = PartialFunction.condOpt(c) {
case Case(
Term.Name("None") | Pat.Wildcard(),
None,
WrapInvalid(method, err)
) =>
(method, err)
}
}

private object Cases {
def unapply(cases: List[Case]): Option[(String, Term)] = PartialFunction.condOpt(cases) {
case List(
CatsToValid.SomeCase(),
CatsToValid.NoneCase(x1, x2),
) =>
(x1, x2)
case List(
CatsToValid.NoneCase(x1, x2),
CatsToValid.SomeCase(),
) =>
(x1, x2)
}
}
}

0 comments on commit 45fced0

Please sign in to comment.