feat: tagの削除とwildcard伝播
This commit is contained in:
parent
58ad0e67c9
commit
a6e951b48c
10
README.md
10
README.md
|
|
@ -109,8 +109,8 @@ stage edits procedurally before ever touching `MutationSession`.
|
||||||
### Concepts
|
### Concepts
|
||||||
|
|
||||||
- **Permission tree** – immutable graph of `PermissionNode`s. Nodes specify description, default value,
|
- **Permission tree** – immutable graph of `PermissionNode`s. Nodes specify description, default value,
|
||||||
boolean children map, optional tags, and the `wildcard` flag (disabled by default) that, when enabled,
|
boolean children map, and the `wildcard` flag (enabled by default) that keeps `namespace.path.*`
|
||||||
makes the library create/update `namespace.path.*` aggregate permissions automatically.
|
aggregate permissions in sync automatically.
|
||||||
- **DSL** – `permissionTree("namespace") { ... }` ensures consistent prefixes and validation (no cycles). Every `node("command", NodeRegistration.PERMISSION)` (or `.STRUCTURAL`) is relative to that namespace, so you never include the namespace manually at the root.
|
- **DSL** – `permissionTree("namespace") { ... }` ensures consistent prefixes and validation (no cycles). Every `node("command", NodeRegistration.PERMISSION)` (or `.STRUCTURAL`) is relative to that namespace, so you never include the namespace manually at the root.
|
||||||
- **Nested nodes** – `node("command", NodeRegistration.STRUCTURAL) { node("reload", NodeRegistration.PERMISSION) { ... } }` automatically produces
|
- **Nested nodes** – `node("command", NodeRegistration.STRUCTURAL) { node("reload", NodeRegistration.PERMISSION) { ... } }` automatically produces
|
||||||
`namespace.command` and `namespace.command.reload` plus wires the parent/child relationship so you don't
|
`namespace.command` and `namespace.command.reload` plus wires the parent/child relationship so you don't
|
||||||
|
|
@ -125,9 +125,9 @@ stage edits procedurally before ever touching `MutationSession`.
|
||||||
other namespaces.
|
other namespaces.
|
||||||
- **PermissionRegistry** – calculates a diff between snapshots and performs the minimum additions,
|
- **PermissionRegistry** – calculates a diff between snapshots and performs the minimum additions,
|
||||||
removals, or updates via Bukkit's `PluginManager`.
|
removals, or updates via Bukkit's `PluginManager`.
|
||||||
- **Wildcards** – opt-in via `wildcard = true` to have the generated `namespace.command.*` child kept in sync,
|
- **Wildcards** – enabled by default; the generated `namespace.command.*` child stays in sync so granting
|
||||||
so granting `example.command.*` automatically grants every nested node you marked; leave it `false` (default)
|
`example.command.*` automatically grants every nested node plus wildcard descendants such as
|
||||||
to keep nodes out of the wildcard.
|
`example.command.debug.*`. Set `wildcard = false` on specific nodes to opt them out.
|
||||||
- **Mutable edits** – `permits.edit { ... }` clones the currently registered tree, lets you mutate nodes
|
- **Mutable edits** – `permits.edit { ... }` clones the currently registered tree, lets you mutate nodes
|
||||||
imperatively, re-validates, and only pushes the structural diff to Bukkit.
|
imperatively, re-validates, and only pushes the structural diff to Bukkit.
|
||||||
- **AttachmentSynchronizer** – manages identity-based `PermissionAttachment`s and exposes high-level
|
- **AttachmentSynchronizer** – manages identity-based `PermissionAttachment`s and exposes high-level
|
||||||
|
|
|
||||||
|
|
@ -70,15 +70,6 @@ class MutablePermissionTree internal constructor(
|
||||||
draft.registration = value
|
draft.registration = value
|
||||||
}
|
}
|
||||||
|
|
||||||
val tags: MutableSet<String>
|
|
||||||
get() = draft.tags
|
|
||||||
|
|
||||||
fun tag(value: String) {
|
|
||||||
if (value.isNotBlank()) {
|
|
||||||
draft.tags += value.trim()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun child(id: String, value: Boolean = true) {
|
fun child(id: String, value: Boolean = true) {
|
||||||
require(id.isNotBlank()) { "Child id must not be blank." }
|
require(id.isNotBlank()) { "Child id must not be blank." }
|
||||||
val permissionId = PermissionId.of("${this.id.value}.${id.lowercase()}")
|
val permissionId = PermissionId.of("${this.id.value}.${id.lowercase()}")
|
||||||
|
|
@ -158,7 +149,6 @@ class MutablePermissionTree internal constructor(
|
||||||
description = draft.description,
|
description = draft.description,
|
||||||
defaultValue = draft.defaultValue,
|
defaultValue = draft.defaultValue,
|
||||||
children = draft.children.toMutableMap(),
|
children = draft.children.toMutableMap(),
|
||||||
tags = draft.tags.toMutableSet(),
|
|
||||||
wildcard = draft.wildcard,
|
wildcard = draft.wildcard,
|
||||||
registration = draft.registration
|
registration = draft.registration
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -13,8 +13,7 @@ data class PermissionNode(
|
||||||
val description: String? = null,
|
val description: String? = null,
|
||||||
val defaultValue: PermissionDefault = PermissionDefault.FALSE,
|
val defaultValue: PermissionDefault = PermissionDefault.FALSE,
|
||||||
val children: Map<PermissionId, Boolean> = emptyMap(),
|
val children: Map<PermissionId, Boolean> = emptyMap(),
|
||||||
val tags: Set<String> = emptySet(),
|
val wildcard: Boolean = true,
|
||||||
val wildcard: Boolean = false,
|
|
||||||
val registration: NodeRegistration = NodeRegistration.PERMISSION
|
val registration: NodeRegistration = NodeRegistration.PERMISSION
|
||||||
) {
|
) {
|
||||||
init {
|
init {
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,7 @@ internal data class PermissionNodeDraft(
|
||||||
var description: String? = null,
|
var description: String? = null,
|
||||||
var defaultValue: PermissionDefault = PermissionDefault.FALSE,
|
var defaultValue: PermissionDefault = PermissionDefault.FALSE,
|
||||||
val children: MutableMap<PermissionId, Boolean> = linkedMapOf(),
|
val children: MutableMap<PermissionId, Boolean> = linkedMapOf(),
|
||||||
val tags: MutableSet<String> = linkedSetOf(),
|
var wildcard: Boolean = true,
|
||||||
var wildcard: Boolean = false,
|
|
||||||
var registration: NodeRegistration = NodeRegistration.PERMISSION
|
var registration: NodeRegistration = NodeRegistration.PERMISSION
|
||||||
) {
|
) {
|
||||||
fun toNode(): PermissionNode =
|
fun toNode(): PermissionNode =
|
||||||
|
|
@ -17,7 +16,6 @@ internal data class PermissionNodeDraft(
|
||||||
description = description,
|
description = description,
|
||||||
defaultValue = defaultValue,
|
defaultValue = defaultValue,
|
||||||
children = children.toMap(),
|
children = children.toMap(),
|
||||||
tags = tags.toSet(),
|
|
||||||
wildcard = wildcard,
|
wildcard = wildcard,
|
||||||
registration = registration
|
registration = registration
|
||||||
)
|
)
|
||||||
|
|
@ -29,7 +27,6 @@ internal data class PermissionNodeDraft(
|
||||||
description = node.description,
|
description = node.description,
|
||||||
defaultValue = node.defaultValue,
|
defaultValue = node.defaultValue,
|
||||||
children = node.children.toMutableMap(),
|
children = node.children.toMutableMap(),
|
||||||
tags = node.tags.toMutableSet(),
|
|
||||||
wildcard = node.wildcard,
|
wildcard = node.wildcard,
|
||||||
registration = node.registration
|
registration = node.registration
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -25,9 +25,6 @@ class TreeSnapshot internal constructor(
|
||||||
digest.update(childId.value.toByteArray())
|
digest.update(childId.value.toByteArray())
|
||||||
digest.update(if (flag) 1 else 0)
|
digest.update(if (flag) 1 else 0)
|
||||||
}
|
}
|
||||||
node.tags.sorted().forEach { tag ->
|
|
||||||
digest.update(tag.toByteArray())
|
|
||||||
}
|
|
||||||
digest.update(if (node.wildcard) 1 else 0)
|
digest.update(if (node.wildcard) 1 else 0)
|
||||||
digest.update(node.registration.name.toByteArray())
|
digest.update(node.registration.name.toByteArray())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@ internal object WildcardAugmentor {
|
||||||
|
|
||||||
nodes.values.forEach { node ->
|
nodes.values.forEach { node ->
|
||||||
if (!node.wildcard) return@forEach
|
if (!node.wildcard) return@forEach
|
||||||
if (node.id.value.endsWith(".*")) return@forEach
|
|
||||||
|
|
||||||
val wildcardId = parentWildcardId(node.id) ?: return@forEach
|
val wildcardId = parentWildcardId(node.id) ?: return@forEach
|
||||||
val existing = result[wildcardId]
|
val existing = result[wildcardId]
|
||||||
|
|
@ -25,7 +24,6 @@ internal object WildcardAugmentor {
|
||||||
description = "Wildcard for ${wildcardId.value}",
|
description = "Wildcard for ${wildcardId.value}",
|
||||||
defaultValue = node.defaultValue,
|
defaultValue = node.defaultValue,
|
||||||
children = updatedChildren,
|
children = updatedChildren,
|
||||||
tags = setOf("wildcard"),
|
|
||||||
wildcard = false
|
wildcard = false
|
||||||
)
|
)
|
||||||
} else if (!alreadyPresent) {
|
} else if (!alreadyPresent) {
|
||||||
|
|
@ -33,6 +31,21 @@ internal object WildcardAugmentor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ensure wildcard permissions include descendant wildcard nodes so granting parent.* cascades.
|
||||||
|
val wildcardEntries = result
|
||||||
|
.filterKeys { it.value.endsWith(".*") }
|
||||||
|
.entries
|
||||||
|
.sortedBy { it.key.value.length } // parents before grandparents not necessary but deterministic
|
||||||
|
|
||||||
|
wildcardEntries.forEach { (childWildcardId, _) ->
|
||||||
|
val parentWildcardId = parentWildcardId(childWildcardId) ?: return@forEach
|
||||||
|
val parent = result[parentWildcardId] ?: return@forEach
|
||||||
|
val updatedChildren = parent.children.toMutableMap()
|
||||||
|
if (updatedChildren[childWildcardId] == true) return@forEach
|
||||||
|
updatedChildren[childWildcardId] = true
|
||||||
|
result[parentWildcardId] = parent.copy(children = updatedChildren)
|
||||||
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,12 +34,6 @@ class PermissionNodeBuilder internal constructor(
|
||||||
draft.registration = value
|
draft.registration = value
|
||||||
}
|
}
|
||||||
|
|
||||||
fun tag(value: String) {
|
|
||||||
if (value.isNotBlank()) {
|
|
||||||
draft.tags += value.trim()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun child(id: String, value: Boolean = true) {
|
fun child(id: String, value: Boolean = true) {
|
||||||
treeBuilder.childRelative(draft, id, value)
|
treeBuilder.childRelative(draft, id, value)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user