mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-10 18:40:15 +08:00
Support ILLEGAL_COMMAND_NAME, ILLEGAL_PERMISSION_NAME, ILLEGAL_PERMISSION_ID, ILLEGAL_PERMISSION_NAMESPACE
This commit is contained in:
parent
78ebdf038d
commit
3fa7c9e128
@ -104,6 +104,7 @@ public interface Command {
|
||||
/**
|
||||
* 检查指令名的合法性. 在非法时抛出 [IllegalArgumentException]
|
||||
*/
|
||||
@JvmStatic
|
||||
@Throws(IllegalArgumentException::class)
|
||||
public fun checkCommandName(@ResolveContext(COMMAND_NAME) name: String) {
|
||||
when {
|
||||
|
@ -32,6 +32,10 @@ public annotation class ResolveContext(
|
||||
* 元素数量可能在任意时间被改动
|
||||
*/
|
||||
public enum class Kind {
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// ConstantKind
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
PLUGIN_ID,
|
||||
PLUGIN_NAME,
|
||||
PLUGIN_VERSION,
|
||||
@ -40,10 +44,11 @@ public annotation class ResolveContext(
|
||||
|
||||
PERMISSION_NAMESPACE,
|
||||
PERMISSION_NAME,
|
||||
PERMISSION_ID, // for parseFromString
|
||||
|
||||
/**
|
||||
* Custom serializers allowed
|
||||
*/
|
||||
RESTRICTED_NO_ARG_CONSTRUCTOR
|
||||
RESTRICTED_NO_ARG_CONSTRUCTOR,
|
||||
}
|
||||
}
|
@ -13,8 +13,7 @@ import kotlinx.serialization.KSerializer
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.builtins.serializer
|
||||
import net.mamoe.mirai.console.compiler.common.ResolveContext
|
||||
import net.mamoe.mirai.console.compiler.common.ResolveContext.Kind.PERMISSION_NAME
|
||||
import net.mamoe.mirai.console.compiler.common.ResolveContext.Kind.PERMISSION_NAMESPACE
|
||||
import net.mamoe.mirai.console.compiler.common.ResolveContext.Kind.*
|
||||
import net.mamoe.mirai.console.internal.data.map
|
||||
|
||||
|
||||
@ -57,13 +56,39 @@ public data class PermissionId(
|
||||
* @throws IllegalArgumentException 在解析失败时抛出.
|
||||
*/
|
||||
@JvmStatic
|
||||
public fun parseFromString(string: String): PermissionId {
|
||||
public fun parseFromString(@ResolveContext(PERMISSION_ID) string: String): PermissionId {
|
||||
return kotlin.runCatching {
|
||||
string.split(':').let { (namespace, id) -> PermissionId(namespace, id) }
|
||||
}.getOrElse {
|
||||
throw IllegalArgumentException("Could not parse PermissionId from '$string'", it)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查 [PermissionId.name] 的合法性. 在非法时抛出 [IllegalArgumentException]
|
||||
*/
|
||||
@JvmStatic
|
||||
@Throws(IllegalArgumentException::class)
|
||||
public fun checkPermissionIdName(@ResolveContext(PERMISSION_NAME) value: String) {
|
||||
when {
|
||||
value.isBlank() -> throw IllegalArgumentException("PermissionId.name should not be blank.")
|
||||
value.any { it.isWhitespace() } -> throw IllegalArgumentException("Spaces is not yet allowed in PermissionId.name.")
|
||||
value.contains(':') -> throw IllegalArgumentException("':' is forbidden in PermissionId.name.")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查 [PermissionId.namespace] 的合法性. 在非法时抛出 [IllegalArgumentException]
|
||||
*/
|
||||
@JvmStatic
|
||||
@Throws(IllegalArgumentException::class)
|
||||
public fun checkPermissionIdNamespace(@ResolveContext(PERMISSION_NAME) value: String) {
|
||||
when {
|
||||
value.isBlank() -> throw IllegalArgumentException("PermissionId.namespace should not be blank.")
|
||||
value.any { it.isWhitespace() } -> throw IllegalArgumentException("Spaces is not yet allowed in PermissionId.namespace.")
|
||||
value.contains(':') -> throw IllegalArgumentException("':' is forbidden in PermissionId.namespace.")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -11,6 +11,7 @@ package net.mamoe.mirai.console.compiler.common.diagnostics;
|
||||
|
||||
import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory1;
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory2;
|
||||
import org.jetbrains.kotlin.diagnostics.Errors;
|
||||
|
||||
import static org.jetbrains.kotlin.diagnostics.Severity.ERROR;
|
||||
@ -19,6 +20,10 @@ public interface MiraiConsoleErrors {
|
||||
DiagnosticFactory1<PsiElement, String> ILLEGAL_PLUGIN_DESCRIPTION = DiagnosticFactory1.create(ERROR);
|
||||
DiagnosticFactory1<PsiElement, String> NOT_CONSTRUCTABLE_TYPE = DiagnosticFactory1.create(ERROR);
|
||||
DiagnosticFactory1<PsiElement, String> UNSERIALIZABLE_TYPE = DiagnosticFactory1.create(ERROR);
|
||||
DiagnosticFactory2<PsiElement, String, String> ILLEGAL_COMMAND_NAME = DiagnosticFactory2.create(ERROR);
|
||||
DiagnosticFactory2<PsiElement, String, String> ILLEGAL_PERMISSION_NAME = DiagnosticFactory2.create(ERROR);
|
||||
DiagnosticFactory2<PsiElement, String, String> ILLEGAL_PERMISSION_ID = DiagnosticFactory2.create(ERROR);
|
||||
DiagnosticFactory2<PsiElement, String, String> ILLEGAL_PERMISSION_NAMESPACE = DiagnosticFactory2.create(ERROR);
|
||||
|
||||
@Deprecated
|
||||
Object _init = new Object() {
|
||||
|
@ -19,19 +19,47 @@ object MiraiConsoleErrorsRendering : DefaultErrorMessages.Extension {
|
||||
put(
|
||||
ILLEGAL_PLUGIN_DESCRIPTION,
|
||||
"{0}",
|
||||
Renderers.STRING
|
||||
Renderers.STRING,
|
||||
)
|
||||
|
||||
put(
|
||||
NOT_CONSTRUCTABLE_TYPE,
|
||||
"类型 {0} 无法通过反射直接构造, 需要提供默认值.",
|
||||
Renderers.STRING
|
||||
"类型 ''{0}'' 无法通过反射直接构造, 需要提供默认值.",
|
||||
Renderers.STRING,
|
||||
)
|
||||
|
||||
put(
|
||||
UNSERIALIZABLE_TYPE,
|
||||
"类型 {0} 无法被自动序列化, 需要添加序列化器",
|
||||
Renderers.STRING
|
||||
"类型 ''{0}'' 无法被自动序列化, 需要添加序列化器",
|
||||
Renderers.STRING,
|
||||
)
|
||||
|
||||
put(
|
||||
ILLEGAL_COMMAND_NAME,
|
||||
"指令名 ''{0}'' 无效: {1}",
|
||||
Renderers.STRING,
|
||||
Renderers.STRING,
|
||||
)
|
||||
|
||||
put(
|
||||
ILLEGAL_PERMISSION_NAME,
|
||||
"权限名 ''{0}'' 无效: {1}",
|
||||
Renderers.STRING,
|
||||
Renderers.STRING,
|
||||
)
|
||||
|
||||
put(
|
||||
ILLEGAL_PERMISSION_ID,
|
||||
"权限 Id ''{0}'' 无效: {1}",
|
||||
Renderers.STRING,
|
||||
Renderers.STRING,
|
||||
)
|
||||
|
||||
put(
|
||||
ILLEGAL_PERMISSION_NAMESPACE,
|
||||
"权限命名空间 ''{0}'' 无效: {1}",
|
||||
Renderers.STRING,
|
||||
Renderers.STRING,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -50,11 +50,17 @@ enum class ResolveContextKind {
|
||||
PLUGIN_NAME,
|
||||
PLUGIN_VERSION,
|
||||
|
||||
COMMAND_NAME,
|
||||
|
||||
PERMISSION_NAMESPACE,
|
||||
PERMISSION_NAME,
|
||||
PERMISSION_ID,
|
||||
|
||||
RESTRICTED_NO_ARG_CONSTRUCTOR
|
||||
;
|
||||
|
||||
companion object {
|
||||
fun valueOfOrNull(string: String): ResolveContextKind? = ResolveContextKind.values().find { it.name == string }
|
||||
fun valueOfOrNull(string: String): ResolveContextKind? = values().find { it.name == string }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -22,7 +22,7 @@ dependencies {
|
||||
compileOnly(kotlin("stdlib-jdk8"))
|
||||
|
||||
val core = "1.3.0"
|
||||
val console = "1.0-RC-dev-3"
|
||||
val console = "1.0-RC-dev-4"
|
||||
|
||||
compileOnly("net.mamoe:mirai-console:$console")
|
||||
compileOnly("net.mamoe:mirai-core:$core")
|
||||
|
@ -3,6 +3,8 @@ package org.example.myplugin
|
||||
import kotlinx.serialization.Serializable
|
||||
import net.mamoe.mirai.console.data.AutoSavePluginConfig
|
||||
import net.mamoe.mirai.console.data.value
|
||||
import net.mamoe.mirai.console.permission.PermissionId
|
||||
import net.mamoe.mirai.console.permission.PermissionService
|
||||
import net.mamoe.mirai.console.plugin.jvm.JvmPluginDescription
|
||||
import net.mamoe.mirai.console.plugin.jvm.KotlinPlugin
|
||||
|
||||
@ -17,6 +19,11 @@ object MyPluginMain : KotlinPlugin(
|
||||
id("")
|
||||
}
|
||||
) {
|
||||
override fun onEnable() {
|
||||
super.onEnable()
|
||||
PermissionService.INSTANCE.register(permissionId("dvs"), "ok")
|
||||
}
|
||||
|
||||
fun test() {
|
||||
|
||||
}
|
||||
|
@ -10,7 +10,7 @@
|
||||
package net.mamoe.mirai.console.intellij.diagnostics
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import net.mamoe.mirai.console.compiler.common.diagnostics.MiraiConsoleErrors
|
||||
import net.mamoe.mirai.console.compiler.common.diagnostics.MiraiConsoleErrors.*
|
||||
import net.mamoe.mirai.console.compiler.common.resolve.ResolveContextKind
|
||||
import net.mamoe.mirai.console.compiler.common.resolve.resolveContextKind
|
||||
import net.mamoe.mirai.console.intellij.resolve.resolveAllCalls
|
||||
@ -31,7 +31,7 @@ class ContextualParametersChecker : DeclarationChecker {
|
||||
private val ID_REGEX: Regex = Regex("""([a-zA-Z]+(?:\.[a-zA-Z0-9]+)*)\.([a-zA-Z]+(?:-[a-zA-Z0-9]+)*)""")
|
||||
private val FORBIDDEN_ID_NAMES: Array<String> = arrayOf("main", "console", "plugin", "config", "data")
|
||||
|
||||
private const val syntax = """类似于 "net.mamoe.mirai.example-plugin", 其中 "net.mamoe.mirai" 为 groupId, "example-plugin" 为插件名. """
|
||||
private const val syntax = """类似于 "net.mamoe.mirai.example-plugin", 其中 "net.mamoe.mirai" 为 groupId, "example-plugin" 为插件名"""
|
||||
|
||||
/**
|
||||
* https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string
|
||||
@ -40,37 +40,74 @@ class ContextualParametersChecker : DeclarationChecker {
|
||||
Regex("""^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?${'$'}""")
|
||||
|
||||
fun checkPluginId(inspectionTarget: PsiElement, value: String): Diagnostic? {
|
||||
if (value.isBlank()) return MiraiConsoleErrors.ILLEGAL_PLUGIN_DESCRIPTION.on(inspectionTarget, "插件 Id 不能为空. \n插件 Id$syntax")
|
||||
if (value.none { it == '.' }) return MiraiConsoleErrors.ILLEGAL_PLUGIN_DESCRIPTION.on(inspectionTarget,
|
||||
if (value.isBlank()) return ILLEGAL_PLUGIN_DESCRIPTION.on(inspectionTarget, "插件 Id 不能为空. \n插件 Id$syntax")
|
||||
if (value.none { it == '.' }) return ILLEGAL_PLUGIN_DESCRIPTION.on(inspectionTarget,
|
||||
"插件 Id '$value' 无效. 插件 Id 必须同时包含 groupId 和插件名称. $syntax")
|
||||
|
||||
val lowercaseId = value.toLowerCase()
|
||||
|
||||
if (ID_REGEX.matchEntire(value) == null) {
|
||||
return MiraiConsoleErrors.ILLEGAL_PLUGIN_DESCRIPTION.on(inspectionTarget, "插件 Id 无效. 正确的插件 Id 应该满足正则表达式 '${ID_REGEX.pattern}', \n$syntax")
|
||||
return ILLEGAL_PLUGIN_DESCRIPTION.on(inspectionTarget, "插件 Id 无效. 正确的插件 Id 应该满足正则表达式 '${ID_REGEX.pattern}', \n$syntax")
|
||||
}
|
||||
|
||||
FORBIDDEN_ID_NAMES.firstOrNull { it == lowercaseId }?.let { illegal ->
|
||||
return MiraiConsoleErrors.ILLEGAL_PLUGIN_DESCRIPTION.on(inspectionTarget, "'$illegal' 不允许作为插件 Id. 确保插件 Id 不完全是这个名称.")
|
||||
return ILLEGAL_PLUGIN_DESCRIPTION.on(inspectionTarget, "'$illegal' 不允许作为插件 Id. 确保插件 Id 不完全是这个名称")
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
fun checkPluginName(inspectionTarget: PsiElement, value: String): Diagnostic? {
|
||||
if (value.isBlank()) return MiraiConsoleErrors.ILLEGAL_PLUGIN_DESCRIPTION.on(inspectionTarget, "插件名不能为空.")
|
||||
if (value.isBlank()) return ILLEGAL_PLUGIN_DESCRIPTION.on(inspectionTarget, "插件名不能为空")
|
||||
val lowercaseName = value.toLowerCase()
|
||||
FORBIDDEN_ID_NAMES.firstOrNull { it == lowercaseName }?.let { illegal ->
|
||||
return MiraiConsoleErrors.ILLEGAL_PLUGIN_DESCRIPTION.on(inspectionTarget, "'$illegal' 不允许作为插件名. 确保插件名不完全是这个名称.")
|
||||
return ILLEGAL_PLUGIN_DESCRIPTION.on(inspectionTarget, "'$illegal' 不允许作为插件名. 确保插件名不完全是这个名称")
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
fun checkPluginVersion(inspectionTarget: PsiElement, value: String): Diagnostic? {
|
||||
if (!SEMANTIC_VERSIONING_REGEX.matches(value)) {
|
||||
return MiraiConsoleErrors.ILLEGAL_PLUGIN_DESCRIPTION.on(inspectionTarget, "版本号无效: '$value'. \nhttps://semver.org/lang/zh-CN/")
|
||||
return ILLEGAL_PLUGIN_DESCRIPTION.on(inspectionTarget, "版本号无效: '$value'. \nhttps://semver.org/lang/zh-CN/")
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
fun checkCommandName(inspectionTarget: PsiElement, value: String): Diagnostic? {
|
||||
return when {
|
||||
value.isBlank() -> ILLEGAL_COMMAND_NAME.on(inspectionTarget, value, "指令名不能为空")
|
||||
value.any { it.isWhitespace() } -> ILLEGAL_COMMAND_NAME.on(inspectionTarget, value, "暂时不允许指令名中存在空格")
|
||||
value.contains(':') -> ILLEGAL_COMMAND_NAME.on(inspectionTarget, value, "指令名不允许包含 ':'")
|
||||
value.contains('.') -> ILLEGAL_COMMAND_NAME.on(inspectionTarget, value, "指令名不允许包含 '.'")
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
fun checkPermissionNamespace(inspectionTarget: PsiElement, value: String): Diagnostic? {
|
||||
return when {
|
||||
value.isBlank() -> ILLEGAL_PERMISSION_NAMESPACE.on(inspectionTarget, value, "权限命名空间不能为空")
|
||||
value.any { it.isWhitespace() } -> ILLEGAL_PERMISSION_NAMESPACE.on(inspectionTarget, value, "暂时不允许权限命名空间中存在空格")
|
||||
value.contains(':') -> ILLEGAL_PERMISSION_NAMESPACE.on(inspectionTarget, value, "权限命名空间不允许包含 ':'")
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
fun checkPermissionName(inspectionTarget: PsiElement, value: String): Diagnostic? {
|
||||
return when {
|
||||
value.isBlank() -> ILLEGAL_PERMISSION_NAME.on(inspectionTarget, value, "权限名称不能为空")
|
||||
value.any { it.isWhitespace() } -> ILLEGAL_PERMISSION_NAME.on(inspectionTarget, value, "暂时不允许权限名称中存在空格")
|
||||
value.contains(':') -> ILLEGAL_PERMISSION_NAME.on(inspectionTarget, value, "权限名称不允许包含 ':'")
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
fun checkPermissionId(inspectionTarget: PsiElement, value: String): Diagnostic? {
|
||||
return when {
|
||||
value.isBlank() -> ILLEGAL_PERMISSION_ID.on(inspectionTarget, value, "权限 Id 不能为空")
|
||||
value.any { it.isWhitespace() } -> ILLEGAL_PERMISSION_ID.on(inspectionTarget, value, "暂时不允许权限 Id 中存在空格")
|
||||
value.count { it == ':' } != 1 -> ILLEGAL_PERMISSION_ID.on(inspectionTarget, value, "权限 Id 必须为 \"命名空间:名称\". 且命名空间和名称均不能包含 ':'")
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val checkersMap: EnumMap<ResolveContextKind, (declaration: PsiElement, value: String) -> Diagnostic?> =
|
||||
@ -78,6 +115,10 @@ class ContextualParametersChecker : DeclarationChecker {
|
||||
put(ResolveContextKind.PLUGIN_NAME, ::checkPluginName)
|
||||
put(ResolveContextKind.PLUGIN_ID, ::checkPluginId)
|
||||
put(ResolveContextKind.PLUGIN_VERSION, ::checkPluginVersion)
|
||||
put(ResolveContextKind.COMMAND_NAME, ::checkCommandName)
|
||||
put(ResolveContextKind.PERMISSION_NAME, ::checkPermissionName)
|
||||
put(ResolveContextKind.PERMISSION_NAMESPACE, ::checkPermissionNamespace)
|
||||
put(ResolveContextKind.PERMISSION_ID, ::checkPermissionId)
|
||||
}
|
||||
|
||||
override fun check(
|
||||
|
Loading…
Reference in New Issue
Block a user