diff --git a/backend/mirai-console/src/internal/util/semver/RangeTokenReader.kt b/backend/mirai-console/src/internal/util/semver/RangeTokenReader.kt index 5f761cb6e..17064132b 100644 --- a/backend/mirai-console/src/internal/util/semver/RangeTokenReader.kt +++ b/backend/mirai-console/src/internal/util/semver/RangeTokenReader.kt @@ -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 diff --git a/backend/mirai-console/src/internal/util/semver/RequirementInternal.kt b/backend/mirai-console/src/internal/util/semver/RequirementInternal.kt new file mode 100644 index 000000000..903f19eea --- /dev/null +++ b/backend/mirai-console/src/internal/util/semver/RequirementInternal.kt @@ -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 +} diff --git a/backend/mirai-console/src/internal/util/semver/SemVersionInternal.kt b/backend/mirai-console/src/internal/util/semver/SemVersionInternal.kt index 1c5e013af..1d9c1af03 100644 --- a/backend/mirai-console/src/internal/util/semver/SemVersionInternal.kt +++ b/backend/mirai-console/src/internal/util/semver/SemVersionInternal.kt @@ -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) } diff --git a/backend/mirai-console/src/util/SemVersion.kt b/backend/mirai-console/src/util/SemVersion.kt index 47c207fa8..f350c0f58 100644 --- a/backend/mirai-console/src/util/SemVersion.kt +++ b/backend/mirai-console/src/util/SemVersion.kt @@ -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 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 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 diff --git a/backend/mirai-console/test/util/TestSemVersion.kt b/backend/mirai-console/test/util/TestSemVersion.kt index 60881b310..3021de67b 100644 --- a/backend/mirai-console/test/util/TestSemVersion.kt +++ b/backend/mirai-console/test/util/TestSemVersion.kt @@ -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 {