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 Show documentation
Show all versions of spine Show documentation
Signals for all occasions
The newest version!
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
}
}