Make SemVersion.Requirement data class

This commit is contained in:
Karlatemp 2020-11-09 23:19:42 +08:00
parent d54f4cd0d9
commit ce678a75b7
No known key found for this signature in database
GPG Key ID: 21FBDDF664FF06F8
5 changed files with 61 additions and 26 deletions

View File

@ -189,7 +189,7 @@ internal object RangeTokenReader {
}
}
fun parse(source: String, token: Token): SemVersion.Requirement {
fun parse(source: String, token: Token): RequirementInternal {
return when (token) {
is Token.Group -> {
if (token.values.size == 1) {
@ -206,7 +206,7 @@ internal object RangeTokenReader {
}.map { parse(source, it) }.toList()
when (logic.first()) {
TokenType.OR -> {
return object : SemVersion.Requirement {
return object : RequirementInternal {
override fun test(version: SemVersion): Boolean {
rules.forEach { if (it.test(version)) return true }
return false
@ -214,7 +214,7 @@ internal object RangeTokenReader {
}
}
TokenType.AND -> {
return object : SemVersion.Requirement {
return object : RequirementInternal {
override fun test(version: SemVersion): Boolean {
rules.forEach { if (!it.test(version)) return false }
return true

View File

@ -0,0 +1,16 @@
/*
* Copyright 2019-2020 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AFFERO GENERAL PUBLIC LICENSE version 3 license that can be found through the following link.
*
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
package net.mamoe.mirai.console.internal.util.semver
import net.mamoe.mirai.console.util.SemVersion
internal interface RequirementInternal {
fun test(version: SemVersion): Boolean
}

View File

@ -75,11 +75,11 @@ internal object SemVersionInternal {
}
@JvmStatic
internal fun parseRule(rule: String): SemVersion.Requirement {
internal fun parseRule(rule: String): RequirementInternal {
val trimmed = rule.trim()
if (directVersion.matches(trimmed)) {
val parsed = SemVersion.invoke(trimmed)
return object : SemVersion.Requirement {
return object : RequirementInternal {
override fun test(version: SemVersion): Boolean = version.compareTo(parsed) == 0
}
}
@ -89,7 +89,7 @@ internal object SemVersionInternal {
.replace("x", ".+") +
"$"
).toRegex()
return object : SemVersion.Requirement {
return object : RequirementInternal {
override fun test(version: SemVersion): Boolean = regex.matches(version.toString())
}
}
@ -120,7 +120,7 @@ internal object SemVersionInternal {
'(', ')' -> ({ it < end })
else -> throw AssertionError()
}
return object : SemVersion.Requirement {
return object : RequirementInternal {
override fun test(version: SemVersion): Boolean = a(version) && b(version)
}
}
@ -129,32 +129,32 @@ internal object SemVersionInternal {
val version1 = SemVersion.invoke(result.groupValues[8])
return when (operator) {
">=" -> {
object : SemVersion.Requirement {
object : RequirementInternal {
override fun test(version: SemVersion): Boolean = version >= version1
}
}
">" -> {
object : SemVersion.Requirement {
object : RequirementInternal {
override fun test(version: SemVersion): Boolean = version > version1
}
}
"<=" -> {
object : SemVersion.Requirement {
object : RequirementInternal {
override fun test(version: SemVersion): Boolean = version <= version1
}
}
"<" -> {
object : SemVersion.Requirement {
object : RequirementInternal {
override fun test(version: SemVersion): Boolean = version < version1
}
}
"=" -> {
object : SemVersion.Requirement {
object : RequirementInternal {
override fun test(version: SemVersion): Boolean = version.compareTo(version1) == 0
}
}
"!=" -> {
object : SemVersion.Requirement {
object : RequirementInternal {
override fun test(version: SemVersion): Boolean = version.compareTo(version1) != 0
}
}
@ -164,15 +164,9 @@ internal object SemVersionInternal {
throw IllegalArgumentException("Cannot parse $rule")
}
private fun SemVersion.Requirement.withRule(rule: String): SemVersion.Requirement {
return object : SemVersion.Requirement {
override fun test(version: SemVersion): Boolean = this@withRule.test(version)
override fun toString(): String = rule
}
}
@JvmStatic
fun parseRangeRequirement(requirement: String): SemVersion.Requirement {
fun parseRangeRequirement(requirement: String): RequirementInternal {
if (requirement.isBlank()) {
throw IllegalArgumentException("Invalid requirement: Empty requirement rule.")
}
@ -180,7 +174,7 @@ internal object SemVersionInternal {
val collected = RangeTokenReader.collect(requirement, tokens.iterator(), true)
RangeTokenReader.check(requirement, collected.iterator(), null)
return kotlin.runCatching {
RangeTokenReader.parse(requirement, RangeTokenReader.Token.Group(collected, 0)).withRule(requirement)
RangeTokenReader.parse(requirement, RangeTokenReader.Token.Group(collected, 0))
}.onFailure { error ->
throw IllegalArgumentException("Exception in parsing $requirement\n\n" + buildString {
collected.forEach { dump("", it) }

View File

@ -81,9 +81,33 @@ internal constructor(
* 一条依赖规则
* @see [parseRangeRequirement]
*/
public interface Requirement {
@Serializable(Requirement.RequirementAsStringSerializer::class)
public data class Requirement internal constructor(
/**
* 规则的字符串表示方式
*
* @see [SemVersion.parseRangeRequirement]
*/
val rule: String
) {
@Transient
private val impl = SemVersionInternal.parseRangeRequirement(rule)
/** 在 [version] 满足此要求时返回 true */
public fun test(version: SemVersion): Boolean
public fun test(version: SemVersion): Boolean {
return impl.test(version)
}
public object RequirementAsStringSerializer : KSerializer<Requirement> by String.serializer().map(
serializer = { it.rule },
deserializer = { parseRangeRequirement(it) }
)
public companion object {
@JvmSynthetic
public operator fun invoke(@ResolveContext(VERSION_REQUIREMENT) requirement: String): Requirement =
parseRangeRequirement(requirement)
}
}
public object SemVersionAsStringSerializer : KSerializer<SemVersion> by String.serializer().map(
@ -149,7 +173,7 @@ internal constructor(
@JvmStatic
@Throws(IllegalArgumentException::class)
public fun parseRangeRequirement(@ResolveContext(VERSION_REQUIREMENT) requirement: String): Requirement =
SemVersionInternal.parseRangeRequirement(requirement)
Requirement(requirement)
/** @see [Requirement.test] */
@JvmStatic

View File

@ -16,6 +16,7 @@ package net.mamoe.mirai.console.util
import net.mamoe.mirai.console.util.SemVersion.Companion.test
import org.junit.jupiter.api.Test
import kotlin.test.assertFails
internal class TestSemVersion {
@Test
@ -50,9 +51,9 @@ internal class TestSemVersion {
}
fun assertInvalid(requirement: String) {
kotlin.runCatching {
assertFails(requirement) {
SemVersion.parseRangeRequirement(requirement)
}.onSuccess { assert(false) { requirement } }
}
}
fun SemVersion.Requirement.assertFalse(version: String): SemVersion.Requirement {