/
StringFormatToInterpolation.scala
70 lines (67 loc) · 2.06 KB
/
StringFormatToInterpolation.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
package fix
import scala.meta.Lit
import scala.meta.Term
import scala.meta.XtensionClassifiable
import scala.meta.XtensionCollectionLikeUI
import scala.meta.XtensionSyntax
import scalafix.Patch
import scalafix.v1.SyntacticDocument
import scalafix.v1.SyntacticRule
import scalafix.v1.XtensionSeqPatch
private object StringFormatToInterpolation {
private object Extract {
def unapply(t: Term): Option[(Boolean, String, List[Term])] = PartialFunction
.condOpt(t) {
case Term.ApplyInfix.Initial(
s: Lit.String,
Term.Name("format"),
Nil,
args
) =>
(s, args)
case Term.Apply.Initial(
Term.Select(
s: Lit.String,
Term.Name("format")
),
args
) =>
(s, args)
}
.collect {
case (s, args)
if args.nonEmpty &&
args.lengthCompare(s.value.sliding(2).count(_ == "%s")) == 0 &&
s.value.forall(_ != '\\') && // TODO support backslash
(s.value.forall(_ != '"') || s.syntax.startsWith("\"\"\"")) && // TODO support double-quote
!args.exists(_.is[Term.Placeholder]) =>
(s.syntax.startsWith("\"\"\""), s.value, args)
}
}
}
class StringFormatToInterpolation extends SyntacticRule("StringFormatToInterpolation") {
override def fix(implicit doc: SyntacticDocument): Patch = {
doc.tree.collect { case t @ StringFormatToInterpolation.Extract(triple, str, args) =>
val buf =
if (triple) {
new java.lang.StringBuilder("s\"\"\"")
} else {
new java.lang.StringBuilder("s\"")
}
str.split("%s", -1).zipWithIndex.foreach { case (s, i) =>
buf.append(s.replace("\n", "\\n"))
if (i < args.length) {
buf.append("${")
buf.append(args(i))
buf.append("}")
}
}
if (triple) {
buf.append("\"\"\"")
} else {
buf.append("\"")
}
Patch.replaceTree(t, buf.toString)
}.asPatch
}
}