forked from scalalandio/chimney
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtest-snippets.scala
More file actions
130 lines (117 loc) · 5.43 KB
/
Copy pathtest-snippets.scala
File metadata and controls
130 lines (117 loc) · 5.43 KB
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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
//> using scala 3.3.8
//> using dep com.kubuszok::scala-cli-md-spec:0.2.1
//> using dep org.virtuslab::scala-yaml:0.3.3
import com.kubuszok.scalaclimdspec.*
import java.io.File
import java.nio.file.Files
import scala.collection.immutable.ListMap
import scala.util.{Try, Using}
import scala.util.chaining.*
// Chimney-specific configuration
case class MkDocsConfig(extra: Map[String, String])
object MkDocsConfig {
def parse(cfgFile: File): Either[String, MkDocsConfig] = {
import org.virtuslab.yaml.*
def decode(any: Any): Map[String, String] = any match {
case map: Map[?, ?] =>
map.flatMap {
case (k, v: Map[?, ?]) => decode(v).map { case (k2, v2) => s"$k.$k2" -> v2 }
case (k, v: List[?]) => decode(v).map { case (k2, v2) => s"$k.$k2" -> v2 }
case (k, v) => Map(k.toString -> v.toString)
}.toMap
case list: List[?] =>
list.zipWithIndex.flatMap {
case (i: Map[?, ?], idx) => decode(i).map { case (k, v) => s"[$idx].$k" -> v }
case (i: List[?], idx) => decode(i).map { case (k, v) => s"[$idx].$k" -> v }
case (i, idx) => Map(s"[$idx]" -> i.toString)
}.toMap
case _ => throw new IllegalArgumentException(s"$any is not an expected YAML")
}
for {
cfgStr <- Using(io.Source.fromFile(cfgFile))(_.getLines().toList.mkString("\n")).toEither.left
.map(_.getMessage())
cfgRaw <- cfgStr.as[Any].left.map(_.toString)
extra <- Try(decode(cfgRaw.asInstanceOf[Map[Any, Any]].apply("extra"))).toEither.left.map(_.getMessage)
} yield MkDocsConfig(extra)
}
}
class ChimneyExtendedRunner(runner: Runner)(
chimneyVersion: String,
mkDocsCfg: MkDocsConfig
) extends Runner {
private val defaultScalaVersion = "3.9.0"
private val replacePatterns = (mkDocsCfg.extra + (raw"chimney_version\(\)" -> chimneyVersion)).map { case (k, v) =>
(raw"\{\{\s*" + k + raw"\s*\}\}") -> v
}
val addDefaultScala: Snippet.Content => Snippet.Content = {
case Snippet.Content.Single(content) =>
Snippet.Content.Single(
if content.contains("//> using scala") then content
else s"//> using scala $defaultScalaVersion\n$content"
)
case Snippet.Content.Multiple(files) =>
Snippet.Content.Multiple(
if files.values.exists(_.content.contains("//> using scala")) then files
else {
val (fileName, Snippet.Content.Single(content0)) = files.head
val content1: Snippet.Content.Single =
Snippet.Content.Single(s"//> using scala $defaultScalaVersion\n$content0")
ListMap(fileName -> content1) ++ files.tail
}
)
}
val interpolateTemplates: Snippet.Content => Snippet.Content = {
case Snippet.Content.Single(content) =>
Snippet.Content.Single(replacePatterns.foldLeft(content) { case (s, (k, v)) => s.replaceAll(k, v) })
case Snippet.Content.Multiple(files) =>
Snippet.Content.Multiple(
ListMap.from(files.mapValues(interpolateTemplates(_).asInstanceOf[Snippet.Content.Single]))
)
}
export runner.{docsDir, filter, howToRun, tmpDir}
extension (snippet: Snippet)
def adjusted: Snippet =
// interpolate templates before Default adjustments
runner.adjusted(snippet.copy(content = interpolateTemplates(snippet.content)))
extension (snippets: List[Snippet])
def adjusted: List[Snippet] = runner.adjusted(snippets).map { snippet =>
// add default Scala but only to those snippets that are already run (adding it before would make all of them run)
howToRun(snippet) match
case Runner.Strategy.Ignore(_) => snippet
case _ => snippet.copy(content = addDefaultScala(snippet.content))
}
}
/** Usage:
*
* From the project root (if called from other directory, adapt path after PWD accordingly):
*
* on CI:
* {{{
* # run all tests, use artifacts published locally from current tag (see docs/Justfile `test-snippets`)
* # NB: under sbt 2.x `print chimney/version` leaks ANSI + a `[success]` line, so strip/grep the version out:
* sbt --client "publish-local-for-tests"
* raw="$(sbt -batch -error 'print chimney/version' 2>&1 || true)"
* chimney_version="$(printf '%s\n' "$raw" | sed -E 's/\x1b\[[0-9;?]*[A-Za-z]//g' | grep -oE '[0-9]+\.[0-9]+\.[0-9]+[A-Za-z0-9.+-]*' | head -1)"
* scala-cli run scripts/test-snippets.scala -- --extra "chimney-version=$chimney_version" "$PWD/docs/docs"
* }}}
*
* during development:
* {{{
* # sbt publish-local-for-tests
* # fix the version to what sbt generated, fix tmp directory to something to be able to preview generated files
* scala-cli run scripts/test-snippets.scala -- --extra "chimney-version=1.x.y-n-g1234567-SNAPSHOT" --test-only "supported-transformations.md*" "$PWD/docs/docs" "/var/folders/m_/sm90t09d5591cgz5h242bkm80000gn/T/docs-snippets13141962741435068727"
* }}}
*/
@main def testChimneySnippets(args: String*): Unit = testSnippets(args.toArray) { cfg =>
ChimneyExtendedRunner(Runner.Default(cfg))(
chimneyVersion = cfg
.extra("chimney-version")
.trim
.pipe("\u001b\\[([0-9]+)m".r.replaceAllIn(_, "")) // remove possible console coloring from sbt
.pipe(raw"(?U)\s".r.replaceAllIn(_, "")) // remove possible ESC characters
.replaceAll("\u001B\\[0J", ""), // replace this one offending thing
mkDocsCfg = MkDocsConfig
.parse(File(s"${cfg.docsDir}/../mkdocs.yml").getAbsoluteFile())
.fold(s => throw Exception(s), identity)
)
}