-
-
Notifications
You must be signed in to change notification settings - Fork 147
feat(key): Add KeyFormat to improve custom Key creation #1227
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
Emilxyz
wants to merge
1
commit into
PaperMC:main/4
Choose a base branch
from
Emilxyz:feat/key-format
base: main/4
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
285 changes: 285 additions & 0 deletions
285
key/src/main/java/net/kyori/adventure/key/KeyFormat.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,285 @@ | ||
| /* | ||
| * This file is part of adventure, licensed under the MIT License. | ||
| * | ||
| * Copyright (c) 2017-2025 KyoriPowered | ||
| * | ||
| * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| * of this software and associated documentation files (the "Software"), to deal | ||
| * in the Software without restriction, including without limitation the rights | ||
| * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| * copies of the Software, and to permit persons to whom the Software is | ||
| * furnished to do so, subject to the following conditions: | ||
| * | ||
| * The above copyright notice and this permission notice shall be included in all | ||
| * copies or substantial portions of the Software. | ||
| * | ||
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
| * SOFTWARE. | ||
| */ | ||
| package net.kyori.adventure.key; | ||
|
|
||
| import java.util.stream.Stream; | ||
| import net.kyori.examination.Examinable; | ||
| import net.kyori.examination.ExaminableProperty; | ||
| import org.jetbrains.annotations.Contract; | ||
| import org.jetbrains.annotations.NotNull; | ||
| import org.jetbrains.annotations.Nullable; | ||
|
|
||
| import static java.util.Objects.requireNonNull; | ||
|
|
||
| /** | ||
| * A factory to create {@link Key}s using configured defaults. | ||
| * | ||
| * <p>The configuration options include:</p> | ||
| * <dl> | ||
| * <dt>namespace</dt> | ||
| * <dd>The namespace to be used as fallback, when no other namespace is specified</dd> | ||
| * <dt>separator</dt> | ||
| * <dd>The character separating namespace and value</dd> | ||
| * </dl> | ||
| * | ||
| * <p>Example usage of this class:</p> | ||
| * <pre>{@code | ||
| * KeyFormat format = keyFormat("adventure", ':'); | ||
| * Key key = format.key("translations"); | ||
| * format.asString(key); // -> "adventure:translations" | ||
| * }</pre> | ||
| * | ||
| * @see Key#key(String) | ||
| * @since 4.24.0 | ||
| */ | ||
| public interface KeyFormat extends Namespaced, Examinable { | ||
| /** | ||
| * Gets the default minecraft key format instance. | ||
| * | ||
| * <p>This uses {@link Key#MINECRAFT_NAMESPACE} and {@link Key#DEFAULT_SEPARATOR}.</p> | ||
| * | ||
| * @return the instance | ||
| * @since 4.24.0 | ||
| */ | ||
| static @NotNull KeyFormat minecraft() { | ||
| return KeyFormatImpl.MINECRAFT_INSTANCE; | ||
| } | ||
|
|
||
| /** | ||
| * Creates a key format with a fallback {@code namespace} from a {@link Namespaced} instance. | ||
| * | ||
| * @param namespaced the namespaced instance to get the namespace from | ||
| * @return the key format | ||
| * @throws IllegalArgumentException if the namespace contains an invalid character | ||
| * @see #namespace(String) | ||
| * @since 4.24.0 | ||
| */ | ||
| static KeyFormat namespace(final @NotNull Namespaced namespaced) { | ||
| return namespace(requireNonNull(namespaced, "namespaced").namespace()); | ||
| } | ||
|
|
||
| /** | ||
| * Creates a key format with a fallback {@code namespace} and the {@link Key#DEFAULT_SEPARATOR}. | ||
| * | ||
| * @param namespace the namespace to be used as fallback in {@link #parse(String)} | ||
| * @return the key format | ||
| * @throws IllegalArgumentException if the namespace contains an invalid character | ||
| * @since 4.24.0 | ||
| */ | ||
| static KeyFormat namespace(@KeyPattern.Namespace final @NotNull String namespace) { | ||
| return keyFormat(namespace, Key.DEFAULT_SEPARATOR); | ||
| } | ||
|
|
||
| /** | ||
| * Creates a key format. | ||
| * | ||
| * @param namespaced the namespaced instance to get the namespace from | ||
| * @param separator the separator to bse used when parsing keys | ||
| * @return the key format | ||
| * @throws IllegalArgumentException if the namespace contains an invalid character | ||
| * @see #keyFormat(String, char) | ||
| * @since 4.24.0 | ||
| */ | ||
| static KeyFormat keyFormat(final @NotNull Namespaced namespaced, final char separator) { | ||
| return keyFormat(requireNonNull(namespaced, "namespaced").namespace(), separator); | ||
| } | ||
|
|
||
| /** | ||
| * Creates a key format. | ||
| * | ||
| * @param namespace the namespace to be used as fallback in {@link #parse(String)} | ||
| * @param separator the separator to be used when parsing keys using {@link #parse(String)} | ||
| * @return the key format | ||
| * @throws IllegalArgumentException if the namespace contains an invalid character | ||
| * @since 4.24.0 | ||
| */ | ||
| static KeyFormat keyFormat(@KeyPattern.Namespace final @NotNull String namespace, final char separator) { | ||
| return keyFormat() | ||
| .namespace(namespace) | ||
| .separator(separator) | ||
| .build(); | ||
| } | ||
|
|
||
| /** | ||
| * Creates a key format builder. | ||
| * | ||
| * @return the builder | ||
| * @since 4.24.0 | ||
| */ | ||
| static KeyFormat.@NotNull Builder keyFormat() { | ||
| return new KeyFormatImpl.BuilderImpl(); | ||
| } | ||
|
|
||
| /** | ||
| * Gets the separator of this key format. | ||
| * | ||
| * @return the separator | ||
| * @since 4.24.0 | ||
| */ | ||
| char separator(); | ||
|
|
||
| /** | ||
| * Gets the fallback namespace of this key format. | ||
| * | ||
| * @return the namespace | ||
| * @since 4.24.0 | ||
| */ | ||
| @KeyPattern.Namespace | ||
| @Override | ||
| @NotNull String namespace(); | ||
|
|
||
| /** | ||
| * Creates a key from this format. | ||
| * | ||
| * <p>This will create a key with {@link #namespace()} and {@code value}.</p> | ||
| * | ||
| * @param value the value of the key | ||
| * @return the key | ||
| * @throws InvalidKeyException if the namespace or value contains an invalid character | ||
| * @since 4.24.0 | ||
| */ | ||
| default @NotNull Key key(@KeyPattern.Value final @NotNull String value) { | ||
| return Key.key(this.namespace(), value); | ||
| } | ||
|
|
||
| /** | ||
| * Creates a key from this format. | ||
| * | ||
| * <p>This will parse {@code string} as a key, using {@link #separator()} as a separator between namespace and value.</p> | ||
| * | ||
| * <p>The namespace is optional. If you do not provide one (for example, if you provide just {@code player} or {@code separator + "player"} | ||
| * as the string) then {@link #namespace()} will be used as a namespace and {@code string} will be used as the value, | ||
| * removing the separator if necessary.</p> | ||
| * | ||
| * @param string the string | ||
| * @return the key | ||
| * @throws InvalidKeyException if the namespace or value contains an invalid character | ||
| * @since 4.24.0 | ||
| */ | ||
| default @NotNull Key parse(final @NotNull String string) { | ||
| return Key.key(string, this.separator(), this.namespace()); | ||
| } | ||
|
|
||
| /** | ||
| * Checks if {@code string} can be parsed into a {@link Key} using this formats {@link #separator()}. | ||
| * If no namespace is specified in {@code string}, the fallback namespace {@link #namespace()} is used. | ||
| * | ||
| * @param string the string | ||
| * @return {@code true} if {@code string} can be parsed into a key using this format, {@code false} otherwise | ||
| * @since 4.24.0 | ||
| */ | ||
| boolean parseable(final @Nullable String string); | ||
|
|
||
| /** | ||
| * Turns a {@link Key} into its string representation using the configuration of this format. | ||
| * | ||
| * @param key the key | ||
| * @return the string representation of the key | ||
| * @since 4.24.0 | ||
| */ | ||
| default @NotNull String asString(final @NotNull Key key) { | ||
| return key.namespace() + this.separator() + key.value(); | ||
| } | ||
|
|
||
| /** | ||
| * Turns a {@link Key} into its string representation in minimal form using the configuration of this format. | ||
| * | ||
| * <p>If the {@link Key#namespace()} of the key is {@link #namespace()}, only the {@link Key#value()} will be returned.</p> | ||
| * | ||
| * @param key the key | ||
| * @return the minimal string representation of the key | ||
| * @since 4.24.0 | ||
| */ | ||
| default @NotNull String asMinimalString(final @NotNull Key key) { | ||
Machine-Maker marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| if (key.namespace().equals(this.namespace())) | ||
| return key.value(); | ||
| return this.asString(key); | ||
| } | ||
|
|
||
| @Override | ||
| default @NotNull Stream<? extends ExaminableProperty> examinableProperties() { | ||
| return Stream.of( | ||
| ExaminableProperty.of("namespace", this.namespace()), | ||
| ExaminableProperty.of("separator", this.separator()) | ||
| ); | ||
| } | ||
|
|
||
| /** | ||
| * A builder for a key format. | ||
| * | ||
| * @since 4.24.0 | ||
| */ | ||
| interface Builder { | ||
| /** | ||
| * Sets the fallback namespace of this builder from a {@link Namespaced} instance. | ||
| * | ||
| * @param namespaced the namespaced instance | ||
| * @return this builder | ||
| * @see #namespace(String) | ||
| * @since 4.24.0 | ||
| */ | ||
| @Contract("_ -> this") | ||
| default @NotNull Builder namespace(final @NotNull Namespaced namespaced) { | ||
| return this.namespace(requireNonNull(namespaced, "namespaced").namespace()); | ||
| } | ||
|
|
||
| /** | ||
| * Sets the fallback namespace of this builder. | ||
| * | ||
| * <p>This namespace is used in {@link #parse(String)} when the input string doesn't specify a namespace.</p> | ||
| * | ||
| * <p>Defaults to {@link Key#MINECRAFT_NAMESPACE}</p> | ||
| * | ||
| * @param namespace the namespace | ||
| * @return this builder | ||
| * @since 4.24.0 | ||
| */ | ||
| @Contract("_ -> this") | ||
| @NotNull Builder namespace(@KeyPattern.Namespace final @NotNull String namespace); | ||
|
|
||
| /** | ||
| * Sets the separator of this builder. | ||
| * | ||
| * <p>The separator is used to separate namespace and value in {@link #parse(String)}.</p> | ||
| * | ||
| * <p>Defaults to {@link Key#DEFAULT_SEPARATOR}</p> | ||
| * | ||
| * @param separator the separator | ||
| * @return this builder | ||
| * @since 4.24.0 | ||
| */ | ||
| @Contract("_ -> this") | ||
| @NotNull Builder separator(final char separator); | ||
|
|
||
| /** | ||
| * Builds the key format. | ||
| * | ||
| * @return the key format | ||
| * @throws IllegalArgumentException if the namespace contains an invalid character | ||
| * @since 4.24.0 | ||
| */ | ||
| @Contract(value = "-> new", pure = true) | ||
| @NotNull KeyFormat build(); | ||
| } | ||
| } | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.