RegexPathPattern.kt

  1. package com.hexagonkt.http.patterns

  2. import com.hexagonkt.core.text.filter
  3. import com.hexagonkt.http.patterns.TemplatePathPattern.Companion.VARIABLE_PATTERN
  4. import com.hexagonkt.http.patterns.TemplatePathPattern.Companion.patternToRegex

  5. data class RegexPathPattern(val regex: Regex) : PathPattern {

  6.     override val pattern: String = regex.pattern
  7.     override val prefix: Boolean = !regex.pattern.endsWith("$")

  8.     internal companion object {
  9.         const val PARAMETER_PREFIX = "(?<"
  10.         const val PARAMETER_SUFFIX = ">$VARIABLE_PATTERN?)"
  11.         val PARAMETER_REGEX = Regex("""\(\?<\w+>""")
  12.     }

  13.     init {
  14.         checkPathPatternPrefix(pattern, listOf("(.*?)", "$"))
  15.     }

  16.     val parameters: List<String> =
  17.         PARAMETER_REGEX.findAll(pattern)
  18.             .map { it.value.removePrefix("(?<").removeSuffix(">") }
  19.             .toList()

  20.     override fun addPrefix(prefix: String?): PathPattern =
  21.         if (prefix == null) this
  22.         else copy(regex = Regex(patternToRegex(prefix, true) + pattern))

  23.     override fun matches(requestUrl: String): Boolean =
  24.         if (prefix) regex.matchesAt(requestUrl, 0)
  25.         else regex.matches(requestUrl)

  26.     override fun extractParameters(requestUrl: String): Map<String, String> {
  27.         val result = regex.matchEntire(requestUrl)
  28.         require(result != null) { "URL '$requestUrl' does not match path" }

  29.         val allValues = result.groupValues
  30.             .drop(1)
  31.             .mapIndexed { ii, v -> ii.toString() to v }
  32.             .toMap()

  33.         val resultGroups = result.groups as MatchNamedGroupCollection
  34.         return if (parameters.isEmpty()) allValues
  35.         else parameters.associateWith { resultGroups[it]?.value ?: "" } + allValues
  36.     }

  37.     override fun insertParameters(parameters: Map<String, Any>): String {
  38.         val keys = parameters.keys
  39.         val patternParameters = this.parameters

  40.         require(keys.toSet() == patternParameters.toSet()) {
  41.             "Parameters must match pattern's parameters($patternParameters). Provided: $keys"
  42.         }

  43.         return pattern.filter(PARAMETER_PREFIX, PARAMETER_SUFFIX, parameters)
  44.     }
  45. }