Skip to content

Commit f6afb6b

Browse files
committed
Knit: Get rid of custom templating, simplify knit name generation
1 parent 83291d4 commit f6afb6b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+170
-177
lines changed

knit/resources/knit.code.include

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@
33
*/
44

55
// This file was automatically generated from ${file.name} by Knit tool. Do not edit.
6-
package ${knit.package}.$$1$$2
6+
package ${knit.package}.${knit.name}

knit/resources/knit.properties

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ module.roots=. integration reactive ui
88
module.marker=build.gradle
99
module.docs=build/dokka
1010

11-
knit.pattern=example-([a-z]+)-(##)\\.kt
11+
knit.pattern=example-[a-zA-Z0-9-]+-##\\.kt
1212
knit.include=knit.code.include
1313

1414
test.include=knit.test.include

knit/src/Knit.kt

+59-64
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,13 @@ val moduleRoots = globalProperties.getValue("module.roots").split(" ")
1313
val moduleMarker = globalProperties.getValue("module.marker")
1414
val moduleDocs = globalProperties.getValue("module.docs")
1515

16+
// --- other props
17+
18+
const val TEST_NAME_PROP = "test.name"
19+
20+
const val KNIT_PATTERN_PROP = "knit.pattern"
21+
const val KNIT_DIR_PROP = "knit.dir"
22+
1623
// --- markdown syntax
1724

1825
const val DIRECTIVE_START = "<!--- "
@@ -25,10 +32,9 @@ const val CLEAR_DIRECTIVE = "CLEAR"
2532
const val TEST_DIRECTIVE = "TEST"
2633

2734
const val KNIT_AUTONUMBER_PLACEHOLDER = '#'
28-
const val KNIT_AUTONUMBER_REGEX = "[0-9a-z]+"
35+
const val KNIT_AUTONUMBER_REGEX = "([0-9a-z]+)"
2936

3037
const val TEST_NAME_DIRECTIVE = "TEST_NAME"
31-
const val TEST_NAME_PROP = "test.name"
3238

3339
const val MODULE_DIRECTIVE = "MODULE"
3440
const val INDEX_DIRECTIVE = "INDEX"
@@ -44,7 +50,6 @@ const val TEST_END = "```"
4450

4551
const val SECTION_START = "##"
4652

47-
const val PACKAGE_PREFIX = "package "
4853
const val STARTS_WITH_PREDICATE = "STARTS_WITH"
4954
const val ARBITRARY_TIME_PREDICATE = "ARBITRARY_TIME"
5055
const val FLEXIBLE_TIME_PREDICATE = "FLEXIBLE_TIME"
@@ -75,70 +80,65 @@ fun main(args: Array<String>) {
7580
class KnitConfig(
7681
val path: String,
7782
val regex: Regex,
78-
val autonumberGroup: Int,
7983
val autonumberDigits: Int
8084
)
8185

8286
fun KnitProps.knitConfig(): KnitConfig? {
83-
val dir = this["knit.dir"] ?: return null
84-
var pattern = getValue("knit.pattern")
87+
val dir = this[KNIT_DIR_PROP] ?: return null
88+
var pattern = getValue(KNIT_PATTERN_PROP)
8589
val i = pattern.indexOf(KNIT_AUTONUMBER_PLACEHOLDER)
86-
var autonumberGroup = 0
8790
var autonumberDigits = 0
8891
if (i >= 0) {
8992
val j = pattern.lastIndexOf(KNIT_AUTONUMBER_PLACEHOLDER)
9093
autonumberDigits = j - i + 1
9194
require(pattern.substring(i, j + 1) == KNIT_AUTONUMBER_PLACEHOLDER.toString().repeat(autonumberDigits)) {
92-
"knit.pattern can only use a contiguous range of '$KNIT_AUTONUMBER_PLACEHOLDER' for auto-numbering"
95+
"$KNIT_PATTERN_PROP property can only use a contiguous range of '$KNIT_AUTONUMBER_PLACEHOLDER' for auto-numbering"
9396
}
94-
autonumberGroup = pattern.substring(0, i).count { it == '(' } + 1 // note: it does not understand escaped open braces
95-
var replacementRegex = KNIT_AUTONUMBER_REGEX
96-
if (pattern.getOrNull(i - 1) != '(' || pattern.getOrNull(j + 1) != ')') {
97-
// needs its own group to extract number
98-
autonumberGroup++
99-
replacementRegex = "($replacementRegex)"
97+
require('(' !in pattern && ')' !in pattern) {
98+
"$KNIT_PATTERN_PROP property cannot have match groups"
10099
}
101-
pattern = pattern.substring(0, i) + replacementRegex + pattern.substring(j + 1)
100+
pattern = pattern.substring(0, i) + KNIT_AUTONUMBER_REGEX + pattern.substring(j + 1)
102101
}
103-
val path = "$dir$pattern"
104-
return KnitConfig(path, Regex("\\(($path)\\)"), autonumberGroup, autonumberDigits)
102+
val path = "$dir($pattern)"
103+
return KnitConfig(path, Regex("\\(($path)\\)"), autonumberDigits)
105104
}
106105

107106
class KnitIncludeEnv(
108107
val file: File,
109-
props: KnitProps
108+
props: KnitProps,
109+
knitName: String
110110
) {
111-
val knit = props.getMap("knit")
111+
val knit = props.getMap("knit") + mapOf("name" to knitName)
112112
}
113113

114-
fun KnitConfig.loadMainInclude(file: File, props: KnitProps): Include {
114+
fun KnitConfig.loadMainInclude(file: File, props: KnitProps, knitName: String): Include {
115115
val include = Include(Regex(path))
116-
include.lines += props.loadTemplateLines("knit.include", KnitIncludeEnv(file, props))
116+
include.lines += props.loadTemplateLines("knit.include", KnitIncludeEnv(file, props, knitName))
117117
include.lines += ""
118118
return include
119119
}
120120

121+
data class KnitInfo(val pkg: String, val name: String)
122+
121123
fun knit(markdownFile: File): Boolean {
122124
println("*** Reading $markdownFile")
123125
val props = markdownFile.findProps()
124126
val knit = props.knitConfig()
125-
var knitAutonumberIndex = HashMap<String, Int>()
127+
val knitAutonumberIndex = HashMap<String, Int>()
126128
val tocLines = arrayListOf<String>()
127129
val includes = arrayListOf<Include>()
128130
val codeLines = arrayListOf<String>()
129131
val testLines = arrayListOf<String>()
130132
var testName: String? = props[TEST_NAME_PROP]
131133
val testOutLines = arrayListOf<String>()
132-
var lastPgk: String? = null
134+
var lastKnit: KnitInfo? = null
133135
val files = mutableSetOf<File>()
134136
val allApiRefs = arrayListOf<ApiRef>()
135137
val remainingApiRefNames = mutableSetOf<String>()
136138
var moduleName: String by Delegates.notNull()
137139
var docsRoot: String by Delegates.notNull()
138140
var retryKnitLater = false
139141
val tocRefs = ArrayList<TocRef>().also { tocRefMap[markdownFile] = it }
140-
// load main includes (if defined)
141-
knit?.loadMainInclude(markdownFile, props)?.let { includes += it }
142142
// read markdown file
143143
val markdown = markdownFile.withMarkdownTextReader {
144144
mainLoop@ while (true) {
@@ -200,7 +200,7 @@ fun knit(markdownFile: File): Boolean {
200200
testName = directive.param
201201
}
202202
TEST_DIRECTIVE -> {
203-
require(lastPgk != null) { "'$PACKAGE_PREFIX' prefix was not found in emitted code"}
203+
require(lastKnit != null) { "$TEST_DIRECTIVE must be preceeded by knitted file" }
204204
require(testName != null) { "Neither $TEST_NAME_DIRECTIVE directive nor '$TEST_NAME_PROP'property was specified" }
205205
val predicate = directive.param
206206
if (testLines.isEmpty()) {
@@ -211,7 +211,7 @@ fun knit(markdownFile: File): Boolean {
211211
} else {
212212
requireSingleLine(directive)
213213
}
214-
makeTest(testOutLines, lastPgk!!, testLines, predicate)
214+
makeTest(testOutLines, lastKnit!!, testLines, predicate)
215215
testLines.clear()
216216
}
217217
MODULE_DIRECTIVE -> {
@@ -261,12 +261,13 @@ fun knit(markdownFile: File): Boolean {
261261
}
262262
}
263263
knit?.regex?.find(inLine)?.let knitRegexMatch@{ knitMatch ->
264-
val fileName = knitMatch.groups[1]!!.value
264+
val path = knitMatch.groups[1]!!.value // full matched knit path dir dir & file name
265+
val fileGroup = knitMatch.groups[2]!!
266+
val fileName = fileGroup.value // knitted file name like "example-basic-01.kt"
265267
if (knit.autonumberDigits != 0) {
266-
val numGroup = knitMatch.groups[knit.autonumberGroup]!!
267-
val key = knitMatch.groupValues.withIndex()
268-
.filter { it.index > 1 && it.index != knit.autonumberGroup }
269-
.joinToString("-") { it.value }
268+
val numGroup = knitMatch.groups[3]!! // file number part like "01"
269+
val key = inLine.substring(fileGroup.range.first, numGroup.range.first) +
270+
inLine.substring(numGroup.range.last + 1, fileGroup.range.last + 1)
270271
val index = knitAutonumberIndex.getOrElse(key) { 1 }
271272
val num = index.toString().padStart(knit.autonumberDigits, '0')
272273
if (numGroup.value != num) { // update and retry with this line if a different number
@@ -277,25 +278,23 @@ fun knit(markdownFile: File): Boolean {
277278
}
278279
knitAutonumberIndex[key] = index + 1
279280
}
280-
val file = File(markdownFile.parentFile, fileName)
281+
val file = File(markdownFile.parentFile, path)
281282
require(files.add(file)) { "Duplicate file: $file"}
282283
println("Knitting $file ...")
283284
val outLines = arrayListOf<String>()
284-
for (include in includes) {
285-
val includeMatch = include.regex.matchEntire(fileName) ?: continue
286-
include.lines.forEach { includeLine ->
287-
val line = makeReplacements(includeLine, includeMatch)
288-
if (line.startsWith(PACKAGE_PREFIX))
289-
lastPgk = line.substring(PACKAGE_PREFIX.length).trim()
290-
outLines += line
291-
}
292-
}
285+
val fileIncludes = arrayListOf<Include>()
286+
// load & process template of the main include
287+
val knitName = fileName.toKnitName()
288+
fileIncludes += knit.loadMainInclude(markdownFile, props, knitName)
289+
fileIncludes += includes.filter { it.regex.matches(path) }
290+
for (include in fileIncludes) outLines += include.lines
293291
if (outLines.last().isNotBlank()) outLines += ""
294292
for (code in codeLines) {
295293
outLines += code.replace("System.currentTimeMillis()", "currentTimeMillis()")
296294
}
297295
codeLines.clear()
298296
writeLinesIfNeeded(file, outLines)
297+
lastKnit = KnitInfo(props.getValue("knit.package"), knitName)
299298
}
300299
}
301300
} ?: return false // false when failed
@@ -326,24 +325,17 @@ fun knit(markdownFile: File): Boolean {
326325
return true
327326
}
328327

328+
// Converts file name like "example-basic-01.kt" to unique knit.name for package like "exampleBasic01"
329+
fun String.toKnitName(): String = substringBefore('.').capitalizeAfter('-')
330+
329331
data class TocRef(val levelPrefix: String, val name: String, val ref: String)
330332

331-
fun makeTest(testOutLines: MutableList<String>, pgk: String, test: List<String>, predicate: String) {
332-
val funName = buildString {
333-
var cap = true
334-
for (c in pgk) {
335-
cap = if (c == '.') {
336-
true
337-
} else {
338-
append(if (cap) c.toUpperCase() else c)
339-
false
340-
}
341-
}
342-
}
333+
fun makeTest(testOutLines: MutableList<String>, knit: KnitInfo, test: List<String>, predicate: String) {
334+
val funName = knit.name.capitalize()
343335
testOutLines += ""
344336
testOutLines += " @Test"
345337
testOutLines += " fun test$funName() {"
346-
val prefix = " test(\"$funName\") { $pgk.main() }"
338+
val prefix = " test(\"$funName\") { ${knit.pkg}.${knit.name}.main() }"
347339
when (predicate) {
348340
"" -> makeTestLines(testOutLines, prefix, "verifyLines", test)
349341
STARTS_WITH_PREDICATE -> makeTestLines(testOutLines, prefix, "verifyLinesStartWith", test)
@@ -362,6 +354,18 @@ fun makeTest(testOutLines: MutableList<String>, pgk: String, test: List<String>,
362354
testOutLines += " }"
363355
}
364356

357+
private fun String.capitalizeAfter(char: Char): String = buildString {
358+
var cap = false
359+
for (c in this@capitalizeAfter) {
360+
cap = if (c == char) {
361+
true
362+
} else {
363+
append(if (cap) c.toUpperCase() else c)
364+
false
365+
}
366+
}
367+
}
368+
365369
private fun makeTestLines(testOutLines: MutableList<String>, prefix: String, method: String, test: List<String>) {
366370
testOutLines += "$prefix.$method("
367371
for ((index, testLine) in test.withIndex()) {
@@ -372,15 +376,6 @@ private fun makeTestLines(testOutLines: MutableList<String>, prefix: String, met
372376
testOutLines += " )"
373377
}
374378

375-
private fun makeReplacements(line: String, match: MatchResult): String {
376-
var result = line
377-
for ((id, group) in match.groups.withIndex()) {
378-
if (group != null)
379-
result = result.replace("\$\$$id", group.value)
380-
}
381-
return result
382-
}
383-
384379
class TestTemplateEnv(
385380
val file: File,
386381
props: KnitProps,

kotlinx-coroutines-core/jvm/test/guide/example-flow-01.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
*/
44

55
// This file was automatically generated from flow.md by Knit tool. Do not edit.
6-
package kotlinx.coroutines.guide.flow01
6+
package kotlinx.coroutines.guide.exampleFlow01
77

88
fun foo(): List<Int> = listOf(1, 2, 3)
99

kotlinx-coroutines-core/jvm/test/guide/example-flow-02.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
*/
44

55
// This file was automatically generated from flow.md by Knit tool. Do not edit.
6-
package kotlinx.coroutines.guide.flow02
6+
package kotlinx.coroutines.guide.exampleFlow02
77

88
fun foo(): Sequence<Int> = sequence { // sequence builder
99
for (i in 1..3) {

kotlinx-coroutines-core/jvm/test/guide/example-flow-03.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
*/
44

55
// This file was automatically generated from flow.md by Knit tool. Do not edit.
6-
package kotlinx.coroutines.guide.flow03
6+
package kotlinx.coroutines.guide.exampleFlow03
77

88
import kotlinx.coroutines.*
99

kotlinx-coroutines-core/jvm/test/guide/example-flow-04.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
*/
44

55
// This file was automatically generated from flow.md by Knit tool. Do not edit.
6-
package kotlinx.coroutines.guide.flow04
6+
package kotlinx.coroutines.guide.exampleFlow04
77

88
import kotlinx.coroutines.*
99
import kotlinx.coroutines.flow.*

kotlinx-coroutines-core/jvm/test/guide/example-flow-05.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
*/
44

55
// This file was automatically generated from flow.md by Knit tool. Do not edit.
6-
package kotlinx.coroutines.guide.flow05
6+
package kotlinx.coroutines.guide.exampleFlow05
77

88
import kotlinx.coroutines.*
99
import kotlinx.coroutines.flow.*

kotlinx-coroutines-core/jvm/test/guide/example-flow-06.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
*/
44

55
// This file was automatically generated from flow.md by Knit tool. Do not edit.
6-
package kotlinx.coroutines.guide.flow06
6+
package kotlinx.coroutines.guide.exampleFlow06
77

88
import kotlinx.coroutines.*
99
import kotlinx.coroutines.flow.*

kotlinx-coroutines-core/jvm/test/guide/example-flow-07.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
*/
44

55
// This file was automatically generated from flow.md by Knit tool. Do not edit.
6-
package kotlinx.coroutines.guide.flow07
6+
package kotlinx.coroutines.guide.exampleFlow07
77

88
import kotlinx.coroutines.*
99
import kotlinx.coroutines.flow.*

kotlinx-coroutines-core/jvm/test/guide/example-flow-08.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
*/
44

55
// This file was automatically generated from flow.md by Knit tool. Do not edit.
6-
package kotlinx.coroutines.guide.flow08
6+
package kotlinx.coroutines.guide.exampleFlow08
77

88
import kotlinx.coroutines.*
99
import kotlinx.coroutines.flow.*

kotlinx-coroutines-core/jvm/test/guide/example-flow-09.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
*/
44

55
// This file was automatically generated from flow.md by Knit tool. Do not edit.
6-
package kotlinx.coroutines.guide.flow09
6+
package kotlinx.coroutines.guide.exampleFlow09
77

88
import kotlinx.coroutines.*
99
import kotlinx.coroutines.flow.*

kotlinx-coroutines-core/jvm/test/guide/example-flow-10.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
*/
44

55
// This file was automatically generated from flow.md by Knit tool. Do not edit.
6-
package kotlinx.coroutines.guide.flow10
6+
package kotlinx.coroutines.guide.exampleFlow10
77

88
import kotlinx.coroutines.*
99
import kotlinx.coroutines.flow.*

kotlinx-coroutines-core/jvm/test/guide/example-flow-11.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
*/
44

55
// This file was automatically generated from flow.md by Knit tool. Do not edit.
6-
package kotlinx.coroutines.guide.flow11
6+
package kotlinx.coroutines.guide.exampleFlow11
77

88
import kotlinx.coroutines.*
99
import kotlinx.coroutines.flow.*

kotlinx-coroutines-core/jvm/test/guide/example-flow-12.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
*/
44

55
// This file was automatically generated from flow.md by Knit tool. Do not edit.
6-
package kotlinx.coroutines.guide.flow12
6+
package kotlinx.coroutines.guide.exampleFlow12
77

88
import kotlinx.coroutines.*
99
import kotlinx.coroutines.flow.*

kotlinx-coroutines-core/jvm/test/guide/example-flow-13.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
*/
44

55
// This file was automatically generated from flow.md by Knit tool. Do not edit.
6-
package kotlinx.coroutines.guide.flow13
6+
package kotlinx.coroutines.guide.exampleFlow13
77

88
import kotlinx.coroutines.*
99
import kotlinx.coroutines.flow.*

0 commit comments

Comments
 (0)