diff --git a/text-minimessage/src/main/java/net/kyori/adventure/text/minimessage/parser/TokenParser.java b/text-minimessage/src/main/java/net/kyori/adventure/text/minimessage/parser/TokenParser.java index c17ae4f6e2..60d0bd8ea8 100644 --- a/text-minimessage/src/main/java/net/kyori/adventure/text/minimessage/parser/TokenParser.java +++ b/text-minimessage/src/main/java/net/kyori/adventure/text/minimessage/parser/TokenParser.java @@ -108,7 +108,7 @@ public static String resolvePreProcessTags(final String message, final TagProvid lastResult = result; final StringResolvingMatchedTokenConsumer stringTokenResolver = new StringResolvingMatchedTokenConsumer(lastResult, provider); - parseString(lastResult, stringTokenResolver); + parseString(lastResult, stringTokenResolver, false); result = stringTokenResolver.result(); passes++; } while (passes < MAX_DEPTH && !lastResult.equals(result)); @@ -125,9 +125,8 @@ public static String resolvePreProcessTags(final String message, final TagProvid * @since 4.10.0 */ public static List tokenize(final String message, final boolean strict) { - tryToNag(message, strict); final TokenListProducingMatchedTokenConsumer listProducer = new TokenListProducingMatchedTokenConsumer(message); - parseString(message, listProducer); + parseString(message, listProducer, strict); final List tokens = listProducer.result(); parseSecondPass(message, tokens); return tokens; @@ -144,9 +143,10 @@ enum FirstPassState { * * @param message the message * @param consumer the consumer + * @param throwOnLegacyCharacter whether to throw an exception if the section symbol is found in parsed strings * @since 4.10.0 */ - public static void parseString(final String message, final MatchedTokenConsumer consumer) { + public static void parseString(final String message, final MatchedTokenConsumer consumer, final boolean throwOnLegacyCharacter) { FirstPassState state = FirstPassState.NORMAL; // If the current state is escaped then the next character is skipped boolean escaped = false; @@ -159,10 +159,17 @@ public static void parseString(final String message, final MatchedTokenConsumer< final int length = message.length(); for (int i = 0; i < length; i++) { final int codePoint = message.codePointAt(i); + if (throwOnLegacyCharacter && codePoint == '§') { + throw new ParsingExceptionImpl( + "Legacy formatting codes have been detected in a component - this is unsupported behaviour. Please refer to the Adventure documentation (https://docs.adventure.kyori.net) for more information.", + message, + new Token(i, i + 2, TokenType.TEXT) + ); + } + if (!Character.isBmpCodePoint(codePoint)) { i++; } - if (!escaped) { // if we're trying to escape and the next character exists if (codePoint == ESCAPE && i + 1 < message.length()) { @@ -614,19 +621,6 @@ public static String unescape(final String text, final int startIndex, final int return sb.toString(); } - /* - * Nags the user about using legacy symbol, if they used it. - * - * @param input the input text - * @param strict strict mode - * @since 4.10.0 - */ - private static void tryToNag(final String input, final boolean strict) { - if (input.contains("§") && strict) { - throw new IllegalArgumentException("Legacy formatting codes have been detected in a component - this is unsupported behaviour. Please refer to the Adventure documentation (https://docs.adventure.kyori.net) for more information."); - } - } - /** * Normalizing provider for tag information. * diff --git a/text-minimessage/src/test/java/net/kyori/adventure/text/minimessage/MiniMessageParserTest.java b/text-minimessage/src/test/java/net/kyori/adventure/text/minimessage/MiniMessageParserTest.java index f4a219f3e2..4ec86648a2 100644 --- a/text-minimessage/src/test/java/net/kyori/adventure/text/minimessage/MiniMessageParserTest.java +++ b/text-minimessage/src/test/java/net/kyori/adventure/text/minimessage/MiniMessageParserTest.java @@ -53,7 +53,9 @@ import static net.kyori.adventure.text.format.TextDecoration.UNDERLINED; import static net.kyori.adventure.text.minimessage.tag.resolver.Placeholder.component; import static net.kyori.adventure.text.minimessage.tag.resolver.Placeholder.parsed; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; public class MiniMessageParserTest extends AbstractTest { @@ -469,4 +471,14 @@ void testIgnorableSelfClosable() { this.assertParsedEquals(parsed, input); } + + @Test + void testLegacySymbolForbiddenInStrictMode() { + final String failingTest = "Hello §Cfriends"; + + // Non-strict + assertDoesNotThrow(() -> PARSER.deserialize(failingTest)); + + System.out.println(assertThrows(ParsingException.class, () -> MiniMessage.builder().strict(true).build().deserialize(failingTest)).getMessage()); + } }