feat(rgb): enhance decodeLegacy with HTML tags, raw hex & format modi… - #244
feat(rgb): enhance decodeLegacy with HTML tags, raw hex & format modi…#244Kuzeex wants to merge 1 commit into
Conversation
📝 WalkthroughWalkthroughChangesRGB decoding
Estimated code review effort: 3 (Moderate) | ~20 minutes Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment Warning |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/util/rgb/Decode.ts`:
- Around line 76-77: Update the codeRegex raw-hex alternative so `&` and `§`
prefixes require a following `#`, while still matching standalone `#RRGGBB`;
ensure `§#RRGGBB` is consumed as one token so no prefix remains visible.
Preserve the existing escaped-hex, span, and formatting-code alternatives.
- Around line 116-124: Update the formatting/reset-code condition near lastChar
in the decoder to match only actual single formatting or reset code shapes,
rather than any value beginning with the escaped section-sign prefix. Ensure
full Legacy Hex sequences, including those using \u00a7, bypass this branch and
continue through color decoding while preserving existing handling for valid
formatting codes.
- Around line 109-115: Update the span style handling in the Decode formatting
parser so currentFmts.bold, italic, underline, and strikethrough are reset for
each new span before applying declarations from styleAttr. Preserve flags only
when the current span explicitly declares the corresponding style, while leaving
the existing reset-code behavior unchanged.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 4a8e2252-f866-4313-bc47-a0394b0f2014
📒 Files selected for processing (1)
src/util/rgb/Decode.ts
| const codeRegex = | ||
| /(?:(?:[&§]|\\u00a7)x(?:(?:[&§]|\\u00a7)[0-9A-Fa-f]){6}|[&#§]\b[0-9A-Fa-f]{6}\b|&#[0-9A-Fa-f]{6}|<span[^>]*style=["']([^"']*)["'][^>]*>|<\/span>|(?:[&§]|\\u00a7)[l-orL-ORkK])/gi; |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
node -e "
const re = /(?:(?:[&§]|\\\\u00a7)x(?:(?:[&§]|\\\\u00a7)[0-9A-Fa-f]){6}|[&#§]\b[0-9A-Fa-f]{6}\b|&#[0-9A-Fa-f]{6}|<span[^>]*style=[\"']([^\"']*)[\"'][^>]*>|<\/span>|(?:[&§]|\\\\u00a7)[l-orL-ORkK])/gi;
console.log('Text: My id is &123456 done', [...('My id is &123456 done').matchAll(re)].map(m => m[0]));
console.log('Text: color §#abcdef here', [...('color §#abcdef here').matchAll(re)].map(m => m[0]));
"Repository: birdflop/web
Length of output: 232
Fix the raw-hex alternative so it does not over-match &/§ and does not break §#RRGGBB.
[&#§]\b[0-9A-Fa-f]{6}\b matches &123456 and §123456 without #, treating plain text as a raw hex color. It also cannot match §#123456 as one token because the boundary after § fails before #, so only #123456 matches and the leading § remains visible.
🐛 Proposed fix
const codeRegex =
/(?:(?:[&§]|\\u00a7)x(?:(?:[&§]|\\u00a7)[0-9A-Fa-f]){6}|[&#§]\b[0-9A-Fa-f]{6}\b|&#[0-9A-Fa-f]{6}|<span[^>]*style=["']([^"']*)["'][^>]*>|<\/span>|(?:[&§]|\\u00a7)[l-orL-ORkK])/gi;
+ /(?:(?:[&§]|\\u00a7)x(?:(?:[&§]|\\u00a7)[0-9A-Fa-f]){6}|#\b[0-9A-Fa-f]{6}\b|(?:&|§)#[0-9A-Fa-f]{6}|<span[^>]*style=["']([^"']*)["'][^>]*>|<\/span>|(?:[&§]|\\u00a7)[l-orL-ORkK])/gi;📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const codeRegex = | |
| /(?:(?:[&§]|\\u00a7)x(?:(?:[&§]|\\u00a7)[0-9A-Fa-f]){6}|[&#§]\b[0-9A-Fa-f]{6}\b|&#[0-9A-Fa-f]{6}|<span[^>]*style=["']([^"']*)["'][^>]*>|<\/span>|(?:[&§]|\\u00a7)[l-orL-ORkK])/gi; | |
| const codeRegex = | |
| /(?:(?:[&§]|\\u00a7)x(?:(?:[&§]|\\u00a7)[0-9A-Fa-f]){6}|#\b[0-9A-Fa-f]{6}\b|(?:&|§)#[0-9A-Fa-f]{6}|<span[^>]*style=["']([^"']*)["'][^>]*>|<\/span>|(?:[&§]|\\u00a7)[l-orL-ORkK])/gi; |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/util/rgb/Decode.ts` around lines 76 - 77, Update the codeRegex raw-hex
alternative so `&` and `§` prefixes require a following `#`, while still
matching standalone `#RRGGBB`; ensure `§#RRGGBB` is consumed as one token so no
prefix remains visible. Preserve the existing escaped-hex, span, and
formatting-code alternatives.
| if (/font-weight:\s*bold/i.test(styleAttr)) currentFmts.bold = true; | ||
| if (/font-style:\s*italic/i.test(styleAttr)) currentFmts.italic = true; | ||
| if (/text-decoration:[^;]*underline/i.test(styleAttr)) currentFmts.underline = true; | ||
| if (/text-decoration:[^;]*line-through/i.test(styleAttr)) currentFmts.strikethrough = true; | ||
| } else if (codeStr.toLowerCase() === '</span>') { | ||
| // closing tag | ||
| } else { |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Files:"
git ls-files | rg '(^|/)Decode\.ts$|rgb|HTML|Parser' || true
echo
echo "Decode outline:"
if [ -f src/util/rgb/Decode.ts ]; then
ast-grep outline src/util/rgb/Decode.ts --view compact || true
echo
echo "Relevant Decode.ts 1-180:"
sed -n '1,180p' src/util/rgb/Decode.ts | cat -n
fi
echo
echo "Search for Decode/rich/span usage:"
rg -n "Decode|\\$<r|r>|currentFmts|font-weight|font-style|text-decoration|span" . --glob '!node_modules/**' --glob '!dist/**' --glob '!build/**' | head -200Repository: birdflop/web
Length of output: 27745
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "MiniMessageDecode relevant sections:"
sed -n '1,380p' src/util/rgb/MiniMessageDecode.ts | cat -n
echo
echo "Decode tests:"
if [ -f src/util/rgb/__tests__ 2>/dev/null ]; then
fd . src/util/rgb/__tests__ -t f -x sh -c 'echo "--- $1"; cat -n "$1"' sh {}
fi
fd './Decode.*\.test\.(ts|tsx|js)$|rgbUtils.test.ts' src packages --exec sh -c 'echo "--- $1"; cat -n "$1"' sh {}
echo
echo "HTML/span examples in rgb package docs/source:"
rg -n "<span[^>]+style=|font-(weight|style)|text-decoration|text:<color>|<color|<span" packages/src packages packages/rgbirdflop --glob '!node_modules/**' --glob '!dist/**' --glob '!build/**' | head -250Repository: birdflop/web
Length of output: 19310
🌐 Web query:
RGBirdflop Decode.ts span HTML style decode legacy miniMessage output <span style="font-weight:bold color:#...
💡 Result:
The specific output format <span style="font-weight:bold color:#... is not a standard MiniMessage or legacy Minecraft format, nor is it a native output format of the RGBirdflop toolset [1][2]. RGBirdflop generates Minecraft-compatible formats like MiniMessage (<gradient:...>), legacy section codes (§), or ampersand codes (&) [1][3][2]. If you are encountering <span style="..."> HTML-like tags, this indicates that the text has likely been processed by an HTML converter, an web-based UI component, or a specialized Minecraft plugin intended to bridge web-based CSS styling with game text [4][5]. To resolve or decode this: 1. Identification: The string structure suggests it is attempting to translate web-style CSS (bold, hex colors) into Minecraft components [4]. This is often used by web dashboards that display server chat or status messages. 2. Conversion Path: If your goal is to get this into a format compatible with Minecraft (MiniMessage), you should use a deserializer that can handle HTML, or perform a string replace/regex to map these CSS styles to standard MiniMessage tags [4][5]. - Example mapping: Replace <span style="font-weight:bold color:#([0-9a-fA-F]{6})"> with <color:#$1><bold>. 3. Authorized Tools: For standard Minecraft conversions, utilize the LegacyComponentSerializer or MiniMessage APIs provided by the Adventure library, which is the authoritative standard for handling these formats in modern Minecraft development [4][5][6]. If you are attempting to use RGBirdflop specifically, ensure you are selecting the correct output format (e.g., MiniMessage or Legacy) in its configuration, as RGBirdflop does not natively output HTML <span> tags [1][3][2].
Citations:
- 1: https://mintlify.wiki/birdflop/web/sdk/quickstart
- 2: https://mintlify.wiki/birdflop/web/tools/rgbirdflop
- 3: https://www.birdflop.com/resources/rgb/
- 4: https://docs.papermc.io/adventure/minimessage/api/
- 5: https://github.com/imDaniX/MiniTranslator
- 6: https://jd.advntr.dev/text-minimessage/latest/net/kyori/adventure/text/minimessage/MiniMessage.html
🌐 Web query:
MiniTranslator <span style="font-weight:bold color:#ffffff"/> text decoration underline line-through Decode.ts
💡 Result:
The term MiniTranslator is commonly associated with a Java utility used to convert Minecraft legacy formatting codes (like &n for underline and &m for strikethrough) into MiniMessage tags [1][2][3]. While there is no single authoritative library named "MiniTranslator" that contains a specific "Decode.ts" file implementing text-decoration logic, technical searches reveal a relevant implementation in the context of converting macOS Notes data to Markdown [4][5]. Specifically, in the macos-ts library, the file src/notes/protobuf/decode.ts handles the decoding of attributes (such as underlined or strikethrough state) from protobuf data [4], and the corresponding src/notes/conversion/proto-to-markdown.ts file processes these decoded attributes to apply text decorations like strikethrough (text) or underline (via HTML tags) during conversion [5]. For Minecraft-related projects, MiniTranslator [1][3] and related tools like FlectonePulse [6][7] map legacy codes to MiniMessage tags as follows: - Underline: &n maps to [3][6] - Strikethrough: &m maps to [3][6] If you are working with a TypeScript codebase and looking for a "Decode.ts" file, it is likely part of a specific project (such as a parser or converter) where you must manually map state flags (e.g., isUnderlined, isStrikethrough) to the desired output format (like HTML or Markdown) [5].
Citations:
- 1: https://github.com/imDaniX/MiniTranslator
- 2: https://github.laiyagushi.com/imDaniX/MiniTranslator
- 3: https://gist.github.com/imDaniX/e536c3e1cce7c8c8ed34e63fee1e0689
- 4: https://cdn.jsdelivr.net/npm/macos-ts@0.15.0/src/notes/protobuf/decode.ts
- 5: https://cdn.jsdelivr.net/npm/macos-ts@0.15.0/src/notes/conversion/proto-to-markdown.ts
- 6: https://dev.bukkit.org/projects/flectonepulse
- 7: https://hangar.papermc.io/TheFaser/FlectonePulse
🌐 Web query:
site:github.com/imDaniX/MiniTranslator Decode.ts span style font-weight bold
💡 Result:
I couldn’t find Decode.ts or the exact span style="font-weight: bold" text in imDaniX/MiniTranslator. The repository is Java-based, with source files under src, and maps Minecraft bold formatting (&l) to MiniMessage’s <b> tag. (github.com)
Citations:
🌐 Web query:
"font-weight:\s*bold" "text-decoration:[^;]*underline" "currentFmts.bold"
💡 Result:
The text pattern provided appears to be a composite of CSS properties (font-weight, text-decoration) and a programmatic object reference (currentFmts.bold) often used in text-processing or editor-related software. 1. CSS Properties: The segments font-weight: bold and text-decoration: underline are standard CSS rules used to style text [1][2]. In rich text editors like CKEditor or Lexical, these CSS properties are frequently used to identify or apply formatting styles during document parsing or transformation [3][4][5]. 2. currentFmts.bold: This is not a standard web API. Based on common coding patterns in text-formatting libraries, it is likely a property or object within an editor's internal state management (such as TinyMCE's formatter engine [6][7], a custom extension [4], or a formatting utility). It represents a flag or boolean configuration indicating that the currently selected text or node should be, or is currently, formatted as bold [4][6]. In summary, the string reflects an internal software operation where a system checks if a specific text range has bold formatting (currentFmts.bold) and applies corresponding CSS styles (font-weight: bold; text-decoration: underline;) when rendering or exporting that content [3][4].
Citations:
- 1: https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/text-decoration
- 2: https://developer.mozilla.org/docs/Web/CSS/CSS_text_decoration
- 3: https://ckeditor.com/docs/ckeditor5/latest/features/basic-styles.html
- 4: https://github.com/facebook/lexical/blob/e03b0fe5/packages/lexical-extension/src/DecoratorTextExtension.ts
- 5: https://ckeditor.com/docs/ckeditor5/15.0.0/features/basic-styles.html
- 6: https://tinymce-docs.iad.tiny.cloud/docs/tinymce/7/apis/tinymce.formatter/
- 7: https://tinymce-docs.iad.tiny.cloud/docs/tinymce/5/apis/tinymce.formatter/
🌐 Web query:
"parseMiniMessage" "decodeMiniMessage"
💡 Result:
In the context of the Adventure library's MiniMessage implementation, which is the industry standard for parsing MiniMessage, the terms parseMiniMessage and decodeMiniMessage are not part of the official public API [1][2][3]. The Adventure MiniMessage API uses the following primary methods to process strings [1][2][4]: deserialize(String input): This is the standard method used to convert a MiniMessage string into a Component object [1][2][3]. serialize(Component component): This is used to convert a Component object back into a MiniMessage string [1][2]. If you have encountered parseMiniMessage or decodeMiniMessage in your codebase, they are likely either: 1. Custom wrapper utility methods defined within your own project or a third-party plugin/library (such as AdventureUtils) to simplify common tasks [5][6]. 2. Legacy method names from older or alternative MiniMessage implementations [7]. For example, some third-party utilities define a parseMiniMessage method that might combine deserialization with other logic, such as legacy color code conversion or applying custom TagResolvers [5][6]. You should check the source code or the documentation of the specific utility class where these methods are defined to understand their exact behavior [5][6].
Citations:
- 1: https://docs.papermc.io/adventure/minimessage/api/
- 2: https://jd.advntr.dev/text-minimessage/latest/net/kyori/adventure/text/minimessage/MiniMessage.html
- 3: https://jd.papermc.io/adventure/5.2.0/net.kyori.adventure.text.minimessage/net/kyori/adventure/text/minimessage/MiniMessage.html
- 4: https://jd.advntr.dev/text-minimessage/4.24.0/net/kyori/adventure/text/minimessage/MiniMessage.html
- 5: https://jd.nexomc.com/1.15/com/nexomc/nexo/utils/AdventureUtils.html
- 6: https://jd.nexomc.com/1.8/com/nexomc/nexo/utils/AdventureUtils.html
- 7: https://github.com/Minevictus/MiniMessage
Reset span formatting flags on each style change.
currentFmts.bold, .italic, .underline, and .strikethrough are set only when a style is present, and </span> is a no-op. A second sibling <span> that omits a previous style keeps that formatting until &r/§r. Assign each flag only when the span’s style declares it, unless nested span inheritance is the required behavior.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/util/rgb/Decode.ts` around lines 109 - 115, Update the span style
handling in the Decode formatting parser so currentFmts.bold, italic, underline,
and strikethrough are reset for each new span before applying declarations from
styleAttr. Preserve flags only when the current span explicitly declares the
corresponding style, while leaving the existing reset-code behavior unchanged.
| const lastChar = codeStr.charAt(codeStr.length - 1).toLowerCase(); | ||
| if (codeStr.length === 2 || codeStr.startsWith('\\u00a7')) { | ||
| if (lastChar === 'r') { | ||
| currentColor = '#ffffff'; | ||
| currentFmts.bold = false; | ||
| currentFmts.italic = false; | ||
| currentFmts.underline = false; | ||
| currentFmts.strikethrough = false; | ||
| currentFmts.obfuscate = false; |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
\u00a7-prefixed Legacy Hex codes are misrouted to the formatting branch and lose their color.
The condition codeStr.length === 2 || codeStr.startsWith('\\u00a7') is meant to isolate single formatting/reset codes (&l, §r, or their \u00a7-escaped forms). But a full Legacy Hex match ((?:[&§]|\\u00a7)x(?:(?:[&§]|\\u00a7)[0-9A-Fa-f]){6}) that happens to use the \u00a7 prefix also starts with that same literal text, so it enters this branch too. Inside, lastChar is one of the trailing hex digits, which never equals r, l, o, n, m, or k, so none of the branches in Lines 118-135 execute. The color encoded in that Legacy Hex sequence is silently dropped, and currentColor retains its prior value.
Detect formatting/reset codes by their actual shape instead of length/prefix heuristics, so a \u00a7-prefixed Legacy Hex match is never confused with a formatting code.
🐛 Proposed fix
const lastChar = codeStr.charAt(codeStr.length - 1).toLowerCase();
- if (codeStr.length === 2 || codeStr.startsWith('\\u00a7')) {
+ if (/^(?:[&§]|\\u00a7)[l-orL-ORkK]$/i.test(codeStr)) {📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const lastChar = codeStr.charAt(codeStr.length - 1).toLowerCase(); | |
| if (codeStr.length === 2 || codeStr.startsWith('\\u00a7')) { | |
| if (lastChar === 'r') { | |
| currentColor = '#ffffff'; | |
| currentFmts.bold = false; | |
| currentFmts.italic = false; | |
| currentFmts.underline = false; | |
| currentFmts.strikethrough = false; | |
| currentFmts.obfuscate = false; | |
| const lastChar = codeStr.charAt(codeStr.length - 1).toLowerCase(); | |
| if (/^(?:[&§]|\\u00a7)[l-orL-ORkK]$/i.test(codeStr)) { | |
| if (lastChar === 'r') { | |
| currentColor = '`#ffffff`'; | |
| currentFmts.bold = false; | |
| currentFmts.italic = false; | |
| currentFmts.underline = false; | |
| currentFmts.strikethrough = false; | |
| currentFmts.obfuscate = false; |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/util/rgb/Decode.ts` around lines 116 - 124, Update the
formatting/reset-code condition near lastChar in the decoder to match only
actual single formatting or reset code shapes, rather than any value beginning
with the escaped section-sign prefix. Ensure full Legacy Hex sequences,
including those using \u00a7, bypass this branch and continue through color
decoding while preserving existing handling for valid formatting codes.
Summary
This PR enhances
decodeLegacyinsrc/util/rgb/Decode.tsto expand Birdflop's RGB decoding capabilities. It allows users to paste raw RGB text formatted in HTML, generic hex, legacy Minecraft codes, or modern formats, automatically extracting character colors, clean plain text, and formatting states without breaking any existing API contracts.Features Added & Improvements
<span style="color:#RRGGBB; font-weight:bold; font-style:italic; text-decoration:underline">...</span>tags and extracts both hex colors and active formatting flags.#RRGGBBhex strings even when&xor&#prefixes are missing.&x&f&f&0&0&5&5/§x§f§f...), Modern Hex (&#ff0055/§#ff0055), and formatting codes (&lbold,&oitalic,&nunderline,&mstrikethrough,&kobfuscate,&rreset).pos) and builds exactcharFormattingsarrays forbuildFormatSegments().##Backward Compatibility
hexToHSL,getSignificantPoints,buildFormatSegments, anddecodeLegacy).Summary by CodeRabbit