commonMain.ru.casperix.file_data.FileDataLoader.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of spine-jvm Show documentation
Show all versions of spine-jvm Show documentation
Signals for all occasions
package ru.casperix.file_data
import ru.casperix.misc.Left
import ru.casperix.misc.Right
import ru.casperix.multiplatform.loader.ResourceLoadError
import ru.casperix.multiplatform.loader.resourceLoader
import ru.casperix.signals.concrete.EitherFuture
import ru.casperix.signals.concrete.map
object FileDataLoader {
private val cache = mutableMapOf>()
data class InvalidFileData(val path: String, val message: String) : ResourceLoadError
fun load(path: String): EitherFuture {
return cache.getOrPut(path) {
resourceLoader.loadText(path).map({
try {
Right(parse(it))
} catch (e: Throwable) {
Left(InvalidFileData(path, e.message ?: ""))
}
}, {
it
})
}
}
fun parse(raw: String): FileData {
val lineSplitter = Regex("(\\r\\n|\\r|\\n)")
val nameValueTemplate = Regex("\\s*(\\w+)\\s*:\\s*(.+)")
val titleTemplate = Regex("^[^:]*")
val fileData = FileData()
var currentPage = PageData()
var currentBlock: BlockData? = null
fileData.pageList += currentPage
val lines = raw.split(lineSplitter)
lines.forEachIndexed { index, line ->
if (line.isEmpty()) {
// ignore last empty line
if (index == lines.lastIndex) return@forEachIndexed
// next page
currentPage = PageData()
fileData.pageList += currentPage
} else {
val res1 = nameValueTemplate.matchEntire(line)
if (res1 != null) {
// next property
val name = res1.groupValues[1]
val value = res1.groupValues[2]
currentBlock!!.values[name] = value
} else {
val res2 = titleTemplate.matchEntire(line)
if (res2 != null) {
// next block
val title = res2.value
currentBlock = BlockData(title)
currentPage.blockList += currentBlock!!
} else {
throw Exception("Invalid file-data")
}
}
}
}
if (!fileData.pageList.contains(currentPage)) {
fileData.pageList += currentPage
}
return fileData
}
}