From e6a993fcf140249ab5f1ae8c32081d4011cf525e Mon Sep 17 00:00:00 2001 From: slhafzjw Date: Wed, 25 Feb 2026 14:24:37 +0800 Subject: [PATCH] feat: support `lateinit var args` declaration for hostArgs injection and add coverage --- scripts/hello.hub.kts | 4 ++-- .../kotlin/work/slhaf/hub/ScriptEngine.kt | 7 ++++-- .../kotlin/work/slhaf/hub/WebHostApiTest.kt | 24 +++++++++++++++++++ tools/slhaf-hub-tui.kts | 2 +- 4 files changed, 32 insertions(+), 5 deletions(-) diff --git a/scripts/hello.hub.kts b/scripts/hello.hub.kts index b3ab673..59a01bb 100644 --- a/scripts/hello.hub.kts +++ b/scripts/hello.hub.kts @@ -1,10 +1,10 @@ // @desc: hello // @timeout: 10s // @param: name | default=world | desc=hello | required=false -// @param: upper | default=true | desc=upper text | required=false +// @param: upper | default=false | desc=upper text | required=false import java.time.LocalDateTime -val args: Array = emptyArray() +lateinit var args: Array val kv = args .mapNotNull { diff --git a/src/main/kotlin/work/slhaf/hub/ScriptEngine.kt b/src/main/kotlin/work/slhaf/hub/ScriptEngine.kt index 7324dc2..6544d79 100644 --- a/src/main/kotlin/work/slhaf/hub/ScriptEngine.kt +++ b/src/main/kotlin/work/slhaf/hub/ScriptEngine.kt @@ -23,7 +23,10 @@ private val metadataCache = ConcurrentHashMap>() // key -> stamp, compiled script private val resolver = CompoundDependenciesResolver(FileSystemDependenciesResolver(), MavenDependenciesResolver()) -private val argsDeclarationRegex = Regex("""^\s*val\s+args\s*:\s*Array\s*=\s*emptyArray\(\)\s*$""") +private val argsDeclarationRegexes = listOf( + Regex("""^\s*val\s+args\s*:\s*Array\s*=\s*emptyArray\(\)\s*$"""), + Regex("""^\s*lateinit\s+var\s+args\s*:\s*Array\s*$"""), +) private const val DEFAULT_SCRIPT_TIMEOUT_MS = 10_000L private val metadataParamNameRegex = Regex("[A-Za-z0-9._-]+") private val evalExecutor = Executors.newCachedThreadPool { r -> @@ -89,7 +92,7 @@ private fun injectArgsBridgeDeclaration(scriptContent: String): String { val injected = "val args: Array = hostArgs" var replaced = false val result = lines.map { line -> - if (!replaced && argsDeclarationRegex.matches(line)) { + if (!replaced && argsDeclarationRegexes.any { it.matches(line) }) { replaced = true injected } else { diff --git a/src/test/kotlin/work/slhaf/hub/WebHostApiTest.kt b/src/test/kotlin/work/slhaf/hub/WebHostApiTest.kt index 4c880ca..25b3270 100644 --- a/src/test/kotlin/work/slhaf/hub/WebHostApiTest.kt +++ b/src/test/kotlin/work/slhaf/hub/WebHostApiTest.kt @@ -291,6 +291,30 @@ class WebHostApiTest { assertTrue(runWithArg.bodyAsText().contains("name=alice")) } + @Test + fun lateinitArgsDeclarationIsSupported() = withApp { _ -> + val create = client.post("/scripts/lateinit-args") { + bearerRoot() + setBody( + """ + // @desc: lateinit args + // @param: name | required=false | default=world | desc=Name fallback + lateinit var args: Array + val kv = args.mapNotNull { + val i = it.indexOf('=') + if (i <= 0) null else it.substring(0, i) to it.substring(i + 1) + }.toMap() + println("name=" + (kv["name"] ?: "missing")) + """.trimIndent() + ) + } + assertEquals(HttpStatusCode.Created, create.status) + + val run = client.get("/run/lateinit-args") { bearerRoot() } + assertEquals(HttpStatusCode.OK, run.status) + assertTrue(run.bodyAsText().contains("name=world")) + } + private fun withApp(testBlock: suspend io.ktor.server.testing.ApplicationTestBuilder.(java.nio.file.Path) -> Unit) { val scriptsDir = createTempDirectory("webhost-api-test-") tempDirs.add(scriptsDir) diff --git a/tools/slhaf-hub-tui.kts b/tools/slhaf-hub-tui.kts index b49ace9..c90e34b 100755 --- a/tools/slhaf-hub-tui.kts +++ b/tools/slhaf-hub-tui.kts @@ -478,7 +478,7 @@ fun initialScriptTemplate(name: String): String = // @timeout: 10s // @param: sample | required=false | default=value | desc=example parameter -val args: Array = emptyArray() +lateinit var args: Array val kv = args.mapNotNull { val i = it.indexOf('=') if (i <= 0) null else it.substring(0, i) to it.substring(i + 1)