Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 23 additions & 7 deletions wisp-runtime/src/main/java/com/angrypodo/wisp/runtime/Wisp.kt
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,30 @@ class Wisp(
*/
fun resolveRoutes(uri: Uri): List<Any> {
val paths = parser.parse(uri)
val queryParams = getQueryParams(uri)

return paths.map { path ->
matchAndCreate(path) ?: throw WispError.UnknownPath(path)
matchAndCreate(path, queryParams) ?: throw WispError.UnknownPath(path)
}
}

private fun getQueryParams(uri: Uri): Map<String, String> {
val params = mutableMapOf<String, String>()
uri.queryParameterNames.forEach { key ->
uri.getQueryParameter(key)?.let { value ->
params[key] = value
}
}
return params
}

private fun matchAndCreate(path: String): Any? {
private fun matchAndCreate(path: String, queryParams: Map<String, String>): Any? {
for ((pattern, factory) in mergedRoutes) {
val params = WispUriMatcher.match(path, pattern)
if (params != null) {
return factory.create(params)
val pathVariables = WispUriMatcher.match(path, pattern)
if (pathVariables != null) {
// Path Variable과 Query Parameter 병합 (Query Param 우선순위 낮음)
val combinedParams = queryParams + pathVariables
return factory.create(combinedParams)
}
}
return null
Expand Down Expand Up @@ -71,7 +85,9 @@ class Wisp(

@JvmStatic
@Synchronized
fun initialize() {
fun initialize(
parser: WispUriParser = DefaultWispUriParser()
) {
if (instance == null) {
val aggregatedRoutes = mutableMapOf<String, RouteFactory>()
val loader = ServiceLoader.load(WispModuleRegistry::class.java)
Expand All @@ -80,7 +96,7 @@ class Wisp(
aggregatedRoutes.putAll(registry.getRoutes())
}

instance = Wisp(aggregatedRoutes)
instance = Wisp(aggregatedRoutes, parser)
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,26 +1,28 @@
package com.angrypodo.wisp.runtime.parser

import android.net.Uri
import com.angrypodo.wisp.runtime.WispError
import java.net.URLDecoder
import java.nio.charset.StandardCharsets

private const val STACK = "stack"
/**
* 기본 URI 파서 구현체입니다.
* URI의 경로(Path)를 지정된 구분자([delimiter])로 분리하여 라우트 경로 리스트를 생성합니다.
*
* 예: "myapp://home/product" (delimiter="/") -> ["home", "product"]
*/
class DefaultWispUriParser(
private val delimiter: String = "/"
) : WispUriParser {

class DefaultWispUriParser : WispUriParser {
override fun parse(uri: Uri): List<String> {
val encodedStack = uri.getQueryParameter(STACK)
val path = uri.path ?: return emptyList()

if (encodedStack.isNullOrBlank()) {
throw WispError.ParsingFailed(uri.toString(), "Missing 'stack' query parameter")
// 경로가 구분자로 시작하면 제거 (예: "/home" -> "home")
val trimmedPath = if (path.startsWith(delimiter)) {
path.substring(delimiter.length)
} else {
path
}

return try {
val decodedStack = URLDecoder.decode(encodedStack, StandardCharsets.UTF_8.name())

decodedStack.split("|").filter { it.isNotBlank() }
} catch (e: Exception) {
throw WispError.ParsingFailed(uri.toString(), e.message ?: "Unknown decoding error")
}
return trimmedPath.split(delimiter)
.filter { it.isNotEmpty() }
}
}
Loading