feat: support lateinit var args declaration for hostArgs injection and add coverage

This commit is contained in:
2026-02-25 14:24:37 +08:00
parent c8f4695582
commit e6a993fcf1
4 changed files with 32 additions and 5 deletions

View File

@@ -1,10 +1,10 @@
// @desc: hello // @desc: hello
// @timeout: 10s // @timeout: 10s
// @param: name | default=world | desc=hello <name> | required=false // @param: name | default=world | desc=hello <name> | required=false
// @param: upper | default=true | desc=upper text | required=false // @param: upper | default=false | desc=upper text | required=false
import java.time.LocalDateTime import java.time.LocalDateTime
val args: Array<String> = emptyArray() lateinit var args: Array<String>
val kv = val kv =
args args
.mapNotNull { .mapNotNull {

View File

@@ -23,7 +23,10 @@ private val metadataCache = ConcurrentHashMap<String, Pair<String, ScriptMetadat
private val compiledScriptCache = ConcurrentHashMap<String, Pair<String, CompiledScript>>() // key -> stamp, compiled script private val compiledScriptCache = ConcurrentHashMap<String, Pair<String, CompiledScript>>() // key -> stamp, compiled script
private val resolver = CompoundDependenciesResolver(FileSystemDependenciesResolver(), MavenDependenciesResolver()) private val resolver = CompoundDependenciesResolver(FileSystemDependenciesResolver(), MavenDependenciesResolver())
private val argsDeclarationRegex = Regex("""^\s*val\s+args\s*:\s*Array<String>\s*=\s*emptyArray\(\)\s*$""") private val argsDeclarationRegexes = listOf(
Regex("""^\s*val\s+args\s*:\s*Array<String>\s*=\s*emptyArray\(\)\s*$"""),
Regex("""^\s*lateinit\s+var\s+args\s*:\s*Array<String>\s*$"""),
)
private const val DEFAULT_SCRIPT_TIMEOUT_MS = 10_000L private const val DEFAULT_SCRIPT_TIMEOUT_MS = 10_000L
private val metadataParamNameRegex = Regex("[A-Za-z0-9._-]+") private val metadataParamNameRegex = Regex("[A-Za-z0-9._-]+")
private val evalExecutor = Executors.newCachedThreadPool { r -> private val evalExecutor = Executors.newCachedThreadPool { r ->
@@ -89,7 +92,7 @@ private fun injectArgsBridgeDeclaration(scriptContent: String): String {
val injected = "val args: Array<String> = hostArgs" val injected = "val args: Array<String> = hostArgs"
var replaced = false var replaced = false
val result = lines.map { line -> val result = lines.map { line ->
if (!replaced && argsDeclarationRegex.matches(line)) { if (!replaced && argsDeclarationRegexes.any { it.matches(line) }) {
replaced = true replaced = true
injected injected
} else { } else {

View File

@@ -291,6 +291,30 @@ class WebHostApiTest {
assertTrue(runWithArg.bodyAsText().contains("name=alice")) 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<String>
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) { private fun withApp(testBlock: suspend io.ktor.server.testing.ApplicationTestBuilder.(java.nio.file.Path) -> Unit) {
val scriptsDir = createTempDirectory("webhost-api-test-") val scriptsDir = createTempDirectory("webhost-api-test-")
tempDirs.add(scriptsDir) tempDirs.add(scriptsDir)

View File

@@ -478,7 +478,7 @@ fun initialScriptTemplate(name: String): String =
// @timeout: 10s // @timeout: 10s
// @param: sample | required=false | default=value | desc=example parameter // @param: sample | required=false | default=value | desc=example parameter
val args: Array<String> = emptyArray() lateinit var args: Array<String>
val kv = args.mapNotNull { val kv = args.mapNotNull {
val i = it.indexOf('=') val i = it.indexOf('=')
if (i <= 0) null else it.substring(0, i) to it.substring(i + 1) if (i <= 0) null else it.substring(0, i) to it.substring(i + 1)