Initial version (Server, Compose clients work)

This commit is contained in:
2026-08-04 12:12:25 +02:00
commit 2a1487037b
59 changed files with 4701 additions and 0 deletions
+95
View File
@@ -0,0 +1,95 @@
#!/usr/bin/env kotlin
@file:DependsOn("org.jetbrains.kotlin:kotlin-compiler-embeddable:2.3.21")
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreApplicationEnvironment
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreApplicationEnvironmentMode
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreProjectEnvironment
import org.jetbrains.kotlin.com.intellij.openapi.util.Disposer
import org.jetbrains.kotlin.parsing.KotlinParserDefinition
import org.jetbrains.kotlin.psi.KtClass
import org.jetbrains.kotlin.psi.KtPsiFactory
import java.nio.file.Files
import java.nio.file.Path
import kotlin.io.path.*
import kotlin.system.exitProcess
fun process(file: Path, outputDir: Path, factory: KtPsiFactory) {
if(!file.exists()) {
System.err.println("Skipping $file: file does not exist")
return
}
if(!file.isReadable()) {
System.err.println("Skipping $file: file is not readable")
return
}
val ktFile = factory.createFile(file.readText())
val pkg = ktFile.packageFqName.toString()
val imports = ktFile.importDirectives.mapNotNull { it.importedFqName }.filter { !it.toString().contains("ToPartialize") }
val classes = ktFile.declarations.mapNotNull { cls ->
if(cls !is KtClass || !cls.isData()) return@mapNotNull null
val annotations = cls.annotationEntries.map { it.text }
if("@ToPartialize" !in annotations) return@mapNotNull null
val ogName = cls.name ?: return@mapNotNull null
val newName = "Partial$ogName"
val nestedTypes = cls.declarations.filterIsInstance<KtClass>().mapNotNull { it.name }.toSet()
val props = cls.primaryConstructorParameters.map {
val name = it.name
val type = it.typeReference?.text
if(name == null || type == null) return@mapNotNull null
name to type
}.joinToString(", ") { (n, t) ->
val nnT = if(t.endsWith('?')) t.substring(startIndex = 0, endIndex = t.length - 1) else t
val useT = if(nnT in nestedTypes) "$ogName.$nnT" else nnT
"val $n: $useT? = null"
}
"@Serializable\ndata class $newName($props)"
}
val cnt = "package $pkg\n\n${imports.joinToString("\n") { "import $it" }}\n\n${classes.joinToString("\n\n")}"
// println(cnt)
val writeDir = outputDir.resolve(pkg.replace('.', '/'))
val fileName = file.fileName
// println("Trying to write to $writeDir/$fileName")
if(!writeDir.exists()) writeDir.createDirectories()
Files.writeString(Path("$writeDir/$fileName"), cnt)
}
// usage kotlin partialize.main.kts output-dir [input-file]+
if(args.isEmpty()) {
System.err.println("Usage: partialize.main.kts <output-dir> <input-file>+")
exitProcess(-1)
}
val outputDir = Path(args[0])
if(outputDir.notExists()) {
println("Creating output directory $outputDir...")
Files.createDirectory(outputDir)
}
else if(!outputDir.isDirectory()) {
System.err.println("Output directory $outputDir is not a directory.")
exitProcess(-1)
}
else if(!outputDir.isWritable()) {
System.err.println("Cannot write to output directory $outputDir")
exitProcess(-1)
}
val inputFiles = args.slice(1 until args.size)
val disp = Disposer.newDisposable()
val appEnv = KotlinCoreApplicationEnvironment.create(disp, KotlinCoreApplicationEnvironmentMode.Production)
appEnv.registerParserDefinition(KotlinParserDefinition())
val project = KotlinCoreProjectEnvironment(disp, appEnv)
val factory = KtPsiFactory(project.project)
inputFiles.forEach {
process(Path(it), outputDir, factory)
}